using System;
using System.IO;
using GeoAPI.DataStructures;
using GeoAPI.Geometries;
namespace SharpMap.Data.Providers
{
///
/// ShapeFile header class
///
internal sealed class ShapeFileHeader
{
internal const int ShapeFileVersion = 1000;
internal const double NoDataBorderValue = -10e38;
internal const double NoDataValue = -10e39;
///
/// Method to determine if a measure value is to be considered a no data value
///
/// The value to test.
/// true if the value is a no data value
public static bool IsNoDataValue(double measure)
{
return measure < NoDataBorderValue;
}
///
/// Method to set a no data measure value to
///
/// The value to check
/// if it is valid, otherwise .
public static Double ParseNoDataValue(double measure)
{
if (IsNoDataValue(measure))
return Coordinate.NullOrdinate;
return measure;
}
private readonly Envelope _envelope;
///
/// Creates an instance of this class using the provided buffer
///
/// The buffer holding the header information
public ShapeFileHeader(byte[] header)
:this(new MemoryStream(header))
{
}
///
/// Creates an instance of this class using the provided stream
///
/// The stream holding the header information
public ShapeFileHeader(Stream header)
:this(new BinaryReader(header))
{
}
///
/// Creates a Shapefile header using the provided
///
/// The path to the Shapefile
public static ShapeFileHeader Read(string shpPath)
{
using (var s = new FileStream(shpPath, FileMode.Open, FileAccess.Read, FileShare.Read))
return new ShapeFileHeader(s);
}
///
/// Creates an instance of this class using the provided .
///
/// The stream holding the header information
public ShapeFileHeader(BinaryReader headerReader)
{
// Check file header
if (headerReader.ReadInt32() != 170328064)
{
//File Code is actually 9994, but in Little Endian Byte Order this is '170328064'
throw (new ApplicationException("Invalid Shapefile (.shp)"));
}
// Get file length
headerReader.BaseStream.Seek(20, SeekOrigin.Current);
FileLength = 2*ShapeFile.SwapByteOrder(headerReader.ReadInt32());
// Check file Version
if (headerReader.ReadInt32() != ShapeFileVersion)
{
throw (new ApplicationException("Invalid Shapefile version"));
}
// Get the shape type
ShapeType = (ShapeType) headerReader.ReadInt32();
// Get the bounding box
_envelope = new Envelope(new Coordinate(headerReader.ReadDouble(), headerReader.ReadDouble()),
new Coordinate(headerReader.ReadDouble(), headerReader.ReadDouble()));
// Get the Z-range
ZRange = Interval.Create(headerReader.ReadDouble(), headerReader.ReadDouble());
// Get the Z-range
MRange = Interval.Create(ParseNoDataValue(headerReader.ReadDouble()),
ParseNoDataValue(headerReader.ReadDouble()));
}
///
/// Gets the file length
///
public int FileLength { get; private set; }
///
/// Gets the shape type encoded in the shape file
///
public ShapeType ShapeType { get; private set; }
///
/// Gets the extent of the shape file
///
public Envelope BoundingBox { get { return new Envelope(_envelope);} }
///
/// Gets the range of Z-Values in the shape file, if there are any
///
public Interval ZRange { get; private set; }
///
/// Gets the range of M-values in the shape file, if there are any
///
public Interval MRange { get; private set; }
}
}