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