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;
///
/// Creates a new Variable Length Record
///
/// The parsed header of the object
/// The position of this header in the source stream
public Record(IRecordPayloadHeader header, long position)
{
this.header = header;
data = new byte[header.RecordLengthAfterHeader];
this.position = position;
}
///
/// Reads the data payload associated with this header
///
/// The source stream
/// A bool representing success or failed
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));
sb.Append(header.ToString());
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: " + RecordID.ToString() + Environment.NewLine);
sb.Append("Description: " + new string(DataHelpers.ToCharArray(Description)) + Environment.NewLine);
return sb.ToString();
}
}
///
/// Extended Variable Length Records differ from VLRs in the maximum data that can be saved, and header size
///
class EVLRHeader : VLRHeader
{
public new const int headerLength = 60;
new public ulong RecordLengthAfterHeader { get; set; }
new public int HeaderLength { get => 60; }
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: " + RecordID.ToString() + Environment.NewLine);
sb.Append("Description: " + new string(DataHelpers.ToCharArray(Description)) + Environment.NewLine);
return base.ToString();
}
}
}