OPeNDAP Hyrax Back End Server (BES)  Updated for version 3.8.3
ffdas.cc
Go to the documentation of this file.
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of ff_handler a FreeForm API handler for the OPeNDAP
4 // DAP2 data server.
5 
6 // Copyright (c) 2005 OPeNDAP, Inc.
7 // Author: James Gallagher <jgallagher@opendap.org>
8 //
9 // This is free software; you can redistribute it and/or modify it under the
10 // terms of the GNU Lesser General Public License as published by the Free
11 // Software Foundation; either version 2.1 of the License, or (at your
12 // option) any later version.
13 //
14 // This software is distributed in the hope that it will be useful, but
15 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
17 // License for more details.
18 //
19 // You should have received a copy of the GNU Lesser General Public
20 // License along with this library; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 //
23 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
24 
25 // (c) COPYRIGHT URI/MIT 1997-98
26 // Please read the full copyright statement in the file COPYRIGHT.
27 //
28 // Authors: reza (Reza Nekovei)
29 
30 // This file contains functions which read the variables and their attributes
31 // from a netcdf file and build the in-memeory DAS. These functions form the
32 // core of the server-side software necessary to extract the DAS from a
33 // netcdf data file.
34 //
35 // ReZa 6/23/97
36 
37 #include "config_ff.h"
38 
39 #include <cstdio>
40 #include <cstring>
41 
42 #include <iostream>
43 #include <string>
44 
45 #include <util.h>
46 #include <DAS.h>
47 #include <Error.h>
48 #include <InternalErr.h>
49 
50 #include "FreeFormCPP.h"
51 #include "FFRequestHandler.h"
52 #include "util_ff.h"
53 #include "freeform.h"
54 
55 // Added 7/30/08 as part of the fix for ticket #1163. jhrg
56 #define ATTR_STRING_QUOTE_FIX
57 
58 // Read header information and populate an AttrTable with the information.
59 
60 static void header_to_attributes(AttrTable *at, DATA_BIN_PTR dbin)
61 {
62  PROCESS_INFO_LIST pinfo_list = NULL;
63  PROCESS_INFO_PTR hd_pinfo = NULL;
64 
65  char text[256];
66 
67  int error = db_ask(dbin, DBASK_PROCESS_INFO, FFF_INPUT | FFF_FILE | FFF_HEADER, &pinfo_list);
68  // A general error indicates that the dataset does not have a header.
69  // Anything else is bad news. 1/29/2001 jhrg
70  if (error) {
71  if (error == ERR_GENERAL) {
72  return;
73  }
74  else {
75  string msg = "Cannot get attribute values. FreeForm error code: ";
76  append_long_to_string((long) error, 10, msg);
77  throw Error(msg);
78  }
79  }
80 
81  pinfo_list = dll_first(pinfo_list);
82  hd_pinfo = ((PROCESS_INFO_PTR) (pinfo_list)->data.u.pi);
83  if (hd_pinfo) {
84  VARIABLE_LIST vlist = NULL;
85  VARIABLE_PTR var = NULL;
86 
87  vlist = FFV_FIRST_VARIABLE(PINFO_FORMAT(hd_pinfo));
88  var = ((VARIABLE_PTR) (vlist)->data.u.var);
89 
90  while (var) {
91  if (IS_EOL(var)) {
92  vlist = (vlist)->next;
93  var = ((VARIABLE_PTR) (vlist)->data.u.var);
94 
95  continue;
96  }
97 
98  switch (FFV_DATA_TYPE(var)) {
99  case FFV_TEXT:
100  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_TEXT, text);
101 #ifndef ATTR_STRING_QUOTE_FIX
102  // Multiple word strings must be quoted.
103  if (strpbrk(text, " \r\t")) { // Any whitespace?
104  string quoted_text;
105  quoted_text = (string)"\"" + text + "\"";
106  at->append_attr(var->name, "STRING",
107  quoted_text.c_str());
108  }
109  else {
110  at->append_attr(var->name, "STRING", text);
111  }
112 #else
113  // The new version of libdap provides the quotes when
114  // printing the DAS. The DDX does not need quotes. jhrg
115  // 7/30/08
116  at->append_attr(var->name, "STRING", text);
117 #endif
118  break;
119 
120  case FFV_INT8:
121  unsigned char int8;
122  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_INT8, &int8);
123  snprintf(text, sizeof(text), "%d", int8);
124  at->append_attr(var->name, "BYTE", text);
125  break;
126 
127  case FFV_INT16:
128  short int16;
129  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_INT16, &int16);
130  snprintf(text, sizeof(text), "%d", int16);
131  at->append_attr(var->name, "INT16", text);
132  break;
133 
134  case FFV_INT32:
135  int int32;
136  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_INT32, &int32);
137  snprintf(text, sizeof(text), "%d", int32);
138  at->append_attr(var->name, "INT32", text);
139  break;
140 
141  case FFV_INT64:
142  long int64;
143  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_INT64, &int64);
144  snprintf(text, sizeof(text), "%ld", int64);
145  at->append_attr(var->name, "INT32", text);
146  break;
147 
148  case FFV_UINT8:
149  unsigned char uint8;
150  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_UINT8, &uint8);
151  snprintf(text, sizeof(text), "%d", uint8);
152  at->append_attr(var->name, "BYTE", text);
153  break;
154 
155  case FFV_UINT16:
156  unsigned short uint16;
157  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_UINT16, &uint16);
158  snprintf(text, sizeof(text), "%d", uint16);
159  at->append_attr(var->name, "UINT16", text);
160  break;
161 
162  case FFV_UINT32:
163  unsigned int uint32;
164  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_UINT32, &uint32);
165  snprintf(text, sizeof(text), "%u", uint32);
166  at->append_attr(var->name, "UINT32", text);
167  break;
168 
169  case FFV_UINT64:
170  unsigned long uint64;
171  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_UINT64, &uint64);
172  snprintf(text, sizeof(text), "%lu", uint64);
173  at->append_attr(var->name, "UINT32", text);
174  break;
175 
176  case FFV_FLOAT32:
177  float float32;
178  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_FLOAT32, &float32);
179  snprintf(text, sizeof(text), "%f", float32);
180  at->append_attr(var->name, "FLOAT32", text);
181  break;
182 
183  case FFV_FLOAT64:
184  double float64;
185  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_FLOAT64, &float64);
186  snprintf(text, sizeof(text), "%f", float64);
187  at->append_attr(var->name, "FLOAT64", text);
188  break;
189 
190  case FFV_ENOTE:
191  double enote;
192  nt_ask(dbin, FFF_FILE | FFF_HEADER, var->name, FFV_ENOTE, &enote);
193  snprintf(text, sizeof(text), "%e", enote);
194  at->append_attr(var->name, "FLOAT64", text);
195  break;
196 
197  default:
198  throw InternalErr(__FILE__, __LINE__, "Unknown FreeForm type!");
199  }
200  vlist = (vlist)->next;
201  var = ((VARIABLE_PTR) (vlist)->data.u.var);
202  }
203  }
204 }
205 
210 void read_attributes(string filename, AttrTable *at)
211 {
212  int error = 0;
213  FF_BUFSIZE_PTR bufsize = NULL;
214  DATA_BIN_PTR dbin = NULL;
215  FF_STD_ARGS_PTR SetUps = NULL;
216 
217  if (!file_exist(filename.c_str()))
218  throw Error((string) "Could not open file " + path_to_filename(filename) + ".");
219 
220  // ff_create_std_args uses calloc so the struct's pointers are all initialized
221  // to null.
222  SetUps = ff_create_std_args();
223  if (!SetUps)
224  throw Error("ff_das: Insufficient memory");
225 
227  SetUps->user.is_stdin_redirected = 0;
228 
229  // Use const_cast because FF only copies the referenced data; the older
230  // version of this handler allocated memory, copied values, leaked the
231  // memory...
232  SetUps->input_file = const_cast<char*>(filename.c_str());
233 
235  string iff = find_ancillary_rss_formats(filename);
236  SetUps->input_format_file = const_cast<char*>(iff.c_str());
237  }
238 
239  SetUps->output_file = NULL;
240 
241  char Msgt[255];
242  error = SetDodsDB(SetUps, &dbin, Msgt);
243  if (error && error < ERR_WARNING_ONLY) {
244  if (dbin)
245  db_destroy(dbin);
246  ff_destroy_std_args(SetUps);
247  throw Error(Msgt);
248  }
249 
250  ff_destroy_std_args(SetUps);
251 
252  try {
253  error = db_ask(dbin, DBASK_FORMAT_SUMMARY, FFF_INPUT, &bufsize);
254  if (error) {
255  string msg = "Cannot get Format Summary. FreeForm error code: ";
256  append_long_to_string((long) error, 10, msg);
257  throw Error(msg);
258  }
259 
260 #ifndef ATTR_STRING_QUOTE_FIX
261  at->append_attr("Server", "STRING",
262  "\"DODS FreeFrom based on FFND release " + FFND_LIB_VER + "\"");
263 #else
264  at->append_attr("Server", "STRING", string("DODS FreeFrom based on FFND release ") + FFND_LIB_VER);
265 #endif
266 
267  header_to_attributes(at, dbin); // throws Error
268  }
269  catch (...) {
270  if (bufsize)
271  ff_destroy_bufsize(bufsize);
272  if (dbin)
273  db_destroy(dbin);
274 
275  throw;
276  }
277 
278  ff_destroy_bufsize(bufsize);
279  db_destroy(dbin);
280 }
281 
282 static void add_variable_containers(DAS &das, const string &filename) throw (Error)
283 {
284  if (!file_exist(filename.c_str()))
285  throw Error(string("ff_dds: Could not open file ") + path_to_filename(filename) + string("."));
286 
287  // Setup the DB access.
289  if (!SetUps)
290  throw Error("Insufficient memory");
291 
292  SetUps->user.is_stdin_redirected = 0;
293 
294  SetUps->input_file = const_cast<char*>(filename.c_str());
295 
297  string iff = find_ancillary_rss_formats(filename);
298  SetUps->input_format_file = const_cast<char*>(iff.c_str());
299  }
300 
301  SetUps->output_file = NULL;
302 
303  // Set the structure values to create the FreeForm DB
304  char Msgt[255];
305  DATA_BIN_PTR dbin = NULL;
306  int error = SetDodsDB(SetUps, &dbin, Msgt);
307  if (error && error < ERR_WARNING_ONLY) {
308  if (dbin)
309  db_destroy(dbin);
310  ff_destroy_std_args(SetUps);
311  string msg = string(Msgt) + " FreeForm error code: ";
312  append_long_to_string((long) error, 10, msg);
313  throw Error(msg);
314  }
315 
316  ff_destroy_std_args(SetUps);
317 
318  // These are defined here so that they can be freed in the catch(...)
319  // block below
320  char **var_names_vector = NULL;
321  PROCESS_INFO_LIST pinfo_list = NULL;
322  char **dim_names_vector = NULL;
323 
324  try {
325  // Get the names of all the variables.
326  int num_names = 0;
327  error = db_ask(dbin, DBASK_VAR_NAMES, FFF_INPUT | FFF_DATA, &num_names, &var_names_vector);
328  if (error) {
329  string msg = "Could not get varible list from the input file. FreeForm error code: ";
330  append_long_to_string((long) error, 10, msg);
331  throw Error(msg);
332  }
333 
334  // I don't understand why this has to happen here, but maybe it's moved
335  // outside the loop because FreeForm is designed so that the pinfo list
336  // only needs to be accessed once and can be used when working with
337  // any/all of the variables. 4/4/2002 jhrg
338  error = db_ask(dbin, DBASK_PROCESS_INFO, FFF_INPUT | FFF_DATA, &pinfo_list);
339  if (error) {
340  string msg = "Could not get process info for the input file. FreeForm error code: ";
341  append_long_to_string((long) error, 10, msg);
342  throw Error(msg);
343  }
344 
345  // For each variable, figure out what its name really is (arrays have
346  // funny names).
347  for (int i = 0; i < num_names; i++) {
348  int num_dim_names = 0;
349  error = db_ask(dbin, DBASK_ARRAY_DIM_NAMES, var_names_vector[i], &num_dim_names, &dim_names_vector);
350  if (error) {
351  string msg = "Could not get array dimension names for variable: " + string(var_names_vector[i])
352  + string(", FreeForm error code: ");
353  append_long_to_string((long) error, 10, msg);
354  throw Error(msg);
355  }
356 
357  // Note: FreeForm array names are returned appended to their format
358  // name with '::'.
359  char *cp = NULL;
360  if (num_dim_names == 0) // sequence names
361  cp = var_names_vector[i];
362  else {
363  cp = strstr(var_names_vector[i], "::");
364  // If cp is not null, advance past the "::"
365  if (cp)
366  cp += 2;
367  }
368 
369  // We need this to figure out if this variable is the/a EOL
370  // variable. We read the pinfo_list just before starting this
371  // for-loop.
372  pinfo_list = dll_first(pinfo_list);
373  PROCESS_INFO_PTR pinfo = ((PROCESS_INFO_PTR) (pinfo_list)->data.u.pi);
374  FORMAT_PTR iformat = PINFO_FORMAT(pinfo);
375  VARIABLE_PTR var = ff_find_variable(cp, iformat);
376 
377  // For some formats: Freefrom sends an extra EOL variable at the end of
378  // the list. Add an attribute container for all the other variables.
379  if (!IS_EOL(var))
380  das.add_table(cp, new AttrTable);
381 
382  memFree(dim_names_vector, "**dim_names_vector");
383  dim_names_vector = NULL;
384  }
385  }
386  catch (...) {
387  if (var_names_vector)
388  memFree(var_names_vector, "**var_names_vector");
389  if (pinfo_list)
390  ff_destroy_process_info_list(pinfo_list);
391  if (dim_names_vector)
392  memFree(dim_names_vector, "**dim_names_vector");
393  if (dbin)
394  db_destroy(dbin);
395 
396  throw;
397  }
398 
399  memFree(var_names_vector, "**var_names_vector");
400  var_names_vector = NULL;
401 
402  ff_destroy_process_info_list(pinfo_list);
403  db_destroy(dbin);
404 }
405 
406 // Given a reference to an instance of class DAS and a filename that refers
407 // to a freefrom file, read the format file and extract the existing
408 // attributes and add them to the instance of DAS.
409 //
410 // Returns: false if an error accessing the file was detected, true
411 // otherwise.
412 
413 void ff_get_attributes(DAS &das, string filename) throw (Error)
414 {
415  AttrTable *attr_table_p = new AttrTable;
416 
417  das.add_table("FF_GLOBAL", attr_table_p);
418  read_attributes(filename, attr_table_p);
419  // Add a table/container for each variable. See bug 284. The DAP spec
420  // calls for each variable to have an attribute container, even if it is
421  // empty. Previously the server did not have containers for all the
422  // variables. 4/4/2002 jhrg
423  add_variable_containers(das, filename);
424 }
#define FFV_UINT16
Definition: freeform.h:532
void ff_destroy_process_info_list(PROCESS_INFO_LIST)
char * input_format_file
Definition: freeform.h:874
#define memFree(P, TAG)
Definition: memtrack.h:141
const string find_ancillary_rss_formats(const string &dataset, const string &, const string &)
Find the RSS (Remote Sensing Systems) format file using their naming convention.
Definition: util_ff.cc:550
#define FFV_FLOAT64
Definition: freeform.h:538
#define DBASK_ARRAY_DIM_NAMES
Definition: freeform.h:1349
#define FFF_INPUT
Definition: freeform.h:660
bool file_exist(const char *filename)
Definition: util_ff.cc:532
VARIABLE_PTR ff_find_variable(char *, FORMAT_PTR)
void ff_destroy_bufsize(FF_BUFSIZE_PTR bufsize)
#define FFV_FLOAT32
Definition: freeform.h:537
int SetDodsDB(FF_STD_ARGS_PTR std_args, DATA_BIN_HANDLE dbin_h, char *Msgt)
Given a set of standard arguments (input filenames), allocate a DATA-BIN_HANDLE and return an error c...
Definition: util_ff.cc:402
DLL_NODE_PTR dll_first(DLL_NODE_PTR node)
struct struct_ff_std_args::struct_std_args_user user
#define DBASK_PROCESS_INFO
Definition: freeform.h:1343
#define DBASK_VAR_NAMES
Definition: freeform.h:1344
#define FFV_TEXT
Definition: freeform.h:499
void ff_get_attributes(DAS &das, string filename)
Definition: ffdas.cc:413
#define FFND_LIB_VER
Definition: freeform.h:23
#define NULL
Definition: wcsUtil.h:65
#define DBASK_FORMAT_SUMMARY
Definition: freeform.h:1342
#define FFV_UINT32
Definition: freeform.h:534
#define FFF_DATA
Definition: freeform.h:656
#define FFV_INT16
Definition: freeform.h:531
#define FFV_DATA_TYPE(v)
Definition: freeform.h:818
char * output_file
Definition: freeform.h:877
#define PINFO_FORMAT(pi)
Definition: freeform.h:1394
void ff_destroy_std_args(FF_STD_ARGS_PTR)
#define ERR_WARNING_ONLY
Definition: err.h:130
void db_destroy(DATA_BIN_PTR)
#define IS_EOL(v)
Definition: freeform.h:621
FF_STD_ARGS_PTR ff_create_std_args(void)
#define FFV_UINT64
Definition: freeform.h:536
#define FFV_UINT8
Definition: freeform.h:530
int db_ask(DATA_BIN_PTR, int,...)
struct struct_ff_variable * VARIABLE_PTR
Definition: freeform.h:1016
#define FFF_FILE
Definition: freeform.h:654
#define FFV_INT64
Definition: freeform.h:535
#define FFV_FIRST_VARIABLE(f)
Definition: freeform.h:811
void read_attributes(string filename, AttrTable *at)
Read the attributes and store their names and values in the attribute table.
Definition: ffdas.cc:210
struct struct_ff_process_info * PROCESS_INFO_PTR
Definition: freeform.h:1192
int nt_ask(DATA_BIN_PTR, FF_TYPES_t origin, char *name, FF_TYPES_t value_type, void *value)
#define FFV_ENOTE
Definition: freeform.h:539
static bool get_RSS_format_support()
#define FFV_INT32
Definition: freeform.h:533
#define FFV_INT8
Definition: freeform.h:529
#define ERR_GENERAL
Definition: err.h:31
#define FFF_HEADER
Definition: freeform.h:653