Coverage Report

Created: 2025-06-09 08:44

/src/gdal/frmts/grib/degrib/g2clib/compack.c
Line
Count
Source (jump to first uncovered line)
1
#include <stdlib.h>
2
#include <math.h>
3
#include "grib2.h"
4
5
6
void compack(g2float *fld,g2int ndpts,g2int idrsnum,g2int *idrstmpl,
7
             unsigned char *cpack,g2int *lcpack)
8
//$$$  SUBPROGRAM DOCUMENTATION BLOCK
9
//                .      .    .                                       .
10
// SUBPROGRAM:    compack
11
//   PRGMMR: Gilbert          ORG: W/NP11    DATE: 2002-11-07
12
//
13
// ABSTRACT: This subroutine packs up a data field using a complex
14
//   packing algorithm as defined in the GRIB2 documentation.  It
15
//   supports GRIB2 complex packing templates with or without
16
//   spatial differences (i.e. DRTs 5.2 and 5.3).
17
//   It also fills in GRIB2 Data Representation Template 5.2 or 5.3
18
//   with the appropriate values.
19
//
20
// PROGRAM HISTORY LOG:
21
// 2002-11-07  Gilbert
22
//
23
// USAGE:    void compack(g2float *fld,g2int ndpts,g2int idrsnum,
24
//                g2int *idrstmpl,unsigned char *cpack,g2int *lcpack)
25
//
26
//   INPUT ARGUMENTS:
27
//     fld[]    - Contains the data values to pack
28
//     ndpts    - The number of data values in array fld[]
29
//     idrsnum  - Data Representation Template number 5.N
30
//                Must equal 2 or 3.
31
//     idrstmpl - Contains the array of values for Data Representation
32
//                Template 5.2 or 5.3
33
//                [0] = Reference value - ignored on input
34
//                [1] = Binary Scale Factor
35
//                [2] = Decimal Scale Factor
36
//                    .
37
//                    .
38
//                [6] = Missing value management
39
//                [7] = Primary missing value
40
//                [8] = Secondary missing value
41
//                    .
42
//                    .
43
//               [16] = Order of Spatial Differencing  ( 1 or 2 )
44
//                    .
45
//                    .
46
//
47
//   OUTPUT ARGUMENTS:
48
//     idrstmpl - Contains the array of values for Data Representation
49
//                Template 5.3
50
//                [0] = Reference value - set by compack routine.
51
//                [1] = Binary Scale Factor - unchanged from input
52
//                [2] = Decimal Scale Factor - unchanged from input
53
//                    .
54
//                    .
55
//     cpack    - The packed data field
56
//     lcpack   - length of packed field cpack (or -1 in case of error)
57
//
58
// REMARKS: None
59
//
60
// ATTRIBUTES:
61
//   LANGUAGE: C
62
//   MACHINE:
63
//
64
//$$$
65
0
{
66
67
0
      const g2int zero=0;
68
0
      g2int  *ifld,*gref,*glen,*gwidth;
69
0
      g2int  *jmin, *jmax, *lbit;
70
0
      g2int  i,j,n, /* nbits, */ imin,imax,left;
71
0
      g2int  isd,itemp,ilmax,ngwidthref=0,nbitsgwidth=0;
72
0
      g2int  nglenref=0,nglenlast=0,iofst,ival1,ival2=0;
73
0
      g2int  minsd,nbitsd=0,maxorig,nbitorig,ngroups;
74
0
      g2int  lg,ng,igmax,iwmax,nbitsgref;
75
0
      g2int  glength,grpwidth,nbitsglen=0;
76
0
      g2int  kfildo, minpk, inc, maxgrps, ibit, jbit, kbit, novref, lbitref;
77
0
      g2int  missopt, miss1, miss2, ier = 0;
78
0
      g2float  bscale,dscale,rmax,rmin,temp;
79
0
      const g2int simple_alg = 0;
80
0
      const g2float alog2=0.69314718f;       //  ln(2.0)
81
0
      const g2int one=1;
82
83
0
      bscale=(float)int_power(2.0,-idrstmpl[1]);
84
0
      dscale=(float)int_power(10.0,idrstmpl[2]);
85
//
86
//  Find max and min values in the data
87
//
88
0
      rmax=fld[0];
89
0
      rmin=fld[0];
90
0
      for (j=1;j<ndpts;j++) {
91
0
        if (fld[j] > rmax) rmax=fld[j];
92
0
        if (fld[j] < rmin) rmin=fld[j];
93
0
      }
94
95
//
96
//  If max and min values are not equal, pack up field.
97
//  If they are equal, we have a constant field, and the reference
98
//  value (rmin) is the value for each point in the field and
99
//  set nbits to 0.
100
//
101
0
      if (rmin != rmax) {
102
0
        iofst=0;
103
0
        ifld=calloc(ndpts,sizeof(g2int));
104
0
        gref=calloc(ndpts,sizeof(g2int));
105
0
        gwidth=calloc(ndpts,sizeof(g2int));
106
0
        glen=calloc(ndpts,sizeof(g2int));
107
0
        if( ifld == NULL || gref == NULL || gwidth == NULL || glen == NULL )
108
0
        {
109
0
            free(ifld);
110
0
            free(gref);
111
0
            free(gwidth);
112
0
            free(glen);
113
0
            *lcpack = -1;
114
0
            return;
115
0
        }
116
        //
117
        //  Scale original data
118
        //
119
0
        if (idrstmpl[1] == 0) {        //  No binary scaling
120
0
           imin=(g2int)RINT(rmin*dscale);
121
           //imax=(g2int)rint(rmax*dscale);
122
0
           rmin=(g2float)imin;
123
0
           for (j=0;j<ndpts;j++)
124
0
              ifld[j]=(g2int)RINT(fld[j]*dscale)-imin;
125
0
        }
126
0
        else {                             //  Use binary scaling factor
127
0
           rmin=rmin*dscale;
128
           //rmax=rmax*dscale;
129
0
           for (j=0;j<ndpts;j++)
130
0
             ifld[j]=(g2int)RINT(((fld[j]*dscale)-rmin)*bscale);
131
0
        }
132
        //
133
        //  Calculate spatial differences, if using DRS Template 5.3.
134
        //
135
0
        if (idrsnum == 3) {        // spatial differences
136
0
           if (idrstmpl[16]!=1 && idrstmpl[16]!=2) idrstmpl[16]=1;
137
0
           if (idrstmpl[16] == 1) {      // first order
138
0
              ival1=ifld[0];
139
0
              for (j=ndpts-1;j>0;j--)
140
0
                 ifld[j]=ifld[j]-ifld[j-1];
141
0
              ifld[0]=0;
142
0
           }
143
0
           else if (idrstmpl[16] == 2) {      // second order
144
0
              ival1=ifld[0];
145
0
              ival2=ifld[1];
146
0
              for (j=ndpts-1;j>1;j--)
147
0
                 ifld[j]=ifld[j]-(2*ifld[j-1])+ifld[j-2];
148
0
              ifld[0]=0;
149
0
              ifld[1]=0;
150
0
           }
151
           //
152
           //  subtract min value from spatial diff field
153
           //
154
0
           isd=idrstmpl[16];
155
0
           minsd=ifld[isd];
156
0
           for (j=isd;j<ndpts;j++)  if ( ifld[j] < minsd ) minsd=ifld[j];
157
0
           for (j=isd;j<ndpts;j++)  ifld[j]=ifld[j]-minsd;
158
           //
159
           //   find num of bits need to store minsd and add 1 extra bit
160
           //   to indicate sign
161
           //
162
0
           temp=(float)(log((double)(abs(minsd)+1))/alog2);
163
0
           nbitsd=(g2int)ceil(temp)+1;
164
           //
165
           //   find num of bits need to store ifld[0] ( and ifld[1]
166
           //   if using 2nd order differencing )
167
           //
168
0
           maxorig=ival1;
169
0
           if (idrstmpl[16]==2 && ival2>ival1) maxorig=ival2;
170
0
           temp=(float)(log((double)(maxorig+1))/alog2);
171
0
           nbitorig=(g2int)ceil(temp)+1;
172
0
           if (nbitorig > nbitsd) nbitsd=nbitorig;
173
           //   increase number of bits to even multiple of 8 ( octet )
174
0
           if ( (nbitsd%8) != 0) nbitsd=nbitsd+(8-(nbitsd%8));
175
           //
176
           //  Store extra spatial differencing info into the packed
177
           //  data section.
178
           //
179
0
           if (nbitsd != 0) {
180
              //   pack first original value
181
0
              if (ival1 >= 0) {
182
0
                 sbit(cpack,&ival1,iofst,nbitsd);
183
0
                 iofst=iofst+nbitsd;
184
0
              }
185
0
              else {
186
0
                 sbit(cpack,&one,iofst,1);
187
0
                 iofst=iofst+1;
188
0
                 itemp=abs(ival1);
189
0
                 sbit(cpack,&itemp,iofst,nbitsd-1);
190
0
                 iofst=iofst+nbitsd-1;
191
0
              }
192
0
              if (idrstmpl[16] == 2) {
193
               //  pack second original value
194
0
                 if (ival2 >= 0) {
195
0
                    sbit(cpack,&ival2,iofst,nbitsd);
196
0
                    iofst=iofst+nbitsd;
197
0
                 }
198
0
                 else {
199
0
                    sbit(cpack,&one,iofst,1);
200
0
                    iofst=iofst+1;
201
0
                    itemp=abs(ival2);
202
0
                    sbit(cpack,&itemp,iofst,nbitsd-1);
203
0
                    iofst=iofst+nbitsd-1;
204
0
                 }
205
0
              }
206
              //  pack overall min of spatial differences
207
0
              if (minsd >= 0) {
208
0
                 sbit(cpack,&minsd,iofst,nbitsd);
209
0
                 iofst=iofst+nbitsd;
210
0
              }
211
0
              else {
212
0
                 sbit(cpack,&one,iofst,1);
213
0
                 iofst=iofst+1;
214
0
                 itemp=abs(minsd);
215
0
                 sbit(cpack,&itemp,iofst,nbitsd-1);
216
0
                 iofst=iofst+nbitsd-1;
217
0
              }
218
0
           }
219
           //printf("SDp %ld %ld %ld %ld\n",ival1,ival2,minsd,nbitsd);
220
0
        }     //  end of spatial diff section
221
        //
222
        //   Determine Groups to be used.
223
        //
224
0
        if ( simple_alg == 1 ) {
225
           //  set group length to 10;  calculate number of groups
226
           //  and length of last group
227
0
           ngroups=ndpts/10;
228
0
           for (j=0;j<ngroups;j++) glen[j]=10;
229
0
           itemp=ndpts%10;
230
0
           if (itemp != 0) {
231
0
              ngroups=ngroups+1;
232
0
              glen[ngroups-1]=itemp;
233
0
           }
234
0
        }
235
0
        else {
236
           // Use Dr. Glahn's algorithm for determining grouping.
237
           //
238
0
           kfildo=6;
239
0
           minpk=10;
240
0
           inc=1;
241
0
           maxgrps=(ndpts/minpk)+1;
242
0
           jmin = calloc(maxgrps,sizeof(g2int));
243
0
           jmax = calloc(maxgrps,sizeof(g2int));
244
0
           lbit = calloc(maxgrps,sizeof(g2int));
245
0
           if( jmin == NULL || jmax == NULL || lbit == NULL )
246
0
           {
247
0
                free(jmin);
248
0
                free(jmax);
249
0
                free(lbit);
250
251
0
                free(ifld);
252
0
                free(gref);
253
0
                free(gwidth);
254
0
                free(glen);
255
0
                *lcpack = -1;
256
0
                return;
257
0
           }
258
0
           missopt=0;
259
0
           pack_gp(&kfildo,ifld,&ndpts,&missopt,&minpk,&inc,&miss1,&miss2,
260
0
                        jmin,jmax,lbit,glen,&maxgrps,&ngroups,&ibit,&jbit,
261
0
                        &kbit,&novref,&lbitref,&ier);
262
           //print *,'SAGier = ',ier,ibit,jbit,kbit,novref,lbitref
263
0
           for ( ng=0; ng<ngroups; ng++) glen[ng]=glen[ng]+novref;
264
0
           free(jmin);
265
0
           free(jmax);
266
0
           free(lbit);
267
0
           if( ier != 0 )
268
0
           {
269
0
                free(ifld);
270
0
                free(gref);
271
0
                free(gwidth);
272
0
                free(glen);
273
0
                *lcpack = -1;
274
0
                return;
275
0
           }
276
0
        }
277
        //
278
        //  For each group, find the group's reference value
279
        //  and the number of bits needed to hold the remaining values
280
        //
281
0
        n=0;
282
0
        for (ng=0;ng<ngroups;ng++) {
283
           //    find max and min values of group
284
0
           gref[ng]=ifld[n];
285
0
           imax=ifld[n];
286
0
           j=n+1;
287
0
           for (lg=1;lg<glen[ng];lg++) {
288
0
              if (ifld[j] < gref[ng]) gref[ng]=ifld[j];
289
0
              if (ifld[j] > imax) imax=ifld[j];
290
0
              j++;
291
0
           }
292
           //   calc num of bits needed to hold data
293
0
           if ( gref[ng] != imax ) {
294
0
              temp=(float)(log((double)(imax-gref[ng]+1))/alog2);
295
0
              gwidth[ng]=(g2int)ceil(temp);
296
0
           }
297
0
           else
298
0
              gwidth[ng]=0;
299
           //   Subtract min from data
300
0
           j=n;
301
0
           for (lg=0;lg<glen[ng];lg++) {
302
0
              ifld[j]=ifld[j]-gref[ng];
303
0
              j++;
304
0
           }
305
           //   increment fld array counter
306
0
           n=n+glen[ng];
307
0
        }
308
        //
309
        //  Find max of the group references and calc num of bits needed
310
        //  to pack each groups reference value, then
311
        //  pack up group reference values
312
        //
313
0
        igmax=gref[0];
314
0
        for (j=1;j<ngroups;j++) if (gref[j] > igmax) igmax=gref[j];
315
0
        if (igmax != 0) {
316
0
           temp=(float)(log((double)(igmax+1))/alog2);
317
0
           nbitsgref=(g2int)ceil(temp);
318
0
           sbits(cpack,gref,iofst,nbitsgref,0,ngroups);
319
0
           itemp=nbitsgref*ngroups;
320
0
           iofst=iofst+itemp;
321
           //         Pad last octet with Zeros, if necessary,
322
0
           if ( (itemp%8) != 0) {
323
0
              left=8-(itemp%8);
324
0
              sbit(cpack,&zero,iofst,left);
325
0
              iofst=iofst+left;
326
0
           }
327
0
        }
328
0
        else
329
0
           nbitsgref=0;
330
        //
331
        //  Find max/min of the group widths and calc num of bits needed
332
        //  to pack each groups width value, then
333
        //  pack up group width values
334
        //
335
0
        iwmax=gwidth[0];
336
0
        ngwidthref=gwidth[0];
337
0
        for (j=1;j<ngroups;j++) {
338
0
           if (gwidth[j] > iwmax) iwmax=gwidth[j];
339
0
           if (gwidth[j] < ngwidthref) ngwidthref=gwidth[j];
340
0
        }
341
0
        if (iwmax != ngwidthref) {
342
0
           temp=(float)(log((double)(iwmax-ngwidthref+1))/alog2);
343
0
           nbitsgwidth=(g2int)ceil(temp);
344
0
           for (i=0;i<ngroups;i++)
345
0
              gwidth[i]=gwidth[i]-ngwidthref;
346
0
           sbits(cpack,gwidth,iofst,nbitsgwidth,0,ngroups);
347
0
           itemp=nbitsgwidth*ngroups;
348
0
           iofst=iofst+itemp;
349
           //         Pad last octet with Zeros, if necessary,
350
0
           if ( (itemp%8) != 0) {
351
0
              left=8-(itemp%8);
352
0
              sbit(cpack,&zero,iofst,left);
353
0
              iofst=iofst+left;
354
0
           }
355
0
        }
356
0
        else {
357
0
           nbitsgwidth=0;
358
0
           for (i=0;i<ngroups;i++) gwidth[i]=0;
359
0
        }
360
        //
361
        //  Find max/min of the group lengths and calc num of bits needed
362
        //  to pack each groups length value, then
363
        //  pack up group length values
364
        //
365
        //write(77,*)'GLENS: ',(glen(j),j=1,ngroups)
366
0
        ilmax=glen[0];
367
0
        nglenref=glen[0];
368
0
        for (j=1;j<ngroups-1;j++) {
369
0
           if (glen[j] > ilmax) ilmax=glen[j];
370
0
           if (glen[j] < nglenref) nglenref=glen[j];
371
0
        }
372
0
        nglenlast=glen[ngroups-1];
373
0
        if (ilmax != nglenref) {
374
0
           temp=(float)(log((double)(ilmax-nglenref+1))/alog2);
375
0
           nbitsglen=(g2int)ceil(temp);
376
0
           for (i=0;i<ngroups-1;i++)  glen[i]=glen[i]-nglenref;
377
0
           sbits(cpack,glen,iofst,nbitsglen,0,ngroups);
378
0
           itemp=nbitsglen*ngroups;
379
0
           iofst=iofst+itemp;
380
           //         Pad last octet with Zeros, if necessary,
381
0
           if ( (itemp%8) != 0) {
382
0
              left=8-(itemp%8);
383
0
              sbit(cpack,&zero,iofst,left);
384
0
              iofst=iofst+left;
385
0
           }
386
0
        }
387
0
        else {
388
0
           nbitsglen=0;
389
0
           for (i=0;i<ngroups;i++) glen[i]=0;
390
0
        }
391
        //
392
        //  For each group, pack data values
393
        //
394
0
        n=0;
395
0
        for (ng=0;ng<ngroups;ng++) {
396
0
           glength=glen[ng]+nglenref;
397
0
           if (ng == (ngroups-1) ) glength=nglenlast;
398
0
           grpwidth=gwidth[ng]+ngwidthref;
399
0
           if ( grpwidth != 0 ) {
400
0
              sbits(cpack,ifld+n,iofst,grpwidth,0,glength);
401
0
              iofst=iofst+(grpwidth*glength);
402
0
           }
403
0
           n=n+glength;
404
0
        }
405
        //         Pad last octet with Zeros, if necessary,
406
0
        if ( (iofst%8) != 0) {
407
0
           left=8-(iofst%8);
408
0
           sbit(cpack,&zero,iofst,left);
409
0
           iofst=iofst+left;
410
0
        }
411
0
        *lcpack=iofst/8;
412
        //
413
0
        free(ifld);
414
0
        free(gref);
415
0
        free(gwidth);
416
0
        free(glen);
417
0
      }
418
0
      else {          //   Constant field ( max = min )
419
        /* nbits=0; */
420
0
        *lcpack=0;
421
0
        nbitsgref=0;
422
0
        ngroups=0;
423
0
      }
424
425
//
426
//  Fill in ref value and number of bits in Template 5.2
427
//
428
0
      mkieee(&rmin,idrstmpl+0,1);   // ensure reference value is IEEE format
429
0
      idrstmpl[3]=nbitsgref;
430
0
      idrstmpl[4]=0;         // original data were reals
431
0
      idrstmpl[5]=1;         // general group splitting
432
0
      idrstmpl[6]=0;         // No internal missing values
433
0
      idrstmpl[7]=0;         // Primary missing value
434
0
      idrstmpl[8]=0;         // secondary missing value
435
0
      idrstmpl[9]=ngroups;          // Number of groups
436
0
      idrstmpl[10]=ngwidthref;       // reference for group widths
437
0
      idrstmpl[11]=nbitsgwidth;      // num bits used for group widths
438
0
      idrstmpl[12]=nglenref;         // Reference for group lengths
439
0
      idrstmpl[13]=1;                // length increment for group lengths
440
0
      idrstmpl[14]=nglenlast;        // True length of last group
441
0
      idrstmpl[15]=nbitsglen;        // num bits used for group lengths
442
0
      if (idrsnum == 3) {
443
0
         idrstmpl[17]=nbitsd/8;      // num bits used for extra spatial
444
                                     // differencing values
445
0
      }
446
447
0
}