Skip to content

Commit

Permalink
improved the way big-endian values are read from file with macros (#335)
Browse files Browse the repository at this point in the history
* improved the way big-endian values are read from file with macros

* improved the way big-endian values are read from file with macros

* improved the way big-endian values are read from file with macros

* improved the way big-endian values are read from file with macros

* improved the way big-endian values are read from file with macros
  • Loading branch information
edwardhartnett authored Oct 17, 2022
1 parent 80f839d commit 8a1fde6
Show file tree
Hide file tree
Showing 5 changed files with 165 additions and 76 deletions.
100 changes: 55 additions & 45 deletions src/g2cfile.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@ int g2c_next_g2cid = 1;
/** Number of bytes to discipline field in GRIB2 message. */
#define BYTES_TO_DISCIPLINE 6

#define ONE_BYTE 1 /**< One byte. */
#define TWO_BYTES 2 /**< Two bytes. */
#define FOUR_BYTES 4 /**< Four bytes. */

/** Search a file for the next GRIB1 or GRIB2 message.
*
* A grib message is identified by its indicator section,
Expand Down Expand Up @@ -700,6 +696,58 @@ add_section(G2C_MESSAGE_INFO_T *msg, int sec_id, unsigned int sec_len, size_t by
return G2C_NOERROR;
}

/**
* Read Section 1.
*
* @param f Pointer to open file.
* @param skip Skip this many bytes to get to section 0.
* @param msg Pointer to G2C_MESSAGE_INFO_T which will be populated
* with the values of section 0.
*
* @return
* -G2C_NOERROR No error.
*
* @author Ed Hartnett @date 10/16/22
*/
int
g2c_read_section1_metadata(FILE *f, size_t skip, G2C_MESSAGE_INFO_T *msg)
{
int int_be;
short short_be;
char sec_num;

/* Skip to section 1. */
if (fseek(f, skip, SEEK_CUR))
return G2C_EFILE;

/* Read the section. */
READ_BE_INT4(f, msg->sec1_len);
READ_BE_INT1(f, sec_num);
if (sec_num != 1)
return G2C_ENOSECTION;
READ_BE_INT2(f, msg->center);
READ_BE_INT2(f, msg->subcenter);
READ_BE_INT1(f, msg->master_version);
READ_BE_INT1(f, msg->local_version);
READ_BE_INT1(f, msg->sig_ref_time);
READ_BE_INT2(f, msg->year);
READ_BE_INT1(f, msg->month);
READ_BE_INT1(f, msg->day);
READ_BE_INT1(f, msg->hour);
READ_BE_INT1(f, msg->minute);
READ_BE_INT1(f, msg->second);
READ_BE_INT1(f, msg->status);
READ_BE_INT1(f, msg->type);

/* Section 1 may contain optional numbers at the end of the
* section. The sec1_len tells us if there are extra values. If
* so, skip them. */
if (msg->sec1_len > G2C_SECTION1_BYTES)
fseek(f, msg->sec1_len - G2C_SECTION1_BYTES, SEEK_CUR);

return G2C_NOERROR;
}

/**
* Read the file to get metadata about a message.
*
Expand All @@ -715,8 +763,6 @@ static int
read_msg_metadata(G2C_MESSAGE_INFO_T *msg)
{
int int_be;
short short_be;
char sec_num;
int total_read = G2C_SECTION0_BYTES;
int sec_id = 0;
int ret;
Expand All @@ -729,44 +775,8 @@ read_msg_metadata(G2C_MESSAGE_INFO_T *msg)
return G2C_EFILE;

/* Read section 1. */
if (fseek(msg->file->f, 9, SEEK_CUR))
return G2C_EFILE;
if ((fread(&int_be, FOUR_BYTES, 1, msg->file->f)) != 1)
return G2C_EFILE;
msg->sec1_len = htonl(int_be);
if ((fread(&sec_num, 1, 1, msg->file->f)) != 1)
return G2C_EFILE;
if (sec_num != 1)
return G2C_ENOSECTION;
if ((fread(&short_be, TWO_BYTES, 1, msg->file->f)) != 1)
return G2C_EFILE;
msg->center = htons(short_be);
if ((fread(&short_be, TWO_BYTES, 1, msg->file->f)) != 1)
return G2C_EFILE;
msg->subcenter = htons(short_be);
if ((fread(&msg->master_version, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->local_version, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->sig_ref_time, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&short_be, TWO_BYTES, 1, msg->file->f)) != 1)
return G2C_EFILE;
msg->year = htons(short_be);
if ((fread(&msg->month, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->day, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->hour, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->minute, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->second, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->status, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((fread(&msg->type, ONE_BYTE, 1, msg->file->f)) != 1)
return G2C_EFILE;
if ((ret = g2c_read_section1_metadata(msg->file->f, 9, msg)))
return ret;
total_read += msg->sec1_len;

/* Read the sections. */
Expand All @@ -775,7 +785,7 @@ read_msg_metadata(G2C_MESSAGE_INFO_T *msg)
int sec_len;
unsigned char sec_num;

LOG((4, "reading new section at file position %ld", ftell(msg->file->f)));
LOG((4, "reading new section at file position %ld", ftell(msg->file->f)));

/* Read section length. */
if ((fread(&int_be, FOUR_BYTES, 1, msg->file->f)) != 1)
Expand Down
7 changes: 6 additions & 1 deletion src/grib2.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,12 @@ g2int jpcunpack(unsigned char *cpack, g2int len, g2int *idrstmpl, g2int ndpts,
#define G2C_NOCLOBBER 0x0004 /**< Don't destroy existing file. Mode flag for g2c_create(). */

/* Useful constants. */
#define G2C_SECTION0_BYTES 16 /**< Number of bytes in section 1. */
#define G2C_SECTION0_BYTES 16 /**< Number of bytes in section 0. */

/** Number of bytes in section 1 (not including reserved, optional
* data at the end of the section). */
#define G2C_SECTION1_BYTES 21

#define G2C_SECTION0_LEN 3 /**< Length of section 0 array. */
#define G2C_SECTION1_LEN 13 /**< Length of section 1 array. */

Expand Down
51 changes: 51 additions & 0 deletions src/grib2_int.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,53 @@
#define BYTE 8 /**< Number of bits in a byte. */
#define WORD 32 /**< Number of bits in four bytes. */

#define ONE_BYTE 1 /**< One byte. */
#define TWO_BYTES 2 /**< Two bytes. */
#define FOUR_BYTES 4 /**< Four bytes. */
#define EIGHT_BYTES 8 /**< Eight bytes. */

/** Byte swap 64-bit ints. This converts big-endian 8-byte ints into
* native endian 8-byte ints. */
#define bswap64(y) (((uint64_t)ntohl(y)) << 32 | ntohl(y>>32))

/** Read a big-endian 1-byte int from an open file; since it is only 1
* byte, no conversion is nevessary. */
#define READ_BE_INT1(f, var) \
do { \
if ((fread(&var, 1, 1, f)) != 1) \
return G2C_EFILE; \
} while(0)

/** Read a big-endian 2-byte int from an open file, and convert it to
* machine-native format. The integer short_be must be declared before
* this macro is used. */
#define READ_BE_INT2(f, var) \
do { \
if ((fread(&short_be, TWO_BYTES, 1, f)) != 1) \
return G2C_EFILE; \
var = htons(short_be); \
} while(0)

/** Read a big-endian 4-byte int from an open file, and convert it to
* machine-native format. The integer int_be must be declared before
* this macro is used. */
#define READ_BE_INT4(f, var) \
do { \
if ((fread(&int_be, FOUR_BYTES, 1, f)) != 1) \
return G2C_EFILE; \
var = htonl(int_be); \
} while(0)

/** Read a big-endian 8-byte int from an open file, and convert it to
* machine-native format. The integer size_t_be must be declared before
* this macro is used. */
#define READ_BE_INT8(f, var) \
do { \
if ((fread(&size_t_be, EIGHT_BYTES, 1, f)) != 1) \
return G2C_EFILE; \
var = bswap64(size_t_be); \
} while(0)

/** This is the information about each message. */
typedef struct g2c_message_info
{
Expand Down Expand Up @@ -264,6 +311,10 @@ int pack_gp(g2int *kfildo, g2int *ic, g2int *nxy,
/* Check the message header and check for message termination. */
int g2c_check_msg(unsigned char *cgrib, g2int *lencurr, int verbose);

/* Read section metadata. */
int g2c_read_section1_metadata(FILE *f, size_t skip, G2C_MESSAGE_INFO_T *msg);
int g2c_log_section1(G2C_MESSAGE_INFO_T *msg);

/* Handle logging. */
#ifdef LOGGING

Expand Down
2 changes: 0 additions & 2 deletions src/seekgb.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@

#define G2C_SEEKMSG_BUFSIZE 4092 /**< Size of buffer used in g2c_seekmsg(). */

#define bswap64(y) (((uint64_t)ntohl(y)) << 32 | ntohl(y>>32)) /**< Byte swap 64-bit ints. */

/** Global file information. */
extern G2C_FILE_INFO_T g2c_file[G2C_MAX_FILES + 1];

Expand Down
81 changes: 53 additions & 28 deletions src/util.c
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,58 @@ g2c_strerror(int g2cerr)
}
}

/**
* Log section 0 information.
*
* @param msg Pointer to ::G2C_MESSAGE_INFO_T which contains section 0
* information.
*
* @return
* - ::G2C_NOERROR No error.
*
* @author Ed Hartnett @date 10/16/22
*/
int
g2c_log_section1(G2C_MESSAGE_INFO_T *msg)
{
#ifdef LOGGING
char desc[G2C_MAX_GRIB_DESC_LEN + 1];
int ret;

/* Read in the XML GRIB2 code definitions. */
if ((ret = g2c_xml_init()))
return ret;

/* Section 0 discipline flag. */
if ((ret = g2c_find_desc("Code table 0.0", msg->discipline, desc)))
return ret;
LOG((2, "Discipline: %s", desc));

/* Section 1 flags. */
LOG((2, "Identification of originating/generating center: %d", msg->center));
LOG((2, "Identification of originating/generating subcenter: %d", msg->subcenter));
if ((ret = g2c_find_desc("Code table 1.0", msg->master_version, desc)))
return ret;
LOG((2, "GRIB master tables version number: %s", desc));
if ((ret = g2c_find_desc("Code table 1.1", msg->local_version, desc)))
return ret;
LOG((2, "Version number of GRIB local tables used to augment Master Tables: %s", desc));
if ((ret = g2c_find_desc("Code table 1.2", msg->sig_ref_time, desc)))
return ret;
LOG((2, "Significance of reference time: %s", desc));
LOG((2, "Reference time: %d/%d/%d %d:%d:%d", msg->year, msg->month, msg->day,
msg->hour, msg->minute, msg->second));
if ((ret = g2c_find_desc("Code table 1.3", msg->status, desc)))
return ret;
LOG((2, "Production Status of Processed data in the GRIB message: %s", desc));
if ((ret = g2c_find_desc("Code table 1.4", msg->type, desc)))
return ret;
LOG((2, "Type of processed data in this GRIB message: %s", desc));

#endif
return G2C_NOERROR;
}

/**
* Print a summary of the contents of an open GRIB2 file. If the
* NCEPLIBS-g2c library is built without the LOGGING option, this
Expand Down Expand Up @@ -250,35 +302,8 @@ g2c_log_file(int g2cid)

/* If we've loaded XML tables, decode some flags. */
if (g2c_table)
{
char desc[G2C_MAX_GRIB_DESC_LEN + 1];

/* Section 0 discipline flag. */
if ((ret = g2c_find_desc("Code table 0.0", msg->discipline, desc)))
return ret;
LOG((2, "Discipline: %s", desc));

/* Section 1 flags. */
LOG((2, "Identification of originating/generating center: %d", msg->center));
LOG((2, "Identification of originating/generating subcenter: %d", msg->subcenter));
if ((ret = g2c_find_desc("Code table 1.0", msg->master_version, desc)))
return ret;
LOG((2, "GRIB master tables version number: %s", desc));
if ((ret = g2c_find_desc("Code table 1.1", msg->local_version, desc)))
return ret;
LOG((2, "Version number of GRIB local tables used to augment Master Tables: %s", desc));
if ((ret = g2c_find_desc("Code table 1.2", msg->sig_ref_time, desc)))
return ret;
LOG((2, "Significance of reference time: %s", desc));
LOG((2, "Reference time: %d/%d/%d %d:%d:%d", msg->year, msg->month, msg->day,
msg->hour, msg->minute, msg->second));
if ((ret = g2c_find_desc("Code table 1.3", msg->status, desc)))
return ret;
LOG((2, "Production Status of Processed data in the GRIB message: %s", desc));
if ((ret = g2c_find_desc("Code table 1.4", msg->type, desc)))
if ((ret = g2c_log_section1(msg)))
return ret;
LOG((2, "Type of processed data in this GRIB message: %s", desc));
}

/* Section info. */
for (sec = msg->sec; sec; sec = sec->next)
Expand Down

0 comments on commit 8a1fde6

Please sign in to comment.