Initial commit

This commit is contained in:
2026-07-03 16:31:37 +07:00
commit 899c7c637d
1939 changed files with 641750 additions and 0 deletions

View File

@@ -0,0 +1,158 @@
/*
* 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 reader of the format produced by ProtoStreamWriter.
/// </summary>
public class ProtoStreamReader : IProtoStreamReader, IDisposable
{
// First eight bytes to identify our proto stream format.
private const ulong Magic = 0x7b1d1f7b5bf501db;
private static readonly JsonSerializerOptions JsonOptions = new()
{
PropertyNameCaseInsensitive = true
};
private readonly FileStream _fileStream;
private bool _disposed;
private bool _magicRead;
public ProtoStreamReader(string filename)
{
if (string.IsNullOrEmpty(filename))
throw new ArgumentException("Filename cannot be null or empty", nameof(filename));
if (!File.Exists(filename))
throw new FileNotFoundException($"File not found: {filename}", filename);
_fileStream = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
ReadMagic();
}
private void ReadMagic()
{
ulong magic = ReadSizeAsLittleEndian();
if (magic != Magic)
{
throw new InvalidDataException($"Invalid proto stream format. Expected magic: 0x{Magic:X16}, got: 0x{magic:X16}");
}
_magicRead = true;
}
private ulong ReadSizeAsLittleEndian()
{
ulong size = 0;
for (int i = 0; i < 8; i++)
{
int byteValue = _fileStream.ReadByte();
if (byteValue == -1)
throw new EndOfStreamException("Unexpected end of stream while reading size");
size >>= 8;
size += (ulong)byteValue << 56;
}
return size;
}
private bool Read(out string decompressedData)
{
decompressedData = string.Empty;
if (!_magicRead)
{
ReadMagic();
}
if (_fileStream.Position >= _fileStream.Length)
{
return false; // EOF
}
// Read compressed size
ulong compressedSize = ReadSizeAsLittleEndian();
if (compressedSize == 0 || compressedSize > int.MaxValue)
{
return false;
}
// Read compressed data
byte[] compressedBytes = new byte[compressedSize];
int bytesRead = _fileStream.Read(compressedBytes, 0, (int)compressedSize);
if (bytesRead != (int)compressedSize)
{
return false;
}
// Decompress using GZip
using var memoryStream = new MemoryStream(compressedBytes);
using var gzipStream = new GZipStream(memoryStream, CompressionMode.Decompress);
using var reader = new StreamReader(gzipStream, Encoding.UTF8);
decompressedData = reader.ReadToEnd();
return true;
}
/// <summary>
/// Deserializes compressed proto from the pb stream.
/// </summary>
public bool ReadProto<T>(out T? proto)
{
proto = default;
if (!Read(out string decompressedData))
{
return false;
}
try
{
proto = JsonSerializer.Deserialize<T>(decompressedData, JsonOptions);
return proto != null && !EqualityComparer<T>.Default.Equals(proto, default);
}
catch (JsonException)
{
proto = default;
return false;
}
}
/// <summary>
/// 'End-of-file' marker for the pb stream.
/// </summary>
public bool Eof => _fileStream.Position >= _fileStream.Length;
public void Dispose()
{
if (!_disposed)
{
_fileStream?.Dispose();
_disposed = true;
}
GC.SuppressFinalize(this);
}
}