1 #if 0
2 /* tdlpack is no longer supported by GDAL */
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
6 #include <math.h>
7 #include "tdlpack.h"
8 #include "myerror.h"
9 #include "meta.h"
10 #include "tendian.h"
11 #include "myassert.h"
12 #include "myutil.h"
13 #include "clock.h"
14 #ifdef MEMWATCH
15 #include "memwatch.h"
16 #endif
17 
18 #define GRIB_UNSIGN_INT3(a,b,c) ((a<<16)+(b<<8)+c)
19 #define GRIB_UNSIGN_INT2(a,b) ((a<<8)+b)
20 #define GRIB_SIGN_INT3(a,b,c) ((1-(int) ((unsigned) (a & 0x80) >> 6)) * (int) (((a & 127) << 16)+(b<<8)+c))
21 #define GRIB_SIGN_INT2(a,b) ((1-(int) ((unsigned) (a & 0x80) >> 6)) * (int) (((a & 0x7f) << 8) + b))
22 
23 #ifdef unused_by_GDAL
24 /* *INDENT-OFF* */
25 static const TDLP_TableType TDLP_B_Table[5] = {
26    /* 0 */ {0, "Continuous field"},
27    /* 1 */ {1, "Point Binary - cumulative from above"},
28    /* 2 */ {2, "Point Binary - cumulative from below"},
29    /* 3 */ {3, "Point Binary - discrete"},
30    /* 4 */ {5, "Grid Binary - "},
31 };
32 
33 static const TDLP_TableType TDLP_DD_Table[9] = {
34    /* 0 */ {0, "Independent of model"},
35    /* 1 */ {6, "NGM model"},
36    /* 2 */ {7, "Eta model"},
37    /* 3 */ {8, "AVN model"},
38    /* 4 */ {9, "MRF model"},
39    /* 5 */ {79, "NDFD forecast"},
40    /* 6 */ {80, "MOS AEV forecast"},
41    /* 7 */ {81, "Local AEV Firecasts"},
42    /* 8 */ {82, "Obs matching AEV Forecasts"},
43 };
44 
45 static const TDLP_TableType TDLP_V_Table[4] = {
46    /* 0 */ {0, "No vertical processing"},
47    /* 1 */ {1, "Difference Levels (UUUU - LLLL)"},
48    /* 2 */ {2, "Sum Levels (UUUU + LLLL)"},
49    /* 3 */ {3, "Mean Levels (UUUU + LLLL) / 2."},
50 };
51 
52 static const TDLP_TableType TDLP_T_Table[3] = {
53    /* 0 */ {0, "No nolinear transform"},
54    /* 1 */ {1, "Square transform"},
55    /* 2 */ {2, "Square root transform"},
56 };
57 
58 static const TDLP_TableType TDLP_Oper_Table[9] = {
59    /* 0 */ {0, "No time operator"},
60    /* 1 */ {1, "Mean (Var 1, Var 2)"},
61    /* 2 */ {2, "Difference (Var 1 - Var 2)"},
62    /* 3 */ {3, "Maximum (Var 1, Var 2)"},
63    /* 4 */ {4, "Minimum (Var 1, Var 2)"},
64    /* 5 */ {5, "Mean (Var 1, Var 2)"},
65    /* 6 */ {6, "Difference (Var 2 - Var 1)"},
66    /* 7 */ {7, "Maximum (Var 1, Var 2)"},
67    /* 8 */ {8, "Minimum (Var 1, Var 2)"},
68 };
69 
70 static const TDLP_TableType TDLP_I_Table[4] = {
71    /* 0 */ {0, "No interpolation"},
72    /* 1 */ {1, "Bi-quadratic interpolation"},
73    /* 2 */ {2, "Bi-linear interpolation"},
74    /* 3 */ {3, "Special interpolation for QPF"},
75 };
76 
77 static const TDLP_TableType TDLP_S_Table[6] = {
78    /* 0 */ {0, "No smoothing"},
79    /* 1 */ {1, "5-point smoothing"},
80    /* 2 */ {2, "9-point smoothing"},
81    /* 3 */ {3, "25-point smoothing"},
82    /* 4 */ {4, "81-point smoothing"},
83    /* 5 */ {5, "168-point smoothing"},
84 };
85 /* *INDENT-ON*  */
86 #endif
87 
88 typedef struct {
89    sInt4 min;           /* Minimum value in a group. Can cause problems if
90                          * this is unsigned. */
91    uChar bit;           /* # of bits in a group. 2^31 is the largest # of
92                          * bits that can be used to hold # of bits in a
93                          * group. However, the # of bits for a number can't
94                          * be > 64, and is probably < 32, so bit is < 6 and
95                          * probably < 5. */
96    uInt4 num;           /* number of values in the group. May need this to be
97                          * signed. */
98    sInt4 max;           /* Max value for the group */
99    uInt4 start;         /* index in Data where group starts. */
100    uChar f_trySplit;    /* Flag, if we have tried to split this group. */
101    uChar f_tryShift;    /* Flag, if we have tried to shift this group. */
102 } TDLGroupType;
103 
104 /*****************************************************************************
105  * ReadTDLPSect1() --
106  *
107  * Arthur Taylor / MDL
108  *
109  * PURPOSE
110  *   Parses the TDLP "Product Definition Section" or section 1, filling out
111  * the pdsMeta data structure.
112  *
113  * ARGUMENTS
114  *     pds = The compressed part of the message dealing with "PDS". (Input)
115  * gribLen = The total length of the TDLP message. (Input)
116  *  curLoc = Current location in the TDLP message. (Output)
117  * pdsMeta = The filled out pdsMeta data structure. (Output)
118  *   f_gds = boolean if there is a Grid Definition Section. (Output)
119  *   f_bms = boolean if there is a Bitmap Section. (Output)
120  *     DSF = Decimal Scale Factor for unpacking the data. (Output)
121  *     BSF = Binary Scale Factor for unpacking the data. (Output)
122  *
123  * FILES/DATABASES: None
124  *
125  * RETURNS: int (could use errSprintf())
126  *  0 = OK
127  * -1 = gribLen is too small.
128  *
129  * HISTORY
130  *  10/2004 Arthur Taylor (MDL): Created.
131  *
132  * NOTES
133  *****************************************************************************
134  */
135 static int ReadTDLPSect1 (uChar *pds, sInt4 tdlpLen, sInt4 *curLoc,
136                           pdsTDLPType * pdsMeta, char *f_gds, char *f_bms,
137                           short int *DSF, short int *BSF)
138 {
139    char sectLen;        /* Length of section. */
140    sInt4 li_temp;       /* Temporary variable. */
141    int W, XXXX, YY;     /* Helps with Threshold calculation. */
142    int year, t_year;    /* The reference year, and a consistency test */
143    uChar month, t_month; /* The reference month, and a consistency test */
144    uChar day, t_day;    /* The reference day, and a consistency test */
145    uChar hour, t_hour;  /* The reference hour, and a consistency test */
146    uChar min;           /* The reference minute */
147    uShort2 project_hr;  /* The projection in hours. */
148    sInt4 tau;           /* Used to cross check project_hr */
149    int lenPL;           /* Length of the Plain Language descriptor. */
150 
151    sectLen = *(pds++);
152    *curLoc += sectLen;
153    if (*curLoc > tdlpLen) {
154       errSprintf ("Ran out of data in PDS (TDLP Section 1)\n");
155       return -1;
156    }
157    if( sectLen > 71 ) {
158       errSprintf ("TDLP Section 1 is too big.\n");
159       return -1;
160    }
161    if (sectLen < 39) {
162       errSprintf ("TDLP Section 1 is too small.\n");
163       return -1;
164    }
165    *f_bms = (GRIB2BIT_7 & *pds) ? 1 : 0;
166    *f_gds = (GRIB2BIT_8 & *pds) ? 1 : 0;
167    pds++;
168    year = GRIB_UNSIGN_INT2 (*pds, pds[1]);
169    pds += 2;
170    month = *(pds++);
171    day = *(pds++);
172    hour = *(pds++);
173    min = *(pds++);
174    MEMCPY_BIG (&li_temp, pds, sizeof (sInt4));
175    pds += 4;
176    t_year = li_temp / 1000000;
177    li_temp -= t_year * 1000000;
178    t_month = li_temp / 10000;
179    li_temp -= t_month * 10000;
180    t_day = li_temp / 100;
181    t_hour = li_temp - t_day * 100;
182    if ((t_year != year) || (t_month != month) || (t_day != day) ||
183        (t_hour != hour)) {
184       errSprintf ("Error Inconsistent Times in ReadTDLPSect1.\n");
185       return -1;
186    }
187    if (ParseTime (&(pdsMeta->refTime), year, month, day, hour, min, 0) != 0) {
188       preErrSprintf ("Error In call to ParseTime in ReadTDLPSect1.\n");
189       return -1;
190    }
191    MEMCPY_BIG (&(li_temp), pds, sizeof (sInt4));
192    pds += 4;
193    pdsMeta->ID1 = li_temp;
194    pdsMeta->CCC = li_temp / 1000000;
195    li_temp -= pdsMeta->CCC * 1000000;
196    pdsMeta->FFF = li_temp / 1000;
197    li_temp -= pdsMeta->FFF * 1000;
198    pdsMeta->B = li_temp / 100;
199    pdsMeta->DD = li_temp - pdsMeta->B * 100;
200    MEMCPY_BIG (&(li_temp), pds, sizeof (sInt4));
201    pds += 4;
202    pdsMeta->ID2 = li_temp;
203    pdsMeta->V = li_temp / 100000000;
204    li_temp -= pdsMeta->V * 100000000;
205    pdsMeta->LLLL = li_temp / 10000;
206    pdsMeta->UUUU = li_temp - pdsMeta->LLLL * 10000;
207    MEMCPY_BIG (&(li_temp), pds, sizeof (sInt4));
208    pds += 4;
209    pdsMeta->ID3 = li_temp;
210    pdsMeta->T = li_temp / 100000000;
211    li_temp -= pdsMeta->T * 100000000;
212    pdsMeta->RR = li_temp / 1000000;
213    li_temp -= pdsMeta->RR * 1000000;
214    pdsMeta->Oper = li_temp / 100000;
215    li_temp -= pdsMeta->Oper * 100000;
216    pdsMeta->HH = li_temp / 1000;
217    pdsMeta->ttt = li_temp - pdsMeta->HH * 1000;
218    MEMCPY_BIG (&(li_temp), pds, sizeof (sInt4));
219    pds += 4;
220    pdsMeta->ID4 = li_temp;
221    W = li_temp / 1000000000;
222    li_temp -= W * 1000000000;
223    XXXX = li_temp / 100000;
224    li_temp -= XXXX * 100000;
225    if (W) {
226       XXXX = -1 * XXXX;
227    }
228    YY = li_temp / 1000;
229    li_temp -= YY * 1000;
230    if (YY >= 50) {
231       YY = -1 * (YY - 50);
232    }
233    pdsMeta->thresh = (XXXX / 10000.) * pow (10.0, YY);
234    pdsMeta->I = li_temp / 100;
235    li_temp -= pdsMeta->I * 100;
236    pdsMeta->S = li_temp / 10;
237    pdsMeta->G = li_temp - pdsMeta->S * 10;
238    project_hr = GRIB_UNSIGN_INT2 (*pds, pds[1]);
239    tau = pdsMeta->ID3 - ((pdsMeta->ID3 / 1000) * 1000);
240    if (tau != project_hr) {
241       printf ("Warning: Inconsistent Projections in hours in "
242               "ReadTDLPSect1 (%d vs %d)\n", tau, project_hr);
243 /*
244       errSprintf ("Warning: Inconsistent Projections in hours in "
245                   "ReadTDLPSect1 (%ld vs %d)\n", tau, project_hr);
246 */
247       project_hr = tau;
248 /*      return -1; */
249    }
250    pds += 2;
251    pdsMeta->project = project_hr * 3600 + (*(pds++)) * 60;
252    pdsMeta->procNum = (*(pds++));
253    pdsMeta->seqNum = (*(pds++));
254    *DSF = (*pds > 128) ? 128 - (*(pds++)) : (*(pds++));
255    *BSF = (*pds > 128) ? 128 - (*(pds++)) : (*(pds++));
256    if ((*pds != 0) || (pds[1] != 0) || (pds[2] != 0)) {
257       errSprintf ("Error Reserved was not set to 0 in ReadTDLPSect1.\n");
258       return -1;
259    }
260    pds += 3;
261    lenPL = (*(pds++));
262    if (sectLen - lenPL != 39) {
263       errSprintf ("Error sectLen(%d) - lenPL(%d) != 39 in ReadTDLPSect1.\n",
264                   sectLen, lenPL);
265       return -1;
266    }
267    if (lenPL > 32) {
268       lenPL = 32;
269    }
270    strncpy (pdsMeta->Descriptor, (char *) pds, lenPL);
271    pdsMeta->Descriptor[lenPL] = '\0';
272    strTrim (pdsMeta->Descriptor);
273    return 0;
274 }
275 
276 #ifdef unused_by_GDAL
277 /*****************************************************************************
278  * TDLP_TableLookUp() --
279  *
280  * Arthur Taylor / MDL
281  *
282  * PURPOSE
283  *   To look up TDL Ids information in a given table.
284  *
285  * ARGUMENTS
286  *    table = The Table to look up the Id in. (Input)
287  * tableLen = The length of the Table. (Input)
288  *    index = The index into the Table. (Input)
289  *
290  * FILES/DATABASES: None
291  *
292  * RETURNS: char *
293  *   Returns the meta data that is associated with index in the table.
294  *
295  * HISTORY
296  *  10/2004 Arthur Taylor (MDL): Created.
297  *
298  * NOTES
299  *****************************************************************************
300  */
301 static const char *TDLP_TableLookUp(const TDLP_TableType * table, int tableLen,
302                                     int index)
303 {
304    int i;               /* Loop counter. */
305 
306    for (i = 0; i < tableLen; i++) {
307       if (table[i].index == index)
308          return (table[i].data);
309    }
310    return "Unknown";
311 }
312 
313 /*****************************************************************************
314  * PrintPDS_TDLP() --
315  *
316  * Arthur Taylor / MDL
317  *
318  * PURPOSE
319  *   To generate the message for the Product Definition Sections of the TDLP
320  * Message.
321  *
322  * ARGUMENTS
323  * pds = The TDLP Product Definition Section to print. (Input)
324  *
325  * FILES/DATABASES: None
326  *
327  * RETURNS: void
328  *
329  * HISTORY
330  *  10/2004 Arthur Taylor (MDL): Created.
331  *
332  * NOTES
333  *****************************************************************************
334  */
335 void PrintPDS_TDLP (pdsTDLPType * pds)
336 {
337    char buffer[25];     /* Stores format of pds1->refTime. */
338 
339 /*
340    strftime (buffer, 25, "%m/%d/%Y %H:%M:%S UTC", gmtime (&(pds->refTime)));
341 */
342    Clock_Print (buffer, 25, pds->refTime, "%m/%d/%Y %H:%M:%S UTC", 0);
343 
344    Print ("PDS-TDLP", "Reference Time", Prt_S, buffer);
345    Print ("PDS-TDLP", "Plain Language", Prt_S, pds->Descriptor);
346    snprintf(buffer, sizeof(buffer), "%09d", pds->ID1);
347    Print ("PDS-TDLP", "ID 1", Prt_S, buffer);
348    snprintf(buffer, sizeof(buffer), "%09d", pds->ID2);
349    Print ("PDS-TDLP", "ID 2", Prt_S, buffer);
350    snprintf(buffer, sizeof(buffer), "%09d", pds->ID3);
351    Print ("PDS-TDLP", "ID 3", Prt_S, buffer);
352    Print ("PDS-TDLP", "ID 4", Prt_D, pds->ID4);
353    Print ("PDS-TDLP", "Model or Process Number", Prt_D, pds->procNum);
354    Print ("PDS-TDLP", "Sequence Number", Prt_D, pds->seqNum);
355 
356    snprintf(buffer, sizeof(buffer), "%03d", pds->CCC);
357    Print ("PDS-TDLP", "ID1-CCC", Prt_S, buffer);
358    snprintf(buffer, sizeof(buffer), "%03d", pds->FFF);
359    Print ("PDS-TDLP", "ID1-FFF", Prt_S, buffer);
360    Print ("PDS-TDLP", "ID1-B", Prt_DS, pds->B,
361           TDLP_TableLookUp (TDLP_B_Table, sizeof (TDLP_B_Table), pds->B));
362    snprintf(buffer, sizeof(buffer), "%02d", pds->DD);
363    Print ("PDS-TDLP", "ID1-DD", Prt_SS, buffer,
364           TDLP_TableLookUp (TDLP_DD_Table, sizeof (TDLP_DD_Table), pds->DD));
365 
366    Print ("PDS-TDLP", "ID2-V", Prt_DS, pds->V,
367           TDLP_TableLookUp (TDLP_V_Table, sizeof (TDLP_V_Table), pds->V));
368    snprintf(buffer, sizeof(buffer), "%04d", pds->LLLL);
369    Print ("PDS-TDLP", "ID2-LLLL", Prt_S, buffer);
370    snprintf(buffer, sizeof(buffer), "%04d", pds->UUUU);
371    Print ("PDS-TDLP", "ID2-UUUU", Prt_S, buffer);
372 
373    if (pds->Oper != 0) {
374       Print ("PDS-TDLP", "ID3-T", Prt_DS, pds->T,
375              TDLP_TableLookUp (TDLP_T_Table, sizeof (TDLP_T_Table), pds->T));
376       snprintf(buffer, sizeof(buffer), "%02d", pds->RR);
377       Print ("PDS-TDLP", "ID3-RR", Prt_SS, buffer,
378              "Run time offset in hours");
379       Print ("PDS-TDLP", "ID3-Oper", Prt_DS, pds->Oper,
380              TDLP_TableLookUp (TDLP_Oper_Table, sizeof (TDLP_Oper_Table),
381                                pds->Oper));
382       snprintf(buffer, sizeof(buffer), "%02d", pds->HH);
383       Print ("PDS-TDLP", "ID3-HH", Prt_SS, buffer,
384              "Number of hours between variables");
385    } else {
386       Print ("PDS-TDLP", "ID3-Oper", Prt_DS, pds->Oper,
387              TDLP_TableLookUp (TDLP_Oper_Table, sizeof (TDLP_Oper_Table),
388                                pds->Oper));
389    }
390    snprintf(buffer, sizeof(buffer), "%03d", pds->ttt);
391    Print ("PDS-TDLP", "ID3-ttt", Prt_SS, buffer, "Forecast Projection");
392 
393    Print ("PDS-TDLP", "ID4-thresh", Prt_F, pds->thresh);
394    Print ("PDS-TDLP", "ID4-I", Prt_DS, pds->I,
395           TDLP_TableLookUp (TDLP_I_Table, sizeof (TDLP_I_Table), pds->I));
396    Print ("PDS-TDLP", "ID4-S", Prt_DS, pds->S,
397           TDLP_TableLookUp (TDLP_S_Table, sizeof (TDLP_S_Table), pds->S));
398    Print ("PDS-TDLP", "ID4-G", Prt_D, pds->G);
399 }
400 #endif // unused_by_GDAL
401 
402 /*****************************************************************************
403  * TDLP_ElemSurfUnit() --
404  *
405  * Arthur Taylor / MDL
406  *
407  * PURPOSE
408  *   Deal with element name, unit, and comment for TDLP items.  Also deals
409  * with the surface information stored in ID2.
410  *
411  * ARGUMENTS
412  *           pds = The TDLP Product Definition Section to parse. (Input)
413  *       element = The resulting element name. (Output)
414  *      unitName = The resulting unit name. (Output)
415  *       comment = The resulting comment. (Output)
416  * shortFstLevel = The resulting short forecast level. (Output)
417  *  longFstLevel = The resulting long forecast level. (Output)
418  *
419  * FILES/DATABASES: None
420  *
421  * RETURNS: void
422  *
423  * HISTORY
424  *  10/2004 Arthur Taylor (MDL): Created.
425  *
426  * NOTES
427  *****************************************************************************
428  */
429 static void TDLP_ElemSurfUnit (pdsTDLPType * pds, char **element,
430                                char **unitName, char **comment,
431                                char **shortFstLevel, char **longFstLevel)
432 {
433    char *ptr;           /* Help guess unitName, and clean the elemName. */
434    char *ptr2;          /* Help guess unitName, and clean the elemName. */
435 
436    myAssert (*element == NULL);
437    myAssert (*unitName == NULL);
438    myAssert (*comment == NULL);
439    myAssert (*shortFstLevel == NULL);
440    myAssert (*longFstLevel == NULL);
441 
442    *element = (char *) malloc (1 + strlen (pds->Descriptor) * sizeof (char));
443    strcpy (*element, pds->Descriptor);
444    (*element)[strlen (pds->Descriptor)] = '\0';
445 
446    ptr = strchr (*element, '(');
447    if (ptr != nullptr) {
448       ptr2 = strchr (ptr, ')');
449       *ptr2 = '\0';
450       if (strcmp (ptr + 1, "unofficial id") == 0) {
451          *unitName = (char *) malloc ((1 + 3) * sizeof (char));
452          strcpy (*unitName, "[-]");
453       } else {
454          reallocSprintf (unitName, "[%s]", ptr + 1);
455       }
456       /* Trim any parens from element. */
457       *ptr = '\0';
458       strTrimRight (*element, ' ');
459    } else {
460       *unitName = (char *) malloc ((1 + 3) * sizeof (char));
461       strcpy (*unitName, "[-]");
462    }
463    ptr = *element;
464    while (*ptr != '\0') {
465       if (*ptr == ' ') {
466          *ptr = '-';
467       }
468       ptr++;
469    }
470    strCompact (*element, '-');
471 
472    reallocSprintf (comment, "%09ld-%09ld-%09ld-%ld %s", pds->ID1,
473                    pds->ID2, pds->ID3, pds->ID4, *unitName);
474    reallocSprintf (shortFstLevel, "%09ld", pds->ID2);
475    reallocSprintf (longFstLevel, "%09ld", pds->ID2);
476 }
477 
478 /*****************************************************************************
479  * TDLP_Inventory() --
480  *
481  * Arthur Taylor / MDL
482  *
483  * PURPOSE
484  *   Parses the TDLP "Product Definition Section" for enough information to
485  * fill out the inventory data structure so we can do a simple inventory on
486  * the file in a similar way to how we did it for GRIB1 and GRIB2.
487  *
488  * ARGUMENTS
489  *      fp = An opened TDLP file already at the correct message. (Input)
490  * tdlpLen = The total length of the TDLP message. (Input)
491  *     inv = The inventory data structure that we need to fill. (Output)
492  *
493  * FILES/DATABASES: None
494  *
495  * RETURNS: int (could use errSprintf())
496  *  0 = OK
497  * -1 = tdlpLen is too small.
498  *
499  * HISTORY
500  *  10/2004 Arthur Taylor (MDL): Created.
501  *
502  * NOTES
503  *   Speed improvements...
504  * 1) pds does not need to be allocated each time.
505  * 2) Not all data is needed, do something like TDLP_RefTime
506  * 3) TDLP_ElemSurfUnit may be slow?
507  *****************************************************************************
508  */
509 int TDLP_Inventory (DataSource &fp, sInt4 tdlpLen, inventoryType *inv)
510 {
511    sInt4 curLoc;        /* Where we are in the current TDLP message. */
512    int i_temp;
513    uChar sectLen;       /* Length of section. */
514    uChar *pds;          /* The part of the message dealing with the PDS. */
515    pdsTDLPType pdsMeta; /* The pds parsed into a usable data structure. */
516    char f_gds;          /* flag if there is a GDS section. */
517    char f_bms;          /* flag if there is a BMS section. */
518    short int DSF;       /* Decimal Scale Factor for unpacking the data. */
519    short int BSF;       /* Binary Scale Factor for unpacking the data. */
520 
521    curLoc = 8;
522    if ((i_temp = fp.DataSourceFgetc()) == EOF) {
523       errSprintf ("Ran out of file in PDS (TDLP_Inventory).\n");
524       return -1;
525    }
526    sectLen = (uChar) i_temp;
527    curLoc += sectLen;
528    if (curLoc > tdlpLen) {
529       errSprintf ("Ran out of data in PDS (TDLP_Inventory)\n");
530       return -1;
531    }
532    if( sectLen < 1 ) {
533        errSprintf ("Wrong sectLen (TDLP_Inventory)\n");
534        return -1;
535    }
536    pds = (uChar *) malloc (sectLen * sizeof (uChar));
537    if( pds == nullptr )
538    {
539       errSprintf ("Ran out of memory in PDS (TDLP_Inventory)\n");
540       return -1;
541    }
542    *pds = sectLen;
543    if (fp.DataSourceFread (pds + 1, sizeof (char), sectLen - 1) + 1 != sectLen) {
544       errSprintf ("Ran out of file.\n");
545       free (pds);
546       return -1;
547    }
548 
549    if (ReadTDLPSect1 (pds, tdlpLen, &curLoc, &pdsMeta, &f_gds, &f_bms,
550                       &DSF, &BSF) != 0) {
551       preErrSprintf ("Inside TDLP_Inventory\n");
552       free (pds);
553       return -1;
554    }
555    free (pds);
556 
557    inv->element = nullptr;
558    inv->unitName = nullptr;
559    inv->comment = nullptr;
560    free (inv->shortFstLevel);
561    inv->shortFstLevel = nullptr;
562    free (inv->longFstLevel);
563    inv->longFstLevel = nullptr;
564    TDLP_ElemSurfUnit (&pdsMeta, &(inv->element), &(inv->unitName),
565                       &(inv->comment), &(inv->shortFstLevel),
566                       &(inv->longFstLevel));
567 
568    inv->refTime = pdsMeta.refTime;
569    inv->validTime = pdsMeta.refTime + pdsMeta.project;
570    inv->foreSec = pdsMeta.project;
571    return 0;
572 }
573 
574 /*****************************************************************************
575  * TDLP_RefTime() --
576  *
577  * Arthur Taylor / MDL
578  *
579  * PURPOSE
580  *   Return just the reference time of a TDLP message.
581  *
582  * ARGUMENTS
583  *      fp = An opened TDLP file already at the correct message. (Input)
584  * tdlpLen = The total length of the TDLP message. (Input)
585  * refTime = The reference time of interest. (Output)
586  *
587  * FILES/DATABASES: None
588  *
589  * RETURNS: int (could use errSprintf())
590  *  0 = OK
591  * -1 = tdlpLen is too small.
592  *
593  * HISTORY
594  *  10/2004 Arthur Taylor (MDL): Created.
595  *
596  * NOTES
597  *****************************************************************************
598  */
599 int TDLP_RefTime (DataSource &fp, sInt4 tdlpLen, double *refTime)
600 {
601    int sectLen;         /* Length of section. */
602    sInt4 curLoc;        /* Where we are in the current TDLP message. */
603    int c_temp;          /* Temporary variable for use with fgetc */
604    short int si_temp;   /* Temporary variable. */
605    int year, t_year;    /* The reference year, and a consistency test */
606    uChar month, t_month; /* The reference month, and a consistency test */
607    uChar day, t_day;    /* The reference day, and a consistency test */
608    uChar hour, t_hour;  /* The reference hour, and a consistency test */
609    uChar min;           /* The reference minute */
610    sInt4 li_temp;       /* Temporary variable. */
611 
612    if ((sectLen = fp.DataSourceFgetc ()) == EOF)
613       goto error;
614    curLoc = 8 + sectLen;
615    if (curLoc > tdlpLen) {
616       errSprintf ("Ran out of data in PDS (TDLP_RefTime)\n");
617       return -1;
618    }
619    if( sectLen > 71 ) {
620       errSprintf ("TDLP Section 1 is too big.\n");
621       return -1;
622    }
623    if (sectLen < 39) {
624       errSprintf ("TDLP Section 1 is too small.\n");
625       return -1;
626    }
627 
628    if ((c_temp = fp.DataSourceFgetc()) == EOF)
629       goto error;
630    if (FREAD_BIG (&si_temp, sizeof (short int), 1, fp) != 1)
631       goto error;
632    year = si_temp;
633    if ((c_temp = fp.DataSourceFgetc()) == EOF)
634       goto error;
635    month = c_temp;
636    if ((c_temp = fp.DataSourceFgetc()) == EOF)
637       goto error;
638    day = c_temp;
639    if ((c_temp = fp.DataSourceFgetc()) == EOF)
640       goto error;
641    hour = c_temp;
642    if ((c_temp = fp.DataSourceFgetc()) == EOF)
643       goto error;
644    min = c_temp;
645 
646    if (FREAD_BIG (&li_temp, sizeof (sInt4), 1, fp) != 1)
647       goto error;
648    t_year = li_temp / 1000000;
649    li_temp -= t_year * 1000000;
650    t_month = li_temp / 10000;
651    li_temp -= t_month * 10000;
652    t_day = li_temp / 100;
653    t_hour = li_temp - t_day * 100;
654 
655    if ((t_year != year) || (t_month != month) || (t_day != day) ||
656        (t_hour != hour)) {
657       errSprintf ("Error Inconsistent Times in TDLP_RefTime.\n");
658       return -1;
659    }
660    if (ParseTime (refTime, year, month, day, hour, min, 0) != 0) {
661       preErrSprintf ("Error In call to ParseTime in TDLP_RefTime.\n");
662       return -1;
663    }
664 
665    /* Get to the end of the TDLP message. */
666    /* (inventory.c : GRIB2Inventory), is responsible for this. */
667    /* fseek (fp, gribLen - sectLen, SEEK_CUR); */
668    return 0;
669  error:
670    errSprintf ("Ran out of file in PDS (TDLP_RefTime).\n");
671    return -1;
672 }
673 
674 /*****************************************************************************
675  * ReadTDLPSect2() --
676  *
677  * Arthur Taylor / MDL
678  *
679  * PURPOSE
680  *   Parses the TDLP "Grid Definition Section" or section 2, filling out
681  * the gdsMeta data structure.
682  *
683  * ARGUMENTS
684  *     gds = The compressed part of the message dealing with "GDS". (Input)
685  * tdlpLen = The total length of the TDLP message. (Input)
686  *  curLoc = Current location in the TDLP message. (Output)
687  * gdsMeta = The filled out gdsMeta data structure. (Output)
688  *
689  * FILES/DATABASES: None
690  *
691  * RETURNS: int (could use errSprintf())
692  *  0 = OK
693  * -1 = tdlpLen is too small.
694  * -2 = unexpected values in gds.
695  *
696  * HISTORY
697  *  10/2004 Arthur Taylor (MDL): Created.
698  *
699  * NOTES
700  *****************************************************************************
701  */
702 static int ReadTDLPSect2 (uChar *gds, sInt4 tdlpLen, sInt4 *curLoc,
703                           gdsType *gdsMeta)
704 {
705    char sectLen;        /* Length of section. */
706    int gridType;        /* Which type of grid. (see enumerated types). */
707    sInt4 li_temp;       /* Temporary variable. */
708 
709    sectLen = *(gds++);
710    *curLoc += sectLen;
711    if (*curLoc > tdlpLen) {
712       errSprintf ("Ran out of data in GDS (TDLP Section 2)\n");
713       return -1;
714    }
715    if( sectLen != 28 ) {
716       errSprintf ("Wrong sectLen (TDLP Section 2)\n");
717       return -1;
718    }
719 
720    gridType = *(gds++);
721    gdsMeta->Nx = GRIB_UNSIGN_INT2 (*gds, gds[1]);
722    gds += 2;
723    gdsMeta->Ny = GRIB_UNSIGN_INT2 (*gds, gds[1]);
724    gds += 2;
725    gdsMeta->lat1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) / 10000.0;
726    gds += 3;
727    gdsMeta->lon1 = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) / 10000.0;
728    gdsMeta->lon1 = 360 - gdsMeta->lon1;
729    if (gdsMeta->lon1 < 0) {
730       gdsMeta->lon1 += 360;
731    }
732    if (gdsMeta->lon1 > 360) {
733       gdsMeta->lon1 -= 360;
734    }
735    gds += 3;
736    gdsMeta->orientLon = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) / 10000.0;
737    gdsMeta->orientLon = 360 - gdsMeta->orientLon;
738    if (gdsMeta->orientLon < 0) {
739       gdsMeta->orientLon += 360;
740    }
741    if (gdsMeta->orientLon > 360) {
742       gdsMeta->orientLon -= 360;
743    }
744    gds += 3;
745    MEMCPY_BIG (&li_temp, gds, sizeof (sInt4));
746    gdsMeta->Dx = li_temp / 1000.0;
747    gds += 4;
748    gdsMeta->meshLat = GRIB_SIGN_INT3 (*gds, gds[1], gds[2]) / 10000.0;
749    gds += 3;
750    if ((*gds != 0) || (gds[1] != 0) || (gds[2] != 0) || (gds[3] != 0) ||
751        (gds[4] != 0) || (gds[5] != 0)) {
752       errSprintf ("Error Reserved was not set to 0 in ReadTDLPSect2.\n");
753       return -1;
754    }
755 
756    gdsMeta->numPts = gdsMeta->Nx * gdsMeta->Ny;
757    gdsMeta->f_sphere = 1;
758    gdsMeta->majEarth = 6371.2;
759    gdsMeta->minEarth = 6371.2;
760    gdsMeta->Dy = gdsMeta->Dx;
761    gdsMeta->resFlag = 0;
762    gdsMeta->center = 0;
763    gdsMeta->scan = 64;
764    gdsMeta->lat2 = 0;
765    gdsMeta->lon2 = 0;
766    gdsMeta->scaleLat1 = gdsMeta->meshLat;
767    gdsMeta->scaleLat2 = gdsMeta->meshLat;
768    gdsMeta->southLat = 0;
769    gdsMeta->southLon = 0;
770    switch (gridType) {
771       case TDLP_POLAR:
772          gdsMeta->projType = GS3_POLAR;
773          /* 4/24/2006 Added the following. */
774          gdsMeta->scaleLat1 = 90;
775          gdsMeta->scaleLat2 = 90;
776          break;
777       case TDLP_LAMBERT:
778          gdsMeta->projType = GS3_LAMBERT;
779          break;
780       case TDLP_MERCATOR:
781          gdsMeta->projType = GS3_MERCATOR;
782          /* 4/24/2006 Added the following. */
783          gdsMeta->scaleLat1 = 0;
784          gdsMeta->scaleLat2 = 0;
785          break;
786       default:
787          errSprintf ("Grid projection number is %d\n", gridType);
788          return -2;
789    }
790    return 0;
791 }
792 
793 /*****************************************************************************
794  * ReadTDLPSect3() --
795  *
796  * Arthur Taylor / MDL
797  *
798  * PURPOSE
799  *   Parses the TDLP "Bit Map Section" or section 3, filling out the bitmap
800  * as needed.
801  *
802  * ARGUMENTS
803  *     bms = The compressed part of the message dealing with "BMS". (Input)
804  * tdlpLen = The total length of the TDLP message. (Input)
805  *  curLoc = Current location in the TDLP message. (Output)
806  *  bitmap = The extracted bitmap. (Output)
807  *    NxNy = The total size of the grid. (Input)
808  *
809  * FILES/DATABASES: None
810  *
811  * RETURNS: int (could use errSprintf())
812  *  0 = OK
813  * -1 = tdlpLen is too small.
814  * -2 = unexpected values in bms.
815  *
816  * HISTORY
817  *  10/2004 Arthur Taylor (MDL): Created.
818  *
819  * NOTES
820  *****************************************************************************
821  */
822 static int ReadTDLPSect3 (CPL_UNUSED uChar *bms,
823                           CPL_UNUSED sInt4 tdlpLen,
824                           CPL_UNUSED sInt4 *curLoc,
825                           CPL_UNUSED uChar *bitmap,
826                           CPL_UNUSED sInt4 NxNy)
827 {
828    errSprintf ("Bitmap data is Not Supported\n");
829    return -1;
830 }
831 
832 /*****************************************************************************
833  * ReadTDLPSect4() --
834  *
835  * Arthur Taylor / MDL
836  *
837  * PURPOSE
838  *   Unpacks the "Binary Data Section" or section 4.
839  *
840  * ARGUMENTS
841  *     bds = The compressed part of the message dealing with "BDS". (Input)
842  * tdlpLen = The total length of the TDLP message. (Input)
843  *  curLoc = Current location in the TDLP message. (Output)
844  *     DSF = Decimal Scale Factor for unpacking the data. (Input)
845  *     BSF = Binary Scale Factor for unpacking the data. (Input)
846  *    data = The extracted grid. (Output)
847  *    meta = The meta data associated with the grid (Input/Output)
848  *   unitM = The M unit conversion value in equation y = Mx + B. (Input)
849  *   unitB = The B unit conversion value in equation y = Mx + B. (Input)
850  *
851  * FILES/DATABASES: None
852  *
853  * RETURNS: int (could use errSprintf())
854  *  0 = OK
855  * -1 = gribLen is too small.
856  * -2 = unexpected values in bds.
857  *
858  * HISTORY
859  *   4/2003 Arthur Taylor (MDL/RSIS): Created
860  *   3/2004 AAT: Switched {# Pts * (# Bits in a Group) +
861  *          # of unused bits != # of available bits} to a warning from an
862  *          error.
863  *   2/2005 AAT: Found bug: memBitRead grp[i].bit was sizeof sInt4 instead
864  *          of uChar.
865  *   2/2005 AAT: Second order diff, no miss value bug (lastData - 1) should
866  *          be lastData.
867  *   2/2005 AAT: Added test to see if the number of bits needed matches the
868  *          section length.
869  *
870  * NOTES
871  * 1) See metaparse.c : ParseGrid()
872  *****************************************************************************
873  */
874 static int ReadTDLPSect4 (uChar *bds, sInt4 tdlpLen, sInt4 *curLoc,
875                           short int DSF, short int BSF, double *data,
876                           grib_MetaData *meta,
877                           CPL_UNUSED double unitM,
878                           CPL_UNUSED double unitB)
879 {
880    uInt4 sectLen;       /* Length in bytes of the current section. */
881    uChar f_notGridPnt;  /* Not Grid point data? */
882    uChar f_complexPack; /* Complex packing? */
883    uChar f_sndOrder;    /* Second order differencing? */
884    uChar f_primMiss;    /* Primary missing value? */
885    uChar f_secMiss;     /* Secondary missing value? */
886    uInt4 numPack;       /* Number of points packed. */
887    sInt4 li_temp;       /* Temporary variable. */
888    uInt4 uli_temp;      /* Temporary variable. */
889    uChar bufLoc;        /* Keeps track of where to start getting more data
890                          * out of the packed data stream. */
891    uChar f_negative;    /* used to help with signs of numbers. */
892    size_t numUsed;      /* How many bytes were used in a given call to
893                          * memBitRead. */
894    sInt4 origVal = 0;   /* Original value. */
895    uChar mbit;          /* # of bits for abs (first first order difference) */
896    sInt4 fstDiff = 0;   /* First first order difference. */
897    sInt4 diff = 0;      /* general first order difference. */
898    uChar nbit;          /* # of bits for abs (overall min value) */
899    sInt4 minVal;        /* Minimum value. */
900    size_t LX;           /* Number of groups. */
901    uChar ibit;          /* # of bits for group min values. */
902    uChar jbit;          /* # of bits for # of bits for group. */
903    uChar kbit;          /* # of bits for # values in a group. */
904    TDLGroupType *grp;   /* Holds the info about each group. */
905    size_t i, j;         /* Loop counters. */
906    uInt4 t_numPack;     /* Used to total number of values in a group to check
907                          * the numPack value. */
908    uInt4 t_numBits;     /* Used to total number of bits used in the groups. */
909    uInt4 t_numBytes;    /* Used to total number of bytes used to compare to
910                          * sectLen. */
911    sInt4 maxVal;        /* The max value in a group. */
912    uInt4 dataCnt;       /* How many values (miss or otherwise) we have read. */
913    uInt4 lastData;      /* Index to last actual data. */
914    uInt4 numVal;        /* # of actual (non-missing values) we have. */
915    double scale;        /* Amount to scale values by. */
916    uInt4 dataInd;       /* Index into data for this value (used to switch
917                          * from a11..a1n,a2n..a21 to normal grid of
918                          * a11..a1n,a21..a2n. */
919    uChar f_missing;     /* Used to help with primary missing values, and the
920                          * 0 bit possibility. */
921 #ifdef DEBUG
922    sInt4 t_UK1 = 0;     /* Used to test theories about un defined values. */
923    sInt4 t_UK2 = 0;     /* Used to test theories about un defined values. */
924 #endif
925 
926    sectLen = GRIB_UNSIGN_INT3 (*bds, bds[1], bds[2]);
927    *curLoc += sectLen;
928    if (*curLoc > tdlpLen) {
929       errSprintf ("Ran out of data in BDS (TDLP Section 4)\n");
930       return -1;
931    }
932    bds += 3;
933    t_numBytes = 3;
934    f_notGridPnt = (GRIB2BIT_4 & *bds) ? 1 : 0;
935    f_complexPack = (GRIB2BIT_5 & *bds) ? 1 : 0;
936    f_sndOrder = (GRIB2BIT_6 & *bds) ? 1 : 0;
937    f_primMiss = (GRIB2BIT_7 & *bds) ? 1 : 0;
938    f_secMiss = (GRIB2BIT_8 & *bds) ? 1 : 0;
939 
940    if (f_secMiss && (!f_primMiss)) {
941       errSprintf ("Secondary missing value without a primary!\n");
942       return -1;
943    }
944    if (f_complexPack) {
945       if (!f_sndOrder) {
946          meta->gridAttrib.packType = GS5_CMPLX;
947       } else {
948          meta->gridAttrib.packType = GS5_CMPLXSEC;
949       }
950    } else {
951       errSprintf ("Simple pack is not supported at this time.\n");
952       return -1;
953    }
954    bds++;
955    MEMCPY_BIG (&numPack, bds, sizeof (sInt4));
956    bds += 4;
957    t_numBytes += 5;
958    if (!f_notGridPnt) {
959       if (numPack != meta->gds.numPts) {
960          errSprintf ("Number packed %d != number of points %d\n", numPack,
961                      meta->gds.numPts);
962          return -1;
963       }
964    }
965    meta->gridAttrib.DSF = DSF;
966    meta->gridAttrib.ESF = BSF;
967    meta->gridAttrib.fieldType = 0;
968    if (!f_primMiss) {
969       meta->gridAttrib.f_miss = 0;
970       meta->gridAttrib.missPri = 0;
971       meta->gridAttrib.missSec = 0;
972    } else {
973       MEMCPY_BIG (&li_temp, bds, sizeof (sInt4));
974       bds += 4;
975       t_numBytes += 4;
976       meta->gridAttrib.missPri = li_temp / 10000.0;
977       if (!f_secMiss) {
978          meta->gridAttrib.f_miss = 1;
979          meta->gridAttrib.missSec = 0;
980       } else {
981          MEMCPY_BIG (&li_temp, bds, sizeof (sInt4));
982          bds += 4;
983          t_numBytes += 4;
984          meta->gridAttrib.missSec = li_temp / 10000.0;
985          meta->gridAttrib.f_miss = 2;
986       }
987    }
988    /* Init the buffer location. */
989    bufLoc = 8;
990    /* The origValue and fstDiff are only present if sndOrder packed. */
991    if (f_sndOrder) {
992       memBitRead (&f_negative, sizeof (f_negative), bds, 1, &bufLoc,
993                   &numUsed);
994       memBitRead (&uli_temp, sizeof (sInt4), bds, 31, &bufLoc, &numUsed);
995       myAssert (numUsed == 4);
996       bds += numUsed;
997       t_numBytes += static_cast<uInt4>(numUsed);
998       origVal = (f_negative) ? -1 * (sInt4)uli_temp : uli_temp;
999       memBitRead (&mbit, sizeof (mbit), bds, 5, &bufLoc, &numUsed);
1000       memBitRead (&f_negative, sizeof (f_negative), bds, 1, &bufLoc,
1001                   &numUsed);
1002       myAssert (numUsed == 0);
1003       myAssert ((mbit > 0) && (mbit < 32));
1004       memBitRead (&uli_temp, sizeof (sInt4), bds, mbit, &bufLoc, &numUsed);
1005       bds += numUsed;
1006       t_numBytes += static_cast<uInt4>(numUsed);
1007       fstDiff = (f_negative) ? -1 * (sInt4)uli_temp : uli_temp;
1008    }
1009    memBitRead (&nbit, sizeof (nbit), bds, 5, &bufLoc, &numUsed);
1010    bds += numUsed;
1011    t_numBytes += static_cast<uInt4>(numUsed);
1012    memBitRead (&f_negative, sizeof (f_negative), bds, 1, &bufLoc, &numUsed);
1013    bds += numUsed;
1014    t_numBytes += static_cast<uInt4>(numUsed);
1015    myAssert ((nbit > 0) && (nbit < 32));
1016    memBitRead (&uli_temp, sizeof (sInt4), bds, nbit, &bufLoc, &numUsed);
1017    bds += numUsed;
1018    t_numBytes += static_cast<uInt4>(numUsed);
1019    minVal = (f_negative) ? -1 * (sInt4)uli_temp : uli_temp;
1020    memBitRead (&LX, sizeof (LX), bds, 16, &bufLoc, &numUsed);
1021    bds += numUsed;
1022    t_numBytes += static_cast<uInt4>(numUsed);
1023    grp = (TDLGroupType *) malloc (LX * sizeof (TDLGroupType));
1024    memBitRead (&ibit, sizeof (ibit), bds, 5, &bufLoc, &numUsed);
1025    bds += numUsed;
1026    t_numBytes += static_cast<uInt4>(numUsed);
1027    memBitRead (&jbit, sizeof (jbit), bds, 5, &bufLoc, &numUsed);
1028    /* Following assert is because it is the # of bits of # of bits.  Which
1029     * means that # of bits of value that has a max of 64. */
1030    myAssert (jbit < 6);
1031    bds += numUsed;
1032    t_numBytes += static_cast<uInt4>(numUsed);
1033    memBitRead (&kbit, sizeof (kbit), bds, 5, &bufLoc, &numUsed);
1034    bds += numUsed;
1035    t_numBytes += static_cast<uInt4>(numUsed);
1036    myAssert (ibit < 33);
1037    for (i = 0; i < LX; i++) {
1038       if (ibit == 0) {
1039          grp[i].min = 0;
1040       } else {
1041          memBitRead (&(grp[i].min), sizeof (sInt4), bds, ibit, &bufLoc,
1042                      &numUsed);
1043          bds += numUsed;
1044          t_numBytes += static_cast<uInt4>(numUsed);
1045       }
1046    }
1047    myAssert (jbit < 8);
1048    for (i = 0; i < LX; i++) {
1049       if (jbit == 0) {
1050          grp[i].bit = 0;
1051       } else {
1052          myAssert (jbit <= sizeof (uChar) * 8);
1053          memBitRead (&(grp[i].bit), sizeof (uChar), bds, jbit, &bufLoc,
1054                      &numUsed);
1055          bds += numUsed;
1056          t_numBytes += static_cast<uInt4>(numUsed);
1057       }
1058       myAssert (grp[i].bit < 32);
1059    }
1060    myAssert (kbit < 33);
1061    t_numPack = 0;
1062    t_numBits = 0;
1063    for (i = 0; i < LX; i++) {
1064       if (kbit == 0) {
1065          grp[i].num = 0;
1066       } else {
1067          memBitRead (&(grp[i].num), sizeof (sInt4), bds, kbit, &bufLoc,
1068                      &numUsed);
1069          bds += numUsed;
1070          t_numBytes += static_cast<uInt4>(numUsed);
1071       }
1072       t_numPack += grp[i].num;
1073       t_numBits += grp[i].num * grp[i].bit;
1074    }
1075    if (t_numPack != numPack) {
1076       errSprintf ("Number packed %d != number of values in groups %d\n",
1077                   numPack, t_numPack);
1078       free (grp);
1079       return -1;
1080    }
1081    if ((t_numBytes + ceil (t_numBits / 8.)) > sectLen) {
1082       errSprintf ("# bytes in groups %ld (%ld + %ld / 8) > sectLen %ld\n",
1083                   (sInt4) (t_numBytes + ceil (t_numBits / 8.)),
1084                   t_numBytes, t_numBits, sectLen);
1085       free (grp);
1086       return -1;
1087    }
1088    dataCnt = 0;
1089    dataInd = 0;
1090 
1091 #ifdef DEBUG
1092    printf ("nbit %d, ibit %d, jbit %d, kbit %d\n", nbit, ibit, jbit, kbit);
1093    if ((t_numBytes + ceil (t_numBits / 8.)) != sectLen) {
1094       printf ("Caution: # bytes in groups %d (%u + %u / 8) != "
1095               "sectLen %u\n", (sInt4) (t_numBytes + ceil (t_numBits / 8.)),
1096               t_numBytes, t_numBits, sectLen);
1097    }
1098 #endif
1099 
1100    /* Binary scale factor in TDLP has reverse sign from GRIB definition. */
1101    scale = pow (10.0, -1 * DSF) * pow (2.0, -1 * BSF);
1102 
1103    meta->gridAttrib.f_maxmin = 0;
1104    /* Work with Second order complex packed data. */
1105    if (f_sndOrder) {
1106       /* *INDENT-OFF* */
1107       /* The algorithm appears to be:
1108        * Data:      a1  a2 a3 a4 a5 ...
1109        * 1st diff:   0  b2 b3 b4 b5 ...
1110        * 2nd diff: UK1 UK2 c3 c4 c5 ...
1111        * We already know a1 and b2, and unpack a stream of UK1 UK2 c3 c4
1112        * The problem is that UK1, UK2 is undefined.  Originally I thought
1113        * this was 0, or c3, but it appears that if b2 != 0, then
1114        * UK2 = c3 + 2 b2, and UK1 = c3 + 1 * b2, otherwise it appears that
1115        * UK1 == UK2, and typically UK1 == c3 (but not always). */
1116       /* *INDENT-ON* */
1117       myAssert (numPack >= 2);
1118       if (f_secMiss) {
1119          numVal = 0;
1120          lastData = 0;
1121          for (i = 0; i < LX; i++) {
1122             maxVal = (1 << grp[i].bit) - 1;
1123             for (j = 0; j < grp[i].num; j++) {
1124                /* signed int. */
1125                memBitRead (&(li_temp), sizeof (sInt4), bds, grp[i].bit,
1126                            &bufLoc, &numUsed);
1127                bds += numUsed;
1128                if (li_temp == maxVal) {
1129                   data[dataInd] = meta->gridAttrib.missPri;
1130                } else if (li_temp == (maxVal - 1)) {
1131                   data[dataInd] = meta->gridAttrib.missSec;
1132                } else {
1133                   if (numVal > 1) {
1134 #ifdef DEBUG
1135                      if (numVal == 2) {
1136                         if (fstDiff != 0) {
1137 /*
1138                            myAssert (t_UK1 == li_temp + fstDiff);
1139                            myAssert (t_UK2 == li_temp + 2 * fstDiff);
1140 */
1141                         } else {
1142                            myAssert (t_UK1 == t_UK2);
1143                         }
1144                      }
1145 #endif
1146                      diff += (li_temp + grp[i].min + minVal);
1147                      data[dataInd] = data[lastData] + diff * scale;
1148                      lastData = dataInd;
1149                   } else if (numVal == 1) {
1150                      data[dataInd] = (origVal + fstDiff) * scale;
1151                      lastData = dataInd;
1152                      diff = fstDiff;
1153 #ifdef DEBUG
1154                      t_UK2 = li_temp;
1155 #endif
1156                   } else {
1157                      data[dataInd] = origVal * scale;
1158 #ifdef DEBUG
1159                      t_UK1 = li_temp;
1160 #endif
1161                   }
1162                   numVal++;
1163                   if (!meta->gridAttrib.f_maxmin) {
1164                      meta->gridAttrib.min = data[dataInd];
1165                      meta->gridAttrib.max = data[dataInd];
1166                      meta->gridAttrib.f_maxmin = 1;
1167                   } else {
1168                      if (data[dataInd] < meta->gridAttrib.min) {
1169                         meta->gridAttrib.min = data[dataInd];
1170                      }
1171                      if (data[dataInd] > meta->gridAttrib.max) {
1172                         meta->gridAttrib.max = data[dataInd];
1173                      }
1174                   }
1175                }
1176                dataCnt++;
1177                dataInd = ((dataCnt / meta->gds.Nx) % 2) ?
1178                      (2 * (dataCnt / meta->gds.Nx) + 1) *
1179                      meta->gds.Nx - dataCnt - 1 : dataCnt;
1180                myAssert ((dataInd < numPack) || (dataCnt == numPack));
1181             }
1182          }
1183       } else if (f_primMiss) {
1184          numVal = 0;
1185          lastData = 0;
1186          for (i = 0; i < LX; i++) {
1187             maxVal = (1 << grp[i].bit) - 1;
1188             for (j = 0; j < grp[i].num; j++) {
1189                /* signed int. */
1190                memBitRead (&(li_temp), sizeof (sInt4), bds, grp[i].bit,
1191                            &bufLoc, &numUsed);
1192                bds += numUsed;
1193                f_missing = 0;
1194                if (li_temp == maxVal) {
1195                   data[dataInd] = meta->gridAttrib.missPri;
1196                   /* In the case of grp[i].bit == 0, if grp[i].min == 0, then
1197                    * it is the missing value, otherwise regular value. Only
1198                    * need to be concerned for primary missing values. */
1199                   f_missing = 1;
1200                   if ((grp[i].bit == 0) && (grp[i].min != 0)) {
1201 #ifdef DEBUG
1202                      printf ("This doesn't happen often.\n");
1203                      printf ("%d %u %d\n", (int) i, grp[i].bit, grp[i].min);
1204 #endif
1205                      myAssert (0);
1206                      f_missing = 0;
1207                   }
1208                }
1209                if (!f_missing) {
1210                   if (numVal > 1) {
1211 #ifdef DEBUG
1212                      if (numVal == 2) {
1213                         if (fstDiff != 0) {
1214 /*
1215                            myAssert (t_UK1 == li_temp + fstDiff);
1216                            myAssert (t_UK2 == li_temp + 2 * fstDiff);
1217 */
1218                         } else {
1219                            myAssert (t_UK1 == t_UK2);
1220                         }
1221                      }
1222 #endif
1223                      diff += (li_temp + grp[i].min + minVal);
1224                      data[dataInd] = data[lastData] + diff * scale;
1225                      lastData = dataInd;
1226                   } else if (numVal == 1) {
1227                      data[dataInd] = (origVal + fstDiff) * scale;
1228                      lastData = dataInd;
1229                      diff = fstDiff;
1230 #ifdef DEBUG
1231                      t_UK2 = li_temp;
1232 #endif
1233                   } else {
1234                      data[dataInd] = origVal * scale;
1235 #ifdef DEBUG
1236                      t_UK1 = li_temp;
1237 #endif
1238                   }
1239                   numVal++;
1240                   if (!meta->gridAttrib.f_maxmin) {
1241                      meta->gridAttrib.min = data[dataInd];
1242                      meta->gridAttrib.max = data[dataInd];
1243                      meta->gridAttrib.f_maxmin = 1;
1244                   } else {
1245                      if (data[dataInd] < meta->gridAttrib.min) {
1246                         meta->gridAttrib.min = data[dataInd];
1247                      }
1248                      if (data[dataInd] > meta->gridAttrib.max) {
1249                         meta->gridAttrib.max = data[dataInd];
1250                      }
1251                   }
1252                }
1253                dataCnt++;
1254                dataInd = ((dataCnt / meta->gds.Nx) % 2) ?
1255                      (2 * (dataCnt / meta->gds.Nx) + 1) *
1256                      meta->gds.Nx - dataCnt - 1 : dataCnt;
1257                myAssert ((dataInd < numPack) || (dataCnt == numPack));
1258             }
1259          }
1260       } else {
1261          lastData = 0;
1262          for (i = 0; i < LX; i++) {
1263             for (j = 0; j < grp[i].num; j++) {
1264                /* signed int. */
1265                memBitRead (&(li_temp), sizeof (sInt4), bds, grp[i].bit,
1266                            &bufLoc, &numUsed);
1267                bds += numUsed;
1268                if (dataCnt > 1) {
1269 #ifdef DEBUG
1270                   if (dataCnt == 2) {
1271                      if (fstDiff != 0) {
1272 /*
1273                         myAssert (t_UK1 == li_temp + fstDiff);
1274                         myAssert (t_UK2 == li_temp + 2 * fstDiff);
1275 */
1276                      } else {
1277                         myAssert (t_UK1 == t_UK2);
1278                      }
1279                   }
1280 #endif
1281                   diff += (li_temp + grp[i].min + minVal);
1282                   data[dataInd] = data[lastData] + diff * scale;
1283                   lastData = dataInd;
1284                } else if (dataCnt == 1) {
1285                   data[dataInd] = (origVal + fstDiff) * scale;
1286                   lastData = dataInd;
1287                   diff = fstDiff;
1288 #ifdef DEBUG
1289                   t_UK2 = li_temp;
1290 #endif
1291                } else {
1292                   data[dataInd] = origVal * scale;
1293 #ifdef DEBUG
1294                   t_UK1 = li_temp;
1295 #endif
1296                }
1297 #ifdef DEBUG
1298 /*
1299                if (i >= 4153) {
1300 */
1301 /*
1302                if ((data[dataInd] > 100) || (data[dataInd] < -100)) {
1303 */
1304 /*
1305                if ((diff > 50) || (diff < -50)) {
1306                   printf ("li_temp :: %ld, diff = %ld\n", li_temp, diff);
1307                   printf ("data[dataInd] :: %f\n", data[dataInd]);
1308                   printf ("Group # %d element %d, grp[i].min %ld, "
1309                           "grp[i].bit %d, minVal %ld\n", i, j, grp[i].min,
1310                           grp[i].bit, minVal);
1311                }
1312 */
1313 #endif
1314                if (!meta->gridAttrib.f_maxmin) {
1315                   meta->gridAttrib.min = data[dataInd];
1316                   meta->gridAttrib.max = data[dataInd];
1317                   meta->gridAttrib.f_maxmin = 1;
1318                } else {
1319                   if (data[dataInd] < meta->gridAttrib.min) {
1320                      meta->gridAttrib.min = data[dataInd];
1321                   }
1322                   if (data[dataInd] > meta->gridAttrib.max) {
1323                      meta->gridAttrib.max = data[dataInd];
1324                   }
1325                }
1326                dataCnt++;
1327                dataInd = ((dataCnt / meta->gds.Nx) % 2) ?
1328                      (2 * (dataCnt / meta->gds.Nx) + 1) *
1329                      meta->gds.Nx - dataCnt - 1 : dataCnt;
1330                myAssert ((dataInd < numPack) || (dataCnt == numPack));
1331             }
1332          }
1333          numVal = dataCnt;
1334       }
1335 
1336       /* Work with regular complex packed data. */
1337    } else {
1338 #ifdef DEBUG
1339 /*
1340    printf ("Work with regular complex packed data\n");
1341 */
1342 #endif
1343       if (f_secMiss) {
1344          numVal = 0;
1345          for (i = 0; i < LX; i++) {
1346             maxVal = (1 << grp[i].bit) - 1;
1347             for (j = 0; j < grp[i].num; j++) {
1348                /* signed int. */
1349                memBitRead (&(li_temp), sizeof (sInt4), bds, grp[i].bit,
1350                            &bufLoc, &numUsed);
1351                bds += numUsed;
1352                if (li_temp == maxVal) {
1353                   data[dataInd] = meta->gridAttrib.missPri;
1354                } else if (li_temp == (maxVal - 1)) {
1355                   data[dataInd] = meta->gridAttrib.missSec;
1356                } else {
1357                   data[dataInd] = (li_temp + grp[i].min + minVal) * scale;
1358                   numVal++;
1359                   if (!meta->gridAttrib.f_maxmin) {
1360                      meta->gridAttrib.min = data[dataInd];
1361                      meta->gridAttrib.max = data[dataInd];
1362                      meta->gridAttrib.f_maxmin = 1;
1363                   } else {
1364                      if (data[dataInd] < meta->gridAttrib.min) {
1365                         meta->gridAttrib.min = data[dataInd];
1366                      }
1367                      if (data[dataInd] > meta->gridAttrib.max) {
1368                         meta->gridAttrib.max = data[dataInd];
1369                      }
1370                   }
1371                }
1372                dataCnt++;
1373                dataInd = ((dataCnt / meta->gds.Nx) % 2) ?
1374                      (2 * (dataCnt / meta->gds.Nx) + 1) *
1375                      meta->gds.Nx - dataCnt - 1 : dataCnt;
1376                myAssert ((dataInd < numPack) || (dataCnt == numPack));
1377             }
1378          }
1379       } else if (f_primMiss) {
1380 #ifdef DEBUG
1381 /*
1382    printf ("Work with primary missing data\n");
1383 */
1384 #endif
1385          numVal = 0;
1386          for (i = 0; i < LX; i++) {
1387             maxVal = (1 << grp[i].bit) - 1;
1388             for (j = 0; j < grp[i].num; j++) {
1389                memBitRead (&(li_temp), sizeof (sInt4), bds, grp[i].bit,
1390                            &bufLoc, &numUsed);
1391                bds += numUsed;
1392                f_missing = 0;
1393                if (li_temp == maxVal) {
1394                   data[dataInd] = meta->gridAttrib.missPri;
1395                   /* In the case of grp[i].bit == 0, if grp[i].min == 0, then
1396                    * it is the missing value, otherwise regular value. Only
1397                    * need to be concerned for primary missing values. */
1398                   f_missing = 1;
1399                   if ((grp[i].bit == 0) && (grp[i].min != 0)) {
1400 #ifdef DEBUG
1401                      printf ("This doesn't happen often.\n");
1402                      printf ("%d %u %d\n", (int) i, grp[i].bit, grp[i].min);
1403                      myAssert (0);
1404 #endif
1405                      f_missing = 0;
1406                   }
1407                }
1408                if (!f_missing) {
1409                   data[dataInd] = (li_temp + grp[i].min + minVal) * scale;
1410                   numVal++;
1411                   if (!meta->gridAttrib.f_maxmin) {
1412                      meta->gridAttrib.min = data[dataInd];
1413                      meta->gridAttrib.max = data[dataInd];
1414                      meta->gridAttrib.f_maxmin = 1;
1415                   } else {
1416                      if (data[dataInd] < meta->gridAttrib.min) {
1417                         meta->gridAttrib.min = data[dataInd];
1418                      }
1419                      if (data[dataInd] > meta->gridAttrib.max) {
1420                         meta->gridAttrib.max = data[dataInd];
1421                      }
1422                   }
1423                }
1424                dataCnt++;
1425                dataInd = ((dataCnt / meta->gds.Nx) % 2) ?
1426                      (2 * (dataCnt / meta->gds.Nx) + 1) *
1427                      meta->gds.Nx - dataCnt - 1 : dataCnt;
1428                myAssert ((dataInd < numPack) || (dataCnt == numPack));
1429             }
1430          }
1431       } else {
1432          for (i = 0; i < LX; i++) {
1433             for (j = 0; j < grp[i].num; j++) {
1434                memBitRead (&(li_temp), sizeof (sInt4), bds, grp[i].bit,
1435                            &bufLoc, &numUsed);
1436                bds += numUsed;
1437                data[dataInd] = (li_temp + grp[i].min + minVal) * scale;
1438                if (!meta->gridAttrib.f_maxmin) {
1439                   meta->gridAttrib.min = data[dataInd];
1440                   meta->gridAttrib.max = data[dataInd];
1441                   meta->gridAttrib.f_maxmin = 1;
1442                } else {
1443                   if (data[dataInd] < meta->gridAttrib.min) {
1444                      meta->gridAttrib.min = data[dataInd];
1445                   }
1446                   if (data[dataInd] > meta->gridAttrib.max) {
1447                      meta->gridAttrib.max = data[dataInd];
1448                   }
1449                }
1450                dataCnt++;
1451                dataInd = ((dataCnt / meta->gds.Nx) % 2) ?
1452                      (2 * (dataCnt / meta->gds.Nx) + 1) *
1453                      meta->gds.Nx - dataCnt - 1 : dataCnt;
1454                myAssert ((dataInd < numPack) || (dataCnt == numPack));
1455             }
1456          }
1457          numVal = dataCnt;
1458       }
1459    }
1460    meta->gridAttrib.numMiss = dataCnt - numVal;
1461    meta->gridAttrib.refVal = (float)(minVal * scale);
1462 
1463    free (grp);
1464    return 0;
1465 }
1466 
1467 /*****************************************************************************
1468  * ReadTDLPRecord() --
1469  *
1470  * Arthur Taylor / MDL
1471  *
1472  * PURPOSE
1473  *   Reads in a TDLP message, and parses the data into various data
1474  * structures, for use with other code.
1475  *
1476  * ARGUMENTS
1477  *           fp = An opened TDLP file already at the correct message. (Input)
1478  *    TDLP_Data = The read in TDLP data. (Output)
1479  * tdlp_DataLen = Size of TDLP_Data. (Output)
1480  *         meta = A filled in meta structure (Output)
1481  *           IS = The structure containing all the arrays that the
1482  *                unpacker uses (Output)
1483  *        sect0 = Already read in section 0 data. (Input)
1484  *      tdlpLen = Length of the TDLP message. (Input)
1485  *     majEarth = Used to override the TDLP major axis of earth. (Input)
1486  *     minEarth = Used to override the TDLP minor axis of earth. (Input)
1487  *
1488  * FILES/DATABASES:
1489  *   An already opened file pointing to the desired TDLP message.
1490  *
1491  * RETURNS: int (could use errSprintf())
1492  *  0 = OK
1493  * -1 = Problems reading in the PDS.
1494  * -2 = Problems reading in the GDS.
1495  * -3 = Problems reading in the BMS.
1496  * -4 = Problems reading in the BDS.
1497  * -5 = Problems reading the closing section.
1498  *
1499  * HISTORY
1500  *  10/2004 Arthur Taylor (MDL): Created
1501  *
1502  * NOTES
1503  *****************************************************************************
1504  */
1505 int ReadTDLPRecord (DataSource &fp, double **TDLP_Data, uInt4 *tdlp_DataLen,
1506                     grib_MetaData *meta, IS_dataType *IS,
1507                     sInt4 sect0[SECT0LEN_WORD], uInt4 tdlpLen,
1508                     double majEarth, double minEarth)
1509 {
1510    sInt4 nd5;           /* Size of TDLP message rounded up to the nearest *
1511                          * sInt4. */
1512    uChar *c_ipack;      /* A char ptr to the message stored in IS->ipack */
1513    sInt4 curLoc;        /* Current location in the GRIB message. */
1514    char f_gds;          /* flag if there is a GDS section. */
1515    char f_bms;          /* flag if there is a BMS section. */
1516    short int DSF;       /* Decimal Scale Factor for unpacking the data. */
1517    short int BSF;       /* Binary Scale Factor for unpacking the data. */
1518    double *tdlp_Data;   /* A pointer to TDLP_Data for ease of manipulation. */
1519    double unitM = 1;    /* M in y = Mx + B, for unit conversion. */
1520    double unitB = 0;    /* B in y = Mx + B, for unit conversion. */
1521    sInt4 li_temp;       /* Used to make sure section 5 is 7777. */
1522    size_t pad;          /* Number of bytes to pad the message to get to the
1523                          * correct byte boundary. */
1524    char buffer[24];     /* Read the trailing bytes in the TDLPack record. */
1525    uChar *bitmap;       /* Would contain bitmap data if it was supported. */
1526 
1527    /* Make room for entire message, and read it in. */
1528    /* nd5 needs to be tdlpLen in (sInt4) units rounded up. */
1529    nd5 = (tdlpLen + 3) / 4;
1530    if (nd5 > IS->ipackLen) {
1531       IS->ipackLen = nd5;
1532       IS->ipack = (sInt4 *) realloc ((void *) (IS->ipack),
1533                                      (IS->ipackLen) * sizeof (sInt4));
1534    }
1535    c_ipack = (uChar *) IS->ipack;
1536    /* Init last sInt4 to 0, to make sure that the padded bytes are 0. */
1537    IS->ipack[nd5 - 1] = 0;
1538    /* Init first 2 sInt4 to sect0. */
1539    memcpy (c_ipack, sect0, SECT0LEN_WORD * 2);
1540    /* Read in the rest of the message. */
1541    if (fp.DataSourceFread(c_ipack + SECT0LEN_WORD * 2, sizeof (char),
1542               (tdlpLen - SECT0LEN_WORD * 2)) + SECT0LEN_WORD * 2 != tdlpLen) {
1543       errSprintf ("Ran out of file\n");
1544       return -1;
1545    }
1546 
1547    /* Preceding was in degrib2, next part is specific to TDLP. */
1548    curLoc = 8;
1549    if (ReadTDLPSect1 (c_ipack + curLoc, tdlpLen, &curLoc, &(meta->pdsTdlp),
1550                       &f_gds, &f_bms, &DSF, &BSF) != 0) {
1551       preErrSprintf ("Inside ReadGrib1Record\n");
1552       return -1;
1553    }
1554 
1555    /* Figure out some basic stuff about the grid. */
1556    free (meta->element);
1557    meta->element = nullptr;
1558    free (meta->unitName);
1559    meta->unitName = nullptr;
1560    free (meta->comment);
1561    meta->comment = nullptr;
1562    free (meta->shortFstLevel);
1563    meta->shortFstLevel = nullptr;
1564    free (meta->longFstLevel);
1565    meta->longFstLevel = nullptr;
1566    TDLP_ElemSurfUnit (&(meta->pdsTdlp), &(meta->element), &(meta->unitName),
1567                       &(meta->comment), &(meta->shortFstLevel),
1568                       &(meta->longFstLevel));
1569    meta->center = 7;    /* US NWS, NCEP */
1570    meta->subcenter = 14; /* NWS Meteorological Development Laboratory */
1571 
1572 /*   strftime (meta->refTime, 20, "%Y%m%d%H%M",
1573              gmtime (&(meta->pdsTdlp.refTime)));
1574 */
1575    Clock_Print (meta->refTime, 20, meta->pdsTdlp.refTime, "%Y%m%d%H%M", 0);
1576 
1577 /*
1578    validTime = meta->pdsTdlp.refTime + meta->pdsTdlp.project;
1579    strftime (meta->validTime, 20, "%Y%m%d%H%M", gmtime (&(validTime)));
1580 */
1581    Clock_Print (meta->validTime, 20, meta->pdsTdlp.refTime +
1582                 meta->pdsTdlp.project, "%Y%m%d%H%M", 0);
1583 
1584    meta->deltTime = meta->pdsTdlp.project;
1585 
1586    /* Get the Grid Definition Section. */
1587    if (f_gds) {
1588       if (ReadTDLPSect2 (c_ipack + curLoc, tdlpLen, &curLoc,
1589                          &(meta->gds)) != 0) {
1590          preErrSprintf ("Inside ReadGrib1Record\n");
1591          return -2;
1592       }
1593    } else {
1594       errSprintf ("Don't know how to handle vector data yet.\n");
1595       return -2;
1596    }
1597 
1598    /* Allow over ride of the earth radii. */
1599    if ((majEarth > 6300) && (majEarth < 6400)) {
1600       if ((minEarth > 6300) && (minEarth < 6400)) {
1601          meta->gds.f_sphere = 0;
1602          meta->gds.majEarth = majEarth;
1603          meta->gds.minEarth = minEarth;
1604          if (majEarth == minEarth) {
1605             meta->gds.f_sphere = 1;
1606          }
1607       } else {
1608          meta->gds.f_sphere = 1;
1609          meta->gds.majEarth = majEarth;
1610          meta->gds.minEarth = majEarth;
1611       }
1612    }
1613 
1614    /* Allocate memory for the grid. */
1615    if (meta->gds.numPts > *tdlp_DataLen) {
1616       *tdlp_DataLen = meta->gds.numPts;
1617       *TDLP_Data = (double *) realloc ((void *) (*TDLP_Data),
1618                                        (*tdlp_DataLen) * sizeof (double));
1619    }
1620    tdlp_Data = *TDLP_Data;
1621 
1622    /* Get the Bit Map Section. */
1623    if (f_bms) {
1624 /*      errSprintf ("Bitmap data is Not Supported\n");*/
1625       /* Need to allocate bitmap when this is implemented. */
1626       bitmap = nullptr;
1627       ReadTDLPSect3 (c_ipack + curLoc, tdlpLen, &curLoc, bitmap,
1628                      meta->gds.numPts);
1629       return -1;
1630    }
1631 
1632    /* Read the GRID. */
1633    if (ReadTDLPSect4 (c_ipack + curLoc, tdlpLen, &curLoc, DSF, BSF,
1634                       tdlp_Data, meta, unitM, unitB) != 0) {
1635       preErrSprintf ("Inside ReadTDLPRecord\n");
1636       return -4;
1637    }
1638 
1639    /* Read section 5.  If it is "7777" == 926365495 we are done. */
1640    memcpy (&li_temp, c_ipack + curLoc, 4);
1641    if (li_temp != 926365495L) {
1642       errSprintf ("Did not find the end of the message.\n");
1643       return -5;
1644    }
1645    curLoc += 4;
1646    /* Read the trailing part of the message. */
1647    /* TDLPack uses 4 bytes for FORTRAN record size, then another 8 bytes for
1648     * the size of the record (so FORTRAN can see it), then the data rounded
1649     * up to an 8 byte boundary, then a trailing 4 bytes for a final FORTRAN
1650     * record size.  However it only stores in the gribLen the non-rounded
1651     * amount, so we need to take care of the rounding, and the trailing 4
1652     * bytes here. */
1653    pad = ((sInt4) (ceil (tdlpLen / 8.0))) * 8 - tdlpLen + 4;
1654    if (fp.DataSourceFread(buffer, sizeof (char), pad) != pad) {
1655       errSprintf ("Ran out of file\n");
1656       return -1;
1657    }
1658    return 0;
1659 }
1660 
1661 #ifdef unused_by_GDAL
1662 
1663 /*****************************************************************************
1664  * TDL_ScaleData() --
1665  *
1666  * Arthur Taylor / MDL
1667  *
1668  * PURPOSE
1669  *   Deal with scaling while excluding the primary and secondary missing
1670  * values.  After this, dst should contain scaled data + primary or secondary
1671  * missing values
1672  *   "tdlpack library"::pack2d.f line 257 or search for:
1673  "the above statement"
1674  *
1675  * ARGUMENTS
1676  *        Src = The original data. (Input)
1677  *        Dst = The scaled data. (Output)
1678  *    numData = The number of elements in data. (Input)
1679  *        DSF = Decimal Scale Factor for scaling the data. (Input)
1680  *        BSF = Binary Scale Factor for scaling the data. (Input)
1681  * f_primMiss = Flag saying if we have a primary missing value (In/Out)
1682  *   primMiss = primary missing value. (In/Out)
1683  *  f_secMiss = Flag saying if we have a secondary missing value (In/Out)
1684  *    secMiss = secondary missing value. (In/Out)
1685  *      f_min = Flag saying if we have the minimum value. (Output)
1686  *        min = minimum scaled value in the grid. (Output)
1687  *
1688  * FILES/DATABASES: None
1689  *
1690  * RETURNS: void
1691  *
1692  * HISTORY
1693  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
1694  *
1695  * NOTES
1696  *****************************************************************************
1697  */
1698 #define SCALE_MISSING 10000
1699 static void TDL_ScaleData (double *Src, sInt4 *Dst, sInt4 numData,
1700                            int DSF, int BSF, char *f_primMiss,
1701                            double *primMiss, char *f_secMiss,
1702                            double *secMiss, char *f_min, sInt4 *min)
1703 {
1704    sInt4 cnt;
1705    double *src = Src;
1706    sInt4 *dst = Dst;
1707    double scale = pow (10.0, -1 * DSF) * pow (2.0, -1 * BSF);
1708    char f_actualPrim = 0;
1709    char f_actualSec = 0;
1710    sInt4 li_primMiss = (sInt4) (*primMiss * SCALE_MISSING + .5);
1711    sInt4 li_secMiss = (sInt4) (*secMiss * SCALE_MISSING + .5);
1712 
1713    *f_min = 0;
1714    for (cnt = 0; cnt < numData; cnt++) {
1715       if (((*f_primMiss) || (*f_secMiss)) && (*src == *primMiss)) {
1716          *(dst++) = li_primMiss;
1717          src++;
1718          f_actualPrim = 1;
1719       } else if ((*f_secMiss) && (*src == *secMiss)) {
1720          *(dst++) = li_secMiss;
1721          src++;
1722          f_actualSec = 1;
1723       } else {
1724          *(dst) = (sInt4) (floor ((*(src++) / scale) + .5));
1725          /* Check if scaled value == primary missing value. */
1726          if (((*f_primMiss) || (*f_secMiss)) && (*dst == li_primMiss)) {
1727             *dst = *dst - 1;
1728          }
1729          /* Check if scaled value == secondary missing value. */
1730          if ((*f_secMiss) && (*dst == li_secMiss)) {
1731             *dst = *dst - 1;
1732             /* Check if adjustment caused scaled value == primary missing. */
1733             if (*dst == li_primMiss) {
1734                *dst = *dst - 1;
1735             }
1736          }
1737          if (!(*f_min)) {
1738             *min = *dst;
1739             *f_min = 1;
1740          } else if (*min > *dst) {
1741             *min = *dst;
1742          }
1743          dst++;
1744       }
1745    }
1746    if ((*f_secMiss) && (!f_actualSec)) {
1747       *f_secMiss = 0;
1748    }
1749    if (((*f_secMiss) || (*f_primMiss)) && (!f_actualPrim)) {
1750       *f_primMiss = 0;
1751       /* Check consistency. */
1752       if (*f_secMiss) {
1753          *f_secMiss = 0;
1754          *f_primMiss = 1;
1755          *primMiss = *secMiss;
1756       }
1757    }
1758 }
1759 
1760 /*****************************************************************************
1761  * TDL_ReorderGrid() --
1762  *
1763  * Arthur Taylor / MDL
1764  *
1765  * PURPOSE
1766  *   Loop through the data, so that
1767  * data is:    "a1,1 ... a1,n  a2,n ... a2,1 ..."
1768  * instead of: "a1,1 ... a1,n  a2,1 ... a2,n ..."
1769  *
1770  * ARGUMENTS
1771  * Src = The data. (Input/Output)
1772  *  NX = The number of X values. (Input)
1773  *  NY = The number of Y values. (Input)
1774  *
1775  * FILES/DATABASES: None
1776  *
1777  * RETURNS: void
1778  *
1779  * HISTORY
1780  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
1781  *
1782  * NOTES
1783  *****************************************************************************
1784  */
1785 static void TDL_ReorderGrid (sInt4 *Src, short int NX, short int NY)
1786 {
1787    int i, j;
1788    sInt4 *src1, *src2;
1789    sInt4 li_temp;
1790 
1791    for (j = 1; j < NY; j += 2) {
1792       src1 = Src + j * NX;
1793       src2 = Src + (j + 1) * NX - 1;
1794       for (i = 0; i < (NX / 2); i++) {
1795          li_temp = *src1;
1796          *(src1++) = *src2;
1797          *(src2--) = li_temp;
1798       }
1799    }
1800 }
1801 
1802 /*****************************************************************************
1803  * TDL_GetSecDiff() --
1804  *
1805  * Arthur Taylor / MDL
1806  *
1807  * PURPOSE
1808  *   Get the second order difference where we have special values for missing,
1809  * and for actual data we have the following scheme.
1810  *       Data:      a1  a2 a3 a4 a5 ...
1811  *       1st diff:   0  b2 b3 b4 b5 ...
1812  *       2nd diff: UK1 UK2 c3 c4 c5 ...
1813  * where UK1 = c3 + b2, and UK2 = c3 + 2 * b2.  Note: The choice of UK1, and
1814  * UK2 doesn't matter because of the following FORTRAN unpacking code:
1815  *       IWORK(1)=IFIRST
1816  *       IWORK(2)=IWORK(1)+IFOD
1817  *       ISUM=IFOD
1818  *       DO 385 K=3,IS4(3)
1819  *         ISUM=IWORK(K)+ISUM
1820  *         IWORK(K)=IWORK(K-1)+ISUM
1821  * 385   CONTINUE
1822  * So ISUM is a function of IWORK(3), not IWORK(1).
1823  *
1824  * ARGUMENTS
1825  *        Data = The data. (Input)
1826  *     numData = The number of elements in data. (Input)
1827  *     SecDiff = The secondary differences of the data. (Output)
1828  *  f_primMiss = Flag saying if we have a primary missing value (Input)
1829  * li_primMiss = Scaled primary missing value. (Input)
1830  *          a1 = First non-missing value in the field. (Output)
1831  *          b2 = First non-missing value in the 1st order delta field (Out)
1832  *         min = The minimum value (Input).
1833  *
1834  * FILES/DATABASES: None
1835  *
1836  * RETURNS: int
1837  *  0 = Success
1838  *  1 = Couldn't find second differences (don't use).
1839  *
1840  * HISTORY
1841  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
1842  *
1843  * NOTES
1844  *****************************************************************************
1845  */
1846 static int TDL_GetSecDiff (sInt4 *Data, int numData, sInt4 *SecDiff,
1847                            char f_primMiss, sInt4 li_primMiss,
1848                            sInt4 *a1, sInt4 *b2, sInt4 *min)
1849 {
1850    int i;
1851    char f_min = 0;
1852    sInt4 last = 0, before_last = 0;
1853    int a1Index = -1;
1854    int a2Index = -1;
1855 
1856    if (numData < 3) {
1857       return 1;
1858    }
1859    if (f_primMiss) {
1860       for (i = 0; i < numData; i++) {
1861          if (Data[i] == li_primMiss) {
1862             SecDiff[i] = li_primMiss;
1863          } else if (a1Index == -1) {
1864             a1Index = i;
1865             *a1 = Data[a1Index];
1866          } else if (a2Index == -1) {
1867             a2Index = i;
1868             *b2 = Data[a2Index] - Data[a1Index];
1869             before_last = Data[a1Index];
1870             last = Data[a2Index];
1871          } else {
1872             SecDiff[i] = Data[i] - 2 * last + before_last;
1873             before_last = last;
1874             last = Data[i];
1875             if (!f_min) {
1876                /* Set the UK1, UK2 values. */
1877                *min = SecDiff[i];
1878                f_min = 1;
1879                SecDiff[a1Index] = SecDiff[i] + *b2;
1880                SecDiff[a2Index] = SecDiff[i] + 2 * (*b2);
1881             } else if (*min > SecDiff[i]) {
1882                *min = SecDiff[i];
1883             }
1884          }
1885       }
1886       if (!f_min) {
1887          return 1;
1888       }
1889    } else {
1890       *a1 = Data[0];
1891       *b2 = Data[1] - Data[0];
1892       for (i = 3; i < numData; i++) {
1893          SecDiff[i] = Data[i] - 2 * Data[i - 1] - Data[i - 2];
1894          if (i == 3) {
1895             *min = SecDiff[i];
1896             /* Set the UK1, UK2 values. */
1897             SecDiff[0] = SecDiff[i] + *b2;
1898             SecDiff[1] = SecDiff[i] + 2 * (*b2);
1899          } else if (*min > SecDiff[i]) {
1900             *min = SecDiff[i];
1901          }
1902       }
1903    }
1904    return 0;
1905 }
1906 
1907 /*****************************************************************************
1908  * TDL_UseSecDiff_Prim() --
1909  *
1910  * Arthur Taylor / MDL
1911  *
1912  * PURPOSE
1913  *   Checks if the average range of 2nd order differences < average range of
1914  *   0 order differences, to determine if we should use second order
1915  *   differences. This deals with the case when we have primary missing values.
1916  *
1917  * ARGUMENTS
1918  *        Data = The data. (Input)
1919  *     numData = The number of elements in data. (Input)
1920  *     SecDiff = The secondary differences of the data. (Input)
1921  * li_primMiss = Scaled primary missing value. (Input)
1922  *    minGroup = The minimum group size. (Input)
1923  *
1924  * FILES/DATABASES: None
1925  *
1926  * RETURNS: int
1927  *  0 = Don't use 2nd order differences.
1928  *  1 = Use 2nd order differences.
1929  *
1930  * HISTORY
1931  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
1932  *
1933  * NOTES
1934  *****************************************************************************
1935  */
1936 static int TDL_UseSecDiff_Prim (sInt4 *Data, sInt4 numData,
1937                                 sInt4 *SecDiff, sInt4 li_primMiss,
1938                                 int minGroup)
1939 {
1940    int i, locCnt;
1941    int range0, range2;
1942    int tot0, tot2;
1943    char f_min;
1944    sInt4 min = 0, max = 0;
1945 
1946    locCnt = 0;
1947    range0 = 0;
1948    tot0 = 0;
1949    f_min = 0;
1950    /* Compute scores for no differences */
1951    for (i = 0; i < numData; i++) {
1952       if (Data[i] != li_primMiss) {
1953          if (!f_min) {
1954             min = Data[i];
1955             max = Data[i];
1956             f_min = 1;
1957          } else {
1958             if (min > Data[i])
1959                min = Data[i];
1960             if (max < Data[i])
1961                max = Data[i];
1962          }
1963       }
1964       locCnt++;
1965       /* Fake a "group" by using the minimum group size. */
1966       if (locCnt == minGroup) {
1967          if (f_min) {
1968             range0 += (max - min);
1969             tot0++;
1970             f_min = 0;
1971          }
1972          locCnt = 0;
1973       }
1974    }
1975    if (locCnt != 0) {
1976       range0 += (max - min);
1977       tot0++;
1978    }
1979 
1980    locCnt = 0;
1981    range2 = 0;
1982    tot2 = 0;
1983    f_min = 0;
1984    /* Compute scores for second order differences */
1985    for (i = 0; i < numData; i++) {
1986       if (SecDiff[i] != li_primMiss) {
1987          if (!f_min) {
1988             min = SecDiff[i];
1989             max = SecDiff[i];
1990             f_min = 1;
1991          } else {
1992             if (min > SecDiff[i])
1993                min = SecDiff[i];
1994             if (max < SecDiff[i])
1995                max = SecDiff[i];
1996          }
1997       }
1998       locCnt++;
1999       /* Fake a "group" by using the minimum group size. */
2000       if (locCnt == minGroup) {
2001          if (f_min) {
2002             range2 += (max - min);
2003             tot2++;
2004             f_min = 0;
2005          }
2006          locCnt = 0;
2007       }
2008    }
2009    if (locCnt != 0) {
2010       range2 += (max - min);
2011       tot2++;
2012    }
2013 
2014    /* Compare average group size of no differencing to second order. */
2015    if ((range0 / (tot0 + 0.0)) <= (range2 / (tot2 + 0.0))) {
2016       return 0;
2017    } else {
2018       return 1;
2019    }
2020 }
2021 
2022 /*****************************************************************************
2023  * TDL_UseSecDiff() --
2024  *
2025  * Arthur Taylor / MDL
2026  *
2027  * PURPOSE
2028  *   Checks if the average range of 2nd order differences < average range of
2029  *   0 order differences, to determine if we should use second order
2030  *   differences.
2031  *
2032  * ARGUMENTS
2033  *        Data = The data. (Input)
2034  *     numData = The number of elements in data. (Input)
2035  *     SecDiff = The secondary differences of the data. (Input)
2036  *    minGroup = The minimum group size. (Input)
2037  *
2038  * FILES/DATABASES: None
2039  *
2040  * RETURNS: int
2041  *  0 = Don't use 2nd order differences.
2042  *  1 = Use 2nd order differences.
2043  *
2044  * HISTORY
2045  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
2046  *
2047  * NOTES
2048  *****************************************************************************
2049  */
2050 static int TDL_UseSecDiff (sInt4 *Data, sInt4 numData,
2051                            sInt4 *SecDiff, int minGroup)
2052 {
2053    int i, locCnt;
2054    int range0, range2;
2055    int tot0, tot2;
2056    sInt4 min = 0, max = 0;
2057 
2058    locCnt = 0;
2059    range0 = 0;
2060    tot0 = 0;
2061    /* Compute scores for no differences */
2062    for (i = 0; i < numData; i++) {
2063       if (locCnt == 0) {
2064          min = Data[i];
2065          max = Data[i];
2066       } else {
2067          if (min > Data[i])
2068             min = Data[i];
2069          if (max < Data[i])
2070             max = Data[i];
2071       }
2072       locCnt++;
2073       /* Fake a "group" by using the minimum group size. */
2074       if (locCnt == minGroup) {
2075          range0 += (max - min);
2076          tot0++;
2077          locCnt = 0;
2078       }
2079    }
2080    if (locCnt != 0) {
2081       range0 += (max - min);
2082       tot0++;
2083    }
2084 
2085    locCnt = 0;
2086    range2 = 0;
2087    tot2 = 0;
2088    /* Compute scores for second order differences */
2089    for (i = 0; i < numData; i++) {
2090       if (locCnt == 0) {
2091          min = SecDiff[i];
2092          max = SecDiff[i];
2093       } else {
2094          if (min > SecDiff[i])
2095             min = SecDiff[i];
2096          if (max < SecDiff[i])
2097             max = SecDiff[i];
2098       }
2099       locCnt++;
2100       /* Fake a "group" by using the minimum group size. */
2101       if (locCnt == minGroup) {
2102          range2 += (max - min);
2103          tot2++;
2104          locCnt = 0;
2105       }
2106    }
2107    if (locCnt != 0) {
2108       range2 += (max - min);
2109       tot2++;
2110    }
2111 
2112    /* Compare average group size of no differencing to second order. */
2113    if ((range0 / (tot0 + 0.0)) <= (range2 / (tot2 + 0.0))) {
2114       return 0;
2115    } else {
2116       return 1;
2117    }
2118 }
2119 
2120 /*****************************************************************************
2121  * power() --
2122  *
2123  * Arthur Taylor / MDL
2124  *
2125  * PURPOSE
2126  *   Calculate the number of bits required to store a given positive number.
2127  *
2128  * ARGUMENTS
2129  *   val = The number to store (Input)
2130  * extra = number of slots to allocate for prim/sec missing values (Input)
2131  *
2132  * FILES/DATABASES: None
2133  *
2134  * RETURNS: int
2135  *   The number of bits needed to store this number.
2136  *
2137  * HISTORY
2138  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
2139  *
2140  * NOTES
2141  *****************************************************************************
2142  */
2143 static int power (uInt4 val, int extra)
2144 {
2145    int i;
2146 
2147    val += extra;
2148    if (val == 0) {
2149       return 1;
2150    }
2151    for (i = 0; val != 0; i++) {
2152       val = val >> 1;
2153    }
2154    return i;
2155 }
2156 
2157 /*****************************************************************************
2158  * findMaxMin2() --
2159  *
2160  * Arthur Taylor / MDL
2161  *
2162  * PURPOSE
2163  *   Find the min/max value between start/stop index values in the data
2164  * Assuming primary and secondary missing values.
2165  *
2166  * ARGUMENTS
2167  *        Data = The data. (Input)
2168  *       start = The starting index in data (Input)
2169  *        stop = The stopping index in data (Input)
2170  * li_primMiss = scaled primary missing value (Input)
2171  *  li_secMiss = scaled secondary missing value (Input)
2172  *         min = The min value found (Output)
2173  *         max = The max value found (Output)
2174  *
2175  * FILES/DATABASES: None
2176  *
2177  * RETURNS: char
2178  *   Flag if min/max are valid.
2179  *
2180  * HISTORY
2181  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
2182  *
2183  * NOTES
2184  *****************************************************************************
2185  */
2186 static char findMaxMin2 (sInt4 *Data, int start, int stop,
2187                          sInt4 li_primMiss, sInt4 li_secMiss,
2188                          sInt4 *min, sInt4 *max)
2189 {
2190    char f_min = 0;      /* Flag if we found the max/min values */
2191    int i;               /* Loop counter. */
2192 
2193    *max = *min = Data[start];
2194    for (i = start; i < stop; i++) {
2195       if ((Data[i] != li_secMiss) && (Data[i] != li_primMiss)) {
2196          if (!f_min) {
2197             *max = Data[i];
2198             *min = Data[i];
2199             f_min = 1;
2200          } else {
2201             if (*max < Data[i]) {
2202                *max = Data[i];
2203             } else if (*min > Data[i]) {
2204                *min = Data[i];
2205             }
2206          }
2207       }
2208    }
2209    return f_min;
2210 }
2211 
2212 /*****************************************************************************
2213  * findMaxMin1() --
2214  *
2215  * Arthur Taylor / MDL
2216  *
2217  * PURPOSE
2218  *   Find the min/max value between start/stop index values in the data
2219  * Assuming primary missing values.
2220  *
2221  * ARGUMENTS
2222  *        Data = The data. (Input)
2223  *       start = The starting index in data (Input)
2224  *        stop = The stopping index in data (Input)
2225  * li_primMiss = scaled primary missing value (Input)
2226  *         min = The min value found (Output)
2227  *         max = The max value found (Output)
2228  *
2229  * FILES/DATABASES: None
2230  *
2231  * RETURNS: char
2232  *   Flag if min/max are valid.
2233  *
2234  * HISTORY
2235  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
2236  *
2237  * NOTES
2238  *****************************************************************************
2239  */
2240 static char findMaxMin1 (sInt4 *Data, int start, int stop,
2241                          sInt4 li_primMiss, sInt4 *min, sInt4 *max)
2242 {
2243    char f_min = 0;      /* Flag if we found the max/min values */
2244    int i;               /* Loop counter. */
2245 
2246    *max = *min = Data[start];
2247    for (i = start; i < stop; i++) {
2248       if (Data[i] != li_primMiss) {
2249          if (!f_min) {
2250             *max = Data[i];
2251             *min = Data[i];
2252             f_min = 1;
2253          } else {
2254             if (*max < Data[i]) {
2255                *max = Data[i];
2256             } else if (*min > Data[i]) {
2257                *min = Data[i];
2258             }
2259          }
2260       }
2261    }
2262    return f_min;
2263 }
2264 
2265 /*****************************************************************************
2266  * findMaxMin0() --
2267  *
2268  * Arthur Taylor / MDL
2269  *
2270  * PURPOSE
2271  *   Find the min/max value between start/stop index values in the data
2272  * Assuming no missing values.
2273  *
2274  * ARGUMENTS
2275  *  Data = The data. (Input)
2276  * start = The starting index in data (Input)
2277  *  stop = The stopping index in data (Input)
2278  *   min = The min value found (Output)
2279  *   max = The max value found (Output)
2280  *
2281  * FILES/DATABASES: None
2282  *
2283  * RETURNS: void
2284  *
2285  * HISTORY
2286  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
2287  *
2288  * NOTES
2289  *****************************************************************************
2290  */
2291 static void findMaxMin0 (sInt4 *Data, int start, int stop, sInt4 *min,
2292                          sInt4 *max)
2293 {
2294    int i;               /* Loop counter. */
2295 
2296    *max = *min = Data[start];
2297    for (i = start + 1; i < stop; i++) {
2298       if (*max < Data[i]) {
2299          *max = Data[i];
2300       } else if (*min > Data[i]) {
2301          *min = Data[i];
2302       }
2303    }
2304 }
2305 
2306 /*****************************************************************************
2307  * findGroup2() --
2308  *
2309  * Arthur Taylor / MDL
2310  *
2311  * PURPOSE
2312  *   Find "split" so that the numbers between start and split are within
2313  * "range" of each other... stops if it reaches "stop".
2314  *   Assumes primary and secondary missing values.
2315  *
2316  * ARGUMENTS
2317  *        Data = The data. (Input)
2318  *       start = The starting index in data (Input)
2319  *        stop = The stopping index in data (Input)
2320  * li_primMiss = scaled primary missing value (Input)
2321  *  li_secMiss = scaled secondary missing value (Input)
2322  *       range = The range to use (Input)
2323  *       split = The first index that is out of the range (Output)
2324  *         min = The min value for the group. (Output)
2325  *         max = The max value for the group. (Output)
2326  *
2327  * FILES/DATABASES: None
2328  *
2329  * RETURNS: void
2330  *
2331  * HISTORY
2332  *   1/2005 Arthur Taylor (MDL): Created
2333  *
2334  * NOTES
2335  *****************************************************************************
2336  */
2337 static void findGroup2 (sInt4 *Data, int start, int stop,
2338                         sInt4 li_primMiss, sInt4 li_secMiss,
2339                         sInt4 range, int *split, sInt4 *min, sInt4 *max)
2340 {
2341    char f_min = 0;      /* Flag if we found the max/min values */
2342    int i;               /* Loop counter. */
2343 
2344    *min = *max = 0;
2345    for (i = start; i < stop; i++) {
2346       if ((Data[i] != li_secMiss) && (Data[i] != li_primMiss)) {
2347          if (!f_min) {
2348             *max = *min = Data[i];
2349             f_min = 1;
2350          } else {
2351             if (*max < Data[i]) {
2352                if ((Data[i] - *min) > range) {
2353                   *split = i;
2354                   return;
2355                }
2356                *max = Data[i];
2357             } else if (*min > Data[i]) {
2358                if ((*max - Data[i]) > range) {
2359                   *split = i;
2360                   return;
2361                }
2362                *min = Data[i];
2363             }
2364          }
2365       }
2366    }
2367    *split = stop;
2368 }
2369 
2370 /*****************************************************************************
2371  * findGroup1() --
2372  *
2373  * Arthur Taylor / MDL
2374  *
2375  * PURPOSE
2376  *   Find "split" so that the numbers between start and split are within
2377  * "range" of each other... stops if it reaches "stop".
2378  *   Assumes primary missing values.
2379  *
2380  * ARGUMENTS
2381  *        Data = The data. (Input)
2382  *       start = The starting index in data (Input)
2383  *        stop = The stopping index in data (Input)
2384  * li_primMiss = scaled primary missing value (Input)
2385  *       range = The range to use (Input)
2386  *       split = The first index that is out of the range (Output)
2387  *         min = The min value for the group. (Output)
2388  *         max = The max value for the group. (Output)
2389  *
2390  * FILES/DATABASES: None
2391  *
2392  * RETURNS: void
2393  *
2394  * HISTORY
2395  *   1/2005 Arthur Taylor (MDL): Created
2396  *
2397  * NOTES
2398  *****************************************************************************
2399  */
2400 static void findGroup1 (sInt4 *Data, int start, int stop,
2401                         sInt4 li_primMiss, sInt4 range, int *split,
2402                         sInt4 *min, sInt4 *max)
2403 {
2404    char f_min = 0;      /* Flag if we found the max/min values */
2405    int i;               /* Loop counter. */
2406 
2407    *min = *max = 0;
2408    for (i = start; i < stop; i++) {
2409       if (Data[i] != li_primMiss) {
2410          if (!f_min) {
2411             *max = *min = Data[i];
2412             f_min = 1;
2413          } else {
2414             if (*max < Data[i]) {
2415                if ((Data[i] - *min) > range) {
2416                   *split = i;
2417                   return;
2418                }
2419                *max = Data[i];
2420             } else if (*min > Data[i]) {
2421                if ((*max - Data[i]) > range) {
2422                   *split = i;
2423                   return;
2424                }
2425                *min = Data[i];
2426             }
2427          }
2428       }
2429    }
2430    *split = stop;
2431 }
2432 
2433 /*****************************************************************************
2434  * findGroup0() --
2435  *
2436  * Arthur Taylor / MDL
2437  *
2438  * PURPOSE
2439  *   Find "split" so that the numbers between start and split are within
2440  * "range" of each other... stops if it reaches "stop".
2441  *   Assumes no missing values.
2442  *
2443  * ARGUMENTS
2444  *        Data = The data. (Input)
2445  *       start = The starting index in data (Input)
2446  *        stop = The stopping index in data (Input)
2447  *       range = The range to use (Input)
2448  *       split = The first index that is out of the range (Output)
2449  *         min = The min value for the group. (Output)
2450  *         max = The max value for the group. (Output)
2451  *
2452  * FILES/DATABASES: None
2453  *
2454  * RETURNS: void
2455  *
2456  * HISTORY
2457  *   1/2005 Arthur Taylor (MDL): Created
2458  *
2459  * NOTES
2460  *****************************************************************************
2461  */
2462 static void findGroup0 (sInt4 *Data, int start, int stop,
2463                         sInt4 range, int *split, sInt4 *min, sInt4 *max)
2464 {
2465    int i;               /* Loop counter. */
2466 
2467    *max = *min = Data[0];
2468    for (i = start + 1; i < stop; i++) {
2469       if (*max < Data[i]) {
2470          if ((Data[i] - *min) > range) {
2471             *split = i;
2472             return;
2473          }
2474          *max = Data[i];
2475       } else if (*min > Data[i]) {
2476          if ((*max - Data[i]) > range) {
2477             *split = i;
2478             return;
2479          }
2480          *min = Data[i];
2481       }
2482    }
2483    *split = stop;
2484 }
2485 
2486 /*****************************************************************************
2487  * findGroupRev2() --
2488  *
2489  * Arthur Taylor / MDL
2490  *
2491  * PURPOSE
2492  *   Find "split" so that the numbers between split and stop are within
2493  * "range" of each other... stops if it reaches "start".
2494  *   Assumes primary and secondary missing values.
2495  *
2496  * ARGUMENTS
2497  *        Data = The data. (Input)
2498  *       start = The starting index in data (Input)
2499  *        stop = The stopping index in data (Input)
2500  * li_primMiss = scaled primary missing value (Input)
2501  *  li_secMiss = scaled secondary missing value (Input)
2502  *       range = The range to use (Input)
2503  *       split = The first index that is still in the range (Output)
2504  *         min = The min value for the group. (Output)
2505  *         max = The max value for the group. (Output)
2506  *
2507  * FILES/DATABASES: None
2508  *
2509  * RETURNS: void
2510  *
2511  * HISTORY
2512  *   1/2005 Arthur Taylor (MDL): Created
2513  *
2514  * NOTES
2515  *****************************************************************************
2516  */
2517 static void findGroupRev2 (sInt4 *Data, int start, int stop,
2518                            sInt4 li_primMiss, sInt4 li_secMiss,
2519                            sInt4 range, int *split, sInt4 *min, sInt4 *max)
2520 {
2521    char f_min = 0;      /* Flag if we found the max/min values */
2522    int i;               /* Loop counter. */
2523 
2524    *min = *max = 0;
2525    for (i = stop - 1; i >= start; i--) {
2526       if ((Data[i] != li_secMiss) && (Data[i] != li_primMiss)) {
2527          if (!f_min) {
2528             *max = *min = Data[i];
2529             f_min = 1;
2530          } else {
2531             if (*max < Data[i]) {
2532                if ((Data[i] - *min) > range) {
2533                   *split = i + 1;
2534                   return;
2535                }
2536                *max = Data[i];
2537             } else if (*min > Data[i]) {
2538                if ((*max - Data[i]) > range) {
2539                   *split = i + 1;
2540                   return;
2541                }
2542                *min = Data[i];
2543             }
2544          }
2545       }
2546    }
2547    *split = start;
2548 }
2549 
2550 /*****************************************************************************
2551  * findGroupRev1() --
2552  *
2553  * Arthur Taylor / MDL
2554  *
2555  * PURPOSE
2556  *   Find "split" so that the numbers between split and stop are within
2557  * "range" of each other... stops if it reaches "start".
2558  *   Assumes primary missing values.
2559  *
2560  * ARGUMENTS
2561  *        Data = The data. (Input)
2562  *       start = The starting index in data (Input)
2563  *        stop = The stopping index in data (Input)
2564  * li_primMiss = scaled primary missing value (Input)
2565  *       range = The range to use (Input)
2566  *       split = The first index that is still in the range (Output)
2567  *         min = The min value for the group. (Output)
2568  *         max = The max value for the group. (Output)
2569  *
2570  * FILES/DATABASES: None
2571  *
2572  * RETURNS: void
2573  *
2574  * HISTORY
2575  *   1/2005 Arthur Taylor (MDL): Created
2576  *
2577  * NOTES
2578  *****************************************************************************
2579  */
2580 static void findGroupRev1 (sInt4 *Data, int start, int stop,
2581                            sInt4 li_primMiss, sInt4 range, int *split,
2582                            sInt4 *min, sInt4 *max)
2583 {
2584    char f_min = 0;      /* Flag if we found the max/min values */
2585    int i;               /* Loop counter. */
2586 
2587    *min = *max = 0;
2588    for (i = stop - 1; i >= start; i--) {
2589       if (Data[i] != li_primMiss) {
2590          if (!f_min) {
2591             *max = *min = Data[i];
2592             f_min = 1;
2593          } else {
2594             if (*max < Data[i]) {
2595                if ((Data[i] - *min) > range) {
2596                   *split = i + 1;
2597                   return;
2598                }
2599                *max = Data[i];
2600             } else if (*min > Data[i]) {
2601                if ((*max - Data[i]) > range) {
2602                   *split = i + 1;
2603                   return;
2604                }
2605                *min = Data[i];
2606             }
2607          }
2608       }
2609    }
2610    *split = start;
2611 }
2612 
2613 /*****************************************************************************
2614  * findGroupRev0() --
2615  *
2616  * Arthur Taylor / MDL
2617  *
2618  * PURPOSE
2619  *   Find "split" so that the numbers between split and stop are within
2620  * "range" of each other... stops if it reaches "start".
2621  *   Assumes no missing values.
2622  *
2623  * ARGUMENTS
2624  *        Data = The data. (Input)
2625  *       start = The starting index in data (Input)
2626  *        stop = The stopping index in data (Input)
2627  * li_primMiss = scaled primary missing value (Input)
2628  *       range = The range to use (Input)
2629  *       split = The first index that is still in the range (Output)
2630  *         min = The min value for the group. (Output)
2631  *         max = The max value for the group. (Output)
2632  *
2633  * FILES/DATABASES: None
2634  *
2635  * RETURNS: void
2636  *
2637  * HISTORY
2638  *   1/2005 Arthur Taylor (MDL): Created
2639  *
2640  * NOTES
2641  *****************************************************************************
2642  */
2643 static void findGroupRev0 (sInt4 *Data, int start, int stop,
2644                            sInt4 range, int *split, sInt4 *min, sInt4 *max)
2645 {
2646    int i;               /* Loop counter. */
2647 
2648    *max = *min = Data[stop - 1];
2649    for (i = stop - 2; i >= start; i--) {
2650       if (*max < Data[i]) {
2651          if ((Data[i] - *min) > range) {
2652             *split = i + 1;
2653             return;
2654          }
2655          *max = Data[i];
2656       } else if (*min > Data[i]) {
2657          if ((*max - Data[i]) > range) {
2658             *split = i + 1;
2659             return;
2660          }
2661          *min = Data[i];
2662       }
2663    }
2664    *split = start;
2665 }
2666 
2667 /*****************************************************************************
2668  * shiftGroup2() --
2669  *
2670  * Arthur Taylor / MDL
2671  *
2672  * PURPOSE
2673  *   Find "split" so that the numbers between split and start1 are all inside
2674  * the range defined by max, min and bit.  It allows max and min to change,
2675  * as long as it doesn't exceed the range defined by bit.
2676  *   This is very similar to findGroupRev?() but here we already know
2677  * information about the min/max values, and are just expanding the group a
2678  * little, while the other one knew nothing about the group, and just wanted
2679  * a group of a given range.
2680  *   Assumes primary and secondary missing values.
2681  *
2682  * ARGUMENTS
2683  *        Data = The data. (Input)
2684  *      start1 = The starting index in data (Input)
2685  *      start2 = The starting index of the earlier group (i.e. don't go to any
2686  *               earlier indices than this. (Input)
2687  * li_primMiss = scaled primary missing value (Input)
2688  *  li_secMiss = scaled secondary missing value (Input)
2689  *         bit = The range we are allowed to store this in. (Input)
2690  *         min = The min value for the group. (Input/Output)
2691  *         max = The max value for the group. (Input/Output)
2692  *       split = The first index that is still in the range (Output)
2693  *
2694  * FILES/DATABASES: None
2695  *
2696  * RETURNS: void
2697  *
2698  * HISTORY
2699  *   1/2005 Arthur Taylor (MDL): Created
2700  *
2701  * NOTES
2702  *****************************************************************************
2703  */
2704 static void shiftGroup2 (sInt4 *Data, int start1, int start2,
2705                          sInt4 li_primMiss, sInt4 li_secMiss, int bit,
2706                          sInt4 *min, sInt4 *max, size_t *split)
2707 {
2708    int i;               /* Loop counter. */
2709    int range;           /* The range defined by bit. */
2710 
2711    range = (int) (pow (2.0, bit) - 1) - 1;
2712    myAssert (start2 <= start1);
2713    for (i = start1; i >= start2; i--) {
2714       if ((Data[i] != li_primMiss) && (Data[i] != li_secMiss)) {
2715          if (Data[i] > *max) {
2716             if ((Data[i] - *min) <= range) {
2717                *max = Data[i];
2718             } else {
2719                *split = i + 1;
2720                return;
2721             }
2722          } else if (Data[i] < *min) {
2723             if ((*max - Data[i]) <= range) {
2724                *min = Data[i];
2725             } else {
2726                *split = i + 1;
2727                return;
2728             }
2729          }
2730       }
2731    }
2732    *split = start2;
2733 }
2734 
2735 /*****************************************************************************
2736  * shiftGroup1() --
2737  *
2738  * Arthur Taylor / MDL
2739  *
2740  * PURPOSE
2741  *   Find "split" so that the numbers between split and start1 are all inside
2742  * the range defined by max, min and bit.  It allows max and min to change,
2743  * as long as it doesn't exceed the range defined by bit.
2744  *   This is very similar to findGroupRev?() but here we already know
2745  * information about the min/max values, and are just expanding the group a
2746  * little, while the other one knew nothing about the group, and just wanted
2747  * a group of a given range.
2748  *   Assumes primary missing values.
2749  *
2750  * ARGUMENTS
2751  *        Data = The data. (Input)
2752  *      start1 = The starting index in data (Input)
2753  *      start2 = The starting index of the earlier group (i.e. don't go to any
2754  *               earlier indices than this. (Input)
2755  * li_primMiss = scaled primary missing value (Input)
2756  *         bit = The range we are allowed to store this in. (Input)
2757  *         min = The min value for the group. (Input/Output)
2758  *         max = The max value for the group. (Input/Output)
2759  *       split = The first index that is still in the range (Output)
2760  *
2761  * FILES/DATABASES: None
2762  *
2763  * RETURNS: void
2764  *
2765  * HISTORY
2766  *   1/2005 Arthur Taylor (MDL): Created
2767  *
2768  * NOTES
2769  *****************************************************************************
2770  */
2771 static void shiftGroup1 (sInt4 *Data, int start1, int start2,
2772                          sInt4 li_primMiss, int bit,
2773                          sInt4 *min, sInt4 *max, size_t *split)
2774 {
2775    int i;               /* Loop counter. */
2776    int range;           /* The range defined by bit. */
2777 
2778    range = (int) (pow (2.0, bit) - 1) - 1;
2779    myAssert (start2 <= start1);
2780    for (i = start1; i >= start2; i--) {
2781       if (Data[i] != li_primMiss) {
2782          if (Data[i] > *max) {
2783             if ((Data[i] - *min) <= range) {
2784                *max = Data[i];
2785             } else {
2786                *split = i + 1;
2787                return;
2788             }
2789          } else if (Data[i] < *min) {
2790             if ((*max - Data[i]) <= range) {
2791                *min = Data[i];
2792             } else {
2793                *split = i + 1;
2794                return;
2795             }
2796          }
2797       }
2798    }
2799    *split = start2;
2800 }
2801 
2802 /*****************************************************************************
2803  * shiftGroup0() --
2804  *
2805  * Arthur Taylor / MDL
2806  *
2807  * PURPOSE
2808  *   Find "split" so that the numbers between split and start1 are all inside
2809  * the range defined by max, min and bit.  It allows max and min to change,
2810  * as long as it doesn't exceed the range defined by bit.
2811  *   This is very similar to findGroupRev?() but here we already know
2812  * information about the min/max values, and are just expanding the group a
2813  * little, while the other one knew nothing about the group, and just wanted
2814  * a group of a given range.
2815  *   Assumes no missing values.
2816  *
2817  * ARGUMENTS
2818  *        Data = The data. (Input)
2819  *      start1 = The starting index in data (Input)
2820  *      start2 = The starting index of the earlier group (i.e. don't go to any
2821  *               earlier indices than this. (Input)
2822  *         bit = The range we are allowed to store this in. (Input)
2823  *         min = The min value for the group. (Input/Output)
2824  *         max = The max value for the group. (Input/Output)
2825  *       split = The first index that is still in the range (Output)
2826  *
2827  * FILES/DATABASES: None
2828  *
2829  * RETURNS: void
2830  *
2831  * HISTORY
2832  *   1/2005 Arthur Taylor (MDL): Created
2833  *
2834  * NOTES
2835  *****************************************************************************
2836  */
2837 static void shiftGroup0 (sInt4 *Data, int start1, int start2, int bit,
2838                          sInt4 *min, sInt4 *max, size_t *split)
2839 {
2840    int i;               /* Loop counter. */
2841    int range;           /* The range defined by bit. */
2842 
2843    range = (int) (pow (2.0, bit) - 1) - 0;
2844    myAssert (start2 <= start1);
2845    for (i = start1; i >= start2; i--) {
2846       if (Data[i] > *max) {
2847          if ((Data[i] - *min) <= range) {
2848             *max = Data[i];
2849          } else {
2850             *split = i + 1;
2851             return;
2852          }
2853       } else if (Data[i] < *min) {
2854          if ((*max - Data[i]) <= range) {
2855             *min = Data[i];
2856          } else {
2857             *split = i + 1;
2858             return;
2859          }
2860       }
2861    }
2862    *split = start2;
2863 }
2864 
2865 /*****************************************************************************
2866  * doSplit() --
2867  *
2868  * Arthur Taylor / MDL
2869  *
2870  * PURPOSE
2871  *   Reduce the "bit range", and create groups that grab as much as they can
2872  * to the right.  Then reduce those groups if they improve the score.
2873  *
2874  * ARGUMENTS
2875  *        Data = The data. (Input)
2876  *     numData = The number of elements in data. (Input)
2877  *           G = The group to split. (Input)
2878  *    lclGroup = The resulting groups (Output)
2879  * numLclGroup = The number of resulting groups. (Output)
2880  *  f_primMiss = Flag if we have a primary missing value (Input)
2881  * li_primMiss = scaled primary missing value (Input)
2882  *   f_secMiss = Flag if we have a secondary missing value (Input)
2883  *  li_secMiss = scaled secondary missing value (Input)
2884  *     xFactor = Estimate of cost (in bits) of a group. (Input)
2885  *
2886  * FILES/DATABASES: None
2887  *
2888  * RETURNS: void
2889  *
2890  * HISTORY
2891  *  1/2005 Arthur Taylor (MDL): Created.
2892  *
2893  * NOTES
2894  *****************************************************************************
2895  */
2896 static void doSplit (sInt4 *Data,
2897                      CPL_UNUSED int numData,
2898                      TDLGroupType * G,
2899                      TDLGroupType ** lclGroup, int *numLclGroup,
2900                      char f_primMiss, sInt4 li_primMiss,
2901                      char f_secMiss, sInt4 li_secMiss, int xFactor)
2902 {
2903    int start;           /* Where to start the current group. */
2904    int range;           /* The range to make the groups. */
2905    int final;           /* One more than the last index in the group G. */
2906    int split;           /* Where to split the group. */
2907    TDLGroupType G1;     /* The current group to add. */
2908    TDLGroupType G2;     /* The group if we evaporated the previous group. */
2909    int evaporate;       /* How many groups we have "evaporated". */
2910    int i;               /* Loop counter to help "evaporate" groups. */
2911    sInt4 scoreA;        /* The original score for 2 groups */
2912    sInt4 scoreB;        /* The new score (having evaporated a group) */
2913    int GroupLen;        /* Actual alloc'ed group len. */
2914 
2915    /* *INDENT-OFF* */
2916    /* The (pow (2, ..) -1) is because 2^n - 1 is max range of a group.
2917     * Example n = 1, 2^1 -1 = 1 range of (1,0) is 1.
2918     * Example n = 2, 2^2 -1 = 3 range of (3,2,1,0) is 3.
2919     * The G.bit - 1 is because we are trying to reduce the range. */
2920    /* *INDENT-ON* */
2921    range = (int) (pow (2.0, G->bit - 1) - 1) - (f_secMiss + f_primMiss);
2922    split = G->start;
2923    start = G->start;
2924    final = G->start + G->num;
2925    myAssert (final <= numData);
2926    *numLclGroup = 0;
2927    GroupLen = 1;
2928    *lclGroup = (TDLGroupType *) malloc (GroupLen * sizeof (TDLGroupType));
2929    while (split < final) {
2930       if (f_secMiss) {
2931          findGroup2 (Data, start, final, li_primMiss, li_secMiss, range,
2932                      &split, &(G1.min), &(G1.max));
2933       } else if (f_primMiss) {
2934          findGroup1 (Data, start, final, li_primMiss, range, &split,
2935                      &(G1.min), &(G1.max));
2936       } else {
2937          findGroup0 (Data, start, final, range, &split, &(G1.min), &(G1.max));
2938       }
2939       G1.bit = (char) power ((uInt4) (G1.max - G1.min),
2940                              f_secMiss + f_primMiss);
2941       G1.num = split - start;
2942       G1.start = start;
2943       G1.f_trySplit = 1;
2944       G1.f_tryShift = 1;
2945       /* Test if we should add to previous group, or create a new group. */
2946       if (*numLclGroup == 0) {
2947          *numLclGroup = 1;
2948          (*lclGroup)[0] = G1;
2949       } else {
2950          G2.start = (*lclGroup)[*numLclGroup - 1].start;
2951          G2.num = (*lclGroup)[*numLclGroup - 1].num + G1.num;
2952          G2.min = ((*lclGroup)[*numLclGroup - 1].min < G1.min) ?
2953                (*lclGroup)[*numLclGroup - 1].min : G1.min;
2954          G2.max = ((*lclGroup)[*numLclGroup - 1].max > G1.max) ?
2955                (*lclGroup)[*numLclGroup - 1].max : G1.max;
2956          G2.bit = (char) power ((uInt4) (G2.max - G2.min),
2957                                 f_secMiss + f_primMiss);
2958          G2.f_trySplit = 1;
2959          G2.f_tryShift = 1;
2960          scoreA = ((*lclGroup)[*numLclGroup - 1].bit *
2961                    (*lclGroup)[*numLclGroup - 1].num) + xFactor;
2962          scoreA += G1.bit * G1.num + xFactor;
2963          scoreB = G2.bit * G2.num + xFactor;
2964          if (scoreB < scoreA) {
2965             (*lclGroup)[*numLclGroup - 1] = G2;
2966             /* See if we can evaporate any of the old groups */
2967             evaporate = 0;
2968             for (i = *numLclGroup - 1; i > 0; i--) {
2969                G1.start = (*lclGroup)[i - 1].start;
2970                G1.num = (*lclGroup)[i].num + (*lclGroup)[i - 1].num;
2971                G1.min = ((*lclGroup)[i].min < (*lclGroup)[i - 1].min) ?
2972                      (*lclGroup)[i].min : (*lclGroup)[i - 1].min;
2973                G1.max = ((*lclGroup)[i].max > (*lclGroup)[i - 1].max) ?
2974                      (*lclGroup)[i].max : (*lclGroup)[i - 1].max;
2975                G1.bit = (char) power ((uInt4) (G1.max - G1.min),
2976                                       f_secMiss + f_primMiss);
2977                G1.f_trySplit = 1;
2978                G1.f_tryShift = 1;
2979                scoreA = (*lclGroup)[i].bit * (*lclGroup)[i].num + xFactor;
2980                scoreA += ((*lclGroup)[i - 1].bit * (*lclGroup)[i - 1].num +
2981                           xFactor);
2982                scoreB = G1.bit * G1.num + xFactor;
2983                if (scoreB < scoreA) {
2984                   evaporate++;
2985                   (*lclGroup)[i - 1] = G1;
2986                } else {
2987                   break;
2988                }
2989             }
2990             if (evaporate != 0) {
2991                *numLclGroup = *numLclGroup - evaporate;
2992             }
2993          } else {
2994             *numLclGroup = *numLclGroup + 1;
2995             if (*numLclGroup > GroupLen) {
2996                GroupLen = *numLclGroup;
2997                *lclGroup = (TDLGroupType *) realloc ((void *) *lclGroup,
2998                                                      GroupLen *
2999                                                      sizeof (TDLGroupType));
3000             }
3001             (*lclGroup)[*numLclGroup - 1] = G1;
3002          }
3003       }
3004       start = split;
3005    }
3006 }
3007 
3008 /*****************************************************************************
3009  * doSplitRight() --
3010  *
3011  * Arthur Taylor / MDL
3012  *
3013  * PURPOSE
3014  *   Break into two groups right has range n - 1, left has range n.
3015  *
3016  * ARGUMENTS
3017  *        Data = The data. (Input)
3018  *     numData = The number of elements in data. (Input)
3019  *           G = The group to split. (Input)
3020  *          G1 = The right most group (Output)
3021  *          G2 = The remainder. (Output)
3022  *  f_primMiss = Flag if we have a primary missing value (Input)
3023  * li_primMiss = scaled primary missing value (Input)
3024  *   f_secMiss = Flag if we have a secondary missing value (Input)
3025  *  li_secMiss = scaled secondary missing value (Input)
3026  *
3027  * FILES/DATABASES: None
3028  *
3029  * RETURNS: void
3030  *
3031  * HISTORY
3032  *  1/2005 Arthur Taylor (MDL): Created.
3033  *
3034  * NOTES
3035  *****************************************************************************
3036  */
3037 static void doSplitRight (sInt4 *Data,
3038                           CPL_UNUSED int numData,
3039                           TDLGroupType * G,
3040                           TDLGroupType * G1, TDLGroupType * G2,
3041                           char f_primMiss, sInt4 li_primMiss,
3042                           char f_secMiss, sInt4 li_secMiss)
3043 {
3044    int range;           /* The range to make the right most group. */
3045    int final;           /* One more than the last index in the group. */
3046    int split;           /* Where to split the group. */
3047 
3048    /* *INDENT-OFF* */
3049    /* The (pow (2, ..) -1) is because 2^n - 1 is max range of a group.
3050     * Example n = 1, 2^1 -1 = 1 range of (1,0) is 1.
3051     * Example n = 2, 2^2 -1 = 3 range of (3,2,1,0) is 3.
3052     * The G.bit - 1 is because we are trying to reduce the range. */
3053    /* *INDENT-ON* */
3054    range = (int) (pow (2.0, G->bit - 1) - 1) - (f_secMiss + f_primMiss);
3055    final = G->start + G->num;
3056    split = final;
3057    myAssert (final <= numData);
3058 
3059    if (f_secMiss) {
3060       findGroupRev2 (Data, G->start, final, li_primMiss, li_secMiss, range,
3061                      &split, &(G1->min), &(G1->max));
3062       findMaxMin2 (Data, G->start, split, li_primMiss, li_secMiss,
3063                    &(G2->min), &(G2->max));
3064    } else if (f_primMiss) {
3065       findGroupRev1 (Data, G->start, final, li_primMiss, range, &split,
3066                      &(G1->min), &(G1->max));
3067       findMaxMin1 (Data, G->start, split, li_primMiss, &(G2->min),
3068                    &(G2->max));
3069    } else {
3070       findGroupRev0 (Data, G->start, final, range, &split, &(G1->min),
3071                      &(G1->max));
3072       findMaxMin0 (Data, G->start, split, &(G2->min), &(G2->max));
3073    }
3074 
3075    G1->bit = (char) power ((uInt4) (G1->max - G1->min),
3076                            f_secMiss + f_primMiss);
3077    G2->bit = (char) power ((uInt4) (G2->max - G2->min),
3078                            f_secMiss + f_primMiss);
3079    G1->start = split;
3080    G2->start = G->start;
3081    G1->num = final - split;
3082    G2->num = split - G->start;
3083    G1->f_trySplit = 1;
3084    G1->f_tryShift = 1;
3085    G2->f_trySplit = 1;
3086    G2->f_tryShift = 1;
3087 }
3088 
3089 /*****************************************************************************
3090  * ComputeGroupSize() --
3091  *
3092  * Arthur Taylor / MDL
3093  *
3094  * PURPOSE
3095  *   Compute the number of bits needed for the various elements of the groups
3096  * as well as the total number of bits needed.
3097  *
3098  * ARGUMENTS
3099  *    group = Groups (Input)
3100  * numGroup = Number of groups (Input)
3101  *     ibit = Number of bits needed for the minimum values of each group.
3102  *            Find max absolute value of group mins.  Note: all group mins
3103  *            are positive (Output)
3104  *     jbit = Number of bits needed for the number of bits for each group.
3105  *            Find max absolute value of number of bits. (Output)
3106  *     kbit = Number of bits needed for the number of values for each group.
3107  *            Find max absolute value of number of values. (Output)
3108  *
3109  * FILES/DATABASES: None
3110  *
3111  * RETURNS: sInt4
3112  *   number of bits needed by the groups
3113  *
3114  * HISTORY
3115  *  12/2004 Arthur Taylor (MDL): Updated from "tdlpack.c" in "C" tdlpack code
3116  *
3117  * NOTES
3118  *****************************************************************************
3119  */
3120 static sInt4 ComputeGroupSize (TDLGroupType * group, int numGroup,
3121                                size_t *ibit, size_t *jbit, size_t *kbit)
3122 {
3123    int i;               /* loop counter. */
3124    sInt4 ans = 0;       /* The number of bits needed. */
3125    sInt4 maxMin = 0;    /* The largest min value in the groups */
3126    uChar maxBit = 0;    /* The largest needed bits in the groups */
3127    uInt4 maxNum = 0;    /* The largest number of values in the groups. */
3128 
3129    for (i = 0; i < numGroup; i++) {
3130       ans += group[i].bit * group[i].num;
3131       if (group[i].min > maxMin) {
3132          maxMin = group[i].min;
3133       }
3134       if (group[i].bit > maxBit) {
3135          maxBit = group[i].bit;
3136       }
3137       if (group[i].num > maxNum) {
3138          maxNum = group[i].num;
3139       }
3140    }
3141    /* This only works for pos numbers... */
3142    for (i = 0; (maxMin != 0); i++) {
3143       maxMin = maxMin >> 1;
3144    }
3145    /* Allow 0 bits for min.  Assumes that decoder allows 0 bits */
3146    *ibit = i;
3147    /* This only works for pos numbers... */
3148    for (i = 0; (maxBit != 0); i++) {
3149       maxBit = maxBit >> 1;
3150    }
3151    /* Allow 0 bits for min.  Assumes that decoder allows 0 bits */
3152    *jbit = i;
3153    /* This only works for pos numbers... */
3154    for (i = 0; (maxNum != 0); i++) {
3155       maxNum = maxNum >> 1;
3156    }
3157    /* Allow 0 bits for min.  Assumes that decoder allows 0 bits */
3158    *kbit = i;
3159    ans += (sInt4) (((*ibit) + (*jbit) + (*kbit)) * numGroup);
3160    return ans;
3161 }
3162 
3163 /*****************************************************************************
3164  * splitGroup() --
3165  *
3166  * Arthur Taylor / MDL
3167  *
3168  * PURPOSE
3169  *   Tries to reduce (split) each group by 1 bit.  It does this by:
3170  *   A) reduce the "bit range", and create groups that grab as much as they
3171  * can to the right.  Then reduce those groups if they improve the score.
3172  *   B) reduce the bit range and grab the left most group only, leaving the
3173  * rest unchanged.
3174  *   C) reduce the bit range and grab the right most group only, leaving the
3175  * rest unchanged.
3176  *
3177  * ARGUMENTS
3178  *        Data = The data. (Input)
3179  *     numData = The number of elements in data. (Input)
3180  *       group = The groups using the "best minGroup. (Input)
3181  *    numGroup = Number of groups (Input)
3182  *    lclGroup = The local copy of the groups (Output)
3183  * numLclGroup = Number of local groups (Output)
3184  *  f_primMiss = Flag if we have a primary missing value (Input)
3185  * li_primMiss = scaled primary missing value (Input)
3186  *   f_secMiss = Flag if we have a secondary missing value (Input)
3187  *  li_secMiss = scaled secondary missing value (Input)
3188  *     xFactor = Estimate of cost (in bits) of a group. (Input)
3189  *
3190  * FILES/DATABASES: None
3191  *
3192  * RETURNS: void
3193  *
3194  * HISTORY
3195  *  1/2005 Arthur Taylor (MDL): Created.
3196  *
3197  * NOTES
3198  *****************************************************************************
3199  */
3200 static int splitGroup (sInt4 *Data, int numData, TDLGroupType * group,
3201                        int numGroup, TDLGroupType ** lclGroup,
3202                        int *numLclGroup, char f_primMiss,
3203                        sInt4 li_primMiss, char f_secMiss,
3204                        sInt4 li_secMiss, size_t xFactor)
3205 {
3206    uInt4 minBit = 1;     /* The fewest # of bits, with no subdivision. */
3207    TDLGroupType *subGroup; /* The subgroups that we tried splitting the
3208                             * primary group into. */
3209    int numSubGroup;     /* The number of groups in subGroup. */
3210    sInt4 A_max;         /* Max value of a given group. */
3211    sInt4 A_min;         /* Min value of a given group. */
3212    sInt4 scoreA;        /* The original score for a given group */
3213    sInt4 scoreB;        /* The new score */
3214    int f_adjust = 0;    /* Flag if group has changed. */
3215    int f_keep;          /* Flag to keep the subgroup instead of original */
3216    int i;               /* Loop counters */
3217    int sub;             /* loop counter over the sub group. */
3218    int lclIndex;        /* Used to help copy data from subGroup to answer. */
3219    int GroupLen;        /* Actual alloc'ed group len. */
3220    int extra;           /* Used to reduce number of allocs. */
3221 
3222    /* Figure out how few bits a group can have without being able to further
3223     * divide it. */
3224    if (f_secMiss) {
3225       /* 11 = primMiss 10 = secMiss 01, 00 = data. */
3226       minBit = 2;
3227    }
3228 #ifdef useless
3229    else if (f_primMiss) {
3230       /* 1 = primMiss 0 = data. */
3231       /* might try minBit = 1 here. */
3232       minBit = 1;
3233    } else {
3234       /* 1, 0 = data. */
3235       minBit = 1;
3236    }
3237 #endif
3238 
3239    *numLclGroup = 0;
3240    *lclGroup = (TDLGroupType *) malloc (numGroup * sizeof (TDLGroupType));
3241    GroupLen = numGroup;
3242    extra = 0;
3243    for (i = 0; i < numGroup; i++) {
3244       /* Check if we have already tried to split this group, or it has too
3245        * few members, or it doesn't have enough bits to split.  If so, skip
3246        * this group. */
3247       if ((group[i].f_trySplit) && (group[i].num > xFactor) &&
3248           (group[i].bit > minBit)) {
3249          f_keep = 0;
3250          doSplit (Data, numData, &(group[i]), &subGroup, &numSubGroup,
3251                   f_primMiss, li_primMiss, f_secMiss, li_secMiss, static_cast<int>(xFactor));
3252          if (numSubGroup != 1) {
3253             scoreA = static_cast<sInt4>(group[i].bit * group[i].num + xFactor);
3254             scoreB = 0;
3255             for (sub = 0; sub < numSubGroup; sub++) {
3256                scoreB += (sInt4) (subGroup[sub].bit * subGroup[sub].num + xFactor);
3257             }
3258             if (scoreB < scoreA) {
3259                f_keep = 1;
3260             } else if (numSubGroup > 2) {
3261                /* We can do "doSplitLeft" (which is breaking it into 2 groups
3262                 * the first having range n - 1, the second having range n,
3263                 * using what we know from doSplit. */
3264                subGroup[1].num = group[i].num - subGroup[0].num;
3265                if (f_secMiss) {
3266                   findMaxMin2 (Data, subGroup[1].start,
3267                                subGroup[1].start + subGroup[1].num,
3268                                li_primMiss, li_secMiss, &A_min, &A_max);
3269                } else if (f_primMiss) {
3270                   findMaxMin1 (Data, subGroup[1].start,
3271                                subGroup[1].start + subGroup[1].num,
3272                                li_primMiss, &A_min, &A_max);
3273                } else {
3274                   findMaxMin0 (Data, subGroup[1].start,
3275                                subGroup[1].start + subGroup[1].num,
3276                                &A_min, &A_max);
3277                }
3278                subGroup[1].min = A_min;
3279                subGroup[1].max = A_max;
3280                subGroup[1].bit = power ((uInt4) (A_max - A_min),
3281                                         f_secMiss + f_primMiss);
3282                subGroup[1].f_trySplit = 1;
3283                subGroup[1].f_tryShift = 1;
3284                numSubGroup = 2;
3285                scoreB = static_cast<sInt4>(subGroup[0].bit * subGroup[0].num + xFactor);
3286                scoreB += static_cast<sInt4>(subGroup[1].bit * subGroup[1].num + xFactor);
3287                if (scoreB < scoreA) {
3288                   f_keep = 1;
3289                }
3290             }
3291          }
3292          if (!f_keep) {
3293             if (numSubGroup == 1) {
3294                subGroup = (TDLGroupType *) realloc (subGroup,
3295                                                     2 *
3296                                                     sizeof (TDLGroupType));
3297             }
3298             numSubGroup = 2;
3299             doSplitRight (Data, numData, &(group[i]), &(subGroup[1]),
3300                           &(subGroup[0]), f_primMiss, li_primMiss, f_secMiss,
3301                           li_secMiss);
3302             scoreA = static_cast<sInt4>(group[i].bit * group[i].num + xFactor);
3303             scoreB = static_cast<sInt4>(subGroup[0].bit * subGroup[0].num + xFactor);
3304             scoreB += static_cast<sInt4>(subGroup[1].bit * subGroup[1].num + xFactor);
3305             if (scoreB < scoreA) {
3306                f_keep = 1;
3307             }
3308          }
3309          if (f_keep) {
3310             lclIndex = *numLclGroup;
3311             *numLclGroup = *numLclGroup + numSubGroup;
3312             if (*numLclGroup > GroupLen) {
3313                GroupLen += extra;
3314                extra = 0;
3315                if (*numLclGroup > GroupLen) {
3316                   GroupLen = *numLclGroup;
3317                }
3318                *lclGroup = (TDLGroupType *) realloc ((void *) *lclGroup,
3319                                                      GroupLen *
3320                                                      sizeof (TDLGroupType));
3321             } else {
3322                extra += numSubGroup - 1;
3323             }
3324             memcpy ((*lclGroup) + lclIndex, subGroup,
3325                     numSubGroup * sizeof (TDLGroupType));
3326             f_adjust = 1;
3327          } else {
3328             *numLclGroup = *numLclGroup + 1;
3329             if (*numLclGroup > GroupLen) {
3330                GroupLen += extra;
3331                extra = 0;
3332                if (*numLclGroup > GroupLen) {
3333                   GroupLen = *numLclGroup;
3334                }
3335                *lclGroup = (TDLGroupType *) realloc ((void *) *lclGroup,
3336                                                      GroupLen *
3337                                                      sizeof (TDLGroupType));
3338             }
3339             (*lclGroup)[*numLclGroup - 1] = group[i];
3340             (*lclGroup)[*numLclGroup - 1].f_trySplit = 0;
3341          }
3342          free (subGroup);
3343          subGroup = NULL;
3344       } else {
3345          *numLclGroup = *numLclGroup + 1;
3346          if (*numLclGroup > GroupLen) {
3347             GroupLen += extra;
3348             extra = 0;
3349             if (*numLclGroup > GroupLen) {
3350                GroupLen = *numLclGroup;
3351             }
3352             *lclGroup = (TDLGroupType *) realloc ((void *) *lclGroup,
3353                                                   GroupLen *
3354                                                   sizeof (TDLGroupType));
3355          }
3356          (*lclGroup)[*numLclGroup - 1] = group[i];
3357          (*lclGroup)[*numLclGroup - 1].f_trySplit = 0;
3358       }
3359    }
3360    myAssert (GroupLen == *numLclGroup);
3361    return f_adjust;
3362 }
3363 
3364 /*****************************************************************************
3365  * shiftGroup() --
3366  *
3367  * Arthur Taylor / MDL
3368  *
3369  * PURPOSE
3370  *   Tries to shift / join the groups together.  It does this by first
3371  * calculating if a group should still exist.  If it should, then it has
3372  * each group grab as much as it can to the left without increasing its "bit
3373  * range".
3374  *
3375  * ARGUMENTS
3376  *        Data = The data. (Input)
3377  *     numData = The number of elements in data. (Input)
3378  *       group = The resulting groups. (Output)
3379  *    numGroup = Number of groups (Output)
3380  *  f_primMiss = Flag if we have a primary missing value (Input)
3381  * li_primMiss = scaled primary missing value (Input)
3382  *   f_secMiss = Flag if we have a secondary missing value (Input)
3383  *  li_secMiss = scaled secondary missing value (Input)
3384  *     xFactor = Estimate of cost (in bits) of a group. (Input)
3385  *
3386  * FILES/DATABASES: None
3387  *
3388  * RETURNS: void
3389  *
3390  * HISTORY
3391  *  1/2005 Arthur Taylor (MDL): Created.
3392  *
3393  * NOTES
3394  *****************************************************************************
3395  */
3396 static void shiftGroup (sInt4 *Data,
3397                         CPL_UNUSED int numData,
3398                         TDLGroupType ** Group,
3399                         size_t *NumGroup, char f_primMiss, sInt4 li_primMiss,
3400                         char f_secMiss, sInt4 li_secMiss, int xFactor)
3401 {
3402    TDLGroupType *group = (*Group); /* Local pointer to Group. */
3403    int numGroup = static_cast<int>(*NumGroup); /* # elements in group. */
3404    int i, j;            /* loop counters. */
3405    sInt4 A_max;         /* Max value of a given group. */
3406    sInt4 A_min;         /* Min value of a given group. */
3407    size_t begin;        /* New start to the group. */
3408    sInt4 scoreA;        /* The original score for group i and i - 1 */
3409    sInt4 scoreB;        /* The new score for group i and i - 1 */
3410    TDLGroupType G1;     /* The "new" group[i - 1]. */
3411    TDLGroupType G2;     /* The "new" group[i]. */
3412    int evaporate = 0;   /* number of groups that "evaporated" */
3413    int index;           /* index while getting rid of "evaporated groups". */
3414 
3415    for (i = numGroup - 1; i > 0; i--) {
3416       myAssert (group[i].num > 0);
3417       /* See if we can evaporate the group n - 1 */
3418       G1.start = group[i - 1].start;
3419       G1.num = group[i].num + group[i - 1].num;
3420       G1.min = (group[i].min < group[i - 1].min) ?
3421             group[i].min : group[i - 1].min;
3422       G1.max = (group[i].max > group[i - 1].max) ?
3423             group[i].max : group[i - 1].max;
3424       G1.bit = (char) power ((uInt4) (G1.max - G1.min),
3425                              f_secMiss + f_primMiss);
3426       G1.f_trySplit = 1;
3427       G1.f_tryShift = 1;
3428       scoreA = group[i].bit * group[i].num + xFactor;
3429       scoreA += group[i - 1].bit * group[i - 1].num + xFactor;
3430       scoreB = G1.bit * G1.num + xFactor;
3431       if (scoreB < scoreA) {
3432          /* One of the groups evaporated. */
3433          evaporate++;
3434          group[i - 1] = G1;
3435          group[i].num = 0;
3436          /* See if that affects any of the previous groups. */
3437          for (j = i + 1; j < numGroup; j++) {
3438             if (group[j].num != 0) {
3439                /*G1.start = G1. start;*/ /* self-assignment... */
3440                G1.num = group[i - 1].num + group[j].num;
3441                G1.min = (group[i - 1].min < group[j].min) ?
3442                      group[i - 1].min : group[j].min;
3443                G1.max = (group[i - 1].max > group[j].max) ?
3444                      group[i - 1].max : group[j].max;
3445                G1.bit = (char) power ((uInt4) (G1.max - G1.min),
3446                                       f_secMiss + f_primMiss);
3447                G1.f_trySplit = 1;
3448                G1.f_tryShift = 1;
3449                scoreA = group[i - 1].bit * group[i - 1].num + xFactor;
3450                scoreA += group[j].bit * group[j].num + xFactor;
3451                scoreB = G1.bit * G1.num + xFactor;
3452                if (scoreB < scoreA) {
3453                   evaporate++;
3454                   group[i - 1] = G1;
3455                   group[j].num = 0;
3456                } else {
3457                   break;
3458                }
3459             }
3460          }
3461       } else if (group[i].f_tryShift) {
3462          /* Group did not evaporate, so do the "grabby" algorithm. */
3463          if ((group[i].bit != 0) && (group[i - 1].bit >= group[i].bit)) {
3464             if (f_secMiss) {
3465                A_max = group[i].max;
3466                A_min = group[i].min;
3467                shiftGroup2 (Data, group[i].start - 1, group[i - 1].start,
3468                             li_primMiss, li_secMiss, group[i].bit, &A_min,
3469                             &A_max, &begin);
3470             } else if (f_primMiss) {
3471                A_max = group[i].max;
3472                A_min = group[i].min;
3473                shiftGroup1 (Data, group[i].start - 1, group[i - 1].start,
3474                             li_primMiss, group[i].bit, &A_min, &A_max,
3475                             &begin);
3476             } else {
3477                A_max = group[i].max;
3478                A_min = group[i].min;
3479                shiftGroup0 (Data, group[i].start - 1, group[i - 1].start,
3480                             group[i].bit, &A_min, &A_max, &begin);
3481             }
3482             if (begin != group[i].start) {
3483                /* Re-Calculate min/max of group[i - 1], since it could have
3484                 * moved to group[i] */
3485                G1 = group[i - 1];
3486                G2 = group[i];
3487                G2.min = A_min;
3488                G2.max = A_max;
3489                G1.num -= static_cast<uInt4>(group[i].start - begin);
3490                if (f_secMiss) {
3491                   findMaxMin2 (Data, G1.start, G1.start + G1.num,
3492                                li_primMiss, li_secMiss, &A_min, &A_max);
3493                } else if (f_primMiss) {
3494                   findMaxMin1 (Data, G1.start, G1.start + G1.num,
3495                                li_primMiss, &A_min, &A_max);
3496                } else {
3497                   findMaxMin0 (Data, G1.start, G1.start + G1.num,
3498                                &A_min, &A_max);
3499                }
3500                if ((A_min != G1.min) || (A_max != G1.max)) {
3501                   G1.min = A_min;
3502                   G1.max = A_max;
3503                   G1.bit = (char) power ((uInt4) (A_max - A_min),
3504                                          f_secMiss + f_primMiss);
3505                   G1.f_trySplit = 1;
3506                   G1.f_tryShift = 1;
3507                }
3508                G2.num += static_cast<uInt4>(group[i].start - begin);
3509                G2.start = static_cast<uInt4>(begin);
3510                G2.f_trySplit = 1;
3511                G2.f_tryShift = 1;
3512                scoreA = group[i].bit * group[i].num + xFactor;
3513                scoreA += group[i - 1].bit * group[i - 1].num + xFactor;
3514                scoreB = G2.bit * G2.num + xFactor;
3515                if (G1.num != 0) {
3516                   scoreB += G1.bit * G1.num + xFactor;
3517                }
3518 #ifdef DEBUG
3519                if (scoreB > scoreA) {
3520                   printf ("Made score worse!\n");
3521                }
3522 #endif
3523                if (begin == group[i - 1].start) {
3524                   /* Grabby algorithm evaporated a group. */
3525                   evaporate++;
3526                   myAssert (G1.num == 0);
3527                   /* Switch the evaporating group to other side so we have
3528                    * potential to continue evaporating the next group down. */
3529                   group[i - 1] = G2;
3530                   group[i] = G1;
3531                } else {
3532                   group[i - 1] = G1;
3533                   group[i] = G2;
3534                }
3535             } else {
3536                group[i].f_tryShift = 0;
3537             }
3538          }
3539       }
3540    }
3541    /* Loop through the grid removing the evaporated groups. */
3542    if (evaporate != 0) {
3543       index = 0;
3544       for (i = 0; i < numGroup; i++) {
3545          if (group[i].num != 0) {
3546             group[index] = group[i];
3547             index++;
3548          }
3549       }
3550       *NumGroup = numGroup - evaporate;
3551       *Group = (TDLGroupType *) realloc ((void *) (*Group),
3552                                          *NumGroup * sizeof (TDLGroupType));
3553    }
3554 }
3555 
3556 /*****************************************************************************
3557  * GroupIt() --
3558  *
3559  * Arthur Taylor / MDL
3560  *
3561  * PURPOSE
3562  *   Attempts to find groups for packing the data.  It starts by preparing
3563  * the data, by removing the overall min value.
3564  *
3565  *   Next it Creates any 0 bit groups (primary missing: missing are all 0
3566  * bit groups, const values are 0 bit groups.  No missing: const values are
3567  * 0 bit groups.)
3568  *
3569  *   Next it tries to reduce (split) each group by 1 bit.  It does this by:
3570  *   A) reduce the "bit range", and create groups that grab as much as they
3571  * can to the right.  Then reduce those groups if they improve the score.
3572  *   B) reduce the bit range and grab the left most group only, leaving the
3573  * rest unchanged.
3574  *   C) reduce the bit range and grab the right most group only, leaving the
3575  * rest unchanged.
3576  *
3577  *   Next it tries to shift / join those groups together.  It does this by
3578  * first calculating if a group should still exist.  If it should, then it
3579  * has each group grab as much as it can to the left without increasing its
3580  * "bit range".
3581  *
3582  * ARGUMENTS
3583  *  OverallMin = The overall min value in the data. (Input)
3584  *        Data = The data. (Input)
3585  *     numData = The number of elements in data. (Input)
3586  *       group = The resulting groups. (Output)
3587  *    numGroup = Number of groups (Output)
3588  *  f_primMiss = Flag if we have a primary missing value (Input)
3589  * li_primMiss = scaled primary missing value (Input)
3590  *   f_secMiss = Flag if we have a secondary missing value (Input)
3591  *  li_secMiss = scaled secondary missing value (Input)
3592  *   groupSize = How many bytes the groups and data will take. (Output)
3593  *        ibit = # of bits for largest minimum value in groups (Output)
3594  *        jbit = # of bits for largest # bits in groups (Output)
3595  *        kbit = # of bits for largest # values in groups (Output)
3596  *
3597  * FILES/DATABASES: None
3598  *
3599  * RETURNS: void
3600  *
3601  * HISTORY
3602  *  1/2005 Arthur Taylor (MDL): Created.
3603  *
3604  * NOTES
3605  *  1) Have not implemented const 0 bit groups for prim miss or no miss.
3606  *  2) MAX_GROUP_LEN (found experimentally) is useful to keep cost of groups
3607  *     down.
3608  *****************************************************************************
3609  */
3610 #define MAX_GROUP_LEN 255
3611 static void GroupIt (sInt4 OverallMin, sInt4 *Data, size_t numData,
3612                      TDLGroupType ** group, size_t *numGroup, char f_primMiss,
3613                      sInt4 li_primMiss, char f_secMiss,
3614                      sInt4 li_secMiss, sInt4 *groupSize, size_t *ibit,
3615                      size_t *jbit, size_t *kbit)
3616 {
3617    sInt4 A_max;         /* Max value of a given group. */
3618    sInt4 A_min;         /* Min value of a given group. */
3619    TDLGroupType G;      /* Used to init the groups. */
3620    int f_adjust;        /* Flag if we have changed the groups. */
3621    TDLGroupType *lclGroup; /* A temporary copy of the groups. */
3622    int numLclGroup;     /* # of groups in lclGroup. */
3623    size_t xFactor;      /* Estimate of cost (in bits) of a group. */
3624    size_t i;            /* loop counter. */
3625 
3626    /* Subtract the Overall Min Value. */
3627    if (OverallMin != 0) {
3628       if (f_secMiss) {
3629          for (i = 0; i < numData; i++) {
3630             if ((Data[i] != li_secMiss) && (Data[i] != li_primMiss)) {
3631                Data[i] -= OverallMin;
3632                // Check if we accidentally adjusted to prim or sec, if so add 1.
3633                if ((Data[i] == li_secMiss) || (Data[i] == li_primMiss)) {
3634                   myAssert (0);
3635                   Data[i]++;
3636                   if ((Data[i] == li_secMiss) || (Data[i] == li_primMiss)) {
3637                      myAssert (0);
3638                      Data[i]++;
3639                   }
3640                }
3641             }
3642          }
3643       } else if (f_primMiss) {
3644          for (i = 0; i < numData; i++) {
3645             if (Data[i] != li_primMiss) {
3646                Data[i] -= OverallMin;
3647                // Check if we accidentally adjusted to prim or sec, if so add 1.
3648                if (Data[i] == li_primMiss) {
3649                   myAssert (0);
3650                   Data[i]++;
3651                }
3652             }
3653          }
3654       } else {
3655          for (i = 0; i < numData; i++) {
3656             Data[i] -= OverallMin;
3657          }
3658       }
3659    }
3660 
3661    myAssert ((f_secMiss == 0) || (f_secMiss == 1));
3662    myAssert ((f_primMiss == 0) || (f_primMiss == 1));
3663 
3664    /* Create zero groups. */
3665    *numGroup = 0;
3666    *group = NULL;
3667    if (f_primMiss) {
3668       G.min = Data[0];
3669       G.max = Data[0];
3670       G.num = 1;
3671       G.start = 0;
3672       for (i = 1; i < numData; i++) {
3673          if (G.min == li_primMiss) {
3674             if (Data[i] == li_primMiss) {
3675                G.num++;
3676                if (G.num == (MAX_GROUP_LEN + 1)) {
3677                   /* Close a missing group */
3678                   G.f_trySplit = 0;
3679                   G.f_tryShift = 1;
3680                   G.bit = 0;
3681                   G.min = 0;
3682                   G.max = 0;
3683                   G.num = MAX_GROUP_LEN;
3684                   (*numGroup)++;
3685                   *group = (TDLGroupType *) realloc ((void *) *group,
3686                                                      *numGroup *
3687                                                      sizeof (TDLGroupType));
3688                   (*group)[(*numGroup) - 1] = G;
3689                   /* Init a missing group. */
3690                   G.min = Data[i];
3691                   G.max = Data[i];
3692                   G.num = 1;
3693                   G.start = static_cast<uInt4>(i);
3694                }
3695             } else {
3696                /* Close a missing group */
3697                G.f_trySplit = 0;
3698                G.f_tryShift = 1;
3699                G.bit = 0;
3700                G.min = 0;
3701                G.max = 0;
3702                (*numGroup)++;
3703                *group = (TDLGroupType *) realloc ((void *) *group,
3704                                                   *numGroup *
3705                                                   sizeof (TDLGroupType));
3706                (*group)[(*numGroup) - 1] = G;
3707                /* Init a non-missing group. */
3708                G.min = Data[i];
3709                G.max = Data[i];
3710                G.num = 1;
3711                G.start = static_cast<uInt4>(i);
3712             }
3713          } else {
3714             if (Data[i] == li_primMiss) {
3715                /* Close a non-missing group */
3716                G.f_trySplit = 1;
3717                G.f_tryShift = 1;
3718                G.bit = (char) power ((uInt4) (G.max - G.min),
3719                                      f_secMiss + f_primMiss);
3720                myAssert (G.bit != 0);
3721                if ((G.min == 0) && (G.bit == 0) && (f_primMiss == 1)) {
3722                   printf ("Warning: potential confusion between const value "
3723                           "and prim-missing.\n");
3724                   G.bit = 1;
3725                }
3726                (*numGroup)++;
3727                *group = (TDLGroupType *) realloc ((void *) *group,
3728                                                   *numGroup *
3729                                                   sizeof (TDLGroupType));
3730                (*group)[(*numGroup) - 1] = G;
3731                /* Init a missing group. */
3732                G.min = Data[i];
3733                G.max = Data[i];
3734                G.num = 1;
3735                G.start = static_cast<uInt4>(i);
3736             } else {
3737                if (G.min > Data[i]) {
3738                   G.min = Data[i];
3739                } else if (G.max < Data[i]) {
3740                   G.max = Data[i];
3741                }
3742                G.num++;
3743             }
3744          }
3745       }
3746       if (G.min == li_primMiss) {
3747          /* Close a missing group */
3748          G.f_trySplit = 0;
3749          G.f_tryShift = 1;
3750          G.bit = 0;
3751          G.min = 0;
3752          G.max = 0;
3753          (*numGroup)++;
3754          *group = (TDLGroupType *) realloc ((void *) *group,
3755                                             *numGroup *
3756                                             sizeof (TDLGroupType));
3757          (*group)[(*numGroup) - 1] = G;
3758       } else {
3759          /* Close a non-missing group */
3760          G.f_trySplit = 1;
3761          G.f_tryShift = 1;
3762          G.bit = (char) power ((uInt4) (G.max - G.min),
3763                                f_secMiss + f_primMiss);
3764          myAssert (G.bit != 0);
3765          if ((G.min == 0) && (G.bit == 0) && (f_primMiss == 1)) {
3766             printf ("Warning: potential confusion between const value and "
3767                     "prim-missing.\n");
3768             G.bit = 1;
3769          }
3770          (*numGroup)++;
3771          *group = (TDLGroupType *) realloc ((void *) *group,
3772                                             *numGroup *
3773                                             sizeof (TDLGroupType));
3774          (*group)[(*numGroup) - 1] = G;
3775       }
3776    } else {
3777       /* Already handled the f_primMiss case */
3778       if (f_secMiss) {
3779          findMaxMin2 (Data, 0, static_cast<int>(numData), li_primMiss, li_secMiss, &A_min,
3780                       &A_max);
3781       } else {
3782          findMaxMin0 (Data, 0, static_cast<int>(numData), &A_min, &A_max);
3783       }
3784       G.start = 0;
3785       G.num = static_cast<uInt4>(numData);
3786       G.min = A_min;
3787       G.max = A_max;
3788       G.bit = (char) power ((uInt4) (A_max - A_min), f_secMiss + f_primMiss);
3789       G.f_trySplit = 1;
3790       G.f_tryShift = 1;
3791       *numGroup = 1;
3792       *group = (TDLGroupType *) malloc (sizeof (TDLGroupType));
3793       (*group)[0] = G;
3794    }
3795 
3796    lclGroup = NULL;
3797    numLclGroup = 0;
3798    *groupSize = ComputeGroupSize (*group, static_cast<int>(*numGroup), ibit, jbit, kbit);
3799    xFactor = *ibit + *jbit + *kbit;
3800 #ifdef DEBUG
3801 /*
3802    printf ("NumGroup = %d: Bytes = %ld: XFactor %d\n", *numGroup,
3803            (*groupSize / 8) + 1, xFactor);
3804 */
3805 #endif
3806 
3807    f_adjust = 1;
3808    while (f_adjust) {
3809       f_adjust = splitGroup (Data, static_cast<int>(numData), *group, static_cast<int>(*numGroup), &lclGroup,
3810                              &numLclGroup, f_primMiss, li_primMiss,
3811                              f_secMiss, li_secMiss, xFactor);
3812       free (*group);
3813       *group = lclGroup;
3814       *numGroup = numLclGroup;
3815 
3816       if (f_adjust) {
3817          shiftGroup (Data, static_cast<int>(numData), group, numGroup, f_primMiss,
3818                      li_primMiss, f_secMiss, li_secMiss, static_cast<int>(xFactor));
3819          *groupSize = ComputeGroupSize (*group, static_cast<int>(*numGroup), ibit, jbit, kbit);
3820          if (xFactor != *ibit + *jbit + *kbit) {
3821             for (i = 0; i < *numGroup; i++) {
3822                if (((*group)[i].num > *ibit + *jbit + *kbit) &&
3823                    ((*group)[i].num <= xFactor)) {
3824                   (*group)[i].f_trySplit = 1;
3825                }
3826             }
3827          }
3828          xFactor = *ibit + *jbit + *kbit;
3829 #ifdef DEBUG
3830 /*
3831          printf ("NumGroup = %d: Bytes = %ld: XFactor %d\n", *numGroup,
3832                  (*groupSize / 8) + 1, xFactor);
3833          fflush (stdout);
3834 */
3835 #endif
3836       }
3837    }
3838 }
3839 
3840 /*****************************************************************************
3841  * GroupPack() --
3842  *
3843  * Arthur Taylor / MDL
3844  *
3845  * PURPOSE
3846  *   To compute groups for packing the data using complex or second order
3847  * complex packing.
3848  *
3849  * ARGUMENTS
3850  *        Src = The original data. (Input)
3851  *        Dst = The scaled data. (Output)
3852  *    numData = The number of elements in data. (Input)
3853  *        DSF = Decimal Scale Factor for scaling the data. (Input)
3854  *        BSF = Binary Scale Factor for scaling the data. (Input)
3855  * f_primMiss = Flag saying if we have a primary missing value (In/Out)
3856  *   primMiss = primary missing value. (In/Out)
3857  *  f_secMiss = Flag saying if we have a secondary missing value (In/Out)
3858  *    secMiss = secondary missing value. (In/Out)
3859  *     f_grid = Flag if this is grid data (or vector) (Input)
3860  *         NX = The number of X values. (Input)
3861  *         NY = The number of Y values. (Input)
3862  * f_sndOrder = Flag if we should do second order differencing (Output)
3863  *      group = Resulting groups. (Output)
3864  *   numGroup = Number of groups. (Output)
3865  *        Min = Overall minimum. (Output)
3866  *         a1 = if f_sndOrder, the first first order difference (Output)
3867  *         b2 = if f_sndOrder, the first second order difference (Output)
3868  *  groupSize = How many bytes the groups and data will take. (Output)
3869  *       ibit = # of bits for largest minimum value in groups (Output)
3870  *       jbit = # of bits for largest # bits in groups (Output)
3871  *       kbit = # of bits for largest # values in groups (Output)
3872  *
3873  * FILES/DATABASES: None
3874  *
3875  * RETURNS: int (could use errSprintf())
3876  *   0 = OK
3877  *  -1 = Primary or Secondary missing value == 0.
3878  *
3879  * HISTORY
3880  *  12/2004 Arthur Taylor (MDL): Updated from "group.c" in "C" tdlpack code.
3881  *   1/2005 AAT: Cleaned up.
3882  *
3883  * NOTES
3884  *****************************************************************************
3885  */
3886 static int GroupPack (double *Src, sInt4 **Dst, sInt4 numData,
3887                       int DSF, int BSF, char *f_primMiss, double *primMiss,
3888                       char *f_secMiss, double *secMiss, char f_grid,
3889                       short int NX, short int NY, char *f_sndOrder,
3890                       TDLGroupType ** group, size_t *numGroup,
3891                       sInt4 *Min, sInt4 *a1, sInt4 *b2,
3892                       sInt4 *groupSize, size_t *ibit, size_t *jbit,
3893                       size_t *kbit)
3894 {
3895    sInt4 *SecDiff = NULL; /* Consists of the 2nd order differences if *
3896                            * requested. */
3897    sInt4 *Data;         /* The scaled data. */
3898    char f_min;          /* Flag saying overallMin is valid. */
3899    sInt4 overallMin = 0;    /* The overall min of the scaled data. */
3900    sInt4 secMin;        /* The overall min of the 2nd order differences */
3901    sInt4 li_primMiss = 0; /* The scaled primary missing value */
3902    sInt4 li_secMiss = 0; /* The scaled secondary missing value */
3903    int minGroup = 20;   /* The minimum group size. Equivalent to xFactor?
3904                          * Chose 20 because that was a good estimate of
3905                          * XFactor. */
3906 
3907    /* Check consistency of f_primMiss and f_secMiss. */
3908    if (*primMiss == *secMiss) {
3909       *f_secMiss = 0;
3910    }
3911    if ((*f_secMiss) && (!(*f_primMiss))) {
3912       *f_primMiss = *f_secMiss;
3913       *primMiss = *secMiss;
3914       *f_secMiss = 0;
3915    }
3916    if (*f_secMiss && (*secMiss == 0)) {
3917       errSprintf ("Error: Secondary missing value not allowed to = 0.\n");
3918       return -1;
3919    }
3920    if (*f_primMiss && (*primMiss == 0)) {
3921       errSprintf ("Error: Primary missing value not allowed to = 0.\n");
3922       return -1;
3923    }
3924 
3925    /* Check minGroup size. */
3926    if (minGroup > numData) {
3927       minGroup = numData;
3928    }
3929 
3930    /* Scale the data and check if we can change f_prim or f_sec. */
3931    /* Note: if we use sec_diff, we have a different overall min. */
3932    f_min = 0;
3933    Data = (sInt4 *) malloc (numData * sizeof (sInt4));
3934    TDL_ScaleData (Src, Data, numData, DSF, BSF, f_primMiss, primMiss,
3935                   f_secMiss, secMiss, &f_min, &overallMin);
3936    /* Note: ScaleData also scales missing values. */
3937    if (*f_primMiss) {
3938       li_primMiss = (sInt4) (*primMiss * SCALE_MISSING + .5);
3939    }
3940    if (*f_secMiss) {
3941       li_secMiss = (sInt4) (*secMiss * SCALE_MISSING + .5);
3942    }
3943 
3944    /* Reason this is after TDL_ScaleData is we don't want to reorder the
3945     * caller's copy of the data. */
3946    if (f_grid) {
3947       TDL_ReorderGrid (Data, NX, NY);
3948    } else {
3949       /* TDLPack requires the following (see pack2d.f and pack1d.f) */
3950       *f_sndOrder = 0;
3951    }
3952    /* TDLPack requires the following (see pack2d.f) */
3953    if (*f_secMiss) {
3954       *f_sndOrder = 0;
3955    }
3956    /* If overallMin is "invalid" then they are all prim or sec values. */
3957    /* See pack2d.f line 336 */
3958    /* IF ALL VALUES ARE MISSING, JUST PACK; DON'T CONSIDER 2ND ORDER
3959     * DIFFERENCES. */
3960    if (!f_min) {
3961       *f_sndOrder = 0;
3962    }
3963 
3964    /* This has to be after TDL_ReorderGrid */
3965    if (*f_sndOrder) {
3966       SecDiff = (sInt4 *) malloc (numData * sizeof (sInt4));
3967       if (TDL_GetSecDiff (Data, numData, SecDiff, *f_primMiss, li_primMiss,
3968                           a1, b2, &secMin)) {
3969          /* Problem finding SecDiff, so we don't bother with it. */
3970          *f_sndOrder = 0;
3971       } else {
3972          /* Check if it is worth doing second order differences. */
3973          if (*f_primMiss) {
3974             *f_sndOrder = TDL_UseSecDiff_Prim (Data, numData, SecDiff,
3975                                                li_primMiss, minGroup);
3976          } else {
3977             *f_sndOrder = TDL_UseSecDiff (Data, numData, SecDiff, minGroup);
3978          }
3979       }
3980    }
3981 
3982    /* Side affect of GroupIt2: it subtracts OverallMin from Data. */
3983    if (!(*f_sndOrder)) {
3984       GroupIt (overallMin, Data, numData, group, numGroup, *f_primMiss,
3985                li_primMiss, *f_secMiss, li_secMiss, groupSize, ibit, jbit,
3986                kbit);
3987       *Min = overallMin;
3988       *a1 = 0;
3989       *b2 = 0;
3990       *Dst = Data;
3991       free (SecDiff);
3992    } else {
3993       GroupIt (secMin, SecDiff, numData, group, numGroup, *f_primMiss,
3994                li_primMiss, *f_secMiss, li_secMiss, groupSize, ibit, jbit,
3995                kbit);
3996       *Min = secMin;
3997       *Dst = SecDiff;
3998       free (Data);
3999    }
4000    return 0;
4001 }
4002 
4003 /*****************************************************************************
4004  * WriteTDLPRecord() --
4005  *
4006  * Arthur Taylor / MDL
4007  *
4008  * PURPOSE
4009  *   Writes a TDLP message to file.
4010  *
4011  * ARGUMENTS
4012  *         fp = An opened TDLP file already at the correct location. (Input)
4013  *       Data = The data to write. (Input)
4014  *    DataLen = Length of Data. (Input)
4015  *        DSF = Decimal scale factor to apply to the data (Input)
4016  *        BSF = Binary scale factor to apply to the data (Input)
4017  * f_primMiss = Flag saying if we have a primary missing value (Input)
4018  *   primMiss = primary missing value. (Input)
4019  *  f_secMiss = Flag saying if we have a secondary missing value (Input)
4020  *    secMiss = secondary missing value. (Input)
4021  *        gds = The grid definition section (Input)
4022  *    comment = Describes the kind of data (max 32 bytes). (Input)
4023  *    refTime = The reference (creation) time of this message. (Input)
4024  *        ID1 = TDLPack ID1 (Input)
4025  *        ID2 = TDLPack ID2 (Input)
4026  *        ID3 = TDLPack ID3 (Input)
4027  *        ID4 = TDLPack ID4 (Input)
4028  *    projSec = The projection in seconds (Input)
4029  * processNum = The process number that created it (Input)
4030  *     seqNum = The sequence number that created it (Input)
4031  *
4032  * FILES/DATABASES:
4033  *   An already opened file pointing to the desired TDLP message.
4034  *
4035  * RETURNS: int (could use errSprintf())
4036  *   0 = OK
4037  *  -1 = comment is too long.
4038  *  -2 = projHr is inconsistent with ID3.
4039  *  -3 = Type of map projection that TDLP can't handle.
4040  *  -4 = Primary or Secondary missing value == 0.
4041  *
4042  * HISTORY
4043  *  12/2004 Arthur Taylor (MDL): Created
4044  *   1/2005 AAT: Cleaned up.
4045  *
4046  * NOTES
4047  *****************************************************************************
4048  */
4049 int WriteTDLPRecord (FILE * fp, double *Data, sInt4 DataLen, int DSF,
4050                      int BSF, char f_primMiss, double primMiss,
4051                      char f_secMiss, double secMiss, gdsType *gds,
4052                      char *comment, double refTime, sInt4 ID1,
4053                      sInt4 ID2, sInt4 ID3, sInt4 ID4,
4054                      sInt4 projSec, sInt4 processNum, sInt4 seqNum)
4055 {
4056    sInt4 *Scaled;       /* The scaled data. */
4057    TDLGroupType *group; /* The groups used to pack the data. */
4058    size_t numGroup;     /* Number of groups. */
4059    char f_grid = 1;     /* Flag if this is gridded data. In theory can handle
4060                          * vector data, but haven't tested it. */
4061    char f_sndOrder;     /* Flag if we should try second order packing. */
4062 
4063    /* TODO: Trace overallMin to figure out how it could be used uninitialized */
4064    sInt4 overallMin;    /* Overall min value of the scaled data. */
4065 
4066    sInt4 a1;            /* 2nd order difference: 1st value. */
4067    sInt4 b2;            /* 2nd order difference: 1st 1st order difference */
4068    sInt4 li_primMiss;   /* Scaled primary missing value. */
4069    sInt4 li_secMiss;    /* Scaled secondary missing value. */
4070    int mbit;            /* # of bits for b2. */
4071    int nbit;            /* # of bits for overallMin. */
4072    size_t ibit;         /* # of bits for largest minimum value in groups */
4073    size_t jbit;         /* # of bits for largest # bits in groups */
4074    size_t kbit;         /* # of bits for largest # values in groups */
4075    int sec1Len;         /* Length of section 1. */
4076    size_t pad;          /* Number of bytes to pad the message to get to the
4077                          * correct byte boundary. */
4078    sInt4 groupSize;     /* How many bytes the groups and data will take. */
4079    sInt4 sec4Len;       /* Length of section 4. */
4080    sInt4 tdlRecSize;    /* Size of the TDLP message. */
4081    sInt4 recSize;       /* Actual record size (including FORTRAN bytes). */
4082    int commentLen;      /* Length of comment */
4083    short int projHr;    /* The hours part of the forecast projection. */
4084    char projMin;        /* The minutes part of the forecast projection. */
4085    sInt4 year;          /* The reference year. */
4086    int month, day;      /* The reference month day. */
4087    int hour, min;       /* The reference hour minute. */
4088    double sec;          /* The reference second. */
4089    char f_bitmap = 0;   /* Bitmap flag: not implemented in specs. */
4090 #ifdef always_true
4091    char f_simple = 0;   /* Simple Pack flag: not implemented in specs. */
4092 #endif
4093    int gridType;        /* Which type of grid. (Polar, Mercator, Lambert). */
4094    int dataCnt;         /* Keeps track of which element we are writing. */
4095    sInt4 max0;          /* The max value in a group.  Represents primary or *
4096                          * secondary missing value depending on scheme. */
4097    sInt4 max1;          /* The next to max value in a group.  Represents *
4098                          * secondary missing value. */
4099    size_t i, j;         /* loop counters */
4100    sInt4 li_temp;       /* Temporary variable (sInt4). */
4101    short int si_temp;   /* Temporary variable (short int). */
4102    double d_temp;       /* Temporary variable (double). */
4103    char buffer[6];      /* Used to write reserved values */
4104    uChar pbuf;          /* A buffer of bits that were not written to disk */
4105    sChar pbufLoc;       /* Where in pbuf to add more bits. */
4106 
4107    commentLen = static_cast<int>(strlen (comment));
4108    if (commentLen > 32) {
4109       errSprintf ("Error: '%s' is > 32 bytes long\n", comment);
4110       return -1;
4111    }
4112    projHr = projSec / 3600;
4113    projMin = (projSec % 3600) / 60;
4114    if (projHr != (ID3 - ((ID3 / 1000) * 1000))) {
4115       errSprintf ("Error: projHr = %d is inconsistent with ID3 = %ld\n",
4116                   projHr, ID3);
4117       return -2;
4118    }
4119    if (f_grid) {
4120       switch (gds->projType) {
4121          case GS3_POLAR:
4122             gridType = TDLP_POLAR;
4123             break;
4124          case GS3_LAMBERT:
4125             gridType = TDLP_LAMBERT;
4126             break;
4127          case GS3_MERCATOR:
4128             gridType = TDLP_MERCATOR;
4129             break;
4130          default:
4131             errSprintf ("TDLPack can't handle GRIB projection type %d\n",
4132                         gds->projType);
4133             return -3;
4134       }
4135    }
4136 
4137    if (GroupPack (Data, &Scaled, DataLen, DSF, BSF, &f_primMiss, &primMiss,
4138                   &f_secMiss, &secMiss, f_grid, gds->Nx, gds->Ny,
4139                   &f_sndOrder, &group, &numGroup, &overallMin, &a1, &b2,
4140                   &groupSize, &ibit, &jbit, &kbit) != 0) {
4141       return -4;
4142    }
4143 
4144    /* Make sure missing data is properly scaled. */
4145    if (f_primMiss) {
4146       li_primMiss = (sInt4) (primMiss * SCALE_MISSING + .5);
4147    }
4148    if (f_secMiss) {
4149       li_secMiss = (sInt4) (secMiss * SCALE_MISSING + .5);
4150    }
4151 
4152    /* Compute TDL record size. */
4153 /* *INDENT-OFF* */
4154    /* TDL Record size
4155     * 8 (section 0),
4156     * 39 + strlen(comment) (section 1),
4157     * 0 or 28 (depending on if you have a section 2),
4158     * 0 (section 3),
4159     * 16 + 5 + 1 + nbit(min val) + 16 + 5 + 5 + 5 + GroupSize() (section 4)
4160     * 4 (section 5)
4161     * pad (to even 8 bytes...)
4162     * Group size uses:
4163     *    ibit * num_groups + jbit * num_groups +
4164     *    kbit * num_groups + group.nbit * group.nvalues */
4165 /* *INDENT-ON*  */
4166    sec1Len = 39 + commentLen;
4167    if (overallMin < 0) {
4168       nbit = power (-1 * overallMin, 0);
4169    } else {
4170       nbit = power (overallMin, 0);
4171    }
4172    if (!f_sndOrder) {
4173       if (f_secMiss) {
4174          sec4Len = 16 + (sInt4) (ceil ((5 + 1 + nbit + 16 + 5 + 5 + 5
4175                                         + groupSize) / 8.));
4176       } else if (f_primMiss) {
4177          sec4Len = 12 + (sInt4) (ceil ((5 + 1 + nbit + 16 + 5 + 5 + 5
4178                                         + groupSize) / 8.));
4179       } else {
4180          sec4Len = 8 + (sInt4) (ceil ((5 + 1 + nbit + 16 + 5 + 5 + 5
4181                                        + groupSize) / 8.));
4182       }
4183    } else {
4184       if (b2 < 0) {
4185          mbit = power (-1 * b2, 0);
4186       } else {
4187          mbit = power (b2, 0);
4188       }
4189       if (f_secMiss) {
4190          sec4Len =
4191                16 +
4192                (sInt4) (ceil
4193                         ((32 + 5 + 1 + mbit + 5 + 1 + nbit + 16 + 5 + 5 + 5 +
4194                           groupSize) / 8.));
4195       } else if (f_primMiss) {
4196          sec4Len =
4197                12 +
4198                (sInt4) (ceil
4199                         ((32 + 5 + 1 + mbit + 5 + 1 + nbit + 16 + 5 + 5 + 5 +
4200                           groupSize) / 8.));
4201       } else {
4202          sec4Len =
4203                8 +
4204                (sInt4) (ceil
4205                         ((32 + 5 + 1 + mbit + 5 + 1 + nbit + 16 + 5 + 5 + 5 +
4206                           groupSize) / 8.));
4207       }
4208    }
4209    if (f_grid) {
4210       tdlRecSize = 8 + sec1Len + 28 + 0 + sec4Len + 4;
4211    } else {
4212       tdlRecSize = 8 + sec1Len + 0 + 0 + sec4Len + 4;
4213    }
4214    /* Actual recSize is 8 + round(tdlRecSize) to nearest 8 byte boundary. */
4215    recSize = 8 + (sInt4) (ceil (tdlRecSize / 8.0)) * 8;
4216    pad = (int) ((recSize - 8) - tdlRecSize);
4217 
4218    /* --- Start Writing record. --- */
4219    /* First write FORTRAN record information */
4220    FWRITE_BIG (&(recSize), sizeof (sInt4), 1, fp);
4221    li_temp = 0;
4222    FWRITE_BIG (&(li_temp), sizeof (sInt4), 1, fp);
4223    li_temp = recSize - 8; /* FORTRAN rec length. */
4224    FWRITE_BIG (&(li_temp), sizeof (sInt4), 1, fp);
4225 
4226    /* Now write section 0. */
4227    fwrite ("TDLP", sizeof (char), 4, fp);
4228    FWRITE_ODDINT_BIG (&(tdlRecSize), 3, fp);
4229    /* version number */
4230    fputc (0, fp);
4231 
4232    /* Now write section 1. */
4233    fputc (sec1Len, fp);
4234    /* output type specification... */
4235    i = 0;
4236    if (f_grid) {
4237       i |= 1;
4238    }
4239    if (f_bitmap) {
4240       i |= 2;
4241    }
4242    fputc (static_cast<int>(i), fp);
4243 /*   tempTime = gmtime (&(refTime));*/
4244    Clock_PrintDate (refTime, &year, &month, &day, &hour, &min, &sec);
4245 /* year = tempTime->tm_year + 1900;
4246    month = tempTime->tm_mon + 1;
4247    day = tempTime->tm_mday;
4248    hour = tempTime->tm_hour;
4249    min = tempTime->tm_min;
4250 */
4251    si_temp = year;
4252    FWRITE_BIG (&si_temp, sizeof (short int), 1, fp);
4253    fputc (month, fp);
4254    fputc (day, fp);
4255    fputc (hour, fp);
4256    fputc (min, fp);
4257    li_temp = (year * 1000000 + month * 10000 + day * 100 + hour);
4258    FWRITE_BIG (&li_temp, sizeof (sInt4), 1, fp);
4259    FWRITE_BIG (&ID1, sizeof (sInt4), 1, fp);
4260    FWRITE_BIG (&ID2, sizeof (sInt4), 1, fp);
4261    FWRITE_BIG (&ID3, sizeof (sInt4), 1, fp);
4262    FWRITE_BIG (&ID4, sizeof (sInt4), 1, fp);
4263    FWRITE_BIG (&projHr, sizeof (short int), 1, fp);
4264    fputc (projMin, fp);
4265    fputc (processNum, fp);
4266    fputc (seqNum, fp);
4267    i = (DSF < 0) ? 128 - DSF : DSF;
4268    fputc (static_cast<int>(i), fp);
4269    i = (BSF < 0) ? 128 - BSF : BSF;
4270    fputc (static_cast<int>(i), fp);
4271    /* Reserved: 3 bytes of 0. */
4272    li_temp = 0;
4273    fwrite (&li_temp, sizeof (char), 3, fp);
4274    fputc (commentLen, fp);
4275    fwrite (comment, sizeof (char), commentLen, fp);
4276 
4277    /* Now write section 2. */
4278    if (f_grid) {
4279       fputc (28, fp);
4280       fputc (gridType, fp);
4281       si_temp = gds->Nx;
4282       FWRITE_BIG (&si_temp, sizeof (short int), 1, fp);
4283       si_temp = gds->Ny;
4284       FWRITE_BIG (&si_temp, sizeof (short int), 1, fp);
4285       li_temp = (sInt4) (gds->lat1 * 10000. + .5);
4286       if (li_temp < 0) {
4287          pbuf = 128;
4288          li_temp = -1 * li_temp;
4289       } else {
4290          pbuf = 0;
4291       }
4292       pbufLoc = 7;
4293       fileBitWrite (&(li_temp), sizeof (li_temp), 23, fp, &pbuf, &pbufLoc);
4294       myAssert (pbufLoc == 8);
4295       myAssert (pbuf == 0);
4296       d_temp = 360 - gds->lon1;
4297       if (d_temp < 0)
4298          d_temp += 360;
4299       if (d_temp > 360)
4300          d_temp -= 360;
4301       li_temp = (sInt4) (d_temp * 10000. + .5);
4302       if (li_temp < 0) {
4303          pbuf = 128;
4304          li_temp = -1 * li_temp;
4305       }
4306       pbufLoc = 7;
4307       fileBitWrite (&(li_temp), sizeof (li_temp), 23, fp, &pbuf, &pbufLoc);
4308       myAssert (pbufLoc == 8);
4309       myAssert (pbuf == 0);
4310       d_temp = 360 - gds->orientLon;
4311       if (d_temp < 0)
4312          d_temp += 360;
4313       if (d_temp > 360)
4314          d_temp -= 360;
4315       li_temp = (sInt4) (d_temp * 10000. + .5);
4316       if (li_temp < 0) {
4317          pbuf = 128;
4318          li_temp = -1 * li_temp;
4319       }
4320       pbufLoc = 7;
4321       fileBitWrite (&(li_temp), sizeof (li_temp), 23, fp, &pbuf, &pbufLoc);
4322       myAssert (pbufLoc == 8);
4323       myAssert (pbuf == 0);
4324       li_temp = (sInt4) (gds->Dx * 1000. + .5);
4325       FWRITE_BIG (&li_temp, sizeof (sInt4), 1, fp);
4326       li_temp = (sInt4) (gds->meshLat * 10000. + .5);
4327       if (li_temp < 0) {
4328          pbuf = 128;
4329          li_temp = -1 * li_temp;
4330       }
4331       pbufLoc = 7;
4332       fileBitWrite (&(li_temp), sizeof (li_temp), 23, fp, &pbuf, &pbufLoc);
4333       myAssert (pbufLoc == 8);
4334       myAssert (pbuf == 0);
4335       memset (buffer, 0, 6);
4336       fwrite (buffer, sizeof (char), 6, fp);
4337    }
4338 
4339    /* Now write section 3. */
4340    /* Bitmap is not supported, skipping. */
4341    myAssert (!f_bitmap);
4342 
4343    /* Now write section 4. */
4344    FWRITE_ODDINT_BIG (&(sec4Len), 3, fp);
4345    i = 0;
4346    if (f_secMiss)
4347       i |= 1;
4348    if (f_primMiss)
4349       i |= 2;
4350    if (f_sndOrder)
4351       i |= 4;
4352 #ifdef always_true
4353    if (!f_simple)
4354 #endif
4355       i |= 8;
4356    if (!f_grid)
4357       i |= 16;
4358    fputc (static_cast<int>(i), fp);
4359    li_temp = DataLen;
4360    FWRITE_BIG (&li_temp, sizeof (sInt4), 1, fp);
4361    if (f_primMiss) {
4362       FWRITE_BIG (&(li_primMiss), sizeof (sInt4), 1, fp);
4363       if (f_secMiss) {
4364          FWRITE_BIG (&(li_secMiss), sizeof (sInt4), 1, fp);
4365       }
4366    }
4367    if (f_sndOrder) {
4368       if (a1 < 0) {
4369          pbuf = 128;
4370          li_temp = -1 * a1;
4371       } else {
4372          pbuf = 0;
4373          li_temp = a1;
4374       }
4375       pbufLoc = 7;
4376       fileBitWrite (&(li_temp), sizeof (li_temp), 31, fp, &pbuf, &pbufLoc);
4377       myAssert (pbufLoc == 8);
4378       myAssert (pbuf == 0);
4379       fileBitWrite (&mbit, sizeof (mbit), 5, fp, &pbuf, &pbufLoc);
4380       if (b2 < 0) {
4381          i = 1;
4382          li_temp = -1 * b2;
4383       } else {
4384          i = 0;
4385          li_temp = b2;
4386       }
4387       fileBitWrite (&i, sizeof (i), 1, fp, &pbuf, &pbufLoc);
4388       myAssert (pbufLoc == 2);
4389       fileBitWrite (&li_temp, sizeof (li_temp), (unsigned short int) mbit,
4390                     fp, &pbuf, &pbufLoc);
4391    }
4392    fileBitWrite (&nbit, sizeof (nbit), 5, fp, &pbuf, &pbufLoc);
4393    if (overallMin < 0) {
4394       i = 1;
4395       li_temp = -1 * overallMin;
4396    } else {
4397       i = 0;
4398       li_temp = overallMin;
4399    }
4400    fileBitWrite (&i, sizeof (i), 1, fp, &pbuf, &pbufLoc);
4401    fileBitWrite (&li_temp, sizeof (li_temp), (unsigned short int) nbit, fp,
4402                  &pbuf, &pbufLoc);
4403    fileBitWrite (&numGroup, sizeof (numGroup), 16, fp, &pbuf, &pbufLoc);
4404    fileBitWrite (&ibit, sizeof (ibit), 5, fp, &pbuf, &pbufLoc);
4405    fileBitWrite (&jbit, sizeof (jbit), 5, fp, &pbuf, &pbufLoc);
4406    fileBitWrite (&kbit, sizeof (kbit), 5, fp, &pbuf, &pbufLoc);
4407    for (i = 0; i < numGroup; i++) {
4408       fileBitWrite (&(group[i].min), sizeof (sInt4),
4409                     (unsigned short int) ibit, fp, &pbuf, &pbufLoc);
4410    }
4411    for (i = 0; i < numGroup; i++) {
4412       fileBitWrite (&(group[i].bit), sizeof (char),
4413                     (unsigned short int) jbit, fp, &pbuf, &pbufLoc);
4414    }
4415 #ifdef DEBUG
4416    li_temp = 0;
4417 #endif
4418    for (i = 0; i < numGroup; i++) {
4419       fileBitWrite (&(group[i].num), sizeof (sInt4),
4420                     (unsigned short int) kbit, fp, &pbuf, &pbufLoc);
4421 #ifdef DEBUG
4422       li_temp += group[i].num;
4423 #endif
4424    }
4425 #ifdef DEBUG
4426    /* Sanity check ! */
4427    if (li_temp != DataLen) {
4428       printf ("Total packed in groups %d != DataLen %d\n", li_temp,
4429               DataLen);
4430    }
4431    myAssert (li_temp == DataLen);
4432 #endif
4433 
4434    dataCnt = 0;
4435    /* Start going through the data. Grid data has already been reordered.
4436     * Already taken care of 2nd order differences. Data at this point should
4437     * contain a stream of either 2nd order differences or 0 order
4438     * differences. We have also removed overallMin from all non-missing
4439     * elements in the stream */
4440    if (f_secMiss) {
4441       for (i = 0; i < numGroup; i++) {
4442          max0 = (1 << group[i].bit) - 1;
4443          max1 = (1 << group[i].bit) - 2;
4444          for (j = 0; j < group[i].num; j++) {
4445             if (Scaled[dataCnt] == li_primMiss) {
4446                li_temp = max0;
4447             } else if (Scaled[dataCnt] == li_secMiss) {
4448                li_temp = max1;
4449             } else {
4450                li_temp = Scaled[dataCnt] - group[i].min;
4451             }
4452             fileBitWrite (&(li_temp), sizeof (sInt4), group[i].bit, fp,
4453                           &pbuf, &pbufLoc);
4454             dataCnt++;
4455          }
4456       }
4457    } else if (f_primMiss) {
4458       for (i = 0; i < numGroup; i++) {
4459          /* see what happens when bit == 0. */
4460          max0 = (1 << group[i].bit) - 1;
4461          for (j = 0; j < group[i].num; j++) {
4462             if (group[i].bit != 0) {
4463                if (Scaled[dataCnt] == li_primMiss) {
4464                   li_temp = max0;
4465                } else {
4466                   li_temp = Scaled[dataCnt] - group[i].min;
4467                }
4468                fileBitWrite (&(li_temp), sizeof (sInt4), group[i].bit, fp,
4469                              &pbuf, &pbufLoc);
4470             }
4471             dataCnt++;
4472          }
4473       }
4474    } else {
4475       for (i = 0; i < numGroup; i++) {
4476          for (j = 0; j < group[i].num; j++) {
4477             li_temp = Scaled[dataCnt] - group[i].min;
4478             if (group[i].bit != 0) {
4479                fileBitWrite (&(li_temp), sizeof (sInt4), group[i].bit, fp,
4480                              &pbuf, &pbufLoc);
4481             }
4482             dataCnt++;
4483          }
4484       }
4485    }
4486    myAssert (dataCnt == DataLen);
4487    /* flush the PutBit buffer... */
4488    if (pbufLoc != 8) {
4489       fputc ((int) pbuf, fp);
4490    }
4491 
4492    /* Now write section 5. */
4493    fwrite ("7777", sizeof (char), 4, fp);
4494 
4495    /* Deal with padding at end of record... */
4496    for (i = 0; i < pad; i++) {
4497       fputc (0, fp);
4498    }
4499    /* Now write FORTRAN record information */
4500    FWRITE_BIG (&(recSize), sizeof (sInt4), 1, fp);
4501 
4502    free (Scaled);
4503    free (group);
4504    return 0;
4505 }
4506 
4507 #endif // unused_by_GDAL
4508 #endif
4509 /* tdlpack is no longer supported by GDAL */
4510