NCEPLIBS-g2c 2.0.0
Loading...
Searching...
No Matches
g2cindex.c
Go to the documentation of this file.
1
8#include "grib2_int.h"
9#include <libgen.h>
10#include <stdarg.h>
11#include <time.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_FIXED_LEN_2 48
30
32#define G2C_INDEX_DATE_STR_LEN 10
33
35#define G2C_INDEX_TIME_STR_LEN 8
36
38#define G2C_INDEX_STR1_LEN 7
39
42
69int
70g2c_start_index_record(FILE *f, int rw_flag, int *reclen, int *msg, int *local, int *gds,
71 int *pds, int *drs, int *bms, int *data, size_t *msglen,
72 unsigned char *version, unsigned char *discipline, short *fieldnum)
73{
74 /* size_t size_t_be; */
75 short fieldnum1; /* This is for the 1-based fieldnum in the index file. */
76 int ret;
77
78 /* All pointers must be provided. */
79 if (!f || !reclen || !msg || !local || !gds || !pds || !drs || !bms || !data || !msglen || !version || !discipline || !fieldnum)
80 return G2C_EINVAL;
81
82 LOG((4, "g2c_start_index_record rw_flag %d", rw_flag));
83
84 /* When writing, set the fieldnum1 to be a 1-based index, just
85 * like in Fortran. */
86 if (rw_flag)
87 fieldnum1 = *fieldnum + 1;
88
89 /* Read or write the values at the beginning of each index
90 * record. */
91 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)reclen)))
92 return ret;
93 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)msg)))
94 return ret;
95 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)local)))
96 return ret;
97 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)gds)))
98 return ret;
99 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)pds)))
100 return ret;
101 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)drs)))
102 return ret;
103 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)bms)))
104 return ret;
105 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)data)))
106 return ret;
107 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)msglen)))
108 return ret;
109 if ((ret = g2c_file_io_ubyte(f, rw_flag, version)))
110 return ret;
111 if ((ret = g2c_file_io_ubyte(f, rw_flag, discipline)))
112 return ret;
113 if ((ret = g2c_file_io_short(f, rw_flag, &fieldnum1)))
114 return ret;
115
116 /* When reading, translate the 1-based fieldnum1 into the 0-based
117 * fieldnum that C programmers will expect and love. */
118 if (!rw_flag)
119 *fieldnum = fieldnum1 - 1;
120
121 return G2C_NOERROR;
122}
123
150int
151g2c_start_index_record_lf(FILE *f, int rw_flag, int *reclen, size_t *msg, size_t *local, size_t *gds,
152 size_t *pds, size_t *drs, size_t *bms, size_t *data, size_t *msglen,
153 unsigned char *version, unsigned char *discipline, short *fieldnum)
154{
155 /* size_t size_t_be; */
156 short fieldnum1; /* This is for the 1-based fieldnum in the index file. */
157 int ret;
158
159 LOG((4, "g2c_start_index_record_lf rw_flag %d", rw_flag));
160
161 /* All pointers must be provided. */
162 if (!f || !reclen || !msg || !local || !gds || !pds || !drs || !bms || !data || !msglen || !version || !discipline || !fieldnum)
163 return G2C_EINVAL;
164
165 /* When writing, set the fieldnum1 to be a 1-based index, just
166 * like in Fortran. */
167 if (rw_flag)
168 fieldnum1 = *fieldnum + 1;
169
170 /* Read or write the values at the beginning of each index
171 * record. */
172 if ((ret = g2c_file_io_uint(f, rw_flag, (unsigned int *)reclen)))
173 return ret;
174 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)msg)))
175 return ret;
176 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)local)))
177 return ret;
178 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)gds)))
179 return ret;
180 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)pds)))
181 return ret;
182 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)drs)))
183 return ret;
184 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)bms)))
185 return ret;
186 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)data)))
187 return ret;
188 if ((ret = g2c_file_io_ulonglong(f, rw_flag, (unsigned long long *)msglen)))
189 return ret;
190 if ((ret = g2c_file_io_ubyte(f, rw_flag, version)))
191 return ret;
192 if ((ret = g2c_file_io_ubyte(f, rw_flag, discipline)))
193 return ret;
194 if ((ret = g2c_file_io_short(f, rw_flag, &fieldnum1)))
195 return ret;
196
197 /* When reading, translate the 1-based fieldnum1 into the 0-based
198 * fieldnum that C programmers will expect and love. */
199 if (!rw_flag)
200 *fieldnum = fieldnum1 - 1;
201
202 return G2C_NOERROR;
203}
204
237int
238g2c_start_index1_record(FILE *f, int rw_flag, unsigned int *b2_msg, unsigned int *b2_pds,
239 unsigned int *b2_gds, unsigned int *b2_bms, unsigned int *b2_bds,
240 unsigned int *msglen, unsigned char *version, unsigned char *pds_val,
241 unsigned char *gds_val, unsigned char *bms_val, unsigned char *bds_val,
242 unsigned char *pds_val2, unsigned char *pds_val3, unsigned char *gds_val2)
243{
244 size_t bytes_read;
245 int ret;
246
247 /* All pointers must be provided. */
248 if (!f || !b2_msg || !b2_pds || !b2_gds || !b2_bms || !b2_bds ||
249 !msglen || !version)
250 return G2C_EINVAL;
251
252 /* Read or write the values at the beginning of each index
253 * record. */
254 if ((ret = g2c_file_io_uint(f, rw_flag, b2_msg)))
255 return ret;
256 if ((ret = g2c_file_io_uint(f, rw_flag, b2_pds)))
257 return ret;
258 if ((ret = g2c_file_io_uint(f, rw_flag, b2_gds)))
259 return ret;
260 if ((ret = g2c_file_io_uint(f, rw_flag, b2_bms)))
261 return ret;
262 if ((ret = g2c_file_io_uint(f, rw_flag, b2_bds)))
263 return ret;
264 if ((ret = g2c_file_io_uint(f, rw_flag, msglen)))
265 return ret;
266 if ((ret = g2c_file_io_ubyte(f, rw_flag, version)))
267 return ret;
268
269 /* The index record contains some metadata copied directly from
270 * the file. These are arrays of unsigned char, of known
271 * length. For more detail see
272 * https://noaa-emc.github.io/NCEPLIBS-grib_util/grbindex/grbindex_8f.html. */
273 if ((bytes_read = fread(pds_val, 1, G2C_INDEX1_PDS_VAL_LEN, f)) != G2C_INDEX1_PDS_VAL_LEN)
274 return G2C_EFILE;
275 if ((bytes_read = fread(gds_val, 1, G2C_INDEX1_GDS_VAL_LEN, f)) != G2C_INDEX1_GDS_VAL_LEN)
276 return G2C_EFILE;
277 if ((bytes_read = fread(bms_val, 1, G2C_INDEX1_BMS_VAL_LEN, f)) != G2C_INDEX1_BMS_VAL_LEN)
278 return G2C_EFILE;
279 if ((bytes_read = fread(bds_val, 1, G2C_INDEX1_BDS_VAL_LEN, f)) != G2C_INDEX1_BDS_VAL_LEN)
280 return G2C_EFILE;
281
282 return G2C_NOERROR;
283}
284
316int
320{
321 G2C_SECTION_INFO_T *s3, *s4, *s5, *s6, *s7;
322
323 /* Check inputs. */
324 if (!msg || fieldnum < 0 || !sec3 || !sec4 || !sec5 || !sec6 || !sec7)
325 return G2C_EINVAL;
326
327 /* Find the product with matching fieldnum. */
328 for (s4 = msg->sec; s4; s4 = s4->next)
329 {
330 G2C_SECTION4_INFO_T *s4info = s4->sec_info;
331 if (s4->sec_num != 4)
332 continue;
333 if (s4info->field_num == fieldnum)
334 break;
335 }
336 if (!s4)
337 return G2C_ENOSECTION;
338
339 /* Find the section 3, grid definition section, which is
340 * associated with this product. */
341 for (s3 = s4->prev; s3; s3 = s3->prev)
342 if (s3->sec_num == 3)
343 break;
344 if (!s3)
345 return G2C_ENOSECTION;
346
347 /* Find the section 5, data representation section, which
348 * is associated with this product. */
349 for (s5 = s4->next; s5; s5 = s5->next)
350 if (s5->sec_num == 5)
351 break;
352 if (!s5)
353 return G2C_ENOSECTION;
354
355 /* Find the section 6, the bit map section. There may not be
356 * one. */
357 for (s6 = s5->next; s6; s6 = s6->next)
358 {
359 if (s6->sec_num == 6)
360 break;
361
362 /* If we hit section 7, there's no bitmap. */
363 if (s6->sec_num == 7)
364 {
365 s6 = NULL;
366 break;
367 }
368 }
369
370 /* Find the section 7, data section, which is associated with this
371 * product. */
372 for (s7 = s5->next; s7; s7 = s7->next)
373 if (s7->sec_num == 7)
374 break;
375 if (!s7)
376 return G2C_ENOSECTION;
377
378 /* Return results to caller. */
379 *sec3 = s3;
380 *sec4 = s4;
381 *sec5 = s5;
382 *sec6 = s6;
383 *sec7 = s7;
384
385 return G2C_NOERROR;
386}
387
430int
431g2c_write_index(int g2cid, int mode, const char *index_file)
432{
433 FILE *f;
434 char h1[G2C_INDEX_HEADER_LEN * 2 + 1]; /* need extra space to silence GNU warnings */
435 char h2[G2C_INDEX_HEADER_LEN + 10];
436 time_t t = time(NULL);
437 struct tm tm = *localtime(&t);
438 size_t items_written;
439 char my_path[G2C_INDEX_BASENAME_LEN + 1];
441 int total_index_size = 0; /* Does not include size of header records. */
442 int index_version = 1; /* 1 for legacy, 2 if indexed file may be > 2 GB. */
443 int reclen;
444 int ret = G2C_NOERROR;
445
446 /* Is this an open GRIB2 file? */
447 if (g2cid < 0 || g2cid > G2C_MAX_FILES)
448 return G2C_EBADID;
449 if (!index_file)
450 return G2C_EINVAL;
451
452 LOG((2, "g2c_write_index g2cid %d mode %d index_file %s", g2cid, mode,
453 index_file));
454
455 /* If NOCLOBBER, check if file exists. */
456 if (mode & G2C_NOCLOBBER)
457 {
458 FILE *f;
459 if ((f = fopen(index_file, "r")))
460 {
461 fclose(f);
462 return G2C_EFILE;
463 }
464 }
465
466 /* If LARGE_INDEX_FILE, set index version. */
467 if (mode & G2C_LARGE_FILE_INDEX)
468 index_version = 2;
469
470 /* Create the index file. */
471 if (!(f = fopen(index_file, "wb+")))
472 return G2C_EFILE;
473
474 /* If using threading, lock the mutex. */
475 MUTEX_LOCK(m);
476
477 if (g2c_file[g2cid].g2cid != g2cid)
478 ret = G2C_EBADID;
479
480 if (!ret)
481 {
482 /* Create header 1. */
483 snprintf(h1, G2C_INDEX_HEADER_LEN + 1,
484 "!GFHDR! 1 1 162 %4.4u-%2.2u-%2.2u %2.2u:%2.2u:%2.2u %s hfe08 grb2index\n",
485 (tm.tm_year + 1900), (tm.tm_mon + 1), tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
486 "GB2IX1");
487
488 /* Write header 1. */
489 if ((items_written = fwrite(h1, G2C_INDEX_HEADER_LEN, 1, f)) != 1)
490 ret = G2C_EFILE;
491 }
492
493 /* Find the total length of the index we are generating. */
494 if (!ret)
495 {
496 for (msg = g2c_file[g2cid].msg; msg; msg = msg->next)
497 {
498 short fieldnum;
499
500 /* Find information for each field in the message. */
501 for (fieldnum = 0; fieldnum < msg->num_fields; fieldnum++)
502 {
503 G2C_SECTION_INFO_T *sec3, *sec4, *sec5, *sec6, *sec7;
504
505 if ((ret = g2c_get_prod_sections(msg, fieldnum, &sec3, &sec4, &sec5, &sec6, &sec7)))
506 break;
507
508 /* What will be the length of this index record? */
509 reclen = (index_version == 1 ? G2C_INDEX_FIXED_LEN : G2C_INDEX_FIXED_LEN_2) +
510 msg->sec1_len + sec3->sec_len + sec4->sec_len + sec5->sec_len + G2C_INDEX_BITMAP_BYTES;
511 total_index_size += reclen;
512 LOG((4, "fieldnum %d reclen %d total_index_size %d", fieldnum, reclen, total_index_size));
513 } /* next product */
514
515 /* If there was a problem, give up. */
516 if (ret)
517 break;
518 } /* next message */
519 }
520
521 /* Create header 2. */
522 if (!ret)
523 {
524 strncpy(my_path, basename(g2c_file[g2cid].path), G2C_INDEX_BASENAME_LEN);
525 sprintf(h2, "IX%dFORM: 162 %6d %6ld %s \n", index_version, total_index_size,
526 g2c_file[g2cid].num_messages, my_path);
527 LOG((5, "header 2: %s", h2));
528
529 /* Write header 2. */
530 if ((items_written = fwrite(h2, G2C_INDEX_HEADER_LEN, 1, f)) != 1)
531 ret = G2C_EFILE;
532 }
533
534 /* Write a record of index file for each message in the file. */
535 if (!ret)
536 {
537 for (msg = g2c_file[g2cid].msg; msg; msg = msg->next)
538 {
539 short fieldnum;
540
541 /* Find information for each field in the message. */
542 for (fieldnum = 0; fieldnum < msg->num_fields; fieldnum++)
543 {
544 G2C_SECTION_INFO_T *sec3, *sec4, *sec5, *sec6, *sec7;
545 int bs3, bs4, bs5, bs6, bs7; /* bytes to each section, as ints. */
546 size_t bs3_8, bs4_8, bs5_8, bs6_8, bs7_8; /* bytes to each section, as size_t. */
547 unsigned char sec_num;
548 int ret;
549
550 if ((ret = g2c_get_prod_sections(msg, fieldnum, &sec3, &sec4, &sec5, &sec6, &sec7)))
551 return ret;
552 bs3 = (int)sec3->bytes_to_sec;
553 bs4 = (int)sec4->bytes_to_sec;
554 bs5 = (int)sec5->bytes_to_sec;
555 bs6 = (int)sec6->bytes_to_sec;
556 bs7 = (int)sec7->bytes_to_sec;
557
558 bs3_8 = sec3->bytes_to_sec;
559 bs4_8 = sec4->bytes_to_sec;
560 bs5_8 = sec5->bytes_to_sec;
561 bs6_8 = sec6->bytes_to_sec;
562 bs7_8 = sec7->bytes_to_sec;
563
564 /* What will be the length of this index record? */
565 reclen = (index_version == 1 ? G2C_INDEX_FIXED_LEN : G2C_INDEX_FIXED_LEN_2) + msg->sec1_len + sec3->sec_len + sec4->sec_len + sec5->sec_len + G2C_INDEX_BITMAP_BYTES;
566 LOG((4, "fieldnum %d reclen %d", fieldnum, reclen));
567
568 /* Write the beginning of the index record. */
569 if (index_version == 2)
570 {
571 if ((ret = g2c_start_index_record_lf(f, G2C_FILE_WRITE, &reclen, &msg->bytes_to_msg, &msg->bytes_to_local,
572 &bs3_8, &bs4_8, &bs5_8, &bs6_8, &bs7_8, &msg->bytes_in_msg, &msg->master_version,
573 &msg->discipline, &fieldnum)))
574 break;
575 }
576 else
577 {
578 int bytes_to_msg = (int)msg->bytes_to_msg;
579 int b2l;
580
581 b2l = (int)msg->bytes_to_local;
582 if ((ret = g2c_start_index_record(f, G2C_FILE_WRITE, &reclen, &bytes_to_msg, &b2l,
583 &bs3, &bs4, &bs5, &bs6, &bs7, &msg->bytes_in_msg, &msg->master_version,
584 &msg->discipline, &fieldnum)))
585 break;
586 }
587
588 /* Write the section 1, identification section. */
589 if ((ret = g2c_rw_section1_metadata(f, G2C_FILE_WRITE, msg)))
590 break;
591
592 /* Write the section 3, grid definition section. */
593 sec_num = 3;
594 if ((ret = g2c_file_io_uint(f, G2C_FILE_WRITE, &sec3->sec_len)))
595 return ret;
596 if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sec_num)))
597 return ret;
598 if ((ret = g2c_rw_section3_metadata(f, G2C_FILE_WRITE, sec3)))
599 break;
600
601 /* Write the section 4, product definition section. */
602 sec_num = 4;
603 if ((ret = g2c_file_io_uint(f, G2C_FILE_WRITE, &sec4->sec_len)))
604 return ret;
605 if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sec_num)))
606 return ret;
607 if ((ret = g2c_rw_section4_metadata(f, G2C_FILE_WRITE, sec4)))
608 break;
609
610 /* Write the section 5, data representation section. */
611 sec_num = 5;
612 if ((ret = g2c_file_io_uint(f, G2C_FILE_WRITE, &sec5->sec_len)))
613 return ret;
614 if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sec_num)))
615 return ret;
616 if ((ret = g2c_rw_section5_metadata(f, G2C_FILE_WRITE, sec5)))
617 break;
618
619 /* Write the first 6 bytes of the bitmap section, if there
620 * is one. */
621 if (!ret && sec6)
622 {
623 unsigned char sample[G2C_INDEX_BITMAP_BYTES];
624 int b;
625
626 /* Read the first 6 bytes of the bitmap section. */
627 if (fseek(msg->file->f, msg->bytes_to_msg + sec6->bytes_to_sec, SEEK_SET))
628 {
629 ret = G2C_EFILE;
630 break;
631 }
632 if ((fread(sample, ONE_BYTE, G2C_INDEX_BITMAP_BYTES, msg->file->f)) != G2C_INDEX_BITMAP_BYTES)
633 {
634 ret = G2C_EFILE;
635 break;
636 }
637
638 /* Now write these bytes to the end of the index record. */
639 for (b = 0; b < G2C_INDEX_BITMAP_BYTES; b++)
640 if ((ret = g2c_file_io_ubyte(f, G2C_FILE_WRITE, &sample[b])))
641 return ret;
642 }
643 } /* next product */
644
645 /* If there was a problem, give up. */
646 if (ret)
647 break;
648 } /* next message */
649 }
650
651 /* If using threading, unlock the mutex. */
652 MUTEX_UNLOCK(m);
653
654 /* Close the index file. */
655 if (!ret)
656 if (fclose(f))
657 return G2C_EFILE;
658
659 return ret;
660}
661
683static int
684read_hdr_rec1(FILE *f, int *ip, int *jp, int *kp, char *date_str, char *time_str)
685{
686 size_t bytes_read;
687 char line[G2C_INDEX_HEADER_LEN + 1];
688 char str1[G2C_INDEX_STR1_LEN + 1];
689 char my_date_str[G2C_INDEX_DATE_STR_LEN + 1];
690 char my_time_str[G2C_INDEX_TIME_STR_LEN + 1];
691 int i, j, k;
692
693 /* Read the first line of header. */
694 if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
695 return G2C_EFILE;
696 line[G2C_INDEX_HEADER_LEN] = 0;
697
698 /* Scan the line. */
699 {
700 char long_date_str[G2C_INDEX_HEADER_LEN + 1], long_time_str[G2C_INDEX_HEADER_LEN + 1];
701 char long_str1[G2C_INDEX_HEADER_LEN + 1];
702
703 sscanf(line, "%s %d %d %d %s %s GB2IX1", long_str1, &i, &j, &k, long_date_str, long_time_str);
704 memcpy(str1, long_str1, G2C_INDEX_STR1_LEN);
705 date_str[G2C_INDEX_STR1_LEN] = 0;
706 memcpy(date_str, long_date_str, G2C_INDEX_DATE_STR_LEN);
707 date_str[G2C_INDEX_DATE_STR_LEN] = 0;
708 memcpy(time_str, long_time_str, G2C_INDEX_TIME_STR_LEN);
709 time_str[G2C_INDEX_TIME_STR_LEN] = 0;
710 }
711 LOG((4, "str1 %s i %d j %d k %d date_str %s time_str %s", str1, i, j, k, date_str,
712 time_str));
713
714 /* Return info to caller where desired. */
715 if (ip)
716 *ip = i;
717 if (jp)
718 *jp = j;
719 if (kp)
720 *kp = k;
721 if (date_str)
722 strncpy(date_str, my_date_str, G2C_INDEX_DATE_STR_LEN + 1);
723 if (time_str)
724 strncpy(time_str, my_time_str, G2C_INDEX_TIME_STR_LEN + 1);
725
726 return G2C_NOERROR;
727}
728
752static int
753read_hdr_rec2(FILE *f, int *skipp, int *total_lenp, int *num_recp,
754 char *basename, int *index_version)
755{
756 size_t bytes_read;
757 char line[G2C_INDEX_HEADER_LEN + 1];
758 int skip;
759 int total_len, num_rec;
760 char my_basename[G2C_INDEX_BASENAME_LEN + 1];
761
762 /* Read the second line of header. */
763 if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
764 return G2C_EFILE;
765 line[G2C_INDEX_HEADER_LEN] = 0;
766 /* Scan the line. Hard! */
767 {
768 char long_basename[G2C_INDEX_HEADER_LEN + 1];
769 sscanf(line, "IX%dFORM: %d %d %d %s", index_version, &skip, &total_len,
770 &num_rec, long_basename);
771 memcpy(my_basename, long_basename, G2C_INDEX_BASENAME_LEN);
772 my_basename[G2C_INDEX_BASENAME_LEN] = 0;
773 }
774
775 /* Return info to caller where desired. */
776 if (skipp)
777 *skipp = skip;
778 if (total_lenp)
779 *total_lenp = total_len;
780 if (num_recp)
781 *num_recp = num_rec;
782 if (basename)
783 strncpy(basename, my_basename, G2C_INDEX_BASENAME_LEN + 1);
784
785 return G2C_NOERROR;
786}
787
799int
800g2c_open_index1(const char *index_file)
801{
802 FILE *f;
803 int i, j, k;
804 char date_str[G2C_INDEX_DATE_STR_LEN + 1];
805 char time_str[G2C_INDEX_TIME_STR_LEN + 1];
806 int skip, total_len, num_rec;
807 char basename[G2C_INDEX_BASENAME_LEN + 1];
808 size_t file_pos = G2C_INDEX_HEADER_LEN * 2;
809 unsigned char pds_val[G2C_INDEX1_PDS_VAL_LEN];
810 unsigned char gds_val[G2C_INDEX1_GDS_VAL_LEN];
811 unsigned char bms_val[G2C_INDEX1_BMS_VAL_LEN];
812 unsigned char bds_val[G2C_INDEX1_BDS_VAL_LEN];
813 int index_version;
814 int rec;
815 int ret = G2C_NOERROR;
816
817 /* Check inputs. */
818 if (!index_file)
819 return G2C_EINVAL;
820
821 LOG((2, "g2c_open_index1 index_file %s", index_file));
822
823 /* If using threading, lock the mutex. */
824 MUTEX_LOCK(m);
825
826 /* Open the index file. */
827 if (!(f = fopen(index_file, "rb")))
828 return G2C_EFILE;
829
830 /* Read header record apparently named after Steve Lord. */
831 if ((ret = read_hdr_rec1(f, &i, &j, &k, date_str, time_str)))
832 return ret;
833 LOG((4, "i %d j %d k %d date_str %s time_str %s", i, j, k, date_str, time_str));
834
835 /* Read second header record. */
836 if ((ret = read_hdr_rec2(f, &skip, &total_len, &num_rec, basename, &index_version)))
837 return ret;
838 LOG((4, "skip %d total_len %d num_rec %d basename %s", skip, total_len, num_rec, basename));
839
840 /* Read each index record. These is one record for each message in
841 the original GRIB1 file. */
842 for (rec = 0; rec < num_rec; rec++)
843 {
844 unsigned int b2_msg, b2_gds, b2_pds, b2_bms, b2_bds, msglen;
845 unsigned char version;
846
847 /* Move to beginning of index record. */
848 if (fseek(f, file_pos, SEEK_SET))
849 {
850 ret = G2C_EFILE;
851 break;
852 }
853
854 /* Read the index1 record. */
855 LOG((4, "reading index1 record at file position %ld", ftell(f)));
856 if ((ret = g2c_start_index1_record(f, G2C_FILE_READ, &b2_msg, &b2_pds, &b2_gds,
857 &b2_bms, &b2_bds, &msglen, &version, pds_val,
858 gds_val, bms_val, bds_val, NULL, NULL, NULL)))
859 break;
860
861 LOG((4, "b2_msg %d b2_pds %d b2_gds %d b2_bms %d b2_bds %d msglen %d version %d",
862 b2_msg, b2_gds, b2_pds, b2_bms, b2_bds, msglen, version));
863 printf("b2_msg %d b2_pds %d b2_gds %d b2_bms %d b2_bds %d msglen %d version %d\n",
864 b2_msg, b2_gds, b2_pds, b2_bms, b2_bds, msglen, version);
865
866 /* Move the file position to the start of the next index record. */
867 file_pos += total_len;
868 } /* next rec */
869
870 /* If using threading, unlock the mutex. */
871 MUTEX_UNLOCK(m);
872
873 /* Close the index file. */
874 if (!ret)
875 fclose(f);
876
877 return ret;
878}
879
901int
902g2c_open_index(const char *data_file, const char *index_file, int mode,
903 int *g2cid)
904{
905 FILE *f;
906 size_t bytes_read;
907 int ret = G2C_NOERROR;
908
909 /* Check inputs. */
910 if (!index_file || !data_file || !g2cid)
911 return G2C_EINVAL;
912 if (strlen(data_file) > G2C_MAX_NAME)
913 return G2C_ENAMETOOLONG;
914
915 LOG((2, "g2c_open_index index_file %s", index_file));
916
917 /* Open the index file. */
918 if (!(f = fopen(index_file, "rb")))
919 return G2C_EFILE;
920
921 /* If using threading, lock the mutex. */
922 MUTEX_LOCK(m);
923
924 /* Remember file metadata. */
925 ret = g2c_add_file(data_file, mode, g2cid);
926
927 /* Read the header. */
928 if (!ret)
929 {
930 char line[G2C_INDEX_HEADER_LEN + 1];
931 char str1[G2C_INDEX_STR1_LEN + 1], date_str[G2C_INDEX_DATE_STR_LEN + 1], time_str[G2C_INDEX_TIME_STR_LEN + 1];
932 int i, j, k;
933 int skip, total_len, num_rec;
934 char basename[G2C_INDEX_BASENAME_LEN + 1];
935 size_t file_pos = G2C_INDEX_HEADER_LEN * 2;
936 int index_version;
937 int rec;
938
939 /* Read the first line of header. */
940 if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
941 return G2C_EFILE;
942 line[G2C_INDEX_HEADER_LEN] = 0;
943 /* Scan the line. */
944 {
945 char long_date_str[G2C_INDEX_HEADER_LEN + 1], long_time_str[G2C_INDEX_HEADER_LEN + 1];
946 char long_str1[G2C_INDEX_HEADER_LEN + 1];
947
948 sscanf(line, "%s %d %d %d %s %s GB2IX1", long_str1, &i, &j, &k, long_date_str, long_time_str);
949 memcpy(str1, long_str1, G2C_INDEX_STR1_LEN);
950 date_str[G2C_INDEX_STR1_LEN] = 0;
951 memcpy(date_str, long_date_str, G2C_INDEX_DATE_STR_LEN);
952 date_str[G2C_INDEX_DATE_STR_LEN] = 0;
953 memcpy(time_str, long_time_str, G2C_INDEX_TIME_STR_LEN);
954 time_str[G2C_INDEX_TIME_STR_LEN] = 0;
955 }
956 LOG((1, "str1 %s i %d j %d k %d date_str %s time_str %s", str1, i, j, k, date_str,
957 time_str));
958
959 /* Read the second line of header. */
960 if ((bytes_read = fread(line, 1, G2C_INDEX_HEADER_LEN, f)) != G2C_INDEX_HEADER_LEN)
961 return G2C_EFILE;
962 line[G2C_INDEX_HEADER_LEN] = 0;
963 /* Scan the line. Hard! */
964 {
965 char long_basename[G2C_INDEX_HEADER_LEN + 1];
966 sscanf(line, "IX%dFORM: %d %d %d %s", &index_version, &skip, &total_len,
967 &num_rec, long_basename);
968 memcpy(basename, long_basename, G2C_INDEX_BASENAME_LEN);
969 basename[G2C_INDEX_BASENAME_LEN] = 0;
970 }
971 LOG((1, "skip %d total_len %d num_rec %d basename %s", skip, total_len, num_rec, basename));
972
973 /* Read each index record. */
974 for (rec = 0; rec < num_rec; rec++)
975 {
976 int reclen, msgint, local, gds, pds, drs, bms, data;
977 size_t local8, gds8, pds8, drs8, bms8, data8;
978 size_t msglen, msg;
979 unsigned char version, discipline;
980 short fieldnum;
981
982 /* Move to beginning of index record. */
983 if (fseek(f, file_pos, SEEK_SET))
984 {
985 ret = G2C_EFILE;
986 break;
987 }
988
989 /* Read the index record. */
990 LOG((4, "reading index record at file position %ld, index_version %d",
991 ftell(f), index_version));
992 if (index_version == 1)
993 {
994 if ((ret = g2c_start_index_record(f, G2C_FILE_READ, &reclen, &msgint, &local, &gds, &pds,
995 &drs, &bms, &data, &msglen, &version, &discipline, &fieldnum)))
996 break;
997 msg = msgint;
998 local8 = local;
999 gds8 = gds;
1000 pds8 = pds;
1001 drs8 = drs;
1002 bms8 = bms;
1003 data8 = data;
1004 }
1005 else
1006 {
1007 if ((ret = g2c_start_index_record_lf(f, G2C_FILE_READ, &reclen, &msg, &local8, &gds8, &pds8,
1008 &drs8, &bms8, &data8, &msglen, &version, &discipline, &fieldnum)))
1009 break;
1010 }
1011
1012 LOG((1, "reclen %d msg %ld local8 %d gds8 %d pds8 %d drs8 %d bms8 %d data8 %d "
1013 "msglen %ld version %d discipline %d fieldnum %d",
1014 reclen, msg, local8, gds8, pds8, drs8, bms8, data8, msglen,
1015 version, discipline, fieldnum));
1016
1017 /* Read the metadata for sections 3, 4, and 5 from
1018 * the index record. */
1019 {
1020 unsigned int sec_len;
1021 unsigned char sec_num;
1022 int s;
1023 G2C_MESSAGE_INFO_T *msgp;
1024 int sec_id = 0;
1025 int sec8_found = 0;
1026
1027 /* Allocate storage for message. */
1028 if ((ret = add_msg(&g2c_file[*g2cid], rec, msg, msglen, 0, &msgp)))
1029 break;
1030 msgp->discipline = discipline;
1031 msgp->bytes_to_local = local8;
1032 msgp->bytes_to_bms = bms8;
1033 msgp->bytes_to_data = data8;
1034 msgp->master_version = version;
1035
1036 /* Read section 1. */
1037 if ((ret = g2c_rw_section1_metadata(f, G2C_FILE_READ, msgp)))
1038 break;
1039 if ((ret = g2c_log_section1(msgp)))
1040 break;
1041
1042 LOG((4, "reading section info at file position %ld", ftell(f)));
1043
1044 /* Add a new section to our list of sections. */
1045 for (s = 3; s < 8 && !sec8_found; s++)
1046 {
1047 size_t bytes_to_sec = gds8; /* Correct value for section 3. */
1048
1049 /* For sections 3, 4, 5, read the section length
1050 * and number from the index record. */
1051 if (s < 7)
1052 {
1053 if ((ret = g2c_file_io_uint(f, G2C_FILE_READ, &sec_len)))
1054 return ret;
1055 if ((ret = g2c_file_io_ubyte(f, G2C_FILE_READ, &sec_num)))
1056 return ret;
1057 }
1058 else
1059 {
1060 /* For section 7, the length of the section is
1061 * not in the index file, but is needed for
1062 * data read operations. So we will use the
1063 * open data file and get the length of this
1064 * section. */
1065 LOG((4, "seeking to section 7 in data file, position msgp->bytes_to_msg %ld data %ld",
1066 msgp->bytes_to_msg, data8));
1067 if (fseek(g2c_file[*g2cid].f, msgp->bytes_to_msg + data8, SEEK_SET))
1068 {
1069 ret = G2C_EFILE;
1070 break;
1071 }
1072 if ((ret = g2c_file_io_uint(g2c_file[*g2cid].f, G2C_FILE_READ, &sec_len)))
1073 return ret;
1074 if ((ret = g2c_file_io_ubyte(g2c_file[*g2cid].f, G2C_FILE_READ, &sec_num)))
1075 return ret;
1076 LOG((4, "read section 7 info from data file. sec_len %d sec_num %d",
1077 sec_len, sec_num));
1078 }
1079
1080 /* Select the value from the index record which is
1081 * the number of bytes to section s. */
1082 if (sec_num == 4)
1083 bytes_to_sec = pds8;
1084 else if (sec_num == 5)
1085 bytes_to_sec = drs8;
1086 else if (sec_num == 6)
1087 bytes_to_sec = bms8;
1088 else if (sec_num == 7)
1089 bytes_to_sec = data8;
1090 else if (sec_num == 8)
1091 sec8_found++;
1092
1093 /* Check some stuff. */
1094 if (s < 6 && sec_num != s)
1095 {
1096 ret = G2C_EBADSECTION;
1097 break;
1098 }
1099 if (sec_num == 4)
1100 if (fieldnum < 0) /* to silence warning */
1101 {
1102 ret = G2C_EBADSECTION;
1103 break;
1104 }
1105
1106 /* Read the section info from the index file,
1107 * using the same functions that read it from the
1108 * GRIB2 data file. */
1109 LOG((4, "about to add_section sec_id %d sec_len %d bytes_to_sec %ld sec_num %d",
1110 sec_id, sec_len, bytes_to_sec, sec_num));
1111 if ((ret = add_section(f, msgp, sec_id++, sec_len, bytes_to_sec, sec_num)))
1112 break;
1113 } /* next section */
1114
1115 /* If anything went wrong, give up. */
1116 if (ret)
1117 break;
1118 }
1119
1120 /* Move the file position to the start of the next index record. */
1121 file_pos += reclen;
1122 } /* next rec */
1123 }
1124
1125 /* If using threading, unlock the mutex. */
1126 MUTEX_UNLOCK(m);
1127
1128 /* Close the index file. */
1129 if (!ret)
1130 fclose(f);
1131
1132 return ret;
1133}
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:1017
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:794
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:663
int g2c_rw_section1_metadata(FILE *f, int rw_flag, G2C_MESSAGE_INFO_T *msg)
Read Section 1.
Definition g2cfile.c:874
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:1143
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:478
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:574
#define G2C_INDEX_FIXED_LEN_2
Length of beginning of index record for large files.
Definition g2cindex.c:29
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:902
int g2c_start_index_record_lf(FILE *f, int rw_flag, int *reclen, size_t *msg, size_t *local, size_t *gds, size_t *pds, size_t *drs, size_t *bms, size_t *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:151
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:238
int g2c_open_index1(const char *index_file)
Open a GRIB1 index file and read the contents.
Definition g2cindex.c:800
static int read_hdr_rec2(FILE *f, int *skipp, int *total_lenp, int *num_recp, char *basename, int *index_version)
Read the second header record of an index file.
Definition g2cindex.c:753
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:684
#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:70
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:431
#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:32
#define G2C_INDEX_STR1_LEN
Length of str1 string in index record.
Definition g2cindex.c:38
#define G2C_INDEX_TIME_STR_LEN
Length of time string in index record.
Definition g2cindex.c:35
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:317
#define G2C_INDEX_BASENAME_LEN
Length of the basename in header record 2.
Definition g2cindex.c:20
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:273
#define G2C_NOCLOBBER
Don't destroy existing file.
Definition grib2.h:278
#define G2C_ENAMETOOLONG
Name too long.
Definition grib2.h:480
#define G2C_ENOSECTION
Cannot find section.
Definition grib2.h:491
#define G2C_EFILE
File I/O error.
Definition grib2.h:482
#define G2C_LARGE_FILE_INDEX
Create a large file index.
Definition grib2.h:279
#define G2C_MAX_NAME
Maximum length of a name.
Definition grib2.h:274
#define G2C_EINVAL
Invalid input.
Definition grib2.h:481
#define G2C_EBADSECTION
Invalid section number.
Definition grib2.h:494
#define G2C_EBADID
Bad ID.
Definition grib2.h:483
#define G2C_NOERROR
No error.
Definition grib2.h:476
Header file with internal function prototypes NCEPLIBS-g2c library.
#define G2C_FILE_READ
Read.
Definition grib2_int.h:131
size_t bytes_to_local
Number of bytes in the message before the (first) local section.
Definition grib2_int.h:144
#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:132
struct g2c_section_info * next
Pointer to next in list.
Definition grib2_int.h:178
struct g2c_section_info * sec
List of section metadata.
Definition grib2_int.h:164
unsigned char master_version
GRIB master tables version number.
Definition grib2_int.h:153
#define MUTEX_UNLOCK(m)
Pthreads not enabled, so do nothing.
Definition grib2_int.h:119
#define G2C_INDEX1_GDS_VAL_LEN
Length of the grid definition section (gds) in index file.
Definition grib2_int.h:67
#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:140
size_t bytes_in_msg
Number of bytes in this message.
Definition grib2_int.h:139
struct g2c_section_info * prev
Pointer to previous in list.
Definition grib2_int.h:179
int num_fields
Number of fields in the message.
Definition grib2_int.h:142
size_t bytes_to_bms
Number of bytes in the message to the bitmap section.
Definition grib2_int.h:145
unsigned char sec_num
Section number.
Definition grib2_int.h:175
#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:177
unsigned int sec_len
Length of the section (in bytes).
Definition grib2_int.h:173
size_t bytes_to_sec
Number of bytes from start of message to this section.
Definition grib2_int.h:174
#define ONE_BYTE
One byte.
Definition grib2_int.h:50
#define LOG(e)
Ignore logging to stdout.
Definition grib2_int.h:428
FILE * f
FILE pointer to open file.
Definition grib2_int.h:241
size_t bytes_to_data
Number of bytes in the message to the (first) data section.
Definition grib2_int.h:146
size_t bytes_to_msg
Number of bytes to skip in the file, to get to this message.
Definition grib2_int.h:138
#define MUTEX_LOCK(m)
Pthreads not enabled, so do nothing.
Definition grib2_int.h:116
#define EXTERN_MUTEX(m)
Pthreads not enabled, so do nothing.
Definition grib2_int.h:113
int sec1_len
Length of section 1.
Definition grib2_int.h:150
struct g2c_message_info * next
Pointer to next in list.
Definition grib2_int.h:166
struct g2c_file_info * file
Pointer to containing file.
Definition grib2_int.h:165
This is the information about each open file.
Definition grib2_int.h:238
This is the information about each message.
Definition grib2_int.h:136
Information about Section 4 PRODUCT DEFINITION SECTION.
Definition grib2_int.h:209
Information about a section 3 through 7 in a GRIB2 message.
Definition grib2_int.h:171