/wrfv2_fire/external/io_grib1/MEL_grib1/grib_enc.c
C | 601 lines | 262 code | 46 blank | 293 comment | 76 complexity | 0577f2bb0b4c84eace2f53c877eb57c2 MD5 | raw file
Possible License(s): AGPL-1.0
- /*
- REVISIONS:
- 10/15/96 A. Nakajima, SAIC: removed 'write_grib' call; make combined lib;
- 11/03/97 /ATN -Realloc
- */
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #ifdef XT3_Catamount
- #include <features.h>
- #undef htonl
- #define htonl(x) swap_byte4(x)
- #elif defined(_WIN32)
- #include <Winsock2.h>
- #else
- #include <netinet/in.h>
- #endif
- #include "dprints.h" /* for dprints */
- #include "grib_lookup.h" /* parm/model/lvl defn */
- #include "gribfuncs.h" /* prototypes */
- /*
- *
- ****************************************************************************
- * A. FUNCTION: grib_enc
- * to encode a GRIB Edition 1 message using the three
- * input internal structures (DATA_INPUT, USER_INPUT, GEOM_IN),
- * and the Floating point data array;
- * It's ok for Float array to be null if Grib Hdr shows that
- * it contains a predefined BDS; that case, just exits w/ no errs;
- *
- * INTERFACE:
- * int grib_enc (Data_Input, User_Input, Geom_In, pfData_Array, gh, errmsg)
- *
- * ARGUMENTS (I=input, O=output, I&O=input and output):
- * (I) DATA_INPUT Data_Input;
- * Structure containing input field information.
- * (I) USER_INPUT User_Input;
- * Structure containing encoder configuration data.
- * (I) GEOM_IN Geom_In;
- * Structure containing grid geometry description.
- * (I&O) float *pfData_Array;
- * array of float data to be packed and stored in the Binary Data
- * Section. Float array may be Null if the Grib Header already
- * contains a Binary Data Section in its attribute 'entire_msg'.
- * That case is referred to as the 'Shuffle Mode' which results
- * in the encoder to only create the sections which are not already
- * in entire_msg;
- * Note: non-null data array will be returned with the data being
- * scaled up by the Decimal Scale Factor.
- * (I&O) GRIB_HDR *gh;
- * Pre-malloced structure used to hold the encoded GRIB message
- * and its info. It contains a large array to hold the encoded
- * message, pointers to each of the Section along with their length,
- * and a flag 'shuffled' which determines how the message is encoded.
- * If 'shuffled' is zero upon entry, all 6 sections will be created
- * and array (float *pfData_Array) must contain the float data.
- * If 'shuffled' is set upon entry, there is already one or more
- * sections in Entire_msg; Each of these pre-included sections
- * sections will have a Non-Null pointer & a non-Zero length.
- * The encoder will then only create the missing sections and
- * append them at the end of the existing sections in array
- * 'entire_msg', hence these sections may not be in the proper
- * order expected by GRIB.
- * (O) char *errmsg
- * Empty array, returned filled if error occurred;
- *
- * RETURN VALUE:
- * 0> no errors;
- * GRIB_HDR is returned with the encoded message in 'entire_msg',
- * w/ total message length in msg_length,
- * w/ pointers to each defined Grib Header Sections in
- * ids_ptr, pds_ptr, gds_ptr, bms_ptr, gds_ptr, eds_ptr,
- * and each section length in ids_len, pds_len, gds_len, bms_len,
- * bds_len, eds_len; Note that the sections may not be in order if
- * the 'shuffled' bit is set;
- * 1> failed, msg in errmsg;
- ****************************************************************************/
- #if PROTOTYPE_NEEDED
- int grib_enc (DATA_INPUT Data_Input, USER_INPUT User_Input, GEOM_IN Geom_In,
- float *pfData_Array, GRIB_HDR *gh, char *errmsg)
- #else
- int grib_enc (Data_Input, User_Input, Geom_In, pfData_Array, gh, errmsg)
- DATA_INPUT Data_Input;
- USER_INPUT User_Input;
- GEOM_IN Geom_In;
- float *pfData_Array;
- GRIB_HDR *gh;
- char *errmsg;
- #endif
- {
- PDS_INPUT *pPDS_Input= 0; /* internal Pds struc */
- GDS_HEAD_INPUT *pGDS_Head_Input = 0; /* Internal Gds struc */
- void *pvGDS_Proj_Input = 0; /* depends on Projection*/
- BDS_HEAD_INPUT *pBDS_Head_Input = 0; /* Internal Bds struc */
- char *func= "grib_enc";
- char *Sevens= "7777";
- int gdsbms_flag= 0; /* whether to include them */
- unsigned char *px; /* working ptr w/in EntireMsg */
- long lTemp; /* working var */
- int n,Stat= 1; /* default to error */
- DPRINT1 ("Entering %s...\n", func);
- /*
- *
- * A.1 IF (ptr is null or if the Entire_msg buffer is null) THEN
- * RETURN 1 !errmsg filled
- * ENDIF
- */
- if (!gh || !gh->entire_msg)
- {
- sprintf (errmsg, "%s: expecting non-null GRIB_HDR struct\n", func);
- goto BYE;
- }
- /*
- *
- * A.2 CREATE storage for the Internal structures;
- * ! PDS_INPUT
- * ! GDS_HEAD_INPUT
- * ! GDS_Proj_Input set to MAX_INP_PROJ_SIZE defined in grib.h
- * ! BDS_HEAD_INPUT
- * RETURN with Malloc Err in errmsg if fails;
- * INITIALIZE Internal structures
- */
- if (! (pPDS_Input= (PDS_INPUT *)malloc(sizeof(PDS_INPUT))) ||
- ! (pGDS_Head_Input =(GDS_HEAD_INPUT*)malloc(sizeof(GDS_HEAD_INPUT))) ||
- ! (pvGDS_Proj_Input= (void *) malloc (MAX_INP_PROJ_SIZE)) ||
- ! (pBDS_Head_Input =(BDS_HEAD_INPUT*)malloc(sizeof(BDS_HEAD_INPUT))))
- {
- sprintf(errmsg,"%s: failed to make storage for Internal Structs\n",
- func);
- goto BYE;
- }
- memset ((void *) pPDS_Input, '\0', sizeof(PDS_INPUT));
- memset ((void *) pGDS_Head_Input, '\0', sizeof (GDS_HEAD_INPUT));
- memset ((void *) pvGDS_Proj_Input,'\0', MAX_INP_PROJ_SIZE);
- memset ((void *) pBDS_Head_Input, '\0', sizeof (BDS_HEAD_INPUT));
- /*
- *
- * A.3 IF (creating all sections)
- * ! ** (shuffled == 0) **
- * ! user passed Float data in, and the GribHdr's
- * ! Entire_Msg array has no valid data in it;
- * ! Must 'put' all Sections 0 thru 5 into Grib Hdr in that order;
- * A.3.a THEN
- */
- if (! gh->shuffled)
- {
- /* Create All Sections mode: user must send float data */
- DPRINT0 ("(SHUFFLE=0) Create ALL sections mode\n");
- /*
- * A.3.a.1 RETURN if Float array is Null; !errmsg filled
- */
- if ( !pfData_Array)
- {
- sprintf(errmsg,
- "%s: <Create-All mode> No DataArray avail to encode\n",func);
- goto BYE;
- }
- /*
- * A.3.a.2 CLEAR out the length and section ptrs
- * ASSIGN beginning of Entire Msg to 'px', as location to
- * append things to;
- */
- gh->msg_length= gh->eds_len= gh->pds_len= gh->gds_len= 0;
- gh->bms_len= gh->bds_len= gh->eds_len= 0;
- gh->eds_ptr= gh->pds_ptr= gh->gds_ptr= NULL;
- gh->bms_ptr= gh->bds_ptr= gh->eds_ptr= NULL;
- px = gh->entire_msg; /* append from here on */
- /*
- *
- * A.3.a.3 BUILD IDS SECTION
- * SET up pointer to IDS
- * SET up IDS length (8 for Edition 1)
- * WRITE the Ident Data Section to Grib Hdr
- * UPDATE 'px' to end of IDS !where to write next section
- */
- gh->ids_len = 8;
- gh->msg_length += 8L;
- gh->ids_ptr = px;
- memcpy ((void *) gh->ids_ptr, (void *)"GRIB....", 8);
- px = gh->entire_msg + gh->msg_length;
- DPRINT3 ("%s: 'putting' IDS (%ld), msg_len=%ld\n",
- func, gh->ids_len,gh->msg_length);
- /*
- *
- * A.3.a.4 FUNCTION gribputpds !Build PDS Section into GRIB_HDR
- * IF failed
- * THEN return with error !errmsg filled
- * ELSE bump 'px' to end of this section
- */
- if (n= gribputpds (Data_Input, User_Input, pPDS_Input, &gh, errmsg))
- {
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- else px = gh->entire_msg + gh->msg_length;
- DPRINT3("%s: Encoding PDS (%ld), msg_len=%ld\n",
- func, gh->pds_len,gh->msg_length);
- /*
- *
- * A.3.a.5 FUNCTION gribputgds !Build GDS Section into GRIB_HDR
- * IF failed
- * THEN return with error !errmsg filled
- * ELSE bump 'px' to end of this section
- */
- if ((int) (User_Input.usGds_bms_id) >= 128)
- {
- if ( n = gribputgds (Geom_In,
- pGDS_Head_Input, &pvGDS_Proj_Input, &gh, errmsg) )
- {
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- else px = gh->entire_msg + gh->msg_length;
- DPRINT3 ("%s: Encoding GDS (%ld), msg_len=%ld\n",
- func, gh->gds_len,gh->msg_length);
- }
- else DPRINT1 ("%s: SKIPPING GDS!\n", func);
- /*
- *
- * A.3.a.6 Force no BMS by default
- */
- gh->bms_ptr=0; gh->bms_len= 0;
- DPRINT1 ("%s: Skipping BMS by default\n", func);
- /*
- *
- * A.3.a.7 FUNCTION gribputbds Build BDS Section into GRIB_HDR
- * IF failed
- * THEN return with error !errmsg filled
- * ELSE bump 'px' to end of this section
- */
- if (n= gribputbds (User_Input, Geom_In.nx*Geom_In.ny,
- pPDS_Input->sDec_sc_fctr,
- pfData_Array,
- pBDS_Head_Input, &gh, errmsg))
- {
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- else px = gh->entire_msg + gh->msg_length;
- DPRINT3 ("%s: Encoding BDS (%ld), msg_len=%ld\n",
- func, gh->bds_len,gh->msg_length);
- /*
- *
- * A.3.a.8 IF (Entire Msg buffer isn't big enough to hold EDS)
- * THEN
- * FUNCTION Expand_gribhdr !make it 4 bytes larger
- * RETURN with Error if fails !errmsg filled
- * ENDIF
- * SET up pointer to EDS
- * WRITE Grib EDS section to the end of Data !"7777"
- * UPDATE Grib Hdr's Eds_Ptr, Eds_Len
- */
- if (gh->msg_length > gh->abs_size
- && Expand_gribhdr (gh, gh->msg_length, errmsg) != 0)
- {
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- gh->eds_ptr= px;
- gh->eds_len= 4;
- gh->msg_length += gh->eds_len;
- memcpy ((void *)gh->eds_ptr, (void*)Sevens, 4);
- DPRINT3 ("%s: 'putting' EDS (%ld), msg_len=%ld\n",
- func, gh->eds_len,gh->msg_length);
- } /* END SHUFFLED == 0 SECTION */
- /*
- * A.3.b ELSE
- * ! ** (shuffled == 1) **
- * ! means that user has already put 1/more GRIB sections
- * ! in GRIB_HDR struct's Entire_Msg; The already included
- * ! Sections may not be in proper GRIB-format order, and have
- * ! non-null Pointers and non-zero length; Msg_Length also
- * ! reflects total length of all included sections;
- * ! -if the Float data is Null, the Bds must already be included
- * ! in the Grib Hdr; Func will return error if the Bds pointer
- * ! is Null or the Bds Len is zero;
- * ! -if the incoming Float data has data and the Grib hdr shows
- * ! that BMS is already defined then the func will Ignore the
- * ! float data;
- * ! otherwise, the float data will be used to create a new
- * ! Binary Data Section;
- * ! Only need to 'put' the Sections that have not already been
- * ! included in the Grib Header;
- */
- else { /* Shuffle Mode: Create Missing Sections mode */
- /*
- * A.3.b.1 IF (there is discrepency in section pointers and length)
- * RETURN 1 !errmsg filled
- * ENDIF
- */
- if ( (gh->ids_ptr && !gh->ids_len) || (gh->ids_len && !gh->ids_ptr)
- || (gh->pds_ptr && !gh->pds_len) || (gh->pds_len && !gh->pds_ptr)
- || (gh->gds_ptr && !gh->gds_len) || (gh->gds_len && !gh->gds_ptr)
- || (gh->bms_ptr && !gh->bms_len) || (gh->bms_len && !gh->bms_ptr)
- || (gh->bds_ptr && !gh->bds_len) || (gh->bds_len && !gh->bds_ptr)
- || (gh->eds_ptr && !gh->eds_len) || (gh->eds_len && !gh->eds_ptr)
- || (gh->entire_msg && !gh->msg_length)
- || (gh->msg_length && !gh->entire_msg) )
- {
- sprintf (errmsg,
- "%s: GribHdr Length/Ptr to sections are not consistent\n", func);
- goto BYE;
- }
- /*
- * A.3.b.2 IF (no float array was passed in AND
- * Grib Hdr shows BDS is undefined) THEN
- * RETURN 1 !errmsg filed
- * ENDIF
- */
- if ( !pfData_Array && !gh->bds_ptr) {
- sprintf(errmsg,
- "%s: <Create Missing Sect mode> No DataArray avail to encode Bds\n",
- func);
- goto BYE;
- }
- /*
- * A.3.b.3 IF (user did send in float array AND
- * Grib Hdr shows BDS is already defined) THEN
- * PRINT warning !won't encode float array
- * ENDIF
- */
- if ( pfData_Array && gh->bds_ptr && gh->bds_len>0) {
- DPRINT2 ("%s: GribHdr already has a BDS (Len=%ld), " \
- " not going to encode the Float Data\n" , func, gh->bds_len);
- }
- DPRINT7 ("(SHUFFLE=1) gribhdr contains msg with totlen=%ld\n" \
- " IDS(%d), PDS(%d), GDS(%d), BMS(%d), BDS(%d), EDS(%d)\n",
- gh->msg_length, gh->ids_len, gh->pds_len, gh->gds_len,
- gh->bms_len, gh->bds_len, gh->eds_len);
- /*
- * A.3.b.4 ASSIGN to local ptr 'px' the address of Msg_length bytes
- * away from Entire Msg, as location to append things to;
- */
- px = gh->entire_msg + gh->msg_length; /* append from here */
-
- /*
- *
- * A.3.b.5 IF (GribHdr has no IDS yet)
- * THEN
- * SET up pointer to IDS
- * SET up IDS length (8 for Edition 1)
- * WRITE the Ident Data Section to Grib Hdr
- * !use dummy message length for now
- * UPDATE 'px' to end of IDS !where to write next section
- * ENDIF
- */
- if ( gh->ids_ptr==NULL )
- {
- gh->ids_len = 8;
- gh->msg_length += 8L;
- gh->ids_ptr = px;
- memcpy ((void *) gh->ids_ptr, (void *)"GRIB....", 8);
- px = gh->entire_msg + gh->msg_length;
- DPRINT3 ("%s: 'putting' IDS (%ld), msg_len=%ld\n",
- func, gh->ids_len,gh->msg_length);
- }
- else DPRINT1 ("%s: skip writing IDS\n", func);
- /*
- *
- * A.3.b.6 IF (GribHdr has no PDS yet)
- * THEN
- * FUNCTION gribputpds !Build PDS Section into GRIB_HDR
- * IF failed
- * THEN return with error !errmsg filled
- * ELSE bump 'px' to end of this section
- * ENDIF
- */
- if ( gh->pds_ptr==NULL)
- {
- if (n= gribputpds (Data_Input, User_Input, pPDS_Input, &gh, errmsg))
- {
- DPRINT2 ("%s: got err=%d in Grib Put Pds()\n",func,n);
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- else px = gh->entire_msg + gh->msg_length;
- DPRINT3("%s: 'putting' PDS (%ld), msg_len=%ld\n",
- func, gh->pds_len,gh->msg_length);
- }
- else DPRINT1("%s: skip writing PDS\n", func);
- /*
- *
- * A.3.b.7 IF (GribHdr has no GDS yet)
- * THEN
- * FUNCTION gribputgds !Build GDS Section into GRIB_HDR
- * IF failed
- * THEN return with error !errmsg filled
- * ELSE bump 'px' to end of this section
- * ENDIF
- */
- if ((gh->gds_ptr==NULL) && (User_Input.usGds_bms_id >= 128))
- {
- if ( n = gribputgds (Geom_In,
- pGDS_Head_Input, &pvGDS_Proj_Input, &gh, errmsg) )
- {
- DPRINT2 ("%s: got err=%d in Grib Put Gds()\n",func,n);
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- else px = gh->entire_msg + gh->msg_length;
- DPRINT3 ("%s: 'putting' GDS (%ld), msg_len=%ld\n",
- func, gh->gds_len,gh->msg_length);
- }
- else DPRINT1 ("%s: skip writing GDS\n", func);
- /*
- *
- * A.3.b.8 CHECK consistency on Gds/Bms flag
- * IF (GDS is included)
- * THEN SET the GdsPresent bit
- * ELSE CLEAR the GdsPresent bit
- * ENDIF
- */
- gdsbms_flag = (int)gh->pds_ptr[7] & 0x000000FF;
- DPRINT1 ("orig gds/bms flag, pds[7] = 0x%x\n", gdsbms_flag);
- if (gh->gds_ptr == NULL) {
- gdsbms_flag &= ~(0x00000080);
- DPRINT2 ("%s: GDS missing, so CLEAR 0x80; newFLG=0x%x, \n",
- func, gdsbms_flag);
- }
- else {
- gdsbms_flag |= (0x00000080);
- DPRINT2 ("%s: GDS Present, so SET 0x80; newFLG=0x%x, \n",
- func, gdsbms_flag);
- /*
- DONOT set grid id to 255, since it is possible for user to
- define a new grid with id w/in range, and still include GDS;
- */
- }
- /*
- *
- * A.3.b.9 IF (BMS is there) THEN
- * SET the BmsPresent bit
- * ELSE
- * CLEAR the BmsPresent bit
- * ENDIF
- */
- if (gh->bms_ptr == NULL) {
- gdsbms_flag &= ~(0x00000040);
- DPRINT2 ("%s: no BMS, so CLEAR 0x40; new FLG=0x%x",func,gdsbms_flag);
- }
- else { gdsbms_flag |= (0x00000040);
- DPRINT2("%s: BMS Present, so SET 0x40; new FLG=0x%x",func,gdsbms_flag);
- }
- gh->pds_ptr[7] = (unsigned char)gdsbms_flag;
- DPRINT1 ("; PDS_ptr[7]= %x\n",gh->pds_ptr[7]);
- /*
- *
- * A.3.b.10 IF (GribHdr has no BDS yet) THEN
- * FUNCTION gribputBds !Build BDS Section into GRIB_HDR
- * !**NOT doing anything to Data even if BMS is included ***
- * IF failed
- * THEN return with error !errmsg filled
- * ELSE bump 'px' to end of this section
- * ENDIF
- */
- if ( gh->bds_ptr==NULL )
- {
- if (n= gribputbds (User_Input, Geom_In.nx*Geom_In.ny,
- pPDS_Input->sDec_sc_fctr,
- pfData_Array,
- pBDS_Head_Input, &gh, errmsg))
- {
- DPRINT2 ("%s: got err=%d in Grib Put BDS()\n",func,n);
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- else px = gh->entire_msg + gh->msg_length;
- DPRINT3 ("%s: 'putting' BDS (%ld), msg_len=%ld\n",
- func, gh->bds_len,gh->msg_length);
- }
- else DPRINT1("%s: skip writing BDS\n", func);
- /*
- *
- * A.3.b.11 IF (GribHdr has no EDS yet)
- * THEN
- * IF (Entire Msg buffer isn't big enough to hold EDS)
- * FUNCTION Expand_gribhdr !make it 4 bytes larger
- * RETURN with Error if fails !errmsg filled
- * ENDIF
- * SET up pointer to EDS
- * WRITE Grib EDS section to the end of Data !"7777"
- * UPDATE Grib Hdr's Eds_Ptr, Eds_Len
- */
- if ( gh->eds_ptr==NULL )
- {
- if (gh->msg_length+5L > gh->abs_size ) {
- DPRINT1 ("Need to expand gribhdr (%ld) to hold EDS\n",
- gh->abs_size);
- /*if (NULL == (realloc (gh->entire_msg, gh->msg_length))) */
- if (Expand_gribhdr (gh, gh->msg_length+5L, errmsg) ) {
- upd_child_errmsg (func, errmsg);
- goto BYE;
- }
- DPRINT1("gribhdr now has abs_size of %ld\n",
- gh->abs_size);
- } /* size changed */
- gh->eds_ptr= px;
- gh->eds_len= 4;
- gh->msg_length += gh->eds_len;
- memcpy ((void *)gh->eds_ptr, (void*)Sevens, 4);
- DPRINT3 ("%s: 'putting' EDS (%ld), msg_len=%ld\n",
- func, gh->eds_len,gh->msg_length);
- }
- else DPRINT1 ("%s: skip writing EDS\n", func);
- /*
- * A.3 ENDIF
- */
- } /* END SHUFFLED == 1 SECTION */
- /*
- *
- * A.4 UPDATE Total Msg Length in Grib Hdr's Ident Data Sect
- */
- set_bytes(gh->msg_length, 3, gh->ids_ptr+4);
-
- /* 1 is for the Edition 1 */
- set_bytes(1,1,gh->ids_ptr+7);
- /*
- *
- * A.5 SET status to 0 ! no errors
- */
- Stat = 0;
-
- BYE:
- /*
- *
- * A.6 PRINT message if error occurred
- */
- if (errmsg[0]!='\0') DPRINT1("%s\n", errmsg);
- /*
- *
- * A.7 FREE up space of local Input structures
- *
- * A.8 RETURN stat
- */
- /*
- * Changed by Todd Hutchinson, TASC
- * With this original code, not all memory was being freed
- */
- /* Original
- if (! pPDS_Input) free(pPDS_Input);
- if (! pGDS_Head_Input) free(pGDS_Head_Input);
- if (! pvGDS_Proj_Input) free(pvGDS_Proj_Input);
- if (! pBDS_Head_Input) free(pBDS_Head_Input);
- */
- /* New: */
- free(pPDS_Input);
- free(pGDS_Head_Input);
- free(pvGDS_Proj_Input);
- free(pBDS_Head_Input);
- DPRINT3 ("Leaving %s (Msglen=%ld), stat=%d\n", func, gh->msg_length,Stat);
- return Stat;
- /*
- *
- * END OF FUNCTION
- *
- *
- */
- }