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