InteractiveComputer/Core/ComputerSandboxStorage.cs
using System;
using System.Text;
#if PANEOS_UNIT_TESTS
#else
using Sandbox;
#endif
namespace PaneOS.InteractiveComputer.Core;
internal static class ComputerSandboxStorage
{
public static string ResolveArchiveStoragePath( string computerId, string? configuredPath )
{
if ( !string.IsNullOrWhiteSpace( configuredPath ) )
{
if ( IsSandboxRelativePath( configuredPath ) )
return NormalizePath( configuredPath );
return $"/paneos/imported/{EncodeOpaqueName( configuredPath )}.datc";
}
return $"/paneos/saves/{SanitizeSegment( computerId )}.datc";
}
public static string ResolveArchiveUserNameStoragePath( string archivePath )
{
return $"{NormalizePath( archivePath )}.user.txt";
}
public static bool FileExists( string path )
{
#if PANEOS_UNIT_TESTS
#else
return FileSystem.Data.FileExists( NormalizePath( path ) );
#endif
}
public static byte[] ReadAllBytes( string path )
{
#if PANEOS_UNIT_TESTS
#else
var normalizedPath = NormalizePath( path );
return FileSystem.Data.FileExists( normalizedPath ) ? FileSystem.Data.ReadAllBytes( normalizedPath ).ToArray() : Array.Empty<byte>();
#endif
}
public static void WriteAllBytes( string path, byte[] bytes )
{
#if PANEOS_UNIT_TESTS
#else
var normalizedPath = NormalizePath( path );
EnsureParentDirectory( normalizedPath );
FileSystem.Data.WriteAllBytes( normalizedPath, bytes );
#endif
}
public static string ReadAllText( string path )
{
#if PANEOS_UNIT_TESTS
#else
var normalizedPath = NormalizePath( path );
return FileSystem.Data.FileExists( normalizedPath ) ? FileSystem.Data.ReadAllText( normalizedPath ) : "";
#endif
}
public static void WriteAllText( string path, string content )
{
#if PANEOS_UNIT_TESTS
#else
var normalizedPath = NormalizePath( path );
EnsureParentDirectory( normalizedPath );
FileSystem.Data.WriteAllText( normalizedPath, content );
#endif
}
public static string GetLocalUserNameFallback()
{
#if PANEOS_UNIT_TESTS
#else
return Sandbox.Utility.Steam.PersonaName ?? "";
#endif
}
#if !PANEOS_UNIT_TESTS
private static void EnsureParentDirectory( string normalizedPath )
{
var lastSlash = normalizedPath.LastIndexOf( '/' );
if ( lastSlash <= 0 )
return;
FileSystem.Data.CreateDirectory( normalizedPath[..lastSlash] );
}
#endif
private static string NormalizePath( string path )
{
var normalized = path.Replace( '\\', '/' ).Trim();
if ( string.IsNullOrWhiteSpace( normalized ) )
return "/paneos/saves/default.datc";
if ( !normalized.StartsWith( "/", StringComparison.Ordinal ) )
normalized = "/" + normalized.TrimStart( '/' );
return normalized;
}
private static bool IsSandboxRelativePath( string configuredPath )
{
return configuredPath.StartsWith( "/", StringComparison.Ordinal ) &&
!configuredPath.Contains( ":", StringComparison.Ordinal );
}
private static string SanitizeSegment( string value )
{
var source = string.IsNullOrWhiteSpace( value ) ? "computer" : value.Trim();
var builder = new StringBuilder( source.Length );
foreach ( var character in source )
{
builder.Append( char.IsLetterOrDigit( character ) || character is '-' or '_' ? character : '_' );
}
return builder.Length == 0 ? "computer" : builder.ToString();
}
private static string EncodeOpaqueName( string value )
{
var bytes = Encoding.UTF8.GetBytes( value.Trim() );
var builder = new StringBuilder( bytes.Length * 2 );
foreach ( var currentByte in bytes )
builder.Append( currentByte.ToString( "x2" ) );
return builder.ToString();
}
#if PANEOS_UNIT_TESTS
#endif
}