Merge branch 'v2' into HEAD
39
.gitignore
vendored
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
*/bin/*
|
||||||
|
*/obj/*
|
||||||
|
.vs/*
|
||||||
|
*.7z
|
||||||
|
*.pdn
|
||||||
|
*.user
|
||||||
|
*launchSettings.json
|
||||||
|
*Thumbs.db
|
||||||
|
|
||||||
|
PbpResign/bin/*
|
||||||
|
PbpResign/obj/*
|
||||||
|
|
||||||
|
ChovySign-CLI/bin/*
|
||||||
|
ChovySign-CLI/obj/*
|
||||||
|
|
||||||
|
ChovySign-GUI/bin/*
|
||||||
|
ChovySign-GUI/obj/*
|
||||||
|
|
||||||
|
|
||||||
|
DiscUtils/bin/*
|
||||||
|
DiscUtils/obj/*
|
||||||
|
|
||||||
|
GameBuilder/bin/*
|
||||||
|
GameBuilder/obj/*
|
||||||
|
|
||||||
|
PspCrypto/bin/*
|
||||||
|
PspCrypto/obj/*
|
||||||
|
|
||||||
|
LibChovy/bin/*
|
||||||
|
LibChovy/obj/*
|
||||||
|
|
||||||
|
LiLib/bin/*
|
||||||
|
LiLib/obj/*
|
||||||
|
|
||||||
|
Vita/bin/*
|
||||||
|
Vita/obj/*
|
||||||
|
|
||||||
|
UnicornTest/*
|
||||||
|
UnicornManaged/*
|
16
ChovySign-CLI/ChovySign-CLI.csproj
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RootNamespace>ChovySign_CLI</RootNamespace>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\GameBuilder\GameBuilder.csproj" />
|
||||||
|
<ProjectReference Include="..\LibChovy\LibChovy.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
6
ChovySign-CLI/ChovySign-CLI.csproj.user
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<PropertyGroup>
|
||||||
|
<_LastSelectedProfileId>C:\Users\Li\Documents\git\Chovy-Sign-v2\ChovySign-CLI\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
310
ChovySign-CLI/Program.cs
Normal file
|
@ -0,0 +1,310 @@
|
||||||
|
using Li.Progress;
|
||||||
|
using GameBuilder.Pops;
|
||||||
|
using GameBuilder.Psp;
|
||||||
|
using LibChovy;
|
||||||
|
using LibChovy.VersionKey;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace ChovySign_CLI
|
||||||
|
{
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
private static ArgumentParsingMode mode = ArgumentParsingMode.ARG;
|
||||||
|
private static List<string> parameters = new List<string>();
|
||||||
|
private static string[] discs;
|
||||||
|
private static bool pspCompress = false;
|
||||||
|
private static bool devKit = false;
|
||||||
|
private static string? popsDiscName;
|
||||||
|
private static string? popsIcon0File;
|
||||||
|
private static string? popsPic0File;
|
||||||
|
private static PbpMode? pbpMode = null;
|
||||||
|
private static NpDrmRif? rifFile = null;
|
||||||
|
private static NpDrmInfo? drmInfo = null;
|
||||||
|
|
||||||
|
private static byte[]? actDat = null;
|
||||||
|
private static byte[]? idps = null;
|
||||||
|
private static string? rifFolder = null;
|
||||||
|
enum PbpMode
|
||||||
|
{
|
||||||
|
PSP = 0,
|
||||||
|
POPS = 1,
|
||||||
|
PCENGINE = 2,
|
||||||
|
NEOGEO = 3
|
||||||
|
}
|
||||||
|
enum ArgumentParsingMode
|
||||||
|
{
|
||||||
|
ARG = 0,
|
||||||
|
POPS_DISC = 1,
|
||||||
|
PSP_UMD = 2,
|
||||||
|
VERSIONKEY = 3,
|
||||||
|
VERSIONKEY_EXTRACT = 4,
|
||||||
|
VERSIONKEY_GENERATOR = 5,
|
||||||
|
POPS_INFO = 6,
|
||||||
|
KEYS_TXT_GEN = 7,
|
||||||
|
RIF = 8
|
||||||
|
}
|
||||||
|
public static int Error(string errorMsg, int ret)
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("ERROR: "+errorMsg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
public static byte[] StringToByteArray(string hex)
|
||||||
|
{
|
||||||
|
return Enumerable.Range(0, hex.Length).Where(x => x % 2 == 0).Select(x => Convert.ToByte(hex.Substring(x, 2), 16)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void onProgress(ProgressInfo info)
|
||||||
|
{
|
||||||
|
string msg = info.CurrentProcess + " " + info.ProgressInt.ToString() + "% (" + info.Done + "/" + info.Remain + ")";
|
||||||
|
int spaceLen = (Console.WindowWidth - msg.Length) - 2;
|
||||||
|
string emptySpace = " ";
|
||||||
|
for (int i = 0; i < spaceLen; i++)
|
||||||
|
emptySpace += " ";
|
||||||
|
Console.Write(msg + emptySpace + "\r");
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void generateKeysTxt()
|
||||||
|
{
|
||||||
|
if (rifFolder is null || actDat is null || idps is null) return;
|
||||||
|
UInt64 accountId = BitConverter.ToUInt64(actDat, 0x8);
|
||||||
|
|
||||||
|
if (File.Exists("KEYS.TXT"))
|
||||||
|
KeysTxtMethod.KeysTxt = File.ReadAllText("KEYS.TXT");
|
||||||
|
else
|
||||||
|
File.WriteAllText("KEYS.TXT", KeysTxtMethod.KeysTxt);
|
||||||
|
|
||||||
|
HashSet<string> knownKeys = new HashSet<string>();
|
||||||
|
foreach (string contentId in KeysTxtMethod.ContentIds)
|
||||||
|
knownKeys.Add(contentId);
|
||||||
|
|
||||||
|
StringBuilder addKeys = new StringBuilder();
|
||||||
|
foreach (string rifFile in Directory.GetFiles(rifFolder, "*.rif"))
|
||||||
|
{
|
||||||
|
NpDrmRif rif = new NpDrmRif(File.ReadAllBytes(rifFile));
|
||||||
|
if (knownKeys.Contains(rif.ContentId)) continue;
|
||||||
|
|
||||||
|
if(rif.AccountId != accountId) { Error(rif.ContentId + " account id does not match: " + accountId.ToString("X") + " (was " + rif.AccountId.ToString("X") + ")", 10); continue; }
|
||||||
|
string[] keys = new string[4];
|
||||||
|
for (int i = 0; i < keys.Length; i++)
|
||||||
|
keys[i] = BitConverter.ToString(ActRifMethod.GetVersionKey(actDat, rif.Rif, idps, i).VersionKey).Replace("-", "");
|
||||||
|
|
||||||
|
string[] keysTxtLine = new string[] { rif.ContentId, keys[0], keys[1], keys[2], keys[3] };
|
||||||
|
string keysTxt = String.Join(' ', keysTxtLine);
|
||||||
|
|
||||||
|
addKeys.AppendLine(keysTxt);
|
||||||
|
Console.WriteLine(keysTxt);
|
||||||
|
}
|
||||||
|
File.AppendAllText("KEYS.TXT", addKeys.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int complete()
|
||||||
|
{
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case ArgumentParsingMode.POPS_DISC:
|
||||||
|
if (parameters.Count > 5) return Error("--pops: no more than 5 disc images allowed in a single game (sony's rules, not mine)", 5);
|
||||||
|
if (parameters.Count < 1) return Error("--pops: at least 1 disc image file is required.", 5);
|
||||||
|
discs = parameters.ToArray();
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.PSP_UMD:
|
||||||
|
if (parameters.Count < 1) return Error("--psp: a path to a disc image is required", 5);
|
||||||
|
if (parameters.Count > 2) return Error("--psp: no more than 2 arguments. ("+parameters.Count+" given)", 5);
|
||||||
|
discs = new string[1];
|
||||||
|
discs[0] = parameters[0];
|
||||||
|
|
||||||
|
if (parameters.Count > 1)
|
||||||
|
pspCompress = parameters[1].ToLowerInvariant() == "true";
|
||||||
|
else
|
||||||
|
pspCompress = false;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.VERSIONKEY:
|
||||||
|
if (parameters.Count != 3) return Error("--vkey: expect 3 arguments. ("+parameters.Count+" given)", 4);
|
||||||
|
drmInfo = new NpDrmInfo(StringToByteArray(parameters[0]), parameters[1], int.Parse(parameters[2]));
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.VERSIONKEY_EXTRACT:
|
||||||
|
if (parameters.Count != 1) return Error("--vkey-extract: expect 1 arguments. ("+parameters.Count+" given)", 4);
|
||||||
|
drmInfo = EbootPbpMethod.GetVersionKey(File.OpenRead(parameters[0]));
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.VERSIONKEY_GENERATOR:
|
||||||
|
if(parameters.Count != 4) return Error("--vkey-gen: expect 4 arguments. ("+parameters.Count+" given)", 4);
|
||||||
|
drmInfo = ActRifMethod.GetVersionKey(File.ReadAllBytes(parameters[0]), File.ReadAllBytes(parameters[1]), StringToByteArray(parameters[2]), int.Parse(parameters[3]));
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.POPS_INFO:
|
||||||
|
if (parameters.Count < 2) return Error("--pops-info takes at least 1 arguments ("+parameters.Count+" given)", 4);
|
||||||
|
if (parameters.Count > 3) return Error("--pops-info takes no more than 3 arguments("+parameters.Count+" given)", 4);
|
||||||
|
popsDiscName = parameters[0];
|
||||||
|
if (parameters.Count > 1)
|
||||||
|
popsIcon0File = parameters[1];
|
||||||
|
if (parameters.Count > 2)
|
||||||
|
popsPic0File = parameters[2];
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.KEYS_TXT_GEN:
|
||||||
|
if (parameters.Count != 3) return Error("--keys-txt-gen takes 3 arguments, (" + parameters.Count + " given)", 4);
|
||||||
|
actDat = File.ReadAllBytes(parameters[0]);
|
||||||
|
idps = StringToByteArray(parameters[1]);
|
||||||
|
rifFolder = parameters[2];
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.RIF:
|
||||||
|
if (parameters.Count != 1) return Error("--rif expects only 1 argument,", 4);
|
||||||
|
rifFile = new NpDrmRif(File.ReadAllBytes(parameters[0]));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
mode = ArgumentParsingMode.ARG;
|
||||||
|
parameters.Clear();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (args.Length == 0)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Chovy-Sign v2 (CLI)");
|
||||||
|
Console.WriteLine("--pops [disc1.cue] [disc2.cue] [disc3.cue] ... (up to 5)");
|
||||||
|
Console.WriteLine("--pops-info [game title] [icon0.png] (optional) [pic1.png] (optional)");
|
||||||
|
Console.WriteLine("--psp [umd.iso] [compress; true/false] (optional)");
|
||||||
|
Console.WriteLine("--rif [GAME.RIF]");
|
||||||
|
Console.WriteLine("--devkit (Use 000000000000 account id)");
|
||||||
|
Console.WriteLine("--vkey [versionkey] [contentid] [key_index]");
|
||||||
|
Console.WriteLine("--vkey-extract [eboot.pbp]");
|
||||||
|
Console.WriteLine("--vkey-gen [act.dat] [license.rif] [console_id] [key_index]");
|
||||||
|
Console.WriteLine("--keys-txt-gen [act.dat] [console_id] [psp_license_folder]");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
foreach (string arg in args)
|
||||||
|
{
|
||||||
|
if (arg.StartsWith("--")) { int ret = complete(); if (ret != 0) return ret; }
|
||||||
|
|
||||||
|
switch (mode)
|
||||||
|
{
|
||||||
|
case ArgumentParsingMode.ARG:
|
||||||
|
switch (arg)
|
||||||
|
{
|
||||||
|
case "--pops":
|
||||||
|
mode = ArgumentParsingMode.POPS_DISC;
|
||||||
|
|
||||||
|
if (pbpMode is not null)
|
||||||
|
return Error("pbpMode is already set to: " + pbpMode.ToString() + " cannot do that *and* POPS", 2);
|
||||||
|
|
||||||
|
pbpMode = PbpMode.POPS;
|
||||||
|
break;
|
||||||
|
case "--pops-info":
|
||||||
|
mode = ArgumentParsingMode.POPS_INFO;
|
||||||
|
break;
|
||||||
|
case "--psp":
|
||||||
|
mode = ArgumentParsingMode.PSP_UMD;
|
||||||
|
|
||||||
|
if (pbpMode is not null)
|
||||||
|
return Error("pbpMode is already set to: " + pbpMode.ToString() + " cannot do that *and* PSP", 2);
|
||||||
|
|
||||||
|
pbpMode = PbpMode.PSP;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "--vkey":
|
||||||
|
mode = ArgumentParsingMode.VERSIONKEY;
|
||||||
|
|
||||||
|
if (drmInfo is not null)
|
||||||
|
return Error("versionkey is already set", 3);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "--vkey-extract":
|
||||||
|
mode = ArgumentParsingMode.VERSIONKEY_EXTRACT;
|
||||||
|
|
||||||
|
if (drmInfo is not null)
|
||||||
|
return Error("versionkey is already set", 3);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "--vkey-gen":
|
||||||
|
mode = ArgumentParsingMode.VERSIONKEY_GENERATOR;
|
||||||
|
|
||||||
|
if (drmInfo is not null)
|
||||||
|
return Error("versionkey is already set", 3);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "--keys-txt-gen":
|
||||||
|
mode = ArgumentParsingMode.KEYS_TXT_GEN;
|
||||||
|
|
||||||
|
if (rifFolder is not null)
|
||||||
|
return Error("rif folder already set", 3);
|
||||||
|
break;
|
||||||
|
case "--rif":
|
||||||
|
mode = ArgumentParsingMode.RIF;
|
||||||
|
|
||||||
|
if (rifFile is not null)
|
||||||
|
return Error("rif is already set", 3);
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "--devkit":
|
||||||
|
devKit = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return Error("Unknown argument: " + arg, 1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ArgumentParsingMode.VERSIONKEY:
|
||||||
|
case ArgumentParsingMode.VERSIONKEY_GENERATOR:
|
||||||
|
case ArgumentParsingMode.VERSIONKEY_EXTRACT:
|
||||||
|
case ArgumentParsingMode.PSP_UMD:
|
||||||
|
case ArgumentParsingMode.POPS_DISC:
|
||||||
|
case ArgumentParsingMode.POPS_INFO:
|
||||||
|
case ArgumentParsingMode.RIF:
|
||||||
|
default:
|
||||||
|
parameters.Add(arg);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int res = complete();
|
||||||
|
if(res != 0) return res;
|
||||||
|
|
||||||
|
generateKeysTxt();
|
||||||
|
|
||||||
|
if (drmInfo is null) return Error("no versionkey was found, exiting", 6);
|
||||||
|
|
||||||
|
//Console.WriteLine("Version Key: " + BitConverter.ToString(drmInfo.VersionKey).Replace("-", "") + ", " + drmInfo.KeyIndex);
|
||||||
|
|
||||||
|
if (pbpMode is null) return Error("no pbp mode was set, exiting", 7);
|
||||||
|
|
||||||
|
if (pbpMode == PbpMode.PSP && drmInfo.KeyIndex != 2)
|
||||||
|
return Error("KeyType is "+drmInfo.KeyIndex+", but PBP mode is PSP, you cant do that .. please use a type 1 versionkey.", 8);
|
||||||
|
|
||||||
|
if (pbpMode == PbpMode.POPS && drmInfo.KeyIndex != 1)
|
||||||
|
return Error("KeyType is " + drmInfo.KeyIndex + ", but PBP mode is POPS, you cant do that .. please use a type 1 versionkey.", 8);
|
||||||
|
|
||||||
|
if (rifFile is null)
|
||||||
|
return Error("Rif is not set, use --rif to specify base game RIF", 8);
|
||||||
|
//if (pbpMode == PbpMode.POPS && (popsDiscName is null || popsIcon0File is null)) return Error("pbp mode is POPS, but you have not specified a disc title or icon file using --pops-info.", 9);
|
||||||
|
ChovySign csign = new ChovySign();
|
||||||
|
csign.RegisterCallback(onProgress);
|
||||||
|
if (pbpMode == PbpMode.POPS)
|
||||||
|
{
|
||||||
|
PopsParameters popsParameters = new PopsParameters(drmInfo, rifFile);
|
||||||
|
|
||||||
|
foreach (string disc in discs)
|
||||||
|
popsParameters.AddCd(disc);
|
||||||
|
|
||||||
|
if(popsDiscName is not null)
|
||||||
|
popsParameters.Name = popsDiscName;
|
||||||
|
|
||||||
|
if(File.Exists(popsIcon0File))
|
||||||
|
popsParameters.Icon0 = File.ReadAllBytes(popsIcon0File);
|
||||||
|
|
||||||
|
popsParameters.Account.Devkit = devKit;
|
||||||
|
|
||||||
|
csign.Go(popsParameters);
|
||||||
|
|
||||||
|
}
|
||||||
|
else if(pbpMode == PbpMode.PSP)
|
||||||
|
{
|
||||||
|
PspParameters pspParameters = new PspParameters(drmInfo, rifFile);
|
||||||
|
pspParameters.Account.Devkit = devKit;
|
||||||
|
pspParameters.Compress = pspCompress;
|
||||||
|
pspParameters.Umd = new UmdInfo(discs.First());
|
||||||
|
|
||||||
|
csign.Go(pspParameters);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
|
-->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration>Release</Configuration>
|
||||||
|
<Platform>Any CPU</Platform>
|
||||||
|
<PublishDir>bin\Release\</PublishDir>
|
||||||
|
<PublishProtocol>FileSystem</PublishProtocol>
|
||||||
|
<_TargetId>Folder</_TargetId>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
|
||||||
|
<SelfContained>true</SelfContained>
|
||||||
|
<PublishSingleFile>true</PublishSingleFile>
|
||||||
|
<PublishReadyToRun>true</PublishReadyToRun>
|
||||||
|
<PublishTrimmed>true</PublishTrimmed>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!--
|
||||||
|
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||||
|
-->
|
||||||
|
<Project>
|
||||||
|
<PropertyGroup>
|
||||||
|
<History>True|2023-04-23T20:18:55.4774877Z;True|2023-04-20T08:33:00.3404616+12:00;False|2023-04-20T08:29:02.1306599+12:00;True|2023-04-19T21:53:45.1116925+12:00;True|2023-04-19T20:46:20.2756012+12:00;True|2023-04-19T19:58:40.3825010+12:00;True|2023-04-18T00:00:51.4131559+12:00;True|2023-04-17T09:56:35.5065135+12:00;True|2023-04-17T09:22:54.8607008+12:00;True|2023-04-17T08:27:16.5281469+12:00;True|2023-04-17T08:22:02.0531219+12:00;</History>
|
||||||
|
<LastFailureDetails />
|
||||||
|
</PropertyGroup>
|
||||||
|
</Project>
|
454
ChovySign-GUI/.gitignore
vendored
Normal file
|
@ -0,0 +1,454 @@
|
||||||
|
## Ignore Visual Studio temporary files, build results, and
|
||||||
|
## files generated by popular Visual Studio add-ons.
|
||||||
|
##
|
||||||
|
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||||
|
|
||||||
|
# User-specific files
|
||||||
|
*.rsuser
|
||||||
|
*.suo
|
||||||
|
*.user
|
||||||
|
*.userosscache
|
||||||
|
*.sln.docstates
|
||||||
|
|
||||||
|
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||||
|
*.userprefs
|
||||||
|
|
||||||
|
# Mono auto generated files
|
||||||
|
mono_crash.*
|
||||||
|
|
||||||
|
# Build results
|
||||||
|
[Dd]ebug/
|
||||||
|
[Dd]ebugPublic/
|
||||||
|
[Rr]elease/
|
||||||
|
[Rr]eleases/
|
||||||
|
x64/
|
||||||
|
x86/
|
||||||
|
[Ww][Ii][Nn]32/
|
||||||
|
[Aa][Rr][Mm]/
|
||||||
|
[Aa][Rr][Mm]64/
|
||||||
|
bld/
|
||||||
|
[Bb]in/
|
||||||
|
[Oo]bj/
|
||||||
|
[Ll]og/
|
||||||
|
[Ll]ogs/
|
||||||
|
|
||||||
|
# Visual Studio 2015/2017 cache/options directory
|
||||||
|
.vs/
|
||||||
|
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||||
|
#wwwroot/
|
||||||
|
|
||||||
|
# Visual Studio 2017 auto generated files
|
||||||
|
Generated\ Files/
|
||||||
|
|
||||||
|
# MSTest test Results
|
||||||
|
[Tt]est[Rr]esult*/
|
||||||
|
[Bb]uild[Ll]og.*
|
||||||
|
|
||||||
|
# NUnit
|
||||||
|
*.VisualState.xml
|
||||||
|
TestResult.xml
|
||||||
|
nunit-*.xml
|
||||||
|
|
||||||
|
# Build Results of an ATL Project
|
||||||
|
[Dd]ebugPS/
|
||||||
|
[Rr]eleasePS/
|
||||||
|
dlldata.c
|
||||||
|
|
||||||
|
# Benchmark Results
|
||||||
|
BenchmarkDotNet.Artifacts/
|
||||||
|
|
||||||
|
# .NET Core
|
||||||
|
project.lock.json
|
||||||
|
project.fragment.lock.json
|
||||||
|
artifacts/
|
||||||
|
|
||||||
|
# Tye
|
||||||
|
.tye/
|
||||||
|
|
||||||
|
# ASP.NET Scaffolding
|
||||||
|
ScaffoldingReadMe.txt
|
||||||
|
|
||||||
|
# StyleCop
|
||||||
|
StyleCopReport.xml
|
||||||
|
|
||||||
|
# Files built by Visual Studio
|
||||||
|
*_i.c
|
||||||
|
*_p.c
|
||||||
|
*_h.h
|
||||||
|
*.ilk
|
||||||
|
*.meta
|
||||||
|
*.obj
|
||||||
|
*.iobj
|
||||||
|
*.pch
|
||||||
|
*.pdb
|
||||||
|
*.ipdb
|
||||||
|
*.pgc
|
||||||
|
*.pgd
|
||||||
|
*.rsp
|
||||||
|
*.sbr
|
||||||
|
*.tlb
|
||||||
|
*.tli
|
||||||
|
*.tlh
|
||||||
|
*.tmp
|
||||||
|
*.tmp_proj
|
||||||
|
*_wpftmp.csproj
|
||||||
|
*.log
|
||||||
|
*.vspscc
|
||||||
|
*.vssscc
|
||||||
|
.builds
|
||||||
|
*.pidb
|
||||||
|
*.svclog
|
||||||
|
*.scc
|
||||||
|
|
||||||
|
# Chutzpah Test files
|
||||||
|
_Chutzpah*
|
||||||
|
|
||||||
|
# Visual C++ cache files
|
||||||
|
ipch/
|
||||||
|
*.aps
|
||||||
|
*.ncb
|
||||||
|
*.opendb
|
||||||
|
*.opensdf
|
||||||
|
*.sdf
|
||||||
|
*.cachefile
|
||||||
|
*.VC.db
|
||||||
|
*.VC.VC.opendb
|
||||||
|
|
||||||
|
# Visual Studio profiler
|
||||||
|
*.psess
|
||||||
|
*.vsp
|
||||||
|
*.vspx
|
||||||
|
*.sap
|
||||||
|
|
||||||
|
# Visual Studio Trace Files
|
||||||
|
*.e2e
|
||||||
|
|
||||||
|
# TFS 2012 Local Workspace
|
||||||
|
$tf/
|
||||||
|
|
||||||
|
# Guidance Automation Toolkit
|
||||||
|
*.gpState
|
||||||
|
|
||||||
|
# ReSharper is a .NET coding add-in
|
||||||
|
_ReSharper*/
|
||||||
|
*.[Rr]e[Ss]harper
|
||||||
|
*.DotSettings.user
|
||||||
|
|
||||||
|
# TeamCity is a build add-in
|
||||||
|
_TeamCity*
|
||||||
|
|
||||||
|
# DotCover is a Code Coverage Tool
|
||||||
|
*.dotCover
|
||||||
|
|
||||||
|
# AxoCover is a Code Coverage Tool
|
||||||
|
.axoCover/*
|
||||||
|
!.axoCover/settings.json
|
||||||
|
|
||||||
|
# Coverlet is a free, cross platform Code Coverage Tool
|
||||||
|
coverage*.json
|
||||||
|
coverage*.xml
|
||||||
|
coverage*.info
|
||||||
|
|
||||||
|
# Visual Studio code coverage results
|
||||||
|
*.coverage
|
||||||
|
*.coveragexml
|
||||||
|
|
||||||
|
# NCrunch
|
||||||
|
_NCrunch_*
|
||||||
|
.*crunch*.local.xml
|
||||||
|
nCrunchTemp_*
|
||||||
|
|
||||||
|
# MightyMoose
|
||||||
|
*.mm.*
|
||||||
|
AutoTest.Net/
|
||||||
|
|
||||||
|
# Web workbench (sass)
|
||||||
|
.sass-cache/
|
||||||
|
|
||||||
|
# Installshield output folder
|
||||||
|
[Ee]xpress/
|
||||||
|
|
||||||
|
# DocProject is a documentation generator add-in
|
||||||
|
DocProject/buildhelp/
|
||||||
|
DocProject/Help/*.HxT
|
||||||
|
DocProject/Help/*.HxC
|
||||||
|
DocProject/Help/*.hhc
|
||||||
|
DocProject/Help/*.hhk
|
||||||
|
DocProject/Help/*.hhp
|
||||||
|
DocProject/Help/Html2
|
||||||
|
DocProject/Help/html
|
||||||
|
|
||||||
|
# Click-Once directory
|
||||||
|
publish/
|
||||||
|
|
||||||
|
# Publish Web Output
|
||||||
|
*.[Pp]ublish.xml
|
||||||
|
*.azurePubxml
|
||||||
|
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||||
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
|
*.pubxml
|
||||||
|
*.publishproj
|
||||||
|
|
||||||
|
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||||
|
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||||
|
# in these scripts will be unencrypted
|
||||||
|
PublishScripts/
|
||||||
|
|
||||||
|
# NuGet Packages
|
||||||
|
*.nupkg
|
||||||
|
# NuGet Symbol Packages
|
||||||
|
*.snupkg
|
||||||
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
**/[Pp]ackages/*
|
||||||
|
# except build/, which is used as an MSBuild target.
|
||||||
|
!**/[Pp]ackages/build/
|
||||||
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
|
#!**/[Pp]ackages/repositories.config
|
||||||
|
# NuGet v3's project.json files produces more ignorable files
|
||||||
|
*.nuget.props
|
||||||
|
*.nuget.targets
|
||||||
|
|
||||||
|
# Microsoft Azure Build Output
|
||||||
|
csx/
|
||||||
|
*.build.csdef
|
||||||
|
|
||||||
|
# Microsoft Azure Emulator
|
||||||
|
ecf/
|
||||||
|
rcf/
|
||||||
|
|
||||||
|
# Windows Store app package directories and files
|
||||||
|
AppPackages/
|
||||||
|
BundleArtifacts/
|
||||||
|
Package.StoreAssociation.xml
|
||||||
|
_pkginfo.txt
|
||||||
|
*.appx
|
||||||
|
*.appxbundle
|
||||||
|
*.appxupload
|
||||||
|
|
||||||
|
# Visual Studio cache files
|
||||||
|
# files ending in .cache can be ignored
|
||||||
|
*.[Cc]ache
|
||||||
|
# but keep track of directories ending in .cache
|
||||||
|
!?*.[Cc]ache/
|
||||||
|
|
||||||
|
# Others
|
||||||
|
ClientBin/
|
||||||
|
~$*
|
||||||
|
*~
|
||||||
|
*.dbmdl
|
||||||
|
*.dbproj.schemaview
|
||||||
|
*.jfm
|
||||||
|
*.pfx
|
||||||
|
*.publishsettings
|
||||||
|
orleans.codegen.cs
|
||||||
|
|
||||||
|
# Including strong name files can present a security risk
|
||||||
|
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||||
|
#*.snk
|
||||||
|
|
||||||
|
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||||
|
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||||
|
#bower_components/
|
||||||
|
|
||||||
|
# RIA/Silverlight projects
|
||||||
|
Generated_Code/
|
||||||
|
|
||||||
|
# Backup & report files from converting an old project file
|
||||||
|
# to a newer Visual Studio version. Backup files are not needed,
|
||||||
|
# because we have git ;-)
|
||||||
|
_UpgradeReport_Files/
|
||||||
|
Backup*/
|
||||||
|
UpgradeLog*.XML
|
||||||
|
UpgradeLog*.htm
|
||||||
|
ServiceFabricBackup/
|
||||||
|
*.rptproj.bak
|
||||||
|
|
||||||
|
# SQL Server files
|
||||||
|
*.mdf
|
||||||
|
*.ldf
|
||||||
|
*.ndf
|
||||||
|
|
||||||
|
# Business Intelligence projects
|
||||||
|
*.rdl.data
|
||||||
|
*.bim.layout
|
||||||
|
*.bim_*.settings
|
||||||
|
*.rptproj.rsuser
|
||||||
|
*- [Bb]ackup.rdl
|
||||||
|
*- [Bb]ackup ([0-9]).rdl
|
||||||
|
*- [Bb]ackup ([0-9][0-9]).rdl
|
||||||
|
|
||||||
|
# Microsoft Fakes
|
||||||
|
FakesAssemblies/
|
||||||
|
|
||||||
|
# GhostDoc plugin setting file
|
||||||
|
*.GhostDoc.xml
|
||||||
|
|
||||||
|
# Node.js Tools for Visual Studio
|
||||||
|
.ntvs_analysis.dat
|
||||||
|
node_modules/
|
||||||
|
|
||||||
|
# Visual Studio 6 build log
|
||||||
|
*.plg
|
||||||
|
|
||||||
|
# Visual Studio 6 workspace options file
|
||||||
|
*.opt
|
||||||
|
|
||||||
|
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||||
|
*.vbw
|
||||||
|
|
||||||
|
# Visual Studio LightSwitch build output
|
||||||
|
**/*.HTMLClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/GeneratedArtifacts
|
||||||
|
**/*.DesktopClient/ModelManifest.xml
|
||||||
|
**/*.Server/GeneratedArtifacts
|
||||||
|
**/*.Server/ModelManifest.xml
|
||||||
|
_Pvt_Extensions
|
||||||
|
|
||||||
|
# Paket dependency manager
|
||||||
|
.paket/paket.exe
|
||||||
|
paket-files/
|
||||||
|
|
||||||
|
# FAKE - F# Make
|
||||||
|
.fake/
|
||||||
|
|
||||||
|
# CodeRush personal settings
|
||||||
|
.cr/personal
|
||||||
|
|
||||||
|
# Python Tools for Visual Studio (PTVS)
|
||||||
|
__pycache__/
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# Cake - Uncomment if you are using it
|
||||||
|
# tools/**
|
||||||
|
# !tools/packages.config
|
||||||
|
|
||||||
|
# Tabs Studio
|
||||||
|
*.tss
|
||||||
|
|
||||||
|
# Telerik's JustMock configuration file
|
||||||
|
*.jmconfig
|
||||||
|
|
||||||
|
# BizTalk build output
|
||||||
|
*.btp.cs
|
||||||
|
*.btm.cs
|
||||||
|
*.odx.cs
|
||||||
|
*.xsd.cs
|
||||||
|
|
||||||
|
# OpenCover UI analysis results
|
||||||
|
OpenCover/
|
||||||
|
|
||||||
|
# Azure Stream Analytics local run output
|
||||||
|
ASALocalRun/
|
||||||
|
|
||||||
|
# MSBuild Binary and Structured Log
|
||||||
|
*.binlog
|
||||||
|
|
||||||
|
# NVidia Nsight GPU debugger configuration file
|
||||||
|
*.nvuser
|
||||||
|
|
||||||
|
# MFractors (Xamarin productivity tool) working folder
|
||||||
|
.mfractor/
|
||||||
|
|
||||||
|
# Local History for Visual Studio
|
||||||
|
.localhistory/
|
||||||
|
|
||||||
|
# BeatPulse healthcheck temp database
|
||||||
|
healthchecksdb
|
||||||
|
|
||||||
|
# Backup folder for Package Reference Convert tool in Visual Studio 2017
|
||||||
|
MigrationBackup/
|
||||||
|
|
||||||
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
|
.ionide/
|
||||||
|
|
||||||
|
# Fody - auto-generated XML schema
|
||||||
|
FodyWeavers.xsd
|
||||||
|
|
||||||
|
##
|
||||||
|
## Visual studio for Mac
|
||||||
|
##
|
||||||
|
|
||||||
|
|
||||||
|
# globs
|
||||||
|
Makefile.in
|
||||||
|
*.userprefs
|
||||||
|
*.usertasks
|
||||||
|
config.make
|
||||||
|
config.status
|
||||||
|
aclocal.m4
|
||||||
|
install-sh
|
||||||
|
autom4te.cache/
|
||||||
|
*.tar.gz
|
||||||
|
tarballs/
|
||||||
|
test-results/
|
||||||
|
|
||||||
|
# Mac bundle stuff
|
||||||
|
*.dmg
|
||||||
|
*.app
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
|
||||||
|
# General
|
||||||
|
.DS_Store
|
||||||
|
.AppleDouble
|
||||||
|
.LSOverride
|
||||||
|
|
||||||
|
# Icon must end with two \r
|
||||||
|
Icon
|
||||||
|
|
||||||
|
|
||||||
|
# Thumbnails
|
||||||
|
._*
|
||||||
|
|
||||||
|
# Files that might appear in the root of a volume
|
||||||
|
.DocumentRevisions-V100
|
||||||
|
.fseventsd
|
||||||
|
.Spotlight-V100
|
||||||
|
.TemporaryItems
|
||||||
|
.Trashes
|
||||||
|
.VolumeIcon.icns
|
||||||
|
.com.apple.timemachine.donotpresent
|
||||||
|
|
||||||
|
# Directories potentially created on remote AFP share
|
||||||
|
.AppleDB
|
||||||
|
.AppleDesktop
|
||||||
|
Network Trash Folder
|
||||||
|
Temporary Items
|
||||||
|
.apdisk
|
||||||
|
|
||||||
|
# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
|
||||||
|
# Windows thumbnail cache files
|
||||||
|
Thumbs.db
|
||||||
|
ehthumbs.db
|
||||||
|
ehthumbs_vista.db
|
||||||
|
|
||||||
|
# Dump file
|
||||||
|
*.stackdump
|
||||||
|
|
||||||
|
# Folder config file
|
||||||
|
[Dd]esktop.ini
|
||||||
|
|
||||||
|
# Recycle Bin used on file shares
|
||||||
|
$RECYCLE.BIN/
|
||||||
|
|
||||||
|
# Windows Installer files
|
||||||
|
*.cab
|
||||||
|
*.msi
|
||||||
|
*.msix
|
||||||
|
*.msm
|
||||||
|
*.msp
|
||||||
|
|
||||||
|
# Windows shortcuts
|
||||||
|
*.lnk
|
||||||
|
|
||||||
|
# JetBrains Rider
|
||||||
|
.idea/
|
||||||
|
*.sln.iml
|
||||||
|
|
||||||
|
##
|
||||||
|
## Visual Studio Code
|
||||||
|
##
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
367
ChovySign-GUI/App.axaml
Normal file
|
@ -0,0 +1,367 @@
|
||||||
|
<Application xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
x:Class="ChovySign_GUI.App">
|
||||||
|
<Application.Styles>
|
||||||
|
<FluentTheme Mode="Light"/>
|
||||||
|
|
||||||
|
<!-- Checkbox Styling -->
|
||||||
|
<Style Selector="CheckBox:checked /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="CheckBox:checked /template/ Border#NormalRectangle">
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="CheckBox:pointerover /template/ Border#NormalRectangle">
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#1f1f1f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="CheckBox /template/ Border#NormalRectangle">
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="CheckBox:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
<Style Selector="CheckBox">
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Button styles -->
|
||||||
|
<Style Selector="Button:disabled /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>DarkRed</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>DarkRed</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Button:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Red</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>DarkRed</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Button">
|
||||||
|
<Setter Property="BorderThickness">
|
||||||
|
<Setter.Value>1</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>Red</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>Red</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- Textbox Styling -->
|
||||||
|
|
||||||
|
<Style Selector="TextBox:focus">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TextBox:focus /template/ TextBlock">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="TextBox:focus /template/ Border">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TextBox:pointerover">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TextBox:pointerover /template/ TextBlock">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="TextBox:pointerover /template/ Border">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#1f1f1f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TextBox">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- ComboBox -->
|
||||||
|
|
||||||
|
<Style Selector="ComboBox">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderThickness">
|
||||||
|
<Setter.Value>1</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ComboBox:pointerover">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ComboBox:pointerover /template/ TextBlock">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
<Style Selector="ComboBox:pointerover /template/ Border">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#1f1f1f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ComboBoxItem:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#1f1f1f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ComboBoxItem:selected /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ComboBoxItem:selected:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ComboBoxItem">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderThickness">
|
||||||
|
<Setter.Value>1</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- ListBox -->
|
||||||
|
|
||||||
|
|
||||||
|
<Style Selector="ListBoxItem:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#1f1f1f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBoxItem:selected /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBoxItem:selected:pointerover /template/ ContentPresenter">
|
||||||
|
<Setter Property="TextBlock.Foreground">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBoxItem">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderThickness">
|
||||||
|
<Setter.Value>1</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="ListBox">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderThickness">
|
||||||
|
<Setter.Value>1</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- TabControl -->
|
||||||
|
|
||||||
|
<Style Selector="TabControl">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TabItem:pointerover /template/ Border">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TabItem:selected">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Green</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="TabItem">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>DarkGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<!-- other -->
|
||||||
|
|
||||||
|
<Style Selector="ProgressBar">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>#3f3f3f</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderThickness">
|
||||||
|
<Setter.Value>1</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Label">
|
||||||
|
<Setter Property="Foreground">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Border">
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>LightGreen</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
|
||||||
|
<Setter Property="BorderThickness">
|
||||||
|
<Setter.Value>1</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
|
||||||
|
<Style Selector="Window">
|
||||||
|
<Setter Property="Background">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
<Setter Property="BorderBrush">
|
||||||
|
<Setter.Value>Black</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</Application.Styles>
|
||||||
|
</Application>
|
38
ChovySign-GUI/App.axaml.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using System;
|
||||||
|
using System.Media;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI
|
||||||
|
{
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
public static async Task PlayFinishSound()
|
||||||
|
{
|
||||||
|
if (!OperatingSystem.IsWindows()) return;
|
||||||
|
await Task.Run(() =>
|
||||||
|
{
|
||||||
|
using (SoundPlayer player = new SoundPlayer(Resource.FINISHSND))
|
||||||
|
{
|
||||||
|
player.Play();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
public override void Initialize()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnFrameworkInitializationCompleted()
|
||||||
|
{
|
||||||
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
|
{
|
||||||
|
desktop.MainWindow = new MainWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
base.OnFrameworkInitializationCompleted();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
ChovySign-GUI/ChovySign-GUI.csproj
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net6.0</TargetFramework>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
|
||||||
|
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||||
|
<RootNamespace>ChovySign_GUI</RootNamespace>
|
||||||
|
<AssemblyName>ChovySign v2</AssemblyName>
|
||||||
|
<ApplicationIcon>ICON.ICO</ApplicationIcon>
|
||||||
|
<Authors>SquallATF, Li, Dots-Tb</Authors>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Remove=".gitignore" />
|
||||||
|
<None Remove="DEFAULTICON.PNG" />
|
||||||
|
<None Remove="Icon.png" />
|
||||||
|
<None Remove="Popup\Global\KeySelector\ACTRIFMETHOD.PNG" />
|
||||||
|
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD.PNG" />
|
||||||
|
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD1.png" />
|
||||||
|
<None Remove="Popup\Global\KeySelector\EBOOTMETHOD2.png" />
|
||||||
|
<None Remove="Popup\Global\KeySelector\KEYSTXTMETHOD.PNG" />
|
||||||
|
<None Remove="PS1CD.PNG" />
|
||||||
|
<None Remove="UMD.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<AvaloniaResource Include="ICON.PNG" />
|
||||||
|
<AvaloniaResource Include="Popup\Global\KeySelector\ACTRIFMETHOD.PNG" />
|
||||||
|
<AvaloniaResource Include="Popup\Global\KeySelector\EBOOTMETHOD1.PNG" />
|
||||||
|
<AvaloniaResource Include="Popup\Global\KeySelector\EBOOTMETHOD2.PNG" />
|
||||||
|
<AvaloniaResource Include="Popup\Global\KeySelector\KEYSTXTMETHOD.PNG" />
|
||||||
|
<AvaloniaResource Include="Ps1\PS1CD.PNG" />
|
||||||
|
<AvaloniaResource Include="Psp\UMD.PNG">
|
||||||
|
<CopyToOutputDirectory>Never</CopyToOutputDirectory>
|
||||||
|
</AvaloniaResource>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="ICON.ICO" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<TrimmerRootDescriptor Include="Roots.xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Avalonia" Version="0.10.19" />
|
||||||
|
<PackageReference Include="Avalonia.Desktop" Version="0.10.19" />
|
||||||
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="0.10.19" />
|
||||||
|
<PackageReference Include="XamlNameReferenceGenerator" Version="1.6.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\GameBuilder\GameBuilder.csproj" />
|
||||||
|
<ProjectReference Include="..\LibChovy\LibChovy.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<UpToDateCheckInput Remove="Global\DevkitToggle.axaml" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Update="Resource.Designer.cs">
|
||||||
|
<DesignTime>True</DesignTime>
|
||||||
|
<AutoGen>True</AutoGen>
|
||||||
|
<DependentUpon>Resource.resx</DependentUpon>
|
||||||
|
</Compile>
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<EmbeddedResource Update="Resource.resx">
|
||||||
|
<Generator>PublicResXFileCodeGenerator</Generator>
|
||||||
|
<LastGenOutput>Resource.Designer.cs</LastGenOutput>
|
||||||
|
</EmbeddedResource>
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
26
ChovySign-GUI/Global/BrowseButton.axaml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
|
||||||
|
x:Class="ChovySign_GUI.Global.BrowseButton"
|
||||||
|
Height="60">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Name="browseLabel" Content="File Path:" VerticalAlignment="Bottom" Grid.Row="0"/>
|
||||||
|
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="75" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBox Name="filePath" HorizontalAlignment="Stretch" VerticalAlignment="Center" Watermark="(None)" Grid.Column="0"/>
|
||||||
|
<Button Name="browseButton" Content="Browse" HorizontalAlignment="Center" VerticalAlignment="Center" Click="browseClick" Grid.Column="1"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
194
ChovySign-GUI/Global/BrowseButton.axaml.cs
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Org.BouncyCastle.Tls.Crypto;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Global
|
||||||
|
{
|
||||||
|
public partial class BrowseButton : UserControl
|
||||||
|
{
|
||||||
|
private string fileTypeName;
|
||||||
|
private string extension;
|
||||||
|
private bool directory;
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? FileChanged;
|
||||||
|
|
||||||
|
protected virtual void OnFileChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if(FileChanged is not null)
|
||||||
|
FileChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Extension
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return extension.Replace(".", "");
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
extension = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string FileTypeName
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return fileTypeName;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
fileTypeName = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDirectory
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.directory;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.directory = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Watermark
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.filePath.Watermark;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.filePath.Watermark = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Label
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string? lbl = this.browseLabel.Content as String;
|
||||||
|
if (lbl is null) return "";
|
||||||
|
else return lbl;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.browseLabel.Content = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public bool ContainsFile
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!this.IsDirectory)
|
||||||
|
return (File.Exists(this.filePath.Text) && Path.GetExtension(this.filePath.Text).Equals("." + Extension, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
else
|
||||||
|
return (Directory.Exists(this.filePath.Text));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string FilePath
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!ContainsFile) return "";
|
||||||
|
return this.filePath.Text;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!this.IsDirectory)
|
||||||
|
{
|
||||||
|
if (File.Exists(value))
|
||||||
|
this.filePath.Text = value;
|
||||||
|
else
|
||||||
|
this.filePath.Text = "";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (Directory.Exists(value))
|
||||||
|
this.filePath.Text = value;
|
||||||
|
else
|
||||||
|
this.filePath.Text = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void browseClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
Button? btn = sender as Button;
|
||||||
|
|
||||||
|
if (btn is Button)
|
||||||
|
{
|
||||||
|
btn.IsEnabled = false;
|
||||||
|
|
||||||
|
if (this.IsDirectory)
|
||||||
|
{
|
||||||
|
// open directory
|
||||||
|
OpenFolderDialog browseDialog = new OpenFolderDialog();
|
||||||
|
|
||||||
|
if (this.ContainsFile) browseDialog.Directory = this.FilePath;
|
||||||
|
|
||||||
|
browseDialog.Title = "Select directory.";
|
||||||
|
|
||||||
|
string? directory = await browseDialog.ShowAsync(currentWindow);
|
||||||
|
if(directory is not null)
|
||||||
|
this.FilePath = directory;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// open file
|
||||||
|
OpenFileDialog browseDialog = new OpenFileDialog();
|
||||||
|
if (extension != "")
|
||||||
|
{
|
||||||
|
browseDialog.Filters = new List<FileDialogFilter>();
|
||||||
|
FileDialogFilter filter = new FileDialogFilter();
|
||||||
|
filter.Extensions.Add(extension);
|
||||||
|
filter.Name = fileTypeName;
|
||||||
|
browseDialog.Filters.Add(filter);
|
||||||
|
browseDialog.Title = "Select " + fileTypeName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
browseDialog.Title = "Select a file.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.ContainsFile) browseDialog.Directory = Path.GetDirectoryName(this.FilePath);
|
||||||
|
|
||||||
|
|
||||||
|
string[]? selectedFiles = await browseDialog.ShowAsync(currentWindow);
|
||||||
|
if (selectedFiles is not null && selectedFiles.Length > 0)
|
||||||
|
this.FilePath = selectedFiles.First();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
btn.IsEnabled = true;
|
||||||
|
OnFileChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public BrowseButton()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
this.filePath.KeyUp += onKeyPress;
|
||||||
|
|
||||||
|
this.extension = "";
|
||||||
|
this.fileTypeName = "All Files";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onKeyPress(object? sender, KeyEventArgs e)
|
||||||
|
{
|
||||||
|
OnFileChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
10
ChovySign-GUI/Global/DevkitToggle.axaml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
|
||||||
|
x:Class="ChovySign_GUI.Global.DevkitToggle">
|
||||||
|
<Grid>
|
||||||
|
<CheckBox Name="devkitCheckbox" Content="I have a DevKit, TestKit or IDU Vita"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
86
ChovySign-GUI/Global/DevkitToggle.axaml.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using ChovySign_GUI.Popup.Global;
|
||||||
|
using LibChovy.Config;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using static ChovySign_GUI.Popup.Global.MessageBox;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Global
|
||||||
|
{
|
||||||
|
public partial class DevkitToggle : UserControl
|
||||||
|
{
|
||||||
|
private static List<DevkitToggle> instances = new List<DevkitToggle>();
|
||||||
|
|
||||||
|
private const string useDevkitModeConfigKey = "USE_DEVKIT_ACCOUNT_ID";
|
||||||
|
internal bool disableEvents = false;
|
||||||
|
private async void onDevkitModeChecked(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (disableEvents) return;
|
||||||
|
|
||||||
|
CheckBox? checkBox = sender as CheckBox;
|
||||||
|
if (checkBox is null) return;
|
||||||
|
|
||||||
|
bool? devMode = checkBox.IsChecked;
|
||||||
|
if (devMode is null) devMode = false;
|
||||||
|
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
MessageBoxResult res = await MessageBox.Show(currentWindow, "This option will force the CMA Account ID to be all 0's\nWhich is how it is on Devkit, Testkit and IDU Firmware\nEnabling this if you have a retail firmware will result in the games just *not* showing up\n\nIf you DON'T know what this means, DON'T enable this.\ndo you want to continue?", "Are you sure?", MessageBoxButtons.YesNo);
|
||||||
|
if (res == MessageBoxResult.Yes)
|
||||||
|
{
|
||||||
|
IsDevkitMode = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
IsDevkitMode = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onDevkitModeUnchecked(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (disableEvents) return;
|
||||||
|
|
||||||
|
CheckBox? checkBox = sender as CheckBox;
|
||||||
|
if (checkBox is null) return;
|
||||||
|
|
||||||
|
bool? devMode = checkBox.IsChecked;
|
||||||
|
if (devMode is null) devMode = false;
|
||||||
|
IsDevkitMode = (bool)devMode;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsDevkitMode
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.devkitCheckbox.IsChecked is null) return false;
|
||||||
|
return (bool)this.devkitCheckbox.IsChecked;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
foreach (DevkitToggle instance in instances)
|
||||||
|
{
|
||||||
|
instance.disableEvents = true;
|
||||||
|
instance.devkitCheckbox.IsChecked = value;
|
||||||
|
instance.disableEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChovyConfig.CurrentConfig.SetBool(useDevkitModeConfigKey, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DevkitToggle()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
bool? isDevkitMode = ChovyConfig.CurrentConfig.GetBool(useDevkitModeConfigKey);
|
||||||
|
if (isDevkitMode is null) isDevkitMode = false;
|
||||||
|
devkitCheckbox.IsChecked = isDevkitMode;
|
||||||
|
devkitCheckbox.Unchecked += onDevkitModeUnchecked;
|
||||||
|
devkitCheckbox.Checked += onDevkitModeChecked;
|
||||||
|
|
||||||
|
instances.Add(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
8
ChovySign-GUI/Global/FilteredTextBox.axaml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="ChovySign_GUI.Global.FilteredTextBox">
|
||||||
|
<TextBox Name="txtBox" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"/>
|
||||||
|
</UserControl>
|
149
ChovySign-GUI/Global/FilteredTextBox.axaml.cs
Normal file
|
@ -0,0 +1,149 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Global
|
||||||
|
{
|
||||||
|
public partial class FilteredTextBox : UserControl
|
||||||
|
{
|
||||||
|
|
||||||
|
private string? allowedChars = null;
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? TextChanged;
|
||||||
|
protected virtual void OnTextChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if (TextChanged is not null)
|
||||||
|
TextChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int MaxLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.MaxLength;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.MaxLength = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Password
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.PasswordChar == default(char);
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value) this.txtBox.PasswordChar = 'X';
|
||||||
|
else this.txtBox.PasswordChar = default(char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Watermark
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.Watermark;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.Watermark = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string? AllowedChars
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (allowedChars is null) return "";
|
||||||
|
else return allowedChars;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
allowedChars = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.txtBox.Text is null) return "";
|
||||||
|
return this.txtBox.Text;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public FilteredTextBox()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.txtBox.PastingFromClipboard += onPaste;
|
||||||
|
this.txtBox.AddHandler(TextInputEvent, onTxtInput, RoutingStrategies.Tunnel);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string filter(string original)
|
||||||
|
{
|
||||||
|
if (allowedChars is not null)
|
||||||
|
{
|
||||||
|
StringBuilder str = new StringBuilder();
|
||||||
|
|
||||||
|
for (int i = 0; i < original.Length; i++)
|
||||||
|
{
|
||||||
|
if (allowedChars.Contains(original[i]))
|
||||||
|
str.Append(original[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.ToString();
|
||||||
|
}
|
||||||
|
return original;
|
||||||
|
}
|
||||||
|
private async Task<bool> setClipboardText(string text)
|
||||||
|
{
|
||||||
|
if (Application.Current is null) return false;
|
||||||
|
if (Application.Current.Clipboard is null) return false;
|
||||||
|
await Application.Current.Clipboard.SetTextAsync(text);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
private async Task<string> getClipboardText()
|
||||||
|
{
|
||||||
|
if (Application.Current is null) return "";
|
||||||
|
if (Application.Current.Clipboard is null) return "";
|
||||||
|
string? clipboard = await Application.Current.Clipboard.GetTextAsync();
|
||||||
|
if (clipboard is null) return "";
|
||||||
|
return clipboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void onPaste(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
TextBox? txt = sender as TextBox;
|
||||||
|
if (txt is null) return;
|
||||||
|
|
||||||
|
string clipboard = getClipboardText().Result;
|
||||||
|
clipboard = filter(clipboard);
|
||||||
|
_ = setClipboardText(clipboard).Result;
|
||||||
|
|
||||||
|
// annoyingly, the text being pasted isnt actually in the textbox yet
|
||||||
|
// and it wont trigger a textInput event when pasting; t-this really is the best can do
|
||||||
|
await Task.Delay(100);
|
||||||
|
OnTextChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onTxtInput(object? sender, TextInputEventArgs e)
|
||||||
|
{
|
||||||
|
string? newTxt = e.Text;
|
||||||
|
if (newTxt is null) newTxt = "";
|
||||||
|
|
||||||
|
newTxt = filter(newTxt);
|
||||||
|
e.Text = newTxt;
|
||||||
|
|
||||||
|
OnTextChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
36
ChovySign-GUI/Global/KeySelector.axaml
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="40"
|
||||||
|
x:Class="ChovySign_GUI.Global.KeySelector">
|
||||||
|
<!-- key selector -->
|
||||||
|
<Border Padding="10 3" HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="80" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid HorizontalAlignment="Stretch" Grid.Column="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="40" />
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label HorizontalAlignment="Left" VerticalAlignment="Center" Content="Rif:" Grid.Column="0"/>
|
||||||
|
<Global:FilteredTextBox Name="zRif" AllowedChars="1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz=+/" HorizontalAlignment="Stretch" Watermark="LICENSE ZRIF" Grid.Column="1"/>
|
||||||
|
</Grid>
|
||||||
|
<Grid HorizontalAlignment="Stretch" Grid.Column="1">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="40" />
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Label HorizontalAlignment="Left" VerticalAlignment="Center" Content="Key:" Grid.Column="0"/>
|
||||||
|
<Global:FilteredTextBox AllowedChars="1234567890ABCDEFabcdef" HorizontalAlignment="Stretch" MaxLength="32" Watermark="Version Key" Name="vKey" Grid.Column="1"/>
|
||||||
|
</Grid>
|
||||||
|
<Button Name="getKeys" Click="getKeysClick" Content="Get Keys" HorizontalAlignment="Center" VerticalAlignment="Center" Grid.Column="2"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
286
ChovySign-GUI/Global/KeySelector.axaml.cs
Normal file
|
@ -0,0 +1,286 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Remote.Protocol.Input;
|
||||||
|
using ChovySign_GUI.Popup.Global;
|
||||||
|
using ChovySign_GUI.Popup.Global.KeySelector;
|
||||||
|
using GameBuilder.Psp;
|
||||||
|
using Ionic.Zlib;
|
||||||
|
using Li.Utilities;
|
||||||
|
using LibChovy.Config;
|
||||||
|
using LibChovy.VersionKey;
|
||||||
|
using SixLabors.ImageSharp.PixelFormats;
|
||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Vita.ContentManager;
|
||||||
|
using Vita.PsvImgTools;
|
||||||
|
using static ChovySign_GUI.Popup.Global.MessageBox;
|
||||||
|
using static PspCrypto.SceNpDrm;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Global
|
||||||
|
{
|
||||||
|
public partial class KeySelector : UserControl
|
||||||
|
{
|
||||||
|
|
||||||
|
private string licenseDataConfigKey
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "KEY_INDEX_" + keyIndex + "_LICENSE_DATA";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private string versionKeyConfigKey
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return "KEY_INDEX_" + keyIndex + "_VERSION_KEY";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool lastValid;
|
||||||
|
private int keyIndex = 1;
|
||||||
|
private NpDrmRif? npRif;
|
||||||
|
private byte[]? versionKey;
|
||||||
|
|
||||||
|
public bool IsValid
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (vKey.Text is null) return false;
|
||||||
|
if (vKey.Text.Length != 32) return false;
|
||||||
|
|
||||||
|
if (zRif.Text is null) return false;
|
||||||
|
if (zRif.Text.Length <= 0) return false;
|
||||||
|
|
||||||
|
byte[] rif = new NpDrmRif(zRif.Text).Rif;
|
||||||
|
if (rif.Length <= 0) return false;
|
||||||
|
return (VersionKey is not null && Rif is not null);
|
||||||
|
}
|
||||||
|
catch { return false; };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[]? VersionKey
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return versionKey;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value is null) return;
|
||||||
|
|
||||||
|
versionKey = value;
|
||||||
|
ChovyConfig.CurrentConfig.SetBytes(versionKeyConfigKey, versionKey);
|
||||||
|
vKey.Text = BitConverter.ToString(versionKey).Replace("-", "");
|
||||||
|
|
||||||
|
OnVersionKeyChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public byte[]? Rif
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (npRif is null) return null;
|
||||||
|
return npRif.Rif;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value is null) return;
|
||||||
|
|
||||||
|
npRif = new NpDrmRif(value);
|
||||||
|
zRif.Text = npRif.ZRif;
|
||||||
|
ChovyConfig.CurrentConfig.SetBytes(licenseDataConfigKey, npRif.Rif);
|
||||||
|
|
||||||
|
OnRifChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private void reloadCfg()
|
||||||
|
{
|
||||||
|
byte[]? rifData = ChovyConfig.CurrentConfig.GetBytes(licenseDataConfigKey);
|
||||||
|
byte[]? vkeyData = ChovyConfig.CurrentConfig.GetBytes(versionKeyConfigKey);
|
||||||
|
|
||||||
|
if(vkeyData is not null)
|
||||||
|
{
|
||||||
|
vKey.Text = BitConverter.ToString(vkeyData).Replace("-", "");
|
||||||
|
versionKey = vkeyData;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rifData is not null)
|
||||||
|
{
|
||||||
|
npRif = new NpDrmRif(rifData);
|
||||||
|
zRif.Text = npRif.ZRif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void getKeysClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Button? btn = sender as Button;
|
||||||
|
if (btn is null) return;
|
||||||
|
|
||||||
|
btn.IsEnabled = false;
|
||||||
|
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
KeyObtainMethods keyObt = new KeyObtainMethods();
|
||||||
|
keyObt.KeyIndex = keyIndex;
|
||||||
|
VersionKeyMethod? method = await keyObt.ShowDialog<VersionKeyMethod>(currentWindow);
|
||||||
|
if (method is null) return;
|
||||||
|
|
||||||
|
NpDrmInfo? key = null;
|
||||||
|
NpDrmRif? rif = null;
|
||||||
|
|
||||||
|
switch (method)
|
||||||
|
{
|
||||||
|
case VersionKeyMethod.ACT_RIF_METHOD:
|
||||||
|
ActRifMethodGUI actRifMethodGUI = new ActRifMethodGUI();
|
||||||
|
NpDrmInfo[]? keys = await actRifMethodGUI.ShowDialog<NpDrmInfo[]>(currentWindow);
|
||||||
|
if (keys is null) break;
|
||||||
|
|
||||||
|
key = keys[keyIndex];
|
||||||
|
rif = actRifMethodGUI.Rif;
|
||||||
|
|
||||||
|
break;
|
||||||
|
case VersionKeyMethod.EBOOT_PBP_METHOD:
|
||||||
|
CmaBackupPicker ebootBackupSelector = new CmaBackupPicker();
|
||||||
|
ebootBackupSelector.BackupType = ((keyIndex == 1) ? "PSGAME" : "PGAME");
|
||||||
|
|
||||||
|
string? gameBackupFolder = await ebootBackupSelector.ShowDialog<string>(currentWindow);
|
||||||
|
string accountId = ebootBackupSelector.AccountId;
|
||||||
|
if (gameBackupFolder is null) break;
|
||||||
|
if (accountId == "") break;
|
||||||
|
|
||||||
|
key = CMAVersionKeyHelper.GetKeyFromGamePsvimg(gameBackupFolder, accountId);
|
||||||
|
rif = CMAVersionKeyHelper.GetRifFromLicensePsvimg(gameBackupFolder, accountId);
|
||||||
|
break;
|
||||||
|
case VersionKeyMethod.KEYS_TXT_METHOD:
|
||||||
|
CmaBackupPicker pspLicenseBackupSelector = new CmaBackupPicker();
|
||||||
|
pspLicenseBackupSelector.BackupType = "PGAME";
|
||||||
|
pspLicenseBackupSelector.Filter = KeysTxtMethod.TitleIds;
|
||||||
|
|
||||||
|
gameBackupFolder = await pspLicenseBackupSelector.ShowDialog<string>(currentWindow);
|
||||||
|
accountId = pspLicenseBackupSelector.AccountId;
|
||||||
|
if (gameBackupFolder is null) break;
|
||||||
|
if (accountId == "") break;
|
||||||
|
|
||||||
|
rif = CMAVersionKeyHelper.GetRifFromLicensePsvimg(gameBackupFolder, accountId);
|
||||||
|
if (rif is null) break;
|
||||||
|
|
||||||
|
key = KeysTxtMethod.GetVersionKey(rif.ContentId, this.KeyIndex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if (key is not null)
|
||||||
|
{
|
||||||
|
if (key.KeyIndex != this.keyIndex)
|
||||||
|
{
|
||||||
|
await MessageBox.Show(currentWindow, "VersionKey obtained, but had keyindex: " + key.KeyIndex + " however keyindex " + this.keyIndex + " was required.", "KeyIndex mismatch!", MessageBoxButtons.Ok);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
VersionKey = key.VersionKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rif is not null)
|
||||||
|
Rif = rif.Rif;
|
||||||
|
|
||||||
|
btn.IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int KeyIndex
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return keyIndex;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
keyIndex = value;
|
||||||
|
reloadCfg();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? VersionKeyChanged;
|
||||||
|
protected virtual void OnVersionKeyChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if (IsValid != lastValid) OnValidStateChanged(new EventArgs());
|
||||||
|
|
||||||
|
|
||||||
|
if (VersionKeyChanged is not null)
|
||||||
|
VersionKeyChanged(this, e);
|
||||||
|
}
|
||||||
|
public event EventHandler<EventArgs>? RifChanged;
|
||||||
|
protected virtual void OnRifChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if (IsValid != lastValid) OnValidStateChanged(new EventArgs());
|
||||||
|
|
||||||
|
if (RifChanged is not null)
|
||||||
|
RifChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? ValidStateChanged;
|
||||||
|
protected virtual void OnValidStateChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
lastValid = IsValid;
|
||||||
|
if (ValidStateChanged is not null)
|
||||||
|
ValidStateChanged(this, e);
|
||||||
|
}
|
||||||
|
public KeySelector()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
reloadCfg();
|
||||||
|
lastValid = IsValid;
|
||||||
|
|
||||||
|
zRif.TextChanged += onZrifChanged;
|
||||||
|
vKey.TextChanged += onVkeyChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onVkeyChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FilteredTextBox? txt = sender as FilteredTextBox;
|
||||||
|
if (txt is null) return;
|
||||||
|
|
||||||
|
if (lastValid != IsValid)
|
||||||
|
OnValidStateChanged(new EventArgs());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (txt.Text is null) return;
|
||||||
|
if (txt.Text.Length != 32) return;
|
||||||
|
|
||||||
|
this.VersionKey = MathUtil.StringToByteArray(txt.Text);
|
||||||
|
}
|
||||||
|
catch { };
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onZrifChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FilteredTextBox? txt = sender as FilteredTextBox;
|
||||||
|
if (txt is null) return;
|
||||||
|
|
||||||
|
if (lastValid != IsValid)
|
||||||
|
OnValidStateChanged(new EventArgs());
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] rifBytes = new NpDrmRif(txt.Text).Rif;
|
||||||
|
if (rifBytes.Length != 0) this.Rif = rifBytes;
|
||||||
|
}
|
||||||
|
catch { };
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
ChovySign-GUI/Global/LabeledComboBox.axaml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
|
||||||
|
x:Class="ChovySign_GUI.Global.LabeledComboBox"
|
||||||
|
Height="60">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Name="lblTxt" Content="Label:" VerticalAlignment="Bottom" Grid.Row="0"/>
|
||||||
|
<ComboBox Name="comboBox" HorizontalAlignment="Stretch" VerticalAlignment="Center" Grid.Row="1"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
81
ChovySign-GUI/Global/LabeledComboBox.axaml.cs
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Global
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
public partial class LabeledComboBox : UserControl
|
||||||
|
{
|
||||||
|
private List<string> items;
|
||||||
|
public string Label
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string? lbl = this.lblTxt.Content as string;
|
||||||
|
if (lbl is null) return "";
|
||||||
|
else return lbl;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.lblTxt.Content = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int SelectedIndex
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.comboBox.SelectedIndex;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.comboBox.SelectedIndex = value;
|
||||||
|
OnSelectionChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string SelectedItem
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string? itm = this.comboBox.SelectedItem as string;
|
||||||
|
if (itm is null) return "";
|
||||||
|
else return itm;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.comboBox.SelectedItem = value;
|
||||||
|
OnSelectionChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string[] Items
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.comboBox.Items = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? SelectionChanged;
|
||||||
|
|
||||||
|
protected virtual void OnSelectionChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if (SelectionChanged is not null)
|
||||||
|
SelectionChanged(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public LabeledComboBox()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.comboBox.SelectionChanged += onComboBoxSelectionChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onComboBoxSelectionChange(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
OnSelectionChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
ChovySign-GUI/Global/LabeledTextBox.axaml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="80"
|
||||||
|
x:Class="ChovySign_GUI.Global.LabeledTextBox"
|
||||||
|
Height="60">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Name="lblTxt" Content="Label:" VerticalAlignment="Bottom" Grid.Row="0"/>
|
||||||
|
<Global:FilteredTextBox Name="txtBox" HorizontalAlignment="Stretch" VerticalAlignment="Center" Grid.Row="1"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
104
ChovySign-GUI/Global/LabeledTextBox.axaml.cs
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Input;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using System;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Global
|
||||||
|
{
|
||||||
|
|
||||||
|
public partial class LabeledTextBox : UserControl
|
||||||
|
{
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? TextChanged;
|
||||||
|
protected virtual void OnTextChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if (TextChanged is not null)
|
||||||
|
TextChanged(this, e);
|
||||||
|
}
|
||||||
|
public int MaxLength
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.MaxLength;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.MaxLength = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Password
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.Password;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.Password = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Watermark
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.Watermark;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.Watermark = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string? AllowedChars
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.AllowedChars;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.AllowedChars = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Text
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.txtBox.Text;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.txtBox.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string Label
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string? lbl = this.lblTxt.Content as string;
|
||||||
|
if (lbl is null) return "";
|
||||||
|
else return lbl;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.lblTxt.Content = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public LabeledTextBox()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.txtBox.TextChanged += onTxtBoxTextChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onTxtBoxTextChange(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OnTextChanged(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
24
ChovySign-GUI/Global/ProgressStatus.axaml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="60"
|
||||||
|
x:Class="ChovySign_GUI.Global.ProgressStatus">
|
||||||
|
|
||||||
|
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Top">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="1*"/>
|
||||||
|
<RowDefinition Height="1*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Label Name="statusLbl" Content="Progress %" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0"/>
|
||||||
|
<Grid Grid.Row="1">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="15*"/>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<ProgressBar Name="progressVal" Maximum="100" Minimum="0" HorizontalAlignment="Stretch" VerticalAlignment="Top" Height="30" Grid.Column="0"/>
|
||||||
|
<Button Name="goButton" Click="goClick" Content="Go!" HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="1"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</UserControl>
|
66
ChovySign-GUI/Global/ProgressStatus.axaml.cs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using ChovySign_GUI.Popup.Global;
|
||||||
|
using Li.Progress;
|
||||||
|
using LibChovy;
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using static ChovySign_GUI.Popup.Global.MessageBox;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Global
|
||||||
|
{
|
||||||
|
public partial class ProgressStatus : UserControl
|
||||||
|
{
|
||||||
|
public ChovySignParameters? Parameters = null;
|
||||||
|
private ChovySign chovySign;
|
||||||
|
public ProgressStatus()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
chovySign = new ChovySign();
|
||||||
|
chovySign.RegisterCallback(onProgress);
|
||||||
|
}
|
||||||
|
public event EventHandler<EventArgs>? BeforeStart;
|
||||||
|
protected virtual void OnBeforeStart(EventArgs e)
|
||||||
|
{
|
||||||
|
if (BeforeStart is not null)
|
||||||
|
BeforeStart(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? Finished;
|
||||||
|
protected virtual void OnFinished(EventArgs e)
|
||||||
|
{
|
||||||
|
if (Finished is not null)
|
||||||
|
Finished(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void goClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
this.goButton.IsEnabled = false;
|
||||||
|
|
||||||
|
OnBeforeStart(new EventArgs());
|
||||||
|
|
||||||
|
if(Parameters is null) { await MessageBox.Show(currentWindow, "ChovySignParameters was null, cannot start!", "Invalid Parameters", MessageBoxButtons.Ok); return; }
|
||||||
|
|
||||||
|
await Task.Run(() => { chovySign.Go(Parameters); });
|
||||||
|
|
||||||
|
OnFinished(new EventArgs());
|
||||||
|
|
||||||
|
this.goButton.IsEnabled = true;
|
||||||
|
|
||||||
|
}
|
||||||
|
private void onProgress(ProgressInfo inf)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
this.statusLbl.Content = inf.CurrentProcess + " (" + inf.Done + "/" + inf.Remain + ") " + inf.ProgressInt + "%";
|
||||||
|
this.progressVal.Value = inf.Progress;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
ChovySign-GUI/ICON.ICO
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
ChovySign-GUI/ICON.PNG
Normal file
After Width: | Height: | Size: 30 KiB |
22
ChovySign-GUI/MainWindow.axaml
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Ps1="clr-namespace:ChovySign_GUI.Ps1"
|
||||||
|
xmlns:Psp="clr-namespace:ChovySign_GUI.Psp"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="850" d:DesignHeight="950"
|
||||||
|
x:Class="ChovySign_GUI.MainWindow"
|
||||||
|
Title="Chovy Sign V2" Icon="/ICON.PNG">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<TabControl>
|
||||||
|
<TabItem Header="PlayStation Portable">
|
||||||
|
<Psp:PspTab Name="pspTab"/>
|
||||||
|
</TabItem>
|
||||||
|
<TabItem Header="PlayStation 1">
|
||||||
|
<Ps1:Ps1Tab Name="ps1Tab"/>
|
||||||
|
</TabItem>
|
||||||
|
</TabControl>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
</Window>
|
12
ChovySign-GUI/MainWindow.axaml.cs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI
|
||||||
|
{
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
ChovySign-GUI/Popup/Global/CmaBackupPicker.axaml
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="ChovySign_GUI.Popup.Global.CmaBackupPicker"
|
||||||
|
Title="Select a Content Manager Backup." Icon="/ICON.PNG">
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="75"/>
|
||||||
|
<RowDefinition Height="1*"/>
|
||||||
|
<RowDefinition Height="40"/>
|
||||||
|
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Grid VerticalAlignment="Top" Grid.Row="0">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Global:BrowseButton Name="cmaDir" Label="CMA Directory" IsDirectory="True" Grid.Column="0" HorizontalAlignment="Stretch"/>
|
||||||
|
<Global:LabeledComboBox Name="accId" Label="Account ID" Grid.Column="1" HorizontalAlignment="Stretch"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<ListBox Name="backupList" VerticalAlignment="Stretch" Grid.Row="1"/>
|
||||||
|
<Button Name="selectBtn" Click="selectBtnClick" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Center">Select "Content Manager" Backup</Button>
|
||||||
|
<Label Name="lookingInLbl" Content="Looking in:" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Left"/>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
218
ChovySign-GUI/Popup/Global/CmaBackupPicker.axaml.cs
Normal file
|
@ -0,0 +1,218 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using ChovySign_GUI.Global;
|
||||||
|
using GameBuilder.Psp;
|
||||||
|
using LibChovy.Config;
|
||||||
|
using Org.BouncyCastle.Utilities.Bzip2;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using Vita.ContentManager;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Popup.Global
|
||||||
|
{
|
||||||
|
public partial class CmaBackupPicker : Window
|
||||||
|
{
|
||||||
|
|
||||||
|
private const string lookingInLabelText = "Looking in: ";
|
||||||
|
private string[]? gameDirectories;
|
||||||
|
private string backupSubFolder = "";
|
||||||
|
|
||||||
|
private string[]? filter;
|
||||||
|
|
||||||
|
private string? cmaAccountId = null;
|
||||||
|
private string? cmaBackupDir = null;
|
||||||
|
|
||||||
|
private const string backupPickerCmaDirectoryConfigKey = "BACKUP_PICKER_CMA_DIRECTORY";
|
||||||
|
|
||||||
|
public string[] Filter
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.filter = value;
|
||||||
|
reloadBackupsList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string AccountId
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (cmaAccountId is null) return "";
|
||||||
|
else return cmaAccountId;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
cmaAccountId = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string BackupDir
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if(cmaBackupDir is null)
|
||||||
|
{
|
||||||
|
string? savedBackupFolder = ChovyConfig.CurrentConfig.GetString(backupPickerCmaDirectoryConfigKey);
|
||||||
|
if (savedBackupFolder is null) savedBackupFolder = SettingsReader.BackupsFolder;
|
||||||
|
|
||||||
|
cmaBackupDir = savedBackupFolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmaBackupDir;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (Directory.Exists(value))
|
||||||
|
{
|
||||||
|
cmaBackupDir = value;
|
||||||
|
ChovyConfig.CurrentConfig.SetString(backupPickerCmaDirectoryConfigKey, cmaBackupDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private string accountIdSearchFolder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string searchIn = Path.Combine(BackupDir, this.BackupType);
|
||||||
|
return searchIn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
private string backupSearchFolder
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (AccountId == "") return accountIdSearchFolder;
|
||||||
|
return Path.Combine(accountIdSearchFolder, AccountId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public string BackupType
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return backupSubFolder;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
backupSubFolder = value;
|
||||||
|
lookingInLbl.Content = lookingInLabelText + backupSubFolder;
|
||||||
|
|
||||||
|
reloadAccountIdsList();
|
||||||
|
reloadBackupsList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reloadAccountIdsList()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string[] usedAccountIds = Directory.GetDirectories(accountIdSearchFolder);
|
||||||
|
List<string> accountIdLst = new List<string>();
|
||||||
|
foreach (string accountId in usedAccountIds)
|
||||||
|
{
|
||||||
|
string aid = Path.GetFileName(accountId);
|
||||||
|
if (aid.Length != 16) continue;
|
||||||
|
accountIdLst.Add(aid);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.accId.Items = accountIdLst.ToArray();
|
||||||
|
|
||||||
|
if (accountIdLst.Count > 0)
|
||||||
|
this.accId.SelectedIndex = 0;
|
||||||
|
}
|
||||||
|
catch { };
|
||||||
|
this.selectBtn.IsEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void selectBtnClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (gameDirectories is null) { this.Close(); return; }
|
||||||
|
if (this.backupList.SelectedIndex == -1) { this.Close(); return; }
|
||||||
|
|
||||||
|
string selectedDir = gameDirectories[this.backupList.SelectedIndex];
|
||||||
|
if (Directory.Exists(selectedDir))
|
||||||
|
this.Close(selectedDir);
|
||||||
|
else
|
||||||
|
this.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void reloadBackupsList()
|
||||||
|
{
|
||||||
|
this.selectBtn.IsEnabled = false;
|
||||||
|
this.backupList.Items = new string[0];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!Directory.Exists(backupSearchFolder)) { return; }
|
||||||
|
string[] gameBackupDirectories = Directory.GetDirectories(backupSearchFolder);
|
||||||
|
List<string> filteredGameDirectories = new List<string>();
|
||||||
|
List<string> gameList = new List<string>();
|
||||||
|
foreach (string gameDirectory in gameBackupDirectories)
|
||||||
|
{
|
||||||
|
string paramFile = Path.Combine(gameDirectory, "sce_sys", "param.sfo");
|
||||||
|
if (File.Exists(paramFile))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Sfo psfo = Sfo.ReadSfo(File.ReadAllBytes(paramFile));
|
||||||
|
string? discId = psfo["DISC_ID"] as string;
|
||||||
|
string? title = psfo["TITLE"] as string;
|
||||||
|
if (discId is null) continue;
|
||||||
|
if (title is null) continue;
|
||||||
|
|
||||||
|
// filter games set in "Filter" property.
|
||||||
|
if (filter is not null)
|
||||||
|
if (!filter.Any(discId.Contains)) continue;
|
||||||
|
|
||||||
|
gameList.Add(discId + " - " + title);
|
||||||
|
filteredGameDirectories.Add(gameDirectory);
|
||||||
|
}
|
||||||
|
catch { continue; };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.gameDirectories = filteredGameDirectories.ToArray();
|
||||||
|
this.backupList.Items = gameList;
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
public CmaBackupPicker()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.cmaDir.FilePath = BackupDir;
|
||||||
|
this.backupSubFolder = "APP";
|
||||||
|
this.accId.SelectionChanged += onAccountSelectionChanged;
|
||||||
|
this.cmaDir.FileChanged += onCmaDirChanged;
|
||||||
|
this.backupList.SelectionChanged += onSelectedBackupChanged;
|
||||||
|
reloadAccountIdsList();
|
||||||
|
reloadBackupsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onSelectedBackupChanged(object? sender, SelectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
ListBox? lstBox = sender as ListBox;
|
||||||
|
if (lstBox.SelectedIndex == -1) selectBtn.IsEnabled = false;
|
||||||
|
else selectBtn.IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onAccountSelectionChanged(object? sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
LabeledComboBox? cbox = sender as LabeledComboBox;
|
||||||
|
if (cbox is null) return;
|
||||||
|
AccountId = cbox.SelectedItem;
|
||||||
|
reloadBackupsList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onCmaDirChanged(object? sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
BrowseButton? button = sender as BrowseButton;
|
||||||
|
if (button is null) return;
|
||||||
|
if (button.ContainsFile)
|
||||||
|
{
|
||||||
|
BackupDir = button.FilePath;
|
||||||
|
reloadAccountIdsList();
|
||||||
|
reloadBackupsList();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
ChovySign-GUI/Popup/Global/KeySelector/ACTRIFMETHOD.PNG
Normal file
After Width: | Height: | Size: 38 KiB |
27
ChovySign-GUI/Popup/Global/KeySelector/ActRifMethodGUI.axaml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="450" d:DesignHeight="200"
|
||||||
|
x:Class="ChovySign_GUI.Popup.Global.KeySelector.ActRifMethodGUI"
|
||||||
|
SizeToContent="Height" Width="450" Height="200"
|
||||||
|
MinWidth="450" MinHeight="200" CanResize="False"
|
||||||
|
Title="Act/Rif Method" Icon="/ICON.PNG">
|
||||||
|
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="1*"/>
|
||||||
|
<RowDefinition Height="1*"/>
|
||||||
|
<RowDefinition Height="1*"/>
|
||||||
|
<RowDefinition Height="1*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Global:LabeledTextBox Name="idpsInput" MaxLength="32" AllowedChars="1234567890ABCDEFabcdef" Label="IDPS / ConsoleID:" Watermark="00000001010200140C00025753578942" Grid.Row="0" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
|
||||||
|
<Global:BrowseButton Name="rifFile" Extension="rif" FileTypeName="Rights Information File" Label="LICENSE.RIF: (found @ ux0:/pspemu/PSP/LICENSE)" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
|
||||||
|
<Global:BrowseButton Name="actFile" Extension="dat" FileTypeName="Activation Data" Label="ACT.DAT: (found @ tm0:/npdrm/act.dat)" Grid.Row="2" VerticalAlignment="Center" HorizontalAlignment="Stretch"/>
|
||||||
|
|
||||||
|
<Button Name="keyGen" Click="keyGenClick" Content="Generate Keys" Grid.Row="3" HorizontalAlignment="Center"/>
|
||||||
|
<CheckBox Name="hideConsoleId" Content="Hide ConsoleID" Grid.Row="3" VerticalAlignment="Bottom"/>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
155
ChovySign-GUI/Popup/Global/KeySelector/ActRifMethodGUI.axaml.cs
Normal file
|
@ -0,0 +1,155 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using ChovySign_GUI.Global;
|
||||||
|
using LibChovy.Config;
|
||||||
|
using LibChovy.VersionKey;
|
||||||
|
using GameBuilder.Psp;
|
||||||
|
using Li.Utilities;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using static ChovySign_GUI.Popup.Global.MessageBox;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Popup.Global.KeySelector
|
||||||
|
{
|
||||||
|
public partial class ActRifMethodGUI : Window
|
||||||
|
{
|
||||||
|
private const string keygenHideConsoleIdKey = "KEYGEN_HIDE_CONSOLEID";
|
||||||
|
private const string keygenIdpsKey = "KEYGEN_CID";
|
||||||
|
private const string keygenActKey = "KEYGEN_ACT";
|
||||||
|
private const string keygenRifKey = "KEYGEN_RIF";
|
||||||
|
|
||||||
|
private NpDrmRif? rif;
|
||||||
|
|
||||||
|
public NpDrmRif? Rif
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return rif;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public ActRifMethodGUI()
|
||||||
|
{
|
||||||
|
bool? lastHideConsoleId = ChovyConfig.CurrentConfig.GetBool(keygenHideConsoleIdKey);
|
||||||
|
byte[]? lastCid = ChovyConfig.CurrentConfig.GetBytes(keygenIdpsKey);
|
||||||
|
string? lastAct = ChovyConfig.CurrentConfig.GetString(keygenActKey);
|
||||||
|
string? lastRif = ChovyConfig.CurrentConfig.GetString(keygenRifKey);
|
||||||
|
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
// reload previous settings
|
||||||
|
if(lastHideConsoleId is not null)
|
||||||
|
{
|
||||||
|
hideConsoleId.IsChecked = lastHideConsoleId;
|
||||||
|
this.idpsInput.Password = (bool)lastHideConsoleId;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastAct is not null)
|
||||||
|
actFile.FilePath = lastAct;
|
||||||
|
|
||||||
|
if (lastCid is not null)
|
||||||
|
idpsInput.Text = BitConverter.ToString(lastCid).Replace("-", "");
|
||||||
|
if (lastAct is not null)
|
||||||
|
actFile.FilePath = lastAct;
|
||||||
|
if (lastRif is not null)
|
||||||
|
rifFile.FilePath = lastRif;
|
||||||
|
|
||||||
|
hideConsoleId.Checked += onChangeCidState;
|
||||||
|
hideConsoleId.Unchecked += onChangeCidState;
|
||||||
|
|
||||||
|
idpsInput.TextChanged += onIdpsChange;
|
||||||
|
actFile.FileChanged += onActFileChange;
|
||||||
|
rifFile.FileChanged += onRifFileChange;
|
||||||
|
|
||||||
|
check();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onRifFileChange(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
BrowseButton? filePth = sender as BrowseButton;
|
||||||
|
if (filePth is null) return;
|
||||||
|
if (!filePth.ContainsFile) return;
|
||||||
|
ChovyConfig.CurrentConfig.SetString(keygenRifKey, filePth.FilePath);
|
||||||
|
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onActFileChange(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
BrowseButton? filePth = sender as BrowseButton;
|
||||||
|
if (filePth is null) return;
|
||||||
|
if (!filePth.ContainsFile) return;
|
||||||
|
ChovyConfig.CurrentConfig.SetString(keygenActKey, filePth.FilePath);
|
||||||
|
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onIdpsChange(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
LabeledTextBox? labledTxtBox = sender as LabeledTextBox;
|
||||||
|
|
||||||
|
if (labledTxtBox is null) return;
|
||||||
|
if (labledTxtBox.Text.Length != 32) return;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] idps = MathUtil.StringToByteArray(labledTxtBox.Text);
|
||||||
|
ChovyConfig.CurrentConfig.SetBytes(keygenIdpsKey, idps);
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
catch{ };
|
||||||
|
}
|
||||||
|
|
||||||
|
private void keyGenClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
NpDrmInfo[] keys = new NpDrmInfo[0x5];
|
||||||
|
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// read data
|
||||||
|
byte[] idps = MathUtil.StringToByteArray(idpsInput.Text);
|
||||||
|
byte[] act = File.ReadAllBytes(actFile.FilePath);
|
||||||
|
byte[] rif = File.ReadAllBytes(rifFile.FilePath);
|
||||||
|
|
||||||
|
// generate keys
|
||||||
|
for (int i = 0; i < 0x5; i++)
|
||||||
|
keys[i] = ActRifMethod.GetVersionKey(act, rif, idps, i);
|
||||||
|
|
||||||
|
this.rif = new NpDrmRif(rif);
|
||||||
|
|
||||||
|
this.Close(keys);
|
||||||
|
|
||||||
|
}
|
||||||
|
catch { MessageBox.Show(currentWindow, "Failed to generate key...", "Failed", MessageBoxButtons.Ok); }
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check()
|
||||||
|
{
|
||||||
|
bool s = true;
|
||||||
|
|
||||||
|
if (idpsInput.Text.Length != 32) s = false;
|
||||||
|
if (!actFile.ContainsFile) s = false;
|
||||||
|
if (!rifFile.ContainsFile) s = false;
|
||||||
|
|
||||||
|
keyGen.IsEnabled = s;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onChangeCidState(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
CheckBox? checkBox = sender as CheckBox;
|
||||||
|
if (checkBox is null) return;
|
||||||
|
|
||||||
|
bool? hideConsoleId = checkBox.IsChecked;
|
||||||
|
if (hideConsoleId is null) return;
|
||||||
|
|
||||||
|
ChovyConfig.CurrentConfig.SetBool(keygenHideConsoleIdKey, (bool)hideConsoleId);
|
||||||
|
this.idpsInput.Password = (bool)hideConsoleId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
ChovySign-GUI/Popup/Global/KeySelector/EBOOTMETHOD1.PNG
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
ChovySign-GUI/Popup/Global/KeySelector/EBOOTMETHOD2.PNG
Normal file
After Width: | Height: | Size: 28 KiB |
BIN
ChovySign-GUI/Popup/Global/KeySelector/KEYSTXTMETHOD.PNG
Normal file
After Width: | Height: | Size: 27 KiB |
|
@ -0,0 +1,29 @@
|
||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="1400" d:DesignHeight="150"
|
||||||
|
x:Class="ChovySign_GUI.Popup.Global.KeySelector.KeyObtainMethods"
|
||||||
|
Title="VersionKey Obtain Method" SizeToContent="WidthAndHeight"
|
||||||
|
MaxWidth="1400" MaxHeight="150" Icon="/ICON.PNG">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="5*"/>
|
||||||
|
<ColumnDefinition Width="5*"/>
|
||||||
|
<ColumnDefinition Width="5*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="30"/>
|
||||||
|
<RowDefinition Height="5*"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Button Content="EBOOT.PBP Method" Click="ebootMethodClick" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
|
<Button Content="IDPS+RIF+ACT Method" Click="actRifMethodClick" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
|
<Button Content="KEYS.TXT Method" Click="keysTxtMethodClick" Grid.Row="0" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||||
|
|
||||||
|
<Image Name="ebootMethodPs1Graphic" Source="/Popup/Global/KeySelector/EBOOTMETHOD1.PNG" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
|
||||||
|
<Image Name="ebootMethodPspGraphic" Source="/Popup/Global/KeySelector/EBOOTMETHOD2.PNG" Grid.Row="1" Grid.Column="0" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
|
||||||
|
<Image Name="actRifMethodGraphic" Source="/Popup/Global/KeySelector/ACTRIFMETHOD.PNG" Grid.Row="1" Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
|
||||||
|
<Image Name="keysTxtMethodGraphic" Source="/Popup/Global/KeySelector/KEYSTXTMETHOD.PNG" Grid.Row="1" Grid.Column="2" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
|
||||||
|
</Grid>
|
||||||
|
</Window>
|
|
@ -0,0 +1,52 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using LibChovy.VersionKey;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Popup.Global.KeySelector
|
||||||
|
{
|
||||||
|
public partial class KeyObtainMethods : Window
|
||||||
|
{
|
||||||
|
private int keyIndex;
|
||||||
|
private VersionKeyMethod method;
|
||||||
|
public VersionKeyMethod Method
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return method;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public int KeyIndex
|
||||||
|
{
|
||||||
|
set
|
||||||
|
{
|
||||||
|
keyIndex = value;
|
||||||
|
if (keyIndex == 1) { ebootMethodPspGraphic.IsVisible = false; ebootMethodPs1Graphic.IsVisible = true; }
|
||||||
|
else { ebootMethodPspGraphic.IsVisible = true; ebootMethodPs1Graphic.IsVisible = false; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ebootMethodClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.method = VersionKeyMethod.EBOOT_PBP_METHOD;
|
||||||
|
this.Close(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void actRifMethodClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.method = VersionKeyMethod.ACT_RIF_METHOD;
|
||||||
|
this.Close(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void keysTxtMethodClick(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
this.method = VersionKeyMethod.KEYS_TXT_METHOD;
|
||||||
|
this.Close(method);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public KeyObtainMethods()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
ChovySign-GUI/Popup/Global/KeySelector/VKEYMETHODS.PNG
Normal file
After Width: | Height: | Size: 115 KiB |
19
ChovySign-GUI/Popup/Global/MessageBox.axaml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<Window xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="ChovySign_GUI.Popup.Global.MessageBox"
|
||||||
|
SizeToContent="WidthAndHeight" CanResize="False" Icon="/ICON.PNG">
|
||||||
|
<StackPanel HorizontalAlignment="Center">
|
||||||
|
<TextBlock Foreground="LightGreen" HorizontalAlignment="Center" Name="Text"/>
|
||||||
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Name="Buttons">
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Style Selector="Button">
|
||||||
|
<Setter Property="Margin" Value="5"/>
|
||||||
|
</Style>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</Window>
|
||||||
|
|
77
ChovySign-GUI/Popup/Global/MessageBox.axaml.cs
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Popup.Global
|
||||||
|
{
|
||||||
|
partial class MessageBox : Window
|
||||||
|
{
|
||||||
|
public enum MessageBoxButtons
|
||||||
|
{
|
||||||
|
Ok,
|
||||||
|
OkCancel,
|
||||||
|
YesNo,
|
||||||
|
YesNoCancel
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum MessageBoxResult
|
||||||
|
{
|
||||||
|
Ok,
|
||||||
|
Cancel,
|
||||||
|
Yes,
|
||||||
|
No
|
||||||
|
}
|
||||||
|
|
||||||
|
public MessageBox()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Task<MessageBoxResult> Show(Window parent, string text, string title, MessageBoxButtons buttons)
|
||||||
|
{
|
||||||
|
var msgbox = new MessageBox()
|
||||||
|
{
|
||||||
|
Title = title
|
||||||
|
};
|
||||||
|
msgbox.FindControl<TextBlock>("Text").Text = text;
|
||||||
|
var buttonPanel = msgbox.FindControl<StackPanel>("Buttons");
|
||||||
|
|
||||||
|
var res = MessageBoxResult.Ok;
|
||||||
|
|
||||||
|
void AddButton(string caption, MessageBoxResult r, bool def = false)
|
||||||
|
{
|
||||||
|
var btn = new Button { Content = caption };
|
||||||
|
btn.Click += (_, __) => {
|
||||||
|
res = r;
|
||||||
|
msgbox.Close();
|
||||||
|
};
|
||||||
|
buttonPanel.Children.Add(btn);
|
||||||
|
if (def)
|
||||||
|
res = r;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttons == MessageBoxButtons.Ok || buttons == MessageBoxButtons.OkCancel)
|
||||||
|
AddButton("Ok", MessageBoxResult.Ok, true);
|
||||||
|
if (buttons == MessageBoxButtons.YesNo || buttons == MessageBoxButtons.YesNoCancel)
|
||||||
|
{
|
||||||
|
AddButton("Yes", MessageBoxResult.Yes);
|
||||||
|
AddButton("No", MessageBoxResult.No, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buttons == MessageBoxButtons.OkCancel || buttons == MessageBoxButtons.YesNoCancel)
|
||||||
|
AddButton("Cancel", MessageBoxResult.Cancel, true);
|
||||||
|
|
||||||
|
|
||||||
|
var tcs = new TaskCompletionSource<MessageBoxResult>();
|
||||||
|
msgbox.Closed += delegate { tcs.TrySetResult(res); };
|
||||||
|
if (parent != null)
|
||||||
|
msgbox.ShowDialog(parent);
|
||||||
|
else msgbox.Show();
|
||||||
|
return tcs.Task;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
21
ChovySign-GUI/Program.cs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
using Avalonia;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI
|
||||||
|
{
|
||||||
|
internal class Program
|
||||||
|
{
|
||||||
|
// Initialization code. Don't use any Avalonia, third-party APIs or any
|
||||||
|
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
|
||||||
|
// yet and stuff might break.
|
||||||
|
[STAThread]
|
||||||
|
public static void Main(string[] args) => BuildAvaloniaApp()
|
||||||
|
.StartWithClassicDesktopLifetime(args);
|
||||||
|
|
||||||
|
// Avalonia configuration, don't remove; also used by visual designer.
|
||||||
|
public static AppBuilder BuildAvaloniaApp()
|
||||||
|
=> AppBuilder.Configure<App>()
|
||||||
|
.UsePlatformDetect()
|
||||||
|
.LogToTrace();
|
||||||
|
}
|
||||||
|
}
|
35
ChovySign-GUI/Ps1/CueSelector.axaml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="300"
|
||||||
|
x:Class="ChovySign_GUI.Ps1.CueSelector">
|
||||||
|
<!-- Bin/Cue Image selector -->
|
||||||
|
<Border Padding="5 5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="10*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Image HorizontalAlignment="Stretch" VerticalAlignment="Center" Source="/Ps1/PS1CD.PNG" Grid.Column="0"/>
|
||||||
|
|
||||||
|
<Grid Grid.Column="1">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
|
<Global:BrowseButton Name="discCue1" Extension="cue" FileTypeName="PS1 Cue Sheet" Label="Disc 1:" Grid.Row="0"/>
|
||||||
|
<Global:BrowseButton Name="discCue2" Extension="cue" FileTypeName="PS1 Cue Sheet" Label="Disc 2:" Grid.Row="1"/>
|
||||||
|
<Global:BrowseButton Name="discCue3" Extension="cue" FileTypeName="PS1 Cue Sheet" Label="Disc 3:" Grid.Row="2"/>
|
||||||
|
<Global:BrowseButton Name="discCue4" Extension="cue" FileTypeName="PS1 Cue Sheet" Label="Disc 4:" Grid.Row="3"/>
|
||||||
|
<Global:BrowseButton Name="discCue5" Extension="cue" FileTypeName="PS1 Cue Sheet" Label="Disc 5:" Grid.Row="4"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
88
ChovySign-GUI/Ps1/CueSelector.axaml.cs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Ps1
|
||||||
|
{
|
||||||
|
public partial class CueSelector : UserControl
|
||||||
|
{
|
||||||
|
public event EventHandler<EventArgs>? DiscsSelected;
|
||||||
|
|
||||||
|
protected virtual void OnDiscsSelected(EventArgs e)
|
||||||
|
{
|
||||||
|
if (DiscsSelected is not null)
|
||||||
|
DiscsSelected(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public string[] Discs
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
List<string> discList = new List<string>();
|
||||||
|
|
||||||
|
if (discCue1.ContainsFile) discList.Add(discCue1.FilePath);
|
||||||
|
if (discCue2.ContainsFile) discList.Add(discCue2.FilePath);
|
||||||
|
if (discCue3.ContainsFile) discList.Add(discCue3.FilePath);
|
||||||
|
if (discCue4.ContainsFile) discList.Add(discCue4.FilePath);
|
||||||
|
if (discCue5.ContainsFile) discList.Add(discCue5.FilePath);
|
||||||
|
|
||||||
|
return discList.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AnyDiscsSelected
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return Discs.Length > 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void clearAllAfter(int amt)
|
||||||
|
{
|
||||||
|
if (amt < 1) { discCue1.FilePath = ""; discCue1.IsEnabled = false; }
|
||||||
|
else discCue1.IsEnabled = true;
|
||||||
|
|
||||||
|
if (amt < 2) { discCue2.FilePath = ""; discCue2.IsEnabled = false; }
|
||||||
|
else discCue2.IsEnabled = true;
|
||||||
|
|
||||||
|
if (amt < 3) { discCue3.FilePath = ""; discCue3.IsEnabled = false; }
|
||||||
|
else discCue3.IsEnabled = true;
|
||||||
|
|
||||||
|
if (amt < 4) { discCue4.FilePath = ""; discCue4.IsEnabled = false; }
|
||||||
|
else discCue4.IsEnabled = true;
|
||||||
|
|
||||||
|
if (amt < 5) { discCue5.FilePath = ""; discCue5.IsEnabled = false; }
|
||||||
|
else discCue5.IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void disableCueBoxes()
|
||||||
|
{
|
||||||
|
if (!discCue1.ContainsFile) clearAllAfter(1);
|
||||||
|
else if (!discCue2.ContainsFile) clearAllAfter(2);
|
||||||
|
else if (!discCue3.ContainsFile) clearAllAfter(3);
|
||||||
|
else if (!discCue4.ContainsFile) clearAllAfter(4);
|
||||||
|
else if (!discCue5.ContainsFile) clearAllAfter(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CueSelector()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
disableCueBoxes();
|
||||||
|
|
||||||
|
discCue1.FileChanged += onFileChange;
|
||||||
|
discCue2.FileChanged += onFileChange;
|
||||||
|
discCue3.FileChanged += onFileChange;
|
||||||
|
discCue4.FileChanged += onFileChange;
|
||||||
|
discCue5.FileChanged += onFileChange;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onFileChange(object? sender, System.EventArgs e)
|
||||||
|
{
|
||||||
|
disableCueBoxes();
|
||||||
|
OnDiscsSelected(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
29
ChovySign-GUI/Ps1/GameInfoSelector.axaml
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="250"
|
||||||
|
x:Class="ChovySign_GUI.Ps1.GameInfoSelector">
|
||||||
|
<Border Padding="5 5" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="7*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Image Name="iconPreview" HorizontalAlignment="Center" VerticalAlignment="Center" Width="80" Height="80" Grid.Column="0"/>
|
||||||
|
<Grid HorizontalAlignment="Stretch" Grid.Column="1">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
<RowDefinition Height="52"/>
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Global:LabeledTextBox HorizontalAlignment="Stretch" Name="gameTitle" Label="Title:" Watermark="The BEST PlayStation 1 Game" MaxLength="128" Grid.Row="0"/>
|
||||||
|
<Global:BrowseButton HorizontalAlignment="Stretch" Name="iconFile" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="icon0.png:" Grid.Row="1"/>
|
||||||
|
<Global:BrowseButton HorizontalAlignment="Stretch" Name="pic0File" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="pic0.png:" Grid.Row="2"/>
|
||||||
|
<Global:BrowseButton HorizontalAlignment="Stretch" Name="pic1File" Extension="png" FileTypeName="Portable Network Graphics" Watermark="(Default)" Label="pic1.png:" Grid.Row="3"/>
|
||||||
|
</Grid>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
173
ChovySign-GUI/Ps1/GameInfoSelector.axaml.cs
Normal file
|
@ -0,0 +1,173 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using ChovySign_GUI.Global;
|
||||||
|
using ChovySign_GUI.Popup.Global;
|
||||||
|
using GameBuilder.Pops;
|
||||||
|
using LibChovy.Art;
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
#pragma warning disable CS8601 // Possible null reference assignment.
|
||||||
|
// beacuse im checking if its null in the setter, but visual studio doesnt seem to understand :d
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Ps1
|
||||||
|
{
|
||||||
|
public partial class GameInfoSelector : UserControl
|
||||||
|
{
|
||||||
|
|
||||||
|
private byte[] iconCache;
|
||||||
|
private byte[] pic0Cache;
|
||||||
|
private byte[] pic1Cache;
|
||||||
|
|
||||||
|
public string Title
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.gameTitle.Text is null) return "";
|
||||||
|
return this.gameTitle.Text;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.gameTitle.Text = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public byte[] Icon0
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return iconCache;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if(value is not null)
|
||||||
|
iconCache = value;
|
||||||
|
|
||||||
|
loadIcon(iconCache);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Pic0
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return pic0Cache;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value is not null)
|
||||||
|
pic0Cache = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Pic1
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return pic1Cache;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value is not null)
|
||||||
|
pic1Cache = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void loadIcon(byte[] imageData)
|
||||||
|
{
|
||||||
|
using (MemoryStream imageStream = new MemoryStream(imageData))
|
||||||
|
this.iconPreview.Source = new Bitmap(imageStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task GetGameInfo(string cueFile)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
DiscInfo disc = new DiscInfo(cueFile);
|
||||||
|
Title = disc.DiscName;
|
||||||
|
|
||||||
|
byte[] newCover = await Downloader.DownloadCover(disc);
|
||||||
|
loadIcon(newCover);
|
||||||
|
iconCache = newCover;
|
||||||
|
}
|
||||||
|
catch (Exception) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task<byte[]?> doLoad(BrowseButton imgFile, int width, int height)
|
||||||
|
{
|
||||||
|
imgFile.IsEnabled = false;
|
||||||
|
|
||||||
|
if (imgFile.FilePath != "")
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
byte[] imageData = await Resizer.LoadImage(imgFile.FilePath, width, height);
|
||||||
|
|
||||||
|
imgFile.IsEnabled = true;
|
||||||
|
return imageData;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
await MessageBox.Show(currentWindow, "The image you selected is could not be loaded!", "Invalid image.", MessageBox.MessageBoxButtons.Ok);
|
||||||
|
|
||||||
|
imgFile.FilePath = "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
imgFile.IsEnabled = true;
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void onIconChange(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
BrowseButton? button = sender as BrowseButton;
|
||||||
|
if (button is null) return;
|
||||||
|
Icon0 = await doLoad(button, 80, 80);
|
||||||
|
}
|
||||||
|
private async void onPic0Change(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
BrowseButton? button = sender as BrowseButton;
|
||||||
|
if (button is null) return;
|
||||||
|
Pic0 = await doLoad(button, 310, 180);
|
||||||
|
}
|
||||||
|
private async void onPic1Change(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
BrowseButton? button = sender as BrowseButton;
|
||||||
|
if (button is null) return;
|
||||||
|
Pic1 = await doLoad(button, 480, 272);
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler<EventArgs>? TitleChanged;
|
||||||
|
protected virtual void OnTitleChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if (TitleChanged is not null)
|
||||||
|
TitleChanged(this, e);
|
||||||
|
}
|
||||||
|
public GameInfoSelector()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
iconCache = LibChovy.Resources.ICON0;
|
||||||
|
pic0Cache = LibChovy.Resources.PIC0;
|
||||||
|
pic1Cache = LibChovy.Resources.PIC1;
|
||||||
|
|
||||||
|
loadIcon(iconCache);
|
||||||
|
|
||||||
|
this.iconFile.FileChanged += onIconChange;
|
||||||
|
this.pic0File.FileChanged += onPic0Change;
|
||||||
|
this.pic1File.FileChanged += onPic1Change;
|
||||||
|
|
||||||
|
this.gameTitle.TextChanged += onTitleChange;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onTitleChange(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OnTitleChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma warning restore CS8601 // Possible null reference assignment.
|
BIN
ChovySign-GUI/Ps1/PS1CD.PNG
Normal file
After Width: | Height: | Size: 164 KiB |
35
ChovySign-GUI/Ps1/Ps1Tab.axaml
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
xmlns:Ps1="clr-namespace:ChovySign_GUI.Ps1"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="900"
|
||||||
|
x:Class="ChovySign_GUI.Ps1.Ps1Tab">
|
||||||
|
<Grid>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="40" />
|
||||||
|
<RowDefinition Height="1.5*" />
|
||||||
|
<RowDefinition Height="1.3*" />
|
||||||
|
<RowDefinition Height="0.6*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
<ColumnDefinition Width="10*"/>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Global:KeySelector Name="keySelector" KeyIndex="1" Grid.Row="0" Grid.Column="1"/>
|
||||||
|
|
||||||
|
<Ps1:CueSelector Name="discSelector" Grid.Row="1" Grid.Column="1"/>
|
||||||
|
<Ps1:GameInfoSelector Name="gameInfo" Grid.Row="2" Grid.Column="1"/>
|
||||||
|
|
||||||
|
<Global:ProgressStatus VerticalAlignment="Center" Name="progressStatus" Grid.Row="3" Grid.Column="1"/>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Credits -->
|
||||||
|
<Global:DevkitToggle Name="devkitAccount" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
|
||||||
|
<Label Content="Li, Dots TB, SquallATF, Motoharu, Davee" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
106
ChovySign-GUI/Ps1/Ps1Tab.axaml.cs
Normal file
|
@ -0,0 +1,106 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using ChovySign_GUI.Global;
|
||||||
|
using ChovySign_GUI.Popup.Global;
|
||||||
|
using GameBuilder.Psp;
|
||||||
|
using LibChovy;
|
||||||
|
using LibChovy.Config;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using Vita.ContentManager;
|
||||||
|
using static ChovySign_GUI.Popup.Global.MessageBox;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Ps1
|
||||||
|
{
|
||||||
|
public partial class Ps1Tab : UserControl
|
||||||
|
{
|
||||||
|
public Ps1Tab()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
discSelector.DiscsSelected += onDiscSelected;
|
||||||
|
keySelector.ValidStateChanged += onKeyValidityChanged;
|
||||||
|
gameInfo.TitleChanged += onTitleChanged;
|
||||||
|
|
||||||
|
progressStatus.BeforeStart += onProcessStarting;
|
||||||
|
progressStatus.Finished += onProcessFinished;
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private async void onProcessFinished(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
keySelector.IsEnabled = true;
|
||||||
|
discSelector.IsEnabled = true;
|
||||||
|
devkitAccount.IsEnabled = true;
|
||||||
|
gameInfo.IsEnabled = true;
|
||||||
|
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
_ = App.PlayFinishSound();
|
||||||
|
await MessageBox.Show(currentWindow, "Finished creating PS1 Game!\nCan now go restore it to your PSVita using Content Manager.", "Done!", MessageBoxButtons.Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onProcessStarting(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
keySelector.IsEnabled = false;
|
||||||
|
discSelector.IsEnabled = false;
|
||||||
|
devkitAccount.IsEnabled = false;
|
||||||
|
gameInfo.IsEnabled = false;
|
||||||
|
|
||||||
|
if (keySelector.Rif is null) return;
|
||||||
|
if (keySelector.VersionKey is null) return;
|
||||||
|
|
||||||
|
NpDrmRif rifInfo = new NpDrmRif(keySelector.Rif);
|
||||||
|
NpDrmInfo drmInfo = new NpDrmInfo(keySelector.VersionKey, rifInfo.ContentId, keySelector.KeyIndex);
|
||||||
|
PspParameters pspParameters = new PspParameters(drmInfo, rifInfo);
|
||||||
|
|
||||||
|
PopsParameters popsParameters = new PopsParameters(drmInfo, rifInfo);
|
||||||
|
|
||||||
|
foreach (string disc in discSelector.Discs)
|
||||||
|
popsParameters.AddCd(disc);
|
||||||
|
|
||||||
|
popsParameters.Name = gameInfo.Title;
|
||||||
|
popsParameters.Icon0 = gameInfo.Icon0;
|
||||||
|
popsParameters.Pic0 = gameInfo.Pic0;
|
||||||
|
popsParameters.Pic1 = gameInfo.Pic1;
|
||||||
|
|
||||||
|
if (devkitAccount.IsDevkitMode)
|
||||||
|
popsParameters.Account = new Account(0);
|
||||||
|
|
||||||
|
progressStatus.Parameters = popsParameters;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onTitleChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void check()
|
||||||
|
{
|
||||||
|
this.progressStatus.IsEnabled = (discSelector.AnyDiscsSelected && keySelector.IsValid && gameInfo.Title != "");
|
||||||
|
}
|
||||||
|
private void onKeyValidityChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
KeySelector? keySelector = sender as KeySelector;
|
||||||
|
if (keySelector is null) return;
|
||||||
|
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void onDiscSelected(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
CueSelector? cueSelector = sender as CueSelector;
|
||||||
|
if (cueSelector is null) return;
|
||||||
|
|
||||||
|
if (cueSelector.AnyDiscsSelected)
|
||||||
|
await this.gameInfo.GetGameInfo(cueSelector.Discs.First());
|
||||||
|
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
26
ChovySign-GUI/Psp/IsoSelector.axaml
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="145"
|
||||||
|
x:Class="ChovySign_GUI.Psp.IsoSelector">
|
||||||
|
<!-- ISO Image selector -->
|
||||||
|
<Border Padding="10 10" HorizontalAlignment="Stretch" VerticalAlignment="Center">
|
||||||
|
<Grid>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*" />
|
||||||
|
<ColumnDefinition Width="5*" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Grid Grid.Column="0">
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="5*" />
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Image HorizontalAlignment="Center" VerticalAlignment="Center" Width="120" Source="/Psp/UMD.PNG" Grid.Row="0"/>
|
||||||
|
<CheckBox Name="compressPbp" Content="Compress PBP" HorizontalAlignment="Center" Grid.Row="1"/>
|
||||||
|
</Grid>
|
||||||
|
<Global:BrowseButton Name="umdFile" Extension="iso" FileTypeName="Universal Media Disc 'UMD' Disc Image (ISO9660)" Label="UMD Image:" Grid.Column="1"/>
|
||||||
|
</Grid>
|
||||||
|
</Border>
|
||||||
|
</UserControl>
|
54
ChovySign-GUI/Psp/IsoSelector.axaml.cs
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using GameBuilder.Psp;
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Psp
|
||||||
|
{
|
||||||
|
public partial class IsoSelector : UserControl
|
||||||
|
{
|
||||||
|
public event EventHandler<EventArgs>? UmdChanged;
|
||||||
|
protected virtual void OnUmdChanged(EventArgs e)
|
||||||
|
{
|
||||||
|
if (UmdChanged is not null)
|
||||||
|
UmdChanged(this, e);
|
||||||
|
}
|
||||||
|
public bool Compress
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (this.compressPbp.IsChecked is null) return false;
|
||||||
|
return (bool)this.compressPbp.IsChecked;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
this.compressPbp.IsChecked = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool HasUmd
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return this.umdFile.ContainsFile;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public UmdInfo? Umd
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!this.umdFile.ContainsFile) return null;
|
||||||
|
return new UmdInfo(this.umdFile.FilePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public IsoSelector()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
this.umdFile.FileChanged += onUmdFileChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUmdFileChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
OnUmdChanged(new EventArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
32
ChovySign-GUI/Psp/PspTab.axaml
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:Global="clr-namespace:ChovySign_GUI.Global"
|
||||||
|
xmlns:Psp="clr-namespace:ChovySign_GUI.Psp"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="900"
|
||||||
|
x:Class="ChovySign_GUI.Psp.PspTab">
|
||||||
|
<Grid>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
<RowDefinition Height="5*" />
|
||||||
|
<RowDefinition Height="1*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
<ColumnDefinition Width="10*"/>
|
||||||
|
<ColumnDefinition Width="1*"/>
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
|
<Global:KeySelector Name="keySelector" KeyIndex="2" Grid.Row="0" Grid.Column="1"/>
|
||||||
|
<Psp:IsoSelector Name="isoSelector" Grid.Row="1" Grid.Column="1"/>
|
||||||
|
<Global:ProgressStatus Name="progressStatus" Grid.Row="2" Grid.Column="1"/>
|
||||||
|
|
||||||
|
</Grid>
|
||||||
|
|
||||||
|
<!-- Credits -->
|
||||||
|
<Global:DevkitToggle Name="devkitAccount" VerticalAlignment="Bottom" HorizontalAlignment="Left"/>
|
||||||
|
<Label Content="Li, Dots TB, SquallATF, Motoharu, Davee" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
82
ChovySign-GUI/Psp/PspTab.axaml.cs
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using ChovySign_GUI.Popup.Global;
|
||||||
|
using GameBuilder.Psp;
|
||||||
|
using LibChovy;
|
||||||
|
using LibChovy.Config;
|
||||||
|
using System;
|
||||||
|
using System.Media;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Vita.ContentManager;
|
||||||
|
using static ChovySign_GUI.Popup.Global.MessageBox;
|
||||||
|
|
||||||
|
namespace ChovySign_GUI.Psp
|
||||||
|
{
|
||||||
|
public partial class PspTab : UserControl
|
||||||
|
{
|
||||||
|
|
||||||
|
private void check()
|
||||||
|
{
|
||||||
|
this.progressStatus.IsEnabled = (this.keySelector.IsValid && this.isoSelector.HasUmd);
|
||||||
|
}
|
||||||
|
public PspTab()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
keySelector.ValidStateChanged += onValidStateChange;
|
||||||
|
isoSelector.UmdChanged += onUmdChanged;
|
||||||
|
|
||||||
|
progressStatus.BeforeStart += onProcessStarting;
|
||||||
|
progressStatus.Finished += onProcessFinished;
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async void onProcessFinished(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
keySelector.IsEnabled = true;
|
||||||
|
isoSelector.IsEnabled = true;
|
||||||
|
devkitAccount.IsEnabled = true;
|
||||||
|
|
||||||
|
Window? currentWindow = this.VisualRoot as Window;
|
||||||
|
if (currentWindow is not Window) throw new Exception("could not find current window");
|
||||||
|
|
||||||
|
_ = App.PlayFinishSound();
|
||||||
|
await MessageBox.Show(currentWindow, "Finished creating PSP Game!\nCan now go restore it to your PSVita using Content Manager.", "Done!", MessageBoxButtons.Ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onProcessStarting(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
keySelector.IsEnabled = false;
|
||||||
|
devkitAccount.IsEnabled = false;
|
||||||
|
isoSelector.IsEnabled = false;
|
||||||
|
if (keySelector.Rif is null) return;
|
||||||
|
if (keySelector.VersionKey is null) return;
|
||||||
|
|
||||||
|
NpDrmRif rifInfo = new NpDrmRif(keySelector.Rif);
|
||||||
|
NpDrmInfo drmInfo = new NpDrmInfo(keySelector.VersionKey, rifInfo.ContentId, keySelector.KeyIndex);
|
||||||
|
PspParameters pspParameters = new PspParameters(drmInfo, rifInfo);
|
||||||
|
|
||||||
|
UmdInfo? umd = isoSelector.Umd;
|
||||||
|
if (umd is null) return;
|
||||||
|
|
||||||
|
pspParameters.Umd = umd;
|
||||||
|
pspParameters.Compress = isoSelector.Compress;
|
||||||
|
|
||||||
|
if (devkitAccount.IsDevkitMode)
|
||||||
|
pspParameters.Account = new Account(0);
|
||||||
|
|
||||||
|
progressStatus.Parameters = pspParameters;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUmdChanged(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onValidStateChange(object? sender, EventArgs e)
|
||||||
|
{
|
||||||
|
check();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
ChovySign-GUI/Psp/UMD.PNG
Normal file
After Width: | Height: | Size: 25 KiB |
72
ChovySign-GUI/Resource.Designer.cs
generated
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
// <auto-generated>
|
||||||
|
// This code was generated by a tool.
|
||||||
|
// Runtime Version:4.0.30319.42000
|
||||||
|
//
|
||||||
|
// Changes to this file may cause incorrect behavior and will be lost if
|
||||||
|
// the code is regenerated.
|
||||||
|
// </auto-generated>
|
||||||
|
//------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
namespace ChovySign_GUI {
|
||||||
|
using System;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
|
public class Resource {
|
||||||
|
|
||||||
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
|
internal Resource() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
public static global::System.Resources.ResourceManager ResourceManager {
|
||||||
|
get {
|
||||||
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ChovySign_GUI.Resource", typeof(Resource).Assembly);
|
||||||
|
resourceMan = temp;
|
||||||
|
}
|
||||||
|
return resourceMan;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
public static global::System.Globalization.CultureInfo Culture {
|
||||||
|
get {
|
||||||
|
return resourceCulture;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
resourceCulture = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized resource of type System.IO.UnmanagedMemoryStream similar to System.IO.MemoryStream.
|
||||||
|
/// </summary>
|
||||||
|
public static System.IO.UnmanagedMemoryStream FINISHSND {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetStream("FINISHSND", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
124
ChovySign-GUI/Resource.resx
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<root>
|
||||||
|
<!--
|
||||||
|
Microsoft ResX Schema
|
||||||
|
|
||||||
|
Version 2.0
|
||||||
|
|
||||||
|
The primary goals of this format is to allow a simple XML format
|
||||||
|
that is mostly human readable. The generation and parsing of the
|
||||||
|
various data types are done through the TypeConverter classes
|
||||||
|
associated with the data types.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
... ado.net/XML headers & schema ...
|
||||||
|
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||||
|
<resheader name="version">2.0</resheader>
|
||||||
|
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||||
|
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||||
|
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||||
|
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||||
|
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||||
|
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||||
|
</data>
|
||||||
|
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||||
|
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||||
|
<comment>This is a comment</comment>
|
||||||
|
</data>
|
||||||
|
|
||||||
|
There are any number of "resheader" rows that contain simple
|
||||||
|
name/value pairs.
|
||||||
|
|
||||||
|
Each data row contains a name, and value. The row also contains a
|
||||||
|
type or mimetype. Type corresponds to a .NET class that support
|
||||||
|
text/value conversion through the TypeConverter architecture.
|
||||||
|
Classes that don't support this are serialized and stored with the
|
||||||
|
mimetype set.
|
||||||
|
|
||||||
|
The mimetype is used for serialized objects, and tells the
|
||||||
|
ResXResourceReader how to depersist the object. This is currently not
|
||||||
|
extensible. For a given mimetype the value must be set accordingly:
|
||||||
|
|
||||||
|
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||||
|
that the ResXResourceWriter will generate, however the reader can
|
||||||
|
read any of the formats listed below.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.binary.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.soap.base64
|
||||||
|
value : The object must be serialized with
|
||||||
|
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
|
||||||
|
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||||
|
value : The object must be serialized into a byte array
|
||||||
|
: using a System.ComponentModel.TypeConverter
|
||||||
|
: and then encoded with base64 encoding.
|
||||||
|
-->
|
||||||
|
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||||
|
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||||
|
<xsd:element name="root" msdata:IsDataSet="true">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:choice maxOccurs="unbounded">
|
||||||
|
<xsd:element name="metadata">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="assembly">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:attribute name="alias" type="xsd:string" />
|
||||||
|
<xsd:attribute name="name" type="xsd:string" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="data">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||||
|
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||||
|
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||||
|
<xsd:attribute ref="xml:space" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
<xsd:element name="resheader">
|
||||||
|
<xsd:complexType>
|
||||||
|
<xsd:sequence>
|
||||||
|
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||||
|
</xsd:sequence>
|
||||||
|
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:choice>
|
||||||
|
</xsd:complexType>
|
||||||
|
</xsd:element>
|
||||||
|
</xsd:schema>
|
||||||
|
<resheader name="resmimetype">
|
||||||
|
<value>text/microsoft-resx</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="version">
|
||||||
|
<value>2.0</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="reader">
|
||||||
|
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<resheader name="writer">
|
||||||
|
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</resheader>
|
||||||
|
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
|
||||||
|
<data name="FINISHSND" type="System.Resources.ResXFileRef, System.Windows.Forms">
|
||||||
|
<value>Resources\Finished.wav;System.IO.MemoryStream, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||||
|
</data>
|
||||||
|
</root>
|
BIN
ChovySign-GUI/Resources/Finished.wav
Normal file
5
ChovySign-GUI/Roots.xml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
<linker>
|
||||||
|
<!-- Can be removed if CompiledBinding and no reflection are used -->
|
||||||
|
<assembly fullname="ChovySign_GUI" preserve="All" />
|
||||||
|
<assembly fullname="Avalonia.Themes.Fluent" preserve="All" />
|
||||||
|
</linker>
|
18
ChovySign-GUI/app.manifest
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<!-- This manifest is used on Windows only.
|
||||||
|
Don't remove it as it might cause problems with window transparency and embeded controls.
|
||||||
|
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
|
||||||
|
<assemblyIdentity version="1.0.0.0" name="AvaloniaTest.Desktop"/>
|
||||||
|
|
||||||
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
|
<application>
|
||||||
|
<!-- A list of the Windows versions that this application has been tested on
|
||||||
|
and is designed to work with. Uncomment the appropriate elements
|
||||||
|
and Windows will automatically select the most compatible environment. -->
|
||||||
|
|
||||||
|
<!-- Windows 10 -->
|
||||||
|
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
|
||||||
|
</application>
|
||||||
|
</compatibility>
|
||||||
|
</assembly>
|
87
ChovySign2.sln
Normal file
|
@ -0,0 +1,87 @@
|
||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.33516.290
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PspCrypto", "PspCrypto\PspCrypto.csproj", "{A60BE4C2-C0D2-42FD-BCFF-631B9AFC62FE}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PbpResign", "PbpResign\PbpResign.csproj", "{834B9F97-1B63-48EB-922E-0FC155BB2481}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{75BBF537-8ED8-42A3-AA8B-80A730F1B3F2} = {75BBF537-8ED8-42A3-AA8B-80A730F1B3F2}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GameBuilder", "GameBuilder\GameBuilder.csproj", "{D1DF66DB-52BE-489C-A292-525BC71F2BB2}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{63475285-AAD2-4DE9-B698-AFC9FAA58AC8} = {63475285-AAD2-4DE9-B698-AFC9FAA58AC8}
|
||||||
|
{BF155D74-2923-432F-8566-26D83B15EEE8} = {BF155D74-2923-432F-8566-26D83B15EEE8}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ChovySign-CLI", "ChovySign-CLI\ChovySign-CLI.csproj", "{90FB2C00-CC46-4B77-8E24-C5F7458AB068}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{A60BE4C2-C0D2-42FD-BCFF-631B9AFC62FE} = {A60BE4C2-C0D2-42FD-BCFF-631B9AFC62FE}
|
||||||
|
{E8782E3B-ED26-4C41-BEEC-798CDD0FECCC} = {E8782E3B-ED26-4C41-BEEC-798CDD0FECCC}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscUtils", "DiscUtils\DiscUtils.csproj", "{BF155D74-2923-432F-8566-26D83B15EEE8}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Vita", "Vita\Vita.csproj", "{75BBF537-8ED8-42A3-AA8B-80A730F1B3F2}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{63475285-AAD2-4DE9-B698-AFC9FAA58AC8} = {63475285-AAD2-4DE9-B698-AFC9FAA58AC8}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LiLib", "LiLib\LiLib.csproj", "{63475285-AAD2-4DE9-B698-AFC9FAA58AC8}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LibChovy", "LibChovy\LibChovy.csproj", "{E8782E3B-ED26-4C41-BEEC-798CDD0FECCC}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ChovySign-GUI", "ChovySign-GUI\ChovySign-GUI.csproj", "{902BD264-EAB6-4011-85FC-C8F8A2B11D90}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{A60BE4C2-C0D2-42FD-BCFF-631B9AFC62FE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A60BE4C2-C0D2-42FD-BCFF-631B9AFC62FE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A60BE4C2-C0D2-42FD-BCFF-631B9AFC62FE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A60BE4C2-C0D2-42FD-BCFF-631B9AFC62FE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{834B9F97-1B63-48EB-922E-0FC155BB2481}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{834B9F97-1B63-48EB-922E-0FC155BB2481}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{834B9F97-1B63-48EB-922E-0FC155BB2481}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{834B9F97-1B63-48EB-922E-0FC155BB2481}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{D1DF66DB-52BE-489C-A292-525BC71F2BB2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{D1DF66DB-52BE-489C-A292-525BC71F2BB2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{D1DF66DB-52BE-489C-A292-525BC71F2BB2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{D1DF66DB-52BE-489C-A292-525BC71F2BB2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{90FB2C00-CC46-4B77-8E24-C5F7458AB068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{90FB2C00-CC46-4B77-8E24-C5F7458AB068}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{90FB2C00-CC46-4B77-8E24-C5F7458AB068}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{90FB2C00-CC46-4B77-8E24-C5F7458AB068}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BF155D74-2923-432F-8566-26D83B15EEE8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BF155D74-2923-432F-8566-26D83B15EEE8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BF155D74-2923-432F-8566-26D83B15EEE8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BF155D74-2923-432F-8566-26D83B15EEE8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{75BBF537-8ED8-42A3-AA8B-80A730F1B3F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{75BBF537-8ED8-42A3-AA8B-80A730F1B3F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{75BBF537-8ED8-42A3-AA8B-80A730F1B3F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{75BBF537-8ED8-42A3-AA8B-80A730F1B3F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{63475285-AAD2-4DE9-B698-AFC9FAA58AC8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{63475285-AAD2-4DE9-B698-AFC9FAA58AC8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{63475285-AAD2-4DE9-B698-AFC9FAA58AC8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{63475285-AAD2-4DE9-B698-AFC9FAA58AC8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{E8782E3B-ED26-4C41-BEEC-798CDD0FECCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{E8782E3B-ED26-4C41-BEEC-798CDD0FECCC}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{E8782E3B-ED26-4C41-BEEC-798CDD0FECCC}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{E8782E3B-ED26-4C41-BEEC-798CDD0FECCC}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{902BD264-EAB6-4011-85FC-C8F8A2B11D90}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{902BD264-EAB6-4011-85FC-C8F8A2B11D90}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{902BD264-EAB6-4011-85FC-C8F8A2B11D90}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{902BD264-EAB6-4011-85FC-C8F8A2B11D90}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {CEC62870-B8D5-4E33-9144-7C2B88EE8F73}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
61
DiscUtils/ApplePartitionMap/BlockZero.cs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.ApplePartitionMap
|
||||||
|
{
|
||||||
|
internal sealed class BlockZero : IByteArraySerializable
|
||||||
|
{
|
||||||
|
public uint BlockCount;
|
||||||
|
public ushort BlockSize;
|
||||||
|
public ushort DeviceId;
|
||||||
|
public ushort DeviceType;
|
||||||
|
public ushort DriverCount;
|
||||||
|
public uint DriverData;
|
||||||
|
public ushort Signature;
|
||||||
|
|
||||||
|
public int Size
|
||||||
|
{
|
||||||
|
get { return 512; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadFrom(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
Signature = EndianUtilities.ToUInt16BigEndian(buffer, offset + 0);
|
||||||
|
BlockSize = EndianUtilities.ToUInt16BigEndian(buffer, offset + 2);
|
||||||
|
BlockCount = EndianUtilities.ToUInt32BigEndian(buffer, offset + 4);
|
||||||
|
DeviceType = EndianUtilities.ToUInt16BigEndian(buffer, offset + 8);
|
||||||
|
DeviceId = EndianUtilities.ToUInt16BigEndian(buffer, offset + 10);
|
||||||
|
DriverData = EndianUtilities.ToUInt32BigEndian(buffer, offset + 12);
|
||||||
|
DriverCount = EndianUtilities.ToUInt16LittleEndian(buffer, offset + 16);
|
||||||
|
|
||||||
|
return 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteTo(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
153
DiscUtils/ApplePartitionMap/PartitionMap.cs
Normal file
|
@ -0,0 +1,153 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Partitions;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.ApplePartitionMap
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Interprets Apple Partition Map structures that partition a disk.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class PartitionMap : PartitionTable
|
||||||
|
{
|
||||||
|
private readonly PartitionMapEntry[] _partitions;
|
||||||
|
private readonly Stream _stream;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the PartitionMap class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">Stream containing the contents of a disk.</param>
|
||||||
|
public PartitionMap(Stream stream)
|
||||||
|
{
|
||||||
|
_stream = stream;
|
||||||
|
|
||||||
|
stream.Position = 0;
|
||||||
|
byte[] initialBytes = StreamUtilities.ReadExact(stream, 1024);
|
||||||
|
|
||||||
|
BlockZero b0 = new BlockZero();
|
||||||
|
b0.ReadFrom(initialBytes, 0);
|
||||||
|
|
||||||
|
PartitionMapEntry initialPart = new PartitionMapEntry(_stream);
|
||||||
|
initialPart.ReadFrom(initialBytes, 512);
|
||||||
|
|
||||||
|
byte[] partTableData = StreamUtilities.ReadExact(stream, (int)(initialPart.MapEntries - 1) * 512);
|
||||||
|
|
||||||
|
_partitions = new PartitionMapEntry[initialPart.MapEntries - 1];
|
||||||
|
for (uint i = 0; i < initialPart.MapEntries - 1; ++i)
|
||||||
|
{
|
||||||
|
_partitions[i] = new PartitionMapEntry(_stream);
|
||||||
|
_partitions[i].ReadFrom(partTableData, (int)(512 * i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the GUID of the disk, always returns Guid.Empty.
|
||||||
|
/// </summary>
|
||||||
|
public override Guid DiskGuid
|
||||||
|
{
|
||||||
|
get { return Guid.Empty; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the partitions present on the disk.
|
||||||
|
/// </summary>
|
||||||
|
public override ReadOnlyCollection<PartitionInfo> Partitions
|
||||||
|
{
|
||||||
|
get { return new ReadOnlyCollection<PartitionInfo>(_partitions); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new partition that encompasses the entire disk.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The partition type.</param>
|
||||||
|
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||||
|
/// <returns>The index of the partition.</returns>
|
||||||
|
/// <remarks>The partition table must be empty before this method is called,
|
||||||
|
/// otherwise IOException is thrown.</remarks>
|
||||||
|
public override int Create(WellKnownPartitionType type, bool active)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new partition with a target size.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">The target size (in bytes).</param>
|
||||||
|
/// <param name="type">The partition type.</param>
|
||||||
|
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||||
|
/// <returns>The index of the new partition.</returns>
|
||||||
|
public override int Create(long size, WellKnownPartitionType type, bool active)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new aligned partition that encompasses the entire disk.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type">The partition type.</param>
|
||||||
|
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||||
|
/// <param name="alignment">The alignment (in byte).</param>
|
||||||
|
/// <returns>The index of the partition.</returns>
|
||||||
|
/// <remarks>The partition table must be empty before this method is called,
|
||||||
|
/// otherwise IOException is thrown.</remarks>
|
||||||
|
/// <remarks>
|
||||||
|
/// Traditionally partitions were aligned to the physical structure of the underlying disk,
|
||||||
|
/// however with modern storage greater efficiency is acheived by aligning partitions on
|
||||||
|
/// large values that are a power of two.
|
||||||
|
/// </remarks>
|
||||||
|
public override int CreateAligned(WellKnownPartitionType type, bool active, int alignment)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new aligned partition with a target size.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="size">The target size (in bytes).</param>
|
||||||
|
/// <param name="type">The partition type.</param>
|
||||||
|
/// <param name="active">Whether the partition is active (bootable).</param>
|
||||||
|
/// <param name="alignment">The alignment (in byte).</param>
|
||||||
|
/// <returns>The index of the new partition.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// Traditionally partitions were aligned to the physical structure of the underlying disk,
|
||||||
|
/// however with modern storage greater efficiency is achieved by aligning partitions on
|
||||||
|
/// large values that are a power of two.
|
||||||
|
/// </remarks>
|
||||||
|
public override int CreateAligned(long size, WellKnownPartitionType type, bool active, int alignment)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a partition at a given index.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="index">The index of the partition.</param>
|
||||||
|
public override void Delete(int index)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
112
DiscUtils/ApplePartitionMap/PartitionMapEntry.cs
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Partitions;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.ApplePartitionMap
|
||||||
|
{
|
||||||
|
internal sealed class PartitionMapEntry : PartitionInfo, IByteArraySerializable
|
||||||
|
{
|
||||||
|
private readonly Stream _diskStream;
|
||||||
|
public uint BootBlock;
|
||||||
|
public uint BootBytes;
|
||||||
|
public uint Flags;
|
||||||
|
public uint LogicalBlocks;
|
||||||
|
public uint LogicalBlockStart;
|
||||||
|
public uint MapEntries;
|
||||||
|
public string Name;
|
||||||
|
public uint PhysicalBlocks;
|
||||||
|
public uint PhysicalBlockStart;
|
||||||
|
public ushort Signature;
|
||||||
|
public string Type;
|
||||||
|
|
||||||
|
public PartitionMapEntry(Stream diskStream)
|
||||||
|
{
|
||||||
|
_diskStream = diskStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override byte BiosType
|
||||||
|
{
|
||||||
|
get { return 0xAF; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long FirstSector
|
||||||
|
{
|
||||||
|
get { return PhysicalBlockStart; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Guid GuidType
|
||||||
|
{
|
||||||
|
get { return Guid.Empty; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long LastSector
|
||||||
|
{
|
||||||
|
get { return PhysicalBlockStart + PhysicalBlocks - 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string TypeAsString
|
||||||
|
{
|
||||||
|
get { return Type; }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal override PhysicalVolumeType VolumeType
|
||||||
|
{
|
||||||
|
get { return PhysicalVolumeType.ApplePartition; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Size
|
||||||
|
{
|
||||||
|
get { return 512; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int ReadFrom(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
Signature = EndianUtilities.ToUInt16BigEndian(buffer, offset + 0);
|
||||||
|
MapEntries = EndianUtilities.ToUInt32BigEndian(buffer, offset + 4);
|
||||||
|
PhysicalBlockStart = EndianUtilities.ToUInt32BigEndian(buffer, offset + 8);
|
||||||
|
PhysicalBlocks = EndianUtilities.ToUInt32BigEndian(buffer, offset + 12);
|
||||||
|
Name = EndianUtilities.BytesToString(buffer, offset + 16, 32).TrimEnd('\0');
|
||||||
|
Type = EndianUtilities.BytesToString(buffer, offset + 48, 32).TrimEnd('\0');
|
||||||
|
LogicalBlockStart = EndianUtilities.ToUInt32BigEndian(buffer, offset + 80);
|
||||||
|
LogicalBlocks = EndianUtilities.ToUInt32BigEndian(buffer, offset + 84);
|
||||||
|
Flags = EndianUtilities.ToUInt32BigEndian(buffer, offset + 88);
|
||||||
|
BootBlock = EndianUtilities.ToUInt32BigEndian(buffer, offset + 92);
|
||||||
|
BootBytes = EndianUtilities.ToUInt32BigEndian(buffer, offset + 96);
|
||||||
|
|
||||||
|
return 512;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteTo(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override SparseStream Open()
|
||||||
|
{
|
||||||
|
return new SubStream(_diskStream, PhysicalBlockStart * 512, PhysicalBlocks * 512);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
66
DiscUtils/ApplePartitionMap/PartitionMapFactory.cs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Partitions;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.ApplePartitionMap
|
||||||
|
{
|
||||||
|
[PartitionTableFactory]
|
||||||
|
internal sealed class PartitionMapFactory : PartitionTableFactory
|
||||||
|
{
|
||||||
|
public override bool DetectIsPartitioned(Stream s)
|
||||||
|
{
|
||||||
|
if (s.Length < 1024)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
s.Position = 0;
|
||||||
|
|
||||||
|
byte[] initialBytes = StreamUtilities.ReadExact(s, 1024);
|
||||||
|
|
||||||
|
BlockZero b0 = new BlockZero();
|
||||||
|
b0.ReadFrom(initialBytes, 0);
|
||||||
|
if (b0.Signature != 0x4552)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartitionMapEntry initialPart = new PartitionMapEntry(s);
|
||||||
|
initialPart.ReadFrom(initialBytes, 512);
|
||||||
|
|
||||||
|
return initialPart.Signature == 0x504d;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override PartitionTable DetectPartitionTable(VirtualDisk disk)
|
||||||
|
{
|
||||||
|
if (!DetectIsPartitioned(disk.Content))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new PartitionMap(disk.Content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
38
DiscUtils/Archives/FileRecord.cs
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace DiscUtils.Archives
|
||||||
|
{
|
||||||
|
internal sealed class FileRecord
|
||||||
|
{
|
||||||
|
public long Length;
|
||||||
|
public string Name;
|
||||||
|
public long Start;
|
||||||
|
|
||||||
|
public FileRecord(string name, long start, long length)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Start = start;
|
||||||
|
Length = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
144
DiscUtils/Archives/TarFile.cs
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.Archives
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Minimal tar file format implementation.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class TarFile
|
||||||
|
{
|
||||||
|
private readonly Dictionary<string, FileRecord> _files;
|
||||||
|
private readonly Stream _fileStream;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the TarFile class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileStream">The Tar file.</param>
|
||||||
|
public TarFile(Stream fileStream)
|
||||||
|
{
|
||||||
|
_fileStream = fileStream;
|
||||||
|
_files = new Dictionary<string, FileRecord>();
|
||||||
|
|
||||||
|
TarHeader hdr = new TarHeader();
|
||||||
|
byte[] hdrBuf = StreamUtilities.ReadExact(_fileStream, TarHeader.Length);
|
||||||
|
hdr.ReadFrom(hdrBuf, 0);
|
||||||
|
while (hdr.FileLength != 0 || !string.IsNullOrEmpty(hdr.FileName))
|
||||||
|
{
|
||||||
|
FileRecord record = new FileRecord(hdr.FileName, _fileStream.Position, hdr.FileLength);
|
||||||
|
_files.Add(record.Name, record);
|
||||||
|
_fileStream.Position += (hdr.FileLength + 511) / 512 * 512;
|
||||||
|
|
||||||
|
hdrBuf = StreamUtilities.ReadExact(_fileStream, TarHeader.Length);
|
||||||
|
hdr.ReadFrom(hdrBuf, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Tries to open a file contained in the archive, if it exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to the file within the archive.</param>
|
||||||
|
/// <param name="stream">A stream containing the file contents, or null.</param>
|
||||||
|
/// <returns><c>true</c> if the file could be opened, else <c>false</c>.</returns>
|
||||||
|
public bool TryOpenFile(string path, out Stream stream)
|
||||||
|
{
|
||||||
|
if (_files.ContainsKey(path))
|
||||||
|
{
|
||||||
|
FileRecord file = _files[path];
|
||||||
|
stream = new SubStream(_fileStream, file.Start, file.Length);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
stream = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Open a file contained in the archive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to the file within the archive.</param>
|
||||||
|
/// <returns>A stream containing the file contents.</returns>
|
||||||
|
/// <exception cref="FileNotFoundException">Thrown if the file is not found.</exception>
|
||||||
|
public Stream OpenFile(string path)
|
||||||
|
{
|
||||||
|
if (_files.ContainsKey(path))
|
||||||
|
{
|
||||||
|
FileRecord file = _files[path];
|
||||||
|
return new SubStream(_fileStream, file.Start, file.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new FileNotFoundException("File is not in archive", path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if a given file exists in the archive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file path to test.</param>
|
||||||
|
/// <returns><c>true</c> if the file is present, else <c>false</c>.</returns>
|
||||||
|
public bool FileExists(string path)
|
||||||
|
{
|
||||||
|
return _files.ContainsKey(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if a given directory exists in the archive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file path to test.</param>
|
||||||
|
/// <returns><c>true</c> if the directory is present, else <c>false</c>.</returns>
|
||||||
|
public bool DirExists(string path)
|
||||||
|
{
|
||||||
|
string searchStr = path;
|
||||||
|
searchStr = searchStr.Replace(@"\", "/");
|
||||||
|
searchStr = searchStr.EndsWith(@"/", StringComparison.Ordinal) ? searchStr : searchStr + @"/";
|
||||||
|
|
||||||
|
foreach (string filePath in _files.Keys)
|
||||||
|
{
|
||||||
|
if (filePath.StartsWith(searchStr, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal IEnumerable<FileRecord> GetFiles(string dir)
|
||||||
|
{
|
||||||
|
string searchStr = dir;
|
||||||
|
searchStr = searchStr.Replace(@"\", "/");
|
||||||
|
searchStr = searchStr.EndsWith(@"/", StringComparison.Ordinal) ? searchStr : searchStr + @"/";
|
||||||
|
|
||||||
|
foreach (string filePath in _files.Keys)
|
||||||
|
{
|
||||||
|
if (filePath.StartsWith(searchStr, StringComparison.Ordinal))
|
||||||
|
{
|
||||||
|
yield return _files[filePath];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
DiscUtils/Archives/TarFileBuilder.cs
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.Archives
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Builder to create UNIX Tar archive files.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class TarFileBuilder : StreamBuilder
|
||||||
|
{
|
||||||
|
private readonly List<UnixBuildFileRecord> _files;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="TarFileBuilder"/> class.
|
||||||
|
/// </summary>
|
||||||
|
public TarFileBuilder()
|
||||||
|
{
|
||||||
|
_files = new List<UnixBuildFileRecord>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a file to the tar archive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the file.</param>
|
||||||
|
/// <param name="buffer">The file data.</param>
|
||||||
|
public void AddFile(string name, byte[] buffer)
|
||||||
|
{
|
||||||
|
_files.Add(new UnixBuildFileRecord(name, buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a file to the tar archive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the file.</param>
|
||||||
|
/// <param name="buffer">The file data.</param>
|
||||||
|
/// <param name="fileMode">The access mode of the file.</param>
|
||||||
|
/// <param name="ownerId">The uid of the owner.</param>
|
||||||
|
/// <param name="groupId">The gid of the owner.</param>
|
||||||
|
/// <param name="modificationTime">The modification time for the file.</param>
|
||||||
|
public void AddFile(
|
||||||
|
string name, byte[] buffer, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||||
|
DateTime modificationTime)
|
||||||
|
{
|
||||||
|
_files.Add(new UnixBuildFileRecord(name, buffer, fileMode, ownerId, groupId, modificationTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a file to the tar archive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the file.</param>
|
||||||
|
/// <param name="stream">The file data.</param>
|
||||||
|
public void AddFile(string name, Stream stream)
|
||||||
|
{
|
||||||
|
_files.Add(new UnixBuildFileRecord(name, stream));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a file to the tar archive.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="name">The name of the file.</param>
|
||||||
|
/// <param name="stream">The file data.</param>
|
||||||
|
/// <param name="fileMode">The access mode of the file.</param>
|
||||||
|
/// <param name="ownerId">The uid of the owner.</param>
|
||||||
|
/// <param name="groupId">The gid of the owner.</param>
|
||||||
|
/// <param name="modificationTime">The modification time for the file.</param>
|
||||||
|
public void AddFile(
|
||||||
|
string name, Stream stream, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||||
|
DateTime modificationTime)
|
||||||
|
{
|
||||||
|
_files.Add(new UnixBuildFileRecord(name, stream, fileMode, ownerId, groupId, modificationTime));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override List<BuilderExtent> FixExtents(out long totalLength)
|
||||||
|
{
|
||||||
|
List<BuilderExtent> result = new List<BuilderExtent>(_files.Count * 2 + 2);
|
||||||
|
long pos = 0;
|
||||||
|
|
||||||
|
foreach (UnixBuildFileRecord file in _files)
|
||||||
|
{
|
||||||
|
BuilderExtent fileContentExtent = file.Fix(pos + TarHeader.Length);
|
||||||
|
|
||||||
|
result.Add(new TarHeaderExtent(
|
||||||
|
pos, file.Name, fileContentExtent.Length, file.FileMode, file.OwnerId, file.GroupId,
|
||||||
|
file.ModificationTime));
|
||||||
|
pos += TarHeader.Length;
|
||||||
|
|
||||||
|
result.Add(fileContentExtent);
|
||||||
|
pos += MathUtilities.RoundUp(fileContentExtent.Length, 512);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Two empty 512-byte blocks at end of tar file.
|
||||||
|
result.Add(new BuilderBufferExtent(pos, new byte[1024]));
|
||||||
|
|
||||||
|
totalLength = pos + 1024;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
102
DiscUtils/Archives/TarHeader.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.Archives
|
||||||
|
{
|
||||||
|
internal sealed class TarHeader
|
||||||
|
{
|
||||||
|
public const int Length = 512;
|
||||||
|
public long FileLength;
|
||||||
|
public UnixFilePermissions FileMode;
|
||||||
|
|
||||||
|
public string FileName;
|
||||||
|
public int GroupId;
|
||||||
|
public DateTime ModificationTime;
|
||||||
|
public int OwnerId;
|
||||||
|
|
||||||
|
public void ReadFrom(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
FileName = ReadNullTerminatedString(buffer, offset + 0, 100);
|
||||||
|
FileMode = (UnixFilePermissions)OctalToLong(ReadNullTerminatedString(buffer, offset + 100, 8));
|
||||||
|
OwnerId = (int)OctalToLong(ReadNullTerminatedString(buffer, offset + 108, 8));
|
||||||
|
GroupId = (int)OctalToLong(ReadNullTerminatedString(buffer, offset + 116, 8));
|
||||||
|
FileLength = OctalToLong(ReadNullTerminatedString(buffer, offset + 124, 12));
|
||||||
|
ModificationTime = OctalToLong(ReadNullTerminatedString(buffer, offset + 136, 12)).FromUnixTimeSeconds().DateTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WriteTo(byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
Array.Clear(buffer, offset, Length);
|
||||||
|
|
||||||
|
EndianUtilities.StringToBytes(FileName, buffer, offset, 99);
|
||||||
|
EndianUtilities.StringToBytes(LongToOctal((long)FileMode, 7), buffer, offset + 100, 7);
|
||||||
|
EndianUtilities.StringToBytes(LongToOctal(OwnerId, 7), buffer, offset + 108, 7);
|
||||||
|
EndianUtilities.StringToBytes(LongToOctal(GroupId, 7), buffer, offset + 116, 7);
|
||||||
|
EndianUtilities.StringToBytes(LongToOctal(FileLength, 11), buffer, offset + 124, 11);
|
||||||
|
EndianUtilities.StringToBytes(LongToOctal(Convert.ToUInt32((new DateTimeOffset(ModificationTime)).ToUnixTimeSeconds()), 11), buffer, offset + 136, 11);
|
||||||
|
|
||||||
|
// Checksum
|
||||||
|
EndianUtilities.StringToBytes(new string(' ', 8), buffer, offset + 148, 8);
|
||||||
|
long checkSum = 0;
|
||||||
|
for (int i = 0; i < 512; ++i)
|
||||||
|
{
|
||||||
|
checkSum += buffer[offset + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
EndianUtilities.StringToBytes(LongToOctal(checkSum, 7), buffer, offset + 148, 7);
|
||||||
|
buffer[155] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string ReadNullTerminatedString(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
return EndianUtilities.BytesToString(buffer, offset, length).TrimEnd('\0');
|
||||||
|
}
|
||||||
|
|
||||||
|
private static long OctalToLong(string value)
|
||||||
|
{
|
||||||
|
long result = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < value.Length; ++i)
|
||||||
|
{
|
||||||
|
result = result * 8 + (value[i] - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string LongToOctal(long value, int length)
|
||||||
|
{
|
||||||
|
string result = string.Empty;
|
||||||
|
|
||||||
|
while (value > 0)
|
||||||
|
{
|
||||||
|
result = (char)('0' + value % 8) + result;
|
||||||
|
value = value / 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new string('0', length - result.Length) + result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
DiscUtils/Archives/TarHeaderExtent.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.Archives
|
||||||
|
{
|
||||||
|
internal sealed class TarHeaderExtent : BuilderBufferExtent
|
||||||
|
{
|
||||||
|
private readonly long _fileLength;
|
||||||
|
private readonly string _fileName;
|
||||||
|
private readonly int _groupId;
|
||||||
|
private readonly UnixFilePermissions _mode;
|
||||||
|
private readonly DateTime _modificationTime;
|
||||||
|
private readonly int _ownerId;
|
||||||
|
|
||||||
|
public TarHeaderExtent(long start, string fileName, long fileLength, UnixFilePermissions mode, int ownerId,
|
||||||
|
int groupId, DateTime modificationTime)
|
||||||
|
: base(start, 512)
|
||||||
|
{
|
||||||
|
_fileName = fileName;
|
||||||
|
_fileLength = fileLength;
|
||||||
|
_mode = mode;
|
||||||
|
_ownerId = ownerId;
|
||||||
|
_groupId = groupId;
|
||||||
|
_modificationTime = modificationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TarHeaderExtent(long start, string fileName, long fileLength)
|
||||||
|
: this(start, fileName, fileLength, 0, 0, 0, DateTimeOffsetExtensions.UnixEpoch) {}
|
||||||
|
|
||||||
|
protected override byte[] GetBuffer()
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[TarHeader.Length];
|
||||||
|
|
||||||
|
TarHeader header = new TarHeader();
|
||||||
|
header.FileName = _fileName;
|
||||||
|
header.FileLength = _fileLength;
|
||||||
|
header.FileMode = _mode;
|
||||||
|
header.OwnerId = _ownerId;
|
||||||
|
header.GroupId = _groupId;
|
||||||
|
header.ModificationTime = _modificationTime;
|
||||||
|
header.WriteTo(buffer, 0);
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
DiscUtils/Archives/UnixBuildFileRecord.cs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.Archives
|
||||||
|
{
|
||||||
|
internal sealed class UnixBuildFileRecord
|
||||||
|
{
|
||||||
|
private readonly BuilderExtentSource _source;
|
||||||
|
|
||||||
|
public UnixBuildFileRecord(string name, byte[] buffer)
|
||||||
|
: this(name, new BuilderBufferExtentSource(buffer), 0, 0, 0, DateTimeOffsetExtensions.UnixEpoch) {}
|
||||||
|
|
||||||
|
public UnixBuildFileRecord(string name, Stream stream)
|
||||||
|
: this(name, new BuilderStreamExtentSource(stream), 0, 0, 0, DateTimeOffsetExtensions.UnixEpoch) {}
|
||||||
|
|
||||||
|
public UnixBuildFileRecord(
|
||||||
|
string name, byte[] buffer, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||||
|
DateTime modificationTime)
|
||||||
|
: this(name, new BuilderBufferExtentSource(buffer), fileMode, ownerId, groupId, modificationTime) {}
|
||||||
|
|
||||||
|
public UnixBuildFileRecord(
|
||||||
|
string name, Stream stream, UnixFilePermissions fileMode, int ownerId, int groupId,
|
||||||
|
DateTime modificationTime)
|
||||||
|
: this(name, new BuilderStreamExtentSource(stream), fileMode, ownerId, groupId, modificationTime) {}
|
||||||
|
|
||||||
|
public UnixBuildFileRecord(string name, BuilderExtentSource fileSource, UnixFilePermissions fileMode,
|
||||||
|
int ownerId, int groupId, DateTime modificationTime)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
_source = fileSource;
|
||||||
|
FileMode = fileMode;
|
||||||
|
OwnerId = ownerId;
|
||||||
|
GroupId = groupId;
|
||||||
|
ModificationTime = modificationTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UnixFilePermissions FileMode { get; }
|
||||||
|
|
||||||
|
public int GroupId { get; }
|
||||||
|
|
||||||
|
public DateTime ModificationTime { get; }
|
||||||
|
|
||||||
|
public string Name { get; }
|
||||||
|
|
||||||
|
public int OwnerId { get; }
|
||||||
|
|
||||||
|
public BuilderExtent Fix(long pos)
|
||||||
|
{
|
||||||
|
return _source.Fix(pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
99
DiscUtils/ChsAddress.cs
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class whose instances represent a CHS (Cylinder, Head, Sector) address on a disk.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Instances of this class are immutable.</remarks>
|
||||||
|
public sealed class ChsAddress
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The address of the first sector on any disk.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly ChsAddress First = new ChsAddress(0, 0, 1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ChsAddress class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cylinder">The number of cylinders of the disk.</param>
|
||||||
|
/// <param name="head">The number of heads (aka platters) of the disk.</param>
|
||||||
|
/// <param name="sector">The number of sectors per track/cylinder of the disk.</param>
|
||||||
|
public ChsAddress(int cylinder, int head, int sector)
|
||||||
|
{
|
||||||
|
Cylinder = cylinder;
|
||||||
|
Head = head;
|
||||||
|
Sector = sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the cylinder number (zero-based).
|
||||||
|
/// </summary>
|
||||||
|
public int Cylinder { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the head (zero-based).
|
||||||
|
/// </summary>
|
||||||
|
public int Head { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the sector number (one-based).
|
||||||
|
/// </summary>
|
||||||
|
public int Sector { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines if this object is equivalent to another.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to test against.</param>
|
||||||
|
/// <returns><c>true</c> if the <paramref name="obj"/> is equivalent, else <c>false</c>.</returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
if (obj == null || obj.GetType() != GetType())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChsAddress other = (ChsAddress)obj;
|
||||||
|
|
||||||
|
return Cylinder == other.Cylinder && Head == other.Head && Sector == other.Sector;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Calculates the hash code for this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The hash code.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Cylinder.GetHashCode() ^ Head.GetHashCode() ^ Sector.GetHashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string representation of this object, in the form (C/H/S).
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The string representation.</returns>
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return "(" + Cylinder + "/" + Head + "/" + Sector + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
75
DiscUtils/ClusterMap.cs
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Class that identifies the role of each cluster in a file system.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class ClusterMap
|
||||||
|
{
|
||||||
|
private readonly object[] _clusterToFileId;
|
||||||
|
private readonly ClusterRoles[] _clusterToRole;
|
||||||
|
private readonly Dictionary<object, string[]> _fileIdToPaths;
|
||||||
|
|
||||||
|
public ClusterMap(ClusterRoles[] clusterToRole, object[] clusterToFileId,
|
||||||
|
Dictionary<object, string[]> fileIdToPaths)
|
||||||
|
{
|
||||||
|
_clusterToRole = clusterToRole;
|
||||||
|
_clusterToFileId = clusterToFileId;
|
||||||
|
_fileIdToPaths = fileIdToPaths;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the role of a cluster within the file system.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cluster">The cluster to inspect.</param>
|
||||||
|
/// <returns>The clusters role (or roles).</returns>
|
||||||
|
public ClusterRoles GetRole(long cluster)
|
||||||
|
{
|
||||||
|
if (_clusterToRole == null || _clusterToRole.Length < cluster)
|
||||||
|
{
|
||||||
|
return ClusterRoles.None;
|
||||||
|
}
|
||||||
|
return _clusterToRole[cluster];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a cluster to a list of file names.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cluster">The cluster to inspect.</param>
|
||||||
|
/// <returns>A list of paths that map to the cluster.</returns>
|
||||||
|
/// <remarks>A list is returned because on file systems with the notion of
|
||||||
|
/// hard links, a cluster may correspond to multiple directory entries.</remarks>
|
||||||
|
public string[] ClusterToPaths(long cluster)
|
||||||
|
{
|
||||||
|
if ((GetRole(cluster) & (ClusterRoles.DataFile | ClusterRoles.SystemFile)) != 0)
|
||||||
|
{
|
||||||
|
object fileId = _clusterToFileId[cluster];
|
||||||
|
return _fileIdToPaths[fileId];
|
||||||
|
}
|
||||||
|
return new string[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
50
DiscUtils/ClusterRoles.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Enumeration of possible cluster roles.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>A cluster may be in more than one role.</remarks>
|
||||||
|
[Flags]
|
||||||
|
public enum ClusterRoles
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Unknown, or unspecified role.
|
||||||
|
/// </summary>
|
||||||
|
None = 0x00,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cluster is free.
|
||||||
|
/// </summary>
|
||||||
|
Free = 0x01,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cluster is in use by a normal file.
|
||||||
|
/// </summary>
|
||||||
|
DataFile = 0x02,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cluster is in use by a system file.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This isn't a file marked with the 'system' attribute,
|
||||||
|
/// rather files that form part of the file system namespace but also
|
||||||
|
/// form part of the file system meta-data.</remarks>
|
||||||
|
SystemFile = 0x04,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cluster is in use for meta-data.
|
||||||
|
/// </summary>
|
||||||
|
Metadata = 0x08,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cluster contains the boot region.
|
||||||
|
/// </summary>
|
||||||
|
BootArea = 0x10,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cluster is marked bad.
|
||||||
|
/// </summary>
|
||||||
|
Bad = 0x20
|
||||||
|
}
|
||||||
|
}
|
93
DiscUtils/Compression/Adler32.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of the Adler-32 checksum algorithm.
|
||||||
|
/// </summary>
|
||||||
|
public class Adler32
|
||||||
|
{
|
||||||
|
private uint _a;
|
||||||
|
private uint _b;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the Adler32 class.
|
||||||
|
/// </summary>
|
||||||
|
public Adler32()
|
||||||
|
{
|
||||||
|
_a = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the checksum of all data processed so far.
|
||||||
|
/// </summary>
|
||||||
|
public int Value
|
||||||
|
{
|
||||||
|
get { return (int)(_b << 16 | _a); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides data that should be checksummed.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Buffer containing the data to checksum.</param>
|
||||||
|
/// <param name="offset">Offset of the first byte to checksum.</param>
|
||||||
|
/// <param name="count">The number of bytes to checksum.</param>
|
||||||
|
/// <remarks>
|
||||||
|
/// Call this method repeatedly until all checksummed
|
||||||
|
/// data has been processed.
|
||||||
|
/// </remarks>
|
||||||
|
public void Process(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (buffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset < 0 || offset > buffer.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Offset outside of array bounds", nameof(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0 || offset + count > buffer.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Array index out of bounds", nameof(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
int processed = 0;
|
||||||
|
while (processed < count)
|
||||||
|
{
|
||||||
|
int innerEnd = Math.Min(count, processed + 2000);
|
||||||
|
while (processed < innerEnd)
|
||||||
|
{
|
||||||
|
_a += buffer[processed++];
|
||||||
|
_b += _a;
|
||||||
|
}
|
||||||
|
|
||||||
|
_a %= 65521;
|
||||||
|
_b %= 65521;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
141
DiscUtils/Compression/BZip2BlockDecoder.cs
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal class BZip2BlockDecoder
|
||||||
|
{
|
||||||
|
private readonly InverseBurrowsWheeler _inverseBurrowsWheeler;
|
||||||
|
|
||||||
|
public BZip2BlockDecoder(int blockSize)
|
||||||
|
{
|
||||||
|
_inverseBurrowsWheeler = new InverseBurrowsWheeler(blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint Crc { get; private set; }
|
||||||
|
|
||||||
|
public int Process(BitStream bitstream, byte[] outputBuffer, int outputBufferOffset)
|
||||||
|
{
|
||||||
|
Crc = 0;
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
Crc = (Crc << 8) | bitstream.Read(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool rand = bitstream.Read(1) != 0;
|
||||||
|
int origPtr = (int)bitstream.Read(24);
|
||||||
|
|
||||||
|
int thisBlockSize = ReadBuffer(bitstream, outputBuffer, outputBufferOffset);
|
||||||
|
|
||||||
|
_inverseBurrowsWheeler.OriginalIndex = origPtr;
|
||||||
|
_inverseBurrowsWheeler.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer,
|
||||||
|
outputBufferOffset);
|
||||||
|
|
||||||
|
if (rand)
|
||||||
|
{
|
||||||
|
BZip2Randomizer randomizer = new BZip2Randomizer();
|
||||||
|
randomizer.Process(outputBuffer, outputBufferOffset, thisBlockSize, outputBuffer, outputBufferOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return thisBlockSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int ReadBuffer(BitStream bitstream, byte[] buffer, int offset)
|
||||||
|
{
|
||||||
|
// The MTF state
|
||||||
|
int numInUse = 0;
|
||||||
|
MoveToFront moveFrontTransform = new MoveToFront();
|
||||||
|
bool[] inUseGroups = new bool[16];
|
||||||
|
for (int i = 0; i < 16; ++i)
|
||||||
|
{
|
||||||
|
inUseGroups[i] = bitstream.Read(1) != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
if (inUseGroups[i / 16])
|
||||||
|
{
|
||||||
|
if (bitstream.Read(1) != 0)
|
||||||
|
{
|
||||||
|
moveFrontTransform.Set(numInUse, (byte)i);
|
||||||
|
numInUse++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize 'virtual' Huffman tree from bitstream
|
||||||
|
BZip2CombinedHuffmanTrees huffmanTree = new BZip2CombinedHuffmanTrees(bitstream, numInUse + 2);
|
||||||
|
|
||||||
|
// Main loop reading data
|
||||||
|
int readBytes = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
uint symbol = huffmanTree.NextSymbol();
|
||||||
|
|
||||||
|
if (symbol < 2)
|
||||||
|
{
|
||||||
|
// RLE, with length stored in a binary-style format
|
||||||
|
uint runLength = 0;
|
||||||
|
int bitShift = 0;
|
||||||
|
while (symbol < 2)
|
||||||
|
{
|
||||||
|
runLength += (symbol + 1) << bitShift;
|
||||||
|
bitShift++;
|
||||||
|
|
||||||
|
symbol = huffmanTree.NextSymbol();
|
||||||
|
}
|
||||||
|
|
||||||
|
byte b = moveFrontTransform.Head;
|
||||||
|
while (runLength > 0)
|
||||||
|
{
|
||||||
|
buffer[offset + readBytes] = b;
|
||||||
|
++readBytes;
|
||||||
|
--runLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (symbol <= numInUse)
|
||||||
|
{
|
||||||
|
// Single byte
|
||||||
|
byte b = moveFrontTransform.GetAndMove((int)symbol - 1);
|
||||||
|
buffer[offset + readBytes] = b;
|
||||||
|
++readBytes;
|
||||||
|
}
|
||||||
|
else if (symbol == numInUse + 1)
|
||||||
|
{
|
||||||
|
// End of block marker
|
||||||
|
return readBytes;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Invalid symbol from Huffman table");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
134
DiscUtils/Compression/BZip2CombinedHuffmanTrees.cs
Normal file
|
@ -0,0 +1,134 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents scheme used by BZip2 where multiple Huffman trees are used as a
|
||||||
|
/// virtual Huffman tree, with a logical selector every 50 bits in the bit stream.
|
||||||
|
/// </summary>
|
||||||
|
internal class BZip2CombinedHuffmanTrees
|
||||||
|
{
|
||||||
|
private HuffmanTree _activeTree;
|
||||||
|
private readonly BitStream _bitstream;
|
||||||
|
private int _nextSelector;
|
||||||
|
private byte[] _selectors;
|
||||||
|
private int _symbolsToNextSelector;
|
||||||
|
private HuffmanTree[] _trees;
|
||||||
|
|
||||||
|
public BZip2CombinedHuffmanTrees(BitStream bitstream, int maxSymbols)
|
||||||
|
{
|
||||||
|
_bitstream = bitstream;
|
||||||
|
|
||||||
|
Initialize(maxSymbols);
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint NextSymbol()
|
||||||
|
{
|
||||||
|
if (_symbolsToNextSelector == 0)
|
||||||
|
{
|
||||||
|
_symbolsToNextSelector = 50;
|
||||||
|
_activeTree = _trees[_selectors[_nextSelector]];
|
||||||
|
_nextSelector++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_symbolsToNextSelector--;
|
||||||
|
|
||||||
|
return _activeTree.NextSymbol(_bitstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Initialize(int maxSymbols)
|
||||||
|
{
|
||||||
|
int numTrees = (int)_bitstream.Read(3);
|
||||||
|
if (numTrees < 2 || numTrees > 6)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Invalid number of tables");
|
||||||
|
}
|
||||||
|
|
||||||
|
int numSelectors = (int)_bitstream.Read(15);
|
||||||
|
if (numSelectors < 1)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Invalid number of selectors");
|
||||||
|
}
|
||||||
|
|
||||||
|
_selectors = new byte[numSelectors];
|
||||||
|
MoveToFront mtf = new MoveToFront(numTrees, true);
|
||||||
|
for (int i = 0; i < numSelectors; ++i)
|
||||||
|
{
|
||||||
|
_selectors[i] = mtf.GetAndMove(CountSetBits(numTrees));
|
||||||
|
}
|
||||||
|
|
||||||
|
_trees = new HuffmanTree[numTrees];
|
||||||
|
for (int t = 0; t < numTrees; ++t)
|
||||||
|
{
|
||||||
|
uint[] lengths = new uint[maxSymbols];
|
||||||
|
|
||||||
|
uint len = _bitstream.Read(5);
|
||||||
|
for (int i = 0; i < maxSymbols; ++i)
|
||||||
|
{
|
||||||
|
if (len < 1 || len > 20)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Invalid length constructing Huffman tree");
|
||||||
|
}
|
||||||
|
|
||||||
|
while (_bitstream.Read(1) != 0)
|
||||||
|
{
|
||||||
|
len = _bitstream.Read(1) == 0 ? len + 1 : len - 1;
|
||||||
|
|
||||||
|
if (len < 1 || len > 20)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Invalid length constructing Huffman tree");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lengths[i] = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
_trees[t] = new HuffmanTree(lengths);
|
||||||
|
}
|
||||||
|
|
||||||
|
_symbolsToNextSelector = 0;
|
||||||
|
_nextSelector = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private byte CountSetBits(int max)
|
||||||
|
{
|
||||||
|
byte val = 0;
|
||||||
|
while (_bitstream.Read(1) != 0)
|
||||||
|
{
|
||||||
|
val++;
|
||||||
|
if (val >= max)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Exceeded max number of consecutive bits");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
348
DiscUtils/Compression/BZip2DecoderStream.cs
Normal file
|
@ -0,0 +1,348 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Internal;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of a BZip2 decoder.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class BZip2DecoderStream : Stream
|
||||||
|
{
|
||||||
|
private readonly BitStream _bitstream;
|
||||||
|
|
||||||
|
private readonly byte[] _blockBuffer;
|
||||||
|
private uint _blockCrc;
|
||||||
|
private readonly BZip2BlockDecoder _blockDecoder;
|
||||||
|
private Crc32 _calcBlockCrc;
|
||||||
|
private uint _calcCompoundCrc;
|
||||||
|
private uint _compoundCrc;
|
||||||
|
private Stream _compressedStream;
|
||||||
|
|
||||||
|
private bool _eof;
|
||||||
|
private readonly Ownership _ownsCompressed;
|
||||||
|
private long _position;
|
||||||
|
private BZip2RleStream _rleStream;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the BZip2DecoderStream class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The compressed input stream.</param>
|
||||||
|
/// <param name="ownsStream">Whether ownership of stream passes to the new instance.</param>
|
||||||
|
public BZip2DecoderStream(Stream stream, Ownership ownsStream)
|
||||||
|
{
|
||||||
|
_compressedStream = stream;
|
||||||
|
_ownsCompressed = ownsStream;
|
||||||
|
|
||||||
|
_bitstream = new BigEndianBitStream(new BufferedStream(stream));
|
||||||
|
|
||||||
|
// The Magic BZh
|
||||||
|
byte[] magic = new byte[3];
|
||||||
|
magic[0] = (byte)_bitstream.Read(8);
|
||||||
|
magic[1] = (byte)_bitstream.Read(8);
|
||||||
|
magic[2] = (byte)_bitstream.Read(8);
|
||||||
|
if (magic[0] != 0x42 || magic[1] != 0x5A || magic[2] != 0x68)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Bad magic at start of stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
// The size of the decompression blocks in multiples of 100,000
|
||||||
|
int blockSize = (int)_bitstream.Read(8) - 0x30;
|
||||||
|
if (blockSize < 1 || blockSize > 9)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Unexpected block size in header: " + blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
blockSize *= 100000;
|
||||||
|
|
||||||
|
_rleStream = new BZip2RleStream();
|
||||||
|
_blockDecoder = new BZip2BlockDecoder(blockSize);
|
||||||
|
_blockBuffer = new byte[blockSize];
|
||||||
|
|
||||||
|
if (ReadBlock() == 0)
|
||||||
|
{
|
||||||
|
_eof = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an indication of whether read access is permitted.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an indication of whether seeking is permitted.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanSeek
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an indication of whether write access is permitted.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the length of the stream (the capacity of the underlying buffer).
|
||||||
|
/// </summary>
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets and sets the current position within the stream.
|
||||||
|
/// </summary>
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get { return _position; }
|
||||||
|
set { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes all data to the underlying storage.
|
||||||
|
/// </summary>
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads a number of bytes from the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The destination buffer.</param>
|
||||||
|
/// <param name="offset">The start offset within the destination buffer.</param>
|
||||||
|
/// <param name="count">The number of bytes to read.</param>
|
||||||
|
/// <returns>The number of bytes read.</returns>
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (buffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buffer.Length < offset + count)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Buffer smaller than declared");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Offset less than zero", nameof(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Count less than zero", nameof(count));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_eof)
|
||||||
|
{
|
||||||
|
throw new IOException("Attempt to read beyond end of stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int numRead = _rleStream.Read(buffer, offset, count);
|
||||||
|
if (numRead == 0)
|
||||||
|
{
|
||||||
|
// If there was an existing block, check it's crc.
|
||||||
|
if (_calcBlockCrc != null)
|
||||||
|
{
|
||||||
|
if (_blockCrc != _calcBlockCrc.Value)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Decompression failed - block CRC mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read a new block (if any), if none - check the overall CRC before returning
|
||||||
|
if (ReadBlock() == 0)
|
||||||
|
{
|
||||||
|
_eof = true;
|
||||||
|
if (_calcCompoundCrc != _compoundCrc)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Decompression failed - compound CRC");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
numRead = _rleStream.Read(buffer, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
_calcBlockCrc.Process(buffer, offset, numRead);
|
||||||
|
|
||||||
|
// Pre-read next block, so a client that knows the decompressed length will still
|
||||||
|
// have the overall CRC calculated.
|
||||||
|
if (_rleStream.AtEof)
|
||||||
|
{
|
||||||
|
// If there was an existing block, check it's crc.
|
||||||
|
if (_calcBlockCrc != null)
|
||||||
|
{
|
||||||
|
if (_blockCrc != _calcBlockCrc.Value)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Decompression failed - block CRC mismatch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_calcCompoundCrc = ((_calcCompoundCrc << 1) | (_calcCompoundCrc >> 31)) ^ _blockCrc;
|
||||||
|
if (ReadBlock() == 0)
|
||||||
|
{
|
||||||
|
_eof = true;
|
||||||
|
if (_calcCompoundCrc != _compoundCrc)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Decompression failed - compound CRC mismatch");
|
||||||
|
}
|
||||||
|
|
||||||
|
return numRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_position += numRead;
|
||||||
|
return numRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the current stream position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The origin-relative stream position.</param>
|
||||||
|
/// <param name="origin">The origin for the stream position.</param>
|
||||||
|
/// <returns>The new stream position.</returns>
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the length of the stream (the underlying buffer's capacity).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The new length of the stream.</param>
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a buffer to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The buffer to write.</param>
|
||||||
|
/// <param name="offset">The starting offset within buffer.</param>
|
||||||
|
/// <param name="count">The number of bytes to write.</param>
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases underlying resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">Whether this method is called from Dispose.</param>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
if (_compressedStream != null && _ownsCompressed == Ownership.Dispose)
|
||||||
|
{
|
||||||
|
_compressedStream.Dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
_compressedStream = null;
|
||||||
|
|
||||||
|
if (_rleStream != null)
|
||||||
|
{
|
||||||
|
_rleStream.Dispose();
|
||||||
|
_rleStream = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int ReadBlock()
|
||||||
|
{
|
||||||
|
ulong marker = ReadMarker();
|
||||||
|
if (marker == 0x314159265359)
|
||||||
|
{
|
||||||
|
int blockSize = _blockDecoder.Process(_bitstream, _blockBuffer, 0);
|
||||||
|
_rleStream.Reset(_blockBuffer, 0, blockSize);
|
||||||
|
_blockCrc = _blockDecoder.Crc;
|
||||||
|
_calcBlockCrc = new Crc32BigEndian(Crc32Algorithm.Common);
|
||||||
|
return blockSize;
|
||||||
|
}
|
||||||
|
if (marker == 0x177245385090)
|
||||||
|
{
|
||||||
|
_compoundCrc = ReadUint();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
throw new InvalidDataException("Found invalid marker in stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
private uint ReadUint()
|
||||||
|
{
|
||||||
|
uint val = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 4; ++i)
|
||||||
|
{
|
||||||
|
val = (val << 8) | _bitstream.Read(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
private ulong ReadMarker()
|
||||||
|
{
|
||||||
|
ulong marker = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 6; ++i)
|
||||||
|
{
|
||||||
|
marker = (marker << 8) | _bitstream.Read(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
124
DiscUtils/Compression/BZip2Randomizer.cs
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal class BZip2Randomizer : DataBlockTransform
|
||||||
|
{
|
||||||
|
private static readonly int[] RandomVals =
|
||||||
|
{
|
||||||
|
619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
|
||||||
|
985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
|
||||||
|
733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
|
||||||
|
419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
|
||||||
|
878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
|
||||||
|
862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
|
||||||
|
150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
|
||||||
|
170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
|
||||||
|
73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
|
||||||
|
909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
|
||||||
|
641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
|
||||||
|
161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
|
||||||
|
382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
|
||||||
|
98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
|
||||||
|
227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
|
||||||
|
469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
|
||||||
|
184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
|
||||||
|
715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
|
||||||
|
951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
|
||||||
|
652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
|
||||||
|
645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
|
||||||
|
609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
|
||||||
|
653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
|
||||||
|
411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
|
||||||
|
170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
|
||||||
|
857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
|
||||||
|
669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
|
||||||
|
944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
|
||||||
|
344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
|
||||||
|
897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
|
||||||
|
433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
|
||||||
|
686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
|
||||||
|
946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
|
||||||
|
978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
|
||||||
|
680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
|
||||||
|
707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
|
||||||
|
297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
|
||||||
|
134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
|
||||||
|
343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
|
||||||
|
140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
|
||||||
|
170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
|
||||||
|
369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
|
||||||
|
804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
|
||||||
|
896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
|
||||||
|
661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
|
||||||
|
768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
|
||||||
|
61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
|
||||||
|
372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
|
||||||
|
780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
|
||||||
|
920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
|
||||||
|
645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
|
||||||
|
936, 638
|
||||||
|
};
|
||||||
|
|
||||||
|
protected override bool BuffersMustNotOverlap
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
|
||||||
|
{
|
||||||
|
if (input != output || inputOffset != outputOffset)
|
||||||
|
{
|
||||||
|
Array.Copy(input, inputOffset, output, outputOffset, inputCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
int randIndex = 1;
|
||||||
|
int nextByte = RandomVals[0] - 2;
|
||||||
|
|
||||||
|
while (nextByte < inputCount)
|
||||||
|
{
|
||||||
|
output[nextByte] ^= 1;
|
||||||
|
nextByte += RandomVals[randIndex++];
|
||||||
|
randIndex &= 0x1FF;
|
||||||
|
}
|
||||||
|
|
||||||
|
return inputCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int MaxOutputCount(int inputCount)
|
||||||
|
{
|
||||||
|
return inputCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int MinOutputCount(int inputCount)
|
||||||
|
{
|
||||||
|
return inputCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
157
DiscUtils/Compression/BZip2RleStream.cs
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
//
|
||||||
|
// Based on "libbzip2", Copyright (C) 1996-2007 Julian R Seward.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal class BZip2RleStream : Stream
|
||||||
|
{
|
||||||
|
private byte[] _blockBuffer;
|
||||||
|
private int _blockOffset;
|
||||||
|
private int _blockRemaining;
|
||||||
|
private byte _lastByte;
|
||||||
|
|
||||||
|
private int _numSame;
|
||||||
|
private long _position;
|
||||||
|
private int _runBytesOutstanding;
|
||||||
|
|
||||||
|
public bool AtEof
|
||||||
|
{
|
||||||
|
get { return _runBytesOutstanding == 0 && _blockRemaining == 0; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanSeek
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get { return _position; }
|
||||||
|
set { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Reset(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
_position = 0;
|
||||||
|
_blockBuffer = buffer;
|
||||||
|
_blockOffset = offset;
|
||||||
|
_blockRemaining = count;
|
||||||
|
_numSame = -1;
|
||||||
|
_lastByte = 0;
|
||||||
|
_runBytesOutstanding = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
int numRead = 0;
|
||||||
|
|
||||||
|
while (numRead < count && _runBytesOutstanding > 0)
|
||||||
|
{
|
||||||
|
int runCount = Math.Min(_runBytesOutstanding, count);
|
||||||
|
for (int i = 0; i < runCount; ++i)
|
||||||
|
{
|
||||||
|
buffer[offset + numRead] = _lastByte;
|
||||||
|
}
|
||||||
|
|
||||||
|
_runBytesOutstanding -= runCount;
|
||||||
|
numRead += runCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (numRead < count && _blockRemaining > 0)
|
||||||
|
{
|
||||||
|
byte b = _blockBuffer[_blockOffset];
|
||||||
|
++_blockOffset;
|
||||||
|
--_blockRemaining;
|
||||||
|
|
||||||
|
if (_numSame == 4)
|
||||||
|
{
|
||||||
|
int runCount = Math.Min(b, count - numRead);
|
||||||
|
for (int i = 0; i < runCount; ++i)
|
||||||
|
{
|
||||||
|
buffer[offset + numRead] = _lastByte;
|
||||||
|
numRead++;
|
||||||
|
}
|
||||||
|
|
||||||
|
_runBytesOutstanding = b - runCount;
|
||||||
|
_numSame = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (b != _lastByte || _numSame <= 0)
|
||||||
|
{
|
||||||
|
_lastByte = b;
|
||||||
|
_numSame = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[offset + numRead] = b;
|
||||||
|
numRead++;
|
||||||
|
_numSame++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_position += numRead;
|
||||||
|
return numRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
94
DiscUtils/Compression/BigEndianBitStream.cs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a byte stream into a bit stream.
|
||||||
|
/// </summary>
|
||||||
|
internal class BigEndianBitStream : BitStream
|
||||||
|
{
|
||||||
|
private uint _buffer;
|
||||||
|
private int _bufferAvailable;
|
||||||
|
private readonly Stream _byteStream;
|
||||||
|
|
||||||
|
private readonly byte[] _readBuffer = new byte[2];
|
||||||
|
|
||||||
|
public BigEndianBitStream(Stream byteStream)
|
||||||
|
{
|
||||||
|
_byteStream = byteStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int MaxReadAhead
|
||||||
|
{
|
||||||
|
get { return 16; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override uint Read(int count)
|
||||||
|
{
|
||||||
|
if (count > 16)
|
||||||
|
{
|
||||||
|
uint result = Read(16) << (count - 16);
|
||||||
|
return result | Read(count - 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
EnsureBufferFilled();
|
||||||
|
|
||||||
|
_bufferAvailable -= count;
|
||||||
|
|
||||||
|
uint mask = (uint)((1 << count) - 1);
|
||||||
|
|
||||||
|
return (_buffer >> _bufferAvailable) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override uint Peek(int count)
|
||||||
|
{
|
||||||
|
EnsureBufferFilled();
|
||||||
|
|
||||||
|
uint mask = (uint)((1 << count) - 1);
|
||||||
|
|
||||||
|
return (_buffer >> (_bufferAvailable - count)) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Consume(int count)
|
||||||
|
{
|
||||||
|
EnsureBufferFilled();
|
||||||
|
|
||||||
|
_bufferAvailable -= count;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void EnsureBufferFilled()
|
||||||
|
{
|
||||||
|
if (_bufferAvailable < 16)
|
||||||
|
{
|
||||||
|
_readBuffer[0] = 0;
|
||||||
|
_readBuffer[1] = 0;
|
||||||
|
_byteStream.Read(_readBuffer, 0, 2);
|
||||||
|
|
||||||
|
_buffer = _buffer << 16 | (uint)(_readBuffer[0] << 8) | _readBuffer[1];
|
||||||
|
_bufferAvailable += 16;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
60
DiscUtils/Compression/BitStream.cs
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for bit streams.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// The rules for conversion of a byte stream to a bit stream vary
|
||||||
|
/// between implementations.
|
||||||
|
/// </remarks>
|
||||||
|
internal abstract class BitStream
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the maximum number of bits that can be peeked on the stream.
|
||||||
|
/// </summary>
|
||||||
|
public abstract int MaxReadAhead { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads bits from the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">The number of bits to read.</param>
|
||||||
|
/// <returns>The bits as a UInt32.</returns>
|
||||||
|
public abstract uint Read(int count);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Queries data from the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">The number of bits to query.</param>
|
||||||
|
/// <returns>The bits as a UInt32.</returns>
|
||||||
|
/// <remarks>This method does not consume the bits (i.e. move the file pointer).</remarks>
|
||||||
|
public abstract uint Peek(int count);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Consumes bits from the stream without returning them.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="count">The number of bits to consume.</param>
|
||||||
|
public abstract void Consume(int count);
|
||||||
|
}
|
||||||
|
}
|
64
DiscUtils/Compression/BlockCompressor.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for block compression algorithms.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class BlockCompressor
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the block size parameter to the algorithm.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Some algorithms may use this to control both compression and decompression, others may
|
||||||
|
/// only use it to control compression. Some may ignore it entirely.
|
||||||
|
/// </remarks>
|
||||||
|
public int BlockSize { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Compresses some data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The uncompressed input.</param>
|
||||||
|
/// <param name="sourceOffset">Offset of the input data in <c>source</c>.</param>
|
||||||
|
/// <param name="sourceLength">The amount of uncompressed data.</param>
|
||||||
|
/// <param name="compressed">The destination for the output compressed data.</param>
|
||||||
|
/// <param name="compressedOffset">Offset for the output data in <c>compressed</c>.</param>
|
||||||
|
/// <param name="compressedLength">The maximum size of the compressed data on input, and the actual size on output.</param>
|
||||||
|
/// <returns>Indication of success, or indication the data could not compress into the requested space.</returns>
|
||||||
|
public abstract CompressionResult Compress(byte[] source, int sourceOffset, int sourceLength, byte[] compressed,
|
||||||
|
int compressedOffset, ref int compressedLength);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Decompresses some data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">The compressed input.</param>
|
||||||
|
/// <param name="sourceOffset">Offset of the input data in <c>source</c>.</param>
|
||||||
|
/// <param name="sourceLength">The amount of compressed data.</param>
|
||||||
|
/// <param name="decompressed">The destination for the output decompressed data.</param>
|
||||||
|
/// <param name="decompressedOffset">Offset for the output data in <c>decompressed</c>.</param>
|
||||||
|
/// <returns>The amount of decompressed data.</returns>
|
||||||
|
public abstract int Decompress(byte[] source, int sourceOffset, int sourceLength, byte[] decompressed,
|
||||||
|
int decompressedOffset);
|
||||||
|
}
|
||||||
|
}
|
50
DiscUtils/Compression/CompressionResult.cs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Possible results of attempting to compress data.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A compression routine <i>may</i> return <c>Compressed</c>, even if the data
|
||||||
|
/// was 'all zeros' or increased in size. The <c>AllZeros</c> and <c>Incompressible</c>
|
||||||
|
/// values are for algorithms that include special detection for these cases.
|
||||||
|
/// </remarks>
|
||||||
|
public enum CompressionResult
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The data compressed succesfully.
|
||||||
|
/// </summary>
|
||||||
|
Compressed,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data was all-zero's.
|
||||||
|
/// </summary>
|
||||||
|
AllZeros,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data was incompressible (could not fit into destination buffer).
|
||||||
|
/// </summary>
|
||||||
|
Incompressible
|
||||||
|
}
|
||||||
|
}
|
70
DiscUtils/Compression/DataBlockTransform.cs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal abstract class DataBlockTransform
|
||||||
|
{
|
||||||
|
protected abstract bool BuffersMustNotOverlap { get; }
|
||||||
|
|
||||||
|
public int Process(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
|
||||||
|
{
|
||||||
|
if (output.Length < outputOffset + (long)MinOutputCount(inputCount))
|
||||||
|
{
|
||||||
|
throw new ArgumentException(
|
||||||
|
string.Format(
|
||||||
|
CultureInfo.InvariantCulture,
|
||||||
|
"Output buffer to small, must be at least {0} bytes may need to be {1} bytes",
|
||||||
|
MinOutputCount(inputCount),
|
||||||
|
MaxOutputCount(inputCount)));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BuffersMustNotOverlap)
|
||||||
|
{
|
||||||
|
int maxOut = MaxOutputCount(inputCount);
|
||||||
|
|
||||||
|
if (input == output
|
||||||
|
&& (inputOffset + (long)inputCount > outputOffset)
|
||||||
|
&& (inputOffset <= outputOffset + (long)maxOut))
|
||||||
|
{
|
||||||
|
byte[] tempBuffer = new byte[maxOut];
|
||||||
|
|
||||||
|
int outCount = DoProcess(input, inputOffset, inputCount, tempBuffer, 0);
|
||||||
|
Array.Copy(tempBuffer, 0, output, outputOffset, outCount);
|
||||||
|
|
||||||
|
return outCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DoProcess(input, inputOffset, inputCount, output, outputOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset);
|
||||||
|
|
||||||
|
protected abstract int MaxOutputCount(int inputCount);
|
||||||
|
|
||||||
|
protected abstract int MinOutputCount(int inputCount);
|
||||||
|
}
|
||||||
|
}
|
102
DiscUtils/Compression/HuffmanTree.cs
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A canonical Huffman tree implementation.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// A lookup table is created that will take any bit sequence (max tree depth in length),
|
||||||
|
/// indicating the output symbol. In WIM files, in practice, no chunk exceeds 32768 bytes
|
||||||
|
/// in length, so we often end up generating a bigger lookup table than the data it's
|
||||||
|
/// encoding. This makes for exceptionally fast symbol lookups O(1), but is inefficient
|
||||||
|
/// overall.
|
||||||
|
/// </remarks>
|
||||||
|
internal sealed class HuffmanTree
|
||||||
|
{
|
||||||
|
private readonly uint[] _buffer;
|
||||||
|
private readonly int _numBits; // Max bits per symbol
|
||||||
|
private readonly int _numSymbols; // Max symbols
|
||||||
|
|
||||||
|
public HuffmanTree(uint[] lengths)
|
||||||
|
{
|
||||||
|
Lengths = lengths;
|
||||||
|
_numSymbols = lengths.Length;
|
||||||
|
|
||||||
|
uint maxLength = 0;
|
||||||
|
for (int i = 0; i < Lengths.Length; ++i)
|
||||||
|
{
|
||||||
|
if (Lengths[i] > maxLength)
|
||||||
|
{
|
||||||
|
maxLength = Lengths[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_numBits = (int)maxLength;
|
||||||
|
_buffer = new uint[1 << _numBits];
|
||||||
|
|
||||||
|
Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
public uint[] Lengths { get; }
|
||||||
|
|
||||||
|
public uint NextSymbol(BitStream bitStream)
|
||||||
|
{
|
||||||
|
uint symbol = _buffer[bitStream.Peek(_numBits)];
|
||||||
|
|
||||||
|
// We may have over-read, reset bitstream position
|
||||||
|
bitStream.Consume((int)Lengths[symbol]);
|
||||||
|
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Build()
|
||||||
|
{
|
||||||
|
int position = 0;
|
||||||
|
|
||||||
|
// For each bit-length...
|
||||||
|
for (int i = 1; i <= _numBits; ++i)
|
||||||
|
{
|
||||||
|
// Check each symbol
|
||||||
|
for (uint symbol = 0; symbol < _numSymbols; ++symbol)
|
||||||
|
{
|
||||||
|
if (Lengths[symbol] == i)
|
||||||
|
{
|
||||||
|
int numToFill = 1 << (_numBits - i);
|
||||||
|
for (int n = 0; n < numToFill; ++n)
|
||||||
|
{
|
||||||
|
_buffer[position + n] = symbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
position += numToFill;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = position; i < _buffer.Length; ++i)
|
||||||
|
{
|
||||||
|
_buffer[i] = uint.MaxValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
97
DiscUtils/Compression/InverseBurrowsWheeler.cs
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal sealed class InverseBurrowsWheeler : DataBlockTransform
|
||||||
|
{
|
||||||
|
private readonly int[] _nextPos;
|
||||||
|
private readonly int[] _pointers;
|
||||||
|
|
||||||
|
public InverseBurrowsWheeler(int bufferSize)
|
||||||
|
{
|
||||||
|
_pointers = new int[bufferSize];
|
||||||
|
_nextPos = new int[256];
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool BuffersMustNotOverlap
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public int OriginalIndex { get; set; }
|
||||||
|
|
||||||
|
protected override int DoProcess(byte[] input, int inputOffset, int inputCount, byte[] output, int outputOffset)
|
||||||
|
{
|
||||||
|
int outputCount = inputCount;
|
||||||
|
|
||||||
|
// First find the frequency of each value
|
||||||
|
Array.Clear(_nextPos, 0, _nextPos.Length);
|
||||||
|
for (int i = inputOffset; i < inputOffset + inputCount; ++i)
|
||||||
|
{
|
||||||
|
_nextPos[input[i]]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We know they're 'sorted' in the first column, so now can figure
|
||||||
|
// out the position of the first instance of each.
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < 256; ++i)
|
||||||
|
{
|
||||||
|
int tempSum = sum;
|
||||||
|
sum += _nextPos[i];
|
||||||
|
_nextPos[i] = tempSum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For each value in the final column, put a pointer to to the
|
||||||
|
// 'next' character in the first (sorted) column.
|
||||||
|
for (int i = 0; i < inputCount; ++i)
|
||||||
|
{
|
||||||
|
_pointers[_nextPos[input[inputOffset + i]]++] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The 'next' character after the end of the original string is the
|
||||||
|
// first character of the original string.
|
||||||
|
int focus = _pointers[OriginalIndex];
|
||||||
|
|
||||||
|
// We can now just walk the pointers to reconstruct the original string
|
||||||
|
for (int i = 0; i < outputCount; ++i)
|
||||||
|
{
|
||||||
|
output[outputOffset + i] = input[inputOffset + focus];
|
||||||
|
focus = _pointers[focus];
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int MaxOutputCount(int inputCount)
|
||||||
|
{
|
||||||
|
return inputCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int MinOutputCount(int inputCount)
|
||||||
|
{
|
||||||
|
return inputCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
DiscUtils/Compression/MoveToFront.cs
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal class MoveToFront
|
||||||
|
{
|
||||||
|
private readonly byte[] _buffer;
|
||||||
|
|
||||||
|
public MoveToFront()
|
||||||
|
: this(256, false) {}
|
||||||
|
|
||||||
|
public MoveToFront(int size, bool autoInit)
|
||||||
|
{
|
||||||
|
_buffer = new byte[size];
|
||||||
|
|
||||||
|
if (autoInit)
|
||||||
|
{
|
||||||
|
for (byte i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
_buffer[i] = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte Head
|
||||||
|
{
|
||||||
|
get { return _buffer[0]; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Set(int pos, byte val)
|
||||||
|
{
|
||||||
|
_buffer[pos] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte GetAndMove(int pos)
|
||||||
|
{
|
||||||
|
byte val = _buffer[pos];
|
||||||
|
|
||||||
|
for (int i = pos; i > 0; --i)
|
||||||
|
{
|
||||||
|
_buffer[i] = _buffer[i - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
_buffer[0] = val;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
64
DiscUtils/Compression/SizedDeflateStream.cs
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014, Quamotion
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal class SizedDeflateStream : DeflateStream
|
||||||
|
{
|
||||||
|
private readonly int _length;
|
||||||
|
private int _position;
|
||||||
|
|
||||||
|
public SizedDeflateStream(Stream stream, CompressionMode mode, bool leaveOpen, int length)
|
||||||
|
: base(stream, mode, leaveOpen)
|
||||||
|
{
|
||||||
|
_length = length;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get { return _length; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get { return _position; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value != Position)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(byte[] array, int offset, int count)
|
||||||
|
{
|
||||||
|
int read = base.Read(array, offset, count);
|
||||||
|
_position += read;
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
86
DiscUtils/Compression/ZlibBuffer.cs
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2014, Quamotion
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
using Buffer=DiscUtils.Streams.Buffer;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
internal class ZlibBuffer : Buffer
|
||||||
|
{
|
||||||
|
private Ownership _ownership;
|
||||||
|
private readonly Stream _stream;
|
||||||
|
private int position;
|
||||||
|
|
||||||
|
public ZlibBuffer(Stream stream, Ownership ownership)
|
||||||
|
{
|
||||||
|
_stream = stream;
|
||||||
|
_ownership = ownership;
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get { return _stream.CanRead; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return _stream.CanWrite; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override long Capacity
|
||||||
|
{
|
||||||
|
get { return _stream.Length; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override int Read(long pos, byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (pos != position)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
int read = _stream.Read(buffer, offset, count);
|
||||||
|
position += read;
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Write(long pos, byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void SetCapacity(long value)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<StreamExtent> GetExtentsInRange(long start, long count)
|
||||||
|
{
|
||||||
|
yield return new StreamExtent(0, _stream.Length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
240
DiscUtils/Compression/ZlibStream.cs
Normal file
|
@ -0,0 +1,240 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.IO.Compression;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils.Compression
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Implementation of the Zlib compression algorithm.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Only decompression is currently implemented.</remarks>
|
||||||
|
public class ZlibStream : Stream
|
||||||
|
{
|
||||||
|
private readonly Adler32 _adler32;
|
||||||
|
private readonly DeflateStream _deflateStream;
|
||||||
|
private readonly CompressionMode _mode;
|
||||||
|
private readonly Stream _stream;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the ZlibStream class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stream">The stream to compress of decompress.</param>
|
||||||
|
/// <param name="mode">Whether to compress or decompress.</param>
|
||||||
|
/// <param name="leaveOpen">Whether closing this stream should leave <c>stream</c> open.</param>
|
||||||
|
public ZlibStream(Stream stream, CompressionMode mode, bool leaveOpen)
|
||||||
|
{
|
||||||
|
_stream = stream;
|
||||||
|
_mode = mode;
|
||||||
|
|
||||||
|
if (mode == CompressionMode.Decompress)
|
||||||
|
{
|
||||||
|
// We just sanity check against expected header values...
|
||||||
|
byte[] headerBuffer = StreamUtilities.ReadExact(stream, 2);
|
||||||
|
ushort header = EndianUtilities.ToUInt16BigEndian(headerBuffer, 0);
|
||||||
|
|
||||||
|
if (header % 31 != 0)
|
||||||
|
{
|
||||||
|
throw new IOException("Invalid Zlib header found");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((header & 0x0F00) != 8 << 8)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Zlib compression not using DEFLATE algorithm");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((header & 0x0020) != 0)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Zlib compression using preset dictionary");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ushort header =
|
||||||
|
(8 << 8) // DEFLATE
|
||||||
|
| (7 << 12) // 32K window size
|
||||||
|
| 0x80; // Default algorithm
|
||||||
|
header |= (ushort)(31 - header % 31);
|
||||||
|
|
||||||
|
byte[] headerBuffer = new byte[2];
|
||||||
|
EndianUtilities.WriteBytesBigEndian(header, headerBuffer, 0);
|
||||||
|
stream.Write(headerBuffer, 0, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
_deflateStream = new DeflateStream(stream, mode, leaveOpen);
|
||||||
|
_adler32 = new Adler32();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the stream can be read.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get { return _deflateStream.CanRead; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the stream pointer can be changed.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanSeek
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets whether the stream can be written to.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get { return _deflateStream.CanWrite; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the length of the stream.
|
||||||
|
/// </summary>
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets and sets the stream position.
|
||||||
|
/// </summary>
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get { throw new NotSupportedException(); }
|
||||||
|
set { throw new NotSupportedException(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes the stream.
|
||||||
|
/// </summary>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (_mode == CompressionMode.Decompress)
|
||||||
|
{
|
||||||
|
// Can only check Adler checksum on seekable streams. Since DeflateStream
|
||||||
|
// aggresively caches input, it normally has already consumed the footer.
|
||||||
|
if (_stream.CanSeek)
|
||||||
|
{
|
||||||
|
_stream.Seek(-4, SeekOrigin.End);
|
||||||
|
byte[] footerBuffer = StreamUtilities.ReadExact(_stream, 4);
|
||||||
|
if (EndianUtilities.ToInt32BigEndian(footerBuffer, 0) != _adler32.Value)
|
||||||
|
{
|
||||||
|
throw new InvalidDataException("Corrupt decompressed data detected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_deflateStream.Dispose();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_deflateStream.Dispose();
|
||||||
|
|
||||||
|
byte[] footerBuffer = new byte[4];
|
||||||
|
EndianUtilities.WriteBytesBigEndian(_adler32.Value, footerBuffer, 0);
|
||||||
|
_stream.Write(footerBuffer, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes the stream.
|
||||||
|
/// </summary>
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
_deflateStream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads data from the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The buffer to populate.</param>
|
||||||
|
/// <param name="offset">The first byte to write.</param>
|
||||||
|
/// <param name="count">The number of bytes requested.</param>
|
||||||
|
/// <returns>The number of bytes read.</returns>
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
CheckParams(buffer, offset, count);
|
||||||
|
|
||||||
|
int numRead = _deflateStream.Read(buffer, offset, count);
|
||||||
|
_adler32.Process(buffer, offset, numRead);
|
||||||
|
return numRead;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Seeks to a new position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">Relative position to seek to.</param>
|
||||||
|
/// <param name="origin">The origin of the seek.</param>
|
||||||
|
/// <returns>The new position.</returns>
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the length of the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The new desired length of the stream.</param>
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes data to the stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Buffer containing the data to write.</param>
|
||||||
|
/// <param name="offset">Offset of the first byte to write.</param>
|
||||||
|
/// <param name="count">Number of bytes to write.</param>
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
CheckParams(buffer, offset, count);
|
||||||
|
|
||||||
|
_adler32.Process(buffer, offset, count);
|
||||||
|
_deflateStream.Write(buffer, offset, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void CheckParams(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (buffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset < 0 || offset > buffer.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Offset outside of array bounds", nameof(offset));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count < 0 || offset + count > buffer.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentException("Array index out of bounds", nameof(count));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
23
DiscUtils/CoreCompat/EncodingHelper.cs
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#if NETSTANDARD
|
||||||
|
using System.Text;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace DiscUtils.CoreCompat
|
||||||
|
{
|
||||||
|
internal static class EncodingHelper
|
||||||
|
{
|
||||||
|
private static bool _registered;
|
||||||
|
|
||||||
|
public static void RegisterEncodings()
|
||||||
|
{
|
||||||
|
if (_registered)
|
||||||
|
return;
|
||||||
|
|
||||||
|
_registered = true;
|
||||||
|
|
||||||
|
#if NETSTANDARD
|
||||||
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
91
DiscUtils/CoreCompat/ReflectionHelper.cs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
namespace DiscUtils.CoreCompat
|
||||||
|
{
|
||||||
|
internal static class ReflectionHelper
|
||||||
|
{
|
||||||
|
public static bool IsEnum(Type type)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return type.GetTypeInfo().IsEnum;
|
||||||
|
#else
|
||||||
|
return type.IsEnum;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Attribute GetCustomAttribute(PropertyInfo property, Type attributeType)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return property.GetCustomAttribute(attributeType);
|
||||||
|
#else
|
||||||
|
return Attribute.GetCustomAttribute(property, attributeType);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Attribute GetCustomAttribute(PropertyInfo property, Type attributeType, bool inherit)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return property.GetCustomAttribute(attributeType, inherit);
|
||||||
|
#else
|
||||||
|
return Attribute.GetCustomAttribute(property, attributeType, inherit);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Attribute GetCustomAttribute(FieldInfo field, Type attributeType)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return field.GetCustomAttribute(attributeType);
|
||||||
|
#else
|
||||||
|
return Attribute.GetCustomAttribute(field, attributeType);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Attribute GetCustomAttribute(Type type, Type attributeType)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return type.GetTypeInfo().GetCustomAttribute(attributeType);
|
||||||
|
#else
|
||||||
|
return Attribute.GetCustomAttribute(type, attributeType);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Attribute GetCustomAttribute(Type type, Type attributeType, bool inherit)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return type.GetTypeInfo().GetCustomAttribute(attributeType, inherit);
|
||||||
|
#else
|
||||||
|
return Attribute.GetCustomAttribute(type, attributeType);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Attribute> GetCustomAttributes(Type type, Type attributeType, bool inherit)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return type.GetTypeInfo().GetCustomAttributes(attributeType, inherit);
|
||||||
|
#else
|
||||||
|
return Attribute.GetCustomAttributes(type, attributeType);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Assembly GetAssembly(Type type)
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return type.GetTypeInfo().Assembly;
|
||||||
|
#else
|
||||||
|
return type.Assembly;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int SizeOf<T>()
|
||||||
|
{
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
return Marshal.SizeOf<T>();
|
||||||
|
#else
|
||||||
|
return Marshal.SizeOf(typeof(T));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
15
DiscUtils/CoreCompat/StringExtensions.cs
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
#if NETSTANDARD1_5
|
||||||
|
using System.Globalization;
|
||||||
|
|
||||||
|
namespace DiscUtils.CoreCompat
|
||||||
|
{
|
||||||
|
internal static class StringExtensions
|
||||||
|
{
|
||||||
|
public static string ToUpper(this string value, CultureInfo culture)
|
||||||
|
{
|
||||||
|
return value.ToUpper();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
190
DiscUtils/DiscDirectoryInfo.cs
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Internal;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides information about a directory on a disc.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// This class allows navigation of the disc directory/file hierarchy.
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class DiscDirectoryInfo : DiscFileSystemInfo
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DiscDirectoryInfo class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="fileSystem">The file system the directory info relates to.</param>
|
||||||
|
/// <param name="path">The path within the file system of the directory.</param>
|
||||||
|
internal DiscDirectoryInfo(DiscFileSystem fileSystem, string path)
|
||||||
|
: base(fileSystem, path) {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the directory exists.
|
||||||
|
/// </summary>
|
||||||
|
public override bool Exists
|
||||||
|
{
|
||||||
|
get { return FileSystem.DirectoryExists(Path); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the full path of the directory.
|
||||||
|
/// </summary>
|
||||||
|
public override string FullName
|
||||||
|
{
|
||||||
|
get { return base.FullName + @"\"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a directory.
|
||||||
|
/// </summary>
|
||||||
|
public void Create()
|
||||||
|
{
|
||||||
|
FileSystem.CreateDirectory(Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a directory, even if it's not empty.
|
||||||
|
/// </summary>
|
||||||
|
public override void Delete()
|
||||||
|
{
|
||||||
|
FileSystem.DeleteDirectory(Path, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a directory, with the caller choosing whether to recurse.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="recursive"><c>true</c> to delete all child node, <c>false</c> to fail if the directory is not empty.</param>
|
||||||
|
public void Delete(bool recursive)
|
||||||
|
{
|
||||||
|
FileSystem.DeleteDirectory(Path, recursive);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves a directory and it's contents to a new path.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destinationDirName">The destination directory name.</param>
|
||||||
|
public void MoveTo(string destinationDirName)
|
||||||
|
{
|
||||||
|
FileSystem.MoveDirectory(Path, destinationDirName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all child directories.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of child directories.</returns>
|
||||||
|
public DiscDirectoryInfo[] GetDirectories()
|
||||||
|
{
|
||||||
|
return Utilities.Map(FileSystem.GetDirectories(Path),
|
||||||
|
p => new DiscDirectoryInfo(FileSystem, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all child directories matching a search pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The search pattern.</param>
|
||||||
|
/// <returns>An array of child directories, or empty if none match.</returns>
|
||||||
|
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
|
||||||
|
/// and ? (matching 1 character).</remarks>
|
||||||
|
public DiscDirectoryInfo[] GetDirectories(string pattern)
|
||||||
|
{
|
||||||
|
return GetDirectories(pattern, SearchOption.TopDirectoryOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all descendant directories matching a search pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The search pattern.</param>
|
||||||
|
/// <param name="searchOption">Whether to search just this directory, or all children.</param>
|
||||||
|
/// <returns>An array of descendant directories, or empty if none match.</returns>
|
||||||
|
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
|
||||||
|
/// and ? (matching 1 character). The option parameter determines whether only immediate
|
||||||
|
/// children, or all children are returned.</remarks>
|
||||||
|
public DiscDirectoryInfo[] GetDirectories(string pattern, SearchOption searchOption)
|
||||||
|
{
|
||||||
|
return Utilities.Map(FileSystem.GetDirectories(Path, pattern, searchOption),
|
||||||
|
p => new DiscDirectoryInfo(FileSystem, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all files.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of files.</returns>
|
||||||
|
public DiscFileInfo[] GetFiles()
|
||||||
|
{
|
||||||
|
return Utilities.Map(FileSystem.GetFiles(Path), p => new DiscFileInfo(FileSystem, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all files matching a search pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The search pattern.</param>
|
||||||
|
/// <returns>An array of files, or empty if none match.</returns>
|
||||||
|
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
|
||||||
|
/// and ? (matching 1 character).</remarks>
|
||||||
|
public DiscFileInfo[] GetFiles(string pattern)
|
||||||
|
{
|
||||||
|
return GetFiles(pattern, SearchOption.TopDirectoryOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all descendant files matching a search pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The search pattern.</param>
|
||||||
|
/// <param name="searchOption">Whether to search just this directory, or all children.</param>
|
||||||
|
/// <returns>An array of descendant files, or empty if none match.</returns>
|
||||||
|
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
|
||||||
|
/// and ? (matching 1 character). The option parameter determines whether only immediate
|
||||||
|
/// children, or all children are returned.</remarks>
|
||||||
|
public DiscFileInfo[] GetFiles(string pattern, SearchOption searchOption)
|
||||||
|
{
|
||||||
|
return Utilities.Map(FileSystem.GetFiles(Path, pattern, searchOption),
|
||||||
|
p => new DiscFileInfo(FileSystem, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all files and directories in this directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>An array of files and directories.</returns>
|
||||||
|
public DiscFileSystemInfo[] GetFileSystemInfos()
|
||||||
|
{
|
||||||
|
return Utilities.Map(FileSystem.GetFileSystemEntries(Path),
|
||||||
|
p => new DiscFileSystemInfo(FileSystem, p));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets all files and directories in this directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="pattern">The search pattern.</param>
|
||||||
|
/// <returns>An array of files and directories.</returns>
|
||||||
|
/// <remarks>The search pattern can include the wildcards * (matching 0 or more characters)
|
||||||
|
/// and ? (matching 1 character).</remarks>
|
||||||
|
public DiscFileSystemInfo[] GetFileSystemInfos(string pattern)
|
||||||
|
{
|
||||||
|
return Utilities.Map(FileSystem.GetFileSystemEntries(Path, pattern),
|
||||||
|
p => new DiscFileSystemInfo(FileSystem, p));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
200
DiscUtils/DiscFileInfo.cs
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides information about a file on a disc.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class DiscFileInfo : DiscFileSystemInfo
|
||||||
|
{
|
||||||
|
internal DiscFileInfo(DiscFileSystem fileSystem, string path)
|
||||||
|
: base(fileSystem, path) {}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an instance of the parent directory.
|
||||||
|
/// </summary>
|
||||||
|
public DiscDirectoryInfo Directory
|
||||||
|
{
|
||||||
|
get { return Parent; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a string representing the directory's full path.
|
||||||
|
/// </summary>
|
||||||
|
public string DirectoryName
|
||||||
|
{
|
||||||
|
get { return Directory.FullName; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the file exists.
|
||||||
|
/// </summary>
|
||||||
|
public override bool Exists
|
||||||
|
{
|
||||||
|
get { return FileSystem.FileExists(Path); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a value indicating whether the file is read-only.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsReadOnly
|
||||||
|
{
|
||||||
|
get { return (Attributes & FileAttributes.ReadOnly) != 0; }
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (value)
|
||||||
|
{
|
||||||
|
Attributes = Attributes | FileAttributes.ReadOnly;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Attributes = Attributes & ~FileAttributes.ReadOnly;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the length of the current file in bytes.
|
||||||
|
/// </summary>
|
||||||
|
public long Length
|
||||||
|
{
|
||||||
|
get { return FileSystem.GetFileLength(Path); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a file.
|
||||||
|
/// </summary>
|
||||||
|
public override void Delete()
|
||||||
|
{
|
||||||
|
FileSystem.DeleteFile(Path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a <see cref="StreamWriter" /> that appends text to the file represented by this <see cref="DiscFileInfo"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The newly created writer.</returns>
|
||||||
|
public StreamWriter AppendText()
|
||||||
|
{
|
||||||
|
return new StreamWriter(Open(FileMode.Append));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies an existing file to a new file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destinationFileName">The destination file.</param>
|
||||||
|
public void CopyTo(string destinationFileName)
|
||||||
|
{
|
||||||
|
CopyTo(destinationFileName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies an existing file to a new file, allowing overwriting of an existing file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destinationFileName">The destination file.</param>
|
||||||
|
/// <param name="overwrite">Whether to permit over-writing of an existing file.</param>
|
||||||
|
public void CopyTo(string destinationFileName, bool overwrite)
|
||||||
|
{
|
||||||
|
FileSystem.CopyFile(Path, destinationFileName, overwrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new file for reading and writing.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The newly created stream.</returns>
|
||||||
|
public Stream Create()
|
||||||
|
{
|
||||||
|
return Open(FileMode.Create);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a new <see cref="StreamWriter"/> that writes a new text file.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>A new stream writer that can write to the file contents.</returns>
|
||||||
|
public StreamWriter CreateText()
|
||||||
|
{
|
||||||
|
return new StreamWriter(Open(FileMode.Create));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves a file to a new location.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="destinationFileName">The new name of the file.</param>
|
||||||
|
public void MoveTo(string destinationFileName)
|
||||||
|
{
|
||||||
|
FileSystem.MoveFile(Path, destinationFileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the current file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mode">The file mode for the created stream.</param>
|
||||||
|
/// <returns>The newly created stream.</returns>
|
||||||
|
/// <remarks>Read-only file systems only support <c>FileMode.Open</c>.</remarks>
|
||||||
|
public Stream Open(FileMode mode)
|
||||||
|
{
|
||||||
|
return FileSystem.OpenFile(Path, mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the current file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="mode">The file mode for the created stream.</param>
|
||||||
|
/// <param name="access">The access permissions for the created stream.</param>
|
||||||
|
/// <returns>The newly created stream.</returns>
|
||||||
|
/// <remarks>Read-only file systems only support <c>FileMode.Open</c> and <c>FileAccess.Read</c>.</remarks>
|
||||||
|
public Stream Open(FileMode mode, FileAccess access)
|
||||||
|
{
|
||||||
|
return FileSystem.OpenFile(Path, mode, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens an existing file for read-only access.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The newly created stream.</returns>
|
||||||
|
public Stream OpenRead()
|
||||||
|
{
|
||||||
|
return Open(FileMode.Open, FileAccess.Read);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens an existing file for reading as UTF-8 text.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The newly created reader.</returns>
|
||||||
|
public StreamReader OpenText()
|
||||||
|
{
|
||||||
|
return new StreamReader(OpenRead());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens a file for writing.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The newly created stream.</returns>
|
||||||
|
public Stream OpenWrite()
|
||||||
|
{
|
||||||
|
return Open(FileMode.Open, FileAccess.Write);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
93
DiscUtils/DiscFileLocator.cs
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Internal;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
internal sealed class DiscFileLocator : FileLocator
|
||||||
|
{
|
||||||
|
private readonly string _basePath;
|
||||||
|
private readonly DiscFileSystem _fileSystem;
|
||||||
|
|
||||||
|
public DiscFileLocator(DiscFileSystem fileSystem, string basePath)
|
||||||
|
{
|
||||||
|
_fileSystem = fileSystem;
|
||||||
|
_basePath = basePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool Exists(string fileName)
|
||||||
|
{
|
||||||
|
return _fileSystem.FileExists(Utilities.CombinePaths(_basePath, fileName));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override Stream OpenFile(string fileName, FileMode mode, FileAccess access, FileShare share)
|
||||||
|
{
|
||||||
|
return _fileSystem.OpenFile(Utilities.CombinePaths(_basePath, fileName), mode, access);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override FileLocator GetRelativeLocator(string path)
|
||||||
|
{
|
||||||
|
return new DiscFileLocator(_fileSystem, Utilities.CombinePaths(_basePath, path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetFullPath(string path)
|
||||||
|
{
|
||||||
|
return Utilities.CombinePaths(_basePath, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetDirectoryFromPath(string path)
|
||||||
|
{
|
||||||
|
return Utilities.GetDirectoryFromPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string GetFileFromPath(string path)
|
||||||
|
{
|
||||||
|
return Utilities.GetFileFromPath(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override DateTime GetLastWriteTimeUtc(string path)
|
||||||
|
{
|
||||||
|
return _fileSystem.GetLastWriteTimeUtc(Utilities.CombinePaths(_basePath, path));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasCommonRoot(FileLocator other)
|
||||||
|
{
|
||||||
|
DiscFileLocator otherDiscLocator = other as DiscFileLocator;
|
||||||
|
|
||||||
|
if (otherDiscLocator == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Common root if the same file system instance.
|
||||||
|
return ReferenceEquals(otherDiscLocator._fileSystem, _fileSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ResolveRelativePath(string path)
|
||||||
|
{
|
||||||
|
return Utilities.ResolveRelativePath(_basePath, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
509
DiscUtils/DiscFileSystem.cs
Normal file
|
@ -0,0 +1,509 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Streams;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the base class for all file systems.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class DiscFileSystem :
|
||||||
|
#if !NETSTANDARD
|
||||||
|
MarshalByRefObject,
|
||||||
|
#endif
|
||||||
|
IFileSystem, IDisposable
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DiscFileSystem class.
|
||||||
|
/// </summary>
|
||||||
|
protected DiscFileSystem()
|
||||||
|
{
|
||||||
|
Options = new DiscFileSystemOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the DiscFileSystem class.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="defaultOptions">The options instance to use for this file system instance.</param>
|
||||||
|
protected DiscFileSystem(DiscFileSystemOptions defaultOptions)
|
||||||
|
{
|
||||||
|
Options = defaultOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Finalizes an instance of the DiscFileSystem class.
|
||||||
|
/// </summary>
|
||||||
|
~DiscFileSystem()
|
||||||
|
{
|
||||||
|
Dispose(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the file system options, which can be modified.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DiscFileSystemOptions Options { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a friendly description of the file system type.
|
||||||
|
/// </summary>
|
||||||
|
public abstract string FriendlyName { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the file system is read-only or read-write.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>true if the file system is read-write.</returns>
|
||||||
|
public abstract bool CanWrite { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the root directory of the file system.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DiscDirectoryInfo Root
|
||||||
|
{
|
||||||
|
get { return new DiscDirectoryInfo(this, string.Empty); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the volume label.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string VolumeLabel
|
||||||
|
{
|
||||||
|
get { return string.Empty; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the file system is thread-safe.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool IsThreadSafe
|
||||||
|
{
|
||||||
|
get { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies an existing file to a new file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceFile">The source file.</param>
|
||||||
|
/// <param name="destinationFile">The destination file.</param>
|
||||||
|
public virtual void CopyFile(string sourceFile, string destinationFile)
|
||||||
|
{
|
||||||
|
CopyFile(sourceFile, destinationFile, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Copies an existing file to a new file, allowing overwriting of an existing file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceFile">The source file.</param>
|
||||||
|
/// <param name="destinationFile">The destination file.</param>
|
||||||
|
/// <param name="overwrite">Whether to permit over-writing of an existing file.</param>
|
||||||
|
public abstract void CopyFile(string sourceFile, string destinationFile, bool overwrite);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the new directory.</param>
|
||||||
|
public abstract void CreateDirectory(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the directory to delete.</param>
|
||||||
|
public abstract void DeleteDirectory(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a directory, optionally with all descendants.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the directory to delete.</param>
|
||||||
|
/// <param name="recursive">Determines if the all descendants should be deleted.</param>
|
||||||
|
public virtual void DeleteDirectory(string path, bool recursive)
|
||||||
|
{
|
||||||
|
if (recursive)
|
||||||
|
{
|
||||||
|
foreach (string dir in GetDirectories(path))
|
||||||
|
{
|
||||||
|
DeleteDirectory(dir, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string file in GetFiles(path))
|
||||||
|
{
|
||||||
|
DeleteFile(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DeleteDirectory(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file to delete.</param>
|
||||||
|
public abstract void DeleteFile(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if a directory exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to test.</param>
|
||||||
|
/// <returns>true if the directory exists.</returns>
|
||||||
|
public abstract bool DirectoryExists(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if a file exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to test.</param>
|
||||||
|
/// <returns>true if the file exists.</returns>
|
||||||
|
public abstract bool FileExists(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if a file or directory exists.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to test.</param>
|
||||||
|
/// <returns>true if the file or directory exists.</returns>
|
||||||
|
public virtual bool Exists(string path)
|
||||||
|
{
|
||||||
|
return FileExists(path) || DirectoryExists(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of subdirectories in a specified directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <returns>Array of directories.</returns>
|
||||||
|
public virtual string[] GetDirectories(string path)
|
||||||
|
{
|
||||||
|
return GetDirectories(path, "*.*", SearchOption.TopDirectoryOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of subdirectories in a specified directory matching a specified
|
||||||
|
/// search pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <param name="searchPattern">The search string to match against.</param>
|
||||||
|
/// <returns>Array of directories matching the search pattern.</returns>
|
||||||
|
public virtual string[] GetDirectories(string path, string searchPattern)
|
||||||
|
{
|
||||||
|
return GetDirectories(path, searchPattern, SearchOption.TopDirectoryOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of subdirectories in a specified directory matching a specified
|
||||||
|
/// search pattern, using a value to determine whether to search subdirectories.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <param name="searchPattern">The search string to match against.</param>
|
||||||
|
/// <param name="searchOption">Indicates whether to search subdirectories.</param>
|
||||||
|
/// <returns>Array of directories matching the search pattern.</returns>
|
||||||
|
public abstract string[] GetDirectories(string path, string searchPattern, SearchOption searchOption);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of files in a specified directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <returns>Array of files.</returns>
|
||||||
|
public virtual string[] GetFiles(string path)
|
||||||
|
{
|
||||||
|
return GetFiles(path, "*.*", SearchOption.TopDirectoryOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of files in a specified directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <param name="searchPattern">The search string to match against.</param>
|
||||||
|
/// <returns>Array of files matching the search pattern.</returns>
|
||||||
|
public virtual string[] GetFiles(string path, string searchPattern)
|
||||||
|
{
|
||||||
|
return GetFiles(path, searchPattern, SearchOption.TopDirectoryOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of files in a specified directory matching a specified
|
||||||
|
/// search pattern, using a value to determine whether to search subdirectories.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <param name="searchPattern">The search string to match against.</param>
|
||||||
|
/// <param name="searchOption">Indicates whether to search subdirectories.</param>
|
||||||
|
/// <returns>Array of files matching the search pattern.</returns>
|
||||||
|
public abstract string[] GetFiles(string path, string searchPattern, SearchOption searchOption);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of all files and subdirectories in a specified directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <returns>Array of files and subdirectories matching the search pattern.</returns>
|
||||||
|
public abstract string[] GetFileSystemEntries(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the names of files and subdirectories in a specified directory matching a specified
|
||||||
|
/// search pattern.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to search.</param>
|
||||||
|
/// <param name="searchPattern">The search string to match against.</param>
|
||||||
|
/// <returns>Array of files and subdirectories matching the search pattern.</returns>
|
||||||
|
public abstract string[] GetFileSystemEntries(string path, string searchPattern);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves a directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceDirectoryName">The directory to move.</param>
|
||||||
|
/// <param name="destinationDirectoryName">The target directory name.</param>
|
||||||
|
public abstract void MoveDirectory(string sourceDirectoryName, string destinationDirectoryName);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves a file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceName">The file to move.</param>
|
||||||
|
/// <param name="destinationName">The target file name.</param>
|
||||||
|
public virtual void MoveFile(string sourceName, string destinationName)
|
||||||
|
{
|
||||||
|
MoveFile(sourceName, destinationName, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves a file, allowing an existing file to be overwritten.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sourceName">The file to move.</param>
|
||||||
|
/// <param name="destinationName">The target file name.</param>
|
||||||
|
/// <param name="overwrite">Whether to permit a destination file to be overwritten.</param>
|
||||||
|
public abstract void MoveFile(string sourceName, string destinationName, bool overwrite);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the specified file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the file to open.</param>
|
||||||
|
/// <param name="mode">The file mode for the created stream.</param>
|
||||||
|
/// <returns>The new stream.</returns>
|
||||||
|
public virtual SparseStream OpenFile(string path, FileMode mode)
|
||||||
|
{
|
||||||
|
return OpenFile(path, mode, FileAccess.ReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Opens the specified file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The full path of the file to open.</param>
|
||||||
|
/// <param name="mode">The file mode for the created stream.</param>
|
||||||
|
/// <param name="access">The access permissions for the created stream.</param>
|
||||||
|
/// <returns>The new stream.</returns>
|
||||||
|
public abstract SparseStream OpenFile(string path, FileMode mode, FileAccess access);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the attributes of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file or directory to inspect.</param>
|
||||||
|
/// <returns>The attributes of the file or directory.</returns>
|
||||||
|
public abstract FileAttributes GetAttributes(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the attributes of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file or directory to change.</param>
|
||||||
|
/// <param name="newValue">The new attributes of the file or directory.</param>
|
||||||
|
public abstract void SetAttributes(string path, FileAttributes newValue);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the creation time (in local time) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <returns>The creation time.</returns>
|
||||||
|
public virtual DateTime GetCreationTime(string path)
|
||||||
|
{
|
||||||
|
return GetCreationTimeUtc(path).ToLocalTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the creation time (in local time) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <param name="newTime">The new time to set.</param>
|
||||||
|
public virtual void SetCreationTime(string path, DateTime newTime)
|
||||||
|
{
|
||||||
|
SetCreationTimeUtc(path, newTime.ToUniversalTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the creation time (in UTC) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <returns>The creation time.</returns>
|
||||||
|
public abstract DateTime GetCreationTimeUtc(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the creation time (in UTC) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <param name="newTime">The new time to set.</param>
|
||||||
|
public abstract void SetCreationTimeUtc(string path, DateTime newTime);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the last access time (in local time) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <returns>The last access time.</returns>
|
||||||
|
public virtual DateTime GetLastAccessTime(string path)
|
||||||
|
{
|
||||||
|
return GetLastAccessTimeUtc(path).ToLocalTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the last access time (in local time) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <param name="newTime">The new time to set.</param>
|
||||||
|
public virtual void SetLastAccessTime(string path, DateTime newTime)
|
||||||
|
{
|
||||||
|
SetLastAccessTimeUtc(path, newTime.ToUniversalTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the last access time (in UTC) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <returns>The last access time.</returns>
|
||||||
|
public abstract DateTime GetLastAccessTimeUtc(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the last access time (in UTC) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <param name="newTime">The new time to set.</param>
|
||||||
|
public abstract void SetLastAccessTimeUtc(string path, DateTime newTime);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the last modification time (in local time) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <returns>The last write time.</returns>
|
||||||
|
public virtual DateTime GetLastWriteTime(string path)
|
||||||
|
{
|
||||||
|
return GetLastWriteTimeUtc(path).ToLocalTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the last modification time (in local time) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <param name="newTime">The new time to set.</param>
|
||||||
|
public virtual void SetLastWriteTime(string path, DateTime newTime)
|
||||||
|
{
|
||||||
|
SetLastWriteTimeUtc(path, newTime.ToUniversalTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the last modification time (in UTC) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <returns>The last write time.</returns>
|
||||||
|
public abstract DateTime GetLastWriteTimeUtc(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the last modification time (in UTC) of a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path of the file or directory.</param>
|
||||||
|
/// <param name="newTime">The new time to set.</param>
|
||||||
|
public abstract void SetLastWriteTimeUtc(string path, DateTime newTime);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the length of a file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The path to the file.</param>
|
||||||
|
/// <returns>The length in bytes.</returns>
|
||||||
|
public abstract long GetFileLength(string path);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an object representing a possible file.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file path.</param>
|
||||||
|
/// <returns>The representing object.</returns>
|
||||||
|
/// <remarks>The file does not need to exist.</remarks>
|
||||||
|
public virtual DiscFileInfo GetFileInfo(string path)
|
||||||
|
{
|
||||||
|
return new DiscFileInfo(this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an object representing a possible directory.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The directory path.</param>
|
||||||
|
/// <returns>The representing object.</returns>
|
||||||
|
/// <remarks>The directory does not need to exist.</remarks>
|
||||||
|
public virtual DiscDirectoryInfo GetDirectoryInfo(string path)
|
||||||
|
{
|
||||||
|
return new DiscDirectoryInfo(this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an object representing a possible file system object (file or directory).
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="path">The file system path.</param>
|
||||||
|
/// <returns>The representing object.</returns>
|
||||||
|
/// <remarks>The file system object does not need to exist.</remarks>
|
||||||
|
public virtual DiscFileSystemInfo GetFileSystemInfo(string path)
|
||||||
|
{
|
||||||
|
return new DiscFileSystemInfo(this, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads the boot code of the file system into a byte array.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The boot code, or <c>null</c> if not available.</returns>
|
||||||
|
public virtual byte[] ReadBootCode()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Size of the Filesystem in bytes
|
||||||
|
/// </summary>
|
||||||
|
public abstract long Size { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used space of the Filesystem in bytes
|
||||||
|
/// </summary>
|
||||||
|
public abstract long UsedSpace { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Available space of the Filesystem in bytes
|
||||||
|
/// </summary>
|
||||||
|
public abstract long AvailableSpace { get; }
|
||||||
|
|
||||||
|
#region IDisposable Members
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes of this instance, releasing all resources.
|
||||||
|
/// </summary>
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Dispose(true);
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Disposes of this instance.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">The value <c>true</c> if Disposing.</param>
|
||||||
|
protected virtual void Dispose(bool disposing) {}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
43
DiscUtils/DiscFileSystemChecker.cs
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Base class for objects that validate file system integrity.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Instances of this class do not offer the ability to fix/correct
|
||||||
|
/// file system issues, just to perform a limited number of checks on
|
||||||
|
/// integrity of the file system.</remarks>
|
||||||
|
public abstract class DiscFileSystemChecker
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Checks the integrity of a file system held in a stream.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reportOutput">A report on issues found.</param>
|
||||||
|
/// <param name="levels">The amount of detail to report.</param>
|
||||||
|
/// <returns><c>true</c> if the file system appears valid, else <c>false</c>.</returns>
|
||||||
|
public abstract bool Check(TextWriter reportOutput, ReportLevels levels);
|
||||||
|
}
|
||||||
|
}
|
219
DiscUtils/DiscFileSystemInfo.cs
Normal file
|
@ -0,0 +1,219 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using DiscUtils.Internal;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides the base class for both <see cref="DiscFileInfo"/> and <see cref="DiscDirectoryInfo"/> objects.
|
||||||
|
/// </summary>
|
||||||
|
public class DiscFileSystemInfo
|
||||||
|
{
|
||||||
|
internal DiscFileSystemInfo(DiscFileSystem fileSystem, string path)
|
||||||
|
{
|
||||||
|
if (path == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystem = fileSystem;
|
||||||
|
Path = path.Trim('\\');
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="System.IO.FileAttributes"/> of the current <see cref="DiscFileSystemInfo"/> object.
|
||||||
|
/// </summary>
|
||||||
|
public virtual FileAttributes Attributes
|
||||||
|
{
|
||||||
|
get { return FileSystem.GetAttributes(Path); }
|
||||||
|
set { FileSystem.SetAttributes(Path, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the creation time (in local time) of the current <see cref="DiscFileSystemInfo"/> object.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DateTime CreationTime
|
||||||
|
{
|
||||||
|
get { return CreationTimeUtc.ToLocalTime(); }
|
||||||
|
set { CreationTimeUtc = value.ToUniversalTime(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the creation time (in UTC) of the current <see cref="DiscFileSystemInfo"/> object.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DateTime CreationTimeUtc
|
||||||
|
{
|
||||||
|
get { return FileSystem.GetCreationTimeUtc(Path); }
|
||||||
|
set { FileSystem.SetCreationTimeUtc(Path, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the file system object exists.
|
||||||
|
/// </summary>
|
||||||
|
public virtual bool Exists
|
||||||
|
{
|
||||||
|
get { return FileSystem.Exists(Path); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the extension part of the file or directory name.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string Extension
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
string name = Name;
|
||||||
|
int sepIdx = name.LastIndexOf('.');
|
||||||
|
if (sepIdx >= 0)
|
||||||
|
{
|
||||||
|
return name.Substring(sepIdx + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Empty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the file system the referenced file or directory exists on.
|
||||||
|
/// </summary>
|
||||||
|
public DiscFileSystem FileSystem { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the full path of the file or directory.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string FullName
|
||||||
|
{
|
||||||
|
get { return Path; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the last time (in local time) the file or directory was accessed.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Read-only file systems will never update this value, it will remain at a fixed value.</remarks>
|
||||||
|
public virtual DateTime LastAccessTime
|
||||||
|
{
|
||||||
|
get { return LastAccessTimeUtc.ToLocalTime(); }
|
||||||
|
set { LastAccessTimeUtc = value.ToUniversalTime(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the last time (in UTC) the file or directory was accessed.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Read-only file systems will never update this value, it will remain at a fixed value.</remarks>
|
||||||
|
public virtual DateTime LastAccessTimeUtc
|
||||||
|
{
|
||||||
|
get { return FileSystem.GetLastAccessTimeUtc(Path); }
|
||||||
|
set { FileSystem.SetLastAccessTimeUtc(Path, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the last time (in local time) the file or directory was written to.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DateTime LastWriteTime
|
||||||
|
{
|
||||||
|
get { return LastWriteTimeUtc.ToLocalTime(); }
|
||||||
|
set { LastWriteTimeUtc = value.ToUniversalTime(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the last time (in UTC) the file or directory was written to.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DateTime LastWriteTimeUtc
|
||||||
|
{
|
||||||
|
get { return FileSystem.GetLastWriteTimeUtc(Path); }
|
||||||
|
set { FileSystem.SetLastWriteTimeUtc(Path, value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the file or directory.
|
||||||
|
/// </summary>
|
||||||
|
public virtual string Name
|
||||||
|
{
|
||||||
|
get { return Utilities.GetFileFromPath(Path); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the <see cref="DiscDirectoryInfo"/> of the directory containing the current <see cref="DiscFileSystemInfo"/> object.
|
||||||
|
/// </summary>
|
||||||
|
public virtual DiscDirectoryInfo Parent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(Path))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new DiscDirectoryInfo(FileSystem, Utilities.GetDirectoryFromPath(Path));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the path to the referenced file.
|
||||||
|
/// </summary>
|
||||||
|
protected string Path { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Deletes a file or directory.
|
||||||
|
/// </summary>
|
||||||
|
public virtual void Delete()
|
||||||
|
{
|
||||||
|
if ((Attributes & FileAttributes.Directory) != 0)
|
||||||
|
{
|
||||||
|
FileSystem.DeleteDirectory(Path);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileSystem.DeleteFile(Path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates if <paramref name="obj"/> is equivalent to this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="obj">The object to compare.</param>
|
||||||
|
/// <returns><c>true</c> if <paramref name="obj"/> is equivalent, else <c>false</c>.</returns>
|
||||||
|
public override bool Equals(object obj)
|
||||||
|
{
|
||||||
|
DiscFileSystemInfo asInfo = obj as DiscFileSystemInfo;
|
||||||
|
if (obj == null)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return string.Compare(Path, asInfo.Path, StringComparison.Ordinal) == 0 &&
|
||||||
|
Equals(FileSystem, asInfo.FileSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the hash code for this object.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The hash code.</returns>
|
||||||
|
public override int GetHashCode()
|
||||||
|
{
|
||||||
|
return Path.GetHashCode() ^ FileSystem.GetHashCode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
41
DiscUtils/DiscFileSystemOptions.cs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2011, Kenneth Bell
|
||||||
|
//
|
||||||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
// copy of this software and associated documentation files (the "Software"),
|
||||||
|
// to deal in the Software without restriction, including without limitation
|
||||||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
// Software is furnished to do so, subject to the following conditions:
|
||||||
|
//
|
||||||
|
// The above copyright notice and this permission notice shall be included in
|
||||||
|
// all copies or substantial portions of the Software.
|
||||||
|
//
|
||||||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
// DEALINGS IN THE SOFTWARE.
|
||||||
|
//
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace DiscUtils
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Common file system options.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Not all options are honoured by all file systems.</remarks>
|
||||||
|
public class DiscFileSystemOptions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the random number generator the file system should use.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>This option is normally <c>null</c>, which is fine for most purposes.
|
||||||
|
/// Use this option when you need to finely control the filesystem for
|
||||||
|
/// reproducibility of behaviour (for example in a test harness).</remarks>
|
||||||
|
public Random RandomNumberGenerator { get; set; }
|
||||||
|
}
|
||||||
|
}
|