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;
129 return escattr(
static_cast<const char*
>(vals));
131 string tmp_str =
static_cast<const char*
>(vals);
136 gp.stringp = (
char **) vals;
137 rep << *(gp.stringp + loc);
141 gp.sp = (
short *) vals;
142 rep << *(gp.sp + loc);
146 gp.usp = (uint16_t *) vals;
147 rep << *(gp.usp + loc);
151 gp.i = (int32_t *) vals;
152 rep << *(gp.i + loc);
156 gp.ui = (uint32_t *) vals;
157 rep << *(gp.ui + loc);
161 gp.fp = (
float *) vals;
162 float valAtLoc = *(gp.fp + loc);
164 rep << std::showpoint;
165 rep << std::setprecision(9);
167 if (isnan(valAtLoc)) {
178 string tmp_value = rep.str();
179 if (tmp_value.find(
'.') == string::npos && tmp_value.find(
'e') == string::npos && tmp_value.find(
'E') == string::npos
180 && tmp_value.find(
"nan") == string::npos && tmp_value.find(
"NaN") == string::npos && tmp_value.find(
"NAN") == string::npos) rep <<
".";
185 gp.dp = (
double *) vals;
186 double valAtLoc = *(gp.dp + loc);
188 rep << std::showpoint;
189 rep << std::setprecision(16);
191 if (std::isnan(valAtLoc)) {
197 string tmp_value = rep.str();
198 if (tmp_value.find(
'.') == string::npos && tmp_value.find(
'e') == string::npos && tmp_value.find(
'E') == string::npos
199 && tmp_value.find(
"nan") == string::npos && tmp_value.find(
"NaN") == string::npos && tmp_value.find(
"NAN") == string::npos) rep <<
".";
204 if (NCRequestHandler::get_ignore_unknown_types())
205 cerr <<
"The netcdf handler tried to print an attribute that has an unrecognized type. (1)" << endl;
207 throw InternalErr(__FILE__, __LINE__,
"The netcdf handler tried to print an attribute that has an unrecognized type. (1)");
220static string print_type(nc_type datatype)
231 if (NCRequestHandler::get_promote_byte_to_short()) {
257 return "NC_COMPOUND";
277 if (NCRequestHandler::get_ignore_unknown_types())
278 cerr <<
"The netcdf handler tried to print an attribute that has an unrecognized type. (2)" << endl;
280 throw InternalErr(__FILE__, __LINE__,
"The netcdf handler tried to print an attribute that has an unrecognized type. (2)");
291static void append_values(
int ncid,
int v,
int len, nc_type datatype,
char *attrname, AttrTable *at)
294 int errstat = nc_inq_type(ncid, datatype, 0, &size);
295 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the size for the type.");
298 errstat = nc_get_att(ncid, v, attrname, value.data());
299 if (errstat != NC_NOERR) {
300 throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
306 if (datatype == NC_CHAR) {
312 for (
int loc = 0; loc < len; loc++) {
313 string print_rep = print_attr(datatype, loc, value.data());
314 at->append_attr(attrname, print_type(datatype), print_rep);
329static void read_attributes_netcdf4(
int ncid,
int varid,
int natts, AttrTable *at)
331 BESDEBUG(MODULE, prolog <<
"In read_attributes_netcdf4" << endl);
333 for (
int attr_num = 0; attr_num < natts; ++attr_num) {
334 int errstat = NC_NOERR;
336 char attrname[MAX_NC_NAME];
337 errstat = nc_inq_attname(ncid, varid, attr_num, attrname);
338 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the name for attribute " + long_to_string(attr_num));
343 errstat = nc_inq_att(ncid, varid, attrname, &datatype, &len);
344 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get the name for attribute '" +
string(attrname) +
"'");
346 BESDEBUG(MODULE, prolog <<
"nc_inq_att returned datatype = " << datatype <<
" for '" << attrname <<
"'" << endl);
348 if (datatype >= NC_FIRSTUSERTYPEID) {
349 char type_name[NC_MAX_NAME + 1];
354 errstat = nc_inq_user_type(ncid, datatype, type_name, &size, &base_type, &nfields, &class_type);
355 if (errstat != NC_NOERR)
356 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about a user-defined type (" + long_to_string(errstat) +
")."));
358 BESDEBUG(MODULE, prolog <<
"Before switch(class_type)" << endl);
359 switch (class_type) {
364 int errstat = nc_get_att(ncid, varid, attrname, values.data());
365 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
367 for (
size_t i = 0; i < nfields; ++i) {
368 char field_name[NC_MAX_NAME + 1];
369 nc_type field_typeid;
371 nc_inq_compound_field(ncid, datatype, i, field_name, &field_offset, &field_typeid, 0, 0);
373 at->append_attr(field_name, print_type(field_typeid), print_attr(field_typeid, 0, values.data() + field_offset));
379 if (NCRequestHandler::get_ignore_unknown_types())
380 cerr <<
"in build_user_defined; found a vlen." << endl;
382 throw Error(
"The netCDF handler does not yet support the NC_VLEN type.");
388 int errstat = nc_get_att(ncid, varid, attrname, values.data());
389 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
391 for (
size_t i = 0; i < size; ++i)
392 at->append_attr(attrname, print_type(NC_BYTE), print_attr(NC_BYTE, i, values.data()));
400 size_t base_size, num_members;
401 errstat = nc_inq_enum(ncid, datatype, 0, &basetype, &base_size, &num_members);
402 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the size of the enum base type for '") + attrname +
string(
"'"));
406 int errstat = nc_get_att(ncid, varid, attrname, values.data());
407 if (errstat != NC_NOERR)
throw Error(errstat,
string(
"Could not get the value for attribute '") + attrname +
string(
"'"));
409 for (
size_t i = 0; i < len; ++i)
410 at->append_attr(attrname, print_type(base_type), print_attr(base_type, i, values.data()));
416 throw InternalErr(__FILE__, __LINE__,
"Expected one of NC_COMPOUND, NC_VLEN, NC_OPAQUE or NC_ENUM");
419 BESDEBUG(MODULE, prolog <<
"After switch(class-type)" << endl);
433 BESDEBUG(MODULE, prolog <<
"Before append_values ..." << endl);
434 append_values(ncid, varid, len, datatype, attrname, at);
435 BESDEBUG(MODULE, prolog <<
"After append_values ..." << endl);
440 string note =
"Attribute elided: Unsupported attribute type ";
441 note +=
"(" + print_type(datatype) +
")";
442 at->append_attr(attrname,
"String", note);
450 throw InternalErr(__FILE__, __LINE__,
"user-defined attribute type not recognized as such!");
453 throw InternalErr(__FILE__, __LINE__,
"Unrecognized attribute type.");
457 BESDEBUG(MODULE, prolog <<
"Exiting read_attributes_netcdf4" << endl);
469void nc_read_dataset_attributes(DAS &das,
const string &filename)
471 BESDEBUG(MODULE, prolog <<
"In nc_read_dataset_attributes" << endl);
474 errstat = nc_open(filename.c_str(), NC_NOWRITE, &ncid);
475 if (errstat != NC_NOERR)
throw Error(errstat,
"NetCDF handler: Could not open " + filename +
".");
479 errstat = nc_inq(ncid, (
int *) 0, &nvars, &ngatts, (
int *) 0);
480 if (errstat != NC_NOERR)
throw Error(errstat,
"NetCDF handler: Could not inquire about netcdf file: " + path_to_filename(filename) +
".");
483 char varname[MAX_NC_NAME];
486 for (
int varid = 0; varid < nvars; ++varid) {
487 BESDEBUG(MODULE, prolog <<
"Top of for loop; for each var..." << endl);
489 errstat = nc_inq_var(ncid, varid, varname, &var_type, (
int*) 0, (
int*) 0, &natts);
490 if (errstat != NC_NOERR)
throw Error(errstat,
"Could not get information for variable: " + long_to_string(varid));
492 AttrTable *attr_table_ptr = das.get_table(varname);
493 if (!attr_table_ptr) attr_table_ptr = das.add_table(varname,
new AttrTable);
495 read_attributes_netcdf4(ncid, varid, natts, attr_table_ptr);
498 if (var_type == NC_CHAR) {
501 int vdimids[MAX_VAR_DIMS];
502 errstat = nc_inq_var(ncid, varid, (
char *) 0, (nc_type *) 0, &num_dim, vdimids, (
int *) 0);
503 if (errstat != NC_NOERR)
504 throw Error(errstat,
string(
"NetCDF handler: Could not read information about a NC_CHAR variable while building the DAS."));
509 string print_rep = print_attr(NC_INT, 0, (
void *) &size);
510 attr_table_ptr->append_attr(
"string_length", print_type(NC_INT), print_rep);
515 for (
int i = 0; i < num_dim; ++i) {
516 if ((errstat = nc_inq_dimlen(ncid, vdimids[i], &dim_sizes[i])) != NC_NOERR) {
518 string(
"NetCDF handler: Could not read dimension information about the variable `") + varname +
string(
"'."));
523 string print_rep = print_attr(NC_INT, 0, (
void *) (&dim_sizes[num_dim - 1]));
524 attr_table_ptr->append_attr(
"string_length", print_type(NC_INT), print_rep);
527 else if (is_user_defined_type(ncid, var_type)) {
531 errstat = nc_inq_user_type(ncid, var_type, name.data(), 0, 0, 0, &class_type);
532 if (errstat != NC_NOERR)
533 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about a user-defined type (" + long_to_string(errstat) +
")."));
535 switch (class_type) {
537 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFBaseType", print_type(NC_STRING),
"NC_OPAQUE");
538 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFTypeName", print_type(NC_STRING), name.data());
544 nc_type base_nc_type;
545 size_t base_size, num_members;
546 errstat = nc_inq_enum(ncid, var_type, 0, &base_nc_type, &base_size, &num_members);
547 if (errstat != NC_NOERR)
548 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about an enum(" + long_to_string(errstat) +
")."));
552 if (base_nc_type == NC_INT64 || base_nc_type == NC_UINT64) {
553 if (NCRequestHandler::get_ignore_unknown_types())
554 cerr <<
"An Enum uses 64-bit integers, but this handler does not support that type." << endl;
556 throw Error(
"An Enum uses 64-bit integers, but this handler does not support that type.");
560 for (
size_t i = 0; i < num_members; ++i) {
563 errstat = nc_inq_enum_member(ncid, var_type, i, member_name.data(), member_value.data());
564 if (errstat != NC_NOERR)
565 throw(InternalErr(__FILE__, __LINE__,
"Could not get information about an enum value (" + long_to_string(errstat) +
")."));
566 attr_table_ptr->append_attr(
"DAP2_EnumValues", print_type(base_nc_type), print_attr(base_nc_type, 0, member_value.data()));
567 attr_table_ptr->append_attr(
"DAP2_EnumNames", print_type(NC_STRING), member_name.data());
570 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFBaseType", print_type(NC_STRING),
"NC_ENUM");
571 attr_table_ptr->append_attr(
"DAP2_OriginalNetCDFTypeName", print_type(NC_STRING), name.data());
582 BESDEBUG(MODULE, prolog <<
"Starting global attributes" << endl);
586 AttrTable *attr_table_ptr = das.add_table(
"NC_GLOBAL",
new AttrTable);
587 read_attributes_netcdf4(ncid, NC_GLOBAL, ngatts, attr_table_ptr);
592 char dimname[MAX_NC_NAME];
593 nc_type datatype = NC_CHAR;
594 if ((errstat = nc_inq(ncid, (
int *) 0, (
int *) 0, (
int *) 0, &xdimid)) != NC_NOERR)
595 throw InternalErr(__FILE__, __LINE__,
string(
"NetCDF handler: Could not access variable information: ") + nc_strerror(errstat));
597 if ((errstat = nc_inq_dim(ncid, xdimid, dimname, (
size_t *) 0)) != NC_NOERR)
598 throw InternalErr(__FILE__, __LINE__,
string(
"NetCDF handler: Could not access dimension information: ") + nc_strerror(errstat));
599 string print_rep = print_attr(datatype, 0, dimname);
600 AttrTable *attr_table_ptr = das.add_table(
"DODS_EXTRA",
new AttrTable);
601 attr_table_ptr->append_attr(
"Unlimited_Dimension", print_type(datatype), print_rep);
604 if (nc_close(ncid) != NC_NOERR)
throw InternalErr(__FILE__, __LINE__,
"NetCDF handler: Could not close the dataset!");
606 BESDEBUG(MODULE, prolog <<
"Exiting nc_read_dataset_attributes" << endl);