bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
ffdds.cc
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// (c) COPYRIGHT URI/MIT 1997-99
25// Please read the full copyright statement in the file COPYRIGHT.
26//
27// Authors: reza (Reza Nekovei)
28
29// This file contains functions which read the variables and their description
30// from a freeform API and build the in-memory DDS. These functions form the
31// core of the server-side software necessary to extract the DDS from a
32// FreeForm data file.
33//
34// It also contains test code which will print the in-memory DDS to
35// stdout.
36//
37// ReZa 6/20/97
38
39#include "config_ff.h"
40
41#include <cstdio>
42#include <cstring>
43
44#include <iostream>
45#include <string>
46
47#include <libdap/Error.h>
48#include <libdap/InternalErr.h>
49#include <libdap/mime_util.h>
50#include <libdap/util.h>
51
52#include "FreeFormCPP.h"
53
54#include <libdap/DDS.h>
55
56#include "FFInt16.h"
57#include "FFUInt16.h"
58#include "FFInt32.h"
59#include "FFUInt32.h"
60#include "FFFloat32.h"
61#include "FFFloat64.h"
62#include "FFByte.h"
63#include "FFArray.h"
64#include "FFSequence.h"
65#include "FFGrid.h"
66#include "FFStr.h"
67#include "util_ff.h"
68
69#include "FFRequestHandler.h"
70
71void ff_read_descriptors(DDS &dds_table, const string &filename)
72{
73 if (!file_exist(filename.c_str()))
74 throw Error((string) "Could not open file " + path_to_filename(filename) + string("."));
75
76 // Set dataset name
77 dds_table.set_dataset_name(name_path(filename));
78
79 FF_STD_ARGS_PTR SetUps = NULL;
80 SetUps = ff_create_std_args();
81 if (!SetUps)
82 throw Error("Insufficient memory");
83
84 // Set the structure values to create the FreeForm DB
85 SetUps->user.is_stdin_redirected = 0;
86
87 SetUps->input_file = const_cast<char*>(filename.c_str());
88
89 // Setting the input format file here causes db_set (called by SetDodsDB)
90 // to not set that field of SetUps. In the original modification for the
91 // RSS-hosted data, the server also called this code in FFArray.cc and
92 // FFSequence. However, in a later version of the handler I moved the
93 // format finding code here and recorded the results in the various
94 // objects (including FFArray, ...). So I think the RSS format-specific
95 // code in those classes is not needed anymore. I'm going to #if 0 #endif
96 // them out and check in the result. 10/30/08 jhrg
97 string iff = "";
98 if (FFRequestHandler::get_RSS_format_support()) {
99 iff = find_ancillary_rss_formats(filename);
100 SetUps->input_format_file = const_cast<char*>(iff.c_str());
101 }
102 // Regex support
103 if (FFRequestHandler::get_Regex_format_support()) {
104 iff = get_Regex_format_file(filename);
105 if (!iff.empty())
106 SetUps->input_format_file = const_cast<char*>(iff.c_str());
107 }
108
109 SetUps->output_file = NULL;
110
111 DATA_BIN_PTR dbin = NULL;
112 char Msgt[Msgt_size];
113 int error = SetDodsDB(SetUps, &dbin, Msgt);
114 if (error && error < ERR_WARNING_ONLY) {
115 if (dbin)
116 db_destroy(dbin);
117 ff_destroy_std_args(SetUps);
118 string msg = (string) Msgt + " FreeForm error code: ";
119 append_long_to_string((long) error, 10, msg);
120 throw Error(msg);
121 }
122
123 ff_destroy_std_args(SetUps);
124
125 // These things are defined here so that they can be freed in the catch(...)
126 // clause below
127 PROCESS_INFO_LIST pinfo_list = NULL;
128 char **var_names_vector = NULL;
129 char **dim_names_vector = NULL;
130 Array *ar = NULL;
131 Sequence *seq = NULL;
132
133 try {
134
135 int num_names = 0;
136 error = db_ask(dbin, DBASK_VAR_NAMES, FFF_INPUT | FFF_DATA, &num_names, &var_names_vector);
137 if (error) {
138 string msg = "Could not get variable list from the input file. FreeForm error code: ";
139 append_long_to_string((long) error, 10, msg);
140 throw Error(msg);
141 }
142
143 error = db_ask(dbin, DBASK_PROCESS_INFO, FFF_INPUT | FFF_DATA, &pinfo_list);
144 if (error) {
145 string msg = "Could not get process info for the input file. FreeForm error code: ";
146 append_long_to_string((long) error, 10, msg);
147 throw Error(msg);
148 }
149
150 bool newseq = true;
151 bool is_array = true;
152 for (int i = 0; i < num_names; i++) {
153 int num_dim_names = 0;
154
155 char *cp = NULL;
156
157 error = db_ask(dbin, DBASK_ARRAY_DIM_NAMES, var_names_vector[i], &num_dim_names, &dim_names_vector);
158 if (error) {
159 string msg = "Could not get array dimension names for variable: ";
160 msg += (string) var_names_vector[i] + ", FreeForm error code: ";
161 append_long_to_string((long) error, 10, msg);
162 throw Error(msg);
163 }
164
165 if (num_dim_names == 0) // sequence names
166 cp = var_names_vector[i];
167 else {
168 cp = strstr(var_names_vector[i], "::");
169 // If cp is not null, advance past the "::"
170 if (cp)
171 cp += 2;
172 }
173
174 pinfo_list = dll_first(pinfo_list);
175 PROCESS_INFO_PTR pinfo = ((PROCESS_INFO_PTR) (pinfo_list)->data.u.pi);
176 FORMAT_PTR iformat = PINFO_FORMAT(pinfo);
177 VARIABLE_PTR var = ff_find_variable(cp, iformat);
178
179 // For some formats Freefrom sends an extra EOL variable at the end of
180 // the list.
181 if (IS_EOL(var)) {
182 memFree(dim_names_vector, "**dim_names_vector");
183 dim_names_vector = NULL;
184 break;
185 }
186
187 while (!var) { // search formats in the format list for the variable
188 pinfo_list = (pinfo_list)->next;
189 pinfo = ((PROCESS_INFO_PTR) (pinfo_list)->data.u.pi);
190
191 if (!pinfo) {
192 string msg = "Variable " + (string)cp + " was not found in the format file.";
193 throw Error(msg);
194 }
195
196 iformat = PINFO_FORMAT(pinfo);
197 var = ff_find_variable(cp, iformat);
198 }
199
200 string input_format_file = PINFO_ORIGIN(pinfo);
201
202 BaseType *bt = NULL;
203 switch (FFV_DATA_TYPE(var)) {
204 case FFV_TEXT:
205 bt = new FFStr(cp, filename);
206 static_cast<FFStr&>(*bt).set_size(var->end_pos - var->start_pos + 1);
207 break;
208
209 case FFV_INT8:
210 bt = new FFByte(cp, filename);
211 break;
212
213 case FFV_UINT8:
214 bt = new FFByte(cp, filename); // Byte is unsigned.
215 break;
216
217 case FFV_INT16:
218 bt = new FFInt16(cp, filename);
219 break;
220
221 case FFV_UINT16:
222 bt = new FFUInt16(cp, filename);
223 break;
224
225 case FFV_INT32:
226 bt = new FFInt32(cp, filename);
227 break;
228
229 case FFV_UINT32:
230 bt = new FFUInt32(cp, filename);
231 break;
232
233 case FFV_INT64:
234 bt = new FFInt32(cp, filename); // Ouch!
235 break;
236
237 case FFV_UINT64:
238 bt = new FFUInt32(cp, filename);
239 break;
240
241 case FFV_FLOAT32:
242 bt = new FFFloat32(cp, filename);
243 break;
244
245 case FFV_FLOAT64:
246 bt = new FFFloat64(cp, filename);
247 break;
248
249 case FFV_ENOTE:
250 bt = new FFFloat64(cp, filename);
251 break;
252
253 default:
254 throw InternalErr(__FILE__, __LINE__, "Unknown FreeForm type!");
255 }
256
257 if (num_dim_names == 0) {
258 if (!seq || newseq) {
259 newseq = false;
260 // The format name cannot contain spaces! 8/12/98 jhrg
261 seq = new FFSequence(iformat->name, filename, input_format_file);
262 }
263 seq->add_var_nocopy(bt);
264 is_array = false;
265 }
266 else {
267 ar = new FFArray(cp, filename, bt, input_format_file);
268 delete bt;
269 newseq = true; // An array terminates the old sequence
270 is_array = true;
271 //} The follow loop was separate from this else clause but the
272 // loop won't run if num_dim_names is not > 0
273
274 for (int j = 0; j < num_dim_names; j++) {
275 FF_ARRAY_DIM_INFO_PTR array_dim_info = NULL;
276
277 error = db_ask(dbin, DBASK_ARRAY_DIM_INFO, var_names_vector[i], dim_names_vector[j],
278 &array_dim_info);
279 if (error) {
280 string msg = string("Could not get array dimension info for variable ")
281 + string(var_names_vector[i]) + string(", FreeForm error code: ");
282 append_long_to_string((long) error, 10, msg);
283 throw Error(msg);
284 }
285
286 int DimSiz = (array_dim_info->end_index - array_dim_info->start_index + 1)
287 / array_dim_info->granularity;
288 ar->append_dim(DimSiz, (string) dim_names_vector[j]);
289
290 memFree(array_dim_info, "");
291 array_dim_info = NULL;
292 }
293 }
294
295 memFree(dim_names_vector, "**dim_names_vector");
296 dim_names_vector = NULL;
297
298 if (is_array)
299 dds_table.add_var_nocopy(ar);
300 else if (newseq)
301 dds_table.add_var_nocopy(seq);
302 } // End of the for num_names.
303
304 if (!is_array)
305 dds_table.add_var_nocopy(seq);
306 }
307 catch (...) {
308 // Because these are added to the DDS using the nocopy methods,
309 // they should only be deleted when an excpetion is thrown
310 delete seq;
311 delete ar;
312
313 if (dbin)
314 db_destroy(dbin);
315 if (var_names_vector)
316 memFree(var_names_vector, "**var_names_vector");
317 if (pinfo_list)
318 ff_destroy_process_info_list(pinfo_list);
319 if (dim_names_vector)
320 memFree(dim_names_vector, "**dim_names_vector");
321
322 throw;
323 }
324
325 if (dbin)
326 db_destroy(dbin);
327 if (var_names_vector)
328 memFree(var_names_vector, "**var_names_vector");
329 if (pinfo_list)
330 ff_destroy_process_info_list(pinfo_list);
331 if (dim_names_vector)
332 memFree(dim_names_vector, "**dim_names_vector");
333}
Definition FFStr.h:47