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; } } }