bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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-2023 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 410 E University Ave,
22// Suite 200, Champaign, IL 61820
23
35
36
37#include "h5cfdaputil.h"
38#include <math.h>
39
40using namespace std;
41using 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
60string 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.size();
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.size();
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.
94string
95HDF5CFDAPUtil::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
105void 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
121string 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
181D4AttributeType 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
230H5DataType
231HDF5CFDAPUtil::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 shortcut for this function
235 return ((H5INT16 == dtype) && (1 == mem_dtype_size))?H5CHAR:dtype;
236}
237
238string
239HDF5CFDAPUtil:: print_attr(H5DataType type, unsigned 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 if (isnan(attr_val))
332 rep<<"NaN";
333 else {
334 gp.fp = (float *) vals;
335 rep << showpoint;
336 rep << setprecision(10);
337 rep << *(gp.fp+loc);
338#if 0
339 bool is_a_fin = isfinite(attr_val);
340 string tmp_rep_str = rep.str();
341 if (tmp_rep_str.find('.') == string::npos
342 && tmp_rep_str.find('e') == string::npos
343 && tmp_rep_str.find('E') == string::npos
344 && (true == is_a_fin)){
345 rep<<".";
346 }
347#endif
348 if ((rep.str().find_first_of(".eE")==string::npos) && isfinite(attr_val))
349 rep<<".";
350 }
351 return rep.str();
352 }
353
354 case H5FLOAT64:
355 {
356 double attr_val = *(double*)vals;
357 if (isnan(attr_val))
358 rep<<"NaN";
359 else {
360 gp.dp = (double *) vals;
361 rep << std::showpoint;
362 rep << std::setprecision(17);
363 rep << *(gp.dp+loc);
364#if 0
365 bool is_a_fin = isfinite(attr_val);
366 string tmp_rep_str = rep.str();
367 if (tmp_rep_str.find('.') == string::npos
368 && tmp_rep_str.find('e') == string::npos
369 && tmp_rep_str.find('E') == string::npos
370 && (true == is_a_fin)) {
371 rep << ".";
372 }
373#endif
374 if ((rep.str().find_first_of(".eE")==string::npos) && isfinite(attr_val))
375 rep<<".";
376 }
377 return rep.str();
378 }
379 default:
380 return string("UNKNOWN");
381 }
382
383}
384
385// This helper function is used for 64-bit integer DAP4 support.
386// We need to support the attributes of all types for 64-bit integer variables.
387D4AttributeType HDF5CFDAPUtil::daptype_strrep_to_dap4_attrtype(const std::string &s){
388
389 if (s == "Byte")
390 return attr_byte_c;
391 else if (s == "Int8")
392 return attr_int8_c;
393 else if (s == "UInt8") // This may never be used.
394 return attr_uint8_c;
395 else if (s == "Int16")
396 return attr_int16_c;
397 else if (s == "UInt16")
398 return attr_uint16_c;
399 else if (s == "Int32")
400 return attr_int32_c;
401 else if (s == "UInt32")
402 return attr_uint32_c;
403 else if (s == "Int64")
404 return attr_int64_c;
405 else if (s == "UInt64")
406 return attr_uint64_c;
407 else if (s == "Float32")
408 return attr_float32_c;
409 else if (s == "Float64")
410 return attr_float64_c;
411 else if (s == "String")
412 return attr_str_c;
413 else if (s == "Url")
414 return attr_url_c;
415 else
416 return attr_null_c;
417
418
419}
420
421
static string escattr(string s)
static D4AttributeType daptype_strrep_to_dap4_attrtype(const string &s)
static string octstring(unsigned char val)
Helper function for escattr.
Helper functions for generating DAS attributes and a function to check BES Key.