OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
hdfdesc.cc
Go to the documentation of this file.
1 // This file is part of the hdf4 data handler for the OPeNDAP data server.
6 // The code includes the support of HDF-EOS2 and NASA HDF4 files that follow CF.
7 // Copyright (c) 2008-2012 The HDF Group.
8 // Author: MuQun Yang <myang6@hdfgroup.org>
9 // Author: Hyo-Kyung Lee <hyoklee@hdfgroup.org>
10 //
11 // Copyright (c) 2005 OPeNDAP, Inc.
12 // Author: James Gallagher <jgallagher@opendap.org>
13 //
14 // This is free software; you can redistribute it and/or modify it under the
15 // terms of the GNU Lesser General Public License as published by the Free
16 // Software Foundation; either version 2.1 of the License, or (at your
17 // option) any later version.
18 //
19 // This software is distributed in the hope that it will be useful, but
20 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
21 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
22 // License for more details.
23 //
24 // You should have received a copy of the GNU Lesser General Public License
25 // along with this software; if not, write to the Free Software Foundation,
26 // Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
27 //
28 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
29 
31 // Copyright 1996, by the California Institute of Technology.
32 // ALL RIGHTS RESERVED. United States Government Sponsorship
33 // acknowledged. Any commercial use must be negotiated with the
34 // Office of Technology Transfer at the California Institute of
35 // Technology. This software may be subject to U.S. export control
36 // laws and regulations. By accepting this software, the user
37 // agrees to comply with all applicable U.S. export laws and
38 // regulations. User has the responsibility to obtain export
39 // licenses, or other export authority as may be required before
40 // exporting such information to foreign countries or providing
41 // access to foreign persons.
42 
43 // Author: Todd Karakashian, NASA/Jet Propulsion Laboratory
44 // Todd.K.Karakashian@jpl.nasa.gov
45 //
46 //
48 
49 #include "config_hdf.h"
50 
51 #include <cstdio>
52 #include <cassert>
53 #include <libgen.h>
54 
55 // STL includes
56 #include <string>
57 #include <fstream>
58 #include <iostream>
59 #include <sstream>
60 #include <algorithm>
61 #include <numeric>
62 #include <functional>
63 
64 
65 // Include this on linux to suppress an annoying warning about multiple
66 // definitions of MIN and MAX.
67 #ifdef HAVE_SYS_PARAM_H
68 #include <sys/param.h>
69 #endif
70 
71 #include <unistd.h>
72 #include <sys/types.h>
73 #include <dirent.h>
74 #include <iomanip>
75 
76 
77 // HDF and HDFClass includes
78 #include <mfhdf.h>
79 
80 // DODS includes
81 #include <DDS.h>
82 #include <DAS.h>
83 #include <escaping.h>
84 #include <parser.h>
85 #include <InternalErr.h>
86 #include <debug.h>
87 
88 #include <BESDebug.h>
89 #include <BESLog.h>
90 
91 // DODS/HDF includes for the default option only
92 #include "hcstream.h"
93 #include "hdfclass.h"
94 #include "hcerr.h"
95 #include "dhdferr.h"
96 #include "HDFArray.h"
97 #include "HDFSequence.h"
98 #include "HDFTypeFactory.h"
99 #include "HDFGrid.h"
100 #include "dodsutil.h"
101 #include "hdf-dods.h"
102 #include "hdf-maps.h"
103 
104 // DAP2 doesn't have signed char type, the signed char will be converted to int32 with this macro.
105 #define SIGNED_BYTE_TO_INT32 1
106 
107 // HDF datatype headers for both the default and the CF options
108 #include "HDFByte.h"
109 #include "HDFInt16.h"
110 #include "HDFUInt16.h"
111 #include "HDFInt32.h"
112 #include "HDFUInt32.h"
113 #include "HDFFloat32.h"
114 #include "HDFFloat64.h"
115 #include "HDFStr.h"
116 
117 // Routines that handle SDS and Vdata attributes for the HDF-EOS2 objects in a hybrid HDF-EOS2 file for the CF option
118 #include "HE2CF.h"
119 
120 // HDF4 for the CF option(EOS2 will treat as pure HDF4 objects if the HDF-EOS2 library is not configured in)
121 #include "HDFSP.h"
122 #include "HDFSPArray_RealField.h"
123 #include "HDFSPArrayGeoField.h"
124 #include "HDFSPArrayMissField.h"
125 #include "HDFSPArrayAddCVField.h"
126 #include "HDFSPArray_VDField.h"
127 #include "HDFCFStrField.h"
128 #include "HDFCFStr.h"
129 #include "HDFCFUtil.h"
130 
131 // HDF-EOS2 (including the hybrid) will be handled as HDF-EOS2 objects if the HDF-EOS2 library is configured in
132 #ifdef USE_HDFEOS2_LIB
133 #include "HDFEOS2.h"
134 #include "HDFEOS2Array_RealField.h"
137 #include "HDFEOS2ArrayMissField.h"
139 //#include "HDFEOS2ArraySwathGeoDimMapField.h"
141 #include "HDFEOS2CFStr.h"
142 #include "HDFEOS2CFStrField.h"
143 #include "HDFEOS2HandleType.h"
144 #endif
145 
146 // For performance checking
147 #undef KENT
148 #undef KENT2
149 #undef KENT3
150 
151 using namespace std;
152 
153 // Added 5/7/09; This bug (#1163) was fixed in July 2008 except for this
154 // handler. jhrg
155 #define ATTR_STRING_QUOTE_FIX
156 
157 template < class T > string num2string(T n)
158 {
159  ostringstream oss;
160  oss << n;
161  return oss.str();
162 }
163 
164 // Glue routines declared in hdfeos.lex
165 void hdfeos_switch_to_buffer(void *new_buffer);
166 void hdfeos_delete_buffer(void * buffer);
167 void *hdfeos_string(const char *yy_str);
168 
169 struct yy_buffer_state;
170 yy_buffer_state *hdfeos_scan_string(const char *str);
171 extern int hdfeosparse(libdap::parser_arg *arg); // defined in hdfeos.tab.c
172 
173 // Functions for the default option
174 void AddHDFAttr(DAS & das, const string & varname,
175  const vector < hdf_attr > &hav);
176 void AddHDFAttr(DAS & das, const string & varname,
177  const vector < string > &anv);
178 
179 static void build_descriptions(DDS & dds, DAS & das,
180  const string & filename);
181 static void SDS_descriptions(sds_map & map, DAS & das,
182  const string & filename);
183 static void Vdata_descriptions(vd_map & map, DAS & das,
184  const string & filename);
185 static void Vgroup_descriptions(DDS & dds, DAS & das,
186  const string & filename, sds_map & sdmap,
187  vd_map & vdmap, gr_map & grmap);
188 static void GR_descriptions(gr_map & map, DAS & das,
189  const string & filename);
190 static void FileAnnot_descriptions(DAS & das, const string & filename);
191 static vector < hdf_attr > Pals2Attrs(const vector < hdf_palette > palv);
192 static vector < hdf_attr > Dims2Attrs(const hdf_dim dim);
193 
194 void read_das(DAS & das, const string & filename);
195 void read_dds(DDS & dds, const string & filename);
196 
197 // For the CF option
198 // read_dds for HDF4 files. Some NASA non-eos2 HDF4 products are handled specifially to follow the CF conventions.
199 bool read_dds_hdfsp(DDS & dds, const string & filename,int32 sdfd, int32 fileid,HDFSP::File*h4file);
200 bool read_das_hdfsp(DAS & das, const string & filename,int32 sdfd, int32 fileid,HDFSP::File**h4filepptr);
201 
202 // read_dds for special NASA HDF-EOS2 hybrid(non-EOS2) objects
203 bool read_dds_hdfhybrid(DDS & dds, const string & filename,int32 sdfd, int32 fileid,HDFSP::File*h4file);
204 bool read_das_hdfhybrid(DAS & das, const string & filename,int32 sdfd, int32 fileid,HDFSP::File**h4filepptr);
205 
206 // Functions to read special 1-d HDF-EOS2 grid. This grid can be built up quickly.
207 //bool read_dds_special_1d_grid(DDS &dds, HDFSP::File *spf, const string & filename,int32 sdfd, int32 fileid);
208 bool read_dds_special_1d_grid(DDS &dds, HDFSP::File *spf, const string & filename,int32 sdfd, int32 fileid);
209 bool read_das_special_eos2(DAS &das,const string & filename,int32 sdid, int32 fileid,bool ecs_metadata,HDFSP::File**h4filepptr);
210 bool read_das_special_eos2_core(DAS &das, HDFSP::File *spf, const string & filename,bool ecs_metadata);
211 void change_das_mod08_scale_offset(DAS & das, HDFSP::File *spf);
212 
213 // Functions to handle SDS fields for the CF option.
214 void read_dds_spfields(DDS &dds,const string& filename,const int sdfd,HDFSP::SDField *spsds, SPType sptype);
215 
216 // Functions to handle Vdata fields for the CF option.
217 void read_dds_spvdfields(DDS &dds,const string& filename, const int fileid,int32 vdref, int32 numrec,HDFSP::VDField *spvd);
218 
219 // Check if this is a special HDF-EOS2 file that can be handled by HDF4 directly. Using HDF4 only can improve performance.
220 int check_special_eosfile(const string&filename,string&grid_name,int32 sdfd,int32 fileid);
221 
222 
223 // The following blocks only handle HDF-EOS2 objects based on HDF-EOS2 libraries.
224 #ifdef USE_HDFEOS2_LIB
225 
226 // Parse HDF-EOS2's ECS metadata(coremetadata etc.)
227 void parse_ecs_metadata(DAS &das,const string & metaname, const string &metadata);
228 
229 // read_dds for HDF-EOS2
231 // We find some special HDF-EOS2(MOD08_M3) products that provides coordinate variables
232 // without using the dimension scales. We will handle this in a special way.
233 // So change the return value of read_dds_hdfeos2 to represent different cases
234 // 0: general non-EOS2 pure HDF4
235 // 1: HDF-EOS2 hybrid
236 // 2: MOD08_M3
237 // HDF-EOS2 but no need to use HDF-EOS2 lib: no real dimension scales but have CVs for every dimension, treat differently
238 // 3: AIRS version 6
239 // HDF-EOS2 but no need to use HDF-EOS2 lib:
240 // have dimension scales but don’t have CVs for every dimension, also need to condense dimensions, treat differently
241 // 4. Expected AIRS level 3 or level 2
242 // HDF-EOS2 but no need to use HDF-EOS2 lib: Have dimension scales for all dimensions
243 // 5. MERRA
244 // Special handling for MERRA file
245 int read_dds_hdfeos2(DDS & dds, const string & filename,int32 sdfd,int32 fileid, int32 gridfd, int32 swathfd,HDFSP::File*h4file,HDFEOS2::File*eosfile);
246 
247 // reas das for HDF-EOS2
248 int read_das_hdfeos2(DAS & das, const string & filename,int32 sdfd,int32 fileid, int32 gridfd, int32 swathfd,bool ecs_metadata,HDFSP::File**h4filepptr,HDFEOS2::File**eosfilepptr);
249 
250 
251 // read_dds for one grid or swath
252 void read_dds_hdfeos2_grid_swath(DDS &dds, const string&filename, HDFEOS2::Dataset *dataset, int grid_or_swath,bool ownll, SOType sotype,
253  int32 sdfd, int32 fileid, int32 gridfd,int32 swathfd)
254 {
255 
256  BESDEBUG("h4","Coming to read_dds_hdfeos2_grid_swath "<<endl);
257  // grid_or_swath - 0: grid, 1: swath
258  if(grid_or_swath < 0 || grid_or_swath > 1)
259  throw InternalErr(__FILE__, __LINE__, "The current type should be either grid or swath");
260 
262 
263  // Declare dim. map entry. The defination of dimmap_entry can be found at HDFCFUtil.h.
264  vector<struct dimmap_entry> dimmaps;
265 
266  //The extra dim map file name(lat/lon of swath with dim. map can be found in a separate HDF file.
267  string modis_geofilename="";
268  bool geofile_has_dimmap = false;
269 
270  // 1. Obtain dimension map info and stores the info. to dimmaps.
271  // 2. Check if MODIS swath geo-location HDF-EOS2 file exists for the dimension map case of MODIS Swath
272  if(grid_or_swath == 1)
273  HDFCFUtil::obtain_dimmap_info(filename,dataset,dimmaps,modis_geofilename,geofile_has_dimmap);
275 
276 #if 0
277  int32 projcode=-1;
280 
281  // Obtain the projection code for a grid
282  if(0 == grid_or_swath)
283  {
284  HDFEOS2::GridDataset *gd = static_cast<HDFEOS2::GridDataset *>(dataset);
285  projcode = gd->getProjection().getCode();
286  }
288 #endif
289 
291  const vector<HDFEOS2::Field*>& fields = (dataset)->getDataFields();
292  vector<HDFEOS2::Field*> all_fields = fields;
293  vector<HDFEOS2::Field*>::const_iterator it_f;
294 
295  if(1 == grid_or_swath) {
296  HDFEOS2::SwathDataset *sw = static_cast<HDFEOS2::SwathDataset *>(dataset);
297  const vector<HDFEOS2::Field*>geofields = sw->getGeoFields();
298  for (it_f = geofields.begin(); it_f != geofields.end(); it_f++)
299  all_fields.push_back(*it_f);
300  }
302 
304  for(it_f = all_fields.begin(); it_f != all_fields.end(); it_f++)
305  {
306  BESDEBUG("h4","New field Name " <<(*it_f)->getNewName()<<endl);
307 
308  BaseType *bt=NULL;
309 
310  // Whether the field is real field,lat/lon field or missing Z-dimension field
311  int fieldtype = (*it_f)->getFieldType();
312 
313  // Check if the datatype needs to be changed.This is for MODIS data that needs to apply scale and offset.
314  // ctype_field_namelist is assigned in the function read_das_hdfeos2.
315  bool changedtype = false;
316  for (vector<string>::const_iterator i = ctype_field_namelist.begin(); i != ctype_field_namelist.end(); ++i){
317  if ((*i) == (*it_f)->getNewName()){
318  changedtype = true;
319  break;
320  }
321  }
322 
323  switch((*it_f)->getType())
324  {
325 
326 #define HANDLE_CASE2(tid, type) \
327  case tid: \
328  if(true == changedtype && fieldtype==0) \
329  bt = new (HDFFloat32) ((*it_f)->getNewName(), (dataset)->getName()); \
330  else \
331  bt = new (type)((*it_f)->getNewName(), (dataset)->getName()); \
332  break;
333 
334 #define HANDLE_CASE(tid, type)\
335  case tid: \
336  bt = new (type)((*it_f)->getNewName(), (dataset)->getName()); \
337  break;
338  HANDLE_CASE(DFNT_FLOAT32, HDFFloat32);
339  HANDLE_CASE(DFNT_FLOAT64, HDFFloat64);
340  HANDLE_CASE(DFNT_CHAR8,HDFStr);
341 #ifndef SIGNED_BYTE_TO_INT32
342  HANDLE_CASE2(DFNT_INT8, HDFByte);
343 #else
344  HANDLE_CASE2(DFNT_INT8,HDFInt32);
345 #endif
346  HANDLE_CASE2(DFNT_UINT8, HDFByte);
347  HANDLE_CASE2(DFNT_INT16, HDFInt16);
348  HANDLE_CASE2(DFNT_UINT16,HDFUInt16);
349  HANDLE_CASE2(DFNT_INT32, HDFInt32);
350  HANDLE_CASE2(DFNT_UINT32, HDFUInt32);
351  HANDLE_CASE2(DFNT_UCHAR8, HDFByte);
352  default:
353  throw InternalErr(__FILE__,__LINE__,"unsupported data type.");
354 #undef HANDLE_CASE
355 #undef HANDLE_CASE2
356  }
357 
358  if(bt)
359  {
360  const vector<HDFEOS2::Dimension*>& dims= (*it_f)->getCorrectedDimensions();
361  vector<HDFEOS2::Dimension*>::const_iterator it_d;
362 
363  if(DFNT_CHAR == (*it_f)->getType()) {
364 
365  if((*it_f)->getRank() >1) {
366 
367  HDFEOS2CFStrField * ar = NULL;
368 
369  try {
370 
371  ar = new HDFEOS2CFStrField(
372  (*it_f)->getRank() -1,
373  (grid_or_swath ==0)?gridfd:swathfd,
374  filename,
375  (dataset)->getName(),
376  (*it_f)->getName(),
377  grid_or_swath,
378  (*it_f)->getNewName(),
379  bt);
380  }
381  catch(...) {
382  delete bt;
383  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStr instance.");
384  }
385  for(it_d = dims.begin(); it_d != dims.begin()+dims.size()-1; it_d++){
386  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
387  }
388 
389  dds.add_var(ar);
390  delete bt;
391  if(ar != NULL)
392  delete ar;
393 
394  }
395 
396  else {
397  HDFEOS2CFStr * sca_str = NULL;
398  try {
399 
400  sca_str = new HDFEOS2CFStr(
401  (grid_or_swath ==0)?gridfd:swathfd,
402  filename,
403  (dataset)->getName(),
404  (*it_f)->getName(),
405  (*it_f)->getNewName(),
406  grid_or_swath);
407  }
408  catch(...) {
409  delete bt;
410  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStr instance.");
411  }
412  dds.add_var(sca_str);
413  delete bt;
414  delete sca_str;
415  }
416 
417  }
418 
419  // For general variables and non-lat/lon existing coordinate variables
420  else if(fieldtype == 0 || fieldtype == 3 || fieldtype == 5) {
421 
422  // grid
423  if(grid_or_swath==0){
424  HDFEOS2Array_RealField *ar = NULL;
425  ar = new HDFEOS2Array_RealField(
426  (*it_f)->getRank(),
427  filename,false,sdfd,gridfd,
428  (dataset)->getName(), "", (*it_f)->getName(),
429  sotype,
430  (*it_f)->getNewName(), bt);
431  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
432  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
433  dds.add_var(ar);
434  delete bt;
435  delete ar;
436  }
437  // swath
438  else if(grid_or_swath==1){
439 
440  string tempfieldname = (*it_f)->getName();
441 
442  // This swath uses the dimension map
443  if((*it_f)->UseDimMap()) {
444  // We also find that a separate geolocation file exists
445 
446  if (!modis_geofilename.empty()) {
447 
448  // This field can be found in the geo-location file. The field name may be corrected.
449  if (true == HDFCFUtil::is_modis_dimmap_nonll_field(tempfieldname)) {
450 
451  if(false == geofile_has_dimmap) {
452 
453  // Here we have to use HDFEOS2Array_RealField since the field may
454  // need to apply scale and offset equation.
455  // MODIS geolocation swath name is always MODIS_Swath_Type_GEO.
456  // We can improve the handling of this by not hard-coding the swath name
457  // in the future. KY 2012-08-16
458  HDFEOS2Array_RealField *ar = NULL;
459  ar = new HDFEOS2Array_RealField(
460  (*it_f)->getRank(),
461  modis_geofilename,
462  true,
463  sdfd,
464  swathfd,
465  "",
466  "MODIS_Swath_Type_GEO",
467  tempfieldname,
468  sotype,
469  (*it_f)->getNewName(),
470  bt);
471 
472  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
473  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
474  dds.add_var(ar);
475  delete bt;
476  delete ar;
477  }
478  else {// Use dimension maps in the dimension map file
479 
480  HDFEOS2ArraySwathDimMapField * ar = NULL;
481 
482  // SET dimmaps to empty.
483  // This is very key since we are using the geolocation file for the new information.
484  // The dimension map info. will be obtained when the data is reading. KY 2013-03-13
485 
486  dimmaps.clear();
487  ar = new HDFEOS2ArraySwathDimMapField(
488  (*it_f)->getRank(),
489  modis_geofilename,
490  true,
491  sdfd,
492  swathfd,
493  "",
494  "MODIS_Swath_Type_GEO",
495  tempfieldname,
496  dimmaps,
497  sotype,
498  (*it_f)->getNewName(),
499  bt);
500  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
501  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
502  dds.add_var(ar);
503  delete bt;
504  delete ar;
505  }
506  }
507  else { // This field cannot be found in the dimension map file.
508 
509  HDFEOS2ArraySwathDimMapField * ar = NULL;
510 
511  // Even if the dimension map file exists, it only applies to some
512  // specific data fields, if this field doesn't belong to these fields,
513  // we should still apply the dimension map rule to these fields.
514 
515  ar = new HDFEOS2ArraySwathDimMapField(
516  (*it_f)->getRank(),
517  filename,
518  false,
519  sdfd,
520  swathfd,
521  "",
522  (dataset)->getName(),
523  tempfieldname,
524  dimmaps,
525  sotype,
526  (*it_f)->getNewName(),
527  bt);
528  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
529  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
530  dds.add_var(ar);
531  delete bt;
532  delete ar;
533 
534 
535  }
536  }
537  else {// No dimension map file
538  HDFEOS2ArraySwathDimMapField * ar = NULL;
539  ar = new HDFEOS2ArraySwathDimMapField(
540  (*it_f)->getRank(),
541  filename,
542  false,
543  sdfd,
544  swathfd,
545  "",
546  (dataset)->getName(),
547  tempfieldname,
548  dimmaps,
549  sotype,
550  (*it_f)->getNewName(),
551  bt);
552  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
553  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
554  dds.add_var(ar);
555  delete bt;
556  delete ar;
557  }
558  }
559  else { // No dimension map
560 //cerr<<"no dimension map "<<endl;
561 
562  HDFEOS2Array_RealField * ar = NULL;
563  ar = new HDFEOS2Array_RealField(
564  (*it_f)->getRank(),
565  filename,
566  false,
567  sdfd,
568  swathfd,
569  "",
570  (dataset)->getName(),
571  tempfieldname,
572  sotype,
573  (*it_f)->getNewName(),
574  bt);
575  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
576  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
577  dds.add_var(ar);
578  delete bt;
579  delete ar;
580  }
581  }
582  else {
583  delete bt;
584  throw InternalErr(__FILE__, __LINE__, "The current type should be either grid or swath");
585  }
586  }
587 
588  // For latitude and longitude
589  else if(fieldtype == 1 || fieldtype == 2) {
590 
591  // For grid
592  if(grid_or_swath==0) {
593 
594  HDFEOS2ArrayGridGeoField *ar = NULL;
595  int fieldtype = (*it_f)->getFieldType();
596  bool ydimmajor = (*it_f)->getYDimMajor();
597  bool condenseddim = (*it_f)->getCondensedDim();
598  bool speciallon = (*it_f)->getSpecialLon();
599  int specialformat = (*it_f)->getSpecialLLFormat();
600 // short fieldcache = (*it_f)->UseFieldCache();
601 //cerr<<"fieldcache in hdfdesc.cc is "<<fieldcache <<endl;
602 
603  ar = new HDFEOS2ArrayGridGeoField(
604  (*it_f)->getRank(),
605  fieldtype,
606  ownll,
607  ydimmajor,
608  condenseddim,
609  speciallon,
610  specialformat,
611  /*fieldcache,*/
612  filename,
613  gridfd,
614  (dataset)->getName(),
615  (*it_f)->getName(),
616  (*it_f)->getNewName(),
617  bt);
618 
619  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
620  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
621  dds.add_var(ar);
622  delete bt;
623  delete ar;
624  }
625 
626  // We encounter a very special MODIS case (MOD/MYD ATML2 files),
627  // Latitude and longitude fields are located under data fields.
628  // So include this case. KY 2010-7-12
629  // We also encounter another special case(MOD11_L2.A2012248.2355.041.2012249083024.hdf),
630  // the latitude/longitude with dimension map is under the "data fields".
631  // So we have to consider this. KY 2012-09-24
632 
633  if(grid_or_swath ==1) {
634 
635  // Use Swath dimension map
636  if((*it_f)->UseDimMap()) {
637 
638  // Have an extra HDF-EOS file for latitude and longtiude
639  if(!modis_geofilename.empty()) {
640 
641  if (false == geofile_has_dimmap) {
642  HDFEOS2ArraySwathGeoDimMapExtraField *ar = NULL;
643  ar = new HDFEOS2ArraySwathGeoDimMapExtraField(
644  (*it_f)->getRank(),
645  modis_geofilename,
646  (*it_f)->getName(),
647  (*it_f)->getNewName(),
648  bt);
649  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
650  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
651  dds.add_var(ar);
652  delete bt;
653  delete ar;
654  }
655  else {
656 
657  HDFEOS2ArraySwathDimMapField * ar = NULL;
658 
659  // SET dimmaps to empty.
660  // This is essential since we are using the geolocation file for the new information.
661  // The dimension map info. will be obtained when the data is read. KY 2013-03-13
662  dimmaps.clear();
663  ar = new HDFEOS2ArraySwathDimMapField(
664  (*it_f)->getRank(),
665  modis_geofilename,
666  true,
667  sdfd,
668  swathfd,
669  "",
670  "MODIS_Swath_Type_GEO",
671  (*it_f)->getName(),
672  dimmaps,
673  sotype,
674  (*it_f)->getNewName(),
675  bt);
676  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
677  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
678 
679  dds.add_var(ar);
680  delete bt;
681  delete ar;
682  }
683  }
684  // Will interpolate by the handler
685  else {
686 
687  HDFEOS2ArraySwathDimMapField * ar = NULL;
688  ar = new HDFEOS2ArraySwathDimMapField(
689  (*it_f)->getRank(),
690  filename,
691  false,
692  sdfd,
693  swathfd,
694  "",
695  (dataset)->getName(),
696  (*it_f)->getName(),
697  dimmaps,
698  sotype,
699  (*it_f)->getNewName(),
700  bt);
701  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
702  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
703 
704  dds.add_var(ar);
705  delete bt;
706  delete ar;
707  }
708  }
709  else {// No Dimension map
710 
711  HDFEOS2ArraySwathGeoField * ar = NULL;
712  ar = new HDFEOS2ArraySwathGeoField(
713  (*it_f)->getRank(),
714  filename,
715  swathfd,
716  (dataset)->getName(),
717  (*it_f)->getName(),
718  (*it_f)->getNewName(),
719  bt);
720 
721  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
722  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
723  dds.add_var(ar);
724  delete bt;
725  delete ar;
726  }
727  }
728  }
729 
730  //missing Z dimensional field
731  else if(fieldtype == 4) {
732 
733  if((*it_f)->getRank()!=1){
734  delete bt;
735  throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
736  }
737 
738  int nelem = ((*it_f)->getCorrectedDimensions()[0])->getSize();
739  HDFEOS2ArrayMissGeoField *ar = NULL;
740  ar = new HDFEOS2ArrayMissGeoField(
741  (*it_f)->getRank(),
742  nelem,
743  (*it_f)->getNewName(),
744  bt);
745 
746  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
747  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
748 
749  dds.add_var(ar);
750  delete bt;
751  delete ar;
752  }
753  }
754  }
755 
756 }
757 
758 // Build DDS for HDF-EOS2 only.
759 //bool read_dds_hdfeos2(DDS & dds, const string & filename)
760 int read_dds_hdfeos2(DDS & dds, const string & filename,int32 sdfd,int32 fileid, int32 gridfd, int32 swathfd,HDFSP::File*spf,HDFEOS2::File*f)
761 {
762 
763  BESDEBUG("h4","Coming to read_dds_hdfeos2 "<<endl);
764 
765  // Set DDS dataset.
766  dds.set_dataset_name(basename(filename));
767 
768  // There are some HDF-EOS2 files(MERRA) that should be treated
769  // exactly like HDF4 SDS files. We don't need to use HDF-EOS2 APIs to
770  // retrieve any information. In fact, treating them as HDF-EOS2 files
771  // will cause confusions and we may get wrong information.
772  // So far, we've found only MERRA data that have this problem.
773  // A quick fix is to check if the file name contains MERRA. KY 2011-3-4
774  // Find MERRA data, return 5, use HDF4 SDS code.
775  if((basename(filename).size() >=5) && ((basename(filename)).compare(0,5,"MERRA")==0))
776  return 5;
777  //return false;
778 
779  string check_enable_spec_eos_key="H4.EnableSpecialEOS";
780  bool turn_on_enable_spec_eos_key= false;
781  turn_on_enable_spec_eos_key = HDFCFUtil::check_beskeys(check_enable_spec_eos_key);
782 
783  if(true == turn_on_enable_spec_eos_key) {
784 
785  string grid_name;
786  int ret_val = check_special_eosfile(filename,grid_name,sdfd,fileid);
787 
788  // Expected AIRS level 2 or level 3 case
789  if(4== ret_val)
790  return ret_val;
791 
792  //bool special_1d_grid = false;
793  //bool airs_l2_l3_v6 = false;
794 
795  if(2 == ret_val || 3 == ret_val) {
796 
797 // Performance test code to check the performance improvement by passing the file pointer spf, leave it for the time being. KY 2014-10-23
798 //#define KENT2 1
799 #undef KENT2
800 #ifdef KENT2
801 struct timeval start_time,end_time;
802 gettimeofday(&start_time,NULL);
803 #endif
804  // Leave the following code for performance test
805  //HDFSP::File *spf = NULL;
806 #if 0
807  try {
808  spf = HDFSP::File::Read(filename.c_str(),sdfd,fileid);
809  }
810  catch (HDFSP::Exception &e)
811  {
812  //if(spf != NULL)
813  //delete spf;
814  throw InternalErr(e.what());
815  }
816 #endif
817 
818 
819 #ifdef KENT2
820 gettimeofday(&end_time,NULL);
821 
822 int total_time_spent = (end_time.tv_sec - start_time.tv_sec)*1000000 +end_time.tv_usec-start_time.tv_usec;
823 cerr<<"total time spent is "<<total_time_spent<< "micro seconds "<<endl;
824 #endif
825 
826 
827 #if 0
828  if(2==ret_val) {
829 
830  // NEED TO MAKE SURE THE dimension information
831  // WILL NOT BE REMOVED.
832  if(spf->Check_if_special(grid_name)== true){
833 
834  special_1d_grid = true;
835 
836  // building the normal DDS here.
837  read_dds_special_1d_grid(dds,spf,filename,sdfd,fileid);
838  }
839  }
840  else {
841  airs_l2_l3_v6 = true;
842  spf->Handle_AIRS_L23();
843  read_dds_special_1d_grid(dds,spf,filename,sdfd,fileid);
844  }
845  //delete spf;
846 
847 #endif
848 //end of code for performance test for HDF4 file pointer spf.
849 //
850  try {
851  read_dds_special_1d_grid(dds,spf,filename,sdfd,fileid);
852  } catch (...)
853  {
854  //delete spf;
855  throw;
856  }
857  return ret_val;
858 
859  }
860 
861  }
862 
863  // Special HDF-EOS2 file, doesn't use HDF-EOS2 file structure. Return.
864  if( f == NULL)
865  return 0;
866 
867 // Performance tests to see the performance improvement by passing file pointer f.
868 #undef KENT
869 //#define KENT 1
870 #ifdef KENT
871 struct timeval start_time,end_time;
872 gettimeofday(&start_time,NULL);
873 #endif
874 
875  // Adding if filepointer is NULL, ignore.
876  //HDFEOS2::File *f = NULL;
877 
878 #if 0
879  try {
880  // Read all the information of EOS objects from an HDF-EOS2 file
881  f= HDFEOS2::File::Read(filename.c_str(),gridfd,swathfd);
882  }
883  catch (HDFEOS2::Exception &e){
884 
885  //if(f != NULL)
886  //delete f;
887  // If this file is not an HDF-EOS2 file, return false.
888  if (!e.getFileType()){
889  //return false;
890  return 0;
891  }
892  else
893  {
894  throw InternalErr(e.what());
895  }
896  }
897 
898  try {
899  // Generate CF coordinate variables(including auxiliary coordinate variables) and dimensions
900  // All the names follow CF.
901  f->Prepare(filename.c_str());
902  }
903 
904  catch (HDFEOS2:: Exception &e) {
905  //if (f != NULL)
906  // delete f;
907  throw InternalErr(e.what());
908  }
909 #endif
910 
911 #ifdef KENT
912 gettimeofday(&end_time,NULL);
913 
914 int total_time_spent = (end_time.tv_sec - start_time.tv_sec)*1000000 +end_time.tv_usec-start_time.tv_usec;
915 cerr<<"total time spent is "<<total_time_spent<< "micro seconds "<<endl;
916 #endif
917 
918 #if 0
919  HDFEOS2::File *f;
920  try {
921 
922  // Read all the field, attribute, dimension information from the file
923  f = HDFEOS2::File::Read(filename.c_str());
924  } catch (HDFEOS2::Exception &e)
925  {
926  // If this is not an HDF-EOS2 file, return falase. We will treat it as an HDF4 file.
927  if(!e.getFileType()){
928  return 0;
929  //return false;
930  }
931  else {
932  throw InternalErr(e.what());
933  }
934  }
935 
936 
937  bool special_1d_grid = false;
938  try {
939 
940  // Generate CF coordinate variables(including auxillary coordinate variables) and dimensions
941  if (f->check_special_1d_grid()) {
942 
943 cerr<<"This is a special 1d grid at the EOS layer" <<endl;
944  // Very strange behavior for the HDF4 library, I have to obtain the ID here.
945  // If defined inside the Read function, the id will be 0 and the output is
946  // unexpected. KY 2010-8-9
947  int32 myfileid;
948  myfileid = Hopen(const_cast<char *>(filename.c_str()), DFACC_READ,0);
949 
950  HDFSP::File *spf;
951  try {
952 
953  string grid_name = f->get_first_grid_name();
954 cerr<<"grid name is "<<grid_name <<endl;
955  spf = HDFSP::File::Read(filename.c_str(),myfileid);
956  if(spf->Check_if_special(grid_name)== true){
957  special_1d_grid = true;
958 cerr<<"This is a special 1d grid " <<endl;
959 
960  // building the normal DDS here.
961  read_dds_special_1d_grid(dds,spf,filename);
962  }
963  delete spf;
964 
965  } catch (HDFSP::Exception &e)
966  {
967  throw InternalErr(e.what());
968  }
969 
970  }
971  } catch (HDFEOS2::Exception &e)
972  {
973  delete f;
974  throw InternalErr(e.what());
975  }
976 
977  if (true == special_1d_grid){
978 cerr<<"special_1d_grid is true "<<endl;
979  delete f;
980  return 1;
981  }
982  else{
983  try {
984  f->Prepare(filename.c_str());
985  }
986 
987  catch (HDFEOS2:: Exception &e) {
988  delete f;
989  throw InternalErr(e.what());
990  }
991  }
992 
993 #endif
994 // End of performance test for HDF-EOS2 file pointer f
995 
996  //Some grids have one shared lat/lon pair. For this case,"onelatlon" is true.
997  // Other grids have their individual grids. We have to handle them differently.
998  // ownll is the flag to distinguish "one lat/lon pair" and multiple lat/lon pairs.
999  const vector<HDFEOS2::GridDataset *>& grids = f->getGrids();
1000  bool ownll = false;
1001  bool onelatlon = f->getOneLatLon();
1002 
1003  // Set scale and offset type to the DEFAULT one.
1004  SOType sotype = DEFAULT_CF_EQU;
1005 
1006  // Iterate all the grids of this file and map them to DAP DDS.
1007  vector<HDFEOS2::GridDataset *>::const_iterator it_g;
1008  for(it_g = grids.begin(); it_g != grids.end(); it_g++){
1009 
1010  // Check if this grid provides its own lat/lon.
1011  ownll = onelatlon?onelatlon:(*it_g)->getLatLonFlag();
1012 
1013  // Obtain Scale and offset type. This is for MODIS products who use non-CF scale/offset rules.
1014  sotype = (*it_g)->getScaleType();
1015  try {
1016  read_dds_hdfeos2_grid_swath(
1017  dds, filename, static_cast<HDFEOS2::Dataset*>(*it_g), 0,ownll,sotype,sdfd,fileid,gridfd,swathfd);
1018  }
1019  catch(...) {
1020  // delete f;
1021  throw;
1022  }
1023  }
1024 
1025  // Iterate all the swaths of this file and map them to DAP DDS.
1026  const vector<HDFEOS2::SwathDataset *>& swaths= f->getSwaths();
1027  vector<HDFEOS2::SwathDataset *>::const_iterator it_s;
1028  for(it_s = swaths.begin(); it_s != swaths.end(); it_s++) {
1029 
1030  // Obtain Scale and offset type. This is for MODIS products who use non-CF scale/offset rules.
1031  sotype = (*it_s)->getScaleType();
1032  try {
1033  read_dds_hdfeos2_grid_swath(
1034  dds, filename, static_cast<HDFEOS2::Dataset*>(*it_s), 1,false,sotype,sdfd,fileid,gridfd,swathfd);//No global lat/lon for multiple swaths
1035  }
1036  catch(...) {
1037  //delete f;
1038  throw;
1039  }
1040  }
1041 
1042  // Clear the field name list of which the datatype is changed. KY 2012-8-1
1043  // ctype_field_namelist is a global vector(see HDFEOS2HandleType.h for more description)
1044  // Since the handler program is a continuously running service, this values of this global vector may
1045  // change from one file to another. So clearing this vector each time when mapping DDS is over.
1046  ctype_field_namelist.clear();
1047 
1048  //delete f;
1049  return 1;
1050  //return true;
1051 }
1052 
1053 
1054 // The wrapper of building DDS of non-EOS fields and attributes in a hybrid HDF-EOS2 file.
1055 //bool read_dds_hdfhybrid(DDS & dds, const string & filename,int32 sdfd, int32 fileid,int32 gridfd,int32 swathfd)
1056 bool read_dds_hdfhybrid(DDS & dds, const string & filename,int32 sdfd, int32 fileid,HDFSP::File*f)
1057 
1058 {
1059 
1060  BESDEBUG("h4","Coming to read_dds_hdfhybrid "<<endl);
1061  // Set DDS dataset.
1062  dds.set_dataset_name(basename(filename));
1063 
1064 
1065  // Declare an non-EOS file pointer.
1066  //HDFSP::File *f = NULL;
1067 
1068 #if 0
1069  try {
1070  // Read all the non-EOS field and attribute information from the hybrid file.
1071  f = HDFSP::File::Read_Hybrid(filename.c_str(), sdfd,fileid);
1072  } catch (HDFSP::Exception &e)
1073  {
1074 
1075  //if (f != NULL)
1076  // delete f;
1077  throw InternalErr(e.what());
1078  }
1079 #endif
1080 
1081  // Obtain non-EOS SDS fields.
1082  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
1083 
1084  // Read SDS
1085  vector<HDFSP::SDField *>::const_iterator it_g;
1086  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1087  try {
1088  read_dds_spfields(dds,filename,sdfd,(*it_g),f->getSPType());
1089  }
1090  catch(...) {
1091  //delete f;
1092  throw;
1093  }
1094  }
1095 
1096  // Read Vdata fields.
1097  // To speed up the performance for CERES data, we turn off some CERES vdata fields
1098 
1099  // Many MODIS and MISR products use Vdata intensively. To make the output CF compliant, we map
1100  // each vdata field to a DAP array. However, this may cause the generation of many DAP fields. So
1101  // we use the BES keys for users to turn on/off as they choose. By default, the key is turned on. KY 2012-6-26
1102 
1103  string check_hybrid_vdata_key="H4.EnableHybridVdata";
1104  bool turn_on_hybrid_vdata_key = false;
1105  turn_on_hybrid_vdata_key = HDFCFUtil::check_beskeys(check_hybrid_vdata_key);
1106 
1107  if( true == turn_on_hybrid_vdata_key) {
1108  //if(f->getSPType() != CER_AVG &&
1109  // f->getSPType() != CER_ES4 &&
1110  // f->getSPType() !=CER_SRB &&
1111  // f->getSPType() != CER_ZAVG) {
1112  for(vector<HDFSP::VDATA *>::const_iterator i = f->getVDATAs().begin(); i!=f->getVDATAs().end();i++) {
1113  if(false == (*i)->getTreatAsAttrFlag()){
1114  for(vector<HDFSP::VDField *>::const_iterator j=(*i)->getFields().begin();j!=(*i)->getFields().end();j++) {
1115  try {
1116  read_dds_spvdfields(dds,filename,fileid, (*i)->getObjRef(),(*j)->getNumRec(),(*j));
1117  }
1118  catch(...) {
1119  //delete f;
1120  throw;
1121  }
1122  }
1123  }
1124  }
1125  //}
1126  }
1127 
1128  //delete f;
1129  return true;
1130 }
1131 
1132 
1133 // Build DAS for non-EOS objects in a hybrid HDF-EOS2 file.
1134 bool read_das_hdfhybrid(DAS & das, const string & filename,int32 sdfd, int32 fileid,HDFSP::File**fpptr)
1135 {
1136 
1137  BESDEBUG("h4","Coming to read_das_hdfhybrid "<<endl);
1138  // Declare a non-EOS file pointer
1139  HDFSP::File *f = NULL;
1140  try {
1141  // Read non-EOS objects in a hybrid HDF-EOS2 file.
1142  f = HDFSP::File::Read_Hybrid(filename.c_str(), sdfd,fileid);
1143  }
1144  catch (HDFSP::Exception &e)
1145  {
1146  if(f!=NULL)
1147  delete f;
1148  throw InternalErr(e.what());
1149  }
1150 
1151  // Remember the file pointer
1152  *fpptr = f;
1153 
1154  string check_scale_offset_type_key = "H4.EnableCheckScaleOffsetType";
1155  bool turn_on_enable_check_scale_offset_key= false;
1156  turn_on_enable_check_scale_offset_key = HDFCFUtil::check_beskeys(check_scale_offset_type_key);
1157 
1158  // First Added non-HDFEOS2 SDS attributes.
1159  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
1160  vector<HDFSP::SDField *>::const_iterator it_g;
1161  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
1162 
1163  // Use CF field name as the DAS table name.
1164  AttrTable *at = das.get_table((*it_g)->getNewName());
1165  if (!at)
1166  at = das.add_table((*it_g)->getNewName(), new AttrTable);
1167 
1168  // Some fields have "long_name" attributes,so we have to use this attribute rather than creating our own "long_name"
1169  bool long_name_flag = false;
1170 
1171  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();i!=(*it_g)->getAttributes().end();i++) {
1172 
1173  if((*i)->getName() == "long_name") {
1174  long_name_flag = true;
1175  break;
1176  }
1177  }
1178 
1179  if(false == long_name_flag)
1180  at->append_attr("long_name", "String", (*it_g)->getName());
1181 
1182  // Map all attributes to DAP DAS.
1183  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();i!=(*it_g)->getAttributes().end();i++) {
1184 
1185  // Handle string first.
1186  if((*i)->getType()==DFNT_UCHAR || (*i)->getType() == DFNT_CHAR){
1187 
1188  // Questionable use of string. KY 2014-02-12
1189  string tempstring2((*i)->getValue().begin(),(*i)->getValue().end());
1190  string tempfinalstr= string(tempstring2.c_str());
1191 
1192  // We want to escape the possible special characters except the fullpath attribute.
1193  // The fullpath is only added for some CERES and MERRA data. People use fullpath to keep their
1194  // original names even their original name includes special characters. KY 2014-02-12
1195  at->append_attr((*i)->getNewName(), "String" , ((*i)->getNewName()=="fullpath")?tempfinalstr:HDFCFUtil::escattr(tempfinalstr));
1196  }
1197  else {
1198  for (int loc=0; loc < (*i)->getCount() ; loc++) {
1199  string print_rep = HDFCFUtil::print_attr((*i)->getType(), loc, (void*) &((*i)->getValue()[0]));
1200  at->append_attr((*i)->getNewName(), HDFCFUtil::print_type((*i)->getType()), print_rep);
1201  }
1202  }
1203  }
1204 
1205  // Check if having _FillValue. If having _FillValue, compare the datatype of _FillValue
1206  // with the variable datatype. Correct the fillvalue datatype if necessary.
1207  if(at != NULL) {
1208  int32 var_type = (*it_g)->getType();
1209  try {
1210  HDFCFUtil::correct_fvalue_type(at,var_type);
1211  }
1212  catch(...) {
1213  //delete f;
1214  throw;
1215  }
1216  }
1217 
1218  // If H4.EnableCheckScaleOffsetType BES key is true,
1219  // if yes, check if having scale_factor and add_offset attributes;
1220  // if yes, check if scale_factor and add_offset attribute types are the same;
1221  // if no, make add_offset's datatype be the same as the datatype of scale_factor.
1222  // (CF requires the type of scale_factor and add_offset the same).
1223  if (true == turn_on_enable_check_scale_offset_key && at !=NULL)
1225 
1226  }
1227 
1228  // Handle vdata attributes.
1229  try {
1231  }
1232  catch(...) {
1233  //delete f;
1234  throw;
1235  }
1236 
1237  //delete f;
1238  return true;
1239 
1240 }
1241 
1244 void read_dds_use_eos2lib(DDS & dds, const string & filename,int32 sdfd,int32 fileid, int32 gridfd, int32 swathfd,HDFSP::File*h4file,HDFEOS2::File*eosfile)
1245 {
1246 
1247  BESDEBUG("h4","Coming to read_dds_use_eos2lib" <<endl);
1248 
1249  int ret_value = read_dds_hdfeos2(dds,filename,sdfd,fileid,gridfd,swathfd,h4file,eosfile);
1250 
1251  BESDEBUG("h4","ret_value of read_dds_hdfeos2 is "<<ret_value<<endl);
1252 
1253  // read_dds_hdfeos2 return value description:
1254  // 0: general non-EOS2 pure HDF4
1255  // 1: HDF-EOS2 hybrid
1256  // 2: MOD08_M3
1257  // HDF-EOS2 but no need to use HDF-EOS2 lib: no real dimension scales but have CVs for every dimension, treat differently
1258  // 3: AIRS level 3
1259  // HDF-EOS2 but no need to use HDF-EOS2 lib:
1260  // have dimension scales but don’t have CVs for every dimension, also need to condense dimensions, treat differently
1261  // 4. Expected AIRS level 3
1262  // HDF-EOS2 but no need to use HDF-EOS2 lib: Have dimension scales for all dimensions
1263  // 5. MERRA
1264  // Special handling for MERRA file as 0.
1265 
1266 
1267  // Treat MERRA and non-HDFEOS2 HDF4 products as pure HDF4 objects
1268  // For Expected AIRS level 3 products, we temporarily handle them in a generic HDF4 way.
1269  if (0 == ret_value || 5 == ret_value || 4 == ret_value ) {
1270  if(true == read_dds_hdfsp(dds, filename,sdfd,fileid,h4file))
1271  return;
1272  }
1273  // Special handling
1274  else if ( 1 == ret_value ) {
1275 
1276  // Map non-EOS2 objects to DDS
1277  if(true ==read_dds_hdfhybrid(dds,filename,sdfd,fileid,h4file))
1278  return;
1279  }
1280  else {// ret_value = 2 and 3 are handled already
1281  return;
1282  }
1283 
1284 // leave this code block for performance comparison.
1285 #if 0
1286  // first map HDF-EOS2 objects to DDS
1287  if(true == read_dds_hdfeos2(dds, filename)){
1288 
1289  // Map non-EOS2 objects to DDS
1290  if(true == read_dds_hdfhybrid(dds,filename))
1291  return;
1292  }
1293 
1294  // Map HDF4 objects in pure HDF4 files to DDS
1295  if(read_dds_hdfsp(dds, filename)){
1296  return;
1297  }
1298 #endif
1299 
1300  // Call the default mapping of HDF4 to DDS. It should never reach here.
1301  // We add this line to ensure the HDF4 objects mapped to DDS even if the above routines return false.
1302  read_dds(dds, filename);
1303 
1304 }
1305 
1306 // Map other HDF global attributes, this routine must be called after all ECS metadata are handled.
1307 void write_non_ecsmetadata_attrs(HE2CF& cf) {
1308 
1310 
1311 }
1312 
1313 // Map HDF-EOS2's ECS attributes to DAS. ECS attributes include coremetadata, structmetadata etc.
1314 void write_ecsmetadata(DAS& das, HE2CF& cf, const string& _meta)
1315 {
1316 
1317  // There is a maximum length for each ECS metadata if one uses ECS toolkit to add the metadata.
1318  // For some products of which the metadata size is huge, one metadata may be stored in several
1319  // ECS attributes such as coremetadata.0, coremetadata.1 etc.
1320  // When mapping the ECS metadata, we need to merge such metadata attributes into one attribute(coremetadata)
1321  // so that end users can easily understand this metadata.
1322  // ECS toolkit recommends data producers to use the format shown in the following coremetadata example:
1323  // coremetadata.0, coremetadata.1, etc.
1324  // Most NASA HDF-EOS2 products follow this naming convention.
1325  // However, the toolkit also allows data producers to freely name its metadata.
1326  // So we also find the following slightly different format:
1327  // (1) No suffix: coremetadata
1328  // (2) only have one such ECS attribute: coremetadata.0
1329  // (3) have several ECS attributes with two dots after the name: coremetadata.0, coremetadata.0.1 etc.
1330  // (4) Have non-number suffix: productmetadata.s, productmetadata.t etc.
1331  // We handle the above case in the function set_metadata defined in HE2CF.cc. KY 2013-07-06
1332 
1333  bool suffix_is_number = true;
1334  vector<string> meta_nonum_names;
1335  vector<string> meta_nonum_data;
1336 
1337  string meta = cf.get_metadata(_meta,suffix_is_number,meta_nonum_names, meta_nonum_data);
1338 
1339  if(""==meta && true == suffix_is_number){
1340  return; // No _meta metadata exists.
1341  }
1342 
1343  BESDEBUG("h4",meta << endl);
1344 
1345  if (false == suffix_is_number) {
1346  // For the case when the suffix is like productmetadata.s, productmetadata.t,
1347  // we will not merge the metadata since we are not sure about the order.
1348  // We just parse each attribute individually.
1349  for (unsigned int i = 0; i <meta_nonum_names.size(); i++)
1350  parse_ecs_metadata(das,meta_nonum_names[i],meta_nonum_data[i]);
1351  }
1352  else
1353  parse_ecs_metadata(das,_meta,meta);
1354 
1355 }
1356 
1357 void parse_ecs_metadata(DAS &das,const string & metaname, const string &metadata) {
1358 
1359 
1360  AttrTable *at = das.get_table(metaname);
1361  if (!at)
1362  at = das.add_table(metaname, new AttrTable);
1363 
1364  // tell lexer to scan attribute string
1365  void *buf = hdfeos_string(metadata.c_str());
1366  parser_arg arg(at);
1367 
1368  if (hdfeosparse(&arg) != 0) {
1369  hdfeos_delete_buffer(buf);
1370  throw Error("HDF-EOS parse error while processing a " + metadata + " HDFEOS attribute.");
1371  }
1372 
1373  if (arg.status() == false) {
1374  (*BESLog::TheLog())<< "HDF-EOS parse error while processing a "
1375  << metadata << " HDFEOS attribute. (2) " << endl;
1376  // << arg.error()->get_error_message() << endl;
1377  }
1378 
1379  hdfeos_delete_buffer(buf);
1380 }
1381 
1382 // Build DAS for HDFEOS2 files.
1383 int read_das_hdfeos2(DAS & das, const string & filename,int32 sdfd,int32 fileid, int32 gridfd, int32 swathfd,
1384  bool ecs_metadata,HDFSP::File**spfpptr,HDFEOS2::File **fpptr)
1385 {
1386 
1387  BESDEBUG("h4","Coming to read_das_hdfeos2 " << endl);
1388 
1389  // There are some HDF-EOS2 files(MERRA) that should be treated
1390  // exactly like HDF4 SDS files. We don't need to use HDF-EOS2 APIs to
1391  // retrieve any information. In fact, treating them as HDF-EOS2 files
1392  // will cause confusions and retrieve wrong information, though may not be essential.
1393  // So far, we've only found that the MERRA product has this problem.
1394  // A quick fix is to check if the file name contains MERRA. KY 2011-3-4
1395 
1396  // Find MERRA data, return false, use HDF4 SDS code.
1397  if((basename(filename).size() >=5) && ((basename(filename)).compare(0,5,"MERRA")==0)) {
1398  return 5;
1399  //return false;
1400  }
1401 
1402  // We will check if the handler wants to turn on the special EOS key checking
1403  string check_enable_spec_eos_key="H4.EnableSpecialEOS";
1404  bool turn_on_enable_spec_eos_key= false;
1405  turn_on_enable_spec_eos_key = HDFCFUtil::check_beskeys(check_enable_spec_eos_key);
1406  if(true == turn_on_enable_spec_eos_key) {
1407 
1408  string grid_name;
1409  int ret_val = check_special_eosfile(filename,grid_name,sdfd,fileid);
1410 
1411  // Expected AIRS level 2 or 3
1412  if(4== ret_val)
1413  return ret_val;
1414 
1415  bool airs_l2_l3_v6 = false;
1416  bool special_1d_grid = false;
1417 
1418  // AIRS level 2,3 version 6 or MOD08_M3-like products
1419  if(2 == ret_val || 3 == ret_val) {
1420 
1421 // For performance tests.
1422 #undef KENT3
1423 //#define KENT3 1
1424 #ifdef KENT3
1425 struct timeval start_time3,end_time3;
1426 gettimeofday(&start_time3,NULL);
1427 #endif
1428 
1429  HDFSP::File *spf = NULL;
1430  try {
1431  spf = HDFSP::File::Read(filename.c_str(),sdfd,fileid);
1432  }
1433  catch (HDFSP::Exception &e)
1434  {
1435  if (spf != NULL)
1436  delete spf;
1437  throw InternalErr(e.what());
1438  }
1439 
1440 // Leave it for performance tests.
1441 #ifdef KENT3
1442 gettimeofday(&end_time3,NULL);
1443 
1444 int total_time_spent3 = (end_time3.tv_sec - start_time3.tv_sec)*1000000 +end_time3.tv_usec-start_time3.tv_usec;
1445 cerr<<"total time spent DAS is "<<total_time_spent3<< "micro seconds "<<endl;
1446 #endif
1447 
1448  try {
1449  if( 2 == ret_val) {
1450 
1451  // More check and build the relations if this is a special MOD08_M3-like file
1452  if(spf->Check_update_special(grid_name)== true){
1453 
1454  special_1d_grid = true;
1455 
1456  // building the normal DAS here.
1457  read_das_special_eos2_core(das,spf,filename,ecs_metadata);
1458 
1459  if(grid_name =="mod08") {
1461  }
1462  }
1463  }
1464  else {
1465 
1466  airs_l2_l3_v6 = true;
1467  spf->Handle_AIRS_L23();
1468  read_das_special_eos2_core(das,spf,filename,ecs_metadata);
1469  }
1470  //delete spf;
1471 
1472  }
1473  catch (...)
1474  {
1475  delete spf;
1476  throw;
1477  }
1478 
1479  if (true == special_1d_grid || true == airs_l2_l3_v6) {
1480  *spfpptr = spf;
1481  return ret_val;
1482  }
1483 
1484  }
1485  }
1486 
1487  HDFEOS2::File *f = NULL;
1488 
1489  try {
1490  // Read all the information of EOS objects from an HDF-EOS2 file
1491  f= HDFEOS2::File::Read(filename.c_str(),gridfd,swathfd);
1492  }
1493  catch (HDFEOS2::Exception &e){
1494 
1495  if(f != NULL)
1496  delete f;
1497 
1498  // If this file is not an HDF-EOS2 file, return 0.
1499  if (!e.getFileType()){
1500  //return false;
1501  return 0;
1502  }
1503  else
1504  {
1505  throw InternalErr(e.what());
1506  }
1507  }
1508 
1509  try {
1510  // Generate CF coordinate variables(including auxiliary coordinate variables) and dimensions
1511  // All the names follow CF.
1512  f->Prepare(filename.c_str());
1513  }
1514 
1515  catch (HDFEOS2:: Exception &e) {
1516  if(f!=NULL)
1517  delete f;
1518  throw InternalErr(e.what());
1519  }
1520 
1521  *fpptr = f;
1522 
1523 // Leave this code for the time being. This code maps all grid/swath object attributes to HDF_GLOBAL.
1524 #if 0
1525  try {
1526 
1527  // Process grid and swath attributes
1528  AttrTable *at = das.get_table("HDF_GLOBAL");
1529  if (!at)
1530  at = das.add_table("HDF_GLOBAL", new AttrTable);
1531 
1532  // MAP grid attributes to DAS.
1533  for (int i = 0; i < (int) f->getGrids().size(); i++) {
1534 
1535  HDFEOS2::GridDataset* grid = f->getGrids()[i];
1536  string gname = grid->getName();
1537  const vector<HDFEOS2::Attribute *> grid_attrs = grid->getAttributes();
1538  vector<HDFEOS2::Attribute*>::const_iterator it_a;
1539  for (it_a = grid_attrs.begin(); it_a != grid_attrs.end(); ++it_a) {
1540 
1541  string attr_name = (*it_a)->getName();
1542  int attr_type = (*it_a)->getType();
1543 
1544  // We treat string differently. DFNT_UCHAR and DFNT_CHAR are treated as strings.
1545  if(attr_type==DFNT_UCHAR || attr_type == DFNT_CHAR){
1546  string tempstring2((*it_a)->getValue().begin(),(*it_a)->getValue().end());
1547  string tempfinalstr= string(tempstring2.c_str());
1548 
1549  // Using the customized escattr function to escape special characters except
1550  // \n,\r,\t since escaping them may make the attributes hard to read. KY 2013-10-14
1551  // at->append_attr((*i)->getNewName(), "String" , escattr(tempfinalstr));
1552  at->append_attr((*it_a)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
1553  }
1554 
1555 
1556  else {
1557  for (int loc=0; loc < (*it_a)->getCount() ; loc++) {
1558  string print_rep = HDFCFUtil::print_attr((*it_a)->getType(), loc, (void*) &((*it_a)->getValue()[0]));
1559  at->append_attr((*it_a)->getNewName(), HDFCFUtil::print_type((*it_a)->getType()), print_rep);
1560  }
1561  }
1562  }
1563  }
1564 
1565  //
1566  // MAP swath attributes to DAS.
1567  for (int i = 0; i < (int) f->getSwaths().size(); i++) {
1568 
1569  HDFEOS2::SwathDataset* swath = f->getSwaths()[i];
1570  string gname = swath->getName();
1571  const vector<HDFEOS2::Attribute *> swath_attrs = swath->getAttributes();
1572  vector<HDFEOS2::Attribute*>::const_iterator it_a;
1573  for (it_a = swath_attrs.begin(); it_a != swath_attrs.end(); ++it_a) {
1574 
1575  string attr_name = (*it_a)->getName();
1576  int attr_type = (*it_a)->getType();
1577 
1578  // We treat string differently. DFNT_UCHAR and DFNT_CHAR are treated as strings.
1579  if(attr_type==DFNT_UCHAR || attr_type == DFNT_CHAR){
1580  string tempstring2((*it_a)->getValue().begin(),(*it_a)->getValue().end());
1581  string tempfinalstr= string(tempstring2.c_str());
1582 
1583  // Using the customized escattr function to escape special characters except
1584  // \n,\r,\t since escaping them may make the attributes hard to read. KY 2013-10-14
1585  // at->append_attr((*i)->getNewName(), "String" , escattr(tempfinalstr));
1586  at->append_attr((*it_a)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
1587  }
1588 
1589 
1590  else {
1591  for (int loc=0; loc < (*it_a)->getCount() ; loc++) {
1592  string print_rep = HDFCFUtil::print_attr((*it_a)->getType(), loc, (void*) &((*it_a)->getValue()[0]));
1593  at->append_attr((*it_a)->getNewName(), HDFCFUtil::print_type((*it_a)->getType()), print_rep);
1594  }
1595 
1596  }
1597  }
1598  }
1599  }
1600  catch(...) {
1601  delete f;
1602  throw;
1603  }
1604 
1605 #endif
1606 
1607  // HE2CF cf is used to handle hybrid SDS and SD attributes.
1608  HE2CF cf;
1609 
1610  try {
1611  cf.open(filename,sdfd,fileid);
1612  }
1613  catch(...) {
1614  // delete f;
1615  throw;
1616  }
1617  cf.set_DAS(&das);
1618 
1619  SOType sotype = DEFAULT_CF_EQU;
1620 
1621  // A flag not to generate structMetadata for the MOD13C2 file.
1622  // MOD13C2's structMetadata has wrong values. It couldn't pass the parser.
1623  // So we want to turn it off. KY 2010-8-10
1624  bool tempstrflag = false;
1625 
1626  // Product name(AMSR_E) that needs to change attribute from "SCALE FACTOR" to scale_factor etc. to follow the CF conventions
1627  bool filename_change_scale = false;
1628  if (f->getSwaths().size() > 0) {
1629  string temp_fname = basename(filename);
1630  string temp_prod_prefix = "AMSR_E";
1631  if ((temp_fname.size() > temp_prod_prefix.size()) &&
1632  (0 == (temp_fname.compare(0,temp_prod_prefix.size(),temp_prod_prefix))))
1633  filename_change_scale = true;
1634  }
1635 
1636  // Obtain information to identify MEaSURES VIP. This product needs to be handled properly.
1637  bool gridname_change_valid_range = false;
1638  if(1 == f->getGrids().size()) {
1639  string gridname = f->getGrids()[0]->getName();
1640  if ("VIP_CMG_GRID" == gridname)
1641  gridname_change_valid_range = true;
1642  }
1643 
1644  // Obtain information to identify MODIS_SWATH_Type_L1B product. This product's scale and offset need to be handled properly.
1645  bool is_modis_l1b = false;
1646  // Since this is a swath product, we check swath only.
1647  for (int i = 0; i<(int) f->getSwaths().size(); i++) {
1648  HDFEOS2::SwathDataset* swath = f->getSwaths()[i];
1649  string sname = swath->getName();
1650  if("MODIS_SWATH_Type_L1B" == sname){
1651  is_modis_l1b = true;
1652  break;
1653  }
1654  }
1655 
1656  string check_disable_scale_comp_key = "H4.DisableScaleOffsetComp";
1657  bool turn_on_disable_scale_comp_key= false;
1658  turn_on_disable_scale_comp_key = HDFCFUtil::check_beskeys(check_disable_scale_comp_key);
1659 
1660  string check_scale_offset_type_key = "H4.EnableCheckScaleOffsetType";
1661  bool turn_on_enable_check_scale_offset_key= false;
1662  turn_on_enable_check_scale_offset_key = HDFCFUtil::check_beskeys(check_scale_offset_type_key);
1663 
1664  try {
1665 
1666  // MAP grids to DAS.
1667  for (int i = 0; i < (int) f->getGrids().size(); i++) {
1668 
1669  HDFEOS2::GridDataset* grid = f->getGrids()[i];
1670  string gname = grid->getName();
1671  sotype = grid->getScaleType();
1672 
1673  const vector<HDFEOS2::Field*>gfields = grid->getDataFields();
1674  vector<HDFEOS2::Field*>::const_iterator it_gf;
1675 
1676  for (it_gf = gfields.begin();it_gf != gfields.end();++it_gf) {
1677 
1678  bool change_fvtype = false;
1679 
1680  // original field name
1681  string fname = (*it_gf)->getName();
1682 
1683  // new field name that follows CF
1684  string newfname = (*it_gf)->getNewName();
1685 
1686  BESDEBUG("h4","Original field name: " << fname << endl);
1687  BESDEBUG("h4","Corrected field name: " << newfname << endl);
1688 
1689  // whether coordinate variable or data variables
1690  int fieldtype = (*it_gf)->getFieldType();
1691 
1692  // 0 means that the data field is NOT a coordinate variable.
1693  if (fieldtype == 0){
1694 
1695  // If you don't find any _FillValue through generic API.
1696  if((*it_gf)->haveAddedFillValue()) {
1697  BESDEBUG("h4","Has an added fill value." << endl);
1698  float addedfillvalue =
1699  (*it_gf)->getAddedFillValue();
1700  int type =
1701  (*it_gf)->getType();
1702  BESDEBUG("h4","Added fill value = "<<addedfillvalue);
1703  cf.write_attribute_FillValue(newfname,
1704  type, addedfillvalue);
1705  }
1706  string coordinate = (*it_gf)->getCoordinate();
1707  BESDEBUG("h4","Coordinate attribute: " << coordinate <<endl);
1708  if (coordinate != "")
1709  cf.write_attribute_coordinates(newfname, coordinate);
1710  }
1711 
1712  // This will override _FillValue if it's defined on the field.
1713  cf.write_attribute(gname, fname, newfname,
1714  f->getGrids().size(), fieldtype);
1715 
1716  // For fieldtype values:
1717  // 0 is general fields
1718  // 1 is latitude.
1719  // 2 is longtitude.
1720  // 3 is defined level.
1721  // 4 is an inserted natural number.
1722  // 5 is time.
1723  if(fieldtype > 0){
1724 
1725  // MOD13C2 is treated specially.
1726  if(fieldtype == 1 && ((*it_gf)->getSpecialLLFormat())==3)
1727  tempstrflag = true;
1728 
1729  // Don't change the units if the 3-rd dimension field exists.(fieldtype =3)
1730  // KY 2013-02-15
1731  if (fieldtype !=3) {
1732  string tempunits = (*it_gf)->getUnits();
1733  BESDEBUG("h4",
1734  "fieldtype " << fieldtype
1735  << " units" << tempunits
1736  << endl);
1737  cf.write_attribute_units(newfname, tempunits);
1738  }
1739  }
1740 
1741  //Rename attributes of MODIS products.
1742  AttrTable *at = das.get_table(newfname);
1743 
1744  // No need for CF scale and offset equation.
1745  if(sotype!=DEFAULT_CF_EQU && at!=NULL)
1746  {
1747  bool has_Key_attr = false;
1748  AttrTable::Attr_iter it = at->attr_begin();
1749  while (it!=at->attr_end())
1750  {
1751  if(at->get_name(it)=="Key")
1752  {
1753  has_Key_attr = true;
1754  break;
1755  }
1756  it++;
1757  }
1758 
1759  if((false == is_modis_l1b) && (false == gridname_change_valid_range)&&(false == has_Key_attr) && (true == turn_on_disable_scale_comp_key))
1760  HDFCFUtil::handle_modis_special_attrs_disable_scale_comp(at,basename(filename), true, newfname,sotype);
1761  else {
1762 
1763  // Check if the datatype of this field needs to be changed.
1764  bool changedtype = HDFCFUtil::change_data_type(das,sotype,newfname);
1765 
1766  // Build up the field name list if the datatype of the field needs to be changed.
1767  if (true == changedtype)
1768  ctype_field_namelist.push_back(newfname);
1769 
1770  HDFCFUtil::handle_modis_special_attrs(at,basename(filename),true, newfname,sotype,gridname_change_valid_range,changedtype,change_fvtype);
1771 
1772  }
1773  }
1774 
1775  // Handle AMSR-E attributes.
1776  HDFCFUtil::handle_amsr_attrs(at);
1777 
1778  // Check if having _FillValue. If having _FillValue, compare the datatype of _FillValue
1779  // with the variable datatype. Correct the fillvalue datatype if necessary.
1780  if((false == change_fvtype) && at != NULL) {
1781  int32 var_type = (*it_gf)->getType();
1782  HDFCFUtil::correct_fvalue_type(at,var_type);
1783  }
1784 
1785  // if h4.enablecheckscaleoffsettype bes key is true,
1786  // if yes, check if having scale_factor and add_offset attributes;
1787  // if yes, check if scale_factor and add_offset attribute types are the same;
1788  // if no, make add_offset's datatype be the same as the datatype of scale_factor.
1789  // (cf requires the type of scale_factor and add_offset the same).
1790  if (true == turn_on_enable_check_scale_offset_key && at!=NULL)
1792  }
1793  }
1794  }
1795  catch(...) {
1796  //delete f;
1797  throw;
1798  }
1799 
1800  try {
1801  // MAP Swath attributes to DAS.
1802  for (int i = 0; i < (int) f->getSwaths().size(); i++) {
1803 
1804  HDFEOS2::SwathDataset* swath = f->getSwaths()[i];
1805 
1806  // Swath includes two parts: "Geolocation Fields" and "Data Fields".
1807  // The all_fields vector includes both.
1808  const vector<HDFEOS2::Field*> geofields = swath->getGeoFields();
1809  vector<HDFEOS2::Field*> all_fields = geofields;
1810  vector<HDFEOS2::Field*>::const_iterator it_f;
1811 
1812  const vector<HDFEOS2::Field*> datafields = swath->getDataFields();
1813  for (it_f = datafields.begin(); it_f != datafields.end(); it_f++)
1814  all_fields.push_back(*it_f);
1815 
1816  int total_geofields = geofields.size();
1817 
1818  string gname = swath->getName();
1819  BESDEBUG("h4","Swath name: " << gname << endl);
1820 
1821  sotype = swath->getScaleType();
1822 
1823  // field_counter is only used to separate geo field from data field.
1824  int field_counter = 0;
1825 
1826  for(it_f = all_fields.begin(); it_f != all_fields.end(); it_f++)
1827  {
1828  bool change_fvtype = false;
1829  string fname = (*it_f)->getName();
1830  string newfname = (*it_f)->getNewName();
1831  BESDEBUG("h4","Original Field name: " << fname << endl);
1832  BESDEBUG("h4","Corrected Field name: " << newfname << endl);
1833 
1834  int fieldtype = (*it_f)->getFieldType();
1835  if (fieldtype == 0){
1836  string coordinate = (*it_f)->getCoordinate();
1837  BESDEBUG("h4","Coordinate attribute: " << coordinate <<endl);
1838  if (coordinate != "")
1839  cf.write_attribute_coordinates(newfname, coordinate);
1840  }
1841 
1842  // 1 is latitude.
1843  // 2 is longitude.
1844  // Don't change "units" if a non-latlon coordinate variable exists.
1845  //if(fieldtype >0 )
1846  if(fieldtype >0 && fieldtype !=3){
1847  string tempunits = (*it_f)->getUnits();
1848  BESDEBUG("h4",
1849  "fieldtype " << fieldtype
1850  << " units" << tempunits << endl);
1851  cf.write_attribute_units(newfname, tempunits);
1852 
1853  }
1854  BESDEBUG("h4","Field Name: " << fname << endl);
1855 
1856  // coordinate "fillvalue" attribute
1857  // This operation should only apply to data fields.
1858  if (field_counter >=total_geofields) {
1859  if((*it_f)->haveAddedFillValue()){
1860  float addedfillvalue =
1861  (*it_f)->getAddedFillValue();
1862  int type =
1863  (*it_f)->getType();
1864  BESDEBUG("h4","Added fill value = "<<addedfillvalue);
1865  cf.write_attribute_FillValue(newfname, type, addedfillvalue);
1866  }
1867  }
1868 
1869  cf.write_attribute(gname, fname, newfname,
1870  f->getSwaths().size(), fieldtype);
1871 
1872  AttrTable *at = das.get_table(newfname);
1873 
1874  // No need for CF scale and offset equation.
1875  if(sotype!=DEFAULT_CF_EQU && at!=NULL)
1876  {
1877 
1878  bool has_Key_attr = false;
1879  AttrTable::Attr_iter it = at->attr_begin();
1880  while (it!=at->attr_end())
1881  {
1882  if(at->get_name(it)=="Key")
1883  {
1884  has_Key_attr = true;
1885  break;
1886  }
1887  it++;
1888  }
1889 
1890  if((false == is_modis_l1b) && (false == gridname_change_valid_range) &&(false == has_Key_attr) && (true == turn_on_disable_scale_comp_key))
1891  HDFCFUtil::handle_modis_special_attrs_disable_scale_comp(at,basename(filename),false,newfname,sotype);
1892  else {
1893 
1894  // Check if the datatype of this field needs to be changed.
1895  bool changedtype = HDFCFUtil::change_data_type(das,sotype,newfname);
1896 
1897  // Build up the field name list if the datatype of the field needs to be changed.
1898  if (true == changedtype)
1899 
1900  ctype_field_namelist.push_back(newfname);
1901 
1902  // Handle MODIS special attributes such as valid_range, scale_factor and add_offset etc.
1903  // Need to catch the exception since this function calls handle_modis_vip_special_attrs that may
1904  // throw an exception.
1905  HDFCFUtil::handle_modis_special_attrs(at,basename(filename), false,newfname,sotype,gridname_change_valid_range,changedtype,change_fvtype);
1906  }
1907  }
1908 
1909  // Handle AMSR-E attributes
1910  HDFCFUtil::handle_amsr_attrs(at);
1911 
1912  // Check if having _FillValue. If having _FillValue, compare the datatype of _FillValue
1913  // with the variable datatype. Correct the fillvalue datatype if necessary.
1914  if((false == change_fvtype) && at != NULL) {
1915  int32 var_type = (*it_f)->getType();
1916  HDFCFUtil::correct_fvalue_type(at,var_type);
1917  }
1918 
1919  // If H4.EnableCheckScaleOffsetType BES key is true,
1920  // if yes, check if having scale_factor and add_offset attributes;
1921  // if yes, check if scale_factor and add_offset attribute types are the same;
1922  // if no, make add_offset's datatype be the same as the datatype of scale_factor.
1923  // (CF requires the type of scale_factor and add_offset the same).
1924  if (true == turn_on_enable_check_scale_offset_key && at !=NULL)
1926 
1927  field_counter++;
1928  }
1929  }
1930  }
1931  catch(...) {
1932  //delete f;
1933  throw;
1934  }
1935 
1936 
1937  try {
1938 
1939  if(ecs_metadata == true) {
1940 
1941  // Handle ECS metadata. The following metadata are what we found so far.
1942  write_ecsmetadata(das,cf, "CoreMetadata");
1943 
1944  write_ecsmetadata(das,cf, "coremetadata");
1945 
1946  write_ecsmetadata(das,cf,"ArchiveMetadata");
1947 
1948  write_ecsmetadata(das,cf,"archivemetadata");
1949 
1950  write_ecsmetadata(das,cf,"ProductMetadata");
1951 
1952  write_ecsmetadata(das,cf,"productmetadata");
1953  }
1954 
1955  // This cause a problem for a MOD13C2 file, So turn it off temporarily. KY 2010-6-29
1956  if(false == tempstrflag) {
1957 
1958  string check_disable_smetadata_key ="H4.DisableStructMetaAttr";
1959  bool is_check_disable_smetadata = false;
1960  is_check_disable_smetadata = HDFCFUtil::check_beskeys(check_disable_smetadata_key);
1961 
1962  if (false == is_check_disable_smetadata) {
1963  write_ecsmetadata(das, cf, "StructMetadata");
1964  }
1965  }
1966 
1967  // Write other HDF global attributes, this routine must be called after all ECS metadata are handled.
1968  write_non_ecsmetadata_attrs(cf);
1969 
1970  cf.close();
1971  }
1972  catch(...) {
1973  //delete f;
1974  throw;
1975  }
1976 
1977  try {
1978 
1979  // Check if swath or grid object (like vgroup) attributes should be mapped to DAP2. If yes, start mapping.
1980  string check_enable_sg_attr_key="H4.EnableSwathGridAttr";
1981  bool turn_on_enable_sg_attr_key= false;
1982  turn_on_enable_sg_attr_key = HDFCFUtil::check_beskeys(check_enable_sg_attr_key);
1983 
1984  if(true == turn_on_enable_sg_attr_key) {
1985 
1986  // MAP grid attributes to DAS.
1987  for (int i = 0; i < (int) f->getGrids().size(); i++) {
1988 
1989 
1990  HDFEOS2::GridDataset* grid = f->getGrids()[i];
1991 
1992  string gname = HDFCFUtil::get_CF_string(grid->getName());
1993 
1994  AttrTable*at = NULL;
1995 
1996  // Create a "grid" DAS table if this grid has attributes.
1997  if(grid->getAttributes().size() != 0) {
1998  at = das.get_table(gname);
1999  if (!at)
2000  at = das.add_table(gname, new AttrTable);
2001  }
2002 
2003  // Process grid attributes
2004  const vector<HDFEOS2::Attribute *> grid_attrs = grid->getAttributes();
2005  vector<HDFEOS2::Attribute*>::const_iterator it_a;
2006  for (it_a = grid_attrs.begin(); it_a != grid_attrs.end(); ++it_a) {
2007 
2008  int attr_type = (*it_a)->getType();
2009 
2010  // We treat string differently. DFNT_UCHAR and DFNT_CHAR are treated as strings.
2011  if(attr_type==DFNT_UCHAR || attr_type == DFNT_CHAR){
2012  string tempstring2((*it_a)->getValue().begin(),(*it_a)->getValue().end());
2013  string tempfinalstr= string(tempstring2.c_str());
2014 
2015  // Using the customized escattr function to escape special characters except
2016  // \n,\r,\t since escaping them may make the attributes hard to read. KY 2013-10-14
2017  // at->append_attr((*i)->getNewName(), "String" , escattr(tempfinalstr));
2018  at->append_attr((*it_a)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2019  }
2020 
2021 
2022  else {
2023  for (int loc=0; loc < (*it_a)->getCount() ; loc++) {
2024  string print_rep = HDFCFUtil::print_attr((*it_a)->getType(), loc, (void*) &((*it_a)->getValue()[0]));
2025  at->append_attr((*it_a)->getNewName(), HDFCFUtil::print_type((*it_a)->getType()), print_rep);
2026  }
2027  }
2028  }
2029  }
2030 
2031  //
2032  // MAP swath attributes to DAS.
2033  for (int i = 0; i < (int) f->getSwaths().size(); i++) {
2034 
2035  HDFEOS2::SwathDataset* swath = f->getSwaths()[i];
2036  string sname = swath->getName();
2037  AttrTable*at = NULL;
2038 
2039  // Create a "swath" DAS table if this swath has attributes.
2040  if(swath->getAttributes().size() != 0) {
2041  at = das.get_table(sname);
2042  if (!at)
2043  at = das.add_table(sname, new AttrTable);
2044  }
2045 
2046  const vector<HDFEOS2::Attribute *> swath_attrs = swath->getAttributes();
2047  vector<HDFEOS2::Attribute*>::const_iterator it_a;
2048  for (it_a = swath_attrs.begin(); it_a != swath_attrs.end(); ++it_a) {
2049 
2050  int attr_type = (*it_a)->getType();
2051 
2052  // We treat string differently. DFNT_UCHAR and DFNT_CHAR are treated as strings.
2053  if(attr_type==DFNT_UCHAR || attr_type == DFNT_CHAR){
2054  string tempstring2((*it_a)->getValue().begin(),(*it_a)->getValue().end());
2055  string tempfinalstr= string(tempstring2.c_str());
2056 
2057  // Using the customized escattr function to escape special characters except
2058  // \n,\r,\t since escaping them may make the attributes hard to read. KY 2013-10-14
2059  // at->append_attr((*i)->getNewName(), "String" , escattr(tempfinalstr));
2060  at->append_attr((*it_a)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2061  }
2062 
2063 
2064  else {
2065  for (int loc=0; loc < (*it_a)->getCount() ; loc++) {
2066  string print_rep = HDFCFUtil::print_attr((*it_a)->getType(), loc, (void*) &((*it_a)->getValue()[0]));
2067  at->append_attr((*it_a)->getNewName(), HDFCFUtil::print_type((*it_a)->getType()), print_rep);
2068  }
2069 
2070  }
2071  }
2072  }
2073  }// end of mapping swath and grid object attributes to DAP2
2074  }
2075  catch(...) {
2076  //delete f;
2077  throw;
2078  }
2079 
2080 
2081  //delete f;
2082  //return true;
2083  return 1;
2084 }
2085 
2086 //The wrapper of building HDF-EOS2 and special HDF4 files.
2087 void read_das_use_eos2lib(DAS & das, const string & filename,
2088  int32 sdfd,int32 fileid, int32 gridfd, int32 swathfd,bool ecs_metadata,
2089  HDFSP::File**h4filepptr,HDFEOS2::File**eosfilepptr)
2090 {
2091 
2092  BESDEBUG("h4","Coming to read_das_use_eos2lib" << endl);
2093 
2094  int ret_value = read_das_hdfeos2(das,filename,sdfd,fileid, gridfd, swathfd,ecs_metadata,h4filepptr,eosfilepptr);
2095 
2096  BESDEBUG("h4","ret_value of read_das_hdfeos2 is "<<ret_value <<endl);
2097 
2098  // read_das_hdfeos2 return value description:
2099  // 0: general non-EOS2 pure HDF4
2100  // 1: HDF-EOS2 hybrid
2101  // 2: MOD08_M3
2102  // HDF-EOS2 but no need to use HDF-EOS2 lib: no real dimension scales but have CVs for every dimension, treat differently
2103  // 3: AIRS version 6 level 3 and level 2
2104  // HDF-EOS2 but no need to use HDF-EOS2 lib:
2105  // have dimension scales but don’t have CVs for every dimension, also need to condense dimensions, treat differently
2106  // 4. Expected AIRS version 6 level 3 and level 2
2107  // HDF-EOS2 but no need to use HDF-EOS2 lib: Have dimension scales for all dimensions
2108  // 5. MERRA
2109  // Special handling for MERRA file as 0.
2110 
2111 
2112  // Treat as pure HDF4 objects
2113  if (ret_value == 4) {
2114  if(true == read_das_special_eos2(das, filename,sdfd,fileid,ecs_metadata,h4filepptr))
2115  return;
2116  }
2117  // Special handling, already handled
2118  else if (ret_value == 2 || ret_value == 3) {
2119  return;
2120  }
2121  else if (ret_value == 1) {
2122 
2123  // Map non-EOS2 objects to DDS
2124  if(true == read_das_hdfhybrid(das,filename,sdfd,fileid,h4filepptr))
2125  return;
2126  }
2127  else {// ret_value is 0(pure HDF4) or 5(Merra)
2128  if(true == read_das_hdfsp(das, filename,sdfd, fileid,h4filepptr))
2129  return;
2130  }
2131 
2132 
2133 // Leave the original code that don't pass the file pointers.
2134 #if 0
2135  // First map HDF-EOS2 attributes to DAS
2136  if(true == read_das_hdfeos2(das, filename)){
2137 
2138  // Map non-EOS2 attributes to DAS
2139  if (true == read_das_hdfhybrid(das,filename))
2140  return;
2141  }
2142 
2143  // Map HDF4 attributes in pure HDF4 files to DAS
2144  if(true == read_das_hdfsp(das, filename)){
2145  return;
2146  }
2147 #endif
2148 
2149  // Call the default mapping of HDF4 to DAS. It should never reach here.
2150  // We add this line to ensure the HDF4 attributes mapped to DAS even if the above routines return false.
2151  read_das(das, filename);
2152 }
2153 
2154 #endif // #ifdef USE_HDFEOS2_LIB
2155 
2156 // The wrapper of building DDS function.
2157 //bool read_dds_hdfsp(DDS & dds, const string & filename,int32 sdfd, int32 fileid,int32 gridfd, int32 swathfd)
2158 bool read_dds_hdfsp(DDS & dds, const string & filename,int32 sdfd, int32 fileid,HDFSP::File*f)
2159 {
2160 
2161  BESDEBUG("h4","Coming to read_dds_sp "<<endl);
2162  dds.set_dataset_name(basename(filename));
2163 
2164  //HDFSP::File *f = NULL;
2165 #if 0
2166  try {
2167  // Read all the information of the HDF4 file
2168  f = HDFSP::File::Read(filename.c_str(), sdfd,fileid);
2169  }
2170  catch (HDFSP::Exception &e)
2171  {
2172  //if(f != NULL)
2173  // delete f;
2174  throw InternalErr(e.what());
2175  }
2176 
2177 
2178  try {
2179  // Generate CF coordinate variable names(including auxiliary coordinate variables) and dimension names
2180  f->Prepare();
2181  }
2182  catch (HDFSP::Exception &e) {
2183  //delete f;
2184  throw InternalErr(e.what());
2185  }
2186 
2187 #endif
2188  // Obtain SDS fields
2189  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
2190 
2191  // Read SDS
2192  vector<HDFSP::SDField *>::const_iterator it_g;
2193  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2194 
2195  // Although the following line's logic needs to improve, it is right.
2196  // When Has_Dim_NoScale_Field is false, it only happens to the OTHERHDF case.
2197  // For the OTHERHDF case, we will not map the dimension_no_dim_scale (empty) field. This is equivalent to
2198  // (0 == (*it_g)->getFieldType()) || (true == (*it_g)->IsDimScale())
2199  if (false == f->Has_Dim_NoScale_Field() || (0 == (*it_g)->getFieldType()) || (true == (*it_g)->IsDimScale())){
2200  try {
2201  read_dds_spfields(dds,filename,sdfd,(*it_g),f->getSPType());
2202  }
2203  catch(...) {
2204  //delete f;
2205  throw;
2206  }
2207  }
2208  }
2209 
2210  // Read Vdata fields.
2211  // To speed up the performance for handling CERES data, we turn off some CERES vdata fields, this should be resumed in the future version with BESKeys.
2212  string check_ceres_vdata_key="H4.EnableCERESVdata";
2213  bool turn_on_ceres_vdata_key= false;
2214  turn_on_ceres_vdata_key = HDFCFUtil::check_beskeys(check_ceres_vdata_key);
2215 
2216  bool output_vdata_flag = true;
2217  if (false == turn_on_ceres_vdata_key &&
2218  (CER_AVG == f->getSPType() ||
2219  CER_ES4 == f->getSPType() ||
2220  CER_SRB == f->getSPType() ||
2221  CER_ZAVG == f->getSPType()))
2222  output_vdata_flag = false;
2223 
2224 // if(f->getSPType() != CER_AVG &&
2225 // f->getSPType() != CER_ES4 &&
2226 // f->getSPType() != CER_SRB &&
2227 // f->getSPType() != CER_ZAVG) {
2228  if(true == output_vdata_flag) {
2229  for(vector<HDFSP::VDATA *>::const_iterator i=f->getVDATAs().begin(); i!=f->getVDATAs().end();i++) {
2230  if(!(*i)->getTreatAsAttrFlag()){
2231  for(vector<HDFSP::VDField *>::const_iterator j=(*i)->getFields().begin();j!=(*i)->getFields().end();j++) {
2232  try {
2233  read_dds_spvdfields(dds,filename,fileid,(*i)->getObjRef(),(*j)->getNumRec(),(*j));
2234  }
2235  catch(...) {
2236  //delete f;
2237  throw;
2238  }
2239  }
2240  }
2241  }
2242  }
2243 
2244  // delete f;
2245  return true;
2246 }
2247 
2248 // Follow CF to build DAS for non-HDFEOS2 HDF4 products. This routine also applies
2249 // to all HDF4 products when HDF-EOS2 library is not configured in.
2250 //bool read_das_hdfsp(DAS & das, const string & filename, int32 sdfd, int32 fileid,int32 gridfd, int32 swathfd)
2251 bool read_das_hdfsp(DAS & das, const string & filename, int32 sdfd, int32 fileid,HDFSP::File**fpptr)
2252 {
2253 
2254  BESDEBUG("h4","Coming to read_das_sp "<<endl);
2255 
2256  // Define a file pointer
2257  HDFSP::File *f = NULL;
2258  try {
2259 
2260  // Obtain all the necesary information from HDF4 files.
2261  f = HDFSP::File::Read(filename.c_str(), sdfd,fileid);
2262  }
2263  catch (HDFSP::Exception &e)
2264  {
2265  if (f != NULL)
2266  delete f;
2267  throw InternalErr(e.what());
2268  }
2269 
2270  try {
2271  // Generate CF coordinate variables(including auxiliary coordinate variables) and dimensions
2272  // All the names follow CF.
2273  f->Prepare();
2274  }
2275  catch (HDFSP::Exception &e) {
2276  delete f;
2277  throw InternalErr(e.what());
2278  }
2279 
2280  *fpptr = f;
2281  // Check if mapping vgroup attribute key is turned on, if yes, mapping vgroup attributes.
2282  string check_enable_vg_attr_key="H4.EnableVgroupAttr";
2283  bool turn_on_enable_vg_attr_key= false;
2284  turn_on_enable_vg_attr_key = HDFCFUtil::check_beskeys(check_enable_vg_attr_key);
2285 
2286 #if 0
2287  // To speed up the performance for handling CERES data, we turn off some CERES vdata fields, this should be resumed in the future version with BESKeys.
2288  string check_ceres_vdata_key="H4.EnableCERESVdata";
2289  bool turn_on_ceres_vdata_key= false;
2290  turn_on_ceres_vdata_key = HDFCFUtil::check_beskeys(check_ceres_vdata_key);
2291 
2292  bool output_vdata_flag = true;
2293  if (false == turn_on_ceres_vdata_key &&
2294  (CER_AVG == f->getSPType() ||
2295  CER_ES4 == f->getSPType() ||
2296  CER_SRB == f->getSPType() ||
2297  CER_ZAVG == f->getSPType()))
2298  output_vdata_flag = false;
2299 #endif
2300 
2301 
2302  //if(true == turn_on_enable_vg_attr_key && true == output_vdata_flag) {
2303  if(true == turn_on_enable_vg_attr_key ) {
2304 
2305  // Obtain vgroup attributes if having vgroup attributes.
2306  vector<HDFSP::AttrContainer *>vg_container = f->getVgattrs();
2307  for(vector<HDFSP::AttrContainer *>::const_iterator i=f->getVgattrs().begin();i!=f->getVgattrs().end();i++) {
2308  AttrTable *vgattr_at = das.get_table((*i)->getName());
2309  if (!vgattr_at)
2310  vgattr_at = das.add_table((*i)->getName(), new AttrTable);
2311 
2312  for(vector<HDFSP::Attribute *>::const_iterator j=(*i)->getAttributes().begin();j!=(*i)->getAttributes().end();j++) {
2313 
2314  // Handle string first.
2315  if((*j)->getType()==DFNT_UCHAR || (*j)->getType() == DFNT_CHAR){
2316  string tempstring2((*j)->getValue().begin(),(*j)->getValue().end());
2317  string tempfinalstr= string(tempstring2.c_str());
2318 
2319  //escaping the special characters in string attributes when mapping to DAP
2320  vgattr_at->append_attr((*j)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2321  }
2322  else {
2323  for (int loc=0; loc < (*j)->getCount() ; loc++) {
2324 
2325  string print_rep = HDFCFUtil::print_attr((*j)->getType(), loc, (void*) &((*j)->getValue()[0]));
2326  vgattr_at->append_attr((*j)->getNewName(), HDFCFUtil::print_type((*j)->getType()), print_rep);
2327  }
2328  }
2329  }
2330  }
2331  }// end of mapping vgroup attributes.
2332 
2333  // Initialize ECS metadata
2334  string core_metadata = "";
2335  string archive_metadata = "";
2336  string struct_metadata = "";
2337 
2338  // Obtain SD pointer, this is used to retrieve the file attributes associated with the SD interface
2339  HDFSP::SD* spsd = f->getSD();
2340 
2341  // Except TRMM, we don't find ECS metadata in other non-EOS products. For the option to treat EOS2 as pure HDF4, we
2342  // kind of relax the support of merging metadata as we do for the EOS2 case(read_das_hdfeos2). We will see if we have the user
2343  // request to make them consistent in the future. KY 2013-07-08
2344  for(vector<HDFSP::Attribute *>::const_iterator i=spsd->getAttributes().begin();i!=spsd->getAttributes().end();i++) {
2345 
2346  // Here we try to combine ECS metadata into a string.
2347  if(((*i)->getName().compare(0, 12, "CoreMetadata" )== 0) ||
2348  ((*i)->getName().compare(0, 12, "coremetadata" )== 0)){
2349 
2350  // We assume that CoreMetadata.0, CoreMetadata.1, ..., CoreMetadata.n attribures
2351  // are processed in the right order during HDFSP::Attribute vector iteration.
2352  // Otherwise, this won't work.
2353  string tempstring((*i)->getValue().begin(),(*i)->getValue().end());
2354 
2355  // Temporarily turn off CERES data since there are so many fields in CERES. It will choke clients KY 2010-7-9
2356  if(f->getSPType() != CER_AVG &&
2357  f->getSPType() != CER_ES4 &&
2358  f->getSPType() !=CER_SRB &&
2359  f->getSPType() != CER_ZAVG)
2360  core_metadata.append(tempstring);
2361  }
2362  else if(((*i)->getName().compare(0, 15, "ArchiveMetadata" )== 0) ||
2363  ((*i)->getName().compare(0, 16, "ArchivedMetadata")==0) ||
2364  ((*i)->getName().compare(0, 15, "archivemetadata" )== 0)){
2365  string tempstring((*i)->getValue().begin(),(*i)->getValue().end());
2366  // Currently some TRMM "swath" archivemetadata includes special characters that cannot be handled by OPeNDAP
2367  // So turn it off.
2368  // Turn off CERES data since it may choke JAVA clients KY 2010-7-9
2369  if(f->getSPType() != TRMML2_V6 && f->getSPType() != CER_AVG && f->getSPType() != CER_ES4 && f->getSPType() !=CER_SRB && f->getSPType() != CER_ZAVG)
2370  archive_metadata.append(tempstring);
2371  }
2372  else if(((*i)->getName().compare(0, 14, "StructMetadata" )== 0) ||
2373  ((*i)->getName().compare(0, 14, "structmetadata" )== 0)){
2374 
2375  string check_disable_smetadata_key ="H4.DisableStructMetaAttr";
2376  bool is_check_disable_smetadata = false;
2377  is_check_disable_smetadata = HDFCFUtil::check_beskeys(check_disable_smetadata_key);
2378 
2379  if (false == is_check_disable_smetadata) {
2380 
2381  string tempstring((*i)->getValue().begin(),(*i)->getValue().end());
2382 
2383  // Turn off TRMM "swath" verison 6 level 2 productsCERES data since it may choke JAVA clients KY 2010-7-9
2384  if(f->getSPType() != TRMML2_V6 &&
2385  f->getSPType() != CER_AVG &&
2386  f->getSPType() != CER_ES4 &&
2387  f->getSPType() !=CER_SRB &&
2388  f->getSPType() != CER_ZAVG)
2389  struct_metadata.append(tempstring);
2390 
2391  }
2392  }
2393  else {
2394  // Process gloabal attributes
2395  AttrTable *at = das.get_table("HDF_GLOBAL");
2396  if (!at)
2397  at = das.add_table("HDF_GLOBAL", new AttrTable);
2398 
2399  // We treat string differently. DFNT_UCHAR and DFNT_CHAR are treated as strings.
2400  if((*i)->getType()==DFNT_UCHAR || (*i)->getType() == DFNT_CHAR){
2401  string tempstring2((*i)->getValue().begin(),(*i)->getValue().end());
2402  string tempfinalstr= string(tempstring2.c_str());
2403 
2404  // Using the customized escattr function to escape special characters except
2405  // \n,\r,\t since escaping them may make the attributes hard to read. KY 2013-10-14
2406  // at->append_attr((*i)->getNewName(), "String" , escattr(tempfinalstr));
2407  at->append_attr((*i)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2408  }
2409 
2410  else {
2411  for (int loc=0; loc < (*i)->getCount() ; loc++) {
2412  string print_rep = HDFCFUtil::print_attr((*i)->getType(), loc, (void*) &((*i)->getValue()[0]));
2413  at->append_attr((*i)->getNewName(), HDFCFUtil::print_type((*i)->getType()), print_rep);
2414  }
2415 
2416  }
2417  }
2418 
2419  }
2420 
2421  // The following code may be condensed in the future. KY 2012-09-19
2422  // Coremetadata, structmetadata and archive metadata need special parsers.
2423 
2424  // Write coremetadata.
2425  if(core_metadata.size() > 0){
2426  AttrTable *at = das.get_table("CoreMetadata");
2427  if (!at)
2428  at = das.add_table("CoreMetadata", new AttrTable);
2429  // tell lexer to scan attribute string
2430  void *buf = hdfeos_string(core_metadata.c_str());
2431  parser_arg arg(at);
2432 
2433  if (hdfeosparse(&arg) != 0) {
2434  // delete f;
2435  hdfeos_delete_buffer(buf);
2436  throw Error("Parse error while processing a CoreMetadata attribute.");
2437  }
2438 
2439  // Errors returned from here are ignored.
2440  if (arg.status() == false) {
2441 //cerr<<"parsing error "<<endl;
2442  (*BESLog::TheLog()) << "Parse error while processing a CoreMetadata attribute. (2) " << endl;
2443  // << arg.error()->get_error_message() << endl;
2444  }
2445 
2446  hdfeos_delete_buffer(buf);
2447  }
2448 
2449  // Write archive metadata.
2450  if(archive_metadata.size() > 0){
2451  AttrTable *at = das.get_table("ArchiveMetadata");
2452  if (!at)
2453  at = das.add_table("ArchiveMetadata", new AttrTable);
2454  // tell lexer to scan attribute string
2455  void *buf = hdfeos_string(archive_metadata.c_str());
2456  parser_arg arg(at);
2457  if (hdfeosparse(&arg) != 0){
2458  // delete f;
2459  hdfeos_delete_buffer(buf);
2460  throw Error("Parse error while processing an ArchiveMetadata attribute.");
2461  }
2462 
2463  // Errors returned from here are ignored.
2464  if (arg.status() == false) {
2465  (*BESLog::TheLog())<< "Parse error while processing an ArchiveMetadata attribute. (2) " << endl;
2466  // << arg.error()->get_error_message() << endl;
2467  }
2468 
2469  hdfeos_delete_buffer(buf);
2470  }
2471 
2472  // Write struct metadata.
2473  if(struct_metadata.size() > 0){
2474  AttrTable *at = das.get_table("StructMetadata");
2475  if (!at)
2476  at = das.add_table("StructMetadata", new AttrTable);
2477  // tell lexer to scan attribute string
2478  void *buf = hdfeos_string(struct_metadata.c_str());
2479  parser_arg arg(at);
2480  if (hdfeosparse(&arg) != 0){
2481  // delete f;
2482  hdfeos_delete_buffer(buf);
2483  throw Error("Parse error while processing a StructMetadata attribute.");
2484  }
2485 
2486  if (arg.status() == false) {
2487  (*BESLog::TheLog())<< "Parse error while processing a StructMetadata attribute. (2)" << endl;
2488  }
2489 
2490 
2491  // Errors returned from here are ignored.
2492 #if 0
2493  if (arg.status() == false) {
2494  (*BESLog::TheLog())<< "Parse error while processing a StructMetadata attribute. (2)" << endl
2495  << arg.error()->get_error_message() << endl;
2496  }
2497 #endif
2498 
2499  hdfeos_delete_buffer(buf);
2500  }
2501 
2502  // The following code checks the special handling of scale and offset of the OBPG products.
2503  //Store value of "Scaling" attribute.
2504  string scaling;
2505 
2506  //Store value of "Slope" attribute.
2507  float slope = 0.;
2508  bool global_slope_flag = false;
2509  float intercept = 0.;
2510  bool global_intercept_flag = false;
2511 
2512  // Check OBPG attributes. Specifically, check if slope and intercept can be obtained from the file level.
2513  // If having global slope and intercept, obtain OBPG scaling, slope and intercept values.
2514  HDFCFUtil::check_obpg_global_attrs(f,scaling,slope,global_slope_flag,intercept,global_intercept_flag);
2515 
2516  // Handle individual fields
2517  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
2518  vector<HDFSP::SDField *>::const_iterator it_g;
2519  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2520 
2521  // The following two if-statements are double secure checks. It will
2522  // make sure no-dimension-scale dimension variables and the associated coordinate variables(if any) are ignored.
2523  // Ignore ALL coordinate variables if this is "OTHERHDF" case and some dimensions
2524  // don't have dimension scale data.
2525  if ( true == f->Has_Dim_NoScale_Field() &&
2526  ((*it_g)->getFieldType() !=0)&&
2527  ((*it_g)->IsDimScale() == false))
2528  continue;
2529 
2530  // Ignore the empty(no data) dimension variable.
2531  if (OTHERHDF == f->getSPType() && true == (*it_g)->IsDimNoScale())
2532  continue;
2533 
2534  AttrTable *at = das.get_table((*it_g)->getNewName());
2535  if (!at)
2536  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2537 
2538  // Some fields have "long_name" attributes,so we have to use this attribute rather than creating our own
2539  bool long_name_flag = false;
2540 
2541  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();
2542  i!=(*it_g)->getAttributes().end();i++) {
2543 
2544  if((*i)->getName() == "long_name") {
2545  long_name_flag = true;
2546  break;
2547  }
2548  }
2549 
2550  if(false == long_name_flag) {
2551  if (f->getSPType() == TRMML2_V7) {
2552  if((*it_g)->getFieldType() == 1)
2553  at->append_attr("standard_name","String","latitude");
2554  else if ((*it_g)->getFieldType() == 2) {
2555  at->append_attr("standard_name","String","longitude");
2556 
2557  }
2558 
2559  }
2560  else if (f->getSPType() == TRMML3S_V7 || f->getSPType() == TRMML3M_V7) {
2561  if((*it_g)->getFieldType() == 1) {
2562  at->append_attr("long_name","String","latitude");
2563  at->append_attr("standard_name","String","latitude");
2564 
2565  }
2566  else if ((*it_g)->getFieldType() == 2) {
2567  at->append_attr("long_name","String","longitude");
2568  at->append_attr("standard_name","String","longitude");
2569  }
2570 
2571  }
2572  else
2573  at->append_attr("long_name", "String", (*it_g)->getName());
2574  }
2575 
2576  // For some OBPG files that only provide slope and intercept at the file level,
2577  // we need to add the global slope and intercept to all fields and change their names to scale_factor and add_offset.
2578  // For OBPG files that provide slope and intercept at the field level, we need to rename those attribute names to scale_factor and add_offset.
2579  HDFCFUtil::add_obpg_special_attrs(f,das,*it_g,scaling,slope,global_slope_flag,intercept,global_intercept_flag);
2580 
2581  // MAP individual SDS field to DAP DAS
2582  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();i!=(*it_g)->getAttributes().end();i++) {
2583 
2584  // Handle string first.
2585  if((*i)->getType()==DFNT_UCHAR || (*i)->getType() == DFNT_CHAR){
2586  string tempstring2((*i)->getValue().begin(),(*i)->getValue().end());
2587  string tempfinalstr= string(tempstring2.c_str());
2588 
2589  // We want to escape the possible special characters except the fullpath attribute. This may be overkilled since
2590  // fullpath is only added for some CERES and MERRA data. We think people use fullpath really mean to keep their
2591  // original names. So escaping them for the time being. KY 2013-10-14
2592 
2593  at->append_attr((*i)->getNewName(), "String" ,((*i)->getNewName()=="fullpath")?tempfinalstr:HDFCFUtil::escattr(tempfinalstr));
2594  }
2595  else {
2596  for (int loc=0; loc < (*i)->getCount() ; loc++) {
2597  string print_rep = HDFCFUtil::print_attr((*i)->getType(), loc, (void*) &((*i)->getValue()[0]));
2598  at->append_attr((*i)->getNewName(), HDFCFUtil::print_type((*i)->getType()), print_rep);
2599  }
2600  }
2601 
2602  }
2603 
2604  // MAP dimension info. to DAS(Currently this should only affect the OTHERHDF case when no dimension scale for some dimensions)
2605  // KY 2012-09-19
2606 
2607  // For the type DFNT_CHAR, one dimensional char array is mapped to a scalar DAP string,
2608  // N dimensional char array is mapped to N-1 dimensional DAP string,
2609  // So the number of dimension info stored in the attribute container should be reduced by 1.
2610  // KY 2014-04-11
2611 
2612  bool has_dim_info = true;
2613  vector<HDFSP::AttrContainer *>::const_iterator it_end = (*it_g)->getDimInfo().end();
2614  if((*it_g)->getType() == DFNT_CHAR) {
2615  if((*it_g)->getRank() >1 && (*it_g)->getDimInfo().size() >1)
2616  it_end = (*it_g)->getDimInfo().begin()+(*it_g)->getDimInfo().size() -1;
2617  else
2618  has_dim_info = false;
2619  }
2620 
2621  if( true == has_dim_info) {
2622  for(vector<HDFSP::AttrContainer *>::const_iterator i=(*it_g)->getDimInfo().begin();i!=it_end;i++) {
2623  //for(vector<HDFSP::AttrContainer *>::const_iterator i=(*it_g)->getDimInfo().begin();i!=(*it_g)->getDimInfo().end();i++) {
2624 
2625  // Here a little surgory to add the field path(including) name before dim0, dim1, etc.
2626  string attr_container_name = (*it_g)->getNewName() + (*i)->getName();
2627  AttrTable *dim_at = das.get_table(attr_container_name);
2628  if (!dim_at)
2629  dim_at = das.add_table(attr_container_name, new AttrTable);
2630 
2631  for(vector<HDFSP::Attribute *>::const_iterator j=(*i)->getAttributes().begin();j!=(*i)->getAttributes().end();j++) {
2632 
2633  // Handle string first.
2634  if((*j)->getType()==DFNT_UCHAR || (*j)->getType() == DFNT_CHAR){
2635  string tempstring2((*j)->getValue().begin(),(*j)->getValue().end());
2636  string tempfinalstr= string(tempstring2.c_str());
2637 
2638  //escaping the special characters in string attributes when mapping to DAP
2639  dim_at->append_attr((*j)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2640  }
2641  else {
2642  for (int loc=0; loc < (*j)->getCount() ; loc++) {
2643 
2644  string print_rep = HDFCFUtil::print_attr((*j)->getType(), loc, (void*) &((*j)->getValue()[0]));
2645  dim_at->append_attr((*j)->getNewName(), HDFCFUtil::print_type((*j)->getType()), print_rep);
2646  }
2647  }
2648  }
2649 
2650  }
2651  }
2652 
2653  // Handle special CF attributes such as units, valid_range and coordinates
2654  // Overwrite units if fieldtype is latitude.
2655  if((*it_g)->getFieldType() == 1){
2656 
2657  at->del_attr("units"); // Override any existing units attribute.
2658  at->append_attr("units", "String",(*it_g)->getUnits());
2659  if (f->getSPType() == CER_ES4) // Drop the valid_range attribute since the value will be interpreted wrongly by CF tools
2660  at->del_attr("valid_range");
2661 
2662 
2663  }
2664  // Overwrite units if fieldtype is longitude
2665  if((*it_g)->getFieldType() == 2){
2666  at->del_attr("units"); // Override any existing units attribute.
2667  at->append_attr("units", "String",(*it_g)->getUnits());
2668  if (f->getSPType() == CER_ES4) // Drop the valid_range attribute since the value will be interpreted wrongly by CF tools
2669  at->del_attr("valid_range");
2670 
2671  }
2672 
2673  // The following if-statement may not be necessary since fieldtype=4 is the missing CV.
2674  // This missing CV is added by the handler and the units is always level.
2675  if((*it_g)->getFieldType() == 4){
2676  at->del_attr("units"); // Override any existing units attribute.
2677  at->append_attr("units", "String",(*it_g)->getUnits());
2678  }
2679 
2680  // Overwrite coordinates if fieldtype is neither lat nor lon.
2681  if((*it_g)->getFieldType() == 0){
2682  at->del_attr("coordinates"); // Override any existing units attribute.
2683 
2684  // If no "dimension scale" dimension exists, delete the "coordinates" attributes
2685  if (false == f->Has_Dim_NoScale_Field()) {
2686  string coordinate = (*it_g)->getCoordinate();
2687  if (coordinate !="")
2688  at->append_attr("coordinates", "String", coordinate);
2689  }
2690  }
2691  }
2692 
2693 
2694  // For OTHERHDF products, add units for latitude and longitude; also change unit to units.
2696 
2697  // For NASA products, add missing CF attributes if possible
2699 
2700  string check_scale_offset_type_key = "H4.EnableCheckScaleOffsetType";
2701  bool turn_on_enable_check_scale_offset_key= false;
2702  turn_on_enable_check_scale_offset_key = HDFCFUtil::check_beskeys(check_scale_offset_type_key);
2703 
2704  // Check if having _FillValue. If having _FillValue, compare the datatype of _FillValue
2705  // with the variable datatype. Correct the fillvalue datatype if necessary.
2706  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2707 
2708  AttrTable *at = das.get_table((*it_g)->getNewName());
2709  if (at != NULL) {
2710  int32 var_type = (*it_g)->getType();
2711  try {
2712  HDFCFUtil::correct_fvalue_type(at,var_type);
2713  }
2714  catch(...) {
2715  // delete f;
2716  throw;
2717  }
2718  }
2719 
2720  // If H4.EnableCheckScaleOffsetType BES key is true,
2721  // if yes, check if having scale_factor and add_offset attributes;
2722  // if yes, check if scale_factor and add_offset attribute types are the same;
2723  // if no, make add_offset's datatype be the same as the datatype of scale_factor.
2724  // (CF requires the type of scale_factor and add_offset the same).
2725  if (true == turn_on_enable_check_scale_offset_key && at !=NULL)
2727  }
2728 
2729  // Optimization for users to tune the DAS output.
2731 
2732  // Check the EnableVdataDescAttr key. If this key is turned on, the handler-added attribute VDdescname and
2733  // the attributes of vdata and vdata fields will be outputed to DAS. Otherwise, these attributes will
2734  // not output to DAS. The key will be turned off by default to shorten the DAP output. KY 2012-09-18
2735  try {
2737  }
2738  catch(...) {
2739  //delete f;
2740  throw;
2741  }
2742 
2743  //delete f;
2744  return true;
2745 }
2746 
2747 // This routine is for case 4 of the cases returned by read_das_hdfeos2.
2748 // Creating this routine is for performance reasons. Structmetadata is
2749 // turned off because the information has been retrieved and presented
2750 // by DDS and DAS.
2751 // Currently we don't have a user case for this routine and also
2752 // this code is not used. We still keep it for the future usage.
2753 // KY 2014-01-29
2754 
2755 bool read_das_special_eos2(DAS &das,const string& filename,int32 sdfd,int32 fileid,bool ecs_metadata,HDFSP::File**fpptr) {
2756 
2757  BESDEBUG("h4","Coming to read_das_special_eos2 " << endl);
2758 
2759 #if 0
2760  // HDF4 H interface ID
2761  int32 myfileid;
2762  myfileid = Hopen(const_cast<char *>(filename.c_str()), DFACC_READ,0);
2763 #endif
2764 
2765  // Define a file pointer
2766  HDFSP::File *f = NULL;
2767  try {
2768 
2769  // Obtain all the necesary information from HDF4 files.
2770  f = HDFSP::File::Read(filename.c_str(), sdfd,fileid);
2771  }
2772  catch (HDFSP::Exception &e)
2773  {
2774  if (f!= NULL)
2775  delete f;
2776  throw InternalErr(e.what());
2777  }
2778 
2779  try {
2780  // Generate CF coordinate variables(including auxiliary coordinate variables) and dimensions
2781  // All the names follow CF.
2782  f->Prepare();
2783  }
2784  catch (HDFSP::Exception &e) {
2785  delete f;
2786  throw InternalErr(e.what());
2787  }
2788 
2789  *fpptr = f;
2790 
2791  try {
2792  read_das_special_eos2_core(das, f, filename,ecs_metadata);
2793  }
2794  catch(...) {
2795  //delete f;
2796  throw;
2797  }
2798  //delete f;
2799 
2800  // The return value is a dummy value, not used.
2801  return true;
2802 }
2803 
2804 // This routine is for special EOS2 that can be tuned to build up DAS and DDS quickly.
2805 // We also turn off the generation of StructMetadata for the performance reason.
2806 bool read_das_special_eos2_core(DAS &das,HDFSP::File* f,const string& filename,bool ecs_metadata) {
2807 
2808  BESDEBUG("h4","Coming to read_das_special_eos2_core "<<endl);
2809  // Initialize ECS metadata
2810  string core_metadata = "";
2811  string archive_metadata = "";
2812  string struct_metadata = "";
2813 
2814  // Obtain SD pointer, this is used to retrieve the file attributes associated with the SD interface
2815  HDFSP::SD* spsd = f->getSD();
2816 
2817  //Ignore StructMetadata to improve performance
2818  for(vector<HDFSP::Attribute *>::const_iterator i=spsd->getAttributes().begin();i!=spsd->getAttributes().end();i++) {
2819 
2820  // Here we try to combine ECS metadata into a string.
2821  if(((*i)->getName().compare(0, 12, "CoreMetadata" )== 0) ||
2822  ((*i)->getName().compare(0, 12, "coremetadata" )== 0)){
2823 
2824  if(ecs_metadata == true) {
2825  // We assume that CoreMetadata.0, CoreMetadata.1, ..., CoreMetadata.n attribures
2826  // are processed in the right order during HDFSP::Attribute vector iteration.
2827  // Otherwise, this won't work.
2828  string tempstring((*i)->getValue().begin(),(*i)->getValue().end());
2829  core_metadata.append(tempstring);
2830  }
2831  }
2832  else if(((*i)->getName().compare(0, 15, "ArchiveMetadata" )== 0) ||
2833  ((*i)->getName().compare(0, 16, "ArchivedMetadata")==0) ||
2834  ((*i)->getName().compare(0, 15, "archivemetadata" )== 0)){
2835  if(ecs_metadata == true) {
2836  string tempstring((*i)->getValue().begin(),(*i)->getValue().end());
2837  archive_metadata.append(tempstring);
2838  }
2839  }
2840  else if(((*i)->getName().compare(0, 14, "StructMetadata" )== 0) ||
2841  ((*i)->getName().compare(0, 14, "structmetadata" )== 0))
2842  ; // Ignore StructMetadata for performance
2843  else {
2844  // Process gloabal attributes
2845  AttrTable *at = das.get_table("HDF_GLOBAL");
2846  if (!at)
2847  at = das.add_table("HDF_GLOBAL", new AttrTable);
2848 
2849  // We treat string differently. DFNT_UCHAR and DFNT_CHAR are treated as strings.
2850  if((*i)->getType()==DFNT_UCHAR || (*i)->getType() == DFNT_CHAR){
2851  string tempstring2((*i)->getValue().begin(),(*i)->getValue().end());
2852  string tempfinalstr= string(tempstring2.c_str());
2853 
2854  // Using the customized escattr function to escape special characters except
2855  // \n,\r,\t since escaping them may make the attributes hard to read. KY 2013-10-14
2856  // at->append_attr((*i)->getNewName(), "String" , escattr(tempfinalstr));
2857  at->append_attr((*i)->getNewName(), "String" , HDFCFUtil::escattr(tempfinalstr));
2858  }
2859 
2860  else {
2861  for (int loc=0; loc < (*i)->getCount() ; loc++) {
2862  string print_rep = HDFCFUtil::print_attr((*i)->getType(), loc, (void*) &((*i)->getValue()[0]));
2863  at->append_attr((*i)->getNewName(), HDFCFUtil::print_type((*i)->getType()), print_rep);
2864  }
2865 
2866  }
2867  }
2868 
2869  }
2870 
2871  // The following code may be condensed in the future. KY 2012-09-19
2872  // Coremetadata, structmetadata and archive metadata need special parsers.
2873 
2874  if(ecs_metadata == true) {
2875  // Write coremetadata.
2876  if(core_metadata.size() > 0){
2877  AttrTable *at = das.get_table("CoreMetadata");
2878  if (!at)
2879  at = das.add_table("CoreMetadata", new AttrTable);
2880  // tell lexer to scan attribute string
2881  void *buf = hdfeos_string(core_metadata.c_str());
2882  parser_arg arg(at);
2883 
2884  if (hdfeosparse(&arg) != 0) {
2885  hdfeos_delete_buffer(buf);
2886  throw Error("Parse error while processing a CoreMetadata attribute.");
2887  }
2888 
2889  // Errors returned from here are ignored.
2890  if (arg.status() == false) {
2891  (*BESLog::TheLog()) << "Parse error while processing a CoreMetadata attribute. (2)" << endl;
2892 // << arg.error()->get_error_message() << endl;
2893  }
2894 
2895  hdfeos_delete_buffer(buf);
2896 
2897  }
2898 
2899  // Write archive metadata.
2900  if(archive_metadata.size() > 0){
2901  AttrTable *at = das.get_table("ArchiveMetadata");
2902  if (!at)
2903  at = das.add_table("ArchiveMetadata", new AttrTable);
2904  // tell lexer to scan attribute string
2905  void *buf = hdfeos_string(archive_metadata.c_str());
2906  parser_arg arg(at);
2907  if (hdfeosparse(&arg) != 0) {
2908  hdfeos_delete_buffer(buf);
2909  throw Error("Parse error while processing an ArchiveMetadata attribute.");
2910  }
2911 
2912  // Errors returned from here are ignored.
2913  if (arg.status() == false) {
2914  (*BESLog::TheLog())<< "Parse error while processing an ArchiveMetadata attribute. (2)" << endl;
2915  // << arg.error()->get_error_message() << endl;
2916  }
2917 
2918  hdfeos_delete_buffer(buf);
2919  }
2920  }
2921 
2922  // Handle individual fields
2923  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
2924  vector<HDFSP::SDField *>::const_iterator it_g;
2925  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
2926 
2927  // Add units for CV variables
2928 // if((*it_g)->getFieldType() != 0 && (*it_g)->IsDimScale() == false){
2929  if((*it_g)->getFieldType() != 0){
2930 
2931  AttrTable *at = das.get_table((*it_g)->getNewName());
2932  if (!at)
2933  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2934 
2935  string tempunits = (*it_g)->getUnits();
2936  if(at->simple_find("units")== at->attr_end() && tempunits!="")
2937  at->append_attr("units", "String" ,tempunits);
2938  if((*it_g)->getFieldType() == 1){
2939  if(at->simple_find("long_name")== at->attr_end())
2940  at->append_attr("long_name","String","Latitude");
2941  }
2942  else if((*it_g)->getFieldType() == 2) {
2943  if(at->simple_find("long_name")== at->attr_end())
2944  at->append_attr("long_name","String","Longitude");
2945  }
2946  }
2947  else {// We will check if having the coordinates attribute.
2948  AttrTable *at = das.get_table((*it_g)->getNewName());
2949  if (!at)
2950  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2951  string tempcoors = (*it_g)->getCoordinate();
2952  // If we add the coordinates attribute, any existing coordinates attribute will be removed.
2953  if(tempcoors!=""){
2954  at->del_attr("coordinates");
2955  at->append_attr("coordinates","String",tempcoors);
2956  }
2957 
2958  }
2959 
2960  // Ignore variables that don't have attributes.
2961  if((*it_g)->getAttributes().size() == 0)
2962  continue;
2963 
2964  AttrTable *at = das.get_table((*it_g)->getNewName());
2965  if (!at)
2966  at = das.add_table((*it_g)->getNewName(), new AttrTable);
2967 
2968  // MAP individual SDS field to DAP DAS
2969  for(vector<HDFSP::Attribute *>::const_iterator i=(*it_g)->getAttributes().begin();i!=(*it_g)->getAttributes().end();i++) {
2970 
2971  // Handle string first.
2972  if((*i)->getType()==DFNT_UCHAR || (*i)->getType() == DFNT_CHAR){
2973  string tempstring2((*i)->getValue().begin(),(*i)->getValue().end());
2974  string tempfinalstr= string(tempstring2.c_str());
2975 
2976  // We want to escape the possible special characters except the fullpath attribute. This may be overkilled since
2977  // fullpath is only added for some CERES and MERRA data. We think people use fullpath really mean to keep their
2978  // original names. So escaping them for the time being. KY 2013-10-14
2979 
2980  at->append_attr((*i)->getNewName(), "String" ,((*i)->getNewName()=="fullpath")?tempfinalstr:HDFCFUtil::escattr(tempfinalstr));
2981  }
2982  else {
2983  for (int loc=0; loc < (*i)->getCount() ; loc++) {
2984  string print_rep = HDFCFUtil::print_attr((*i)->getType(), loc, (void*) &((*i)->getValue()[0]));
2985  at->append_attr((*i)->getNewName(), HDFCFUtil::print_type((*i)->getType()), print_rep);
2986  }
2987  }
2988  }
2989 
2990  }
2991 
2992  return true;
2993 }
2994 
2996 
2997  // Handle individual fields
2998  // Check HDFCFUtil::handle_modis_special_attrs_disable_scale_comp
2999  const vector<HDFSP::SDField *>& spsds = f->getSD()->getFields();
3000  vector<HDFSP::SDField *>::const_iterator it_g;
3001  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
3002  if((*it_g)->getFieldType() == 0){
3003  AttrTable *at = das.get_table((*it_g)->getNewName());
3004  if (!at)
3005  at = das.add_table((*it_g)->getNewName(), new AttrTable);
3006 
3007  // Declare add_offset type in string format.
3008  string add_offset_type;
3009 
3010  // add_offset values
3011  string add_offset_value="0";
3012  double orig_offset_value = 0;
3013  bool add_offset_modify = false;
3014 
3015 
3016  // Go through all attributes to find add_offset
3017  // If add_offset is 0 or add_offset is not found, we don't need
3018  // to modify the add_offset value.
3019  AttrTable::Attr_iter it = at->attr_begin();
3020  while (it!=at->attr_end())
3021  {
3022  if(at->get_name(it)=="add_offset")
3023  {
3024  add_offset_value = (*at->get_attr_vector(it)->begin());
3025  orig_offset_value = atof(add_offset_value.c_str());
3026  add_offset_type = at->get_type(it);
3027  if(add_offset_value == "0.0" || orig_offset_value == 0)
3028  add_offset_modify = false;
3029  else
3030  add_offset_modify = true;
3031  break;
3032  }
3033  it++;
3034 
3035  }
3036 
3037  // We need to modify the add_offset value if the add_offset exists.
3038  if( true == add_offset_modify) {
3039 
3040  // Declare scale_factor type in string format.
3041  string scale_factor_type;
3042 
3043  // Scale values
3044  string scale_factor_value="";
3045  double orig_scale_value = 1;
3046 
3047  it = at->attr_begin();
3048  while (it!=at->attr_end())
3049  {
3050  if(at->get_name(it)=="scale_factor")
3051  {
3052  scale_factor_value = (*at->get_attr_vector(it)->begin());
3053  orig_scale_value = atof(scale_factor_value.c_str());
3054  scale_factor_type = at->get_type(it);
3055  }
3056  it++;
3057  }
3058 
3059  if(scale_factor_value.length() !=0) {
3060  double new_offset_value = -1 * orig_scale_value*orig_offset_value;
3061  string print_rep = HDFCFUtil::print_attr(DFNT_FLOAT64,0,(void*)(&new_offset_value));
3062  at->del_attr("add_offset");
3063  at->append_attr("add_offset", HDFCFUtil::print_type(DFNT_FLOAT64), print_rep);
3064  }
3065  }
3066 
3067  }
3068 
3069  }
3070 
3071 }
3072 
3073 // Function to build special AIRS version 6 and MOD08_M3 DDS. Doing this way is for improving performance.
3074 bool read_dds_special_1d_grid(DDS &dds,HDFSP::File* spf,const string& filename, int32 sdid, int32 fileid) {
3075 
3076  BESDEBUG("h4","Coming to read_dds_special_1d_grid "<<endl);
3077 
3078  SPType sptype = OTHERHDF;
3079  const vector<HDFSP::SDField *>& spsds = spf->getSD()->getFields();
3080 
3081  // Read SDS
3082  vector<HDFSP::SDField *>::const_iterator it_g;
3083  for(it_g = spsds.begin(); it_g != spsds.end(); it_g++){
3084 
3085  BaseType *bt=NULL;
3086  switch((*it_g)->getType()) {
3087 #define HANDLE_CASE(tid, type) \
3088  case tid: \
3089  bt = new (type)((*it_g)->getNewName(),filename); \
3090  break;
3091  HANDLE_CASE(DFNT_FLOAT32, HDFFloat32);
3092  HANDLE_CASE(DFNT_FLOAT64, HDFFloat64);
3093  HANDLE_CASE(DFNT_CHAR, HDFStr);
3094 #ifndef SIGNED_BYTE_TO_INT32
3095  HANDLE_CASE(DFNT_INT8, HDFByte);
3096 #else
3097  HANDLE_CASE(DFNT_INT8,HDFInt32);
3098 #endif
3099  HANDLE_CASE(DFNT_UINT8, HDFByte);
3100  HANDLE_CASE(DFNT_INT16, HDFInt16);
3101  HANDLE_CASE(DFNT_UINT16, HDFUInt16);
3102  HANDLE_CASE(DFNT_INT32, HDFInt32);
3103  HANDLE_CASE(DFNT_UINT32, HDFUInt32);
3104  HANDLE_CASE(DFNT_UCHAR8, HDFByte);
3105  default:
3106  InternalErr(__FILE__,__LINE__,"unsupported data type.");
3107 #undef HANDLE_CASE
3108  }
3109 
3110  if(bt)
3111  {
3112 
3113  const vector<HDFSP::Dimension*>& dims= (*it_g)->getDimensions();
3114  //const vector<HDFSP::Dimension*>& dims= spsds->getCorrectedDimensions();
3115  vector<HDFSP::Dimension*>::const_iterator it_d;
3116  if(DFNT_CHAR == (*it_g)->getType()) {
3117 
3118  if(1 == (*it_g)->getRank()) {
3119 
3120  HDFCFStr * sca_str = NULL;
3121  try {
3122  sca_str = new HDFCFStr(
3123  sdid,
3124  (*it_g)->getFieldRef(),
3125  filename,
3126  (*it_g)->getName(),
3127  (*it_g)->getNewName(),
3128  false
3129  );
3130  }
3131  catch(...) {
3132  delete bt;
3133  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStr instance.");
3134  }
3135  dds.add_var(sca_str);
3136  delete bt;
3137  delete sca_str;
3138  }
3139 
3140  else {
3141  HDFCFStrField *ar = NULL;
3142  try {
3143 
3144  ar = new HDFCFStrField(
3145  (*it_g)->getRank() -1 ,
3146  filename,
3147  false,
3148  sdid,
3149  (*it_g)->getFieldRef(),
3150  0,
3151  (*it_g)->getName(),
3152  (*it_g)->getNewName(),
3153  bt);
3154 
3155  }
3156  catch(...) {
3157  delete bt;
3158  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStrField instance.");
3159  }
3160 
3161  for(it_d = dims.begin(); it_d != dims.begin()+dims.size()-1; it_d++)
3162  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3163  dds.add_var(ar);
3164  delete bt;
3165  delete ar;
3166  }
3167 
3168  }
3169 
3170  else {
3171 
3172  if((*it_g)->getFieldType() != 4) {
3173  HDFSPArray_RealField *ar = NULL;
3174 
3175  try {
3176  ar = new HDFSPArray_RealField(
3177  (*it_g)->getRank(),
3178  filename,
3179  sdid,
3180  (*it_g)->getFieldRef(),
3181  (*it_g)->getType(),
3182  sptype,
3183  (*it_g)->getName(),
3184  (*it_g)->getNewName(),
3185  bt);
3186  }
3187  catch(...) {
3188  delete bt;
3189  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFSPArray_RealField instance.");
3190  }
3191  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
3192  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3193  dds.add_var(ar);
3194  delete bt;
3195  delete ar;
3196  }
3197  else {
3198  if((*it_g)->getRank()!=1){
3199  delete bt;
3200  throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
3201  }
3202  int nelem = ((*it_g)->getDimensions()[0])->getSize();
3203 
3205 
3206  try {
3207  ar = new HDFSPArrayMissGeoField(
3208  (*it_g)->getRank(),
3209  nelem,
3210  (*it_g)->getNewName(),
3211  bt);
3212  }
3213  catch(...) {
3214  delete bt;
3215  InternalErr(__FILE__,__LINE__,
3216  "Unable to allocate the HDFSPArrayMissGeoField instance.");
3217  }
3218 
3219 
3220  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
3221  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3222  dds.add_var(ar);
3223  delete bt;
3224  delete ar;
3225 
3226  }
3227  }
3228  }
3229 
3230  }
3231 
3232  return true;
3233 
3234 }
3235 
3236 // Read SDS fields
3237 void read_dds_spfields(DDS &dds,const string& filename,const int sdfd,HDFSP::SDField *spsds, SPType sptype) {
3238 
3239  BESDEBUG("h4","Coming to read_dds_spfields "<<endl);
3240  // Ignore the dimension variable that is empty for non-special handling NASA HDF products
3241  if(OTHERHDF == sptype && (true == spsds->IsDimNoScale()))
3242  return;
3243 
3244  BaseType *bt=NULL;
3245  switch(spsds->getType()) {
3246 
3247 #define HANDLE_CASE(tid, type) \
3248  case tid: \
3249  bt = new (type)(spsds->getNewName(),filename); \
3250  break;
3251  HANDLE_CASE(DFNT_FLOAT32, HDFFloat32);
3252  HANDLE_CASE(DFNT_FLOAT64, HDFFloat64);
3253  HANDLE_CASE(DFNT_CHAR, HDFStr);
3254 #ifndef SIGNED_BYTE_TO_INT32
3255  HANDLE_CASE(DFNT_INT8, HDFByte);
3256  //HANDLE_CASE(DFNT_CHAR, HDFByte);
3257 #else
3258  HANDLE_CASE(DFNT_INT8,HDFInt32);
3259  //HANDLE_CASE(DFNT_CHAR, HDFInt32);
3260 #endif
3261  HANDLE_CASE(DFNT_UINT8, HDFByte);
3262  HANDLE_CASE(DFNT_INT16, HDFInt16);
3263  HANDLE_CASE(DFNT_UINT16, HDFUInt16);
3264  HANDLE_CASE(DFNT_INT32, HDFInt32);
3265  HANDLE_CASE(DFNT_UINT32, HDFUInt32);
3266  HANDLE_CASE(DFNT_UCHAR, HDFByte);
3267  default:
3268  InternalErr(__FILE__,__LINE__,"unsupported data type.");
3269 #undef HANDLE_CASE
3270  }
3271  int fieldtype = spsds->getFieldType();// Whether the field is real field,lat/lon field or missing Z-dimension field
3272 
3273  if(bt)
3274  {
3275 
3276  const vector<HDFSP::Dimension*>& dims= spsds->getCorrectedDimensions();
3277  vector<HDFSP::Dimension*>::const_iterator it_d;
3278 
3279  if(DFNT_CHAR == spsds->getType()) {
3280 
3281  if(1 == spsds->getRank()) {
3282 
3283  HDFCFStr * sca_str = NULL;
3284 
3285  try {
3286 
3287  sca_str = new HDFCFStr(
3288  sdfd,
3289  spsds->getFieldRef(),
3290  filename,
3291  spsds->getName(),
3292  spsds->getNewName(),
3293  false
3294  );
3295  }
3296  catch(...) {
3297  delete bt;
3298  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStr instance.");
3299  }
3300  dds.add_var(sca_str);
3301  delete bt;
3302  delete sca_str;
3303  }
3304  else {
3305  HDFCFStrField *ar = NULL;
3306  try {
3307 
3308  ar = new HDFCFStrField(
3309  spsds->getRank() -1 ,
3310  filename,
3311  false,
3312  sdfd,
3313  spsds->getFieldRef(),
3314  0,
3315  spsds->getName(),
3316  spsds->getNewName(),
3317  bt);
3318 
3319  }
3320  catch(...) {
3321  delete bt;
3322  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStrField instance.");
3323  }
3324 
3325  for(it_d = dims.begin(); it_d != dims.begin()+dims.size()-1; it_d++)
3326  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3327  dds.add_var(ar);
3328  delete bt;
3329  delete ar;
3330  }
3331 
3332  }
3333 
3334  // For non-CV variables and the existing non-lat/lon CV variables
3335  else if(fieldtype == 0 || fieldtype == 3 ) {
3336 
3337  HDFSPArray_RealField *ar = NULL;
3338 
3339  try {
3340  ar = new HDFSPArray_RealField(
3341  spsds->getRank(),
3342  filename,
3343  sdfd,
3344  spsds->getFieldRef(),
3345  spsds->getType(),
3346  sptype,
3347  spsds->getName(),
3348  spsds->getNewName(),
3349  bt);
3350  }
3351  catch(...) {
3352  delete bt;
3353  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFSPArray_RealField instance.");
3354  }
3355 
3356  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
3357  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3358  dds.add_var(ar);
3359  delete bt;
3360  delete ar;
3361  }
3362 
3363  // For latitude and longitude
3364  else if(fieldtype == 1 || fieldtype == 2) {
3365 
3366  if(sptype == MODISARNSS || sptype == TRMML2_V7) {
3367 
3368  HDFSPArray_RealField *ar = NULL;
3369 
3370  try {
3371  ar = new HDFSPArray_RealField(
3372  spsds->getRank(),
3373  filename,
3374  sdfd,
3375  spsds->getFieldRef(),
3376  spsds->getType(),
3377  sptype,
3378  spsds->getName(),
3379  spsds->getNewName(),
3380  bt);
3381  }
3382  catch(...) {
3383  delete bt;
3384  InternalErr(__FILE__,__LINE__,
3385  "Unable to allocate the HDFSPArray_RealField instance.");
3386  }
3387 
3388 
3389  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
3390  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3391  dds.add_var(ar);
3392  delete bt;
3393  delete ar;
3394 
3395  }
3396  else {
3397 
3398  HDFSPArrayGeoField *ar = NULL;
3399 
3400  try {
3401  ar = new HDFSPArrayGeoField(
3402  spsds->getRank(),
3403  filename,
3404  sdfd,
3405  spsds->getFieldRef(),
3406  spsds->getType(),
3407  sptype,
3408  fieldtype,
3409  spsds->getName(),
3410  spsds->getNewName(),
3411  bt);
3412  }
3413  catch(...) {
3414  delete bt;
3415  InternalErr(__FILE__,__LINE__,
3416  "Unable to allocate the HDFSPArray_RealField instance.");
3417  }
3418 
3419  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
3420  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3421  dds.add_var(ar);
3422  delete bt;
3423  delete ar;
3424  }
3425  }
3426 
3427 
3428  else if(fieldtype == 4) { //missing Z dimensional field(or coordinate variables with missing values)
3429  if(spsds->getRank()!=1){
3430  delete bt;
3431  throw InternalErr(__FILE__, __LINE__, "The rank of missing Z dimension field must be 1");
3432  }
3433  int nelem = (spsds->getDimensions()[0])->getSize();
3434 
3436 
3437  try {
3438  ar = new HDFSPArrayMissGeoField(
3439  spsds->getRank(),
3440  nelem,
3441  spsds->getNewName(),
3442  bt);
3443  }
3444  catch(...) {
3445  delete bt;
3446  InternalErr(__FILE__,__LINE__,
3447  "Unable to allocate the HDFSPArrayMissGeoField instance.");
3448  }
3449 
3450 
3451  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
3452  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3453  dds.add_var(ar);
3454  delete bt;
3455  delete ar;
3456  }
3457  // fieldtype =5 originally keeps for time. Still keep it for a while.
3458 
3459  else if(fieldtype == 6) { //Coordinate variables added from the product specification
3460 
3461  if(spsds->getRank()!=1){
3462  delete bt;
3463  throw InternalErr(__FILE__, __LINE__, "The rank of added coordinate variable must be 1");
3464  }
3465  int nelem = (spsds->getDimensions()[0])->getSize();
3466 
3467  HDFSPArrayAddCVField *ar = NULL;
3468  try {
3469  ar = new HDFSPArrayAddCVField(
3470  spsds->getType(),
3471  sptype,
3472  spsds->getName(),
3473  nelem,
3474  spsds->getNewName(),
3475  bt);
3476  }
3477  catch(...) {
3478  delete bt;
3479  InternalErr(__FILE__,__LINE__,
3480  "Unable to allocate the HDFSPArrayAddCVField instance.");
3481  }
3482 
3483 
3484  for(it_d = dims.begin(); it_d != dims.end(); it_d++)
3485  ar->append_dim((*it_d)->getSize(), (*it_d)->getName());
3486  dds.add_var(ar);
3487  delete bt;
3488  delete ar;
3489  }
3490 
3491 
3492  }
3493 
3494 }
3495 
3496 // Read Vdata fields.
3497 void read_dds_spvdfields(DDS &dds,const string & filename, const int fileid,int32 objref,int32 numrec,HDFSP::VDField *spvd) {
3498 
3499  BESDEBUG("h4","Coming to read_dds_spvdfields "<<endl);
3500 
3501  // First map the HDF4 datatype to DAP2
3502  BaseType *bt=NULL;
3503  switch(spvd->getType()) {
3504 #define HANDLE_CASE(tid, type) \
3505  case tid: \
3506  bt = new (type)(spvd->getNewName(),filename); \
3507  break;
3508  HANDLE_CASE(DFNT_FLOAT32, HDFFloat32);
3509  HANDLE_CASE(DFNT_FLOAT64, HDFFloat64);
3510  HANDLE_CASE(DFNT_CHAR8,HDFStr);
3511 #ifndef SIGNED_BYTE_TO_INT32
3512  HANDLE_CASE(DFNT_INT8, HDFByte);
3513 #else
3514  HANDLE_CASE(DFNT_INT8,HDFInt32);
3515 #endif
3516  HANDLE_CASE(DFNT_UINT8, HDFByte);
3517  HANDLE_CASE(DFNT_INT16, HDFInt16);
3518  HANDLE_CASE(DFNT_UINT16, HDFUInt16);
3519  HANDLE_CASE(DFNT_INT32, HDFInt32);
3520  HANDLE_CASE(DFNT_UINT32, HDFUInt32);
3521  HANDLE_CASE(DFNT_UCHAR8, HDFByte);
3522  //HANDLE_CASE(DFNT_CHAR8, HDFByte);
3523  //HANDLE_CASE(DFNT_CHAR8, HDFByte);
3524  default:
3525  InternalErr(__FILE__,__LINE__,"unsupported data type.");
3526 #undef HANDLE_CASE
3527  }
3528 
3529  if(bt)
3530  {
3531 
3532  if(DFNT_CHAR == spvd->getType()) {
3533 
3534  // If the field order is >1, the vdata field will be 2-D array
3535  // with the number of elements along the fastest changing dimension
3536  // as the field order.
3537  int vdrank = ((spvd->getFieldOrder())>1)?2:1;
3538  if (1 == vdrank) {
3539 
3540  HDFCFStr * sca_str = NULL;
3541  try {
3542  sca_str = new HDFCFStr(
3543  fileid,
3544  objref,
3545  filename,
3546  spvd->getName(),
3547  spvd->getNewName(),
3548  true
3549  );
3550  }
3551  catch(...) {
3552  delete bt;
3553  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStr instance.");
3554  }
3555  dds.add_var(sca_str);
3556  delete bt;
3557  delete sca_str;
3558  }
3559 
3560  else {
3561 
3562  HDFCFStrField *ar = NULL;
3563  try {
3564 
3565  ar = new HDFCFStrField(
3566  vdrank -1 ,
3567  filename,
3568  true,
3569  fileid,
3570  objref,
3571  spvd->getFieldOrder(),
3572  spvd->getName(),
3573  spvd->getNewName(),
3574  bt);
3575 
3576  }
3577  catch(...) {
3578  delete bt;
3579  InternalErr(__FILE__,__LINE__,"Unable to allocate the HDFCFStrField instance.");
3580  }
3581 
3582  string dimname0 = "VDFDim0_"+spvd->getNewName();
3583  ar->append_dim(numrec, dimname0);
3584  dds.add_var(ar);
3585  delete bt;
3586  delete ar;
3587 
3588  }
3589  }
3590  else {
3591  HDFSPArray_VDField *ar = NULL;
3592 
3593  // If the field order is >1, the vdata field will be 2-D array
3594  // with the number of elements along the fastest changing dimension
3595  // as the field order.
3596  int vdrank = ((spvd->getFieldOrder())>1)?2:1;
3597  ar = new HDFSPArray_VDField(
3598  vdrank,
3599  filename,
3600  fileid,
3601  objref,
3602  spvd->getType(),
3603  spvd->getFieldOrder(),
3604  spvd->getName(),
3605  spvd->getNewName(),
3606  bt);
3607 
3608  string dimname1 = "VDFDim0_"+spvd->getNewName();
3609 
3610  string dimname2 = "VDFDim1_"+spvd->getNewName();
3611  if(spvd->getFieldOrder() >1) {
3612  ar->append_dim(numrec,dimname1);
3613  ar->append_dim(spvd->getFieldOrder(),dimname2);
3614  }
3615  else
3616  ar->append_dim(numrec,dimname1);
3617 
3618  dds.add_var(ar);
3619  delete bt;
3620  delete ar;
3621  }
3622  }
3623 
3624 }
3625 
3626 // This routine will check if this is a special EOS2 file that we can improve the performance
3627 // Currently AIRS level 2 and 3 version 6 and MOD08_M3-like products are what we can serve. KY 2014-01-29
3628 int check_special_eosfile(const string & filename, string& grid_name,int32 sdfd,int32 fileid ) {
3629 
3630  //int32 sdid = 0;
3631  int32 sds_id = 0;
3632  int32 n_sds = 0;
3633  int32 n_sd_attrs = 0;
3634  bool is_eos = false;
3635  int ret_val = 1;
3636 
3637 #if 0
3638  sdid = SDstart (const_cast < char *>(filename.c_str ()), DFACC_READ);
3639  if (sdid <0)
3640  throw InternalErr(__FILE__, __LINE__, "The SD interface cannot be open.");
3641 #endif
3642 
3643  // Obtain number of SDS objects and number of SD(file) attributes
3644  if (SDfileinfo (sdfd, &n_sds, &n_sd_attrs) == FAIL){
3645  throw InternalErr (__FILE__,__LINE__,"SDfileinfo failed ");
3646  }
3647 
3648  char attr_name[H4_MAX_NC_NAME];
3649  int32 attr_type = -1;
3650  int32 attr_count = -1;
3651  char structmdname[] = "StructMetadata.0";
3652 
3653  // Is this an HDF-EOS2 file?
3654  for (int attr_index = 0; attr_index < n_sd_attrs;attr_index++) {
3655  if(SDattrinfo(sdfd,attr_index,attr_name,&attr_type,&attr_count) == FAIL) {
3656  throw InternalErr (__FILE__,__LINE__,"SDattrinfo failed ");
3657  }
3658 
3659  if(strcmp(attr_name,structmdname)==0) {
3660  is_eos = true;
3661  break;
3662  }
3663  }
3664 
3665  if(true == is_eos) {
3666 
3667  int sds_index = 0;
3668  int32 sds_rank = 0;
3669  int32 dim_sizes[H4_MAX_VAR_DIMS];
3670  int32 sds_dtype = 0;
3671  int32 n_sds_attrs = 0;
3672  char sds_name[H4_MAX_NC_NAME];
3673  char xdim_name[] ="XDim";
3674  char ydim_name[] ="YDim";
3675 
3676  string temp_grid_name1;
3677  string temp_grid_name2;
3678  bool xdim_is_cv_flag = false;
3679  bool ydim_is_cv_flag = false;
3680 
3681 
3682  // The following for-loop checks if this is a MOD08_M3-like HDF-EOS2 product.
3683  for (sds_index = 0; sds_index < (int)n_sds; sds_index++) {
3684 
3685  sds_id = SDselect (sdfd, sds_index);
3686  if (sds_id == FAIL) {
3687  throw InternalErr (__FILE__,__LINE__,"SDselect failed ");
3688  }
3689 
3690  // Obtain object name, rank, size, field type and number of SDS attributes
3691  int status = SDgetinfo (sds_id, sds_name, &sds_rank, dim_sizes,
3692  &sds_dtype, &n_sds_attrs);
3693  if (status == FAIL) {
3694  SDendaccess(sds_id);
3695  throw InternalErr (__FILE__,__LINE__,"SDgetinfo failed ");
3696  }
3697 
3698  if(1 == sds_rank) {
3699 
3700  // This variable "XDim" exists
3701  if(strcmp(sds_name,xdim_name) == 0) {
3702  int32 sds_dimid = SDgetdimid(sds_id,0);
3703  if(sds_dimid == FAIL) {
3704  SDendaccess(sds_id);
3705  throw InternalErr (__FILE__,__LINE__,"SDgetinfo failed ");
3706  }
3707  char dim_name[H4_MAX_NC_NAME];
3708  int32 dim_size = 0;
3709  int32 dim_type = 0;
3710  int32 num_dim_attrs = 0;
3711  if(SDdiminfo(sds_dimid,dim_name,&dim_size,&dim_type,&num_dim_attrs) == FAIL) {
3712  SDendaccess(sds_id);
3713  throw InternalErr(__FILE__,__LINE__,"SDdiminfo failed ");
3714  }
3715 
3716  // No dimension scale and XDim exists
3717  if(0 == dim_type) {
3718  string tempdimname(dim_name);
3719  if(tempdimname.size() >=5) {
3720  if(tempdimname.compare(0,5,"XDim:") == 0) {
3721 
3722  // Obtain the grid name.
3723  temp_grid_name1 = tempdimname.substr(5);
3724  xdim_is_cv_flag = true;
3725 
3726  }
3727  }
3728  else if("XDim" == tempdimname)
3729  xdim_is_cv_flag = true;
3730  }
3731  }
3732 
3733  // The variable "YDim" exists
3734  if(strcmp(sds_name,ydim_name) == 0) {
3735 
3736  int32 sds_dimid = SDgetdimid(sds_id,0);
3737  if(sds_dimid == FAIL) {
3738  SDendaccess (sds_id);
3739  throw InternalErr (__FILE__,__LINE__,"SDgetinfo failed ");
3740  }
3741  char dim_name[H4_MAX_NC_NAME];
3742  int32 dim_size = 0;
3743  int32 dim_type = 0;
3744  int32 num_dim_attrs = 0;
3745  if(SDdiminfo(sds_dimid,dim_name,&dim_size,&dim_type,&num_dim_attrs) == FAIL) {
3746  SDendaccess(sds_id);
3747  throw InternalErr(__FILE__,__LINE__,"SDdiminfo failed ");
3748  }
3749 
3750  // For this case, the dimension should not have dimension scales.
3751  if(0 == dim_type) {
3752  string tempdimname(dim_name);
3753  if(tempdimname.size() >=5) {
3754  if(tempdimname.compare(0,5,"YDim:") == 0) {
3755  // Obtain the grid name.
3756  temp_grid_name2 = tempdimname.substr(5);
3757  ydim_is_cv_flag = true;
3758  }
3759  }
3760  else if ("YDim" == tempdimname)
3761  ydim_is_cv_flag = true;
3762  }
3763  }
3764  }
3765 
3766  SDendaccess(sds_id);
3767  if((true == xdim_is_cv_flag) && (true == ydim_is_cv_flag ))
3768  break;
3769 
3770  }
3771 
3772  // If one-grid and variable XDim/YDim exist and also they don't have dim. scales,we treat this as MOD08-M3-like products
3773  if ((temp_grid_name1 == temp_grid_name2) && (true == xdim_is_cv_flag) && (true == ydim_is_cv_flag)) {
3774  grid_name = temp_grid_name1;
3775  ret_val = 2;
3776  }
3777 
3778  // Check if this is a new AIRS level 2 and 3 product. Since new AIRS level 2 and 3 version 6 products still have dimensions that don't have
3779  // dimension scales and the old way to handle level 2 and 3 dimensions makes the performance suffer. We will see if we can improve
3780  // performance by handling the data with just the HDF4 interfaces.
3781  // At least the file name should have string AIRS.L3. or AIRS.L2..
3782  else if((basename(filename).size() >8) && (basename(filename).compare(0,4,"AIRS") == 0)
3783  && ((basename(filename).find(".L3.")!=string::npos) || (basename(filename).find(".L2.")!=string::npos))){
3784 
3785  bool has_dimscale = false;
3786 
3787  // Go through the SDS object and check if this file has dimension scales.
3788  for (sds_index = 0; sds_index < n_sds; sds_index++) {
3789 
3790  sds_id = SDselect (sdfd, sds_index);
3791  if (sds_id == FAIL) {
3792  throw InternalErr (__FILE__,__LINE__,"SDselect failed ");
3793  }
3794 
3795  // Obtain object name, rank, size, field type and number of SDS attributes
3796  int status = SDgetinfo (sds_id, sds_name, &sds_rank, dim_sizes,
3797  &sds_dtype, &n_sds_attrs);
3798  if (status == FAIL) {
3799  SDendaccess(sds_id);
3800  throw InternalErr (__FILE__,__LINE__,"SDgetinfo failed ");
3801  }
3802 
3803  for (int dim_index = 0; dim_index<sds_rank; dim_index++) {
3804 
3805  int32 sds_dimid = SDgetdimid(sds_id,dim_index);
3806  if(sds_dimid == FAIL) {
3807  SDendaccess(sds_id);
3808  throw InternalErr (__FILE__,__LINE__,"SDgetinfo failed ");
3809  }
3810 
3811  char dim_name[H4_MAX_NC_NAME];
3812  int32 dim_size = 0;
3813  int32 dim_type = 0;
3814  int32 num_dim_attrs = 0;
3815  if(SDdiminfo(sds_dimid,dim_name,&dim_size,&dim_type,&num_dim_attrs) == FAIL) {
3816  SDendaccess(sds_id);
3817  throw InternalErr(__FILE__,__LINE__,"SDdiminfo failed ");
3818  }
3819 
3820  if(dim_type !=0) {
3821  has_dimscale = true;
3822  break;
3823  }
3824 
3825  }
3826  SDendaccess(sds_id);
3827  if( true == has_dimscale)
3828  break;
3829  }
3830 
3831  // If having dimension scales, this is an AIRS level 2 or 3 version 6. Treat it differently. Otherwise, this is an old AIRS level 3 product.
3832  if (true == has_dimscale)
3833  ret_val = 3;
3834  }
3835  else {// Check if this is an HDF-EOS2 file but not using HDF-EOS2 at all.
3836  // We turn off this for the time being because
3837  // 1) We need to make sure this is a grid file not swath or point file.
3838  // It will be time consuming to identify grids or swaths and hurts the performance for general case.
3839  // 2) No real NASA files exist. We will handle them later.
3840  // KY 2014-01-29
3841  ;
3842 #if 0
3843  bool has_dimscale = true;
3844  bool is_grid = false;
3845 
3846  // Go through the SDS object
3847  for (sds_index = 0; sds_index < n_sds; sds_index++) {
3848 
3849  sds_id = SDselect (sdid, sds_index);
3850  if (sds_id == FAIL) {
3851  SDend(sdid);
3852  throw InternalErr (__FILE__,__LINE__,"SDselect failed ");
3853  }
3854 
3855  // Obtain object name, rank, size, field type and number of SDS attributes
3856  int status = SDgetinfo (sds_id, sds_name, &sds_rank, dim_sizes,
3857  &sds_dtype, &n_sds_attrs);
3858  if (status == FAIL) {
3859  SDendaccess(sds_id);
3860  SDend(sdid);
3861  throw InternalErr (__FILE__,__LINE__,"SDgetinfo failed ");
3862  }
3863 
3864 
3865  for (int dim_index = 0; dim_index<sds_rank; dim_index++) {
3866 
3867  int32 sds_dimid = SDgetdimid(sds_id,dim_index);
3868  if(sds_dimid == FAIL) {
3869  SDendaccess(sds_id);
3870  SDend(sdid);
3871  throw InternalErr (__FILE__,__LINE__,"SDgetinfo failed ");
3872  }
3873  char dim_name[H4_MAX_NC_NAME];
3874  int32 dim_size = 0;
3875  int32 dim_type = 0;
3876  int32 num_dim_attrs = 0;
3877  if(SDdiminfo(sds_dimid,dim_name,&dim_size,&dim_type,&num_dim_attrs) == FAIL) {
3878  SDendaccess(sds_id);
3879  SDend(sdid);
3880  throw InternalErr(__FILE__,__LINE__,"SDdiminfo failed ");
3881  }
3882 
3883  if(0 == dim_type) {
3884  has_dimscale = false;
3885  }
3886 
3887  }
3888  SDendaccess(sds_id);
3889  }
3890  if (true == has_dimscale)
3891  ret_val = 4;
3892 #endif
3893  }
3894  }
3895 
3896  return ret_val;
3897 }
3898 
3899 // Default option
3900 void read_dds(DDS & dds, const string & filename)
3901 {
3902  // generate DDS, DAS
3903  DAS das;
3904  dds.set_dataset_name(basename(filename));
3905  build_descriptions(dds, das, filename);
3906 
3907  if (!dds.check_semantics()) { // DDS didn't get built right
3909  }
3910  return;
3911 }
3912 
3913 void read_das(DAS & das, const string & filename)
3914 {
3915  // generate DDS, DAS
3916  DDS dds(NULL);
3917  dds.set_dataset_name(basename(filename));
3918 
3919  build_descriptions(dds, das, filename);
3920 
3921  if (!dds.check_semantics()) { // DDS didn't get built right
3922  dds.print(cout);
3924  }
3925  return;
3926 }
3927 
3928 // Scan the HDF file and build the DDS and DAS
3929 static void build_descriptions(DDS & dds, DAS & das,
3930  const string & filename)
3931 {
3932  sds_map sdsmap;
3933  vd_map vdatamap;
3934  gr_map grmap;
3935 
3936  // Build descriptions of SDS items
3937  // If CF option is enabled, StructMetadata will be parsed here.
3938  SDS_descriptions(sdsmap, das, filename);
3939 
3940  // Build descriptions of file annotations
3941  FileAnnot_descriptions(das, filename);
3942 
3943  // Build descriptions of Vdatas
3944  Vdata_descriptions(vdatamap, das, filename);
3945 
3946  // Build descriptions of General Rasters
3947  GR_descriptions(grmap, das, filename);
3948 
3949  // Build descriptions of Vgroups and add SDS/Vdata/GR in the correct order
3950  Vgroup_descriptions(dds, das, filename, sdsmap, vdatamap, grmap);
3951  return;
3952 }
3953 
3954 // These two Functor classes are used to look for EOS attributes with certain
3955 // base names (is_named) and to accumulate values in in different hdf_attr
3956 // objects with the same base names (accum_attr). These are used by
3957 // merge_split_eos_attributes() to do just that. Some HDF EOS attributes are
3958 // longer than HDF 4's 32,000 character limit. Those attributes are split up
3959 // in the HDF 4 files and named `StructMetadata.0', `StructMetadata.1', et
3960 // cetera. This code merges those attributes so that they can be processed
3961 // correctly by the hdf eos attribute parser (see AddHDFAttr() further down
3962 // in this file). 10/29/2001 jhrg
3963 
3964 struct accum_attr
3965  :public binary_function < hdf_genvec &, hdf_attr, hdf_genvec & > {
3966 
3967  string d_named;
3968 
3969  accum_attr(const string & named):d_named(named) {
3970  }
3971 
3972  hdf_genvec & operator() (hdf_genvec & accum, const hdf_attr & attr) {
3973  // Assume that all fields with the same base name should be combined,
3974  // and assume that they are in order.
3975  BESDEBUG("h4", "attr.name: " << attr.name << endl);
3976  if (attr.name.find(d_named) != string::npos) {
3977 #if 0
3978  string stuff;
3979  stuff.assign(attr.values.data(), attr.values.size());
3980  cerr << "Attribute chunk: " << attr.name << endl;
3981  cerr << stuff << endl;
3982 #endif
3983  accum.append(attr.values.number_type(), attr.values.data(),
3984  attr.values.size());
3985  return accum;
3986  }
3987  else {
3988  return accum;
3989  }
3990  }
3991 };
3992 
3993 struct is_named:public unary_function < hdf_attr, bool > {
3994  string d_named;
3995 
3996  is_named(const string & named):d_named(named) {
3997  }
3998 
3999  bool operator() (const hdf_attr & attr) {
4000  return (attr.name.find(d_named) != string::npos);
4001  }
4002 };
4003 
4004 static void
4005 merge_split_eos_attributes(vector < hdf_attr > &attr_vec,
4006  const string & attr_name)
4007 {
4008  // Only do this if there's more than one part.
4009  if (count_if(attr_vec.begin(), attr_vec.end(), is_named(attr_name)) > 1) {
4010  // Merge all split up parts named `attr_name.' Assume they are in
4011  // order in `attr_vec.'
4012  hdf_genvec attributes;
4013  attributes = accumulate(attr_vec.begin(), attr_vec.end(),
4014  attributes, accum_attr(attr_name));
4015 
4016  // When things go south, check out the hdf_genvec...
4017  // BEDEBUG seems not providing a way to handle the following debugging info.
4018  // I can define a vector and call attributes.print(s_m), then use
4019  // BESDEBUG to output the debugging info. The downside is that whether BESDEBUG
4020  // is called, a vector of s_m will always be generated and a chunk of memory is
4021  // always used. So don't change this for the time being. KY 2012-09-13
4022  DBG(vector < string > s_m;
4023  attributes.print(s_m);
4024  cerr << "Accum struct MD: (" << s_m.size() << ") "
4025  << s_m[0] << endl);
4026 
4027  // Remove all the parts that have been merged
4028  attr_vec.erase(remove_if(attr_vec.begin(), attr_vec.end(),
4029  is_named(attr_name)), attr_vec.end());
4030 
4031  // Make a new hdf_attr and assign it the newly merged attributes...
4032  hdf_attr merged_attr;
4033  merged_attr.name = attr_name;
4034  merged_attr.values = attributes;
4035 
4036  // And add it to the vector of attributes.
4037  attr_vec.push_back(merged_attr);
4038  }
4039 }
4040 
4041 // Read SDS's out of filename, build descriptions and put them into dds, das.
4042 static void SDS_descriptions(sds_map & map, DAS & das,
4043  const string & filename)
4044 {
4045 
4046  hdfistream_sds sdsin(filename);
4047  sdsin.setmeta(true);
4048 
4049  // Read SDS file attributes attr_iter i = ;
4050 
4051  vector < hdf_attr > fileattrs;
4052  sdsin >> fileattrs;
4053 
4054  // Read SDS's
4055  sdsin.rewind();
4056  while (!sdsin.eos()) {
4057  sds_info sdi; // add the next sds_info to map
4058  sdsin >> sdi.sds;
4059  sdi.in_vgroup = false; // assume we're not part of a vgroup
4060  map[sdi.sds.ref] = sdi; // assign to map by ref
4061  }
4062 
4063  sdsin.close();
4064 
4065  // This is the call to combine SDS attributes that have been split up
4066  // into N 32,000 character strings. 10/24/2001 jhrg
4067  merge_split_eos_attributes(fileattrs, "StructMetadata");
4068  merge_split_eos_attributes(fileattrs, "CoreMetadata");
4069  merge_split_eos_attributes(fileattrs, "ProductMetadata");
4070  merge_split_eos_attributes(fileattrs, "ArchiveMetadata");
4071  merge_split_eos_attributes(fileattrs, "coremetadata");
4072  merge_split_eos_attributes(fileattrs, "productmetadata");
4073 
4074  // Build DAS, add SDS file attributes
4075  AddHDFAttr(das, string("HDF_GLOBAL"), fileattrs);
4076  // add each SDS's attrs
4077  vector < hdf_attr > dattrs;
4078 
4079  // TODO Remove these attributes (name and dimension)? jhrg 8/17/11
4080  // ***
4081  for (SDSI s = map.begin(); s != map.end(); ++s) {
4082  const hdf_sds *sds = &s->second.sds;
4083  AddHDFAttr(das, sds->name, sds->attrs);
4084  for (int k = 0; k < (int) sds->dims.size(); ++k) {
4085  dattrs = Dims2Attrs(sds->dims[k]);
4086  AddHDFAttr(das, sds->name + "_dim_" + num2string(k), dattrs);
4087  }
4088 
4089  }
4090 
4091  return;
4092 }
4093 
4094 // Read Vdata's out of filename, build descriptions and put them into dds.
4095 static void Vdata_descriptions(vd_map & map, DAS & das,
4096  const string & filename)
4097 {
4098  hdfistream_vdata vdin(filename);
4099  vdin.setmeta(true);
4100 
4101  // Read Vdata's
4102  while (!vdin.eos()) {
4103  vd_info vdi; // add the next vd_info to map
4104  vdin >> vdi.vdata;
4105  vdi.in_vgroup = false; // assume we're not part of a vgroup
4106  map[vdi.vdata.ref] = vdi; // assign to map by ref
4107  }
4108  vdin.close();
4109 
4110  // Build DAS
4111  vector < hdf_attr > dattrs;
4112  for (VDI s = map.begin(); s != map.end(); ++s) {
4113  const hdf_vdata *vd = &s->second.vdata;
4114  AddHDFAttr(das, vd->name, vd->attrs);
4115  }
4116 
4117  return;
4118 }
4119 
4120 // Read Vgroup's out of filename, build descriptions and put them into dds.
4121 static void Vgroup_descriptions(DDS & dds, DAS & das,
4122  const string & filename, sds_map & sdmap,
4123  vd_map & vdmap, gr_map & grmap)
4124 {
4125 
4126  hdfistream_vgroup vgin(filename);
4127 
4128  // Read Vgroup's
4129  vg_map vgmap;
4130  while (!vgin.eos()) {
4131  vg_info vgi; // add the next vg_info to map
4132  vgin >> vgi.vgroup; // read vgroup itself
4133  vgi.toplevel = true; // assume toplevel until we prove otherwise
4134  vgmap[vgi.vgroup.ref] = vgi; // assign to map by vgroup ref
4135  }
4136  vgin.close();
4137  // for each Vgroup
4138  for (VGI v = vgmap.begin(); v != vgmap.end(); ++v) {
4139  const hdf_vgroup *vg = &v->second.vgroup;
4140 
4141  // Add Vgroup attributes
4142  AddHDFAttr(das, vg->name, vg->attrs);
4143 
4144  // now, assign children
4145  for (uint32 i = 0; i < vg->tags.size(); i++) {
4146  int32 tag = vg->tags[i];
4147  int32 ref = vg->refs[i];
4148  switch (tag) {
4149  case DFTAG_VG:
4150  // Could be a GRI or a Vgroup
4151  if (grmap.find(ref) != grmap.end())
4152  grmap[ref].in_vgroup = true;
4153  else
4154  vgmap[ref].toplevel = false;
4155  break;
4156  case DFTAG_VH:
4157  vdmap[ref].in_vgroup = true;
4158  break;
4159  case DFTAG_NDG:
4160  sdmap[ref].in_vgroup = true;
4161  break;
4162  default:
4163  (*BESLog::TheLog()) << "unknown tag: " << tag << " ref: " << ref << endl;
4164  // TODO: Make this an exception? jhrg 8/19/11
4165  // Don't make an exception. Possibly you will meet other valid tags. Need to know if it
4166  // is worth to tackle this. KY 09/13/12
4167  // cerr << "unknown tag: " << tag << " ref: " << ref << endl;
4168  break;
4169  }// switch (tag)
4170  } // for (uint32 i = 0; i < vg->tags.size(); i++)
4171  } // for (VGI v = vgmap.begin(); v != vgmap.end(); ++v)
4172  // Build DDS for all toplevel vgroups
4173  BaseType *pbt = 0;
4174  for (VGI v = vgmap.begin(); v != vgmap.end(); ++v) {
4175  if (!v->second.toplevel)
4176  continue; // skip over non-toplevel vgroups
4177  pbt = NewStructureFromVgroup(v->second.vgroup,
4178  vgmap, sdmap, vdmap,
4179  grmap, filename);
4180  if (pbt != 0) {
4181  dds.add_var(pbt);
4182  delete pbt;
4183  }
4184 
4185  } // for (VGI v = vgmap.begin(); v != vgmap.end(); ++v)
4186 
4187  // add lone SDS's
4188  for (SDSI s = sdmap.begin(); s != sdmap.end(); ++s) {
4189  if (s->second.in_vgroup)
4190  continue; // skip over SDS's in vgroups
4191  if (s->second.sds.has_scale()) // make a grid
4192  pbt = NewGridFromSDS(s->second.sds, filename);
4193  else
4194  pbt = NewArrayFromSDS(s->second.sds, filename);
4195  if (pbt != 0) {
4196  dds.add_var(pbt);
4197  delete pbt;
4198  }
4199  }
4200 
4201  // add lone Vdata's
4202  for (VDI v = vdmap.begin(); v != vdmap.end(); ++v) {
4203  if (v->second.in_vgroup)
4204  continue; // skip over Vdata in vgroups
4205  pbt = NewSequenceFromVdata(v->second.vdata, filename);
4206  if (pbt != 0) {
4207  dds.add_var(pbt);
4208  delete pbt;
4209  }
4210  }
4211  // add lone GR's
4212  for (GRI g = grmap.begin(); g != grmap.end(); ++g) {
4213  if (g->second.in_vgroup)
4214  continue; // skip over GRs in vgroups
4215  pbt = NewArrayFromGR(g->second.gri, filename);
4216  if (pbt != 0) {
4217  dds.add_var(pbt);
4218  delete pbt ;
4219  }
4220  }
4221 }
4222 
4223 static void GR_descriptions(gr_map & map, DAS & das,
4224  const string & filename)
4225 {
4226 
4227  hdfistream_gri grin(filename);
4228  grin.setmeta(true);
4229 
4230  // Read GR file attributes
4231  vector < hdf_attr > fileattrs;
4232  grin >> fileattrs;
4233 
4234  // Read general rasters
4235  grin.rewind();
4236  while (!grin.eos()) {
4237  gr_info gri; // add the next gr_info to map
4238  grin >> gri.gri;
4239  gri.in_vgroup = false; // assume we're not part of a vgroup
4240  map[gri.gri.ref] = gri; // assign to map by ref
4241  }
4242 
4243  grin.close();
4244 
4245  // Build DAS
4246  AddHDFAttr(das, string("HDF_GLOBAL"), fileattrs); // add GR file attributes
4247 
4248  // add each GR's attrs
4249  vector < hdf_attr > pattrs;
4250  for (GRI g = map.begin(); g != map.end(); ++g) {
4251  const hdf_gri *gri = &g->second.gri;
4252  // add GR attributes
4253  AddHDFAttr(das, gri->name, gri->attrs);
4254 
4255  // add palettes as attributes
4256  pattrs = Pals2Attrs(gri->palettes);
4257  AddHDFAttr(das, gri->name, pattrs);
4258 
4259  }
4260 
4261  return;
4262 }
4263 
4264 // Read file annotations out of filename, put in attribute structure
4265 static void FileAnnot_descriptions(DAS & das, const string & filename)
4266 {
4267 
4268  hdfistream_annot annotin(filename);
4269  vector < string > fileannots;
4270 
4271  annotin >> fileannots;
4272  AddHDFAttr(das, string("HDF_GLOBAL"), fileannots);
4273 
4274  annotin.close();
4275  return;
4276 }
4277 
4278 // add a vector of hdf_attr to a DAS
4279 void AddHDFAttr(DAS & das, const string & varname,
4280  const vector < hdf_attr > &hav)
4281 {
4282  if (hav.size() == 0) // nothing to add
4283  return;
4284  // get pointer to the AttrTable for the variable varname (create one if
4285  // necessary)
4286  string tempname = varname;
4287  AttrTable *atp = das.get_table(tempname);
4288  if (atp == 0) {
4289  atp = new AttrTable;
4290  atp = das.add_table(tempname, atp);
4291  }
4292  // add the attributes to the DAS
4293  vector < string > attv; // vector of attribute strings
4294  string attrtype; // name of type of attribute
4295  for (int i = 0; i < (int) hav.size(); ++i) { // for each attribute
4296 
4297  attrtype = DAPTypeName(hav[i].values.number_type());
4298  // get a vector of strings representing the values of the attribute
4299  attv = vector < string > (); // clear attv
4300  hav[i].values.print(attv);
4301 
4302  // add the attribute and its values to the DAS
4303  for (int j = 0; j < (int) attv.size(); ++j) {
4304  // handle HDF-EOS metadata with separate parser
4305  string container_name = hav[i].name;
4306  if (container_name.find("StructMetadata") == 0
4307  || container_name.find("CoreMetadata") == 0
4308  || container_name.find("ProductMetadata") == 0
4309  || container_name.find("ArchiveMetadata") == 0
4310  || container_name.find("coremetadata") == 0
4311  || container_name.find("productmetadata") == 0) {
4312  string::size_type dotzero = container_name.find('.');
4313  if (dotzero != container_name.npos)
4314  container_name.erase(dotzero); // erase .0
4315 
4316 
4317  AttrTable *at = das.get_table(container_name);
4318  if (!at)
4319  at = das.add_table(container_name, new AttrTable);
4320 
4321  // tell lexer to scan attribute string
4322  void *buf = hdfeos_string(attv[j].c_str());
4323 
4324  // cerr << "About to print attributes to be parsed..." << endl;
4325  // TODO: remove when done!
4326  // cerr << "attv[" << j << "]" << endl << attv[j].c_str() << endl;
4327 
4328  parser_arg arg(at);
4329  // HDF-EOS attribute parsing is complex and some errors are
4330  // tolerated. Thus, if the parser proper returns an error,
4331  // that results in an exception that is fatal. However, if
4332  // the status returned by an otherwise successful parse shows
4333  // an error was encountered but successful parsing continued,
4334  // that's OK, but it should be logged.
4335  //
4336  // Also, HDF-EOS files should be read using the new HDF-EOS
4337  // features and not this older parser. jhrg 8/18/11
4338  //
4339  // TODO: How to log (as opposed to using BESDEBUG)?
4340  if (hdfeosparse(&arg) != 0){
4341  hdfeos_delete_buffer(buf);
4342  throw Error("HDF-EOS parse error while processing a " + container_name + " HDFEOS attribute.");
4343  }
4344 
4345  // We don't use the parse_error for this case since it generates memory leaking. KY 2014-02-25
4346  if (arg.status() == false) {
4347  (*BESLog::TheLog())<< "HDF-EOS parse error while processing a "
4348  << container_name << " HDFEOS attribute. (2)" << endl;
4349  //<< arg.error()->get_error_message() << endl;
4350  }
4351 
4352  hdfeos_delete_buffer(buf);
4353  }
4354  else {
4355  if (attrtype == "String")
4356 #ifdef ATTR_STRING_QUOTE_FIX
4357  attv[j] = escattr(attv[j]);
4358 #else
4359  attv[j] = "\"" + escattr(attv[j]) + "\"";
4360 #endif
4361 
4362  if (atp->append_attr(hav[i].name, attrtype, attv[j]) == 0)
4364  }
4365  }
4366  }
4367 
4368  return;
4369 }
4370 
4371 // add a vector of annotations to a DAS. They are stored as attributes. They
4372 // are encoded as string values of an attribute named "HDF_ANNOT".
4373 void AddHDFAttr(DAS & das, const string & varname,
4374  const vector < string > &anv)
4375 {
4376  if (anv.size() == 0) // nothing to add
4377  return;
4378 
4379  // get pointer to the AttrTable for the variable varname (create one if
4380  // necessary)
4381  AttrTable *atp = das.get_table(varname);
4382  if (atp == 0) {
4383  atp = new AttrTable;
4384  atp = das.add_table(varname, atp);
4385  }
4386  // add the annotations to the DAS
4387  string an;
4388  for (int i = 0; i < (int) anv.size(); ++i) { // for each annotation
4389 #ifdef ATTR_STRING_QUOTE_FIX
4390  an = escattr(anv[i]); // quote strings
4391 #else
4392  an = "\"" + escattr(anv[i]) + "\""; // quote strings
4393 #endif
4394  if (atp->append_attr(string("HDF_ANNOT"), "String", an) == 0)
4396  }
4397 
4398  return;
4399 }
4400 
4401 // Add a vector of palettes as attributes to a GR. Each palette is added as
4402 // two attributes: the first contains the palette data; the second contains
4403 // the number of components in the palette.
4404 static vector < hdf_attr > Pals2Attrs(const vector < hdf_palette > palv)
4405 {
4406  vector < hdf_attr > pattrs;
4407 
4408  if (palv.size() != 0) {
4409  // for each palette create an attribute with the palette inside, and an
4410  // attribute containing the number of components
4411  hdf_attr pattr;
4412  string palname;
4413  for (int i = 0; i < (int) palv.size(); ++i) {
4414  palname = "hdf_palette_" + num2string(i);
4415  pattr.name = palname;
4416  pattr.values = palv[i].table;
4417  pattrs.push_back(pattr);
4418  pattr.name = palname + "_ncomps";
4419  pattr.values = hdf_genvec(DFNT_INT32,
4420  const_cast <
4421  int32 * >(&palv[i].ncomp), 1);
4422  pattrs.push_back(pattr);
4423  if (palv[i].name.length() != 0) {
4424  pattr.name = palname + "_name";
4425  pattr.values = hdf_genvec(DFNT_CHAR,
4426  const_cast <
4427  char *>(palv[i].name.c_str()),
4428  palv[i].name.length());
4429  pattrs.push_back(pattr);
4430  }
4431  }
4432  }
4433  return pattrs;
4434 }
4435 
4436 // Convert the meta information in a hdf_dim into a vector of
4437 // hdf_attr.
4438 static vector < hdf_attr > Dims2Attrs(const hdf_dim dim)
4439 {
4440  vector < hdf_attr > dattrs;
4441  hdf_attr dattr;
4442  if (dim.name.length() != 0) {
4443  dattr.name = "name";
4444  dattr.values =
4445  hdf_genvec(DFNT_CHAR, const_cast < char *>(dim.name.c_str()),
4446  dim.name.length());
4447  dattrs.push_back(dattr);
4448  }
4449  if (dim.label.length() != 0) {
4450  dattr.name = "long_name";
4451  dattr.values =
4452  hdf_genvec(DFNT_CHAR, const_cast < char *>(dim.label.c_str()),
4453  dim.label.length());
4454  dattrs.push_back(dattr);
4455  }
4456  if (dim.unit.length() != 0) {
4457  dattr.name = "units";
4458  dattr.values =
4459  hdf_genvec(DFNT_CHAR, const_cast < char *>(dim.unit.c_str()),
4460  dim.unit.length());
4461  dattrs.push_back(dattr);
4462  }
4463  if (dim.format.length() != 0) {
4464  dattr.name = "format";
4465  dattr.values =
4466  hdf_genvec(DFNT_CHAR, const_cast < char *>(dim.format.c_str()),
4467  dim.format.length());
4468  dattrs.push_back(dattr);
4469  }
4470  return dattrs;
4471 }
4472 
SOType
const std::vector< VDATA * > & getVDATAs() const
Public interface to Obtain Vdata.
Definition: HDFSP.h:778
HDFArray * NewArrayFromGR(const hdf_gri &gr, const string &dataset)
Definition: hc2dap.cc:272
bool read_dds_special_1d_grid(DDS &dds, HDFSP::File *spf, const string &filename, int32 sdfd, int32 fileid)
Definition: hdfdesc.cc:3074
bool read_das_special_eos2(DAS &das, const string &filename, int32 sdid, int32 fileid, bool ecs_metadata, HDFSP::File **h4filepptr)
Definition: hdfdesc.cc:2755
static void add_missing_cf_attrs(HDFSP::File *f, libdap::DAS &das)
Definition: HDFCFUtil.cc:1671
void read_dds(DDS &dds, const string &filename)
Definition: hdfdesc.cc:3900
void Handle_AIRS_L23()
Definition: HDFSP.cc:969
int32 getRank() const
Get the dimension rank of this field.
Definition: HDFSP.h:302
vector< hdf_attr > attrs
Definition: hdfclass.h:188
hdf_sds sds
Definition: hdf-maps.h:46
void change_das_mod08_scale_offset(DAS &das, HDFSP::File *spf)
Definition: hdfdesc.cc:2995
std::vector< std::string > ctype_field_namelist
vector< hdf_dim > dims
Definition: hdfclass.h:186
bool read_das_hdfhybrid(DAS &das, const string &filename, int32 sdfd, int32 fileid, HDFSP::File **h4filepptr)
bool read_dds_hdfhybrid(DDS &dds, const string &filename, int32 sdfd, int32 fileid, HDFSP::File *h4file)
map< int32, vd_info, less< int32 > > vd_map
Definition: hdf-maps.h:66
bool open(const string &filename, const int sd_id, const int file_id)
openes HDF4 file.
Definition: HE2CF.cc:1068
string basename(const string &path)
Definition: dodsutil.h:133
HDFGrid * NewGridFromSDS(const hdf_sds &sds, const string &dataset)
Definition: hc2dap.cc:304
bool write_attribute_FillValue(const string &varname, int type, float val)
writes _FillValue attribute into varname attribute table.
Definition: HE2CF.cc:1151
const std::vector< Dimension * > & getDimensions() const
Get the list of dimensions.
Definition: HDFSP.h:411
A class for writing attributes from an HDF-EOS2 file.
Definition: HE2CF.h:57
static void check_obpg_global_attrs(HDFSP::File *f, std::string &scaling, float &slope, bool &global_slope_flag, float &intercept, bool &global_intercept_flag)
Definition: HDFCFUtil.cc:1384
const char * data(void) const
Definition: hdfclass.h:86
This class retrieves all information from an HDF4 file. It is a container for SDS and Vdata...
Definition: HDFSP.h:727
const std::string & getNewName() const
Get the CF name(special characters replaced by underscores) of this field.
Definition: HDFSP.h:296
void read_das(DAS &das, const string &filename)
Definition: hdfdesc.cc:3913
map< int32, sds_info, less< int32 > >::const_iterator SDSI
Definition: hdf-maps.h:70
STL namespace.
bool read_dds_hdfsp(DDS &dds, const string &filename, int32 sdfd, int32 fileid, HDFSP::File *h4file)
Definition: hdfdesc.cc:2158
This class retrieves all SDS objects and SD file attributes.
Definition: HDFSP.h:556
#define HANDLE_CASE(tid, type)
static void handle_otherhdf_special_attrs(HDFSP::File *f, libdap::DAS &das)
Definition: HDFCFUtil.cc:1577
int check_special_eosfile(const string &filename, string &grid_name, int32 sdfd, int32 fileid)
Definition: hdfdesc.cc:3628
void read_dds_spfields(DDS &dds, const string &filename, const int sdfd, HDFSP::SDField *spsds, SPType sptype)
Definition: hdfdesc.cc:3237
int size(void) const
Definition: hdfclass.h:84
bool toplevel
Definition: hdf-maps.h:62
void * hdfeos_string(const char *yy_str)
Definition: lex.hdfeos.cc:2033
bool set_non_ecsmetadata_attrs()
Definition: HE2CF.cc:337
HDFSequence * NewSequenceFromVdata(const hdf_vdata &vd, const string &dataset)
Definition: hc2dap.cc:120
bool in_vgroup
Definition: hdf-maps.h:57
One instance of this class represents one Vdata field.
Definition: HDFSP.h:500
string name
Definition: hdfclass.h:185
string DAPTypeName(int32 hdf_type)
Definition: hc2dap.cc:399
map< int32, gr_info, less< int32 > > gr_map
Definition: hdf-maps.h:67
bool IsDimNoScale() const
Is this field a dimension without dimension scale(or empty[no data]dimension variable) ...
Definition: HDFSP.h:424
SD * getSD() const
Public interface to Obtain SD.
Definition: HDFSP.h:772
string name
Definition: hdfclass.h:246
static void handle_merra_ceres_attrs_with_bes_keys(HDFSP::File *f, libdap::DAS &das, const std::string &filename)
Definition: HDFCFUtil.cc:2246
map< int32, vd_info, less< int32 > >::const_iterator VDI
Definition: hdf-maps.h:71
vector< hdf_palette > palettes
Definition: hdfclass.h:247
static void handle_vdata_attrs_with_desc_key(HDFSP::File *f, libdap::DAS &das)
Definition: HDFCFUtil.cc:2295
hdf_vdata vdata
Definition: hdf-maps.h:51
static void correct_fvalue_type(libdap::AttrTable *at, int32 dtype)
CF requires the _FillValue attribute datatype is the same as the corresponding field datatype...
Definition: HDFCFUtil.cc:395
int32 getFieldOrder() const
Get the order of this field.
Definition: HDFSP.h:511
const int getFieldType() const
Definition: HDFSP.h:399
bool write_attribute_units(const string &varname, string units)
writes units attribute into varname attribute table.
Definition: HE2CF.cc:1243
int32 number_type(void) const
Definition: hdfclass.h:82
#define NULL
Definition: wcsUtil.h:65
string name
Definition: hdfclass.h:151
One instance of this class represents one SDS object.
Definition: HDFSP.h:344
HDFArray * NewArrayFromSDS(const hdf_sds &sds, const string &dataset)
Definition: hc2dap.cc:242
bool Check_update_special(const std::string &gridname)
Definition: HDFSP.cc:825
void Prepare()
The main step to make HDF4 SDS objects CF-complaint. All dimension(coordinate variables) information ...
Definition: HDFSP.cc:3974
int32 ref
Definition: hdfclass.h:184
static std::string print_type(int32)
Print datatype in string.
Definition: HDFCFUtil.cc:290
hdf_vgroup vgroup
Definition: hdf-maps.h:61
void print(vector< string > &strv) const
Definition: genvec.cc:904
static File * Read(const char *path, int32 sdid, int32 fileid)
Retrieve SDS and Vdata information from the HDF4 file.
Definition: HDFSP.cc:196
vector< int32 > tags
Definition: hdfclass.h:225
void hdfeos_switch_to_buffer(void *new_buffer)
Definition: lex.hdfeos.cc:2039
bool in_vgroup
Definition: hdf-maps.h:52
This class provides a way to map HDF4 1-D character array to DAP Str for the CF option.
const std::string & getName() const
Get the name of this field.
Definition: HDFSP.h:290
void append(int32 nt, const char *new_data, int32 nelts)
Definition: genvec.cc:200
vector< int32 > refs
Definition: hdfclass.h:226
bool in_vgroup
Definition: hdf-maps.h:47
static File * Read_Hybrid(const char *path, int32 sdid, int32 fileid)
Retrieve SDS and Vdata information from the hybrid HDF-EOS file. Currently we only support the access...
Definition: HDFSP.cc:249
string num2string(T n)
Definition: hdfdesc.cc:157
int32 getFieldRef() const
Definition: HDFSP.h:405
static void add_obpg_special_attrs(HDFSP::File *f, libdap::DAS &das, HDFSP::SDField *spsds, std::string &scaling, float &slope, bool &global_slope_flag, float &intercept, bool &global_intercept_flag)
Definition: HDFCFUtil.cc:1452
void hdfeos_delete_buffer(void *buffer)
Definition: lex.hdfeos.cc:2045
virtual const char * what() const
Return exception message.
Definition: HDFSP.h:109
static std::string escattr(std::string s)
A customized escaping function to escape special characters following OPeNDAP's escattr function that...
Definition: HDFCFUtil.cc:2502
bool close()
closes the opened file.
Definition: HE2CF.cc:1043
#define THROW(x)
Definition: dhdferr.h:51
string unit
Definition: hdfclass.h:171
bool write_attribute_coordinates(const string &varname, string coord)
writes coordinates attribute into varname attribute table.
Definition: HE2CF.cc:1230
void set_DAS(DAS *das)
sets DAS pointer so that we can bulid attribute tables.
Definition: HE2CF.cc:332
int32 ref
Definition: hdfclass.h:208
int hdfeosparse(libdap::parser_arg *arg)
static std::string print_attr(int32, int, void *)
Print attribute values in string.
Definition: HDFCFUtil.cc:184
This class provides a way to map HDFEOS2 character >1D array to DAP Str array for the CF option...
const std::vector< Attribute * > & getAttributes() const
Public interface to obtain the SD(file) attributes.
Definition: HDFSP.h:579
string name
Definition: hdfclass.h:169
hdf_genvec values
Definition: hdfclass.h:152
HDFStructure * NewStructureFromVgroup(const hdf_vgroup &vg, vg_map &vgmap, sds_map &sdmap, vd_map &vdmap, gr_map &grmap, const string &dataset)
Definition: hc2dap.cc:177
map< int32, vg_info, less< int32 > >::const_iterator VGI
Definition: hdf-maps.h:73
string name
Definition: hdfclass.h:223
int32 ref
Definition: hdfclass.h:222
static BESLog * TheLog()
Definition: BESLog.cc:347
string format
Definition: hdfclass.h:172
string name
Definition: hdfclass.h:209
int32 ref
Definition: hdfclass.h:245
const std::vector< AttrContainer * > & getVgattrs() const
Get attributes for all vgroups.
Definition: HDFSP.h:784
static std::string get_CF_string(std::string s)
Change special characters to "_".
Definition: HDFCFUtil.cc:80
void read_dds_spvdfields(DDS &dds, const string &filename, const int fileid, int32 vdref, int32 numrec, HDFSP::VDField *spvd)
Definition: hdfdesc.cc:3497
static bool check_beskeys(const std::string &key)
Check the BES key. This function will check a BES key specified at the file h4.conf.in. If the key's value is either true or yes. The handler claims to find a key and will do some operations. Otherwise, will do different operations. For example, One may find a line H4.EnableCF=true at h4.conf.in. That means, the HDF4 handler will handle the HDF4 files by following CF conventions.
Definition: HDFCFUtil.cc:17
const std::vector< Dimension * > & getCorrectedDimensions() const
Get the list of the corrected dimensions.
Definition: HDFSP.h:357
string get_metadata(const string &metadataname, bool &suffix_is_num, vector< string > &non_num_names, vector< string > &non_num_data)
retrieves the merged metadata.
Definition: HE2CF.cc:1059
SPType getSPType() const
Obtain special HDF4 product type.
Definition: HDFSP.h:750
SPType
Definition: HDFSPEnumType.h:4
This class provides a way to map HDFEOS2 1-D character array to DAP Str for the CF option...
string label
Definition: hdfclass.h:170
#define BESDEBUG(x, y)
macro used to send debug information to the debug stream
Definition: BESDebug.h:64
hdf_gri gri
Definition: hdf-maps.h:56
int32 getType() const
Get the data type of this field.
Definition: HDFSP.h:308
static void correct_scale_offset_type(libdap::AttrTable *at)
CF requires the scale_factor and add_offset attribute datatypes hold the same datatype. So far we haven't found that scale_factor and add_offset attributes hold different datatypes in NASA files. But just in case, we implement a BES key to give users a chance to check this. By default, the key is always off.
Definition: HDFCFUtil.cc:462
bool Has_Dim_NoScale_Field() const
This file has a field that is a SDS dimension but no dimension scale.
Definition: HDFSP.h:757
void AddHDFAttr(DAS &das, const string &varname, const vector< hdf_attr > &hav)
Definition: hdfdesc.cc:4279
const std::vector< SDField * > & getFields() const
Public interface to obtain information of all SDS vectors(objects).
Definition: HDFSP.h:573
bool read_das_hdfsp(DAS &das, const string &filename, int32 sdfd, int32 fileid, HDFSP::File **h4filepptr)
Definition: hdfdesc.cc:2251
bool write_attribute(const string &gname, const string &fname, const string &newfname, int n_groups, int fieldtype)
writes attribute table into DAS given grid/swath name and its field name.
Definition: HE2CF.cc:1098
map< int32, sds_info, less< int32 > > sds_map
Definition: hdf-maps.h:65
yy_buffer_state * hdfeos_scan_string(const char *str)
vector< hdf_attr > attrs
Definition: hdfclass.h:212
map< int32, gr_info, less< int32 > >::const_iterator GRI
Definition: hdf-maps.h:72
vector< hdf_attr > attrs
Definition: hdfclass.h:248
vector< hdf_attr > attrs
Definition: hdfclass.h:228
bool read_das_special_eos2_core(DAS &das, HDFSP::File *spf, const string &filename, bool ecs_metadata)
Definition: hdfdesc.cc:2806
map< int32, vg_info, less< int32 > > vg_map
Definition: hdf-maps.h:68
Definition: HDFStr.h:52