PageRenderTime 56ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/DICOM/IO/Reader/DicomReader.cs

https://github.com/petnet/fo-dicom
C# | 434 lines | 342 code | 82 blank | 10 comment | 118 complexity | 89a95a6f605ffa5527fc3fc71b9e4eb8 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading;
  6. using Dicom.IO;
  7. using Dicom.IO.Buffer;
  8. using Dicom.Imaging.Mathematics;
  9. namespace Dicom.IO.Reader {
  10. public class DicomReader : IDicomReader {
  11. private const uint UndefinedLength = 0xffffffff;
  12. public enum ParseState {
  13. Tag,
  14. VR,
  15. Length,
  16. Value
  17. }
  18. private ParseState _state;
  19. private DicomTag _tag;
  20. private DicomVR _vr;
  21. private uint _length;
  22. private int _fragmentItem;
  23. private DicomTag _stop;
  24. private IDicomReaderObserver _observer;
  25. private EventAsyncResult _async;
  26. private Exception _exception;
  27. private volatile DicomReaderResult _result;
  28. private bool _explicit;
  29. private DicomDictionary _dict;
  30. private Dictionary<uint, string> _private;
  31. private Stack<object> _stack;
  32. public DicomReader() {
  33. _private = new Dictionary<uint, string>();
  34. _stack = new Stack<object>();
  35. _dict = DicomDictionary.Default;
  36. }
  37. public DicomDictionary Dictionary {
  38. get { return _dict; }
  39. set { _dict = value; }
  40. }
  41. public bool IsExplicitVR {
  42. get { return _explicit; }
  43. set { _explicit = value; }
  44. }
  45. public DicomReaderResult Status {
  46. get { return _result; }
  47. }
  48. public DicomReaderResult Read(IByteSource source, IDicomReaderObserver observer, DicomTag stop = null) {
  49. return EndRead(BeginRead(source, observer, stop, null, null));
  50. }
  51. public IAsyncResult BeginRead(IByteSource source, IDicomReaderObserver observer, DicomTag stop, AsyncCallback callback, object state) {
  52. _stop = stop;
  53. _observer = observer;
  54. _result = DicomReaderResult.Processing;
  55. _exception = null;
  56. _async = new EventAsyncResult(callback, state);
  57. ThreadPool.QueueUserWorkItem(ParseProc, source);
  58. return _async;
  59. }
  60. public DicomReaderResult EndRead(IAsyncResult result) {
  61. _async.AsyncWaitHandle.WaitOne();
  62. if (_exception != null)
  63. throw _exception;
  64. return _result;
  65. }
  66. private void ParseProc(object state) {
  67. ParseDataset(state as IByteSource, null);
  68. }
  69. private void ParseDataset(IByteSource source, object state) {
  70. try {
  71. _result = DicomReaderResult.Processing;
  72. while (!source.IsEOF && !source.HasReachedMilestone()) {
  73. if (_state == ParseState.Tag) {
  74. source.Mark();
  75. if (!source.Require(4, ParseDataset, state)) {
  76. _result = DicomReaderResult.Suspended;
  77. return;
  78. }
  79. ushort group = source.GetUInt16();
  80. ushort element = source.GetUInt16();
  81. DicomPrivateCreator creator = null;
  82. if (group.IsOdd() && element > 0x00ff) {
  83. string pvt = null;
  84. uint card = (uint)(group << 16) + (uint)(element >> 8);
  85. if (_private.TryGetValue(card, out pvt))
  86. creator = Dictionary.GetPrivateCreator(pvt);
  87. }
  88. _tag = new DicomTag(group, element, creator);
  89. if (_stop != null && _tag.CompareTo(_stop) >= 0) {
  90. _result = DicomReaderResult.Stopped;
  91. return;
  92. }
  93. _state = ParseState.VR;
  94. }
  95. while (_state == ParseState.VR) {
  96. if (_tag == DicomTag.Item || _tag == DicomTag.ItemDelimitationItem || _tag == DicomTag.SequenceDelimitationItem) {
  97. _vr = DicomVR.NONE;
  98. _state = ParseState.Length;
  99. break;
  100. }
  101. if (IsExplicitVR) {
  102. if (!source.Require(2, ParseDataset, state)) {
  103. _result = DicomReaderResult.Suspended;
  104. return;
  105. }
  106. byte[] bytes = source.GetBytes(2);
  107. string vr = Encoding.ASCII.GetString(bytes);
  108. _vr = DicomVR.Parse(vr);
  109. } else {
  110. DicomDictionaryEntry entry = Dictionary[_tag];
  111. if (entry != null) {
  112. if (entry.ValueRepresentations.Contains(DicomVR.OB) && entry.ValueRepresentations.Contains(DicomVR.OW))
  113. _vr = DicomVR.OW; // ???
  114. else
  115. _vr = entry.ValueRepresentations.FirstOrDefault();
  116. }
  117. }
  118. if (_vr == null)
  119. _vr = DicomVR.UN;
  120. _state = ParseState.Length;
  121. if (_vr == DicomVR.UN) {
  122. if (_tag.Element == 0x0000) {
  123. // Group Length to UL
  124. _vr = DicomVR.UL;
  125. break;
  126. }
  127. if (_tag.Group.IsOdd()) {
  128. if (_tag.Element <= 0x00ff) {
  129. // Private Creator to LO
  130. _vr = DicomVR.LO;
  131. break;
  132. } else if (IsExplicitVR) {
  133. DicomDictionaryEntry entry = Dictionary[_tag];
  134. if (entry != null)
  135. _vr = entry.ValueRepresentations.FirstOrDefault();
  136. if (_vr == null)
  137. _vr = DicomVR.UN;
  138. break;
  139. }
  140. }
  141. }
  142. }
  143. while (_state == ParseState.Length) {
  144. if (_tag == DicomTag.Item || _tag == DicomTag.ItemDelimitationItem || _tag == DicomTag.SequenceDelimitationItem) {
  145. if (!source.Require(4, ParseDataset, state)) {
  146. _result = DicomReaderResult.Suspended;
  147. return;
  148. }
  149. _length = source.GetUInt32();
  150. _state = ParseState.Value;
  151. break;
  152. }
  153. if (IsExplicitVR) {
  154. if (_vr.Is16bitLength) {
  155. if (!source.Require(2, ParseDataset, state)) {
  156. _result = DicomReaderResult.Suspended;
  157. return;
  158. }
  159. _length = source.GetUInt16();
  160. } else {
  161. if (!source.Require(6, ParseDataset, state)) {
  162. _result = DicomReaderResult.Suspended;
  163. return;
  164. }
  165. source.Skip(2);
  166. _length = source.GetUInt32();
  167. }
  168. } else {
  169. if (!source.Require(4, ParseDataset, state)) {
  170. _result = DicomReaderResult.Suspended;
  171. return;
  172. }
  173. _length = source.GetUInt32();
  174. }
  175. _state = ParseState.Value;
  176. }
  177. if (_state == ParseState.Value) {
  178. if (_tag == DicomTag.ItemDelimitationItem) {
  179. // end of sequence item
  180. ParseItemSequence(source, state);
  181. return;
  182. }
  183. if (_vr == DicomVR.SQ) {
  184. // start of sequence
  185. _observer.OnBeginSequence(source, _tag, _length);
  186. _state = ParseState.Tag;
  187. if (_length != UndefinedLength)
  188. source.PushMilestone(_length);
  189. PushState(state);
  190. ParseItemSequence(source, null);
  191. continue;
  192. }
  193. if (_length == UndefinedLength) {
  194. _observer.OnBeginFragmentSequence(source, _tag, _vr);
  195. _state = ParseState.Tag;
  196. PushState(state);
  197. ParseFragmentSequence(source, null);
  198. continue;
  199. }
  200. if (!source.Require(_length, ParseDataset, state)) {
  201. _result = DicomReaderResult.Suspended;
  202. return;
  203. }
  204. IByteBuffer buffer = source.GetBuffer(_length);
  205. if (!_vr.IsString)
  206. buffer = EndianByteBuffer.Create(buffer, source.Endian, _vr.UnitSize);
  207. _observer.OnElement(source, _tag, _vr, buffer);
  208. ResetState();
  209. }
  210. }
  211. if (source.HasReachedMilestone()) {
  212. // end of explicit length sequence item
  213. _observer.OnEndSequenceItem();
  214. source.PopMilestone();
  215. ParseItemSequence(source, state);
  216. return;
  217. }
  218. // end of processing
  219. _result = DicomReaderResult.Success;
  220. } catch (Exception e) {
  221. _exception = e;
  222. _result = DicomReaderResult.Error;
  223. } finally {
  224. if (_result != DicomReaderResult.Processing && _result != DicomReaderResult.Suspended) {
  225. _async.Set();
  226. }
  227. }
  228. }
  229. private void ParseItemSequence(IByteSource source, object state) {
  230. try {
  231. _result = DicomReaderResult.Processing;
  232. while (!source.IsEOF && !source.HasReachedMilestone()) {
  233. if (_state == ParseState.Tag) {
  234. source.Mark();
  235. if (!source.Require(8, ParseItemSequence, state)) {
  236. _result = DicomReaderResult.Suspended;
  237. return;
  238. }
  239. ushort group = source.GetUInt16();
  240. ushort element = source.GetUInt16();
  241. DicomTag tag = new DicomTag(group, element);
  242. if (tag != DicomTag.Item && tag != DicomTag.SequenceDelimitationItem)
  243. throw new DicomReaderException("Unexpected tag in DICOM sequence: {0}", tag);
  244. _length = source.GetUInt32();
  245. if (tag == DicomTag.SequenceDelimitationItem) {
  246. // end of sequence
  247. _observer.OnEndSequence();
  248. ResetState();
  249. ParseDataset(source, PopState());
  250. return;
  251. }
  252. _state = ParseState.Value;
  253. }
  254. if (_state == ParseState.Value) {
  255. if (_tag == DicomTag.ItemDelimitationItem) {
  256. // end of sequence item
  257. _observer.OnEndSequenceItem();
  258. ResetState();
  259. continue;
  260. }
  261. if (_length != UndefinedLength) {
  262. if (!source.Require(_length, ParseItemSequence, state)) {
  263. _result = DicomReaderResult.Suspended;
  264. return;
  265. }
  266. source.PushMilestone(_length);
  267. }
  268. _observer.OnBeginSequenceItem(source, _length);
  269. ResetState();
  270. ParseDataset(source, state);
  271. return;
  272. }
  273. }
  274. // end of explicit length sequence
  275. if (source.HasReachedMilestone())
  276. source.PopMilestone();
  277. _observer.OnEndSequence();
  278. } catch (Exception e) {
  279. _exception = e;
  280. _result = DicomReaderResult.Error;
  281. } finally {
  282. if (_result != DicomReaderResult.Processing && _result != DicomReaderResult.Suspended) {
  283. _async.Set();
  284. }
  285. }
  286. }
  287. private void ParseFragmentSequence(IByteSource source, object state) {
  288. try {
  289. _result = DicomReaderResult.Processing;
  290. while (!source.IsEOF) {
  291. if (_state == ParseState.Tag) {
  292. source.Mark();
  293. if (!source.Require(8, ParseFragmentSequence, state)) {
  294. _result = DicomReaderResult.Suspended;
  295. return;
  296. }
  297. ushort group = source.GetUInt16();
  298. ushort element = source.GetUInt16();
  299. DicomTag tag = new DicomTag(group, element);
  300. if (tag != DicomTag.Item && tag != DicomTag.SequenceDelimitationItem)
  301. throw new DicomReaderException("Unexpected tag in DICOM fragment sequence: {0}", tag);
  302. _length = source.GetUInt32();
  303. if (tag == DicomTag.SequenceDelimitationItem) {
  304. // end of fragment
  305. _observer.OnEndFragmentSequence();
  306. _fragmentItem = 0;
  307. ResetState();
  308. ParseDataset(source, PopState());
  309. return;
  310. }
  311. _fragmentItem++;
  312. _state = ParseState.Value;
  313. }
  314. if (_state == ParseState.Value) {
  315. if (!source.Require(_length, ParseFragmentSequence, state)) {
  316. _result = DicomReaderResult.Suspended;
  317. return;
  318. }
  319. IByteBuffer buffer = source.GetBuffer(_length);
  320. if (_fragmentItem == 1)
  321. buffer = EndianByteBuffer.Create(buffer, source.Endian, 4);
  322. else
  323. buffer = EndianByteBuffer.Create(buffer, source.Endian, _vr.UnitSize);
  324. _observer.OnFragmentSequenceItem(source, buffer);
  325. _state = ParseState.Tag;
  326. }
  327. }
  328. } catch (Exception e) {
  329. _exception = e;
  330. _result = DicomReaderResult.Error;
  331. } finally {
  332. if (_result != DicomReaderResult.Processing && _result != DicomReaderResult.Suspended) {
  333. _async.Set();
  334. }
  335. }
  336. }
  337. private void PushState(object state) {
  338. _stack.Push(state);
  339. }
  340. private object PopState() {
  341. if (_stack.Count > 0)
  342. return _stack.Pop();
  343. return null;
  344. }
  345. private void ResetState() {
  346. _state = ParseState.Tag;
  347. _tag = null;
  348. _vr = null;
  349. _length = 0;
  350. }
  351. }
  352. }