static void show_stats(uv_handle_t *handle, int status) { int64_t diff; #if PRINT_STATS LOGF("connections: %d, read: %.1f gbit/s, write: %.1f gbit/s\n", read_sockets, gbit(nrecv, STATS_INTERVAL), gbit(nsent, STATS_INTERVAL)); #endif /* Exit if the show is over */ if (!--stats_left) { uv_update_time(); diff = uv_now() - start_time; LOGF("pump_%d: %.1f gbit/s\n", read_sockets, gbit(nrecv_total, diff)); exit(0); } /* Reset read and write counters */ nrecv = 0; nsent = 0; }
static void show_stats(uv_timer_t* handle, int status) { int64_t diff; int i; #if PRINT_STATS LOGF("connections: %d, write: %.1f gbit/s\n", write_sockets, gbit(nsent, STATS_INTERVAL)); #endif /* Exit if the show is over */ if (!--stats_left) { uv_update_time(); diff = uv_now() - start_time; LOGF("%s_pump%d_client: %.1f gbit/s\n", type == TCP ? "tcp" : "pipe", write_sockets, gbit(nsent_total, diff)); for (i = 0; i < write_sockets; i++) { uv_close(type == TCP ? (uv_handle_t*)&tcp_write_handles[i] : (uv_handle_t*)&pipe_write_handles[i], NULL); } exit(0); } /* Reset read and write counters */ nrecv = 0; nsent = 0; }
static void read_show_stats() { int64_t diff; uv_update_time(); diff = uv_now() - start_time; LOGF("%s_pump%d_server: %.1f gbit/s\n", type == TCP ? "tcp" : "pipe", max_read_sockets, gbit(nrecv_total, diff)); }
/** * Returns the next bytes of a byte-buffer as an integer. Advances the * byte-buffer's cursor by the given number of bytes. * * @param[in] bb Pointer to a byte-buffer. * @param[in] nbytes The length of the integer in bytes. * @param[out] value Pointer to an integer to hold the value. * @return 0 Success. \c *value will be set. * @retval -1 The integer extends beyond the data in the byte-buffer. * \c *value will be unset. */ int bb_getInt( ByteBuf* const bb, const int nbytes, g2int* const value) { if (bb->cursor + nbytes > bb->byteCount) return -1; /* * The casts in the following are known to be safe. */ gbit((unsigned char*)bb->buf, value, (g2int)bb->cursor*CHAR_BIT, (g2int)nbytes*CHAR_BIT); bb->cursor += nbytes; return 0; }
g2int g2_unpack2(unsigned char *cgrib,g2int *iofst,g2int *lencsec2,unsigned char **csec2) ////$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack2 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This subroutine unpacks Section 2 (Local Use Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // // USAGE: int g2_unpack2(unsigned char *cgrib,g2int *iofst,g2int *lencsec2, // unsigned char **csec2) // INPUT ARGUMENT LIST: // cgrib - char array containing Section 2 of the GRIB2 message // iofst - Bit offset for the beginning of Section 2 in cgrib. // // OUTPUT ARGUMENT LIST: // iofst - Bit offset at the end of Section 2, returned. // lencsec2 - Length (in octets) of Local Use data // csec2 - Pointer to a char array containing local use data // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 2 = Array passed is not section 2 // 6 = memory allocation error // // REMARKS: None // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$// { g2int ierr,isecnum; g2int lensec,ipos,j; ierr=0; *lencsec2=0; *csec2=0; // NULL gbit(cgrib,&lensec,*iofst,32); // Get Length of Section *iofst=*iofst+32; *lencsec2=lensec-5; gbit(cgrib,&isecnum,*iofst,8); // Get Section Number *iofst=*iofst+8; ipos=(*iofst/8); if ( isecnum != 2 ) { ierr=2; *lencsec2=0; fprintf(stderr,"g2_unpack2: Not Section 2 data.\n"); return(ierr); } *csec2=(unsigned char *)malloc(*lencsec2); if (*csec2 == 0) { ierr=6; *lencsec2=0; return(ierr); } //printf(" SAGIPO %d \n",(int)ipos); for (j=0;j<*lencsec2;j++) { *(*csec2+j)=cgrib[ipos+j]; } *iofst=*iofst+(*lencsec2*8); return(ierr); // End of Section 2 processing }
g2int g2_info(unsigned char *cgrib,g2int *listsec0,g2int *listsec1, g2int *numfields,g2int *numlocal) //$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_info // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 // // ABSTRACT: This subroutine searches through a GRIB2 message and // returns the number of gridded fields found in the message and // the number (and maximum size) of Local Use Sections. // Also various checks are performed // to see if the message is a valid GRIB2 message. // // PROGRAM HISTORY LOG: // 2002-10-28 Gilbert // // USAGE: int g2_info(unsigned char *cgrib,g2int *listsec0,g2int *listsec1, // g2int *numfields,g2int *numlocal) // INPUT ARGUMENT: // cgrib - Character pointer to the GRIB2 message // // OUTPUT ARGUMENTS: // listsec0 - pointer to an array containing information decoded from // GRIB Indicator Section 0. // Must be allocated with >= 3 elements. // listsec0[0]=Discipline-GRIB Master Table Number // (see Code Table 0.0) // listsec0[1]=GRIB Edition Number (currently 2) // listsec0[2]=Length of GRIB message // listsec1 - pointer to an array containing information read from GRIB // Identification Section 1. // Must be allocated with >= 13 elements. // listsec1[0]=Id of originating centre (Common Code Table C-1) // listsec1[1]=Id of originating sub-centre (local table) // listsec1[2]=GRIB Master Tables Version Number (Code Table 1.0) // listsec1[3]=GRIB Local Tables Version Number // listsec1[4]=Significance of Reference Time (Code Table 1.1) // listsec1[5]=Reference Time - Year (4 digits) // listsec1[6]=Reference Time - Month // listsec1[7]=Reference Time - Day // listsec1[8]=Reference Time - Hour // listsec1[9]=Reference Time - Minute // listsec1[10]=Reference Time - Second // listsec1[11]=Production status of data (Code Table 1.2) // listsec1[12]=Type of processed data (Code Table 1.3) // numfields- The number of gridded fields found in the GRIB message. // That is, the number of occurrences of Sections 4 - 7. // numlocal - The number of Local Use Sections ( Section 2 ) found in // the GRIB message. // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 1 = Beginning characters "GRIB" not found. // 2 = GRIB message is not Edition 2. // 3 = Could not find Section 1, where expected. // 4 = End string "7777" found, but not where expected. // 5 = End string "7777" not found at end of message. // 6 = Invalid section number found. // // REMARKS: None // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ { g2int mapsec1len=13; g2int mapsec1[13]={2,2,1,1,1,2,1,1,1,1,1,1,1}; g2int i,j,istart,iofst,lengrib,lensec0,lensec1; g2int ipos,isecnum,nbits,lensec; *numlocal=0; *numfields=0; // // Check for beginning of GRIB message in the first 100 bytes // istart=-1; for (j=0;j<100;j++) { if (cgrib[j]=='G' && cgrib[j+1]=='R' &&cgrib[j+2]=='I' && cgrib[j+3]=='B') { istart=j; break; } } if (istart == -1) { printf("g2_info: Beginning characters GRIB not found."); return(1); } // // Unpack Section 0 - Indicator Section // iofst=8*(istart+6); gbit(cgrib,listsec0+0,iofst,8); // Discipline iofst=iofst+8; gbit(cgrib,listsec0+1,iofst,8); // GRIB edition number iofst=iofst+8; iofst=iofst+32; gbit(cgrib,&lengrib,iofst,32); // Length of GRIB message iofst=iofst+32; listsec0[2]=lengrib; lensec0=16; ipos=istart+lensec0; // // Currently handles only GRIB Edition 2. // if (listsec0[1] != 2) { printf("g2_info: can only decode GRIB edition 2."); return(2); } // // Unpack Section 1 - Identification Section // gbit(cgrib,&lensec1,iofst,32); // Length of Section 1 iofst=iofst+32; gbit(cgrib,&isecnum,iofst,8); // Section number ( 1 ) iofst=iofst+8; if (isecnum != 1) { printf("g2_info: Could not find section 1."); return(3); } // // Unpack each input value in array listsec1 into the // the appropriate number of octets, which are specified in // corresponding entries in array mapsec1. // for (i=0;i<mapsec1len;i++) { nbits=mapsec1[i]*8; gbit(cgrib,listsec1+i,iofst,nbits); iofst=iofst+nbits; } ipos=ipos+lensec1; // // Loop through the remaining sections to see if they are valid. // Also count the number of times Section 2 // and Section 4 appear. // for (;;) { if (cgrib[ipos]=='7' && cgrib[ipos+1]=='7' && cgrib[ipos+2]=='7' && cgrib[ipos+3]=='7') { ipos=ipos+4; if (ipos != (istart+lengrib)) { printf("g2_info: '7777' found, but not where expected.\n"); return(4); } break; } iofst=ipos*8; gbit(cgrib,&lensec,iofst,32); // Get Length of Section iofst=iofst+32; gbit(cgrib,&isecnum,iofst,8); // Get Section number /*iofst=iofst+8;*/ ipos=ipos+lensec; // Update beginning of section pointer if (ipos > (istart+lengrib)) { printf("g2_info: '7777' not found at end of GRIB message.\n"); return(5); } if ( isecnum>=2 && isecnum<=7 ) { if (isecnum == 2) // Local Section 2 // increment counter for total number of local sections found (*numlocal)++; else if (isecnum == 4) // increment counter for total number of fields found (*numfields)++; } else { printf("g2_info: Invalid section number found in GRIB message: %d\n" ,isecnum); return(6); } } return(0); }
int comunpack(unsigned char *cpack,g2int lensec,g2int idrsnum,g2int *idrstmpl,g2int ndpts,g2float *fld) /*//$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: comunpack // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-29 // // ABSTRACT: This subroutine unpacks a data field that was packed using a // complex packing algorithm as defined in the GRIB2 documention, // using info from the GRIB2 Data Representation Template 5.2 or 5.3. // Supports GRIB2 complex packing templates with or without // spatial differences (i.e. DRTs 5.2 and 5.3). // // PROGRAM HISTORY LOG: // 2002-10-29 Gilbert // 2004-12-16 Gilbert - Added test ( provided by Arthur Taylor/MDL ) // to verify that group widths and lengths are // consistent with section length. // // USAGE: int comunpack(unsigned char *cpack,g2int lensec,g2int idrsnum, // g2int *idrstmpl, g2int ndpts,g2float *fld) // INPUT ARGUMENT LIST: // cpack - pointer to the packed data field. // lensec - length of section 7 (used for error checking). // idrsnum - Data Representation Template number 5.N // Must equal 2 or 3. // idrstmpl - pointer to the array of values for Data Representation // Template 5.2 or 5.3 // ndpts - The number of data values to unpack // // OUTPUT ARGUMENT LIST: // fld - Contains the unpacked data values. fld must be allocated // with at least ndpts*sizeof(g2float) bytes before // calling this routine. // // REMARKS: None // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$*/ { g2int nbitsd=0,isign; g2int j,iofst,ival1,ival2,minsd,itemp,l,k,n,non=0; g2int *ifld,*ifldmiss=0; g2int *gref,*gwidth,*glen; g2int itype,ngroups,nbitsgref,nbitsgwidth,nbitsglen; g2int msng1,msng2; g2float ref,bscale,dscale,rmiss1,rmiss2; g2int totBit, totLen; /*printf('IDRSTMPL: ',(idrstmpl(j),j=1,16)*/ g2_rdieee(idrstmpl+0,&ref,1); /* printf("SAGTref: %f\n",ref);*/ bscale = (g2float)int_power(2.0,idrstmpl[1]); dscale = (g2float)int_power(10.0,-idrstmpl[2]); nbitsgref = idrstmpl[3]; itype = idrstmpl[4]; ngroups = idrstmpl[9]; nbitsgwidth = idrstmpl[11]; nbitsglen = idrstmpl[15]; if (idrsnum == 3) nbitsd=idrstmpl[17]*8; /* Constant field*/ if (ngroups == 0) { for (j=0;j<ndpts;j++) fld[j]=ref; return(0); } iofst=0; ifld=(g2int *)calloc(ndpts,sizeof(g2int)); /*printf("ALLOC ifld: %d %x\n",(int)ndpts,ifld);*/ gref=(g2int *)calloc(ngroups,sizeof(g2int)); /*printf("ALLOC gref: %d %x\n",(int)ngroups,gref);*/ gwidth=(g2int *)calloc(ngroups,sizeof(g2int)); /*printf("ALLOC gwidth: %d %x\n",(int)ngroups,gwidth);*/ /* // Get missing values, if supplied */ if ( idrstmpl[6] == 1 ) { if (itype == 0) g2_rdieee(idrstmpl+7,&rmiss1,1); else rmiss1=(g2float)idrstmpl[7]; } if ( idrstmpl[6] == 2 ) { if (itype == 0) { g2_rdieee(idrstmpl+7,&rmiss1,1); g2_rdieee(idrstmpl+8,&rmiss2,1); } else { rmiss1=(g2float)idrstmpl[7]; rmiss2=(g2float)idrstmpl[8]; } } /*printf("RMISSs: %f %f %f \n",rmiss1,rmiss2,ref);*/ /* // Extract Spatial differencing values, if using DRS Template 5.3 */ if (idrsnum == 3) { if (nbitsd != 0) { gbit(cpack,&isign,iofst,1); iofst=iofst+1; gbit(cpack,&ival1,iofst,nbitsd-1); iofst=iofst+nbitsd-1; if (isign == 1) ival1=-ival1; if (idrstmpl[16] == 2) { gbit(cpack,&isign,iofst,1); iofst=iofst+1; gbit(cpack,&ival2,iofst,nbitsd-1); iofst=iofst+nbitsd-1; if (isign == 1) ival2=-ival2; } gbit(cpack,&isign,iofst,1); iofst=iofst+1; gbit(cpack,&minsd,iofst,nbitsd-1); iofst=iofst+nbitsd-1; if (isign == 1) minsd=-minsd; } else { ival1=0; ival2=0; minsd=0; } /*printf("SDu %ld %ld %ld %ld \n",ival1,ival2,minsd,nbitsd);*/ } /* // Extract Each Group's reference value */ /*printf("SAG1: %ld %ld %ld \n",nbitsgref,ngroups,iofst);*/ if (nbitsgref != 0) { gbits(cpack,gref+0,iofst,nbitsgref,0,ngroups); itemp=nbitsgref*ngroups; iofst=iofst+itemp; if (itemp%8 != 0) iofst=iofst+(8-(itemp%8)); } else { for (j=0;j<ngroups;j++) gref[j]=0; } /* // Extract Each Group's bit width */ /*printf("SAG2: %ld %ld %ld %ld \n",nbitsgwidth,ngroups,iofst,idrstmpl[10]);*/ if (nbitsgwidth != 0) { gbits(cpack,gwidth+0,iofst,nbitsgwidth,0,ngroups); itemp=nbitsgwidth*ngroups; iofst=iofst+itemp; if (itemp%8 != 0) iofst=iofst+(8-(itemp%8)); } else { for (j=0;j<ngroups;j++) gwidth[j]=0; } for (j=0;j<ngroups;j++) gwidth[j]=gwidth[j]+idrstmpl[10]; /* // Extract Each Group's length (number of values in each group) */ glen=(g2int *)calloc(ngroups,sizeof(g2int)); /*printf("ALLOC glen: %d %x\n",(int)ngroups,glen);*/ /*printf("SAG3: %ld %ld %ld %ld %ld \n",nbitsglen,ngroups,iofst,idrstmpl[13],idrstmpl[12]);*/ if (nbitsglen != 0) { gbits(cpack,glen,iofst,nbitsglen,0,ngroups); itemp=nbitsglen*ngroups; iofst=iofst+itemp; if (itemp%8 != 0) iofst=iofst+(8-(itemp%8)); } else { for (j=0;j<ngroups;j++) glen[j]=0; } for (j=0;j<ngroups;j++) glen[j]=(glen[j]*idrstmpl[13])+idrstmpl[12]; glen[ngroups-1]=idrstmpl[14]; /* // Test to see if the group widths and lengths are consistent with number of // values, and length of section 7. */ totBit = 0; totLen = 0; for (j=0;j<ngroups;j++) { totBit += (gwidth[j]*glen[j]); totLen += glen[j]; } if (totLen != ndpts) { return 1; } if (totBit / 8. > lensec) { return 1; } /* // For each group, unpack data values */ if ( idrstmpl[6] == 0 ) { /* no missing values*/ n=0; for (j=0;j<ngroups;j++) { if (gwidth[j] != 0) { gbits(cpack,ifld+n,iofst,gwidth[j],0,glen[j]); for (k=0;k<glen[j];k++) { ifld[n]=ifld[n]+gref[j]; n=n+1; } } else { for (l=n;l<n+glen[j];l++) ifld[l]=gref[j]; n=n+glen[j]; } iofst=iofst+(gwidth[j]*glen[j]); } } else if ( idrstmpl[6]==1 || idrstmpl[6]==2 ) { /* missing values included*/ ifldmiss=(g2int *)malloc(ndpts*sizeof(g2int)); /*printf("ALLOC ifldmiss: %d %x\n",(int)ndpts,ifldmiss);*/ /*for (j=0;j<ndpts;j++) ifldmiss[j]=0;*/ n=0; non=0; for (j=0;j<ngroups;j++) { /*printf(" SAGNGP %d %d %d %d\n",j,gwidth[j],glen[j],gref[j]);*/ if (gwidth[j] != 0) { msng1=(g2int)int_power(2.0,gwidth[j])-1; msng2=msng1-1; gbits(cpack,ifld+n,iofst,gwidth[j],0,glen[j]); iofst=iofst+(gwidth[j]*glen[j]); for (k=0;k<glen[j];k++) { if (ifld[n] == msng1) { ifldmiss[n]=1; /*ifld[n]=0;*/ } else if (idrstmpl[6]==2 && ifld[n]==msng2) { ifldmiss[n]=2; /*ifld[n]=0;*/ } else { ifldmiss[n]=0; ifld[non++]=ifld[n]+gref[j]; } n++; } } else { msng1=(g2int)int_power(2.0,nbitsgref)-1; msng2=msng1-1; if (gref[j] == msng1) { for (l=n;l<n+glen[j];l++) ifldmiss[l]=1; } else if (idrstmpl[6]==2 && gref[j]==msng2) { for (l=n;l<n+glen[j];l++) ifldmiss[l]=2; } else { for (l=n;l<n+glen[j];l++) ifldmiss[l]=0; for (l=non;l<non+glen[j];l++) ifld[l]=gref[j]; non += glen[j]; } n=n+glen[j]; } } } if ( gref != 0 ) free(gref); if ( gwidth != 0 ) free(gwidth); if ( glen != 0 ) free(glen); /* // If using spatial differences, add overall min value, and // sum up recursively */ /*printf("SAGod: %ld %ld\n",idrsnum,idrstmpl[16]);*/ if (idrsnum == 3) { /* spatial differencing*/ if (idrstmpl[16] == 1) { /* first order*/ ifld[0]=ival1; if ( idrstmpl[6] == 0 ) itemp=ndpts; /* no missing values*/ else itemp=non; for (n=1;n<itemp;n++) { ifld[n]=ifld[n]+minsd; ifld[n]=ifld[n]+ifld[n-1]; } } else if (idrstmpl[16] == 2) { /* second order*/ ifld[0]=ival1; ifld[1]=ival2; if ( idrstmpl[6] == 0 ) itemp=ndpts; /* no missing values*/ else itemp=non; for (n=2;n<itemp;n++) { ifld[n]=ifld[n]+minsd; ifld[n]=ifld[n]+(2*ifld[n-1])-ifld[n-2]; } } } /* // Scale data back to original form */ /*printf("SAGT: %f %f %f\n",ref,bscale,dscale);*/ if ( idrstmpl[6] == 0 ) { /* no missing values*/ for (n=0;n<ndpts;n++) { fld[n]=(((g2float)ifld[n]*bscale)+ref)*dscale; } } else if ( idrstmpl[6]==1 || idrstmpl[6]==2 ) { /* missing values included*/ non=0; for (n=0;n<ndpts;n++) { if ( ifldmiss[n] == 0 ) { fld[n]=(((g2float)ifld[non++]*bscale)+ref)*dscale; /*printf(" SAG %d %f %d %f %f %f\n",n,fld[n],ifld[non-1],bscale,ref,dscale);*/ } else if ( ifldmiss[n] == 1 ) fld[n]=rmiss1; else if ( ifldmiss[n] == 2 ) fld[n]=rmiss2; } if ( ifldmiss != 0 ) free(ifldmiss); } if ( ifld != 0 ) free(ifld); return(0); }
g2int g2_unpack7(unsigned char *cgrib,g2int *iofst,g2int igdsnum,g2int *igdstmpl, g2int idrsnum,g2int *idrstmpl,g2int ndpts,g2float **fld) //$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack7 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This subroutine unpacks Section 7 (Data Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // 2002-12-20 Gilbert - Added GDT info to arguments // and added 5.51 processing. // 2003-08-29 Gilbert - Added support for new templates using // PNG and JPEG2000 algorithms/templates. // 2004-11-29 Gilbert - JPEG2000 now allowed to use WMO Template no. 5.40 // PNG now allowed to use WMO Template no. 5.41 // 2004-12-16 Taylor - Added check on comunpack return code. // 2008-12-23 Wesley - Initialize Number of data points unpacked // // USAGE: int g2_unpack7(unsigned char *cgrib,g2int *iofst,g2int igdsnum, // g2int *igdstmpl, g2int idrsnum, // g2int *idrstmpl, g2int ndpts,g2float **fld) // INPUT ARGUMENTS: // cgrib - char array containing Section 7 of the GRIB2 message // iofst - Bit offset of the beginning of Section 7 in cgrib. // igdsnum - Grid Definition Template Number ( see Code Table 3.0) // ( Only used for DRS Template 5.51 ) // igdstmpl - Pointer to an integer array containing the data values for // the specified Grid Definition // Template ( N=igdsnum ). Each element of this integer // array contains an entry (in the order specified) of Grid // Definition Template 3.N // ( Only used for DRS Template 5.51 ) // idrsnum - Data Representation Template Number ( see Code Table 5.0) // idrstmpl - Pointer to an integer array containing the data values for // the specified Data Representation // Template ( N=idrsnum ). Each element of this integer // array contains an entry (in the order specified) of Data // Representation Template 5.N // ndpts - Number of data points unpacked and returned. // // OUTPUT ARGUMENTS: // iofst - Bit offset at the end of Section 7, returned. // fld - Pointer to a float array containing the unpacked data field. // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 2 = Not section 7 // 4 = Unrecognized Data Representation Template // 5 = need one of GDT 3.50 through 3.53 to decode DRT 5.51 // 6 = memory allocation error // 7 = corrupt section 7. // // REMARKS: None // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$// { g2int ierr,isecnum; g2int ipos,lensec; g2float *lfld; ierr=0; *fld=0; //NULL gbit(cgrib,&lensec,*iofst,32); // Get Length of Section *iofst=*iofst+32; gbit(cgrib,&isecnum,*iofst,8); // Get Section Number *iofst=*iofst+8; if ( isecnum != 7 ) { ierr=2; //fprintf(stderr,"g2_unpack7: Not Section 7 data.\n"); return(ierr); } ipos=(*iofst/8); lfld=(g2float *)calloc(ndpts ? ndpts : 1,sizeof(g2float)); if (lfld == 0) { ierr=6; return(ierr); } *fld=lfld; if (idrsnum == 0) simunpack(cgrib+ipos,idrstmpl,ndpts,lfld); else if (idrsnum == 2 || idrsnum == 3) { if (comunpack(cgrib+ipos,lensec,idrsnum,idrstmpl,ndpts,lfld) != 0) { return 7; } } else if( idrsnum == 4 ) { // Grid point data - IEEE Floating Point Data static const int one = 1; int is_lsb = *((char*)&one) == 1; if (idrstmpl[0] == 1) { // IEEE754 single precision memcpy(lfld, cgrib+ipos, 4 * ndpts ); if( is_lsb ) { int i; unsigned char* ch_fld = (unsigned char*) lfld; for(i=0;i<ndpts;i++) { unsigned char temp = ch_fld[i*4]; ch_fld[i*4] = ch_fld[i*4+3]; ch_fld[i*4+3] = temp; temp = ch_fld[i*4+1]; ch_fld[i*4+1] = ch_fld[i*4+2]; ch_fld[i*4+2] = temp; } } } else if( idrstmpl[0] == 2) { // IEEE754 double precision // FIXME? due to the interface: we downgrade it to float int i; unsigned char* src = cgrib+ipos; if( is_lsb ) { for(i=0;i<ndpts;i++) { unsigned char temp[8]; double d; { int j; for(j = 0; j < 8; j++ ) temp[j] = src[i * 8 + 7 - j]; } memcpy(&d, temp, 8); lfld[i] = DoubleToFloatClamp(d); } } else { for(i=0;i<ndpts;i++) { double d; memcpy(&d, src + i * 8, 8); lfld[i] = DoubleToFloatClamp(d); } } } else { fprintf(stderr,"g2_unpack7: Invalid precision=%ld for Data Section 5.4.\n", idrstmpl[0]); ierr=5; free(lfld); *fld=0; //NULL return(ierr); } } else if (idrsnum == 50) { // Spectral Simple simunpack(cgrib+ipos,idrstmpl,ndpts-1,lfld+1); rdieee(idrstmpl+4,lfld+0,1); } else if (idrsnum == 51) // Spectral complex if ( igdsnum>=50 && igdsnum <=53 ) specunpack(cgrib+ipos,idrstmpl,ndpts,igdstmpl[0],igdstmpl[2],igdstmpl[2],lfld); else { fprintf(stderr,"g2_unpack7: Cannot use GDT 3.%d to unpack Data Section 5.51.\n",(int)igdsnum); ierr=5; free(lfld); *fld=0; //NULL return(ierr); } #ifdef USE_JPEG2000 else if (idrsnum == 40 || idrsnum == 40000) { jpcunpack(cgrib+ipos,lensec-5,idrstmpl,ndpts,lfld); } #endif /* USE_JPEG2000 */ #ifdef USE_PNG else if (idrsnum == 41 || idrsnum == 40010) { pngunpack(cgrib+ipos,lensec-5,idrstmpl,ndpts,lfld); } #endif /* USE_PNG */ else { fprintf(stderr,"g2_unpack7: Data Representation Template 5.%d not yet implemented.\n",(int)idrsnum); ierr=4; free(lfld); *fld=0; //NULL return(ierr); } *iofst=*iofst+(8*lensec); return(ierr); // End of Section 7 processing }
void seekgb(FILE *lugb,g2int iseek,g2int mseek,g2int *lskip,g2int *lgrib) /*$$$ SUBPROGRAM DOCUMENTATION BLOCK // // SUBPROGRAM: seekgb Searches a file for the next GRIB message. // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 // // ABSTRACT: This subprogram searches a file for the next GRIB Message. // The search is done starting at byte offset iseek of the file referenced // by lugb for mseek bytes at a time. // If found, the starting position and length of the message are returned // in lskip and lgrib, respectively. // The search is terminated when an EOF or I/O error is encountered. // // PROGRAM HISTORY LOG: // 2002-10-28 GILBERT Modified from Iredell's skgb subroutine // 2009-01-16 VUONG Changed lskip to 4 instead of sizof(g2int) // // USAGE: seekgb(FILE *lugb,g2int iseek,g2int mseek,int *lskip,int *lgrib) // INPUT ARGUMENTS: // lugb - FILE pointer for the file to search. File must be // opened before this routine is called. // iseek - number of bytes in the file to skip before search // mseek - number of bytes to search at a time // OUTPUT ARGUMENTS: // lskip - number of bytes to skip from the beggining of the file // to where the GRIB message starts // lgrib - number of bytes in message (set to 0, if no message found) // // ATTRIBUTES: // LANGUAGE: C // //$$$*/ { g2int ret; g2int k,k4,ipos,nread,lim,start,vers,lengrib; int end; unsigned char *cbuf; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ *lgrib=0; cbuf=(unsigned char *)malloc(mseek); nread=mseek; ipos=iseek; /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/ /* LOOP UNTIL GRIB MESSAGE IS FOUND*/ while (*lgrib==0 && nread==mseek) { /* READ PARTIAL SECTION*/ ret=fseek(lugb,ipos,SEEK_SET); nread=fread(cbuf,sizeof(unsigned char),mseek,lugb); lim=nread-8; /* LOOK FOR 'GRIB...' IN PARTIAL SECTION*/ for (k=0;k<lim;k++) { gbit(cbuf,&start,(k+0)*8,4*8); gbit(cbuf,&vers,(k+7)*8,1*8); if (start==1196575042 && (vers==1 || vers==2)) { /* LOOK FOR '7777' AT END OF GRIB MESSAGE*/ if (vers == 1) gbit(cbuf,&lengrib,(k+4)*8,3*8); if (vers == 2) gbit(cbuf,&lengrib,(k+12)*8,4*8); ret=fseek(lugb,ipos+k+lengrib-4,SEEK_SET); /* Hard code to 4 instead of sizeof(g2int)*/ k4=fread(&end,4,1,lugb); if (k4 == 1 && end == 926365495) { /*GRIB message found*/ *lskip=ipos+k; *lgrib=lengrib; break; } } } ipos=ipos+lim; } free(cbuf); }
g2int g2_unpack2(unsigned char *cgrib, size_t sz, g2int *iofst,g2int *lencsec2, unsigned char **csec2) /*//$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack2 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This subroutine unpacks Section 2 (Local Use Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // 2008-12-23 Wesley - Initialize lencsec2 Length of Local Use data // 2014-02-25 Steve Emmerson - Add length-checking of "cgrib" // // USAGE: int g2_unpack2(unsigned char *cgrib, size_t sz, g2int *iofst, // g2int *lencsec2, unsigned char **csec2) // INPUT ARGUMENT LIST: // cgrib - char array containing Section 2 of the GRIB2 message // sz - size of "cgrib" array in bytes // iofst - Bit offset for the beginning of Section 2 in cgrib. // // OUTPUT ARGUMENT LIST: // iofst - Bit offset at the end of Section 2, returned. // lencsec2 - Length (in octets) of Local Use data // csec2 - Pointer to a char array containing local use data // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 2 = Array passed is not section 2 // 6 = memory allocation error // // REMARKS: None // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$//*/ { g2int ierr,isecnum; g2int lensec,ipos,j; size_t bitsz = sz * 8; ierr=0; *lencsec2=0; *csec2=0; /* NULL*/ if (*iofst + 40 > bitsz) { fprintf(stderr, "Section too short to contain length and section " "number"); ierr=2; return(ierr); } gbit(cgrib,&lensec,*iofst,32); /* Get Length of Section*/ *iofst=*iofst+32; *lencsec2=lensec-5; gbit(cgrib,&isecnum,*iofst,8); /* Get Section Number*/ *iofst=*iofst+8; ipos=(*iofst/8); if ( isecnum != 2 ) { ierr=2; *lencsec2=0; fprintf(stderr,"g2_unpack2: Not Section 2 data.\n"); return(ierr); } *csec2=(unsigned char *)malloc(*lencsec2+1); if (*csec2 == 0) { ierr=6; *lencsec2=0; return(ierr); } /*printf(" SAGIPO %d \n",(int)ipos);*/ if (ipos + *lencsec2 > sz) { fprintf(stderr, "Section too short to contain required data"); ierr=2; return(ierr); } for (j=0;j<*lencsec2;j++) { *(*csec2+j)=cgrib[ipos+j]; } *iofst=*iofst+(*lencsec2*8); return(ierr); /* End of Section 2 processing*/ }
g2int g2_unpack4(unsigned char *cgrib,g2int *iofst,g2int *ipdsnum,g2int **ipdstmpl, g2int *mappdslen,g2float **coordlist,g2int *numcoord) ////$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack4 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This subroutine unpacks Section 4 (Product Definition Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // // USAGE: int g2_unpack4(unsigned char *cgrib,g2int *iofst,g2int *ipdsnum, // g2int **ipdstmpl,g2int *mappdslen, // g2float **coordlist,g2int *numcoord) // INPUT ARGUMENTS: // cgrib - Char array containing Section 4 of the GRIB2 message // iofst - Bit offset of the beginning of Section 4 in cgrib. // // OUTPUT ARGUMENTS: // iofst - Bit offset of the end of Section 4, returned. // ipdsnum - Product Definition Template Number ( see Code Table 4.0) // ipdstmpl - Pointer to integer array containing the data values for // the specified Product Definition // Template ( N=ipdsnum ). Each element of this integer // array contains an entry (in the order specified) of Product // Defintion Template 4.N // mappdslen- Number of elements in ipdstmpl[]. i.e. number of entries // in Product Defintion Template 4.N ( N=ipdsnum ). // coordlist- Pointer to real array containing floating point values // intended to document // the vertical discretisation associated to model data // on hybrid coordinate vertical levels. (part of Section 4) // numcoord - number of values in array coordlist. // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 2 = Not section 4 // 5 = "GRIB" message contains an undefined Product Definition // Template. // 6 = memory allocation error // // REMARKS: // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$// { g2int ierr,needext,i,j,nbits,isecnum; g2int lensec,isign,newlen; g2int *coordieee; g2int *lipdstmpl=0; g2float *lcoordlist; xxtemplate *mappds; ierr=0; *ipdstmpl=0; // NULL *coordlist=0; // NULL gbit(cgrib,&lensec,*iofst,32); // Get Length of Section *iofst=*iofst+32; gbit(cgrib,&isecnum,*iofst,8); // Get Section Number *iofst=*iofst+8; if ( isecnum != 4 ) { ierr=2; *numcoord=0; *mappdslen=0; // fprintf(stderr,"g2_unpack4: Not Section 4 data.\n"); return(ierr); } gbit(cgrib,numcoord,*iofst,16); // Get num of coordinate values *iofst=*iofst+16; gbit(cgrib,ipdsnum,*iofst,16); // Get Prod. Def Template num. *iofst=*iofst+16; // Get Product Definition Template mappds=getpdstemplate(*ipdsnum); if (mappds == 0) { // undefine template ierr=5; *mappdslen=0; return(ierr); } *mappdslen=mappds->maplen; needext=mappds->needext; // // Unpack each value into array ipdstmpl from the // the appropriate number of octets, which are specified in // corresponding entries in array mappds. // if (*mappdslen > 0) lipdstmpl=(g2int *)calloc(*mappdslen,sizeof(g2int)); if (lipdstmpl == 0) { ierr=6; *mappdslen=0; *ipdstmpl=0; //NULL if ( mappds != 0 ) free(mappds); return(ierr); } else { *ipdstmpl=lipdstmpl; } for (i=0;i<mappds->maplen;i++) { nbits=abs(mappds->map[i])*8; if ( mappds->map[i] >= 0 ) { gbit(cgrib,lipdstmpl+i,*iofst,nbits); } else { gbit(cgrib,&isign,*iofst,1); gbit(cgrib,lipdstmpl+i,*iofst+1,nbits-1); if (isign == 1) lipdstmpl[i]=-1*lipdstmpl[i]; } *iofst=*iofst+nbits; } // // Check to see if the Product Definition Template needs to be // extended. // The number of values in a specific template may vary // depending on data specified in the "static" part of the // template. // if ( needext ==1 ) { free(mappds); mappds=extpdstemplate(*ipdsnum,lipdstmpl); newlen=mappds->maplen+mappds->extlen; lipdstmpl=(g2int *)realloc(lipdstmpl,newlen*sizeof(g2int)); *ipdstmpl=lipdstmpl; // Unpack the rest of the Product Definition Template j=0; for (i=*mappdslen;i<newlen;i++) { nbits=abs(mappds->ext[j])*8; if ( mappds->ext[j] >= 0 ) { gbit(cgrib,lipdstmpl+i,*iofst,nbits); } else { gbit(cgrib,&isign,*iofst,1); gbit(cgrib,lipdstmpl+i,*iofst+1,nbits-1); if (isign == 1) lipdstmpl[i]=-1*lipdstmpl[i]; } *iofst=*iofst+nbits; j++; } *mappdslen=newlen; } if( mappds->ext != 0 ) free(mappds->ext); if( mappds != 0 ) free(mappds); // // Get Optional list of vertical coordinate values // after the Product Definition Template, if necessary. // *coordlist=0; // NULL if ( *numcoord != 0 ) { coordieee=(g2int *)calloc(*numcoord,sizeof(g2int)); lcoordlist=(g2float *)calloc(*numcoord,sizeof(g2float)); if (coordieee == 0 || lcoordlist == 0) { ierr=6; *numcoord=0; *coordlist=0; // NULL if( coordieee != 0 ) free(coordieee); if( lcoordlist != 0 ) free(lcoordlist); return(ierr); } else { *coordlist=lcoordlist; } gbits(cgrib,coordieee,*iofst,32,0,*numcoord); rdieee(coordieee,*coordlist,*numcoord); free(coordieee); *iofst=*iofst+(32*(*numcoord)); } return(ierr); // End of Section 4 processing }
g2int g2_info(unsigned char *cgrib,int sz,g2int *listsec0,g2int *listsec1, g2int *numfields,g2int *numlocal) /*$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_info // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 // // ABSTRACT: This subroutine searches through a GRIB2 message and // returns the number of gridded fields found in the message and // the number (and maximum size) of Local Use Sections. // Also various checks are performed // to see if the message is a valid GRIB2 message. // // PROGRAM HISTORY LOG: // 2002-10-28 Gilbert // ????-??-?? S. Chiswell modified to pass message size to ensure reading // doesn't go past message length // 2013-05-28 Steve Emmerson modified to increase the level of verification of // the GRIB2 message structure. // // USAGE: int g2_info(unsigned char *cgrib, g2int sz, g2int *listsec0, // g2int *listsec1, g2int *numfields,g2int *numlocal) // INPUT ARGUMENTS: // cgrib - Character pointer to the GRIB2 message. May have junk in the // first 100 bytes before the "GRIB" sentinel and may have junk // after the valid GRIB message. // sz - Length of "cgrib" data in bytes // // OUTPUT ARGUMENTS: // listsec0 - pointer to an array containing information decoded from // GRIB Indicator Section 0. // Must be allocated with >= 3 elements. // listsec0[0]=Discipline-GRIB Master Table Number // (see Code Table 0.0) // listsec0[1]=GRIB Edition Number (currently 2) // listsec0[2]=Length of GRIB message // listsec1 - pointer to an array containing information read from GRIB // Identification Section 1. // Must be allocated with >= 13 elements. // listsec1[0]=Id of orginating centre (Common Code Table C-1) // listsec1[1]=Id of orginating sub-centre (local table) // listsec1[2]=GRIB Master Tables Version Number (Code Table 1.0) // listsec1[3]=GRIB Local Tables Version Number // listsec1[4]=Significance of Reference Time (Code Table 1.1) // listsec1[5]=Reference Time - Year (4 digits) // listsec1[6]=Reference Time - Month // listsec1[7]=Reference Time - Day // listsec1[8]=Reference Time - Hour // listsec1[9]=Reference Time - Minute // listsec1[10]=Reference Time - Second // listsec1[11]=Production status of data (Code Table 1.2) // listsec1[12]=Type of processed data (Code Table 1.3) // numfields- The number of gridded fields found in the GRIB message. // That is, the number of occurences of Sections 4 - 7. // numlocal - The number of Local Use Sections ( Section 2 ) found in // the GRIB message. // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 1 = Beginning characters "GRIB" not found. // 2 = GRIB message is not Edition 2. // 3 = Could not find Section 1 where expected. // 4 = End string "7777" found prematurely // 5 = End string "7777" not found at end of message. // 6 = Invalid section number found. // 7 = Invalid total or section length parameter in message // // REMARKS: This function ASSUMES that "CHAR_BIT == 8" // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$*/ { /* * NB: The following 3 parameters must be kept consonant. */ # define MAP_SEC1_LEN 13 const g2int mapsec1[MAP_SEC1_LEN]={2,2,1,1,1,2,1,1,1,1,1,1,1}; const int MIN_LEN_SEC_1 = 16; /* minimum length, in bytes, of section 1 */ g2int i,j,istart,iofst,lengrib,lensec1; g2int ipos,isecnum,nbits,lensec; long remaining; /* number of bytes remaining to be decoded */ *numlocal=0; *numfields=0; /* // Check for beginning of GRIB message in the first 100 bytes // S. Chiswell, constrain to j<sz too*/ istart=-1; for (j=0;j<sz-3 && j<100;j++) { if (cgrib[j]=='G' && cgrib[j+1]=='R' &&cgrib[j+2]=='I' && cgrib[j+3]=='B') { istart=j; break; } } if (istart == -1) { printf("g2_info: Beginning characters GRIB not found.\n"); return 1; } remaining = sz - istart; /* * Unpack Section 0 - Indicator Section */ # define LEN_SEC_0 16 /* The length, in bytes, of section 0. */ if (LEN_SEC_0 > remaining) { printf("g2_info: Sanity check, bulletin too small to contain section 0: %ld\n", remaining); return 7; } iofst=8*(istart+6); gbit(cgrib,listsec0+0,iofst,8); /* Discipline*/ iofst=iofst+8; gbit(cgrib,listsec0+1,iofst,8); /* GRIB edition number*/ iofst=iofst+8; iofst=iofst+32; gbit(cgrib,&lengrib,iofst,32); /* Length of GRIB message*/ iofst=iofst+32; listsec0[2]=lengrib; /* * Validate length of GRIB message. S. Chiswell & S. Emmerson. */ if (lengrib < LEN_SEC_0 || lengrib > remaining) { printf("g2_info: Sanity check, grib length too big or too small: %ld\n", (long)lengrib); return 7; } ipos=istart+LEN_SEC_0; remaining = lengrib - LEN_SEC_0; /* * Currently handles only GRIB Edition 2. */ if (listsec0[1] != 2) { printf("g2_info: can only decode GRIB edition 2.\n"); return 2; } /* * Unpack Section 1 - Identification Section */ if (MIN_LEN_SEC_1 > remaining) { printf("g2_info: Sanity check, bulletin too small to contain section 1: %ld\n", remaining); } gbit(cgrib,&lensec1,iofst,32); /* Length of Section 1*/ iofst=iofst+32; /* * Validate length of section 1. S. Emmerson. */ if (lensec1 < MIN_LEN_SEC_1 || lensec1 > remaining) { printf("g2_info: Sanity check, section 1 length too big or too small: %ld\n", (long)lensec1); return 7; } /* * Decode and validate the section number. */ gbit(cgrib,&isecnum,iofst,8); iofst=iofst+8; if (isecnum != 1) { printf("g2_info: Could not find section 1.\n"); return 3; } /* * Unpack each input value in array listsec1 into the * the appropriate number of octets, which are specified in * corresponding entries in array mapsec1. */ for (i=0;i<MAP_SEC1_LEN;i++) { nbits=mapsec1[i]*8; gbit(cgrib,listsec1+i,iofst,nbits); iofst=iofst+nbits; } ipos += lensec1; remaining -= lensec1; /* * Loop through the remaining sections to see if they are valid. * Also count the number of times Section 2 * and Section 4 appear. */ while (remaining >= 4) { if (cgrib[ipos]=='7' && cgrib[ipos+1]=='7' && cgrib[ipos+2]=='7' && cgrib[ipos+3]=='7') { remaining -= 4; if (remaining) { printf("g2_info: '7777' found, but not where expected.\n"); return 4; } return 0; } /* * Minimum length of a section in bytes (section length & section number) */ # define MIN_LEN_SEC 5 if (remaining < MIN_LEN_SEC) { printf("g2_info: Sanity check, section too small: %ld\n", remaining); return 7; } iofst=ipos*8; /* * Decode and validate the section length. */ gbit(cgrib,&lensec,iofst,32); iofst=iofst+32; if (lensec < MIN_LEN_SEC || lensec > remaining) { printf("g2_info: Sanity check, section length too big or too small: %ld\n", (long)lensec); return 7; } /* * Decode and validate the section number. */ gbit(cgrib,&isecnum,iofst,8); iofst=iofst+8; if ( isecnum>=2 && isecnum<=7 ) { if (isecnum == 2) { /* Local Section 2*/ /* increment counter for total number of local sections found*/ (*numlocal)++; } else if (isecnum == 4) { /* increment counter for total number of fields found*/ (*numfields)++; } } else { printf("g2_info: Invalid section number found in GRIB message: %ld\n", (long)isecnum); return 6; } ipos += lensec; /* Update beginning of section pointer*/ remaining -= lensec; } /* while sufficient bytes remain */ if (remaining) { printf("g2_info: '7777' not found at end of GRIB message.\n"); return 5; } return 0; }
g2int g2_unpack6(unsigned char *cgrib,size_t sz,g2int *iofst,g2int ngpts, g2int *ibmap, g2int **bmap) /*$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack6 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This subroutine unpacks Section 6 (Bit-Map Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // 2014-02-25 Steve Emmerson (UCAR/Unidata) Add length-checking of "cgrib" // array // // USAGE: int g2_unpack6(unsigned char *cgrib,size_t sz, g2int *iofst, // g2int ngpts, g2int *ibmap,g2int **bmap) // INPUT ARGUMENTS: // cgrib - char array containing Section 6 of the GRIB2 message // sz - Size of "cgrib" array in bytes // iofst - Bit offset of the beginning of Section 6 in cgrib. // ngpts - Number of grid points specified in the bit-map // // OUTPUT ARGUMENTS: // iofst - Bit offset at the end of Section 6, returned. // ibmap - Bitmap indicator ( see Code Table 6.0 ) // 0 = bitmap applies and is included in Section 6. // 1-253 = Predefined bitmap applies // 254 = Previously defined bitmap applies to this field // 255 = Bit map does not apply to this product. // bmap - Pointer to an integer array containing decoded bitmap. // ( if ibmap=0 ) // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 2 = Not Section 6 // 4 = Unrecognized pre-defined bit-map. // 6 = memory allocation error // // REMARKS: None // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$*/ { g2int j,ierr,isecnum; g2int *lbmap=0; g2int *intbmap; size_t bitsz = sz * 8; ierr=0; *bmap=0; /*NULL*/ if (*iofst + 40 > bitsz) return 2; *iofst=*iofst+32; /* skip Length of Section*/ gbit(cgrib,&isecnum,*iofst,8); /* Get Section Number*/ *iofst=*iofst+8; if ( isecnum != 6 ) { ierr=2; fprintf(stderr,"g2_unpack6: Not Section 6 data.\n"); return(ierr); } if (*iofst + 8 > bitsz) return 2; gbit(cgrib,ibmap,*iofst,8); /* Get bit-map indicator*/ *iofst=*iofst+8; if (*ibmap == 0) { /* Unpack bitmap*/ if (ngpts > 0) lbmap=(g2int *)calloc(ngpts,sizeof(g2int)); if (lbmap == 0) { ierr=6; return(ierr); } else { *bmap=lbmap; } intbmap=(g2int *)calloc(ngpts,sizeof(g2int)); if (*iofst + ngpts > bitsz) { if (intbmap) free(intbmap); return 2; } gbits(cgrib,intbmap,*iofst,1,0,ngpts); *iofst=*iofst+ngpts; for (j=0;j<ngpts;j++) { lbmap[j]=(g2int)intbmap[j]; } free(intbmap); /* else if (*ibmap.eq.254) ! Use previous bitmap // return(ierr); // else if (*ibmap.eq.255) ! No bitmap in message // bmap(1:ngpts)=.true. // else { // print *,'gf_unpack6: Predefined bitmap ',*ibmap,' not recognized.' // ierr=4;*/ } return(ierr); /* End of Section 6 processing*/ }
g2int g2_unpack3(unsigned char *cgrib,g2int *iofst,g2int **igds,g2int **igdstmpl, g2int *mapgridlen,g2int **ideflist,g2int *idefnum) ////$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack3 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This routine unpacks Section 3 (Grid Definition Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // // USAGE: int g2_unpack3(unsigned char *cgrib,g2int *iofst,g2int **igds, // g2int **igdstmpl,g2int *mapgridlen, // g2int **ideflist,g2int *idefnum) // INPUT ARGUMENTS: // cgrib - Char array ontaining Section 3 of the GRIB2 message // iofst - Bit offset for the beginning of Section 3 in cgrib. // // OUTPUT ARGUMENTS: // iofst - Bit offset at the end of Section 3, returned. // igds - Contains information read from the appropriate GRIB Grid // Definition Section 3 for the field being returned. // igds[0]=Source of grid definition (see Code Table 3.0) // igds[1]=Number of grid points in the defined grid. // igds[2]=Number of octets needed for each // additional grid points definition. // Used to define number of // points in each row ( or column ) for // non-regular grids. // = 0, if using regular grid. // igds[3]=Interpretation of list for optional points // definition. (Code Table 3.11) // igds[4]=Grid Definition Template Number (Code Table 3.1) // igdstmpl - Pointer to integer array containing the data values for // the specified Grid Definition // Template ( NN=igds[4] ). Each element of this integer // array contains an entry (in the order specified) of Grid // Defintion Template 3.NN // mapgridlen- Number of elements in igdstmpl[]. i.e. number of entries // in Grid Defintion Template 3.NN ( NN=igds[4] ). // ideflist - (Used if igds[2] .ne. 0) Pointer to integer array containing // the number of grid points contained in each row ( or column ). // (part of Section 3) // idefnum - (Used if igds[2] .ne. 0) The number of entries // in array ideflist. i.e. number of rows ( or columns ) // for which optional grid points are defined. // ierr - Error return code. // 0 = no error // 2 = Not Section 3 // 5 = "GRIB" message contains an undefined Grid Definition // Template. // 6 = memory allocation error // // REMARKS: // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ { g2int ierr,i,j,nbits,isecnum; g2int lensec,ibyttem=0,isign,newlen; g2int *ligds,*ligdstmpl=0,*lideflist=0; xxtemplate *mapgrid; ierr=0; *igds=0; // NULL *igdstmpl=0; // NULL *ideflist=0; // NULL gbit(cgrib,&lensec,*iofst,32); // Get Length of Section *iofst=*iofst+32; gbit(cgrib,&isecnum,*iofst,8); // Get Section Number *iofst=*iofst+8; if ( isecnum != 3 ) { ierr=2; *idefnum=0; *mapgridlen=0; // fprintf(stderr,"g2_unpack3: Not Section 3 data.\n"); return(ierr); } ligds=(g2int *)calloc(5,sizeof(g2int)); *igds=ligds; gbit(cgrib,ligds+0,*iofst,8); // Get source of Grid def. *iofst=*iofst+8; gbit(cgrib,ligds+1,*iofst,32); // Get number of grid pts. *iofst=*iofst+32; gbit(cgrib,ligds+2,*iofst,8); // Get num octets for opt. list *iofst=*iofst+8; gbit(cgrib,ligds+3,*iofst,8); // Get interpret. for opt. list *iofst=*iofst+8; gbit(cgrib,ligds+4,*iofst,16); // Get Grid Def Template num. *iofst=*iofst+16; if (ligds[4] != 65535) { // Get Grid Definition Template mapgrid=getgridtemplate(ligds[4]); if (mapgrid == 0) { // undefined template ierr=5; return(ierr); } *mapgridlen=mapgrid->maplen; // // Unpack each value into array igdstmpl from the // the appropriate number of octets, which are specified in // corresponding entries in array mapgrid. // if (*mapgridlen > 0) { ligdstmpl=0; ligdstmpl=(g2int *)calloc(*mapgridlen,sizeof(g2int)); if (ligdstmpl == 0) { ierr=6; *mapgridlen=0; *igdstmpl=0; //NULL if( mapgrid != 0 ) free(mapgrid); return(ierr); } else { *igdstmpl=ligdstmpl; } } ibyttem=0; for (i=0;i<*mapgridlen;i++) { nbits=abs(mapgrid->map[i])*8; if ( mapgrid->map[i] >= 0 ) { gbit(cgrib,ligdstmpl+i,*iofst,nbits); } else { gbit(cgrib,&isign,*iofst,1); gbit(cgrib,ligdstmpl+i,*iofst+1,nbits-1); if (isign == 1) ligdstmpl[i]=-1*ligdstmpl[i]; } *iofst=*iofst+nbits; ibyttem=ibyttem+abs(mapgrid->map[i]); } // // Check to see if the Grid Definition Template needs to be // extended. // The number of values in a specific template may vary // depending on data specified in the "static" part of the // template. // if ( mapgrid->needext == 1 ) { free(mapgrid); mapgrid=extgridtemplate(ligds[4],ligdstmpl); // Unpack the rest of the Grid Definition Template newlen=mapgrid->maplen+mapgrid->extlen; ligdstmpl=(g2int *)realloc(ligdstmpl,newlen*sizeof(g2int)); *igdstmpl=ligdstmpl; j=0; for (i=*mapgridlen;i<newlen;i++) { nbits=abs(mapgrid->ext[j])*8; if ( mapgrid->ext[j] >= 0 ) { gbit(cgrib,ligdstmpl+i,*iofst,nbits); } else { gbit(cgrib,&isign,*iofst,1); gbit(cgrib,ligdstmpl+i,*iofst+1,nbits-1); if (isign == 1) ligdstmpl[i]=-1*ligdstmpl[i]; } *iofst=*iofst+nbits; ibyttem=ibyttem+abs(mapgrid->ext[j]); j++; } *mapgridlen=newlen; } if( mapgrid->ext != 0 ) free(mapgrid->ext); if( mapgrid != 0 ) free(mapgrid); } else { // No Grid Definition Template *mapgridlen=0; *igdstmpl=0; } // // Unpack optional list of numbers defining number of points // in each row or column, if included. This is used for non regular // grids. // if ( ligds[2] != 0 ) { nbits=ligds[2]*8; *idefnum=(lensec-14-ibyttem)/ligds[2]; if (*idefnum > 0) lideflist=(g2int *)calloc(*idefnum,sizeof(g2int)); if (lideflist == 0) { ierr=6; *idefnum=0; *ideflist=0; //NULL return(ierr); } else { *ideflist=lideflist; } gbits(cgrib,lideflist,*iofst,nbits,0,*idefnum); *iofst=*iofst+(nbits*(*idefnum)); } else { *idefnum=0; *ideflist=0; // NULL } return(ierr); // End of Section 3 processing }
g2int g2_addgrid(unsigned char *cgrib,g2int *igds,g2int *igdstmpl,g2int *ideflist,g2int idefnum) //$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_addgrid // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-01 // // ABSTRACT: This routine packs up a Grid Definition Section (Section 3) // and adds it to a GRIB2 message. It is used with routines "g2_create", // "g2_addlocal", "g2_addfield", // and "g2_gribend" to create a complete GRIB2 message. // g2_create must be called first to initialize a new GRIB2 message. // // PROGRAM HISTORY LOG: // 2002-11-01 Gilbert // 2009-01-14 Vuong Changed structure name template to gtemplate // // USAGE: int g2_addgrid(unsigned char *cgrib,g2int *igds,g2int *igdstmpl, // g2int *ideflist,g2int idefnum) // INPUT ARGUMENTS: // cgrib - Char array that contains the GRIB2 message to which // section should be added. // igds - Contains information needed for GRIB Grid Definition Section 3 // Must be dimensioned >= 5. // igds[0]=Source of grid definition (see Code Table 3.0) // igds[1]=Number of grid points in the defined grid. // igds[2]=Number of octets needed for each // additional grid points definition. // Used to define number of // points in each row ( or column ) for // non-regular grids. // = 0, if using regular grid. // igds[3]=Interpretation of list for optional points // definition. (Code Table 3.11) // igds[4]=Grid Definition Template Number (Code Table 3.1) // igdstmpl - Contains the data values for the specified Grid Definition // Template ( NN=igds[4] ). Each element of this integer // array contains an entry (in the order specified) of Grid // Defintion Template 3.NN // ideflist - (Used if igds[2] != 0) This array contains the // number of grid points contained in each row ( or column ) // idefnum - (Used if igds[2] != 0) The number of entries // in array ideflist. i.e. number of rows ( or columns ) // for which optional grid points are defined. // // OUTPUT ARGUMENTS: // cgrib - Char array to contain the updated GRIB2 message. // Must be allocated large enough to store the entire // GRIB2 message. // // RETURN VALUES: // ierr - Return code. // > 0 = Current size of updated GRIB2 message // -1 = GRIB message was not initialized. Need to call // routine gribcreate first. // -2 = GRIB message already complete. Cannot add new section. // -3 = Sum of Section byte counts doesn't add to total byte count // -4 = Previous Section was not 1, 2 or 7. // -5 = Could not find requested Grid Definition Template. // // REMARKS: Note that the Grid Def Section ( Section 3 ) can only follow // Section 1, 2 or Section 7 in a GRIB2 message. // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ { g2int ierr; static unsigned char G=0x47; // 'G' static unsigned char R=0x52; // 'R' static unsigned char I=0x49; // 'I' static unsigned char B=0x42; // 'B' static unsigned char seven=0x37; // '7' static g2int one=1,three=3,miss=65535; g2int lensec3,iofst,ibeg,lencurr,len; g2int i,j,temp,ilen,isecnum,nbits; gtemplate *mapgrid=0; ierr=0; // // Check to see if beginning of GRIB message exists // if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { // printf("g2_addgrid: GRIB not found in given message.\n"); // printf("g2_addgrid: Call to routine gribcreate required to initialize GRIB messge.\n"); ierr=-1; return(ierr); } // // Get current length of GRIB message // gbit(cgrib,&lencurr,96,32); // // Check to see if GRIB message is already complete // if ( cgrib[lencurr-4]==seven && cgrib[lencurr-3]==seven && cgrib[lencurr-2]==seven && cgrib[lencurr-1]==seven ) { // printf("g2_addgrid: GRIB message already complete. Cannot add new section.\n"); ierr=-2; return(ierr); } // // Loop through all current sections of the GRIB message to // find the last section number. // len=16; // length of Section 0 for (;;) { // Get section number and length of next section iofst=len*8; gbit(cgrib,&ilen,iofst,32); iofst=iofst+32; gbit(cgrib,&isecnum,iofst,8); len=len+ilen; // Exit loop if last section reached if ( len == lencurr ) break; // If byte count for each section doesn't match current // total length, then there is a problem. if ( len > lencurr ) { // printf("g2_addgrid: Section byte counts don''t add to total.\n"); // printf("g2_addgrid: Sum of section byte counts = %ld\n",len); // printf("g2_addgrid: Total byte count in Section 0 = %ld\n",lencurr); ierr=-3; return(ierr); } } // // Section 3 can only be added after sections 1, 2 and 7. // if ( (isecnum!=1) && (isecnum!=2) && (isecnum!=7) ) { // printf("g2_addgrid: Section 3 can only be added after Section 1, 2 or 7.\n"); // printf("g2_addgrid: Section ',isecnum,' was the last found in given GRIB message.\n"); ierr=-4; return(ierr); } // // Add Section 3 - Grid Definition Section // ibeg=lencurr*8; // Calculate offset for beginning of section 3 iofst=ibeg+32; // leave space for length of section sbit(cgrib,&three,iofst,8); // Store section number ( 3 ) iofst=iofst+8; sbit(cgrib,igds+0,iofst,8); // Store source of Grid def. iofst=iofst+8; sbit(cgrib,igds+1,iofst,32); // Store number of data pts. iofst=iofst+32; sbit(cgrib,igds+2,iofst,8); // Store number of extra octets. iofst=iofst+8; sbit(cgrib,igds+3,iofst,8); // Store interp. of extra octets. iofst=iofst+8; // if Octet 6 is not equal to zero, Grid Definition Template may // not be supplied. if ( igds[0] == 0 ) sbit(cgrib,igds+4,iofst,16); // Store Grid Def Template num. else sbit(cgrib,&miss,iofst,16); // Store missing value as Grid Def Template num. iofst=iofst+16; // // Get Grid Definition Template // if (igds[0] == 0) { mapgrid=getgridtemplate(igds[4]); if (mapgrid == 0) { // undefined template ierr=-5; return(ierr); } // // Extend the Grid Definition Template, if necessary. // The number of values in a specific template may vary // depending on data specified in the "static" part of the // template. // if ( mapgrid->needext ) { free(mapgrid); mapgrid=extgridtemplate(igds[4],igdstmpl); } } // // Pack up each input value in array igdstmpl into the // the appropriate number of octets, which are specified in // corresponding entries in array mapgrid. // for (i=0;i<mapgrid->maplen;i++) { nbits=abs(mapgrid->map[i])*8; if ( (mapgrid->map[i] >= 0) || (igdstmpl[i] >= 0) ) sbit(cgrib,igdstmpl+i,iofst,nbits); else { sbit(cgrib,&one,iofst,1); temp=abs(igdstmpl[i]); sbit(cgrib,&temp,iofst+1,nbits-1); } iofst=iofst+nbits; } // Pack template extension, if appropriate j=mapgrid->maplen; if ( mapgrid->needext && (mapgrid->extlen > 0) ) { for (i=0;i<mapgrid->extlen;i++) { nbits=abs(mapgrid->ext[i])*8; if ( (mapgrid->ext[i] >= 0) || (igdstmpl[j] >= 0) ) sbit(cgrib,igdstmpl+j,iofst,nbits); else { sbit(cgrib,&one,iofst,1); temp=abs(igdstmpl[j]); sbit(cgrib,&temp,iofst+1,nbits-1); } iofst=iofst+nbits; j++; } } free(mapgrid); // // If requested, // Insert optional list of numbers defining number of points // in each row or column. This is used for non regular // grids. // if ( igds[2] != 0 ) { nbits=igds[2]*8; sbits(cgrib,ideflist,iofst,nbits,0,idefnum); iofst=iofst+(nbits*idefnum); } // // Calculate length of section 3 and store it in octets // 1-4 of section 3. // lensec3=(iofst-ibeg)/8; sbit(cgrib,&lensec3,ibeg,32); // // Update current byte total of message in Section 0 // lencurr+=lensec3; sbit(cgrib,&lencurr,96,32); return(lencurr); }
g2int g2_getfld(unsigned char *cgrib,g2int ifldnum,g2int unpack,g2int expand, gribfield **gfld) //$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_getfld // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-28 // // ABSTRACT: This subroutine returns all the metadata, template values, // Bit-map ( if applicable ), and the unpacked data for a given data // field. All of the information returned is stored in a gribfield // structure, which is defined in file grib2.h. // Users of this routine will need to include "grib2.h" in their source // code that calls this routine. Each component of the gribfield // struct is also described in the OUTPUT ARGUMENTS section below. // // Since there can be multiple data fields packed into a GRIB2 // message, the calling routine indicates which field is being requested // with the ifldnum argument. // // PROGRAM HISTORY LOG: // 2002-10-28 Gilbert // // USAGE: #include "grib2.h" // int g2_getfld(unsigned char *cgrib,g2int ifldnum,g2int unpack, // g2int expand,gribfield **gfld) // INPUT ARGUMENTS: // cgrib - Character pointer to the GRIB2 message // ifldnum - Specifies which field in the GRIB2 message to return. // unpack - Boolean value indicating whether to unpack bitmap/data field // 1 = unpack bitmap (if present) and data values // 0 = do not unpack bitmap and data values // expand - Boolean value indicating whether the data points should be // expanded to the correspond grid, if a bit-map is present. // 1 = if possible, expand data field to grid, inserting zero // values at gridpoints that are bitmapped out. // (SEE REMARKS2) // 0 = do not expand data field, leaving it an array of // consecutive data points for each "1" in the bitmap. // This argument is ignored if unpack == 0 OR if the // returned field does not contain a bit-map. // // OUTPUT ARGUMENT: // gribfield gfld; - pointer to structure gribfield containing // all decoded data for the data field. // // gfld->version = GRIB edition number ( currently 2 ) // gfld->discipline = Message Discipline ( see Code Table 0.0 ) // gfld->idsect = Contains the entries in the Identification // Section ( Section 1 ) // This element is a pointer to an array // that holds the data. // gfld->idsect[0] = Identification of originating Centre // ( see Common Code Table C-1 ) // 7 - US National Weather Service // gfld->idsect[1] = Identification of originating Sub-centre // gfld->idsect[2] = GRIB Master Tables Version Number // ( see Code Table 1.0 ) // 0 - Experimental // 1 - Initial operational version number // gfld->idsect[3] = GRIB Local Tables Version Number // ( see Code Table 1.1 ) // 0 - Local tables not used // 1-254 - Number of local tables version used // gfld->idsect[4] = Significance of Reference Time (Code Table 1.2) // 0 - Analysis // 1 - Start of forecast // 2 - Verifying time of forecast // 3 - Observation time // gfld->idsect[5] = Year ( 4 digits ) // gfld->idsect[6] = Month // gfld->idsect[7) = Day // gfld->idsect[8] = Hour // gfld->idsect[9] = Minute // gfld->idsect[10] = Second // gfld->idsect[11] = Production status of processed data // ( see Code Table 1.3 ) // 0 - Operational products // 1 - Operational test products // 2 - Research products // 3 - Re-analysis products // gfld->idsect[12] = Type of processed data ( see Code Table 1.4 ) // 0 - Analysis products // 1 - Forecast products // 2 - Analysis and forecast products // 3 - Control forecast products // 4 - Perturbed forecast products // 5 - Control and perturbed forecast products // 6 - Processed satellite observations // 7 - Processed radar observations // gfld->idsectlen = Number of elements in gfld->idsect[]. // gfld->local = Pointer to character array containing contents // of Local Section 2, if included // gfld->locallen = length of array gfld->local[] // gfld->ifldnum = field number within GRIB message // gfld->griddef = Source of grid definition (see Code Table 3.0) // 0 - Specified in Code table 3.1 // 1 - Predetermined grid Defined by originating centre // gfld->ngrdpts = Number of grid points in the defined grid. // gfld->numoct_opt = Number of octets needed for each // additional grid points definition. // Used to define number of // points in each row ( or column ) for // non-regular grids. // = 0, if using regular grid. // gfld->interp_opt = Interpretation of list for optional points // definition. (Code Table 3.11) // gfld->igdtnum = Grid Definition Template Number (Code Table 3.1) // gfld->igdtmpl = Contains the data values for the specified Grid // Definition Template ( NN=gfld->igdtnum ). Each // element of this integer array contains an entry (in // the order specified) of Grid Defintion Template 3.NN // This element is a pointer to an array // that holds the data. // gfld->igdtlen = Number of elements in gfld->igdtmpl[]. i.e. number of // entries in Grid Defintion Template 3.NN // ( NN=gfld->igdtnum ). // gfld->list_opt = (Used if gfld->numoct_opt .ne. 0) This array // contains the number of grid points contained in // each row ( or column ). (part of Section 3) // This element is a pointer to an array // that holds the data. This pointer is nullified // if gfld->numoct_opt=0. // gfld->num_opt = (Used if gfld->numoct_opt .ne. 0) // The number of entries // in array ideflist. i.e. number of rows ( or columns ) // for which optional grid points are defined. This value // is set to zero, if gfld->numoct_opt=0. // gfdl->ipdtnum = Product Definition Template Number(see Code Table 4.0) // gfld->ipdtmpl = Contains the data values for the specified Product // Definition Template ( N=gfdl->ipdtnum ). Each element // of this integer array contains an entry (in the // order specified) of Product Defintion Template 4.N. // This element is a pointer to an array // that holds the data. // gfld->ipdtlen = Number of elements in gfld->ipdtmpl[]. i.e. number of // entries in Product Defintion Template 4.N // ( N=gfdl->ipdtnum ). // gfld->coord_list = Real array containing floating point values // intended to document the vertical discretisation // associated to model data on hybrid coordinate // vertical levels. (part of Section 4) // This element is a pointer to an array // that holds the data. // gfld->num_coord = number of values in array gfld->coord_list[]. // gfld->ndpts = Number of data points unpacked and returned. // gfld->idrtnum = Data Representation Template Number // ( see Code Table 5.0) // gfld->idrtmpl = Contains the data values for the specified Data // Representation Template ( N=gfld->idrtnum ). Each // element of this integer array contains an entry // (in the order specified) of Product Defintion // Template 5.N. // This element is a pointer to an array // that holds the data. // gfld->idrtlen = Number of elements in gfld->idrtmpl[]. i.e. number // of entries in Data Representation Template 5.N // ( N=gfld->idrtnum ). // gfld->unpacked = logical value indicating whether the bitmap and // data values were unpacked. If false, // gfld->bmap and gfld->fld pointers are nullified. // gfld->expanded = Logical value indicating whether the data field // was expanded to the grid in the case where a // bit-map is present. If true, the data points in // gfld->fld match the grid points and zeros were // inserted at grid points where data was bit-mapped // out. If false, the data values in gfld->fld were // not expanded to the grid and are just a consecutive // array of data points corresponding to each value of // "1" in gfld->bmap. // gfld->ibmap = Bitmap indicator ( see Code Table 6.0 ) // 0 = bitmap applies and is included in Section 6. // 1-253 = Predefined bitmap applies // 254 = Previously defined bitmap applies to this field // 255 = Bit map does not apply to this product. // gfld->bmap = integer array containing decoded bitmap, // if gfld->ibmap=0 or gfld->ibap=254. Otherwise nullified // This element is a pointer to an array // that holds the data. // gfld->fld = Array of gfld->ndpts unpacked data points. // This element is a pointer to an array // that holds the data. // // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 1 = Beginning characters "GRIB" not found. // 2 = GRIB message is not Edition 2. // 3 = The data field request number was not positive. // 4 = End string "7777" found, but not where expected. // 6 = GRIB message did not contain the requested number of // data fields. // 7 = End string "7777" not found at end of message. // 8 = Unrecognized Section encountered. // 9 = Data Representation Template 5.NN not yet implemented. // 15 = Error unpacking Section 1. // 16 = Error unpacking Section 2. // 10 = Error unpacking Section 3. // 11 = Error unpacking Section 4. // 12 = Error unpacking Section 5. // 13 = Error unpacking Section 6. // 14 = Error unpacking Section 7. // 17 = Previous bitmap specified, yet none exists. // // REMARKS: Note that struct gribfield is allocated by this routine and it // also contains pointers to many arrays of data that were allocated // during decoding. Users are encouraged to free up this memory, // when it is no longer needed, by an explicit call to routine g2_free. // EXAMPLE: // #include "grib2.h" // gribfield *gfld; // ret=g2_getfld(cgrib,1,1,1,&gfld); // ... // g2_free(gfld); // // Routine g2_info can be used to first determine // how many data fields exist in a given GRIB message. // // REMARKS2: It may not always be possible to expand a bit-mapped data field. // If a pre-defined bit-map is used and not included in the GRIB2 // message itself, this routine would not have the necessary // information to expand the data. In this case, gfld->expanded would // would be set to 0 (false), regardless of the value of input // argument expand. // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ { g2int have3,have4,have5,have6,have7,ierr,jerr; g2int numfld,j,n,istart,iofst,ipos; g2int disc,ver,lensec0,lengrib,lensec,isecnum; g2int *igds; g2int *bmpsave; g2float *newfld; gribfield *lgfld; have3=0; have4=0; have5=0; have6=0; have7=0; ierr=0; numfld=0; lgfld=(gribfield *)malloc(sizeof(gribfield)); *gfld=lgfld; lgfld->locallen=0; lgfld->idsect=0; lgfld->local=0; lgfld->list_opt=0; lgfld->igdtmpl=0; lgfld->ipdtmpl=0; lgfld->idrtmpl=0; lgfld->coord_list=0; lgfld->bmap=0; lgfld->fld=0; // // Check for valid request number // if (ifldnum <= 0) { printf("g2_getfld: Request for field number must be positive.\n"); ierr=3; return(ierr); } // // Check for beginning of GRIB message in the first 100 bytes // istart=-1; for (j=0;j<100;j++) { if (cgrib[j]=='G' && cgrib[j+1]=='R' &&cgrib[j+2]=='I' && cgrib[j+3]=='B') { istart=j; break; } } if (istart == -1) { printf("g2_getfld: Beginning characters GRIB not found.\n"); ierr=1; return(ierr); } // // Unpack Section 0 - Indicator Section // iofst=8*(istart+6); gbit(cgrib,&disc,iofst,8); // Discipline iofst=iofst+8; gbit(cgrib,&ver,iofst,8); // GRIB edition number iofst=iofst+8; iofst=iofst+32; gbit(cgrib,&lengrib,iofst,32); // Length of GRIB message iofst=iofst+32; lensec0=16; ipos=istart+lensec0; // // Currently handles only GRIB Edition 2. // if (ver != 2) { printf("g2_getfld: can only decode GRIB edition 2.\n"); ierr=2; return(ierr); } // // Loop through the remaining sections keeping track of the // length of each. Also keep the latest Grid Definition Section info. // Unpack the requested field number. // for (;;) { // Check to see if we are at end of GRIB message if (cgrib[ipos]=='7' && cgrib[ipos+1]=='7' && cgrib[ipos+2]=='7' && cgrib[ipos+3]=='7') { ipos=ipos+4; // If end of GRIB message not where expected, issue error if (ipos != (istart+lengrib)) { printf("g2_getfld: '7777' found, but not where expected.\n"); ierr=4; return(ierr); } break; } // Get length of Section and Section number iofst=(ipos-1)*8; iofst=ipos*8; gbit(cgrib,&lensec,iofst,32); // Get Length of Section iofst=iofst+32; gbit(cgrib,&isecnum,iofst,8); // Get Section number iofst=iofst+8; //printf(" lensec= %d secnum= %d \n",lensec,isecnum); // // Check to see if section number is valid // if ( isecnum<1 || isecnum>7 ) { printf("g2_getfld: Unrecognized Section Encountered=%d\n",isecnum); ierr=8; return(ierr); } // // If found Section 1, decode elements in Identification Section // if (isecnum == 1) { iofst=iofst-40; // reset offset to beginning of section jerr=g2_unpack1(cgrib,&iofst,&lgfld->idsect,&lgfld->idsectlen); if (jerr !=0 ) { ierr=15; return(ierr); } } // // If found Section 2, Grab local section // Save in case this is the latest one before the requested field. // if (isecnum == 2) { iofst=iofst-40; // reset offset to beginning of section if (lgfld->local!=0) free(lgfld->local); jerr=g2_unpack2(cgrib,&iofst,&lgfld->locallen,&lgfld->local); if (jerr != 0) { ierr=16; return(ierr); } } // // If found Section 3, unpack the GDS info using the // appropriate template. Save in case this is the latest // grid before the requested field. // if (isecnum == 3) { iofst=iofst-40; // reset offset to beginning of section if (lgfld->igdtmpl!=0) free(lgfld->igdtmpl); if (lgfld->list_opt!=0) free(lgfld->list_opt); jerr=g2_unpack3(cgrib,&iofst,&igds,&lgfld->igdtmpl, &lgfld->igdtlen,&lgfld->list_opt,&lgfld->num_opt); if (jerr == 0) { have3=1; lgfld->griddef=igds[0]; lgfld->ngrdpts=igds[1]; lgfld->numoct_opt=igds[2]; lgfld->interp_opt=igds[3]; lgfld->igdtnum=igds[4]; } else { ierr=10; return(ierr); } } // // If found Section 4, check to see if this field is the // one requested. // if (isecnum == 4) { numfld=numfld+1; if (numfld == ifldnum) { lgfld->discipline=disc; lgfld->version=ver; lgfld->ifldnum=ifldnum; lgfld->unpacked=unpack; lgfld->expanded=0; iofst=iofst-40; // reset offset to beginning of section jerr=g2_unpack4(cgrib,&iofst,&lgfld->ipdtnum, &lgfld->ipdtmpl,&lgfld->ipdtlen,&lgfld->coord_list, &lgfld->num_coord); if (jerr == 0) have4=1; else { ierr=11; return(ierr); } } } // // If found Section 5, check to see if this field is the // one requested. // if (isecnum == 5 && numfld == ifldnum) { iofst=iofst-40; // reset offset to beginning of section jerr=g2_unpack5(cgrib,&iofst,&lgfld->ndpts,&lgfld->idrtnum, &lgfld->idrtmpl,&lgfld->idrtlen); if (jerr == 0) have5=1; else { ierr=12; return(ierr); } } // // If found Section 6, Unpack bitmap. // Save in case this is the latest // bitmap before the requested field. // if (isecnum == 6) { if (unpack) { // unpack bitmap iofst=iofst-40; // reset offset to beginning of section bmpsave=lgfld->bmap; // save pointer to previous bitmap jerr=g2_unpack6(cgrib,&iofst,lgfld->ngrdpts,&lgfld->ibmap, &lgfld->bmap); if (jerr == 0) { have6=1; if (lgfld->ibmap == 254) // use previously specified bitmap if( bmpsave!=0 ) lgfld->bmap=bmpsave; else { printf("g2_getfld: Prev bit-map specified, but none exist.\n"); ierr=17; return(ierr); } else // get rid of it if( bmpsave!=0 ) free(bmpsave); } else { ierr=13; return(ierr); } } else { // do not unpack bitmap gbit(cgrib,&lgfld->ibmap,iofst,8); // Get BitMap Indicator have6=1; } } // // If found Section 7, check to see if this field is the // one requested. // if (isecnum==7 && numfld==ifldnum && unpack) { iofst=iofst-40; // reset offset to beginning of section jerr=g2_unpack7(cgrib,&iofst,lgfld->igdtnum,lgfld->igdtmpl, lgfld->idrtnum,lgfld->idrtmpl,lgfld->ndpts, &lgfld->fld); if (jerr == 0) { have7=1; // If bitmap is used with this field, expand data field // to grid, if possible. if ( lgfld->ibmap != 255 && lgfld->bmap != 0 ) { if ( expand == 1 ) { n=0; newfld=(g2float *)calloc(lgfld->ngrdpts,sizeof(g2float)); for (j=0;j<lgfld->ngrdpts;j++) { if (lgfld->bmap[j]==1) newfld[j]=lgfld->fld[n++]; } free(lgfld->fld); lgfld->fld=newfld; lgfld->expanded=1; } else { lgfld->expanded=0; } } else { lgfld->expanded=1; } } else { printf("g2_getfld: return from g2_unpack7 = %d \n",(int)jerr); ierr=14; return(ierr); } } // // Check to see if we read pass the end of the GRIB // message and missed the terminator string '7777'. // ipos=ipos+lensec; // Update beginning of section pointer if (ipos > (istart+lengrib)) { printf("g2_getfld: '7777' not found at end of GRIB message.\n"); ierr=7; return(ierr); } // // If unpacking requested, return when all sections have been // processed // if (unpack && have3 && have4 && have5 && have6 && have7) return(ierr); // // If unpacking is not requested, return when sections // 3 through 6 have been processed // if ((! unpack) && have3 && have4 && have5 && have6) return(ierr); } // // If exited from above loop, the end of the GRIB message was reached // before the requested field was found. // printf("g2_getfld: GRIB message contained %d different fields.\n",numfld); printf("g2_getfld: The request was for field %d.\n",ifldnum); ierr=6; return(ierr); }
g2int g2_unpack1(unsigned char *cgrib,g2int *iofst,g2int **ids,g2int *idslen) /*//$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack1 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-29 // // ABSTRACT: This subroutine unpacks Section 1 (Identification Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-29 Gilbert // // USAGE: int g2_unpack1(unsigned char *cgrib,g2int *iofst,g2int **ids, // g2int *idslen) // INPUT ARGUMENTS: // cgrib - char array containing Section 1 of the GRIB2 message // iofst - Bit offset for the beginning of Section 1 in cgrib. // // OUTPUT ARGUMENTS: // iofst - Bit offset at the end of Section 1, returned. // ids - address of pointer to integer array containing information // read from Section 1, the Identification section. // ids[0] = Identification of originating Centre // ( see Common Code Table C-1 ) // ids[1] = Identification of originating Sub-centre // ids[2] = GRIB Master Tables Version Number // ( see Code Table 1.0 ) // ids[3] = GRIB Local Tables Version Number // ( see Code Table 1.1 ) // ids[4] = Significance of Reference Time (Code Table 1.2) // ids[5] = Year ( 4 digits ) // ids[6] = Month // ids[7] = Day // ids[8] = Hour // ids[9] = Minute // ids[10] = Second // ids[11] = Production status of processed data // ( see Code Table 1.3 ) // ids[12] = Type of processed data ( see Code Table 1.4 ) // idslen - Number of elements in ids[]. // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 2 = Array passed is not section 1 // 6 = memory allocation error // // REMARKS: // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ */ { g2int i,lensec,nbits,ierr,isecnum; g2int mapid[13]={2,2,1,1,1,2,1,1,1,1,1,1,1}; ierr=0; *idslen=13; *ids=0; gbit(cgrib,&lensec,*iofst,32); // Get Length of Section *iofst=*iofst+32; gbit(cgrib,&isecnum,*iofst,8); // Get Section Number *iofst=*iofst+8; if ( isecnum != 1 ) { ierr=2; *idslen=13; // fprintf(stderr,"g2_unpack1: Not Section 1 data.\n"); return(ierr); } // // Unpack each value into array ids from the // the appropriate number of octets, which are specified in // corresponding entries in array mapid. // *ids=(g2int *)calloc(*idslen,sizeof(g2int)); if (*ids == 0) { ierr=6; return(ierr); } for (i=0;i<*idslen;i++) { nbits=mapid[i]*8; gbit(cgrib,*ids+i,*iofst,nbits); *iofst=*iofst+nbits; } return(ierr); // End of Section 1 processing }
g2int g2_addlocal(unsigned char *cgrib,unsigned char *csec2,g2int lcsec2) //$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_addlocal // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-01 // // ABSTRACT: This routine adds a Local Use Section (Section 2) to // a GRIB2 message. It is used with routines "g2_create", // "g2_addgrid", "g2_addfield", // and "g2_gribend" to create a complete GRIB2 message. // g2_create must be called first to initialize a new GRIB2 message. // // PROGRAM HISTORY LOG: // 2002-11-01 Gilbert // // USAGE: int g2_addlocal(unsigned char *cgrib,unsigned char *csec2, // g2int lcsec2) // INPUT ARGUMENTS: // cgrib - Char array that contains the GRIB2 message to which section // 2 should be added. // csec2 - Character array containing information to be added in // Section 2. // lcsec2 - Number of bytes of character array csec2 to be added to // Section 2. // // OUTPUT ARGUMENT: // cgrib - Char array to contain the updated GRIB2 message. // Must be allocated large enough to store the entire // GRIB2 message. // // RETURN VALUES: // ierr - Return code. // > 0 = Current size of updated GRIB2 message // -1 = GRIB message was not initialized. Need to call // routine gribcreate first. // -2 = GRIB message already complete. Cannot add new section. // -3 = Sum of Section byte counts doesn't add to total byte count // -4 = Previous Section was not 1 or 7. // // REMARKS: Note that the Local Use Section ( Section 2 ) can only follow // Section 1 or Section 7 in a GRIB2 message. // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ { const unsigned char G=0x47; // 'G' const unsigned char R=0x52; // 'R' const unsigned char I=0x49; // 'I' const unsigned char B=0x42; // 'B' const unsigned char seven=0x37; // '7' const g2int two=2; g2int j,k,lensec2,iofst,ibeg,lencurr,ilen,len,istart; g2int isecnum; // // Check to see if beginning of GRIB message exists // if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { printf("g2_addlocal: GRIB not found in given message.\n"); printf("g2_addlocal: Call to routine g2_create required to initialize GRIB message.\n"); return(-1); } // // Get current length of GRIB message // gbit(cgrib,&lencurr,96,32); // // Check to see if GRIB message is already complete // if ( cgrib[lencurr-4]==seven && cgrib[lencurr-3]==seven && cgrib[lencurr-2]==seven && cgrib[lencurr-1]==seven ) { printf("g2_addlocal: GRIB message already complete. Cannot add new section.\n"); return(-2); } // // Loop through all current sections of the GRIB message to // find the last section number. // len=16; // length of Section 0 for (;;) { // Get section number and length of next section iofst=len*8; gbit(cgrib,&ilen,iofst,32); iofst=iofst+32; gbit(cgrib,&isecnum,iofst,8); len=len+ilen; // Exit loop if last section reached if ( len == lencurr ) break; // If byte count for each section doesn't match current // total length, then there is a problem. if ( len > lencurr ) { printf("g2_addlocal: Section byte counts don't add to total.\n"); printf("g2_addlocal: Sum of section byte counts = %d\n",len); printf("g2_addlocal: Total byte count in Section 0 = %d\n",lencurr); return(-3); } } // // Section 2 can only be added after sections 1 and 7. // if ( (isecnum!=1) && (isecnum!=7) ) { printf("g2_addlocal: Section 2 can only be added after Section 1 or Section 7.\n"); printf("g2_addlocal: Section %d was the last found in given GRIB message.\n",isecnum); return(-4); } // // Add Section 2 - Local Use Section // ibeg=lencurr*8; // Calculate offset for beginning of section 2 iofst=ibeg+32; // leave space for length of section sbit(cgrib,&two,iofst,8); // Store section number ( 2 ) istart=lencurr+5; //cgrib(istart+1:istart+lcsec2)=csec2(1:lcsec2) k=0; for (j=istart;j<istart+lcsec2;j++) { cgrib[j]=csec2[k++]; } // // Calculate length of section 2 and store it in octets // 1-4 of section 2. // lensec2=lcsec2+5; // bytes sbit(cgrib,&lensec2,ibeg,32); // // Update current byte total of message in Section 0 // lencurr+=lensec2; sbit(cgrib,&lencurr,96,32); return(lencurr); }
g2int 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) //$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_addfield // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-11-05 // // ABSTRACT: This routine packs up Sections 4 through 7 for a given field // and adds them to a GRIB2 message. They are Product Definition Section, // Data Representation Section, Bit-Map Section and Data Section, // respectively. // This routine is used with routines "g2_create", "g2_addlocal", // "g2_addgrid", and "g2_gribend" to create a complete GRIB2 message. // g2_create must be called first to initialize a new GRIB2 message. // Also, routine g2_addgrid must be called after g2_create and // before this routine to add the appropriate grid description to // the GRIB2 message. Also, a call to g2_gribend is required to complete // GRIB2 message after all fields have been added. // // PROGRAM HISTORY LOG: // 2002-11-05 Gilbert // 2002-12-23 Gilbert - Added complex spherical harmonic packing // 2003-08-27 Gilbert - Added support for new templates using // PNG and JPEG2000 algorithms/templates. // 2004-11-29 Gilbert - JPEG2000 now allowed to use WMO Template no. 5.40 // PNG now allowed to use WMO Template no. 5.41 // - Added check to determine if packing algorithm failed. // 2005-05-10 Gilbert - Imposed minimum size on cpack, used to hold encoded // bit string. // // USAGE: int 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) // INPUT ARGUMENT LIST: // cgrib - Char array that contains the GRIB2 message to which sections // 4 through 7 should be added. // ipdsnum - Product Definition Template Number ( see Code Table 4.0) // ipdstmpl - Contains the data values for the specified Product Definition // Template ( N=ipdsnum ). Each element of this integer // array contains an entry (in the order specified) of Product // Defintion Template 4.N // coordlist- Array containg floating point values intended to document // the vertical discretisation associated to model data // on hybrid coordinate vertical levels. // numcoord - number of values in array coordlist. // idrsnum - Data Representation Template Number ( see Code Table 5.0 ) // idrstmpl - Contains the data values for the specified Data Representation // Template ( N=idrsnum ). Each element of this integer // array contains an entry (in the order specified) of Data // Representation Template 5.N // Note that some values in this template (eg. reference // values, number of bits, etc...) may be changed by the // data packing algorithms. // Use this to specify scaling factors and order of // spatial differencing, if desired. // fld[] - Array of data points to pack. // ngrdpts - Number of data points in grid. // i.e. size of fld and bmap. // ibmap - Bitmap indicator ( see Code Table 6.0 ) // 0 = bitmap applies and is included in Section 6. // 1-253 = Predefined bitmap applies // 254 = Previously defined bitmap applies to this field // 255 = Bit map does not apply to this product. // bmap[] - Integer array containing bitmap to be added. ( if ibmap=0 ) // // OUTPUT ARGUMENT LIST: // cgrib - Character array to contain the updated GRIB2 message. // Must be allocated large enough to store the entire // GRIB2 message. // // RETURN VALUES: // ierr - Return code. // > 0 = Current size of updated GRIB2 message // -1 = GRIB message was not initialized. Need to call // routine g2_create first. // -2 = GRIB message already complete. Cannot add new section. // -3 = Sum of Section byte counts doesn't add to total byte count // -4 = Previous Section was not 3 or 7. // -5 = Could not find requested Product Definition Template. // -6 = Section 3 (GDS) not previously defined in message // -7 = Tried to use unsupported Data Representationi Template // -8 = Specified use of a previously defined bitmap, but one // does not exist in the GRIB message. // -9 = GDT of one of 5.50 through 5.53 required to pack field // using DRT 5.51. // -10 = Error packing data field. // // REMARKS: Note that the Sections 4 through 7 can only follow // Section 3 or Section 7 in a GRIB2 message. // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ { g2int ierr; static unsigned char G=0x47; // 'G' static unsigned char R=0x52; // 'R' static unsigned char I=0x49; // 'I' static unsigned char B=0x42; // 'B' static unsigned char s7=0x37; // '7' unsigned char *cpack; static g2int zero=0,one=1,four=4,five=5,six=6,seven=7; const g2int minsize=50000; g2int iofst,ibeg,lencurr,len,nsize; g2int ilen,isecnum,i,nbits,temp,left; g2int ibmprev,j,lcpack,ioctet,newlen,ndpts; g2int lensec4,lensec5,lensec6,lensec7; g2int issec3,isprevbmap,lpos3=0,JJ,KK,MM; g2int *coordieee; g2int width,height,iscan,itemp; g2float *pfld; xxtemplate *mappds,*mapdrs; unsigned int allones=4294967295u; ierr=0; // // Check to see if beginning of GRIB message exists // if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { printf("g2_addfield: GRIB not found in given message.\n"); printf("g2_addfield: Call to routine g2_create required to initialize GRIB messge.\n"); ierr=-1; return(ierr); } // // Get current length of GRIB message // gbit(cgrib,&lencurr,96,32); // // Check to see if GRIB message is already complete // if ( cgrib[lencurr-4]==s7 && cgrib[lencurr-3]==s7 && cgrib[lencurr-2]==s7 && cgrib[lencurr-1]==s7 ) { printf("g2_addfield: GRIB message already complete. Cannot add new section.\n"); ierr=-2; return(ierr); } // // Loop through all current sections of the GRIB message to // find the last section number. // issec3=0; isprevbmap=0; len=16; // length of Section 0 for (;;) { // Get number and length of next section iofst=len*8; gbit(cgrib,&ilen,iofst,32); iofst=iofst+32; gbit(cgrib,&isecnum,iofst,8); iofst=iofst+8; // Check if previous Section 3 exists if (isecnum == 3) { issec3=1; lpos3=len; } // Check if a previous defined bitmap exists if (isecnum == 6) { gbit(cgrib,&ibmprev,iofst,8); iofst=iofst+8; if ((ibmprev >= 0) && (ibmprev <= 253)) isprevbmap=1; } len=len+ilen; // Exit loop if last section reached if ( len == lencurr ) break; // If byte count for each section doesn't match current // total length, then there is a problem. if ( len > lencurr ) { printf("g2_addfield: Section byte counts don''t add to total.\n"); printf("g2_addfield: Sum of section byte counts = %d\n",len); printf("g2_addfield: Total byte count in Section 0 = %d\n",lencurr); ierr=-3; return(ierr); } } // // Sections 4 through 7 can only be added after section 3 or 7. // if ( (isecnum != 3) && (isecnum != 7) ) { printf("g2_addfield: Sections 4-7 can only be added after Section 3 or 7.\n"); printf("g2_addfield: Section ',isecnum,' was the last found in given GRIB message.\n"); ierr=-4; return(ierr); // // Sections 4 through 7 can only be added if section 3 was previously defined. // } else if ( ! issec3) { printf("g2_addfield: Sections 4-7 can only be added if Section 3 was previously included.\n"); printf("g2_addfield: Section 3 was not found in given GRIB message.\n"); printf("g2_addfield: Call to routine addgrid required to specify Grid definition.\n"); ierr=-6; return(ierr); } // // Add Section 4 - Product Definition Section // ibeg=lencurr*8; // Calculate offset for beginning of section 4 iofst=ibeg+32; // leave space for length of section sbit(cgrib,&four,iofst,8); // Store section number ( 4 ) iofst=iofst+8; sbit(cgrib,&numcoord,iofst,16); // Store num of coordinate values iofst=iofst+16; sbit(cgrib,&ipdsnum,iofst,16); // Store Prod Def Template num. iofst=iofst+16; // // Get Product Definition Template // mappds=getpdstemplate(ipdsnum); if (mappds == 0) { // undefined template ierr=-5; return(ierr); } // // Extend the Product Definition Template, if necessary. // The number of values in a specific template may vary // depending on data specified in the "static" part of the // template. // if ( mappds->needext ) { free(mappds); mappds=extpdstemplate(ipdsnum,ipdstmpl); } // // Pack up each input value in array ipdstmpl into the // the appropriate number of octets, which are specified in // corresponding entries in array mappds. // for (i=0;i<mappds->maplen;i++) { nbits=abs(mappds->map[i])*8; if ( (mappds->map[i] >= 0) || (ipdstmpl[i] >= 0) ) sbit(cgrib,ipdstmpl+i,iofst,nbits); else { sbit(cgrib,&one,iofst,1); temp=abs(ipdstmpl[i]); sbit(cgrib,&temp,iofst+1,nbits-1); } iofst=iofst+nbits; } // Pack template extension, if appropriate j=mappds->maplen; if ( mappds->needext && (mappds->extlen > 0) ) { for (i=0;i<mappds->extlen;i++) { nbits=abs(mappds->ext[i])*8; if ( (mappds->ext[i] >= 0) || (ipdstmpl[j] >= 0) ) sbit(cgrib,ipdstmpl+j,iofst,nbits); else { sbit(cgrib,&one,iofst,1); temp=abs(ipdstmpl[j]); sbit(cgrib,&temp,iofst+1,nbits-1); } iofst=iofst+nbits; j++; } } free(mappds); // // Add Optional list of vertical coordinate values // after the Product Definition Template, if necessary. // if ( numcoord != 0 ) { coordieee=(g2int *)calloc(numcoord,sizeof(g2int)); mkieee(coordlist,coordieee,numcoord); sbits(cgrib,coordieee,iofst,32,0,numcoord); iofst=iofst+(32*numcoord); free(coordieee); } // // Calculate length of section 4 and store it in octets // 1-4 of section 4. // lensec4=(iofst-ibeg)/8; sbit(cgrib,&lensec4,ibeg,32); // // Pack Data using appropriate algorithm // // // Get Data Representation Template // mapdrs=getdrstemplate(idrsnum); if (mapdrs == 0) { ierr=-5; return(ierr); } // // contract data field, removing data at invalid grid points, // if bit-map is provided with field. // if ( ibmap == 0 || ibmap==254 ) { pfld=(g2float *)malloc(ngrdpts*sizeof(g2float)); ndpts=0; for (j=0;j<ngrdpts;j++) { if ( bmap[j]==1 ) pfld[ndpts++]=fld[j]; } } else { ndpts=ngrdpts; pfld=fld; } nsize=ndpts*4; if ( nsize < minsize ) nsize=minsize; cpack=malloc(nsize); if (idrsnum == 0) // Simple Packing simpack(pfld,ndpts,idrstmpl,cpack,&lcpack); else if (idrsnum==2 || idrsnum==3) // Complex Packing cmplxpack(pfld,ndpts,idrsnum,idrstmpl,cpack,&lcpack); else if (idrsnum == 50) { // Sperical Harmonic Simple Packing simpack(pfld+1,ndpts-1,idrstmpl,cpack,&lcpack); mkieee(pfld+0,idrstmpl+4,1); // ensure RE(0,0) value is IEEE format } else if (idrsnum == 51) { // Sperical Harmonic Complex Packing getpoly(cgrib+lpos3,&JJ,&KK,&MM); if ( JJ!=0 && KK!=0 && MM!=0 ) specpack(pfld,ndpts,JJ,KK,MM,idrstmpl,cpack,&lcpack); else { printf("g2_addfield: Cannot pack DRT 5.51.\n"); return (-9); } } else if (idrsnum == 40 || idrsnum == 40000) { /* JPEG2000 encoding */ if (ibmap == 255) { getdim(cgrib+lpos3,&width,&height,&iscan); if ( width==0 || height==0 ) { width=ndpts; height=1; } else if ( width==allones || height==allones ) { width=ndpts; height=1; } else if ( (iscan&32) == 32) { /* Scanning mode: bit 3 */ itemp=width; width=height; height=itemp; } } else { width=ndpts; height=1; } lcpack=nsize; jpcpack(pfld,width,height,idrstmpl,cpack,&lcpack); } #ifdef USE_PNG else if (idrsnum == 41 || idrsnum == 40010) { /* PNG encoding */ if (ibmap == 255) { getdim(cgrib+lpos3,&width,&height,&iscan); if ( width==0 || height==0 ) { width=ndpts; height=1; } else if ( width==allones || height==allones ) { width=ndpts; height=1; } else if ( (iscan&32) == 32) { /* Scanning mode: bit 3 */ itemp=width; width=height; height=itemp; } } else { width=ndpts; height=1; } pngpack(pfld,width,height,idrstmpl,cpack,&lcpack); } #endif /* USE_PNG */ else { printf("g2_addfield: Data Representation Template 5.%d not yet implemented.\n",idrsnum); ierr=-7; return(ierr); } if ( ibmap == 0 || ibmap==254 ) { // free temp space if (fld != pfld) free(pfld); } if ( lcpack < 0 ) { if( cpack != 0 ) free(cpack); ierr=-10; return(ierr); } // // Add Section 5 - Data Representation Section // ibeg=iofst; // Calculate offset for beginning of section 5 iofst=ibeg+32; // leave space for length of section sbit(cgrib,&five,iofst,8); // Store section number ( 5 ) iofst=iofst+8; sbit(cgrib,&ndpts,iofst,32); // Store num of actual data points iofst=iofst+32; sbit(cgrib,&idrsnum,iofst,16); // Store Data Repr. Template num. iofst=iofst+16; // // Pack up each input value in array idrstmpl into the // the appropriate number of octets, which are specified in // corresponding entries in array mapdrs. // for (i=0;i<mapdrs->maplen;i++) { nbits=abs(mapdrs->map[i])*8; if ( (mapdrs->map[i] >= 0) || (idrstmpl[i] >= 0) ) sbit(cgrib,idrstmpl+i,iofst,nbits); else { sbit(cgrib,&one,iofst,1); temp=abs(idrstmpl[i]); sbit(cgrib,&temp,iofst+1,nbits-1); } iofst=iofst+nbits; } free(mapdrs); // // Calculate length of section 5 and store it in octets // 1-4 of section 5. // lensec5=(iofst-ibeg)/8; sbit(cgrib,&lensec5,ibeg,32); // // Add Section 6 - Bit-Map Section // ibeg=iofst; // Calculate offset for beginning of section 6 iofst=ibeg+32; // leave space for length of section sbit(cgrib,&six,iofst,8); // Store section number ( 6 ) iofst=iofst+8; sbit(cgrib,&ibmap,iofst,8); // Store Bit Map indicator iofst=iofst+8; // // Store bitmap, if supplied // if (ibmap == 0) { sbits(cgrib,bmap,iofst,1,0,ngrdpts); // Store BitMap iofst=iofst+ngrdpts; } // // If specifying a previously defined bit-map, make sure // one already exists in the current GRIB message. // if ((ibmap==254) && ( ! isprevbmap)) { printf("g2_addfield: Requested previously defined bitmap,"); printf(" but one does not exist in the current GRIB message.\n"); ierr=-8; return(ierr); } // // Calculate length of section 6 and store it in octets // 1-4 of section 6. Pad to end of octect, if necessary. // left=8-(iofst%8); if (left != 8) { sbit(cgrib,&zero,iofst,left); // Pad with zeros to fill Octet iofst=iofst+left; } lensec6=(iofst-ibeg)/8; sbit(cgrib,&lensec6,ibeg,32); // // Add Section 7 - Data Section // ibeg=iofst; // Calculate offset for beginning of section 7 iofst=ibeg+32; // leave space for length of section sbit(cgrib,&seven,iofst,8); // Store section number ( 7 ) iofst=iofst+8; // Store Packed Binary Data values, if non-constant field if (lcpack != 0) { ioctet=iofst/8; //cgrib(ioctet+1:ioctet+lcpack)=cpack(1:lcpack) for (j=0;j<lcpack;j++) cgrib[ioctet+j]=cpack[j]; iofst=iofst+(8*lcpack); } // // Calculate length of section 7 and store it in octets // 1-4 of section 7. // lensec7=(iofst-ibeg)/8; sbit(cgrib,&lensec7,ibeg,32); if( cpack != 0 ) free(cpack); // // Update current byte total of message in Section 0 // newlen=lencurr+lensec4+lensec5+lensec6+lensec7; sbit(cgrib,&newlen,96,32); return(newlen); }
g2int g2_gribend(unsigned char *cgrib) //$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_gribend // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This routine finalizes a GRIB2 message after all grids // and fields have been added. It adds the End Section ( "7777" ) // to the end of the GRIB message and calculates the length and stores // it in the appropriate place in Section 0. // This routine is used with routines "g2_create", "g2_addlocal", // "g2_addgrid", and "g2_addfield" to create a complete GRIB2 message. // g2_create must be called first to initialize a new GRIB2 message. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // // USAGE: int g2_gribend(unsigned char *cgrib) // INPUT ARGUMENT: // cgrib - Char array containing all the data sections added // be previous calls to g2_create, g2_addlocal, g2_addgrid, // and g2_addfield. // // OUTPUT ARGUMENTS: // cgrib - Char array containing the finalized GRIB2 message // // RETURN VALUES: // ierr - Return code. // > 0 = Length of the final GRIB2 message in bytes. // -1 = GRIB message was not initialized. Need to call // routine g2_create first. // -2 = GRIB message already complete. // -3 = Sum of Section byte counts doesn't add to total byte count // -4 = Previous Section was not 7. // // REMARKS: This routine is intended for use with routines "g2_create", // "g2_addlocal", "g2_addgrid", and "g2_addfield" to create a complete // GRIB2 message. // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$ { g2int iofst,lencurr,len,ilen,isecnum; g2int ierr,lengrib; static unsigned char G=0x47; // 'G' static unsigned char R=0x52; // 'R' static unsigned char I=0x49; // 'I' static unsigned char B=0x42; // 'B' static unsigned char seven=0x37; // '7' ierr=0; // // Check to see if beginning of GRIB message exists // if ( cgrib[0]!=G || cgrib[1]!=R || cgrib[2]!=I || cgrib[3]!=B ) { printf("g2_gribend: GRIB not found in given message.\n"); ierr=-1; return (ierr); } // // Get current length of GRIB message // gbit(cgrib,&lencurr,96,32); // // Loop through all current sections of the GRIB message to // find the last section number. // len=16; // Length of Section 0 for (;;) { // Get number and length of next section iofst=len*8; gbit(cgrib,&ilen,iofst,32); iofst=iofst+32; gbit(cgrib,&isecnum,iofst,8); len=len+ilen; // Exit loop if last section reached if ( len == lencurr ) break; // If byte count for each section doesn't match current // total length, then there is a problem. if ( len > lencurr ) { printf("g2_gribend: Section byte counts don''t add to total.\n"); printf("g2_gribend: Sum of section byte counts = %d\n",(int)len); printf("g2_gribend: Total byte count in Section 0 = %d\n",(int)lencurr); ierr=-3; return (ierr); } } // // Can only add End Section (Section 8) after Section 7. // if ( isecnum != 7 ) { printf("g2_gribend: Section 8 can only be added after Section 7.\n"); printf("g2_gribend: Section %d was the last found in given GRIB message.\n",isecnum); ierr=-4; return (ierr); } // // Add Section 8 - End Section // //cgrib(lencurr+1:lencurr+4)=c7777 cgrib[lencurr]=seven; cgrib[lencurr+1]=seven; cgrib[lencurr+2]=seven; cgrib[lencurr+3]=seven; // // Update current byte total of message in Section 0 // lengrib=lencurr+4; sbit(cgrib,&lengrib,96,32); return (lengrib); }
g2int g2_unpack5(unsigned char *cgrib,size_t sz,g2int *iofst,g2int *ndpts, g2int *idrsnum,g2int **idrstmpl,g2int *mapdrslen) /*//$$$ SUBPROGRAM DOCUMENTATION BLOCK // . . . . // SUBPROGRAM: g2_unpack5 // PRGMMR: Gilbert ORG: W/NP11 DATE: 2002-10-31 // // ABSTRACT: This subroutine unpacks Section 5 (Data Representation Section) // as defined in GRIB Edition 2. // // PROGRAM HISTORY LOG: // 2002-10-31 Gilbert // 2009-01-14 Vuong Changed structure name template to gtemplate // 2014-02-25 Steve Emmerson (UCAR/Unidata) Add length-checking of "cgrib" // array // // USAGE: int g2_unpack5(unsigned char *cgrib,size_t sz,g2int *iofst, // g2int *ndpts, g2int *idrsnum,g2int **idrstmpl, // g2int *mapdrslen) // INPUT ARGUMENTS: // cgrib - char array containing Section 5 of the GRIB2 message // sz - Size of "cgrib" array in bytes // iofst - Bit offset for the beginning of Section 5 in cgrib. // // OUTPUT ARGUMENTS: // iofst - Bit offset at the end of Section 5, returned. // ndpts - Number of data points unpacked and returned. // idrsnum - Data Representation Template Number ( see Code Table 5.0) // idrstmpl - Pointer to an integer array containing the data values for // the specified Data Representation // Template ( N=idrsnum ). Each element of this integer // array contains an entry (in the order specified) of Data // Representation Template 5.N // mapdrslen- Number of elements in idrstmpl[]. i.e. number of entries // in Data Representation Template 5.N ( N=idrsnum ). // // RETURN VALUES: // ierr - Error return code. // 0 = no error // 2 = Not Section 5 // 6 = memory allocation error // 7 = "GRIB" message contains an undefined Data // Representation Template. // // REMARKS: None // // ATTRIBUTES: // LANGUAGE: C // MACHINE: // //$$$*/ { g2int ierr,needext,i,j,nbits,isecnum; g2int lensec,isign,newlen; g2int *lidrstmpl=0; gtemplate *mapdrs; size_t bitsz = sz * 8; ierr=0; *idrstmpl=0; /*NULL*/ if (*iofst + 40 > bitsz) return 2; gbit(cgrib,&lensec,*iofst,32); /* Get Length of Section*/ *iofst=*iofst+32; gbit(cgrib,&isecnum,*iofst,8); /* Get Section Number*/ *iofst=*iofst+8; if ( isecnum != 5 ) { ierr=2; *ndpts=0; *mapdrslen=0; /* fprintf(stderr,"g2_unpack5: Not Section 5 data.\n");*/ return(ierr); } if (*iofst + 48 > bitsz) return 2; gbit(cgrib,ndpts,*iofst,32); /* Get num of data points*/ *iofst=*iofst+32; gbit(cgrib,idrsnum,*iofst,16); /* Get Data Rep Template Num.*/ *iofst=*iofst+16; /* Gen Data Representation Template*/ mapdrs=getdrstemplate(*idrsnum); if (mapdrs == 0) { ierr=7; *mapdrslen=0; return(ierr); } *mapdrslen=mapdrs->maplen; needext=mapdrs->needext; /* // Unpack each value into array ipdstmpl from the // the appropriate number of octets, which are specified in // corresponding entries in array mapdrs. */ if (*mapdrslen > 0) lidrstmpl=(g2int *)calloc(*mapdrslen,sizeof(g2int)); if (lidrstmpl == 0) { ierr=6; *mapdrslen=0; *idrstmpl=0; /*NULL*/ if ( mapdrs != 0 ) free(mapdrs); return(ierr); } else { *idrstmpl=lidrstmpl; } for (i=0;i<mapdrs->maplen;i++) { nbits=abs(mapdrs->map[i])*8; if ( mapdrs->map[i] >= 0 ) { if (*iofst + nbits > bitsz) { free(mapdrs); return 2; } gbit(cgrib,lidrstmpl+i,*iofst,nbits); } else { if (*iofst + nbits > bitsz) { free(mapdrs); return 2; } gbit(cgrib,&isign,*iofst,1); gbit(cgrib,lidrstmpl+i,*iofst+1,nbits-1); if (isign == 1) lidrstmpl[i]=-1*lidrstmpl[i]; } *iofst=*iofst+nbits; } /* // Check to see if the Data Representation Template needs to be // extended. // The number of values in a specific gtemplate may vary // depending on data specified in the "static" part of the // gtemplate. */ if ( needext == 1 ) { free(mapdrs); mapdrs=extdrstemplate(*idrsnum,lidrstmpl); newlen=mapdrs->maplen+mapdrs->extlen; lidrstmpl=(g2int *)realloc(lidrstmpl,newlen*sizeof(g2int)); *idrstmpl=lidrstmpl; /* Unpack the rest of the Data Representation Template*/ j=0; for (i=*mapdrslen;i<newlen;i++) { nbits=abs(mapdrs->ext[j])*8; if ( mapdrs->ext[j] >= 0 ) { if (*iofst + nbits > bitsz) { free(mapdrs); return 2; } gbit(cgrib,lidrstmpl+i,*iofst,nbits); } else { if (*iofst + nbits > bitsz) { free(mapdrs); return 2; } gbit(cgrib,&isign,*iofst,1); gbit(cgrib,lidrstmpl+i,*iofst+1,nbits-1); if (isign == 1) lidrstmpl[i]=-1*lidrstmpl[i]; } *iofst=*iofst+nbits; j++; } *mapdrslen=newlen; } if( mapdrs->ext != 0 ) free(mapdrs->ext); free(mapdrs); return(ierr); /* End of Section 5 processing*/ }