Skip to content

Commit 68d2ea6

Browse files
committed
add extended offset table support
1 parent 2550955 commit 68d2ea6

File tree

2 files changed

+129
-61
lines changed

2 files changed

+129
-61
lines changed

src/dicom-file.c

Lines changed: 124 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ struct _DcmFilehandle {
8383
// push and pop these while we parse
8484
UT_array *dataset_stack;
8585
UT_array *sequence_stack;
86+
87+
// skip to tags during parse
88+
uint32_t *skip_to_tags;
89+
90+
// set if we see an ext offset table
91+
bool have_extended_offset_table;
8692
};
8793

8894

@@ -1003,6 +1009,8 @@ static bool read_frame_index(DcmError **error,
10031009
.stop = parse_frame_index_stop,
10041010
};
10051011

1012+
dcm_log_debug("Reading per frame functional group sequence.");
1013+
10061014
filehandle->frame_index = DCM_NEW_ARRAY(error,
10071015
filehandle->num_tiles,
10081016
uint32_t);
@@ -1029,10 +1037,10 @@ static bool read_frame_index(DcmError **error,
10291037
}
10301038

10311039

1032-
static bool parse_skip_to_index(void *client,
1033-
uint32_t tag,
1034-
DcmVR vr,
1035-
uint32_t length)
1040+
static bool parse_skip_to(void *client,
1041+
uint32_t tag,
1042+
DcmVR vr,
1043+
uint32_t length)
10361044
{
10371045
DcmFilehandle *filehandle = (DcmFilehandle *) client;
10381046

@@ -1041,21 +1049,25 @@ static bool parse_skip_to_index(void *client,
10411049

10421050
filehandle->last_tag = tag;
10431051

1044-
return tag == TAG_PER_FRAME_FUNCTIONAL_GROUP_SEQUENCE ||
1045-
tag == TAG_PIXEL_DATA ||
1046-
tag == TAG_FLOAT_PIXEL_DATA ||
1047-
tag == TAG_DOUBLE_PIXEL_DATA;
1052+
for (int i = 0; filehandle->skip_to_tags[i]; i++)
1053+
if (tag == filehandle->skip_to_tags[i])
1054+
return true;
1055+
1056+
return false;
1057+
10481058
}
10491059

10501060

1051-
static bool read_skip_to_index(DcmError **error,
1052-
DcmFilehandle *filehandle)
1061+
static bool read_skip_to(DcmError **error,
1062+
DcmFilehandle *filehandle,
1063+
uint32_t *skip_to_tags)
10531064

10541065
{
10551066
static DcmParse parse = {
1056-
.stop = parse_skip_to_index,
1067+
.stop = parse_skip_to,
10571068
};
10581069

1070+
filehandle->skip_to_tags = skip_to_tags;
10591071
if (!dcm_parse_dataset(error,
10601072
filehandle->io,
10611073
filehandle->implicit,
@@ -1068,10 +1080,36 @@ static bool read_skip_to_index(DcmError **error,
10681080
}
10691081

10701082

1071-
static bool parse_skip_to_pixel_data(void *client,
1072-
uint32_t tag,
1073-
DcmVR vr,
1074-
uint32_t length)
1083+
static bool parse_extended_offsets_element_create(DcmError **error,
1084+
void *client,
1085+
uint32_t tag,
1086+
DcmVR vr,
1087+
char *value,
1088+
uint32_t length)
1089+
{
1090+
USED(error);
1091+
USED(vr);
1092+
1093+
DcmFilehandle *filehandle = (DcmFilehandle *) client;
1094+
int64_t expected_size = filehandle->num_frames * sizeof(int64_t);
1095+
1096+
if (tag == TAG_EXTENDED_OFFSET_TABLE && length == expected_size) {
1097+
memcpy(filehandle->offset_table, value, length);
1098+
filehandle->have_extended_offset_table = true;
1099+
1100+
// the size of the pixeldata header, plus the size of the empty frame
1101+
// 0 (the BOT)
1102+
filehandle->first_frame_offset = 20;
1103+
}
1104+
1105+
return true;
1106+
}
1107+
1108+
1109+
static bool parse_extended_offsets_stop(void *client,
1110+
uint32_t tag,
1111+
DcmVR vr,
1112+
uint32_t length)
10751113
{
10761114
DcmFilehandle *filehandle = (DcmFilehandle *) client;
10771115

@@ -1080,18 +1118,17 @@ static bool parse_skip_to_pixel_data(void *client,
10801118

10811119
filehandle->last_tag = tag;
10821120

1083-
return tag == TAG_PIXEL_DATA ||
1084-
tag == TAG_FLOAT_PIXEL_DATA ||
1085-
tag == TAG_DOUBLE_PIXEL_DATA;
1121+
return tag != TAG_EXTENDED_OFFSET_TABLE;
10861122
}
10871123

10881124

1089-
static bool read_skip_to_pixel_data(DcmError **error,
1090-
DcmFilehandle *filehandle)
1091-
1125+
static bool
1126+
read_extended_offsets(DcmError **error,
1127+
DcmFilehandle *filehandle)
10921128
{
10931129
static DcmParse parse = {
1094-
.stop = parse_skip_to_pixel_data,
1130+
.element_create = parse_extended_offsets_element_create,
1131+
.stop = parse_extended_offsets_stop,
10951132
};
10961133

10971134
if (!dcm_parse_dataset(error,
@@ -1110,6 +1147,13 @@ bool dcm_filehandle_prepare_read_frame(DcmError **error,
11101147
DcmFilehandle *filehandle)
11111148
{
11121149
if (filehandle->offset_table == NULL) {
1150+
filehandle->offset_table = DCM_NEW_ARRAY(error,
1151+
filehandle->num_frames,
1152+
int64_t);
1153+
if (filehandle->offset_table == NULL) {
1154+
return false;
1155+
}
1156+
11131157
// move to the first of our stop tags
11141158
if (dcm_filehandle_get_metadata_subset(error, filehandle) == NULL) {
11151159
return false;
@@ -1122,24 +1166,49 @@ bool dcm_filehandle_prepare_read_frame(DcmError **error,
11221166
return false;
11231167
}
11241168

1125-
// we may have previously stopped for many reasons ... skip ahead to per
1126-
// frame functional group, or pixel data
1127-
if (!read_skip_to_index(error, filehandle)) {
1169+
// skip ahead to per frame functional group, if present, and read it
1170+
uint32_t skip_to_per_frame[] = {
1171+
TAG_PER_FRAME_FUNCTIONAL_GROUP_SEQUENCE,
1172+
TAG_EXTENDED_OFFSET_TABLE,
1173+
TAG_PIXEL_DATA,
1174+
TAG_FLOAT_PIXEL_DATA,
1175+
TAG_DOUBLE_PIXEL_DATA,
1176+
0
1177+
};
1178+
if (!read_skip_to(error, filehandle, skip_to_per_frame)) {
11281179
return false;
11291180
}
1130-
1131-
// if we're on per frame func, read that in
11321181
if (filehandle->last_tag == TAG_PER_FRAME_FUNCTIONAL_GROUP_SEQUENCE &&
11331182
!read_frame_index(error, filehandle)) {
11341183
return false;
11351184
}
11361185

1137-
// now skip over things like extended offset table
1138-
if (!read_skip_to_pixel_data(error, filehandle)) {
1186+
// skip ahead to extended offset table, if present
1187+
uint32_t skip_to_offset[] = {
1188+
TAG_EXTENDED_OFFSET_TABLE,
1189+
TAG_PIXEL_DATA,
1190+
TAG_FLOAT_PIXEL_DATA,
1191+
TAG_DOUBLE_PIXEL_DATA,
1192+
0
1193+
};
1194+
if (!read_skip_to(error, filehandle, skip_to_offset)) {
1195+
return false;
1196+
}
1197+
if (filehandle->last_tag == TAG_EXTENDED_OFFSET_TABLE &&
1198+
!read_extended_offsets(error, filehandle)) {
11391199
return false;
11401200
}
11411201

1142-
// and we must now be on pixel data
1202+
// skip to pixel data
1203+
uint32_t skip_to_pixel_data[] = {
1204+
TAG_PIXEL_DATA,
1205+
TAG_FLOAT_PIXEL_DATA,
1206+
TAG_DOUBLE_PIXEL_DATA,
1207+
0
1208+
};
1209+
if (!read_skip_to(error, filehandle, skip_to_pixel_data)) {
1210+
return false;
1211+
}
11431212
if (filehandle->last_tag != TAG_PIXEL_DATA &&
11441213
filehandle->last_tag != TAG_FLOAT_PIXEL_DATA &&
11451214
filehandle->last_tag != TAG_DOUBLE_PIXEL_DATA) {
@@ -1153,37 +1222,32 @@ bool dcm_filehandle_prepare_read_frame(DcmError **error,
11531222
return false;
11541223
}
11551224

1156-
// read the BOT, or build it
1157-
dcm_log_debug("Reading PixelData.");
1158-
filehandle->offset_table = DCM_NEW_ARRAY(error,
1159-
filehandle->num_frames,
1160-
int64_t);
1161-
if (filehandle->offset_table == NULL) {
1162-
return false;
1163-
}
1164-
1165-
const char *syntax = dcm_filehandle_get_transfer_syntax_uid(filehandle);
1166-
if (dcm_is_encapsulated_transfer_syntax(syntax)) {
1167-
// read the bot if available, otherwise parse pixeldata to find
1168-
// offsets
1169-
if (!dcm_parse_pixeldata_offsets(error,
1170-
filehandle->io,
1171-
filehandle->implicit,
1172-
&filehandle->first_frame_offset,
1173-
filehandle->offset_table,
1174-
filehandle->num_frames)) {
1175-
return false;
1176-
}
1177-
} else {
1178-
for (uint32_t i = 0; i < filehandle->num_frames; i++) {
1179-
filehandle->offset_table[i] = i *
1180-
filehandle->desc.rows *
1181-
filehandle->desc.columns *
1182-
filehandle->desc.samples_per_pixel;
1225+
// if there was no ext offset table, we must read the basic one, or
1226+
// create it
1227+
if (!filehandle->have_extended_offset_table) {
1228+
const char *syntax =
1229+
dcm_filehandle_get_transfer_syntax_uid(filehandle);
1230+
if (dcm_is_encapsulated_transfer_syntax(syntax)) {
1231+
// read the bot if available, otherwise parse pixeldata to find
1232+
// offsets
1233+
if (!dcm_parse_pixeldata_offsets(error,
1234+
filehandle->io,
1235+
filehandle->implicit,
1236+
&filehandle->first_frame_offset,
1237+
filehandle->offset_table,
1238+
filehandle->num_frames)) {
1239+
return false;
1240+
}
1241+
} else {
1242+
for (uint32_t i = 0; i < filehandle->num_frames; i++) {
1243+
filehandle->offset_table[i] = i *
1244+
filehandle->desc.rows *
1245+
filehandle->desc.columns *
1246+
filehandle->desc.samples_per_pixel;
1247+
}
1248+
1249+
filehandle->first_frame_offset = 12;
11831250
}
1184-
1185-
// Header of Pixel Data Element
1186-
filehandle->first_frame_offset = 12;
11871251
}
11881252
} else {
11891253
// always position at pixel_data

src/dicom-parse.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -881,6 +881,8 @@ bool dcm_parse_pixeldata_offsets(DcmError **error,
881881

882882
int64_t position = 0;
883883

884+
dcm_log_debug("Parsing PixelData.");
885+
884886
uint32_t tag;
885887
DcmVR vr;
886888
uint32_t length;
@@ -912,7 +914,7 @@ bool dcm_parse_pixeldata_offsets(DcmError **error,
912914

913915
if (length > 0) {
914916
// There is a non-zero length BOT, use that
915-
dcm_log_info("Read Basic Offset Table value.");
917+
dcm_log_info("Reading Basic Offset Table.");
916918

917919
// Read offset values from BOT Item value
918920
// FIXME .. could do this with a single require to a uint32_t array,
@@ -952,6 +954,8 @@ bool dcm_parse_pixeldata_offsets(DcmError **error,
952954
// we could use our generic parser above ^^ but we have a special loop
953955
// here as an optimisation (we can skip over the pixel data itself)
954956

957+
dcm_log_info("Building offset table from pixel data scan.");
958+
955959
// 0 in the BOT is the offset to the start of frame 1, ie. here
956960
*first_frame_offset = position;
957961

0 commit comments

Comments
 (0)