bufr2synop 0.24.0
bufrdeco.c
Go to the documentation of this file.
1/***************************************************************************
2 * Copyright (C) 2013-2022 by Guillermo Ballester Valor *
3 * gbv@ogimet.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20/*!
21 \file bufrdeco.c
22 \brief This file has the code for library bufrdeco API functions
23*/
24#ifndef CONFIG_H
25# include "config.h"
26# define CONFIG_H
27#endif
28
29#include "bufrdeco.h"
30
31#ifdef DEBUG_TIME
32 clock_t bufrdeco_clock_start, bufrdeco_clock_end;
33#endif
34
35/*!
36 \fn char *bufrdeco_get_version(char *version, char *build, char *builder, int *version_major, int *version_minor, int *version_patch)
37 \brief Get strings with version information and build date and time
38 \param version pointer to string with version as result if not NULL
39 \param dversion dimension of string \ref version
40 \param build pointer to string with compiler and compilation date and time if not NULL
41 \param dbuild dimension of string \ref build
42 \param builder pointer to string with builder utility. 'cmake' or 'autotools' if not NULL
43 \param dbuilder dimension of string \ref builder
44 \param version_major pointer to string with version_major component if not NULL
45 \param version_minor pointer to string with version_minor component if not NULL
46 \param version_patch pointer to string with version_patch component if not NULL
47
48 Retuns string pointer \ref version.
49 */
50char *bufrdeco_get_version ( char *version, size_t dversion, char *build, size_t dbuild, char *builder, size_t dbuilder,
51 int *version_major, int *version_minor, int *version_patch )
52{
53 int major = 0, minor = 0, patch = 0;
54 size_t used;
55
56 // Check argument
57 if ( version == NULL )
58 return NULL;
59
60 snprintf ( version, dversion, "%s", VERSION );
61 // default
62 sscanf ( version, "%d.%d.%d", &major, &minor, &patch );
63
64 if ( build )
65 {
66 used = 0;
67#if defined(__INTEL_COMPILER)
68 used += snprintf ( build + used, dbuild - used, "using INTEL C compiler icc %d.%d ", __INTEL_COMPILER, __INTEL_COMPILER_UPDATE );
69#elif defined(__clang_version__)
70 used += snprintf ( build + used, dbuild - used, "using clang C compiler ", __clang_version__ );
71#elif defined(__GNUC__)
72 used += snprintf ( build + used, dbuild - used, "using GNU C compiler gcc %d.%d.%d ", __GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__ );
73#elif defined(_MSC_VER)
74 used += snprintf ( build + used, dbuild - used, "using MICROSOFT C compiler %d ", _MSC_VER );
75#else
76 used += snprintf ( build + used, dbuild - used, "using an unknown C compiler " );
77#endif
78 snprintf ( build + used, dbuild - used,"at %s %s",__DATE__,__TIME__ );
79 }
80
81 if ( builder )
82#ifdef BUILD_USING_CMAKE
83 strncpy_safe ( builder, "cmake", dbuilder );
84#else
85 strncpy_safe ( builder, "autotools", dbuilder );
86#endif
87 if ( version_major )
88 *version_major = major;
89 if ( version_minor )
90 *version_minor = minor;
91 if ( version_patch )
92 *version_patch = patch;
93 return version;
94}
95
96/*!
97 \fn int bufrdeco_parse_tree ( struct bufrdeco *b )
98 \brief Parse the tree of descriptors without expand the replicators
99 \param b Pointer to the source struct \ref bufrdeco
100
101 This is the user function to parse the descriptor structure of a BUFR report. This is the first task
102 we need to perform after read the bufr report with the aid of \ref bufrdeco_read_bufr function.
103
104 At the end we will get an array of structs \ref bufr_sequence defining the tree
105
106 A sequence layer is needed when parsing expanded descriptor sec3 and sec4
107
108 First bufr_sequence is the sequence of descriptors in sec3 after
109 byte 8. This is a bufr_sequence in level 0.
110
111 When a sequence descriptor is found in a layer, the sequence entries found in table D
112 form this descriptor is a son bufr_sequence. This son has then a father
113 and also can have one or more sons. The index level is incremented by one every step it
114 go into decendents.
115
116 And so we go in a recursive way up to the end.
117
118 \return If success return 0, if something went wrong return 1
119*/
121{
122 bufrdeco_assert ( b != NULL );
123
124 // here we start the parse
125 return bufrdeco_parse_tree_recursive ( b, NULL, 0, NULL );
126}
127
128/*!
129 \fn int bufrdeco_init(struct bufrdeco *b)
130 \brief Inits and allocate memory for a struct \ref bufrdeco
131 \param b pointer to the target struct
132
133 This function only must be called once. When finished the function \ref bufrdeco_close must be called to
134 free all needed memory
135
136 \return If succeeded return 0, otherwise 1
137*/
138int bufrdeco_init ( struct bufrdeco *b )
139{
140 bufrdeco_assert ( b != NULL );
141
142 // First clear all
143 memset ( b, 0, sizeof ( struct bufrdeco ) );
144
145 // Then allocate all needed memory when starting. Further we will need to allocate some more depending on
146 // data
147
148 // allocate memory for Tables
149 if ( bufrdeco_init_tables ( &b->tables ) )
150 {
151 snprintf ( b->error, sizeof ( b->error ),"%s(): Cannot allocate space for tables\n", __func__ );
152 return 1;
153 }
154
155 // Output default streams
156 b->out = stdout;
157 b->err = stderr;
158
159 // allocate memory for expanded tree of descriptors
160 if ( bufrdeco_init_expanded_tree ( &b->tree ) )
161 {
162 snprintf ( b->error, sizeof ( b->error ),"%s(): Cannot allocate space for expanded tree of descriptors\n", __func__ );
163 return 1;
164 }
165
166
167 return 0;
168}
169
170/*!
171 \fn int bufrdeco_reset(struct bufrdeco *b)
172 \brief Reset an struct \ref bufrdeco. This is needed when changing to another bufr.
173 \param b pointer to the target struct to be resed with another bufrfile
174
175 This function must be called when parsing another BUFR report without calling
176 \ref bufrdeco_close and \ref bufrdeco_init. It
177
178 \return If succeeded return 0, otherwise 1
179*/
180int bufrdeco_reset ( struct bufrdeco *b )
181{
182 struct bufr_tables *tb;
183 struct bufr_tables_cache ch;
184 FILE *out,*err;
185 uint32_t mask;
186 bufrdeco_assert ( b != NULL );
187
188 // save the data we do not reset
189 memcpy(&ch, &b->cache, sizeof (struct bufr_tables_cache));
190 tb = b->tables;
191 mask = b->mask;
192 out = b->out;
193 err = b->err;
198
199 memset ( b, 0, sizeof ( struct bufrdeco ) );
200
201 // Restore data
202 b->out = out;
203 b->err = err;
204 b->mask = mask;
205 b->tables = tb;
206 memcpy(&b->cache, &ch, sizeof (struct bufr_tables_cache));
207
208 // allocate memory for expanded tree of descriptors
209 if ( bufrdeco_init_expanded_tree ( &b->tree ) )
210 {
211 snprintf ( b->error, sizeof ( b->error ),"%s(): Cannot allocate space for expanded tree of descriptors\n", __func__ );
212 return 1;
213 }
214
215 return 0;
216}
217
218/*!
219 * \fn int bufrdeco_set_out_stream (FILE *out, struct bufrdeco *b)
220 * \brief Set the library normal output stream.
221 * \param out stream opened by caller
222 * \param b pointer to current active struct \ref bufrdeco
223 * \return If succeeded return 0, otherwise 1
224 *
225 * Without calling to this funcion, the default is stdout
226*/
227int bufrdeco_set_out_stream (FILE *out, struct bufrdeco *b)
228{
229 b->out = out;
230 return 0;
231}
232
233/*!
234 * \fn int bufrdeco_set_err_stream (FILE *err, struct bufrdeco *b)
235 * \brief Set the error stream.
236 * \param err stream opened by caller
237 * \param b pointer to current active struct \ref bufrdeco
238 * \return If succeeded return 0, otherwise 1
239 *
240 * Without calling to this funcion, the default is stderr
241 */
242int bufrdeco_set_err_stream (FILE *err, struct bufrdeco *b)
243{
244 b->out = err;
245 return 0;
246}
247
248/*!
249 \fn int bufrdeco_close ( struct bufrdeco *b )
250 \brief Free all allocated memory. Needed when no more task to do with bufrdeco library
251 \param b pointer to the target struct
252 \return If succeeded return 0, otherwise 1
253
254 This function must be called at the end when no more calls to bufrdeco library is needed
255
256 b->out and b->err must be closed by caller if are not the default stdout or stderr
257
258*/
259int bufrdeco_close ( struct bufrdeco *b )
260{
261 bufrdeco_assert ( b != NULL );
262
263 // first deallocate all memory
268 {
270 b->tables = 0;
271 }
272 else
273 {
274 bufrdeco_free_tables ( & ( b->tables ) );
275 }
277
278 return 0;
279}
280
281/*!
282 * \fn int bufrdeco_set_tables_dir( struct bufrdeco *b, char *tables_dir)
283 * \brief Sets the directory path for BUFR tables. Needed if it is not any default directories.
284 * \param b pointer to the target struct
285 * \param tables_dir Source path of tables directory
286 * \return 1 if problem, 0 otherwise
287 *
288 * The default directories are '/usr/share/bufr2synop' and '/usr/local/share/bufr2synop'
289 *
290 */
291int bufrdeco_set_tables_dir ( struct bufrdeco *b, char *tables_dir )
292{
293 bufrdeco_assert_with_return_val ( b != NULL || tables_dir == NULL, 1 );
294
296 return 0;
297}
298
299/*!
300 \fn int bufrdeco_get_bufr ( struct bufrdeco *b, char *filename )
301 \brief Read file and try to find a bufr report inserted in. Once found do the same that \ref bufrdeco_read_bufr()
302 \param b pointer to struct \ref bufrdeco
303 \param filename complete path of BUFR file
304 \return Returns 0 if all is OK, 1 otherwise
305
306
307 This function does the folowing tasks:
308 - Try to find first buffer of bytes begining with 'BUFR' chars and ending with '7777'. This will be considered as a bufr file.
309 - Read the file and checks the marks at the begining and end to see wheter is a BUFR file
310 - Init the structs and allocate the needed memory for raw data if not done previously
311 - Splits and parse the BUFR sections (without expanding descriptors nor parsing data)
312 - Reads the needed Table files and store them in memory.
313
314 */
315int bufrdeco_get_bufr ( struct bufrdeco *b, char *filename )
316{
317 bufrdeco_assert_with_return_val ( b != NULL || filename == NULL, 1 );
318
319 return bufrdeco_extract_bufr ( b, filename );
320}
321
322
323/*!
324 * \fn int bufrdeco_write_subset_offset_bits ( struct bufrdeco *b, char *filename )
325 * \brief Write offset bit array for subsets in a non-compressed bufr
326 * \param filename complete path of output file to open
327 * \param b pointer to the struct \ref bufrdeco
328 * \return 1 if problem, 0 otherwise
329 */
330int bufrdeco_write_subset_offset_bits ( struct bufrdeco *b, char *filename )
331{
332 FILE *f;
333
334 // assert nice args
335 bufrdeco_assert_with_return_val ( b != NULL || filename == NULL, 1 );
336
337 // open the file
338 f = fopen ( filename, "w" );
339 bufrdeco_assert_with_return_val ( f != NULL, 1 );
340
341 // Read the offsets
342 if ( bufr_write_subset_offset_bits ( f, & ( b->offsets ) ) )
343 {
344 fclose ( f );
345 return 1;
346 }
347 fclose ( f );
348 return 0;
349}
350
351/*!
352 * \fn int bufrdeco_read_subset_offset_bits ( struct bufrdeco *b, char *filename )
353 * \brief Write offset bit array for subsets in a non-compressed bufr
354 * \param filename complete path of input file to open
355 * \param b pointer to the struct \ref bufrdeco
356 * \return 1 if problem, 0 otherwise
357 */
358int bufrdeco_read_subset_offset_bits ( struct bufrdeco *b, char *filename )
359{
360 struct stat st;
361 FILE *f;
362
363 // assert nice args
364 bufrdeco_assert_with_return_val ( b != NULL || filename == NULL, 1 );
365
366 // silently return if cannot stat the file
367 if ( stat ( filename, &st ) < 0 )
368 {
369 return 1;
370 }
371
372 // open the file
373 f = fopen ( filename, "r" );
374 bufrdeco_assert_with_return_val ( f != NULL, 1 );
375
376 // Read the offsets
377 if ( bufr_read_subset_offset_bits ( f, & ( b->offsets ) ) )
378 {
379 fclose ( f );
380 return 1;
381 }
382 fclose ( f );
383 return 0;
384}
385
386
387/*!
388 * \fn struct bufrdeco_subset_sequence_data *bufrdeco_get_target_subset_sequence_data (buf_t nset, struct bufrdeco *b)
389 * \brief Prepare the struct \ref bufrdeco to get data from the solicited subset
390 * \param nset index of subset we want to parse and get data. First subset in a BUFR file has index 0.
391 * \param b pointer to the struct \ref bufrdeco
392 *
393 * \return If succeeded returns a pointer to the struct \ref bufrdeco_subset_sequence_data with the results for the
394 * desired subset, otherwise returns NULL
395 */
397{
398 buf_t n = 0;
399 bufrdeco_assert ( b != NULL );
400 uint32_t mask0 = b->mask;
401
402 if ( b->sec3.subsets <= nset )
403 {
404 snprintf ( b->error, sizeof ( b->error ), "%s(): The index of target subset is over the bufr subsets (%d)\n", __func__, b->sec3.subsets );
405 return NULL;
406 }
407
408 if ( b->sec3.compressed )
409 {
410#ifdef __DEBUG
411 printf ("# Compressed\n");
412#endif
413 // case of compressed, we just need the compressed references
414 if ( b->refs.nd == 0 )
415 {
416 // case of compressed data and still not parsed the refs
417 if ( bufrdeco_parse_compressed ( & ( b->refs ), b ) )
418 {
419 return NULL;
420 }
421
422 }
423 }
424 else if ( nset > 0 )
425 {
426 // In case of not compressed bufr, to parse a subset we need to know the bit offset of the subset data in sec4
427 // There are only two ways to know that offset:
428 // 1) Parse the data of all prior subsets from n = 0 to (nset - 1).
429 // 2) Get the subset bit offset from the struct bufrdeco_subset_bit_offset already stored.
430 // This is only possible if we already parsed this subset in this session (among two bufrdeco_reset() calls)
431 // or if readed the struct from a file
432 // In any case the subset bit offset array must be poluted for all n < (nset - 1)
433
434 // clear bit BUFRDECO_OUTPUT_JSON_SUBSET_DATA if actived
435 b->mask &= ~((uint32_t) BUFRDECO_OUTPUT_JSON_SUBSET_DATA);
436
437 if ( b->offsets.nr == 0 || b->offsets.ofs[nset] == 0 )
438 {
439 for ( n = b->state.subset ; n < nset ; n++ )
440 {
441 // In every call to bufrdeco_decode_data_subset(), b->state.subset is incremented and b->offsets is updated if needed
442#ifdef __DEBUG
443 printf ("# Go to parse for subset %lu waiting %lu\n", b->state.subset, nset);
444#endif
446 }
447 }
448 }
449 // Once the previous task is made, we just adjust the subset
450 b->state.subset = nset;
451 b->mask = mask0;
452
453 // and now parse and get the desired subset data
454#ifdef __DEBUG
455 printf ("# Finally going to target parse for subset %lu\n", b->state.subset);
456#endif
458}
int bufrdeco_reset(struct bufrdeco *b)
Reset an struct bufrdeco. This is needed when changing to another bufr.
Definition: bufrdeco.c:180
int bufrdeco_get_bufr(struct bufrdeco *b, char *filename)
Read file and try to find a bufr report inserted in. Once found do the same that bufrdeco_read_bufr()
Definition: bufrdeco.c:315
int bufrdeco_set_out_stream(FILE *out, struct bufrdeco *b)
Set the library normal output stream.
Definition: bufrdeco.c:227
int bufrdeco_set_tables_dir(struct bufrdeco *b, char *tables_dir)
Sets the directory path for BUFR tables. Needed if it is not any default directories.
Definition: bufrdeco.c:291
int bufrdeco_close(struct bufrdeco *b)
Free all allocated memory. Needed when no more task to do with bufrdeco library.
Definition: bufrdeco.c:259
int bufrdeco_set_err_stream(FILE *err, struct bufrdeco *b)
Set the error stream.
Definition: bufrdeco.c:242
char * bufrdeco_get_version(char *version, size_t dversion, char *build, size_t dbuild, char *builder, size_t dbuilder, int *version_major, int *version_minor, int *version_patch)
Definition: bufrdeco.c:50
int bufrdeco_write_subset_offset_bits(struct bufrdeco *b, char *filename)
Write offset bit array for subsets in a non-compressed bufr.
Definition: bufrdeco.c:330
int bufrdeco_parse_tree(struct bufrdeco *b)
Parse the tree of descriptors without expand the replicators.
Definition: bufrdeco.c:120
int bufrdeco_read_subset_offset_bits(struct bufrdeco *b, char *filename)
Write offset bit array for subsets in a non-compressed bufr.
Definition: bufrdeco.c:358
struct bufrdeco_subset_sequence_data * bufrdeco_get_target_subset_sequence_data(buf_t nset, struct bufrdeco *b)
Prepare the struct bufrdeco to get data from the solicited subset.
Definition: bufrdeco.c:396
int bufrdeco_init(struct bufrdeco *b)
Inits and allocate memory for a struct bufrdeco.
Definition: bufrdeco.c:138
Include header file for bufrdeco library.
int bufrdeco_init_tables(struct bufr_tables **t)
Init a struct bufr_tables allocating space.
uint32_t buf_t
Type to set offsets and dimension of arrays or counters used in bufrdeco.
Definition: bufrdeco.h:346
struct bufrdeco_subset_sequence_data * bufrdeco_get_subset_sequence_data(struct bufrdeco *b)
Parse and get a struct bufrdeco_subset_sequence_data.
Definition: bufrdeco_data.c:39
#define bufrdeco_assert(__my_expr__)
Check a expression and exit if it fails.
Definition: bufrdeco.h:374
int bufrdeco_free_subset_sequence_data(struct bufrdeco_subset_sequence_data *ba)
Free the memory for sequence array in a struct bufrdeco_subset_sequence_data.
int bufrdeco_init_expanded_tree(struct bufrdeco_expanded_tree **t)
Init a struct bufrdeco_expanded_tree allocating space.
#define strncpy_safe(_target_, _src_, _dim_)
Macro to make safely a strcpy when we know in calling function the size of string target directly.
Definition: bufrdeco.h:366
int bufrdeco_free_tables(struct bufr_tables **t)
Frees the allocated space for a struct bufr_tables.
int bufr_write_subset_offset_bits(FILE *f, struct bufrdeco_subset_bit_offsets *off)
Write offset bit array for subsets in a non-compressed bufr.
int bufrdeco_free_cache_tables(struct bufr_tables_cache *c)
deallocate and clean a bufr_tables_cache
Definition: bufrdeco_wmo.c:322
int bufrdeco_free_bitmap_array(struct bufrdeco_bitmap_array *a)
Free an allocated bitmap array.
#define BUFRDECO_OUTPUT_JSON_SUBSET_DATA
Bit mask to the member mask of struct bufrdeco to print bufr subset data in json format.
Definition: bufrdeco.h:299
int bufr_read_subset_offset_bits(FILE *f, struct bufrdeco_subset_bit_offsets *off)
Write offset bit array for subsets in a non-compressed bufr.
#define bufrdeco_assert_with_return_val(__my_expr__, __returnval__)
Check a expression and returns a given value if it fails.
Definition: bufrdeco.h:385
int bufrdeco_parse_tree_recursive(struct bufrdeco *b, struct bufr_sequence *father, buf_t father_idesc, const char *key)
Parse the descriptor tree in a recursive way.
Definition: bufrdeco_tree.c:60
#define BUFRDECO_PATH_LENGTH
Length for files/directory path strings.
Definition: bufrdeco.h:335
#define BUFRDECO_USE_TABLES_CACHE
Bit mask to the member mask of struct bufrdeco to mark the use of bufr_tables cache.
Definition: bufrdeco.h:268
int bufrdeco_free_expanded_tree(struct bufrdeco_expanded_tree **t)
Frees the allocated space for a struct bufrdeco_expanded_tree.
int bufrdeco_parse_compressed(struct bufrdeco_compressed_data_references *r, struct bufrdeco *b)
Preliminary parse of a compressed data bufr.
int bufrdeco_extract_bufr(struct bufrdeco *b, char *filename)
Read file and try to find a bufr report inserted in. Once found do the same that bufrdeco_read_file()
int bufrdeco_free_compressed_data_references(struct bufrdeco_compressed_data_references *rf)
Free the memory allocated for array of references in a struct bufrdeco_compressed_data_references.
int bufrdeco_decode_data_subset(struct bufrdeco *b)
User interface to decode a BUFR subset.
Definition: bufrdeco_data.c:62
#define VERSION
Definition: config.h:8
uint8_t compressed
Definition: bufrdeco.h:812
uint32_t subsets
Definition: bufrdeco.h:810
Struct to store the cache of structs bufr_tables.
Definition: bufrdeco.h:951
Contains all tables needed to parse a bufr file.
Definition: bufrdeco.h:938
buf_t ofs[BUFR_MAX_SUBSETS]
Definition: bufrdeco.h:687
Contains all the information for a subset in a expanded squence This is a version to use with bufrdec...
Definition: bufrdeco.h:458
This struct contains all needed data to parse and decode a BUFR file.
Definition: bufrdeco.h:965
struct bufrdeco_bitmap_array bitmap
Definition: bufrdeco.h:980
struct bufrdeco_subset_sequence_data seq
Definition: bufrdeco.h:979
uint32_t mask
Definition: bufrdeco.h:966
FILE * err
Definition: bufrdeco.h:985
struct bufr_tables_cache cache
Definition: bufrdeco.h:974
struct bufrdeco_compressed_data_references refs
Definition: bufrdeco.h:978
struct bufrdeco_subset_bit_offsets offsets
Definition: bufrdeco.h:977
struct bufrdeco_decoding_data_state state
Definition: bufrdeco.h:976
struct bufr_tables * tables
Definition: bufrdeco.h:973
char bufrtables_dir[BUFRDECO_PATH_LENGTH]
Definition: bufrdeco.h:982
struct bufr_sec3 sec3
Definition: bufrdeco.h:971
FILE * out
Definition: bufrdeco.h:984
struct bufrdeco_expanded_tree * tree
Definition: bufrdeco.h:975
char error[1024]
Definition: bufrdeco.h:983