Describe the bug
Any DICOM-typed connector that has a filter or transformer attached fails to process messages containing an undefined-length sequence under a private tag that dcm4che2 resolves to VR UN (implicit VR, tag not in its dictionary). Common real-world producers: FujiFILM (0029,E131) and Siemens MEDCOM (0029,1140). Messages with no filter/transformer pass through fine, because they never go through the XML round trip.
com.mirth.connect.donkey.model.message.MessageSerializerException: Error converting XML to DICOM
Caused by: java.lang.IllegalStateException: state:EXPECT_FRAG
at org.dcm4che2.io.ContentHandlerAdapter.startElement(...)
at com.mirth.connect.plugins.datatypes.dicom.DICOMSerializer.fromXML(...)
Root cause
dcm4che2 2.0.29's XML round trip is asymmetric:
DicomInputStream reads a UN element with undefined length whose items hold dataset elements and represents it as SQ in memory.
toXML uses the streaming SAXWriter, which emits the wire VR: <tag0029E131 vr="UN" len="-1"> with structured <item> children.
fromXML hands that to ContentHandlerAdapter, which only enters its sequence state for vr="SQ" and otherwise expects fragments; the first <attr> inside the item throws state:EXPECT_FRAG.
dcm4che2 has had no release since 2015, so this cannot be fixed at the library.
To Reproduce
Programmatic, no fixtures needed (this is what the accompanying test does):
- Build a
BasicDicomObject, putNestedDicomObject(0x0029E131, item) with any element in the item, write it as Implicit VR Little Endian.
new DICOMSerializer().toXML(base64) — note the output carries vr="UN" with an <item> child.
fromXML(thatXml) throws.
Or in a running engine: DICOM Listener → any transformer step → send a Fuji or Siemens CR/CT object carrying a private sequence.
Expected behavior
fromXML accepts the XML toXML produced, and the re-encoded DICOM is identical to what the engine emits without a transformer.
Proposed fix
Reader-side, in DICOMSerializer.fromXML's existing DOM pre-pass (the one that renames <tagXXXXXXXX> back to <attr>): when an element's <item> children contain renamed <attr> elements, set vr="SQ" before the SAX parse. That is the same content-based decision DicomInputStream makes for the binary form. toXML output is unchanged, so transformer scripts see identical XML; fragment containers (encapsulated pixel data) are untouched; every input that parses today produces an identical DicomObject; and the rewrite is a no-op if a future dcm4che emits SQ itself.
Verified byte-for-byte that the transformer round trip now produces the same DICOM as the no-transformer pass-through path, for implicit and explicit VR LE. PR to follow.
Environment
- OIE
main at 423df18 (also reproduces on 4.6.0-based builds)
- dcm4che2 2.0.29 as bundled
Describe the bug
Any DICOM-typed connector that has a filter or transformer attached fails to process messages containing an undefined-length sequence under a private tag that dcm4che2 resolves to VR
UN(implicit VR, tag not in its dictionary). Common real-world producers: FujiFILM(0029,E131)and Siemens MEDCOM(0029,1140). Messages with no filter/transformer pass through fine, because they never go through the XML round trip.Root cause
dcm4che2 2.0.29's XML round trip is asymmetric:
DicomInputStreamreads aUNelement with undefined length whose items hold dataset elements and represents it asSQin memory.toXMLuses the streamingSAXWriter, which emits the wire VR:<tag0029E131 vr="UN" len="-1">with structured<item>children.fromXMLhands that toContentHandlerAdapter, which only enters its sequence state forvr="SQ"and otherwise expects fragments; the first<attr>inside the item throwsstate:EXPECT_FRAG.dcm4che2 has had no release since 2015, so this cannot be fixed at the library.
To Reproduce
Programmatic, no fixtures needed (this is what the accompanying test does):
BasicDicomObject,putNestedDicomObject(0x0029E131, item)with any element in the item, write it as Implicit VR Little Endian.new DICOMSerializer().toXML(base64)— note the output carriesvr="UN"with an<item>child.fromXML(thatXml)throws.Or in a running engine: DICOM Listener → any transformer step → send a Fuji or Siemens CR/CT object carrying a private sequence.
Expected behavior
fromXMLaccepts the XMLtoXMLproduced, and the re-encoded DICOM is identical to what the engine emits without a transformer.Proposed fix
Reader-side, in
DICOMSerializer.fromXML's existing DOM pre-pass (the one that renames<tagXXXXXXXX>back to<attr>): when an element's<item>children contain renamed<attr>elements, setvr="SQ"before the SAX parse. That is the same content-based decisionDicomInputStreammakes for the binary form.toXMLoutput is unchanged, so transformer scripts see identical XML; fragment containers (encapsulated pixel data) are untouched; every input that parses today produces an identicalDicomObject; and the rewrite is a no-op if a future dcm4che emitsSQitself.Verified byte-for-byte that the transformer round trip now produces the same DICOM as the no-transformer pass-through path, for implicit and explicit VR LE. PR to follow.
Environment
mainat 423df18 (also reproduces on 4.6.0-based builds)