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 
13 /*
14    This is used by make_class.pl
15 
16    START_CLASS_DEF
17    CLASS      = accessor
18    SUPER      = grib_accessor_class_long
19    IMPLEMENTS = unpack_long
20    IMPLEMENTS = init;dump
21    MEMBERS=const char* date
22    MEMBERS=const char* time
23    MEMBERS=const char* step
24    MEMBERS=const char* stepUnits
25    MEMBERS=const char* hours
26    MEMBERS=const char* minutes
27    END_CLASS_DEF
28 
29  */
30 
31 /* START_CLASS_IMP */
32 
33 /*
34 
35 Don't edit anything between START_CLASS_IMP and END_CLASS_IMP
36 Instead edit values between START_CLASS_DEF and END_CLASS_DEF
37 or edit "accessor.class" and rerun ./make_class.pl
38 
39 */
40 
41 static int unpack_long(grib_accessor*, long* val, size_t* len);
42 static void dump(grib_accessor*, grib_dumper*);
43 static void init(grib_accessor*, const long, grib_arguments*);
44 static void init_class(grib_accessor_class*);
45 
46 typedef struct grib_accessor_validity_time
47 {
48     grib_accessor att;
49     /* Members defined in gen */
50     /* Members defined in long */
51     /* Members defined in validity_time */
52     const char* date;
53     const char* time;
54     const char* step;
55     const char* stepUnits;
56     const char* hours;
57     const char* minutes;
58 } grib_accessor_validity_time;
59 
60 extern grib_accessor_class* grib_accessor_class_long;
61 
62 static grib_accessor_class _grib_accessor_class_validity_time = {
63     &grib_accessor_class_long,           /* super                     */
64     "validity_time",                     /* name                      */
65     sizeof(grib_accessor_validity_time), /* size                      */
66     0,                                   /* inited */
67     &init_class,                         /* init_class */
68     &init,                               /* init                      */
69     0,                                   /* post_init                      */
70     0,                                   /* free mem                       */
71     &dump,                               /* describes himself         */
72     0,                                   /* get length of section     */
73     0,                                   /* get length of string      */
74     0,                                   /* get number of values      */
75     0,                                   /* get number of bytes      */
76     0,                                   /* get offset to bytes           */
77     0,                                   /* get native type               */
78     0,                                   /* get sub_section                */
79     0,                                   /* grib_pack procedures long      */
80     0,                                   /* grib_pack procedures long      */
81     0,                                   /* grib_pack procedures long      */
82     &unpack_long,                        /* grib_unpack procedures long    */
83     0,                                   /* grib_pack procedures double    */
84     0,                                   /* grib_unpack procedures double  */
85     0,                                   /* grib_pack procedures string    */
86     0,                                   /* grib_unpack procedures string  */
87     0,                                   /* grib_pack array procedures string    */
88     0,                                   /* grib_unpack array procedures string  */
89     0,                                   /* grib_pack procedures bytes     */
90     0,                                   /* grib_unpack procedures bytes   */
91     0,                                   /* pack_expression */
92     0,                                   /* notify_change   */
93     0,                                   /* update_size   */
94     0,                                   /* preferred_size   */
95     0,                                   /* resize   */
96     0,                                   /* nearest_smaller_value */
97     0,                                   /* next accessor    */
98     0,                                   /* compare vs. another accessor   */
99     0,                                   /* unpack only ith value          */
100     0,                                   /* unpack a subarray         */
101     0,                                   /* clear          */
102     0,                                   /* clone accessor          */
103 };
104 
105 
106 grib_accessor_class* grib_accessor_class_validity_time = &_grib_accessor_class_validity_time;
107 
108 
init_class(grib_accessor_class * c)109 static void init_class(grib_accessor_class* c)
110 {
111     c->next_offset            = (*(c->super))->next_offset;
112     c->string_length          = (*(c->super))->string_length;
113     c->value_count            = (*(c->super))->value_count;
114     c->byte_count             = (*(c->super))->byte_count;
115     c->byte_offset            = (*(c->super))->byte_offset;
116     c->get_native_type        = (*(c->super))->get_native_type;
117     c->sub_section            = (*(c->super))->sub_section;
118     c->pack_missing           = (*(c->super))->pack_missing;
119     c->is_missing             = (*(c->super))->is_missing;
120     c->pack_long              = (*(c->super))->pack_long;
121     c->pack_double            = (*(c->super))->pack_double;
122     c->unpack_double          = (*(c->super))->unpack_double;
123     c->pack_string            = (*(c->super))->pack_string;
124     c->unpack_string          = (*(c->super))->unpack_string;
125     c->pack_string_array      = (*(c->super))->pack_string_array;
126     c->unpack_string_array    = (*(c->super))->unpack_string_array;
127     c->pack_bytes             = (*(c->super))->pack_bytes;
128     c->unpack_bytes           = (*(c->super))->unpack_bytes;
129     c->pack_expression        = (*(c->super))->pack_expression;
130     c->notify_change          = (*(c->super))->notify_change;
131     c->update_size            = (*(c->super))->update_size;
132     c->preferred_size         = (*(c->super))->preferred_size;
133     c->resize                 = (*(c->super))->resize;
134     c->nearest_smaller_value  = (*(c->super))->nearest_smaller_value;
135     c->next                   = (*(c->super))->next;
136     c->compare                = (*(c->super))->compare;
137     c->unpack_double_element  = (*(c->super))->unpack_double_element;
138     c->unpack_double_subarray = (*(c->super))->unpack_double_subarray;
139     c->clear                  = (*(c->super))->clear;
140     c->make_clone             = (*(c->super))->make_clone;
141 }
142 
143 /* END_CLASS_IMP */
144 
145 /* Table of multipliers to convert step units to minutes */
146 static const double u2m[] = {
147     1,            /* index 0:  minutes  */
148     60,           /* index 1:  hour     */
149     24 * 60,      /* index 2:  day      */
150     24 * 60 * 30, /* index 3:  month    */
151     -1,           /* index 4:  year     */
152     -1,           /* index 5:  decade   */
153     -1,           /* index 6:  30 years */
154     -1,           /* index 7:  century  */
155     -1,           /* index 8:  RESERVED */
156     -1,           /* index 9:  RESERVED */
157     3 * 60,       /* index 10: 3 hours  */
158     6 * 60,       /* index 11: 6 hours  */
159     12 * 60,      /* index 12: 12 hours */
160     1 / 60.0,     /* index 13: seconds  */
161     15,           /* index 14: 15 mins  */
162     30            /* index 15: 30 mins  */
163 };
164 
convert_to_minutes(long step,long stepUnits)165 static long convert_to_minutes(long step, long stepUnits)
166 {
167     double result = 0;
168     if (stepUnits == 0)
169         return step; /* unit=minutes so no change */
170     if (stepUnits == 1)
171         return step * 60; /* unit=hours */
172     if (stepUnits == 13)
173         return step / 60; /* unit=seconds*/
174     /* Assert( stepUnits < sizeof(u2m)/sizeof(u2m[0]) ); */
175 
176     result = step * u2m[stepUnits];
177     return (long)result;
178 }
179 
init(grib_accessor * a,const long l,grib_arguments * c)180 static void init(grib_accessor* a, const long l, grib_arguments* c)
181 {
182     grib_accessor_validity_time* self = (grib_accessor_validity_time*)a;
183     grib_handle* hand                 = grib_handle_of_accessor(a);
184     int n                             = 0;
185 
186     self->date      = grib_arguments_get_name(hand, c, n++);
187     self->time      = grib_arguments_get_name(hand, c, n++);
188     self->step      = grib_arguments_get_name(hand, c, n++);
189     self->stepUnits = grib_arguments_get_name(hand, c, n++);
190     self->hours     = grib_arguments_get_name(hand, c, n++);
191     self->minutes   = grib_arguments_get_name(hand, c, n++);
192 
193     a->flags |= GRIB_ACCESSOR_FLAG_READ_ONLY;
194 }
195 
dump(grib_accessor * a,grib_dumper * dumper)196 static void dump(grib_accessor* a, grib_dumper* dumper)
197 {
198     grib_dump_long(dumper, a, NULL);
199 }
200 
unpack_long(grib_accessor * a,long * val,size_t * len)201 static int unpack_long(grib_accessor* a, long* val, size_t* len)
202 {
203     grib_accessor_validity_time* self = (grib_accessor_validity_time*)a;
204     grib_handle* hand                 = grib_handle_of_accessor(a);
205     int ret                           = 0;
206     long date                         = 0;
207     long time                         = 0;
208     long step                         = 0;
209     long stepUnits                    = 0;
210     long hours = 0, minutes = 0, step_mins = 0, tmp, tmp_hrs, tmp_mins;
211 
212     if (self->hours) {
213         if ((ret = grib_get_long_internal(hand, self->hours, &hours)) != GRIB_SUCCESS)
214             return ret;
215         if ((ret = grib_get_long_internal(hand, self->minutes, &minutes)) != GRIB_SUCCESS)
216             return ret;
217         *val = hours * 100 + minutes;
218         return GRIB_SUCCESS;
219     }
220     if ((ret = grib_get_long_internal(hand, self->date, &date)) != GRIB_SUCCESS)
221         return ret;
222     if ((ret = grib_get_long_internal(hand, self->time, &time)) != GRIB_SUCCESS)
223         return ret;
224     if ((ret = grib_get_long(hand, self->step, &step)) != GRIB_SUCCESS) {
225         if ((ret = grib_get_long_internal(hand, "endStep", &step)) != GRIB_SUCCESS) {
226             return ret; /* See ECC-817 */
227         }
228     }
229 
230     /* Seconds will always be zero. So convert to minutes */
231     if (self->stepUnits) {
232         if ((ret = grib_get_long_internal(hand, self->stepUnits, &stepUnits)) != GRIB_SUCCESS)
233             return ret;
234         step_mins = convert_to_minutes(step, stepUnits);
235     }
236 
237     minutes  = time % 100;
238     hours    = time / 100;
239     tmp      = minutes + step_mins; /* add the step to our minutes */
240     tmp_hrs  = tmp / 60;            /* how many hours and mins is that? */
241     tmp_mins = tmp % 60;
242     hours += tmp_hrs; /* increment hours */
243     if (hours > 0) {
244         hours = hours % 24; /* wrap round if >= 24 */
245     }
246     else {
247         /* GRIB-29: Negative forecast time */
248         while (hours < 0) {
249             hours += 24;
250         }
251     }
252     time = hours * 100 + tmp_mins;
253 
254     if (*len < 1)
255         return GRIB_ARRAY_TOO_SMALL;
256 
257     *val = time;
258 
259     return GRIB_SUCCESS;
260 }
261