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