public void OnElement_SmallObject_ReturnValueTrue() { const string expected = "STEREOTACTIC"; var e = new ManualResetEventSlim(false); var element = new DicomCodeString(DicomTag.ApplicatorType, expected); using (var stream = new MemoryStream()) { var target = new StreamByteTarget(stream); var writer = new DicomWriter( DicomTransferSyntax.ExplicitVRLittleEndian, new DicomWriteOptions { LargeObjectSize = 14 }, target); writer.OnBeginWalk(); Assert.True(writer.OnElement(element)); e.Wait(100); stream.Seek(8, SeekOrigin.Begin); using (var reader = new StreamReader(stream)) { var actual = reader.ReadToEnd().Trim(); Assert.Equal(expected, actual); } } }
private void OnCompletePreamble(IByteTarget target, object state) { // recalculate FMI group length as required by standard _fileMetaInfo.RecalculateGroupLengths(); DicomWriter writer = new DicomWriter(DicomTransferSyntax.ExplicitVRLittleEndian, _options, _target); DicomDatasetWalker walker = new DicomDatasetWalker(_fileMetaInfo); walker.BeginWalk(writer, OnCompleteFileMetaInfo, walker); }
private DicomDataset DeepClone_(DicomDataset dataset) { var ms = new MemoryStream(); var target = new StreamByteTarget(ms); var writer = new DicomWriter(DicomTransferSyntax.ImplicitVRLittleEndian, DicomWriteOptions.Default, target); var walker = new DicomDatasetWalker(dataset); walker.Walk(writer); var clone = new DicomDataset(); var reader = new DicomReader { IsExplicitVR = false }; var byteSource = new ByteBufferByteSource( new MemoryByteBuffer(ms.ToArray())); reader.Read(byteSource, new DicomDatasetReaderObserver(clone)); return clone; }
private void SendNextMessage() { while (true) { DicomMessage msg; lock (_lock) { if (_msgQueue.Count == 0) { if (_pending.Count == 0) OnSendQueueEmpty(); return; } if (_sending) return; if (Association.MaxAsyncOpsInvoked > 0 && _pending.Count >= Association.MaxAsyncOpsInvoked) return; _sending = true; msg = _msgQueue.Dequeue(); } if (msg is DicomRequest) _pending.Add(msg as DicomRequest); DicomPresentationContext pc = null; if (msg is DicomCStoreRequest) { pc = Association.PresentationContexts.FirstOrDefault( x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID && x.AcceptedTransferSyntax == (msg as DicomCStoreRequest).TransferSyntax); if (pc == null) pc = Association.PresentationContexts.FirstOrDefault( x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID); } else { pc = Association.PresentationContexts.FirstOrDefault( x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID); } if (pc == null) { pc = msg.PresentationContext; } if (pc == null) { _pending.Remove(msg as DicomRequest); try { if (msg is DicomCStoreRequest) (msg as DicomCStoreRequest).PostResponse( this, new DicomCStoreResponse(msg as DicomCStoreRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomCEchoRequest) (msg as DicomCEchoRequest).PostResponse( this, new DicomCEchoResponse(msg as DicomCEchoRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomCFindRequest) (msg as DicomCFindRequest).PostResponse( this, new DicomCFindResponse(msg as DicomCFindRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomCMoveRequest) (msg as DicomCMoveRequest).PostResponse( this, new DicomCMoveResponse( msg as DicomCMoveRequest, DicomStatus.SOPClassNotSupported)); //TODO: add N services } catch { } Logger.Error( "No accepted presentation context found for abstract syntax: {sopClassUid}", msg.SOPClassUID); } else { var dimse = new Dimse { Message = msg, PresentationContext = pc }; // force calculation of command group length as required by standard msg.Command.RecalculateGroupLengths(); if (msg.HasDataset) { // remove group lengths as recommended in PS 3.5 7.2 // // 2. It is recommended that Group Length elements be removed during storage or transfer // in order to avoid the risk of inconsistencies arising during coercion of data // element values and changes in transfer syntax. msg.Dataset.RemoveGroupLengths(); if (msg.Dataset.InternalTransferSyntax != dimse.PresentationContext.AcceptedTransferSyntax) msg.Dataset = msg.Dataset.ChangeTransferSyntax(dimse.PresentationContext.AcceptedTransferSyntax); } Logger.Info("{logId} -> {dicomMessage}", LogID, msg.ToString(Options.LogDimseDatasets)); try { dimse.Stream = new PDataTFStream(this, pc.ID, Association.MaximumPDULength); var writer = new DicomWriter( DicomTransferSyntax.ImplicitVRLittleEndian, DicomWriteOptions.Default, new StreamByteTarget(dimse.Stream)); dimse.Walker = new DicomDatasetWalker(msg.Command); dimse.Walker.Walk(writer); if (dimse.Message.HasDataset) { dimse.Stream.IsCommand = false; writer = new DicomWriter( dimse.PresentationContext.AcceptedTransferSyntax, DicomWriteOptions.Default, new StreamByteTarget(dimse.Stream)); dimse.Walker = new DicomDatasetWalker(dimse.Message.Dataset); dimse.Walker.Walk(writer); } } catch (Exception e) { Logger.Error("Exception sending DIMSE: {@error}", e); } finally { dimse.Stream.Flush(true).Wait(); dimse.Stream.Dispose(); } } lock (_lock) _sending = false; } }
private void OnCompleteFileMetaInfo(IAsyncResult result) { try { DicomDatasetWalker walker; if (result != null) { walker = result.AsyncState as DicomDatasetWalker; walker.EndWalk(result); } DicomTransferSyntax syntax = _fileMetaInfo.TransferSyntax; if (_options.KeepGroupLengths) { // update transfer syntax and recalculate existing group lengths _dataset.InternalTransferSyntax = syntax; _dataset.RecalculateGroupLengths(false); } else { // remove group lengths as suggested in PS 3.5 7.2 // // 2. It is recommended that Group Length elements be removed during storage or transfer // in order to avoid the risk of inconsistencies arising during coercion of data // element values and changes in transfer syntax. _dataset.RemoveGroupLengths(); } DicomWriter writer = new DicomWriter(syntax, _options, _target); walker = new DicomDatasetWalker(_dataset); walker.BeginWalk(writer, OnCompleteDataset, walker); } catch (Exception e) { _exception = e; _async.Set(); } }
private void OnEndSendCommand(IAsyncResult result) { var dimse = result.AsyncState as Dimse; try { dimse.Walker.EndWalk(result); dimse.Stream.IsCommand = false; var writer = new DicomWriter(dimse.PresentationContext.AcceptedTransferSyntax, DicomWriteOptions.Default, new StreamByteTarget(dimse.Stream)); dimse.Walker = new DicomDatasetWalker(dimse.Message.Dataset); dimse.Walker.BeginWalk(writer, OnEndSendMessage, dimse); } catch (Exception e) { Logger.Error("Exception sending DIMSE: {@error}", e); } finally { if (!dimse.Message.HasDataset) { lock (_lock) _sending = false; SendNextMessage(); } } }
private void SendNextMessage() { DicomMessage msg; lock (_lock) { if (_msgQueue.Count == 0) { if (_pending.Count == 0) OnSendQueueEmpty(); return; } if (_sending) return; if (Association.MaxAsyncOpsInvoked > 0 && _pending.Count >= Association.MaxAsyncOpsInvoked) return; _sending = true; msg = _msgQueue.Dequeue(); } if (msg is DicomRequest) _pending.Add(msg as DicomRequest); DicomPresentationContext pc = null; if (msg is DicomCStoreRequest) { pc = Association.PresentationContexts.FirstOrDefault(x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID && x.AcceptedTransferSyntax == (msg as DicomCStoreRequest).TransferSyntax); if (pc == null) pc = Association.PresentationContexts.FirstOrDefault(x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID); } else { pc = Association.PresentationContexts.FirstOrDefault(x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID); } if (pc == null) { Logger.Error("No accepted presentation context found for abstract syntax: {0}", msg.SOPClassUID); lock (_lock) _sending = false; SendNextMessage(); return; } var dimse = new Dimse(); dimse.Message = msg; dimse.PresentationContext = pc; // force calculation of command group length as required by standard msg.Command.RecalculateGroupLengths(); if (msg.HasDataset) { // remove group lengths as recommended in PS 3.5 7.2 // // 2. It is recommended that Group Length elements be removed during storage or transfer // in order to avoid the risk of inconsistencies arising during coercion of data // element values and changes in transfer syntax. msg.Dataset.RemoveGroupLengths(); if (msg.Dataset.InternalTransferSyntax != dimse.PresentationContext.AcceptedTransferSyntax) msg.Dataset = msg.Dataset.ChangeTransferSyntax(dimse.PresentationContext.AcceptedTransferSyntax); } Logger.Info("{0} -> {1}", LogID, msg.ToString(Options.LogDimseDatasets)); dimse.Stream = new PDataTFStream(this, pc.ID, Association.MaximumPDULength); var writer = new DicomWriter(DicomTransferSyntax.ImplicitVRLittleEndian, DicomWriteOptions.Default, new StreamByteTarget(dimse.Stream)); dimse.Walker = new DicomDatasetWalker(msg.Command); if (dimse.Message.HasDataset) dimse.Walker.BeginWalk(writer, OnEndSendCommand, dimse); else dimse.Walker.BeginWalk(writer, OnEndSendMessage, dimse); }
/// <summary> /// Write DICOM file meta information. /// </summary> /// <param name="target">Byte target subject to writing.</param> /// <param name="fileMetaInfo">File meta information.</param> /// <param name="options">Writer options.</param> private static void WriteFileMetaInfo( IByteTarget target, DicomDataset fileMetaInfo, DicomWriteOptions options) { // recalculate FMI group length as required by standard fileMetaInfo.RecalculateGroupLengths(); var writer = new DicomWriter(DicomTransferSyntax.ExplicitVRLittleEndian, options, target); var walker = new DicomDatasetWalker(fileMetaInfo); walker.Walk(writer); }
/// <summary> /// Write DICOM dataset. /// </summary> /// <param name="target">Byte target subject to writing.</param> /// <param name="syntax">Transfer syntax applicable to dataset.</param> /// <param name="dataset">Dataset.</param> /// <param name="options">Writer options.</param> private static Task WriteDatasetAsync( IByteTarget target, DicomTransferSyntax syntax, DicomDataset dataset, DicomWriteOptions options) { UpdateDatasetGroupLengths(syntax, dataset, options); var writer = new DicomWriter(syntax, options, target); var walker = new DicomDatasetWalker(dataset); return walker.WalkAsync(writer); }
private void OnCompletePreamble(IByteTarget target, object state) { DicomWriter writer = new DicomWriter(DicomTransferSyntax.ExplicitVRLittleEndian, _options, _target); DicomDatasetWalker walker = new DicomDatasetWalker(_fileMetaInfo); walker.BeginWalk(writer, OnCompleteFileMetaInfo, walker); }
private void OnCompleteFileMetaInfo(IAsyncResult result) { try { DicomDatasetWalker walker; if (result != null) { walker = result.AsyncState as DicomDatasetWalker; walker.EndWalk(result); } DicomTransferSyntax syntax = _fileMetaInfo.TransferSyntax; DicomWriter writer = new DicomWriter(syntax, _options, _target); walker = new DicomDatasetWalker(_dataset); walker.BeginWalk(writer, OnCompleteDataset, walker); } catch (Exception e) { _exception = e; _async.Set(); } }
private static void WalkDataset( IByteTarget target, DicomTransferSyntax syntax, DicomDataset dataset, DicomWriteOptions options) { var writer = new DicomWriter(syntax, options, target); var walker = new DicomDatasetWalker(dataset); walker.Walk(writer); }
private void SendNextMessage() { while (true) { DicomMessage msg; lock (_lock) { if (_sending) { return; } if (_msgQueue.Count == 0) { if (_pending.Count == 0) OnSendQueueEmpty(); return; } if (!Options.IgnoreAsyncOps && Association.MaxAsyncOpsInvoked > 0 && _pending.Count >= Association.MaxAsyncOpsInvoked) { Logger.Debug("Cannot send messages since pending: {pending} would exceed max async ops invoked: {invoked}", _pending.Count, Association.MaxAsyncOpsInvoked); return; // Cannot easily recover from this unwanted state, so better to throw. throw new DicomNetworkException( "Cannot send messages since pending: {0} would exceed max async ops invoked: {1}", _pending.Count, Association.MaxAsyncOpsInvoked); } _sending = true; msg = _msgQueue.Dequeue(); if (msg is DicomRequest) { _pending.Add(msg as DicomRequest); } } DicomPresentationContext pc = null; if (msg is DicomCStoreRequest) { pc = Association.PresentationContexts.FirstOrDefault( x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID && x.AcceptedTransferSyntax == (msg as DicomCStoreRequest).TransferSyntax); if (pc == null) pc = Association.PresentationContexts.FirstOrDefault( x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID); } else if (msg is DicomResponse) { //the presentation context should be set already from the request object pc = msg.PresentationContext; //fail safe if no presentation context is already assigned to the response (is this going to happen) if (pc == null) { pc = this.Association.PresentationContexts.FirstOrDefault<DicomPresentationContext>(x => (x.Result == DicomPresentationContextResult.Accept) && (x.AbstractSyntax == msg.SOPClassUID)); } } else { pc = Association.PresentationContexts.FirstOrDefault( x => x.Result == DicomPresentationContextResult.Accept && x.AbstractSyntax == msg.SOPClassUID); } if (pc == null) { pc = msg.PresentationContext; } if (pc == null) { lock (_lock) { _pending.Remove(msg as DicomRequest); } try { if (msg is DicomCStoreRequest) (msg as DicomCStoreRequest).PostResponse( this, new DicomCStoreResponse(msg as DicomCStoreRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomCEchoRequest) (msg as DicomCEchoRequest).PostResponse( this, new DicomCEchoResponse(msg as DicomCEchoRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomCFindRequest) (msg as DicomCFindRequest).PostResponse( this, new DicomCFindResponse( msg as DicomCFindRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomCGetRequest) (msg as DicomCGetRequest).PostResponse( this, new DicomCGetResponse( msg as DicomCGetRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomCMoveRequest) (msg as DicomCMoveRequest).PostResponse( this, new DicomCMoveResponse( msg as DicomCMoveRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomNActionRequest) (msg as DicomNActionRequest).PostResponse( this, new DicomNActionResponse( msg as DicomNActionRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomNCreateRequest) (msg as DicomNCreateRequest).PostResponse( this, new DicomNCreateResponse( msg as DicomNCreateRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomNDeleteRequest) (msg as DicomNDeleteRequest).PostResponse( this, new DicomNDeleteResponse( msg as DicomNDeleteRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomNEventReportRequest) (msg as DicomNEventReportRequest).PostResponse( this, new DicomNEventReportResponse( msg as DicomNEventReportRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomNGetRequest) (msg as DicomNGetRequest).PostResponse( this, new DicomNGetResponse( msg as DicomNGetRequest, DicomStatus.SOPClassNotSupported)); else if (msg is DicomNSetRequest) (msg as DicomNSetRequest).PostResponse( this, new DicomNSetResponse( msg as DicomNSetRequest, DicomStatus.SOPClassNotSupported)); else { Logger.Warn("Unknown message type: {type}", msg.Type); } } catch { } Logger.Error( "No accepted presentation context found for abstract syntax: {sopClassUid}", msg.SOPClassUID); } else { var dimse = new Dimse { Message = msg, PresentationContext = pc }; // force calculation of command group length as required by standard msg.Command.RecalculateGroupLengths(); if (msg.HasDataset) { // remove group lengths as recommended in PS 3.5 7.2 // // 2. It is recommended that Group Length elements be removed during storage or transfer // in order to avoid the risk of inconsistencies arising during coercion of data // element values and changes in transfer syntax. msg.Dataset.RemoveGroupLengths(); if (msg.Dataset.InternalTransferSyntax != dimse.PresentationContext.AcceptedTransferSyntax) { Logger.Debug("{logId} Changing Transfer Syntax from {0} to {1}", LogID, msg.Dataset.InternalTransferSyntax, dimse.PresentationContext.AcceptedTransferSyntax); msg.Dataset = msg.Dataset.Clone(dimse.PresentationContext.AcceptedTransferSyntax); } } Logger.Info("{logId} -> {dicomMessage}", LogID, msg.ToString(Options.LogDimseDatasets)); try { dimse.Stream = new PDataTFStream(this, pc.ID, Association.MaximumPDULength); var writer = new DicomWriter( DicomTransferSyntax.ImplicitVRLittleEndian, DicomWriteOptions.Default, new StreamByteTarget(dimse.Stream)); dimse.Walker = new DicomDatasetWalker(msg.Command); dimse.Walker.Walk(writer); if (dimse.Message.HasDataset) { dimse.Stream.SetIsCommandAsync(false).Wait(); writer = new DicomWriter( dimse.PresentationContext.AcceptedTransferSyntax, DicomWriteOptions.Default, new StreamByteTarget(dimse.Stream)); dimse.Walker = new DicomDatasetWalker(dimse.Message.Dataset); dimse.Walker.Walk(writer); } } catch (Exception e) { Logger.Error("Exception sending DIMSE: {@error}", e); } finally { dimse.Stream.FlushAsync(true).Wait(); dimse.Stream.Dispose(); } } lock (_lock) _sending = false; } }
public void OnFragmentItem_LargeBuffer_ReturnValueTrue() { var expected = Enumerable.Range(0, 256).Select(i => (byte)i).ToArray(); var e = new ManualResetEventSlim(false); using (var stream = new MemoryStream()) { var target = new StreamByteTarget(stream); var writer = new DicomWriter( DicomTransferSyntax.ExplicitVRLittleEndian, new DicomWriteOptions { LargeObjectSize = 200 }, target); writer.OnBeginWalk(); Assert.True(writer.OnFragmentItem(new MemoryByteBuffer(expected))); e.Wait(100); var actual = new byte[expected.Length]; stream.Seek(8, SeekOrigin.Begin); stream.Read(actual, 0, actual.Length); Assert.Equal(expected, actual); } }