bes  Updated for version 3.20.13
h5cfdaputil.cc
Go to the documentation of this file.
1 // This file is part of hdf5_handler: an HDF5 file handler for the OPeNDAP
2 // data server.
3 
4 // Copyright (c) 2011-2016 The HDF Group, Inc. and OPeNDAP, Inc.
5 //
6 // This is free software; you can redistribute it and/or modify it under the
7 // terms of the GNU Lesser General Public License as published by the Free
8 // Software Foundation; either version 2.1 of the License, or (at your
9 // option) any later version.
10 //
11 // This software is distributed in the hope that it will be useful, but
12 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 // License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 //
20 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
21 // You can contact The HDF Group, Inc. at 1800 South Oak Street,
22 // Suite 203, Champaign, IL 61820
23 
35 
36 
37 #include "h5cfdaputil.h"
38 #include <math.h>
39 
40 using namespace std;
41 using namespace libdap;
42 
43 // Part of a large fix for attributes. Escaping the values of the attributes
44 // may have been a bad idea. It breaks using JSON, for example. If this is a
45 // bad idea - to turn of escaping - then we'll have to figure out how to store
46 // 'serialized JSON' in attributes because it's being used in netcdf/hdf files.
47 // If we stick with this, there's clearly a more performant solution - eliminate
48 // the calls to this code.
49 // jhrg 6/25/21
50 //
51 // This may have been a mistake. Not escaping the string attributes results in
52 // binary values in the attribute value and that winds up in the DMR & DDX XML
53 // documents, breaking downstream parsers. It also seems to be the case that the
54 // escaped double quotes do not affect the JSON parsers, esp. since the JSON in
55 // question - the history_json attribute - is built only when the server builds
56 // a netcdf file as the response type. Thus, that JSON is a pretty special case.
57 // Reset this compile-time constant to 1. jhrg 3/8/22
58 #define ESCAPE_STRING_ATTRIBUTES 1
59 
60 string HDF5CFDAPUtil::escattr(string s)
61 {
62  const string printable = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789~`!@#$%^&*()_-+={[}]|\\:;<,>.?/'\"\n\t\r";
63  const string ESC = "\\";
64  size_t ind = 0;
65 #if ESCAPE_STRING_ATTRIBUTES
66  const string DOUBLE_ESC = ESC + ESC;
67  const string QUOTE = "\"";
68  const string ESCQUOTE = ESC + QUOTE;
69 
70  // escape \ with a second backslash
71  ind = 0;
72  while ((ind = s.find(ESC, ind)) != string::npos) {
73  s.replace(ind, 1, DOUBLE_ESC);
74  ind += DOUBLE_ESC.length();
75  }
76 
77  // escape " with backslash
78  ind = 0;
79  while ((ind = s.find(QUOTE, ind)) != string::npos) {
80  s.replace(ind, 1, ESCQUOTE);
81  ind += ESCQUOTE.length();
82  }
83 #endif
84 
85  // escape non-printing characters with octal escape
86  ind = 0;
87  while ((ind = s.find_first_not_of(printable, ind)) != string::npos)
88  s.replace(ind, 1, ESC + octstring(s[ind]));
89 
90  return s;
91 }
92 
93 // present the string in octal base.
94 string
95 HDF5CFDAPUtil::octstring(unsigned char val)
96 {
97  ostringstream buf;
98  buf << oct << setw(3) << setfill('0')
99  << static_cast<unsigned int>(val);
100 
101  return buf.str();
102 }
103 
104 
105 void HDF5CFDAPUtil::replace_double_quote(string & str) {
106 
107  const string offend_char = "\"";
108  const string replace_str = "&quote";
109  size_t found_quote = 0;
110  size_t start_pos = 0;
111  while (found_quote != string::npos) {
112  found_quote = str.find(offend_char,start_pos);
113  if (found_quote!= string::npos){
114  str.replace(found_quote,offend_char.size(),replace_str);
115  start_pos = found_quote+1;
116  }
117  }
118 }
119 
120 
121 string HDF5CFDAPUtil::print_type(H5DataType type) {
122 
123  // The list is based on libdap/AttrTable.h.
124  // We added DAP4 INT64 and UINT64 support.
125  string DAPUNSUPPORTED ="Unsupported";
126  string DAPBYTE ="Byte";
127  string DAPINT16 ="Int16";
128  string DAPUINT16 ="Uint16";
129  string DAPINT32 ="Int32";
130  string DAPUINT32 ="Uint32";
131  string DAPFLOAT32 ="Float32";
132  string DAPFLOAT64 ="Float64";
133  string DAP4INT64 ="Int64";
134  string DAP4UINT64 ="UInt64";
135  string DAPSTRING = "String";
136 
137  switch (type) {
138 
139  case H5UCHAR:
140  return DAPBYTE;
141 
142  case H5CHAR:
143  return DAPINT16;
144 
145  case H5INT16:
146  return DAPINT16;
147 
148  case H5UINT16:
149  return DAPUINT16;
150 
151  case H5INT32:
152  return DAPINT32;
153 
154  case H5UINT32:
155  return DAPUINT32;
156 
157  case H5FLOAT32:
158  return DAPFLOAT32;
159 
160  case H5FLOAT64:
161  return DAPFLOAT64;
162 
163  case H5FSTRING:
164  case H5VSTRING:
165  return DAPSTRING;
166  case H5INT64:
167  return DAP4INT64;
168  case H5UINT64:
169  return DAP4UINT64;
170  case H5REFERENCE:
171  case H5COMPOUND:
172  case H5ARRAY:
173  return DAPUNSUPPORTED;
174 
175  default:
176  return DAPUNSUPPORTED;
177  }
178 
179 }
180 
181 D4AttributeType HDF5CFDAPUtil::print_type_dap4(H5DataType type) {
182 
183  switch (type) {
184 
185  case H5UCHAR:
186  return attr_byte_c;
187 
188  case H5CHAR:
189  return attr_int8_c;
190 
191  case H5INT16:
192  return attr_int16_c;
193 
194  case H5UINT16:
195  return attr_uint16_c;
196 
197  case H5INT32:
198  return attr_int32_c;
199 
200  case H5UINT32:
201  return attr_uint32_c;
202 
203  case H5INT64:
204  return attr_int64_c;
205 
206  case H5UINT64:
207  return attr_uint64_c;
208 
209  case H5FLOAT32:
210  return attr_float32_c;
211 
212  case H5FLOAT64:
213  return attr_float64_c;
214 
215  case H5FSTRING:
216  case H5VSTRING:
217  return attr_str_c;
218  case H5REFERENCE:
219  case H5COMPOUND:
220  case H5ARRAY:
221  return attr_null_c;
222 
223  default:
224  return attr_null_c;
225  }
226 
227 }
228 
229 
230 H5DataType
231 HDF5CFDAPUtil::get_mem_dtype(H5DataType dtype,size_t mem_dtype_size ) {
232 
233  // Currently in addition to "char" to "int16", all other memory datatype will be the same as the datatype.
234  // So we have a short cut for this function
235  return ((H5INT16 == dtype) && (1 == mem_dtype_size))?H5CHAR:dtype;
236 }
237 
238 string
239 HDF5CFDAPUtil:: print_attr(H5DataType type, int loc, void *vals)
240 {
241  ostringstream rep;
242 
243  union {
244  unsigned char* ucp;
245  char *cp;
246  short *sp;
247  unsigned short *usp;
248  int *ip;
249  unsigned int *uip;
250  long long *llp;
251  unsigned long long *ullp;
252  float *fp;
253  double *dp;
254  } gp;
255 
256  switch (type) {
257 
258  case H5UCHAR:
259  {
260  unsigned char uc;
261  gp.ucp = (unsigned char *) vals;
262 
263  uc = *(gp.ucp+loc);
264  rep << (int)uc;
265 
266  return rep.str();
267  }
268 
269  case H5CHAR:
270  {
271  gp.cp = (char *) vals;
272  char c;
273  c = *(gp.cp+loc);
274  // Since the character may be a special character and DAP may not be able to represent so supposedly we should escape the character
275  // by calling the escattr function. However, HDF5 native char maps to DAP Int16. So the mapping assumes that users will never
276  // use HDF5 native char or HDF5 unsigned native char to represent characters. Instead, HDF5 string should be used to represent characters.
277  // So don't do any escaping of H5CHAR for now. KY 2016-10-14
278  rep <<(int)c;
279  return rep.str();
280  }
281 
282 
283  case H5INT16:
284  {
285  gp.sp = (short *) vals;
286  rep<< *(gp.sp+loc);
287  return rep.str();
288  }
289 
290  case H5UINT16:
291 
292  {
293  gp.usp = (unsigned short *) vals;
294  rep << *(gp.usp+loc);
295  return rep.str();
296  }
297 
298 
299  case H5INT32:
300  {
301  gp.ip = (int *) vals;
302  rep << *(gp.ip+loc);
303  return rep.str();
304  }
305 
306  case H5UINT32:
307  {
308  gp.uip = (unsigned int *) vals;
309  rep << *(gp.uip+loc);
310  return rep.str();
311  }
312  case H5INT64: // For DAP4 CF support only
313  {
314  gp.llp = (long long *) vals;
315  rep << *(gp.llp+loc);
316  return rep.str();
317  }
318 
319  case H5UINT64: // For DAP4 CF support only
320  {
321  gp.ullp = (unsigned long long *) vals;
322  rep << *(gp.ullp+loc);
323  return rep.str();
324  }
325 
326 
327 
328  case H5FLOAT32:
329  {
330  float attr_val = *(float*)vals;
331  bool is_a_fin = isfinite(attr_val);
332  gp.fp = (float *) vals;
333  rep << showpoint;
334  rep << setprecision(10);
335  rep << *(gp.fp+loc);
336  string tmp_rep_str = rep.str();
337  if (tmp_rep_str.find('.') == string::npos
338  && tmp_rep_str.find('e') == string::npos
339  && tmp_rep_str.find('E') == string::npos
340  && (true == is_a_fin)){
341  rep<<".";
342  }
343  return rep.str();
344  }
345 
346  case H5FLOAT64:
347  {
348  double attr_val = *(double*)vals;
349  bool is_a_fin = isfinite(attr_val);
350  gp.dp = (double *) vals;
351  rep << std::showpoint;
352  rep << std::setprecision(17);
353  rep << *(gp.dp+loc);
354  string tmp_rep_str = rep.str();
355  if (tmp_rep_str.find('.') == string::npos
356  && tmp_rep_str.find('e') == string::npos
357  && tmp_rep_str.find('E') == string::npos
358  && (true == is_a_fin)) {
359  rep << ".";
360  }
361  return rep.str();
362  }
363  default:
364  return string("UNKNOWN");
365  }
366 
367 }
368 
369 // This helper function is used for 64-bit integer DAP4 support.
370 // We need to support the attributes of all types for 64-bit integer variables.
371 D4AttributeType HDF5CFDAPUtil::daptype_strrep_to_dap4_attrtype(const std::string &s){
372 
373  if (s == "Byte")
374  return attr_byte_c;
375  else if (s == "Int8")
376  return attr_int8_c;
377  else if (s == "UInt8") // This may never be used.
378  return attr_uint8_c;
379  else if (s == "Int16")
380  return attr_int16_c;
381  else if (s == "UInt16")
382  return attr_uint16_c;
383  else if (s == "Int32")
384  return attr_int32_c;
385  else if (s == "UInt32")
386  return attr_uint32_c;
387  else if (s == "Int64")
388  return attr_int64_c;
389  else if (s == "UInt64")
390  return attr_uint64_c;
391  else if (s == "Float32")
392  return attr_float32_c;
393  else if (s == "Float64")
394  return attr_float64_c;
395  else if (s == "String")
396  return attr_str_c;
397  else if (s == "Url")
398  return attr_url_c;
399  else
400  return attr_null_c;
401 
402 
403 }
404 
405 
static string escattr(string s)
Definition: h5cfdaputil.cc:60
static D4AttributeType daptype_strrep_to_dap4_attrtype(const string &s)
Definition: h5cfdaputil.cc:371
static string octstring(unsigned char val)
Helper function for escattr.
Definition: h5cfdaputil.cc:95
Helper functions for generating DAS attributes and a function to check BES Key.