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