Merge branch 'v2' into HEAD
|
@ -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/*
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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 { };
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 4.2 KiB |
After Width: | Height: | Size: 30 KiB |
|
@ -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>
|
|
@ -0,0 +1,12 @@
|
|||
using Avalonia.Controls;
|
||||
|
||||
namespace ChovySign_GUI
|
||||
{
|
||||
public partial class MainWindow : Window
|
||||
{
|
||||
public MainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 38 KiB |
|
@ -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>
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 28 KiB |
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();
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 115 KiB |
|
@ -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>
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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.
|
After Width: | Height: | Size: 164 KiB |
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 25 KiB |
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
|
@ -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>
|
|
@ -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>
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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; }
|
||||
}
|
||||
}
|