-
Notifications
You must be signed in to change notification settings - Fork 0
/
XtfDocument.cs
199 lines (176 loc) · 7.98 KB
/
XtfDocument.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
using stdlibXtf.SubPackets;
using stdlibXtf.Common;
using System;
using System.Collections.Generic;
using System.IO;
namespace stdlibXtf
{
/// <summary>
/// Represents a document to read XTF files.
/// </summary>
public class XtfDocument
{
#region private properties
private XtfMainHeader _MainHeader;
private List<ChannelInfo> _Channels;
private List<IndexEntry> _PacketIndexes;
private StatCollection _Stats;
#endregion private properties
#region public properties
/// <summary>
/// Gets the number that identify the correct start of the packet.
/// </summary>
static public UInt16 MagicNumber { get { return 64206; } }
/// <summary>
/// Gets the XtfMainHeader object that contain the document header information.
/// </summary>
public XtfMainHeader MainHeader { get { return _MainHeader; } }
/// <summary>
/// Gets a list of the sonar channels, and the relative informations, contained in this document.
/// </summary>
public List<ChannelInfo> Channels { get { return _Channels; } }
/// <summary>
/// Gets a list of all the packets, and their position, stored inside this document.
/// </summary>
public List<IndexEntry> Packets { get { return _PacketIndexes; } }
/// <summary>
/// Gets a summary of the packets type and informations stored inside this document.
/// </summary>
public StatCollection Statistics { get { return _Stats; } }
#endregion public properties
#region constructor
/// <summary>
/// Initializes a new instance of the XtfDocument class that has default zero values.
/// </summary>
public XtfDocument()
{
_MainHeader = new XtfMainHeader();
_Channels = new List<ChannelInfo> { };
_PacketIndexes = new List<IndexEntry> { };
_Stats = new StatCollection();
}
/// <summary>
/// Initializes a new instance of the XtfDocument class that contain the values extracted from the given byte array.
/// </summary>
/// <param name="byteArray"></param>
public XtfDocument(Byte[] byteArray)
{
_MainHeader = new XtfMainHeader();
_Channels = new List<ChannelInfo> { };
_PacketIndexes = new List<IndexEntry> { };
_Stats = new StatCollection();
if (byteArray.Length >= 1024)
{
using (BinaryReader dp = new BinaryReader(ArrayToStream.BytesToMemory(byteArray)))
{
// Make sure to start from the first byte
dp.BaseStream.Seek(0, SeekOrigin.Begin);
// Read the header of the file.
_MainHeader = new XtfMainHeader(dp.ReadBytes(256));
// Read the channel data attacched to the header of the file.
_Channels.Clear();
int chnum = _MainHeader.NumberOfSonarChannels + _MainHeader.NumberOfBathymetryChannels - 1;
if (chnum >= 0)
{
if (chnum <= 6)
{
for (int i = 0; i <= chnum; i++)
{
_Channels.Add(new ChannelInfo(dp.ReadBytes(128)));
}
}
else
{
if (byteArray.Length >= 2048)
{
for (int i = 0; i <= chnum; i++)
{
_Channels.Add(new ChannelInfo(dp.ReadBytes(128)));
}
}
else
{
for (int i = 0; i <= 6; i++)
{
_Channels.Add(new ChannelInfo(dp.ReadBytes(128)));
}
}
}
}
UInt32 actualByte;
UInt32 totalBytes = (UInt32)byteArray.Length;
// Compute the dimension of the header.
if (_Channels.Count <= 6) { actualByte = 1024; }
else
{
if (_Channels.Count <= 14) { actualByte = 2048; }
else { actualByte = 3072; } // Up to 22 channels seem to be more than enough.
}
// Make sure to start from the first packet after the header.
dp.BaseStream.Seek(actualByte - 1, SeekOrigin.Begin);
// read all the data packets
bool IsEndOfStream = false;
long bytesToEnd;
while (!IsEndOfStream)
{
try
{
// Explicit cast to fix the difference operator with uint values
bytesToEnd = (long)totalBytes - (long)actualByte;
if (bytesToEnd > 256)
{
PacketSniffer snif = new PacketSniffer(dp.ReadBytes(256));
if (snif.MagicNumber == MagicNumber)
{
_PacketIndexes.Add(new IndexEntry(snif.HeaderType, actualByte));
_Stats.AddPacket(snif);
// Update the reading position
actualByte = actualByte + snif.NumberBytesThisRecord;
dp.BaseStream.Seek(actualByte - 1, SeekOrigin.Begin);
}
else
{
// Update the reading position
actualByte = actualByte + 1;
dp.BaseStream.Seek(actualByte - 1, SeekOrigin.Begin);
}
IsEndOfStream = false;
}
else
{
if (bytesToEnd >= 64)
{
PacketSniffer snif = new PacketSniffer(dp.ReadBytes(14));
if (snif.MagicNumber == MagicNumber)
{
_PacketIndexes.Add(new IndexEntry(snif.HeaderType, actualByte));
_Stats.AddPacket(snif);
// Update the reading position
actualByte = actualByte + snif.NumberBytesThisRecord;
dp.BaseStream.Seek(actualByte - 1, SeekOrigin.Begin);
}
else
{
// Update the reading position
actualByte = actualByte + 1;
dp.BaseStream.Seek(actualByte - 1, SeekOrigin.Begin);
}
IsEndOfStream = true;
}
else
{
IsEndOfStream = true;
}
}
}
catch
{
// Error
}
}
}
}
}
#endregion constructor
}
}