Reader.cs 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Text.RegularExpressions;
  7. namespace NationalInstruments.Tdms
  8. {
  9. public class Reader
  10. {
  11. private readonly BinaryReader _reader;
  12. public Reader(Stream stream)
  13. {
  14. _reader = new BinaryReader(stream);
  15. }
  16. public Segment? ReadFirstSegment()
  17. {
  18. return ReadSegment(0);
  19. }
  20. public Segment? ReadSegment(long offset)
  21. {
  22. if (offset < 0 || offset >= _reader.BaseStream.Length) return null;
  23. _reader.BaseStream.Seek(offset, SeekOrigin.Begin);
  24. var leadin = new Segment { Offset = offset, MetadataOffset = offset + Segment.Length };
  25. leadin.Identifier = Encoding.ASCII.GetString(_reader.ReadBytes(4));
  26. var tableOfContentsMask = _reader.ReadInt32();
  27. leadin.TableOfContents = new TableOfContents
  28. {
  29. ContainsNewObjects = ((tableOfContentsMask >> 2) & 1) == 1,
  30. HasDaqMxData = ((tableOfContentsMask >> 7) & 1) == 1,
  31. HasMetaData = ((tableOfContentsMask >> 1) & 1) == 1,
  32. HasRawData = ((tableOfContentsMask >> 3) & 1) == 1,
  33. NumbersAreBigEndian = ((tableOfContentsMask >> 6) & 1) == 1,
  34. RawDataIsInterleaved = ((tableOfContentsMask >> 5) & 1) == 1
  35. };
  36. leadin.Version = _reader.ReadInt32();
  37. Func<long, long> resetWhenEol = x => x < _reader.BaseStream.Length ? x : -1;
  38. leadin.NextSegmentOffset = resetWhenEol(_reader.ReadInt64() + offset + Segment.Length);
  39. leadin.RawDataOffset = _reader.ReadInt64() + offset + Segment.Length;
  40. return leadin;
  41. }
  42. public IList<Metadata> ReadMetadata(Segment segment)
  43. {
  44. _reader.BaseStream.Seek(segment.MetadataOffset, SeekOrigin.Begin);
  45. var objectCount = _reader.ReadInt32();
  46. var metadatas = new List<Metadata>();
  47. var rawDataOffset = segment.RawDataOffset;
  48. bool isInterleaved = segment.TableOfContents.RawDataIsInterleaved;
  49. int interleaveStride = 0;
  50. for (var x = 0; x < objectCount; x++)
  51. {
  52. var metadata = new Metadata();
  53. metadata.Path = Regex.Matches(Encoding.UTF8.GetString(_reader.ReadBytes(_reader.ReadInt32())), "'(.*?)'").Cast<Match>().
  54. SelectMany(y => y.Groups.Cast<System.Text.RegularExpressions.Group>().Skip(1), (m, g) => g.Value).ToArray();
  55. metadata.RawData = new RawData();
  56. var rawDataIndexLength = _reader.ReadInt32();
  57. if (rawDataIndexLength > 0)
  58. {
  59. metadata.RawData.Offset = rawDataOffset;
  60. metadata.RawData.IsInterleaved = segment.TableOfContents.RawDataIsInterleaved;
  61. metadata.RawData.DataType = _reader.ReadInt32();
  62. metadata.RawData.ClrDataType = DataType.GetClrType(metadata.RawData.DataType);
  63. metadata.RawData.Dimension = _reader.ReadInt32();
  64. metadata.RawData.Count = _reader.ReadInt64();
  65. metadata.RawData.Size = rawDataIndexLength == 28 ? _reader.ReadInt64() :
  66. DataType.GetArrayLength(metadata.RawData.DataType, metadata.RawData.Count);
  67. if (isInterleaved)
  68. {
  69. //fixed error. The interleave stride is the sum of all channel (type) dataSizes
  70. rawDataOffset += DataType.GetLength(metadata.RawData.DataType);
  71. interleaveStride += DataType.GetLength(metadata.RawData.DataType);
  72. }
  73. else
  74. rawDataOffset += metadata.RawData.Size;
  75. }
  76. var propertyCount = _reader.ReadInt32();
  77. metadata.Properties = new Dictionary<string, object>();
  78. for (var y = 0; y < propertyCount; y++)
  79. {
  80. var key = _reader.ReadLengthPrefixedString() ?? string.Empty;
  81. var value = _reader.Read(_reader.ReadInt32());
  82. metadata.Properties[key] = value!;
  83. }
  84. metadatas.Add(metadata);
  85. }
  86. if (isInterleaved)
  87. {
  88. foreach (var metadata in metadatas)
  89. {
  90. if (metadata.RawData.ClrDataType != null)
  91. {
  92. metadata.RawData.InterleaveStride = interleaveStride;
  93. metadata.RawData.Count = segment.NextSegmentOffset > 0
  94. ? (segment.NextSegmentOffset - metadata.RawData.Offset + interleaveStride - 1) / interleaveStride
  95. : (_reader.BaseStream.Length - metadata.RawData.Offset + interleaveStride - 1) / interleaveStride;
  96. }
  97. }
  98. }
  99. return metadatas;
  100. }
  101. public IEnumerable<object> ReadRawData(RawData rawData)
  102. {
  103. if (rawData.IsInterleaved)
  104. return ReadRawInterleaved(rawData.Offset, rawData.Count, rawData.DataType, rawData.InterleaveStride - DataType.GetLength(rawData.DataType)); //fixed error
  105. return rawData.DataType == DataType.String ? ReadRawStrings(rawData.Offset, rawData.Count) :
  106. ReadRawFixed(rawData.Offset, rawData.Count, rawData.DataType);
  107. }
  108. private IEnumerable<object> ReadRawFixed(long offset, long count, int dataType)
  109. {
  110. _reader.BaseStream.Seek(offset, SeekOrigin.Begin);
  111. for (var x = 0; x < count; x++) yield return _reader.Read(dataType);
  112. }
  113. private IEnumerable<object> ReadRawInterleaved(long offset, long count, int dataType, int interleaveSkip)
  114. {
  115. _reader.BaseStream.Seek(offset, SeekOrigin.Begin);
  116. for (var x = 0; x < count; x++)
  117. {
  118. var value = _reader.Read(dataType);
  119. _reader.BaseStream.Seek(interleaveSkip, SeekOrigin.Current);
  120. yield return value;
  121. }
  122. }
  123. private IEnumerable<object> ReadRawStrings(long offset, long count)
  124. {
  125. _reader.BaseStream.Seek(offset, SeekOrigin.Begin);
  126. var dataOffset = offset + (count * 4);
  127. var indexPosition = _reader.BaseStream.Position;
  128. var dataPosition = dataOffset;
  129. for (var x = 0; x < count; x++)
  130. {
  131. var endOfString = _reader.ReadInt32();
  132. indexPosition = _reader.BaseStream.Position;
  133. _reader.BaseStream.Seek(dataPosition, SeekOrigin.Begin);
  134. yield return _reader.ReadString((int)((dataOffset + endOfString) - dataPosition));
  135. dataPosition = dataOffset + endOfString;
  136. _reader.BaseStream.Seek(indexPosition, SeekOrigin.Begin);
  137. }
  138. }
  139. public long FileSize
  140. {
  141. get { return _reader.BaseStream.Length; }
  142. }
  143. public class Segment
  144. {
  145. public const long Length = 28;
  146. public long Offset { get; set; }
  147. public long MetadataOffset { get; set; }
  148. public long RawDataOffset { get; set; }
  149. public long NextSegmentOffset { get; set; }
  150. public string Identifier { get; set; } = string.Empty;
  151. public TableOfContents TableOfContents { get; set; } = new TableOfContents();
  152. public int Version { get; set; }
  153. }
  154. public class TableOfContents
  155. {
  156. public bool HasMetaData { get; set; }
  157. public bool HasRawData { get; set; }
  158. public bool HasDaqMxData { get; set; }
  159. public bool RawDataIsInterleaved { get; set; }
  160. public bool NumbersAreBigEndian { get; set; }
  161. public bool ContainsNewObjects { get; set; }
  162. }
  163. public class Metadata
  164. {
  165. public string[] Path { get; set; }= new string[0];
  166. public RawData RawData { get; set; } = new RawData();
  167. public IDictionary<string, object> Properties { get; set; } = new Dictionary<string, object>();
  168. }
  169. public class RawData
  170. {
  171. public long Offset { get; set; }
  172. public int DataType { get; set; }
  173. public Type? ClrDataType { get; set; } = null;
  174. public int Dimension { get; set; }
  175. public long Count { get; set; }
  176. public long Size { get; set; }
  177. public bool IsInterleaved { get; set; }
  178. public int InterleaveStride { get; set; }
  179. }
  180. }
  181. }