NCEPLIBS-g2c  1.8.0
g2cindex.c
Go to the documentation of this file.
1 
8 #include "grib2_int.h"
9 #include <time.h>
10 #include <stdarg.h>
11 #include <libgen.h>
12 
15 
17 #define G2C_INDEX_HEADER_LEN 81
18 
20 #define G2C_INDEX_BASENAME_LEN 40
21 
23 #define G2C_INDEX_BITMAP_BYTES 6
24 
26 #define G2C_INDEX_FIXED_LEN 44
27 
29 #define G2C_INDEX_DATE_STR_LEN 10
30 
32 #define G2C_INDEX_TIME_STR_LEN 8
33 
35 #define G2C_INDEX_STR1_LEN 7
36 
39 
66 int
67 g2c_start_index_record(FILE *f, int rw_flag, int *reclen, int *msg, int *local, int *gds,
68  int *pds, int *drs, int *bms, int *data, size_t *msglen,
69  unsigned char *version, unsigned char *discipline, short *fieldnum)
70 {
71  /* size_t size_t_be; */
72  short fieldnum1; /* This is for the 1-based fieldnum in the index file. */
73  int ret;
74 
75  /* All pointers must be provided. */
76  if (!f || !reclen || !msg || !local || !gds || !pds || !drs || !bms || !data
77  || !msglen || !version || !discipline || !fieldnum)
78  return G2C_EINVAL;
79 
80  /* When writing, set the fieldnum1 to be a 1-based index, just
81  * like in Fortran. */
82  if (rw_flag)
83  fieldnum1 = *fieldnum + 1;
84 
85  /* Read or write the values at the beginning of each index
86  * record. */
87  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)reclen)))
88  return ret;
89  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)msg)))
90  return ret;
91  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)local)))
92  return ret;
93  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)gds)))
94  return ret;
95  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)pds)))
96  return ret;
97  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)drs)))
98  return ret;
99  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)bms)))
100  return ret;
101  if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)data)))
102  return ret;
103  if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)msglen)))
104  return ret;
105  if ((ret = g2c_file_io_ubyte(f, rw_flag, version)))
106  return ret;
107  if ((ret = g2c_file_io_ubyte(f, rw_flag, discipline)))
108  return ret;
109  if ((ret = g2c_file_io_short(f, rw_flag, &fieldnum1)))
110  return ret;
111 
112  /* When reading, translate the 1-based fieldnum1 into the 0-based
113  * fieldnum that C programmers will expect and love. */
114  if (!rw_flag)
115  *fieldnum = fieldnum1 - 1;
116 
117  return G2C_NOERROR;
118 }
119 
152 int
153 g2c_start_index1_record(FILE *f, int rw_flag, unsigned int *b2_msg, unsigned int *b2_pds,
154  unsigned int *b2_gds, unsigned int *b2_bms, unsigned int *b2_bds,
155  unsigned int *msglen, unsigned char *version, unsigned char *pds_val,
156  unsigned char *gds_val, unsigned char *bms_val, unsigned char *bds_val,
157  unsigned char *pds_val2, unsigned char *pds_val3, unsigned char *gds_val2)
158 {
159  size_t bytes_read;
160  int ret;
161 
162  /* All pointers must be provided. */
163  if (!f || !b2_msg || !b2_pds || !b2_gds || !b2_bms || !b2_bds ||
164  !msglen || !version)
165  return G2C_EINVAL;
166 
167  /* Read or write the values at the beginning of each index
168  * record. */
169  if ((ret = g2c_file_io_uint(f, rw_flag, b2_msg)))
170  return ret;
171  if ((ret = g2c_file_io_uint(f, rw_flag, b2_pds)))
172  return ret;
173  if ((ret = g2c_file_io_uint(f, rw_flag, b2_gds)))
174  return ret;
175  if ((ret = g2c_file_io_uint(f, rw_flag, b2_bms)))
176  return ret;
177  if ((ret = g2c_file_io_uint(f, rw_flag, b2_bds)))
178  return ret;
179  if ((ret = g2c_file_io_uint(f, rw_flag, msglen)))
180  return ret;
181  if ((ret = g2c_file_io_ubyte(f, rw_flag, version)))
182  return ret;
183 
184  /* The index record contains some metadata copied directly from
185  * the file. These are arrays of unsigned char, of known
186  * length. For more detail see
187  * https://noaa-emc.github.io/NCEPLIBS-grib_util/grbindex/grbindex_8f.html. */
188  if ((bytes_read = fread(pds_val, 1, G2C_INDEX1_PDS_VAL_LEN, f)) != G2C_INDEX1_PDS_VAL_LEN)
189  return G2C_EFILE;
190  if ((bytes_read = fread(gds_val, 1, G2C_INDEX1_GDS_VAL_LEN, f)) != G2C_INDEX1_GDS_VAL_LEN)
191  return G2C_EFILE;
192  if ((bytes_read = fread(bms_val, 1, G2C_INDEX1_BMS_VAL_LEN, f)) != G2C_INDEX1_BMS_VAL_LEN)
193  return G2C_EFILE;
194  if ((bytes_read = fread(bds_val, 1, G2C_INDEX1_BDS_VAL_LEN, f)) != G2C_INDEX1_BDS_VAL_LEN)
195  return G2C_EFILE;
196 
197  return G2C_NOERROR;
198 }
199 
231 int
233  G2C_SECTION_INFO_T **sec4, G2C_SECTION_INFO_T **sec5,
234  G2C_SECTION_INFO_T **sec6, G2C_SECTION_INFO_T **sec7)
235 {
236  G2C_SECTION_INFO_T *s3, *s4, *s5, *s6, *s7;
237 
238  /* Check inputs. */
239  if (!msg || fieldnum < 0 ||!sec3 || !sec4 || !sec5 || !sec6 || !sec7)
240  return G2C_EINVAL;
241 
242  /* Find the product with matching fieldnum. */
243  for (s4 = msg->sec; s4; s4 = s4->next)
244  {
245  G2C_SECTION4_INFO_T *s4info = s4->sec_info;
246  if (s4->sec_num != 4)
247  continue;
248  if (s4info->field_num == fieldnum)
249  break;
250  }
251  if (!s4)
252  return G2C_ENOSECTION;
253 
254  /* Find the section 3, grid definition section, which is
255  * associated with this product. */
256  for (s3 = s4->prev; s3; s3 = s3->prev)
257  if (s3->sec_num == 3)
258  break;
259  if (!s3)
260  return G2C_ENOSECTION;
261 
262  /* Find the section 5, data representation section, which
263  * is associated with this product. */
264  for (s5 = s4->next; s5; s5 = s5->next)
265  if (s5->sec_num == 5)
266  break;
267  if (!s5)
268  return G2C_ENOSECTION;
269 
270  /* Find the section 6, the bit map section. There may not be
271  * one. */
272  for (s6 = s5->next; s6; s6 = s6->next)
273  {
274  if (s6->sec_num == 6)
275  break;
276 
277  /* If we hit section 7, there's no bitmap. */
278  if (s6->sec_num == 7)
279  {
280  s6 = NULL;
281  break;
282  }
283  }
284 
285  /* Find the section 7, data section, which is associated with this
286  * product. */
287  for (s7 = s5->next; s7; s7 = s7->next)
288  if (s7->sec_num == 7)
289  break;
290  if (!s7)
291  return G2C_ENOSECTION;
292 
293  /* Return results to caller. */
294  *sec3 = s3;
295  *sec4 = s4;
296  *sec5 = s5;
297  *sec6 = s6;
298  *sec7 = s7;
299 
300  return G2C_NOERROR;
301 }
302 
345 int
346 g2c_write_index(int g2cid, int mode, const char *index_file)
347 {
348  FILE *f;
349  char h1[G2C_INDEX_HEADER_LEN * 2 + 1]; /* need extra space to silence GNU warnings */
350  char h2[G2C_INDEX_HEADER_LEN + 10];
351  time_t t = time(NULL);
352  struct tm tm = *localtime(&t);
353  size_t items_written;
354  char my_path[G2C_INDEX_BASENAME_LEN + 1];
355  G2C_MESSAGE_INFO_T *msg;
356  int total_index_size = 0; /* Does not include size of header records. */
357  int reclen;
358  int ret = G2C_NOERROR;
359 
360  /* Is this an open GRIB2 file? */
361  if (g2cid < 0 || g2cid > G2C_MAX_FILES)
362  return G2C_EBADID;
363  if (!index_file)
364  return G2C_EINVAL;
365 
366  LOG((1, "g2c_write_index g2cid %d mode %d index_file %s", g2cid, mode,
367  index_file));
368 
369  /* If NOCLOBBER, check if file exists. */
370  if (mode & G2C_NOCLOBBER)
371  {
372  FILE *f;
373  if ((f = fopen(index_file, "r")))
374  {
375  fclose(f);
376  return G2C_EFILE;
377  }
378  }
379 
380  /* Create the index file. */
381  if (!(f = fopen(index_file, "wb+")))
382  return G2C_EFILE;
383 
384  /* If using threading, lock the mutex. */
385  MUTEX_LOCK(m);
386 
387  if (g2c_file[g2cid].g2cid != g2cid)
388  ret = G2C_EBADID;
389 
390  if (!ret)
391  {
392  /* Create header 1. */
393  snprintf(h1, G2C_INDEX_HEADER_LEN + 1,
394  "!GFHDR! 1 1 162 %4.4u-%2.2u-%2.2u %2.2u:%2.2u:%2.2u GB2IX1 hfe08 grb2index\n",
395  (tm.tm_year + 1900), (tm.tm_mon + 1), tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
396 
397  /* Write header 1. */
398  if ((items_written = fwrite(h1, G2C_INDEX_HEADER_LEN, 1, f)) != 1)
399  ret = G2C_EFILE;
400  }
401 
402  /* Find the total length of the index we are generating. */
403  if (!ret)
404  {
405  for (msg = g2c_file[g2cid].msg; msg; msg = msg->next)
406  {
407  short fieldnum;
408 
409  /* Find information for each field in the message. */
410  for (fieldnum = 0; fieldnum < msg->num_fields; fieldnum++)
411  {
412  G2C_SECTION_INFO_T *sec3, *sec4, *sec5, *sec6, *sec7;
413 
414  if ((ret = g2c_get_prod_sections(msg, fieldnum, &sec3, &sec4, &sec5, &sec6, &sec7)))
415  break;
416 
417  /* What will be the length of this index record? */
418  reclen = G2C_INDEX_FIXED_LEN + msg->sec1_len + sec3->sec_len + sec4->sec_len +
420  total_index_size += reclen;
421  LOG((4, "fieldnum %d reclen %d total_index_size %d", fieldnum, reclen, total_index_size));
422  } /* next product */
423 
424  /* If there was a problem, give up. */
425  if (ret)
426  break;
427  } /* next message */
428  }
429 
430  /* Create header 2. */
431  if (!ret)
432  {
433  strncpy(my_path, basename(g2c_file[g2cid].path), G2C_INDEX_BASENAME_LEN);
434  sprintf(h2, "IX1FORM: 162 %6d %6ld %s \n", total_index_size,
435  g2c_file[g2cid].num_messages, my_path);
436  LOG((5, "header 2: %s", h2));
437 
438  /* Write header 2. */
439  if ((items_written = fwrite(h2, G2C_INDEX_HEADER_LEN, 1, f)) != 1)
440  ret = G2C_EFILE;
441  }
442 
443  /* Write a record of index file for each message in the file. */
444  if (!ret)
445  {
446  for (msg = g2c_file[g2cid].msg; msg; msg = msg->next)
447  {
448  short fieldnum;
449 
450  /* Find information for each field in the message. */
451  for (fieldnum = 0; fieldnum < msg->num_fields; fieldnum++)
452  {
453  G2C_SECTION_INFO_T *sec3, *sec4, *sec5, *sec6, *sec7;
454  int bytes_to_msg = (int)msg->bytes_to_msg;
455  int bs3, bs4, bs5, bs6, bs7; /* bytes to each section, as ints. */
456  unsigned char sec_num;
457  int ret;
458 
459  if ((ret = g2c_get_prod_sections(msg, fieldnum, &sec3, &sec4, &sec5, &sec6, &sec7)))
460  return ret;
461  bs3 = (int)sec3->bytes_to_sec;
462  bs4 = (int)sec4->bytes_to_sec;
463  bs5 = (int)sec5->bytes_to_sec;
464  bs6 = (int)sec6->bytes_to_sec;
465  bs7 = (int)sec7->bytes_to_sec;
466 
467  /* What will be the length of this index record? */
468  reclen = G2C_INDEX_FIXED_LEN + msg->sec1_len + sec3->sec_len + sec4->sec_len +
470  LOG((4, "fieldnum %d reclen %d", fieldnum, reclen));
471 
472  /* Write the beginning of the index record. */
473  if ((ret = g2c_start_index_record(f, G2C_FILE_WRITE, &reclen, &bytes_to_msg, &msg->bytes_to_local,
474  &bs3, &bs4, &bs5, &bs6, &bs7, &msg->bytes_in_msg, &msg->master_version,
475  &msg->discipline, &fieldnum)))
476  break;
477 
478  /* Write the section 1, identification section. */
479  if ((ret = g2c_rw_section1_metadata(f, G2C_FILE_WRITE, msg)))
480  break;
481 
482  /* Write the section 3, grid definition section. */
483  sec_num = 3;
484  if ((ret = g2c_file_io_uint(f, G2C_FILE_WRITE, &sec3->sec_len)))
485  return ret;
486  if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sec_num)))
487  return ret;
488  if ((ret = g2c_rw_section3_metadata(f, G2C_FILE_WRITE, sec3)))
489  break;
490 
491  /* Write the section 4, product definition section. */
492  sec_num = 4;
493  if ((ret = g2c_file_io_uint(f, G2C_FILE_WRITE, &sec4->sec_len)))
494  return ret;
495  if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sec_num)))
496  return ret;
497  if ((ret = g2c_rw_section4_metadata(f, G2C_FILE_WRITE, sec4)))
498  break;
499 
500  /* Write the section 5, data representation section. */
501  sec_num = 5;
502  if ((ret = g2c_file_io_uint(f, G2C_FILE_WRITE, &sec5->sec_len)))
503  return ret;
504  if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sec_num)))
505  return ret;
506  if ((ret = g2c_rw_section5_metadata(f, G2C_FILE_WRITE, sec5)))
507  break;
508 
509  /* Write the first 6 bytes of the bitmap section, if there
510  * is one. */
511  if (!ret && sec6)
512  {
513  unsigned char sample[G2C_INDEX_BITMAP_BYTES];
514  int b;
515 
516  /* Read the first 6 bytes of the bitmap section. */
517  if (fseek(msg->file->f, msg->bytes_to_msg + sec6->bytes_to_sec, SEEK_SET))
518  {
519  ret = G2C_EFILE;
520  break;
521  }
522  if ((fread(sample, ONE_BYTE, G2C_INDEX_BITMAP_BYTES, msg->file->f)) != G2C_INDEX_BITMAP_BYTES)
523  {
524  ret = G2C_EFILE;
525  break;
526  }
527 
528  /* Now write these bytes to the end of the index record. */
529  for (b = 0; b < G2C_INDEX_BITMAP_BYTES; b++)
530  if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sample[b])))
531  return ret;
532  }
533  } /* next product */
534 
535  /* If there was a problem, give up. */
536  if (ret)
537  break;
538  } /* next message */
539  }
540 
541  /* If using threading, unlock the mutex. */
542  MUTEX_UNLOCK(m);
543 
544  /* Close the index file. */
545  if (!ret)
546  if (fclose(f))
547  return G2C_EFILE;
548 
549  return ret;
550 }
551 
573 static int
574 read_hdr_rec1(FILE *f, int *ip, int *jp, int *kp, char *date_str, char *time_str)
575 {
576  size_t bytes_read;
577  char line[G2C_INDEX_HEADER_LEN + 1];
578  char str1[G2C_INDEX_STR1_LEN + 1];
579  char my_date_str[G2C_INDEX_DATE_STR_LEN + 1];
580  char my_time_str[G2C_INDEX_TIME_STR_LEN + 1];
581  int i, j, k;
582 
583  /* Read the first line of header. */
584  if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
585  return G2C_EFILE;
586  line[G2C_INDEX_HEADER_LEN] = 0;
587 
588  /* Scan the line. */
589  {
590  char long_date_str[G2C_INDEX_HEADER_LEN + 1], long_time_str[G2C_INDEX_HEADER_LEN + 1];
591  char long_str1[G2C_INDEX_HEADER_LEN + 1];
592 
593  sscanf(line, "%s %d %d %d %s %s GB2IX1", long_str1, &i, &j, &k, long_date_str, long_time_str);
594  memcpy(str1, long_str1, G2C_INDEX_STR1_LEN);
595  date_str[G2C_INDEX_STR1_LEN] = 0;
596  memcpy(date_str, long_date_str, G2C_INDEX_DATE_STR_LEN);
597  date_str[G2C_INDEX_DATE_STR_LEN] = 0;
598  memcpy(time_str, long_time_str, G2C_INDEX_TIME_STR_LEN);
599  time_str[G2C_INDEX_TIME_STR_LEN] = 0;
600  }
601  LOG((2, "str1 %s i %d j %d k %d date_str %s time_str %s", str1, i, j, k, date_str,
602  time_str));
603 
604  /* Return info to caller where desired. */
605  if (ip)
606  *ip = i;
607  if (jp)
608  *jp = j;
609  if (kp)
610  *kp = k;
611  if (date_str)
612  strncpy(date_str, my_date_str, G2C_INDEX_DATE_STR_LEN + 1);
613  if (time_str)
614  strncpy(time_str, my_time_str, G2C_INDEX_TIME_STR_LEN + 1);
615 
616  return G2C_NOERROR;
617 }
618 
640 static int
641 read_hdr_rec2(FILE *f, int *skipp, int *total_lenp, int *num_recp, char *basename)
642 {
643  size_t bytes_read;
644  char line[G2C_INDEX_HEADER_LEN + 1];
645  int skip, total_len, num_rec;
646  char my_basename[G2C_INDEX_BASENAME_LEN + 1];
647 
648  /* Read the second line of header. */
649  if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
650  return G2C_EFILE;
651  line[G2C_INDEX_HEADER_LEN] = 0;
652  /* Scan the line. Hard! */
653  {
654  char long_basename[G2C_INDEX_HEADER_LEN + 1];
655  sscanf(line, "IX1FORM: %d %d %d %s", &skip, &total_len, &num_rec, long_basename);
656  memcpy(my_basename, long_basename, G2C_INDEX_BASENAME_LEN);
657  my_basename[G2C_INDEX_BASENAME_LEN] = 0;
658  }
659 
660  /* Return info to caller where desired. */
661  if (skipp)
662  *skipp = skip;
663  if (total_lenp)
664  *total_lenp = total_len;
665  if (num_recp)
666  *num_recp = num_rec;
667  if (basename)
668  strncpy(basename, my_basename, G2C_INDEX_BASENAME_LEN + 1);
669 
670  return G2C_NOERROR;
671 }
672 
684 int
685 g2c_open_index1(const char *index_file)
686 {
687  FILE *f;
688  int i, j, k;
689  char date_str[G2C_INDEX_DATE_STR_LEN + 1];
690  char time_str[G2C_INDEX_TIME_STR_LEN + 1];
691  int skip, total_len, num_rec;
692  char basename[G2C_INDEX_BASENAME_LEN + 1];
693  size_t file_pos = G2C_INDEX_HEADER_LEN * 2;
694  unsigned char pds_val[G2C_INDEX1_PDS_VAL_LEN];
695  unsigned char gds_val[G2C_INDEX1_GDS_VAL_LEN];
696  unsigned char bms_val[G2C_INDEX1_BMS_VAL_LEN];
697  unsigned char bds_val[G2C_INDEX1_BDS_VAL_LEN];
698  int rec;
699  int ret = G2C_NOERROR;
700 
701  /* Check inputs. */
702  if (!index_file)
703  return G2C_EINVAL;
704 
705  LOG((1, "g2c_open_index1 index_file %s", index_file));
706 
707  /* If using threading, lock the mutex. */
708  MUTEX_LOCK(m);
709 
710  /* Open the index file. */
711  if (!(f = fopen(index_file, "rb")))
712  return G2C_EFILE;
713 
714  /* Read header record apparently named after Steve Lord. */
715  if ((ret = read_hdr_rec1(f, &i, &j, &k, date_str, time_str)))
716  return ret;
717  LOG((2, "i %d j %d k %d date_str %s time_str %s", i, j, k, date_str, time_str));
718 
719  /* Read second header record. */
720  if ((ret = read_hdr_rec2(f, &skip, &total_len, &num_rec, basename)))
721  return ret;
722  LOG((2, "skip %d total_len %d num_rec %d basename %s", skip, total_len, num_rec, basename));
723 
724  /* Read each index record. These is one record for each message in
725  the original GRIB1 file. */
726  for (rec = 0; rec < num_rec; rec++)
727  {
728  unsigned int b2_msg, b2_gds, b2_pds, b2_bms, b2_bds, msglen;
729  unsigned char version;
730 
731  /* Move to beginning of index record. */
732  if (fseek(f, file_pos, SEEK_SET))
733  {
734  ret = G2C_EFILE;
735  break;
736  }
737 
738  /* Read the index1 record. */
739  LOG((4, "reading index1 record at file position %ld", ftell(f)));
740  if ((ret = g2c_start_index1_record(f, G2C_FILE_READ, &b2_msg, &b2_pds, &b2_gds,
741  &b2_bms, &b2_bds, &msglen, &version, pds_val,
742  gds_val, bms_val, bds_val, NULL, NULL, NULL)))
743  break;
744 
745  LOG((3, "b2_msg %d b2_pds %d b2_gds %d b2_bms %d b2_bds %d msglen %d version %d",
746  b2_msg, b2_gds, b2_pds, b2_bms, b2_bds, msglen, version));
747  printf("b2_msg %d b2_pds %d b2_gds %d b2_bms %d b2_bds %d msglen %d version %d\n",
748  b2_msg, b2_gds, b2_pds, b2_bms, b2_bds, msglen, version);
749 
750  /* Move the file position to the start of the next index record. */
751  file_pos += total_len;
752  } /* next rec */
753 
754  /* If using threading, unlock the mutex. */
755  MUTEX_UNLOCK(m);
756 
757  /* Close the index file. */
758  if (!ret)
759  fclose(f);
760 
761  return ret;
762 }
763 
785 int
786 g2c_open_index(const char *data_file, const char *index_file, int mode,
787  int *g2cid)
788 {
789  FILE *f;
790  size_t bytes_read;
791  int ret = G2C_NOERROR;
792 
793  /* Check inputs. */
794  if (!index_file || !data_file || !g2cid)
795  return G2C_EINVAL;
796  if (strlen(data_file) > G2C_MAX_NAME)
797  return G2C_ENAMETOOLONG;
798 
799  LOG((1, "g2c_open_index index_file %s", index_file));
800 
801  /* Open the index file. */
802  if (!(f = fopen(index_file, "rb")))
803  return G2C_EFILE;
804 
805  /* If using threading, lock the mutex. */
806  MUTEX_LOCK(m);
807 
808  /* Remember file metadata. */
809  ret = g2c_add_file(data_file, mode, g2cid);
810 
811  /* Read the header. */
812  if (!ret)
813  {
814  char line[G2C_INDEX_HEADER_LEN + 1];
815  char str1[G2C_INDEX_STR1_LEN + 1], date_str[G2C_INDEX_DATE_STR_LEN + 1], time_str[G2C_INDEX_TIME_STR_LEN + 1];
816  int i, j, k;
817  int skip, total_len, num_rec;
818  char basename[G2C_INDEX_BASENAME_LEN + 1];
819  size_t file_pos = G2C_INDEX_HEADER_LEN * 2;
820  int rec;
821 
822  /* Read the first line of header. */
823  if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
824  return G2C_EFILE;
825  line[G2C_INDEX_HEADER_LEN] = 0;
826  /* Scan the line. */
827  {
828  char long_date_str[G2C_INDEX_HEADER_LEN + 1], long_time_str[G2C_INDEX_HEADER_LEN + 1];
829  char long_str1[G2C_INDEX_HEADER_LEN + 1];
830 
831  sscanf(line, "%s %d %d %d %s %s GB2IX1", long_str1, &i, &j, &k, long_date_str, long_time_str);
832  memcpy(str1, long_str1, G2C_INDEX_STR1_LEN);
833  date_str[G2C_INDEX_STR1_LEN] = 0;
834  memcpy(date_str, long_date_str, G2C_INDEX_DATE_STR_LEN);
835  date_str[G2C_INDEX_DATE_STR_LEN] = 0;
836  memcpy(time_str, long_time_str, G2C_INDEX_TIME_STR_LEN);
837  time_str[G2C_INDEX_TIME_STR_LEN] = 0;
838  }
839  LOG((2, "str1 %s i %d j %d k %d date_str %s time_str %s", str1, i, j, k, date_str,
840  time_str));
841 
842  /* Read the second line of header. */
843  if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
844  return G2C_EFILE;
845  line[G2C_INDEX_HEADER_LEN] = 0;
846  /* Scan the line. Hard! */
847  {
848  char long_basename[G2C_INDEX_HEADER_LEN + 1];
849  sscanf(line, "IX1FORM: %d %d %d %s", &skip, &total_len, &num_rec, long_basename);
850  memcpy(basename, long_basename, G2C_INDEX_BASENAME_LEN);
851  basename[G2C_INDEX_BASENAME_LEN] = 0;
852  }
853  LOG((2, "skip %d total_len %d num_rec %d basename %s", skip, total_len, num_rec, basename));
854 
855  /* Read each index record. */
856  for (rec = 0; rec < num_rec; rec++)
857  {
858  int reclen, msg, local, gds, pds, drs, bms, data;
859  size_t msglen;
860  unsigned char version, discipline;
861  short fieldnum;
862 
863  /* Move to beginning of index record. */
864  if (fseek(f, file_pos, SEEK_SET))
865  {
866  ret = G2C_EFILE;
867  break;
868  }
869 
870  /* Read the index record. */
871  LOG((4, "reading index record at file position %ld", ftell(f)));
872  if ((ret = g2c_start_index_record(f, G2C_FILE_READ, &reclen, &msg, &local, &gds, &pds,
873  &drs, &bms, &data, &msglen, &version, &discipline, &fieldnum)))
874  break;
875 
876  LOG((3, "reclen %d msg %d local %d gds %d pds %d drs %d bms %d data %d "
877  "msglen %ld version %d discipline %d fieldnum %d",
878  reclen, msg, local, gds, pds, drs, bms, data, msglen,
879  version, discipline, fieldnum));
880 
881  /* Read the metadata for sections 3, 4, and 5 from
882  * the index record. */
883  {
884  unsigned int sec_len;
885  unsigned char sec_num;
886  int s;
887  G2C_MESSAGE_INFO_T *msgp;
888  int sec_id = 0;
889 
890  /* Allocate storage for message. */
891  if ((ret = add_msg(&g2c_file[*g2cid], rec, msg, msglen, 0, &msgp)))
892  break;
893  msgp->discipline = discipline;
894  msgp->bytes_to_local = local;
895  msgp->bytes_to_bms = bms;
896  msgp->bytes_to_data = data;
897  msgp->master_version = version;
898 
899  /* Read section 1. */
900  if ((ret = g2c_rw_section1_metadata(f, G2C_FILE_READ, msgp)))
901  break;
902  if ((ret = g2c_log_section1(msgp)))
903  break;
904 
905  LOG((4, "reading section info at file position %ld", ftell(f)));
906 
907  /* Add a new section to our list of sections. */
908  for (s = 3; s < 8; s++)
909  {
910  size_t bytes_to_sec = gds; /* Correct value for section 3. */
911 
912  /* For sections 3, 4, 5, read the section length
913  * and number from the index record. */
914  if (s < 6)
915  {
916  if ((ret = g2c_file_io_uint(f, G2C_FILE_READ, &sec_len)))
917  return ret;
918  if ((ret = g2c_file_io_ubyte(f, G2C_FILE_READ, &sec_num)))
919  return ret;
920  }
921  else
922  {
923  /* For section 7, the length of the section is
924  * not in the index file, but is needed for
925  * data read operations. So we will use the
926  * open data file and get the length of this
927  * section. */
928  if (fseek(g2c_file[*g2cid].f, msgp->bytes_to_msg + data, SEEK_SET))
929  {
930  ret = G2C_EFILE;
931  break;
932  }
933  if ((ret = g2c_file_io_uint(g2c_file[*g2cid].f, G2C_FILE_READ, &sec_len)))
934  return ret;
935  if ((ret = g2c_file_io_ubyte(g2c_file[*g2cid].f, G2C_FILE_READ, &sec_num)))
936  return ret;
937  LOG((4, "read section 7 info from data file. sec_len %d sec_num %d",
938  sec_len, sec_num));
939  }
940 
941  /* Select the value from the index record which is
942  * the number of bytes to section s. */
943  if (s == 4)
944  bytes_to_sec = pds;
945  else if (s == 5)
946  bytes_to_sec = drs;
947  else if (s == 6)
948  bytes_to_sec = bms;
949  else if (s == 7)
950  bytes_to_sec = data;
951 
952  /* Check some stuff. */
953  if (s < 6 && sec_num != s)
954  {
955  ret = G2C_EBADSECTION;
956  break;
957  }
958  if (sec_num == 4)
959  if (fieldnum < 0) /* to silence warning */
960  {
961  ret = G2C_EBADSECTION;
962  break;
963  }
964 
965  /* Read the section info from the index file,
966  * using the same functions that read it from the
967  * GRIB2 data file. */
968  if ((ret = add_section(f, msgp, sec_id++, sec_len, bytes_to_sec, s)))
969  break;
970  } /* next section */
971 
972  /* If anything went wrong, give up. */
973  if (ret)
974  break;
975  }
976 
977  /* Move the file position to the start of the next index record. */
978  file_pos += reclen;
979  } /* next rec */
980  }
981 
982  /* If using threading, unlock the mutex. */
983  MUTEX_UNLOCK(m);
984 
985  /* Close the index file. */
986  if (!ret)
987  fclose(f);
988 
989  return ret;
990 }
int add_msg(G2C_FILE_INFO_T *file, int msg_num, size_t bytes_to_msg, size_t bytes_in_msg, int read_file, G2C_MESSAGE_INFO_T **msg)
Add new message to linked list.
Definition: g2cfile.c:1020
int add_section(FILE *f, G2C_MESSAGE_INFO_T *msg, int sec_id, unsigned int sec_len, size_t bytes_to_sec, unsigned char sec_num)
Add metadata about a new section 3, 4, 5, 6, or 7.
Definition: g2cfile.c:797
int g2c_rw_section5_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec)
Read or write the metadata from section 5 (Data Representation Section) of a GRIB2 message.
Definition: g2cfile.c:666
int g2c_rw_section1_metadata(FILE *f, int rw_flag, G2C_MESSAGE_INFO_T *msg)
Read Section 1.
Definition: g2cfile.c:877
int g2c_add_file(const char *path, int mode, int *g2cid)
Open a GRIB2 file and add it to the list of open files.
Definition: g2cfile.c:1146
int g2c_rw_section3_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec)
Read the metadata from section 3 (Grid Definition Section) of a GRIB2 message.
Definition: g2cfile.c:481
int g2c_rw_section4_metadata(FILE *f, int rw_flag, G2C_SECTION_INFO_T *sec)
Read or write the metadata from section 4 (Product Definition Section) of a GRIB2 message.
Definition: g2cfile.c:577
int g2c_open_index(const char *data_file, const char *index_file, int mode, int *g2cid)
Open a GRIB2 file with the help of an index file.
Definition: g2cindex.c:786
int g2c_start_index1_record(FILE *f, int rw_flag, unsigned int *b2_msg, unsigned int *b2_pds, unsigned int *b2_gds, unsigned int *b2_bms, unsigned int *b2_bds, unsigned int *msglen, unsigned char *version, unsigned char *pds_val, unsigned char *gds_val, unsigned char *bms_val, unsigned char *bds_val, unsigned char *pds_val2, unsigned char *pds_val3, unsigned char *gds_val2)
Read or write the start of a version 1 index record.
Definition: g2cindex.c:153
int g2c_open_index1(const char *index_file)
Open a GRIB1 index file and read the contents.
Definition: g2cindex.c:685
static int read_hdr_rec1(FILE *f, int *ip, int *jp, int *kp, char *date_str, char *time_str)
Read the header record apparently named after Steve Lord.
Definition: g2cindex.c:574
#define G2C_INDEX_BITMAP_BYTES
Length of bitmap section included in the index record.
Definition: g2cindex.c:23
#define G2C_INDEX_HEADER_LEN
Length of the two header lines at the top of the index file.
Definition: g2cindex.c:17
G2C_FILE_INFO_T g2c_file[G2C_MAX_FILES+1]
Global file information.
Definition: g2cfile.c:10
int g2c_start_index_record(FILE *f, int rw_flag, int *reclen, int *msg, int *local, int *gds, int *pds, int *drs, int *bms, int *data, size_t *msglen, unsigned char *version, unsigned char *discipline, short *fieldnum)
Read or write the start of a version 2 index record.
Definition: g2cindex.c:67
int g2c_write_index(int g2cid, int mode, const char *index_file)
Create an index file from a GRIB2 file, just like those created by the grb2index utility.
Definition: g2cindex.c:346
#define G2C_INDEX_FIXED_LEN
Length of beginning of index record.
Definition: g2cindex.c:26
#define G2C_INDEX_DATE_STR_LEN
Length of date string in index record.
Definition: g2cindex.c:29
#define G2C_INDEX_STR1_LEN
Length of str1 string in index record.
Definition: g2cindex.c:35
#define G2C_INDEX_TIME_STR_LEN
Length of time string in index record.
Definition: g2cindex.c:32
int g2c_get_prod_sections(G2C_MESSAGE_INFO_T *msg, int fieldnum, G2C_SECTION_INFO_T **sec3, G2C_SECTION_INFO_T **sec4, G2C_SECTION_INFO_T **sec5, G2C_SECTION_INFO_T **sec6, G2C_SECTION_INFO_T **sec7)
Given a pointer to a message, and a field number, return pointers to all relevent section structs for...
Definition: g2cindex.c:232
EXTERN_MUTEX(m)
Use externally-defined mutex for thread-safety.
#define G2C_INDEX_BASENAME_LEN
Length of the basename in header record 2.
Definition: g2cindex.c:20
static int read_hdr_rec2(FILE *f, int *skipp, int *total_lenp, int *num_recp, char *basename)
Read the second header record of an index file.
Definition: g2cindex.c:641
int g2c_file_io_ulonglong(FILE *f, int write, unsigned long long *var)
Read or write a big-endian unsigned long long to an open GRIB2 file, with conversion between native a...
Definition: g2cio.c:380
int g2c_file_io_short(FILE *f, int write, short *var)
Read or write a big-endian signed short to an open GRIB2 file, with conversion between native and big...
Definition: g2cio.c:273
int g2c_file_io_ubyte(FILE *f, int write, unsigned char *var)
Read or write a big-endian unsigned byte to an open GRIB2 file, with conversion between native and bi...
Definition: g2cio.c:337
int g2c_file_io_uint(FILE *f, int write, unsigned int *var)
Read or write a big-endian 4-byte unsigned int to an open GRIB2 file, with conversion between native ...
Definition: g2cio.c:251
int g2c_log_section1(G2C_MESSAGE_INFO_T *msg)
Log section 0 information.
Definition: g2cutil.c:101
#define G2C_MAX_FILES
Maximum number of open files.
Definition: grib2.h:289
#define G2C_NOCLOBBER
Don't destroy existing file.
Definition: grib2.h:294
#define G2C_ENAMETOOLONG
Name too long.
Definition: grib2.h:495
#define G2C_ENOSECTION
Cannot find section.
Definition: grib2.h:506
#define G2C_EFILE
File I/O error.
Definition: grib2.h:497
#define G2C_MAX_NAME
Maximum length of a name.
Definition: grib2.h:290
#define G2C_EINVAL
Invalid input.
Definition: grib2.h:496
#define G2C_EBADSECTION
Invalid section number.
Definition: grib2.h:509
#define G2C_EBADID
Bad ID.
Definition: grib2.h:498
#define G2C_NOERROR
No error.
Definition: grib2.h:491
Header file with internal function prototypes NCEPLIBS-g2c library.
#define G2C_FILE_READ
Read.
Definition: grib2_int.h:129
int bytes_to_local
Number of bytes in the message before the (first) local section.
Definition: grib2_int.h:142
#define G2C_INDEX1_BDS_VAL_LEN
Length of the binary data section (bds) in index file.
Definition: grib2_int.h:73
#define G2C_FILE_WRITE
Write.
Definition: grib2_int.h:130
struct g2c_section_info * next
Pointer to next in list.
Definition: grib2_int.h:176
struct g2c_section_info * sec
List of section metadata.
Definition: grib2_int.h:162
unsigned char master_version
GRIB master tables version number.
Definition: grib2_int.h:151
#define MUTEX_UNLOCK(m)
Pthreads not enabled, so do nothing.
Definition: grib2_int.h:117
#define G2C_INDEX1_GDS_VAL_LEN
Length of the grid definition section (gds) in index file.
Definition: grib2_int.h:67
int bytes_to_data
Number of bytes in the message to the (first) data section.
Definition: grib2_int.h:144
#define G2C_INDEX1_BMS_VAL_LEN
Length of the bitmap section (bms) in index file.
Definition: grib2_int.h:70
unsigned char discipline
Discipline from section 0.
Definition: grib2_int.h:138
size_t bytes_in_msg
Number of bytes in this message.
Definition: grib2_int.h:137
struct g2c_section_info * prev
Pointer to previous in list.
Definition: grib2_int.h:177
int num_fields
Number of fields in the message.
Definition: grib2_int.h:140
unsigned char sec_num
Section number.
Definition: grib2_int.h:173
#define G2C_INDEX1_PDS_VAL_LEN
Length of the product definition section (pds) in index file.
Definition: grib2_int.h:64
void * sec_info
Pointer to struct specific for section 3, 4, 5, 6, or 7.
Definition: grib2_int.h:175
unsigned int sec_len
Length of the section (in bytes).
Definition: grib2_int.h:171
size_t bytes_to_sec
Number of bytes from start of message to this section.
Definition: grib2_int.h:172
#define ONE_BYTE
One byte.
Definition: grib2_int.h:50
#define LOG(e)
Ignore logging to stdout.
Definition: grib2_int.h:426
FILE * f
FILE pointer to open file.
Definition: grib2_int.h:239
int bytes_to_bms
Number of bytes in the message to the bitmap section.
Definition: grib2_int.h:143
size_t bytes_to_msg
Number of bytes to skip in the file, to get to this message.
Definition: grib2_int.h:136
#define MUTEX_LOCK(m)
Pthreads not enabled, so do nothing.
Definition: grib2_int.h:114
int sec1_len
Length of section 1.
Definition: grib2_int.h:148
struct g2c_message_info * next
Pointer to next in list.
Definition: grib2_int.h:164
struct g2c_file_info * file
Pointer to containing file.
Definition: grib2_int.h:163
This is the information about each open file.
Definition: grib2_int.h:236
This is the information about each message.
Definition: grib2_int.h:134
Information about Section 4 PRODUCT DEFINITION SECTION.
Definition: grib2_int.h:207
Information about a section 3 through 7 in a GRIB2 message.
Definition: grib2_int.h:169