diff --git a/src/eccodes.h b/src/eccodes.h index 7a535808e..f0b110b86 100644 --- a/src/eccodes.h +++ b/src/eccodes.h @@ -1458,7 +1458,10 @@ int codes_bufr_header_get_string(codes_bufr_header* bh, const char* key, char* v * strict_mode = If 1 means fail if any message is invalid. * returns 0 if OK, integer value on error. */ -int codes_extract_offsets_malloc(codes_context* c, const char* filename, ProductKind product, off_t** offsets, int* num_messages, int strict_mode); +int codes_extract_offsets_malloc(codes_context* c, const char* filename, ProductKind product, + off_t** offsets, int* num_messages, int strict_mode); +int codes_extract_offsets_sizes_malloc(codes_context* c, const char* filename, ProductKind product, + off_t** offsets, size_t** sizes, int* num_messages, int strict_mode); /* --------------------------------------- */ #ifdef __cplusplus diff --git a/src/eccodes_prototypes.h b/src/eccodes_prototypes.h index 9041e2bc2..307f29330 100644 --- a/src/eccodes_prototypes.h +++ b/src/eccodes_prototypes.h @@ -1025,7 +1025,9 @@ int grib_read_any_from_memory_alloc(grib_context* ctx, unsigned char** data, siz int grib_read_any_from_memory(grib_context* ctx, unsigned char** data, size_t* data_length, void* buffer, size_t* len); int grib_count_in_file(grib_context* c, FILE* f, int* n); int grib_count_in_filename(grib_context* c, const char* filename, int* n); -int codes_extract_offsets_malloc(grib_context* c, const char* filename, ProductKind product, off_t** offsets, int* length, int strict_mode); +int codes_extract_offsets_malloc(grib_context* c, const char* filename, ProductKind product, off_t** offsets, int* num_messages, int strict_mode); +int codes_extract_offsets_sizes_malloc(grib_context* c, const char* filename, ProductKind product, + off_t** offsets, size_t** sizes, int* num_messages, int strict_mode); /* grib_trie.cc*/ diff --git a/src/grib_io.cc b/src/grib_io.cc index 6f878c8af..64c197a29 100644 --- a/src/grib_io.cc +++ b/src/grib_io.cc @@ -1815,7 +1815,11 @@ static int count_product_in_file(grib_context* c, FILE* f, ProductKind product, return err == GRIB_END_OF_FILE ? 0 : err; } -int codes_extract_offsets_malloc(grib_context* c, const char* filename, ProductKind product, off_t** offsets, int* length, int strict_mode) +static int codes_extract_offsets_malloc_internal( + grib_context* c, const char* filename, ProductKind product, + off_t** offsets, size_t** sizes, + int* number_of_elements, + int strict_mode) { int err = 0; size_t size = 0; @@ -1848,7 +1852,7 @@ int codes_extract_offsets_malloc(grib_context* c, const char* filename, ProductK fclose(f); return err; } - *length = num_messages; + *number_of_elements = num_messages; if (num_messages == 0) { grib_context_log(c, GRIB_LOG_ERROR, "%s: No messages in file", __func__); fclose(f); @@ -1859,6 +1863,13 @@ int codes_extract_offsets_malloc(grib_context* c, const char* filename, ProductK fclose(f); return GRIB_OUT_OF_MEMORY; } + if (sizes) { + *sizes = (size_t*)calloc(num_messages, sizeof(size_t)); + if (!*sizes) { + fclose(f); + return GRIB_OUT_OF_MEMORY; + } + } i = 0; while (err != GRIB_END_OF_FILE) { @@ -1868,6 +1879,9 @@ int codes_extract_offsets_malloc(grib_context* c, const char* filename, ProductK err = decoder(f, &size, &offset); if (!err) { (*offsets)[i] = offset; + if (sizes) { + (*sizes)[i] = size; + } } else { if (strict_mode && (err != GRIB_END_OF_FILE && err != GRIB_PREMATURE_END_OF_FILE)) { @@ -1881,3 +1895,20 @@ int codes_extract_offsets_malloc(grib_context* c, const char* filename, ProductK fclose(f); return err; } + +// The lagacy version only did the offsets +int codes_extract_offsets_malloc( + grib_context* c, const char* filename, ProductKind product, + off_t** offsets, int* number_of_elements, int strict_mode) +{ + // Call without doing the message sizes + return codes_extract_offsets_malloc_internal(c, filename, product, offsets, NULL, number_of_elements, strict_mode); +} + +// New function does both message offsets and sizes +int codes_extract_offsets_sizes_malloc( + grib_context* c, const char* filename, ProductKind product, + off_t** offsets, size_t** sizes, int* number_of_elements, int strict_mode) +{ + return codes_extract_offsets_malloc_internal(c, filename, product, offsets, sizes, number_of_elements, strict_mode); +} diff --git a/tests/extract_offsets.cc b/tests/extract_offsets.cc index 13d0ce378..ea5a02073 100644 --- a/tests/extract_offsets.cc +++ b/tests/extract_offsets.cc @@ -15,23 +15,42 @@ int main(int argc, char* argv[]) { - char *filename; + char *filename = NULL; + char *what = NULL; // offsets or sizes int err = 0; int num_messages = 0, i =0; off_t* offsets = NULL; + size_t* sizes = NULL; codes_context* c = codes_context_get_default(); const int strict_mode = 1; - /* Usage: prog file */ - assert(argc == 2); + /* Usage: prog mode file */ + assert(argc == 3); - filename = argv[1]; - err = codes_extract_offsets_malloc(c, filename, PRODUCT_ANY, &offsets, &num_messages, strict_mode); - if (err) return err; + what = argv[1]; + filename = argv[2]; - for (i = 0; i < num_messages; ++i) { - printf("%lu\n", (unsigned long)offsets[i]); + if (strcmp(what, "-o")==0) { + err = codes_extract_offsets_malloc(c, filename, PRODUCT_ANY, &offsets, &num_messages, strict_mode); + if (err) return err; + + for (i = 0; i < num_messages; ++i) { + printf("%lu\n", (unsigned long)offsets[i]); + } + free(offsets); } - free(offsets); + + if (strcmp(what, "-s")==0) { + // Version getting offsets as well as sizes of messages + err = codes_extract_offsets_sizes_malloc(c, filename, PRODUCT_ANY, &offsets, &sizes, &num_messages, strict_mode); + if (err) return err; + + for (i = 0; i < num_messages; ++i) { + printf("%zu\n", sizes[i]); + } + free(offsets); + free(sizes); + } + return 0; } diff --git a/tests/extract_offsets.sh b/tests/extract_offsets.sh index b36005cb9..60bb42708 100755 --- a/tests/extract_offsets.sh +++ b/tests/extract_offsets.sh @@ -19,15 +19,20 @@ tempLog="temp.${label}.log" echo "Multi-message BUFR..." # --------------------------- input=${data_dir}/bufr/aeolus_wmo_26.bufr -$EXEC ${test_dir}/extract_offsets $input > $temp1 +$EXEC ${test_dir}/extract_offsets -o $input > $temp1 ${tools_dir}/bufr_get -p offset:i $input > $temp2 diff $temp1 $temp2 +$EXEC ${test_dir}/extract_offsets -s $input > $temp1 +${tools_dir}/bufr_get -p totalLength $input > $temp2 +diff $temp1 $temp2 + + echo "Multi-message GRIBs..." # -------------------------- inputs="${data_dir}/mixed.grib ${data_dir}/test.grib1 ${data_dir}/v.grib2" for input in $inputs; do - $EXEC ${test_dir}/extract_offsets $input > $temp1 + $EXEC ${test_dir}/extract_offsets -o $input > $temp1 ${tools_dir}/grib_get -p offset:i $input > $temp2 diff $temp1 $temp2 done @@ -35,21 +40,21 @@ done echo "Test with invalid inputs..." # --------------------------------- set +e -$EXEC ${test_dir}/extract_offsets ${data_dir} > $tempLog 2>&1 +$EXEC ${test_dir}/extract_offsets -o ${data_dir} > $tempLog 2>&1 status=$? set -e [ $status -ne 0 ] grep -q "is a directory" $tempLog set +e -$EXEC ${test_dir}/extract_offsets ${data_dir}/bad.grib > $tempLog 2>&1 +$EXEC ${test_dir}/extract_offsets -o ${data_dir}/bad.grib > $tempLog 2>&1 status=$? set -e [ $status -ne 0 ] grep -q "Wrong message length" $tempLog set +e -$EXEC ${test_dir}/extract_offsets nonexistentfile > $tempLog 2>&1 +$EXEC ${test_dir}/extract_offsets -o nonexistentfile > $tempLog 2>&1 status=$? set -e [ $status -ne 0 ]