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    IMPLEMENTS = header;footer
24    MEMBERS = long section_offset
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 static void header(grib_dumper*, grib_handle*);
58 static void footer(grib_dumper*, grib_handle*);
59 
60 typedef struct grib_dumper_bufr_encode_python
61 {
62     grib_dumper dumper;
63     /* Members defined in bufr_encode_python */
64     long section_offset;
65     long empty;
66     long end;
67     long isLeaf;
68     long isAttribute;
69     grib_string_list* keys;
70 } grib_dumper_bufr_encode_python;
71 
72 
73 static grib_dumper_class _grib_dumper_class_bufr_encode_python = {
74     0,                                      /* super                     */
75     "bufr_encode_python",                   /* name                      */
76     sizeof(grib_dumper_bufr_encode_python), /* size                      */
77     0,                                      /* inited */
78     &init_class,                            /* init_class */
79     &init,                                  /* init                      */
80     &destroy,                               /* free mem                       */
81     &dump_long,                             /* dump long         */
82     &dump_double,                           /* dump double    */
83     &dump_string,                           /* dump string    */
84     &dump_string_array,                     /* dump string array   */
85     &dump_label,                            /* dump labels  */
86     &dump_bytes,                            /* dump bytes  */
87     &dump_bits,                             /* dump bits   */
88     &dump_section,                          /* dump section      */
89     &dump_values,                           /* dump values   */
90     &header,                                /* header   */
91     &footer,                                /* footer   */
92 };
93 
94 grib_dumper_class* grib_dumper_class_bufr_encode_python = &_grib_dumper_class_bufr_encode_python;
95 
96 /* END_CLASS_IMP */
97 static void dump_attributes(grib_dumper* d, grib_accessor* a, const char* prefix);
98 
99 /* Note: A fast cut-down version of strcmp which does NOT return -1 */
100 /* 0 means input strings are equal and 1 means not equal */
grib_inline_strcmp(const char * a,const char * b)101 GRIB_INLINE static int grib_inline_strcmp(const char* a, const char* b)
102 {
103     if (*a != *b)
104         return 1;
105     while ((*a != 0 && *b != 0) && *(a) == *(b)) {
106         a++;
107         b++;
108     }
109     return (*a == 0 && *b == 0) ? 0 : 1;
110 }
111 
112 typedef struct string_count string_count;
113 struct string_count
114 {
115     char* value;
116     int count;
117     string_count* next;
118 };
119 
120 static int depth = 0;
121 
init_class(grib_dumper_class * c)122 static void init_class(grib_dumper_class* c) {}
123 
init(grib_dumper * d)124 static int init(grib_dumper* d)
125 {
126     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
127     grib_context* c                      = d->context;
128     self->section_offset                 = 0;
129     self->empty                          = 1;
130     d->count                             = 1;
131     self->isLeaf                         = 0;
132     self->isAttribute                    = 0;
133     self->keys                           = (grib_string_list*)grib_context_malloc_clear(c, sizeof(grib_string_list));
134 
135     return GRIB_SUCCESS;
136 }
137 
destroy(grib_dumper * d)138 static int destroy(grib_dumper* d)
139 {
140     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
141     grib_string_list* next               = self->keys;
142     grib_string_list* cur                = NULL;
143     grib_context* c                      = d->context;
144     while (next) {
145         cur  = next;
146         next = next->next;
147         grib_context_free(c, cur->value);
148         grib_context_free(c, cur);
149     }
150     return GRIB_SUCCESS;
151 }
152 
lval_to_string(grib_context * c,long v)153 static char* lval_to_string(grib_context* c, long v)
154 {
155     char* sval = (char*)grib_context_malloc_clear(c, sizeof(char) * 40);
156     if (v == GRIB_MISSING_LONG)
157         sprintf(sval, "CODES_MISSING_LONG");
158     else
159         sprintf(sval, "%ld", v);
160     return sval;
161 }
dval_to_string(const grib_context * c,double v)162 static char* dval_to_string(const grib_context* c, double v)
163 {
164     char* sval = (char*)grib_context_malloc_clear(c, sizeof(char) * 40);
165     if (v == GRIB_MISSING_DOUBLE)
166         sprintf(sval, "CODES_MISSING_DOUBLE");
167     else
168         sprintf(sval, "%.18e", v);
169     return sval;
170 }
171 
dump_values(grib_dumper * d,grib_accessor * a)172 static void dump_values(grib_dumper* d, grib_accessor* a)
173 {
174     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
175     double value                         = 0;
176     size_t size = 0, size2 = 0;
177     double* values = NULL;
178     int err        = 0;
179     int i, r, icount;
180     int cols   = 2;
181     long count = 0;
182     char* sval;
183     grib_context* c = a->context;
184     grib_handle* h  = grib_handle_of_accessor(a);
185 
186     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
187         return;
188 
189     grib_value_count(a, &count);
190     size = size2 = count;
191 
192     if (size > 1) {
193         values = (double*)grib_context_malloc_clear(c, sizeof(double) * size);
194         err    = grib_unpack_double(a, values, &size2);
195     }
196     else {
197         err = grib_unpack_double(a, &value, &size2);
198     }
199     Assert(size2 == size);
200 
201     self->empty = 0;
202 
203     if (size > 1) {
204         fprintf(self->dumper.out, "    rvalues = (");
205 
206         icount = 0;
207         for (i = 0; i < size - 1; ++i) {
208             if (icount > cols || i == 0) {
209                 fprintf(self->dumper.out, "\n        ");
210                 icount = 0;
211             }
212             sval = dval_to_string(c, values[i]);
213             fprintf(self->dumper.out, "%s, ", sval);
214             grib_context_free(c, sval);
215             icount++;
216         }
217         if (icount > cols || i == 0) {
218             fprintf(self->dumper.out, "\n        ");
219         }
220         sval = dval_to_string(c, values[i]);
221         fprintf(self->dumper.out, "%s", sval);
222         grib_context_free(c, sval);
223 
224         depth -= 2;
225         /* Note: In Python to make a tuple with one element, you need the trailing comma */
226         if (size > 4)
227             fprintf(self->dumper.out, ",) # %lu values\n", (unsigned long)size);
228         else
229             fprintf(self->dumper.out, ",)\n");
230         grib_context_free(c, values);
231 
232         if ((r = compute_bufr_key_rank(h, self->keys, a->name)) != 0)
233             fprintf(self->dumper.out, "    codes_set_array(ibufr, '#%d#%s', rvalues)\n", r, a->name);
234         else
235             fprintf(self->dumper.out, "    codes_set_array(ibufr, '%s', rvalues)\n", a->name);
236     }
237     else {
238         r    = compute_bufr_key_rank(h, self->keys, a->name);
239         sval = dval_to_string(c, value);
240         if (r != 0)
241             fprintf(self->dumper.out, "    codes_set(ibufr, '#%d#%s', %s)\n", r, a->name, sval);
242         else
243             fprintf(self->dumper.out, "    codes_set(ibufr, '%s', %s)\n", a->name, sval);
244         grib_context_free(c, sval);
245     }
246 
247     if (self->isLeaf == 0) {
248         char* prefix;
249         int dofree = 0;
250 
251         if (r != 0) {
252             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
253             dofree = 1;
254             sprintf(prefix, "#%d#%s", r, a->name);
255         }
256         else
257             prefix = (char*)a->name;
258 
259         dump_attributes(d, a, prefix);
260         if (dofree)
261             grib_context_free(c, prefix);
262         depth -= 2;
263     }
264 
265     (void)err; /* TODO */
266 }
267 
dump_values_attribute(grib_dumper * d,grib_accessor * a,const char * prefix)268 static void dump_values_attribute(grib_dumper* d, grib_accessor* a, const char* prefix)
269 {
270     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
271     double value                         = 0;
272     size_t size = 0, size2 = 0;
273     double* values = NULL;
274     int err = 0, i = 0, icount = 0;
275     int cols   = 2;
276     long count = 0;
277     char* sval;
278     grib_context* c = a->context;
279 
280     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
281         return;
282 
283     grib_value_count(a, &count);
284     size = size2 = count;
285 
286     if (size > 1) {
287         values = (double*)grib_context_malloc_clear(c, sizeof(double) * size);
288         err    = grib_unpack_double(a, values, &size2);
289     }
290     else {
291         err = grib_unpack_double(a, &value, &size2);
292     }
293     Assert(size2 == size);
294 
295     self->empty = 0;
296 
297     if (size > 1) {
298         fprintf(self->dumper.out, "    rvalues = (");
299 
300         icount = 0;
301         for (i = 0; i < size - 1; ++i) {
302             if (icount > cols || i == 0) {
303                 fprintf(self->dumper.out, "\n      ");
304                 icount = 0;
305             }
306             sval = dval_to_string(c, values[i]);
307             fprintf(self->dumper.out, "%s, ", sval);
308             grib_context_free(c, sval);
309             icount++;
310         }
311         if (icount > cols || i == 0) {
312             fprintf(self->dumper.out, "\n      ");
313         }
314         sval = dval_to_string(c, values[i]);
315         fprintf(self->dumper.out, "%s", sval);
316         grib_context_free(c, sval);
317 
318         depth -= 2;
319         /* Note: In python to make a tuple with one element, you need the trailing comma */
320         if (size > 4)
321             fprintf(self->dumper.out, ",) # %lu values\n", (unsigned long)size);
322         else
323             fprintf(self->dumper.out, ",)\n");
324         grib_context_free(c, values);
325 
326         fprintf(self->dumper.out, "    codes_set_array(ibufr, '%s->%s' \n, rvalues)\n", prefix, a->name);
327     }
328     else {
329         sval = dval_to_string(c, value);
330         fprintf(self->dumper.out, "    codes_set(ibufr, '%s->%s' \n,%s)\n", prefix, a->name, sval);
331         grib_context_free(c, sval);
332     }
333 
334     if (self->isLeaf == 0) {
335         char* prefix1;
336 
337         prefix1 = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + strlen(prefix) + 5));
338         sprintf(prefix1, "%s->%s", prefix, a->name);
339 
340         dump_attributes(d, a, prefix1);
341 
342         grib_context_free(c, prefix1);
343         depth -= 2;
344     }
345 
346     (void)err; /* TODO */
347 }
348 
is_hidden(grib_accessor * a)349 static int is_hidden(grib_accessor* a)
350 {
351     return ( (a->flags & GRIB_ACCESSOR_FLAG_HIDDEN) != 0 );
352 }
353 
dump_long(grib_dumper * d,grib_accessor * a,const char * comment)354 static void dump_long(grib_dumper* d, grib_accessor* a, const char* comment)
355 {
356     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
357     long value                           = 0;
358     size_t size = 0, size2 = 0;
359     long* values = NULL;
360     int err = 0, i = 0, r = 0, icount = 0;
361     int cols                        = 4;
362     long count                      = 0;
363     char* sval                      = NULL;
364     grib_context* c                 = a->context;
365     grib_handle* h                  = grib_handle_of_accessor(a);
366     int doing_unexpandedDescriptors = 0;
367 
368     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0) { /* key does not have the dump attribute */
369         int skip = 1;
370         /* See ECC-1107 */
371         if (!is_hidden(a) && strcmp(a->name, "messageLength") == 0) skip = 0;
372         if (skip) return;
373     }
374 
375     doing_unexpandedDescriptors = (strcmp(a->name, "unexpandedDescriptors") == 0);
376     grib_value_count(a, &count);
377     size = size2 = count;
378 
379     if ((a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0) {
380         if (self->isLeaf == 0) {
381             char* prefix;
382             int dofree = 0;
383 
384             r = compute_bufr_key_rank(h, self->keys, a->name);
385             if (r != 0) {
386                 prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
387                 dofree = 1;
388                 sprintf(prefix, "#%d#%s", r, a->name);
389             }
390             else
391                 prefix = (char*)a->name;
392 
393             dump_attributes(d, a, prefix);
394             if (dofree)
395                 grib_context_free(c, prefix);
396             depth -= 2;
397         }
398         return;
399     }
400 
401     if (size > 1) {
402         values = (long*)grib_context_malloc_clear(a->context, sizeof(long) * size);
403         err    = grib_unpack_long(a, values, &size2);
404     }
405     else {
406         err = grib_unpack_long(a, &value, &size2);
407     }
408     Assert(size2 == size);
409 
410     self->empty = 0;
411 
412     if (size > 1) {
413         fprintf(self->dumper.out, "    ivalues = (");
414         icount = 0;
415         for (i = 0; i < size - 1; i++) {
416             if (icount > cols || i == 0) {
417                 fprintf(self->dumper.out, "\n        ");
418                 icount = 0;
419             }
420             fprintf(self->dumper.out, "%ld, ", values[i]);
421             icount++;
422         }
423         if (icount > cols || i == 0) {
424             fprintf(self->dumper.out, "\n        ");
425         }
426         fprintf(self->dumper.out, "%ld", values[i]);
427 
428         depth -= 2;
429         /* Note: In python to make a tuple with one element, you need the trailing comma */
430         if (size > 4)
431             fprintf(self->dumper.out, ",) # %lu values\n", (unsigned long)size);
432         else
433             fprintf(self->dumper.out, ",)\n");
434         grib_context_free(a->context, values);
435 
436         if ((r = compute_bufr_key_rank(h, self->keys, a->name)) != 0) {
437             fprintf(self->dumper.out, "    codes_set_array(ibufr, '#%d#%s', ivalues)\n", r, a->name);
438         }
439         else {
440             if (doing_unexpandedDescriptors) {
441                 fprintf(self->dumper.out, "\n    # Create the structure of the data section\n");
442                 /* fprintf(self->dumper.out,"    codes_set(ibufr, 'skipExtraKeyAttributes', 1)\n"); */
443             }
444             fprintf(self->dumper.out, "    codes_set_array(ibufr, '%s', ivalues)\n", a->name);
445             if (doing_unexpandedDescriptors)
446                 fprintf(self->dumper.out, "\n");
447         }
448     }
449     else {
450         r    = compute_bufr_key_rank(h, self->keys, a->name);
451         sval = lval_to_string(c, value);
452         if (r != 0) {
453             fprintf(self->dumper.out, "    codes_set(ibufr, '#%d#%s', ", r, a->name);
454         }
455         else {
456             if (doing_unexpandedDescriptors) {
457                 fprintf(self->dumper.out, "\n    # Create the structure of the data section\n");
458                 /* fprintf(self->dumper.out,"    codes_set(ibufr, 'skipExtraKeyAttributes', 1)\n"); */
459             }
460             fprintf(self->dumper.out, "    codes_set(ibufr, '%s', ", a->name);
461         }
462 
463         fprintf(self->dumper.out, "%s)\n", sval);
464         grib_context_free(c, sval);
465         if (doing_unexpandedDescriptors)
466             fprintf(self->dumper.out, "\n");
467     }
468 
469     if (self->isLeaf == 0) {
470         char* prefix;
471         int dofree = 0;
472 
473         if (r != 0) {
474             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
475             dofree = 1;
476             sprintf(prefix, "#%d#%s", r, a->name);
477         }
478         else
479             prefix = (char*)a->name;
480 
481         dump_attributes(d, a, prefix);
482         if (dofree)
483             grib_context_free(c, prefix);
484         depth -= 2;
485     }
486     (void)err; /* TODO */
487 }
488 
dump_long_attribute(grib_dumper * d,grib_accessor * a,const char * prefix)489 static void dump_long_attribute(grib_dumper* d, grib_accessor* a, const char* prefix)
490 {
491     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
492     long value                           = 0;
493     size_t size = 0, size2 = 0;
494     long* values = NULL;
495     int err = 0, i = 0, icount = 0;
496     int cols        = 4;
497     long count      = 0;
498     grib_context* c = a->context;
499 
500     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
501         return;
502 
503     grib_value_count(a, &count);
504     size = size2 = count;
505 
506     if (size > 1) {
507         values = (long*)grib_context_malloc_clear(a->context, sizeof(long) * size);
508         err    = grib_unpack_long(a, values, &size2);
509     }
510     else {
511         err = grib_unpack_long(a, &value, &size2);
512     }
513     Assert(size2 == size);
514 
515     self->empty = 0;
516 
517     if (size > 1) {
518         fprintf(self->dumper.out, "    ivalues = (");
519         icount = 0;
520         for (i = 0; i < size - 1; i++) {
521             if (icount > cols || i == 0) {
522                 fprintf(self->dumper.out, "  \n        ");
523                 icount = 0;
524             }
525             fprintf(self->dumper.out, "%ld, ", values[i]);
526             icount++;
527         }
528         if (icount > cols || i == 0) {
529             fprintf(self->dumper.out, "  \n        ");
530         }
531         fprintf(self->dumper.out, "%ld ", values[i]);
532 
533         depth -= 2;
534         /* Note: In python to make a tuple with one element, you need the trailing comma */
535         if (size > 4)
536             fprintf(self->dumper.out, ",) # %lu values\n", (unsigned long)size);
537         else
538             fprintf(self->dumper.out, ",)\n");
539         grib_context_free(a->context, values);
540 
541         fprintf(self->dumper.out, "    codes_set_array(ibufr, '%s->%s', ivalues)\n", prefix, a->name);
542     }
543     else {
544         char* sval = lval_to_string(c, value);
545         fprintf(self->dumper.out, "    codes_set(ibufr, '%s->%s', ", prefix, a->name);
546         fprintf(self->dumper.out, "%s)\n", sval);
547         grib_context_free(c, sval);
548     }
549 
550     if (self->isLeaf == 0) {
551         char* prefix1;
552 
553         prefix1 = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + strlen(prefix) + 5));
554         sprintf(prefix1, "%s->%s", prefix, a->name);
555 
556         dump_attributes(d, a, prefix1);
557 
558         grib_context_free(c, prefix1);
559         depth -= 2;
560     }
561     (void)err; /* TODO */
562 }
563 
dump_bits(grib_dumper * d,grib_accessor * a,const char * comment)564 static void dump_bits(grib_dumper* d, grib_accessor* a, const char* comment)
565 {
566 }
567 
dump_double(grib_dumper * d,grib_accessor * a,const char * comment)568 static void dump_double(grib_dumper* d, grib_accessor* a, const char* comment)
569 {
570     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
571     double value;
572     size_t size = 1;
573     int r;
574     char* sval;
575     grib_handle* h  = grib_handle_of_accessor(a);
576     grib_context* c = h->context;
577 
578     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
579         return;
580 
581     grib_unpack_double(a, &value, &size);
582     self->empty = 0;
583 
584     r = compute_bufr_key_rank(h, self->keys, a->name);
585 
586     sval = dval_to_string(c, value);
587     if (r != 0)
588         fprintf(self->dumper.out, "    codes_set(ibufr, '#%d#%s', %s)\n", r, a->name, sval);
589     else
590         fprintf(self->dumper.out, "    codes_set(ibufr, '%s', %s)\n", a->name, sval);
591     grib_context_free(c, sval);
592 
593     if (self->isLeaf == 0) {
594         char* prefix;
595         int dofree = 0;
596 
597         if (r != 0) {
598             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
599             dofree = 1;
600             sprintf(prefix, "#%d#%s", r, a->name);
601         }
602         else
603             prefix = (char*)a->name;
604 
605         dump_attributes(d, a, prefix);
606         if (dofree)
607             grib_context_free(c, prefix);
608         depth -= 2;
609     }
610 }
611 
dump_string_array(grib_dumper * d,grib_accessor * a,const char * comment)612 static void dump_string_array(grib_dumper* d, grib_accessor* a, const char* comment)
613 {
614     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
615     char** values;
616     size_t size = 0, i = 0;
617     grib_context* c = a->context;
618     int err         = 0;
619     long count      = 0;
620     int r           = 0;
621     grib_handle* h  = grib_handle_of_accessor(a);
622 
623     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
624         return;
625 
626     grib_value_count(a, &count);
627     size = count;
628     if (size == 1) {
629         dump_string(d, a, comment);
630         return;
631     }
632 
633     fprintf(self->dumper.out, "    svalues = (");
634 
635     self->empty = 0;
636 
637     values = (char**)grib_context_malloc_clear(c, size * sizeof(char*));
638     if (!values) {
639         grib_context_log(c, GRIB_LOG_FATAL, "unable to allocate %d bytes", (int)size);
640         return;
641     }
642 
643     err = grib_unpack_string_array(a, values, &size);
644 
645     for (i = 0; i < size - 1; i++) {
646         fprintf(self->dumper.out, "    \"%s\", \n", values[i]);
647     }
648     fprintf(self->dumper.out, "    \"%s\", )\n", values[i]);
649 
650     if (self->isLeaf == 0) {
651         if ((r = compute_bufr_key_rank(h, self->keys, a->name)) != 0)
652             fprintf(self->dumper.out, "    codes_set_array(ibufr, '#%d#%s', svalues)\n", r, a->name);
653         else
654             fprintf(self->dumper.out, "    codes_set_array(ibufr, '%s', svalues)\n", a->name);
655     }
656 
657     if (self->isLeaf == 0) {
658         char* prefix;
659         int dofree = 0;
660 
661         if (r != 0) {
662             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(a->name) + 10));
663             dofree = 1;
664             sprintf(prefix, "#%d#%s", r, a->name);
665         }
666         else
667             prefix = (char*)a->name;
668 
669         dump_attributes(d, a, prefix);
670         if (dofree)
671             grib_context_free(c, prefix);
672         depth -= 2;
673     }
674     for (i=0; i<size; ++i) grib_context_free(c, values[i]);
675     grib_context_free(c, values);
676     (void)err; /* TODO */
677 }
678 
dump_string(grib_dumper * d,grib_accessor * a,const char * comment)679 static void dump_string(grib_dumper* d, grib_accessor* a, const char* comment)
680 {
681     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
682     char* value                          = NULL;
683     char* p                              = NULL;
684     size_t size                          = 0;
685     grib_context* c                      = a->context;
686     int r = 0, err = 0;
687     grib_handle* h       = grib_handle_of_accessor(a);
688     const char* acc_name = a->name;
689 
690     _grib_get_string_length(a, &size);
691     if (size == 0)
692         return;
693 
694     if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0 || (a->flags & GRIB_ACCESSOR_FLAG_READ_ONLY) != 0)
695         return;
696 
697     value = (char*)grib_context_malloc_clear(c, size);
698     if (!value) {
699         grib_context_log(c, GRIB_LOG_FATAL, "unable to allocate %d bytes", (int)size);
700         return;
701     }
702 
703     self->empty = 0;
704 
705     err = grib_unpack_string(a, value, &size);
706     p   = value;
707     r   = compute_bufr_key_rank(h, self->keys, acc_name);
708     if (grib_is_missing_string(a, (unsigned char*)value, size)) {
709         strcpy(value, ""); /* Empty string means MISSING string */
710     }
711 
712     while (*p) {
713         if (!isprint(*p))
714             *p = '.';
715         p++;
716     }
717 
718     if (self->isLeaf == 0) {
719         depth += 2;
720         if (r != 0)
721             fprintf(self->dumper.out, "    codes_set(ibufr, '#%d#%s',", r, acc_name);
722         else
723             fprintf(self->dumper.out, "    codes_set(ibufr, '%s',", acc_name);
724     }
725     fprintf(self->dumper.out, "\'%s\')\n", value);
726 
727 
728     if (self->isLeaf == 0) {
729         char* prefix;
730         int dofree = 0;
731 
732         if (r != 0) {
733             prefix = (char*)grib_context_malloc_clear(c, sizeof(char) * (strlen(acc_name) + 10));
734             dofree = 1;
735             sprintf(prefix, "#%d#%s", r, acc_name);
736         }
737         else
738             prefix = (char*)acc_name;
739 
740         dump_attributes(d, a, prefix);
741         if (dofree)
742             grib_context_free(c, prefix);
743         depth -= 2;
744     }
745 
746     grib_context_free(c, value);
747     (void)err; /* TODO */
748 }
749 
dump_bytes(grib_dumper * d,grib_accessor * a,const char * comment)750 static void dump_bytes(grib_dumper* d, grib_accessor* a, const char* comment)
751 {
752 }
753 
dump_label(grib_dumper * d,grib_accessor * a,const char * comment)754 static void dump_label(grib_dumper* d, grib_accessor* a, const char* comment)
755 {
756 }
757 
_dump_long_array(grib_handle * h,FILE * f,const char * key,const char * print_key)758 static void _dump_long_array(grib_handle* h, FILE* f, const char* key, const char* print_key)
759 {
760     long* val;
761     size_t size = 0, i;
762     int cols = 9, icount = 0;
763 
764     if (grib_get_size(h, key, &size) == GRIB_NOT_FOUND)
765         return;
766     if (size == 0)
767         return;
768 
769     fprintf(f, "    ivalues = (");
770 
771     val = (long*)grib_context_malloc_clear(h->context, sizeof(long) * size);
772     grib_get_long_array(h, key, val, &size);
773     for (i = 0; i < size - 1; i++) {
774         if (icount > cols || i == 0) {
775             fprintf(f, "  \n        ");
776             icount = 0;
777         }
778         fprintf(f, "%ld, ", val[i]);
779         icount++;
780     }
781     if (icount > cols) {
782         fprintf(f, "  \n        ");
783     }
784     /* Note: In python to make a tuple with one element, you need the trailing comma */
785     if (size > 4)
786         fprintf(f, "%ld ,) # %lu values\n", val[size - 1], (unsigned long)size);
787     else
788         fprintf(f, "%ld ,)\n", val[size - 1]);
789 
790     grib_context_free(h->context, val);
791     fprintf(f, "    codes_set_array(ibufr, '%s', ivalues)\n", print_key);
792 }
793 
dump_section(grib_dumper * d,grib_accessor * a,grib_block_of_accessors * block)794 static void dump_section(grib_dumper* d, grib_accessor* a, grib_block_of_accessors* block)
795 {
796     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
797     if (!grib_inline_strcmp(a->name, "BUFR") ||
798         !grib_inline_strcmp(a->name, "GRIB") ||
799         !grib_inline_strcmp(a->name, "META")) {
800         grib_handle* h = grib_handle_of_accessor(a);
801         depth          = 2;
802         self->empty    = 1;
803         depth += 2;
804         _dump_long_array(h, self->dumper.out, "dataPresentIndicator", "inputDataPresentIndicator");
805         _dump_long_array(h, self->dumper.out, "delayedDescriptorReplicationFactor", "inputDelayedDescriptorReplicationFactor");
806         _dump_long_array(h, self->dumper.out, "shortDelayedDescriptorReplicationFactor", "inputShortDelayedDescriptorReplicationFactor");
807         _dump_long_array(h, self->dumper.out, "extendedDelayedDescriptorReplicationFactor", "inputExtendedDelayedDescriptorReplicationFactor");
808         _dump_long_array(h, self->dumper.out, "inputOverriddenReferenceValues", "inputOverriddenReferenceValues");
809         grib_dump_accessors_block(d, block);
810         depth -= 2;
811     }
812     else if (!grib_inline_strcmp(a->name, "groupNumber")) {
813         if ((a->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0)
814             return;
815         self->empty = 1;
816         depth += 2;
817         grib_dump_accessors_block(d, block);
818         depth -= 2;
819     }
820     else {
821         grib_dump_accessors_block(d, block);
822     }
823 }
824 
dump_attributes(grib_dumper * d,grib_accessor * a,const char * prefix)825 static void dump_attributes(grib_dumper* d, grib_accessor* a, const char* prefix)
826 {
827     int i                                = 0;
828     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
829     unsigned long flags;
830     while (i < MAX_ACCESSOR_ATTRIBUTES && a->attributes[i]) {
831         self->isAttribute = 1;
832         if ((d->option_flags & GRIB_DUMP_FLAG_ALL_ATTRIBUTES) == 0 && (a->attributes[i]->flags & GRIB_ACCESSOR_FLAG_DUMP) == 0) {
833             i++;
834             continue;
835         }
836         self->isLeaf = a->attributes[i]->attributes[0] == NULL ? 1 : 0;
837         flags        = a->attributes[i]->flags;
838         a->attributes[i]->flags |= GRIB_ACCESSOR_FLAG_DUMP;
839         switch (grib_accessor_get_native_type(a->attributes[i])) {
840             case GRIB_TYPE_LONG:
841                 dump_long_attribute(d, a->attributes[i], prefix);
842                 break;
843             case GRIB_TYPE_DOUBLE:
844                 dump_values_attribute(d, a->attributes[i], prefix);
845                 break;
846             case GRIB_TYPE_STRING:
847                 break;
848         }
849         a->attributes[i]->flags = flags;
850         i++;
851     }
852     self->isLeaf      = 0;
853     self->isAttribute = 0;
854 }
855 
header(grib_dumper * d,grib_handle * h)856 static void header(grib_dumper* d, grib_handle* h)
857 {
858     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
859     char sampleName[200]                 = { 0 };
860     long localSectionPresent, edition, bufrHeaderCentre, isSatellite;
861 
862     grib_get_long(h, "localSectionPresent", &localSectionPresent);
863     grib_get_long(h, "bufrHeaderCentre", &bufrHeaderCentre);
864     grib_get_long(h, "edition", &edition);
865 
866     if (localSectionPresent && bufrHeaderCentre == 98) {
867         grib_get_long(h, "isSatellite", &isSatellite);
868         if (isSatellite)
869             sprintf(sampleName, "BUFR%ld_local_satellite", edition);
870         else
871             sprintf(sampleName, "BUFR%ld_local", edition);
872     }
873     else {
874         sprintf(sampleName, "BUFR%ld", edition);
875     }
876 
877     if (d->count < 2) {
878         /* This is the first message being processed */
879         fprintf(self->dumper.out, "#  This program was automatically generated with bufr_dump -Epython\n");
880         fprintf(self->dumper.out, "#  Using ecCodes version: ");
881         grib_print_api_version(self->dumper.out);
882         fprintf(self->dumper.out, "\n\n");
883         fprintf(self->dumper.out, "from __future__ import print_function\n");
884         fprintf(self->dumper.out, "import traceback\n");
885         fprintf(self->dumper.out, "import sys\n");
886         fprintf(self->dumper.out, "from eccodes import *\n\n\n");
887         fprintf(self->dumper.out, "def bufr_encode():\n");
888     }
889     fprintf(self->dumper.out, "    ibufr = codes_bufr_new_from_samples('%s')\n", sampleName);
890 }
891 
footer(grib_dumper * d,grib_handle * h)892 static void footer(grib_dumper* d, grib_handle* h)
893 {
894     grib_dumper_bufr_encode_python* self = (grib_dumper_bufr_encode_python*)d;
895     fprintf(self->dumper.out, "\n    # Encode the keys back in the data section\n");
896     fprintf(self->dumper.out, "    codes_set(ibufr, 'pack', 1)\n\n");
897     if (d->count == 1)
898         fprintf(self->dumper.out, "    outfile = open('outfile.bufr', 'wb')\n");
899     else
900         fprintf(self->dumper.out, "    outfile = open('outfile.bufr', 'ab')\n");
901 
902     fprintf(self->dumper.out, "    codes_write(ibufr, outfile)\n");
903     if (d->count == 1)
904         fprintf(self->dumper.out, "    print (\"Created output BUFR file 'outfile.bufr'\")\n");
905     /*fprintf(self->dumper.out,"    codes_close_file(outfile)\n");*/
906     fprintf(self->dumper.out, "    codes_release(ibufr)\n");
907 }
908