Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/Benchmarks/ReadBenchmark/SingleThreadComparison.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public void Setup()
_xml = KbinConverter.ReadXml(_kbin);
_xmlStr = _linq.ToString();
}

[Benchmark(Baseline = true)]
public object? ReadRawStream()
{
Expand Down
6 changes: 1 addition & 5 deletions src/Benchmarks/V2Benchmarks/MultiThreadUtils.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading;

namespace ReadBenchmark
namespace ReadBenchmark
{
internal static class MultiThreadUtils
{
Expand Down
1 change: 0 additions & 1 deletion src/KbinXml.Net/Internal/Providers/XDocumentProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml.Linq;
using KbinXml.Net.Utils;

namespace KbinXml.Net.Internal.Providers;

Expand Down
1 change: 0 additions & 1 deletion src/KbinXml.Net/Internal/Providers/XmlDocumentProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml;
using KbinXml.Net.Utils;

namespace KbinXml.Net.Internal.Providers;

Expand Down
1 change: 0 additions & 1 deletion src/KbinXml.Net/Internal/Providers/XmlWriterProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Runtime.CompilerServices;
using System.Text;
using System.Xml;
using KbinXml.Net.Utils;

namespace KbinXml.Net.Internal.Providers;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public int WriteString(ref ValueListBuilder<byte> builder, ReadOnlySpan<char> st
{
throw new NotSupportedException("Binary data should not be written as string.");
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(ReadOnlySpan<byte> span)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public int WriteString(ref ValueListBuilder<byte> builder, ReadOnlySpan<char> st
{
throw new NotSupportedException("String data should not be written as string.");
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(ReadOnlySpan<byte> span)
{
Expand Down
2 changes: 1 addition & 1 deletion src/KbinXml.Net/Internal/TypeConverters/FloatConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public int WriteString(ref ValueListBuilder<byte> builder, ReadOnlySpan<char> st
return BitConverterHelper.WriteBeBytes(ref builder, ParseHelper.ParseSingle(str, ConvertHelper.UsNumberFormat));
// 返回 4(大端字节序写入 4 个字节)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(ReadOnlySpan<byte> span)
{
Expand Down
2 changes: 1 addition & 1 deletion src/KbinXml.Net/Internal/TypeConverters/S16Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public int WriteString(ref ValueListBuilder<byte> builder, ReadOnlySpan<char> st
return BitConverterHelper.WriteBeBytes(ref builder, ParseHelper.ParseInt16(str));
// 返回 2(大端字节序写入 2 个字节)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(ReadOnlySpan<byte> span)
{
Expand Down
2 changes: 1 addition & 1 deletion src/KbinXml.Net/Internal/TypeConverters/S64Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public int WriteString(ref ValueListBuilder<byte> builder, ReadOnlySpan<char> st
return BitConverterHelper.WriteBeBytes(ref builder, ParseHelper.ParseInt64(str));
// 返回 8(大端字节序写入 8 个字节)
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(ReadOnlySpan<byte> span)
{
Expand Down
2 changes: 1 addition & 1 deletion src/KbinXml.Net/Internal/TypeConverters/U8Converter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public int WriteString(ref ValueListBuilder<byte> builder, ReadOnlySpan<char> st
builder.Append(ParseHelper.ParseByte(str, numberStyle));
return 1; // 写入 1 个字节
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public string ToString(ReadOnlySpan<byte> span)
{
Expand Down
52 changes: 51 additions & 1 deletion src/KbinXml.Net/Internal/ValueReadResult.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
namespace KbinXml.Net.Internal;
using System.Diagnostics;

namespace KbinXml.Net.Internal;

[DebuggerDisplay("{ToDebuggerDisplay}")]
internal readonly ref struct ValueReadResult<T>
{
public readonly T Value;
Expand All @@ -18,4 +21,51 @@
ReadStatus = readStatus;
#endif
}

public string ToDebuggerDisplay
{
get
{
if (Value is byte b)
return b.ToString("X2");
if (Value is short @short)
{
return @short.ToString("X4");
}
if (Value is int @int)
{
return @int.ToString("X8");
}
if (Value is long @long)
{
return @long.ToString("X16");
}
if (Value is sbyte sb)
{
return sb.ToString("X2");
}
if (Value is ushort us)
{
return us.ToString("X4");
}
if (Value is uint ui)
{
return ui.ToString("X8");
}
if (Value is ulong ul)
{
return ul.ToString("X16");
}
if (Value is float f)
{
return f.ToString("F");
}
if (Value is double d)
{
return d.ToString("F");
}

return Value.ToString();

Check warning on line 68 in src/KbinXml.Net/Internal/ValueReadResult.cs

View workflow job for this annotation

GitHub Actions / Build and Release

Possible null reference return.

Check warning on line 68 in src/KbinXml.Net/Internal/ValueReadResult.cs

View workflow job for this annotation

GitHub Actions / Build and Release

Dereference of a possibly null reference.
}
}
}
3 changes: 1 addition & 2 deletions src/KbinXml.Net/Internal/Writers/DataWriter.Base.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Runtime.CompilerServices;
using KbinXml.Net.Utils;

namespace KbinXml.Net.Internal.Writers;
Expand Down
93 changes: 93 additions & 0 deletions src/KbinXml.Net/KbinConverter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System;
using System.Buffers;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using KbinXml.Net.Internal;
Expand Down Expand Up @@ -81,4 +83,95 @@ private static bool IsDigit(char c)
{
return c is >= '0' and <= '9';
}

/// <summary>
/// Determines whether the specified byte array represents a valid KBin format.
/// </summary>
/// <param name="buffer">The byte array to check.</param>
/// <returns>
/// <c>true</c> if the buffer contains valid KBin format data; otherwise, <c>false</c>.
/// </returns>
/// <remarks>
/// This method checks the KBin file signature and header structure to determine validity.
/// It verifies:
/// <list type="bullet">
/// <item><description>The signature byte (0xA0)</description></item>
/// <item><description>The encoding flag and its inverse relationship</description></item>
/// <item><description>Minimum required buffer length</description></item>
/// </list>
/// </remarks>
public static bool IsKbinFormat(byte[] buffer)
{
if (buffer == null)
return false;

return IsKbinFormat(buffer.AsSpan());
}

/// <summary>
/// Determines whether the specified span represents a valid KBin format.
/// </summary>
/// <param name="buffer">The span to check.</param>
/// <returns>
/// <c>true</c> if the buffer contains valid KBin format data; otherwise, <c>false</c>.
/// </returns>
/// <inheritdoc cref="IsKbinFormat(byte[])"/>
public static bool IsKbinFormat(ReadOnlySpan<byte> buffer)
{
// kbin format requires at least 4 bytes for the header
if (buffer.Length < 4)
return false;

// Check signature (first byte must be 0xA0)
if (buffer[0] != 0xA0)
return false;

// Get encoding flag and its inverse
var encodingFlag = buffer[2];
var encodingFlagNot = buffer[3];

// Encoding flag should be an inverse of the fourth byte
if ((byte)~encodingFlag != encodingFlagNot)
return false;

return true;
}

/// <summary>
/// Determines whether the specified stream contains valid KBin format data.
/// </summary>
/// <param name="stream">The stream to check. The stream position will be restored after checking.</param>
/// <returns>
/// <c>true</c> if the stream contains valid KBin format data; otherwise, <c>false</c>.
/// </returns>
/// <exception cref="ArgumentNullException"><paramref name="stream"/> is null.</exception>
/// <exception cref="NotSupportedException">The stream does not support seeking.</exception>
/// <inheritdoc cref="IsKbinFormat(byte[])"/>
public static bool IsKbinFormat(Stream stream)
{
if (stream == null)
throw new ArgumentNullException(nameof(stream));

if (!stream.CanSeek)
throw new NotSupportedException("Stream must support seeking to check KBin format.");

var originalPosition = stream.Position;
var buffer = ArrayPool<byte>.Shared.Rent(4);
try
{
// Read the first 4 bytes for header validation
var bytesRead = stream.Read(buffer, 0, 4);

if (bytesRead < 4)
return false;

return IsKbinFormat(buffer.AsSpan(0, 4));
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
// Restore original position
stream.Position = originalPosition;
}
}
}
4 changes: 2 additions & 2 deletions src/KbinXml.Net/WriteOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,15 @@ public class WriteOptions
/// The default value is <see langword="true"/> (strict validation enabled).
/// </value>
public bool StrictMode { get; set; } = true;

/// <summary>
/// Gets or sets a value indicating whether XML output should be compressed using SixBit algorithm.
/// </summary>
/// <value>
/// The default value is <see langword="true"/> (compression enabled).
/// </value>
public bool Compress { get; set; } = true;

/// <summary>
/// Gets or sets the prefix used to repair invalid XML element names during serialization. (e.g.: Names which start with numbers).
/// When set to a non-null value, invalid names will be prefixed with this string.
Expand Down
Loading
Loading