55#include <libdap/util.h>
56#include <libdap/escaping.h>
57#include <libdap/DAS.h>
61#include "NCRequestHandler.h"
64#define ATTR_STRING_QUOTE_FIX 1
65#define STOP_ESCAPING_STRING_ATTRS 0
68#define prolog std::string("ncdas::").append(__func__).append("() - ")
82static string print_attr(nc_type type,
int loc,
void *vals)
99 gp.cp = (
char *) vals;
106 if (NCRequestHandler::get_promote_byte_to_short()) {
108 gp.cp = (
char *) vals;
116 gp.cp = (
char *) vals;
124 return escattr(
static_cast<const char*
>(vals));
127 gp.stringp = (
char **) vals;
128 rep << *(gp.stringp + loc);
132 gp.sp = (
short *) vals;
133 rep << *(gp.sp + loc);
137 gp.usp = (uint16_t *) vals;
138 rep << *(gp.usp + loc);
142 gp.i = (int32_t *) vals;
143 rep << *(gp.i + loc);
147 gp.ui = (uint32_t *) vals;
148 rep << *(gp.ui + loc);
152 gp.fp = (
float *) vals;
153 float valAtLoc = *(gp.fp + loc);
155 rep << std::showpoint;
156 rep << std::setprecision(9);
158 if (isnan(valAtLoc)) {
169 string tmp_value = rep.str();
170 if (tmp_value.find(
'.') == string::npos && tmp_value.find(
'e') == string::npos && tmp_value.find(
'E') == string::npos
171 && tmp_value.find(
"nan") == string::npos && tmp_value.find(
"NaN") == string::npos && tmp_value.find(
"NAN") == string::npos) rep <<
".";
176 gp.dp = (
double *) vals;
177 double valAtLoc = *(gp.dp + loc);
179 rep << std::showpoint;
180 rep << std::setprecision(16);
182 if (std::isnan(valAtLoc)) {
188 string tmp_value = rep.str();
189 if (tmp_value.find(
'.') == string::npos && tmp_value.find(
'e') == string::npos && tmp_value.find(
'E') == string::npos
190 && tmp_value.find(
"nan") == string::npos && tmp_value.find(
"NaN") == string::npos && tmp_value.find(
"NAN") == string::npos) rep <<
".";
195 if (NCRequestHandler::get_ignore_unknown_types())
196 cerr <<
"The netcdf handler tried to print an attribute that has an unrecognized type. (1)" << endl;
198 throw InternalErr(__FILE__, __LINE__,
"The netcdf handler tried to print an attribute that has an unrecognized type. (1)");
211static string print_type(nc_type datatype)
222 if (NCRequestHandler::get_promote_byte_to_short()) {
248 return "NC_COMPOUND";
268 if (NCRequestHandler::get_ignore_unknown_types())
269 cerr <<
"The netcdf handler tried to print an attribute that has an unrecognized type. (2)" << endl;
271 throw InternalErr(__FILE__, __LINE__,
"The netcdf handler tried to print an attribute that has an unrecognized type. (2)");
282static void append_values(
int ncid,
int v,
int len, nc_type datatype,
char *attrname, AttrTable *at)
285 int errstat = nc_inq_type(ncid, datatype, 0, &size);
286 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the size for the type.");
288 vector<char> value((len + 1) * size);
289 errstat = nc_get_att(ncid, v, attrname, value.data());
290 if (errstat != NC_NOERR) {
291 throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
297 if (datatype == NC_CHAR) {
303 for (
int loc = 0; loc < len; loc++) {
304 string print_rep =
print_attr(datatype, loc, value.data());
305 at->append_attr(attrname, print_type(datatype), print_rep);
320static void read_attributes_netcdf4(
int ncid,
int varid,
int natts, AttrTable *at)
322 BESDEBUG(MODULE, prolog <<
"In read_attributes_netcdf4" << endl);
324 for (
int attr_num = 0; attr_num < natts; ++attr_num) {
325 int errstat = NC_NOERR;
327 char attrname[MAX_NC_NAME];
328 errstat = nc_inq_attname(ncid, varid, attr_num, attrname);
329 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the name for attribute " + long_to_string(attr_num));
334 errstat = nc_inq_att(ncid, varid, attrname, &datatype, &len);
335 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the name for attribute '" +
string(attrname) +
"'");
337 BESDEBUG(MODULE, prolog <<
"nc_inq_att returned datatype = " << datatype <<
" for '" << attrname <<
"'" << endl);
339 if (datatype >= NC_FIRSTUSERTYPEID) {
340 char type_name[NC_MAX_NAME + 1];
345 errstat = nc_inq_user_type(ncid, datatype, type_name, &size, &base_type, &nfields, &class_type);
346 if (errstat != NC_NOERR)
347 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about a user-defined type (" + long_to_string(errstat) +
")."));
349 BESDEBUG(MODULE, prolog <<
"Before switch(class_type)" << endl);
350 switch (class_type) {
353 vector<unsigned char> values((len + 1) * size);
355 int errstat = nc_get_att(ncid, varid, attrname, values.data());
356 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
358 for (
size_t i = 0; i < nfields; ++i) {
359 char field_name[NC_MAX_NAME + 1];
360 nc_type field_typeid;
362 nc_inq_compound_field(ncid, datatype, i, field_name, &field_offset, &field_typeid, 0, 0);
364 at->append_attr(field_name, print_type(field_typeid),
print_attr(field_typeid, 0, values.data() + field_offset));
370 if (NCRequestHandler::get_ignore_unknown_types())
371 cerr <<
"in build_user_defined; found a vlen." << endl;
373 throw Error(
"The netCDF handler does not yet support the NC_VLEN type.");
377 vector<unsigned char> values((len + 1) * size);
379 int errstat = nc_get_att(ncid, varid, attrname, values.data());
380 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
382 for (
size_t i = 0; i < size; ++i)
383 at->append_attr(attrname, print_type(NC_BYTE),
print_attr(NC_BYTE, i, values.data()));
391 size_t base_size, num_members;
392 errstat = nc_inq_enum(ncid, datatype, 0, &basetype, &base_size, &num_members);
393 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the size of the enum base type for '") + attrname +
string(
"'"));
395 vector<unsigned char> values((len + 1) * size);
397 int errstat = nc_get_att(ncid, varid, attrname, values.data());
398 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
400 for (
size_t i = 0; i < len; ++i)
401 at->append_attr(attrname, print_type(base_type),
print_attr(base_type, i, values.data()));
407 throw InternalErr(__FILE__, __LINE__,
"Expected one of NC_COMPOUND, NC_VLEN, NC_OPAQUE or NC_ENUM");
410 BESDEBUG(MODULE, prolog <<
"After switch(class-type)" << endl);
424 BESDEBUG(MODULE, prolog <<
"Before append_values ..." << endl);
425 append_values(ncid, varid, len, datatype, attrname, at);
426 BESDEBUG(MODULE, prolog <<
"After append_values ..." << endl);
431 string note =
"Attribute elided: Unsupported attribute type ";
432 note +=
"(" + print_type(datatype) +
")";
433 at->append_attr(attrname,
"String", note);
441 throw InternalErr(__FILE__, __LINE__,
"user-defined attribute type not recognized as such!");
444 throw InternalErr(__FILE__, __LINE__,
"Unrecognized attribute type.");
448 BESDEBUG(MODULE, prolog <<
"Exiting read_attributes_netcdf4" << endl);
460void nc_read_dataset_attributes(DAS &das,
const string &filename)
462 BESDEBUG(MODULE, prolog <<
"In nc_read_dataset_attributes" << endl);
465 errstat = nc_open(filename.c_str(), NC_NOWRITE, &ncid);
466 if (errstat != NC_NOERR)
throw Error(errstat,
"NetCDF handler: Could not open " + filename +
".");
470 errstat = nc_inq(ncid, (
int *) 0, &nvars, &ngatts, (
int *) 0);
471 if (errstat != NC_NOERR)
throw Error(errstat,
"NetCDF handler: Could not inquire about netcdf file: " + path_to_filename(filename) +
".");
474 char varname[MAX_NC_NAME];
477 for (
int varid = 0; varid < nvars; ++varid) {
478 BESDEBUG(MODULE, prolog <<
"Top of for loop; for each var..." << endl);
480 errstat = nc_inq_var(ncid, varid, varname, &var_type, (
int*) 0, (
int*) 0, &natts);
481 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get information for variable: " + long_to_string(varid));
483 AttrTable *attr_table_ptr = das.get_table(varname);
484 if (!attr_table_ptr) attr_table_ptr = das.add_table(varname,
new AttrTable);
486 read_attributes_netcdf4(ncid, varid, natts, attr_table_ptr);
489 if (var_type == NC_CHAR) {
492 int vdimids[MAX_VAR_DIMS];
493 errstat = nc_inq_var(ncid, varid, (
char *) 0, (nc_type *) 0, &num_dim, vdimids, (
int *) 0);
494 if (errstat != NC_NOERR)
495 throw Error(errstat,
string(
"NetCDF handler: Could not read information about a NC_CHAR variable while building the DAS."));
500 string print_rep =
print_attr(NC_INT, 0, (
void *) &size);
501 attr_table_ptr->append_attr(
"string_length", print_type(NC_INT), print_rep);
505 vector<size_t> dim_sizes(num_dim);
506 for (
int i = 0; i < num_dim; ++i) {
507 if ((errstat = nc_inq_dimlen(ncid, vdimids[i], &dim_sizes[i])) != NC_NOERR) {
509 string(
"NetCDF handler: Could not read dimension information about the variable `") + varname +
string(
"'."));
514 string print_rep =
print_attr(NC_INT, 0, (
void *) (&dim_sizes[num_dim - 1]));
515 attr_table_ptr->append_attr(
"string_length", print_type(NC_INT), print_rep);
518 else if (is_user_defined_type(ncid, var_type)) {
520 vector<char> name(MAX_NC_NAME + 1);
522 errstat = nc_inq_user_type(ncid, var_type, name.data(), 0, 0, 0, &class_type);
523 if (errstat != NC_NOERR)
524 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about a user-defined type (" + long_to_string(errstat) +
")."));
526 switch (class_type) {
528 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFBaseType", print_type(NC_STRING),
"NC_OPAQUE");
529 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFTypeName", print_type(NC_STRING), name.data());
535 nc_type base_nc_type;
536 size_t base_size, num_members;
537 errstat = nc_inq_enum(ncid, var_type, 0, &base_nc_type, &base_size, &num_members);
538 if (errstat != NC_NOERR)
539 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about an enum(" + long_to_string(errstat) +
")."));
543 if (base_nc_type == NC_INT64 || base_nc_type == NC_UINT64) {
544 if (NCRequestHandler::get_ignore_unknown_types())
545 cerr <<
"An Enum uses 64-bit integers, but this handler does not support that type." << endl;
547 throw Error(
"An Enum uses 64-bit integers, but this handler does not support that type.");
551 for (
size_t i = 0; i < num_members; ++i) {
552 vector<char> member_name(MAX_NC_NAME + 1);
553 vector<char> member_value(base_size);
554 errstat = nc_inq_enum_member(ncid, var_type, i, member_name.data(), member_value.data());
555 if (errstat != NC_NOERR)
556 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about an enum value (" + long_to_string(errstat) +
")."));
557 attr_table_ptr->append_attr(
"DAP2_EnumValues", print_type(base_nc_type),
print_attr(base_nc_type, 0, member_value.data()));
558 attr_table_ptr->append_attr(
"DAP2_EnumNames", print_type(NC_STRING), member_name.data());
561 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFBaseType", print_type(NC_STRING),
"NC_ENUM");
562 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFTypeName", print_type(NC_STRING), name.data());
573 BESDEBUG(MODULE, prolog <<
"Starting global attributes" << endl);
577 AttrTable *attr_table_ptr = das.add_table(
"NC_GLOBAL",
new AttrTable);
578 read_attributes_netcdf4(ncid, NC_GLOBAL, ngatts, attr_table_ptr);
583 char dimname[MAX_NC_NAME];
584 nc_type datatype = NC_CHAR;
585 if ((errstat = nc_inq(ncid, (
int *) 0, (
int *) 0, (
int *) 0, &xdimid)) != NC_NOERR)
586 throw InternalErr(__FILE__, __LINE__,
string(
"NetCDF handler: Could not access variable information: ") + nc_strerror(errstat));
588 if ((errstat = nc_inq_dim(ncid, xdimid, dimname, (
size_t *) 0)) != NC_NOERR)
589 throw InternalErr(__FILE__, __LINE__,
string(
"NetCDF handler: Could not access dimension information: ") + nc_strerror(errstat));
590 string print_rep =
print_attr(datatype, 0, dimname);
591 AttrTable *attr_table_ptr = das.add_table(
"DODS_EXTRA",
new AttrTable);
592 attr_table_ptr->append_attr(
"Unlimited_Dimension", print_type(datatype), print_rep);
595 if (nc_close(ncid) != NC_NOERR)
throw InternalErr(__FILE__, __LINE__,
"NetCDF handler: Could not close the dataset!");
597 BESDEBUG(MODULE, prolog <<
"Exiting nc_read_dataset_attributes" << endl);
string print_attr(hid_t type, int loc, void *sm_buf)