bes  Updated for version 3.20.13
HDFSP.cc
1 // This file is part of the hdf4 data handler for the OPeNDAP data server.
19 
28 
30 #include <sstream>
31 #include <algorithm>
32 #include <functional>
33 #include <vector>
34 #include <map>
35 #include <set>
36 #include<libgen.h>
37 #include "HDFCFUtil.h"
38 #include "HDFSP.h"
39 #include "dodsutil.h"
40 #include "HDF4RequestHandler.h"
41 
42 const char *_BACK_SLASH= "/";
43 
44 using namespace HDFSP;
45 using namespace std;
46 
47 #define ERR_LOC1(x) #x
48 #define ERR_LOC2(x) ERR_LOC1(x)
49 #define ERR_LOC __FILE__ " : " ERR_LOC2(__LINE__)
50 // Convenient function to handle exceptions
51 template < typename T, typename U, typename V, typename W, typename X > static void
52 _throw5 (const char *fname, int line, int numarg,
53  const T & a1, const U & a2, const V & a3, const W & a4, const X & a5)
54 {
55  std::ostringstream ss;
56  ss << fname << ":" << line << ":";
57  for (int i = 0; i < numarg; ++i) {
58  ss << " ";
59  switch (i) {
60 
61  case 0:
62  ss << a1;
63  break;
64  case 1:
65  ss << a2;
66  break;
67  case 2:
68  ss << a3;
69  break;
70  case 3:
71  ss << a4;
72  break;
73  case 4:
74  ss << a5;
75  break;
76  default:
77  ss <<" Argument number is beyond 5";
78  }
79  }
80  throw Exception (ss.str ());
81 }
82 
84 // number of arguments.
86 #define throw1(a1) _throw5(__FILE__, __LINE__, 1, a1, 0, 0, 0, 0)
87 #define throw2(a1, a2) _throw5(__FILE__, __LINE__, 2, a1, a2, 0, 0, 0)
88 #define throw3(a1, a2, a3) _throw5(__FILE__, __LINE__, 3, a1, a2, a3, 0, 0)
89 #define throw4(a1, a2, a3, a4) _throw5(__FILE__, __LINE__, 4, a1, a2, a3, a4, 0)
90 #define throw5(a1, a2, a3, a4, a5) _throw5(__FILE__, __LINE__, 5, a1, a2, a3, a4, a5)
91 
92 #define assert_throw0(e) do { if (!(e)) throw1("assertion failure"); } while (false)
93 #define assert_range_throw0(e, ge, l) assert_throw0((ge) <= (e) && (e) < (l))
94 
95 
96 // Convenient function to release resources.
97 struct delete_elem
98 {
99  template < typename T > void operator () (T * ptr)
100  {
101  delete ptr;
102  }
103 };
104 
105 
106 // Class File destructor
107 File::~File ()
108 {
109 
110  // Release SD resources
111  if (this->sdfd != -1) {
112  if (sd != nullptr)
113  delete sd;
114  // No need to close SD interface.
115  // it is handled(opened/closed) at the top level(HDF4RequestHandler.cc)
116  // KY 2014-02-18
117 #if 0
118  //SDend (this->sdfd);
119 #endif
120  }
121 
122  // Close V interface IDs and release vdata resources
123  if (this->fileid != -1) {
124 
125 #if 0
126  for (vector < VDATA * >::const_iterator i = this->vds.begin ();
127  i != this->vds.end (); ++i) {
128  delete *i;
129  }
130 
131  for (vector < AttrContainer * >::const_iterator i = this->vg_attrs.begin ();
132  i != this->vg_attrs.end (); ++i) {
133  delete *i;
134  }
135 #endif
136 
137  std::for_each (this->vds.begin (), this->vds.end (), delete_elem ());
138  std::for_each (this->vg_attrs.begin (), this->vg_attrs.end (), delete_elem ());
139 
140  Vend (this->fileid);
141  // No need to close H interface
142  // it is handled(opened/closed) at the top level(HDF4RequestHandler.cc)
143 #if 0
144  //Hclose (this->fileid);
145 #endif
146  }
147 }
148 
149 // Destructor to release vdata resources
150 VDATA::~VDATA ()
151 {
152  // Release vdata field pointers
153  std::for_each (this->vdfields.begin (), this->vdfields.end (),
154  delete_elem ());
155 
156  // Release vdata attributes
157  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
158 }
159 
160 // Destructor to release SD resources
162 {
163  // Release SD attributes
164  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
165 
166  // Release SD field pointers
167  std::for_each (this->sdfields.begin (), this->sdfields.end (),
168  delete_elem ());
169 
170 }
171 
172 // Destructor to release SD field resources
173 SDField::~SDField ()
174 {
175  // Release dimension resources
176  std::for_each (this->dims.begin (), this->dims.end (), delete_elem ());
177 
178  // Release corrected dimension resources
179  std::for_each (this->correcteddims.begin (), this->correcteddims.end (),
180  delete_elem ());
181 
182  // Release attribute container dims_info resources(Only apply for the OTHERHDF case)
183  std::for_each (this->dims_info.begin (), this->dims_info.end (), delete_elem ());
184 }
185 
186 // Vdata field constructors, nothing needs to do here. We don't provide vdata dimensions.
187 // Only when mapping to DDS (at hdfdesc.cc,search VDFDim0), we add the dimension info. to DDS. The addition
188 // may not be in a good place, however, the good part is that we don't need to allocate dimension resources
189 // for vdata.
190 
191 
192 // We only need to release attributes since that's shared for both Vdata fields and SDS fields.
193 Field::~Field ()
194 {
195  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
196 }
197 
198 // Release attribute container resources. This should only apply to the OTHERHDF case.
199 AttrContainer::~AttrContainer()
200 {
201  std::for_each (this->attrs.begin (), this->attrs.end (), delete_elem ());
202 }
203 
204 
205 // Retrieve all the information from an HDF file; this is the same approach
206 // as the way to handle HDF-EOS2 files.
207 File *
208 File::Read (const char *path, int32 mysdid, int32 myfileid)
209 throw (Exception)
210 {
211 
212  // Allocate a new file object.
213  auto file = new File (path);
214 
215 #if 0
216  int32 mysdid = -1;
217 
218  // Obtain the SD ID.
219  if ((mysdid =
220  SDstart (const_cast < char *>(file->path.c_str ()),
221  DFACC_READ)) == -1) {
222  delete file;
223  throw2 ("SDstart", path);
224  }
225 #endif
226 
227  // Old comments just for reminders(KY 2014-02-18)
228  // A strange compiling bug was found if we don't pass the file id to this fuction.
229  // It will always give 0 number as the ID and the HDF4 library doesn't complain!!
230  // Will try dumplicating the problem and submit a bug report. KY 2010-7-14
231  file->sdfd = mysdid;
232  file->fileid = myfileid;
233 
234  if(myfileid != -1) {
235  // Start V interface
236  int32 status = Vstart (file->fileid);
237  if (status == FAIL) {
238  delete file;
239  throw2 ("Cannot start vdata/vgroup interface", path);
240  }
241  }
242 
243  try {
244  // Read SDS info.
245  file->sd = SD::Read (file->sdfd, file->fileid);
246 
247  // Handle lone vdatas, non-lone vdatas will be handled in Prepare().
248  // Read lone vdata.
249  if(myfileid != -1)
250  file->ReadLoneVdatas(file);
251  }
252  catch(...) {
253  delete file;
254  throw;
255  }
256 
257  return file;
258 }
259 
260 // Retrieve all the information from the additional SDS objects of an HDF file; this is the same approach
261 // as the way to handle other HDF4 files.
262 File *
263 File::Read_Hybrid (const char *path, int32 mysdid, int32 myfileid)
264 throw (Exception)
265 {
266  // New File
267  auto file = new File (path);
268  if(file == nullptr)
269  throw1("Memory allocation for file class failed. ");
270 
271 #if 0
272 //cerr<<"File is opened for HDF4 "<<endl;
273 #endif
274 
275 #if 0
276  // Obtain SD interface
277  int32 mysdid = -1;
278  if ((mysdid =
279  SDstart (const_cast < char *>(file->path.c_str ()),
280  DFACC_READ)) == -1) {
281  delete file;
282  throw2 ("SDstart", path);
283  }
284 #endif
285 
286  // Old comments just for reminders. The HDF4 issue may still exist. KY 2014-02-18
287  // A strange compiling bug was found if we don't pass the file id to this fuction.
288  // It will always give 0 number as the ID and the HDF4 library doesn't complain!!
289  // Will try dumplicating the problem and submit a bug report. KY 2010-7-14
290  file->sdfd = mysdid;
291  file->fileid = myfileid;
292 
293  // Start V interface
294  int status = Vstart (file->fileid);
295  if (status == FAIL) {
296  delete file;
297  throw2 ("Cannot start vdata/vgroup interface", path);
298  }
299 
300 #if 0
301  //if(file != nullptr) {// Coverity doesn't recongize the throw macro, see if this makes it happy.
302 #endif
303 
304  try {
305 
306  // Retrieve extra SDS info.
307  file->sd = SD::Read_Hybrid(file->sdfd, file->fileid);
308 
309  // Retrieve lone vdata info.(HDF-EOS2 doesn't support any lone vdata)
310  file->ReadLoneVdatas(file);
311 
312  // Retrieve extra non-lone vdata in the hybrid HDF-EOS2 file
313  file->ReadHybridNonLoneVdatas(file);
314  }
315  catch(...) {
316  delete file;
317  throw;
318  }
319 
320 #if 0
321  //}
322 #endif
323 
324  return file;
325 }
326 
327 // Retrieve lone vdata info.
328 void
330 
331  int status = -1;
332  // No need to start V interface again
333 #if 0
334  // Start V interface
335  int status = Vstart (file->fileid);
336  if (status == FAIL)
337  throw2 ("Cannot start vdata/vgroup interface", path);
338 #endif
339 
340  // Obtain number of lone vdata.
341  int num_lone_vdata = VSlone (file->fileid, nullptr, 0);
342 
343  if (num_lone_vdata == FAIL)
344  throw2 ("Fail to obtain lone vdata number", path);
345 
346  // Currently the vdata name buffer has to be static allocated according to HDF4 reference manual. KY 2010-7-14
347  // Now HDF4 provides a dynamic way to allocate the length of vdata_class, should update to use that in the future.
348  // Documented in a jira ticket HFRHANDLER-168.
349  // KY 2013-07-11
350  char vdata_class[VSNAMELENMAX];
351  char vdata_name[VSNAMELENMAX];
352 
353  if (num_lone_vdata > 0) {
354 
355  vector<int32>ref_array;
356  ref_array.resize(num_lone_vdata);
357 
358  if (VSlone (file->fileid, ref_array.data(), num_lone_vdata) == FAIL) {
359  throw2 ("cannot obtain lone vdata reference arrays", path);
360  }
361 
362  for (int i = 0; i < num_lone_vdata; i++) {
363 
364  int32 vdata_id = -1;
365 
366  vdata_id = VSattach (file->fileid, ref_array[i], "r");
367  if (vdata_id == FAIL) {
368  throw2 ("Fail to attach Vdata", path);
369  }
370  status = VSgetclass (vdata_id, vdata_class);
371  if (status == FAIL) {
372  VSdetach (vdata_id);
373  throw2 ("Fail to obtain Vdata class", path);
374  }
375 
376  if (VSgetname (vdata_id, vdata_name) == FAIL) {
377  VSdetach (vdata_id);
378  throw3 ("Fail to obtain Vdata name", path, vdata_name);
379  }
380 
381  // Ignore any vdata that is either an HDF4 attribute or is used
382  // to store internal data structures.
383  if (VSisattr (vdata_id) == TRUE
384  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
385  strlen (_HDF_CHK_TBL_CLASS))
386  || !strncmp (vdata_class, _HDF_SDSVAR, strlen (_HDF_SDSVAR))
387  || !strncmp (vdata_class, _HDF_CRDVAR, strlen (_HDF_CRDVAR))
388  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
389  || !strncmp (vdata_class, DIM_VALS01, strlen (DIM_VALS01))
390  || !strncmp (vdata_class, RIGATTRCLASS, strlen (RIGATTRCLASS))
391  || !strncmp (vdata_name, RIGATTRNAME, strlen (RIGATTRNAME))) {
392 
393  status = VSdetach (vdata_id);
394  if (status == FAIL) {
395  throw3 ("VSdetach failed ", "Vdata name ", vdata_name);
396  }
397  }
398 
399  else {
400  VDATA*vdataobj = nullptr;
401 
402  try {
403  // Read vdata information
404  vdataobj = VDATA::Read (vdata_id, ref_array[i]);
405  }
406  catch (...) {
407  VSdetach(vdata_id);
408  throw;
409  }
410 
411  // We want to map fields of vdata with more than 10 records to DAP variables
412  // and we need to add the path and vdata name to the new vdata field name
413  if (!vdataobj->getTreatAsAttrFlag ()) {
414  for (const auto &vdf:vdataobj->getFields ()) {
415 
416  // vdata name conventions.
417  // "vdata"+vdata_newname+"_vdf_"+vdf->newname
418  vdf->newname = "vdata_" + vdataobj->newname + "_vdf_" + vdf->name;
419 
420  //Make sure the name is following CF, KY 2012-6-26
421  vdf->newname = HDFCFUtil::get_CF_string(vdf->newname);
422  }
423  }
424 
425  // Save this vdata info. in the file instance.
426  file->vds.push_back (vdataobj);
427 
428  // THe following code should be replaced by using the VDField member functions in the future
429  // The code has largely overlapped with VDField member functions, but not for this release.
430  // KY 2010-8-11
431 
432  // To know if the data product is CERES, we need to check Vdata CERE_metadata(CERE_META_NAME).
433  // One field name LOCALGRANULEID(CERE_META_FIELD_NAME) includes the product name.
434  // We want to assign the filetype of this CERES file based on the LOCALGRANULEID.
435  // Please note that CERES products we support to follow CF are pure HDF4 files.
436  // For hybrid HDF-EOS2 files, this if loop is simply skipped.
437 
438  // When the vdata name indicates this is a CERES product, we need to do the following:
439  if (false == strncmp
440  (vdata_name, CERE_META_NAME, strlen (CERE_META_NAME))) {
441 
442  char *fieldname = nullptr;
443 
444  // Obtain number of vdata fields
445  int num_field = VFnfields (vdata_id);
446  if (num_field == FAIL) {
447  VSdetach (vdata_id);
448  throw3 ("number of fields at Vdata ", vdata_name," is -1");
449  }
450 
451  // Search through the number of vdata fields
452  for (int j = 0; j < num_field; j++) {
453 
454  fieldname = VFfieldname (vdata_id, j);
455  if (fieldname == nullptr) {
456  VSdetach (vdata_id);
457  throw5 ("vdata ", vdata_name, " field index ", j,
458  " field name is nullptr.");
459  }
460 
461  // If the field name matches CERES's specific field name"LOCALGRANULEID"
462  else if (!strcmp (fieldname, CERE_META_FIELD_NAME)) {
463 
464  int32 fieldsize = -1;
465  int32 nelms = -1;
466 
467  // Obtain field size
468  fieldsize = VFfieldesize (vdata_id, j);
469  if (fieldsize == FAIL) {
470  VSdetach (vdata_id);
471  throw5 ("vdata ", vdata_name, " field ",fieldname, " size is wrong.");
472  }
473 
474  // Obtain number of elements
475  nelms = VSelts (vdata_id);
476  if (nelms == FAIL) {
477  VSdetach (vdata_id);
478  throw5 ("vdata ", vdata_name,
479  " number of field record ", nelms," is wrong.");
480  }
481 
482  string err_msg;
483  bool data_buf_err = false;
484  bool VS_fun_err = false;
485 
486  // Allocate data buf
487  auto databuf = (char *) malloc (fieldsize * nelms);
488  if (databuf == nullptr) {
489  err_msg = string(ERR_LOC) + "No enough memory to allocate buffer.";
490  data_buf_err = true;
491  goto cleanFail;
492  }
493 
494  // Initialize the seeking process
495  if (VSseek (vdata_id, 0) == FAIL) {
496  err_msg = string(ERR_LOC) + "VSseek failed";
497  VS_fun_err = true;
498  goto cleanFail;
499  }
500 
501  // The field to seek is CERE_META_FIELD_NAME
502  if (VSsetfields (vdata_id, CERE_META_FIELD_NAME) == FAIL) {
503  err_msg = "VSsetfields failed";
504  VS_fun_err = true;
505  goto cleanFail;
506  }
507 
508  // Read this vdata field value
509  if (VSread(vdata_id, (uint8 *) databuf, 1,FULL_INTERLACE)
510  == FAIL) {
511  err_msg = "VSread failed";
512  VS_fun_err = true;
513  goto cleanFail;
514  }
515 
516  // Assign the corresponding special product indicator we supported for CF
517  if (!strncmp(databuf, CER_AVG_NAME,strlen (CER_AVG_NAME)))
518  file->sptype = CER_AVG;
519  else if (!strncmp
520  (databuf, CER_ES4_NAME,strlen(CER_ES4_NAME)))
521  file->sptype = CER_ES4;
522  else if (!strncmp
523  (databuf, CER_CDAY_NAME,strlen (CER_CDAY_NAME)))
524  file->sptype = CER_CDAY;
525  else if (!strncmp
526  (databuf, CER_CGEO_NAME,strlen (CER_CGEO_NAME)))
527  file->sptype = CER_CGEO;
528  else if (!strncmp
529  (databuf, CER_SRB_NAME,strlen (CER_SRB_NAME)))
530  file->sptype = CER_SRB;
531  else if (!strncmp
532  (databuf, CER_SYN_NAME,strlen (CER_SYN_NAME)))
533  file->sptype = CER_SYN;
534  else if (!strncmp
535  (databuf, CER_ZAVG_NAME,
536  strlen (CER_ZAVG_NAME)))
537  file->sptype = CER_ZAVG;
538 
539 cleanFail:
540  if(data_buf_err == true || VS_fun_err == true) {
541  VSdetach(vdata_id);
542  if(data_buf_err == true)
543  throw1(err_msg);
544  else {
545  free(databuf);
546  throw5("vdata ",vdata_name,"field ",
547  CERE_META_FIELD_NAME,err_msg);
548  }
549  }
550  else
551  free(databuf);
552  }
553  }
554  }
555  VSdetach (vdata_id);
556  }
557 
558  }
559  }
560 }
561 
562 // Handle non-attribute non-lone vdata for Hybrid HDF-EOS2 files.
563 void
565 
566 
567  int32 status = -1;
568  int32 file_id = -1;
569  int32 vgroup_id = -1;
570  int32 vdata_id = -1;
571 
572 #if 0
573  //int32 vgroup_ref = -1;
574  //int32 obj_index = -1;
575  //int32 num_of_vg_objs = -1;
576 #endif
577 
578  int32 obj_tag = -1;
579  int32 obj_ref = -1;
580 
581  int32 lone_vg_number = 0;
582  int32 num_of_lones = -1;
583  int32 num_gobjects = 0;
584 
585  // This can be updated in the future with new HDF4 APIs that can provide the actual length of an object name.
586  // Documented in a jira ticket HFRHANDLER-168.
587  // KY 2013-07-11
588  char vdata_name[VSNAMELENMAX];
589  char vdata_class[VSNAMELENMAX];
590  char vgroup_name[VGNAMELENMAX*4];
591  char vgroup_class[VGNAMELENMAX*4];
592 
593  // Full path of this vgroup
594  char *full_path = nullptr;
595 
596  // Copy of a full path of this vgroup
597  char *cfull_path = nullptr;
598 
599  // Obtain H interface ID
600  file_id = file->fileid;
601 
602  // No need to start V interface again.
603 #if 0
604  // Start V interface
605  status = Vstart (file_id);
606  if (status == FAIL)
607  throw2 ("Cannot start vdata/vgroup interface", path);
608 #endif
609 
610  // No NASA HDF4 files have the vgroup that forms a ring; so ignore this case.
611  // First, call Vlone with num_of_lones set to 0 to get the number of
612  // lone vgroups in the file, but not to get their reference numbers.
613  num_of_lones = Vlone (file_id, nullptr, 0);
614  if (num_of_lones == FAIL)
615  throw3 ("Fail to obtain lone vgroup number", "file id is", file_id);
616 
617  // if there are any lone vgroups,
618  if (num_of_lones > 0) {
619 
620  // Use the num_of_lones returned to allocate sufficient space for the
621  // buffer ref_array to hold the reference numbers of all lone vgroups,
622 
623  // Use vectors to avoid the clean-up of the memory
624  vector<int32>ref_array;
625  ref_array.resize(num_of_lones);
626 
627  // Call Vlone again to retrieve the reference numbers into
628  // the buffer ref_array.
629  num_of_lones = Vlone (file_id, ref_array.data(), num_of_lones);
630  if (num_of_lones == FAIL) {
631  throw3 ("Cannot obtain lone vgroup reference arrays ",
632  "file id is ", file_id);
633  }
634 
635  // Loop the lone vgroups.
636  for (lone_vg_number = 0; lone_vg_number < num_of_lones;
637  lone_vg_number++) {
638 
639  // Attach to the current vgroup
640  vgroup_id = Vattach (file_id, ref_array[lone_vg_number], "r");
641  if (vgroup_id == FAIL) {
642  throw3 ("Vattach failed ", "Reference number is ",
643  ref_array[lone_vg_number]);
644  }
645 
646  // Obtain the vgroup name.
647  status = Vgetname (vgroup_id, vgroup_name);
648  if (status == FAIL) {
649  Vdetach (vgroup_id);
650  throw3 ("Vgetname failed ", "vgroup_id is ", vgroup_id);
651  }
652 
653  // Obtain the vgroup_class name.
654  status = Vgetclass (vgroup_id, vgroup_class);
655  if (status == FAIL) {
656  Vdetach (vgroup_id);
657  throw3 ("Vgetclass failed ", "vgroup_name is ", vgroup_name);
658  }
659 
660  //Ignore internal HDF groups
661  if (strcmp (vgroup_class, _HDF_ATTRIBUTE) == 0
662  || strcmp (vgroup_class, _HDF_VARIABLE) == 0
663  || strcmp (vgroup_class, _HDF_DIMENSION) == 0
664  || strcmp (vgroup_class, _HDF_UDIMENSION) == 0
665  || strcmp (vgroup_class, _HDF_CDF) == 0
666  || strcmp (vgroup_class, GR_NAME) == 0
667  || strcmp (vgroup_class, RI_NAME) == 0) {
668  Vdetach(vgroup_id);
669  continue;
670  }
671 
672  // Obtain number of objects under this vgroup
673  num_gobjects = Vntagrefs (vgroup_id);
674  if (num_gobjects < 0) {
675  Vdetach (vgroup_id);
676  throw3 ("Vntagrefs failed ", "vgroup_name is ", vgroup_name);
677  }
678 
679  // STOP: error handling to avoid the false alarm from coverity scan or sonar cloud
680  string err_msg;
681  bool VS_or_mem_err = false;
682 
683  // Allocate enough buffer for the full path
684  // MAX_FULL_PATH_LEN(1024) is long enough
685  // to cover any HDF4 object path for all NASA HDF4 products.
686  // We replace strcpy and strcat with strncpy and strncat as suggested. KY 2013-08-29
687  full_path = (char *) malloc (MAX_FULL_PATH_LEN);
688  if (full_path == nullptr) {
689  err_msg = "No enough memory to allocate the buffer for full_path.";
690  VS_or_mem_err = true;
691  goto cleanFail;
692 #if 0
693  //Vdetach (vgroup_id);
694  //throw;
695  //throw1 ("No enough memory to allocate the buffer.");
696 #endif
697  }
698  else
699  memset(full_path,'\0',MAX_FULL_PATH_LEN);
700 
701  // Obtain the full path of this vgroup
702  strncpy (full_path,_BACK_SLASH,strlen(_BACK_SLASH));
703  strncat(full_path,vgroup_name,strlen(vgroup_name));
704  strncat(full_path,_BACK_SLASH,strlen(_BACK_SLASH));
705 
706  // Make a copy the current vgroup full path since full path may be passed to a recursive routine
707  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
708  if (cfull_path == nullptr) {
709  //Vdetach (vgroup_id);
710  //free (full_path);
711  err_msg = "No enough memory to allocate the buffer for cfull_path.";
712  VS_or_mem_err = true;
713  goto cleanFail;
714 #if 0
715  //throw;
716  //throw1 ("No enough memory to allocate the buffer.");
717 #endif
718  }
719  else
720  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
721  strncpy(cfull_path,full_path,strlen(full_path));
722 
723  // Loop all vgroup objects
724 
725  for (int i = 0; i < num_gobjects; i++) {
726 
727  // Obtain the object tag/ref pair of an object
728  if (Vgettagref (vgroup_id, i, &obj_tag, &obj_ref) == FAIL) {
729  err_msg = "Vgettagref failed";
730  VS_or_mem_err = true;
731  goto cleanFail;
732 #if 0
733  //Vdetach (vgroup_id);
734  //free (full_path);
735  //free (cfull_path);
736  //throw5 ("Vgettagref failed ", "vgroup_name is ",
737  // vgroup_name, " reference number is ", obj_ref);
738 #endif
739  }
740 
741  // If the object is a vgroup,always pass the original full path to its decendant vgroup
742  // The reason to use a copy is because the full_path will be changed when it goes down to its descendant.
743  if (Visvg (vgroup_id, obj_ref) == TRUE) {
744  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
745  full_path[strlen(cfull_path)]='\0';
746  obtain_vdata_path (file_id, full_path, obj_ref);
747  }
748 
749  // If this object is vdata
750  else if (Visvs (vgroup_id, obj_ref)) {
751 
752  // Obtain vdata ID
753  vdata_id = VSattach (file_id, obj_ref, "r");
754  if (vdata_id == FAIL) {
755  err_msg = "VSattach failed";
756  VS_or_mem_err = true;
757  goto cleanFail;
758  }
759 
760  // Obtain vdata name
761  status = VSgetname (vdata_id, vdata_name);
762  if (status == FAIL) {
763  err_msg = "VSgetname failed";
764  VS_or_mem_err = true;
765  goto cleanFail;
766  }
767 
768  // Obtain vdata class name
769  status = VSgetclass (vdata_id, vdata_class);
770  if (status == FAIL) {
771  err_msg = "VSgetclass failed";
772  VS_or_mem_err = true;
773  goto cleanFail;
774  }
775 
776  // Ignore the vdata to store internal HDF structure and the vdata used as an attribute
777  if (VSisattr (vdata_id) == TRUE
778  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
779  strlen (_HDF_CHK_TBL_CLASS))
780  || !strncmp (vdata_class, _HDF_SDSVAR,
781  strlen (_HDF_SDSVAR))
782  || !strncmp (vdata_class, _HDF_CRDVAR,
783  strlen (_HDF_CRDVAR))
784  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
785  || !strncmp (vdata_class, DIM_VALS01,
786  strlen (DIM_VALS01))
787  || !strncmp (vdata_class, RIGATTRCLASS,
788  strlen (RIGATTRCLASS))
789  || !strncmp (vdata_name, RIGATTRNAME,
790  strlen (RIGATTRNAME))) {
791 
792  status = VSdetach (vdata_id);
793  if (status == FAIL) {
794  err_msg = "VSdetach failed in the if block to ignore the HDF4 internal attributes.";
795  VS_or_mem_err = true;
796  goto cleanFail;
797  }
798 
799  }
800  // Now user-defined vdata
801  else {
802 
803  VDATA *vdataobj = nullptr;
804  try {
805  vdataobj = VDATA::Read (vdata_id, obj_ref);
806  }
807  catch(...) {
808  free (full_path);
809  free (cfull_path);
810  VSdetach(vdata_id);
811  Vdetach (vgroup_id);
812  throw;
813  }
814 
815  if(full_path != nullptr)//Make coverity happy since it doesn't understand the throw macro
816  vdataobj->newname = full_path +vdataobj->name;
817 
818  //We want to map fields of vdata with more than 10 records to DAP variables
819  // and we need to add the path and vdata name to the new vdata field name
820  if (!vdataobj->getTreatAsAttrFlag ()) {
821  for (const auto &vdf:vdataobj->getFields ()) {
822 
823  // Change vdata name conventions.
824  // "vdata"+vdata_newname+"_vdf_"+vdf->newname
825 
826  vdf->newname =
827  "vdata" + vdataobj->newname + "_vdf_" + vdf->name;
828 
829  //Make sure the name is following CF, KY 2012-6-26
830  vdf->newname = HDFCFUtil::get_CF_string(vdf->newname);
831  }
832 
833  }
834 
835  // Make sure the name is following CF
836  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
837 
838  // Save back this vdata
839  this->vds.push_back (vdataobj);
840 
841  status = VSdetach (vdata_id);
842  if (status == FAIL) {
843  err_msg = "VSdetach failed in the user-defined vdata block";
844  VS_or_mem_err = true;
845  goto cleanFail;
846  }
847  }
848  }
849 
850  //Ignore the handling of SDS objects. They are handled elsewhere.
851 #if 0
852  else{
853 
854  }
855 #endif
856  }
857 
858 cleanFail:
859  if(full_path != nullptr)
860  free (full_path);
861  if(cfull_path != nullptr)
862  free (cfull_path);
863 
864  status = Vdetach (vgroup_id);
865  if (status == FAIL) {
866  throw3 ("Vdetach failed ", "vgroup_name is ", vgroup_name);
867  }
868  if(true == VS_or_mem_err)
869  throw3(err_msg,"vgroup_name is ",vgroup_name);
870 
871  }//end of the for loop
872 
873  }// end of the if loop
874 
875 }
876 
877 // Check if this is a special SDS(MOD08_M3) that needs the connection between CVs and dimension names.
878 // General algorithm:
879 // 1. Insert a set for fields' dimensions,
880 // 2. in the mean time, insert a set for 1-D field
881 // 3. For each dimension in the set, search if one can find the corresponding field that has the same dimension name in the set.
882 // Return false if non-found occurs.
883 // Else return true.
884 
885 bool
886 File::Check_update_special(const string& grid_name) throw(Exception) {
887 
888  set<string> dimnameset;
889  set<SDField*> fldset;
890 
891  // Build up a dimension set and a 1-D field set.
892  // We already know that XDim and YDim should be in the dimension set. so inserting them.
893  // Hopefully by doing this, we can save some time since many variables have dimensions
894  // "XDim" and "YDim" and excluding "XDim" and "YDim" may save some time if there are many
895  // dimensions in the dimnameset.
896 
897  string FullXDim;
898  string FullYDim;
899  FullXDim="XDim:" ;
900  FullYDim="YDim:";
901 
902  FullXDim= FullXDim+grid_name;
903  FullYDim =FullYDim+grid_name;
904 
905  for (const auto &sdf:this->sd->getFields ()) {
906 
907  for (const auto &dim:sdf->getDimensions()) {
908  if(dim->getName() !=FullXDim && dim->getName()!=FullYDim)
909  dimnameset.insert(dim->getName());
910  }
911 
912  if (1==sdf->getRank())
913  fldset.insert(sdf);
914 
915  }
916 
917 
918  // Check if all dimension names in the dimension set can be found in the 1-D variable sets. Moreover, the size of a dimension
919  // should be smaller or the same as the size of 1-D variable.
920  // Plus XDim and YDim for number of dimensions
921  if (fldset.size() < (dimnameset.size()+2))
922  return false;
923 
924  int total_num_dims = 0;
925  size_t grid_name_size = grid_name.size();
926  string reduced_dimname;
927 
928  for (const auto &fld:fldset) {
929  size_t dim_size = (fld->getDimensions())[0]->getName().size();
930  if( dim_size > grid_name_size){
931  reduced_dimname = (fld->getDimensions())[0]->getName().substr(0,dim_size-grid_name_size-1);
932  if (fld->getName() == reduced_dimname)
933  total_num_dims++;
934  }
935  }
936 
937  if((size_t)total_num_dims != (dimnameset.size()+2))
938  return false;
939 
940  // Updated dimension names for all variables: removing the grid_name prefix.
941  for (const auto &sdf:this->sd->getFields()) {
942 
943  for (const auto &dim:sdf->getDimensions ()) {
944 
945  size_t dim_size = dim->getName().size();
946  if( dim_size > grid_name_size){
947  reduced_dimname = dim->getName().substr(0,dim_size-grid_name_size-1);
948  dim->name = reduced_dimname;
949  }
950  else // Here we enforce that the dimension name has the grid suffix. This can be lifted in the future. KY 2014-01-16
951  return false;
952  }
953 
954  }
955 
956  // Build up Dimensions for DDS and DAS.
957  for (const auto &fld:fldset) {
958 
959  if (fld->getName() == (fld->getDimensions())[0]->getName()) {
960 
961  if("XDim" == fld->getName()){
962  std::string tempunits = "degrees_east";
963  fld->setUnits (tempunits);
964  fld->fieldtype = 2;
965  }
966 
967  else if("YDim" == fld->getName()){
968  std::string tempunits = "degrees_north";
969  fld->setUnits (tempunits);
970  fld->fieldtype = 1;
971  }
972 
973  else if("Pressure_Level" == fld->getName()) {
974  std::string tempunits = "hPa";
975  fld->setUnits (tempunits);
976  fld->fieldtype = 3;
977  }
978  else {
979  std::string tempunits = "level";
980  fld->setUnits (tempunits);
981  fld->fieldtype = 3;
982  }
983  }
984  }
985 
986  return true;
987 
988 }
989 
990 #if 0
991 // This routine is used to check if this grid is a special MOD08M3-like grid in DDS-build.
992 // Check_if_special is used when building DAS. The reason to separate is that we pass the
993 // File pointer from DAS to DDS to reduce the building time.
994 // How to check:
995 // 1)
996 
997 bool
998 File::Check_if_special(const string& grid_name) throw(Exception) {
999 
1000 
1001  bool xdim_is_lon = false;
1002  bool ydim_is_lat = false;
1003  bool pre_unit_hpa = true;
1004  for (vector < SDField * >::const_iterator i =
1005  this->sd->getFields ().begin ();
1006  i != this->sd->getFields ().end (); ++i) {
1007  if (1==(*i)->getRank()) {
1008  if(1 == ((*i)->fieldtype)) {
1009  if("YDim" == (*j)->getName()
1010 
1011  }
1012 
1013  }
1014  }
1015 }
1016 #endif
1017 
1018 void
1019 File::Handle_AIRS_L23() throw(Exception) {
1020 
1021  File *file = this;
1022 
1023  bool airs_l3 = true;
1024  if(basename(file->path).find(".L2.")!=string::npos)
1025  airs_l3 = false;
1026 
1027  // set of names of dimensions that have dimension scales.
1028  set<string> scaled_dname_set;
1029 
1030  // set of names of dimensions that don't have dimension scales.
1031  set<string> non_scaled_dname_set;
1032  pair<set<string>::iterator,bool> ret;
1033 
1034  // For dimensions that don't have dimension scales, a map between dimension name and size.
1035  map<string,int> non_scaled_dname_to_size;
1036 
1037  // 1. Loop through SDS fields and remove suffixes(:???) of the dimension names and the variable names.
1038  // Also create scaled dim. name set and non-scaled dim. name set.
1039  for (const auto &sdf:file->sd->sdfields) {
1040 
1041  string tempname = sdf->name;
1042  size_t found_colon = tempname.find_first_of(':');
1043  if(found_colon!=string::npos)
1044  sdf->newname = tempname.substr(0,found_colon);
1045 
1046  for (const auto &dim:sdf->getDimensions()) {
1047 
1048  tempname = dim->name;
1049  found_colon = tempname.find_first_of(':');
1050  if(found_colon!=string::npos)
1051  dim->name = tempname.substr(0,found_colon);
1052 
1053  if(0==dim->getType()) {
1054  ret = non_scaled_dname_set.insert(dim->name);
1055  if (true == ret.second)
1056  non_scaled_dname_to_size[dim->name] = dim->dimsize;
1057  }
1058  else
1059  scaled_dname_set.insert(dim->name);
1060 
1061 
1062  }
1063 
1064  }
1065 #if 0
1066 for(set<string>::const_iterator sdim_it = scaled_dname_set.begin();
1067  sdim_it !=scaled_dname_set.end();
1068  ++sdim_it) {
1069 cerr<<"scaled dim. name "<<*sdim_it <<endl;
1070 
1071 }
1072 #endif
1073 
1074  // For AIRS level 3 only ****
1075  // 2. Remove potential redundant CVs
1076  // For AIRS level 3 version 6 products, many dimension scale variables shared the same value. Physically they are the same.
1077  // So to keep the performance optimal and reduce the non-necessary clutter, I remove the duplicate variables.
1078  // An Example: StdPressureLev:asecending is the same as the StdPressureLev:descending, reduce to StdPressureLev
1079 
1080  // Make a copy of the scaled-dim name set:scaled-dim-marker
1081 
1082  if(true == airs_l3) {
1083 
1084  set<string>scaled_dname_set_marker = scaled_dname_set;
1085 
1086  // Loop through all the SDS objects,
1087  // If finding a 1-D variable name
1088  // b1) in both the scaled-dim name set and the scaled-dim-marker set,
1089  // keep this variable but remove the variable name from the scaled-dim-marker.
1090  // Mark this variable as a CV.(XDim: 2, YDim:1 Others: 3).
1091  // b2) In the scaled-dim name set but not in the scaled-dim-marker set,
1092  // remove the variable from the variable vector.
1093  for (std::vector < SDField * >::iterator i =
1094  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ) {
1095  if(1 == (*i)->getRank()) {
1096  if(scaled_dname_set.find((*i)->getNewName())!=scaled_dname_set.end()) {
1097  if(scaled_dname_set_marker.find((*i)->getNewName())!=scaled_dname_set_marker.end()) {
1098  scaled_dname_set_marker.erase((*i)->getNewName());
1099  ++i;
1100  }
1101 
1102  else {// Redundant variables
1103  delete(*i);
1104  i= file->sd->sdfields.erase(i);
1105  }
1106  }
1107  else {
1108  ++i;
1109  }
1110  }
1111  // Remove Latitude and Longitude
1112  else if( 2 == (*i)->getRank()) {
1113  if ("Latitude" == (*i)->getNewName() || "Longitude" == (*i)->getNewName()) {
1114  delete(*i);
1115  i = file->sd->sdfields.erase(i);
1116  }
1117  else {
1118  ++i;
1119  }
1120  }
1121  else
1122  ++i;
1123  }
1124  }
1125 
1126 #if 0
1127 for(set<string>::const_iterator sdim_it = scaled_dname_set.begin();
1128  sdim_it !=scaled_dname_set.end();
1129  ++sdim_it) {
1130 cerr<<"new scaled dim. name "<<*sdim_it <<endl;
1131 
1132 }
1133 #endif
1134 
1135  //3. Add potential missing CVs
1136 
1137  // 3.1 Find the true dimensions that don't have dimension scales.
1138  set<string>final_non_scaled_dname_set;
1139  for (const auto &non_sdim:non_scaled_dname_set) {
1140  if(scaled_dname_set.find(non_sdim)==scaled_dname_set.end())
1141  final_non_scaled_dname_set.insert(non_sdim);
1142  }
1143 
1144  // 3.2 Create the missing CVs based on the non-scaled dimensions.
1145  for (const auto &non_sdim:final_non_scaled_dname_set) {
1146 
1147  auto missingfield = new SDField ();
1148 
1149  // The name of the missingfield is not necessary.
1150  // We only keep here for consistency.
1151  missingfield->type = DFNT_INT32;
1152  missingfield->name = non_sdim;
1153  missingfield->newname = non_sdim;
1154  missingfield->rank = 1;
1155  missingfield->fieldtype = 4;
1156  missingfield->setUnits("level");
1157  auto dim = new Dimension (non_sdim,non_scaled_dname_to_size[non_sdim] , 0);
1158 
1159  missingfield->dims.push_back (dim);
1160  file->sd->sdfields.push_back (missingfield);
1161  }
1162 
1163  // For AIRS level 3 only
1164  // Change XDim to Longitude and YDim to Latitude for field name and dimension names
1165 
1166  if (true == airs_l3) {
1167  for (const auto &sdf:file->sd->sdfields) {
1168 
1169  if(1 ==sdf->getRank()){
1170  if ("XDim" == sdf->newname)
1171  sdf->newname = "Longitude";
1172  else if ("YDim" == sdf->newname)
1173  sdf->newname = "Latitude";
1174  }
1175 
1176  for (const auto &dim:sdf->getDimensions()) {
1177  if("XDim" == dim->name)
1178  dim->name = "Longitude";
1179  else if ("YDim" == dim->name)
1180  dim->name = "Latitude";
1181  }
1182 
1183  }
1184  }
1185 
1186  // For AIRS level 2 only
1187  if(false == airs_l3) {
1188 
1189  bool change_lat_unit = false;
1190  bool change_lon_unit = false;
1191  string ll_dimname1 = "";
1192  string ll_dimname2 = "";
1193 
1194  // 1. Assign the lat/lon units according to the CF conventions.
1195  // 2. Obtain dimension names of lat/lon.
1196  for (const auto &sdf:file->sd->sdfields) {
1197 
1198  if(2 == sdf->getRank()) {
1199  if("Latitude" == sdf->newname){
1200  sdf->fieldtype = 1;
1201  change_lat_unit = true;
1202  string tempunits = "degrees_north";
1203  sdf->setUnits(tempunits);
1204  ll_dimname1 = sdf->getDimensions()[0]->getName();
1205  ll_dimname2 = sdf->getDimensions()[1]->getName();
1206 
1207  }
1208  else if("Longitude" == sdf->newname) {
1209  sdf->fieldtype = 2;
1210  change_lon_unit = true;
1211  string tempunits = "degrees_east";
1212  sdf->setUnits(tempunits);
1213  }
1214  if((true == change_lat_unit) && (true == change_lon_unit))
1215  break;
1216  }
1217  }
1218 
1219  // 2. Generate the coordinate attribute
1220  string tempcoordinates = "";
1221  string tempfieldname = "";
1222  int tempcount = 0;
1223 
1224  for (const auto &sdf:file->sd->sdfields) {
1225 
1226  // We don't want to add "coordinates" attributes to all dimension scale variables.
1227  bool dimscale_var = false;
1228  dimscale_var = (sdf->rank == 1) & ((sdf->newname) == (sdf->getDimensions()[0]->getName()));
1229 
1230  if ((0 ==sdf->fieldtype) && (false == dimscale_var)) {
1231 
1232  tempcount = 0;
1233  tempcoordinates = "";
1234  tempfieldname = "";
1235 
1236  // First check if the dimension names of this variable include both ll_dimname1 and ll_dimname2.
1237  bool has_lldim1 = false;
1238  bool has_lldim2 = false;
1239  for (const auto &dim:sdf->getDimensions ()) {
1240  if(dim->name == ll_dimname1)
1241  has_lldim1 = true;
1242  else if (dim->name == ll_dimname2)
1243  has_lldim2 = true;
1244  if((true == has_lldim1) && (true == has_lldim2))
1245  break;
1246 
1247  }
1248 
1249  if ((true == has_lldim1) && (true == has_lldim2)) {
1250  for (const auto &dim:sdf->getDimensions ()) {
1251  if(dim->name == ll_dimname1)
1252  tempfieldname = "Latitude";
1253  else if (dim->name == ll_dimname2)
1254  tempfieldname = "Longitude";
1255  else
1256  tempfieldname = dim->name;
1257 
1258  if (0 == tempcount)
1259  tempcoordinates = tempfieldname;
1260  else
1261  tempcoordinates = tempcoordinates + " " + tempfieldname;
1262  tempcount++;
1263  }
1264  }
1265  else {
1266  for (const auto &dim:sdf->getDimensions()) {
1267  if (0 == tempcount)
1268  tempcoordinates = dim->name;
1269  else
1270  tempcoordinates = tempcoordinates + " " + dim->name;
1271  tempcount++;
1272  }
1273  }
1274  sdf->setCoordinates (tempcoordinates);
1275 
1276  }
1277  }
1278  }
1279 }
1280 
1281 // This method will check if the HDF4 file is one of TRMM or OBPG products or MODISARNSS we supported.
1282 void
1284 throw (Exception)
1285 {
1286 
1287  // check the TRMM version 7 cases
1288  // The default sptype is OTHERHDF.
1289  // 2A,2B check attribute FileHeader, FileInfo and SwathHeader
1290  // 3A,3B check attribute FileHeader, FileInfo and GridHeader
1291  // 3A25 check attribute FileHeader, FileInfo and GridHeader1, GridHeader2
1292  if (this->sptype == OTHERHDF) {
1293 
1294  int trmm_multi_gridflag = 0;
1295  int trmm_single_gridflag = 0;
1296  int trmm_swathflag = 0;
1297 
1298  for (const auto &attr:this->sd->getAttributes ()) {
1299  if (attr->getName () == "FileHeader") {
1300  trmm_multi_gridflag++;
1301  trmm_single_gridflag++;
1302  trmm_swathflag++;
1303  }
1304  if (attr->getName () == "FileInfo") {
1305  trmm_multi_gridflag++;
1306  trmm_single_gridflag++;
1307  trmm_swathflag++;
1308  }
1309  if (attr->getName () == "SwathHeader")
1310  trmm_swathflag++;
1311 
1312  if (attr->getName () == "GridHeader")
1313  trmm_single_gridflag++;
1314 
1315  else if ((attr->getName ().find ("GridHeader") == 0) &&
1316  ((attr->getName()).size() >10))
1317  trmm_multi_gridflag++;
1318 
1319  }
1320 
1321 
1322  if(3 == trmm_single_gridflag)
1323  this->sptype = TRMML3S_V7;
1324  else if(3 == trmm_swathflag)
1325  this->sptype = TRMML2_V7;
1326  else if(trmm_multi_gridflag >3)
1327  this->sptype = TRMML3M_V7;
1328 
1329  }
1330 
1331  // check the TRMM and MODARNSS/MYDARNSS cases
1332  // The default sptype is OTHERHDF.
1333  if (this->sptype == OTHERHDF) {
1334 
1335  int metadataflag = 0;
1336 
1337  for (const auto &attr:this->sd->getAttributes ()) {
1338  if (attr->getName () == "CoreMetadata.0")
1339  metadataflag++;
1340  if (attr->getName () == "ArchiveMetadata.0")
1341  metadataflag++;
1342  if (attr->getName () == "StructMetadata.0")
1343  metadataflag++;
1344  if (attr->getName ().find ("SubsettingMethod") !=
1345  std::string::npos)
1346  metadataflag++;
1347  }
1348 
1349  // This is a very special MODIS product. It includes StructMetadata.0
1350  // but it is not an HDF-EOS2 file. We use metadata name "SubsettingMethod" as an indicator.
1351  // We find this metadata name is uniquely applied to this MODIS product.
1352  // We need to change the way if HDF-EOS MODIS files also use this metadata name.
1353  if (metadataflag == 4)
1354  this->sptype = MODISARNSS;
1355 
1356  // DATA_GRANULE is the TRMM "swath" name; geolocation
1357  // is the TRMM "geolocation" field.
1358  if (metadataflag == 2) {
1359 
1360  for (const auto &sdf:this->sd->getFields ()) {
1361  if ((sdf->getName () == "geolocation")
1362  && sdf->getNewName ().find ("DATA_GRANULE") != string::npos
1363  && sdf->getNewName ().find ("SwathData") != string::npos
1364  && sdf->getRank () == 3) {
1365  this->sptype = TRMML2_V6;
1366  break;
1367  }
1368  }
1369 
1370  // For TRMM Level 3 3A46, CSH, 3B42 and 3B43 data.
1371  // The vgroup name is DATA_GRANULE.
1372  // For 3B42 and 3B43, at least one field is 1440*400 array.
1373  // For CSH and 3A46 the number of dimension should be >2.
1374  // CSH: 2 dimensions should be 720 and 148.
1375  // 3A46: 2 dimensions should be 180 and 360.
1376  // The information is obtained from
1377  // http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
1378  if (this->sptype == OTHERHDF) {
1379  for (const auto &sdf:this->sd->getFields ()) {
1380  if (sdf->getNewName ().find ("DATA_GRANULE") != string::npos) {
1381  bool l3b_v6_lonflag = false;
1382  bool l3b_v6_latflag = false;
1383  for (std::vector < Dimension * >::const_iterator k =
1384  sdf->getDimensions ().begin ();
1385  k != sdf->getDimensions ().end (); ++k) {
1386  if ((*k)->getSize () == 1440)
1387  l3b_v6_lonflag = true;
1388 
1389  if ((*k)->getSize () == 400)
1390  l3b_v6_latflag = true;
1391  }
1392  if (l3b_v6_lonflag == true && l3b_v6_latflag == true) {
1393  this->sptype = TRMML3B_V6;
1394  break;
1395  }
1396 
1397  bool l3a_v6_latflag = false;
1398  bool l3a_v6_lonflag = false;
1399 
1400  bool l3c_v6_lonflag = false;
1401  bool l3c_v6_latflag = false;
1402 
1403  if (sdf->getRank()>2) {
1404  for (const auto &dim:sdf->getDimensions()) {
1405  if (dim->getSize () == 360)
1406  l3a_v6_lonflag = true;
1407 
1408  if (dim->getSize () == 180)
1409  l3a_v6_latflag = true;
1410 
1411  if (dim->getSize () == 720)
1412  l3c_v6_lonflag = true;
1413 
1414  if (dim->getSize () == 148)
1415  l3c_v6_latflag = true;
1416  }
1417 
1418  }
1419 
1420  if (true == l3a_v6_latflag && true == l3a_v6_lonflag) {
1421  this->sptype = TRMML3A_V6;
1422  break;
1423  }
1424 
1425  if (true == l3c_v6_latflag && true == l3c_v6_lonflag) {
1426  this->sptype = TRMML3C_V6;
1427  break;
1428  }
1429  }
1430  }
1431  }
1432  }
1433  }
1434 
1435 #if 0
1436 if(this->sptype == TRMML3A_V6)
1437 cerr<<"3A46 products "<<endl;
1438 if(this->sptype == TRMML3C_V6)
1439 cerr<<"CSH products "<<endl;
1440 #endif
1441 
1442  // Check the OBPG case
1443  // OBPG includes SeaWIFS,OCTS,CZCS,MODISA,MODIST
1444  // One attribute "Product Name" includes unique information for each product,
1445  // For example, SeaWIFS L2 data' "Product Name" is S2003006001857.L2_MLAC
1446  // Since we only support Level 2 and Level 3m data, we just check if those characters exist inside the attribute.
1447  // The reason we cannot support L1A data is that lat/lon consists of fill values.
1448 
1449  if (this->sptype == OTHERHDF) {
1450 
1451  // MODISA level 2 product flag
1452  int modisal2flag = 0;
1453 
1454  // MODIST level 2 product flag
1455  int modistl2flag = 0;
1456 
1457  // OCTS level 2 product flag
1458  int octsl2flag = 0;
1459 
1460  // SeaWiFS level 2 product flag
1461  int seawifsl2flag = 0;
1462 
1463  // CZCS level 2 product flag
1464  int czcsl2flag = 0;
1465 
1466  // MODISA level 3m product flag
1467  int modisal3mflag = 0;
1468 
1469  // MODIST level 3m product flag
1470  int modistl3mflag = 0;
1471 
1472  // OCTS level 3m product flag
1473  int octsl3mflag = 0;
1474 
1475  // SeaWIFS level 3m product flag
1476  int seawifsl3mflag = 0;
1477 
1478  // CZCS level 3m product flag
1479  int czcsl3mflag = 0;
1480 
1481  // Loop the global attributes and find the attribute called "Product Name"
1482  // and the attribute called "Sensor Name",
1483  // then identify different products.
1484 
1485  for (const auto &attr:this->sd->getAttributes ()) {
1486 
1487  if (attr->getName () == "Product Name") {
1488 
1489  std::string attrvalue (attr->getValue ().begin (),
1490  attr->getValue ().end ());
1491  if ((attrvalue.find_first_of ('A', 0) == 0)
1492  && (attrvalue.find (".L2", 0) != std::string::npos))
1493  modisal2flag++;
1494  else if ((attrvalue.find_first_of ('A', 0) == 0)
1495  && (attrvalue.find (".L3m", 0) != std::string::npos))
1496  modisal3mflag++;
1497  else if ((attrvalue.find_first_of ('T', 0) == 0)
1498  && (attrvalue.find (".L2", 0) != std::string::npos))
1499  modistl2flag++;
1500  else if ((attrvalue.find_first_of ('T', 0) == 0)
1501  && (attrvalue.find (".L3m", 0) != std::string::npos))
1502  modistl3mflag++;
1503  else if ((attrvalue.find_first_of ('O', 0) == 0)
1504  && (attrvalue.find (".L2", 0) != std::string::npos))
1505  octsl2flag++;
1506  else if ((attrvalue.find_first_of ('O', 0) == 0)
1507  && (attrvalue.find (".L3m", 0) != std::string::npos))
1508  octsl3mflag++;
1509  else if ((attrvalue.find_first_of ('S', 0) == 0)
1510  && (attrvalue.find (".L2", 0) != std::string::npos))
1511  seawifsl2flag++;
1512  else if ((attrvalue.find_first_of ('S', 0) == 0)
1513  && (attrvalue.find (".L3m", 0) != std::string::npos))
1514  seawifsl3mflag++;
1515  else if ((attrvalue.find_first_of ('C', 0) == 0)
1516  && ((attrvalue.find (".L2", 0) != std::string::npos)
1517  ||
1518  (attrvalue.find (".L1A", 0) != std::string::npos)))
1519  czcsl2flag++;
1520  else if ((attrvalue.find_first_of ('C', 0) == 0)
1521  && (attrvalue.find (".L3m", 0) != std::string::npos))
1522  czcsl3mflag++;
1523  }
1524  if (attr->getName () == "Sensor Name") {
1525 
1526  std::string attrvalue (attr->getValue ().begin (),
1527  attr->getValue ().end ());
1528  if (attrvalue.find ("MODISA", 0) != std::string::npos) {
1529  modisal2flag++;
1530  modisal3mflag++;
1531  }
1532  else if (attrvalue.find ("MODIST", 0) != std::string::npos) {
1533  modistl2flag++;
1534  modistl3mflag++;
1535  }
1536  else if (attrvalue.find ("OCTS", 0) != std::string::npos) {
1537  octsl2flag++;
1538  octsl3mflag++;
1539  }
1540  else if (attrvalue.find ("SeaWiFS", 0) != std::string::npos) {
1541  seawifsl2flag++;
1542  seawifsl3mflag++;
1543  }
1544  else if (attrvalue.find ("CZCS", 0) != std::string::npos) {
1545  czcsl2flag++;
1546  czcsl3mflag++;
1547  }
1548  }
1549 
1550  if ((modisal2flag == 2) || (modisal3mflag == 2)
1551  || (modistl2flag == 2) || (modistl3mflag == 2)
1552  || (octsl2flag == 2) || (octsl3mflag == 2)
1553  || (seawifsl2flag == 2) || (seawifsl3mflag == 2)
1554  || (czcsl2flag == 2) || (czcsl3mflag == 2))
1555  break;
1556 
1557  }
1558 
1559  // Only when both the sensor name and the product name match, we can
1560  // be sure the products are OBPGL2 or OBPGL3m.
1561  if ((modisal2flag == 2) || (modistl2flag == 2) ||
1562  (octsl2flag == 2) || (seawifsl2flag == 2) || (czcsl2flag == 2))
1563  this->sptype = OBPGL2;
1564 
1565  if ((modisal3mflag == 2) ||
1566  (modistl3mflag == 2) || (octsl3mflag == 2) ||
1567  (seawifsl3mflag == 2) || (czcsl3mflag == 2))
1568  this->sptype = OBPGL3;
1569 
1570  }
1571 }
1572 
1573 // Read SDS information from the HDF4 file
1574 SD *
1575 SD::Read (int32 sdfd, int32 fileid)
1576 throw (Exception)
1577 {
1578 
1579  // Indicator of status
1580  int32 status = 0;
1581 
1582  // Number of SDS objects in this file
1583  int32 n_sds = 0;
1584 
1585  // Number of SDS attributes in this file
1586  int32 n_sd_attrs = 0;
1587 
1588  // SDS ID
1589  int32 sds_id = 0;
1590 
1591  // Dimension sizes
1592  int32 dim_sizes[H4_MAX_VAR_DIMS];
1593 
1594  // number of SDS attributes
1595  int32 n_sds_attrs = 0;
1596 
1597  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
1598  // Documented in a jira ticket HFRHANDLER-168.
1599 
1600  // SDS name
1601  char sds_name[H4_MAX_NC_NAME];
1602 
1603  // SDS dimension names
1604  char dim_name[H4_MAX_NC_NAME];
1605 
1606  // SDS attribute names
1607  char attr_name[H4_MAX_NC_NAME];
1608 
1609  // Dimension size
1610  int32 dim_size = 0;
1611 
1612  // SDS reference number
1613  int32 sds_ref = 0;
1614 
1615  // Dimension type(if dimension type is 0, this dimension doesn't have dimension scales)
1616  // Otherwise, this dimension type is the datatype of this dimension scale.
1617  int32 dim_type = 0;
1618 
1619 #if 0
1620  // Number of dimension attributes(This is almost never used)
1621  //int32 num_dim_attrs = 0;
1622 #endif
1623 
1624  // Attribute value count
1625  int32 attr_value_count = 0;
1626 
1627  // Obtain a SD instance
1628  auto sd = new SD ();
1629 
1630 
1631  // Obtain number of SDS objects and number of SD(file) attributes
1632  if (SDfileinfo (sdfd, &n_sds, &n_sd_attrs) == FAIL) {
1633  delete sd;
1634  throw2 ("SDfileinfo failed ", sdfd);
1635  }
1636 
1637  // Go through the SDS object
1638  for (int sds_index = 0; sds_index < n_sds; sds_index++) {
1639 
1640  // New SDField instance
1641  auto field = new SDField ();
1642 
1643  // Obtain SDS ID.
1644  sds_id = SDselect (sdfd, sds_index);
1645  if (sds_id == FAIL) {
1646  delete sd;
1647  delete field;
1648  // We only need to close SDS ID. SD ID will be closed when the destructor is called.
1649  SDendaccess (sds_id);
1650  throw3 ("SDselect Failed ", "SDS index ", sds_index);
1651  }
1652 
1653  // Obtain SDS reference number
1654  sds_ref = SDidtoref (sds_id);
1655  if (sds_ref == FAIL) {
1656  delete sd;
1657  delete field;
1658  SDendaccess (sds_id);
1659  throw3 ("Cannot obtain SDS reference number", " SDS ID is ",
1660  sds_id);
1661  }
1662 
1663  // Obtain object name, rank, size, field type and number of SDS attributes
1664  status = SDgetinfo (sds_id, sds_name, &field->rank, dim_sizes,
1665  &field->type, &n_sds_attrs);
1666  if (status == FAIL) {
1667  delete sd;
1668  delete field;
1669  SDendaccess (sds_id);
1670  throw2 ("SDgetinfo failed ", sds_name);
1671  }
1672 
1673  //Assign SDS field info. to class field instance.
1674  string tempname (sds_name);
1675  field->name = tempname;
1676  field->newname = field->name;
1677  field->fieldref = sds_ref;
1678  // This will be used to obtain the SDS full path later.
1679  sd->refindexlist[sds_ref] = sds_index;
1680 
1681  // Handle dimension scale
1682  bool dim_no_dimscale = false;
1683  vector <int> dimids;
1684  if (field->rank >0)
1685  dimids.assign(field->rank,0);
1686 
1687  // Assign number of dimension attribute vector
1688  vector <int>num_dim_attrs;
1689  if (field->rank >0)
1690  num_dim_attrs.assign(field->rank,0);
1691 
1692  // Handle dimensions with original dimension names
1693  for (int dimindex = 0; dimindex < field->rank; dimindex++) {
1694 
1695  // Obtain dimension ID.
1696  int dimid = SDgetdimid (sds_id, dimindex);
1697  if (dimid == FAIL) {
1698  delete sd;
1699  delete field;
1700  SDendaccess (sds_id);
1701  throw5 ("SDgetdimid failed ", "SDS name ", sds_name,
1702  "dim index= ", dimindex);
1703  }
1704 
1705  // Obtain dimension info.: dim_name, dim_size,dim_type and num of dim. attrs.
1706  int32 temp_num_dim_attrs = 0;
1707  status = SDdiminfo (dimid, dim_name, &dim_size, &dim_type, &temp_num_dim_attrs);
1708  if (status == FAIL) {
1709  delete sd;
1710  delete field;
1711  SDendaccess (sds_id);
1712  throw5 ("SDdiminfo failed ", "SDS name ", sds_name,
1713  "dim index= ", dimindex);
1714  }
1715 
1716  num_dim_attrs[dimindex] = temp_num_dim_attrs;
1717 
1718  // No dimension attribute has been found in NASA files,
1719  // so don't handle it now. KY 2010-06-08
1720 
1721  // Dimension attributes are found in one JPL file(S2000415.HDF).
1722  // So handle it.
1723  // If the corresponding dimension scale exists, no need to
1724  // specially handle the attributes.
1725  // But when the dimension scale doesn't exist, we would like to
1726  // handle the attributes following
1727  // the default HDF4 handler. We will add attribute containers.
1728  // For example, variable name foo has
1729  // two dimensions, foo1, foo2. We just create two attribute names:
1730  // foo_dim0, foo_dim1,
1731  // foo_dim0 will include an attribute "name" with the value as
1732  // foo1 and other attributes.
1733  // KY 2012-09-11
1734 
1735  string dim_name_str (dim_name);
1736 
1737  // Since dim_size will be 0 if the dimension is
1738  // unlimited dimension, so use dim_sizes instead
1739  auto dim = new Dimension (dim_name_str, dim_sizes[dimindex], dim_type);
1740 
1741  // Save this dimension
1742  field->dims.push_back (dim);
1743 
1744  // First check if there are dimensions in this field that
1745  // don't have dimension scales.
1746  dimids[dimindex] = dimid;
1747  if (0 == dim_type) {
1748  if (false == dim_no_dimscale)
1749  dim_no_dimscale = true;
1750  if ((dim_name_str == field->name) && (1 == field->rank))
1751  field->is_noscale_dim = true;
1752  }
1753  }
1754 
1755  // Find dimensions that have no dimension scales,
1756  // add attribute for this whole field ???_dim0, ???_dim1 etc.
1757 
1758  if( true == dim_no_dimscale) {
1759 
1760  for (int dimindex = 0; dimindex < field->rank; dimindex++) {
1761 
1762  string dim_name_str = (field->dims)[dimindex]->name;
1763  auto dim_info = new AttrContainer ();
1764  string index_str;
1765  stringstream out_index;
1766  out_index << dimindex;
1767  index_str = out_index.str();
1768  dim_info->name = "_dim_" + index_str;
1769 
1770  // newname will be created at the final stage.
1771 
1772  bool dimname_flag = false;
1773 
1774  int32 dummy_type = 0;
1775  int32 dummy_value_count = 0;
1776 
1777  // Loop through to check if an attribute called "name" exists and set a flag.
1778  for (int attrindex = 0; attrindex < num_dim_attrs[dimindex]; attrindex++) {
1779 
1780  status = SDattrinfo(dimids[dimindex],attrindex,attr_name,
1781  &dummy_type,&dummy_value_count);
1782  if (status == FAIL) {
1783  delete sd;
1784  delete field;
1785  SDendaccess (sds_id);
1786  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
1787  }
1788 
1789  string tempname2(attr_name);
1790  if ("name"==tempname2) {
1791  dimname_flag = true;
1792  break;
1793  }
1794  }
1795 
1796  // Loop through to obtain the dimension attributes and save the corresponding attributes to dim_info.
1797  for (int attrindex = 0; attrindex < num_dim_attrs[dimindex]; attrindex++) {
1798 
1799  auto attr = new Attribute();
1800  status = SDattrinfo(dimids[dimindex],attrindex,attr_name,
1801  &attr->type,&attr_value_count);
1802  if (status == FAIL) {
1803  delete sd;
1804  delete field;
1805  SDendaccess (sds_id);
1806  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
1807  }
1808  string tempname3 (attr_name);
1809  attr->name = tempname3;
1810  tempname3 = HDFCFUtil::get_CF_string(tempname3);
1811 
1812  attr->newname = tempname3;
1813  attr->count = attr_value_count;
1814  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
1815  if (SDreadattr (dimids[dimindex], attrindex, &attr->value[0]) == -1) {
1816  delete sd;
1817  delete field;
1818  SDendaccess (sds_id);
1819  throw5 ("read SDS attribute failed ", "Field name ",
1820  field->name, " Attribute name ", attr->name);
1821  }
1822 
1823  dim_info->attrs.push_back (attr);
1824 
1825  }
1826 
1827  // If no attribute called "name", we create an attribute "name" and save the name of the attribute
1828  // as the attribute value.
1829  if (false == dimname_flag) {
1830 
1831  auto attr = new Attribute();
1832  attr->name = "name";
1833  attr->newname = "name";
1834  attr->type = DFNT_CHAR;
1835  attr->count = dim_name_str.size();
1836  attr->value.resize(attr->count);
1837  copy(dim_name_str.begin(),dim_name_str.end(),attr->value.begin());
1838  dim_info->attrs.push_back(attr);
1839 
1840  }
1841  field->dims_info.push_back(dim_info);
1842  }
1843  }
1844 
1845  // Loop through all the SDS attributes and save them to the class field instance.
1846  for (int attrindex = 0; attrindex < n_sds_attrs; attrindex++) {
1847  auto attr = new Attribute ();
1848  status =
1849  SDattrinfo (sds_id, attrindex, attr_name, &attr->type,
1850  &attr_value_count);
1851 
1852  if (status == FAIL) {
1853  delete attr;
1854  delete sd;
1855  delete field;
1856  SDendaccess (sds_id);
1857  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
1858  }
1859 
1860  if(attr != nullptr) {//Make coverity happy(it doesn't understand the throw macro.
1861  string tempname4 (attr_name);
1862  attr->name = tempname4;
1863  tempname4 = HDFCFUtil::get_CF_string(tempname4);
1864 
1865  attr->newname = tempname4;
1866  attr->count = attr_value_count;
1867  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
1868  if (SDreadattr (sds_id, attrindex, &attr->value[0]) == -1) {
1869  string temp_field_name = field->name;
1870  string temp_attr_name = attr->name;
1871  delete attr;
1872  delete sd;
1873  delete field;
1874  SDendaccess (sds_id);
1875  throw5 ("read SDS attribute failed ", "Field name ",
1876  temp_field_name, " Attribute name ", temp_attr_name);
1877  }
1878  field->attrs.push_back (attr);
1879  }
1880  }
1881  SDendaccess (sds_id);
1882  sd->sdfields.push_back (field);
1883  }
1884 
1885  // Loop through all SD(file) attributes and save them to the class sd instance.
1886  for (int attrindex = 0; attrindex < n_sd_attrs; attrindex++) {
1887 
1888  auto attr = new Attribute ();
1889  status = SDattrinfo (sdfd, attrindex, attr_name, &attr->type,
1890  &attr_value_count);
1891  if (status == FAIL) {
1892  delete attr;
1893  delete sd;
1894  throw3 ("SDattrinfo failed ", "SD id ", sdfd);
1895  }
1896  if(attr != nullptr) {//Make coverity happy because it doesn't understand throw3
1897  std::string tempname5 (attr_name);
1898  attr->name = tempname5;
1899 
1900  // Checking and handling the special characters for the SDS attribute name.
1901  tempname5 = HDFCFUtil::get_CF_string(tempname5);
1902  attr->newname = tempname5;
1903  attr->count = attr_value_count;
1904  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
1905  if (SDreadattr (sdfd, attrindex, &attr->value[0]) == -1) {
1906  delete attr;
1907  delete sd;
1908  throw3 ("Cannot read SD attribute", " Attribute name ",
1909  attr_name);
1910  }
1911  sd->attrs.push_back (attr);
1912  }
1913  }
1914 
1915  return sd;
1916 
1917 }
1918 
1919 // Retrieve the extra SDS object info. from a hybrid HDF-EOS2 file
1920 SD *
1921 SD::Read_Hybrid (int32 sdfd, int32 fileid)
1922 throw (Exception)
1923 {
1924  // Indicator of status
1925  int32 status = 0;
1926 
1927  // Number of SDS objects in this file
1928  int32 n_sds = 0;
1929 
1930  // Number of SDS attributes in this file
1931  int32 n_sd_attrs = 0;
1932 
1933  // SDS Object index
1934  int sds_index = 0;
1935 
1936  // Extra SDS object index
1937  int extra_sds_index = 0;
1938 
1939  // SDS ID
1940  int32 sds_id = 0;
1941 
1942  // Dimension sizes
1943  int32 dim_sizes[H4_MAX_VAR_DIMS];
1944 
1945  // number of SDS attributes
1946  int32 n_sds_attrs = 0;
1947 
1948  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
1949  // Documented in a jira ticket HFRHANDLER-168.
1950 
1951  // SDS name
1952  char sds_name[H4_MAX_NC_NAME];
1953 
1954  // SDS dimension names
1955  char dim_name[H4_MAX_NC_NAME];
1956 
1957  // SDS attribute names
1958  char attr_name[H4_MAX_NC_NAME];
1959 
1960  // Dimension size
1961  int32 dim_size = 0;
1962 
1963  // SDS reference number
1964  int32 sds_ref = 0;
1965 
1966  // Dimension type(if dimension type is 0, this dimension doesn't have dimension scales)
1967  // Otherwise, this dimension type is the datatype of this dimension scale.
1968  int32 dim_type = 0;
1969 
1970  // Number of dimension attributes(This is almost never used)
1971  int32 num_dim_attrs = 0;
1972 
1973  // Attribute value count
1974  int32 attr_value_count = 0;
1975 
1976 
1977  // TO OBTAIN the full path of the SDS objects
1978  int32 vgroup_id = 0;
1979 
1980  // lone vgroup index
1981  int32 lone_vg_number = 0;
1982 
1983  // number of lone vgroups
1984  int32 num_of_lones = -1;
1985 
1986  int32 num_gobjects = 0;
1987 
1988  // Object reference and tag pair. Key to find an HDF4 object
1989  int32 obj_ref = 0;
1990  int32 obj_tag = 0;
1991 
1992 
1993  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
1994  // Documented in a jira ticket HFRHANDLER-168.
1995  char vgroup_name[VGNAMELENMAX*4];
1996  char vgroup_class[VGNAMELENMAX*4];
1997 
1998  // full path of an object
1999  char *full_path = nullptr;
2000  // char full_path[MAX_FULL_PATH_LEN];
2001 
2002  // copy of the full path
2003  char *cfull_path = nullptr;
2004 // char cfull_path[MAX_FULL_PATH_LEN];
2005 
2006  // Obtain a SD instance
2007  SD *sd = new SD ();
2008 
2009  // Obtain number of SDS objects and number of SD(file) attributes
2010  if (SDfileinfo (sdfd, &n_sds, &n_sd_attrs) == FAIL) {
2011  if(sd != nullptr)
2012  delete sd;
2013  throw2 ("SDfileinfo failed ", sdfd);
2014  }
2015 
2016  // Loop through all SDS objects to obtain the SDS reference numbers.
2017  // Then save the reference numbers into the SD instance sd.
2018  for (sds_index = 0; sds_index < n_sds; sds_index++) {
2019  sds_id = SDselect (sdfd, sds_index);
2020 
2021  if (sds_id == FAIL) {
2022  if(sd != nullptr)
2023  delete sd;
2024  // We only need to close SDS ID. SD ID will be closed when
2025  // the destructor is called.
2026  SDendaccess (sds_id);
2027  throw3 ("SDselect Failed ", "SDS index ", sds_index);
2028  }
2029 
2030  sds_ref = SDidtoref (sds_id);
2031  if (sds_ref == FAIL) {
2032  if(sd != nullptr)
2033  delete sd;
2034  SDendaccess (sds_id);
2035  throw3 ("Cannot obtain SDS reference number", " SDS ID is ",
2036  sds_id);
2037  }
2038  sd->sds_ref_list.push_back(sds_ref);
2039  SDendaccess(sds_id);
2040  }
2041 
2042  // Now we need to obtain the sds reference numbers
2043  // for SDS objects that are accessed as the HDF-EOS2 grid or swath.
2044  // No NASA HDF4 files have the vgroup that forms a ring; so ignore this case.
2045  // First, call Vlone with num_of_lones set to 0 to get the number of
2046  // lone vgroups in the file, but not to get their reference numbers.
2047 
2048  num_of_lones = Vlone (fileid, nullptr, 0);
2049  if (num_of_lones == FAIL){
2050  if(sd != nullptr)
2051  delete sd;
2052  throw3 ("Fail to obtain lone vgroup number", "file id is", fileid);
2053  }
2054 
2055  // if there are any lone vgroups,
2056  if (num_of_lones > 0) {
2057 
2058  // use the num_of_lones returned to allocate sufficient space for the
2059  // buffer ref_array to hold the reference numbers of all lone vgroups,
2060  vector<int32>ref_array;
2061  ref_array.resize(num_of_lones);
2062 
2063  // and call Vlone again to retrieve the reference numbers into
2064  // the buffer ref_array.
2065  num_of_lones = Vlone (fileid, ref_array.data(), num_of_lones);
2066  if (num_of_lones == FAIL) {
2067  if(sd != nullptr)
2068  delete sd;
2069  throw3 ("Cannot obtain lone vgroup reference arrays ",
2070  "file id is ", fileid);
2071  }
2072 
2073  // loop through all the lone vgroup objects
2074  for (lone_vg_number = 0; lone_vg_number < num_of_lones;
2075  lone_vg_number++) {
2076 
2077  // Attach to the current vgroup
2078  vgroup_id = Vattach (fileid, ref_array[lone_vg_number], "r");
2079  if (vgroup_id == FAIL) {
2080  if(sd != nullptr)
2081  delete sd;
2082  throw3 ("Vattach failed ", "Reference number is ",
2083  ref_array[lone_vg_number]);
2084  }
2085 
2086  status = Vgetname (vgroup_id, vgroup_name);
2087  if (status == FAIL) {
2088  if(sd != nullptr)
2089  delete sd;
2090  Vdetach (vgroup_id);
2091  throw3 ("Vgetname failed ", "vgroup_id is ", vgroup_id);
2092  }
2093 
2094  status = Vgetclass (vgroup_id, vgroup_class);
2095  if (status == FAIL) {
2096  if(sd != nullptr)
2097  delete sd;
2098  Vdetach (vgroup_id);
2099  throw3 ("Vgetclass failed ", "vgroup_name is ", vgroup_name);
2100  }
2101 
2102  //Ignore internal HDF groups
2103  if (strcmp (vgroup_class, _HDF_ATTRIBUTE) == 0
2104  || strcmp (vgroup_class, _HDF_VARIABLE) == 0
2105  || strcmp (vgroup_class, _HDF_DIMENSION) == 0
2106  || strcmp (vgroup_class, _HDF_UDIMENSION) == 0
2107  || strcmp (vgroup_class, _HDF_CDF) == 0
2108  || strcmp (vgroup_class, GR_NAME) == 0
2109  || strcmp (vgroup_class, RI_NAME) == 0) {
2110  Vdetach (vgroup_id);
2111  continue;
2112  }
2113 
2114  // Obtain the number of objects of this vgroup
2115  num_gobjects = Vntagrefs (vgroup_id);
2116  if (num_gobjects < 0) {
2117  if(sd != nullptr)
2118  delete sd;
2119  Vdetach (vgroup_id);
2120  throw3 ("Vntagrefs failed ", "vgroup_name is ", vgroup_name);
2121  }
2122 
2123  // Obtain the vgroup full path and the copied vgroup full path
2124  // MAX_FULL_PATH_LEN(1024) is long enough
2125  // to cover any HDF4 object path for all NASA HDF4 products.
2126  // So using strcpy and strcat is safe in a practical sense.
2127  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
2128  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
2129  // Documented in a jira ticket HFRHANDLER-168.
2130  // KY 2013-07-12
2131  // We replace strcpy and strcat with strncpy and strncat as suggested. KY 2013-08-29
2132 
2133  full_path = (char *) malloc (MAX_FULL_PATH_LEN);
2134  if (full_path == nullptr) {
2135  if(sd!= nullptr)
2136  delete sd;
2137  Vdetach (vgroup_id);
2138  throw1 ("No enough memory to allocate the buffer.");
2139  }
2140  else
2141  memset(full_path,'\0',MAX_FULL_PATH_LEN);
2142  strncpy(full_path,_BACK_SLASH,strlen(_BACK_SLASH));
2143  strncat(full_path, vgroup_name,strlen(vgroup_name));
2144 
2145  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
2146  if (cfull_path == nullptr) {
2147  if(sd != nullptr)
2148  delete sd;
2149  Vdetach (vgroup_id);
2150  if(full_path != nullptr)
2151  free (full_path);
2152  throw1 ("No enough memory to allocate the buffer.");
2153  }
2154  else
2155  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
2156  strncpy (cfull_path, full_path,strlen(full_path));
2157 
2158  // Loop all objects in this vgroup
2159  for (int i = 0; i < num_gobjects; i++) {
2160 
2161  // Obtain the object reference and tag of this object
2162  if (Vgettagref (vgroup_id, i, &obj_tag, &obj_ref) == FAIL) {
2163  if(sd != nullptr)
2164  delete sd;
2165  Vdetach (vgroup_id);
2166  if(full_path != nullptr)
2167  free (full_path);
2168  if(cfull_path != nullptr)
2169  free (cfull_path);
2170  throw5 ("Vgettagref failed ", "vgroup_name is ",
2171  vgroup_name, " reference number is ", obj_ref);
2172  }
2173 
2174  // If this object is a vgroup, will call recursively to obtain the SDS path.
2175  if (Visvg (vgroup_id, obj_ref) == TRUE) {
2176  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
2177  full_path[strlen(cfull_path)]='\0';
2178  sd->obtain_noneos2_sds_path (fileid, full_path, obj_ref);
2179  }
2180 
2181  // These are SDS objects
2182  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
2183  || obj_tag == DFTAG_SD) {
2184 
2185  // Here we need to check if the SDS is an EOS object by checking
2186  // if the the path includes "Data Fields" or "Geolocation Fields".
2187  // If the object is an EOS object, we will remove the sds
2188  // reference number from the list.
2189  auto temp_str = string(full_path);
2190  if((temp_str.find("Data Fields") != std::string::npos)||
2191  (temp_str.find("Geolocation Fields") != std::string::npos))
2192  sd->sds_ref_list.remove(obj_ref);
2193 
2194  }
2195  // Do nothing for other objects
2196  }
2197  free (full_path);
2198  free (cfull_path);
2199 
2200  status = Vdetach (vgroup_id);
2201 
2202  if (status == FAIL) {
2203  if(sd != nullptr)
2204  delete sd;
2205  throw3 ("Vdetach failed ", "vgroup_name is ", vgroup_name);
2206  }
2207  }//end of the for loop
2208 
2209  }// end of the if loop
2210 
2211  // Loop through the sds reference list; now the list should only include non-EOS SDS objects.
2212 #if 0
2213  for(std::list<int32>::iterator sds_ref_it = sd->sds_ref_list.begin();
2214  sds_ref_it!=sd->sds_ref_list.end();++sds_ref_it) {
2215 #endif
2216  for (const auto &sds_ref:sd->sds_ref_list) {
2217 
2218  extra_sds_index = SDreftoindex(sdfd,sds_ref);
2219  if(extra_sds_index == FAIL) {
2220  delete sd;
2221  throw3("SDreftoindex Failed ","SDS reference number ", sds_ref);
2222  }
2223 
2224  auto field = new SDField ();
2225  sds_id = SDselect (sdfd, extra_sds_index);
2226  if (sds_id == FAIL) {
2227  delete field;
2228  delete sd;
2229  // We only need to close SDS ID. SD ID will be closed when the destructor is called.
2230  SDendaccess (sds_id);
2231  throw3 ("SDselect Failed ", "SDS index ", extra_sds_index);
2232  }
2233 
2234  // Obtain object name, rank, size, field type and number of SDS attributes
2235  status = SDgetinfo (sds_id, sds_name, &field->rank, dim_sizes,
2236  &field->type, &n_sds_attrs);
2237  if (status == FAIL) {
2238  delete field;
2239  delete sd;
2240  SDendaccess (sds_id);
2241  throw2 ("SDgetinfo failed ", sds_name);
2242  }
2243 
2244  // new name for added SDS objects are renamed as original_name + "NONEOS".
2245  string tempname (sds_name);
2246  field->name = tempname;
2247  tempname = HDFCFUtil::get_CF_string(tempname);
2248  field->newname = tempname+"_"+"NONEOS";
2249  field->fieldref = sds_ref;
2250  sd->refindexlist[sds_ref] = extra_sds_index;
2251 
2252  // Handle dimensions with original dimension names
2253  for (int dimindex = 0; dimindex < field->rank; dimindex++) {
2254  int dimid = SDgetdimid (sds_id, dimindex);
2255  if (dimid == FAIL) {
2256  delete field;
2257  delete sd;
2258  SDendaccess (sds_id);
2259  throw5 ("SDgetdimid failed ", "SDS name ", sds_name,
2260  "dim index= ", dimindex);
2261  }
2262  status = SDdiminfo (dimid, dim_name, &dim_size, &dim_type,
2263  &num_dim_attrs);
2264 
2265  if (status == FAIL) {
2266  delete field;
2267  delete sd;
2268  SDendaccess (sds_id);
2269  throw5 ("SDdiminfo failed ", "SDS name ", sds_name,
2270  "dim index= ", dimindex);
2271  }
2272 
2273  string dim_name_str (dim_name);
2274 
2275  // Since dim_size will be 0 if the dimension is unlimited dimension,
2276  // so use dim_sizes instead
2277  auto dim = new Dimension (dim_name_str, dim_sizes[dimindex], dim_type);
2278 
2279  field->dims.push_back (dim);
2280 
2281  // The corrected dims are added simply for the consistency in hdfdesc.cc,
2282  // it doesn't matter
2283  // for the added SDSes at least for now. KY 2011-2-13
2284 
2285  // However, some dimension names have special characters.
2286  // We need to remove special characters.
2287  // Since no coordinate attributes will be provided for
2288  // these extra SDSes, we don't need to
2289  // make the dimension names consistent with other dimension names.
2290  // But we need to keep an eye
2291  // on if the units of the extra SDSes are degrees_north or degrees_east.
2292  // This will make the tools
2293  // automatically treat them as latitude or longitude.
2294  // Need to double check. KY 2011-2-17
2295  // So far we don't meet the above case. KY 2013-07-12
2296 
2297  string cfdimname = HDFCFUtil::get_CF_string(dim_name_str);
2298  auto correcteddim =
2299  new Dimension (cfdimname, dim_sizes[dimindex], dim_type);
2300 
2301  field->correcteddims.push_back (correcteddim);
2302 
2303  }
2304 
2305  // Loop through all SDS attributes and save them to field.
2306  for (int attrindex = 0; attrindex < n_sds_attrs; attrindex++) {
2307 
2308  auto attr = new Attribute ();
2309 
2310  status = SDattrinfo (sds_id, attrindex, attr_name, &attr->type,
2311  &attr_value_count);
2312  if (status == FAIL) {
2313  delete attr;
2314  delete field;
2315  delete sd;
2316  SDendaccess (sds_id);
2317  throw3 ("SDattrinfo failed ", "SDS name ", sds_name);
2318  }
2319 
2320  string temp_attrname (attr_name);
2321  attr->name = temp_attrname;
2322 
2323  // Checking and handling the special characters for the SDS attribute name.
2324  temp_attrname = HDFCFUtil::get_CF_string(temp_attrname);
2325  attr->newname = temp_attrname;
2326  attr->count = attr_value_count;
2327  attr->value.resize (attr_value_count * DFKNTsize (attr->type));
2328  if (SDreadattr (sds_id, attrindex, &attr->value[0]) == -1) {
2329  delete attr;
2330  delete field;
2331  delete sd;
2332  SDendaccess (sds_id);
2333  throw5 ("read SDS attribute failed ", "Field name ",
2334  field->name, " Attribute name ", attr->name);
2335  }
2336  field->attrs.push_back (attr);
2337  }
2338  SDendaccess (sds_id);
2339  sd->sdfields.push_back (field);
2340  }
2341  return sd;
2342 }
2343 
2344 // Retrieve Vdata information from the HDF4 file
2345 VDATA *
2346 VDATA::Read (int32 vdata_id, int32 obj_ref)
2347 throw (Exception)
2348 {
2349 
2350  // Vdata field size
2351  int32 fieldsize = 0;
2352 
2353  // Vdata field datatype
2354  int32 fieldtype = 0;
2355 
2356  // Vdata field order
2357  int32 fieldorder = 0;
2358 
2359  // Vdata field name
2360  char *fieldname = nullptr;
2361 
2362  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
2363  // Documented in a jira ticket HFRHANDLER-168.
2364  char vdata_name[VSNAMELENMAX];
2365 
2366  auto vdata = new VDATA (obj_ref);
2367 
2368  vdata->vdref = obj_ref;
2369 
2370  if (VSQueryname (vdata_id, vdata_name) == FAIL){
2371  delete vdata;
2372  throw3 ("VSQueryname failed ", "vdata id is ", vdata_id);
2373  }
2374 
2375  string vdatanamestr (vdata_name);
2376 
2377  vdata->name = vdatanamestr;
2378  vdata->newname = HDFCFUtil::get_CF_string(vdata->name);
2379  int32 num_field = VFnfields (vdata_id);
2380 
2381  if (num_field == -1){
2382  delete vdata;
2383  throw3 ("For vdata, VFnfields failed. ", "vdata name is ",
2384  vdata->name);
2385  }
2386 
2387  int32 num_record = VSelts (vdata_id);
2388 
2389  if (num_record == -1) {
2390  delete vdata;
2391  throw3 ("For vdata, VSelts failed. ", "vdata name is ", vdata->name);
2392  }
2393 
2394 
2395  // Using the BES KEY for people to choose to map the vdata to attribute for a smaller number of record.
2396  // KY 2012-6-26
2397 
2398  // The reason to add this flag is if the number of record is too big, the DAS table is too huge to allow some clients to work.
2399  // Currently if the number of record is >=10; one vdata field is mapped to a DAP variable.
2400  // Otherwise, it is mapped to a DAP attribute.
2401 
2402  if (num_record <= 10 && true == HDF4RequestHandler::get_enable_vdata_attr())
2403  vdata->TreatAsAttrFlag = true;
2404  else
2405  vdata->TreatAsAttrFlag = false;
2406 
2407  // Loop through all fields and save information to a vector
2408  for (int i = 0; i < num_field; i++) {
2409 
2410  auto field = new VDField ();
2411 
2412  if(field == nullptr) {
2413  delete vdata;
2414  throw1("Memory allocation for field class failed.");
2415 
2416  }
2417  fieldsize = VFfieldesize (vdata_id, i);
2418  if (fieldsize == FAIL) {
2419  string temp_vdata_name = vdata->name;
2420  delete field;
2421  delete vdata;
2422  throw5 ("For vdata field, VFfieldsize failed. ", "vdata name is ",
2423  temp_vdata_name, " index is ", i);
2424  }
2425 
2426  fieldname = VFfieldname (vdata_id, i);
2427  if (fieldname == nullptr) {
2428  string temp_vdata_name = vdata->name;
2429  delete field;
2430  delete vdata;
2431  throw5 ("For vdata field, VFfieldname failed. ", "vdata name is ",
2432  temp_vdata_name, " index is ", i);
2433  }
2434 
2435  fieldtype = VFfieldtype (vdata_id, i);
2436  if (fieldtype == FAIL) {
2437  string temp_vdata_name = vdata->name;
2438  delete field;
2439  delete vdata;
2440  throw5 ("For vdata field, VFfieldtype failed. ", "vdata name is ",
2441  temp_vdata_name, " index is ", i);
2442  }
2443 
2444  fieldorder = VFfieldorder (vdata_id, i);
2445  if (fieldorder == FAIL) {
2446  string temp_vdata_name = vdata->name;
2447  delete field;
2448  delete vdata;
2449  throw5 ("For vdata field, VFfieldtype failed. ", "vdata name is ",
2450  temp_vdata_name, " index is ", i);
2451  }
2452 
2453  if(fieldname !=nullptr) // Only make coverity happy
2454  field->name = fieldname;
2455  field->newname = HDFCFUtil::get_CF_string(field->name);
2456  field->type = fieldtype;
2457  field->order = fieldorder;
2458  field->size = fieldsize;
2459  field->rank = 1;
2460  field->numrec = num_record;
2461 
2462 #if 0
2463 //cerr<<"vdata field name is "<<field->name <<endl;
2464 //cerr<<"vdata field type is "<<field->type <<endl;
2465 #endif
2466 
2467 
2468  if (vdata->getTreatAsAttrFlag () && num_record > 0) { // Currently we only save small size vdata to attributes
2469 
2470  field->value.resize (num_record * fieldsize);
2471  if (VSseek (vdata_id, 0) == FAIL) {
2472  if(field != nullptr)
2473  delete field;
2474  if(vdata != nullptr)
2475  delete vdata;
2476  throw5 ("vdata ", vdata_name, "field ", fieldname,
2477  " VSseek failed.");
2478  }
2479 
2480  if (VSsetfields (vdata_id, fieldname) == FAIL) {
2481  if(field != nullptr)
2482  delete field;
2483  if(vdata != nullptr)
2484  delete vdata;
2485  throw3 ("vdata field ", fieldname, " VSsetfields failed.");
2486  }
2487 
2488  if (VSread
2489  (vdata_id, (uint8 *) & field->value[0], num_record,
2490  FULL_INTERLACE) == FAIL){
2491  if(field != nullptr)
2492  delete field;
2493  if(vdata != nullptr)
2494  delete vdata;
2495  throw3 ("vdata field ", fieldname, " VSread failed.");
2496  }
2497 
2498  }
2499 
2500  if(field != nullptr) {// Coverity doesn't know the throw macro. See if this makes it happy.
2501  try {
2502  // Read field attributes
2503  field->ReadAttributes (vdata_id, i);
2504  }
2505  catch(...) {
2506  delete field;
2507  delete vdata;
2508  throw;
2509  }
2510  vdata->vdfields.push_back (field);
2511  }
2512  }
2513 
2514  try {
2515  // Read Vdata attributes
2516  vdata->ReadAttributes (vdata_id);
2517  }
2518  catch(...) {
2519  delete vdata;
2520  throw;
2521  }
2522  return vdata;
2523 
2524 }
2525 
2526 // Read Vdata attributes and save them into vectors
2527 void
2528 VDATA::ReadAttributes (int32 vdata_id)
2529 throw (Exception)
2530 {
2531  // Vdata attribute name
2532  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
2533  // Documented in a jira ticket HFRHANDLER-168.
2534  char attr_name[H4_MAX_NC_NAME];
2535 
2536  // Number of attributes
2537  int32 nattrs = 0;
2538 
2539  // Number of attribute size
2540  int32 attrsize = 0;
2541 
2542  // API status indicator
2543  int32 status = 0;
2544 
2545  // Number of vdata attributes
2546  nattrs = VSfnattrs (vdata_id, _HDF_VDATA);
2547 
2548 // This is just to check if the weird MacOS portability issue go away.KY 2011-3-31
2549 #if 0
2550  if (nattrs == FAIL)
2551  throw3 ("VSfnattrs failed ", "vdata id is ", vdata_id);
2552 #endif
2553 
2554  if (nattrs > 0) {
2555 
2556  // Obtain number of vdata attributes
2557  for (int i = 0; i < nattrs; i++) {
2558 
2559  auto attr = new Attribute ();
2560 
2561  status = VSattrinfo (vdata_id, _HDF_VDATA, i, attr_name,
2562  &attr->type, &attr->count, &attrsize);
2563  if (status == FAIL) {
2564  delete attr;
2565  throw5 ("VSattrinfo failed ", "vdata id is ", vdata_id,
2566  " attr index is ", i);
2567  }
2568 
2569  // Checking and handling the special characters for the vdata attribute name.
2570  string tempname(attr_name);
2571  if(attr != nullptr) {
2572  attr->name = tempname;
2573  attr->newname = HDFCFUtil::get_CF_string(attr->name);
2574  attr->value.resize (attrsize);
2575  }
2576  if (VSgetattr (vdata_id, _HDF_VDATA, i, &attr->value[0]) == FAIL) {
2577  delete attr;
2578  throw5 ("VSgetattr failed ", "vdata id is ", vdata_id,
2579  " attr index is ", i);
2580  }
2581  attrs.push_back (attr);
2582  }
2583  }
2584 }
2585 
2586 
2587 // Retrieve VD field attributes from the HDF4 file.
2588 // Input parameters are vdata ID and vdata field index
2589 void
2590 VDField::ReadAttributes (int32 vdata_id, int32 fieldindex)
2591 throw (Exception)
2592 {
2593  // In the future, we may use the latest HDF4 APIs to obtain the length of object names etc. dynamically.
2594  // Documented in a jira ticket HFRHANDLER-168.
2595  // vdata field attribute name
2596  char attr_name[H4_MAX_NC_NAME];
2597 
2598  // Number of vdata field attributes
2599  int32 nattrs = 0;
2600 
2601  // Vdata attribute size
2602  int32 attrsize = 0;
2603 
2604  // Indicator of vdata field APIs
2605  int32 status = 0;
2606 
2607  // Obtain
2608  nattrs = VSfnattrs (vdata_id, fieldindex);
2609 
2610 // This is just to check if the weird MacOS portability issue go away.KY 2011-3-9
2611 #if 0
2612  if (nattrs == FAIL)
2613  throw5 ("VSfnattrs failed ", "vdata id is ", vdata_id,
2614  "Field index is ", fieldindex);
2615 #endif
2616 
2617  if (nattrs > 0) {
2618 
2619  // Obtain vdata field attributes
2620  for (int i = 0; i < nattrs; i++) {
2621 
2622  auto attr = new Attribute ();
2623 
2624  status = VSattrinfo (vdata_id, fieldindex, i, attr_name,
2625  &attr->type, &attr->count, &attrsize);
2626 
2627  if (status == FAIL) {
2628  delete attr;
2629  throw5 ("VSattrinfo failed ", "vdata field index ",
2630  fieldindex, " attr index is ", i);
2631  }
2632 
2633  if (attr != nullptr) { // Make coverity happy since it doesn't understand throw5.
2634 
2635  string tempname(attr_name);
2636  attr->name = tempname;
2637 
2638  // Checking and handling the special characters for the vdata field attribute name.
2639  attr->newname = HDFCFUtil::get_CF_string(attr->name);
2640 
2641  attr->value.resize (attrsize);
2642  if (VSgetattr (vdata_id, fieldindex, i, &attr->value[0]) == FAIL) {
2643  delete attr;
2644  throw5 ("VSgetattr failed ", "vdata field index is ",
2645  fieldindex, " attr index is ", i);
2646  }
2647  attrs.push_back (attr);
2648  }
2649  }
2650  }
2651 }
2652 
2653 void
2654 File::ReadVgattrs(int32 vgroup_id,const char*fullpath) throw(Exception) {
2655 
2656  intn status_n;
2657  //int n_attr_value = 0;
2658  char attr_name[H4_MAX_NC_NAME];
2659  AttrContainer *vg_attr = nullptr;
2660 
2661  intn n_attrs = Vnattrs(vgroup_id);
2662  if(n_attrs == FAIL)
2663  throw1("Vnattrs failed");
2664  if(n_attrs > 0) {
2665  vg_attr = new AttrContainer();
2666  string temp_container_name(fullpath);
2667  vg_attr->name = HDFCFUtil::get_CF_string(temp_container_name);
2668  }
2669 
2670  for(int attr_index = 0; attr_index <n_attrs; attr_index++) {
2671 
2672  Attribute *attr = new Attribute();
2673  int32 value_size_32 = 0;
2674  status_n = Vattrinfo(vgroup_id, attr_index, attr_name, &attr->type,
2675  &attr->count, &value_size_32);
2676  if(status_n == FAIL) {
2677  delete attr;
2678  throw1("Vattrinfo failed.");
2679  }
2680  int value_size = value_size_32;
2681 
2682  string tempname (attr_name);
2683  if(attr != nullptr) {// See if I can make coverity happy
2684  attr->name = tempname;
2685  tempname = HDFCFUtil::get_CF_string(tempname);
2686  attr->newname = tempname;
2687  attr->value.resize (value_size);
2688 
2689  status_n = Vgetattr(vgroup_id,(intn)attr_index,&attr->value[0]);
2690  if(status_n == FAIL) {
2691  if(attr!=nullptr)
2692  delete attr;
2693  throw3("Vgetattr failed. ","The attribute name is ",attr->name);
2694  }
2695  vg_attr->attrs.push_back(attr);
2696  }
2697  }
2698 
2699  if(vg_attr !=nullptr)
2700  vg_attrs.push_back(vg_attr);
2701 
2702 
2703 }
2704 
2705 // This code is used to obtain the full path of SDS and vdata.
2706 // Since it uses HDF4 library a lot, we keep the C style. KY 2010-7-13
2707 void
2709 throw (Exception)
2710 {
2711  /************************* Variable declaration **************************/
2712 
2713  // Status indicator of HDF4 APIs
2714  int32 status = 0;
2715 
2716  // H interface ID
2717  int32 file_id = 0;
2718 
2719  // vgroup ID
2720  int32 vgroup_id = 0;
2721 
2722  // Vdata ID
2723  int32 vdata_id = 0;
2724 
2725  // Number of lone vgroups
2726  int32 num_of_lones = -1;
2727 
2728  // Number of vgroup objects
2729  int32 num_gobjects = 0;
2730 
2731  // Object reference number and tag(The pair is a key to identify an HDF4 object)
2732  int32 obj_ref = 0;
2733  int32 obj_tag = 0;
2734 
2735  // We may use new HDF4 APIs to obtain the length of the following object names and then
2736  // allocate a buffer to store the names dynamically. Documented in a jira ticket HFRHANDLER-168.
2737 
2738  // Vdata name
2739  char vdata_name[VSNAMELENMAX];
2740 
2741  // Vdata class
2742  char vdata_class[VSNAMELENMAX];
2743 
2744  // Vgroup name
2745  char vgroup_name[VGNAMELENMAX*4];
2746 
2747  // Vgroup class
2748  char vgroup_class[VGNAMELENMAX*4];
2749 
2750  // Full path of an object
2751  char *full_path = nullptr;
2752 
2753  // Copy of a full path of an object
2754  char *cfull_path = nullptr;
2755 
2756  // SD interface ID
2757  int32 sd_id;
2758 
2759  file_id = this->fileid;
2760  sd_id = this->sdfd;
2761 
2762  // No NASA HDF4 files have the vgroup that forms a ring; so ignore this case.
2763  // First, call Vlone with num_of_lones set to 0 to get the number of
2764  // lone vgroups in the file, but not to get their reference numbers.
2765  num_of_lones = Vlone (file_id, nullptr, 0);
2766  if (num_of_lones == FAIL)
2767  throw3 ("Fail to obtain lone vgroup number", "file id is", file_id);
2768 
2769  // if there are any lone vgroups,
2770  if (num_of_lones > 0) {
2771 
2772  // Use the num_of_lones returned to allocate sufficient space for the
2773  // buffer ref_array to hold the reference numbers of all lone vgroups,
2774  vector<int32>ref_array;
2775  ref_array.resize(num_of_lones);
2776 
2777  // And call Vlone again to retrieve the reference numbers into
2778  // the buffer ref_array.
2779  num_of_lones = Vlone (file_id, ref_array.data(), num_of_lones);
2780  if (num_of_lones == FAIL) {
2781  throw3 ("Cannot obtain lone vgroup reference arrays ",
2782  "file id is ", file_id);
2783  }
2784 
2785  // Loop through all lone vgroups
2786  for (int lone_vg_number = 0; lone_vg_number < num_of_lones;
2787  lone_vg_number++) {
2788 
2789  // Attach to the current vgroup
2790  vgroup_id = Vattach (file_id, ref_array[lone_vg_number], "r");
2791  if (vgroup_id == FAIL) {
2792  throw3 ("Vattach failed ", "Reference number is ",
2793  ref_array[lone_vg_number]);
2794  }
2795 
2796  status = Vgetname (vgroup_id, vgroup_name);
2797  if (status == FAIL) {
2798  Vdetach (vgroup_id);
2799  throw3 ("Vgetname failed ", "vgroup_id is ", vgroup_id);
2800  }
2801 
2802  status = Vgetclass (vgroup_id, vgroup_class);
2803  if (status == FAIL) {
2804  Vdetach (vgroup_id);
2805  throw3 ("Vgetclass failed ", "vgroup_name is ", vgroup_name);
2806  }
2807 
2808  //Ignore internal HDF groups
2809  if (strcmp (vgroup_class, _HDF_ATTRIBUTE) == 0
2810  || strcmp (vgroup_class, _HDF_VARIABLE) == 0
2811  || strcmp (vgroup_class, _HDF_DIMENSION) == 0
2812  || strcmp (vgroup_class, _HDF_UDIMENSION) == 0
2813  || strcmp (vgroup_class, _HDF_CDF) == 0
2814  || strcmp (vgroup_class, GR_NAME) == 0
2815  || strcmp (vgroup_class, RI_NAME) == 0) {
2816  Vdetach(vgroup_id);
2817  continue;
2818  }
2819 
2820  num_gobjects = Vntagrefs (vgroup_id);
2821  if (num_gobjects < 0) {
2822  Vdetach (vgroup_id);
2823  throw3 ("Vntagrefs failed ", "vgroup_name is ", vgroup_name);
2824  }
2825 
2826  // Obtain full path and cfull_path.
2827  // MAX_FULL_PATH_LEN(1024) is long enough
2828  // to cover any HDF4 object path for all NASA HDF4 products.
2829  // KY 2013-07-12
2830  //
2831  full_path = (char *) malloc (MAX_FULL_PATH_LEN);
2832  if (full_path == nullptr) {
2833  Vdetach (vgroup_id);
2834  throw1 ("No enough memory to allocate the buffer.");
2835  }
2836  else {// Not necessary, however this will make coverity scan happy.
2837  memset(full_path,'\0',MAX_FULL_PATH_LEN);
2838  strncpy (full_path,_BACK_SLASH,strlen(_BACK_SLASH));
2839  strncat(full_path,vgroup_name,strlen(vgroup_name));
2840  }
2841  try {
2842  ReadVgattrs(vgroup_id,full_path);
2843 
2844  }
2845  catch(...) {
2846  Vdetach (vgroup_id);
2847  free (full_path);
2848  throw1 ("ReadVgattrs failed ");
2849  }
2850  strncat(full_path,_BACK_SLASH,strlen(_BACK_SLASH));
2851 
2852  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
2853  if (cfull_path == nullptr) {
2854  Vdetach (vgroup_id);
2855  free (full_path);
2856  throw1 ("No enough memory to allocate the buffer.");
2857  }
2858  else { // Not necessary, however this will make coverity scan happy.
2859  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
2860  strncpy (cfull_path, full_path,strlen(full_path));
2861  }
2862 
2863  // Loop all vgroup objects
2864  for (int i = 0; i < num_gobjects; i++) {
2865  if (Vgettagref (vgroup_id, i, &obj_tag, &obj_ref) == FAIL) {
2866  Vdetach (vgroup_id);
2867  free (full_path);
2868  free (cfull_path);
2869  throw5 ("Vgettagref failed ", "vgroup_name is ",
2870  vgroup_name, " reference number is ", obj_ref);
2871  }
2872 
2873  // If this is a vgroup, recursively obtain information
2874  if (Visvg (vgroup_id, obj_ref) == TRUE) {
2875  strncpy (full_path, cfull_path,strlen(cfull_path)+1);
2876  full_path[strlen(cfull_path)]='\0';
2877  obtain_path (file_id, sd_id, full_path, obj_ref);
2878  }
2879  // This is a vdata
2880  else if (Visvs (vgroup_id, obj_ref)) {
2881 
2882  vdata_id = VSattach (file_id, obj_ref, "r");
2883  if (vdata_id == FAIL) {
2884  Vdetach (vgroup_id);
2885  free (full_path);
2886  free (cfull_path);
2887  throw5 ("VSattach failed ", "vgroup_name is ",
2888  vgroup_name, " reference number is ",
2889  obj_ref);
2890  }
2891  status = VSgetname (vdata_id, vdata_name);
2892  if (status == FAIL) {
2893  Vdetach (vgroup_id);
2894  free (full_path);
2895  free (cfull_path);
2896  throw5 ("VSgetclass failed ", "vgroup_name is ",
2897  vgroup_name, " reference number is ",
2898  obj_ref);
2899  }
2900 
2901  status = VSgetclass (vdata_id, vdata_class);
2902  if (status == FAIL) {
2903  Vdetach (vgroup_id);
2904  free (full_path);
2905  free (cfull_path);
2906  throw5 ("VSgetclass failed ", "vgroup_name is ",
2907  vgroup_name, " reference number is ",
2908  obj_ref);
2909  }
2910 
2911  //NOTE: I found that for 1BTRMMdata(1B21...), there
2912  // is an attribute stored in vdata under vgroup SwathData that cannot
2913  // be retrieved by any attribute APIs. I suspect this is an HDF4 bug.
2914  // This attribute is supposed to be an attribute under vgroup SwathData.
2915  // Since currently the information has been preserved by the handler,
2916  // so we don't have to handle this. It needs to be reported to the
2917  // HDF4 developer. 2010-6-25 ky
2918 
2919  // Vdata that is either used to store attributes or internal HDF4 classes. ignore.
2920  if (VSisattr (vdata_id) == TRUE
2921  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
2922  strlen (_HDF_CHK_TBL_CLASS))
2923  || !strncmp (vdata_class, _HDF_SDSVAR,
2924  strlen (_HDF_SDSVAR))
2925  || !strncmp (vdata_class, _HDF_CRDVAR,
2926  strlen (_HDF_CRDVAR))
2927  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
2928  || !strncmp (vdata_class, DIM_VALS01,
2929  strlen (DIM_VALS01))
2930  || !strncmp (vdata_class, RIGATTRCLASS,
2931  strlen (RIGATTRCLASS))
2932  || !strncmp (vdata_name, RIGATTRNAME,
2933  strlen (RIGATTRNAME))) {
2934 
2935  status = VSdetach (vdata_id);
2936  if (status == FAIL) {
2937  Vdetach (vgroup_id);
2938  free (full_path);
2939  free (cfull_path);
2940  throw3 ("VSdetach failed ",
2941  "Vdata is under vgroup ", vgroup_name);
2942  }
2943 
2944  }
2945  else {
2946 
2947  VDATA*vdataobj = nullptr;
2948  try {
2949  vdataobj = VDATA::Read (vdata_id, obj_ref);
2950  }
2951  catch(...) {
2952  free (full_path);
2953  free (cfull_path);
2954  VSdetach(vdata_id);
2955  Vdetach (vgroup_id);
2956  throw;
2957  }
2958 
2959 
2960  vdataobj->newname = full_path +vdataobj->name;
2961 
2962  //We want to map fields of vdata with more than 10 records to DAP variables
2963  // and we need to add the path and vdata name to the new vdata field name
2964  if (!vdataobj->getTreatAsAttrFlag ()) {
2965  for (const auto &vdf:vdataobj->getFields ()) {
2966 
2967  // Change vdata name conventions.
2968  // "vdata"+vdata_newname+"_vdf_"+vdf->newname
2969 
2970  vdf->newname =
2971  "vdata" + vdataobj->newname + "_vdf_" + vdf->name;
2972 
2973  //Make sure the name is following CF, KY 2012-6-26
2974  vdf->newname = HDFCFUtil::get_CF_string(vdf->newname);
2975  }
2976  }
2977 
2978  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
2979 
2980  this->vds.push_back (vdataobj);
2981 
2982  status = VSdetach (vdata_id);
2983  if (status == FAIL) {
2984  Vdetach (vgroup_id);
2985  free (full_path);
2986  free (cfull_path);
2987  throw3 ("VSdetach failed ",
2988  "Vdata is under vgroup ", vgroup_name);
2989  }
2990  }
2991  }
2992 
2993  // These are SDS objects
2994  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
2995  || obj_tag == DFTAG_SD) {
2996 
2997  // We need to obtain the SDS index; also need to store the new name(object name + full_path).
2998  if (this->sd->refindexlist.find (obj_ref) != sd->refindexlist.end ()) {
2999  // coverity cannot recognize the macro of throw(throw1,2,3..), so
3000  // it claims that full_path is freed. The coverity is wrong.
3001  // To make coverity happy, here I will have a check.
3002  if(full_path != nullptr) {
3003  this->sd->sdfields[this->sd->refindexlist[obj_ref]]->newname =
3004  full_path +
3005  this->sd->sdfields[this->sd->refindexlist[obj_ref]]->name;
3006  }
3007  }
3008  else {
3009  Vdetach (vgroup_id);
3010  free (full_path);
3011  free (cfull_path);
3012  throw3 ("SDS with the reference number ", obj_ref,
3013  " is not found");
3014  }
3015  }
3016  }
3017  free (full_path);
3018  free (cfull_path);
3019 
3020  status = Vdetach (vgroup_id);
3021  if (status == FAIL) {
3022  throw3 ("Vdetach failed ", "vgroup_name is ", vgroup_name);
3023  }
3024  }//end of the for loop
3025  }// end of the if loop
3026 
3027 }
3028 
3029 // This fuction is called recursively to obtain the full path of an HDF4 object.
3030 // obtain_path, obtain_noneos2_sds_path,obtain_vdata_path are very similar.
3031 // We may combine them in the future. Documented at HFRHANDLER-166.
3032 void
3033 File::obtain_path (int32 file_id, int32 sd_id, char *full_path,
3034  int32 pobj_ref)
3035 throw (Exception)
3036 {
3037  // Vgroup parent ID
3038  int32 vgroup_pid = -1;
3039 
3040  // Indicator of status
3041  int32 status = 0;
3042 
3043  // Index i
3044  int i = 0;
3045 
3046  // Number of group objects
3047  int num_gobjects = 0;
3048 
3049  // The following names are statically allocated.
3050  // This can be updated in the future with new HDF4 APIs that can provide the actual length of an object name.
3051  // Documented in a jira ticket HFRHANDLER-168.
3052  // KY 2013-07-11
3053 
3054  // Child vgroup name
3055  char cvgroup_name[VGNAMELENMAX*4];
3056 
3057  // Vdata name
3058  char vdata_name[VSNAMELENMAX];
3059 
3060  // Vdata class name
3061  char vdata_class[VSNAMELENMAX];
3062 
3063  // Vdata ID
3064  int32 vdata_id = -1;
3065 
3066  // Object tag
3067  int32 obj_tag = 0;
3068 
3069  // Object reference
3070  int32 obj_ref = 0;
3071 
3072  // full path of the child group
3073  char *cfull_path = nullptr;
3074 
3075  bool unexpected_fail = false;
3076 
3077  vgroup_pid = Vattach (file_id, pobj_ref, "r");
3078  if (vgroup_pid == FAIL)
3079  throw3 ("Vattach failed ", "Object reference number is ", pobj_ref);
3080 
3081 
3082  if (Vgetname (vgroup_pid, cvgroup_name) == FAIL) {
3083  Vdetach (vgroup_pid);
3084  throw3 ("Vgetname failed ", "Object reference number is ", pobj_ref);
3085  }
3086  num_gobjects = Vntagrefs (vgroup_pid);
3087  if (num_gobjects < 0) {
3088  Vdetach (vgroup_pid);
3089  throw3 ("Vntagrefs failed ", "Object reference number is ", pobj_ref);
3090  }
3091  // MAX_FULL_PATH_LEN(1024) is long enough
3092  // to cover any HDF4 object path for all NASA HDF4 products.
3093  // So using strcpy and strcat is safe in a practical sense.
3094  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
3095  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
3096  // Documented in a jira ticket HFRHANDLER-168.
3097  // KY 2013-07-12
3098  // We use strncpy and strncat to replace strcpy and strcat. KY 2013-09-06
3099 
3100  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
3101  if (cfull_path == nullptr)
3102  throw1 ("No enough memory to allocate the buffer");
3103  else
3104  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
3105 
3106  strncpy(cfull_path,full_path,strlen(full_path));
3107  strncat(cfull_path,cvgroup_name,strlen(cvgroup_name));
3108  try {
3109  ReadVgattrs(vgroup_pid,cfull_path);
3110 
3111  }
3112  catch(...) {
3113  Vdetach (vgroup_pid);
3114  free (cfull_path);
3115  throw1 ("ReadVgattrs failed ");
3116  }
3117 
3118  strncat(cfull_path,_BACK_SLASH,strlen(_BACK_SLASH));
3119 
3120  // Introduce err_msg mainly to get rid of fake solarcloud warnings
3121  // We may use the same method for all error handling if we have time.
3122  string err_msg;
3123 
3124  for (i = 0; i < num_gobjects; i++) {
3125 
3126  if (Vgettagref (vgroup_pid, i, &obj_tag, &obj_ref) == FAIL) {
3127  unexpected_fail = true;
3128  err_msg = string(ERR_LOC) + " Vgettagref failed. ";
3129  goto cleanFail;
3130  }
3131 
3132  if (Visvg (vgroup_pid, obj_ref) == TRUE) {
3133  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
3134  full_path[strlen(cfull_path)]='\0';
3135  obtain_path (file_id, sd_id, full_path, obj_ref);
3136  }
3137  else if (Visvs (vgroup_pid, obj_ref)) {
3138 
3139  vdata_id = VSattach (file_id, obj_ref, "r");
3140  if (vdata_id == FAIL) {
3141  unexpected_fail = true;
3142  err_msg = string(ERR_LOC) + " VSattach failed. ";
3143  goto cleanFail;
3144  }
3145 
3146  status = VSQueryname (vdata_id, vdata_name);
3147  if (status == FAIL) {
3148  unexpected_fail = true;
3149  err_msg = string(ERR_LOC) + " VSQueryname failed. ";
3150  goto cleanFail;
3151  }
3152 
3153  status = VSgetclass (vdata_id, vdata_class);
3154  if (status == FAIL) {
3155  unexpected_fail = true;
3156  err_msg = string(ERR_LOC) + " VSgetclass failed. ";
3157  goto cleanFail;
3158  }
3159 
3160  if (VSisattr (vdata_id) != TRUE) {
3161  if (strncmp
3162  (vdata_class, _HDF_CHK_TBL_CLASS,
3163  strlen (_HDF_CHK_TBL_CLASS))) {
3164 
3165  VDATA *vdataobj = nullptr;
3166 
3167  try {
3168  vdataobj = VDATA::Read (vdata_id, obj_ref);
3169  }
3170  catch(...) {
3171  free (cfull_path);
3172  VSdetach(vdata_id);
3173  Vdetach (vgroup_pid);
3174  throw;
3175  }
3176 
3177 
3178  // The new name conventions require the path prefixed before the object name.
3179  vdataobj->newname = cfull_path + vdataobj->name;
3180  // We want to map fields of vdata with more than 10 records to DAP variables
3181  // and we need to add the path and vdata name to the new vdata field name
3182  if (!vdataobj->getTreatAsAttrFlag ()) {
3183  for (std::vector <VDField * >::const_iterator it_vdf =
3184  vdataobj->getFields ().begin ();
3185  it_vdf != vdataobj->getFields ().end ();
3186  it_vdf++) {
3187 
3188  // Change vdata name conventions.
3189  // "vdata"+vdata_newname+"_vdf_"+(*it_vdf)->newname
3190  (*it_vdf)->newname =
3191  "vdata" + vdataobj->newname + "_vdf_" +
3192  (*it_vdf)->name;
3193 
3194  (*it_vdf)->newname = HDFCFUtil::get_CF_string((*it_vdf)->newname);
3195  }
3196  }
3197 
3198  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
3199  this->vds.push_back (vdataobj);
3200  }
3201  }
3202  status = VSdetach (vdata_id);
3203  if (status == FAIL) {
3204  unexpected_fail = true;
3205  err_msg = string(ERR_LOC) + " VSdetach failed. ";
3206  goto cleanFail;
3207  }
3208  }
3209  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
3210  || obj_tag == DFTAG_SD) {
3211  if (this->sd->refindexlist.find (obj_ref) !=
3212  this->sd->refindexlist.end ())
3213  this->sd->sdfields[this->sd->refindexlist[obj_ref]]->newname =
3214  // New name conventions require the path to be prefixed before the object name
3215  cfull_path + this->sd->sdfields[this->sd->refindexlist[obj_ref]]->name;
3216  else {
3217  unexpected_fail = true;
3218  stringstream temp_ss;
3219  temp_ss <<obj_ref;
3220  err_msg = string(ERR_LOC) + "SDS with the reference number"
3221  + temp_ss.str() + " is not found.";
3222  goto cleanFail;
3223  }
3224  }
3225  else{
3226 
3227  }
3228  }
3229  vdata_id = -1;
3230 cleanFail:
3231  free (cfull_path);
3232  if(vdata_id != -1) {
3233  status = VSdetach(vdata_id);
3234  if (status == FAIL) {
3235  Vdetach(vgroup_pid);
3236  string err_msg2 = "In the cleanup " + string(ERR_LOC) + " VSdetached failed. ";
3237  err_msg = err_msg + err_msg2;
3238  throw1(err_msg);
3239  }
3240  else if(true == unexpected_fail)
3241  throw1(err_msg);
3242 
3243  }
3244 
3245  if(vgroup_pid != -1) {
3246  status = Vdetach(vgroup_pid);
3247  if (status == FAIL) {
3248  string err_msg2 = "In the cleanup " + string(ERR_LOC) + " VSdetached failed. ";
3249  err_msg = err_msg + err_msg2;
3250  throw1(err_msg);
3251  }
3252  else if(true == unexpected_fail)
3253  throw1(err_msg);
3254 
3255  }
3256 
3257 }
3258 
3259 // This fuction is called recursively to obtain the full path of an HDF4 SDS path for extra SDS objects
3260 // in a hybrid HDF-EOS2 file.
3261 // obtain_path, obtain_noneos2_sds_path,obtain_vdata_path are very similar.
3262 // We may combine them in the future. Documented at HFRHANDLER-166.
3263 // Also we only add minimum comments since this code may be removed in the future.
3264 void
3265 SD::obtain_noneos2_sds_path (int32 file_id, char *full_path, int32 pobj_ref)
3266 throw (Exception)
3267 {
3268 
3269  int32 vgroup_cid = -1;
3270  int32 status = 0;
3271  int num_gobjects = 0;
3272 
3273  // Now HDF4 provides a dynamic way to allocate the length of an HDF4 object name, should update to use that in the future.
3274  // Documented in a jira ticket HFRHANDLER-168.
3275  // KY 2013-07-11
3276  char cvgroup_name[VGNAMELENMAX*4];
3277 
3278  int32 obj_tag =0;
3279  int32 obj_ref = 0;
3280  char *cfull_path = nullptr;
3281 
3282  bool unexpected_fail = false;
3283 
3284  vgroup_cid = Vattach (file_id, pobj_ref, "r");
3285  if (vgroup_cid == FAIL)
3286  throw3 ("Vattach failed ", "Object reference number is ", pobj_ref);
3287 
3288  if (Vgetname (vgroup_cid, cvgroup_name) == FAIL) {
3289  Vdetach (vgroup_cid);
3290  throw3 ("Vgetname failed ", "Object reference number is ", pobj_ref);
3291  }
3292  num_gobjects = Vntagrefs (vgroup_cid);
3293  if (num_gobjects < 0) {
3294  Vdetach (vgroup_cid);
3295  throw3 ("Vntagrefs failed ", "Object reference number is ", pobj_ref);
3296  }
3297 
3298  // MAX_FULL_PATH_LEN(1024) is long enough
3299  // to cover any HDF4 object path for all NASA HDF4 products.
3300  // So using strcpy and strcat is safe in a practical sense.
3301  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
3302  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
3303  // Documented in a jira ticket HFRHANDLER-168.
3304  // KY 2013-07-12
3305  // We use strncpy and strncat to replace strcpy and strcat. KY 2013-09-06
3306 
3307  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
3308  if (cfull_path == nullptr)
3309  throw1 ("No enough memory to allocate the buffer");
3310  else
3311  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
3312 
3313 
3314  // NOTE: The order of cat gets changed.
3315  strncpy(cfull_path,full_path,strlen(full_path));
3316  strncat(cfull_path,cvgroup_name,strlen(cvgroup_name));
3317  strncat(cfull_path,_BACK_SLASH,strlen(_BACK_SLASH));
3318 
3319  string err_msg;
3320 
3321  for (int i = 0; i < num_gobjects; i++) {
3322 
3323  if (Vgettagref (vgroup_cid, i, &obj_tag, &obj_ref) == FAIL) {
3324  unexpected_fail = true;
3325  err_msg = string(ERR_LOC) + " Vgettagref failed. ";
3326  goto cleanFail;
3327  }
3328 
3329  if (Visvg (vgroup_cid, obj_ref) == TRUE) {
3330  strncpy (full_path, cfull_path,strlen(cfull_path)+1);
3331  full_path[strlen(cfull_path)]='\0';
3332  obtain_noneos2_sds_path (file_id, full_path, obj_ref);
3333  }
3334  else if (obj_tag == DFTAG_NDG || obj_tag == DFTAG_SDG
3335  || obj_tag == DFTAG_SD) {
3336 
3337  // Here we need to check if the SDS is an EOS object by checking
3338  // if the the path includes "Data Fields" or "Geolocation Fields".
3339  // If the object is an EOS object, we will remove it from the list.
3340 
3341  string temp_str = string(cfull_path);
3342  if((temp_str.find("Data Fields") != std::string::npos)||
3343  (temp_str.find("Geolocation Fields") != std::string::npos))
3344  sds_ref_list.remove(obj_ref);
3345  }
3346  else{
3347 
3348  }
3349  }
3350 cleanFail:
3351  free (cfull_path);
3352  if(vgroup_cid != -1) {
3353  status = Vdetach(vgroup_cid);
3354  if (status == FAIL) {
3355  string err_msg2 = "In the cleanup " + string(ERR_LOC) + " Vdetached failed. ";
3356  err_msg = err_msg + err_msg2;
3357  throw1(err_msg);
3358  }
3359  else if(true == unexpected_fail)
3360  throw1(err_msg);
3361  }
3362 
3363 }
3364 
3365 
3366 // This fuction is called recursively to obtain the full path of the HDF4 vgroup.
3367 // This function is especially used when obtaining non-lone vdata objects for a hybrid file.
3368 // obtain_path, obtain_noneos2_sds_path,obtain_vdata_path are very similar.
3369 // We may combine them in the future. Documented at HFRHANDLER-166.
3370 
3371 void
3372 File::obtain_vdata_path (int32 file_id, char *full_path, int32 pobj_ref)
3373 throw (Exception)
3374 {
3375 
3376  int32 vgroup_cid = -1;
3377  int32 status = -1;
3378  int i = -1;
3379  int num_gobjects = -1;
3380 
3381  // Now HDF4 provides dynamic ways to allocate the length of object names, should update to use that in the future.
3382  // Documented in a jira ticket HFRHANDLER-168.
3383  // KY 2013-07-11
3384  char cvgroup_name[VGNAMELENMAX*4];
3385  char vdata_name[VSNAMELENMAX];
3386  char vdata_class[VSNAMELENMAX];
3387  int32 vdata_id = -1;
3388  int32 obj_tag = -1;
3389  int32 obj_ref = -1;
3390  char *cfull_path = nullptr;
3391 
3392  string temp_str;
3393  bool unexpected_fail = false;
3394  string err_msg;
3395  // MAX_FULL_PATH_LEN(1024) is long enough
3396  // to cover any HDF4 object path for all NASA HDF4 products.
3397  // So using strcpy and strcat is safe in a practical sense.
3398  // However, in the future, we should update the code to use HDF4 APIs to obtain vgroup_name length dynamically.
3399  // At that time, we will use strncpy and strncat instead. We may even think to use C++ vector <char>.
3400  // Documented in a jira ticket HFRHANDLER-168.
3401  // KY 2013-07-12
3402  // We replace strcpy and strcat with strncpy and strncat as suggested. KY 2013-08-29
3403 
3404  cfull_path = (char *) malloc (MAX_FULL_PATH_LEN);
3405  if (cfull_path == nullptr)
3406  throw1 ("No enough memory to allocate the buffer");
3407  else
3408  memset(cfull_path,'\0',MAX_FULL_PATH_LEN);
3409 
3410  vgroup_cid = Vattach (file_id, pobj_ref, "r");
3411  if (vgroup_cid == FAIL) {
3412  unexpected_fail = true;
3413  err_msg = string(ERR_LOC)+"Vattach failed";
3414  goto cleanFail;
3415  //throw3 ("Vattach failed ", "Object reference number is ", pobj_ref);
3416  }
3417 
3418  if (Vgetname (vgroup_cid, cvgroup_name) == FAIL) {
3419  unexpected_fail = true;
3420  err_msg = string(ERR_LOC)+"Vgetname failed";
3421  goto cleanFail;
3422  }
3423  num_gobjects = Vntagrefs (vgroup_cid);
3424  if (num_gobjects < 0) {
3425  unexpected_fail = true;
3426  err_msg = string(ERR_LOC)+"Vntagrefs failed";
3427  goto cleanFail;
3428  }
3429 
3430  strncpy(cfull_path,full_path,strlen(full_path));
3431  strncat(cfull_path,cvgroup_name,strlen(cvgroup_name));
3432  strncat(cfull_path,_BACK_SLASH,strlen(_BACK_SLASH));
3433 
3434 
3435  // If having a vgroup "Geolocation Fields", we would like to set the EOS2Swath flag.
3436  temp_str = string(cfull_path);
3437 
3438  if (temp_str.find("Geolocation Fields") != string::npos) {
3439  if(false == this->EOS2Swathflag)
3440  this->EOS2Swathflag = true;
3441  }
3442 
3443  for (i = 0; i < num_gobjects; i++) {
3444 
3445  if (Vgettagref (vgroup_cid, i, &obj_tag, &obj_ref) == FAIL) {
3446  unexpected_fail = true;
3447  err_msg = string(ERR_LOC)+"Vgettagref failed";
3448  goto cleanFail;
3449  }
3450 
3451  if (Visvg (vgroup_cid, obj_ref) == TRUE) {
3452  strncpy(full_path,cfull_path,strlen(cfull_path)+1);
3453  full_path[strlen(cfull_path)] = '\0';
3454  obtain_vdata_path (file_id, full_path, obj_ref);
3455  }
3456  else if (Visvs (vgroup_cid, obj_ref)) {
3457 
3458  vdata_id = VSattach (file_id, obj_ref, "r");
3459  if (vdata_id == FAIL) {
3460  unexpected_fail = true;
3461  err_msg = string(ERR_LOC)+"VSattach failed";
3462  goto cleanFail;
3463  }
3464 
3465  status = VSQueryname (vdata_id, vdata_name);
3466  if (status == FAIL) {
3467  unexpected_fail = true;
3468  err_msg = string(ERR_LOC)+"VSQueryname failed";
3469  goto cleanFail;
3470  }
3471 
3472  status = VSgetclass (vdata_id, vdata_class);
3473  if (status == FAIL) {
3474  unexpected_fail = true;
3475  err_msg = string(ERR_LOC)+"VSgetclass failed";
3476  goto cleanFail;
3477  }
3478 
3479  // Obtain the C++ string format of the path.
3480  string temp_str2 = string(cfull_path);
3481 
3482  // Swath 1-D is mapped to Vdata, we need to ignore them.
3483  // But if vdata is added to a grid, we should not ignore.
3484  // Since "Geolocation Fields" will always appear before
3485  // the "Data Fields", we can use a flag to distinguish
3486  // the swath from the grid. Swath includes both "Geolocation Fields"
3487  // and "Data Fields". Grid only has "Data Fields".
3488  // KY 2013-01-03
3489 
3490  bool ignore_eos2_geo_vdata = false;
3491  bool ignore_eos2_data_vdata = false;
3492  if (temp_str2.find("Geolocation Fields") != string::npos) {
3493  ignore_eos2_geo_vdata = true;
3494  }
3495 
3496  // Only ignore "Data Fields" vdata when "Geolocation Fields" appears.
3497  if (temp_str2.find("Data Fields") != string::npos) {
3498  if (true == this->EOS2Swathflag)
3499  ignore_eos2_data_vdata = true;
3500  }
3501  if ((true == ignore_eos2_data_vdata)
3502  ||(true == ignore_eos2_geo_vdata)
3503  || VSisattr (vdata_id) == TRUE
3504  || !strncmp (vdata_class, _HDF_CHK_TBL_CLASS,
3505  strlen (_HDF_CHK_TBL_CLASS))
3506  || !strncmp (vdata_class, _HDF_SDSVAR,
3507  strlen (_HDF_SDSVAR))
3508  || !strncmp (vdata_class, _HDF_CRDVAR,
3509  strlen (_HDF_CRDVAR))
3510  || !strncmp (vdata_class, DIM_VALS, strlen (DIM_VALS))
3511  || !strncmp (vdata_class, DIM_VALS01,
3512  strlen (DIM_VALS01))
3513  || !strncmp (vdata_class, RIGATTRCLASS,
3514  strlen (RIGATTRCLASS))
3515  || !strncmp (vdata_name, RIGATTRNAME,
3516  strlen (RIGATTRNAME))) {
3517 
3518  status = VSdetach (vdata_id);
3519  if (status == FAIL) {
3520  unexpected_fail = true;
3521  err_msg = string(ERR_LOC)+"VSdetach failed";
3522  goto cleanFail;
3523  }
3524  }
3525  else {
3526 
3527  VDATA *vdataobj = nullptr;
3528  try {
3529  vdataobj = VDATA::Read (vdata_id, obj_ref);
3530  }
3531  catch(...) {
3532  free (cfull_path);
3533  VSdetach(vdata_id);
3534  Vdetach (vgroup_cid);
3535  throw;
3536  }
3537 
3538  // The new name conventions require the path prefixed before the object name.
3539  vdataobj->newname = cfull_path + vdataobj->name;
3540  // We want to map fields of vdata with more than 10 records to DAP variables
3541  // and we need to add the path and vdata name to the new vdata field name
3542  if (!vdataobj->getTreatAsAttrFlag ()) {
3543  for (std::vector <VDField * >::const_iterator it_vdf =
3544  vdataobj->getFields ().begin ();
3545  it_vdf != vdataobj->getFields ().end ();
3546  it_vdf++) {
3547 
3548  // Change vdata name conventions.
3549  // "vdata"+vdata_newname+"_vdf_"+(*it_vdf)->newname
3550  (*it_vdf)->newname =
3551  "vdata" + vdataobj->newname + "_vdf_" +
3552  (*it_vdf)->name;
3553 
3554  (*it_vdf)->newname = HDFCFUtil::get_CF_string((*it_vdf)->newname);
3555  }
3556  }
3557 
3558  vdataobj->newname = HDFCFUtil::get_CF_string(vdataobj->newname);
3559  this->vds.push_back (vdataobj);
3560  status = VSdetach (vdata_id);
3561  if (status == FAIL) {
3562  unexpected_fail = true;
3563  err_msg = string(ERR_LOC)+"VSdetach failed";
3564  goto cleanFail;
3565  }
3566  }
3567  }
3568  else{
3569 
3570  }
3571  }
3572 
3573 cleanFail:
3574  free (cfull_path);
3575  if(vgroup_cid != -1) {
3576  status = Vdetach(vgroup_cid);
3577  if (status == FAIL) {
3578  string err_msg2 = "In the cleanup " + string(ERR_LOC) + " Vdetached failed. ";
3579  err_msg = err_msg + err_msg2;
3580  throw3(err_msg,"vgroup name is ",cvgroup_name);
3581  }
3582  else if(true == unexpected_fail)
3583  throw3(err_msg,"vgroup name is ",cvgroup_name);
3584  }
3585 
3586 
3587 }
3588 
3589 // Handle SDS fakedim names: make the dimensions with the same dimension size
3590 // share the same dimension name. In this way, we can reduce many fakedims.
3591 void
3593 
3594  File *file = this;
3595 
3596  // Build Dimension name list
3597  // We have to assume that NASA HDF4 SDSs provide unique dimension names under each vgroup
3598  // Find unique dimension name list
3599  // Build a map from unique dimension name list to the original dimension name list
3600  // Don't count fakeDim ......
3601  // Based on the new dimension name list, we will build a coordinate field for each dimension
3602  // for each product we support. If dimension scale data are found, that dimension scale data will
3603  // be retrieved according to our knowledge to the data product.
3604  // The unique dimension name is the dimension name plus the full path
3605  // We should build a map to obtain the final coordinate fields of each field
3606 
3607  std::string tempdimname;
3608  std::pair < std::set < std::string >::iterator, bool > ret;
3609  std::string temppath;
3610  std::set < int32 > fakedimsizeset;
3611  std::pair < std::set < int32 >::iterator, bool > fakedimsizeit;
3612  std::map < int32, std::string > fakedimsizenamelist;
3613  std::map < int32, std::string >::iterator fakedimsizenamelistit;
3614 
3615  for (const auto &sdf:file->sd->sdfields) {
3616 
3617  for (const auto &sdim:sdf->getDimensions ()) {
3618 
3619  //May treat corrected dimension names as the original dimension names the SAME, CORRECT it in the future.
3620  if (file->sptype != OTHERHDF)
3621  tempdimname = sdim->getName ();
3622  else
3623  tempdimname = sdim->getName () + temppath;
3624 
3625  Dimension *dim =
3626  new Dimension (tempdimname, sdim->getSize (),
3627  sdim->getType ());
3628  sdf->correcteddims.push_back (dim);
3629  if (tempdimname.find ("fakeDim") != std::string::npos) {
3630  fakedimsizeit = fakedimsizeset.insert (sdim->getSize ());
3631  if (fakedimsizeit.second == true) {
3632  fakedimsizenamelist[sdim->getSize ()] = sdim->getName (); //Here we just need the original name since fakeDim is globally generated.
3633  }
3634  }
3635  }
3636  }
3637 
3638  // The CF conventions have to be followed for products(TRMM etc.) that use fakeDims . KY 2012-6-26
3639  // Sequeeze "fakeDim" names according to fakeDim size. For example, if fakeDim1, fakeDim3, fakeDim5 all shares the same size,
3640  // we use one name(fakeDim1) to be the dimension name. This will reduce the number of fakeDim names.
3641 
3642  if (file->sptype != OTHERHDF) {
3643  for (std::vector < SDField * >::const_iterator i =
3644  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3645  for (std::vector < Dimension * >::const_iterator j =
3646  (*i)->getCorrectedDimensions ().begin ();
3647  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3648  if ((*j)->getName ().find ("fakeDim") != std::string::npos) {
3649  if (fakedimsizenamelist.find ((*j)->getSize ()) !=
3650  fakedimsizenamelist.end ()) {
3651  (*j)->name = fakedimsizenamelist[(*j)->getSize ()]; //sequeeze the redundant fakeDim with the same size
3652  }
3653  else
3654  throw5 ("The fakeDim name ", (*j)->getName (),
3655  "with the size", (*j)->getSize (),
3656  "does not in the fakedimsize list");
3657  }
3658  }
3659  }
3660  }
3661 }
3662 
3663 // Create the new dimension name set and the dimension name to size map.
3665 
3666  File *file = this;
3667 
3668  // Create the new dimension name set and the dimension name to size map.
3669  for (const auto &sdf:file->sd->sdfields) {
3670  for (const auto &dim:sdf->getCorrectedDimensions ()) {
3671  std::pair < std::set < std::string >::iterator, bool > ret;
3672  ret = file->sd->fulldimnamelist.insert (dim->getName ());
3673 
3674  // Map from the unique dimension name to its size
3675  if (ret.second == true) {
3676  file->sd->n1dimnamelist[dim->getName ()] = dim->getSize ();
3677  }
3678  }
3679  }
3680 
3681 }
3682 
3683 // Add the missing coordinate variables based on the corrected dimension name list
3685 
3686  File *file = this;
3687 
3688  // Adding the missing coordinate variables based on the corrected dimension name list
3689  // For some CERES products, there are so many vgroups, so there are potentially many missing fields.
3690  // Go through the n1dimnamelist and check the map dimcvarlist; if no dimcvarlist[dimname], then this dimension namelist must be a missing field
3691  // Create the missing field and insert the missing field to the SDField list.
3692 
3693  for (std::map < std::string, int32 >::const_iterator i =
3694  file->sd->n1dimnamelist.begin ();
3695  i != file->sd->n1dimnamelist.end (); ++i) {
3696 
3697  if (file->sd->nonmisscvdimnamelist.find ((*i).first) == file->sd->nonmisscvdimnamelist.end ()) {// Create a missing Z-dimension field
3698 
3699  SDField *missingfield = new SDField ();
3700 
3701  // The name of the missingfield is not necessary.
3702  // We only keep here for consistency.
3703 
3704  missingfield->type = DFNT_INT32;
3705  missingfield->name = (*i).first;
3706  missingfield->newname = (*i).first;
3707  missingfield->rank = 1;
3708  missingfield->fieldtype = 4;
3709  Dimension *dim = new Dimension ((*i).first, (*i).second, 0);
3710 
3711  missingfield->dims.push_back (dim);
3712  dim = new Dimension ((*i).first, (*i).second, 0);
3713  missingfield->correcteddims.push_back (dim);
3714  file->sd->sdfields.push_back (missingfield);
3715  }
3716  }
3717 }
3718 
3719 // Create the final CF-compliant dimension name list for each field
3721 
3722  File * file = this;
3723 
3725  // We will create the final unique dimension name list(erasing special characters etc.)
3726  // After erasing special characters, the nameclashing for dimension name is still possible.
3727  // So still handle the name clashings.
3728 
3729  vector<string>tempfulldimnamelist;
3730  for (std::set < std::string >::const_iterator i =
3731  file->sd->fulldimnamelist.begin ();
3732  i != file->sd->fulldimnamelist.end (); ++i)
3733  tempfulldimnamelist.push_back(HDFCFUtil::get_CF_string(*i));
3734 
3735  HDFCFUtil::Handle_NameClashing(tempfulldimnamelist);
3736 
3737  // Not the most efficient way, but to keep the original code structure,KY 2012-6-27
3738  int total_dcounter = 0;
3739  for (std::set < std::string >::const_iterator i =
3740  file->sd->fulldimnamelist.begin ();
3741  i != file->sd->fulldimnamelist.end (); ++i) {
3742  HDFCFUtil::insert_map(file->sd->n2dimnamelist, (*i), tempfulldimnamelist[total_dcounter]);
3743  total_dcounter++;
3744  }
3745 
3746  // change the corrected dimension name list for each SDS field
3747  std::map < std::string, std::string >::iterator tempmapit;
3748  for (std::vector < SDField * >::const_iterator i =
3749  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3750  for (std::vector < Dimension * >::const_iterator j =
3751  (*i)->getCorrectedDimensions ().begin ();
3752  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3753  tempmapit = file->sd->n2dimnamelist.find ((*j)->getName ());
3754  if (tempmapit != file->sd->n2dimnamelist.end ())
3755  (*j)->name = tempmapit->second;
3756  else { //When the dimension name is fakeDim***, we will ignore. this dimension will not have the corresponding coordinate variable.
3757  throw5 ("This dimension with the name ", (*j)->name,
3758  "and the field name ", (*i)->name,
3759  " is not found in the dimension list.");
3760  }
3761  }
3762  }
3763 
3764 }
3765 
3766 // Create the final CF-compliant field name list
3767 void
3768 File::handle_sds_names(bool & COARDFLAG, string & lldimname1, string&lldimname2) throw(Exception)
3769 {
3770 
3771  File * file = this;
3772 
3773  // Handle name clashings
3774 
3775  // There are many fields in CERES data(a few hundred) and the full name(with the additional path)
3776  // is very long. It causes Java clients choken since Java clients append names in the URL
3777  // To improve the performance and to make Java clients access the data, simply use the field names for
3778  // these fields. Users can turn off this feature by commenting out the line: H4.EnableCERESMERRAShortName=true
3779  // or set the H4.EnableCERESMERRAShortName=false
3780  // KY 2012-6-27
3781 
3782 #if 0
3783  string check_ceres_short_name_key="H4.EnableCERESMERRAShortName";
3784  bool turn_on_ceres_short_name_key= false;
3785 
3786  turn_on_ceres_short_name_key = HDFCFUtil::check_beskeys(check_ceres_short_name_key);
3787 #endif
3788 
3789  //if (true == turn_on_ceres_short_name_key && (file->sptype == CER_ES4 || file->sptype == CER_SRB
3790  if (true == HDF4RequestHandler::get_enable_ceres_merra_short_name() && (file->sptype == CER_ES4 || file->sptype == CER_SRB
3791  || file->sptype == CER_CDAY || file->sptype == CER_CGEO
3792  || file->sptype == CER_SYN || file->sptype == CER_ZAVG
3793  || file->sptype == CER_AVG)) {
3794 
3795  for (unsigned int i = 0; i < file->sd->sdfields.size (); ++i) {
3796  file->sd->sdfields[i]->special_product_fullpath = file->sd->sdfields[i]->newname;
3797  file->sd->sdfields[i]->newname = file->sd->sdfields[i]->name;
3798  }
3799  }
3800 
3801 
3802  vector<string>sd_data_fieldnamelist;
3803  vector<string>sd_latlon_fieldnamelist;
3804  vector<string>sd_nollcv_fieldnamelist;
3805 
3806  set<string>sd_fieldnamelist;
3807 
3808  for (std::vector < SDField * >::const_iterator i =
3809  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3810  if ((*i)->fieldtype ==0)
3811  sd_data_fieldnamelist.push_back(HDFCFUtil::get_CF_string((*i)->newname));
3812  else if ((*i)->fieldtype == 1 || (*i)->fieldtype == 2)
3813  sd_latlon_fieldnamelist.push_back(HDFCFUtil::get_CF_string((*i)->newname));
3814  else
3815  sd_nollcv_fieldnamelist.push_back(HDFCFUtil::get_CF_string((*i)->newname));
3816  }
3817 
3818  HDFCFUtil::Handle_NameClashing(sd_data_fieldnamelist,sd_fieldnamelist);
3819  HDFCFUtil::Handle_NameClashing(sd_latlon_fieldnamelist,sd_fieldnamelist);
3820  HDFCFUtil::Handle_NameClashing(sd_nollcv_fieldnamelist,sd_fieldnamelist);
3821 
3822  // Check the special characters and change those characters to _ for field namelist
3823  // Also create dimension name to coordinate variable name list
3824 
3825  int total_data_counter = 0;
3826  int total_latlon_counter = 0;
3827  int total_nollcv_counter = 0;
3828 
3829  //bool COARDFLAG = false;
3830  //string lldimname1;
3831  //string lldimname2;
3832 
3833  // change the corrected dimension name list for each SDS field
3834  std::map < std::string, std::string >::iterator tempmapit;
3835 
3836 
3837  for (std::vector < SDField * >::const_iterator i =
3838  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3839 
3840  // Handle dimension name to coordinate variable map
3841  // Currently there is a backward compatibility issue in the CF conventions,
3842  // If a field temp[ydim = 10][xdim =5][zdim=2], the
3843  // coordinate variables are lat[ydim=10][xdim=5],
3844  // lon[ydim =10][xdim=5], zdim[zdim =2]. Panoply and IDV will
3845  // not display these properly because they think the field is
3846  // following COARD conventions based on zdim[zdim =2].
3847  // To make the IDV and Panoply work, we have to change zdim[zdim=2]
3848  // to something like zdim_v[zdim=2] to distinguish the dimension name
3849  // from the variable name.
3850  // KY 2010-7-21
3851  // set a flag
3852 
3853  if ((*i)->fieldtype != 0) {
3854  if ((*i)->fieldtype == 1 || (*i)->fieldtype == 2) {
3855 
3856  (*i)->newname = sd_latlon_fieldnamelist[total_latlon_counter];
3857  total_latlon_counter++;
3858 
3859  if ((*i)->getRank () > 2)
3860  throw3 ("the lat/lon rank should NOT be greater than 2",
3861  (*i)->name, (*i)->getRank ());
3862  else if ((*i)->getRank () == 2) {// Each lat/lon must be 2-D under the same group.
3863  for (std::vector < Dimension * >::const_iterator j =
3864  (*i)->getCorrectedDimensions ().begin ();
3865  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3866  tempmapit =
3867  file->sd->dimcvarlist.find ((*j)->getName ());
3868  if (tempmapit == file->sd->dimcvarlist.end ()) {
3869  HDFCFUtil::insert_map(file->sd->dimcvarlist, (*j)->name, (*i)->newname);
3870 
3871  // Save this dim. to lldims
3872  if (lldimname1 =="")
3873  lldimname1 =(*j)->name;
3874  else
3875  lldimname2 = (*j)->name;
3876  break;
3877  }
3878  }
3879  }
3880 
3881  else {
3882  // When rank = 1, must follow COARD conventions.
3883  // Here we don't check name clashing for the performance
3884  // reason, the chance of clashing is very,very rare.
3885  (*i)->newname =
3886  (*i)->getCorrectedDimensions ()[0]->getName ();
3887  HDFCFUtil::insert_map(file->sd->dimcvarlist, (*i)->getCorrectedDimensions()[0]->getName(), (*i)->newname);
3888  COARDFLAG = true;
3889 
3890  }
3891  }
3892  }
3893  else {
3894  (*i)->newname = sd_data_fieldnamelist[total_data_counter];
3895  total_data_counter++;
3896  }
3897  }
3898 
3899 
3900  for (std::vector < SDField * >::const_iterator i =
3901  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3902 
3903 
3904  // Handle dimension name to coordinate variable map
3905  // Currently there is a backward compatibility issue in the CF conventions,
3906  // If a field temp[ydim = 10][xdim =5][zdim=2], the
3907  // coordinate variables are lat[ydim=10][xdim=5],
3908  // lon[ydim =10][xdim=5], zdim[zdim =2]. Panoply and IDV will
3909  // not display these properly because they think the field is
3910  // following COARD conventions based on zdim[zdim =2].
3911  // To make the IDV and Panoply work, we have to change zdim[zdim=2]
3912  // to something like zdim_v[zdim=2] to distinguish the dimension name
3913  // from the variable name.
3914  // KY 2010-7-21
3915  // set a flag
3916 
3917  if ((*i)->fieldtype != 0) {
3918  if ((*i)->fieldtype != 1 && (*i)->fieldtype != 2) {
3919  // "Missing" coordinate variables or coordinate variables having dimensional scale data
3920 
3921  (*i)->newname = sd_nollcv_fieldnamelist[total_nollcv_counter];
3922  total_nollcv_counter++;
3923 
3924  if ((*i)->getRank () > 1)
3925  throw3 ("The lat/lon rank should be 1", (*i)->name,
3926  (*i)->getRank ());
3927 
3928  // The current OTHERHDF case we support(MERRA and SDS dimension scale)
3929  // follow COARDS conventions. Panoply fail to display the data,
3930  // if we just follow CF conventions. So following COARD. KY-2011-3-4
3931 #if 0
3932  if (COARDFLAG || file->sptype == OTHERHDF)// Follow COARD Conventions
3933  (*i)->newname =
3934  (*i)->getCorrectedDimensions ()[0]->getName ();
3935  else
3936  // It seems that netCDF Java stricts following COARDS conventions, so change the dimension name back. KY 2012-5-4
3937  (*i)->newname =
3938  (*i)->getCorrectedDimensions ()[0]->getName ();
3939 // (*i)->newname =
3940 // (*i)->getCorrectedDimensions ()[0]->getName () + "_d";
3941 #endif
3942  (*i)->newname = (*i)->getCorrectedDimensions ()[0]->getName ();
3943 
3944  HDFCFUtil::insert_map(file->sd->dimcvarlist, (*i)->getCorrectedDimensions()[0]->getName(), (*i)->newname);
3945 
3946  }
3947  }
3948  }
3949 }
3950 
3951 // Create "coordinates", "units" CF attributes
3952 void
3953 File::handle_sds_coords(bool & COARDFLAG,std::string & lldimname1, std::string & lldimname2) throw(Exception) {
3954 
3955  File *file = this;
3956 
3957  // 9. Generate "coordinates " attribute
3958 
3959  std::map < std::string, std::string >::iterator tempmapit;
3960  int tempcount;
3961 
3962  std::string tempcoordinates;
3963  std::string tempfieldname;
3964  for (std::vector < SDField * >::const_iterator i =
3965  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
3966  if ((*i)->fieldtype == 0) {
3967  tempcount = 0;
3968  tempcoordinates = "";
3969  tempfieldname = "";
3970 
3971  for (std::vector < Dimension * >::const_iterator j =
3972  (*i)->getCorrectedDimensions ().begin ();
3973  j != (*i)->getCorrectedDimensions ().end (); ++j) {
3974  tempmapit = (file->sd->dimcvarlist).find ((*j)->getName ());
3975  if (tempmapit != (file->sd->dimcvarlist).end ())
3976  tempfieldname = tempmapit->second;
3977  else
3978  throw3 ("The dimension with the name ", (*j)->getName (),
3979  "must have corresponding coordinate variables.");
3980  if (tempcount == 0)
3981  tempcoordinates = tempfieldname;
3982  else
3983  tempcoordinates = tempcoordinates + " " + tempfieldname;
3984  tempcount++;
3985  }
3986  (*i)->setCoordinates (tempcoordinates);
3987  }
3988 
3989  // Add units for latitude and longitude
3990  if ((*i)->fieldtype == 1) { // latitude,adding the "units" attribute degrees_east.
3991  std::string tempunits = "degrees_north";
3992  (*i)->setUnits (tempunits);
3993  }
3994 
3995  if ((*i)->fieldtype == 2) { // longitude, adding the units of
3996  std::string tempunits = "degrees_east";
3997  (*i)->setUnits (tempunits);
3998  }
3999 
4000  // Add units for Z-dimension, now it is always "level"
4001  if (((*i)->fieldtype == 3) || ((*i)->fieldtype == 4)) {
4002  std::string tempunits = "level";
4003  (*i)->setUnits (tempunits);
4004  }
4005  }
4006 
4007  // Remove some coordinates attribute for some variables. This happens when a field just share one dimension name with
4008  // latitude/longitude that have 2 dimensions. For example, temp[latlondim1][otherdim] with lat[latlondim1][otherdim]; the
4009  // "coordinates" attribute may become "lat ???", which is not correct. Remove the coordinates for this case.
4010 
4011  if (false == COARDFLAG) {
4012  for (std::vector < SDField * >::const_iterator i =
4013  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4014  if ((*i)->fieldtype == 0) {
4015  bool has_lldim1 = false;
4016  bool has_lldim2 = false;
4017  for (std::vector < Dimension * >::const_iterator j =
4018  (*i)->getCorrectedDimensions ().begin ();
4019  j != (*i)->getCorrectedDimensions ().end (); ++j) {
4020  if(lldimname1 == (*j)->name)
4021  has_lldim1 = true;
4022  else if(lldimname2 == (*j)->name)
4023  has_lldim2 = true;
4024  }
4025 
4026  // Currently we don't remove the "coordinates" attribute if no lat/lon dimension names are used.
4027  if (has_lldim1^has_lldim2)
4028  (*i)->coordinates = "";
4029  }
4030  }
4031  }
4032 }
4033 
4034 
4035 // Handle Vdata
4036 void
4038 
4039  // Define File
4040  File *file = this;
4041 
4042  // Handle vdata, only need to check name clashings and special characters for vdata field names
4043  //
4044  // Check name clashings, the chance for the nameclashing between SDS and Vdata fields are almost 0. Not
4045  // to add performance burden, I won't consider the nameclashing check between SDS and Vdata fields. KY 2012-6-28
4046  //
4047 
4048 #if 0
4049  string check_disable_vdata_nameclashing_key="H4.DisableVdataNameclashingCheck";
4050  bool turn_on_disable_vdata_nameclashing_key = false;
4051 
4052  turn_on_disable_vdata_nameclashing_key = HDFCFUtil::check_beskeys(check_disable_vdata_nameclashing_key);
4053 #endif
4054 
4055 
4056  //if (false == turn_on_disable_vdata_nameclashing_key) {
4057  if (false == HDF4RequestHandler::get_disable_vdata_nameclashing_check()) {
4058 
4059  vector<string> tempvdatafieldnamelist;
4060 
4061  for (std::vector < VDATA * >::const_iterator i = file->vds.begin ();
4062  i != file->vds.end (); ++i) {
4063  for (std::vector < VDField * >::const_iterator j =
4064  (*i)->getFields ().begin (); j != (*i)->getFields ().end ();
4065  ++j)
4066  tempvdatafieldnamelist.push_back((*j)->newname);
4067  }
4068 
4069  HDFCFUtil::Handle_NameClashing(tempvdatafieldnamelist);
4070 
4071  int total_vfd_counter = 0;
4072 
4073  for (std::vector < VDATA * >::const_iterator i = file->vds.begin ();
4074  i != file->vds.end (); ++i) {
4075  for (std::vector < VDField * >::const_iterator j =
4076  (*i)->getFields ().begin (); j != (*i)->getFields ().end ();
4077  ++j) {
4078  (*j)->newname = tempvdatafieldnamelist[total_vfd_counter];
4079  total_vfd_counter++;
4080  }
4081  }
4082  }
4083 
4084 
4085 }
4086 
4087 // This is the main function that make the HDF SDS objects follow the CF convention.
4088 void
4090 {
4091 
4092  File *file = this;
4093 
4094  // 1. Obtain the original SDS and Vdata path,
4095  // Start with the lone vgroup they belong to and add the path
4096  // This also add Vdata objects that belong to lone vgroup
4098 
4099  // 2. Check the SDS special type(CERES special type has been checked at the Read function)
4100  file->CheckSDType ();
4101 
4102  // 2.1 Remove AttrContainer from the Dimension list for non-OTHERHDF products
4103  if (file->sptype != OTHERHDF) {
4104 
4105  for (std::vector < SDField * >::const_iterator i =
4106  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4107  for (vector<AttrContainer *>::iterator j = (*i)->dims_info.begin();
4108  j!= (*i)->dims_info.end(); ) {
4109  delete (*j);
4110  j = (*i)->dims_info.erase(j);
4111  //j--;
4112  }
4113  if ((*i)->dims_info.size() != 0)
4114  throw1("Not totally erase the dimension container ");
4115  }
4116  }
4117 
4118  // 3. Handle fake dimensions of HDF4 SDS objects. make the dimensions with the same dimension size
4119  // share the same dimension name. In this way, we can reduce many fakedims.
4120 
4121  handle_sds_fakedim_names();
4122 
4123  // 4. Prepare the latitude/longitude "coordinate variable" list for each special NASA HDF product
4124  switch (file->sptype) {
4125  case TRMML2_V6:
4126  {
4127  file->PrepareTRMML2_V6 ();
4128  break;
4129  }
4130  case TRMML3B_V6:
4131  {
4132  file->PrepareTRMML3B_V6 ();
4133  break;
4134  }
4135  case TRMML3A_V6:
4136  {
4137  file->PrepareTRMML3A_V6 ();
4138  break;
4139  }
4140  case TRMML3C_V6:
4141  {
4142  file->PrepareTRMML3C_V6 ();
4143  break;
4144  }
4145  case TRMML2_V7:
4146  {
4147  file->PrepareTRMML2_V7 ();
4148  break;
4149  }
4150  case TRMML3S_V7:
4151  {
4152  file->PrepareTRMML3S_V7 ();
4153  break;
4154  }
4155  case TRMML3M_V7:
4156  {
4157  file->PrepareTRMML3M_V7 ();
4158  break;
4159  }
4160  case CER_AVG:
4161  {
4162  file->PrepareCERAVGSYN ();
4163  break;
4164  }
4165  case CER_ES4:
4166  {
4167  file->PrepareCERES4IG ();
4168  break;
4169  }
4170  case CER_CDAY:
4171  {
4172  file->PrepareCERSAVGID ();
4173  break;
4174  }
4175  case CER_CGEO:
4176  {
4177  file->PrepareCERES4IG ();
4178  break;
4179  }
4180  case CER_SRB:
4181  {
4182  file->PrepareCERSAVGID ();
4183  break;
4184  }
4185  case CER_SYN:
4186  {
4187  file->PrepareCERAVGSYN ();
4188  break;
4189  }
4190  case CER_ZAVG:
4191  {
4192  file->PrepareCERZAVG ();
4193  break;
4194  }
4195  case OBPGL2:
4196  {
4197  file->PrepareOBPGL2 ();
4198  break;
4199  }
4200  case OBPGL3:
4201  {
4202  file->PrepareOBPGL3 ();
4203  break;
4204  }
4205 
4206  case MODISARNSS:
4207  {
4208  file->PrepareMODISARNSS ();
4209  break;
4210  }
4211 
4212  case OTHERHDF:
4213  {
4214  file->PrepareOTHERHDF ();
4215  break;
4216  }
4217  default:
4218  {
4219  throw3 ("No such SP datatype ", "sptype is ", sptype);
4220  break;
4221  }
4222  }
4223 
4224 
4225  // 5. Create the new dimension name set and the dimension name to size map
4226  create_sds_dim_name_list();
4227 
4228  // 6. Add the missing coordinate variables based on the corrected dimension name list
4229  handle_sds_missing_fields();
4230 
4231  // 7. Create the final CF-compliant dimension name list for each field
4232  handle_sds_final_dim_names();
4233 
4234  bool COARDFLAG = false;
4235  string lldimname1;
4236  string lldimname2;
4237 
4238  // 8. Create the final CF-compliant field name list, pass COARDFLAG as a reference
4239  // since COARDS may requires the names to change.
4240  handle_sds_names(COARDFLAG, lldimname1, lldimname2);
4241 
4242  // 9. Create "coordinates", "units" CF attributes
4243  handle_sds_coords(COARDFLAG, lldimname1,lldimname2);
4244 
4245  // 10. Handle Vdata
4246  handle_vdata();
4247 }
4248 
4249 void File:: Obtain_TRMML3S_V7_latlon_size(int &latsize, int&lonsize) {
4250 
4251  // No need to check if "GridHeader" etc. exists since this has been checked in the CheckSDType routine.
4252  for (std::vector < Attribute * >::const_iterator i =
4253  this->sd->getAttributes ().begin ();
4254  i != this->sd->getAttributes ().end (); ++i) {
4255 
4256  if ((*i)->getName () == "GridHeader") {
4257  float lat_start = 0.;
4258  float lon_start = 0.;
4259  float lat_res = 1.;
4260  float lon_res = 1.;
4261  try {
4262  HDFCFUtil::parser_trmm_v7_gridheader((*i)->getValue(),latsize,lonsize,
4263  lat_start,lon_start,
4264  lat_res,lon_res,false);
4265  }
4266  catch(...){
4267  throw;
4268  }
4269  break;
4270  }
4271  }
4272 
4273 }
4274 
4275 bool File:: Obtain_TRMM_V7_latlon_name(const SDField* sdfield, const int latsize,
4276  const int lonsize, string& latname, string& lonname) throw(Exception) {
4277 
4278 // bool latflag = false;
4279 // bool lonflag = false;
4280 
4281  int latname_index = -1;
4282  int lonname_index = -1;
4283  for (int temp_index = 0; temp_index <sdfield->getRank(); ++temp_index) {
4284  if(-1==latname_index && sdfield->getCorrectedDimensions()[temp_index]->getSize() == latsize) {
4285  latname_index = temp_index;
4286 //cerr<<"lat name index = "<<latname_index <<endl;
4287  latname = sdfield->getCorrectedDimensions()[temp_index]->getName();
4288  }
4289  else if (-1 == lonname_index && sdfield->getCorrectedDimensions()[temp_index]->getSize() == lonsize) {
4290  lonname_index = temp_index;
4291 //cerr<<"lon name index = "<<lonname_index <<endl;
4292  lonname = sdfield->getCorrectedDimensions()[temp_index]->getName();
4293  }
4294  }
4295 
4296  return (latname_index + lonname_index == 1);
4297 
4298 }
4300 
4301  File *file = this;
4302 
4303  // 1. Obtain the geolocation field: type,dimension size and dimension name
4304  // 2. Create latitude and longtiude fields according to the geolocation field.
4305  std::string tempdimname1;
4306  std::string tempdimname2;
4307  std::string tempnewdimname1;
4308  std::string tempnewdimname2;
4309  std::string temppath;
4310 
4311  //int32 tempdimsize1, tempdimsize2;
4312  //SDField *longitude;
4313  //SDField *latitude;
4314 
4315  // Create a temporary map from the dimension size to the dimension name
4316  std::set < int32 > tempdimsizeset;
4317  std::map < int32, std::string > tempdimsizenamelist;
4318  std::map < int32, std::string >::iterator tempsizemapit;
4319  std::pair < std::set < int32 >::iterator, bool > tempsetit;
4320 
4321  // Reduce the fakeDim list. FakeDim is found to be used by TRMM team.
4322  for (std::vector < SDField * >::const_iterator i =
4323  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4324  for (std::vector < Dimension * >::const_iterator j =
4325  (*i)->getCorrectedDimensions ().begin ();
4326  j != (*i)->getCorrectedDimensions ().end (); ++j) {
4327  if (((*j)->getName ()).find ("fakeDim") == std::string::npos) { //No fakeDim in the string
4328  tempsetit = tempdimsizeset.insert ((*j)->getSize ());
4329  if (tempsetit.second == true)
4330  tempdimsizenamelist[(*j)->getSize ()] = (*j)->getName ();
4331  }
4332  }
4333  }
4334 
4335  // Reduce the fakeDim list. FakeDim is found to be used by TRMM team.
4336  for (std::vector < SDField * >::const_iterator i =
4337  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4338 
4339  string temp_name = (*i)->newname.substr(1) ;
4340  size_t temp_pos = temp_name.find_first_of('/');
4341  if (temp_pos !=string::npos)
4342  (*i)->newname = temp_name.substr(temp_pos+1);
4343 
4344  }
4345 
4346 
4347  for (std::vector < SDField * >::const_iterator i =
4348  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4349 
4350  if((*i)->getName() == "Latitude") {
4351  if((*i)->getRank() ==2) {
4352 
4353  tempnewdimname1 =
4354  ((*i)->getCorrectedDimensions ())[0]->getName ();
4355  tempnewdimname2 =
4356  ((*i)->getCorrectedDimensions ())[1]->getName ();
4357  }
4358 
4359  (*i)->fieldtype = 1;
4360 
4361  }
4362  else if ((*i)->getName() == "Longitude") {
4363  (*i)->fieldtype = 2;
4364 
4365  }
4366  else {
4367 
4368  // Use the temp. map (size to name) to replace the name of "fakeDim???" with the dimension name having the same dimension length
4369  // This is done only for TRMM. It should be evaluated if this can be applied to other products.
4370  for (std::vector < Dimension * >::const_iterator k =
4371  (*i)->getCorrectedDimensions ().begin ();
4372  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4373  size_t fakeDimpos = ((*k)->getName ()).find ("fakeDim");
4374 
4375  if (fakeDimpos != std::string::npos) {
4376  tempsizemapit =
4377  tempdimsizenamelist.find ((*k)->getSize ());
4378  if (tempsizemapit != tempdimsizenamelist.end ())
4379  (*k)->name = tempdimsizenamelist[(*k)->getSize ()];// Change the dimension name
4380  }
4381  }
4382 
4383  }
4384  }
4385 
4386  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
4387  if(tempnewdimname1.empty()!=true)
4388  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
4389 
4390  if(tempnewdimname2.empty()!=true)
4391  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
4392 
4393  string base_filename;
4394  size_t last_slash_pos = file->getPath().find_last_of("/");
4395  if(last_slash_pos != string::npos)
4396  base_filename = file->getPath().substr(last_slash_pos+1);
4397  if(""==base_filename)
4398  base_filename = file->getPath();
4399 
4400 
4401  if(base_filename.find("2A12")!=string::npos) {
4402  SDField *nlayer = nullptr;
4403  string nlayer_name ="nlayer";
4404 
4405  for (vector < SDField * >::iterator i =
4406  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4407 
4408  bool has_nlayer = false;
4409 
4410  for (vector < Dimension * >::const_iterator k =
4411  (*i)->getDimensions ().begin ();
4412  k != (*i)->getDimensions ().end (); ++k) {
4413 
4414  if((*k)->getSize() == 28 && (*k)->name == nlayer_name) {
4415 
4416  nlayer = new SDField();
4417  nlayer->name = nlayer_name;
4418  nlayer->rank = 1;
4419  nlayer->type = DFNT_FLOAT32;
4420  nlayer->fieldtype = 6;
4421 
4422  nlayer->newname = nlayer->name ;
4423  Dimension *dim =
4424  new Dimension (nlayer->name, (*k)->getSize (), 0);
4425  nlayer->dims.push_back(dim);
4426 
4427  dim = new Dimension(nlayer->name,(*k)->getSize(),0);
4428  nlayer->correcteddims.push_back(dim);
4429 
4430  has_nlayer = true;
4431  break;
4432  }
4433 
4434  }
4435 
4436  if(true == has_nlayer)
4437  break;
4438  }
4439 
4440  if(nlayer !=nullptr) {
4441  file->sd->sdfields.push_back(nlayer);
4442  file->sd->nonmisscvdimnamelist.insert (nlayer_name);
4443  }
4444  }
4445 
4446 }
4447 
4448 void
4450 
4451  File *file = this;
4452  for (std::vector < SDField * >::iterator i =
4453  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ) {
4454 
4455  //According to GES DISC, the next three variables should be removed from the list.
4456  if((*i)->name == "InputFileNames") {
4457  delete (*i);
4458  i = file->sd->sdfields.erase(i);
4459  }
4460  else if((*i)->name == "InputAlgorithmVersions") {
4461  delete (*i);
4462  i = file->sd->sdfields.erase(i);
4463  }
4464  else if((*i)->name == "InputGenerationDateTimes") {
4465  delete (*i);
4466  i = file->sd->sdfields.erase(i);
4467  }
4468  else {// Just use SDS names and for performance reasons, change them here.
4469  (*i)->newname = (*i)->name;
4470  ++i;
4471  }
4472  }
4473 
4474 
4475  SDField *nlayer = nullptr;
4476  string nlayer_name ="nlayer";
4477 
4478  for (vector < SDField * >::iterator i =
4479  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4480 
4481  bool has_nlayer = false;
4482 
4483  for (vector < Dimension * >::const_iterator k =
4484  (*i)->getDimensions ().begin ();
4485  k != (*i)->getDimensions ().end (); ++k) {
4486 
4487  if((*k)->getSize() == 28 && (*k)->name == nlayer_name) {
4488 
4489  nlayer = new SDField();
4490  nlayer->name = nlayer_name;
4491  nlayer->rank = 1;
4492  nlayer->type = DFNT_FLOAT32;
4493  nlayer->fieldtype = 6;
4494 
4495  nlayer->newname = nlayer->name ;
4496  Dimension *dim =
4497  new Dimension (nlayer->name, (*k)->getSize (), 0);
4498  nlayer->dims.push_back(dim);
4499 
4500  dim = new Dimension(nlayer->name,(*k)->getSize(),0);
4501  nlayer->correcteddims.push_back(dim);
4502 
4503  has_nlayer = true;
4504  break;
4505  }
4506 
4507  }
4508 
4509  if(true == has_nlayer)
4510  break;
4511  }
4512 
4513  if(nlayer !=nullptr) {
4514  file->sd->sdfields.push_back(nlayer);
4515  file->sd->nonmisscvdimnamelist.insert (nlayer_name);
4516  }
4517 
4518  int latsize = 0;
4519  int lonsize = 0;
4520 
4521  Obtain_TRMML3S_V7_latlon_size(latsize,lonsize);
4522 //cerr<<"latsize "<<latsize <<endl;
4523 //cerr<<"lonsize "<<lonsize <<endl;
4524 
4525  string latname;
4526  string lonname;
4527 
4528  bool llname_found = false;
4529  for (std::vector < SDField * >::iterator i =
4530  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4531 
4532  if(2 == (*i)->getRank()) {
4533 
4534  llname_found = Obtain_TRMM_V7_latlon_name((*i),latsize,lonsize,latname,lonname);
4535  if (true == llname_found)
4536  break;
4537 
4538  }
4539  }
4540 
4541 //cerr<<"latitude name "<<latname <<endl;
4542 //cerr<<"longitude name "<<lonname <<endl;
4543  // Create lat/lon SD fields.
4544  SDField* longitude = new SDField ();
4545  longitude->name = lonname;
4546  longitude->rank = 1;
4547  longitude->type = DFNT_FLOAT32;
4548  longitude->fieldtype = 2;
4549 
4550  longitude->newname = longitude->name;
4551  Dimension *dim =
4552  new Dimension (lonname, lonsize, 0);
4553  longitude->dims.push_back (dim);
4554 
4555  dim = new Dimension (lonname, lonsize, 0);
4556  longitude->correcteddims.push_back (dim);
4557  file->sd->sdfields.push_back(longitude);
4558 
4559  SDField* latitude = new SDField ();
4560  latitude->name = latname;
4561  latitude->rank = 1;
4562  latitude->type = DFNT_FLOAT32;
4563  latitude->fieldtype = 1;
4564 
4565  latitude->newname = latitude->name;
4566  dim = new Dimension (latname, latsize, 0);
4567  latitude->dims.push_back (dim);
4568 
4569  dim = new Dimension (latname, latsize, 0);
4570  latitude->correcteddims.push_back (dim);
4571  file->sd->sdfields.push_back(latitude);
4572 
4573  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
4574  file->sd->nonmisscvdimnamelist.insert (latname);
4575  file->sd->nonmisscvdimnamelist.insert (lonname);
4576 
4577 
4578  // Now we want to handle the special CVs for 3A26 products. Since these special CVs only apply to the 3A26 products,
4579  // we don't want to find them from other products to reduce the performance cost. So here I simply check the filename
4580  string base_filename;
4581  if(path.find_last_of("/") != string::npos)
4582  base_filename = path.substr(path.find_last_of("/")+1);
4583  if(base_filename.find("3A26")!=string::npos) {
4584 
4585  bool ZOflag = false;
4586  bool SRTflag = false;
4587  bool HBflag = false;
4588  string nthrsh_base_name = "nthrsh";
4589  string nthrsh_zo_name ="nthrshZO";
4590  string nthrsh_hb_name ="nthrshHB";
4591  string nthrsh_srt_name ="nthrshSRT";
4592 
4593  SDField* nthrsh_zo = nullptr;
4594  SDField* nthrsh_hb = nullptr;
4595  SDField* nthrsh_srt = nullptr;
4596 
4597  for (vector < SDField * >::iterator i =
4598  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4599 
4600  if(ZOflag != true) {
4601  if((*i)->name.find("Order")!=string::npos) {
4602  for (vector < Dimension * >::const_iterator k =
4603  (*i)->getDimensions ().begin ();
4604  k != (*i)->getDimensions ().end (); ++k) {
4605 
4606  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4607  if(nthrsh_zo == nullptr) {// Not necessary for this product, this only makes coverity scan happy.
4608  nthrsh_zo = new SDField();
4609  nthrsh_zo->name = nthrsh_zo_name;
4610  nthrsh_zo->rank = 1;
4611  nthrsh_zo->type = DFNT_FLOAT32;
4612  nthrsh_zo->fieldtype = 6;
4613 
4614  nthrsh_zo->newname = nthrsh_zo->name ;
4615  Dimension *dim =
4616  new Dimension (nthrsh_zo->name, (*k)->getSize (), 0);
4617  nthrsh_zo->dims.push_back(dim);
4618 
4619  dim = new Dimension(nthrsh_zo->name,(*k)->getSize(),0);
4620  nthrsh_zo->correcteddims.push_back(dim);
4621 
4622  ZOflag = true;
4623  }
4624 
4625  }
4626  }
4627  }
4628 
4629  }
4630 
4631  else if(SRTflag != true) {
4632  if((*i)->name.find("2A25")!=string::npos) {
4633 
4634  for (vector < Dimension * >::const_iterator k =
4635  (*i)->getDimensions ().begin ();
4636  k != (*i)->getDimensions ().end (); ++k) {
4637 
4638  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4639  if(nthrsh_srt == nullptr) { // Not necessary for this product, this only makes coverity scan happy.
4640  nthrsh_srt = new SDField();
4641  nthrsh_srt->name = nthrsh_srt_name;
4642  nthrsh_srt->rank = 1;
4643  nthrsh_srt->type = DFNT_FLOAT32;
4644  nthrsh_srt->fieldtype = 6;
4645 
4646  nthrsh_srt->newname = nthrsh_srt->name ;
4647  Dimension *dim =
4648  new Dimension (nthrsh_srt->name, (*k)->getSize (), 0);
4649  nthrsh_srt->dims.push_back(dim);
4650 
4651  dim = new Dimension(nthrsh_srt->name,(*k)->getSize(),0);
4652  nthrsh_srt->correcteddims.push_back(dim);
4653 
4654  SRTflag = true;
4655  }
4656 
4657  }
4658  }
4659  }
4660  }
4661  else if(HBflag != true) {
4662  if((*i)->name.find("hb")!=string::npos || (*i)->name.find("HB")!=string::npos) {
4663 
4664  for (vector < Dimension * >::const_iterator k =
4665  (*i)->getDimensions ().begin ();
4666  k != (*i)->getDimensions ().end (); ++k) {
4667 
4668  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4669 
4670  if(nthrsh_hb == nullptr) {// Not necessary for this product, only makes coverity scan happy.
4671  nthrsh_hb = new SDField();
4672  nthrsh_hb->name = nthrsh_hb_name;
4673  nthrsh_hb->rank = 1;
4674  nthrsh_hb->type = DFNT_FLOAT32;
4675  nthrsh_hb->fieldtype = 6;
4676 
4677  nthrsh_hb->newname = nthrsh_hb->name ;
4678  Dimension *dim =
4679  new Dimension (nthrsh_hb->name, (*k)->getSize (), 0);
4680  nthrsh_hb->dims.push_back(dim);
4681 
4682  dim = new Dimension(nthrsh_hb->name,(*k)->getSize(),0);
4683  nthrsh_hb->correcteddims.push_back(dim);
4684 
4685  HBflag = true;
4686  }
4687  }
4688  }
4689  }
4690  }
4691  }
4692 
4693 
4694  for (vector < SDField * >::iterator i =
4695  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4696 
4697  if((*i)->name.find("Order")!=string::npos && ZOflag == true) {
4698  for (vector < Dimension * >::const_iterator k =
4699  (*i)->getDimensions ().begin ();
4700  k != (*i)->getDimensions ().end (); ++k) {
4701 
4702  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4703  (*k)->name = nthrsh_zo_name;
4704  break;
4705  }
4706  }
4707 
4708  for (std::vector < Dimension * >::const_iterator k =
4709  (*i)->getCorrectedDimensions ().begin ();
4710  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4711  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4712  (*k)->name = nthrsh_zo_name;
4713  break;
4714  }
4715  }
4716 
4717  }
4718 
4719  else if(((*i)->name.find("hb")!=string::npos || (*i)->name.find("HB")!=string::npos)&& HBflag == true) {
4720  for (vector < Dimension * >::const_iterator k =
4721  (*i)->getDimensions ().begin ();
4722  k != (*i)->getDimensions ().end (); ++k) {
4723 
4724  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4725  (*k)->name = nthrsh_hb_name;
4726  break;
4727  }
4728  }
4729 
4730  for (std::vector < Dimension * >::const_iterator k =
4731  (*i)->getCorrectedDimensions ().begin ();
4732  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4733  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4734  (*k)->name = nthrsh_hb_name;
4735  break;
4736  }
4737  }
4738 
4739  }
4740  else if(((*i)->name.find("2A25")!=string::npos) && SRTflag == true) {
4741  for (vector < Dimension * >::const_iterator k =
4742  (*i)->getDimensions ().begin ();
4743  k != (*i)->getDimensions ().end (); ++k) {
4744 
4745  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4746  (*k)->name = nthrsh_srt_name;
4747  break;
4748  }
4749  }
4750 
4751  for (std::vector < Dimension * >::const_iterator k =
4752  (*i)->getCorrectedDimensions ().begin ();
4753  k != (*i)->getCorrectedDimensions ().end (); ++k) {
4754  if((*k)->getSize() == 6 && (*k)->name == nthrsh_base_name) {
4755  (*k)->name = nthrsh_srt_name;
4756  break;
4757  }
4758  }
4759 
4760  }
4761 
4762 
4763  }
4764 
4765  if(nthrsh_zo !=nullptr) {
4766  file->sd->sdfields.push_back(nthrsh_zo);
4767  file->sd->nonmisscvdimnamelist.insert (nthrsh_zo_name);
4768  }
4769 
4770  if(nthrsh_hb !=nullptr) {
4771  file->sd->sdfields.push_back(nthrsh_hb);
4772  file->sd->nonmisscvdimnamelist.insert (nthrsh_hb_name);
4773  }
4774 
4775  if(nthrsh_srt !=nullptr) {
4776  file->sd->sdfields.push_back(nthrsh_srt);
4777  file->sd->nonmisscvdimnamelist.insert (nthrsh_srt_name);
4778  }
4779 
4780  }
4781 
4782 }
4783 
4784 void
4786 
4787  File *file = this;
4788  for (std::vector < SDField * >::iterator i =
4789  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ) {
4790 
4791  if((*i)->name == "InputFileNames") {
4792  delete (*i);
4793  i = file->sd->sdfields.erase(i);
4794  //i--;
4795  }
4796  else if((*i)->name == "InputAlgorithmVersions") {
4797  delete (*i);
4798  i = file->sd->sdfields.erase(i);
4799  //i--;
4800  }
4801  else if((*i)->name == "InputGenerationDateTimes") {
4802  delete (*i);
4803  i = file->sd->sdfields.erase(i);
4804  //i--;
4805  }
4806  else {
4807  ++i;
4808 
4809  }
4810  }
4811 
4812 
4813 #if 0
4814  NOTE for programming:
4815  1. Outer loop: loop global attribute for GridHeader?. Retrieve ? as a number for index.
4816  1.5. Obtain the lat/lon sizes for this grid.
4817  The following steps are to retrieve lat/lon names for this grid.
4818  2. Inner loop: Then loop through the field
4819  3. Check the field rank,
4820  3.1 if the rank is not 2, (if the index is the first index, change the newname to name )
4821  continue.
4822  3.2 else {
4823  3.2.1 Retrieve the index from the field new name(retrieve last path Grid1 then retrieve 1)
4824  3.2.2 If the index from the field is the same as that from the GridHeader, continue checking
4825  the lat/lon name for this grid as the single grid.
4826  change the newname to name.
4827  }
4828 #endif
4829 
4830  // The following code tries to be performance-friendly by looping through the fields and handling the operations
4831  // as less as I can.
4832 
4833  int first_index = -1;
4834  for (vector < Attribute * >::const_iterator i =
4835  this->sd->getAttributes ().begin ();
4836  i != this->sd->getAttributes ().end (); ++i) {
4837 
4838  if ((*i)->getName ().find("GridHeader")==0) {
4839  string temp_name = (*i)->getName();
4840 
4841  // The size of "GridHeader" is 10, no need to calculate.
4842  string str_num = temp_name.substr(10);
4843  stringstream ss_num(str_num);
4844 
4845  int grid_index;
4846  ss_num >> grid_index;
4847 
4848  if ( -1 == first_index)
4849  first_index = grid_index;
4850 
4851  float lat_start = 0.;
4852  float lon_start = 0.;
4853  float lat_res = 1.;
4854  float lon_res = 1.;
4855  int latsize = 0;
4856  int lonsize = 0;
4857 
4858  try {
4859  HDFCFUtil::parser_trmm_v7_gridheader((*i)->getValue(),latsize,lonsize,
4860  lat_start,lon_start,
4861  lat_res, lon_res, false);
4862  }
4863  catch(...) {
4864  throw;
4865  }
4866 
4867  string latname;
4868  string lonname;
4869 
4870  bool llname_found = false;
4871  for (std::vector < SDField * >::iterator i =
4872  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4873 
4874  // Just loop the 2-D fields to find the lat/lon size
4875  if(2 == (*i)->getRank()) {
4876 
4877  // If a grid has not been visited, we will check the fields attached to this grid.
4878  if ((*i)->newname !=(*i)->name) {
4879 
4880  string temp_field_full_path = (*i)->getNewName();
4881  size_t last_path_pos = temp_field_full_path.find_last_of('/');
4882  char str_index = temp_field_full_path[last_path_pos-1];
4883  if(grid_index ==(int)(str_index - '0')) {
4884  if(llname_found != true)
4885  llname_found = Obtain_TRMM_V7_latlon_name((*i),latsize,lonsize,latname,lonname);
4886  (*i)->newname = (*i)->name;
4887  }
4888  }
4889  }
4890  else if (first_index == grid_index)
4891  (*i)->newname = (*i)->name;
4892  }
4893 
4894  // Create lat/lon SD fields.
4895  SDField* longitude = new SDField ();
4896  longitude->name = lonname;
4897  longitude->rank = 1;
4898  longitude->type = DFNT_FLOAT32;
4899  longitude->fieldtype = 2;
4900  longitude->fieldref = grid_index;
4901 
4902  longitude->newname = longitude->name;
4903  Dimension *dim =
4904  new Dimension (lonname, lonsize, 0);
4905  longitude->dims.push_back (dim);
4906 
4907  dim = new Dimension (lonname, lonsize, 0);
4908  longitude->correcteddims.push_back (dim);
4909  file->sd->sdfields.push_back(longitude);
4910 
4911  SDField* latitude = new SDField ();
4912  latitude->name = latname;
4913  latitude->rank = 1;
4914  latitude->type = DFNT_FLOAT32;
4915  latitude->fieldtype = 1;
4916  latitude->fieldref = grid_index;
4917 
4918  latitude->newname = latitude->name;
4919  dim = new Dimension (latname, latsize, 0);
4920  latitude->dims.push_back (dim);
4921 
4922  dim = new Dimension (latname, latsize, 0);
4923  latitude->correcteddims.push_back (dim);
4924  file->sd->sdfields.push_back(latitude);
4925 
4926  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
4927  file->sd->nonmisscvdimnamelist.insert (latname);
4928  file->sd->nonmisscvdimnamelist.insert (lonname);
4929 
4930  }
4931  }
4932 }
4933 
4936 void
4938 throw (Exception)
4939 {
4940 
4941  File *file = this;
4942 
4943  // 1. Obtain the geolocation field: type,dimension size and dimension name
4944  // 2. Create latitude and longtiude fields according to the geolocation field.
4945  std::string tempdimname1;
4946  std::string tempdimname2;
4947  std::string tempnewdimname1;
4948  std::string tempnewdimname2;
4949  std::string temppath;
4950 
4951  int32 tempdimsize1;
4952  int32 tempdimsize2;
4953  SDField *longitude = nullptr;
4954  SDField *latitude = nullptr;
4955 
4956  // Create a temporary map from the dimension size to the dimension name
4957  std::set < int32 > tempdimsizeset;
4958  std::map < int32, std::string > tempdimsizenamelist;
4959  std::map < int32, std::string >::iterator tempsizemapit;
4960  std::pair < std::set < int32 >::iterator, bool > tempsetit;
4961 
4962  // Reduce the fakeDim list. FakeDim is found to be used by TRMM team.
4963  for (std::vector < SDField * >::const_iterator i =
4964  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4965  for (std::vector < Dimension * >::const_iterator j =
4966  (*i)->getCorrectedDimensions ().begin ();
4967  j != (*i)->getCorrectedDimensions ().end (); ++j) {
4968  if (((*j)->getName ()).find ("fakeDim") == std::string::npos) { //No fakeDim in the string
4969  tempsetit = tempdimsizeset.insert ((*j)->getSize ());
4970  if (tempsetit.second == true)
4971  tempdimsizenamelist[(*j)->getSize ()] = (*j)->getName ();
4972  }
4973  }
4974  }
4975 
4976  for (std::vector < SDField * >::const_iterator i =
4977  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
4978 
4979  if ((*i)->getName () == "geolocation") {
4980 
4981  // Obtain the size and the name of the first two dimensions of the geolocation field;
4982  // make these two dimensions the dimensions of latitude and longtiude.
4983  tempdimname1 = ((*i)->getDimensions ())[0]->getName ();
4984  tempdimsize1 = ((*i)->getDimensions ())[0]->getSize ();
4985  tempdimname2 = ((*i)->getDimensions ())[1]->getName ();
4986  tempdimsize2 = ((*i)->getDimensions ())[1]->getSize ();
4987 
4988  tempnewdimname1 =
4989  ((*i)->getCorrectedDimensions ())[0]->getName ();
4990  tempnewdimname2 =
4991  ((*i)->getCorrectedDimensions ())[1]->getName ();
4992 
4993  // TRMM level 2 version 6 only has one geolocation field.
4994  // So latitude and longitude are only assigned once.
4995  // However, coverity scan doesn't know this and complain about
4996  // the re-allocation of latitude and longitude that may cause the
4997  // potential resource leaks. KY 2015-05-12
4998  if(latitude == nullptr) {
4999 
5000  latitude = new SDField ();
5001  latitude->name = "latitude";
5002  latitude->rank = 2;
5003  latitude->fieldref = (*i)->fieldref;
5004  latitude->type = (*i)->getType ();
5005  temppath = (*i)->newname.substr ((*i)->name.size ());
5006  latitude->newname = latitude->name + temppath;
5007  latitude->fieldtype = 1;
5008  latitude->rootfieldname = "geolocation";
5009 
5010  Dimension *dim = new Dimension (tempdimname1, tempdimsize1, 0);
5011 
5012  latitude->dims.push_back (dim);
5013 
5014  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5015  latitude->dims.push_back (dim);
5016 
5017  dim = new Dimension (tempnewdimname1, tempdimsize1, 0);
5018  latitude->correcteddims.push_back (dim);
5019 
5020  dim = new Dimension (tempnewdimname2, tempdimsize2, 0);
5021  latitude->correcteddims.push_back (dim);
5022  }
5023 
5024  if(longitude == nullptr) {
5025  longitude = new SDField ();
5026  longitude->name = "longitude";
5027  longitude->rank = 2;
5028  longitude->fieldref = (*i)->fieldref;
5029  longitude->type = (*i)->getType ();
5030  longitude->newname = longitude->name + temppath;
5031  longitude->fieldtype = 2;
5032  longitude->rootfieldname = "geolocation";
5033 
5034  Dimension *dim = new Dimension (tempdimname1, tempdimsize1, 0);
5035  longitude->dims.push_back (dim);
5036  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5037  longitude->dims.push_back (dim);
5038 
5039  dim = new Dimension (tempnewdimname1, tempdimsize1, 0);
5040  longitude->correcteddims.push_back (dim);
5041 
5042  dim = new Dimension (tempnewdimname2, tempdimsize2, 0);
5043  longitude->correcteddims.push_back (dim);
5044  }
5045 
5046  }
5047  else {
5048 
5049  // Use the temp. map (size to name) to replace the name of "fakeDim???" with the dimension name having the same dimension length
5050  // This is done only for TRMM. It should be evaluated if this can be applied to other products.
5051  for (std::vector < Dimension * >::const_iterator k =
5052  (*i)->getCorrectedDimensions ().begin ();
5053  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5054  size_t fakeDimpos = ((*k)->getName ()).find ("fakeDim");
5055 
5056  if (fakeDimpos != std::string::npos) {
5057  tempsizemapit =
5058  tempdimsizenamelist.find ((*k)->getSize ());
5059  if (tempsizemapit != tempdimsizenamelist.end ())
5060  (*k)->name = tempdimsizenamelist[(*k)->getSize ()];// Change the dimension name
5061  }
5062  }
5063  }
5064  }
5065 
5066  file->sd->sdfields.push_back (latitude);
5067  file->sd->sdfields.push_back (longitude);
5068 
5069  // 3. Remove the geolocation field from the field list
5070  SDField *origeo = nullptr;
5071 
5072  std::vector < SDField * >::iterator toeraseit;
5073  for (std::vector < SDField * >::iterator i = file->sd->sdfields.begin ();
5074  i != file->sd->sdfields.end (); ++i) {
5075  if ((*i)->getName () == "geolocation") { // Check the release of dimension and other resources
5076  toeraseit = i;
5077  origeo = *i;
5078  break;
5079  }
5080  }
5081 
5082  file->sd->sdfields.erase (toeraseit);
5083  if (origeo != nullptr)
5084  delete (origeo);
5085 
5086  // 4. Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5087  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5088  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5089 
5090 }
5091 
5092 // Prepare TRMM Level 3, no lat/lon are in the original HDF4 file. Need to provide them.
5093 void
5095 throw (Exception)
5096 {
5097 
5098  std::string tempnewdimname1, tempnewdimname2;
5099  int latflag = 0;
5100  int lonflag = 0;
5101 
5102  std::string temppath;
5103  SDField *latitude = nullptr;
5104  SDField *longitude = nullptr;
5105  File *file = this;
5106 
5107  for (std::vector < SDField * >::const_iterator i =
5108  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5109 
5110  for (std::vector < Dimension * >::const_iterator k =
5111  (*i)->getDimensions ().begin ();
5112  k != (*i)->getDimensions ().end (); ++k) {
5113 
5114  // This dimension has the dimension name
5115  if ((((*k)->getName ()).find ("fakeDim")) == std::string::npos) {
5116 
5117  temppath = (*i)->newname.substr ((*i)->name.size ());
5118  // The lat/lon formula is from GES DISC web site. http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
5119  // KY 2010-7-13
5120  if ((*k)->getSize () == 1440 && (*k)->getType () == 0) {//No dimension scale
5121 
5122  if(longitude == nullptr) { // Not necessary for this product, only makes coverity happy.
5123  longitude = new SDField ();
5124  longitude->name = "longitude";
5125  longitude->rank = 1;
5126  longitude->type = DFNT_FLOAT32;
5127  longitude->fieldtype = 2;
5128 
5129  longitude->newname = longitude->name + temppath;
5130  Dimension *dim =
5131  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
5132  longitude->dims.push_back (dim);
5133  tempnewdimname2 = (*k)->getName ();
5134 
5135  dim =
5136  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
5137  longitude->correcteddims.push_back (dim);
5138  lonflag++;
5139  }
5140  }
5141 
5142  if ((*k)->getSize () == 400 && (*k)->getType () == 0) {
5143 
5144  if(latitude == nullptr) {
5145  latitude = new SDField ();
5146  latitude->name = "latitude";
5147  latitude->rank = 1;
5148  latitude->type = DFNT_FLOAT32;
5149  latitude->fieldtype = 1;
5150  latitude->newname = latitude->name + temppath;
5151  Dimension *dim =
5152  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
5153  latitude->dims.push_back (dim);
5154  tempnewdimname1 = (*k)->getName ();
5155 
5156  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5157  // Leave here just as a reference.
5158  // std::string uniquedimname = (*k)->getName() +temppath;
5159  // tempnewdimname1 = uniquedimname;
5160  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5161  dim =
5162  new Dimension ((*k)->getName (), (*k)->getSize (), 0);
5163  latitude->correcteddims.push_back (dim);
5164  latflag++;
5165  }
5166  }
5167  }
5168 
5169  if (latflag == 1 && lonflag == 1)
5170  break;
5171  }
5172 
5173  if (latflag == 1 && lonflag == 1)
5174  break; // For this case, a field that needs lon and lot must exist
5175 
5176  // Need to reset the flag to avoid false alarm. For TRMM L3 we can handle, a field that has dimension
5177  // which size is 400 and 1440 must exist in the file.
5178  latflag = 0;
5179  lonflag = 0;
5180  }
5181 
5182  if (latflag != 1 || lonflag != 1) {
5183  if(latitude != nullptr)
5184  delete latitude;
5185  if(longitude != nullptr)
5186  delete longitude;
5187  throw5 ("Either latitude or longitude doesn't exist.", "lat. flag= ",
5188  latflag, "lon. flag= ", lonflag);
5189  }
5190  file->sd->sdfields.push_back (latitude);
5191  file->sd->sdfields.push_back (longitude);
5192 
5193 
5194  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5195  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5196  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5197 
5198 }
5199 
5200 // Prepare TRMM Level 3, no lat/lon are in the original HDF4 file. Need to provide them.
5201 void
5203 throw (Exception)
5204 {
5205  std::string tempnewdimname1;
5206  std::string tempnewdimname2;
5207  bool latflag = false;
5208  bool lonflag = false;
5209 
5210  SDField *latitude = nullptr;
5211  SDField *longitude = nullptr;
5212  File *file = this;
5213 
5214  for (std::vector < SDField * >::const_iterator i =
5215  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5216 
5217  for (std::vector < Dimension * >::const_iterator k =
5218  (*i)->getDimensions ().begin ();
5219  k != (*i)->getDimensions ().end (); ++k) {
5220  if ((((*k)->getName ()).find ("latitude")) == 0)
5221  (*k)->name = "fakeDim1";
5222  if ((((*k)->getName()).find ("longitude")) == 0)
5223  (*k)->name = "fakeDim2";
5224 
5225  }
5226 
5227  // Since we use correctedims, we also need to change them. We may
5228  // need to remove correctedims from HDFSP space in the future.
5229  for (std::vector < Dimension * >::const_iterator k =
5230  (*i)->getCorrectedDimensions ().begin ();
5231  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5232  if ((((*k)->getName ()).find ("latitude")) == 0)
5233  (*k)->name = "fakeDim1";
5234  if ((((*k)->getName()).find ("longitude")) == 0)
5235  (*k)->name = "fakeDim2";
5236 
5237  }
5238  }
5239 
5240  for (std::vector < SDField * >::const_iterator i =
5241  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5242 
5243 
5244  for (std::vector < Dimension * >::const_iterator k =
5245  (*i)->getDimensions ().begin ();
5246  k != (*i)->getDimensions ().end (); ++k) {
5247 
5248 
5249  // This dimension has the dimension name
5250  //if ((((*k)->getName ()).find ("fakeDim")) == std::string::npos)
5251 
5252  // The lat/lon formula is from GES DISC web site. http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
5253  // KY 2010-7-13
5254  if ((*k)->getSize () == 360 && (*k)->getType () == 0) {//No dimension scale
5255 
5256  if(longitude == nullptr) {
5257  longitude = new SDField ();
5258  longitude->name = "longitude";
5259  longitude->rank = 1;
5260  longitude->type = DFNT_FLOAT32;
5261  longitude->fieldtype = 2;
5262 
5263  longitude->newname = longitude->name ;
5264  Dimension *dim =
5265  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5266  longitude->dims.push_back (dim);
5267  tempnewdimname2 = longitude->name;
5268 
5269  dim =
5270  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5271  longitude->correcteddims.push_back (dim);
5272  lonflag = true;
5273  }
5274  }
5275 
5276  if ((*k)->getSize () == 180 && (*k)->getType () == 0) {
5277 
5278  if(latitude == nullptr) {
5279  latitude = new SDField ();
5280  latitude->name = "latitude";
5281  latitude->rank = 1;
5282  latitude->type = DFNT_FLOAT32;
5283  latitude->fieldtype = 1;
5284  latitude->newname = latitude->name ;
5285  Dimension *dim =
5286  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5287 
5288  latitude->dims.push_back (dim);
5289  tempnewdimname1 = latitude->getName ();
5290 
5291  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5292  // Leave here just as a reference.
5293  // std::string uniquedimname = (*k)->getName() +temppath;
5294  // tempnewdimname1 = uniquedimname;
5295  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5296  dim =
5297  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5298  latitude->correcteddims.push_back (dim);
5299  latflag = true;
5300  }
5301  }
5302 
5303 
5304  if (latflag == true && lonflag == true)
5305  break;
5306  }
5307 
5308  if (latflag == true && lonflag == true)
5309  break; // For this case, a field that needs lon and lot must exist
5310 
5311  // Need to reset the flag to avoid false alarm. For TRMM L3 we can handle, a field that has dimension
5312  // which size is 400 and 1440 must exist in the file.
5313  latflag = false;
5314  lonflag = false;
5315  }
5316 
5317  if (latflag !=true || lonflag != true) {
5318  if(latitude != nullptr)
5319  delete latitude;
5320  if(longitude != nullptr)
5321  delete longitude;
5322  throw5 ("Either latitude or longitude doesn't exist.", "lat. flag= ",
5323  latflag, "lon. flag= ", lonflag);
5324  }
5325 
5326  else {// Without else this is fine since throw5 will go before this. This is just make Coverity happy.KY 2015-10-23
5327  for (std::vector < SDField * >::const_iterator i =
5328  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5329 
5330 
5331  for (std::vector < Dimension * >::const_iterator k =
5332  (*i)->getDimensions ().begin ();
5333  k != (*i)->getDimensions ().end (); ++k) {
5334 
5335  if ((*k)->getSize () == 360 )
5336  (*k)->name = longitude->name;
5337 
5338  if ((*k)->getSize () == 180 )
5339  (*k)->name = latitude->name;
5340 
5341  }
5342 
5343  for (std::vector < Dimension * >::const_iterator k =
5344  (*i)->getCorrectedDimensions ().begin ();
5345  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5346 
5347  if ((*k)->getSize () == 360 )
5348  (*k)->name = longitude->name;
5349 
5350  if ((*k)->getSize () == 180 )
5351  (*k)->name = latitude->name;
5352 
5353  }
5354 
5355 
5356  }
5357 
5358 
5359  file->sd->sdfields.push_back (latitude);
5360  file->sd->sdfields.push_back (longitude);
5361  }
5362 
5363 
5364  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5365  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5366  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5367 
5368 }
5369 
5370 // Prepare TRMM Level 3, no lat/lon are in the original HDF4 file. Need to provide them.
5371 void
5373 throw (Exception)
5374 {
5375 
5376  std::string tempnewdimname1;
5377  std::string tempnewdimname2;
5378  std::string tempnewdimname3;
5379  bool latflag = false;
5380  bool lonflag = false;
5381  bool heiflag = false;
5382 
5383  SDField *latitude = nullptr;
5384  SDField *longitude = nullptr;
5385  SDField *height = nullptr;
5386 
5387  File *file = this;
5388 
5389  for (std::vector < SDField * >::const_iterator i =
5390  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5391 
5392 
5393  for (std::vector < Dimension * >::const_iterator k =
5394  (*i)->getDimensions ().begin ();
5395  k != (*i)->getDimensions ().end (); ++k) {
5396 
5397 
5398  // This dimension has the dimension name
5399  //if ((((*k)->getName ()).find ("fakeDim")) == std::string::npos)
5400 
5401  // The lat/lon formula is from GES DISC web site. http://disc.sci.gsfc.nasa.gov/additional/faq/precipitation_faq.shtml#lat_lon
5402  // KY 2010-7-13
5403  if ((*k)->getSize () == 720 && (*k)->getType () == 0) {//No dimension scale
5404 
5405  // TRMM only has one longitude and latitude. The following if only makes coverity happy.
5406  if(longitude == nullptr) {
5407  longitude = new SDField ();
5408  longitude->name = "longitude";
5409  longitude->rank = 1;
5410  longitude->type = DFNT_FLOAT32;
5411  longitude->fieldtype = 2;
5412 
5413  longitude->newname = longitude->name ;
5414  Dimension *dim =
5415  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5416  longitude->dims.push_back (dim);
5417  tempnewdimname2 = longitude->name;
5418 
5419  dim =
5420  new Dimension (longitude->getName (), (*k)->getSize (), 0);
5421  longitude->correcteddims.push_back (dim);
5422  lonflag = true;
5423  }
5424  }
5425 
5426  if ((*k)->getSize () == 148 && (*k)->getType () == 0) {
5427 
5428  if(latitude == nullptr) {
5429  latitude = new SDField ();
5430  latitude->name = "latitude";
5431  latitude->rank = 1;
5432  latitude->type = DFNT_FLOAT32;
5433  latitude->fieldtype = 1;
5434  latitude->newname = latitude->name ;
5435  Dimension *dim =
5436  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5437 
5438  latitude->dims.push_back (dim);
5439  tempnewdimname1 = latitude->getName ();
5440 
5441  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5442  // Leave here just as a reference.
5443  // std::string uniquedimname = (*k)->getName() +temppath;
5444  // tempnewdimname1 = uniquedimname;
5445  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5446  dim =
5447  new Dimension (latitude->getName (), (*k)->getSize (), 0);
5448  latitude->correcteddims.push_back (dim);
5449  latflag = true;
5450  }
5451  }
5452 
5453  if ((*k)->getSize () == 19 && (*k)->getType () == 0) {
5454 
5455  if(height == nullptr) {
5456  height = new SDField ();
5457  height->name = "height";
5458  height->rank = 1;
5459  height->type = DFNT_FLOAT32;
5460  height->fieldtype = 6;
5461  height->newname = height->name ;
5462  Dimension *dim =
5463  new Dimension (height->getName (), (*k)->getSize (), 0);
5464 
5465  height->dims.push_back (dim);
5466  tempnewdimname3 = height->getName ();
5467 
5468  // We donot need to generate the unique dimension name based on the full path for all the current cases we support.
5469  // Leave here just as a reference.
5470  // std::string uniquedimname = (*k)->getName() +temppath;
5471  // tempnewdimname1 = uniquedimname;
5472  // dim = new Dimension(uniquedimname,(*k)->getSize(),(*i)->getType());
5473  dim =
5474  new Dimension (height->getName (), (*k)->getSize (), 0);
5475  height->correcteddims.push_back (dim);
5476  heiflag = true;
5477  }
5478  }
5479 
5480 
5481  }
5482 
5483  if (latflag == true && lonflag == true)
5484  break; // For this case, a field that needs lon and lot must exist
5485 
5486  // Need to reset the flag to avoid false alarm. For TRMM L3 we can handle, a field that has dimension
5487  // which size is 400 and 1440 must exist in the file.
5488  latflag = false;
5489  lonflag = false;
5490  heiflag = false;
5491  }
5492 
5493  if (latflag != true || lonflag != true) {
5494  if(latitude != nullptr)
5495  delete latitude;
5496  if(longitude != nullptr)
5497  delete longitude;
5498  throw5 ("Either latitude or longitude doesn't exist.", "lat. flag= ",
5499  latflag, "lon. flag= ", lonflag);
5500  }
5501 
5502  if(height!=nullptr && heiflag !=true) {
5503  delete height;
5504  throw1("Height is allocated but the flag is not true");
5505  }
5506 
5507 
5508  file->sd->sdfields.push_back (latitude);
5509  file->sd->sdfields.push_back (longitude);
5510 
5511  if(height!=nullptr) {
5512 
5513  if(heiflag != true) {
5514  delete height;
5515  throw1("Height is allocated but the flag is not true");
5516  }
5517  else {
5518  file->sd->sdfields.push_back (height);
5519  file->sd->nonmisscvdimnamelist.insert (tempnewdimname3);
5520  }
5521  }
5522 
5523  // Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5524  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5525  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5526 
5527 }
5528 // This applies to all OBPG level 2 products include SeaWIFS, MODISA, MODIST,OCTS, CZCS
5529 // A formula similar to swath dimension map needs to apply to this file.
5530 void
5532 throw (Exception)
5533 {
5534  int pixels_per_scan_line = 0;
5535 
5536  std::string pixels_per_scan_line_name = "Pixels per Scan Line";
5537  std::string number_pixels_control_points = "Number of Pixel Control Points";
5538  std::string tempnewdimname1, tempnewdimname2;
5539 
5540  File *file = this;
5541 
5542  // 1. Obtain the expanded size of the latitude/longitude
5543  for (std::vector < Attribute * >::const_iterator i =
5544  file->sd->getAttributes ().begin ();
5545  i != file->sd->getAttributes ().end (); ++i) {
5546  if ((*i)->getName () == pixels_per_scan_line_name) {
5547  int *attrvalueptr = (int *) (&((*i)->getValue ()[0]));
5548  pixels_per_scan_line = *attrvalueptr;
5549  break;
5550  }
5551  }
5552 
5553  if ( 0 == pixels_per_scan_line)
5554  throw1("The attribute 'Pixels per Scan Line' doesn't exist");
5555 
5556  // 2. Obtain the latitude and longitude information
5557  // Assign the new dimension name and the dimension size
5558  // std::string temppath;
5559  int tempcountllflag = 0;
5560 
5561  for (std::vector < SDField * >::const_iterator i =
5562  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5563 
5564  if ((*i)->getName () == "longitude" || (*i)->getName () == "latitude") {
5565  if ((*i)->getName () == "longitude")
5566  (*i)->fieldtype = 2;
5567  if ((*i)->getName () == "latitude")
5568  (*i)->fieldtype = 1;
5569 
5570  tempcountllflag++;
5571  if ((*i)->getRank () != 2)
5572  throw3 ("The lat/lon rank must be 2", (*i)->getName (),
5573  (*i)->getRank ());
5574  for (std::vector < Dimension * >::const_iterator k =
5575  (*i)->getDimensions ().begin ();
5576  k != (*i)->getDimensions ().end (); ++k) {
5577  if ((*k)->getName () == number_pixels_control_points) {
5578  (*k)->name = pixels_per_scan_line_name;
5579  (*k)->dimsize = pixels_per_scan_line;
5580  break;
5581  }
5582  }
5583 
5584  for (std::vector < Dimension * >::const_iterator k =
5585  (*i)->getCorrectedDimensions ().begin ();
5586  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5587  if ((*k)->getName ().find (number_pixels_control_points) !=
5588  std::string::npos) {
5589  (*k)->name = pixels_per_scan_line_name;
5590  (*k)->dimsize = pixels_per_scan_line;
5591  if (tempcountllflag == 1)
5592  tempnewdimname2 = (*k)->name;
5593  }
5594  else {
5595  if (tempcountllflag == 1)
5596  tempnewdimname1 = (*k)->name;
5597  }
5598  }
5599  }
5600  if (tempcountllflag == 2)
5601  break;
5602  }
5603 
5604 
5605  // 3. Create the <dimname,coordinate variable> map from the corresponding dimension names to the latitude and the longitude
5606  // Obtain the corrected dimension names for latitude and longitude
5607  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5608  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5609 
5610 }
5611 
5612 // This applies to all OBPG l3m products include SeaWIFS, MODISA, MODIST,OCTS, CZCS
5613 // Latitude and longitude need to be calculated based on attributes.
5614 //
5615 void
5617 throw (Exception)
5618 {
5619 
5620  std::string num_lat_name = "Number of Lines";
5621  std::string num_lon_name = "Number of Columns";
5622  int32 num_lat = 0;
5623  int32 num_lon = 0;
5624 
5625  File *file = this;
5626 
5627  int tempcountllflag = 0;
5628 
5629  for (std::vector < Attribute * >::const_iterator i =
5630  file->sd->getAttributes ().begin ();
5631  i != file->sd->getAttributes ().end (); ++i) {
5632 
5633  if ((*i)->getName () == num_lon_name) {
5634 
5635  // Check later if float can be changed to float32
5636  int *attrvalue = (int *) (&((*i)->getValue ()[0]));
5637 
5638  num_lon = *attrvalue;
5639  tempcountllflag++;
5640  }
5641 
5642  if ((*i)->getName () == num_lat_name) {
5643 
5644  int *attrvalue = (int *) (&((*i)->getValue ()[0]));
5645 
5646  num_lat = *attrvalue;
5647  tempcountllflag++;
5648  }
5649  if (tempcountllflag == 2)
5650  break;
5651  }
5652 
5653  // Longitude
5654  SDField *longitude = new SDField ();
5655  if(longitude == nullptr)
5656  throw1("Allocate memory for longitude failed .");
5657 
5658  longitude->name = "longitude";
5659  longitude->rank = 1;
5660  longitude->type = DFNT_FLOAT32;
5661  longitude->fieldtype = 2;
5662 
5663  // No need to assign fullpath, in this case, only one SDS under one file. If finding other OBPGL3 data, will handle then.
5664  longitude->newname = longitude->name;
5665  if (0 == num_lon) {
5666  delete longitude;
5667  throw3("The size of the dimension of the longitude ",longitude->name," is 0.");
5668  }
5669 
5670  Dimension *dim = new Dimension (num_lon_name, num_lon, 0);
5671  if(dim == nullptr) {
5672  delete longitude;
5673  throw1("Allocate memory for dim failed .");
5674  }
5675 
5676  //if(longitude != nullptr)
5678  longitude->dims.push_back (dim);
5679 
5680  dim = nullptr;
5681  // Add the corrected dimension name only to be consistent with general handling of other cases.
5682  dim = new Dimension (num_lon_name, num_lon, 0);
5683  if(dim == nullptr) {
5684  delete longitude;
5685  throw1("Allocate memory for dim failed .");
5686  }
5687  //if(longitude != nullptr)
5688  longitude->correcteddims.push_back (dim);
5689 
5690  // Latitude
5691  SDField *latitude = new SDField ();
5692  if(latitude == nullptr) {
5693  delete latitude;
5694  throw1("Allocate memory for dim failed .");
5695  }
5696  latitude->name = "latitude";
5697  latitude->rank = 1;
5698  latitude->type = DFNT_FLOAT32;
5699  latitude->fieldtype = 1;
5700 
5701  // No need to assign fullpath, in this case, only one SDS under one file. If finding other OBPGL3 data, will handle then.
5702  latitude->newname = latitude->name;
5703  if (0 == num_lat) {
5704  delete longitude;
5705  delete latitude;
5706  throw3("The size of the dimension of the latitude ",latitude->name," is 0.");
5707  }
5708 
5709  dim = nullptr;
5710  dim = new Dimension (num_lat_name, num_lat, 0);
5711  if( dim == nullptr) {
5712  delete longitude;
5713  delete latitude;
5714  throw1("Allocate memory for dim failed .");
5715  }
5716 
5717  if(latitude != nullptr)
5718  latitude->dims.push_back (dim);
5719 
5720  dim = nullptr;
5721  // Add the corrected dimension name only to be consistent with general handling of other cases.
5722  dim = new Dimension (num_lat_name, num_lat, 0);
5723  if(dim == nullptr) {
5724  delete longitude;
5725  delete latitude;
5726  throw1("Allocate memory for dim failed .");
5727  }
5728  //if(latitude != nullptr)
5729  latitude->correcteddims.push_back (dim);
5730 
5731  // The dimension names of the SDS are fakeDim, so need to change them to dimension names of latitude and longitude
5732  for (std::vector < SDField * >::const_iterator i =
5733  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
5734  if ((*i)->getRank () != 2) {
5735  //if(latitude !=nullptr)
5736  delete latitude;
5737  //if(longitude !=nullptr)
5738  delete longitude;
5739  throw3 ("The lat/lon rank must be 2", (*i)->getName (),
5740  (*i)->getRank ());
5741  }
5742  for (std::vector < Dimension * >::const_iterator k =
5743  (*i)->getDimensions ().begin ();
5744  k != (*i)->getDimensions ().end (); ++k) {
5745  if ((((*k)->getName ()).find ("fakeDim")) != std::string::npos) {
5746  if ((*k)->getSize () == num_lon)
5747  (*k)->name = num_lon_name;
5748  if ((*k)->getSize () == num_lat)
5749  (*k)->name = num_lat_name;
5750  }
5751  }
5752  for (std::vector < Dimension * >::const_iterator k =
5753  (*i)->getCorrectedDimensions ().begin ();
5754  k != (*i)->getCorrectedDimensions ().end (); ++k) {
5755  if ((((*k)->getName ()).find ("fakeDim")) != std::string::npos) {
5756  if ((*k)->getSize () == num_lon)
5757  (*k)->name = num_lon_name;
5758  if ((*k)->getSize () == num_lat)
5759  (*k)->name = num_lat_name;
5760  }
5761  }
5762  }
5763  file->sd->sdfields.push_back (latitude);
5764  file->sd->sdfields.push_back (longitude);
5765 
5766  // Set dimname,coordinate variable list
5767  file->sd->nonmisscvdimnamelist.insert (num_lat_name);
5768  file->sd->nonmisscvdimnamelist.insert (num_lon_name);
5769 
5770 }
5771 
5772 // This applies to CERES AVG and SYN(CER_AVG_??? and CER_SYN_??? cases)
5773 // Latitude and longitude are provided; some redundant CO-Latitude and longitude are removed from the final DDS.
5774 void
5776 throw (Exception)
5777 {
5778 
5779  bool colatflag = false;
5780  bool lonflag = false;
5781 
5782  std::string tempnewdimname1;
5783  std::string tempnewdimname2;
5784  std::string tempcvarname1;
5785  std::string tempcvarname2;
5786  File *file = this;
5787  // int eraseflag = 0; Unused jhrg 3/16/11
5788 
5789  std::vector < SDField * >::iterator beerasedit;
5790 
5791  // SDField *beerased; Unused jhrg 3/16/11
5792 
5793  for (std::vector < SDField * >::iterator i = file->sd->sdfields.begin ();
5794  i != file->sd->sdfields.end (); ) {
5795 
5796  // This product uses "Colatitude".
5797  if (((*i)->getName ()).find ("Colatitude") != std::string::npos) {
5798  if (!colatflag) {
5799  if ((*i)->getRank () != 2)
5800  throw3 ("The lat/lon rank must be 2", (*i)->getName (),
5801  (*i)->getRank ());
5802  int dimsize0 = (*i)->getDimensions ()[0]->getSize ();
5803  int dimsize1 = (*i)->getDimensions ()[1]->getSize ();
5804 
5805  // The following comparision may not be necessary.
5806  // For most cases, the C-order first dimension is cooresponding to lat(in 1-D),
5807  // which is mostly smaller than the dimension of lon(in 2-D). E.g. 90 for lat vs 180 for lon.
5808  if (dimsize0 < dimsize1) {
5809  tempnewdimname1 = (*i)->getDimensions ()[0]->getName ();
5810  tempnewdimname2 = (*i)->getDimensions ()[1]->getName ();
5811  }
5812  else {
5813  tempnewdimname1 = (*i)->getDimensions ()[1]->getName ();
5814  tempnewdimname2 = (*i)->getDimensions ()[0]->getName ();
5815 
5816  }
5817 
5818  colatflag = true;
5819  (*i)->fieldtype = 1;
5820  tempcvarname1 = (*i)->getName ();
5821 
5822  ++i;
5823  }
5824  else {//remove the redundant Colatitude field
5825  delete (*i);
5826  i = file->sd->sdfields.erase (i);
5827  // When erasing the iterator, the iterator will
5828  // automatically go to the next element,
5829  // so we need to go back 1 in order not to miss the next element.
5830  //i--;
5831  }
5832  }
5833 
5834  else if (((*i)->getName ()).find ("Longitude") != std::string::npos) {
5835  if (!lonflag) {
5836  lonflag = true;
5837  (*i)->fieldtype = 2;
5838  tempcvarname2 = (*i)->getName ();
5839  ++i;
5840  }
5841  else {//remove the redundant Longitude field
5842  delete (*i);
5843  i = file->sd->sdfields.erase (i);
5844  // When erasing the iterator, the iterator will
5845  // automatically go to the next element, so we need to go back 1
5846  // in order not to miss the next element.
5847  //i--;
5848  }
5849  }
5850  else {
5851  ++i;
5852  }
5853  }//end for (vector ....)
5854 
5855  file->sd->nonmisscvdimnamelist.insert (tempnewdimname1);
5856  file->sd->nonmisscvdimnamelist.insert (tempnewdimname2);
5857 
5858 }
5859 
5860 // Handle CERES ES4 and ISCCP-GEO cases. Essentially the lat/lon need to be condensed to 1-D for the geographic projection.
5861 void
5863 throw (Exception)
5864 {
5865 
5866  std::string tempdimname1;
5867  std::string tempdimname2;
5868  int tempdimsize1 = 0;
5869  int tempdimsize2 = 0;
5870  std::string tempcvarname1;
5871  std::string tempcvarname2;
5872  std::string temppath;
5873  std::set < std::string > tempdimnameset;
5874  std::pair < std::set < std::string >::iterator, bool > tempsetit;
5875 
5876  // bool eraseflag = false; Unused jhrg 3/16/11
5877  bool cvflag = false;
5878  File *file = this;
5879 
5880  // The original latitude is 3-D array; we have to use the dimension name to determine which dimension is the final dimension
5881  // for 1-D array. "regional colat" and "regional lon" are consistently used in these two CERES cases.
5882  for (std::vector < SDField * >::iterator i = file->sd->sdfields.begin ();
5883  i != file->sd->sdfields.end (); ) {
5884  std::string tempfieldname = (*i)->getName ();
5885  if (tempfieldname.find ("Colatitude") != std::string::npos) {
5886  // They may have more than 2 dimensions, so we have to adjust it.
5887  for (std::vector < Dimension * >::const_iterator j =
5888  (*i)->getDimensions ().begin ();
5889  j != (*i)->getDimensions ().end (); ++j) {
5890  if (((*j)->getName ()).find ("regional colat") !=
5891  std::string::npos) {
5892  tempsetit = tempdimnameset.insert ((*j)->getName ());
5893  if (tempsetit.second == true) {
5894  tempdimname1 = (*j)->getName ();
5895  tempdimsize1 = (*j)->getSize ();
5896  (*i)->fieldtype = 1;
5897  (*i)->rank = 1;
5898  cvflag = true;
5899  break;
5900  }
5901  }
5902  }
5903 
5904  if (cvflag) {// change the dimension from 3-D to 1-D.
5905  // Clean up the original dimension vector first
5906  for (std::vector < Dimension * >::const_iterator j =
5907  (*i)->getDimensions ().begin ();
5908  j != (*i)->getDimensions ().end (); ++j)
5909  delete (*j);
5910  for (std::vector < Dimension * >::const_iterator j =
5911  (*i)->getCorrectedDimensions ().begin ();
5912  j != (*i)->getCorrectedDimensions ().end (); ++j)
5913  delete (*j);
5914  (*i)->dims.clear ();
5915  (*i)->correcteddims.clear ();
5916 
5917  Dimension *dim =
5918  new Dimension (tempdimname1, tempdimsize1, 0);
5919  (*i)->dims.push_back (dim);
5920  dim = new Dimension (tempdimname1, tempdimsize1, 0);
5921  (*i)->correcteddims.push_back (dim);
5922  file->sd->nonmisscvdimnamelist.insert (tempdimname1);
5923  cvflag = false;
5924  ++i;
5925  }
5926  else {//delete this element from the vector and erase it.
5927  delete (*i);
5928  i = file->sd->sdfields.erase (i);
5929 
5930  // When erasing the iterator, the iterator will automatically
5931  // go to the next element, so we need to go back 1 in order not
5932  // to miss the next element.
5933  //i--;
5934  }
5935  }
5936 
5937  else if (tempfieldname.find ("Longitude") != std::string::npos) {
5938  for (std::vector < Dimension * >::const_iterator j =
5939  (*i)->getDimensions ().begin ();
5940  j != (*i)->getDimensions ().end (); ++j) {
5941  if (((*j)->getName ()).find ("regional long") !=
5942  std::string::npos) {
5943  tempsetit = tempdimnameset.insert ((*j)->getName ());
5944  if (tempsetit.second == true) {
5945  tempdimname2 = (*j)->getName ();
5946  tempdimsize2 = (*j)->getSize ();
5947  (*i)->fieldtype = 2;
5948  (*i)->rank = 1;
5949  cvflag = true;
5950  break;
5951  }
5952  // Make this the only dimension name of this field
5953  }
5954  }
5955  if (cvflag) {
5956  for (std::vector < Dimension * >::const_iterator j =
5957  (*i)->getDimensions ().begin ();
5958  j != (*i)->getDimensions ().end (); ++j) {
5959  delete (*j);
5960  }
5961  for (std::vector < Dimension * >::const_iterator j =
5962  (*i)->getCorrectedDimensions ().begin ();
5963  j != (*i)->getCorrectedDimensions ().end (); ++j) {
5964  delete (*j);
5965  }
5966  (*i)->dims.clear ();
5967  (*i)->correcteddims.clear ();
5968 
5969  Dimension *dim =
5970  new Dimension (tempdimname2, tempdimsize2, 0);
5971  (*i)->dims.push_back (dim);
5972  dim = new Dimension (tempdimname2, tempdimsize2, 0);
5973  (*i)->correcteddims.push_back (dim);
5974 
5975  file->sd->nonmisscvdimnamelist.insert (tempdimname2);
5976  cvflag = false;
5977  ++i;
5978  }
5979  else{//delete this element from the vector and erase it.
5980  delete (*i);
5981  i = file->sd->sdfields.erase (i);
5982  // When erasing the iterator, the iterator
5983  // will automatically go to the next element,
5984  // so we need to go back 1 in order not to miss the next element.
5985  //i--;
5986  }
5987  }
5988  else {
5989  ++i;
5990  }
5991  }// end for(vector ....)
5992 }
5993 
5994 
5995 // CERES SAVG and CERES ISCCP-IDAY cases.
5996 // We need provide nested CERES grid 2-D lat/lon.
5997 // The lat and lon should be calculated following:
5998 // http://eosweb.larc.nasa.gov/PRODOCS/ceres/SRBAVG/Quality_Summaries/srbavg_ed2d/nestedgrid.html
5999 // or https://eosweb.larc.nasa.gov/sites/default/files/project/ceres/quality_summaries/srbavg_ed2d/nestedgrid.pdf
6000 // The dimension names and sizes are set according to the studies of these files.
6001 void
6003 throw (Exception)
6004 {
6005 
6006  // bool colatflag = false; unused jhrg 3/16/11
6007  // bool lonflag = false; Unused jhrg 3/16/11
6008 
6009  std::string tempdimname1 = "1.0 deg. regional colat. zones";
6010  std::string tempdimname2 = "1.0 deg. regional long. zones";
6011  std::string tempdimname3 = "1.0 deg. zonal colat. zones";
6012  std::string tempdimname4 = "1.0 deg. zonal long. zones";
6013  int tempdimsize1 = 180;
6014  int tempdimsize2 = 360;
6015  int tempdimsize3 = 180;
6016  int tempdimsize4 = 1;
6017 
6018  std::string tempnewdimname1;
6019  std::string tempnewdimname2;
6020  std::string tempcvarname1;
6021  std::string tempcvarname2;
6022  File *file;
6023 
6024  file = this;
6025 
6026  SDField *latitude = new SDField ();
6027 
6028  latitude->name = "latitude";
6029  latitude->rank = 2;
6030  latitude->type = DFNT_FLOAT32;
6031  latitude->fieldtype = 1;
6032 
6033  // No need to obtain the full path
6034  latitude->newname = latitude->name;
6035 
6036  Dimension *dim = new Dimension (tempdimname1, tempdimsize1, 0);
6037 
6038  latitude->dims.push_back (dim);
6039 
6040  dim = new Dimension (tempdimname2, tempdimsize2, 0);
6041  latitude->dims.push_back (dim);
6042 
6043  dim = new Dimension (tempdimname1, tempdimsize1, 0);
6044  latitude->correcteddims.push_back (dim);
6045 
6046  dim = new Dimension (tempdimname2, tempdimsize2, 0);
6047  latitude->correcteddims.push_back (dim);
6048  file->sd->sdfields.push_back (latitude);
6049 
6050  SDField *longitude = new SDField ();
6051 
6052  longitude->name = "longitude";
6053  longitude->rank = 2;
6054  longitude->type = DFNT_FLOAT32;
6055  longitude->fieldtype = 2;
6056 
6057  // No need to obtain the full path
6058  longitude->newname = longitude->name;
6059 
6060  dim = new Dimension (tempdimname1, tempdimsize1, 0);
6061  longitude->dims.push_back (dim);
6062 
6063  dim = new Dimension (tempdimname2, tempdimsize2, 0);
6064  longitude->dims.push_back (dim);
6065 
6066  dim = new Dimension (tempdimname1, tempdimsize1, 0);
6067  longitude->correcteddims.push_back (dim);
6068 
6069  dim = new Dimension (tempdimname2, tempdimsize2, 0);
6070  longitude->correcteddims.push_back (dim);
6071  file->sd->sdfields.push_back (longitude);
6072 
6073  // For the CER_SRB case, zonal average data is also included.
6074  // We need only provide the latitude.
6075  if (file->sptype == CER_SRB) {
6076 
6077  SDField *latitudez = new SDField ();
6078 
6079  latitudez->name = "latitudez";
6080  latitudez->rank = 1;
6081  latitudez->type = DFNT_FLOAT32;
6082  latitudez->fieldtype = 1;
6083  latitudez->newname = latitudez->name;
6084 
6085  dim = new Dimension (tempdimname3, tempdimsize3, 0);
6086  latitudez->dims.push_back (dim);
6087 
6088  dim = new Dimension (tempdimname3, tempdimsize3, 0);
6089  latitudez->correcteddims.push_back (dim);
6090  file->sd->sdfields.push_back (latitudez);
6091 
6092  SDField *longitudez = new SDField ();
6093  longitudez->name = "longitudez";
6094  longitudez->rank = 1;
6095  longitudez->type = DFNT_FLOAT32;
6096  longitudez->fieldtype = 2;
6097  longitudez->newname = longitudez->name;
6098 
6099  dim = new Dimension (tempdimname4, tempdimsize4, 0);
6100  longitudez->dims.push_back (dim);
6101 
6102  dim = new Dimension (tempdimname4, tempdimsize4, 0);
6103  longitudez->correcteddims.push_back (dim);
6104  file->sd->sdfields.push_back (longitudez);
6105  }
6106 
6107  if (file->sptype == CER_SRB) {
6108  file->sd->nonmisscvdimnamelist.insert (tempdimname3);
6109  file->sd->nonmisscvdimnamelist.insert (tempdimname4);
6110  }
6111 
6112  file->sd->nonmisscvdimnamelist.insert (tempdimname1);
6113  file->sd->nonmisscvdimnamelist.insert (tempdimname2);
6114 
6115  if(file->sptype == CER_CDAY) {
6116 
6117  string odddimname1= "1.0 deg. regional Colat. zones";
6118  string odddimname2 = "1.0 deg. regional Long. zones";
6119 
6120  // Add a loop to change the odddimnames to (normal)tempdimnames.
6121  for (std::vector < SDField * >::const_iterator i =
6122  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6123  for (std::vector < Dimension * >::const_iterator j =
6124  (*i)->getDimensions ().begin ();
6125  j != (*i)->getDimensions ().end (); ++j) {
6126  if (odddimname1 == (*j)->name)
6127  (*j)->name = tempdimname1;
6128  if (odddimname2 == (*j)->name)
6129  (*j)->name = tempdimname2;
6130  }
6131  for (std::vector < Dimension * >::const_iterator j =
6132  (*i)->getCorrectedDimensions ().begin ();
6133  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6134  if (odddimname1 == (*j)->name)
6135  (*j)->name = tempdimname1;
6136  if (odddimname2 == (*j)->name)
6137  (*j)->name = tempdimname2;
6138 
6139  }
6140  }
6141  }
6142 }
6143 
6144 // Prepare the CER_ZAVG case. This is the zonal average case.
6145 // Only latitude is needed.
6146 void
6148 throw (Exception)
6149 {
6150 
6151  std::string tempdimname3 = "1.0 deg. zonal colat. zones";
6152  std::string tempdimname4 = "1.0 deg. zonal long. zones";
6153  int tempdimsize3 = 180;
6154  int tempdimsize4 = 1;
6155  File *file = this;
6156 
6157  SDField *latitudez = new SDField ();
6158 
6159  latitudez->name = "latitudez";
6160  latitudez->rank = 1;
6161  latitudez->type = DFNT_FLOAT32;
6162  latitudez->fieldtype = 1;
6163  latitudez->newname = latitudez->name;
6164 
6165 
6166  Dimension *dim = new Dimension (tempdimname3, tempdimsize3, 0);
6167  latitudez->dims.push_back (dim);
6168 
6169  dim = new Dimension (tempdimname3, tempdimsize3, 0);
6170  latitudez->correcteddims.push_back (dim);
6171 
6172  file->sd->sdfields.push_back (latitudez);
6173  SDField *longitudez = new SDField ();
6174 
6175  longitudez->name = "longitudez";
6176  longitudez->rank = 1;
6177  longitudez->type = DFNT_FLOAT32;
6178  longitudez->fieldtype = 2;
6179  longitudez->newname = longitudez->name;
6180 
6181  dim = new Dimension (tempdimname4, tempdimsize4, 0);
6182  longitudez->dims.push_back (dim);
6183 
6184  dim = new Dimension (tempdimname4, tempdimsize4, 0);
6185  longitudez->correcteddims.push_back (dim);
6186 
6187  file->sd->sdfields.push_back (longitudez);
6188  file->sd->nonmisscvdimnamelist.insert (tempdimname3);
6189  file->sd->nonmisscvdimnamelist.insert (tempdimname4);
6190 
6191 }
6192 
6193 // Prepare the "Latitude" and "Longitude" for the MODISARNSS case.
6194 // This file has Latitude and Longitude. The only thing it needs
6195 // to change is to assure the dimension names of the field names the same
6196 // as the lat and lon.
6197 void
6199 throw (Exception)
6200 {
6201 
6202  std::set < std::string > tempfulldimnamelist;
6203  std::pair < std::set < std::string >::iterator, bool > ret;
6204 
6205  std::map < int, std::string > tempsizedimnamelist;
6206 
6207  File *file = this;
6208 
6209  for (std::vector < SDField * >::const_iterator i =
6210  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6211  if ((*i)->getName () == "Latitude")
6212  (*i)->fieldtype = 1;
6213  if ((*i)->getName () == "Longitude") {
6214  (*i)->fieldtype = 2;
6215 
6216  // Fields associate with lat/lon use different dimension names;
6217  // To be consistent with other code, use size-dim map to change
6218  // fields that have the same size as lat/lon to hold the same dimension names.
6219  for (std::vector < Dimension * >::const_iterator j =
6220  (*i)->getCorrectedDimensions ().begin ();
6221  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6222  tempsizedimnamelist[(*j)->getSize ()] = (*j)->getName ();
6223  file->sd->nonmisscvdimnamelist.insert ((*j)->getName ());
6224  }
6225  }
6226  }
6227 
6228  for (std::vector < SDField * >::const_iterator i =
6229  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6230  for (std::vector < Dimension * >::const_iterator j =
6231  (*i)->getCorrectedDimensions ().begin ();
6232  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6233 
6234  // Need to change those dimension names to be the same as lat/lon
6235  // so that a coordinate variable dimension name map can be built.
6236  if ((*i)->fieldtype == 0) {
6237  if ((tempsizedimnamelist.find ((*j)->getSize ())) !=
6238  tempsizedimnamelist.end ())
6239  (*j)->name = tempsizedimnamelist[(*j)->getSize ()];
6240  }
6241  }
6242  }
6243 }
6244 
6245 
6246 // For all other cases not listed above. What we did here is very limited.
6247 // We only consider the field to be a "third-dimension" coordinate variable
6248 // when dimensional scale is applied.
6249 void
6251 throw (Exception)
6252 {
6253 
6254  std::set < std::string > tempfulldimnamelist;
6255  std::pair < std::set < std::string >::iterator, bool > ret;
6256  File *file = this;
6257 
6258  // I need to trimm MERRA data field and dim. names according to NASA's request.
6259  // Currently the field name includes the full path(/EOSGRID/Data Fields/PLE);
6260  // the dimension name is something
6261  // like XDim::EOSGRID, which are from the original HDF-EOS2 files.
6262  // I need to trim them. Field name PLE, Dimension name: XDim.
6263  // KY 2012-7-2
6264 
6265  bool merra_is_eos2 = false;
6266  size_t found_forward_slash = file->path.find_last_of("/");
6267  if ((found_forward_slash != string::npos) &&
6268  (((file->path).substr(found_forward_slash+1).compare(0,5,"MERRA"))==0)){
6269 
6270  for (std::vector < Attribute * >::const_iterator i =
6271  file->sd->getAttributes ().begin ();
6272  i != file->sd->getAttributes ().end (); ++i) {
6273 
6274  // CHeck if this MERRA file is an HDF-EOS2 or not.
6275  if(((*i)->getName().compare(0, 14, "StructMetadata" )== 0) ||
6276  ((*i)->getName().compare(0, 14, "structmetadata" )== 0)) {
6277  merra_is_eos2 = true;
6278  break;
6279  }
6280 
6281  }
6282  }
6283 
6284  if( true == merra_is_eos2) {
6285  vector <string> noneos_newnamelist;
6286 
6287  // 1. Remove EOSGRID from the added-non-EOS field names(XDim:EOSGRID to XDim)
6288  for (std::vector < SDField * >::const_iterator i =
6289  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6290  (*i)->special_product_fullpath = (*i)->newname;
6291  // "EOSGRID" inside variable and dim. names needs to be trimmed out. KY 7-2-2012
6292  string EOSGRIDstring=":EOSGRID";
6293  size_t found = ((*i)->name).rfind(EOSGRIDstring);
6294 
6295  if (found !=string::npos && (((*i)->name).size() == (found + EOSGRIDstring.size()))) {
6296 
6297  (*i)->newname = (*i)->name.substr(0,found);
6298  noneos_newnamelist.push_back((*i)->newname);
6299  }
6300  else
6301  (*i)->newname = (*i)->name;
6302  }
6303 
6304  // 2. Make the redundant and clashing CVs such as XDim to XDim_EOS etc.
6305  // I don't want to remove these fields since a variable like Time is different than TIME
6306  // So still keep it in case it is useful for some users.
6307 
6308  for (std::vector < SDField * >::const_iterator i =
6309  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6310 
6311  for(vector<string>::const_iterator j =
6312  noneos_newnamelist.begin(); j !=noneos_newnamelist.end();++j) {
6313 
6314  if ((*i)->newname == (*j) && (*i)->name == (*j)) {
6315  // Make XDim to XDim_EOS so that we don't have two "XDim".
6316  (*i)->newname = (*i)->newname +"_EOS";
6317  }
6318  }
6319  }
6320 
6321  // 3. Handle Dimension scales
6322  // 3.1 Change the dimension names for coordinate variables.
6323  map<string,string> dimname_to_newdimname;
6324  for (std::vector < SDField * >::const_iterator i =
6325  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6326  for (std::vector < Dimension * >::const_iterator j =
6327  (*i)->getCorrectedDimensions ().begin ();
6328  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6329  // Find the dimension scale
6330  if ((*j)->getType () != 0) {
6331  if ((*i)->name == (*j)->getName () && (*i)->getRank () == 1){
6332  (*i)->fieldtype = 3;
6333  (*i)->is_dim_scale = true;
6334  (*j)->name = (*i)->newname;
6335  // Build up the map from the original name to the new name, Note (*i)->name is the original
6336  // dimension name.
6337  HDFCFUtil::insert_map(dimname_to_newdimname,(*i)->name,(*j)->name);
6338  }
6339  file->sd->nonmisscvdimnamelist.insert ((*j)->name);
6340  }
6341  }
6342  }
6343 
6344  // 3.2 Change the dimension names for data variables.
6345  map<string,string>::iterator itmap;
6346  for (std::vector < SDField * >::const_iterator i =
6347  file->sd->sdfields.begin (); i != file->sd->sdfields.end (); ++i) {
6348 
6349  if (0 == (*i)->fieldtype) {
6350  for (std::vector < Dimension * >::const_iterator j =
6351  (*i)->getCorrectedDimensions ().begin ();
6352  j != (*i)->getCorrectedDimensions ().end (); ++j) {
6353  itmap = dimname_to_newdimname.find((*j)->name);
6354  if (itmap == dimname_to_newdimname.end())
6355  throw2("Cannot find the corresponding new dim. name for dim. name ",(*j)->name);
6356  else
6357  (*j)->name = (*itmap).second;
6358 
6359  }
6360  }
6361  }
6362  }
6363  else {
6364 
6365  for (std::vector < SDField * >::const_iterator i =
6366  file->sd->sdfields.begin (); i != file->sd->sdfields.end () && (false == this->OTHERHDF_Has_Dim_NoScale_Field); ++i) {
6367  for (std::vector < Dimension * >::const_iterator j =
6368  (*i)->getCorrectedDimensions ().begin ();
6369  j != (*i)->getCorrectedDimensions ().end () && (false == this->OTHERHDF_Has_Dim_NoScale_Field); ++j) {
6370 
6371  if ((*j)->getType () != 0) {
6372  if ((*i)->name == (*j)->getName () && (*i)->getRank () == 1)
6373  (*i)->fieldtype = 3;
6374  file->sd->nonmisscvdimnamelist.insert ((*j)->getName ());
6375  }
6376  else {
6377  this->OTHERHDF_Has_Dim_NoScale_Field = true;
6378  }
6379  }
6380  }
6381 
6382  // For OTHERHDF cases, currently if we find that there are "no dimension scale" dimensions, we will NOT generate any "cooridnates" attributes.
6383  // That means "nonmisscvdimnamelist" should be cleared if OTHERHDF_Has_Dim_NoScale_Field is true.
6384 
6385  if (true == this->OTHERHDF_Has_Dim_NoScale_Field)
6386  file->sd->nonmisscvdimnamelist.clear();
6387  }
6388 }
#define throw1(a1)
The followings are convenient functions to throw exceptions with different.
Definition: HDF5CF.h:128
Representing one attribute in grid or swath.
Definition: HDFSP.h:173
const std::string & getName() const
Get the name of this field.
Definition: HDFSP.h:282
int32 rank
The rank of this field.
Definition: HDFSP.h:324
std::string newname
The CF full path(special characters replaced by underscores) of this field.
Definition: HDFSP.h:315
int32 type
The datatype of this field.
Definition: HDFSP.h:321
std::string name
The original name of this field.
Definition: HDFSP.h:318
static File * Read(const char *path, int32 sdid, int32 fileid)
Retrieve SDS and Vdata information from the HDF4 file.
Definition: HDFSP.cc:208
void handle_sds_final_dim_names()
Create the final CF-compliant dimension name list for each field.
Definition: HDFSP.cc:3720
void PrepareTRMML3M_V7()
Special method to prepare TRMM multiple grid Level 3 geolocation fields(latitude,longitude,...
Definition: HDFSP.cc:4785
void handle_sds_coords(bool &COARDFLAG, std::string &lldimname1, std::string &lldimname2)
Create "coordinates", "units" CF attributes.
Definition: HDFSP.cc:3953
void handle_vdata()
Handle Vdata.
Definition: HDFSP.cc:4037
void Prepare()
Definition: HDFSP.cc:4089
void PrepareMODISARNSS()
Definition: HDFSP.cc:6198
void handle_sds_missing_fields()
Add the missing coordinate variables based on the corrected dimension name list.
Definition: HDFSP.cc:3684
void PrepareTRMML3S_V7()
Special method to prepare TRMM single grid Level 3 geolocation fields(latitude,longitude,...
Definition: HDFSP.cc:4449
void CheckSDType()
This method will check if the HDF4 file is one of TRMM or OBPG products we supported.
Definition: HDFSP.cc:1283
void ReadVgattrs(int32 vgroup_id, const char *fullpath)
Obtain vgroup attributes.
Definition: HDFSP.cc:2654
void PrepareTRMML2_V7()
Latitude and longitude are stored in different fields. Need to separate.
Definition: HDFSP.cc:4299
void PrepareCERAVGSYN()
Definition: HDFSP.cc:5775
void Obtain_TRMML3S_V7_latlon_size(int &latsize, int &lonsize)
void Obtain_TRMML3S_V7_latlon_size(int &latsize, int&lonsize) throw(Exception);
Definition: HDFSP.cc:4249
void PrepareTRMML3C_V6()
Special method to prepare TRMM Level 3 CSH latitude,longitude and Height information.
Definition: HDFSP.cc:5372
static File * Read_Hybrid(const char *path, int32 sdid, int32 fileid)
Definition: HDFSP.cc:263
void handle_sds_fakedim_names()
Definition: HDFSP.cc:3592
void PrepareOBPGL3()
Special method to prepare OBPG Level 3 latitude and longitude information. The latitude and longitude...
Definition: HDFSP.cc:5616
void ReadHybridNonLoneVdatas(File *)
Definition: HDFSP.cc:564
void obtain_vdata_path(int32 file_id, char *full_path, int32 pobj_ref)
The internal function used to obtain the path for hybrid non-lone vdata.
Definition: HDFSP.cc:3372
void handle_sds_names(bool &COARDFLAG, std::string &lldimname1, std::string &lldimname2)
Create the final CF-compliant field name list.
Definition: HDFSP.cc:3768
void PrepareCERES4IG()
Definition: HDFSP.cc:5862
void PrepareOTHERHDF()
We still provide a hook for other HDF data product although no CF compliant is followed.
Definition: HDFSP.cc:6250
void ReadLoneVdatas(File *)
Handle non-attribute lone vdatas.
Definition: HDFSP.cc:329
void PrepareTRMML3A_V6()
Special method to prepare TRMM Level 3A46 latitude and longitude information.
Definition: HDFSP.cc:5202
void PrepareTRMML3B_V6()
Special method to prepare TRMM Level 3B latitude and longitude information.
Definition: HDFSP.cc:5094
void InsertOrigFieldPath_ReadVgVdata()
The full path of SDS and Vdata will be obtained.
Definition: HDFSP.cc:2708
void PrepareCERSAVGID()
Definition: HDFSP.cc:6002
void PrepareOBPGL2()
Special method to prepare OBPG Level 2 latitude and longitude information. The latitude and longitude...
Definition: HDFSP.cc:5531
void create_sds_dim_name_list()
Create the new dimension name set and the dimension name to size map.
Definition: HDFSP.cc:3664
void obtain_path(int32 file_id, int32 sd_id, char *full_path, int32 pobj_ref)
The internal function used by InsertOrigFieldPath_ReadVgVdata.
Definition: HDFSP.cc:3033
void PrepareCERZAVG()
Special method to prepare CERES Zonal Average latitude and longitude information.
Definition: HDFSP.cc:6147
void PrepareTRMML2_V6()
Latitude and longitude are stored in one array(geolocation). Need to separate.
Definition: HDFSP.cc:4937
const std::string & getPath() const
Obtain the path of the file.
Definition: HDFSP.h:757
One instance of this class represents one SDS object.
Definition: HDFSP.h:337
This class retrieves all SDS objects and SD file attributes.
Definition: HDFSP.h:542
~SD()
Destructor.
Definition: HDFSP.cc:161
const std::vector< Attribute * > & getAttributes() const
Public interface to obtain the SD(file) attributes.
Definition: HDFSP.h:567
static SD * Read_Hybrid(int32 sdfileid, int32 hfileid)
Read the information of all hybrid SDS objects from the HDF4 file.
Definition: HDFSP.cc:1921
static SD * Read(int32 sdfileid, int32 hfileid)
Read the information of all SDS objects from the HDF4 file.
Definition: HDFSP.cc:1575
void obtain_noneos2_sds_path(int32, char *, int32)
Obtain SDS path, this is like a clone of obtain_path in File class, except the Vdata and some minor p...
Definition: HDFSP.cc:3265
This class retrieves all information of one Vdata.
Definition: HDFSP.h:631
bool getTreatAsAttrFlag() const
Definition: HDFSP.h:669
const std::vector< VDField * > & getFields() const
Obtain Vdata fields.
Definition: HDFSP.h:655
void ReadAttributes(int32 vdata_id)
Retrieve all attributes of this Vdata.
Definition: HDFSP.cc:2528
static VDATA * Read(int32 vdata_id, int32 obj_ref)
Retrieve all information of this Vdata.
Definition: HDFSP.cc:2346
One instance of this class represents one Vdata field.
Definition: HDFSP.h:490
void ReadAttributes(int32 vdata_id, int32 fieldindex)
Read vdata field attributes.
Definition: HDFSP.cc:2590
Definition: HDFSP.h:86
static bool insert_map(std::map< std::string, std::string > &m, std::string key, std::string val)
Definition: HDFCFUtil.cc:150
static void Handle_NameClashing(std::vector< std::string > &newobjnamelist)
General routines to handle name clashings.
Definition: HDFCFUtil.cc:260
static std::string get_CF_string(std::string s)
Change special characters to "_".
Definition: HDFCFUtil.cc:166