Initial commit
This commit is contained in:
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* Copyright 2016 The Cartographer Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace CartographerSharp.IO;
|
||||
|
||||
/// <summary>
|
||||
/// A simple writer of a compressed sequence of protocol buffer messages to a file.
|
||||
/// The format is not intended to be compatible with any other format used outside of Cartographer.
|
||||
/// </summary>
|
||||
public class ProtoStreamWriter : IProtoStreamWriter, IDisposable
|
||||
{
|
||||
// First eight bytes to identify our proto stream format.
|
||||
private const ulong Magic = 0x7b1d1f7b5bf501db;
|
||||
|
||||
private static readonly JsonSerializerOptions JsonOptions = new()
|
||||
{
|
||||
WriteIndented = false,
|
||||
DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.Never
|
||||
};
|
||||
|
||||
private readonly FileStream _fileStream;
|
||||
private bool _disposed;
|
||||
private bool _magicWritten;
|
||||
|
||||
public ProtoStreamWriter(string filename)
|
||||
{
|
||||
if (string.IsNullOrEmpty(filename))
|
||||
throw new ArgumentException("Filename cannot be null or empty", nameof(filename));
|
||||
|
||||
_fileStream = new FileStream(filename, FileMode.Create, FileAccess.Write, FileShare.Read);
|
||||
WriteMagic();
|
||||
}
|
||||
|
||||
private void WriteMagic()
|
||||
{
|
||||
WriteSizeAsLittleEndian(Magic);
|
||||
_magicWritten = true;
|
||||
}
|
||||
|
||||
private void WriteSizeAsLittleEndian(ulong size)
|
||||
{
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
_fileStream.WriteByte((byte)(size & 0xff));
|
||||
size >>= 8;
|
||||
}
|
||||
}
|
||||
|
||||
private void Write(string uncompressedData)
|
||||
{
|
||||
if (!_magicWritten)
|
||||
{
|
||||
WriteMagic();
|
||||
}
|
||||
|
||||
// Compress using GZip
|
||||
byte[] uncompressedBytes = Encoding.UTF8.GetBytes(uncompressedData);
|
||||
byte[] compressedBytes;
|
||||
|
||||
using (var memoryStream = new MemoryStream())
|
||||
{
|
||||
using (var gzipStream = new GZipStream(memoryStream, CompressionMode.Compress, leaveOpen: true))
|
||||
{
|
||||
gzipStream.Write(uncompressedBytes, 0, uncompressedBytes.Length);
|
||||
}
|
||||
compressedBytes = memoryStream.ToArray();
|
||||
}
|
||||
|
||||
// Write compressed size
|
||||
WriteSizeAsLittleEndian((ulong)compressedBytes.Length);
|
||||
|
||||
// Write compressed data
|
||||
_fileStream.Write(compressedBytes, 0, compressedBytes.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Serializes, compresses and writes the proto to the file.
|
||||
/// </summary>
|
||||
public void WriteProto<T>(T proto)
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(proto, nameof(proto));
|
||||
|
||||
// Serialize to JSON (we use System.Text.Json instead of Google.Protobuf)
|
||||
string json = JsonSerializer.Serialize(proto, JsonOptions);
|
||||
|
||||
Write(json);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This should be called to check whether writing was successful.
|
||||
/// </summary>
|
||||
public bool Close()
|
||||
{
|
||||
if (_disposed)
|
||||
return false;
|
||||
|
||||
_fileStream.Flush();
|
||||
_fileStream.Close();
|
||||
_disposed = true; // Prevent Dispose() from calling Close() again (double-close would throw on Flush)
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!_disposed)
|
||||
{
|
||||
Close();
|
||||
_fileStream?.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user