bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
HDF5CF.cc
Go to the documentation of this file.
1// This file is part of the hdf5_handler implementing for the CF-compliant
2// Copyright (c) 2011-2023 The HDF Group, Inc. and OPeNDAP, Inc.
3//
4// This is free software; you can redistribute it and/or modify it under the
5// terms of the GNU Lesser General Public License as published by the Free
6// Software Foundation; either version 2.1 of the License, or (at your
7// option) any later version.
8//
9// This software is distributed in the hope that it will be useful, but
10// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
12// License for more details.
13//
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17//
18// You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
19// You can contact The HDF Group, Inc. at 410 E University Ave,
20// Suite 200, Champaign, IL 61820
21
36
37#include <memory>
38#include <sstream>
39#include <algorithm>
40#include <climits>
41#include "HDF5CF.h"
42#include "h5cfdaputil.h"
43#include "HDF5RequestHandler.h"
44#include "h5apicompatible.h"
45#include "BESDebug.h"
46
47using namespace HDF5CF;
48
49Var::Var(const Var *var)
50{
51
52 newname = var->newname;
53 name = var->name;
54 fullpath = var->fullpath;
55 rank = var->rank;
56 total_elems = var->total_elems;
57 zero_storage_size = var->zero_storage_size;
58 dtype = var->dtype;
59 comp_ratio = var->comp_ratio;
60 unsupported_attr_dtype = var->unsupported_attr_dtype;
61 unsupported_attr_dspace = var->unsupported_attr_dspace;
62 unsupported_dspace = var->unsupported_dspace;
63 unsupported_attr_dspace = var->unsupported_attr_dspace;
64 dimnameflag = var->dimnameflag;
65 coord_attr_add_path = var->coord_attr_add_path;
66
67 for (const auto &vattr:var->attrs) {
68 auto attr_unique = make_unique<Attribute>();
69 auto attr = attr_unique.release();
70 attr->name = vattr->name;
71 attr->newname = vattr->newname;
72 attr->dtype = vattr->dtype;
73 attr->count = vattr->count;
74 attr->strsize = vattr->strsize;
75 attr->fstrsize = vattr->fstrsize;
76 attr->value = vattr->value;
77 attrs.push_back(attr);
78 }
79
80 for (const auto &vdim:var->dims) {
81 auto dim_unique = make_unique<Dimension>(vdim->size);
82 auto dim = dim_unique.release();
83 dim->name = vdim->name;
84 dim->newname = vdim->newname;
85 dim->unlimited_dim = vdim->unlimited_dim;
86 dims.push_back(dim);
87 }
88
89}
90
91bool CVar::isLatLon() const
92{
93
94 bool ret_value = false;
95 if (CV_EXIST == this->cvartype || CV_MODIFY == this->cvartype || CV_SPECIAL == this->cvartype) {
96 string attr_name = "units";
97 string lat_unit_value = "degrees_north";
98 string lon_unit_value = "degrees_east";
99
100 for (const auto &attr:this->attrs) {
101
102 if ((H5FSTRING == attr->getType()) || (H5VSTRING == attr->getType())) {
103 if (attr_name == attr->newname) {
104 string attr_value1(attr->getValue().begin(), attr->getValue().end());
105
106 if (attr->getCount() == 1) {
107 string attr_value(attr->getValue().begin(), attr->getValue().end());
108 if (attr_value.compare(0, lat_unit_value.size(), lat_unit_value) == 0) {
109 if (attr_value.size() == lat_unit_value.size()) {
110 ret_value = true;
111 break;
112 }
113 else if (attr_value.size() == (lat_unit_value.size() + 1)) {
114 if (attr_value[attr_value.size() - 1] == '\0'
115 || attr_value[attr_value.size() - 1] == ' ') {
116 ret_value = true;
117 break;
118 }
119 }
120 }
121 else if (attr_value.compare(0, lon_unit_value.size(), lon_unit_value) == 0) {
122 if (attr_value.size() == lon_unit_value.size()) {
123 ret_value = true;
124 break;
125 }
126 else if (attr_value.size() == (lon_unit_value.size() + 1)) {
127 if (attr_value[attr_value.size() - 1] == '\0'
128 || attr_value[attr_value.size() - 1] == ' ') {
129 ret_value = true;
130 break;
131 }
132 }
133
134 }
135
136 }
137 }
138 }
139 }
140 }
141 else if (this->cvartype == CV_LAT_MISS || this->cvartype == CV_LON_MISS) ret_value = true;
142 return ret_value;
143
144}
145File::~File()
146{
147
148 if (this->fileid >= 0) {
149 if (this->rootid >= 0) {
150 for_each(this->groups.begin(), this->groups.end(), delete_elem());
151 for_each(this->vars.begin(), this->vars.end(), delete_elem());
152 for_each(this->root_attrs.begin(), this->root_attrs.end(), delete_elem());
153 H5Gclose(rootid);
154 }
155 }
156}
157
158Group::~Group()
159{
160 for_each(this->attrs.begin(), this->attrs.end(), delete_elem());
161}
162
163Var::~Var()
164{
165 for_each(this->dims.begin(), this->dims.end(), delete_elem());
166 for_each(this->attrs.begin(), this->attrs.end(), delete_elem());
167}
168
169
170void File::Retrieve_H5_Info(const char * /*path*/, hid_t file_id, bool include_attr)
171{
172
173 BESDEBUG("h5", "coming to Retrieve_H5_Info" <<endl);
174
175 if (true == include_attr) {
176
177 // Obtain the BES key to check the ignored objects
178 // We will only use DAS to output these information.
179 this->check_ignored = HDF5RequestHandler::get_check_ignore_obj();
180 if (true == this->check_ignored) this->add_ignored_info_page_header();
181
182 }
183
184 hid_t root_id;
185 if ((root_id = H5Gopen(file_id, "/", H5P_DEFAULT)) < 0) {
186 throw1("Cannot open the HDF5 root group ");
187 }
188 this->rootid = root_id;
189 try {
190 this->Retrieve_H5_Obj(root_id, "/", include_attr);
191 }
192 catch (...) {
193 throw;
194 }
195
196 // Obtain attributes only necessary
197 if (true == include_attr) {
198
199 // Find the file(root group) attribute
200
201 // Obtain the object type, such as group or dataset.
202 H5O_info_t oinfo;
203 int num_attrs = 0;
204
205 if (H5OGET_INFO(root_id, &oinfo) < 0)
206 throw1("Error obtaining the info for the root group");
207
208 num_attrs = (int)(oinfo.num_attrs);
209 bool temp_unsup_attr_atype = false;
210 bool temp_unsup_attr_dspace = false;
211
212 for (int j = 0; j < num_attrs; j++) {
213 auto attr_unique = make_unique<Attribute>();
214 auto attr = attr_unique.release();
215 try {
216 this->Retrieve_H5_Attr_Info(attr, root_id, j, temp_unsup_attr_atype, temp_unsup_attr_dspace);
217 }
218 catch (...) {
219 delete attr;
220 throw;
221
222 }
223 this->root_attrs.push_back(attr);
224 }
225
226 this->unsupported_attr_dtype = temp_unsup_attr_atype;
227 this->unsupported_attr_dspace = temp_unsup_attr_dspace;
228 }
229}
230
231void File::Retrieve_H5_Obj(hid_t grp_id, const char*gname, bool include_attr)
232{
233
234 // Iterate through the file to see the members of the group from the root.
235 H5G_info_t g_info;
236 hsize_t nelems = 0;
237
238 if (H5Gget_info(grp_id, &g_info) < 0)
239 throw2("Counting hdf5 group elements error for ", gname);
240 nelems = g_info.nlinks;
241
242 ssize_t oname_size = 0;
243 for (hsize_t i = 0; i < nelems; i++) {
244
245 hid_t cgroup = -1;
246 hid_t cdset = -1;
247 Group *group = nullptr;
248 Var *var = nullptr;
249 Attribute *attr = nullptr;
250
251 try {
252
253 size_t dummy_name_len = 1;
254
255 // Query the length of object name.
256 oname_size = H5Lget_name_by_idx(grp_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE, i, nullptr, dummy_name_len,
257 H5P_DEFAULT);
258 if (oname_size <= 0)
259 throw2("Error getting the size of the hdf5 object from the group: ", gname);
260
261 // Obtain the name of the object
262 vector<char> oname;
263 oname.resize((size_t) oname_size + 1);
264
265 if (H5Lget_name_by_idx(grp_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE, i, oname.data(), (size_t) (oname_size + 1),
266 H5P_DEFAULT) < 0)
267 throw2("Error getting the hdf5 object name from the group: ", gname);
268
269 // Check if it is a hard link or a soft link
270 H5L_info_t linfo;
271 if (H5Lget_info(grp_id, oname.data(), &linfo, H5P_DEFAULT) < 0)
272 throw2("HDF5 link name error from ", gname);
273
274 // We ignore soft links and external links for the CF options
275 if (H5L_TYPE_SOFT == linfo.type || H5L_TYPE_EXTERNAL == linfo.type) {
276 if (true == include_attr && true == check_ignored) {
277 this->add_ignored_info_links_header();
278 string full_path_name;
279 string temp_oname(oname.begin(), oname.end());
280 full_path_name = (
281 (string(gname) != "/") ?
282 (string(gname) + "/" + temp_oname.substr(0, temp_oname.size() - 1)) :
283 ("/" + temp_oname.substr(0, temp_oname.size() - 1)));
284 this->add_ignored_info_links(full_path_name);
285
286 }
287 continue;
288 }
289
290 // Obtain the object type, such as group or dataset.
291 H5O_info_t oinfo;
292
293 if (H5OGET_INFO_BY_IDX(grp_id, ".", H5_INDEX_NAME, H5_ITER_NATIVE, i, &oinfo, H5P_DEFAULT) < 0)
294 throw2("Error obtaining the info for the object ", string(oname.begin(), oname.end()));
295
296 H5O_type_t obj_type = oinfo.type;
297
298 switch (obj_type) {
299
300 case H5O_TYPE_GROUP: {
301
302 // Obtain the full path name
303 string full_path_name;
304 string temp_oname(oname.begin(), oname.end());
305
306 full_path_name = (
307 (string(gname) != "/") ?
308 (string(gname) + "/" + temp_oname.substr(0, temp_oname.size() - 1)) :
309 ("/" + temp_oname.substr(0, temp_oname.size() - 1)));
310
311 cgroup = H5Gopen(grp_id, full_path_name.c_str(), H5P_DEFAULT);
312 if (cgroup < 0)
313 throw2("Error opening the group ", full_path_name);
314
315 auto group_unique = make_unique<Group>();
316 group = group_unique.release();
317 group->path = full_path_name;
318 group->newname = full_path_name;
319
320 // Retrieve group attribute if the attribute flag is true
321 if (true == include_attr) {
322
323 auto num_attrs = (int)(oinfo.num_attrs);
324 bool temp_unsup_attr_dtype = false;
325 bool temp_unsup_attr_dspace = false;
326
327 for (int j = 0; j < num_attrs; j++) {
328
329 auto attr_unique = make_unique<Attribute>();
330 attr = attr_unique.release();
331 Retrieve_H5_Attr_Info(attr, cgroup, j, temp_unsup_attr_dtype, temp_unsup_attr_dspace);
332 group->attrs.push_back(attr);
333 attr = nullptr;
334 }
335
336 group->unsupported_attr_dtype = temp_unsup_attr_dtype;
337 group->unsupported_attr_dspace = temp_unsup_attr_dspace;
338 }
339 this->groups.push_back(group);
340 Retrieve_H5_Obj(cgroup, full_path_name.c_str(), include_attr);
341 if (H5Gclose(cgroup) < 0)
342 throw2("Error closing the group ", full_path_name);
343 }
344 break;
345 case H5O_TYPE_DATASET: {
346
347 // Obtain the absolute path of the HDF5 dataset
348 string temp_oname(oname.begin(), oname.end());
349 string full_path_name = (
350 (string(gname) != "/") ?
351 (string(gname) + "/" + temp_oname.substr(0, temp_oname.size() - 1)) :
352 ("/" + temp_oname.substr(0, temp_oname.size() - 1)));
353
354 auto var_unique = make_unique<Var>();
355 var = var_unique.release();
356 var->name = temp_oname.substr(0, temp_oname.size() - 1);
357 var->fullpath = full_path_name;
358
359 // newname is for the final CF name
360 var->newname = full_path_name;
361
362 cdset = H5Dopen(grp_id, full_path_name.c_str(), H5P_DEFAULT);
363 if (cdset < 0)
364 throw2("Error opening the HDF5 dataset ", full_path_name);
365
366 // Retrieve the HDF5 dataset datatype, return the flag for unsupported types.
367 bool temp_unsup_var_dtype = false;
368 Retrieve_H5_VarType(var, cdset, full_path_name, temp_unsup_var_dtype);
369
370 // Update the unsupported datatype flag
371 if (!this->unsupported_var_dtype && temp_unsup_var_dtype) this->unsupported_var_dtype = true;
372
373 // Retrieve the HDF5 dataset data space, return the flag for unsupported dataspaces.
374 bool temp_unsup_var_dspace = false;
375 Retrieve_H5_VarDim(var, cdset, full_path_name, temp_unsup_var_dspace);
376
377 // Update the unsupported data space flag
378 if (!this->unsupported_var_dspace && temp_unsup_var_dspace) this->unsupported_var_dspace = true;
379
380 hsize_t d_storage_size = H5Dget_storage_size(cdset);
381 var->zero_storage_size =(d_storage_size ==0);
382 var->comp_ratio = Retrieve_H5_VarCompRatio(var, cdset);
383
384 // Retrieve the attribute info. if asked
385 if (true == include_attr) {
386
387 auto num_attrs = (int)(oinfo.num_attrs);
388 bool temp_unsup_attr_dtype = false;
389 bool temp_unsup_attr_dspace = false;
390
391 for (int j = 0; j < num_attrs; j++) {
392
393 auto attr_unique = make_unique<Attribute>();
394 attr = attr_unique.release();
395
396 Retrieve_H5_Attr_Info(attr, cdset, j, temp_unsup_attr_dtype, temp_unsup_attr_dspace);
397 var->attrs.push_back(attr);
398 attr = nullptr;
399 }
400
401 var->unsupported_attr_dtype = temp_unsup_attr_dtype;
402 var->unsupported_attr_dspace = temp_unsup_attr_dspace;
403
404 if (!this->unsupported_var_attr_dspace && temp_unsup_attr_dspace)
405 this->unsupported_var_attr_dspace = true;
406 }
407
408 this->vars.push_back(var);
409 if (H5Dclose(cdset) < 0)
410 throw2("Error closing the HDF5 dataset ", full_path_name);
411 }
412 break;
413
414 case H5O_TYPE_NAMED_DATATYPE: {
415 // ignore the named datatype
416 if (true == include_attr && true == check_ignored) {
417 this->add_ignored_info_namedtypes(string(gname), string(oname.begin(), oname.end()));
418 }
419 }
420 break;
421 default:
422 break;
423 } // "switch (obj_type)"
424 } // try
425 catch (...) {
426
427 if (attr != nullptr) {
428 delete attr;
429 attr = nullptr;
430 }
431
432 if (var != nullptr) {
433 delete var;
434 var = nullptr;
435 }
436
437 if (group != nullptr) {
438 delete group;
439 group = nullptr;
440 }
441
442 if (cgroup != -1) H5Gclose(cgroup);
443
444 if (cdset != -1) H5Dclose(cdset);
445 throw;
446
447 } // catch
448 } // "for (hsize_t i = 0; i < nelems; i++)"
449
450}
451
452// Retrieve HDF5 dataset compression ratio
453float File::Retrieve_H5_VarCompRatio(const Var *var, const hid_t dset_id) const
454{
455
456 float comp_ratio = 1.0;
457 // Obtain the data type of the variable.
458 hid_t dset_create_plist = H5Dget_create_plist(dset_id);
459 if (dset_create_plist < 0)
460 throw1("unable to obtain hdf5 dataset creation property list ");
461 H5D_layout_t dset_layout = H5Pget_layout(dset_create_plist);
462 if (dset_layout < 0) {
463 H5Pclose(dset_create_plist);
464 throw1("unable to obtain hdf5 dataset creation property list storage layout");
465 }
466
467 if (dset_layout == H5D_CHUNKED) {
468
469 hsize_t dstorage_size = H5Dget_storage_size(dset_id);
470 if (dstorage_size > 0 && var->total_elems > 0) {
471 hid_t ty_id = -1;
472
473 // Obtain the data type of the variable.
474 if ((ty_id = H5Dget_type(dset_id)) < 0)
475 throw1("unable to obtain hdf5 datatype for the dataset ");
476 size_t type_size = H5Tget_size(ty_id);
477 comp_ratio = ((float)((var->total_elems) * type_size))/(float)dstorage_size;
478 H5Tclose(ty_id);
479 }
480
481 }
482 H5Pclose(dset_create_plist);
483 return comp_ratio;
484
485}
486// Retrieve HDF5 dataset datatype
487void File::Retrieve_H5_VarType(Var *var, hid_t dset_id, const string & varname, bool &unsup_var_dtype) const
488{
489
490 hid_t ty_id = -1;
491
492 // Obtain the data type of the variable.
493 if ((ty_id = H5Dget_type(dset_id)) < 0)
494 throw2("unable to obtain hdf5 datatype for the dataset ", varname);
495
496 // The following datatype class and datatype will not be supported for the CF option.
497 // H5T_TIME, H5T_BITFIELD
498 // H5T_OPAQUE, H5T_ENUM
499 // H5T_REFERENCE, H5T_COMPOUND
500 // H5T_VLEN,H5T_ARRAY
501 // 64-bit integer
502
503 // Note: H5T_REFERENCE H5T_COMPOUND and H5T_ARRAY can be mapped to DAP2 DDS for the default option.
504 // H5T_COMPOUND, H5T_ARRAY can be mapped to DAP2 DAS for the default option.
505 // 1-D variable length of string can also be mapped for the CF option.
506 // The variable length string class is H5T_STRING rather than H5T_VLEN,
507 // We also ignore the mapping of integer 64 bit since DAP2 doesn't
508 // support 64-bit integer. In theory, DAP2 doesn't support long double
509 // (128-bit or 92-bit floating point type).
510 //
511
512 var->dtype = HDF5CFUtil::H5type_to_H5DAPtype(ty_id);
513 if (false == HDF5CFUtil::cf_strict_support_type(var->dtype,_is_dap4))
514 unsup_var_dtype = true;
515
516 if (H5Tclose(ty_id) < 0)
517 throw1("Unable to close the HDF5 datatype ");
518}
519
520// Retrieve the HDF5 dataset dimension information
521void File::Retrieve_H5_VarDim(Var *var, hid_t dset_id, const string & varname, bool &unsup_var_dspace)
522{
523
524 vector<hsize_t> dsize;
525 vector<hsize_t> maxsize;
526
527 hid_t dspace_id = -1;
528 hid_t ty_id = -1;
529
530 try {
531 if ((dspace_id = H5Dget_space(dset_id)) < 0)
532 throw2("Cannot get hdf5 dataspace id for the variable ", varname);
533
534 H5S_class_t space_class = H5S_NO_CLASS;
535 if ((space_class = H5Sget_simple_extent_type(dspace_id)) < 0)
536 throw2("Cannot obtain the HDF5 dataspace class for the variable ", varname);
537
538 if (H5S_NULL == space_class)
539 unsup_var_dspace = true;
540 else {
541 if (false == unsup_var_dspace) {
542
543 hssize_t h5_total_elms = H5Sget_simple_extent_npoints(dspace_id);
544 if (h5_total_elms < 0)
545 throw2("Cannot get the total number of elements of HDF5 dataset ", varname);
546 else
547 var->total_elems = (size_t) h5_total_elms;
548 int ndims = H5Sget_simple_extent_ndims(dspace_id);
549 if (ndims < 0)
550 throw2("Cannot get the hdf5 dataspace number of dimension for the variable ", varname);
551
552 var->rank = ndims;
553 if (ndims != 0) {
554 dsize.resize(ndims);
555 maxsize.resize(ndims);
556 }
557
558 // The netcdf DAP client supports the representation of the unlimited dimension.
559 // So we need to check.
560 if (H5Sget_simple_extent_dims(dspace_id, dsize.data(), maxsize.data()) < 0)
561 throw2("Cannot obtain the dim. info for the variable ", varname);
562
563 for (int i = 0; i < ndims; i++) {
564 auto dim_unique = make_unique<Dimension>(dsize[i]);
565 auto dim = dim_unique.release();
566 if (maxsize[i] == H5S_UNLIMITED) {
567 dim->unlimited_dim = true;
568 if (false == have_udim)
569 have_udim = true;
570 }
571 var->dims.push_back(dim);
572 }
573 }
574 }
575
576 var->unsupported_dspace = unsup_var_dspace;
577
578 if (H5Sclose(dspace_id) < 0)
579 throw1("Cannot close the HDF5 dataspace .");
580
581 }
582
583 catch (...) {
584
585 if (dspace_id != -1) H5Sclose(dspace_id);
586
587 if (ty_id != -1) H5Tclose(ty_id);
588 throw;
589 }
590
591}
592
593// Retrieve the HDF5 attribute information.
594void File::Retrieve_H5_Attr_Info(Attribute * attr, hid_t obj_id, const int j, bool &unsup_attr_dtype,
595 bool &unsup_attr_dspace) const
596
597{
598
599 hid_t attrid = -1;
600 hid_t ty_id = -1;
601 hid_t aspace_id = -1;
602 hid_t memtype = -1;
603
604 try {
605
606 // Obtain the attribute ID.
607 if ((attrid = H5Aopen_by_idx(obj_id, ".", H5_INDEX_CRT_ORDER, H5_ITER_INC, (hsize_t) j, H5P_DEFAULT,
608 H5P_DEFAULT)) < 0)
609 throw1("Unable to open attribute by index ");
610
611 // Obtain the size of attribute name.
612 ssize_t name_size = H5Aget_name(attrid, 0, nullptr);
613 if (name_size < 0)
614 throw1("Unable to obtain the size of the hdf5 attribute name ");
615
616 string attr_name;
617 attr_name.resize(name_size + 1);
618
619 // Obtain the attribute name.
620 if ((H5Aget_name(attrid, name_size + 1, &attr_name[0])) < 0)
621 throw1("unable to obtain the hdf5 attribute name ");
622
623 // Obtain the type of the attribute.
624 if ((ty_id = H5Aget_type(attrid)) < 0)
625 throw2("unable to obtain hdf5 datatype for the attribute ", attr_name);
626
627 // The following datatype class and datatype will not be supported for the CF option.
628 // H5T_TIME, H5T_BITFIELD
629 // H5T_OPAQUE, H5T_ENUM
630 // H5T_REFERENCE, H5T_COMPOUND
631 // H5T_VLEN,H5T_ARRAY
632 // 64-bit integer
633
634 // Note: H5T_REFERENCE H5T_COMPOUND and H5T_ARRAY can be mapped to DAP2 DDS for the default option.
635 // H5T_COMPOUND, H5T_ARRAY can be mapped to DAP2 DAS for the default option.
636 // 1-D variable length of string can also be mapped for the CF option.
637 // The variable length string class is H5T_STRING rather than H5T_VLEN,
638 // We also ignore the mapping of integer 64 bit since DAP2 doesn't
639 // support 64-bit integer. In theory, DAP2 doesn't support long double
640 // (128-bit or 92-bit floating point type).
641 //
642 attr->dtype = HDF5CFUtil::H5type_to_H5DAPtype(ty_id);
643 if (false == HDF5CFUtil::cf_strict_support_type(attr->dtype,_is_dap4))
644 unsup_attr_dtype = true;
645
646 if(H5VSTRING == attr->dtype || H5FSTRING == attr->dtype) {
647 H5T_cset_t c_set_type = H5Tget_cset(ty_id);
648 if(c_set_type <0)
649 throw2("Cannot get hdf5 character set type for the attribute ", attr_name);
650 // This is a UTF-8 string
651 if(c_set_type == H5T_CSET_UTF8)
652 attr->is_cset_ascii = false;
653 }
654
655 if ((aspace_id = H5Aget_space(attrid)) < 0)
656 throw2("Cannot get hdf5 dataspace id for the attribute ", attr_name);
657
658 int ndims = H5Sget_simple_extent_ndims(aspace_id);
659 if (ndims < 0)
660 throw2("Cannot get the hdf5 dataspace number of dimension for attribute ", attr_name);
661
662 hsize_t nelmts = 1;
663
664 // if it is a scalar attribute, just define number of elements to be 1.
665 if (ndims != 0) {
666
667 vector<hsize_t> asize;
668 vector<hsize_t> maxsize;
669 asize.resize(ndims);
670 maxsize.resize(ndims);
671
672 // Obtain the attribute data space information.
673 if (H5Sget_simple_extent_dims(aspace_id, asize.data(), maxsize.data()) < 0)
674 throw2("Cannot obtain the dim. info for the attribute ", attr_name);
675
676 // Here we need to take care of 0-length attribute. This is legal in HDF5.
677 for (int dim_count = 0;dim_count < ndims; dim_count ++) {
678 // STOP adding unsupported_attr_dspace!
679 if (asize[dim_count] == 0) {
680 unsup_attr_dspace = true;
681 break;
682 }
683 }
684
685 if (false == unsup_attr_dspace) {
686 // Return ndims and size[ndims].
687 for (int dim_count = 0; dim_count< ndims; dim_count++)
688 nelmts *= asize[dim_count];
689 }
690 else
691 nelmts = 0;
692 } // "if(ndims != 0)"
693
694 size_t ty_size = H5Tget_size(ty_id);
695 if (0 == ty_size)
696 throw2("Cannot obtain the dtype size for the attribute ", attr_name);
697
698 memtype = H5Tget_native_type(ty_id, H5T_DIR_ASCEND);
699 if (memtype < 0)
700 throw2("Cannot obtain the memory datatype for the attribute ", attr_name);
701
702 // Store the name and the count
703 string temp_aname(attr_name.begin(), attr_name.end());
704 attr->name = temp_aname.substr(0, temp_aname.size() - 1);
705 attr->newname = attr->name;
706 attr->count = nelmts;
707
708 // Release HDF5 resources.
709 if (H5Tclose(ty_id) < 0)
710 throw1("Cannot successfully close the attribute datatype.");
711 if (H5Tclose(memtype) < 0)
712 throw1("Cannot successfully close the attribute memory datatype.");
713 if (H5Sclose(aspace_id) < 0)
714 throw1("Cannot successfully close the HDF5 dataspace.");
715 if (H5Aclose(attrid) < 0)
716 throw1("Cannot successfully close the HDF5 attribute.");
717
718 } // try
719 catch (...) {
720
721 if (ty_id != -1) H5Tclose(ty_id);
722
723 if (memtype != -1) H5Tclose(memtype);
724
725 if (aspace_id != -1) H5Sclose(aspace_id);
726
727 if (attrid != -1) H5Aclose(attrid);
728
729 throw;
730 }
731
732}
733
734// Retrieve all HDF5 supported attribute values.
736{
737
738 for (auto &root_attr:this->root_attrs)
739 Retrieve_H5_Attr_Value(root_attr, "/");
740
741 for (const auto &grp:this->groups) {
742 for (auto &grp_attr:grp->attrs)
743 Retrieve_H5_Attr_Value(grp_attr, grp->path);
744 }
745
746 for (const auto &var:this->vars) {
747 for (auto &var_attr:var->attrs) {
748 Retrieve_H5_Attr_Value(var_attr, var->fullpath);
749 }
750 }
751}
752
754{
755 for (auto &attr:var->attrs)
756 Retrieve_H5_Attr_Value(attr, var->fullpath);
757}
758
759// Retrieve the values of a specific HDF5 attribute.
760void File::Retrieve_H5_Attr_Value(Attribute *attr, const string & obj_name) const
761{
762
763 // Define HDF5 object Ids.
764 hid_t obj_id = -1;
765 hid_t attr_id = -1;
766 hid_t ty_id = -1;
767 hid_t memtype_id = -1;
768 hid_t aspace_id = -1;
769
770 try {
771
772 // Open the object that hold this attribute
773 obj_id = H5Oopen(this->fileid, obj_name.c_str(), H5P_DEFAULT);
774 if (obj_id < 0)
775 throw2("Cannot open the object ", obj_name);
776
777 attr_id = H5Aopen(obj_id, (attr->name).c_str(), H5P_DEFAULT);
778 if (attr_id < 0)
779 throw4("Cannot open the attribute ", attr->name, " of object ", obj_name);
780
781 ty_id = H5Aget_type(attr_id);
782 if (ty_id < 0)
783 throw4("Cannot obtain the datatype of the attribute ", attr->name, " of object ", obj_name);
784
785 memtype_id = H5Tget_native_type(ty_id, H5T_DIR_ASCEND);
786 if (memtype_id < 0)
787 throw2("Cannot obtain the memory datatype for the attribute ", attr->name);
788
789 size_t ty_size = H5Tget_size(memtype_id);
790 if (0 == ty_size)
791 throw4("Cannot obtain the dtype size for the attribute ", attr->name, " of object ", obj_name);
792
793 size_t total_bytes = attr->count * ty_size;
794
795 // We have to handle variable length string differently.
796 if (H5VSTRING == attr->dtype) {
797
798 // Variable length string attribute values only store pointers of the actual string value.
799 vector<char> temp_buf;
800 temp_buf.resize(total_bytes);
801
802 if (H5Aread(attr_id, memtype_id, temp_buf.data()) < 0)
803 throw4("Cannot obtain the value of the attribute ", attr->name, " of object ", obj_name);
804
805 char *temp_bp = nullptr;
806 const char *ptr_1stvlen_ptr = temp_buf.data();
807 temp_bp = temp_buf.data();
808 const char* onestring = nullptr;
809 string total_vstring;
810
811 attr->strsize.resize(attr->count);
812
813 for (unsigned int temp_i = 0; temp_i < attr->count; temp_i++) {
814
815 // This line will assure that we get the real variable length string value.
816 onestring = *(char **) temp_bp;
817 if (onestring != nullptr) {
818 total_vstring += string(onestring);
819 attr->strsize[temp_i] = (string(onestring)).size();
820 }
821 else
822 attr->strsize[temp_i] = 0;
823
824 // going to the next value.
825 temp_bp += ty_size;
826 }
827
828 if (ptr_1stvlen_ptr != nullptr) {
829 aspace_id = H5Aget_space(attr_id);
830 if (aspace_id < 0)
831 throw4("Cannot obtain space id for ", attr->name, " of object ", obj_name);
832
833 // Reclaim any VL memory if necessary.
834 if (H5Dvlen_reclaim(memtype_id, aspace_id, H5P_DEFAULT, temp_buf.data()) < 0)
835 throw4("Cannot reclaim VL memory for ", attr->name, " of object ", obj_name);
836
837 H5Sclose(aspace_id);
838 }
839
840 if (HDF5CFUtil::H5type_to_H5DAPtype(ty_id) != H5VSTRING)
841 throw4("Error to obtain the VL string type for attribute ", attr->name, " of object ", obj_name);
842
843 attr->value.resize(total_vstring.size());
844
845 copy(total_vstring.begin(), total_vstring.end(), attr->value.begin());
846
847 }
848 else {
849
850 if (attr->dtype == H5FSTRING) {
851 attr->fstrsize = ty_size;
852 }
853
854 attr->value.resize(total_bytes);
855
856 // Read HDF5 attribute data.
857 if (H5Aread(attr_id, memtype_id, (void *) &attr->value[0]) < 0)
858 throw4("Cannot obtain the dtype size for the attribute ", attr->name, " of object ", obj_name);
859
860 if (attr->dtype == H5FSTRING) {
861
862 size_t sect_size = ty_size;
863 int num_sect = 1;
864 if (sect_size > 0)
865 num_sect =
866 (total_bytes % sect_size == 0) ? (total_bytes / sect_size) : (total_bytes / sect_size + 1);
867 else
868 throw4("The attribute datatype size is not a positive integer ", attr->name, " of object ",
869 obj_name);
870
871 vector<size_t> sect_newsize;
872 sect_newsize.resize(num_sect);
873
874 auto total_fstring = string(attr->value.begin(), attr->value.end());
875
876 string new_total_fstring = HDF5CFUtil::trim_string(memtype_id, total_fstring, num_sect, sect_size,
877 sect_newsize);
878 attr->value.resize(new_total_fstring.size());
879 copy(new_total_fstring.begin(), new_total_fstring.end(), attr->value.begin());
880 attr->strsize.resize(num_sect);
881 for (int temp_i = 0; temp_i < num_sect; temp_i++)
882 attr->strsize[temp_i] = sect_newsize[temp_i];
883
884#if 0
885 // "h5","new string value " <<string(attr->value.begin(), attr->value.end()) <<endl;
886 cerr<<"Attr name is "<<attr->name <<endl;
887 for (int temp_i = 0; temp_i <num_sect; temp_i ++)
888 cerr<<"string new section size = " << attr->strsize[temp_i] <<endl;
889#endif
890 }
891 }
892
893 if (H5Tclose(memtype_id) < 0)
894 throw1("Fail to close the HDF5 memory datatype ID.");
895 if (H5Tclose(ty_id) < 0)
896 throw1("Fail to close the HDF5 datatype ID.");
897 if (H5Aclose(attr_id) < 0)
898 throw1("Fail to close the HDF5 attribute ID.");
899 if (H5Oclose(obj_id) < 0)
900 throw1("Fail to close the HDF5 object ID.");
901
902 }
903
904 catch (...) {
905
906 if (memtype_id != -1) H5Tclose(memtype_id);
907
908 if (ty_id != -1) H5Tclose(ty_id);
909
910 if (aspace_id != -1) H5Sclose(aspace_id);
911
912 if (attr_id != -1) H5Aclose(attr_id);
913
914 if (obj_id != -1) H5Oclose(obj_id);
915
916 throw;
917 }
918
919}
920
921// Handle the unsupported datatype
922void File::Handle_Unsupported_Dtype(bool include_attr)
923{
924
925 if (true == include_attr) {
926 Handle_Group_Unsupported_Dtype();
927 Handle_VarAttr_Unsupported_Dtype();
928 }
929
930 Handle_Var_Unsupported_Dtype();
931}
932
933//Leave this code here.
934#if 0
935// First the root attributes
936if (true == include_attr) {
937 if (true == this->unsupported_attr_dtype) {
938 for (vector<Attribute *>::iterator ira = this->root_attrs.begin();
939 ira != this->root_attrs.end(); ) {
940 H5DataType temp_dtype = (*ira)->getType();
941 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype)) {
942 delete (*ira);
943 ira = this->root_attrs.erase(ira);
944
945 }
946 else {
947 ++ira;
948 }
949 }
950 }
951}
952
953// Then the group attributes
954if (false == this->groups.empty()) {
955 for (vector<Group *>::iterator irg = this->groups.begin();
956 irg != this->groups.end(); ++irg) {
957 if (false == (*irg)->attrs.empty()) {
958 if (true == (*irg)->unsupported_attr_dtype) {
959 for (vector<Attribute *>::iterator ira = (*irg)->attrs.begin();
960 ira != (*irg)->attrs.end(); ) {
961 H5DataType temp_dtype = (*ira)->getType();
962 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype)) {
963 delete (*ira);
964 ira = (*irg)->attrs.erase(ira);
965 }
966 else {
967 ++ira;
968 }
969 }
970 }
971 }
972 }
973}
974}
975
976 // Then the variable(HDF5 dataset) and the correponding attributes.
977if (false == this->vars.empty()) {
978if (true == include_attr) {
979 for (vector<Var *>::iterator irv = this->vars.begin();
980 irv != this->vars.end();++irv ) {
981 if (false == (*irv)->attrs.empty()) {
982 if (true == (*irv)->unsupported_attr_dtype) {
983 for (vector<Attribute *>::iterator ira = (*irv)->attrs.begin();
984 ira != (*irv)->attrs.end(); ) {
985 H5DataType temp_dtype = (*ira)->getType();
986 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype)) {
987 delete (*ira);
988 ira = (*irv)->attrs.erase(ira);
989 //ira--;
990 }
991 else {
992 ++ira;
993 }
994 }
995 }
996 }
997 }
998}
999if (true == this->unsupported_var_dtype) {
1000 // "h5","having unsupported variable datatype" <<endl;
1001 for (vector<Var *>::iterator irv = this->vars.begin();
1002 irv != this->vars.end(); ) {
1003 H5DataType temp_dtype = (*irv)->getType();
1004 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype)) {
1005 delete (*irv);
1006 irv = this->vars.erase(irv);
1007 //irv--;
1008 }
1009 else
1010 ++irv;
1011 }
1012}
1013}
1014#endif
1015
1016void File::Handle_Group_Unsupported_Dtype()
1017{
1018
1019 // First root
1020 if (false == this->root_attrs.empty()) {
1021 if (true == this->unsupported_attr_dtype) {
1022 for (auto ira = this->root_attrs.begin(); ira != this->root_attrs.end();) {
1023 H5DataType temp_dtype = (*ira)->getType();
1024 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
1025 delete (*ira);
1026 ira = this->root_attrs.erase(ira);
1027 }
1028 else {
1029 ++ira;
1030 }
1031 }
1032 }
1033 }
1034
1035 // Then the group attributes
1036 if (false == this->groups.empty()) {
1037 for (const auto &grp:this->groups) {
1038 if (false == grp->attrs.empty()) {
1039 if (true == grp->unsupported_attr_dtype) {
1040 for (auto ira = grp->attrs.begin(); ira != grp->attrs.end();) {
1041 H5DataType temp_dtype = (*ira)->getType();
1042 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
1043 delete (*ira);
1044 ira = grp->attrs.erase(ira);
1045 }
1046 else {
1047 ++ira;
1048 }
1049 }
1050 }
1051 }
1052 }
1053 }
1054}
1055
1056// Generate group unsupported datatype Information, this is for the BES ignored object key
1057void File::Gen_Group_Unsupported_Dtype_Info()
1058{
1059
1060 // First root
1061 if (false == this->root_attrs.empty()) {
1062 //if (true == this->unsupported_attr_dtype) {
1063 for (const auto &root_attr:this->root_attrs) {
1064 H5DataType temp_dtype = root_attr->getType();
1065 // TODO: Don't know why we still include 64-bit integer here.
1066 //if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype) || temp_dtype == H5INT64 || temp_dtype == H5UINT64) {
1067 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)
1068 || temp_dtype == H5INT64 || temp_dtype == H5UINT64) {
1069 this->add_ignored_info_attrs(true, "/", root_attr->name);
1070 }
1071 }
1072 //}
1073 }
1074
1075 // Then the group attributes
1076 if (false == this->groups.empty()) {
1077 for (const auto &grp:this->groups) {
1078 if (false == grp->attrs.empty()) {
1079 //if (true == grp->unsupported_attr_dtype) {
1080 for (const auto &grp_attr:grp->attrs) {
1081 H5DataType temp_dtype = grp_attr->getType();
1082 // TODO: Don't know why we still include 64-bit integer here.
1083 //if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype) || temp_dtype == H5INT64 || temp_dtype==H5UINT64 ) {
1084 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)
1085 || temp_dtype == H5INT64 || temp_dtype==H5UINT64 ) {
1086 this->add_ignored_info_attrs(true, grp->path, grp_attr->name);
1087 }
1088 }
1089 //}
1090 }
1091 }
1092 }
1093}
1094
1095// Handler unsupported variable datatype
1096void File::Handle_Var_Unsupported_Dtype()
1097{
1098 if (false == this->vars.empty()) {
1099 if (true == this->unsupported_var_dtype) {
1100 for (auto irv = this->vars.begin(); irv != this->vars.end();) {
1101 H5DataType temp_dtype = (*irv)->getType();
1102 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
1103 delete (*irv);
1104 irv = this->vars.erase(irv);
1105 }
1106 else {
1107 ++irv;
1108
1109 }
1110 }
1111 }
1112 }
1113}
1114
1115// Generate unsupported variable type info. This is for the ignored objects.
1116void File::Gen_Var_Unsupported_Dtype_Info()
1117{
1118
1119 if (false == this->vars.empty()) {
1120 //if (true == this->unsupported_var_dtype) {
1121 for (const auto &var:this->vars) {
1122 H5DataType temp_dtype = var->getType();
1123 //TODO: don't know why 64-bit integer is still listed here.
1124 //if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype)||(H5INT64 == temp_dtype) ||(H5UINT64 == temp_dtype)) {
1125 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)
1126 ||(H5INT64 == temp_dtype) ||(H5UINT64 == temp_dtype)) {
1127 this->add_ignored_info_objs(false, var->fullpath);
1128 }
1129 }
1130 //}
1131 }
1132
1133}
1134
1135// Handling unsupported datatypes for variable(HDF5 dataset) and the corresponding attributes.
1136void File::Handle_VarAttr_Unsupported_Dtype()
1137{
1138 if (false == this->vars.empty()) {
1139 for (const auto &var:this->vars) {
1140 if (false == var->attrs.empty()) {
1141 if (true == var->unsupported_attr_dtype) {
1142 for (auto ira = var->attrs.begin(); ira != var->attrs.end();) {
1143 H5DataType temp_dtype = (*ira)->getType();
1144 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)) {
1145 delete (*ira);
1146 ira = var->attrs.erase(ira);
1147 }
1148 else {
1149 ++ira;
1150 }
1151 }
1152 }
1153 }
1154 }
1155 }
1156}
1157
1158// Generated unsupported var/attribute unsupported datatype Info when the BES ignored object key is on.
1159void File::Gen_VarAttr_Unsupported_Dtype_Info()
1160{
1161
1162 if (false == this->vars.empty()) {
1163 for (const auto &var:this->vars) {
1164 if (false == var->attrs.empty()) {
1165 //if (true == var->unsupported_attr_dtype) {
1166 for (const auto &attr:var->attrs) {
1167 H5DataType temp_dtype = attr->getType();
1168 // TODO: check why 64-bit integer is still listed here.
1169 //if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype) || (temp_dtype==H5INT64) || (temp_dtype == H5UINT64)) {
1170 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)
1171 || (temp_dtype==H5INT64) || (temp_dtype == H5UINT64)) {
1172 this->add_ignored_info_attrs(false, var->fullpath, attr->name);
1173 }
1174 }
1175 //}
1176 }
1177 }
1178 }
1179}
1180
1181// Generated unsupported datatype information for HDF5 dimension scales.
1182// The datatypes of HDF5 dimension scales("DIMENSION_LIST" and "REFERENCE_LIST")
1183// are not supported. However, the information
1184// are retrieved by the handlers, so we don't want to report them as ignored objects.
1185void File::Gen_DimScale_VarAttr_Unsupported_Dtype_Info()
1186{
1187
1188 for (const auto &var:this->vars) {
1189
1190 // If the attribute REFERENCE_LIST comes with the attribut CLASS, the
1191 // attribute REFERENCE_LIST is okay to ignore. No need to report.
1192 bool is_ignored = ignored_dimscale_ref_list(var);
1193 if (false == var->attrs.empty()) {
1194 //if (true == var->unsupported_attr_dtype) {
1195 for (const auto &attr:var->attrs) {
1196 H5DataType temp_dtype = attr->getType();
1197 // TODO: check why 64-bit is still listed here.
1198 if (false == HDF5CFUtil::cf_strict_support_type(temp_dtype,_is_dap4)
1199 || (temp_dtype == H5INT64) || (temp_dtype == H5UINT64)) {
1200 // "DIMENSION_LIST" is okay to ignore and "REFERENCE_LIST"
1201 // is okay to ignore if the variable has another attribute
1202 // CLASS="DIMENSION_SCALE"
1203 if (("DIMENSION_LIST" != attr->name)
1204 && ("REFERENCE_LIST" != attr->name || true == is_ignored))
1205 this->add_ignored_info_attrs(false, var->fullpath, attr->name);
1206 }
1207 }
1208 //}
1209 }
1210 }
1211}
1212
1213// Handle unsupported dataspace for group attributes.
1214void File::Handle_GroupAttr_Unsupported_Dspace()
1215{
1216
1217 // First root
1218 if (false == this->root_attrs.empty()) {
1219 if (true == this->unsupported_attr_dspace) {
1220 for (auto ira = this->root_attrs.begin(); ira != this->root_attrs.end();) {
1221 // Remove 0-size attribute
1222 if ((*ira)->count == 0) {
1223 delete (*ira);
1224 ira = this->root_attrs.erase(ira);
1225 }
1226 else {
1227 ++ira;
1228 }
1229 }
1230 }
1231 }
1232
1233 // Then the group attributes
1234 if (false == this->groups.empty()) {
1235 for (auto irg = this->groups.begin(); irg != this->groups.end(); ++irg) {
1236 if (false == (*irg)->attrs.empty()) {
1237 if (true == (*irg)->unsupported_attr_dspace) {
1238 for (auto ira = (*irg)->attrs.begin(); ira != (*irg)->attrs.end();) {
1239 if ((*ira)->count == 0) {
1240 delete (*ira);
1241 ira = (*irg)->attrs.erase(ira);
1242 }
1243 else {
1244 ++ira;
1245 }
1246 }
1247 }
1248 }
1249 }
1250 }
1251}
1252
1253// Handle unsupported data space information for variable and attribute
1254void File::Handle_VarAttr_Unsupported_Dspace()
1255{
1256
1257 if (false == this->vars.empty()) {
1258 if (true == this->unsupported_var_attr_dspace) {
1259 for (const auto &var:this->vars) {
1260 if (false == var->attrs.empty()) {
1261 if (true == var->unsupported_attr_dspace) {
1262 for (auto ira = var->attrs.begin(); ira != var->attrs.end();) {
1263 if (0 == (*ira)->count) {
1264 delete (*ira);
1265 ira = var->attrs.erase(ira);
1266 }
1267 else {
1268 ++ira;
1269 }
1270 }
1271 }
1272 }
1273 }
1274 }
1275 }
1276}
1277
1278// Handle unsupported data space.
1279void File::Handle_Unsupported_Dspace(bool include_attr)
1280{
1281
1282 // The unsupported data space
1283 if (false == this->vars.empty()) {
1284 if (true == this->unsupported_var_dspace) {
1285 for (auto irv = this->vars.begin(); irv != this->vars.end();) {
1286 if (true == (*irv)->unsupported_dspace) {
1287 delete (*irv);
1288 irv = this->vars.erase(irv);
1289 }
1290 else {
1291 ++irv;
1292
1293 }
1294 }
1295 }
1296 }
1297
1298 if (true == include_attr) {
1299 Handle_GroupAttr_Unsupported_Dspace();
1300 Handle_VarAttr_Unsupported_Dspace();
1301 }
1302}
1303
1304// Generated unsupported dataspace Info when the BES ignored object key is on.
1305void File::Gen_Unsupported_Dspace_Info()
1306{
1307
1308 // Notice in this function, we deliberately don't put the case when an attribute dimension has 0 length.
1309 // Since doing this requires non-trivial change of the source code and the 0-size attribute case is really, really rare,
1310 // so we just "ignore" this case in the "ignored" information.
1311 // In fact, the zero size variable is allowed in both HDF5 and DAP2. So we don't ignore 0-size HDF5 dataset. So
1312 // the only case this function checks is the H5S_NULL case.
1313 if (false == this->vars.empty()) {
1314 if (true == this->unsupported_var_dspace) {
1315 for (const auto &var:this->vars) {
1316 if (true == var->unsupported_dspace) {
1317 this->add_ignored_info_objs(true, var->fullpath);
1318 }
1319 }
1320 }
1321 }
1322
1323}
1324
1325// Handle other unsupported information.
1326void File::Handle_Unsupported_Others(bool include_attr)
1327{
1328
1329 if (true == this->check_ignored && true == include_attr) {
1330
1331 if (true == HDF5RequestHandler::get_drop_long_string()) {
1332
1333 // netCDF java doesn't have limitation for attributes
1334#if 0
1335 for (vector<Attribute *>::iterator ira = this->root_attrs.begin(); ira != this->root_attrs.end(); ++ira) {
1336 if (H5FSTRING == (*ira)->dtype || H5VSTRING == (*ira)->dtype) {
1337 if ((*ira)->getBufSize() > NC_JAVA_STR_SIZE_LIMIT) {
1338 this->add_ignored_droplongstr_hdr();
1339 this->add_ignored_grp_longstr_info("/", (*ira)->name);
1340 }
1341 }
1342 }
1343
1344 for (vector<Group *>::iterator irg = this->groups.begin(); irg != this->groups.end(); ++irg) {
1345 for (vector<Attribute *>::iterator ira = (*irg)->attrs.begin(); ira != (*irg)->attrs.end(); ++ira) {
1346 if (H5FSTRING == (*ira)->dtype || H5VSTRING == (*ira)->dtype) {
1347 if ((*ira)->getBufSize() > NC_JAVA_STR_SIZE_LIMIT) {
1348 this->add_ignored_droplongstr_hdr();
1349 this->add_ignored_grp_longstr_info((*irg)->path, (*ira)->name);
1350 }
1351 }
1352 }
1353 }
1354#endif
1355 for (const auto &var:this->vars) {
1356 if (true == Check_DropLongStr(var, nullptr)) {
1357 this->add_ignored_droplongstr_hdr();
1358 this->add_ignored_var_longstr_info(var, nullptr);
1359 }
1360 // netCDF java doesn't have limitation for attributes
1361#if 0
1362 for (auto ira = (*irv)->attrs.begin(); ira != (*irv)->attrs.end(); ++ira) {
1363 if (true == Check_DropLongStr((*irv), (*ira))) {
1364 this->add_ignored_droplongstr_hdr();
1365 this->add_ignored_var_longstr_info((*irv), (*ira));
1366 }
1367 }
1368#endif
1369 }
1370 }
1371 }
1372
1373}
1374
1375// Flatten the object name, mainly call get_CF_string.
1376void File::Flatten_Obj_Name(bool include_attr)
1377{
1378 for (auto &var:this->vars) {
1379 var->newname = get_CF_string(var->newname);
1380 for (auto &dim:var->dims)
1381 dim->newname = get_CF_string(dim->newname);
1382 }
1383
1384 if (true == include_attr) {
1385
1386 for (auto &root_attr:this->root_attrs) {
1387 root_attr->newname = get_CF_string(root_attr->newname);
1388 }
1389
1390 for (auto &grp:this->groups) {
1391 grp->newname = get_CF_string(grp->newname);
1392 for (auto &grp_attr:grp->attrs)
1393 grp_attr->newname = get_CF_string(grp_attr->newname);
1394 }
1395
1396 for (const auto &var:this->vars) {
1397 for (auto attr:var->attrs)
1398 attr->newname = get_CF_string(attr->newname);
1399 }
1400 }
1401}
1402
1403// Variable name clashing
1404void File::Handle_Var_NameClashing(set<string>&objnameset)
1405{
1406
1407 Handle_General_NameClashing(objnameset, this->vars);
1408}
1409
1410// Group name clashing
1411void File::Handle_Group_NameClashing(set<string> &objnameset)
1412{
1413
1414 pair<set<string>::iterator, bool> setret;
1415
1416 // Now for DAS, we need to handle name clashing for
1417 // DAS tables, namely we need to make sure the global attribute
1418 // table(HDF5_GLOBAL) and the attribute tables mapped from
1419 // HDF5 groups will not have name clashing with the variable name
1420 // lists. If having the name clashing, the global attribute table and
1421 // the attribute tables generated from the groups will be changed.
1422 // The file attribute name clashing
1423
1424 setret = objnameset.insert(FILE_ATTR_TABLE_NAME);
1425 if (false == setret.second) {
1426
1427 int clash_index = 1;
1428 string fa_clash_name = FILE_ATTR_TABLE_NAME;
1429 HDF5CFUtil::gen_unique_name(fa_clash_name, objnameset, clash_index);
1430 FILE_ATTR_TABLE_NAME = fa_clash_name;
1431 }
1432
1433 // The group attribute name clashing
1434 Handle_General_NameClashing(objnameset, this->groups);
1435
1436}
1437
1438//Object attribute name clashing
1439void File::Handle_Obj_AttrNameClashing()
1440{
1441
1442 // Now handling the possible name clashing for attributes
1443 // For attribute clashing, we only need to resolve the name clashing
1444 // for attributes within each variable, file attributes and attributes
1445 // within each group. The name clashing for attributes should be very rare.
1446 // Potentially the checking and the correcting may be costly.
1447 // This is another reason for special products, we may not even need to check
1448 // the name clashings. KY 2011-12-24
1449
1450 set<string> objnameset;
1451
1452 // For root attributes
1453 Handle_General_NameClashing(objnameset, this->root_attrs);
1454
1455 // For group attributes
1456 for (const auto &grp:this->groups) {
1457 objnameset.clear();
1458 Handle_General_NameClashing(objnameset, grp->attrs);
1459 }
1460
1461 // For variable attributes
1462 for (const auto &var:this->vars) {
1463 objnameset.clear();
1464 Handle_General_NameClashing(objnameset, var->attrs);
1465 }
1466}
1467
1468// Handle General name clashing
1469//class T must have member string newname. In our case, T is either groups, attributes or vars.
1470template<class T> void File::Handle_General_NameClashing(set<string>&objnameset, vector<T*>& objvec)
1471{
1472
1473#if 0
1474// set<string> objnameset;
1475#endif
1476
1477 pair<set<string>::iterator, bool> setret;
1478 set<string>::iterator iss;
1479
1480 vector<string> clashnamelist;
1481
1482 map<int, int> cl_to_ol;
1483 int ol_index = 0;
1484 int cl_index = 0;
1485
1486 /*class*/
1487
1488 for (const auto &obj:objvec) {
1489 setret = objnameset.insert(obj->newname);
1490 if (false == setret.second) {
1491 clashnamelist.insert(clashnamelist.end(), obj->newname);
1492 cl_to_ol[cl_index] = ol_index;
1493 cl_index++;
1494 }
1495 ol_index++;
1496 }
1497
1498 // Now change the clashed elements to unique elements,
1499 // Generate the set which has the same size as the original vector.
1500 for (auto &clashname:clashnamelist) {
1501 int clash_index = 1;
1502 string temp_clashname = clashname + '_';
1503 HDF5CFUtil::gen_unique_name(temp_clashname, objnameset, clash_index);
1504 clashname = temp_clashname;
1505 }
1506
1507 // Now go back to the original vector, make it unique.
1508 for (unsigned int i = 0; i < clashnamelist.size(); i++)
1509 objvec[cl_to_ol[i]]->newname = clashnamelist[i];
1510
1511}
1512
1513// Handle General object name clashing
1514void File::Handle_GeneralObj_NameClashing(bool include_attr, set<string>& objnameset)
1515{
1516
1517 Handle_Var_NameClashing(objnameset);
1518 if (true == include_attr) {
1519 Handle_Group_NameClashing(objnameset);
1520 Handle_Obj_AttrNameClashing();
1521 }
1522}
1523
1524// Get CF name, flatten the path, change the non-alphanumeric letters to underscore.
1525string File::get_CF_string(string s)
1526{
1527
1528 if ("" == s) return s;
1529 string insertString(1, '_');
1530
1531 // Always start with _ if the first character is not a letter
1532 if (true == isdigit(s[0])) s.insert(0, insertString);
1533
1534 for (unsigned int i = 0; i < s.size(); i++)
1535 if ((false == isalnum(s[i])) && (s[i] != '_')) s[i] = '_';
1536
1537 return s;
1538
1539}
1540
1541// For the connection of variable dimensions. Build dimname to dimsize(unlimited) maps
1542void File::Insert_One_NameSizeMap_Element(const string &name, hsize_t size, bool unlimited)
1543{
1544 pair<map<string, hsize_t>::iterator, bool> mapret;
1545 mapret = dimname_to_dimsize.insert(pair<string, hsize_t>(name, size));
1546 if (false == mapret.second)
1547 throw4("The dimension name ", name, " should map to ", size);
1548
1549 pair<map<string, bool>::iterator, bool> mapret2;
1550 mapret2 = dimname_to_unlimited.insert(pair<string, bool>(name, unlimited));
1551 if (false == mapret2.second)
1552 throw3("The dimension name ", name, " unlimited dimension info. should be provided.");
1553
1554}
1555
1556// Similar to Inset_One_NameSizeMap_Element but the maps are provided as parameters.
1557void File::Insert_One_NameSizeMap_Element2(map<string, hsize_t>& name_to_size, map<string, bool>& name_to_unlimited,
1558 const string &name, hsize_t size, bool unlimited) const
1559{
1560 pair<map<string, hsize_t>::iterator, bool> mapret;
1561 mapret = name_to_size.insert(pair<string, hsize_t>(name, size));
1562 if (false == mapret.second)
1563 throw4("The dimension name ", name, " should map to ", size);
1564
1565 pair<map<string, bool>::iterator, bool> mapret2;
1566 mapret2 = name_to_unlimited.insert(pair<string, bool>(name, unlimited));
1567 if (false == mapret2.second)
1568 throw3("The dimension name ", name, " unlimited dimension info. should be provided.");
1569
1570}
1571
1572// For dimension names added by the handlers, by default,
1573// Each dimension will have a unique dimension name. For example,
1574// Int foo[100][200] will be Int foo[Fakedim1][Fakedim2]
1575// If you have many variables, the dimension names may be too many.
1576// To reduce numbers, we ASSUME that the dimension having the same
1577// size shares the same dimension. In this way, the number of dimension names
1578// will be reduced.
1579// For example, Int foo2[100][300] will be Int foo2[Fakedim1][Fakedim3]
1580// instead of foo2[Fakedim3][Fakedim4]. However, that may impose
1581// another problem. Suppose Int Foosame[100][100] becomes
1582// Int Foosame[FakeDim1][FakeDim1]. This doesn't make sense for some
1583// applications. The function Adjust_Duplicate_FakeDim_Name will make sure
1584// this case will not happen.
1585void File::Add_One_FakeDim_Name(Dimension *dim)
1586{
1587
1588 stringstream sfakedimindex;
1589 string fakedimstr = "FakeDim";
1590 pair<set<string>::iterator, bool> setret;
1591 map<hsize_t, string>::iterator im;
1592 pair<map<hsize_t, string>::iterator, bool> mapret;
1593
1594 sfakedimindex << addeddimindex;
1595 string added_dimname = fakedimstr + sfakedimindex.str();
1596
1597 // Build up the size to fakedim map.
1598 mapret = dimsize_to_fakedimname.insert(pair<hsize_t, string>(dim->size, added_dimname));
1599 if (false == mapret.second) { //The dim size exists, use the corresponding name.
1600 dim->name = dimsize_to_fakedimname[dim->size];
1601 dim->newname = dim->name;
1602 }
1603 else { // Insert this (dimsize,dimname) pair to dimsize_to_fakedimname map successfully.
1604 //First make sure this new dim name doesn't have name clashing
1605 // with previous dim names, after the checking, inserting to the
1606 // dimname list set.
1607 // dimnamelist is a private memeber of File.
1608 setret = dimnamelist.insert(added_dimname);
1609 if (false == setret.second) {
1610 int clash_index = 1;
1611 string temp_clashname = added_dimname + '_';
1612 HDF5CFUtil::gen_unique_name(temp_clashname, dimnamelist, clash_index);
1613 dim->name = temp_clashname;
1614 dim->newname = dim->name;
1615 setret = dimnamelist.insert(dim->name);
1616 if (false == setret.second)
1617 throw2("Fail to insert the unique dimsizede name ", dim->name);
1618
1619 // We have to adjust the dim. name of the dimsize_to_fakedimname map, since the
1620 // dimname has been updated for this size.
1621 dimsize_to_fakedimname.erase(dim->size);
1622 mapret = dimsize_to_fakedimname.insert(pair<hsize_t, string>(dim->size, dim->name));
1623 if (false == mapret.second)
1624 throw4("The dimension size ", dim->size, " should map to ", dim->name);
1625 }
1626
1627 // New dim name is inserted successfully, update the dimname_to_dimsize map.
1628 dim->name = added_dimname;
1629 dim->newname = dim->name;
1630 Insert_One_NameSizeMap_Element(dim->name, dim->size, dim->unlimited_dim);
1631
1632 // Increase the dimindex since the new dimname has been inserted.
1633 addeddimindex++;
1634 } // else
1635}
1636
1637// See the function comments of Add_One_FakeDim_Name
1638void File::Adjust_Duplicate_FakeDim_Name(Dimension * dim)
1639{
1640
1641 // No need to adjust the dimsize_to_fakedimname map, only create a new Fakedim
1642 // The simplest way is to increase the dim index and resolve any name clashings with other dim names.
1643 // Note: No need to update the dimsize_to_dimname map since the original "FakeDim??" of this size
1644 // can be used as a dimension name of other variables. But we need to update the dimname_to_dimsize map
1645 // since this is a new dim name.
1646 stringstream sfakedimindex;
1647 pair<set<string>::iterator, bool> setret;
1648
1649 addeddimindex++;
1650 sfakedimindex << addeddimindex;
1651 string added_dimname = "FakeDim" + sfakedimindex.str();
1652 setret = dimnamelist.insert(added_dimname);
1653 if (false == setret.second) {
1654 int clash_index = 1;
1655 string temp_clashname = added_dimname + '_';
1656 HDF5CFUtil::gen_unique_name(temp_clashname, dimnamelist, clash_index);
1657 dim->name = temp_clashname;
1658 dim->newname = dim->name;
1659 setret = dimnamelist.insert(dim->name);
1660 if (false == setret.second)
1661 throw2("Fail to insert the unique dimsizede name ", dim->name);
1662 }
1663 dim->name = added_dimname;
1664 dim->newname = dim->name;
1665 Insert_One_NameSizeMap_Element(dim->name, dim->size, dim->unlimited_dim);
1666
1667 // Need to prepare for the next unique FakeDim.
1668 addeddimindex++;
1669}
1670// 1. See the function comments of Add_One_FakeDim_Name
1671// 2. This is for the case when we have foo[100][100],foo2[100][100].
1672// The Adjust_Duplicate_FakeDim_Name() assures the uniqueness of Dimension
1673// names for each var,like foo[FakeDim0][FakeDim1],foo2[FakeDim0][FakeDim3]..
1674// but the dimension names are not desirable for products like SMAP level 3.
1675// For similar vars, the dimension names like foo[FakeDim0][FakeDim1] and
1676// foo2[FakeDim0][FakeDim1] ,foo3[FakeDim0][FakeDim1][FakeDim2] are the way to go.
1677
1678void File::Adjust_Duplicate_FakeDim_Name2(Dimension * dim, int dup_dim_size_index)
1679{
1680
1681 // Search if vector of dup (dimsize dimname) pair has the current size
1682 // If yes, insert the dim name from the vector.
1683 // Note: in case we have foo[100][100][100] etc., we need to remember the
1684 // vector index, to obtain the correct dup_dim_size, dup_dim_name pair.
1685 // if no, build up the new FakeDim.
1686 bool dup_dim_size_exist = false;
1687 int temp_dup_dim_size_index = 0;
1688 for (const auto &one_dup_dimsize_dimname:dup_dimsize_dimname) {
1689 // The dup vector may include different size, so we need to check
1690 // if having the same size.
1691 if(dim->size == one_dup_dimsize_dimname.first) {
1692 temp_dup_dim_size_index++;
1693 // Make sure we obtain the correct index in the vector
1694 if(dup_dim_size_index == temp_dup_dim_size_index) {
1695 dup_dim_size_exist = true;
1696 dim->name = one_dup_dimsize_dimname.second;
1697 dim->newname = dim->name;
1698 break;
1699 }
1700 }
1701 }
1702
1703 // If we cannot find this dimension in the existing (dup dimsize dimname) vector,
1704 // create the FakeDim by increasing the index and update the dup vector etc.
1705 if(dup_dim_size_exist == false) {
1706
1707 stringstream sfakedimindex;
1708 pair<set<string>::iterator, bool> setret;
1709
1710 sfakedimindex << addeddimindex;
1711 string added_dimname = "FakeDim" + sfakedimindex.str();
1712 setret = dimnamelist.insert(added_dimname);
1713 if (false == setret.second) {
1714 throw2("Inside Adjust_Duplicate_FakeDim_Name2(), Fail to insert the unique dim name ", dim->name);
1715 }
1716 dim->name = added_dimname;
1717 dim->newname = dim->name;
1718 Insert_One_NameSizeMap_Element(dim->name, dim->size, dim->unlimited_dim);
1719 // push back to the duplicate size, name vector.
1720 dup_dimsize_dimname.emplace_back(dim->size,dim->name);
1721 addeddimindex++;
1722
1723 }
1724
1725}
1726
1727// Replace all dimension names, this function is currently not used. So comment out. May delete it in the future.
1728#if 0
1729void File::Replace_Dim_Name_All(const string orig_dim_name, const string new_dim_name) {
1730
1731 // The newname of the original dimension should also be replaced by new_dim_name
1732 for (vector<Var *>::iterator irv = this->vars.begin();
1733 irv != this->vars.end(); ++irv) {
1734 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
1735 ird != (*irv)->dims.end(); ++ird) {
1736 if((*ird)->name == orig_dim_name) {
1737 (*ird)->name = new_dim_name;
1738 (*ird)->newname = new_dim_name;
1739 }
1740
1741 }
1742 }
1743}
1744#endif
1745
1746#if 0
1747void File::Use_Dim_Name_With_Size_All(const string dim_name, const size_t dim_size) {
1748
1749 // The newname of the original dimension should also be replaced by new_dim_name
1750 for (vector<Var *>::iterator irv = this->vars.begin();
1751 irv != this->vars.end(); ++irv) {
1752 for (vector<Dimension *>::iterator ird= (*irv)->dims.begin();
1753 ird != (*irv)->dims.end(); ++ird) {
1754 if((*ird)->size == orig_dim_name) {
1755 (*ird)->name = new_dim_name;
1756 (*ird)->newname = new_dim_name;
1757 }
1758
1759 }
1760 }
1761}
1762#endif
1763
1764// Often times we need to add a CF attribute with string datatype because some products don't provide them
1765// Examples are units, comment etc.
1766void File::Add_Str_Attr(Attribute* attr, const string &attrname, const string& strvalue) const
1767{
1768
1769 attr->name = attrname;
1770 attr->newname = attr->name;
1771 attr->dtype = H5FSTRING;
1772 attr->count = 1;
1773 attr->fstrsize = strvalue.size();
1774 attr->strsize.resize(1);
1775 attr->strsize[0] = attr->fstrsize;
1776 attr->value.resize(strvalue.size());
1777 copy(strvalue.begin(), strvalue.end(), attr->value.begin());
1778}
1779
1780#if 0
1781bool
1782File:: Var_Has_Attr(Var*var,const string &attrname) {
1783
1784 for (vector<Attribute *>:: iterator ira =var->attrs.begin(); ira !=var->attrs.end(); ++ira) {
1785
1786 // We only check the original attribute name
1787 // Remove the original "coordinates" attribute.
1788 if((*ira)->name == attrname || (*ira)->newname == attrname) {
1789 return true;
1790 }
1791 }
1792 return false;
1793}
1794#endif
1795
1796// Rretrieve the variable attribute in string.var_path is the variable path.
1797string File::Retrieve_Str_Attr_Value(Attribute *attr, const string & var_path) const
1798{
1799
1800 if (attr != nullptr && var_path != "") {
1801 Retrieve_H5_Attr_Value(attr, var_path);
1802 string orig_attr_value(attr->value.begin(), attr->value.end());
1803 return orig_attr_value;
1804 }
1805 return "";
1806
1807}
1808
1809//Check if the attribute value of this variable is the input value.
1810bool File::Is_Str_Attr(Attribute* attr, const string& varfullpath, const string &attrname, const string& strvalue)
1811{
1812 bool ret_value = false;
1813 if (attrname == get_CF_string(attr->newname)) {
1814 Retrieve_H5_Attr_Value(attr, varfullpath);
1815 string attr_value(attr->value.begin(), attr->value.end());
1816 if (attr_value == strvalue) ret_value = true;
1817 }
1818 return ret_value;
1819}
1820
1821// If this latitude or longitude units follows the CF
1822bool File::has_latlon_cf_units(Attribute *attr, const string &varfullpath, bool is_lat)
1823{
1824 string attr_name = "units";
1825 if (true == is_lat) {
1826 string lat_unit_value = "degrees_north";
1827 return Is_Str_Attr(attr, varfullpath, attr_name, lat_unit_value);
1828 }
1829 else {
1830 string lon_unit_value = "degrees_east";
1831 return Is_Str_Attr(attr, varfullpath, attr_name, lon_unit_value);
1832 }
1833}
1834
1835// This function is mainly to add _FillValue.
1836void File::Add_One_Float_Attr(Attribute* attr, const string &attrname, float float_value) const
1837{
1838 attr->name = attrname;
1839 attr->newname = attr->name;
1840 attr->dtype = H5FLOAT32;
1841 attr->count = 1;
1842 attr->value.resize(sizeof(float));
1843 memcpy(&(attr->value[0]), (void*) (&float_value), sizeof(float));
1844}
1845
1846// Products like GPM use string type for MissingValue, we need to change them to the corresponding variable datatype and
1847// get the value corrected.
1848void File::Change_Attr_One_Str_to_Others(Attribute* attr, const Var*var) const
1849{
1850
1851 char *pEnd;
1852 // string to long int number.
1853 long int num_sli = 0;
1854 if (attr->dtype != H5FSTRING)
1855 throw2("Currently we only convert fixed-size string to other datatypes. ", attr->name);
1856 if (attr->count != 1)
1857 throw4("The fixed-size string count must be 1 and the current count is ", attr->count, " for the attribute ",
1858 attr->name);
1859
1860 Retrieve_H5_Attr_Value(attr, var->fullpath);
1861 string attr_value;
1862 attr_value.resize(attr->value.size());
1863 copy(attr->value.begin(), attr->value.end(), attr_value.begin());
1864
1865 switch (var->dtype) {
1866
1867 case H5UCHAR: {
1868 num_sli = strtol(&(attr->value[0]), &pEnd, 10);
1869 if (num_sli < 0 || num_sli > UCHAR_MAX)
1870 throw5("Attribute type is unsigned char, the current attribute ", attr->name, " has the value ", num_sli,
1871 ". It is overflowed. ");
1872 else {
1873 auto num_suc = (unsigned char) num_sli;
1874 attr->dtype = H5UCHAR;
1875 attr->value.resize(sizeof(unsigned char));
1876 memcpy(&(attr->value[0]), (void*) (&num_suc), sizeof(unsigned char));
1877 }
1878
1879 }
1880 break;
1881 case H5CHAR: {
1882 num_sli = strtol(&(attr->value[0]), &pEnd, 10);
1883 if (num_sli < SCHAR_MIN || num_sli > SCHAR_MAX)
1884 throw5("Attribute type is signed char, the current attribute ", attr->name, " has the value ", num_sli,
1885 ". It is overflowed. ");
1886 else {
1887 auto num_sc = (char) num_sli;
1888 attr->dtype = H5CHAR;
1889 attr->value.resize(sizeof(char));
1890 memcpy(&(attr->value[0]), (void*) (&num_sc), sizeof(char));
1891 }
1892
1893 }
1894 break;
1895 case H5INT16: {
1896 num_sli = strtol(&(attr->value[0]), &pEnd, 10);
1897 if (num_sli < SHRT_MIN || num_sli > SHRT_MAX)
1898 throw5("Attribute type is 16-bit integer, the current attribute ", attr->name, " has the value ", num_sli,
1899 ". It is overflowed. ");
1900 else {
1901 auto num_ss = (short) num_sli;
1902 attr->dtype = H5INT16;
1903 attr->value.resize(sizeof(short));
1904 memcpy(&(attr->value[0]), (void*) (&num_ss), sizeof(short));
1905 }
1906
1907 }
1908 break;
1909 case H5UINT16: {
1910 num_sli = strtol(&(attr->value[0]), &pEnd, 10);
1911 if (num_sli < 0 || num_sli > USHRT_MAX)
1912 throw5("Attribute type is unsigned 16-bit integer, the current attribute ", attr->name, " has the value ",
1913 num_sli, ". It is overflowed. ");
1914 else {
1915 auto num_uss = (unsigned short) num_sli;
1916 attr->dtype = H5UINT16;
1917 attr->value.resize(sizeof(unsigned short));
1918 memcpy(&(attr->value[0]), (void*) (&num_uss), sizeof(unsigned short));
1919 }
1920 }
1921 break;
1922 case H5INT32: {
1923 num_sli = strtol(&(attr->value[0]), &pEnd, 10);
1924 //No need to check overflow, the number will always be in the range.
1925#if 0
1926 //if(num_sli <LONG_MIN || num_sli >LONG_MAX)
1927 // throw5("Attribute type is 32-bit integer, the current attribute ",attr->name, " has the value ",num_sli, ". It is overflowed. ");
1928#endif
1929 attr->dtype = H5INT32;
1930 attr->value.resize(sizeof(long int));
1931 memcpy(&(attr->value[0]), (void*) (&num_sli), sizeof(long int));
1932
1933 }
1934 break;
1935 case H5UINT32: {
1936 unsigned long int num_suli = strtoul(&(attr->value[0]), &pEnd, 10);
1937 // No need to check since num_suli will not be bigger than ULONG_MAX.
1938 attr->dtype = H5UINT32;
1939 attr->value.resize(sizeof(unsigned long int));
1940 memcpy(&(attr->value[0]), (void*) (&num_suli), sizeof(unsigned long int));
1941 }
1942 break;
1943 case H5FLOAT32: {
1944 float num_sf = strtof(&(attr->value[0]), nullptr);
1945 // Don't think it is necessary to check if floating-point is overflowed for this routine. ignore it now. KY 2014-09-22
1946 attr->dtype = H5FLOAT32;
1947 attr->value.resize(sizeof(float));
1948 memcpy(&(attr->value[0]), (void*) (&num_sf), sizeof(float));
1949 }
1950 break;
1951 case H5FLOAT64: {
1952 double num_sd = strtod(&(attr->value[0]), nullptr);
1953 // Don't think it is necessary to check if floating-point is overflowed for this routine. ignore it now. KY 2014-09-22
1954 attr->dtype = H5FLOAT64;
1955 attr->value.resize(sizeof(double));
1956 memcpy(&(attr->value[0]), (void*) (&num_sd), sizeof(double));
1957 }
1958 break;
1959
1960 default:
1961 throw4("Unsupported HDF5 datatype that the string is converted to for the attribute ", attr->name,
1962 " of the variable ", var->fullpath);
1963 } // "switch(var->dtype)"
1964
1965}
1966
1967// Change a string type attribute to the input value
1968void File::Replace_Var_Str_Attr(Var* var, const string &attr_name, const string& strvalue)
1969{
1970
1971 bool rep_attr = true;
1972 bool rem_attr = false;
1973 for (auto &attr:var->attrs) {
1974 if (attr->name == attr_name) {
1975 if (true == Is_Str_Attr(attr, var->fullpath, attr_name, strvalue))
1976 rep_attr = false;
1977 else
1978 rem_attr = true;
1979 break;
1980 }
1981 }
1982
1983 // Remove the attribute if the attribute value is not strvalue
1984 if (true == rem_attr) {
1985 for (auto ira = var->attrs.begin(); ira != var->attrs.end(); ira++) {
1986 if ((*ira)->name == attr_name) {
1987 delete (*ira);
1988 var->attrs.erase(ira);
1989 break;
1990 }
1991 }
1992 }
1993
1994 // Add the attribute with strvalue
1995 if (true == rep_attr) {
1996 auto attr_unique = make_unique<Attribute>();
1997 auto attr = attr_unique.release();
1998 Add_Str_Attr(attr, attr_name, strvalue);
1999 var->attrs.push_back(attr);
2000 }
2001}
2002
2003// Check if this variable is latitude,longitude.We check the three name pairs(lat,lon),(latitude,longitude),(Latitude,Longitude)
2004bool File::Is_geolatlon(const string & var_name, bool is_lat) const
2005{
2006
2007 bool ret_value = false;
2008 if (true == is_lat) {
2009 string lat1 = "lat";
2010 string lat2 = "latitude";
2011 string lat3 = "Latitude";
2012
2013 if (var_name.compare(lat1) == 0 || var_name.compare(lat2) == 0 || var_name.compare(lat3) == 0) ret_value = true;
2014 }
2015
2016 else {
2017 string lon1 = "lon";
2018 string lon2 = "longitude";
2019 string lon3 = "Longitude";
2020 if (var_name.compare(lon1) == 0 || var_name.compare(lon2) == 0 || var_name.compare(lon3) == 0) ret_value = true;
2021
2022 }
2023 return ret_value;
2024}
2025
2026// Add supplementary attributes.
2027void File::Add_Supplement_Attrs(bool add_path)
2028{
2029
2030 if (false == add_path) return;
2031
2032 // Adding variable original name(origname) and full path(fullpath)
2033 for (auto &var:this->vars) {
2034 auto attr_unique = make_unique<Attribute>();
2035 auto attr = attr_unique.release();
2036 const string varname = var->name;
2037 const string attrname = "origname";
2038 Add_Str_Attr(attr, attrname, varname);
2039 var->attrs.push_back(attr);
2040 }
2041
2042 for (auto &var:this->vars) {
2043 // Turn off the fullnamepath attribute when zero_storage_size is 0.
2044 // Use the BES key since quite a few testing cases will be affected.
2045 // KY 2020-03-23
2046 if (var->zero_storage_size==false
2047 || HDF5RequestHandler::get_no_zero_size_fullnameattr() == false) {
2048 auto attr_unique = make_unique<Attribute>();
2049 auto attr = attr_unique.release();
2050 const string varname = var->fullpath;
2051 const string attrname = "fullnamepath";
2052 Add_Str_Attr(attr, attrname, varname);
2053 var->attrs.push_back(attr);
2054 }
2055 }
2056
2057 // Adding group path
2058 for (const auto &grp:this->groups) {
2059 // Only when this group has attributes, the original path of the group has some values. So add it.
2060 if (false == grp->attrs.empty()) {
2061
2062 const string varname = grp->path;
2063 const string attrname = "fullnamepath";
2064 auto attr_unique = make_unique<Attribute>();
2065 auto attr = attr_unique.release();
2066 Add_Str_Attr(attr, attrname, varname);
2067 grp->attrs.push_back(attr);
2068 }
2069 }
2070}
2071
2072// Variable target will not be deleted, but rather its contents are replaced.
2073// We may make this as an operator = in the future.
2074// Note: the attributes can not be replaced.
2075void File::Replace_Var_Info(const Var *src, Var *target)
2076{
2077
2078#if 0
2079 for_each (target->dims.begin (), target->dims.end (),
2080 delete_elem ());
2081 for_each (target->attrs.begin (), target->attrs.end (),
2082 delete_elem ());
2083#endif
2084
2085 target->newname = src->newname;
2086 target->name = src->name;
2087 target->fullpath = src->fullpath;
2088 target->rank = src->rank;
2089 target->dtype = src->dtype;
2090 target->unsupported_attr_dtype = src->unsupported_attr_dtype;
2091 target->unsupported_dspace = src->unsupported_dspace;
2092#if 0
2093 for (auto ira = target->attrs.begin();
2094 ira!=target->attrs.end(); ++ira) {
2095 delete (*ira);
2096 target->attrs.erase(ira);
2097 ira--;
2098 }
2099#endif
2100 for (auto ird = target->dims.begin(); ird != target->dims.end();) {
2101 delete (*ird);
2102 ird = target->dims.erase(ird);
2103 }
2104
2105 // Somehow attributes cannot be replaced.
2106#if 0
2107 for (vector<Attribute*>::iterator ira = src->attrs.begin();
2108 ira!=src->attrs.end(); ++ira) {
2109 Attribute* attr= new Attribute();
2110 attr->name = (*ira)->name;
2111 attr->newname = (*ira)->newname;
2112 attr->dtype =(*ira)->dtype;
2113 attr->count =(*ira)->count;
2114 attr->strsize = (*ira)->strsize;
2115 attr->fstrsize = (*ira)->fstrsize;
2116 attr->value =(*ira)->value;
2117 target->attrs.push_back(attr);
2118 }
2119#endif
2120
2121 for (const auto& sdim:src->dims) {
2122 auto dim_unique = make_unique<Dimension>(sdim->size);
2123 auto dim = dim_unique.release();
2124 dim->name = sdim->name;
2125 dim->newname = sdim->newname;
2126 target->dims.push_back(dim);
2127 }
2128
2129}
2130
2131// Replace the attributes of target with src.
2132void File::Replace_Var_Attrs(const Var *src, Var *target)
2133{
2134
2135#if 0
2136 for_each (target->dims.begin (), target->dims.end (),
2137 delete_elem ());
2138 for_each (target->attrs.begin (), target->attrs.end (),
2139 delete_elem ());
2140#endif
2141
2142 for (auto ira = target->attrs.begin(); ira != target->attrs.end();) {
2143 delete (*ira);
2144 ira = target->attrs.erase(ira);
2145 }
2146 for (const auto &sattr:src->attrs) {
2147 auto attr_unique = make_unique<Attribute>();
2148 auto attr = attr_unique.release();
2149 attr->name = sattr->name;
2150 attr->newname = sattr->newname;
2151 attr->dtype = sattr->dtype;
2152 attr->count = sattr->count;
2153 attr->strsize = sattr->strsize;
2154 attr->fstrsize = sattr->fstrsize;
2155 attr->value = sattr->value;
2156 target->attrs.push_back(attr);
2157 }
2158
2159}
2160
2161// Check if a variable with a var name is under a specific group with group name
2162// note: the variable's size at each dimension is also returned. The user must allocate the
2163// memory for the dimension sizes of an array(vector is preferred).
2164bool File::is_var_under_group(const string &varname, const string &grpname, const int var_rank,
2165 vector<size_t> & var_size) const
2166{
2167
2168 bool ret_value = false;
2169 for (const auto &var:this->vars) {
2170
2171 if (var->rank == var_rank) {
2172 if (var->name == varname) {
2173
2174 // Obtain the variable path
2175 string var_path = HDF5CFUtil::obtain_string_before_lastslash(var->fullpath);
2176
2177 // Check if we find the variable under this group
2178 if (grpname == var_path) {
2179 ret_value = true;
2180 for (int i = 0; i < var_rank; i++)
2181 var_size[i] = var->getDimensions()[i]->size;
2182 break;
2183 }
2184 }
2185 }
2186 }
2187
2188 return ret_value;
2189}
2190
2192
2193 bool ret_value = false;
2194 for (const auto& var:this->vars) {
2195 for (const auto& attr:var->attrs) {
2196 if(attr->name =="grid_mapping") {
2197 ret_value = true;
2198 break;
2199 }
2200 }
2201 if(true == ret_value)
2202 break;
2203 }
2204
2205 return ret_value;
2206}
2207
2209
2210 for (auto &var:this->vars) {
2211 string attr_value;
2212 for (auto ira = var->attrs.begin(); ira != var->attrs.end(); ++ira) {
2213 if((*ira)->name =="grid_mapping") {
2214 Retrieve_H5_Attr_Value(*ira, var->fullpath);
2215 attr_value.resize((*ira)->value.size());
2216 copy((*ira)->value.begin(), (*ira)->value.end(), attr_value.begin());
2217 break;
2218 }
2219
2220 }
2221 if(attr_value.find('/') ==string::npos){
2222 string new_name = Check_Grid_Mapping_VarName(attr_value,var->fullpath);
2223 if(new_name != "")
2224 Replace_Var_Str_Attr(var,"grid_mapping",new_name);
2225
2226 }
2227 else {
2228 string new_name = Check_Grid_Mapping_FullPath(attr_value);
2229 //Using new_name as the attribute value
2230 if(new_name != "")
2231 Replace_Var_Str_Attr(var,"grid_mapping",new_name);
2232 }
2233 }
2234
2235}
2236
2237string File::Check_Grid_Mapping_VarName(const string & a_value,const string & var_fpath) const {
2238
2239 string var_path = HDF5CFUtil::obtain_string_before_lastslash(var_fpath);
2240 string gmap_new_name;
2241 for (const auto &var:this->vars) {
2242 if(var->name == a_value){
2243 if(var_path == HDF5CFUtil::obtain_string_before_lastslash(var->fullpath)) {
2244 gmap_new_name = var->newname;
2245 break;
2246 }
2247 }
2248 }
2249 return gmap_new_name;
2250}
2251
2252
2253string File::Check_Grid_Mapping_FullPath(const string & a_value) const {
2254
2255 string gmap_new_name;
2256 for (const auto &var:this->vars) {
2257 if(var->fullpath == a_value){
2258 gmap_new_name = var->newname;
2259 break;
2260 }
2261 }
2262
2263 return gmap_new_name;
2264}
2265
2266void File::remove_netCDF_internal_attributes(bool include_attr) {
2267
2268 if(true == include_attr) {
2269
2270 for (const auto &var:this->vars) {
2271
2272 bool var_has_dimscale = false;
2273
2274 for (auto ira = var->attrs.begin(); ira != var->attrs.end();) {
2275 if((*ira)->name == "CLASS") {
2276 string class_value = Retrieve_Str_Attr_Value(*ira,var->fullpath);
2277
2278 // Compare the attribute "CLASS" value with "DIMENSION_SCALE". We only compare the string with the size of
2279 // "DIMENSION_SCALE", which is 15.
2280 if (0 == class_value.compare(0,15,"DIMENSION_SCALE")) {
2281 delete(*ira);
2282 ira = var->attrs.erase(ira);
2283 var_has_dimscale = true;
2284
2285 }
2286#if 0
2287 else if(1) {// Add a BES key,also delete
2288
2289 }
2290#endif
2291 else {
2292 ++ira;
2293 }
2294 }
2295#if 0
2296 else if((*ira)->name == "NAME") {// Add a BES Key
2297 string name_value = Retrieve_Str_Attr_Value(*ira,var->fullpath);
2298 if( 0 == name_value.compare(0,var->name.size(),var->name)) {
2299 delete(*ira);
2300 ira =var->attrs.erase(ira);
2301 }
2302 else {
2303 string netcdf_dim_mark= "This is a netCDF dimension but not a netCDF variable";
2304 if( 0 == name_value.compare(0,netcdf_dim_mark.size(),netcdf_dim_mark)) {
2305 delete(*ira);
2306 ira =var->attrs.erase(ira);
2307 }
2308 else {
2309 ++ira;
2310 }
2311 }
2312
2313 }
2314#endif
2315 else if((*ira)->name == "_Netcdf4Dimid") {
2316 delete(*ira);
2317 ira =var->attrs.erase(ira);
2318 }
2319 else if((*ira)->name == "_Netcdf4Coordinates") {
2320 delete(*ira);
2321 ira =var->attrs.erase(ira);
2322 }
2323#if 0
2324 else if((*ira)->name == "_nc3_strict") {
2325 delete((*ira));
2326 ira =var->attrs.erase(ira);
2327 }
2328#endif
2329 else {
2330 ++ira;
2331 }
2332 }
2333
2334 if(true == var_has_dimscale) {
2335 for(auto ira = var->attrs.begin();
2336 ira != var->attrs.end();++ira) {
2337 if((*ira)->name == "NAME") {// Add a BES Key
2338 delete(*ira);
2339 ira =var->attrs.erase(ira);
2340 break;
2341 }
2342 }
2343 }
2344 }
2345 }
2346
2347}
2348// Add ignored page header info. Mainly a helper message.
2349void File::add_ignored_info_page_header()
2350{
2351 ignored_msg =
2352 " \n This page is for HDF5 CF hyrax data providers or distributors to check if any HDF5 object or attribute information are ignored during the mapping. \n\n";
2353}
2354
2355// Add ignored object header info. Mainly a helper message.
2356void File::add_ignored_info_obj_header()
2357{
2358
2359 ignored_msg += " Some HDF5 objects or the object information are ignored when mapping to DAP2 by the HDF5 OPeNDAP";
2360 ignored_msg += " handler due to the restrictions of DAP2, CF conventions or CF tools.";
2361 ignored_msg += " Please use HDF5 tools(h5dump or HDFView) to check carefully and make sure that these objects";
2362 ignored_msg +=
2363 " are OK to ignore for your service. For questions or requests to find a way to handle the ignored objects, please";
2364 ignored_msg += " contact the HDF5 OPeNDAP handler developer or send an email to help@hdfgroup.org.\n";
2365
2366 ignored_msg += " \n In general, ignored HDF5 objects include HDF5 soft links, external links and named datatype.\n";
2367 ignored_msg +=
2368 " \n The HDF5 datasets(variables in the CF term) and attributes that have the following datatypes are ignored: \n";
2369 ignored_msg +=
2370 " Signed and unsigned 64-bit integers, HDF5 compound, HDF5 variable size(excluding variable length string),";
2371 ignored_msg += " HDF5 reference, HDF5 enum, HDF5 opaque , HDF5 bitfield, HDF5 Array and HDF5 Time datatypes.\n";
2372
2373 ignored_msg +=
2374 " \n The HDF5 datasets(variables in the CF term) and attributes associated with the following dimensions are ignored: \n";
2375 ignored_msg += " 1) variables that have HDF5 NULL dataspace(H5S_NULL)(rarely occurred)\n";
2376 ignored_msg += " 2) attributes that have any zero size dimensions(not reported due to extreme rarity and non-trivial coding)\n\n";
2377
2378}
2379
2380// Add the ignored links information.Mainly a helper message.
2381void File::add_ignored_info_links_header()
2382{
2383
2384 if (false == this->have_ignored) {
2385 add_ignored_info_obj_header();
2386 have_ignored = true;
2387 }
2388 // Add ignored datatype header.
2389 string lh_msg = "******WARNING******\n";
2390 lh_msg += "IGNORED soft links or external links are: ";
2391 if (ignored_msg.rfind(lh_msg) == string::npos) ignored_msg += lh_msg + "\n";
2392
2393}
2394
2395// Leave the code for the time being.
2396#if 0
2397void
2398File:: add_ignored_info_obj_dtype_header() {
2399
2400 // Add ignored datatype header.
2401 ignored_msg += " \n Variables and attributes ignored due to the unsupported datatypes. \n";
2402 ignored_msg += " In general, the unsupported datatypes include: \n";
2403 ignored_msg += " Signed and unsigned 64-bit integers, HDF5 compound, HDF5 variable size(excluding variable length string),";
2404 ignored_msg += " HDF5 reference, HDF5 enum, HDF5 opaque , HDF5 bitfield, HDF5 Array and HDF5 Time datatypes.\n";
2405
2406}
2407
2408void
2409File:: add_ignored_info_obj_dspace_header() {
2410
2411 // Add ignored dataspace header.
2412 ignored_msg += " \n Variables and attributes ignored due to the unsupported dimensions. \n";
2413 ignored_msg += " In general, the unsupported dimensions include: \n";
2414 ignored_msg += " 1) variables that have HDF5 NULL dataspace(H5S_NULL)(rarely occurred)\n";
2415 ignored_msg += " 2) variables that have any zero size dimensions\n";
2416
2417}
2418#endif
2419
2420// Add the ignored link info.
2421void File::add_ignored_info_links(const string & link_path)
2422{
2423 if (ignored_msg.find("Link paths: ") == string::npos)
2424 ignored_msg += " Link paths: " + link_path;
2425 else
2426 ignored_msg += " " + link_path;
2427}
2428
2429// Add the ignored name datatype info.
2430void File::add_ignored_info_namedtypes(const string& grp_name, const string& named_dtype_name)
2431{
2432
2433 if (false == this->have_ignored) {
2434 add_ignored_info_obj_header();
2435 have_ignored = true;
2436 }
2437
2438 string ignored_HDF5_named_dtype_hdr = "\n******WARNING******";
2439 ignored_HDF5_named_dtype_hdr += "\n IGNORED HDF5 named datatype objects:\n";
2440 string ignored_HDF5_named_dtype_msg = " Group name: " + grp_name + " HDF5 named datatype name: " + named_dtype_name.substr(0,named_dtype_name.size()-1)
2441 + "\n";
2442 if (ignored_msg.find(ignored_HDF5_named_dtype_hdr) == string::npos)
2443 ignored_msg += ignored_HDF5_named_dtype_hdr + ignored_HDF5_named_dtype_msg;
2444 else
2445 ignored_msg += ignored_HDF5_named_dtype_msg;
2446
2447}
2448
2449// Add the ignored attribute information. When is_grp is true, the ignored group attribute names are added.
2450// Otherwise, the ignored dataset attribute names are added.
2451void File::add_ignored_info_attrs(bool is_grp, const string & obj_path, const string & attr_name)
2452{
2453
2454 if (false == this->have_ignored) {
2455 add_ignored_info_obj_header();
2456 have_ignored = true;
2457 }
2458
2459
2460 string ignored_warning_str = "\n******WARNING******";
2461 string ignored_HDF5_grp_hdr = ignored_warning_str + "\n Ignored attributes under root and groups:\n";
2462 string ignored_HDF5_grp_msg = " Group path: " + obj_path + " Attribute names: " + attr_name + "\n";
2463 string ignored_HDF5_var_hdr = ignored_warning_str + "\n Ignored attributes for variables:\n";
2464 string ignored_HDF5_var_msg = " Variable path: " + obj_path + " Attribute names: " + attr_name + "\n";
2465
2466
2467 if (true == is_grp) {
2468 if (ignored_msg.find(ignored_HDF5_grp_hdr) == string::npos)
2469 ignored_msg += ignored_HDF5_grp_hdr + ignored_HDF5_grp_msg;
2470 else
2471 ignored_msg += ignored_HDF5_grp_msg;
2472 }
2473 else {
2474 if (ignored_msg.find(ignored_HDF5_var_hdr) == string::npos)
2475 ignored_msg += ignored_HDF5_var_hdr + ignored_HDF5_var_msg;
2476 else
2477 ignored_msg += ignored_HDF5_var_msg;
2478 }
2479
2480}
2481
2482//Ignored object information. When is_dim_related is true, ignored data space info. is present.
2483//When is_dim_related is false, ignored data type info. is present.
2484void File::add_ignored_info_objs(bool is_dim_related, const string & obj_path)
2485{
2486
2487 if (false == this->have_ignored) {
2488 add_ignored_info_obj_header();
2489 have_ignored = true;
2490 }
2491
2492 string ignored_warning_str = "\n******WARNING******";
2493 string ignored_HDF5_dtype_var_hdr = ignored_warning_str + "\n IGNORED variables due to unsupported datatypes:\n";
2494 string ignored_HDF5_dspace_var_hdr = ignored_warning_str + "\n IGNORED variables due to unsupported dimensions:\n";
2495 string ignored_HDF5_var_msg = " Variable path: " + obj_path + "\n";
2496
2497 if (true == is_dim_related) {
2498 if (ignored_msg.find(ignored_HDF5_dspace_var_hdr) == string::npos)
2499 ignored_msg += ignored_HDF5_dspace_var_hdr + ignored_HDF5_var_msg;
2500 else
2501 ignored_msg += ignored_HDF5_var_msg;
2502
2503 }
2504 else {
2505 if (ignored_msg.find(ignored_HDF5_dtype_var_hdr) == string::npos)
2506 ignored_msg += ignored_HDF5_dtype_var_hdr + ignored_HDF5_var_msg;
2507 else
2508 ignored_msg += ignored_HDF5_var_msg;
2509 }
2510
2511}
2512
2513// No ignored info.
2514void File::add_no_ignored_info()
2515{
2516
2517 ignored_msg += "There are no ignored HDF5 objects or attributes.";
2518
2519}
2520
2521// This function should only be used when the HDF5 file is following the netCDF data model.
2522// Check if we should not report the Dimension scale related attributes as ignored.
2523bool File::ignored_dimscale_ref_list(const Var *var) const
2524{
2525
2526 bool ignored_dimscale = true;
2527 // Only when "General_Product == this->product_type && GENERAL_DIMSCALE== this->gproduct_pattern)"
2528
2529 bool has_dimscale = false;
2530 bool has_reference_list = false;
2531 for (const auto &attr:var->attrs) {
2532 if (attr->name == "REFERENCE_LIST" && false == HDF5CFUtil::cf_strict_support_type(attr->getType(),_is_dap4))
2533 has_reference_list = true;
2534 if (attr->name == "CLASS") {
2535 Retrieve_H5_Attr_Value(attr, var->fullpath);
2536 string class_value;
2537 class_value.resize(attr->value.size());
2538 copy(attr->value.begin(), attr->value.end(), class_value.begin());
2539
2540 // Compare the attribute "CLASS" value with "DIMENSION_SCALE". We only compare the string with the size of
2541 // "DIMENSION_SCALE", which is 15.
2542 if (0 == class_value.compare(0, 15, "DIMENSION_SCALE")) {
2543 has_dimscale = true;
2544 }
2545 }
2546
2547 if (true == has_dimscale && true == has_reference_list) {
2548 ignored_dimscale = false;
2549 break;
2550 }
2551
2552 }
2553 return ignored_dimscale;
2554}
2555
2556// Check if the long string can should be dropped from a dataset or an attribute. Users can set up a BES key to turn it off or on.
2557bool File::Check_DropLongStr(const Var *var, const Attribute * attr)
2558{
2559
2560 bool drop_longstr = false;
2561 if (nullptr == attr) {
2562 if (H5FSTRING == var->dtype || H5VSTRING == var->dtype) {
2563 try {
2564 drop_longstr = Check_VarDropLongStr(var->fullpath, var->dims, var->dtype);
2565 }
2566 catch (...) {
2567 throw1("Check_VarDropLongStr fails ");
2568 }
2569 }
2570 }
2571 // No limitation for the attributes. KY 2018-02-26
2572#if 0
2573 else {
2574 if (H5FSTRING == attr->dtype || H5VSTRING == attr->dtype) {
2575 if (attr->getBufSize() > NC_JAVA_STR_SIZE_LIMIT) {
2576 drop_longstr = true;
2577 }
2578 }
2579
2580 }
2581#endif
2582 return drop_longstr;
2583}
2584
2585// Check if a long string dataset should be dropped. Users can turn on a BES key not to drop the long string.
2586// However, the Java clients may not access.
2587//
2588bool File::Check_VarDropLongStr(const string & varpath, const vector<Dimension *>& dims, H5DataType dtype) const
2589
2590{
2591
2592 bool drop_longstr = false;
2593
2594 hid_t dset_id = H5Dopen2(this->fileid, varpath.c_str(), H5P_DEFAULT);
2595 if (dset_id < 0)
2596 throw2("Cannot open the dataset ", varpath);
2597
2598 hid_t dtype_id = -1;
2599 if ((dtype_id = H5Dget_type(dset_id)) < 0) {
2600 H5Dclose(dset_id);
2601 throw2("Cannot obtain the datatype of the dataset ", varpath);
2602 }
2603
2604 size_t ty_size = H5Tget_size(dtype_id);
2605 if (ty_size == 0) {
2606 H5Tclose(dtype_id);
2607 H5Dclose(dset_id);
2608 throw2("Cannot obtain the datatype size of the dataset ", varpath);
2609 }
2610
2611 if (H5FSTRING == dtype) { // Fixed-size, just check the number of elements.
2612 if (ty_size > NC_JAVA_STR_SIZE_LIMIT) drop_longstr = true;
2613 }
2614 else if (H5VSTRING == dtype) {
2615
2616 unsigned long long total_elms = 1;
2617 if (dims.empty() == false) {
2618 for (const auto &dim:dims)
2619 total_elms = total_elms * (dim->size);
2620 }
2621 vector<char> strval;
2622 strval.resize(total_elms * ty_size);
2623 hid_t read_ret = H5Dread(dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void*) strval.data());
2624 if (read_ret < 0) {
2625 H5Tclose(dtype_id);
2626 H5Dclose(dset_id);
2627 throw2("Cannot read the data of the dataset ", varpath);
2628 }
2629
2630 vector<string> finstrval;
2631 finstrval.resize(total_elms);
2632 char*temp_bp = strval.data();
2633 char*onestring = nullptr;
2634 for (unsigned long long i = 0; i < total_elms; i++) {
2635 onestring = *(char**) temp_bp;
2636 if (onestring != nullptr) {
2637 finstrval[i] = string(onestring);
2638 if(finstrval[i].size()>NC_JAVA_STR_SIZE_LIMIT) {
2639 drop_longstr = true;
2640 break;
2641 }
2642 }
2643 temp_bp += ty_size;
2644 }
2645
2646 if (false == strval.empty()) {
2647 herr_t ret_vlen_claim;
2648 hid_t dspace_id = H5Dget_space(dset_id);
2649 if (dspace_id < 0) {
2650 H5Tclose(dtype_id);
2651 H5Dclose(dset_id);
2652 throw2("Cannot obtain the dataspace id.", varpath);
2653 }
2654 ret_vlen_claim = H5Dvlen_reclaim(dtype_id, dspace_id, H5P_DEFAULT, (void*) strval.data());
2655 if (ret_vlen_claim < 0) {
2656 H5Tclose(dtype_id);
2657 H5Sclose(dspace_id);
2658 H5Dclose(dset_id);
2659 throw2("Cannot reclaim the vlen space ", varpath);
2660 }
2661 if (H5Sclose(dspace_id) < 0) {
2662 H5Tclose(dtype_id);
2663 H5Dclose(dset_id);
2664 throw2("Cannot close the HDF5 data space.", varpath);
2665 }
2666 }
2667 }
2668 if (H5Tclose(dtype_id) < 0) {
2669 H5Dclose(dset_id);
2670 throw2("Cannot close the HDF5 data type.", varpath);
2671 }
2672 if (H5Dclose(dset_id) < 0)
2673 throw2("Cannot close the HDF5 data type.", varpath);
2674
2675 return drop_longstr;
2676}
2677#if 0
2678bool File::Check_VarDropLongStr(const string & varpath, const vector<Dimension *>& dims, H5DataType dtype)
2679
2680{
2681
2682 bool drop_longstr = false;
2683
2684 unsigned long long total_elms = 1;
2685 if (dims.size() != 0) {
2686 for (unsigned int i = 0; i < dims.size(); i++)
2687 total_elms = total_elms * ((dims[i])->size);
2688 }
2689
2690 if (total_elms > NC_JAVA_STR_SIZE_LIMIT)
2691 drop_longstr = true;
2692
2693 else { // We need to check both fixed-size and variable-length strings.
2694
2695 hid_t dset_id = H5Dopen2(this->fileid, varpath.c_str(), H5P_DEFAULT);
2696 if (dset_id < 0)
2697 throw2("Cannot open the dataset ", varpath);
2698
2699 hid_t dtype_id = -1;
2700 if ((dtype_id = H5Dget_type(dset_id)) < 0) {
2701 H5Dclose(dset_id);
2702 throw2("Cannot obtain the datatype of the dataset ", varpath);
2703 }
2704
2705 size_t ty_size = H5Tget_size(dtype_id);
2706 if (ty_size == 0) {
2707 H5Tclose(dtype_id);
2708 H5Dclose(dset_id);
2709 throw2("Cannot obtain the datatype size of the dataset ", varpath);
2710 }
2711
2712 if (H5FSTRING == dtype) { // Fixed-size, just check the number of elements.
2713 if ((ty_size * total_elms) > NC_JAVA_STR_SIZE_LIMIT) drop_longstr = true;
2714 }
2715 else if (H5VSTRING == dtype) {
2716
2717 vector<char> strval;
2718 strval.resize(total_elms * ty_size);
2719 hid_t read_ret = H5Dread(dset_id, dtype_id, H5S_ALL, H5S_ALL, H5P_DEFAULT, (void*) strval.data());
2720 if (read_ret < 0) {
2721 H5Tclose(dtype_id);
2722 H5Dclose(dset_id);
2723 throw2("Cannot read the data of the dataset ", varpath);
2724 }
2725
2726 vector<string> finstrval;
2727 finstrval.resize(total_elms);
2728 char*temp_bp = strval.data();
2729 char*onestring = nullptr;
2730 for (unsigned long long i = 0; i < total_elms; i++) {
2731 onestring = *(char**) temp_bp;
2732 if (onestring != nullptr)
2733 finstrval[i] = string(onestring);
2734 else
2735 // We will add a NULL if onestring is NULL.
2736 finstrval[i] = "";
2737 temp_bp += ty_size;
2738 }
2739
2740 if (false == strval.empty()) {
2741 herr_t ret_vlen_claim;
2742 hid_t dspace_id = H5Dget_space(dset_id);
2743 if (dspace_id < 0) {
2744 H5Tclose(dtype_id);
2745 H5Dclose(dset_id);
2746 throw2("Cannot obtain the dataspace id.", varpath);
2747 }
2748 ret_vlen_claim = H5Dvlen_reclaim(dtype_id, dspace_id, H5P_DEFAULT, (void*) strval.data());
2749 if (ret_vlen_claim < 0) {
2750 H5Tclose(dtype_id);
2751 H5Sclose(dspace_id);
2752 H5Dclose(dset_id);
2753 throw2("Cannot reclaim the vlen space ", varpath);
2754 }
2755 if (H5Sclose(dspace_id) < 0) {
2756 H5Tclose(dtype_id);
2757 H5Dclose(dset_id);
2758 throw2("Cannot close the HDF5 data space.", varpath);
2759 }
2760 }
2761 unsigned long long total_str_size = 0;
2762 for (unsigned long long i = 0; i < total_elms; i++) {
2763 total_str_size += finstrval[i].size();
2764 if (total_str_size > NC_JAVA_STR_SIZE_LIMIT) {
2765 drop_longstr = true;
2766 break;
2767 }
2768 }
2769 }
2770 if (H5Tclose(dtype_id) < 0) {
2771 H5Dclose(dset_id);
2772 throw2("Cannot close the HDF5 data type.", varpath);
2773 }
2774 if (H5Dclose(dset_id) < 0)
2775 throw2("Cannot close the HDF5 data type.", varpath);
2776 }
2777 return drop_longstr;
2778}
2779#endif
2780
2781
2782// Provide if the long string is dropped.
2783void File::add_ignored_grp_longstr_info(const string& grp_path, const string & attr_name)
2784{
2785 ignored_msg += "The HDF5 group: " + grp_path + " has an empty-set string attribute: " + attr_name + "\n";
2786
2787}
2788
2789// Provide if the long variable string is dropped.
2790void File::add_ignored_var_longstr_info(const Var *var, const Attribute *attr)
2791{
2792
2793 if (nullptr == attr)
2794 ignored_msg += "String variable: " + var->fullpath + " value is set to empty.\n";
2795 else {
2796 ignored_msg += "The variable: " + var->fullpath + " has an empty-set string attribute: " + attr->name + "\n";
2797
2798 }
2799
2800}
2801
2802// The warnings of the drop of the long string header
2803void File::add_ignored_droplongstr_hdr()
2804{
2805
2806 if (false == this->have_ignored) this->have_ignored = true;
2807 string hdr = "\n\n The values of the following string variables ";
2808 hdr += " are set to empty because at least one string size in this variable exceeds netCDF Java string limit(32767 bytes).\n";
2809 hdr += "To obtain the values, change the BES key H5.EnableDropLongString=true at the handler BES";
2810 hdr += " configuration file(h5.conf)\nto H5.EnableDropLongString=false.\n\n";
2811
2812 if (ignored_msg.rfind(hdr) == string::npos) ignored_msg += hdr;
2813
2814}
2815
2816// Sometimes, we need to release the temporary added resources.
2817void File::release_standalone_var_vector(vector<Var*>&temp_vars)
2818{
2819
2820 for (auto i = temp_vars.begin(); i != temp_vars.end();) {
2821 delete (*i);
2822 i = temp_vars.erase(i);
2823 }
2824
2825}
This class specifies the core engineering of mapping HDF5 to DAP by following CF.
include the entry functions to execute the handlers
This class represents one attribute.
Definition HDF5CF.h:185
This class repersents one dimension of an HDF5 dataset(variable).
Definition HDF5CF.h:142
std::vector< Group * > groups
Non-root group vectors.
Definition HDF5CF.h:791
virtual void Retrieve_H5_Var_Attr_Values(Var *var)
Retrieve attribute values for a variable.
Definition HDF5CF.cc:753
virtual void Handle_Unsupported_Dspace(bool)
Handle unsupported HDF5 dataspaces for datasets.
Definition HDF5CF.cc:1279
std::map< hsize_t, std::string > dimsize_to_fakedimname
Handle added dimension names.
Definition HDF5CF.h:808
virtual void Handle_Grid_Mapping_Vars()
Handle Grid Mapping Vars.
Definition HDF5CF.cc:2208
virtual void Handle_Unsupported_Others(bool)
Handle other unmapped objects/attributes.
Definition HDF5CF.cc:1326
virtual void Retrieve_H5_Supported_Attr_Values()
Retrieve attribute values for the supported HDF5 datatypes.
Definition HDF5CF.cc:735
std::vector< Var * > vars
Var vectors.
Definition HDF5CF.h:785
virtual void Add_Supplement_Attrs(bool)
Add supplemental attributes such as fullpath and original name.
Definition HDF5CF.cc:2027
virtual void Retrieve_H5_Info(const char *path, hid_t file_id, bool)
Definition HDF5CF.cc:170
std::vector< Attribute * > root_attrs
Root attribute vectors.
Definition HDF5CF.h:788
virtual void Handle_Unsupported_Dtype(bool)
Handle unsupported HDF5 datatypes.
Definition HDF5CF.cc:922
virtual void Flatten_Obj_Name(bool)
Flatten the object name.
Definition HDF5CF.cc:1376
virtual bool Have_Grid_Mapping_Attrs()
Check if having Grid Mapping Attrs.
Definition HDF5CF.cc:2191
This class represents an HDF5 group. The group will be flattened according to the CF conventions.
Definition HDF5CF.h:521
This class represents one HDF5 dataset(CF variable)
Definition HDF5CF.h:252
H5DataType getType() const
Get the data type of this variable(Not HDF5 datatype id)
Definition HDF5CF.h:300
const std::vector< Dimension * > & getDimensions() const
Get the list of the dimensions.
Definition HDF5CF.h:311
STL class.
STL class.
STL class.
STL iterator class.
STL class.
Helper functions for generating DAS attributes and a function to check BES Key.
static H5DataType H5type_to_H5DAPtype(hid_t h5_type_id)
Map HDF5 Datatype to the intermediate H5DAPtype for the future use.
Definition HDF5CFUtil.cc:53
static std::string trim_string(hid_t dtypeid, const std::string &s, int num_sect, size_t section_size, std::vector< size_t > &sect_newsize)