1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "grib2.h"
4 
5 g2int getdim(unsigned char *,g2int *,g2int *,g2int *);
6 g2int getpoly(unsigned char *,g2int *,g2int *,g2int *);
7 void simpack(g2float *, g2int, g2int *, unsigned char *, g2int *);
8 void cmplxpack(g2float *, g2int, g2int, g2int *, unsigned char *, g2int *);
9 void specpack(g2float *,g2int,g2int,g2int,g2int,g2int *,unsigned char *,
10               g2int *);
11 void jpcpack(g2float *,g2int,g2int,g2int *,unsigned char *,g2int *);
12 #ifdef USE_PNG
13   void pngpack(g2float *,g2int,g2int,g2int *,unsigned char *,g2int *);
14 #endif  /* USE_PNG */
15 
16 
17 
g2_addfield(unsigned char * cgrib,g2int ipdsnum,g2int * ipdstmpl,g2float * coordlist,g2int numcoord,g2int idrsnum,g2int * idrstmpl,g2float * fld,g2int ngrdpts,g2int ibmap,g2int * bmap)18 g2int g2_addfield(unsigned char *cgrib,g2int ipdsnum,g2int *ipdstmpl,
19                 g2float *coordlist,g2int numcoord,g2int idrsnum,g2int *idrstmpl,
20                 g2float *fld,g2int ngrdpts,g2int ibmap,g2int *bmap)
21 //$$$  SUBPROGRAM DOCUMENTATION BLOCK
22 //                .      .    .                                       .
23 // SUBPROGRAM:    g2_addfield
24 //   PRGMMR: Gilbert         ORG: W/NP11    DATE: 2002-11-05
25 //
26 // ABSTRACT: This routine packs up Sections 4 through 7 for a given field
27 //   and adds them to a GRIB2 message.  They are Product Definition Section,
28 //   Data Representation Section, Bit-Map Section and Data Section,
29 //   respectively.
30 //   This routine is used with routines "g2_create", "g2_addlocal",
31 //   "g2_addgrid", and "g2_gribend" to create a complete GRIB2 message.
32 //   g2_create must be called first to initialize a new GRIB2 message.
33 //   Also, routine g2_addgrid must be called after g2_create and
34 //   before this routine to add the appropriate grid description to
35 //   the GRIB2 message.   Also, a call to g2_gribend is required to complete
36 //   GRIB2 message after all fields have been added.
37 //
38 // PROGRAM HISTORY LOG:
39 // 2002-11-05  Gilbert
40 // 2002-12-23  Gilbert  -  Added complex spherical harmonic packing
41 // 2003-08-27  Gilbert  - Added support for new templates using
42 //                        PNG and JPEG2000 algorithms/templates.
43 // 2004-11-29  Gilbert  - JPEG2000 now allowed to use WMO Template no. 5.40
44 //                        PNG now allowed to use WMO Template no. 5.41
45 //                      - Added check to determine if packing algorithm failed.
46 // 2005-05-10  Gilbert -  Imposed minimum size on cpack, used to hold encoded
47 //                        bit string.
48 // 2009-01-14  Vuong     Changed structure name template to gtemplate
49 //
50 // USAGE:    int g2_addfield(unsigned char *cgrib,g2int ipdsnum,g2int *ipdstmpl,
51 //              g2float *coordlist,g2int numcoord,g2int idrsnum,g2int *idrstmpl,
52 //              g2float *fld,g2int ngrdpts,g2int ibmap,g2int *bmap)
53 //   INPUT ARGUMENT LIST:
54 //     cgrib    - Char array that contains the GRIB2 message to which sections
55 //                4 through 7 should be added.
56 //     ipdsnum  - Product Definition Template Number ( see Code Table 4.0)
57 //     ipdstmpl - Contains the data values for the specified Product Definition
58 //                Template ( N=ipdsnum ).  Each element of this integer
59 //                array contains an entry (in the order specified) of Product
60 //                Definition Template 4.N
61 //     coordlist- Array containing floating point values intended to document
62 //                the vertical discretisation associated to model data
63 //                on hybrid coordinate vertical levels.
64 //     numcoord - number of values in array coordlist.
65 //     idrsnum  - Data Representation Template Number ( see Code Table 5.0 )
66 //     idrstmpl - Contains the data values for the specified Data Representation
67 //                Template ( N=idrsnum ).  Each element of this integer
68 //                array contains an entry (in the order specified) of Data
69 //                Representation Template 5.N
70 //                Note that some values in this template (eg. reference
71 //                values, number of bits, etc...) may be changed by the
72 //                data packing algorithms.
73 //                Use this to specify scaling factors and order of
74 //                spatial differencing, if desired.
75 //     fld[]    - Array of data points to pack.
76 //     ngrdpts  - Number of data points in grid.
77 //                i.e.  size of fld and bmap.
78 //     ibmap    - Bitmap indicator ( see Code Table 6.0 )
79 //                0 = bitmap applies and is included in Section 6.
80 //                1-253 = Predefined bitmap applies
81 //                254 = Previously defined bitmap applies to this field
82 //                255 = Bit map does not apply to this product.
83 //     bmap[]   - Integer array containing bitmap to be added. ( if ibmap=0 )
84 //
85 //   OUTPUT ARGUMENT LIST:
86 //     cgrib    - Character array to contain the updated GRIB2 message.
87 //                Must be allocated large enough to store the entire
88 //                GRIB2 message.
89 //
90 //   RETURN VALUES:
91 //     ierr     - Return code.
92 //              > 0 = Current size of updated GRIB2 message
93 //               -1 = GRIB message was not initialized.  Need to call
94 //                    routine g2_create first.
95 //               -2 = GRIB message already complete.  Cannot add new section.
96 //               -3 = Sum of Section byte counts doesn't add to total byte count
97 //               -4 = Previous Section was not 3 or 7.
98 //               -5 = Could not find requested Product Definition Template.
99 //               -6 = Section 3 (GDS) not previously defined in message
100 //               -7 = Tried to use unsupported Data Representationi Template
101 //               -8 = Specified use of a previously defined bitmap, but one
102 //                    does not exist in the GRIB message.
103 //               -9 = GDT of one of 5.50 through 5.53 required to pack field
104 //                    using DRT 5.51.
105 //              -10 = Error packing data field.
106 //
107 // REMARKS: Note that the Sections 4 through 7 can only follow
108 //          Section 3 or Section 7 in a GRIB2 message.
109 //
110 // ATTRIBUTES:
111 //   LANGUAGE: C
112 //   MACHINE:
113 //
114 //$$$
115 {
116       g2int ierr;
117       const unsigned char G=0x47;       // 'G'
118       const unsigned char R=0x52;       // 'R'
119       const unsigned char I=0x49;       // 'I'
120       const unsigned char B=0x42;       // 'B'
121       const unsigned char s7=0x37;   // '7'
122 
123       unsigned char *cpack;
124       const g2int  zero=0,one=1,four=4,five=5,six=6,seven=7;
125       const g2int  minsize=50000;
126       g2int   iofst,ibeg,lencurr,len,nsize;
127       g2int   ilen,isecnum,i,nbits,temp,left;
128       g2int   ibmprev,j,lcpack,ioctet,newlen,ndpts;
129       g2int   lensec4,lensec5,lensec6,lensec7;
130       g2int   issec3,isprevbmap,lpos3=0,JJ,KK,MM;
131       g2int   *coordieee;
132       g2int   width,height,iscan,itemp;
133       g2float *pfld;
134       gtemplate  *mappds,*mapdrs;
135       const unsigned int allones=4294967295u;
136 
137       ierr=0;
138 //
139 //  Check to see if beginning of GRIB message exists
140 //
141       if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) {
142         printf("g2_addfield: GRIB not found in given message.\n");
143         printf("g2_addfield: Call to routine g2_create required to initialize GRIB message.\n");
144         ierr=-1;
145         return(ierr);
146       }
147 //
148 //  Get current length of GRIB message
149 //
150       gbit(cgrib,&lencurr,96,32);
151 //
152 //  Check to see if GRIB message is already complete
153 //
154       if ( cgrib[lencurr-4]==s7 && cgrib[lencurr-3]==s7 &&
155            cgrib[lencurr-2]==s7 && cgrib[lencurr-1]==s7 ) {
156         printf("g2_addfield: GRIB message already complete.  Cannot add new section.\n");
157         ierr=-2;
158         return(ierr);
159       }
160 //
161 //  Loop through all current sections of the GRIB message to
162 //  find the last section number.
163 //
164       issec3=0;
165       isprevbmap=0;
166       len=16;    // length of Section 0
167       for (;;) {
168       //    Get number and length of next section
169         iofst=len*8;
170         gbit(cgrib,&ilen,iofst,32);
171         iofst=iofst+32;
172         gbit(cgrib,&isecnum,iofst,8);
173         iofst=iofst+8;
174       //  Check if previous Section 3 exists
175         if (isecnum == 3) {
176             issec3=1;
177             lpos3=len;
178         }
179       //  Check if a previous defined bitmap exists
180         if (isecnum == 6) {
181           gbit(cgrib,&ibmprev,iofst,8);
182           /*iofst=iofst+8;*/
183           if ((ibmprev >= 0) && (ibmprev <= 253)) isprevbmap=1;
184         }
185         len=len+ilen;
186       //    Exit loop if last section reached
187         if ( len == lencurr ) break;
188       //    If byte count for each section doesn't match current
189       //    total length, then there is a problem.
190         if ( len > lencurr ) {
191           printf("g2_addfield: Section byte counts don''t add to total.\n");
192           printf("g2_addfield: Sum of section byte counts = %d\n",len);
193           printf("g2_addfield: Total byte count in Section 0 = %d\n",lencurr);
194           ierr=-3;
195           return(ierr);
196         }
197       }
198 //
199 //  Sections 4 through 7 can only be added after section 3 or 7.
200 //
201       if ( (isecnum != 3) && (isecnum != 7) ) {
202         printf("g2_addfield: Sections 4-7 can only be added after Section 3 or 7.\n");
203         printf("g2_addfield: Section ',isecnum,' was the last found in given GRIB message.\n");
204         ierr=-4;
205         return(ierr);
206 //
207 //  Sections 4 through 7 can only be added if section 3 was previously defined.
208 //
209       }
210       else if ( ! issec3) {
211         printf("g2_addfield: Sections 4-7 can only be added if Section 3 was previously included.\n");
212         printf("g2_addfield: Section 3 was not found in given GRIB message.\n");
213         printf("g2_addfield: Call to routine addgrid required to specify Grid definition.\n");
214         ierr=-6;
215         return(ierr);
216       }
217 //
218 //  Add Section 4  - Product Definition Section
219 //
220       ibeg=lencurr*8;        //   Calculate offset for beginning of section 4
221       iofst=ibeg+32;         //   leave space for length of section
222       sbit(cgrib,&four,iofst,8);     // Store section number ( 4 )
223       iofst=iofst+8;
224       sbit(cgrib,&numcoord,iofst,16);   // Store num of coordinate values
225       iofst=iofst+16;
226       sbit(cgrib,&ipdsnum,iofst,16);    // Store Prod Def Template num.
227       iofst=iofst+16;
228       //
229       //   Get Product Definition Template
230       //
231       mappds=getpdstemplate(ipdsnum);
232       if (mappds == 0) {          // undefined template
233         ierr=-5;
234         return(ierr);
235       }
236       //
237       //   Extend the Product Definition Template, if necessary.
238       //   The number of values in a specific template may vary
239       //   depending on data specified in the "static" part of the
240       //   template.
241       //
242       if ( mappds->needext ) {
243         free(mappds);
244         mappds=extpdstemplate(ipdsnum,ipdstmpl);
245       }
246       //
247       //   Pack up each input value in array ipdstmpl into the
248       //   the appropriate number of octets, which are specified in
249       //   corresponding entries in array mappds.
250       //
251       for (i=0;i<mappds->maplen;i++) {
252         nbits=abs(mappds->map[i])*8;
253         if ( (mappds->map[i] >= 0) || (ipdstmpl[i] >= 0) )
254           sbit(cgrib,ipdstmpl+i,iofst,nbits);
255         else {
256           sbit(cgrib,&one,iofst,1);
257           temp=abs(ipdstmpl[i]);
258           sbit(cgrib,&temp,iofst+1,nbits-1);
259         }
260         iofst=iofst+nbits;
261       }
262       //  Pack template extension, if appropriate
263       j=mappds->maplen;
264       if ( mappds->needext && (mappds->extlen > 0) ) {
265          for (i=0;i<mappds->extlen;i++) {
266            nbits=abs(mappds->ext[i])*8;
267            if ( (mappds->ext[i] >= 0) || (ipdstmpl[j] >= 0) )
268              sbit(cgrib,ipdstmpl+j,iofst,nbits);
269            else {
270              sbit(cgrib,&one,iofst,1);
271              temp=abs(ipdstmpl[j]);
272              sbit(cgrib,&temp,iofst+1,nbits-1);
273            }
274            iofst=iofst+nbits;
275            j++;
276          }
277       }
278       free(mappds);
279       //
280       //   Add Optional list of vertical coordinate values
281       //   after the Product Definition Template, if necessary.
282       //
283       if ( numcoord != 0 ) {
284         coordieee=(g2int *)calloc(numcoord,sizeof(g2int));
285         mkieee(coordlist,coordieee,numcoord);
286         sbits(cgrib,coordieee,iofst,32,0,numcoord);
287         iofst=iofst+(32*numcoord);
288         free(coordieee);
289       }
290       //
291       //   Calculate length of section 4 and store it in octets
292       //   1-4 of section 4.
293       //
294       lensec4=(iofst-ibeg)/8;
295       sbit(cgrib,&lensec4,ibeg,32);
296 //
297 //  Pack Data using appropriate algorithm
298 //
299       //
300       //   Get Data Representation Template
301       //
302       mapdrs=getdrstemplate(idrsnum);
303       if (mapdrs == 0) {
304         ierr=-5;
305         return(ierr);
306       }
307       //
308       //  contract data field, removing data at invalid grid points,
309       //  if bit-map is provided with field.
310       //
311       if ( ibmap == 0 || ibmap==254 ) {
312          pfld=(g2float *)malloc(ngrdpts*sizeof(g2float));
313          ndpts=0;
314          for (j=0;j<ngrdpts;j++) {
315              if ( bmap[j]==1 ) pfld[ndpts++]=fld[j];
316          }
317       }
318       else {
319          ndpts=ngrdpts;
320          pfld=fld;
321       }
322       nsize=ndpts*4;
323       if ( nsize < minsize ) nsize=minsize;
324       cpack=malloc(nsize);
325       if (idrsnum == 0)           //  Simple Packing
326         simpack(pfld,ndpts,idrstmpl,cpack,&lcpack);
327       else if (idrsnum==2 || idrsnum==3)           //  Complex Packing
328         cmplxpack(pfld,ndpts,idrsnum,idrstmpl,cpack,&lcpack);
329       else if (idrsnum == 50) {         //  Sperical Harmonic Simple Packing
330         simpack(pfld+1,ndpts-1,idrstmpl,cpack,&lcpack);
331         mkieee(pfld+0,idrstmpl+4,1);  // ensure RE(0,0) value is IEEE format
332       }
333       else if (idrsnum == 51) {         //  Sperical Harmonic Complex Packing
334         getpoly(cgrib+lpos3,&JJ,&KK,&MM);
335         if ( JJ!=0 && KK!=0 && MM!=0 )
336            specpack(pfld,ndpts,JJ,KK,MM,idrstmpl,cpack,&lcpack);
337         else {
338            printf("g2_addfield: Cannot pack DRT 5.51.\n");
339            return (-9);
340         }
341       }
342       else if (idrsnum == 40 || idrsnum == 40000) {    /*  JPEG2000 encoding  */
343         if (ibmap == 255) {
344            getdim(cgrib+lpos3,&width,&height,&iscan);
345            if ( width==0 || height==0 ) {
346               width=ndpts;
347               height=1;
348            }
349            else if ( (unsigned int)width==allones || (unsigned int)height==allones ) {
350               width=ndpts;
351               height=1;
352            }
353            else if ( (iscan&32) == 32) {   /* Scanning mode: bit 3  */
354               itemp=width;
355               width=height;
356               height=itemp;
357            }
358         }
359         else {
360            width=ndpts;
361            height=1;
362         }
363         lcpack=nsize;
364         jpcpack(pfld,width,height,idrstmpl,cpack,&lcpack);
365       }
366 #ifdef USE_PNG
367       else if (idrsnum == 41 || idrsnum == 40010) {      /*  PNG encoding   */
368         if (ibmap == 255) {
369            getdim(cgrib+lpos3,&width,&height,&iscan);
370            if ( width==0 || height==0 ) {
371               width=ndpts;
372               height=1;
373            }
374            else if ( (unsigned int)width==allones || (unsigned int)height==allones ) {
375               width=ndpts;
376               height=1;
377            }
378            else if ( (iscan&32) == 32) {   /* Scanning mode: bit 3  */
379               itemp=width;
380               width=height;
381               height=itemp;
382            }
383         }
384         else {
385            width=ndpts;
386            height=1;
387         }
388         pngpack(pfld,width,height,idrstmpl,cpack,&lcpack);
389       }
390 #endif  /* USE_PNG */
391       else {
392         printf("g2_addfield: Data Representation Template 5.%d not yet implemented.\n",idrsnum);
393         ierr=-7;
394         return(ierr);
395       }
396       if ( ibmap == 0 || ibmap==254 ) {      // free temp space
397          if (fld != pfld) free(pfld);
398       }
399       if ( lcpack < 0 ) {
400         if( cpack != 0 ) free(cpack);
401         ierr=-10;
402         return(ierr);
403       }
404 
405 //
406 //  Add Section 5  - Data Representation Section
407 //
408       ibeg=iofst;            //   Calculate offset for beginning of section 5
409       iofst=ibeg+32;         //   leave space for length of section
410       sbit(cgrib,&five,iofst,8);     // Store section number ( 5 )
411       iofst=iofst+8;
412       sbit(cgrib,&ndpts,iofst,32);    // Store num of actual data points
413       iofst=iofst+32;
414       sbit(cgrib,&idrsnum,iofst,16);    // Store Data Repr. Template num.
415       iofst=iofst+16;
416       //
417       //   Pack up each input value in array idrstmpl into the
418       //   the appropriate number of octets, which are specified in
419       //   corresponding entries in array mapdrs.
420       //
421       for (i=0;i<mapdrs->maplen;i++) {
422         nbits=abs(mapdrs->map[i])*8;
423         if ( (mapdrs->map[i] >= 0) || (idrstmpl[i] >= 0) )
424           sbit(cgrib,idrstmpl+i,iofst,nbits);
425         else {
426           sbit(cgrib,&one,iofst,1);
427           temp=abs(idrstmpl[i]);
428           sbit(cgrib,&temp,iofst+1,nbits-1);
429         }
430         iofst=iofst+nbits;
431       }
432       free(mapdrs);
433       //
434       //   Calculate length of section 5 and store it in octets
435       //   1-4 of section 5.
436       //
437       lensec5=(iofst-ibeg)/8;
438       sbit(cgrib,&lensec5,ibeg,32);
439 
440 //
441 //  Add Section 6  - Bit-Map Section
442 //
443       ibeg=iofst;            //   Calculate offset for beginning of section 6
444       iofst=ibeg+32;         //   leave space for length of section
445       sbit(cgrib,&six,iofst,8);     // Store section number ( 6 )
446       iofst=iofst+8;
447       sbit(cgrib,&ibmap,iofst,8);    // Store Bit Map indicator
448       iofst=iofst+8;
449       //
450       //  Store bitmap, if supplied
451       //
452       if (ibmap == 0) {
453         sbits(cgrib,bmap,iofst,1,0,ngrdpts);    // Store BitMap
454         iofst=iofst+ngrdpts;
455       }
456       //
457       //  If specifying a previously defined bit-map, make sure
458       //  one already exists in the current GRIB message.
459       //
460       if ((ibmap==254) && ( ! isprevbmap)) {
461         printf("g2_addfield: Requested previously defined bitmap,");
462         printf(" but one does not exist in the current GRIB message.\n");
463         ierr=-8;
464         return(ierr);
465       }
466       //
467       //   Calculate length of section 6 and store it in octets
468       //   1-4 of section 6.  Pad to end of octet, if necessary.
469       //
470       left=8-(iofst%8);
471       if (left != 8) {
472         sbit(cgrib,&zero,iofst,left);     // Pad with zeros to fill Octet
473         iofst=iofst+left;
474       }
475       lensec6=(iofst-ibeg)/8;
476       sbit(cgrib,&lensec6,ibeg,32);
477 
478 //
479 //  Add Section 7  - Data Section
480 //
481       ibeg=iofst;            //   Calculate offset for beginning of section 7
482       iofst=ibeg+32;        //   leave space for length of section
483       sbit(cgrib,&seven,iofst,8);    // Store section number ( 7 )
484       iofst=iofst+8;
485       //      Store Packed Binary Data values, if non-constant field
486       if (lcpack != 0) {
487         ioctet=iofst/8;
488         //cgrib(ioctet+1:ioctet+lcpack)=cpack(1:lcpack)
489         for (j=0;j<lcpack;j++) cgrib[ioctet+j]=cpack[j];
490         iofst=iofst+(8*lcpack);
491       }
492       //
493       //   Calculate length of section 7 and store it in octets
494       //   1-4 of section 7.
495       //
496       lensec7=(iofst-ibeg)/8;
497       sbit(cgrib,&lensec7,ibeg,32);
498 
499       if( cpack != 0 ) free(cpack);
500 //
501 //  Update current byte total of message in Section 0
502 //
503       newlen=lencurr+lensec4+lensec5+lensec6+lensec7;
504       sbit(cgrib,&newlen,96,32);
505 
506       return(newlen);
507 
508 }
509