1 /*
2  * (C) Copyright 2005- ECMWF.
3  *
4  * This software is licensed under the terms of the Apache Licence Version 2.0
5  * which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
6  *
7  * In applying this licence, ECMWF does not waive the privileges and immunities granted to it by
8  * virtue of its status as an intergovernmental organisation nor does it submit to any jurisdiction.
9  */
10 
11 #include "grib_api_internal.h"
12 #include <ctype.h>
13 /*
14    This is used by make_class.pl
15 
16    START_CLASS_DEF
17    CLASS      = dumper
18    IMPLEMENTS = dump_long;dump_bits
19    IMPLEMENTS = dump_double;dump_string;dump_string_array
20    IMPLEMENTS = dump_bytes;dump_values
21    IMPLEMENTS = dump_label;dump_section
22    IMPLEMENTS = init;destroy
23    MEMBERS = long section_offset
24    MEMBERS = long begin
25    MEMBERS = long empty
26    MEMBERS = long end
27    MEMBERS = long isLeaf
28    MEMBERS = long isAttribute
29    MEMBERS = grib_string_list* keys
30    END_CLASS_DEF
31 
32  */
33 
34 
35 /* START_CLASS_IMP */
36 
37 /*
38 
39 Don't edit anything between START_CLASS_IMP and END_CLASS_IMP
40 Instead edit values between START_CLASS_DEF and END_CLASS_DEF
41 or edit "dumper.class" and rerun ./make_class.pl
42 
43 */
44 
45 static void init_class(grib_dumper_class*);
46 static int init(grib_dumper* d);
47 static int destroy(grib_dumper*);
48 static void dump_long(grib_dumper* d, grib_accessor* a, const char* comment);
49 static void dump_bits(grib_dumper* d, grib_accessor* a, const char* comment);
50 static void dump_double(grib_dumper* d, grib_accessor* a, const char* comment);
51 static void dump_string(grib_dumper* d, grib_accessor* a, const char* comment);
52 static void dump_string_array(grib_dumper* d, grib_accessor* a, const char* comment);
53 static void dump_bytes(grib_dumper* d, grib_accessor* a, const char* comment);
54 static void dump_values(grib_dumper* d, grib_accessor* a);
55 static void dump_label(grib_dumper* d, grib_accessor* a, const char* comment);
56 static void dump_section(grib_dumper* d, grib_accessor* a, grib_block_of_accessors* block);
57 
58 typedef struct grib_dumper_bufr_decode_filter
59 {
60     grib_dumper dumper;
61     /* Members defined in bufr_decode_filter */
62     long section_offset;
63     long begin;
64     long empty;
65     long end;
66     long isLeaf;
67     long isAttribute;
68     grib_string_list* keys;
69 } grib_dumper_bufr_decode_filter;
70 
71 
72 static grib_dumper_class _grib_dumper_class_bufr_decode_filter = {
73     0,                                      /* super                     */
74     "bufr_decode_filter",                   /* name                      */
75     sizeof(grib_dumper_bufr_decode_filter), /* size                      */
76     0,                                      /* inited */
77     &init_class,                            /* init_class */
78     &init,                                  /* init                      */
79     &destroy,                               /* free mem                       */
80     &dump_long,                             /* dump long         */
81     &dump_double,                           /* dump double    */
82     &dump_string,                           /* dump string    */
83     &dump_string_array,                     /* dump string array   */
84     &dump_label,                            /* dump labels  */
85     &dump_bytes,                            /* dump bytes  */
86     &dump_bits,                             /* dump bits   */
87     &dump_section,                          /* dump section      */
88     &dump_values,                           /* dump values   */
89     0,                                      /* header   */
90     0,                                      /* footer   */
91 };
92 
93 grib_dumper_class* grib_dumper_class_bufr_decode_filter = &_grib_dumper_class_bufr_decode_filter;
94 
95 /* END_CLASS_IMP */
96 static void dump_attributes(grib_dumper* d, grib_accessor* a, const char* prefix);
97 
98 /* Note: A fast cut-down version of strcmp which does NOT return -1 */
99 /* 0 means input strings are equal and 1 means not equal */
grib_inline_strcmp(const char * a,const char * b)100 GRIB_INLINE static int grib_inline_strcmp(const char* a, const char* b)
101 {
102     if (*a != *b)
103         return 1;
104     while ((*a != 0 && *b != 0) && *(a) == *(b)) {
105         a++;
106         b++;
107     }
108     return (*a == 0 && *b == 0) ? 0 : 1;
109 }
110 
111 typedef struct string_count string_count;
112 struct string_count
113 {
114     char* value;
115     int count;
116     string_count* next;
117 };
118 
119 static int depth = 0;
120 
init_class(grib_dumper_class * c)121 static void init_class(grib_dumper_class* c) {}
122 
init(grib_dumper * d)123 static int init(grib_dumper* d)
124 {
125     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
126     grib_context* c                      = d->context;
127     self->section_offset                 = 0;
128     self->empty                          = 1;
129     self->isLeaf                         = 0;
130     self->isAttribute                    = 0;
131     self->keys                           = (grib_string_list*)grib_context_malloc_clear(c, sizeof(grib_string_list));
132 
133     return GRIB_SUCCESS;
134 }
135 
destroy(grib_dumper * d)136 static int destroy(grib_dumper* d)
137 {
138     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
139     grib_string_list* next               = self->keys;
140     grib_string_list* cur                = NULL;
141     grib_context* c                      = d->context;
142     while (next) {
143         cur  = next;
144         next = next->next;
145         grib_context_free(c, cur->value);
146         grib_context_free(c, cur);
147     }
148     return GRIB_SUCCESS;
149 }
150 
dump_values(grib_dumper * d,grib_accessor * a)151 static void dump_values(grib_dumper* d, grib_accessor* a)
152 {
153     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
154     double value                         = 0;
155     size_t size                          = 0;
156     int err                              = 0;
157     int r;
158     long count      = 0;
159     grib_context* c = a->context;
160     grib_handle* h  = grib_handle_of_accessor(a);
161 
162     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
163         return;
164 
165     grib_value_count(a, &count);
166     size = count;
167 
168     if (size <= 1) {
169         err = grib_unpack_double(a, &value, &size);
170     }
171 
172     self->begin = 0;
173     self->empty = 0;
174 
175     if (size > 1) {
176         if ((r = compute_bufr_key_rank(h, self->keys, a->name)) != 0)
177             fprintf(self->dumper.out, "print \"#%d#%s=[#%d#%s]\";\n", r, a->name, r, a->name);
178         else
179             fprintf(self->dumper.out, "print \"%s=[%s]\";\n", a->name, a->name);
180     }
181     else {
182         r = compute_bufr_key_rank(h, self->keys, a->name);
183         if (!grib_is_missing_double(a, value)) {
184             if (r != 0)
185                 fprintf(self->dumper.out, "print \"#%d#%s=[#%d#%s]\";\n", r, a->name, r, a->name);
186             else
187                 fprintf(self->dumper.out, "print \"%s=[%s]\";\n", a->name, a->name);
188         }
189     }
190 
191     if (self->isLeaf == 0) {
192         char* prefix;
193         int dofree = 0;
194 
195         if (r != 0) {
196             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
197             dofree = 1;
198             sprintf(prefix, "#%d#%s", r, a->name);
199         }
200         else
201             prefix = (char*)a->name;
202 
203         dump_attributes(d, a, prefix);
204         if (dofree)
205             grib_context_free(c, prefix);
206         depth -= 2;
207     }
208 
209     (void)err; /* TODO */
210 }
211 
dump_values_attribute(grib_dumper * d,grib_accessor * a,const char * prefix)212 static void dump_values_attribute(grib_dumper* d, grib_accessor* a, const char* prefix)
213 {
214     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
215     double value                         = 0;
216     size_t size                          = 0;
217     int err                              = 0;
218     long count                           = 0;
219     grib_context* c                      = a->context;
220 
221     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
222         return;
223 
224     grib_value_count(a, &count);
225     size = count;
226 
227     if (size <= 1) {
228         err = grib_unpack_double(a, &value, &size);
229     }
230 
231     self->empty = 0;
232 
233     if (size > 1) {
234         fprintf(self->dumper.out, "print \"%s->%s = [%s->%s]\";\n", prefix, a->name, prefix, a->name);
235     }
236     else {
237         if (!grib_is_missing_double(a, value)) {
238             fprintf(self->dumper.out, "print \"%s->%s = [%s->%s]\";\n", prefix, a->name, prefix, a->name);
239         }
240     }
241 
242     if (self->isLeaf == 0) {
243         char* prefix1 = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + strlen(prefix) + 5));
244         sprintf(prefix1, "%s->%s", prefix, a->name);
245 
246         dump_attributes(d, a, prefix1);
247 
248         grib_context_free(c, prefix1);
249         depth -= 2;
250     }
251 
252     (void)err; /* TODO */
253 }
254 
dump_long(grib_dumper * d,grib_accessor * a,const char * comment)255 static void dump_long(grib_dumper* d, grib_accessor* a, const char* comment)
256 {
257     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
258     long value                           = 0;
259     size_t size                          = 0;
260     int err                              = 0;
261     int r                                = 0;
262     long count                           = 0;
263     grib_context* c                      = a->context;
264     grib_handle* h                       = grib_handle_of_accessor(a);
265 
266     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0)
267         return;
268 
269     grib_value_count(a, &count);
270     size = count;
271 
272     if ((a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0) {
273         if (self->isLeaf == 0) {
274             char* prefix;
275             int dofree = 0;
276 
277             r = compute_bufr_key_rank(h, self->keys, a->name);
278             if (r != 0) {
279                 prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
280                 dofree = 1;
281                 sprintf(prefix, "#%d#%s", r, a->name);
282             }
283             else
284                 prefix = (char*)a->name;
285 
286             dump_attributes(d, a, prefix);
287             if (dofree)
288                 grib_context_free(c, prefix);
289             depth -= 2;
290         }
291         return;
292     }
293 
294     if (size <= 1) {
295         err = grib_unpack_long(a, &value, &size);
296     }
297 
298     self->begin = 0;
299     self->empty = 0;
300 
301     if (size > 1) {
302         if ((r = compute_bufr_key_rank(h, self->keys, a->name)) != 0)
303             fprintf(self->dumper.out, "print \"#%d#%s=[#%d#%s]\";\n", r, a->name, r, a->name);
304         else
305             fprintf(self->dumper.out, "print \"%s=[%s]\";\n", a->name, a->name);
306     }
307     else {
308         r = compute_bufr_key_rank(h, self->keys, a->name);
309         if (!grib_is_missing_long(a, value)) {
310             if (r != 0)
311                 fprintf(self->dumper.out, "print \"#%d#%s=[#%d#%s]\";\n", r, a->name, r, a->name);
312             else
313                 fprintf(self->dumper.out, "print \"%s=[%s]\";\n", a->name, a->name);
314         }
315     }
316 
317     if (self->isLeaf == 0) {
318         char* prefix;
319         int dofree = 0;
320 
321         if (r != 0) {
322             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
323             dofree = 1;
324             sprintf(prefix, "#%d#%s", r, a->name);
325         }
326         else
327             prefix = (char*)a->name;
328 
329         dump_attributes(d, a, prefix);
330         if (dofree)
331             grib_context_free(c, prefix);
332         depth -= 2;
333     }
334     (void)err; /* TODO */
335 }
336 
dump_long_attribute(grib_dumper * d,grib_accessor * a,const char * prefix)337 static void dump_long_attribute(grib_dumper* d, grib_accessor* a, const char* prefix)
338 {
339     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
340     int err                              = 0;
341     grib_context* c                      = a->context;
342 
343     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
344         return;
345 
346     self->empty = 0;
347     fprintf(self->dumper.out, "print \"%s->%s = [%s->%s]\";\n", prefix, a->name, prefix, a->name);
348 
349     if (self->isLeaf == 0) {
350         char* prefix1 = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + strlen(prefix) + 5));
351         sprintf(prefix1, "%s->%s", prefix, a->name);
352 
353         dump_attributes(d, a, prefix1);
354 
355         grib_context_free(c, prefix1);
356         depth -= 2;
357     }
358     (void)err; /* TODO */
359 }
360 
dump_bits(grib_dumper * d,grib_accessor * a,const char * comment)361 static void dump_bits(grib_dumper* d, grib_accessor* a, const char* comment)
362 {
363 }
364 
dump_double(grib_dumper * d,grib_accessor * a,const char * comment)365 static void dump_double(grib_dumper* d, grib_accessor* a, const char* comment)
366 {
367     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
368     double value                         = 0;
369     size_t size                          = 1;
370     int r;
371     grib_handle* h  = grib_handle_of_accessor(a);
372     grib_context* c = h->context;
373 
374     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
375         return;
376 
377     grib_unpack_double(a, &value, &size);
378     self->begin = 0;
379     self->empty = 0;
380 
381     r = compute_bufr_key_rank(h, self->keys, a->name);
382     if (!grib_is_missing_double(a, value)) {
383         if (r != 0)
384             fprintf(self->dumper.out, "print \"#%d#%s=[#%d#%s]\";\n", r, a->name, r, a->name);
385         else
386             fprintf(self->dumper.out, "print \"%s=[%s]\";\n", a->name, a->name);
387     }
388 
389     if (self->isLeaf == 0) {
390         char* prefix;
391         int dofree = 0;
392 
393         if (r != 0) {
394             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
395             dofree = 1;
396             sprintf(prefix, "#%d#%s", r, a->name);
397         }
398         else
399             prefix = (char*)a->name;
400 
401         dump_attributes(d, a, prefix);
402         if (dofree)
403             grib_context_free(c, prefix);
404         depth -= 2;
405     }
406 }
407 
dump_string_array(grib_dumper * d,grib_accessor * a,const char * comment)408 static void dump_string_array(grib_dumper* d, grib_accessor* a, const char* comment)
409 {
410     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
411     size_t size                          = 0;
412     grib_context* c                      = NULL;
413     int err                              = 0;
414     long count                           = 0;
415     int r                                = 0;
416     grib_handle* h                       = grib_handle_of_accessor(a);
417 
418     c = a->context;
419 
420     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
421         return;
422 
423     grib_value_count(a, &count);
424     size = count;
425     if (size == 1) {
426         dump_string(d, a, comment);
427         return;
428     }
429 
430     self->begin = 0;
431 
432     if (self->isLeaf == 0) {
433         depth += 2;
434         if ((r = compute_bufr_key_rank(h, self->keys, a->name)) != 0)
435             fprintf(self->dumper.out, "print \"#%d#%s=[#%d#%s]\";\n", r, a->name, r, a->name);
436         else
437             fprintf(self->dumper.out, "print \"%s=[%s]\";\n", a->name, a->name);
438     }
439 
440     self->empty = 0;
441 
442     if (self->isLeaf == 0) {
443         char* prefix;
444         int dofree = 0;
445 
446         if (r != 0) {
447             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
448             dofree = 1;
449             sprintf(prefix, "#%d#%s", r, a->name);
450         }
451         else
452             prefix = (char*)a->name;
453 
454         dump_attributes(d, a, prefix);
455         if (dofree)
456             grib_context_free(c, prefix);
457         depth -= 2;
458     }
459 
460     (void)err; /* TODO */
461 }
462 
463 #define MAX_STRING_SIZE 4096
dump_string(grib_dumper * d,grib_accessor * a,const char * comment)464 static void dump_string(grib_dumper* d, grib_accessor* a, const char* comment)
465 {
466     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
467     char value[MAX_STRING_SIZE] = {0,}; /* See ECC-710 */
468     size_t size                 = MAX_STRING_SIZE;
469     char* p                     = NULL;
470     grib_context* c             = a->context;
471     int r =0, err = 0;
472     grib_handle* h = grib_handle_of_accessor(a);
473 
474     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
475         return;
476 
477     self->begin = 0;
478 
479     self->empty = 0;
480 
481     err = grib_unpack_string(a, value, &size);
482     p   = value;
483     r   = compute_bufr_key_rank(h, self->keys, a->name);
484     if (grib_is_missing_string(a, (unsigned char*)value, size)) {
485         return;
486     }
487 
488     while (*p) {
489         if (!isprint(*p))
490             *p = '.';
491         p++;
492     }
493 
494     if (self->isLeaf == 0) {
495         depth += 2;
496         if (r != 0)
497             fprintf(self->dumper.out, "print \"#%d#%s=[#%d#%s]\";\n", r, a->name, r, a->name);
498         else
499             fprintf(self->dumper.out, "print \"%s=[%s]\";\n", a->name, a->name);
500     }
501 
502     if (self->isLeaf == 0) {
503         char* prefix;
504         int dofree = 0;
505 
506         if (r != 0) {
507             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
508             dofree = 1;
509             sprintf(prefix, "#%d#%s", r, a->name);
510         }
511         else
512             prefix = (char*)a->name;
513 
514         dump_attributes(d, a, prefix);
515         if (dofree)
516             grib_context_free(c, prefix);
517         depth -= 2;
518     }
519 
520     (void)err; /* TODO */
521 }
522 
dump_bytes(grib_dumper * d,grib_accessor * a,const char * comment)523 static void dump_bytes(grib_dumper* d, grib_accessor* a, const char* comment)
524 {
525 }
526 
dump_label(grib_dumper * d,grib_accessor * a,const char * comment)527 static void dump_label(grib_dumper* d, grib_accessor* a, const char* comment)
528 {
529 }
530 
_dump_long_array(grib_handle * h,FILE * f,const char * key)531 static void _dump_long_array(grib_handle* h, FILE* f, const char* key)
532 {
533     size_t size = 0;
534     if (grib_get_size(h, key, &size) == GRIB_NOT_FOUND)
535         return;
536     if (size == 0)
537         return;
538 
539     fprintf(f, "print \"%s=[%s]\";\n", key, key);
540 }
541 
dump_section(grib_dumper * d,grib_accessor * a,grib_block_of_accessors * block)542 static void dump_section(grib_dumper* d, grib_accessor* a, grib_block_of_accessors* block)
543 {
544     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
545     if (!grib_inline_strcmp(a->name, "BUFR") ||
546         !grib_inline_strcmp(a->name, "GRIB") ||
547         !grib_inline_strcmp(a->name, "META")) {
548         grib_handle* h = grib_handle_of_accessor(a);
549         depth          = 2;
550         self->begin    = 1;
551         self->empty    = 1;
552         depth += 2;
553         _dump_long_array(h, self->dumper.out, "dataPresentIndicator");
554         _dump_long_array(h, self->dumper.out, "delayedDescriptorReplicationFactor");
555         _dump_long_array(h, self->dumper.out, "shortDelayedDescriptorReplicationFactor");
556         _dump_long_array(h, self->dumper.out, "extendedDelayedDescriptorReplicationFactor");
557         /* Do not show the inputOverriddenReferenceValues array. That's more for ENCODING */
558         /*_dump_long_array(h,self->dumper.out,"inputOverriddenReferenceValues","inputOverriddenReferenceValues");*/
559         grib_dump_accessors_block(d, block);
560         depth -= 2;
561     }
562     else if (!grib_inline_strcmp(a->name, "groupNumber")) {
563         if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0)
564             return;
565         self->begin = 1;
566         self->empty = 1;
567         depth += 2;
568         grib_dump_accessors_block(d, block);
569         depth -= 2;
570     }
571     else {
572         grib_dump_accessors_block(d, block);
573     }
574 }
575 
dump_attributes(grib_dumper * d,grib_accessor * a,const char * prefix)576 static void dump_attributes(grib_dumper* d, grib_accessor* a, const char* prefix)
577 {
578     int i                                = 0;
579     grib_dumper_bufr_decode_filter* self = (grib_dumper_bufr_decode_filter*)d;
580     unsigned long flags;
581     while (i < MAX_ACCESSOR_ATTRIBUTES && a->attributes[i]) {
582         self->isAttribute = 1;
583         if ((d->option_flags & GRIB_DUMP_FLAG_ALL_ATTRIBUTES) == 0 && (a->attributes[i]->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0) {
584             i++;
585             continue;
586         }
587         self->isLeaf = a->attributes[i]->attributes[0] == NULL ? 1 : 0;
588         /* fprintf(self->dumper.out,","); */
589         /* fprintf(self->dumper.out,"\n%-*s",depth," "); */
590         /* fprintf(out,"\"%s\" : ",a->attributes[i]->name); */
591         flags = a->attributes[i]->flags;
592         a->attributes[i]->flags |= GRIB_ACCESSOR_FLAG_DUMP;
593         switch (grib_accessor_get_native_type(a->attributes[i])) {
594             case GRIB_TYPE_LONG:
595                 dump_long_attribute(d, a->attributes[i], prefix);
596                 break;
597             case GRIB_TYPE_DOUBLE:
598                 dump_values_attribute(d, a->attributes[i], prefix);
599                 break;
600             case GRIB_TYPE_STRING:
601                 break;
602         }
603         a->attributes[i]->flags = flags;
604         i++;
605     }
606     self->isLeaf      = 0;
607     self->isAttribute = 0;
608 }
609