213 lines
7.4 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
namespace LASRead.LASFormat
{
public class Record
{
readonly byte[] data;
public readonly IRecordPayloadHeader header;
readonly long position;
/// <summary>
/// Creates a new Variable Length Record
/// </summary>
/// <param name="header">The parsed header of the object</param>
/// <param name="position">The position of this header in the source stream</param>
public Record(IRecordPayloadHeader header, long position)
{
this.header = header;
data = new byte[header.RecordLengthAfterHeader];
this.position = position;
}
/// <summary>
/// Reads the data payload associated with this header
/// </summary>
/// <param name="s">The source stream</param>
/// <returns>A bool representing success or failed</returns>
public bool ReadData(Stream s)
{
long pos = s.Position;
s.Position = position + header.HeaderLength;
s.Read(data, 0, header.RecordLengthAfterHeader);
s.Position = pos;
return true;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append(header.ToString() + Environment.NewLine);
sb.Append(string.Format("Binary Data @{0}, of length {1}{2}", position + header.HeaderLength, header.HeaderLength, Environment.NewLine));
for (int i = 0; i < data.Length; i += 2)
{
if (i % 8 == 0) sb.Append("\n");
sb.Append($"{BitConverter.ToUInt16(data[i..])} ");
}
//sb.Append(Environment.NewLine + new string(DataHelpers.ToCharArray(data)));
return sb.ToString();
}
}
public interface IRecordPayloadHeader
{
int HeaderLength { get; }
ushort Reserved { get; set; }
byte[] Id { get; set; }
ushort RecordID { get; set; }
ushort RecordLengthAfterHeader { get; set; }
byte[] Description { get; set; }
IPointDataRecord Payload { get; set; }
bool VerifyRecord(byte[] source);
bool ReadRecords(byte[] source);
bool ReadRecords(Stream source);
IRecordPayloadHeader ParseRecord(byte[] source);
IRecordPayloadHeader ParseRecord(Stream source);
}
class VLRHeader : IRecordPayloadHeader
{
public const int headerLength = 54;
public ushort Reserved { get; set; }
public byte[] Id { get; set; }
public ushort RecordID { get; set; }
public ushort RecordLengthAfterHeader { get; set; }
public byte[] Description { get; set; }
public IPointDataRecord Payload { get; set; }
public int HeaderLength { get => headerLength; }
public bool VerifyRecord(byte[] source)
{
if (BitConverter.ToUInt16(source, 0) != 0)
{
return false;
}
return true;
}
public virtual bool ReadRecords(byte[] source)
{
if (source.Length != 54)
{
return false;
}
Reserved = BitConverter.ToUInt16(source, 0);
Id = new byte[16];
Array.Copy(source, 2, Id, 0, 16);
RecordID = BitConverter.ToUInt16(source, 18);
RecordLengthAfterHeader = BitConverter.ToUInt16(source, 20);
Description = new byte[32];
Array.Copy(source, 22, Description, 0, 32);
return true;
}
public bool ReadRecords(Stream source)
{
byte[] bytes = new byte[headerLength];
source.Read(bytes, 0, headerLength);
ReadRecords(bytes);
return true;
}
public virtual byte[] GetRecords()
{
byte[] bytes = new byte[54];
bytes[0] = 0;
bytes[1] = 0;
Id.CopyTo(bytes, 2);
BitConverter.GetBytes(RecordID).CopyTo(bytes, 18);
BitConverter.GetBytes(RecordLengthAfterHeader).CopyTo(bytes, 20);
Description.CopyTo(bytes, 22);
return bytes;
}
public virtual IRecordPayloadHeader ParseRecord(byte[] source)
{
VLRHeader newHeader = new VLRHeader();
newHeader.ReadRecords(source);
return newHeader;
}
public virtual IRecordPayloadHeader ParseRecord(Stream source)
{
byte[] bytes = new byte[headerLength];
source.Read(bytes, 0, headerLength);
return ParseRecord(bytes);
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("Reserved: " + Reserved.ToString() + Environment.NewLine);
sb.Append("User ID: " + new string(DataHelpers.ToCharArray(Id)) + Environment.NewLine);
sb.Append("Record ID: " + RecordID.ToString() + Environment.NewLine);
sb.Append("Record Length After Header: " + RecordLengthAfterHeader.ToString() + Environment.NewLine);
sb.Append("Description: " + new string(DataHelpers.ToCharArray(Description)) + Environment.NewLine);
return sb.ToString();
}
}
/// <summary>
/// Extended Variable Length Records differ from VLRs in the maximum data that can be saved, and header size
/// </summary>
class EVLRHeader : VLRHeader
{
public const int headerLength = 60;
new public ulong RecordLengthAfterHeader { get; set; }
new public int HeaderLength { get => headerLength; }
public override bool ReadRecords(byte[] source)
{
if (source.Length != 60)
{
return false;
}
Reserved = BitConverter.ToUInt16(source, 0);
Id = new byte[16];
Array.Copy(source, 2, Id, 0, 16);
RecordID = BitConverter.ToUInt16(source, 18);
RecordLengthAfterHeader = BitConverter.ToUInt64(source, 20);
Description = new byte[32];
Array.Copy(source, 28, Description, 0, 32);
return true;
}
public override byte[] GetRecords()
{
byte[] bytes = new byte[60];
bytes[0] = 0;
bytes[1] = 0;
Id.CopyTo(bytes, 2);
BitConverter.GetBytes(RecordID).CopyTo(bytes, 18);
BitConverter.GetBytes(RecordLengthAfterHeader).CopyTo(bytes, 20);
Description.CopyTo(bytes, 28);
return bytes;
}
public override IRecordPayloadHeader ParseRecord(byte[] source)
{
EVLRHeader newHeader = new EVLRHeader();
newHeader.ReadRecords(source);
return newHeader;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder();
sb.Append("Reserved: " + Reserved.ToString() + Environment.NewLine);
sb.Append("User ID: " + new string(DataHelpers.ToCharArray(Id)) + Environment.NewLine);
sb.Append("Record ID: " + RecordID.ToString() + Environment.NewLine);
sb.Append("Record Length After Header: " + RecordLengthAfterHeader.ToString() + Environment.NewLine);
sb.Append("Description: " + new string(DataHelpers.ToCharArray(Description)) + Environment.NewLine);
return sb.ToString();
}
}
}