bes  Updated for version 3.20.6
FONcAttributes.cc
1 // FONcAttributes.cc
2 
3 // This file is part of BES Netcdf File Out Module
4 
5 // Copyright (c) 2004,2005 University Corporation for Atmospheric Research
6 // Author: Patrick West <pwest@ucar.edu> and Jose Garcia <jgarcia@ucar.edu>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 // You can contact University Corporation for Atmospheric Research at
23 // 3080 Center Green Drive, Boulder, CO 80301
24 
25 // (c) COPYRIGHT University Corporation for Atmospheric Research 2004-2005
26 // Please read the full copyright statement in the file COPYRIGHT_UCAR.
27 //
28 // Authors:
29 // pwest Patrick West <pwest@ucar.edu>
30 // jgarcia Jose Garcia <jgarcia@ucar.edu>
31 
32 #include <sstream>
33 
34 using std::istringstream;
35 
36 #include <netcdf.h>
37 
38 #include <BESDebug.h>
39 #include <BESInternalError.h>
40 #include <BESUtil.h>
41 
42 #include "DapFunctionUtils.h"
43 
44 #include "FONcAttributes.h"
45 #include "FONcUtils.h"
46 
77 void FONcAttributes::add_variable_attributes(int ncid, int varid, BaseType *b) {
78  string emb_name;
79  BaseType *parent = b->get_parent();
80  if (parent) {
81  FONcAttributes::add_variable_attributes_worker(ncid, varid, parent, emb_name);
82  }
83  // addattrs_workerA(ncid, varid, b, "");
84  add_attributes(ncid, varid, b->get_attr_table(), b->name(), "");
85 
86 }
87 
101 void FONcAttributes::add_variable_attributes_worker(int ncid, int varid, BaseType *b, string &emb_name) {
102 
103  BaseType *parent = b->get_parent();
104  if (parent) {
105  FONcAttributes::add_variable_attributes_worker(ncid, varid, parent, emb_name);
106  }
107  if (!emb_name.empty()) {
108  emb_name += FONC_EMBEDDED_SEPARATOR;
109  }
110  emb_name += b->name();
111  // addattrs_workerA(ncid, varid, b, emb_name);
112  add_attributes(ncid, varid, b->get_attr_table(), b->name(), emb_name);
113 }
114 
115 
129 void FONcAttributes::add_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name, const string &prepend_attr) {
130 
131  unsigned int num_attrs = attrs.get_size();
132  if (num_attrs) {
133  AttrTable::Attr_iter i = attrs.attr_begin();
134  AttrTable::Attr_iter e = attrs.attr_end();
135  for (; i != e; i++) {
136  unsigned int num_vals = attrs.get_attr_num(i);
137  if (num_vals) {
138  add_attributes_worker(ncid, varid, var_name, attrs, i, prepend_attr);
139  }
140  }
141  }
142 }
143 
144 
145 
158 void FONcAttributes::add_attributes_worker(int ncid, int varid, const string &var_name,
159  AttrTable &attrs, AttrTable::Attr_iter &attr,
160  const string &prepend_attr) {
161 
162  AttrType attrType = attrs.get_attr_type(attr);
163 
164  string attr_name = attrs.get_name(attr);
165  string new_attr_name("");
166  if (!prepend_attr.empty()) {
167  new_attr_name = prepend_attr + FONC_EMBEDDED_SEPARATOR + attr_name;
168  }
169  else {
170 
171  // If we're doing global attributes AND it's an attr table, and its name is "special"
172  // (ends with "_GLOBAL"), then we suppress the use of the attrTable name in
173  // the NetCDF Attributes name.
174  if (varid == NC_GLOBAL && attrType==Attr_container && BESUtil::endsWith(attr_name, "_GLOBAL")) {
175  BESDEBUG("fonc",
176  "Suppressing global AttributeTable name '" << attr_name << "' from inclusion in NetCDF attributes namespace chain." << endl);
177  new_attr_name = "";
178  }
179  else {
180  new_attr_name = attr_name;
181  }
182  }
183 
184 #if 0
185  // This was the old way of doing it and it polluted the attribute names
186  // by prepending full qualified variable names to the attribute name..
187  string new_name = new_attr_name;
188  if (!var_name.empty()) {
189  new_name = var_name + FONC_ATTRIBUTE_SEPARATOR + new_attr_name;
190  }
191 
192  // BESDEBUG("fonc","new_name: " << new_name << " new_attr_name: " << new_attr_name << " var_name: " << var_name << endl);
193 
194  new_name = FONcUtils::id2netcdf(new_name);
195 #endif
196 
197  string new_name = FONcUtils::id2netcdf(new_attr_name);;
198 
199 
200  if (varid == NC_GLOBAL) {
201  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding global attributes " << attr_name << endl);
202  }
203  else {
204  BESDEBUG("fonc", "FONcAttributes::addattrs() - Adding attribute " << new_name << endl);
205  }
206 
207  int stax = NC_NOERR;
208  unsigned int attri = 0;
209  unsigned int num_vals = attrs.get_attr_num(attr);
210  switch (attrType) {
211  case Attr_container: {
212  // flatten
213  BESDEBUG("fonc", "Attribute " << attr_name << " is an attribute container. new_attr_name: \"" << new_attr_name << "\"" << endl);
214  AttrTable *container = attrs.get_attr_table(attr);
215  if (container) {
216  add_attributes(ncid, varid, *container, var_name, new_attr_name);
217  }
218  }
219  break;
220  case Attr_byte: {
221  // unsigned char
222  unsigned char vals[num_vals];
223  for (attri = 0; attri < num_vals; attri++) {
224  string val = attrs.get_attr(attr, attri);
225  istringstream is(val);
226  unsigned int uival = 0;
227  is >> uival;
228  vals[attri] = (unsigned char) uival;
229  }
230  stax = nc_put_att_uchar(ncid, varid, new_name.c_str(), NC_BYTE,
231  num_vals, vals);
232  if (stax != NC_NOERR) {
233  string err = (string) "File out netcdf, "
234  + "failed to write byte attribute " + new_name;
235  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
236  }
237  }
238  break;
239  case Attr_int16: {
240  // short
241  short vals[num_vals];
242  for (attri = 0; attri < num_vals; attri++) {
243  string val = attrs.get_attr(attr, attri);
244  istringstream is(val);
245  short sval = 0;
246  is >> sval;
247  vals[attri] = sval;
248  }
249  stax = nc_put_att_short(ncid, varid, new_name.c_str(), NC_SHORT,
250  num_vals, vals);
251  if (stax != NC_NOERR) {
252  string err = (string) "File out netcdf, "
253  + "failed to write short attribute " + new_name;
254  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
255  }
256  }
257  break;
258  case Attr_uint16: {
259  // unsigned short
260  // (needs to be big enough to store an unsigned short
261  int vals[num_vals];
262  for (attri = 0; attri < num_vals; attri++) {
263  string val = attrs.get_attr(attr, attri);
264  istringstream is(val);
265  int ival = 0;
266  is >> ival;
267  vals[attri] = ival;
268  }
269  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
270  vals);
271  if (stax != NC_NOERR) {
272  string err = (string) "File out netcdf, "
273  + "failed to write unsinged short attribute " + new_name;
274  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
275  }
276  }
277  break;
278  case Attr_int32: {
279  // int
280  int vals[num_vals];
281  for (attri = 0; attri < num_vals; attri++) {
282  string val = attrs.get_attr(attr, attri);
283  istringstream is(val);
284  int ival = 0;
285  is >> ival;
286  vals[attri] = ival;
287  }
288  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
289  vals);
290  if (stax != NC_NOERR) {
291  string err = (string) "File out netcdf, "
292  + "failed to write int attribute " + new_name;
293  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
294  }
295  }
296  break;
297  case Attr_uint32: {
298  // uint
299  // needs to be big enough to store an unsigned int
300  int vals[num_vals];
301  for (attri = 0; attri < num_vals; attri++) {
302  string val = attrs.get_attr(attr, attri);
303  istringstream is(val);
304  int lval = 0;
305  is >> lval;
306  vals[attri] = lval;
307  }
308  stax = nc_put_att_int(ncid, varid, new_name.c_str(), NC_INT, num_vals,
309  vals);
310  if (stax != NC_NOERR) {
311  string err = (string) "File out netcdf, "
312  + "failed to write byte attribute " + new_name;
313  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
314  }
315  }
316  break;
317  case Attr_float32: {
318  // float
319  float vals[num_vals];
320  for (attri = 0; attri < num_vals; attri++) {
321  string val = attrs.get_attr(attr, attri);
322  istringstream is(val);
323  float fval = 0;
324  is >> fval;
325  vals[attri] = fval;
326  }
327  stax = nc_put_att_float(ncid, varid, new_name.c_str(), NC_FLOAT,
328  num_vals, vals);
329  if (stax != NC_NOERR) {
330  string err = (string) "File out netcdf, "
331  + "failed to write float attribute " + new_name;
332  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
333  }
334  }
335  break;
336  case Attr_float64: {
337  // double
338  double vals[num_vals];
339  for (attri = 0; attri < num_vals; attri++) {
340  string val = attrs.get_attr(attr, attri);
341  istringstream is(val);
342  double dval = 0;
343  is >> dval;
344  vals[attri] = dval;
345  }
346  stax = nc_put_att_double(ncid, varid, new_name.c_str(), NC_DOUBLE,
347  num_vals, vals);
348  if (stax != NC_NOERR) {
349  string err = (string) "File out netcdf, "
350  + "failed to write double attribute " + new_name;
351  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
352  }
353  }
354  break;
355  case Attr_string:
356  case Attr_url:
357  case Attr_other_xml: // Added. jhrg 12.27.2011
358  {
359  // string
360  string val = attrs.get_attr(attr, 0);
361  for (attri = 1; attri < num_vals; attri++) {
362  val += "\n" + attrs.get_attr(attr, attri);
363  }
364  if (attr_name != _FillValue) {
365  stax = nc_put_att_text(ncid, varid, new_name.c_str(), val.length(), val.c_str());
366  }
367  else {
368  BESDEBUG("fonc",
369  "FONcAttributes::add_attributes_worker - Original attribute value is first character: " << val.c_str()[0]<< endl);
370  stax = nc_put_att_text(ncid, varid, new_name.c_str(), 1, val.c_str());
371  if (stax == NC_NOERR) {
372  // New name for attribute _FillValue with original value
373  string new_name_fillvalue = "Orig_FillValue";
374  BESDEBUG("fonc",
375  "FONcAttributes::add_attributes_worker - New attribute value is original value: " << val.c_str() << endl);
376  // This line causes the segmentation fault since attrs is changed and the original iterator of attrs doesn't exist anymore.
377  // So it causes the segmentation fault when next attribute is fetched in the for loop of the add_attributes(). KY 2019-12-13
378 #if 0
379  attrs.append_attr(new_name_fillvalue,"String", val);
380 #endif
381  stax = nc_put_att_text(ncid, varid, new_name_fillvalue.c_str(), val.length(), val.c_str());
382  }
383  }
384 
385  if (stax != NC_NOERR) {
386  string err = (string) "File out netcdf, "
387  + "failed to write string attribute " + new_name;
388  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
389  }
390  }
391  break;
392 
393  case Attr_unknown: {
394  string err = (string) "File out netcdf, "
395  + "failed to write unknown type of attribute " + new_name;
396  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
397  }
398  break;
399  }
400 }
401 
415 void FONcAttributes::add_original_name(int ncid, int varid,
416  const string &var_name, const string &orig) {
417  if (var_name != orig) {
418  string attr_name = FONC_ORIGINAL_NAME;
419  int stax = nc_put_att_text(ncid, varid, attr_name.c_str(),
420  orig.length(), orig.c_str());
421  if (stax != NC_NOERR) {
422  string err = (string) "File out netcdf, "
423  + "failed to write change of name attribute for "
424  + var_name;
425  FONcUtils::handle_error(stax, err, __FILE__, __LINE__);
426  }
427  }
428 }
429 
FONcUtils::id2netcdf
static string id2netcdf(string in)
convert the provided string to a netcdf allowed identifier.
Definition: FONcUtils.cc:75
FONcUtils::handle_error
static void handle_error(int stax, const string &err, const string &file, int line)
handle any netcdf errors
Definition: FONcUtils.cc:245
FONcAttributes::add_variable_attributes
static void add_variable_attributes(int ncid, int varid, BaseType *b)
Add the attributes for an OPeNDAP variable to the netcdf file.
Definition: FONcAttributes.cc:77
BESUtil::endsWith
static bool endsWith(std::string const &fullString, std::string const &ending)
Definition: BESUtil.cc:942
FONcAttributes::add_attributes
static void add_attributes(int ncid, int varid, AttrTable &attrs, const string &var_name, const string &prepend_attr)
helper function for add_attributes
Definition: FONcAttributes.cc:129
FONcAttributes::add_original_name
static void add_original_name(int ncid, int varid, const string &var_name, const string &orig)
Adds an attribute for the variable if the variable name had to be modified in any way.
Definition: FONcAttributes.cc:415