private bool ParseItemSequenceTag(IByteSource source) { if (this.parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(8)) { this.result = DicomReaderResult.Suspended; return(false); } var group = source.GetUInt16(); var element = source.GetUInt16(); this._tag = new DicomTag(@group, element); if (this._tag != DicomTag.Item && this._tag != DicomTag.SequenceDelimitationItem) { // assume invalid sequence source.Rewind(); if (!this._implicit) { source.PopMilestone(); } this.observer.OnEndSequence(); if (this.badPrivateSequence) { this.isExplicitVR = !this.isExplicitVR; this.badPrivateSequence = false; } return(false); } this.length = source.GetUInt32(); if (this._tag == DicomTag.SequenceDelimitationItem) { // #64, in case explicit length has been specified despite occurrence of Sequence Delimitation Item if (source.HasReachedMilestone() && source.MilestonesCount > this.sequenceDepth) { this.ResetState(); return(true); } // end of sequence this.observer.OnEndSequence(); if (this.badPrivateSequence) { this.isExplicitVR = !this.isExplicitVR; this.badPrivateSequence = false; } this.ResetState(); return(false); } this.parseStage = ParseStage.Value; } return(true); }
private void ResetState() { this.parseStage = ParseStage.Tag; this._tag = null; this._entry = null; this._vr = null; this.length = 0; }
private void ResetState() { _parseStage = ParseStage.Tag; _tag = null; _entry = null; _vr = null; _length = 0; }
private bool ParseTag(IByteSource source) { if (_parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(4)) { _result = DicomReaderResult.Suspended; return(false); } var group = source.GetUInt16(); var element = source.GetUInt16(); DicomPrivateCreator creator = null; // according to // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.8.html // The requirements of this section do not allow any use of elements in the ranges // (gggg,0001-000F) and (gggg,0100-0FFF) where gggg is odd. // So element at [0x0100-0x0FFF] should not has a creator if (@group.IsOdd() && element >= 0x1000) { var card = (uint)(@group << 16) + (uint)(element >> 8); lock (_locker) { if (_private.TryGetValue(card, out string pvt)) { creator = _dictionary.GetPrivateCreator(pvt); } } } _tag = new DicomTag(@group, element, creator); _entry = _dictionary[_tag]; if (!_tag.IsPrivate && _entry != null && _entry.MaskTag == null) { _tag = _entry.Tag; // Use dictionary tag } if (_stop != null && _stop(new ParseState { Tag = _tag, SequenceDepth = _sequenceDepth })) { _result = DicomReaderResult.Stopped; return(false); } _parseStage = ParseStage.VR; } return(true); }
private bool ParseTag(IByteSource source) { if (this.parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(4)) { this.result = DicomReaderResult.Suspended; return(false); } var group = source.GetUInt16(); var element = source.GetUInt16(); DicomPrivateCreator creator = null; if (@group.IsOdd() && element > 0x00ff) { var card = (uint)(@group << 16) + (uint)(element >> 8); lock (this.locker) { string pvt; if (this._private.TryGetValue(card, out pvt)) { creator = this.dictionary.GetPrivateCreator(pvt); } } } this._tag = new DicomTag(@group, element, creator); this._entry = this.dictionary[this._tag]; if (!this._tag.IsPrivate && this._entry != null && this._entry.MaskTag == null) { this._tag = this._entry.Tag; // Use dictionary tag } if (this.stop != null && this.stop(new ParseState { Tag = this._tag, SequenceDepth = this.sequenceDepth })) { this.result = DicomReaderResult.Stopped; return(false); } this.parseStage = ParseStage.VR; } return(true); }
private bool ParseFragmentSequenceValue(IByteSource source) { if (_parseStage == ParseStage.Value) { if (!source.Require(_length)) { _result = DicomReaderResult.Suspended; return(false); } var buffer = source.GetBuffer(_length); buffer = EndianByteBuffer.Create(buffer, source.Endian, _fragmentItem == 1 ? 4 : _vr.UnitSize); _observer.OnFragmentSequenceItem(source, buffer); _parseStage = ParseStage.Tag; } return(true); }
private async Task <bool> ParseFragmentSequenceValueAsync(IByteSource source) { if (this.parseStage == ParseStage.Value) { if (!source.Require(this.length)) { this.result = DicomReaderResult.Suspended; return(false); } var buffer = await source.GetBufferAsync(this.length).ConfigureAwait(false); buffer = EndianByteBuffer.Create(buffer, source.Endian, this.fragmentItem == 1 ? 4 : this._vr.UnitSize); this.observer.OnFragmentSequenceItem(source, buffer); this.parseStage = ParseStage.Tag; } return(true); }
private bool ParseFragmentSequenceTag(IByteSource source) { if (_parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(8)) { _result = DicomReaderResult.Suspended; return(false); } var group = source.GetUInt16(); var element = source.GetUInt16(); var tag = new DicomTag(@group, element); if (tag != DicomTag.Item && tag != DicomTag.SequenceDelimitationItem) { throw new DicomReaderException($"Unexpected tag in DICOM fragment sequence: {tag}"); } _length = source.GetUInt32(); if (tag == DicomTag.SequenceDelimitationItem) { // end of fragment _observer.OnEndFragmentSequence(); _fragmentItem = 0; ResetState(); return(false); } _fragmentItem++; _parseStage = ParseStage.Value; } return(true); }
private bool ParseTag(IByteSource source) { if (this.parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(4)) { this.result = DicomReaderResult.Suspended; return false; } var group = source.GetUInt16(); var element = source.GetUInt16(); DicomPrivateCreator creator = null; if (@group.IsOdd() && element > 0x00ff) { var card = (uint)(@group << 16) + (uint)(element >> 8); lock (this.locker) { string pvt; if (this._private.TryGetValue(card, out pvt)) { creator = this.dictionary.GetPrivateCreator(pvt); } } } this._tag = new DicomTag(@group, element, creator); this._entry = this.dictionary[this._tag]; if (!this._tag.IsPrivate && this._entry != null && this._entry.MaskTag == null) { this._tag = this._entry.Tag; // Use dictionary tag } if (this.stop != null && this.stop(new ParseState { Tag = this._tag, SequenceDepth = this.sequenceDepth })) { this.result = DicomReaderResult.Stopped; return false; } this.parseStage = ParseStage.VR; } return true; }
private async Task<bool> ParseFragmentSequenceValueAsync(IByteSource source) { if (this.parseStage == ParseStage.Value) { if (!source.Require(this.length)) { this.result = DicomReaderResult.Suspended; return false; } var buffer = await source.GetBufferAsync(this.length).ConfigureAwait(false); buffer = EndianByteBuffer.Create(buffer, source.Endian, this.fragmentItem == 1 ? 4 : this._vr.UnitSize); this.observer.OnFragmentSequenceItem(source, buffer); this.parseStage = ParseStage.Tag; } return true; }
private bool ParseFragmentSequenceTag(IByteSource source) { if (this.parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(8)) { this.result = DicomReaderResult.Suspended; return false; } var group = source.GetUInt16(); var element = source.GetUInt16(); DicomTag tag = new DicomTag(@group, element); if (tag != DicomTag.Item && tag != DicomTag.SequenceDelimitationItem) { throw new DicomReaderException("Unexpected tag in DICOM fragment sequence: {0}", tag); } this.length = source.GetUInt32(); if (tag == DicomTag.SequenceDelimitationItem) { // end of fragment this.observer.OnEndFragmentSequence(); this.fragmentItem = 0; this.ResetState(); return false; } this.fragmentItem++; this.parseStage = ParseStage.Value; } return true; }
private bool ParseItemSequenceTag(IByteSource source) { if (this.parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(8)) { this.result = DicomReaderResult.Suspended; return false; } var group = source.GetUInt16(); var element = source.GetUInt16(); this._tag = new DicomTag(@group, element); if (this._tag != DicomTag.Item && this._tag != DicomTag.SequenceDelimitationItem) { // assume invalid sequence source.Rewind(); if (!this._implicit) { source.PopMilestone(); } this.observer.OnEndSequence(); if (this.badPrivateSequence) { this.isExplicitVR = !this.isExplicitVR; this.badPrivateSequence = false; } return false; } this.length = source.GetUInt32(); if (this._tag == DicomTag.SequenceDelimitationItem) { // #64, in case explicit length has been specified despite occurrence of Sequence Delimitation Item if (source.HasReachedMilestone() && source.MilestonesCount > this.sequenceDepth) { this.ResetState(); return true; } // end of sequence this.observer.OnEndSequence(); if (this.badPrivateSequence) { this.isExplicitVR = !this.isExplicitVR; this.badPrivateSequence = false; } this.ResetState(); return false; } this.parseStage = ParseStage.Value; } return true; }
void EmitParseError(Error error, string extra = null) { var e = OnParseError; if (e != null) e(error, extra); Stage = ParseStage.Error; }
private async Task <bool> ParseValueAsync(IByteSource source) { if (_parseStage == ParseStage.Value) { // check dictionary for VR after reading length to handle 16-bit lengths // check before reading value to handle SQ elements var parsedVR = _vr; // check dictionary for VR after reading length to handle 16-bit lengths // check before reading value to handle SQ elements if (_vr == DicomVR.Implicit || (_vr == DicomVR.UN && _isExplicitVR)) { var entry = _dictionary[_tag]; if (entry != null) { _vr = entry.ValueRepresentations.FirstOrDefault(); } if (_vr == null) { _vr = DicomVR.UN; } } if (_tag == DicomTag.ItemDelimitationItem || _tag == DicomTag.SequenceDelimitationItem) { // end of sequence item return(false); } while (_vr == DicomVR.SQ && _tag.IsPrivate && _length > 0) { if (!IsPrivateSequence(source)) { _vr = DicomVR.UN; break; } if (IsPrivateSequenceBad(source, _length, _isExplicitVR)) { _badPrivateSequence = true; // store the depth of the bad sequence, we only want to switch back once we've processed // the entire sequence, regardless of any sub-sequences. _badPrivateSequenceDepth = _sequenceDepth; _isExplicitVR = !_isExplicitVR; } break; } var curIndex = source.Position; // Fix to handle sequence items not associated with any sequence (#364) if (_tag.Equals(DicomTag.Item)) { source.Rewind(); _vr = DicomVR.SQ; } if (_vr == DicomVR.SQ) { // start of sequence _observer.OnBeginSequence(source, _tag, _length); _parseStage = ParseStage.Tag; if (_length == 0) { _implicit = false; source.PushMilestone((uint)(source.Position - curIndex)); } else if (_length != _undefinedLength) { _implicit = false; source.PushMilestone(_length); } else { _implicit = true; } var last = source.Position; // Conformance with CP-246 (#177) var needtoChangeEndian = false; if (parsedVR == DicomVR.UN && !_tag.IsPrivate) { _implicit = true; needtoChangeEndian = source.Endian == Endian.Big; } if (needtoChangeEndian) { source.Endian = Endian.Little; } await ParseItemSequenceAsync(source).ConfigureAwait(false); if (needtoChangeEndian) { source.Endian = Endian.Big; } // Aeric Sylvan - https://github.com/rcd/fo-dicom/issues/62#issuecomment-46248073 // Fix reading of SQ with parsed VR of UN if (source.Position > last || _length == 0) { return(true); } _parseStage = ParseStage.Value; _vr = parsedVR; } if (_length == _undefinedLength) { _observer.OnBeginFragmentSequence(source, _tag, _vr); _parseStage = ParseStage.Tag; await ParseFragmentSequenceAsync(source).ConfigureAwait(false); return(true); } if (!source.Require(_length)) { _result = DicomReaderResult.Suspended; return(false); } var buffer = await source.GetBufferAsync(_length).ConfigureAwait(false); if (!_vr.IsString) { buffer = EndianByteBuffer.Create(buffer, source.Endian, _vr.UnitSize); } _observer.OnElement(source, _tag, _vr, buffer); // parse private creator value and add to lookup table // according to // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.8.html // Private Creator Data Elements numbered (gggg,0010-00FF) (gggg is odd) // The VR of the private identification code shall be LO (Long String) and the VM shall be equal to 1. if (_tag.IsPrivate && _tag.Element >= 0x0010 && _tag.Element <= 0x00ff) { var creator = DicomEncoding.Default.GetString(buffer.Data, 0, buffer.Data.Length) .TrimEnd((char)DicomVR.LO.PaddingValue); var card = (uint)(_tag.Group << 16) + _tag.Element; lock (_locker) { _private[card] = creator; } } ResetState(); } return(true); }
private bool ParseVR(IByteSource source) { while (_parseStage == ParseStage.VR) { if (_tag == DicomTag.Item || _tag == DicomTag.ItemDelimitationItem || _tag == DicomTag.SequenceDelimitationItem) { _vr = DicomVR.NONE; _parseStage = ParseStage.Length; break; } if (_isExplicitVR || _badPrivateSequence) { if (!source.Require(2)) { _result = DicomReaderResult.Suspended; return(false); } source.Mark(); var bytes = source.GetBytes(2); var vr = Encoding.UTF8.GetString(bytes, 0, bytes.Length); if (string.IsNullOrEmpty(vr.Trim())) { if (_entry != null) { _vr = _entry.ValueRepresentations.FirstOrDefault(); } } else if (!DicomVR.TryParse(vr, out _vr)) { // unable to parse VR; rewind VR bytes for continued attempt to interpret the data. _vr = DicomVR.Implicit; source.Rewind(); } } else { if (_entry != null) { if (_entry == DicomDictionary.UnknownTag) { _vr = DicomVR.UN; } else if (_entry.ValueRepresentations.Contains(DicomVR.OB) && _entry.ValueRepresentations.Contains(DicomVR.OW)) { _vr = DicomVR.OW; // ??? } else { _vr = _entry.ValueRepresentations.FirstOrDefault(); } } } if (_vr == null) { _vr = DicomVR.UN; } _parseStage = ParseStage.Length; if (_vr == DicomVR.UN) { if (_tag.Element == 0x0000) { // Group Length to UL // change 20161216: if changing from UN to UL then ParseLength causes a error, since length in UL is 2 bytes while length in UN is 6 bytes. // so the source hat UN and coded the length in 6 bytes. if here the VR was changed to UL then ParseLength would only read 2 bytes and the parser is then wrong. // but no worry: in ParseValue in the first lines there is a lookup in the Dictionary of DicomTags and there the VR is changed to UL so that the value is finally interpreted correctly as UL. // _vr = DicomVR.UL; break; } if (_isExplicitVR) { break; } } if (_tag.IsPrivate) { // according to // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.8.html // Private Creator Data Elements numbered (gggg,0010-00FF) (gggg is odd) // The VR of the private identification code shall be LO (Long String) and the VM shall be equal to 1. if (_tag.Element >= 0x0010 && _tag.Element <= 0x00ff && _vr == DicomVR.UN) { _vr = DicomVR.LO; // force private creator to LO } } } return(true); }
private bool ParseVR(IByteSource source) { while (this.parseStage == ParseStage.VR) { if (this._tag == DicomTag.Item || this._tag == DicomTag.ItemDelimitationItem || this._tag == DicomTag.SequenceDelimitationItem) { this._vr = DicomVR.NONE; this.parseStage = ParseStage.Length; break; } if (this.isExplicitVR || this.badPrivateSequence) { if (!source.Require(2)) { this.result = DicomReaderResult.Suspended; return(false); } source.Mark(); var bytes = source.GetBytes(2); var vr = Encoding.UTF8.GetString(bytes, 0, bytes.Length); if (string.IsNullOrEmpty(vr.Trim())) { if (this._entry != null) { this._vr = this._entry.ValueRepresentations.FirstOrDefault(); } } else if (!DicomVR.TryParse(vr, out this._vr)) { // unable to parse VR; rewind VR bytes for continued attempt to interpret the data. this._vr = DicomVR.Implicit; source.Rewind(); } } else { if (this._entry != null) { if (this._entry == DicomDictionary.UnknownTag) { this._vr = DicomVR.UN; } else if (this._entry.ValueRepresentations.Contains(DicomVR.OB) && this._entry.ValueRepresentations.Contains(DicomVR.OW)) { this._vr = DicomVR.OW; // ??? } else { this._vr = this._entry.ValueRepresentations.FirstOrDefault(); } } } if (this._vr == null) { this._vr = DicomVR.UN; } this.parseStage = ParseStage.Length; if (this._vr == DicomVR.UN) { if (this._tag.Element == 0x0000) { // Group Length to UL // change 20161216: if changing from UN to UL then ParseLength causes a error, since length in UL is 2 bytes while length in UN is 6 bytes. // so the source hat UN and coded the length in 6 bytes. if here the VR was changed to UL then ParseLength would only read 2 bytes and the parser is then wrong. // but no worry: in ParseValue in the first lines there is a lookup in the Dictionary of DicomTags and there the VR is changed to UL so that the value is finally interpreted correctly as UL. // this._vr = DicomVR.UL; break; } if (this.isExplicitVR) { break; } } if (this._tag.IsPrivate) { if (this._tag.Element != 0x0000 && this._tag.Element <= 0x00ff && this._vr == DicomVR.UN) { this._vr = DicomVR.LO; // force private creator to LO } } } return(true); }
private void Parse() { MyEvent = null; ParseStage stage = ParseStage.Object; StringBuilder ObjectBuilder = new StringBuilder(); StringBuilder FunctionBuilder = new StringBuilder(); StringBuilder[] ArgBuilder = new StringBuilder[16]; int ArgCount = 0; for (int i = 0; i < Value.Count(); i++) { switch (Value[i]) { case '.': stage = ParseStage.Function; break; case '(': stage = ParseStage.Arguments; break; case ',': if (stage == ParseStage.Arguments) { ArgCount++; } break; case ')': if (ArgBuilder[ArgCount] != null) { ArgCount++; } string[] args = new string[ArgCount]; for (int a = 0; a < ArgCount; a++) { if (ArgBuilder[a] != null) { args[a] = ArgBuilder[a].ToString().ToLower(); ArgBuilder[a] = new StringBuilder(); } } ArgCount = 0; EventCall e = new EventCall(); e.args = args; string ObjectString = ObjectBuilder.ToString(); if (!ObjectString.Equals("this")) { e.MyObject = Parent.ParentLevel.FindObject(ObjectString); if (e.MyObject == null) { e.MyObject = Parent.ParentScene; } } else { e.MyObject = Parent; } string FunctionString = FunctionBuilder.ToString().ToLower(); foreach (EventType t in EventCall.AllEvents) { if (t.ToString().ToLower().Equals(FunctionString)) { e.Function = t; break; } } ObjectBuilder = new StringBuilder(); FunctionBuilder = new StringBuilder(); if (MyEvent == null) { MyEvent = e; } else { MyEvent.Add(e); } stage = ParseStage.Object; break; default: switch (stage) { case ParseStage.Object: if (Value[i] != ' ') { ObjectBuilder.Append(Value[i]); } break; case ParseStage.Function: if (Value[i] != ' ') { FunctionBuilder.Append(Value[i]); } break; case ParseStage.Arguments: if (ArgBuilder[ArgCount] == null) { ArgBuilder[ArgCount] = new StringBuilder(); } ArgBuilder[ArgCount].Append(Value[i]); break; } break; } } NeedsParsing = false; }
private async Task <bool> ParseValueAsync(IByteSource source) { if (this.parseStage == ParseStage.Value) { // check dictionary for VR after reading length to handle 16-bit lengths // check before reading value to handle SQ elements var parsedVR = this._vr; // check dictionary for VR after reading length to handle 16-bit lengths // check before reading value to handle SQ elements if (this._vr == DicomVR.Implicit || (this._vr == DicomVR.UN && this.isExplicitVR)) { var entry = this.dictionary[this._tag]; if (entry != null) { this._vr = entry.ValueRepresentations.FirstOrDefault(); } if (this._vr == null) { this._vr = DicomVR.UN; } } if (this._tag == DicomTag.ItemDelimitationItem) { // end of sequence item return(false); } while (this._vr == DicomVR.SQ && this._tag.IsPrivate) { if (!IsPrivateSequence(source)) { this._vr = DicomVR.UN; break; } if (IsPrivateSequenceBad(source, this.isExplicitVR)) { this.badPrivateSequence = true; this.isExplicitVR = !this.isExplicitVR; } break; } if (this._vr == DicomVR.SQ) { // start of sequence this.observer.OnBeginSequence(source, this._tag, this.length); this.parseStage = ParseStage.Tag; if (this.length != UndefinedLength) { this._implicit = false; source.PushMilestone(this.length); } else { this._implicit = true; } var last = source.Position; // Conformance with CP-246 (#177) var needtoChangeEndian = false; if (parsedVR == DicomVR.UN && !this._tag.IsPrivate) { this._implicit = true; needtoChangeEndian = source.Endian == Endian.Big; } if (needtoChangeEndian) { source.Endian = Endian.Little; } await this.ParseItemSequenceAsync(source).ConfigureAwait(false); if (needtoChangeEndian) { source.Endian = Endian.Big; } // Aeric Sylvan - https://github.com/rcd/fo-dicom/issues/62#issuecomment-46248073 // Fix reading of SQ with parsed VR of UN if (source.Position > last || this.length == 0) { return(true); } this.parseStage = ParseStage.Value; this._vr = parsedVR; } if (this.length == UndefinedLength) { this.observer.OnBeginFragmentSequence(source, this._tag, this._vr); this.parseStage = ParseStage.Tag; await this.ParseFragmentSequenceAsync(source).ConfigureAwait(false); return(true); } if (!source.Require(this.length)) { this.result = DicomReaderResult.Suspended; return(false); } var buffer = await source.GetBufferAsync(this.length).ConfigureAwait(false); if (!this._vr.IsString) { buffer = EndianByteBuffer.Create(buffer, source.Endian, this._vr.UnitSize); } this.observer.OnElement(source, this._tag, this._vr, buffer); // parse private creator value and add to lookup table if (this._tag.IsPrivate && this._tag.Element != 0x0000 && this._tag.Element <= 0x00ff) { var creator = DicomEncoding.Default.GetString(buffer.Data, 0, buffer.Data.Length) .TrimEnd((char)DicomVR.LO.PaddingValue); var card = (uint)(this._tag.Group << 16) + this._tag.Element; lock (this.locker) { this._private[card] = creator; } } this.ResetState(); } return(true); }
private bool ParseVR(IByteSource source) { while (this.parseStage == ParseStage.VR) { if (this._tag == DicomTag.Item || this._tag == DicomTag.ItemDelimitationItem || this._tag == DicomTag.SequenceDelimitationItem) { this._vr = DicomVR.NONE; this.parseStage = ParseStage.Length; break; } if (this.isExplicitVR) { if (!source.Require(2)) { this.result = DicomReaderResult.Suspended; return(false); } source.Mark(); var bytes = source.GetBytes(2); var vr = Encoding.UTF8.GetString(bytes, 0, bytes.Length); if (string.IsNullOrWhiteSpace(vr)) { if (this._entry != null) { this._vr = this._entry.ValueRepresentations.FirstOrDefault(); } } else if (!DicomVR.TryParse(vr, out this._vr)) { // unable to parse VR; rewind VR bytes for continued attempt to interpret the data. this._vr = DicomVR.Implicit; source.Rewind(); } } else { if (this._entry != null) { if (this._entry == DicomDictionary.UnknownTag) { this._vr = DicomVR.UN; } else if (this._entry.ValueRepresentations.Contains(DicomVR.OB) && this._entry.ValueRepresentations.Contains(DicomVR.OW)) { this._vr = DicomVR.OW; // ??? } else { this._vr = this._entry.ValueRepresentations.FirstOrDefault(); } } } if (this._vr == null) { this._vr = DicomVR.UN; } this.parseStage = ParseStage.Length; if (this._vr == DicomVR.UN) { if (this._tag.Element == 0x0000) { // Group Length to UL this._vr = DicomVR.UL; break; } if (this.isExplicitVR) { break; } } if (this._tag.IsPrivate) { if (this._tag.Element != 0x0000 && this._tag.Element <= 0x00ff && this._vr == DicomVR.UN) { this._vr = DicomVR.LO; // force private creator to LO } } } return(true); }
private bool ParseVR(IByteSource source) { while (this.parseStage == ParseStage.VR) { if (this._tag == DicomTag.Item || this._tag == DicomTag.ItemDelimitationItem || this._tag == DicomTag.SequenceDelimitationItem) { this._vr = DicomVR.NONE; this.parseStage = ParseStage.Length; break; } if (this.isExplicitVR) { if (!source.Require(2)) { this.result = DicomReaderResult.Suspended; return false; } source.Mark(); var bytes = source.GetBytes(2); var vr = Encoding.UTF8.GetString(bytes, 0, bytes.Length); if (string.IsNullOrWhiteSpace(vr)) { if (this._entry != null) { this._vr = this._entry.ValueRepresentations.FirstOrDefault(); } } else if (!DicomVR.TryParse(vr, out this._vr)) { // unable to parse VR; rewind VR bytes for continued attempt to interpret the data. this._vr = DicomVR.Implicit; source.Rewind(); } } else { if (this._entry != null) { if (this._entry == DicomDictionary.UnknownTag) { this._vr = DicomVR.UN; } else if (this._entry.ValueRepresentations.Contains(DicomVR.OB) && this._entry.ValueRepresentations.Contains(DicomVR.OW)) { this._vr = DicomVR.OW; // ??? } else { this._vr = this._entry.ValueRepresentations.FirstOrDefault(); } } } if (this._vr == null) { this._vr = DicomVR.UN; } this.parseStage = ParseStage.Length; if (this._vr == DicomVR.UN) { if (this._tag.Element == 0x0000) { // Group Length to UL this._vr = DicomVR.UL; break; } if (this.isExplicitVR) { break; } } if (this._tag.IsPrivate) { if (this._tag.Element != 0x0000 && this._tag.Element <= 0x00ff && this._vr == DicomVR.UN) { this._vr = DicomVR.LO; // force private creator to LO } } } return true; }
private bool ParseLength(IByteSource source) { while (this.parseStage == ParseStage.Length) { if (this._tag == DicomTag.Item || this._tag == DicomTag.ItemDelimitationItem || this._tag == DicomTag.SequenceDelimitationItem) { if (!source.Require(4)) { this.result = DicomReaderResult.Suspended; return false; } this.length = source.GetUInt32(); this.parseStage = ParseStage.Value; break; } if (this.isExplicitVR) { if (this._vr == DicomVR.Implicit) { if (!source.Require(4)) { this.result = DicomReaderResult.Suspended; return false; } this.length = source.GetUInt32(); // assume that undefined length in implicit VR element is SQ if (this.length == UndefinedLength) { this._vr = DicomVR.SQ; } } else if (this._vr.Is16bitLength) { if (!source.Require(2)) { this.result = DicomReaderResult.Suspended; return false; } this.length = source.GetUInt16(); } else { if (!source.Require(6)) { this.result = DicomReaderResult.Suspended; return false; } source.Skip(2); this.length = source.GetUInt32(); // CP-246 (#177) handling // assume that Undefined Length in explicit datasets with VR UN are sequences // According to CP-246 the sequence shall be handled as ILE, but this will be handled later... // in the current code this needs to be restricted to privates if (this.length == UndefinedLength && this._vr == DicomVR.UN && this._tag.IsPrivate) { this._vr = DicomVR.SQ; } } } else { if (!source.Require(4)) { this.result = DicomReaderResult.Suspended; return false; } this.length = source.GetUInt32(); // assume that undefined length in implicit dataset is SQ if (this.length == UndefinedLength && this._vr == DicomVR.UN) { this._vr = DicomVR.SQ; } } this.parseStage = ParseStage.Value; } return true; }
private bool ParseLength(IByteSource source) { while (_parseStage == ParseStage.Length) { if (_tag == DicomTag.Item || _tag == DicomTag.ItemDelimitationItem || _tag == DicomTag.SequenceDelimitationItem) { if (!source.Require(4)) { _result = DicomReaderResult.Suspended; return(false); } _length = source.GetUInt32(); _parseStage = ParseStage.Value; break; } if (_isExplicitVR || _badPrivateSequence) { if (_vr == DicomVR.Implicit) { if (!source.Require(4)) { _result = DicomReaderResult.Suspended; return(false); } _length = source.GetUInt32(); // assume that undefined length in implicit VR element is SQ if (_length == _undefinedLength) { _vr = DicomVR.SQ; } } else if (_vr.Is16bitLength) { if (!source.Require(2)) { _result = DicomReaderResult.Suspended; return(false); } _length = source.GetUInt16(); } else { if (!source.Require(6)) { _result = DicomReaderResult.Suspended; return(false); } source.Skip(2); _length = source.GetUInt32(); // CP-246 (#177) handling // assume that Undefined Length in explicit datasets with VR UN are sequences // According to CP-246 the sequence shall be handled as ILE, but this will be handled later... // in the current code this needs to be restricted to privates if (_length == _undefinedLength && _vr == DicomVR.UN && _tag.IsPrivate) { _vr = DicomVR.SQ; } } } else { if (!source.Require(4)) { _result = DicomReaderResult.Suspended; return(false); } _length = source.GetUInt32(); // assume that undefined length in implicit dataset is SQ if (_length == _undefinedLength && _vr == DicomVR.UN) { _vr = DicomVR.SQ; } } _parseStage = ParseStage.Value; } return(true); }
private async Task<bool> ParseValueAsync(IByteSource source) { if (this.parseStage == ParseStage.Value) { // check dictionary for VR after reading length to handle 16-bit lengths // check before reading value to handle SQ elements var parsedVR = this._vr; // check dictionary for VR after reading length to handle 16-bit lengths // check before reading value to handle SQ elements if (this._vr == DicomVR.Implicit || (this._vr == DicomVR.UN && this.isExplicitVR)) { var entry = this.dictionary[this._tag]; if (entry != null) { this._vr = entry.ValueRepresentations.FirstOrDefault(); } if (this._vr == null) { this._vr = DicomVR.UN; } } if (this._tag == DicomTag.ItemDelimitationItem) { // end of sequence item return false; } while (this._vr == DicomVR.SQ && this._tag.IsPrivate) { if (!IsPrivateSequence(source)) { this._vr = DicomVR.UN; break; } if (IsPrivateSequenceBad(source, this.isExplicitVR)) { this.badPrivateSequence = true; this.isExplicitVR = !this.isExplicitVR; } break; } if (this._vr == DicomVR.SQ) { // start of sequence this.observer.OnBeginSequence(source, this._tag, this.length); this.parseStage = ParseStage.Tag; if (this.length != UndefinedLength) { this._implicit = false; source.PushMilestone(this.length); } else { this._implicit = true; } var last = source.Position; // Conformance with CP-246 (#177) var needtoChangeEndian = false; if (parsedVR == DicomVR.UN && !this._tag.IsPrivate) { this._implicit = true; needtoChangeEndian = source.Endian == Endian.Big; } if (needtoChangeEndian) { source.Endian = Endian.Little; } await this.ParseItemSequenceAsync(source).ConfigureAwait(false); if (needtoChangeEndian) { source.Endian = Endian.Big; } // Aeric Sylvan - https://github.com/rcd/fo-dicom/issues/62#issuecomment-46248073 // Fix reading of SQ with parsed VR of UN if (source.Position > last || this.length == 0) { return true; } this.parseStage = ParseStage.Value; this._vr = parsedVR; } if (this.length == UndefinedLength) { this.observer.OnBeginFragmentSequence(source, this._tag, this._vr); this.parseStage = ParseStage.Tag; await this.ParseFragmentSequenceAsync(source).ConfigureAwait(false); return true; } if (!source.Require(this.length)) { this.result = DicomReaderResult.Suspended; return false; } var buffer = await source.GetBufferAsync(this.length).ConfigureAwait(false); if (!this._vr.IsString) { buffer = EndianByteBuffer.Create(buffer, source.Endian, this._vr.UnitSize); } this.observer.OnElement(source, this._tag, this._vr, buffer); // parse private creator value and add to lookup table if (this._tag.IsPrivate && this._tag.Element != 0x0000 && this._tag.Element <= 0x00ff) { var creator = DicomEncoding.Default.GetString(buffer.Data, 0, buffer.Data.Length) .TrimEnd((char)DicomVR.LO.PaddingValue); var card = (uint)(this._tag.Group << 16) + this._tag.Element; lock (this.locker) { this._private[card] = creator; } } this.ResetState(); } return true; }
private bool ParseItemSequenceTag(IByteSource source) { if (_parseStage == ParseStage.Tag) { source.Mark(); if (!source.Require(8)) { _result = DicomReaderResult.Suspended; return(false); } var group = source.GetUInt16(); var element = source.GetUInt16(); _tag = new DicomTag(@group, element); if (_tag != DicomTag.Item && _tag != DicomTag.SequenceDelimitationItem) { // assume invalid sequence source.Rewind(); if (!_implicit) { source.PopMilestone(); } _observer.OnEndSequence(); // #565 Only reset the badPrivate sequence if we're in the correct depth // This prevents prematurely resetting in case of sub-sequences contained in the bad private sequence if (_badPrivateSequence && _sequenceDepth == _badPrivateSequenceDepth) { _isExplicitVR = !_isExplicitVR; _badPrivateSequence = false; } return(false); } _length = source.GetUInt32(); if (_tag == DicomTag.SequenceDelimitationItem) { // #64, in case explicit length has been specified despite occurrence of Sequence Delimitation Item if (source.HasReachedMilestone() && source.MilestonesCount > _sequenceDepth) { ResetState(); return(true); } // end of sequence _observer.OnEndSequence(); // #565 Only reset the badPrivate sequence if we're in the correct depth // This prevents prematurely resetting in case of sub-sequences contained in the bad private sequence if (_badPrivateSequence && _sequenceDepth == _badPrivateSequenceDepth) { _isExplicitVR = !_isExplicitVR; _badPrivateSequence = false; } ResetState(); return(false); } _parseStage = ParseStage.Value; } return(true); }
public void AddBytes(ArraySegment<byte> data) { for (int i=0; i<data.Count; i++) { // Get the current byte from the input. This is here for DRY; you'll // see `b` get used a whole lot in the state machine. byte b = data.Array[i + data.Offset]; // This is one hell of a monolithic parser. You've been warned. switch (Stage) { #region Error State // If we had a parse error, we're done. We'll // just silently eat all bytes passed to us. case ParseStage.Error: return; #endregion #region Eat Leading CRs/LFs // I guess this isn't strictly compliant with the // RFC, but we're going to eat leading CRs/LFs so // that telnet users or whatever can be trigger-happy // with the newlines. // // And there was much rejoicing. case ParseStage.Start: if (b == 0x0D || b == 0x0A) //CR, LF break; else goto case ParseStage.RequestLine_StartMethod; #endregion #region Method Parsing case ParseStage.RequestLine_StartMethod: SB1.Clear(); Stage = ParseStage.RequestLine_Method; goto case ParseStage.RequestLine_Method; case ParseStage.RequestLine_Method: if (b == 0x20) //Space { Str1 = SB1.ToString(); Stage = ParseStage.RequestLine_StartURI; } else if (b < 0x41 || b > 0x5A) // 'A' <= b <= 'Z' { EmitParseError(Error.BadRequest); return; } else { SB1.Append((char)b); } break; #endregion #region Request URI Parsing case ParseStage.RequestLine_StartURI: if (b == 0x20 || b == 0x09 || b == 0x0D || b == 0x0A) //Space, horizontal tab, CR, LF { EmitParseError(Error.BadRequest); return; } else { SB1.Clear(); SB1.Append((char)b); } Stage = ParseStage.RequestLine_URI; break; case ParseStage.RequestLine_URI: if (b == 0x20) //Space { Stage = ParseStage.RequestLine_StartVersion; } else if (b == 0x09 || b == 0x0D || b == 0x0A) //Horizontal tab, CR, LF { EmitParseError(Error.BadRequest); return; } else { SB1.Append((char)b); // Make sure the URI isn't ridiculously long. This also serves // as a mechanism for ensuring a malformed request won't cause // the parser to endlessly consume additional data from the client. // // I'm using another variable rather than the StringBuilder's length // because I figure 4 bytes is worth the tiny (if anything) performance // increase. Probably should have done some profiling before doing this... if (++Size1 > 4096) { EmitParseError(Error.UriTooLong); return; } } break; #endregion #region HTTP Version Parsing case ParseStage.RequestLine_StartVersion: if (b == 0x48) //H { Stage = ParseStage.RequestLine_H; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.RequestLine_H: if (b == 0x54) //T { Stage = ParseStage.RequestLine_HT; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.RequestLine_HT: if (b == 0x54) //T { Stage = ParseStage.RequestLine_HTT; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.RequestLine_HTT: if (b == 0x50) //P { Stage = ParseStage.RequestLine_HTTP; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.RequestLine_HTTP: if (b == 0x2F) // / { Stage = ParseStage.RequestLine_VersionMajor; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.RequestLine_VersionMajor: if (b == 0x31) //1 { Stage = ParseStage.RequestLine_VersionDot; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.RequestLine_VersionDot: if (b == 0x2E) //. { Stage = ParseStage.RequestLine_VersionMinor; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.RequestLine_VersionMinor: Size1 = 0; if (b == 0x31) //1 { Version = HTTP.Version.HTTP1_1; Stage = ParseStage.RequestLine_EndVersion; } else if (b == 0x30) //0 { Version = HTTP.Version.HTTP1_0; Stage = ParseStage.RequestLine_EndVersion; } else { EmitParseError(Error.BadRequest); return; } break; // Look for a CRLF | LF to signal the end of the request line case ParseStage.RequestLine_EndVersion: if (b == 0x0D) // CR { if (Size1 == 0) { Size1++; break; } else { EmitParseError(Error.BadRequest); return; } } else if (b == 0x0A) // LF { EmitRequestLine(Str1, SB1.ToString(), Version); Stage = ParseStage.Headers_Start; } else { EmitParseError(Error.BadRequest); return; } break; #endregion #region Header Parsing case ParseStage.Headers_Start: SB1.Clear(); if (b == 0x0D) //CR { Stage = ParseStage.Headers_AlmostEnd; } // We allow the headers section to end with just an LF, which // is more flexible than the spec. else if (b == 0x0A) { goto case ParseStage.Headers_AlmostEnd; } else { Stage = ParseStage.Header_Name; goto case ParseStage.Header_Name; } break; case ParseStage.Header_Name: // If we hit the colon, push the stringbuilder's state // into the string, so that we can build the value if (b == 0x3A) // : { // First, make sure there's actually something // in the header name. if (SB1.Length == 0) { EmitParseError(Error.BadRequest); return; } // Store the header name and prepare to parse // the value. Str1 = SB1.ToString(); SB1.Clear(); Stage = ParseStage.Header_ValueStart; } // Look for invalid characters else if (b > 126 // DEL or Non-ASCII || b < 33 // Space or CTL || false) // Theoretically, we could be more precise, but it // doesn't really seem worth spending time on. { EmitParseError(Error.BadRequest); return; } else { SB1.Append((char)b); // Limit header name size to a maximum of 128 characters if (SB1.Length > 128) { EmitParseError(Error.HeaderFieldsTooLarge); return; } } break; case ParseStage.Header_ValueStart: if (b != 0x20 && b != 0x09) //Space, HTab { Size1 = 0; Stage = ParseStage.Header_Value; goto case ParseStage.Header_Value; } else { break; } case ParseStage.Header_Value: if (b == 0x0D) //CR { Stage = ParseStage.Header_AlmostNewLine; } // We allow headers to end with LF, which is more flexible // than the spec. else if (b == 0x0A) // LF { goto case ParseStage.Header_AlmostNewLine; } else { SB1.Append((char)b); // Limit header value size to 4096 characters if (SB1.Length > 4096) { EmitParseError(Error.HeaderFieldsTooLarge, Str1); return; } } break; case ParseStage.Header_AlmostNewLine: if (b == 0x0A) //LF { Stage = ParseStage.Header_NewLine; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.Header_NewLine: // Look for the header continuing on the next line. If the // first character is whitespace, then it's a continuation // and we handle that by adding a ", " to the header's value // and then just appending whatever the value contained in the // header line is. if (b == 0x20 || b == 0x09) //Space, HTab { Stage = ParseStage.Header_Value; SB1.Append(", "); } // If it's anything but whitespace, then the header value is // done, so we can emit it and continue parsing. else { // Emit the header EmitHeader(Str1, SB1.ToString()); // Clean up after ourselves SB1.Clear(); // Cap the number of headers at 128 if (++Size1 > 128) { EmitParseError(Error.HeaderFieldsTooLarge); return; } // If it's a CR, then we're ending headers. if (b == 0x0D) // CR { Stage = ParseStage.Headers_AlmostEnd; } // If it's an LF, then the client just skipped // the CR, and we can handle that gracefully. else if (b == 0x0A) { Stage = ParseStage.Headers_AlmostEnd; goto case ParseStage.Headers_AlmostEnd; } // Otherwise, it's a regular old header and we should // continue parsing it. else { Stage = ParseStage.Header_Name; goto case ParseStage.Header_Name; } } break; case ParseStage.Headers_AlmostEnd: if (b == 0x0A) //LF { if (InTrailers) Stage = ParseStage.Done; else EmitEndHeaders(); // Check to see if we should expect a body if (Entity == EntityType.Identity) { // If the size is zero, the body is over if (EntitySize == 0) Stage = ParseStage.Done; // Otherwise, we've got a flat body else Stage = ParseStage.EntityFlat; } else if (Entity == EntityType.Chunked) { Stage = ParseStage.EntityChunked_StartChunk; } else { Stage = ParseStage.Done; goto case ParseStage.Done; } } else { EmitParseError(Error.BadRequest); return; } break; #endregion #region Entity Parsing #region Flat case ParseStage.EntityFlat: if (EntitySize > data.Count - i) //there's more data coming in the next buffer { //read to the end of the buffer EmitBody(new ArraySegment<byte>(data.Array, i + data.Offset, data.Count - i)); //decrease the remaining byte count EntitySize -= data.Count - i; //force the loop to end i = data.Count; } else //the current buffer contains all the data we need { EmitBody(new ArraySegment<byte>(data.Array, i + data.Offset, EntitySize)); i += EntitySize; Stage = ParseStage.Done; goto case ParseStage.Done; } break; #endregion #region Chunked case ParseStage.EntityChunked_StartChunk: SB1.Clear(); Stage = ParseStage.EntityChunked_ChunkSize; goto case ParseStage.EntityChunked_ChunkSize; case ParseStage.EntityChunked_ChunkSize: if (b == 0x0D) //CR Stage = ParseStage.EntityChunked_ChunkSizeCR; else if (b == 0x0A) // LF goto case ParseStage.EntityChunked_ChunkSizeCR; else SB1.Append((char)b); break; case ParseStage.EntityChunked_ChunkSizeCR: if (b == 0x0A) //LF { if (!int.TryParse(SB1.ToString().Split(';')[0], System.Globalization.NumberStyles.HexNumber, System.Globalization.NumberFormatInfo.InvariantInfo, out Size1)) { EmitParseError(Error.BadRequest); return; } // Handle the final chunk (specified by size of 0) if (Size1 == 0) { InTrailers = true; Stage = ParseStage.Headers_Start; } // Carry on else { Stage = ParseStage.EntityChunked_Chunk; } } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.EntityChunked_Chunk: if (Size1 > data.Count - i) //there's more data coming in the next buffer { //read to the end of the buffer EmitBody(new ArraySegment<byte>(data.Array, i + data.Offset, data.Count - i)); //decrease the remaining byte count Size1 -= data.Count - i; } else //the current buffer contains all the data we need { EmitBody(new ArraySegment<byte>(data.Array, i + data.Offset, Size1)); i += Size1 - 1; Stage = ParseStage.EntityChunked_ChunkEnd; } break; case ParseStage.EntityChunked_ChunkEnd: if (b == 0x0D) // CR { Stage = ParseStage.EntityChunked_ChunkCR; } else if (b == 0x0A) // LF { goto case ParseStage.EntityChunked_ChunkCR; } else { EmitParseError(Error.BadRequest); return; } break; case ParseStage.EntityChunked_ChunkCR: if (b == 0x0A) //LF { Stage = ParseStage.EntityChunked_StartChunk; } else { EmitParseError(Error.BadRequest); return; } break; #endregion #endregion // If we're done, wrap things up and keep on truckin' case ParseStage.Done: // Finish up the request EmitEnd(); // Reset some state Entity = EntityType.None; // Go back to the start, which lets us handle more data on this // packet. Stage = ParseStage.Start; break; } } }