Skip to content

Commit

Permalink
Fixes #1059: Support for reading/writing spatial WKB
Browse files Browse the repository at this point in the history
  • Loading branch information
xuzhg committed Jan 27, 2025
1 parent c1c9b84 commit b31e87c
Show file tree
Hide file tree
Showing 15 changed files with 3,153 additions and 1 deletion.
8 changes: 8 additions & 0 deletions src/Microsoft.Spatial/DataServicesSpatialImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,5 +82,13 @@ public override SpatialPipeline CreateValidator()
{
return new ForwardingSegment(new SpatialValidatorImplementation());
}

/// <summary> Creates a WellKnownBinaryFormatter for this implementation.</summary>
/// <returns>The WellKnownBinaryFormatter created.</returns>
/// <param name="settings">Controls the writing settings.</param>
public override WellKnownBinaryFormatter CreateWellKnownBinaryFormatter(WellKnownBinaryWriterSettings settings)
{
return new WellKnownBinaryFormatterImplementation(this, settings);
}
}
}
20 changes: 19 additions & 1 deletion src/Microsoft.Spatial/PublicAPI/net8.0/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,19 @@

abstract Microsoft.Spatial.SpatialImplementation.CreateWellKnownBinaryFormatter(Microsoft.Spatial.WellKnownBinaryWriterSettings settings) -> Microsoft.Spatial.WellKnownBinaryFormatter
Microsoft.Spatial.ByteOrder
Microsoft.Spatial.ByteOrder.BigEndian = 0 -> Microsoft.Spatial.ByteOrder
Microsoft.Spatial.ByteOrder.LittleEndian = 1 -> Microsoft.Spatial.ByteOrder
Microsoft.Spatial.WellKnownBinaryFormatter
Microsoft.Spatial.WellKnownBinaryFormatter.WellKnownBinaryFormatter(Microsoft.Spatial.SpatialImplementation creator) -> void
Microsoft.Spatial.WellKnownBinaryWriterSettings
Microsoft.Spatial.WellKnownBinaryWriterSettings.HandleM.get -> bool
Microsoft.Spatial.WellKnownBinaryWriterSettings.HandleM.set -> void
Microsoft.Spatial.WellKnownBinaryWriterSettings.HandleSRID.get -> bool
Microsoft.Spatial.WellKnownBinaryWriterSettings.HandleSRID.set -> void
Microsoft.Spatial.WellKnownBinaryWriterSettings.HandleZ.get -> bool
Microsoft.Spatial.WellKnownBinaryWriterSettings.HandleZ.set -> void
Microsoft.Spatial.WellKnownBinaryWriterSettings.IsoWKB.get -> bool
Microsoft.Spatial.WellKnownBinaryWriterSettings.IsoWKB.set -> void
Microsoft.Spatial.WellKnownBinaryWriterSettings.Order.get -> Microsoft.Spatial.ByteOrder
Microsoft.Spatial.WellKnownBinaryWriterSettings.Order.set -> void
Microsoft.Spatial.WellKnownBinaryWriterSettings.WellKnownBinaryWriterSettings() -> void
static Microsoft.Spatial.WellKnownBinaryFormatter.Create(Microsoft.Spatial.WellKnownBinaryWriterSettings settings) -> Microsoft.Spatial.WellKnownBinaryFormatter
90 changes: 90 additions & 0 deletions src/Microsoft.Spatial/SRResources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions src/Microsoft.Spatial/SRResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,36 @@
<data name="WellKnownText_TooManyDimensions" xml:space="preserve">
<value>The WellKnownTextReader is configured to allow only two dimensions, and a third dimension was encountered.</value>
</data>
<data name="WellKnownBinary_NotSupportedSpatial" xml:space="preserve">
<value>The WKB writer: Spatial type "{0}" is not supported.</value>
</data>
<data name="WellKnownBinary_InvalidSubSpatial" xml:space="preserve">
<value>The WKB writer: Invalid to begin a "{0}" under "{1}", Details: "{2}".</value>
</data>
<data name="WellKnownBinary_InvalidBeginOrEndFigureOrAddLine" xml:space="preserve">
<value>The WKB writer: Invalid to "{0}" without specify the spatial type. Please call BeginGeometry(), or beginGeography() first.</value>
</data>
<data name="WellKnownBinary_InvalidBeginFigureOnSpatial" xml:space="preserve">
<value>The WKB writer: Invalid to begin a figure for spatial type "{0}".</value>
</data>
<data name="WellKnownBinary_InvalidBeginFigureWithoutEndingPrevious" xml:space="preserve">
<value>The WKB writer: Invalid to begin a new figure "{0}" without ending the previou figure.</value>
</data>
<data name="WellKnownBinary_InvalidAddLineTo" xml:space="preserve">
<value>The WKB writer: Invalid to AddLineTo for "{0}".{1}</value>
</data>
<data name="WellKnownBinary_InvalidEndFigure" xml:space="preserve">
<value>The WKB writer: Invalid to end figure on "{0}".{1}</value>
</data>
<data name="WellKnownBinary_InvalidEndGeo" xml:space="preserve">
<value>The WKB writer: Invalid to end spatial type "{0}".{1}</value>
</data>
<data name="WellKnownBinary_ByteLengthNotEnough" xml:space="preserve">
<value>The WKB reader is reading a "{0}" value with "{1}" bytes expected but only get "{2}" bytes.</value>
</data>
<data name="WellKnownBinary_UnknownByteOrder" xml:space="preserve">
<value>The WKB reader: the byte order '{0}' is unknown. It should be 0x00 (BigEndian) and 0x01 (LittleEndian).</value>
</data>
<data name="Validator_SridMismatch" xml:space="preserve">
<value>Invalid spatial data: An instance of spatial type can have only one unique CoordinateSystem for all of its coordinates.</value>
</data>
Expand Down
5 changes: 5 additions & 0 deletions src/Microsoft.Spatial/Spatial/SpatialImplementation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,11 @@ public abstract SpatialOperations Operations
/// <param name="allowOnlyTwoDimensions">Controls the writing and reading of the Z and M dimension.</param>
public abstract WellKnownTextSqlFormatter CreateWellKnownTextSqlFormatter(bool allowOnlyTwoDimensions);

/// <summary> Creates a WellKnownBinaryFormatter for this implementation.</summary>
/// <returns>The WellKnownBinaryFormatter created.</returns>
/// <param name="settings">Controls the writing settings.</param>
public abstract WellKnownBinaryFormatter CreateWellKnownBinaryFormatter(WellKnownBinaryWriterSettings settings);

/// <summary> Creates a spatial Validator.</summary>
/// <returns>The SpatialValidator created.</returns>
public abstract SpatialPipeline CreateValidator();
Expand Down
147 changes: 147 additions & 0 deletions src/Microsoft.Spatial/WellKnown/BinaryFormatterExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
//---------------------------------------------------------------------
// <copyright file="BinaryFormatterExtensions.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------

namespace Microsoft.Spatial
{
using System;
using System.Buffers.Binary;
using System.IO;

internal static class BinaryFormatterExtensions
{
/// <summary>
/// Writes the double value based on the byte order setting.
/// </summary>
/// <param name="writer">The binary writer.</param>
/// <param name="value">The double value.</param>
/// <param name="order">The byte order.</param>
public static void Write(this BinaryWriter writer, double value, ByteOrder order)
{
Span<byte> buffer = stackalloc byte[8];
if (order == ByteOrder.LittleEndian)
{
BinaryPrimitives.WriteDoubleLittleEndian(buffer, value);
}
else
{
BinaryPrimitives.WriteDoubleBigEndian(buffer, value);
}

writer.Write(buffer);
}

/// <summary>
/// Writes the uint value based on the byte order setting.
/// </summary>
/// <param name="writer">The binary writer.</param>
/// <param name="value">The uint value.</param>
/// <param name="order">The byte order.</param>
public static void Write(this BinaryWriter writer, uint value, ByteOrder order)
{
Span<byte> buffer = stackalloc byte[4];
if (order == ByteOrder.LittleEndian)
{
BinaryPrimitives.WriteUInt32LittleEndian(buffer, value);
}
else
{
BinaryPrimitives.WriteUInt32BigEndian(buffer, value);
}

writer.Write(buffer);
}

/// <summary>
/// Writes the int value based on the byte order setting.
/// </summary>
/// <param name="writer">The binary writer.</param>
/// <param name="value">The int value.</param>
/// <param name="order">The byte order.</param>
public static void Write(this BinaryWriter writer, int value, ByteOrder order)
{
Span<byte> buffer = stackalloc byte[4];
if (order == ByteOrder.LittleEndian)
{
BinaryPrimitives.WriteInt32LittleEndian(buffer, value);
}
else
{
BinaryPrimitives.WriteInt32BigEndian(buffer, value);
}

writer.Write(buffer);
}

/// <summary>
/// Reads the uint value from reader based on the byte order setting.
/// </summary>
/// <param name="reader">The binary reader.</param>
/// <param name="order">The byte order.</param>
/// <returns>The uint value read from the reader.</returns>
public static uint ReadUInt32(this BinaryReader reader, ByteOrder order)
{
Span<byte> buffer = stackalloc byte[4];
int num = reader.Read(buffer);
if (num != 4)
{
throw new FormatException(Error.Format(SRResources.WellKnownBinary_ByteLengthNotEnough, "UInt32", 4, num));
}

if (order == ByteOrder.LittleEndian)
{
return BinaryPrimitives.ReadUInt32LittleEndian(buffer);
}

return BinaryPrimitives.ReadUInt32BigEndian(buffer);
}

/// <summary>
/// Reads the int value from reader based on the byte order setting.
/// </summary>
/// <param name="reader">The binary reader.</param>
/// <param name="order">The byte order.</param>
/// <returns>The int value read from the reader.</returns>
public static int ReadInt32(this BinaryReader reader, ByteOrder order)
{
Span<byte> buffer = stackalloc byte[4];
int num = reader.Read(buffer);
if (num != 4)
{
throw new FormatException(Error.Format(SRResources.WellKnownBinary_ByteLengthNotEnough, "Int32", 4, num));
}

if (order == ByteOrder.LittleEndian)
{
return BinaryPrimitives.ReadInt32LittleEndian(buffer);
}

return BinaryPrimitives.ReadInt32BigEndian(buffer);
}

/// <summary>
/// Reads the double value from reader based on the byte order setting.
/// </summary>
/// <param name="reader">The binary reader.</param>
/// <param name="order">The byte order.</param>
/// <returns>The double value read from the reader.</returns>
public static double ReadDouble(this BinaryReader reader, ByteOrder order)
{
Span<byte> buffer = stackalloc byte[8];
int num = reader.Read(buffer);
if (num != 8)
{
throw new FormatException(Error.Format(SRResources.WellKnownBinary_ByteLengthNotEnough, "Double", 8, num));
}

if (order == ByteOrder.LittleEndian)
{
return BinaryPrimitives.ReadDoubleLittleEndian(buffer);
}

return BinaryPrimitives.ReadDoubleBigEndian(buffer);
}
}
}
24 changes: 24 additions & 0 deletions src/Microsoft.Spatial/WellKnown/ByteOrder.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//---------------------------------------------------------------------
// <copyright file="ByteOrder.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------

namespace Microsoft.Spatial
{
/// <summary>
/// Byte order
/// </summary>
public enum ByteOrder
{
/// <summary>
/// Big Endian
/// </summary>
BigEndian = 0x00,

/// <summary>
/// Little Endian
/// </summary>
LittleEndian = 0x01,
}
}
32 changes: 32 additions & 0 deletions src/Microsoft.Spatial/WellKnown/WellKnownBinaryFormatter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//---------------------------------------------------------------------
// <copyright file="WellKnownBinaryFormatter.cs" company="Microsoft">
// Copyright (C) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
// </copyright>
//---------------------------------------------------------------------

namespace Microsoft.Spatial
{
using System.IO;

/// <summary>
/// The object to move spatial types to and from the WellKnownBinary format
/// </summary>
public abstract class WellKnownBinaryFormatter : SpatialFormatter<Stream, Stream>
{
/// <summary>
/// Initializes a new instance of the <see cref="WellKnownBinaryFormatter"/> class.
/// </summary>
/// <param name="creator">The implementation that created this instance.</param>
protected WellKnownBinaryFormatter(SpatialImplementation creator)
: base(creator)
{
}

/// <summary>
/// Creates the implementation of the formatter.
/// </summary>
/// <returns>Returns the created <see cref="WellKnownBinaryFormatter"> implementation.</returns>
public static WellKnownBinaryFormatter Create(WellKnownBinaryWriterSettings settings)
=> SpatialImplementation.CurrentImplementation.CreateWellKnownBinaryFormatter(settings);
}
}
Loading

0 comments on commit b31e87c

Please sign in to comment.