diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c92f8f..a503469 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ * fix one-byte overread into struct padding [bgilbert] * support single-frame DICOM images and allow BitsStored > 8 [tokyovigilante] +* fix error handling for string values over max length [arngaillard] +* add `-w` (show warnings) to dcm-dump and dcm-getframe ## 1.2.0, 09/04/2025 diff --git a/doc/source/usage.rst b/doc/source/usage.rst index 469b0af..0236c51 100644 --- a/doc/source/usage.rst +++ b/doc/source/usage.rst @@ -55,6 +55,11 @@ using a standard C type (e.g,. VR ``"US"`` has type ``uint16_t`` and VR ``"UI"`` has type ``char *``) and additional value constraints may be checked at runtime (e.g., the maximal capacity of a character string). +When reading DICOM files, a warning will be issued for character strings which +are too long, but they will still be passed unmodified to the caller. Readers +must not crash if strings are longer than the maximum value in the DICOM +specification. + The VR must be appropriate for the tag. Use :c:func:`dcm_vr_from_tag()` to find the set of allowed VRs for a tag. Use :c:func:`dcm_is_valid_vr_for_tag()` to check if a VR is allowed for a tag. diff --git a/src/dicom-data.c b/src/dicom-data.c index 38f536b..153e8d0 100644 --- a/src/dicom-data.c +++ b/src/dicom-data.c @@ -340,14 +340,12 @@ bool dcm_element_get_value_string(DcmError **error, static bool element_check_capacity(DcmError **error, DcmElement *element, uint32_t capacity) { - uint32_t i; - bool was_assigned = element->assigned; // we have to turn on "assigned" for this func so we can read out values element->assigned = true; - for (i = 0; i < element->vm; i++) { + for (uint32_t i = 0; i < element->vm; i++) { const char *value; if (!dcm_element_get_value_string(error, element, i, &value)) { element->assigned = was_assigned; @@ -402,9 +400,9 @@ static bool dcm_element_validate(DcmError **error, DcmElement *element) if (vr_class == DCM_VR_CLASS_STRING_MULTI || vr_class == DCM_VR_CLASS_STRING_SINGLE) { uint32_t capacity = dcm_dict_vr_capacity(element->vr); - if (!element_check_capacity(error, element, capacity)) { - return false; - } + + // this only checks and issues a warning, it does not set error + (void) element_check_capacity(error, element, capacity); } element->assigned = true; diff --git a/tools/dcm-dump.1.in b/tools/dcm-dump.1.in index 5653347..42c6953 100644 --- a/tools/dcm-dump.1.in +++ b/tools/dcm-dump.1.in @@ -4,13 +4,14 @@ dcm-dump \- print metadata content of DICOM PS3.10 file to standard output .SH SYNOPSIS -.BR "dcm-dump " [ -v "] +.BR "dcm-dump " [ -hViw "] .IR file .SH DESCRIPTION Print metadata content of DICOM PS3.10 file to standard output. .SH OPTIONS + .TP .B -h Display help message (usage summary) and exit. @@ -20,8 +21,12 @@ Display help message (usage summary) and exit. Display version and exit. .TP -.B -v -Increase logging verbosity to INFO. +.B -i +Show info messages. + +.TP +.B -w +Show warning messages. .SH EXIT STATUS .B dcm-dump diff --git a/tools/dcm-dump.c b/tools/dcm-dump.c index b8624ad..cd74f60 100644 --- a/tools/dcm-dump.c +++ b/tools/dcm-dump.c @@ -7,35 +7,39 @@ #include -static const char usage[] = "usage: dcm-dump [-v] [-V] [-h] FILE_PATH ..."; +static const char usage[] = "usage: dcm-dump [-hViw] FILE_PATH ..."; int main(int argc, char *argv[]) { - int i, c; - - while ((c = dcm_getopt(argc, argv, "h?Vv")) != -1) { + int c; + while ((c = dcm_getopt(argc, argv, "h?Vviw")) != -1) { switch (c) { case 'h': case '?': printf("%s\n", usage); return EXIT_SUCCESS; - case 'v': + case 'V': printf("%s\n", dcm_get_version()); return EXIT_SUCCESS; - case 'V': + case 'v': + case 'i': dcm_log_set_level(DCM_LOG_INFO); break; + case 'w': + dcm_log_set_level(DCM_LOG_WARNING); + break; + case '#': default: return EXIT_FAILURE; } } - for (i = dcm_optind; i < argc; i++) { + for (int i = dcm_optind; i < argc; i++) { DcmError *error = NULL; DcmFilehandle *filehandle = NULL; @@ -45,8 +49,8 @@ int main(int argc, char *argv[]) dcm_error_print(error); dcm_error_clear(&error); return EXIT_FAILURE; - } - + } + if (!dcm_filehandle_print(&error, filehandle)) { dcm_error_print(error); dcm_error_clear(&error); diff --git a/tools/dcm-getframe.1.in b/tools/dcm-getframe.1.in index af9f80f..c374236 100644 --- a/tools/dcm-getframe.1.in +++ b/tools/dcm-getframe.1.in @@ -4,7 +4,7 @@ dcm-getframe \- print a frame from a DICOM PS3.10 file to standard output .SH SYNOPSIS -.BR "dcm-getframe " [ -v "] +.BR "dcm-getframe " [ -hViw "] .IR file .IR frame-number @@ -12,10 +12,6 @@ dcm-getframe \- print a frame from a DICOM PS3.10 file to standard output Print a frame from a DICOM PS3.10 file to standard output. .SH OPTIONS -.TP -.B -o OUTPUT-FILENAME -Write frame to OUTPUT-FILENAME. By default, the frame will be written to -stdout. .TP .B -h @@ -26,8 +22,17 @@ Display help message (usage summary) and exit. Display version and exit. .TP -.B -v -Increase logging verbosity to INFO. +.B -o OUTPUT-FILENAME +Write frame to OUTPUT-FILENAME. By default, the frame will be written to +stdout. + +.TP +.B -i +Show info messages. + +.TP +.B -w +Show warning messages. .SH EXIT STATUS .B dcm-getframe diff --git a/tools/dcm-getframe.c b/tools/dcm-getframe.c index ce5b0b9..f1bdf12 100644 --- a/tools/dcm-getframe.c +++ b/tools/dcm-getframe.c @@ -11,7 +11,7 @@ static const char usage[] = "usage: " - "dcm-getframe [-v] [-V] [-h] [-o OUTPUT-FILE] FILE_PATH FRAME_NUMBER"; + "dcm-getframe [-hviw] [-o OUTPUT-FILE] FILE_PATH FRAME_NUMBER"; int main(int argc, char *argv[]) @@ -19,8 +19,7 @@ int main(int argc, char *argv[]) char *output_file = NULL; int c; - - while ((c = dcm_getopt(argc, argv, "h?Vvo:")) != -1) { + while ((c = dcm_getopt(argc, argv, "h?vViwo:")) != -1) { switch (c) { case 'h': case '?': @@ -32,9 +31,14 @@ int main(int argc, char *argv[]) return EXIT_SUCCESS; case 'V': + case 'i': dcm_log_set_level(DCM_LOG_INFO); break; + case 'w': + dcm_log_set_level(DCM_LOG_WARNING); + break; + case 'o': output_file = dcm_optarg; break;