Merge branch 'master' of gitea.azcona-becker.net:universaleditor/editor-dotnet
This commit is contained in:
commit
f6525b7744
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,4 +1,5 @@
|
|||||||
# ---> VisualStudioCode
|
# ---> VisualStudioCode
|
||||||
|
.vscode
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
!.vscode/settings.json
|
||||||
!.vscode/tasks.json
|
!.vscode/tasks.json
|
||||||
|
|||||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@ -1,3 +1,9 @@
|
|||||||
[submodule "framework-dotnet"]
|
[submodule "framework-dotnet"]
|
||||||
path = framework-dotnet
|
path = framework-dotnet
|
||||||
url = git@gitea.azcona-becker.net:alcetech/framework-dotnet
|
url = git@gitea.azcona-becker.net:alcetech/framework-dotnet
|
||||||
|
[submodule "desktop-framework-dotnet"]
|
||||||
|
path = desktop-framework-dotnet
|
||||||
|
url = git@gitea.azcona-becker.net:alcetech/desktop-framework-dotnet
|
||||||
|
[submodule "web-framework-dotnet"]
|
||||||
|
path = web-framework-dotnet
|
||||||
|
url = git@gitea.azcona-becker.net:alcetech/web-framework-dotnet
|
||||||
|
|||||||
1
desktop-framework-dotnet
Submodule
1
desktop-framework-dotnet
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 57316e3557c1c3a566d1a24bd60675c02d1f8744
|
||||||
11
editor
11
editor
@ -5,12 +5,23 @@ SRC_PATH=editor-dotnet/src/app/$APP_NAME
|
|||||||
APP_PATH=$SRC_PATH/bin/Debug/net$DOTNET_VERSION
|
APP_PATH=$SRC_PATH/bin/Debug/net$DOTNET_VERSION
|
||||||
RELEASE=0
|
RELEASE=0
|
||||||
|
|
||||||
|
PREREQUISITES="desktop-framework-dotnet/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3"
|
||||||
|
|
||||||
if [ ! $RELEASE -eq 1 ] || [ ! -f $APP_PATH/$APP_NAME ]; then
|
if [ ! $RELEASE -eq 1 ] || [ ! -f $APP_PATH/$APP_NAME ]; then
|
||||||
|
|
||||||
pushd $SRC_PATH
|
pushd $SRC_PATH
|
||||||
dotnet build
|
dotnet build
|
||||||
popd
|
popd
|
||||||
|
|
||||||
|
# also build desktop-framework-dotnet
|
||||||
|
for prereq in $PREREQUISITES; do
|
||||||
|
pushd $prereq
|
||||||
|
dotnet build
|
||||||
|
popd
|
||||||
|
done
|
||||||
|
|
||||||
|
cp desktop-framework-dotnet/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/bin/Debug/net$DOTNET_VERSION/*.dll $APP_PATH/engines
|
||||||
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
$APP_PATH/$APP_NAME
|
$APP_PATH/$APP_NAME
|
||||||
|
|||||||
214
editor-dotnet.sln
Normal file
214
editor-dotnet.sln
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
|
||||||
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
|
# Visual Studio Version 17
|
||||||
|
VisualStudioVersion = 17.5.002.0
|
||||||
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "editor-dotnet", "editor-dotnet", "{75210F45-D690-4A61-9CD8-96B09E5DAAC5}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{F05001E1-6FFB-48AE-BF7F-7F39A24D3B70}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{C86F60F9-BBC1-4554-A3B0-D553F9C157A8}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBS.Editor.Core", "editor-dotnet\src\lib\MBS.Editor.Core\MBS.Editor.Core.csproj", "{8FFB417A-2CDC-429F-ABE0-19B3015530D3}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBS.Editor.UserInterface", "editor-dotnet\src\lib\MBS.Editor.UserInterface\MBS.Editor.UserInterface.csproj", "{C4316562-555A-4A79-9D71-15737976DF8B}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "app", "app", "{4ED8C38B-47EF-4368-9965-CF627465B45A}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBS.Editor", "editor-dotnet\src\app\MBS.Editor\MBS.Editor.csproj", "{A936C411-0184-43F8-A343-0DE8C3B7B42E}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework-dotnet", "framework-dotnet", "{CC86007D-8193-4EAA-932D-A96B5F09847E}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "framework-dotnet", "framework-dotnet", "{B9747AFE-160D-4807-B989-B3F0ACCA3634}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{BDC147D8-4D97-4663-9408-BC822E1E0B3C}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{80A728D5-7C00-4B59-A37E-321C54CC554F}"
|
||||||
|
EndProject
|
||||||
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MBS.Core", "framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj", "{7565CFB4-9761-4064-B18F-5E2644730BC0}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "plugins", "plugins", "{451AD529-16B4-4049-9D0C-0C79B3DDFA52}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Plugins.Multimedia", "editor-dotnet\src\plugins\MBS.Editor.Plugins.Multimedia\MBS.Editor.Plugins.Multimedia.csproj", "{5978938E-19F6-42AE-B588-7719A65ABCA7}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.TestProject", "editor-dotnet\src\app\MBS.Editor.TestProject\MBS.Editor.TestProject.csproj", "{CDA151F8-5BA7-47DB-883D-CBC2DD94F0DF}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Plugins.CRI", "editor-dotnet\src\plugins\MBS.Editor.Plugins.CRI\MBS.Editor.Plugins.CRI.csproj", "{78B11A3E-1371-48D8-9B8E-AE6ED2380A50}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{74AD8C3F-B0B8-472F-A847-1FFFB1667B34}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Core.Tests", "editor-dotnet\src\tests\MBS.Editor.Core.Tests\MBS.Editor.Core.Tests.csproj", "{7A349FC6-BCE7-465D-ADBC-7A21242E2C78}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Plugins.CRI.Tests", "editor-dotnet\src\tests\MBS.Editor.Plugins.CRI.Tests\MBS.Editor.Plugins.CRI.Tests.csproj", "{2747FFC9-55AA-4A76-B0E9-D8A839E94E47}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "desktop-framework-dotnet", "desktop-framework-dotnet", "{1BEBE6E9-D723-4A76-8210-D470DEB8C9C7}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "desktop-framework-dotnet", "desktop-framework-dotnet", "{68FC9B7D-A168-47CE-9106-A2501F5E4814}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9C1544A0-92FF-46F3-A8F3-93A6EB599EDD}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{418A36B7-1856-4945-AB9D-D66956A6A549}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Desktop", "desktop-framework-dotnet\desktop-framework-dotnet\src\lib\MBS.Desktop\MBS.Desktop.csproj", "{11862DE3-B214-42C5-9CFE-72FFE7F29F09}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "engines", "engines", "{C91C4319-D6B5-448C-BC28-3F5F65EC4EB7}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Desktop.Engines.GTK3", "desktop-framework-dotnet\desktop-framework-dotnet\src\engines\MBS.Desktop.Engines.GTK3\MBS.Desktop.Engines.GTK3.csproj", "{A738CB41-831D-4BB3-A7F5-87DB19FAD87B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Plugins.Mekada", "editor-dotnet\src\plugins\MBS.Editor.Plugins.Mekada\MBS.Editor.Plugins.Mekada.csproj", "{9D1F7A94-B165-4581-B68D-4E2CF9F83D30}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Plugins.Mekada.Tests", "editor-dotnet\src\tests\MBS.Editor.Plugins.Mekada.Tests\MBS.Editor.Plugins.Mekada.Tests.csproj", "{55865BF2-E3C3-4823-A295-C85F6D98901F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Testing", "editor-dotnet\src\lib\MBS.Editor.Testing\MBS.Editor.Testing.csproj", "{93A3D49C-A6EC-4F19-A410-F222DE1C9358}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Plugins.Kronosaur", "editor-dotnet\src\plugins\MBS.Editor.Plugins.Kronosaur\MBS.Editor.Plugins.Kronosaur.csproj", "{5D627852-158F-460D-9E5F-56F80BDB9A0B}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{D5423E32-5CD5-4207-8B56-235D470E7BBB}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Core.Tests", "framework-dotnet\framework-dotnet\src\tests\MBS.Core.Tests\MBS.Core.Tests.csproj", "{13F3D325-9EB8-4479-BB3F-1D663F924A8D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Plugins.Multimedia.Tests", "editor-dotnet\src\tests\MBS.Editor.Plugins.Multimedia.Tests\MBS.Editor.Plugins.Multimedia.Tests.csproj", "{BDE1CD42-771E-4902-93DB-5B17C616C172}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Web.Server", "editor-dotnet\src\app\MBS.Editor.Web.Server\MBS.Editor.Web.Server.csproj", "{A74A8939-9E5A-4811-9D03-7B53E164A979}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "web-framework-dotnet", "web-framework-dotnet", "{B24A3EC9-CAC1-4162-A71F-4E085E828DAD}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5A57B76D-C7E1-48A4-AB10-23E804590287}"
|
||||||
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "lib", "lib", "{91E8E5EA-8098-4929-9E87-6C2D55F35A02}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Web", "web-framework-dotnet\src\lib\MBS.Web\MBS.Web.csproj", "{09CD7984-6CB9-42BC-9A9E-31FA1C21697F}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MBS.Editor.Web", "editor-dotnet\src\lib\MBS.Editor.Web\MBS.Editor.Web.csproj", "{C40F7294-C2FD-4642-A35E-6AEE7DE9F2A1}"
|
||||||
|
EndProject
|
||||||
|
Global
|
||||||
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
|
Debug|Any CPU = Debug|Any CPU
|
||||||
|
Release|Any CPU = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||||
|
{8FFB417A-2CDC-429F-ABE0-19B3015530D3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{8FFB417A-2CDC-429F-ABE0-19B3015530D3}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{8FFB417A-2CDC-429F-ABE0-19B3015530D3}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{8FFB417A-2CDC-429F-ABE0-19B3015530D3}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C4316562-555A-4A79-9D71-15737976DF8B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C4316562-555A-4A79-9D71-15737976DF8B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C4316562-555A-4A79-9D71-15737976DF8B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C4316562-555A-4A79-9D71-15737976DF8B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A936C411-0184-43F8-A343-0DE8C3B7B42E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A936C411-0184-43F8-A343-0DE8C3B7B42E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A936C411-0184-43F8-A343-0DE8C3B7B42E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A936C411-0184-43F8-A343-0DE8C3B7B42E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7565CFB4-9761-4064-B18F-5E2644730BC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7565CFB4-9761-4064-B18F-5E2644730BC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7565CFB4-9761-4064-B18F-5E2644730BC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7565CFB4-9761-4064-B18F-5E2644730BC0}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5978938E-19F6-42AE-B588-7719A65ABCA7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5978938E-19F6-42AE-B588-7719A65ABCA7}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5978938E-19F6-42AE-B588-7719A65ABCA7}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5978938E-19F6-42AE-B588-7719A65ABCA7}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{CDA151F8-5BA7-47DB-883D-CBC2DD94F0DF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{CDA151F8-5BA7-47DB-883D-CBC2DD94F0DF}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{CDA151F8-5BA7-47DB-883D-CBC2DD94F0DF}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{CDA151F8-5BA7-47DB-883D-CBC2DD94F0DF}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{78B11A3E-1371-48D8-9B8E-AE6ED2380A50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{78B11A3E-1371-48D8-9B8E-AE6ED2380A50}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{78B11A3E-1371-48D8-9B8E-AE6ED2380A50}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{78B11A3E-1371-48D8-9B8E-AE6ED2380A50}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{7A349FC6-BCE7-465D-ADBC-7A21242E2C78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{7A349FC6-BCE7-465D-ADBC-7A21242E2C78}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{7A349FC6-BCE7-465D-ADBC-7A21242E2C78}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{7A349FC6-BCE7-465D-ADBC-7A21242E2C78}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{2747FFC9-55AA-4A76-B0E9-D8A839E94E47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{2747FFC9-55AA-4A76-B0E9-D8A839E94E47}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{2747FFC9-55AA-4A76-B0E9-D8A839E94E47}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{2747FFC9-55AA-4A76-B0E9-D8A839E94E47}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{11862DE3-B214-42C5-9CFE-72FFE7F29F09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{11862DE3-B214-42C5-9CFE-72FFE7F29F09}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{11862DE3-B214-42C5-9CFE-72FFE7F29F09}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{11862DE3-B214-42C5-9CFE-72FFE7F29F09}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A738CB41-831D-4BB3-A7F5-87DB19FAD87B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A738CB41-831D-4BB3-A7F5-87DB19FAD87B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A738CB41-831D-4BB3-A7F5-87DB19FAD87B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A738CB41-831D-4BB3-A7F5-87DB19FAD87B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9D1F7A94-B165-4581-B68D-4E2CF9F83D30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9D1F7A94-B165-4581-B68D-4E2CF9F83D30}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9D1F7A94-B165-4581-B68D-4E2CF9F83D30}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9D1F7A94-B165-4581-B68D-4E2CF9F83D30}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{55865BF2-E3C3-4823-A295-C85F6D98901F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{55865BF2-E3C3-4823-A295-C85F6D98901F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{55865BF2-E3C3-4823-A295-C85F6D98901F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{55865BF2-E3C3-4823-A295-C85F6D98901F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{93A3D49C-A6EC-4F19-A410-F222DE1C9358}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{93A3D49C-A6EC-4F19-A410-F222DE1C9358}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{93A3D49C-A6EC-4F19-A410-F222DE1C9358}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{93A3D49C-A6EC-4F19-A410-F222DE1C9358}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{5D627852-158F-460D-9E5F-56F80BDB9A0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{5D627852-158F-460D-9E5F-56F80BDB9A0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{5D627852-158F-460D-9E5F-56F80BDB9A0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{5D627852-158F-460D-9E5F-56F80BDB9A0B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{13F3D325-9EB8-4479-BB3F-1D663F924A8D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{13F3D325-9EB8-4479-BB3F-1D663F924A8D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{13F3D325-9EB8-4479-BB3F-1D663F924A8D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{13F3D325-9EB8-4479-BB3F-1D663F924A8D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{BDE1CD42-771E-4902-93DB-5B17C616C172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{BDE1CD42-771E-4902-93DB-5B17C616C172}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{BDE1CD42-771E-4902-93DB-5B17C616C172}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{BDE1CD42-771E-4902-93DB-5B17C616C172}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A74A8939-9E5A-4811-9D03-7B53E164A979}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A74A8939-9E5A-4811-9D03-7B53E164A979}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A74A8939-9E5A-4811-9D03-7B53E164A979}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A74A8939-9E5A-4811-9D03-7B53E164A979}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{09CD7984-6CB9-42BC-9A9E-31FA1C21697F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{09CD7984-6CB9-42BC-9A9E-31FA1C21697F}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{09CD7984-6CB9-42BC-9A9E-31FA1C21697F}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{09CD7984-6CB9-42BC-9A9E-31FA1C21697F}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C40F7294-C2FD-4642-A35E-6AEE7DE9F2A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C40F7294-C2FD-4642-A35E-6AEE7DE9F2A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C40F7294-C2FD-4642-A35E-6AEE7DE9F2A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C40F7294-C2FD-4642-A35E-6AEE7DE9F2A1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
|
HideSolutionNode = FALSE
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(NestedProjects) = preSolution
|
||||||
|
{F05001E1-6FFB-48AE-BF7F-7F39A24D3B70} = {75210F45-D690-4A61-9CD8-96B09E5DAAC5}
|
||||||
|
{C86F60F9-BBC1-4554-A3B0-D553F9C157A8} = {F05001E1-6FFB-48AE-BF7F-7F39A24D3B70}
|
||||||
|
{8FFB417A-2CDC-429F-ABE0-19B3015530D3} = {C86F60F9-BBC1-4554-A3B0-D553F9C157A8}
|
||||||
|
{C4316562-555A-4A79-9D71-15737976DF8B} = {C86F60F9-BBC1-4554-A3B0-D553F9C157A8}
|
||||||
|
{4ED8C38B-47EF-4368-9965-CF627465B45A} = {F05001E1-6FFB-48AE-BF7F-7F39A24D3B70}
|
||||||
|
{A936C411-0184-43F8-A343-0DE8C3B7B42E} = {4ED8C38B-47EF-4368-9965-CF627465B45A}
|
||||||
|
{B9747AFE-160D-4807-B989-B3F0ACCA3634} = {CC86007D-8193-4EAA-932D-A96B5F09847E}
|
||||||
|
{BDC147D8-4D97-4663-9408-BC822E1E0B3C} = {B9747AFE-160D-4807-B989-B3F0ACCA3634}
|
||||||
|
{80A728D5-7C00-4B59-A37E-321C54CC554F} = {BDC147D8-4D97-4663-9408-BC822E1E0B3C}
|
||||||
|
{7565CFB4-9761-4064-B18F-5E2644730BC0} = {80A728D5-7C00-4B59-A37E-321C54CC554F}
|
||||||
|
{451AD529-16B4-4049-9D0C-0C79B3DDFA52} = {F05001E1-6FFB-48AE-BF7F-7F39A24D3B70}
|
||||||
|
{5978938E-19F6-42AE-B588-7719A65ABCA7} = {451AD529-16B4-4049-9D0C-0C79B3DDFA52}
|
||||||
|
{CDA151F8-5BA7-47DB-883D-CBC2DD94F0DF} = {4ED8C38B-47EF-4368-9965-CF627465B45A}
|
||||||
|
{78B11A3E-1371-48D8-9B8E-AE6ED2380A50} = {451AD529-16B4-4049-9D0C-0C79B3DDFA52}
|
||||||
|
{74AD8C3F-B0B8-472F-A847-1FFFB1667B34} = {F05001E1-6FFB-48AE-BF7F-7F39A24D3B70}
|
||||||
|
{7A349FC6-BCE7-465D-ADBC-7A21242E2C78} = {74AD8C3F-B0B8-472F-A847-1FFFB1667B34}
|
||||||
|
{2747FFC9-55AA-4A76-B0E9-D8A839E94E47} = {74AD8C3F-B0B8-472F-A847-1FFFB1667B34}
|
||||||
|
{68FC9B7D-A168-47CE-9106-A2501F5E4814} = {1BEBE6E9-D723-4A76-8210-D470DEB8C9C7}
|
||||||
|
{9C1544A0-92FF-46F3-A8F3-93A6EB599EDD} = {68FC9B7D-A168-47CE-9106-A2501F5E4814}
|
||||||
|
{418A36B7-1856-4945-AB9D-D66956A6A549} = {9C1544A0-92FF-46F3-A8F3-93A6EB599EDD}
|
||||||
|
{11862DE3-B214-42C5-9CFE-72FFE7F29F09} = {418A36B7-1856-4945-AB9D-D66956A6A549}
|
||||||
|
{C91C4319-D6B5-448C-BC28-3F5F65EC4EB7} = {9C1544A0-92FF-46F3-A8F3-93A6EB599EDD}
|
||||||
|
{A738CB41-831D-4BB3-A7F5-87DB19FAD87B} = {C91C4319-D6B5-448C-BC28-3F5F65EC4EB7}
|
||||||
|
{9D1F7A94-B165-4581-B68D-4E2CF9F83D30} = {451AD529-16B4-4049-9D0C-0C79B3DDFA52}
|
||||||
|
{55865BF2-E3C3-4823-A295-C85F6D98901F} = {74AD8C3F-B0B8-472F-A847-1FFFB1667B34}
|
||||||
|
{93A3D49C-A6EC-4F19-A410-F222DE1C9358} = {C86F60F9-BBC1-4554-A3B0-D553F9C157A8}
|
||||||
|
{5D627852-158F-460D-9E5F-56F80BDB9A0B} = {451AD529-16B4-4049-9D0C-0C79B3DDFA52}
|
||||||
|
{D5423E32-5CD5-4207-8B56-235D470E7BBB} = {BDC147D8-4D97-4663-9408-BC822E1E0B3C}
|
||||||
|
{13F3D325-9EB8-4479-BB3F-1D663F924A8D} = {D5423E32-5CD5-4207-8B56-235D470E7BBB}
|
||||||
|
{BDE1CD42-771E-4902-93DB-5B17C616C172} = {74AD8C3F-B0B8-472F-A847-1FFFB1667B34}
|
||||||
|
{A74A8939-9E5A-4811-9D03-7B53E164A979} = {4ED8C38B-47EF-4368-9965-CF627465B45A}
|
||||||
|
{5A57B76D-C7E1-48A4-AB10-23E804590287} = {B24A3EC9-CAC1-4162-A71F-4E085E828DAD}
|
||||||
|
{91E8E5EA-8098-4929-9E87-6C2D55F35A02} = {5A57B76D-C7E1-48A4-AB10-23E804590287}
|
||||||
|
{09CD7984-6CB9-42BC-9A9E-31FA1C21697F} = {91E8E5EA-8098-4929-9E87-6C2D55F35A02}
|
||||||
|
{C40F7294-C2FD-4642-A35E-6AEE7DE9F2A1} = {C86F60F9-BBC1-4554-A3B0-D553F9C157A8}
|
||||||
|
EndGlobalSection
|
||||||
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
|
SolutionGuid = {4D0B64EB-14E9-4013-AA33-33716704909B}
|
||||||
|
EndGlobalSection
|
||||||
|
EndGlobal
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\..\lib\MBS.Editor.Core\MBS.Editor.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
51
editor-dotnet/src/app/MBS.Editor.TestProject/Program.cs
Normal file
51
editor-dotnet/src/app/MBS.Editor.TestProject/Program.cs
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
using MBS.Core;
|
||||||
|
|
||||||
|
using MBS.Editor.Core;
|
||||||
|
using MBS.Editor.Core.IO;
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
class Program : Application
|
||||||
|
{
|
||||||
|
protected override int StartInternal()
|
||||||
|
{
|
||||||
|
FileStream fs = System.IO.File.Open("/tmp/test.afs", FileMode.Create, FileAccess.Write);
|
||||||
|
/*
|
||||||
|
Writer writer = new Writer(fs);
|
||||||
|
|
||||||
|
writer.Endianness = Endianness.BigEndian;
|
||||||
|
writer.WriteBoolean(true);
|
||||||
|
writer.WriteInt32(1024);
|
||||||
|
writer.WriteInt32(768);
|
||||||
|
writer.WriteFixedLengthString("Hello world");
|
||||||
|
writer.WriteInt32(0x7B);
|
||||||
|
writer.Close();
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
FileSystemObjectModel fsom = new FileSystemObjectModel();
|
||||||
|
fsom.Items.AddFile("test.ini", new ByteArrayFileSource(new byte[] { 0x20, 0x04, 0xFE, 0xDE }));
|
||||||
|
|
||||||
|
Console.WriteLine(Environment.ProcessPath);
|
||||||
|
|
||||||
|
Type t = MBS.Core.Reflection.TypeLoader.FindType("MBS.Editor.Plugins.CRI.DataFormats.FileSystem.AFS.AFSDataFormat");
|
||||||
|
Console.WriteLine("found type {0}", t);
|
||||||
|
|
||||||
|
DataFormat afs = DataFormat.FromType(t);
|
||||||
|
if (afs == null)
|
||||||
|
{
|
||||||
|
Console.WriteLine("could not load type");
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
Document.Save(fsom, afs, fs);
|
||||||
|
fs.Close();
|
||||||
|
|
||||||
|
return base.StartInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
(new Program()).Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../../../../web-framework-dotnet/src/lib/MBS.Web/MBS.Web.csproj" />
|
||||||
|
<ProjectReference Include="../../lib/MBS.Editor.Web/MBS.Editor.Web.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
102
editor-dotnet/src/app/MBS.Editor.Web.Server/Program.cs
Normal file
102
editor-dotnet/src/app/MBS.Editor.Web.Server/Program.cs
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
using System.Text.Json.Nodes;
|
||||||
|
using System.Xml;
|
||||||
|
using MBS.Core;
|
||||||
|
using MBS.Editor.Web.Pages;
|
||||||
|
using MBS.Web;
|
||||||
|
|
||||||
|
public class Program : WebApplication
|
||||||
|
{
|
||||||
|
protected override int DefaultPort => 54920;
|
||||||
|
|
||||||
|
public Program()
|
||||||
|
{
|
||||||
|
Commands.Add(new Command("File", "_File", new CommandItem[]
|
||||||
|
{
|
||||||
|
new CommandReferenceCommandItem("FileOpen")
|
||||||
|
}));
|
||||||
|
Commands.Add(new Command("FileOpen", "_Open"));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override WebServer CreateWebServer()
|
||||||
|
{
|
||||||
|
WebServer ws = base.CreateWebServer();
|
||||||
|
ws.Routes.Add(new WebRoute("/", new WebHandler(delegate(WebContext ctx)
|
||||||
|
{
|
||||||
|
ctx.Response.ContentType = "application/xhtml+xml";
|
||||||
|
|
||||||
|
MainPage page = new MainPage();
|
||||||
|
page.Title = "MBS Editor";
|
||||||
|
|
||||||
|
MBS.Web.UI.WebControls.CommandBar toolbar = new MBS.Web.UI.WebControls.CommandBar();
|
||||||
|
toolbar.Items.Add(new CommandReferenceCommandItem("FileOpen"));
|
||||||
|
page.Controls.Add(toolbar);
|
||||||
|
|
||||||
|
XmlWriter sw = XmlWriter.Create(ctx.Response.Stream);
|
||||||
|
page.Render(sw);
|
||||||
|
sw.Close();
|
||||||
|
})));
|
||||||
|
ws.Routes.Add(new WebRoute("/api/local/browse", new WebHandler(delegate(WebContext ctx)
|
||||||
|
{
|
||||||
|
StreamWriter sw = new StreamWriter(ctx.Response.Stream);
|
||||||
|
|
||||||
|
string relativePath = "";
|
||||||
|
if (ctx.Request.Query.ContainsKey("path"))
|
||||||
|
{
|
||||||
|
List<string> oPath = ctx.Request.Query["path"];
|
||||||
|
if (oPath.Count > 0)
|
||||||
|
{
|
||||||
|
relativePath = oPath[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
JsonObject json = new JsonObject();
|
||||||
|
|
||||||
|
string homeDirectory = "/home/beckermj/Documents";
|
||||||
|
string absolutePath = String.Join("/", new string[] { homeDirectory, relativePath });
|
||||||
|
if (!System.IO.Directory.Exists(absolutePath))
|
||||||
|
{
|
||||||
|
json.Add("result", "failure");
|
||||||
|
json.Add("message", "path not found");
|
||||||
|
|
||||||
|
sw.Write(json.ToJsonString());
|
||||||
|
sw.Close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
json.Add("result", "success");
|
||||||
|
|
||||||
|
JsonArray ary = new JsonArray();
|
||||||
|
string[] files = System.IO.Directory.GetFiles(absolutePath, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
string[] folders = System.IO.Directory.GetDirectories(absolutePath, "*", SearchOption.TopDirectoryOnly);
|
||||||
|
foreach (string file in folders)
|
||||||
|
{
|
||||||
|
JsonObject o = new JsonObject();
|
||||||
|
string title = System.IO.Path.GetFileName(file);
|
||||||
|
o.Add("title", title);
|
||||||
|
o.Add("type", "folder");
|
||||||
|
o.Add("path", file);
|
||||||
|
ary.Add(o);
|
||||||
|
}
|
||||||
|
foreach (string file in files)
|
||||||
|
{
|
||||||
|
JsonObject o = new JsonObject();
|
||||||
|
string title = System.IO.Path.GetFileName(file);
|
||||||
|
o.Add("title", title);
|
||||||
|
o.Add("type", "file");
|
||||||
|
o.Add("path", file);
|
||||||
|
ary.Add(o);
|
||||||
|
}
|
||||||
|
|
||||||
|
json.Add("items", ary);
|
||||||
|
|
||||||
|
sw.Write(json.ToJsonString());
|
||||||
|
sw.Close();
|
||||||
|
})));
|
||||||
|
return ws;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
(new Program()).Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
12
editor-dotnet/src/app/MBS.Editor.Web.Server/TODO.txt
Normal file
12
editor-dotnet/src/app/MBS.Editor.Web.Server/TODO.txt
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
This is MBS Editor Web Server.
|
||||||
|
|
||||||
|
example URL:
|
||||||
|
|
||||||
|
Edit existing registered Document:
|
||||||
|
https://localhost:54920/doc/61b30ad3c7754ae2bc7abf949ee83289/edit
|
||||||
|
|
||||||
|
Create document and register it:
|
||||||
|
https://localhost:54920/doc/new
|
||||||
|
|
||||||
|
- redirects to /doc/.../edit when document is created
|
||||||
|
|
||||||
@ -3,8 +3,8 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\lib\MBS.Editor.Core\MBS.Editor.Core.csproj" />
|
<ProjectReference Include="..\..\lib\MBS.Editor.Core\MBS.Editor.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\lib\MBS.Editor.UserInterface\MBS.Editor.UserInterface.csproj" />
|
<ProjectReference Include="..\..\lib\MBS.Editor.UserInterface\MBS.Editor.UserInterface.csproj" />
|
||||||
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Desktop\MBS.Desktop.csproj" />
|
|
||||||
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
|
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\..\..\..\desktop-framework-dotnet\desktop-framework-dotnet\src\lib\MBS.Desktop\MBS.Desktop.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@ -1,3 +1,19 @@
|
|||||||
using MBS.Editor.UserInterface;
|
// <one line to give the program's name and a brief idea of what it does.>
|
||||||
|
// Copyright (C) <year> <name of author>
|
||||||
|
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using MBS.Editor.UserInterface;
|
||||||
|
|
||||||
return (new EditorApplication()).Start();
|
return (new EditorApplication()).Start();
|
||||||
23
editor-dotnet/src/install-engines.sh
Executable file
23
editor-dotnet/src/install-engines.sh
Executable file
@ -0,0 +1,23 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CONFIDENCE=Debug
|
||||||
|
NET_VERSION=net8.0
|
||||||
|
|
||||||
|
if [ ! -d app/MBS.Editor/bin/$CONFIDENCE/$NET_VERSION/engines ]; then
|
||||||
|
|
||||||
|
mkdir app/MBS.Editor/bin/$CONFIDENCE/$NET_VERSION/engines
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
for dir in ../../desktop-framework-dotnet/desktop-framework-dotnet/src/engines/* ; do
|
||||||
|
|
||||||
|
echo "Building $dir"
|
||||||
|
|
||||||
|
pushd $dir
|
||||||
|
dotnet build
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo "Copying $dir"
|
||||||
|
cp $dir/bin/$CONFIDENCE/$NET_VERSION/*.dll app/MBS.Editor/bin/$CONFIDENCE/$NET_VERSION/engines
|
||||||
|
|
||||||
|
done
|
||||||
30
editor-dotnet/src/install-plugins.sh
Executable file
30
editor-dotnet/src/install-plugins.sh
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
CONFIDENCE=Debug
|
||||||
|
NET_VERSION=net8.0
|
||||||
|
|
||||||
|
if [ ! -d app/MBS.Editor/bin/$CONFIDENCE/$NET_VERSION/plugins ]; then
|
||||||
|
|
||||||
|
mkdir app/MBS.Editor/bin/$CONFIDENCE/$NET_VERSION/plugins
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! -d app/MBS.Editor.TestProject/bin/$CONFIDENCE/$NET_VERSION/plugins ]; then
|
||||||
|
|
||||||
|
mkdir app/MBS.Editor.TestProject/bin/$CONFIDENCE/$NET_VERSION/plugins
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
for dir in plugins/* ; do
|
||||||
|
|
||||||
|
echo "Building $dir"
|
||||||
|
|
||||||
|
pushd $dir
|
||||||
|
dotnet build
|
||||||
|
popd
|
||||||
|
|
||||||
|
echo "Copying $dir"
|
||||||
|
cp $dir/bin/$CONFIDENCE/$NET_VERSION/*.dll app/MBS.Editor/bin/$CONFIDENCE/$NET_VERSION/plugins
|
||||||
|
cp $dir/bin/$CONFIDENCE/$NET_VERSION/*.dll app/MBS.Editor.TestProject/bin/$CONFIDENCE/$NET_VERSION/plugins
|
||||||
|
|
||||||
|
done
|
||||||
157
editor-dotnet/src/lib/MBS.Editor.Core/Checksum/CRCUtilities.cs
Normal file
157
editor-dotnet/src/lib/MBS.Editor.Core/Checksum/CRCUtilities.cs
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Checksum;
|
||||||
|
|
||||||
|
internal static class CRCUtilities
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The number of slicing lookup tables to generate.
|
||||||
|
/// </summary>
|
||||||
|
internal const int SlicingDegree = 16;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates multiple CRC lookup tables for a given polynomial, stored
|
||||||
|
/// in a linear array of uints. The first block (i.e. the first 256
|
||||||
|
/// elements) is the same as the byte-by-byte CRC lookup table.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="polynomial">The generating CRC polynomial</param>
|
||||||
|
/// <param name="isReversed">Whether the polynomial is in reversed bit order</param>
|
||||||
|
/// <returns>A linear array of 256 * <see cref="SlicingDegree"/> elements</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// This table could also be generated as a rectangular array, but the
|
||||||
|
/// JIT compiler generates slower code than if we use a linear array.
|
||||||
|
/// Known issue, see: https://github.com/dotnet/runtime/issues/30275
|
||||||
|
/// </remarks>
|
||||||
|
internal static uint[] GenerateSlicingLookupTable(uint polynomial, bool isReversed)
|
||||||
|
{
|
||||||
|
var table = new uint[256 * SlicingDegree];
|
||||||
|
uint one = isReversed ? 1 : (1U << 31);
|
||||||
|
|
||||||
|
for (int i = 0; i < 256; i++)
|
||||||
|
{
|
||||||
|
uint res = (uint)(isReversed ? i : i << 24);
|
||||||
|
for (int j = 0; j < SlicingDegree; j++)
|
||||||
|
{
|
||||||
|
for (int k = 0; k < 8; k++)
|
||||||
|
{
|
||||||
|
if (isReversed)
|
||||||
|
{
|
||||||
|
res = (res & one) == 1 ? polynomial ^ (res >> 1) : res >> 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = (res & one) != 0 ? polynomial ^ (res << 1) : res << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table[(256 * j) + i] = res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return table;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mixes the first four bytes of input with <paramref name="checkValue"/>
|
||||||
|
/// using normal ordering before calling <see cref="UpdateDataCommon"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">Array of data to checksum</param>
|
||||||
|
/// <param name="offset">Offset to start reading <paramref name="input"/> from</param>
|
||||||
|
/// <param name="crcTable">The table to use for slicing-by-16 lookup</param>
|
||||||
|
/// <param name="checkValue">Checksum state before this update call</param>
|
||||||
|
/// <returns>A new unfinalized checksum value</returns>
|
||||||
|
/// <seealso cref="UpdateDataForReversedPoly"/>
|
||||||
|
/// <remarks>
|
||||||
|
/// Assumes input[offset]..input[offset + 15] are valid array indexes.
|
||||||
|
/// For performance reasons, this must be checked by the caller.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static uint UpdateDataForNormalPoly(byte[] input, int offset, uint[] crcTable, uint checkValue)
|
||||||
|
{
|
||||||
|
byte x1 = (byte)((byte)(checkValue >> 24) ^ input[offset]);
|
||||||
|
byte x2 = (byte)((byte)(checkValue >> 16) ^ input[offset + 1]);
|
||||||
|
byte x3 = (byte)((byte)(checkValue >> 8) ^ input[offset + 2]);
|
||||||
|
byte x4 = (byte)((byte)checkValue ^ input[offset + 3]);
|
||||||
|
|
||||||
|
return UpdateDataCommon(input, offset, crcTable, x1, x2, x3, x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mixes the first four bytes of input with <paramref name="checkValue"/>
|
||||||
|
/// using reflected ordering before calling <see cref="UpdateDataCommon"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">Array of data to checksum</param>
|
||||||
|
/// <param name="offset">Offset to start reading <paramref name="input"/> from</param>
|
||||||
|
/// <param name="crcTable">The table to use for slicing-by-16 lookup</param>
|
||||||
|
/// <param name="checkValue">Checksum state before this update call</param>
|
||||||
|
/// <returns>A new unfinalized checksum value</returns>
|
||||||
|
/// <seealso cref="UpdateDataForNormalPoly"/>
|
||||||
|
/// <remarks>
|
||||||
|
/// Assumes input[offset]..input[offset + 15] are valid array indexes.
|
||||||
|
/// For performance reasons, this must be checked by the caller.
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
internal static uint UpdateDataForReversedPoly(byte[] input, int offset, uint[] crcTable, uint checkValue)
|
||||||
|
{
|
||||||
|
byte x1 = (byte)((byte)checkValue ^ input[offset]);
|
||||||
|
byte x2 = (byte)((byte)(checkValue >>= 8) ^ input[offset + 1]);
|
||||||
|
byte x3 = (byte)((byte)(checkValue >>= 8) ^ input[offset + 2]);
|
||||||
|
byte x4 = (byte)((byte)(checkValue >>= 8) ^ input[offset + 3]);
|
||||||
|
|
||||||
|
return UpdateDataCommon(input, offset, crcTable, x1, x2, x3, x4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A shared method for updating an unfinalized CRC checksum using slicing-by-16.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="input">Array of data to checksum</param>
|
||||||
|
/// <param name="offset">Offset to start reading <paramref name="input"/> from</param>
|
||||||
|
/// <param name="crcTable">The table to use for slicing-by-16 lookup</param>
|
||||||
|
/// <param name="x1">First byte of input after mixing with the old CRC</param>
|
||||||
|
/// <param name="x2">Second byte of input after mixing with the old CRC</param>
|
||||||
|
/// <param name="x3">Third byte of input after mixing with the old CRC</param>
|
||||||
|
/// <param name="x4">Fourth byte of input after mixing with the old CRC</param>
|
||||||
|
/// <returns>A new unfinalized checksum value</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// Even though the first four bytes of input are fed in as arguments,
|
||||||
|
/// <paramref name="offset"/> should be the same value passed to this
|
||||||
|
/// function's caller (either <see cref="UpdateDataForNormalPoly"/> or
|
||||||
|
/// <see cref="UpdateDataForReversedPoly"/>). This method will get inlined
|
||||||
|
/// into both functions, so using the same offset produces faster code.
|
||||||
|
/// </para>
|
||||||
|
/// <para>
|
||||||
|
/// Because most processors running C# have some kind of instruction-level
|
||||||
|
/// parallelism, the order of XOR operations can affect performance. This
|
||||||
|
/// ordering assumes that the assembly code generated by the just-in-time
|
||||||
|
/// compiler will emit a bunch of arithmetic operations for checking array
|
||||||
|
/// bounds. Then it opportunistically XORs a1 and a2 to keep the processor
|
||||||
|
/// busy while those other parts of the pipeline handle the range check
|
||||||
|
/// calculations.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
private static uint UpdateDataCommon(byte[] input, int offset, uint[] crcTable, byte x1, byte x2, byte x3, byte x4)
|
||||||
|
{
|
||||||
|
uint result;
|
||||||
|
uint a1 = crcTable[x1 + 3840] ^ crcTable[x2 + 3584];
|
||||||
|
uint a2 = crcTable[x3 + 3328] ^ crcTable[x4 + 3072];
|
||||||
|
|
||||||
|
result = crcTable[input[offset + 4] + 2816];
|
||||||
|
result ^= crcTable[input[offset + 5] + 2560];
|
||||||
|
a1 ^= crcTable[input[offset + 9] + 1536];
|
||||||
|
result ^= crcTable[input[offset + 6] + 2304];
|
||||||
|
result ^= crcTable[input[offset + 7] + 2048];
|
||||||
|
result ^= crcTable[input[offset + 8] + 1792];
|
||||||
|
a2 ^= crcTable[input[offset + 13] + 512];
|
||||||
|
result ^= crcTable[input[offset + 10] + 1280];
|
||||||
|
result ^= crcTable[input[offset + 11] + 1024];
|
||||||
|
result ^= crcTable[input[offset + 12] + 768];
|
||||||
|
result ^= a1;
|
||||||
|
result ^= crcTable[input[offset + 14] + 256];
|
||||||
|
result ^= crcTable[input[offset + 15]];
|
||||||
|
result ^= a2;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
using System.Formats.Tar;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Checksum;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interface to compute a data checksum used by checked input/output streams.
|
||||||
|
/// A data checksum can be updated by one byte or with a byte array. After each
|
||||||
|
/// update the value of the current checksum can be returned by calling
|
||||||
|
/// <code>getValue</code>. The complete checksum object can also be reset
|
||||||
|
/// so it can be used again with new data.
|
||||||
|
/// </summary>
|
||||||
|
public abstract class ChecksumModule
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the data checksum as if no update was ever called.
|
||||||
|
/// </summary>
|
||||||
|
protected abstract void ResetInternal();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the data checksum as if no update was ever called.
|
||||||
|
/// </summary>
|
||||||
|
public void Reset()
|
||||||
|
{
|
||||||
|
ResetInternal();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void UpdateInternal(int bval);
|
||||||
|
protected abstract long GetValueInternal();
|
||||||
|
|
||||||
|
private long checkValue;
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the data checksum computed so far.
|
||||||
|
/// </summary>
|
||||||
|
public long Value { get { return GetValueInternal(); } }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds one byte to the data checksum.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name = "bval">
|
||||||
|
/// the data value to add. The high byte of the int is ignored.
|
||||||
|
/// </param>
|
||||||
|
public void Update(int bval)
|
||||||
|
{
|
||||||
|
UpdateInternal(bval);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,172 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Checksum.Modules.BZip2CRC;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// CRC-32 with unreversed data and reversed output
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Generate a table for a byte-wise 32-bit CRC calculation on the polynomial:
|
||||||
|
/// x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x^1+x^0.
|
||||||
|
///
|
||||||
|
/// Polynomials over GF(2) are represented in binary, one bit per coefficient,
|
||||||
|
/// with the lowest powers in the most significant bit. Then adding polynomials
|
||||||
|
/// is just exclusive-or, and multiplying a polynomial by x is a right shift by
|
||||||
|
/// one. If we call the above polynomial p, and represent a byte as the
|
||||||
|
/// polynomial q, also with the lowest power in the most significant bit (so the
|
||||||
|
/// byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p,
|
||||||
|
/// where a mod b means the remainder after dividing a by b.
|
||||||
|
///
|
||||||
|
/// This calculation is done using the shift-register method of multiplying and
|
||||||
|
/// taking the remainder. The register is initialized to zero, and for each
|
||||||
|
/// incoming bit, x^32 is added mod p to the register if the bit is a one (where
|
||||||
|
/// x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by
|
||||||
|
/// x (which is shifting right by one and adding x^32 mod p if the bit shifted
|
||||||
|
/// out is a one). We start with the highest power (least significant bit) of
|
||||||
|
/// q and repeat for all eight bits of q.
|
||||||
|
///
|
||||||
|
/// This implementation uses sixteen lookup tables stored in one linear array
|
||||||
|
/// to implement the slicing-by-16 algorithm, a variant of the slicing-by-8
|
||||||
|
/// algorithm described in this Intel white paper:
|
||||||
|
///
|
||||||
|
/// https://web.archive.org/web/20120722193753/http://download.intel.com/technology/comms/perfnet/download/slicing-by-8.pdf
|
||||||
|
///
|
||||||
|
/// The first lookup table is simply the CRC of all possible eight bit values.
|
||||||
|
/// Each successive lookup table is derived from the original table generated
|
||||||
|
/// by Sarwate's algorithm. Slicing a 16-bit input and XORing the outputs
|
||||||
|
/// together will produce the same output as a byte-by-byte CRC loop with
|
||||||
|
/// fewer arithmetic and bit manipulation operations, at the cost of increased
|
||||||
|
/// memory consumed by the lookup tables. (Slicing-by-16 requires a 16KB table,
|
||||||
|
/// which is still small enough to fit in most processors' L1 cache.)
|
||||||
|
/// </remarks>
|
||||||
|
public sealed class BZip2CRCChecksumModule : ChecksumModule
|
||||||
|
{
|
||||||
|
#region Instance Fields
|
||||||
|
|
||||||
|
private const uint crcInit = 0xFFFFFFFF;
|
||||||
|
//const uint crcXor = 0x00000000;
|
||||||
|
|
||||||
|
private static readonly uint[] crcTable = CRCUtilities.GenerateSlicingLookupTable(0x04C11DB7, isReversed: false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The CRC data checksum so far.
|
||||||
|
/// </summary>
|
||||||
|
private uint checkValue;
|
||||||
|
|
||||||
|
#endregion Instance Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise a default instance of <see cref="BZip2Crc"></see>
|
||||||
|
/// </summary>
|
||||||
|
public BZip2CRCChecksumModule()
|
||||||
|
{
|
||||||
|
Reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Resets the CRC data checksum as if no update was ever called.
|
||||||
|
/// </summary>
|
||||||
|
protected override void ResetInternal()
|
||||||
|
{
|
||||||
|
checkValue = crcInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns the CRC data checksum computed so far.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>Reversed Out = true</remarks>
|
||||||
|
protected override long GetValueInternal()
|
||||||
|
{
|
||||||
|
// Technically, the output should be:
|
||||||
|
//return (long)(~checkValue ^ crcXor);
|
||||||
|
// but x ^ 0 = x, so there is no point in adding
|
||||||
|
// the XOR operation
|
||||||
|
return (long)(~checkValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the checksum with the int bval.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name = "bval">
|
||||||
|
/// the byte is taken as the lower 8 bits of bval
|
||||||
|
/// </param>
|
||||||
|
/// <remarks>Reversed Data = false</remarks>
|
||||||
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
|
protected override void UpdateInternal(int bval)
|
||||||
|
{
|
||||||
|
checkValue = unchecked(crcTable[(byte)(((checkValue >> 24) & 0xFF) ^ bval)] ^ (checkValue << 8));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the CRC data checksum with the bytes taken from
|
||||||
|
/// a block of data.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">Contains the data to update the CRC with.</param>
|
||||||
|
public void Update(byte[] buffer)
|
||||||
|
{
|
||||||
|
if (buffer == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
|
Update(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Update CRC data checksum based on a portion of a block of data
|
||||||
|
/// </summary>
|
||||||
|
/// <param name = "segment">
|
||||||
|
/// The chunk of data to add
|
||||||
|
/// </param>
|
||||||
|
public void Update(ArraySegment<byte> segment)
|
||||||
|
{
|
||||||
|
Update(segment.Array, segment.Offset, segment.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Internal helper function for updating a block of data using slicing.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The array containing the data to add</param>
|
||||||
|
/// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
|
||||||
|
/// <param name="count">The number of bytes to checksum starting from <paramref name="offset"/></param>
|
||||||
|
private void Update(byte[] data, int offset, int count)
|
||||||
|
{
|
||||||
|
int remainder = count % CRCUtilities.SlicingDegree;
|
||||||
|
int end = offset + count - remainder;
|
||||||
|
|
||||||
|
while (offset != end)
|
||||||
|
{
|
||||||
|
checkValue = CRCUtilities.UpdateDataForNormalPoly(data, offset, crcTable, checkValue);
|
||||||
|
offset += CRCUtilities.SlicingDegree;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (remainder != 0)
|
||||||
|
{
|
||||||
|
SlowUpdateLoop(data, offset, end + remainder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A non-inlined function for updating data that doesn't fit in a 16-byte
|
||||||
|
/// block. We don't expect to enter this function most of the time, and when
|
||||||
|
/// we do we're not here for long, so disabling inlining here improves
|
||||||
|
/// performance overall.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="data">The array containing the data to add</param>
|
||||||
|
/// <param name="offset">Range start for <paramref name="data"/> (inclusive)</param>
|
||||||
|
/// <param name="end">Range end for <paramref name="data"/> (exclusive)</param>
|
||||||
|
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||||
|
private void SlowUpdateLoop(byte[] data, int offset, int end)
|
||||||
|
{
|
||||||
|
while (offset != end)
|
||||||
|
{
|
||||||
|
Update(data[offset++]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
public class CompressionException : Exception
|
||||||
|
{
|
||||||
|
|
||||||
|
public CompressionException() : base() { }
|
||||||
|
public CompressionException(string message) : base(message) { }
|
||||||
|
public CompressionException(string message, Exception innerException) : base(message, innerException) { }
|
||||||
|
}
|
||||||
@ -0,0 +1,43 @@
|
|||||||
|
namespace MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
public abstract class CompressionModule
|
||||||
|
{
|
||||||
|
|
||||||
|
public byte[] Compress(byte[] input)
|
||||||
|
{
|
||||||
|
MemoryStream inputStream = new MemoryStream(input);
|
||||||
|
MemoryStream outputStream = new MemoryStream();
|
||||||
|
Compress(inputStream, outputStream);
|
||||||
|
|
||||||
|
outputStream.Flush();
|
||||||
|
outputStream.Close();
|
||||||
|
return outputStream.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Compress(Stream inputStream, Stream outputStream)
|
||||||
|
{
|
||||||
|
CompressInternal(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] Decompress(byte[] input)
|
||||||
|
{
|
||||||
|
MemoryStream inputStream = new MemoryStream(input);
|
||||||
|
MemoryStream outputStream = new MemoryStream();
|
||||||
|
Decompress(inputStream, outputStream);
|
||||||
|
|
||||||
|
outputStream.Flush();
|
||||||
|
outputStream.Close();
|
||||||
|
return outputStream.ToArray();
|
||||||
|
}
|
||||||
|
public void Decompress(Stream inputStream, Stream outputStream)
|
||||||
|
{
|
||||||
|
DecompressInternal(inputStream, outputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
//protected abstract void CompressInternal(Stream inputStream, byte[] buffer, int offset, int length);
|
||||||
|
//protected abstract void DecompressInternal(Stream inputStream, byte[] buffer, int offset, int length);
|
||||||
|
|
||||||
|
protected abstract void CompressInternal(Stream inputStream, Stream outputStream);
|
||||||
|
protected abstract void DecompressInternal(Stream inputStream, Stream outputStream);
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
public abstract class DualStreamCompressionModule<TInputStream, TOutputStream> : CompressionModule where TInputStream : Stream where TOutputStream : Stream
|
||||||
|
{
|
||||||
|
protected abstract TOutputStream CreateCompressor(Stream stream);
|
||||||
|
protected abstract TInputStream CreateDecompressor(Stream stream);
|
||||||
|
|
||||||
|
protected override void CompressInternal(Stream inputStream, Stream outputStream)
|
||||||
|
{
|
||||||
|
TOutputStream _compressor = CreateCompressor(outputStream);
|
||||||
|
inputStream.CopyTo(_compressor);
|
||||||
|
|
||||||
|
// !!! IMPORTANT !!! DO NOT FORGET TO FLUSH !!!
|
||||||
|
_compressor.Flush();
|
||||||
|
_compressor.Close();
|
||||||
|
}
|
||||||
|
protected override void DecompressInternal(Stream inputStream, Stream outputStream)
|
||||||
|
{
|
||||||
|
TInputStream _decompressor = CreateDecompressor(inputStream);
|
||||||
|
_decompressor.CopyTo(outputStream);
|
||||||
|
|
||||||
|
// !!! IMPORTANT !!! DO NOT FORGET TO FLUSH !!!
|
||||||
|
_decompressor.Flush();
|
||||||
|
_decompressor.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,38 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
using MBS.Editor.Core.Compression;
|
||||||
|
using MBS.Editor.Core.Compression.Modules.BZip2;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression.Modules.GZip;
|
||||||
|
|
||||||
|
public class BZip2CompressionModule : DualStreamCompressionModule<BZip2InputStream, BZip2OutputStream>
|
||||||
|
{
|
||||||
|
protected override BZip2OutputStream CreateCompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new BZip2OutputStream(stream);
|
||||||
|
}
|
||||||
|
protected override BZip2InputStream CreateDecompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new BZip2InputStream(stream);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
protected override void CompressInternal(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
if (_compressor == null)
|
||||||
|
{
|
||||||
|
MemoryStream ms = new MemoryStream();
|
||||||
|
_compressor = new GZipStream(ms, GetSystemCompressionLevel());
|
||||||
|
}
|
||||||
|
_compressor.Write(buffer, offset, length);
|
||||||
|
}
|
||||||
|
protected override int DecompressInternal(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
if (_decompressor == null)
|
||||||
|
{
|
||||||
|
MemoryStream ms = new MemoryStream();
|
||||||
|
_decompressor = new GZipStream(ms, GetSystemCompressionLevel());
|
||||||
|
}
|
||||||
|
return _decompressor.Read(buffer, offset, length);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
@ -0,0 +1,116 @@
|
|||||||
|
namespace MBS.Editor.Core.Compression.Modules.BZip2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines internal values for both compression and decompression
|
||||||
|
/// </summary>
|
||||||
|
internal static class BZip2Constants
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Random numbers used to randomise repetitive blocks
|
||||||
|
/// </summary>
|
||||||
|
public readonly static int[] RandomNumbers = {
|
||||||
|
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
|
||||||
|
};
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// When multiplied by compression parameter (1-9) gives the block size for compression
|
||||||
|
/// 9 gives the best compression but uses the most memory.
|
||||||
|
/// </summary>
|
||||||
|
public const int BaseBlockSize = 100000;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int MaximumAlphaSize = 258;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int MaximumCodeLength = 23;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int RunA = 0;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int RunB = 1;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int GroupCount = 6;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int GroupSize = 50;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int NumberOfIterations = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int MaximumSelectors = (2 + (900000 / GroupSize));
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Backend constant
|
||||||
|
/// </summary>
|
||||||
|
public const int OvershootBytes = 20;
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression.Modules.BZip2;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// BZip2Exception represents exceptions specific to BZip2 classes and code.
|
||||||
|
/// </summary>
|
||||||
|
public class BZip2Exception : CompressionException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise a new instance of <see cref="BZip2Exception" />.
|
||||||
|
/// </summary>
|
||||||
|
public BZip2Exception()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise a new instance of <see cref="BZip2Exception" /> with its message string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||||
|
public BZip2Exception(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise a new instance of <see cref="BZip2Exception" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||||
|
/// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
|
||||||
|
public BZip2Exception(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,16 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
using MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression.Modules.Deflate;
|
||||||
|
|
||||||
|
public class DeflateCompressionModule : SystemCompressionModule<DeflateStream>
|
||||||
|
{
|
||||||
|
protected override DeflateStream CreateCompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new DeflateStream(stream, GetSystemCompressionLevel());
|
||||||
|
}
|
||||||
|
protected override DeflateStream CreateDecompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new DeflateStream(stream, CompressionMode.Decompress);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,37 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
using MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression.Modules.GZip;
|
||||||
|
|
||||||
|
public class GZipCompressionModule : SystemCompressionModule<GZipStream>
|
||||||
|
{
|
||||||
|
protected override GZipStream CreateCompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new GZipStream(stream, GetSystemCompressionLevel());
|
||||||
|
}
|
||||||
|
protected override GZipStream CreateDecompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new GZipStream(stream, System.IO.Compression.CompressionMode.Decompress);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
protected override void CompressInternal(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
if (_compressor == null)
|
||||||
|
{
|
||||||
|
MemoryStream ms = new MemoryStream();
|
||||||
|
_compressor = new GZipStream(ms, GetSystemCompressionLevel());
|
||||||
|
}
|
||||||
|
_compressor.Write(buffer, offset, length);
|
||||||
|
}
|
||||||
|
protected override int DecompressInternal(byte[] buffer, int offset, int length)
|
||||||
|
{
|
||||||
|
if (_decompressor == null)
|
||||||
|
{
|
||||||
|
MemoryStream ms = new MemoryStream();
|
||||||
|
_decompressor = new GZipStream(ms, GetSystemCompressionLevel());
|
||||||
|
}
|
||||||
|
return _decompressor.Read(buffer, offset, length);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
@ -0,0 +1,62 @@
|
|||||||
|
namespace MBS.Editor.Core.Compression.Modules.LZW.Internal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class contains constants used for LZW
|
||||||
|
/// </summary>
|
||||||
|
[System.Diagnostics.CodeAnalysis.SuppressMessage("Naming", "CA1707:Identifiers should not contain underscores", Justification = "kept for backwards compatibility")]
|
||||||
|
sealed public class LzwConstants
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Magic number found at start of LZW header: 0x1f 0x9d
|
||||||
|
/// </summary>
|
||||||
|
public const int MAGIC = 0x1f9d;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maximum number of bits per code
|
||||||
|
/// </summary>
|
||||||
|
public const int MAX_BITS = 16;
|
||||||
|
|
||||||
|
/* 3rd header byte:
|
||||||
|
* bit 0..4 Number of compression bits
|
||||||
|
* bit 5 Extended header
|
||||||
|
* bit 6 Free
|
||||||
|
* bit 7 Block mode
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Mask for 'number of compression bits'
|
||||||
|
/// </summary>
|
||||||
|
public const int BIT_MASK = 0x1f;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Indicates the presence of a fourth header byte
|
||||||
|
/// </summary>
|
||||||
|
public const int EXTENDED_MASK = 0x20;
|
||||||
|
|
||||||
|
//public const int FREE_MASK = 0x40;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reserved bits
|
||||||
|
/// </summary>
|
||||||
|
public const int RESERVED_MASK = 0x60;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Block compression: if table is full and compression rate is dropping,
|
||||||
|
/// clear the dictionary.
|
||||||
|
/// </summary>
|
||||||
|
public const int BLOCK_MODE_MASK = 0x80;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// LZW file header size (in bytes)
|
||||||
|
/// </summary>
|
||||||
|
public const int HDR_SIZE = 3;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initial number of bits per code
|
||||||
|
/// </summary>
|
||||||
|
public const int INIT_BITS = 9;
|
||||||
|
|
||||||
|
private LzwConstants()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,571 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression.Modules.LZW.Internal;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This filter stream is used to decompress a LZW format stream.
|
||||||
|
/// Specifically, a stream that uses the LZC compression method.
|
||||||
|
/// This file format is usually associated with the .Z file extension.
|
||||||
|
///
|
||||||
|
/// See http://en.wikipedia.org/wiki/Compress
|
||||||
|
/// See http://wiki.wxwidgets.org/Development:_Z_File_Format
|
||||||
|
///
|
||||||
|
/// The file header consists of 3 (or optionally 4) bytes. The first two bytes
|
||||||
|
/// contain the magic marker "0x1f 0x9d", followed by a byte of flags.
|
||||||
|
///
|
||||||
|
/// Based on Java code by Ronald Tschalar, which in turn was based on the unlzw.c
|
||||||
|
/// code in the gzip package.
|
||||||
|
/// </summary>
|
||||||
|
/// <example> This sample shows how to unzip a compressed file
|
||||||
|
/// <code>
|
||||||
|
/// using System;
|
||||||
|
/// using System.IO;
|
||||||
|
///
|
||||||
|
/// using ICSharpCode.SharpZipLib.Core;
|
||||||
|
/// using ICSharpCode.SharpZipLib.LZW;
|
||||||
|
///
|
||||||
|
/// class MainClass
|
||||||
|
/// {
|
||||||
|
/// public static void Main(string[] args)
|
||||||
|
/// {
|
||||||
|
/// using (Stream inStream = new LzwInputStream(File.OpenRead(args[0])))
|
||||||
|
/// using (FileStream outStream = File.Create(Path.GetFileNameWithoutExtension(args[0]))) {
|
||||||
|
/// byte[] buffer = new byte[4096];
|
||||||
|
/// StreamUtils.Copy(inStream, outStream, buffer);
|
||||||
|
/// // OR
|
||||||
|
/// inStream.Read(buffer, 0, buffer.Length);
|
||||||
|
/// // now do something with the buffer
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
/// </code>
|
||||||
|
/// </example>
|
||||||
|
public class LzwInputStream : Stream
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets a flag indicating ownership of underlying stream.
|
||||||
|
/// When the flag is true <see cref="Stream.Dispose()" /> will close the underlying stream also.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>The default value is true.</remarks>
|
||||||
|
public bool IsStreamOwner { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates a LzwInputStream
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="baseInputStream">
|
||||||
|
/// The stream to read compressed data from (baseInputStream LZW format)
|
||||||
|
/// </param>
|
||||||
|
public LzwInputStream(Stream baseInputStream)
|
||||||
|
{
|
||||||
|
this.baseInputStream = baseInputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// See <see cref="System.IO.Stream.ReadByte"/>
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override int ReadByte()
|
||||||
|
{
|
||||||
|
int b = Read(one, 0, 1);
|
||||||
|
if (b == 1)
|
||||||
|
return (one[0] & 0xff);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Reads decompressed data into the provided buffer byte array
|
||||||
|
/// </summary>
|
||||||
|
/// <param name ="buffer">
|
||||||
|
/// The array to read and decompress data into
|
||||||
|
/// </param>
|
||||||
|
/// <param name ="offset">
|
||||||
|
/// The offset indicating where the data should be placed
|
||||||
|
/// </param>
|
||||||
|
/// <param name ="count">
|
||||||
|
/// The number of bytes to decompress
|
||||||
|
/// </param>
|
||||||
|
/// <returns>The number of bytes read. Zero signals the end of stream</returns>
|
||||||
|
public override int Read(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
if (!headerParsed)
|
||||||
|
ParseHeader();
|
||||||
|
|
||||||
|
if (eof)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int start = offset;
|
||||||
|
|
||||||
|
/* Using local copies of various variables speeds things up by as
|
||||||
|
* much as 30% in Java! Performance not tested in C#.
|
||||||
|
*/
|
||||||
|
int[] lTabPrefix = tabPrefix;
|
||||||
|
byte[] lTabSuffix = tabSuffix;
|
||||||
|
byte[] lStack = stack;
|
||||||
|
int lNBits = nBits;
|
||||||
|
int lMaxCode = maxCode;
|
||||||
|
int lMaxMaxCode = maxMaxCode;
|
||||||
|
int lBitMask = bitMask;
|
||||||
|
int lOldCode = oldCode;
|
||||||
|
byte lFinChar = finChar;
|
||||||
|
int lStackP = stackP;
|
||||||
|
int lFreeEnt = freeEnt;
|
||||||
|
byte[] lData = data;
|
||||||
|
int lBitPos = bitPos;
|
||||||
|
|
||||||
|
// empty stack if stuff still left
|
||||||
|
int sSize = lStack.Length - lStackP;
|
||||||
|
if (sSize > 0)
|
||||||
|
{
|
||||||
|
int num = (sSize >= count) ? count : sSize;
|
||||||
|
Array.Copy(lStack, lStackP, buffer, offset, num);
|
||||||
|
offset += num;
|
||||||
|
count -= num;
|
||||||
|
lStackP += num;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
stackP = lStackP;
|
||||||
|
return offset - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// loop, filling local buffer until enough data has been decompressed
|
||||||
|
MainLoop:
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if (end < EXTRA)
|
||||||
|
{
|
||||||
|
Fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
int bitIn = (got > 0) ? (end - end % lNBits) << 3 :
|
||||||
|
(end << 3) - (lNBits - 1);
|
||||||
|
|
||||||
|
while (lBitPos < bitIn)
|
||||||
|
{
|
||||||
|
#region A
|
||||||
|
|
||||||
|
// handle 1-byte reads correctly
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
nBits = lNBits;
|
||||||
|
maxCode = lMaxCode;
|
||||||
|
maxMaxCode = lMaxMaxCode;
|
||||||
|
bitMask = lBitMask;
|
||||||
|
oldCode = lOldCode;
|
||||||
|
finChar = lFinChar;
|
||||||
|
stackP = lStackP;
|
||||||
|
freeEnt = lFreeEnt;
|
||||||
|
bitPos = lBitPos;
|
||||||
|
|
||||||
|
return offset - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check for code-width expansion
|
||||||
|
if (lFreeEnt > lMaxCode)
|
||||||
|
{
|
||||||
|
int nBytes = lNBits << 3;
|
||||||
|
lBitPos = (lBitPos - 1) +
|
||||||
|
nBytes - (lBitPos - 1 + nBytes) % nBytes;
|
||||||
|
|
||||||
|
lNBits++;
|
||||||
|
lMaxCode = (lNBits == maxBits) ? lMaxMaxCode :
|
||||||
|
(1 << lNBits) - 1;
|
||||||
|
|
||||||
|
lBitMask = (1 << lNBits) - 1;
|
||||||
|
lBitPos = ResetBuf(lBitPos);
|
||||||
|
goto MainLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion A
|
||||||
|
|
||||||
|
#region B
|
||||||
|
|
||||||
|
// read next code
|
||||||
|
int pos = lBitPos >> 3;
|
||||||
|
int code = (((lData[pos] & 0xFF) |
|
||||||
|
((lData[pos + 1] & 0xFF) << 8) |
|
||||||
|
((lData[pos + 2] & 0xFF) << 16)) >>
|
||||||
|
(lBitPos & 0x7)) & lBitMask;
|
||||||
|
|
||||||
|
lBitPos += lNBits;
|
||||||
|
|
||||||
|
// handle first iteration
|
||||||
|
if (lOldCode == -1)
|
||||||
|
{
|
||||||
|
if (code >= 256)
|
||||||
|
throw new LZWException("corrupt input: " + code + " > 255");
|
||||||
|
|
||||||
|
lFinChar = (byte)(lOldCode = code);
|
||||||
|
buffer[offset++] = lFinChar;
|
||||||
|
count--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle CLEAR code
|
||||||
|
if (code == TBL_CLEAR && blockMode)
|
||||||
|
{
|
||||||
|
Array.Copy(zeros, 0, lTabPrefix, 0, zeros.Length);
|
||||||
|
lFreeEnt = TBL_FIRST - 1;
|
||||||
|
|
||||||
|
int nBytes = lNBits << 3;
|
||||||
|
lBitPos = (lBitPos - 1) + nBytes - (lBitPos - 1 + nBytes) % nBytes;
|
||||||
|
lNBits = LzwConstants.INIT_BITS;
|
||||||
|
lMaxCode = (1 << lNBits) - 1;
|
||||||
|
lBitMask = lMaxCode;
|
||||||
|
|
||||||
|
// Code tables reset
|
||||||
|
|
||||||
|
lBitPos = ResetBuf(lBitPos);
|
||||||
|
goto MainLoop;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion B
|
||||||
|
|
||||||
|
#region C
|
||||||
|
|
||||||
|
// setup
|
||||||
|
int inCode = code;
|
||||||
|
lStackP = lStack.Length;
|
||||||
|
|
||||||
|
// Handle KwK case
|
||||||
|
if (code >= lFreeEnt)
|
||||||
|
{
|
||||||
|
if (code > lFreeEnt)
|
||||||
|
{
|
||||||
|
throw new LZWException("corrupt input: code=" + code +
|
||||||
|
", freeEnt=" + lFreeEnt);
|
||||||
|
}
|
||||||
|
|
||||||
|
lStack[--lStackP] = lFinChar;
|
||||||
|
code = lOldCode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate output characters in reverse order
|
||||||
|
while (code >= 256)
|
||||||
|
{
|
||||||
|
lStack[--lStackP] = lTabSuffix[code];
|
||||||
|
code = lTabPrefix[code];
|
||||||
|
}
|
||||||
|
|
||||||
|
lFinChar = lTabSuffix[code];
|
||||||
|
buffer[offset++] = lFinChar;
|
||||||
|
count--;
|
||||||
|
|
||||||
|
// And put them out in forward order
|
||||||
|
sSize = lStack.Length - lStackP;
|
||||||
|
int num = (sSize >= count) ? count : sSize;
|
||||||
|
Array.Copy(lStack, lStackP, buffer, offset, num);
|
||||||
|
offset += num;
|
||||||
|
count -= num;
|
||||||
|
lStackP += num;
|
||||||
|
|
||||||
|
#endregion C
|
||||||
|
|
||||||
|
#region D
|
||||||
|
|
||||||
|
// generate new entry in table
|
||||||
|
if (lFreeEnt < lMaxMaxCode)
|
||||||
|
{
|
||||||
|
lTabPrefix[lFreeEnt] = lOldCode;
|
||||||
|
lTabSuffix[lFreeEnt] = lFinChar;
|
||||||
|
lFreeEnt++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remember previous code
|
||||||
|
lOldCode = inCode;
|
||||||
|
|
||||||
|
// if output buffer full, then return
|
||||||
|
if (count == 0)
|
||||||
|
{
|
||||||
|
nBits = lNBits;
|
||||||
|
maxCode = lMaxCode;
|
||||||
|
bitMask = lBitMask;
|
||||||
|
oldCode = lOldCode;
|
||||||
|
finChar = lFinChar;
|
||||||
|
stackP = lStackP;
|
||||||
|
freeEnt = lFreeEnt;
|
||||||
|
bitPos = lBitPos;
|
||||||
|
|
||||||
|
return offset - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion D
|
||||||
|
} // while
|
||||||
|
|
||||||
|
lBitPos = ResetBuf(lBitPos);
|
||||||
|
} while (got > 0); // do..while
|
||||||
|
|
||||||
|
nBits = lNBits;
|
||||||
|
maxCode = lMaxCode;
|
||||||
|
bitMask = lBitMask;
|
||||||
|
oldCode = lOldCode;
|
||||||
|
finChar = lFinChar;
|
||||||
|
stackP = lStackP;
|
||||||
|
freeEnt = lFreeEnt;
|
||||||
|
bitPos = lBitPos;
|
||||||
|
|
||||||
|
eof = true;
|
||||||
|
return offset - start;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Moves the unread data in the buffer to the beginning and resets
|
||||||
|
/// the pointers.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="bitPosition"></param>
|
||||||
|
/// <returns></returns>
|
||||||
|
private int ResetBuf(int bitPosition)
|
||||||
|
{
|
||||||
|
int pos = bitPosition >> 3;
|
||||||
|
Array.Copy(data, pos, data, 0, end - pos);
|
||||||
|
end -= pos;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Fill()
|
||||||
|
{
|
||||||
|
got = baseInputStream.Read(data, end, data.Length - 1 - end);
|
||||||
|
if (got > 0)
|
||||||
|
{
|
||||||
|
end += got;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ParseHeader()
|
||||||
|
{
|
||||||
|
headerParsed = true;
|
||||||
|
|
||||||
|
byte[] hdr = new byte[LzwConstants.HDR_SIZE];
|
||||||
|
|
||||||
|
int result = baseInputStream.Read(hdr, 0, hdr.Length);
|
||||||
|
|
||||||
|
// Check the magic marker
|
||||||
|
if (result < 0)
|
||||||
|
throw new LZWException("Failed to read LZW header");
|
||||||
|
|
||||||
|
if (hdr[0] != (LzwConstants.MAGIC >> 8) || hdr[1] != (LzwConstants.MAGIC & 0xff))
|
||||||
|
{
|
||||||
|
throw new LZWException(String.Format(
|
||||||
|
"Wrong LZW header. Magic bytes don't match. 0x{0:x2} 0x{1:x2}",
|
||||||
|
hdr[0], hdr[1]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the 3rd header byte
|
||||||
|
blockMode = (hdr[2] & LzwConstants.BLOCK_MODE_MASK) > 0;
|
||||||
|
maxBits = hdr[2] & LzwConstants.BIT_MASK;
|
||||||
|
|
||||||
|
if (maxBits > LzwConstants.MAX_BITS)
|
||||||
|
{
|
||||||
|
throw new LZWException("Stream compressed with " + maxBits +
|
||||||
|
" bits, but decompression can only handle " +
|
||||||
|
LzwConstants.MAX_BITS + " bits.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((hdr[2] & LzwConstants.RESERVED_MASK) > 0)
|
||||||
|
{
|
||||||
|
throw new LZWException("Unsupported bits set in the header.");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize variables
|
||||||
|
maxMaxCode = 1 << maxBits;
|
||||||
|
nBits = LzwConstants.INIT_BITS;
|
||||||
|
maxCode = (1 << nBits) - 1;
|
||||||
|
bitMask = maxCode;
|
||||||
|
oldCode = -1;
|
||||||
|
finChar = 0;
|
||||||
|
freeEnt = blockMode ? TBL_FIRST : 256;
|
||||||
|
|
||||||
|
tabPrefix = new int[1 << maxBits];
|
||||||
|
tabSuffix = new byte[1 << maxBits];
|
||||||
|
stack = new byte[1 << maxBits];
|
||||||
|
stackP = stack.Length;
|
||||||
|
|
||||||
|
for (int idx = 255; idx >= 0; idx--)
|
||||||
|
tabSuffix[idx] = (byte)idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Stream Overrides
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the current stream supports reading
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanRead
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return baseInputStream.CanRead;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value of false indicating seeking is not supported for this stream.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanSeek
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value of false indicating that this stream is not writeable.
|
||||||
|
/// </summary>
|
||||||
|
public override bool CanWrite
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// A value representing the length of the stream in bytes.
|
||||||
|
/// </summary>
|
||||||
|
public override long Length
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return got;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The current position within the stream.
|
||||||
|
/// Throws a NotSupportedException when attempting to set the position
|
||||||
|
/// </summary>
|
||||||
|
/// <exception cref="NotSupportedException">Attempting to set the position</exception>
|
||||||
|
public override long Position
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return baseInputStream.Position;
|
||||||
|
}
|
||||||
|
set
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("InflaterInputStream Position not supported");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flushes the baseInputStream
|
||||||
|
/// </summary>
|
||||||
|
public override void Flush()
|
||||||
|
{
|
||||||
|
baseInputStream.Flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Sets the position within the current stream
|
||||||
|
/// Always throws a NotSupportedException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="offset">The relative offset to seek to.</param>
|
||||||
|
/// <param name="origin">The <see cref="SeekOrigin"/> defining where to seek from.</param>
|
||||||
|
/// <returns>The new position in the stream.</returns>
|
||||||
|
/// <exception cref="NotSupportedException">Any access</exception>
|
||||||
|
public override long Seek(long offset, SeekOrigin origin)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("Seek not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Set the length of the current stream
|
||||||
|
/// Always throws a NotSupportedException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The new length value for the stream.</param>
|
||||||
|
/// <exception cref="NotSupportedException">Any access</exception>
|
||||||
|
public override void SetLength(long value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("InflaterInputStream SetLength not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes a sequence of bytes to stream and advances the current position
|
||||||
|
/// This method always throws a NotSupportedException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="buffer">The buffer containing data to write.</param>
|
||||||
|
/// <param name="offset">The offset of the first byte to write.</param>
|
||||||
|
/// <param name="count">The number of bytes to write.</param>
|
||||||
|
/// <exception cref="NotSupportedException">Any access</exception>
|
||||||
|
public override void Write(byte[] buffer, int offset, int count)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("InflaterInputStream Write not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Writes one byte to the current stream and advances the current position
|
||||||
|
/// Always throws a NotSupportedException
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="value">The byte to write.</param>
|
||||||
|
/// <exception cref="NotSupportedException">Any access</exception>
|
||||||
|
public override void WriteByte(byte value)
|
||||||
|
{
|
||||||
|
throw new NotSupportedException("InflaterInputStream WriteByte not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes the input stream. When <see cref="IsStreamOwner"></see>
|
||||||
|
/// is true the underlying stream is also closed.
|
||||||
|
/// </summary>
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (!isClosed)
|
||||||
|
{
|
||||||
|
isClosed = true;
|
||||||
|
if (IsStreamOwner)
|
||||||
|
{
|
||||||
|
baseInputStream.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Stream Overrides
|
||||||
|
|
||||||
|
#region Instance Fields
|
||||||
|
|
||||||
|
private Stream baseInputStream;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Flag indicating wether this instance has been closed or not.
|
||||||
|
/// </summary>
|
||||||
|
private bool isClosed;
|
||||||
|
|
||||||
|
private readonly byte[] one = new byte[1];
|
||||||
|
private bool headerParsed;
|
||||||
|
|
||||||
|
// string table stuff
|
||||||
|
private const int TBL_CLEAR = 0x100;
|
||||||
|
|
||||||
|
private const int TBL_FIRST = TBL_CLEAR + 1;
|
||||||
|
|
||||||
|
private int[] tabPrefix;
|
||||||
|
private byte[] tabSuffix;
|
||||||
|
private readonly int[] zeros = new int[256];
|
||||||
|
private byte[] stack;
|
||||||
|
|
||||||
|
// various state
|
||||||
|
private bool blockMode;
|
||||||
|
|
||||||
|
private int nBits;
|
||||||
|
private int maxBits;
|
||||||
|
private int maxMaxCode;
|
||||||
|
private int maxCode;
|
||||||
|
private int bitMask;
|
||||||
|
private int oldCode;
|
||||||
|
private byte finChar;
|
||||||
|
private int stackP;
|
||||||
|
private int freeEnt;
|
||||||
|
|
||||||
|
// input buffer
|
||||||
|
private readonly byte[] data = new byte[1024 * 8];
|
||||||
|
|
||||||
|
private int bitPos;
|
||||||
|
private int end;
|
||||||
|
private int got;
|
||||||
|
private bool eof;
|
||||||
|
private const int EXTRA = 64;
|
||||||
|
|
||||||
|
#endregion Instance Fields
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using MBS.Editor.Core.Compression.Modules.LZW.Internal;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression.Modules.LZW;
|
||||||
|
|
||||||
|
public class LZWCompressionModule : SystemCompressionModule<LzwInputStream>
|
||||||
|
{
|
||||||
|
protected override LzwInputStream CreateCompressor(Stream stream)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override LzwInputStream CreateDecompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new LzwInputStream(stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,36 @@
|
|||||||
|
using System;
|
||||||
|
using System.Runtime.Serialization;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression.Modules.LZW;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// LZWException represents exceptions specific to LZW classes and code.
|
||||||
|
/// </summary>
|
||||||
|
public class LZWException : CompressionException
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise a new instance of <see cref="LzwException" />.
|
||||||
|
/// </summary>
|
||||||
|
public LZWException()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise a new instance of <see cref="LzwException" /> with its message string.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||||
|
public LZWException(string message)
|
||||||
|
: base(message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialise a new instance of <see cref="LzwException" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">A <see cref="string"/> that describes the error.</param>
|
||||||
|
/// <param name="innerException">The <see cref="Exception"/> that caused this exception.</param>
|
||||||
|
public LZWException(string message, Exception innerException)
|
||||||
|
: base(message, innerException)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
using MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
public class ZlibBuiltinCompressionModule : SystemCompressionModule<ZLibStream>
|
||||||
|
{
|
||||||
|
protected override ZLibStream CreateCompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new ZLibStream(stream, GetSystemCompressionLevel());
|
||||||
|
}
|
||||||
|
protected override ZLibStream CreateDecompressor(Stream stream)
|
||||||
|
{
|
||||||
|
return new ZLibStream(stream, CompressionMode.Decompress);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
namespace MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies values that indicate whether a compression operation emphasizes speed or compression size.
|
||||||
|
/// </summary>
|
||||||
|
public enum SystemCompressionLevel
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// The compression operation should optimally balance compression speed and output size.
|
||||||
|
/// </summary>
|
||||||
|
Optimal = 0,
|
||||||
|
/// <summary>
|
||||||
|
/// The compression operation should complete as quickly as possible, even if the resulting
|
||||||
|
/// file is not optimally compressed.
|
||||||
|
/// </summary>
|
||||||
|
Fastest = 1,
|
||||||
|
/// <summary>
|
||||||
|
/// No compression should be performed on the file.
|
||||||
|
/// </summary>
|
||||||
|
NoCompression = 2,
|
||||||
|
/// <summary>
|
||||||
|
/// The compression operation should create output as small as possible, even if
|
||||||
|
/// the operation takes a longer time to complete.
|
||||||
|
/// </summary>
|
||||||
|
SmallestSize = 3
|
||||||
|
}
|
||||||
@ -0,0 +1,44 @@
|
|||||||
|
using System.IO.Compression;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
public abstract class SystemCompressionModule<TStream> : CompressionModule where TStream : Stream
|
||||||
|
{
|
||||||
|
public SystemCompressionLevel CompressionLevel { get; set; } = SystemCompressionLevel.Optimal;
|
||||||
|
|
||||||
|
|
||||||
|
protected abstract TStream CreateCompressor(Stream stream);
|
||||||
|
protected abstract TStream CreateDecompressor(Stream stream);
|
||||||
|
|
||||||
|
protected override void CompressInternal(Stream inputStream, Stream outputStream)
|
||||||
|
{
|
||||||
|
TStream _compressor = CreateCompressor(outputStream);
|
||||||
|
inputStream.CopyTo(_compressor);
|
||||||
|
|
||||||
|
// !!! IMPORTANT !!! DO NOT FORGET TO FLUSH !!!
|
||||||
|
_compressor.Flush();
|
||||||
|
_compressor.Close();
|
||||||
|
}
|
||||||
|
protected override void DecompressInternal(Stream inputStream, Stream outputStream)
|
||||||
|
{
|
||||||
|
TStream _decompressor = CreateDecompressor(inputStream);
|
||||||
|
_decompressor.CopyTo(outputStream);
|
||||||
|
|
||||||
|
// !!! IMPORTANT !!! DO NOT FORGET TO FLUSH !!!
|
||||||
|
_decompressor.Flush();
|
||||||
|
_decompressor.Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected CompressionLevel GetSystemCompressionLevel()
|
||||||
|
{
|
||||||
|
switch (CompressionLevel)
|
||||||
|
{
|
||||||
|
case SystemCompressionLevel.Fastest: return System.IO.Compression.CompressionLevel.Fastest;
|
||||||
|
case SystemCompressionLevel.NoCompression: return System.IO.Compression.CompressionLevel.NoCompression;
|
||||||
|
case SystemCompressionLevel.Optimal: return System.IO.Compression.CompressionLevel.Optimal;
|
||||||
|
case SystemCompressionLevel.SmallestSize: return System.IO.Compression.CompressionLevel.SmallestSize;
|
||||||
|
}
|
||||||
|
throw new ArgumentException("no System.IO.Compression.CompressionLevel matches the given SystemCompressionLevel");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,6 +1,89 @@
|
|||||||
|
//
|
||||||
|
// DataFormat.cs - translates ObjectModel to serialized data in a particular format
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2024 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
namespace MBS.Editor.Core;
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
public class DataFormat
|
public abstract class DataFormat
|
||||||
{
|
{
|
||||||
|
protected virtual void BeforeLoadInternal(Stack<ObjectModel> objectModels)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
protected virtual void AfterLoadInternal(Stack<ObjectModel> objectModels)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Load(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
Stack<ObjectModel> stack = new Stack<ObjectModel>();
|
||||||
|
stack.Push(objectModel);
|
||||||
|
BeforeLoadInternal(stack);
|
||||||
|
|
||||||
|
ObjectModel omb = stack.Pop();
|
||||||
|
|
||||||
|
LoadInternal(omb, stream);
|
||||||
|
|
||||||
|
stack.Push(omb);
|
||||||
|
AfterLoadInternal(stack);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected abstract void LoadInternal(ObjectModel objectModel, Stream stream);
|
||||||
|
|
||||||
|
protected virtual void BeforeSaveInternal(Stack<ObjectModel> objectModels)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
protected virtual void AfterSaveInternal(Stack<ObjectModel> objectModels)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Save(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
Stack<ObjectModel> stack = new Stack<ObjectModel>();
|
||||||
|
stack.Push(objectModel);
|
||||||
|
BeforeSaveInternal(stack);
|
||||||
|
|
||||||
|
ObjectModel omb = stack.Pop();
|
||||||
|
|
||||||
|
SaveInternal(omb, stream);
|
||||||
|
|
||||||
|
stack.Push(omb);
|
||||||
|
AfterSaveInternal(stack);
|
||||||
|
}
|
||||||
|
protected abstract void SaveInternal(ObjectModel objectModel, Stream stream);
|
||||||
|
|
||||||
|
public static T FromType<T>() where T : DataFormat, new()
|
||||||
|
{
|
||||||
|
T objectModel = new T();
|
||||||
|
return objectModel;
|
||||||
|
}
|
||||||
|
public static DataFormat FromType(Type type)
|
||||||
|
{
|
||||||
|
if (type.IsAbstract || !type.IsSubclassOf(typeof(DataFormat)))
|
||||||
|
{
|
||||||
|
throw new InvalidCastException("type must be a non-abstract subclass of DataFormat");
|
||||||
|
}
|
||||||
|
DataFormat? objectModel = type.Assembly.CreateInstance(type.FullName) as DataFormat;
|
||||||
|
if (objectModel == null)
|
||||||
|
{
|
||||||
|
throw new TypeLoadException("could not create DataFormat from type name");
|
||||||
|
}
|
||||||
|
return objectModel;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
10
editor-dotnet/src/lib/MBS.Editor.Core/DataFormatMetadata.cs
Normal file
10
editor-dotnet/src/lib/MBS.Editor.Core/DataFormatMetadata.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
using MBS.Core.Settings;
|
||||||
|
|
||||||
|
public class DataFormatMetadata
|
||||||
|
{
|
||||||
|
public SettingsProvider ExportSettings { get; }
|
||||||
|
public SettingsProvider ImportSettings { get; }
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,142 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using MBS.Core;
|
||||||
|
using MBS.Editor.Core.IO;
|
||||||
|
using MBS.Editor.Core.ObjectModels.Chunked;
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.DataFormats.FileSystem.Chunked;
|
||||||
|
|
||||||
|
public class ChunkedDataFormat : DataFormat
|
||||||
|
{
|
||||||
|
protected virtual int KeyLength { get; } = 4;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the endianness of multibyte values. For IFF and AIFF, set to
|
||||||
|
/// <see cref="Endianness.BigEndian" />. For RIFF, set to <see cref="Endianness.LittleEndian" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public Endianness Endianness { get; set; } = Endianness.LittleEndian;
|
||||||
|
|
||||||
|
protected virtual int ChunkAlignment { get; } = 0;
|
||||||
|
protected virtual bool IsGroupChunk(string name)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadChunk(Reader reader, IChunkContainer parent)
|
||||||
|
{
|
||||||
|
string chunkName = reader.ReadFixedLengthString(4);
|
||||||
|
int chunkLength = reader.ReadInt32();
|
||||||
|
|
||||||
|
if (IsGroupChunk(chunkName))
|
||||||
|
{
|
||||||
|
string typeName = reader.ReadFixedLengthString(4);
|
||||||
|
|
||||||
|
// is group chunk
|
||||||
|
GroupChunk folder = new GroupChunk(chunkName, typeName);
|
||||||
|
|
||||||
|
while (!reader.BaseStream.EndOfStream())
|
||||||
|
{
|
||||||
|
ReadChunk(reader, folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.Chunks.Add(folder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long offset = reader.BaseStream.Position;
|
||||||
|
|
||||||
|
DataChunk file = new DataChunk(chunkName);
|
||||||
|
file.Source = new EmbeddedFileSource(reader.BaseStream, offset, chunkLength);
|
||||||
|
parent.Chunks.Add(file);
|
||||||
|
|
||||||
|
// CMAP=color map, 768 bytes, 3x256 colors, rgb
|
||||||
|
|
||||||
|
reader.BaseStream.Seek(chunkLength, SeekOrigin.Current);
|
||||||
|
reader.Align(ChunkAlignment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
ChunkedObjectModel chunked = ObjectModel.CastOrThrow<ChunkedObjectModel>(objectModel);
|
||||||
|
|
||||||
|
Reader reader = new Reader(stream);
|
||||||
|
reader.Endianness = Endianness;
|
||||||
|
while (!reader.BaseStream.EndOfStream())
|
||||||
|
{
|
||||||
|
ReadChunk(reader, chunked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected override void SaveInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
ChunkedObjectModel chunked = ObjectModel.CastOrThrow<ChunkedObjectModel>(objectModel);
|
||||||
|
|
||||||
|
Writer writer = new Writer(stream);
|
||||||
|
writer.Endianness = Endianness;
|
||||||
|
foreach (Chunk chunk in chunked.Chunks)
|
||||||
|
{
|
||||||
|
WriteChunk(writer, chunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteChunk(Writer writer, Chunk chunk)
|
||||||
|
{
|
||||||
|
writer.WriteFixedLengthString(chunk.Name, KeyLength);
|
||||||
|
writer.WriteInt32(CalculateChunkSize(chunk));
|
||||||
|
|
||||||
|
if (chunk is GroupChunk g)
|
||||||
|
{
|
||||||
|
writer.WriteFixedLengthString(g.TypeName, KeyLength);
|
||||||
|
foreach (Chunk chunk2 in g.Chunks)
|
||||||
|
{
|
||||||
|
WriteChunk(writer, chunk2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (chunk is DataChunk d)
|
||||||
|
{
|
||||||
|
if (d.Source != null)
|
||||||
|
{
|
||||||
|
writer.WriteBytes(d.Source.GetData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private int CalculateChunkSize(Chunk chunk)
|
||||||
|
{
|
||||||
|
int sz = 0;
|
||||||
|
if (chunk is GroupChunk g)
|
||||||
|
{
|
||||||
|
sz += 4;
|
||||||
|
foreach (Chunk c in g.Chunks)
|
||||||
|
{
|
||||||
|
sz += CalculateChunkSize(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (chunk is DataChunk d)
|
||||||
|
{
|
||||||
|
sz = 0;
|
||||||
|
if (d.Source != null)
|
||||||
|
{
|
||||||
|
sz = (int)d.Source.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sz;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
using MBS.Core;
|
||||||
|
using MBS.Editor.Core.DataFormats.FileSystem.Chunked;
|
||||||
|
using MBS.Editor.Core.IO;
|
||||||
|
using MBS.Editor.Core.ObjectModels.Chunked;
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.DataFormats.FileSystem.IFF;
|
||||||
|
|
||||||
|
public class IFFDataFormat : ChunkedDataFormat
|
||||||
|
{
|
||||||
|
public List<string> GroupChunkNames { get; } = new List<string>();
|
||||||
|
public IFFDataFormat()
|
||||||
|
{
|
||||||
|
Endianness = Endianness.BigEndian;
|
||||||
|
GroupChunkNames.Add("FORM");
|
||||||
|
GroupChunkNames.Add("LIST");
|
||||||
|
GroupChunkNames.Add("CAT");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool IsGroupChunk(string name)
|
||||||
|
{
|
||||||
|
return GroupChunkNames.Contains(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override int ChunkAlignment => 2;
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.DataFormats.FileSystem.IFF;
|
||||||
|
|
||||||
|
public class RIFFDataFormat : IFFDataFormat
|
||||||
|
{
|
||||||
|
public RIFFDataFormat()
|
||||||
|
{
|
||||||
|
GroupChunkNames.Add("RIFF");
|
||||||
|
Endianness = IO.Endianness.LittleEndian;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,13 @@
|
|||||||
|
|
||||||
|
namespace MBS.Editor.Core.DataFormats.FileSystem.ZIP;
|
||||||
|
|
||||||
|
public class ZIPDataFormat : DataFormat
|
||||||
|
{
|
||||||
|
protected override void LoadInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
protected override void SaveInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,205 @@
|
|||||||
|
|
||||||
|
using System.Formats.Asn1;
|
||||||
|
using System.Runtime.InteropServices.Marshalling;
|
||||||
|
using System.Text;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
using MBS.Core.Settings;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class INIDataFormat : DataFormat
|
||||||
|
{
|
||||||
|
public char CommentPrefix { get; set; } = ';';
|
||||||
|
|
||||||
|
private static DataFormatMetadata? _dfr = null;
|
||||||
|
public static DataFormatMetadata Metadata
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_dfr == null)
|
||||||
|
{
|
||||||
|
_dfr = new DataFormatMetadata();
|
||||||
|
|
||||||
|
SettingsGroup sg = new SettingsGroup("General", new Setting[]
|
||||||
|
{
|
||||||
|
new TextSetting("CommentPrefix", "Comment Prefix", ";")
|
||||||
|
});
|
||||||
|
_dfr.ExportSettings.SettingsGroups.Add(sg);
|
||||||
|
}
|
||||||
|
return _dfr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
PropertyListObjectModel? plom = objectModel as PropertyListObjectModel;
|
||||||
|
if (plom == null)
|
||||||
|
throw new ObjectModelNotSupportedException(typeof(PropertyListObjectModel), objectModel?.GetType());
|
||||||
|
|
||||||
|
IPropertyListContainer currentGroup = plom;
|
||||||
|
INIDataFormatToken insideToken = INIDataFormatToken.None;
|
||||||
|
StringBuilder currentString = new StringBuilder();
|
||||||
|
bool escaped = false;
|
||||||
|
|
||||||
|
string currentPropertyName = "";
|
||||||
|
string currentGroupName = "";
|
||||||
|
|
||||||
|
StreamReader sr = new StreamReader(stream);
|
||||||
|
while (!sr.EndOfStream)
|
||||||
|
{
|
||||||
|
int val = sr.Read();
|
||||||
|
if (val == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
char c = (char)val;
|
||||||
|
if (insideToken == INIDataFormatToken.Group)
|
||||||
|
{
|
||||||
|
if (c == ']')
|
||||||
|
{
|
||||||
|
insideToken = INIDataFormatToken.None;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentGroupName += c;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == CommentPrefix)
|
||||||
|
{
|
||||||
|
if (insideToken == INIDataFormatToken.None)
|
||||||
|
{
|
||||||
|
insideToken = INIDataFormatToken.Comment;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '"')
|
||||||
|
{
|
||||||
|
if (insideToken == INIDataFormatToken.None)
|
||||||
|
{
|
||||||
|
insideToken = INIDataFormatToken.String;
|
||||||
|
}
|
||||||
|
else if (insideToken == INIDataFormatToken.String && !escaped)
|
||||||
|
{
|
||||||
|
insideToken = INIDataFormatToken.None;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '\\')
|
||||||
|
{
|
||||||
|
if (insideToken == INIDataFormatToken.None || insideToken == INIDataFormatToken.Comment)
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
else if (insideToken == INIDataFormatToken.String)
|
||||||
|
{
|
||||||
|
if (!escaped)
|
||||||
|
{
|
||||||
|
escaped = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '\n')
|
||||||
|
{
|
||||||
|
if (currentGroupName != "")
|
||||||
|
{
|
||||||
|
PropertyListGroup group = new PropertyListGroup(currentGroupName);
|
||||||
|
currentGroupName = "";
|
||||||
|
|
||||||
|
plom.Items.Add(group);
|
||||||
|
currentGroup = group;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PropertyListProperty property = new PropertyListProperty(currentPropertyName, currentString.ToString());
|
||||||
|
currentString.Clear();
|
||||||
|
|
||||||
|
currentGroup.Items.Add(property);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '=')
|
||||||
|
{
|
||||||
|
if (insideToken == INIDataFormatToken.None)
|
||||||
|
{
|
||||||
|
currentPropertyName = currentString.ToString();
|
||||||
|
currentString.Clear();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == '[')
|
||||||
|
{
|
||||||
|
if (insideToken == INIDataFormatToken.None)
|
||||||
|
{
|
||||||
|
insideToken = INIDataFormatToken.Group;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (c == ']')
|
||||||
|
{
|
||||||
|
if (insideToken != INIDataFormatToken.None)
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
currentString.Append(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteItem(StreamWriter sw, PropertyListItem item)
|
||||||
|
{
|
||||||
|
if (item is PropertyListProperty p)
|
||||||
|
{
|
||||||
|
sw.WriteLine(String.Format("{0}={1}", p.Name, p.Value));
|
||||||
|
}
|
||||||
|
else if (item is PropertyListGroup g)
|
||||||
|
{
|
||||||
|
sw.WriteLine(String.Format("[{0}]", g.Name));
|
||||||
|
foreach (PropertyListItem item2 in g.Items)
|
||||||
|
{
|
||||||
|
WriteItem(sw, item2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (item is PropertyListComment c)
|
||||||
|
{
|
||||||
|
string[] lines = c.Value.Split(System.Environment.NewLine);
|
||||||
|
foreach (string line in lines)
|
||||||
|
{
|
||||||
|
sw.WriteLine(String.Format("{0} {1}", CommentPrefix, line));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SaveInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
PropertyListObjectModel? plom = objectModel as PropertyListObjectModel;
|
||||||
|
if (plom == null)
|
||||||
|
throw new ObjectModelNotSupportedException(typeof(PropertyListObjectModel), objectModel?.GetType());
|
||||||
|
|
||||||
|
StreamWriter sw = new StreamWriter(stream);
|
||||||
|
foreach (PropertyListItem item in plom.Items)
|
||||||
|
{
|
||||||
|
WriteItem(sw, item);
|
||||||
|
}
|
||||||
|
sw.Flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public enum INIDataFormatToken
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Comment,
|
||||||
|
String,
|
||||||
|
Group
|
||||||
|
}
|
||||||
41
editor-dotnet/src/lib/MBS.Editor.Core/Document.cs
Normal file
41
editor-dotnet/src/lib/MBS.Editor.Core/Document.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class Document
|
||||||
|
{
|
||||||
|
public ObjectModel ObjectModel { get; set; }
|
||||||
|
public DataFormat DataFormat { get; set; }
|
||||||
|
|
||||||
|
public Stream InputStream { get; set; }
|
||||||
|
public Stream OutputStream { get; set; }
|
||||||
|
|
||||||
|
public Document(ObjectModel objectModel, DataFormat dataFormat, Stream stream) : this(objectModel, dataFormat, stream, stream) { }
|
||||||
|
public Document(ObjectModel objectModel, DataFormat dataFormat, Stream inputStream, Stream outputStream)
|
||||||
|
{
|
||||||
|
ObjectModel = objectModel;
|
||||||
|
DataFormat = dataFormat;
|
||||||
|
InputStream = inputStream;
|
||||||
|
OutputStream = outputStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Load()
|
||||||
|
{
|
||||||
|
DataFormat.Load(ObjectModel, InputStream);
|
||||||
|
}
|
||||||
|
public void Save()
|
||||||
|
{
|
||||||
|
DataFormat.Save(ObjectModel, OutputStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Document Load(ObjectModel objectModel, DataFormat dataFormat, Stream stream)
|
||||||
|
{
|
||||||
|
Document doc = new Document(objectModel, dataFormat, stream);
|
||||||
|
doc.Load();
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
public static Document Save(ObjectModel objectModel, DataFormat dataFormat, Stream stream)
|
||||||
|
{
|
||||||
|
Document doc = new Document(objectModel, dataFormat, stream);
|
||||||
|
doc.Save();
|
||||||
|
return doc;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
namespace MBS.Editor.Core.Hosting;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
public delegate void HostApplicationMessageModifyingEventHandler(object sender, HostApplicationMessageModifyingEventArgs e);
|
||||||
|
public class HostApplicationMessageModifyingEventArgs
|
||||||
|
: CancelEventArgs
|
||||||
|
{
|
||||||
|
public HostApplicationMessageModifyingEventArgs(HostApplicationMessage message)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HostApplicationMessage Message { get; }
|
||||||
|
}
|
||||||
|
public delegate void HostApplicationMessageModifiedEventHandler(object sender, HostApplicationMessageModifiedEventArgs e);
|
||||||
|
public class HostApplicationMessageModifiedEventArgs
|
||||||
|
: EventArgs
|
||||||
|
{
|
||||||
|
public HostApplicationMessageModifiedEventArgs(HostApplicationMessage message)
|
||||||
|
{
|
||||||
|
Message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
public HostApplicationMessage Message { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public class HostApplicationMessage
|
||||||
|
{
|
||||||
|
public class HostApplicationMessageCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<HostApplicationMessage>
|
||||||
|
{
|
||||||
|
public event HostApplicationMessageModifyingEventHandler? MessageAdding;
|
||||||
|
public event HostApplicationMessageModifyingEventHandler? MessageRemoving;
|
||||||
|
|
||||||
|
public event HostApplicationMessageModifiedEventHandler? MessageAdded;
|
||||||
|
public event HostApplicationMessageModifiedEventHandler? MessageRemoved;
|
||||||
|
|
||||||
|
public HostApplicationMessage Add(HostApplicationMessageSeverity severity, string description, string fileName = null, int? lineNumber = null, int? columnNumber = null, string projectName = null)
|
||||||
|
{
|
||||||
|
HostApplicationMessage message = new HostApplicationMessage();
|
||||||
|
message.Severity = severity;
|
||||||
|
message.Description = description;
|
||||||
|
message.FileName = fileName;
|
||||||
|
message.LineNumber = lineNumber;
|
||||||
|
message.ColumnNumber = columnNumber;
|
||||||
|
message.ProjectName = projectName;
|
||||||
|
Add(message);
|
||||||
|
return message;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnMessageAdding(HostApplicationMessageModifyingEventArgs e)
|
||||||
|
{
|
||||||
|
if (MessageAdding != null)
|
||||||
|
{
|
||||||
|
MessageAdding(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected virtual void OnMessageAdded(HostApplicationMessageModifiedEventArgs e)
|
||||||
|
{
|
||||||
|
if (MessageAdded != null)
|
||||||
|
{
|
||||||
|
MessageAdded(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void OnMessageRemoving(HostApplicationMessageModifyingEventArgs e)
|
||||||
|
{
|
||||||
|
if (MessageRemoving != null)
|
||||||
|
{
|
||||||
|
MessageRemoving(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
protected virtual void OnMessageRemoved(HostApplicationMessageModifiedEventArgs e)
|
||||||
|
{
|
||||||
|
if (MessageRemoved != null)
|
||||||
|
{
|
||||||
|
MessageRemoved(this, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler? MessagesCleared;
|
||||||
|
protected virtual void OnMessagesCleared(EventArgs e)
|
||||||
|
{
|
||||||
|
if (MessagesCleared != null) MessagesCleared(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void InsertItem(int index, HostApplicationMessage item)
|
||||||
|
{
|
||||||
|
HostApplicationMessage message = item;
|
||||||
|
HostApplicationMessageModifyingEventArgs e = new HostApplicationMessageModifyingEventArgs(message);
|
||||||
|
OnMessageAdding(e);
|
||||||
|
if (e.Cancel) return;
|
||||||
|
|
||||||
|
base.InsertItem(index, item);
|
||||||
|
|
||||||
|
OnMessageAdded(new HostApplicationMessageModifiedEventArgs(message));
|
||||||
|
}
|
||||||
|
protected override void RemoveItem(int index)
|
||||||
|
{
|
||||||
|
HostApplicationMessage message = this[index];
|
||||||
|
HostApplicationMessageModifyingEventArgs e = new HostApplicationMessageModifyingEventArgs(message);
|
||||||
|
OnMessageRemoving(e);
|
||||||
|
if (e.Cancel) return;
|
||||||
|
|
||||||
|
base.RemoveItem(index);
|
||||||
|
|
||||||
|
OnMessageRemoved(new HostApplicationMessageModifiedEventArgs(message));
|
||||||
|
}
|
||||||
|
protected override void ClearItems()
|
||||||
|
{
|
||||||
|
base.ClearItems();
|
||||||
|
OnMessagesCleared(EventArgs.Empty);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private HostApplicationMessageSeverity mvarSeverity = HostApplicationMessageSeverity.None;
|
||||||
|
public HostApplicationMessageSeverity Severity { get { return mvarSeverity; } set { mvarSeverity = value; } }
|
||||||
|
|
||||||
|
private string mvarDescription = String.Empty;
|
||||||
|
public string Description { get { return mvarDescription; } set { mvarDescription = value; } }
|
||||||
|
|
||||||
|
private string mvarFileName = null;
|
||||||
|
public string FileName { get { return mvarFileName; } set { mvarFileName = value; } }
|
||||||
|
|
||||||
|
private int? mvarLineNumber = null;
|
||||||
|
public int? LineNumber { get { return mvarLineNumber; } set { mvarLineNumber = value; } }
|
||||||
|
|
||||||
|
private int? mvarColumnNumber = null;
|
||||||
|
public int? ColumnNumber { get { return mvarColumnNumber; } set { mvarColumnNumber = value; } }
|
||||||
|
|
||||||
|
private string mvarProjectName = null;
|
||||||
|
public string ProjectName { get { return mvarProjectName; } set { mvarProjectName = value; } }
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace MBS.Editor.Core.Hosting;
|
||||||
|
|
||||||
|
public enum HostApplicationMessageSeverity
|
||||||
|
{
|
||||||
|
None = 0,
|
||||||
|
Notice = 1,
|
||||||
|
Warning = 2,
|
||||||
|
Error = 3
|
||||||
|
}
|
||||||
@ -0,0 +1,64 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.Hosting;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Handles the output window in Universal Editor. If the user is running a plugin which makes
|
||||||
|
/// use of these features in non-GUI mode, it will write to the console instead.
|
||||||
|
/// </summary>
|
||||||
|
public class HostApplicationOutputWindow
|
||||||
|
{
|
||||||
|
public event TextWrittenEventHandler? TextWritten;
|
||||||
|
protected virtual void OnTextWritten(TextWrittenEventArgs e)
|
||||||
|
{
|
||||||
|
if (TextWritten != null)
|
||||||
|
{
|
||||||
|
TextWritten(this, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Write(e.Text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public event EventHandler? TextCleared;
|
||||||
|
protected virtual void OnTextCleared(EventArgs e)
|
||||||
|
{
|
||||||
|
if (TextCleared != null)
|
||||||
|
{
|
||||||
|
TextCleared(this, e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clear()
|
||||||
|
{
|
||||||
|
OnTextCleared(EventArgs.Empty);
|
||||||
|
}
|
||||||
|
public void Write(string text)
|
||||||
|
{
|
||||||
|
OnTextWritten(new TextWrittenEventArgs(text));
|
||||||
|
}
|
||||||
|
public void WriteLine(string text)
|
||||||
|
{
|
||||||
|
Write(text + System.Environment.NewLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public delegate void TextWrittenEventHandler(object sender, TextWrittenEventArgs e);
|
||||||
|
public class TextWrittenEventArgs
|
||||||
|
{
|
||||||
|
private string mvarText = String.Empty;
|
||||||
|
public string Text { get { return mvarText; } }
|
||||||
|
|
||||||
|
public TextWrittenEventArgs(string text)
|
||||||
|
{
|
||||||
|
mvarText = text;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
namespace MBS.Editor.Core.Hosting;
|
||||||
|
|
||||||
|
public class HostServices
|
||||||
|
{
|
||||||
|
public HostApplicationMessage.HostApplicationMessageCollection Messages { get; } = new HostApplicationMessage.HostApplicationMessageCollection();
|
||||||
|
public HostApplicationOutputWindow OutputWindow { get; } = new HostApplicationOutputWindow();
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace MBS.Editor.Core.Hosting;
|
||||||
|
|
||||||
|
public interface IHostApplication
|
||||||
|
{
|
||||||
|
HostServices HostServices { get; }
|
||||||
|
}
|
||||||
7
editor-dotnet/src/lib/MBS.Editor.Core/IO/Endianness.cs
Normal file
7
editor-dotnet/src/lib/MBS.Editor.Core/IO/Endianness.cs
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
namespace MBS.Editor.Core.IO;
|
||||||
|
|
||||||
|
public enum Endianness
|
||||||
|
{
|
||||||
|
LittleEndian,
|
||||||
|
BigEndian
|
||||||
|
}
|
||||||
11
editor-dotnet/src/lib/MBS.Editor.Core/IO/NewLineSequence.cs
Normal file
11
editor-dotnet/src/lib/MBS.Editor.Core/IO/NewLineSequence.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
namespace MBS.Editor.Core.IO;
|
||||||
|
|
||||||
|
public enum NewLineSequence
|
||||||
|
{
|
||||||
|
Automatic,
|
||||||
|
SystemDefault,
|
||||||
|
CarriageReturn,
|
||||||
|
LineFeed,
|
||||||
|
CarriageReturnLineFeed,
|
||||||
|
LineFeedCarriageReturn
|
||||||
|
}
|
||||||
1823
editor-dotnet/src/lib/MBS.Editor.Core/IO/Reader.cs
Normal file
1823
editor-dotnet/src/lib/MBS.Editor.Core/IO/Reader.cs
Normal file
File diff suppressed because it is too large
Load Diff
90
editor-dotnet/src/lib/MBS.Editor.Core/IO/ReaderWriterBase.cs
Normal file
90
editor-dotnet/src/lib/MBS.Editor.Core/IO/ReaderWriterBase.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.IO;
|
||||||
|
|
||||||
|
public class ReaderWriterBase
|
||||||
|
{
|
||||||
|
private readonly Stream _st;
|
||||||
|
/// <summary>
|
||||||
|
/// Exposes access to the underlying stream of the <see cref="ReaderWriterBase" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The underlying stream associated with the <see cref="ReaderWriterBase" />.
|
||||||
|
/// </value>
|
||||||
|
public Stream BaseStream { get { return _st; } }
|
||||||
|
|
||||||
|
public Encoding DefaultEncoding { get; set; } = Encoding.UTF8;
|
||||||
|
|
||||||
|
public NewLineSequence NewLineSequence { get; set; } = NewLineSequence.SystemDefault;
|
||||||
|
public Endianness Endianness { get; set; } = Endianness.LittleEndian;
|
||||||
|
|
||||||
|
public bool SwapEndianness()
|
||||||
|
{
|
||||||
|
if (Endianness == Endianness.LittleEndian)
|
||||||
|
{
|
||||||
|
Endianness = Endianness.BigEndian;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else if (Endianness == Endianness.BigEndian)
|
||||||
|
{
|
||||||
|
Endianness = Endianness.LittleEndian;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected string GetNewLineSequence()
|
||||||
|
{
|
||||||
|
switch (NewLineSequence)
|
||||||
|
{
|
||||||
|
case NewLineSequence.SystemDefault: return System.Environment.NewLine;
|
||||||
|
case NewLineSequence.CarriageReturnLineFeed: return "\r\n";
|
||||||
|
case NewLineSequence.CarriageReturn: return "\r";
|
||||||
|
case NewLineSequence.LineFeed: return "\n";
|
||||||
|
}
|
||||||
|
return System.Environment.NewLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ReaderWriterBase(Stream st)
|
||||||
|
{
|
||||||
|
_st = st;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Aligns the <see cref="Writer" /> to the specified number of bytes. If the current
|
||||||
|
/// position of the <see cref="Writer" /> is not a multiple of the specified number of bytes,
|
||||||
|
/// the position will be increased by the amount of bytes necessary to bring it to the
|
||||||
|
/// aligned position.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="alignTo">The number of bytes on which to align the <see cref="Reader"/>.</param>
|
||||||
|
/// <param name="extraPadding">Any additional padding bytes that should be included after aligning to the specified boundary.</param>
|
||||||
|
public void Align(int alignTo, int extraPadding = 0)
|
||||||
|
{
|
||||||
|
if (alignTo == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
long paddingCount = ((alignTo - (_st.Position % alignTo)) % alignTo);
|
||||||
|
paddingCount += extraPadding;
|
||||||
|
|
||||||
|
if (paddingCount > 0)
|
||||||
|
{
|
||||||
|
if (_st.Position == _st.Length)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[paddingCount];
|
||||||
|
_st.Write(buffer, 0, buffer.Length);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_st.Position += paddingCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Closes the current stream and releases any resources (such as sockets and file handles) associated with the current stream.
|
||||||
|
/// </summary>
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
BaseStream.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
1023
editor-dotnet/src/lib/MBS.Editor.Core/IO/Writer.cs
Normal file
1023
editor-dotnet/src/lib/MBS.Editor.Core/IO/Writer.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,29 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class InvalidDataFormatException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InvalidDataFormatException" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public InvalidDataFormatException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InvalidDataFormatException" /> class
|
||||||
|
/// with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public InvalidDataFormatException(string? message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="InvalidDataFormatException" /> class
|
||||||
|
/// with a specified error message and a reference to the inner exception that is the
|
||||||
|
/// cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">
|
||||||
|
/// The exception that is the cause of the current exception, or a null reference
|
||||||
|
/// (Nothing in Visual Basic) if no inner exception is specified.
|
||||||
|
/// </param>
|
||||||
|
public InvalidDataFormatException(string? message, Exception? innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,9 +1,10 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net8.0</TargetFramework>
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
<ImplicitUsings>enable</ImplicitUsings>
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
<Nullable>enable</Nullable>
|
<Nullable>enable</Nullable>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@ -4,4 +4,42 @@ public class ObjectModel
|
|||||||
{
|
{
|
||||||
public PropertyCollection Properties { get; } = new PropertyCollection();
|
public PropertyCollection Properties { get; } = new PropertyCollection();
|
||||||
|
|
||||||
|
public virtual void Clear()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void CopyTo(ObjectModel dest)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T FromType<T>() where T : ObjectModel, new()
|
||||||
|
{
|
||||||
|
T objectModel = new T();
|
||||||
|
return objectModel;
|
||||||
|
}
|
||||||
|
public static ObjectModel FromType(Type type)
|
||||||
|
{
|
||||||
|
if (type.IsAbstract || !type.IsSubclassOf(typeof(ObjectModel)))
|
||||||
|
{
|
||||||
|
throw new InvalidCastException("type must be a non-abstract subclass of ObjectModel");
|
||||||
|
}
|
||||||
|
ObjectModel? objectModel = type.Assembly.CreateInstance(type.FullName) as ObjectModel;
|
||||||
|
if (objectModel == null)
|
||||||
|
{
|
||||||
|
throw new TypeLoadException("could not create ObjectModel from type name");
|
||||||
|
}
|
||||||
|
return objectModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static T CastOrThrow<T>(ObjectModel? objectModel) where T : ObjectModel
|
||||||
|
{
|
||||||
|
T om = objectModel as T;
|
||||||
|
if (om == null)
|
||||||
|
{
|
||||||
|
throw new ObjectModelNotSupportedException(typeof(T), objectModel?.GetType());
|
||||||
|
}
|
||||||
|
return om;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class ObjectModelMetadata
|
||||||
|
{
|
||||||
|
public string[] Path { get; set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
using MBS.Core;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class ObjectModelNotSupportedException : Exception
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ObjectModelNotSupportedException" /> class.
|
||||||
|
/// </summary>
|
||||||
|
public ObjectModelNotSupportedException() : base() { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ObjectModelNotSupportedException" /> class
|
||||||
|
/// with a specified error message.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The message that describes the error.</param>
|
||||||
|
public ObjectModelNotSupportedException(string? message) : base(message) { }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ObjectModelNotSupportedException" /> class
|
||||||
|
/// with a specified error message and a reference to the inner exception that is the
|
||||||
|
/// cause of this exception.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message">The error message that explains the reason for the exception.</param>
|
||||||
|
/// <param name="innerException">
|
||||||
|
/// The exception that is the cause of the current exception, or a null reference
|
||||||
|
/// (Nothing in Visual Basic) if no inner exception is specified.
|
||||||
|
/// </param>
|
||||||
|
public ObjectModelNotSupportedException(string? message, Exception? innerException) : base(message, innerException) { }
|
||||||
|
|
||||||
|
public Type? ExpectedObjectModelType { get; }
|
||||||
|
public Type? ActualObjectModelType { get; }
|
||||||
|
|
||||||
|
private static Dictionary<string, string> __c1(Type expected, Type actual)
|
||||||
|
{
|
||||||
|
Dictionary<string, string> dict = new Dictionary<string, string>();
|
||||||
|
dict["expected"] = expected.FullName;
|
||||||
|
dict["actual"] = actual.FullName;
|
||||||
|
return dict;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObjectModelNotSupportedException(Type expectedObjectModelType, Type? actualObjectModelType) : this("The object model is not supported (expected $(expected), got $(actual))", expectedObjectModelType, actualObjectModelType) { }
|
||||||
|
public ObjectModelNotSupportedException(string? message, Type expectedObjectModelType, Type? actualObjectModelType) : base(StringExtensions.Format(message, __c1(expectedObjectModelType, actualObjectModelType)))
|
||||||
|
{
|
||||||
|
ExpectedObjectModelType = expectedObjectModelType;
|
||||||
|
ActualObjectModelType = actualObjectModelType;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Chunked;
|
||||||
|
|
||||||
|
public abstract class Chunk
|
||||||
|
{
|
||||||
|
public class ChunkCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<Chunk>
|
||||||
|
{
|
||||||
|
|
||||||
|
public Chunk? this[string name]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (Chunk item in this)
|
||||||
|
{
|
||||||
|
if (item.Name == name)
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk? this[string name, string typeName]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (Chunk item in this)
|
||||||
|
{
|
||||||
|
if (item is GroupChunk g)
|
||||||
|
{
|
||||||
|
if (g.Name == name && g.TypeName == typeName)
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Chunk(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Chunked;
|
||||||
|
|
||||||
|
public class ChunkedObjectModel : ObjectModel, IChunkContainer
|
||||||
|
{
|
||||||
|
public Chunk.ChunkCollection Chunks { get; } = new Chunk.ChunkCollection();
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Chunked;
|
||||||
|
|
||||||
|
public class DataChunk : Chunk
|
||||||
|
{
|
||||||
|
public DataChunk(string name) : base(name)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
public FileSource? Source { get; set; } = null;
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Chunked;
|
||||||
|
|
||||||
|
public class GroupChunk : Chunk, IChunkContainer
|
||||||
|
{
|
||||||
|
public GroupChunk(string name, string typeName) : base(name)
|
||||||
|
{
|
||||||
|
TypeName = typeName;
|
||||||
|
}
|
||||||
|
public string TypeName { get; set; }
|
||||||
|
|
||||||
|
public Chunk.ChunkCollection Chunks { get; } = new Chunk.ChunkCollection();
|
||||||
|
}
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Chunked;
|
||||||
|
|
||||||
|
public interface IChunkContainer
|
||||||
|
{
|
||||||
|
Chunk.ChunkCollection Chunks { get; }
|
||||||
|
}
|
||||||
@ -0,0 +1,89 @@
|
|||||||
|
//
|
||||||
|
// DatabaseField.cs - represents a field (column) in a DatabaseObjectModel
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a field (column) in a <see cref="DatabaseObjectModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DatabaseField : ICloneable
|
||||||
|
{
|
||||||
|
|
||||||
|
public class DatabaseFieldCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<DatabaseField>
|
||||||
|
{
|
||||||
|
public DatabaseField Add(string Name, object Value = null, Type dataType = null)
|
||||||
|
{
|
||||||
|
DatabaseField df = new DatabaseField();
|
||||||
|
df.Name = Name;
|
||||||
|
df.Value = Value;
|
||||||
|
df.DataType = dataType;
|
||||||
|
|
||||||
|
base.Add(df);
|
||||||
|
return df;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatabaseField this[string Name]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
if (this[i].Name.Equals(Name)) return this[i];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatabaseField(string name = "", object value = null)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; set; } = String.Empty;
|
||||||
|
public object Value { get; set; } = null;
|
||||||
|
public Type DataType { get; set; } = null;
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
DatabaseField clone = new DatabaseField();
|
||||||
|
clone.Name = (Name.Clone() as string);
|
||||||
|
if (Value is ICloneable)
|
||||||
|
{
|
||||||
|
clone.Value = (Value as ICloneable).Clone();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clone.Value = Value;
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return String.Format("{0} = {1}", Name, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,92 @@
|
|||||||
|
//
|
||||||
|
// DatabaseObjectModel.cs - provides an ObjectModel for manipulating databases
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides an <see cref="ObjectModel" /> for manipulating databases.
|
||||||
|
/// </summary>
|
||||||
|
public class DatabaseObjectModel : ObjectModel
|
||||||
|
{
|
||||||
|
private static ObjectModelMetadata _omr = null;
|
||||||
|
public static ObjectModelMetadata Metadata
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_omr == null)
|
||||||
|
{
|
||||||
|
_omr = new ObjectModelMetadata();
|
||||||
|
_omr.Path = new string[] { "General", "Database" };
|
||||||
|
}
|
||||||
|
return _omr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; set; } = null;
|
||||||
|
public DatabaseTable.DatabaseTableCollection Tables { get; } = new DatabaseTable.DatabaseTableCollection();
|
||||||
|
|
||||||
|
public override void Clear()
|
||||||
|
{
|
||||||
|
Tables.Clear();
|
||||||
|
}
|
||||||
|
public override void CopyTo(ObjectModel where)
|
||||||
|
{
|
||||||
|
DatabaseObjectModel clone = (where as DatabaseObjectModel);
|
||||||
|
if (clone == null)
|
||||||
|
throw new ObjectModelNotSupportedException();
|
||||||
|
|
||||||
|
for (int i = 0; i < Tables.Count; i++)
|
||||||
|
{
|
||||||
|
clone.Tables.Add(Tables[i].Clone() as DatabaseTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
public static DatabaseObjectModel FromMarkup(MarkupTagElement tag)
|
||||||
|
{
|
||||||
|
DatabaseObjectModel db = new DatabaseObjectModel();
|
||||||
|
for (int i = 0; i < tag.Elements.Count; i++)
|
||||||
|
{
|
||||||
|
MarkupTagElement tag2 = (tag.Elements[i] as MarkupTagElement);
|
||||||
|
if (tag2 == null) continue;
|
||||||
|
if (tag2.FullName == "Tables")
|
||||||
|
{
|
||||||
|
foreach (MarkupElement elTable in tag2.Elements )
|
||||||
|
{
|
||||||
|
MarkupTagElement tagTable = (elTable as MarkupTagElement);
|
||||||
|
if (tagTable == null) continue;
|
||||||
|
if (tagTable.FullName != "Table") continue;
|
||||||
|
|
||||||
|
MarkupAttribute attName = tag2.Attributes["Name"];
|
||||||
|
if (attName == null) continue;
|
||||||
|
|
||||||
|
DatabaseTable dt = new DatabaseTable();
|
||||||
|
dt.Name = attName.Value;
|
||||||
|
db.Tables.Add(dt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return db;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,70 @@
|
|||||||
|
//
|
||||||
|
// DatabaseRecord.cs - represents a record (row) in a DatabaseObjectModel
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a record (row) in a <see cref="DatabaseObjectModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DatabaseRecord : ICloneable
|
||||||
|
{
|
||||||
|
|
||||||
|
public class DatabaseRecordCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<DatabaseRecord>
|
||||||
|
{
|
||||||
|
public DatabaseRecord Add(params DatabaseField[] parameters)
|
||||||
|
{
|
||||||
|
DatabaseRecord dr = new DatabaseRecord();
|
||||||
|
foreach (DatabaseField df in parameters)
|
||||||
|
{
|
||||||
|
dr.Fields.Add(df.Name, df.Value);
|
||||||
|
}
|
||||||
|
return dr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatabaseRecord(params DatabaseField[] fields)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < fields.Length; i++)
|
||||||
|
{
|
||||||
|
Fields.Add(fields[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DatabaseField.DatabaseFieldCollection mvarFields = new DatabaseField.DatabaseFieldCollection ();
|
||||||
|
public DatabaseField.DatabaseFieldCollection Fields
|
||||||
|
{
|
||||||
|
get { return mvarFields; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
DatabaseRecord clone = new DatabaseRecord();
|
||||||
|
for (int i = 0; i < Fields.Count; i++)
|
||||||
|
{
|
||||||
|
clone.Fields.Add(Fields[i].Clone() as DatabaseField);
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,95 @@
|
|||||||
|
//
|
||||||
|
// DatabaseTable.cs - represents a table in a DatabaseObjectModel
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.Database
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a table in a <see cref="DatabaseObjectModel" />.
|
||||||
|
/// </summary>
|
||||||
|
public class DatabaseTable : ICloneable
|
||||||
|
{
|
||||||
|
public class DatabaseTableCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<DatabaseTable>
|
||||||
|
{
|
||||||
|
public DatabaseTable this[string name]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_itemsByName.ContainsKey(name))
|
||||||
|
return _itemsByName[name];
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, DatabaseTable> _itemsByName = new Dictionary<string, DatabaseTable>();
|
||||||
|
protected override void ClearItems()
|
||||||
|
{
|
||||||
|
base.ClearItems();
|
||||||
|
_itemsByName.Clear();
|
||||||
|
}
|
||||||
|
protected override void InsertItem(int index, DatabaseTable item)
|
||||||
|
{
|
||||||
|
base.InsertItem(index, item);
|
||||||
|
_itemsByName[item.Name] = item;
|
||||||
|
}
|
||||||
|
protected override void RemoveItem(int index)
|
||||||
|
{
|
||||||
|
if (_itemsByName.ContainsKey(this[index].Name))
|
||||||
|
_itemsByName.Remove(this[index].Name);
|
||||||
|
base.RemoveItem(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the name of the <see cref="DatabaseTable" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The name of the <see cref="DatabaseTable" />.</value>
|
||||||
|
public string Name { get; set; } = String.Empty;
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a collection of <see cref="DatabaseField" /> instances representing the fields (columns) in the <see cref="DatabaseTable" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The fields (columns) in the <see cref="DatabaseTable" />.</value>
|
||||||
|
public DatabaseField.DatabaseFieldCollection Fields { get; } = new DatabaseField.DatabaseFieldCollection();
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a collection of <see cref="DatabaseRecord" /> instances representing the records (rows) in the <see cref="DatabaseTable" />.
|
||||||
|
/// </summary>
|
||||||
|
/// <value>The records (rows) in the <see cref="DatabaseTable" />.</value>
|
||||||
|
public DatabaseRecord.DatabaseRecordCollection Records { get; } = new DatabaseRecord.DatabaseRecordCollection();
|
||||||
|
|
||||||
|
public object Clone()
|
||||||
|
{
|
||||||
|
DatabaseTable clone = new DatabaseTable();
|
||||||
|
clone.Name = (Name.Clone() as string);
|
||||||
|
for (int i = 0; i < Fields.Count; i++)
|
||||||
|
{
|
||||||
|
clone.Fields.Add(Fields[i].Clone() as DatabaseField);
|
||||||
|
}
|
||||||
|
for (int i = 0; i < Records.Count; i++)
|
||||||
|
{
|
||||||
|
clone.Records.Add(Records[i].Clone() as DatabaseRecord);
|
||||||
|
}
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public abstract class FileSource
|
||||||
|
{
|
||||||
|
public long Length { get { return GetLengthInternal(); } }
|
||||||
|
|
||||||
|
protected abstract long GetLengthInternal();
|
||||||
|
protected abstract byte[] GetDataInternal(long offset, long length);
|
||||||
|
|
||||||
|
public byte[] GetData() { return GetData(0, GetLengthInternal()); }
|
||||||
|
public byte[] GetData(long offset, long length)
|
||||||
|
{
|
||||||
|
byte[] data = GetDataInternal(offset, length);
|
||||||
|
MemoryStream msInput = new MemoryStream(data);
|
||||||
|
/*
|
||||||
|
for (int i = 0; i < Transformations.Count; i++)
|
||||||
|
{
|
||||||
|
System.IO.MemoryStream msOutput = new System.IO.MemoryStream();
|
||||||
|
Transformations[i].Function(this, msInput, msOutput);
|
||||||
|
msInput = msOutput;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
return msInput.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Stream GetStream()
|
||||||
|
{
|
||||||
|
byte[] data = GetData();
|
||||||
|
MemoryStream msInput = new MemoryStream(data);
|
||||||
|
return msInput;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,55 @@
|
|||||||
|
//
|
||||||
|
// MemoryFileSource.cs - provides a FileSource for retrieving file data from a byte array
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Data;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a <see cref="FileSource" /> for retrieving file data from a <see cref="MemoryAccessor" />.
|
||||||
|
/// </summary>
|
||||||
|
public class ByteArrayFileSource : FileSource
|
||||||
|
{
|
||||||
|
public byte[] Data { get; set; }
|
||||||
|
|
||||||
|
public ByteArrayFileSource(byte[] data)
|
||||||
|
{
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override byte[] GetDataInternal(long offset, long length)
|
||||||
|
{
|
||||||
|
long realLength = Math.Min(length, Data.Length);
|
||||||
|
byte[] realData = Data;
|
||||||
|
long remaining = realData.Length - offset;
|
||||||
|
realLength = Math.Min(realLength, remaining);
|
||||||
|
|
||||||
|
byte[] data = new byte[realLength];
|
||||||
|
Array.Copy(realData, offset, data, 0, realLength);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override long GetLengthInternal()
|
||||||
|
{
|
||||||
|
return Data.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,54 @@
|
|||||||
|
using MBS.Core.Collections;
|
||||||
|
using MBS.Editor.Core.Compression;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
public class CompressedEmbeddedFileSource : EmbeddedFileSource
|
||||||
|
{
|
||||||
|
public CompressionModule? CompressionModule { get; set; } = null;
|
||||||
|
|
||||||
|
public long CompressedLength { get; set; }
|
||||||
|
private long DecompressedLength { get; set; }
|
||||||
|
protected override long ActualLength => DecompressedLength;
|
||||||
|
|
||||||
|
private byte[]? _decompressedData = null;
|
||||||
|
|
||||||
|
protected override byte[] GetDataInternal(long offset, long length)
|
||||||
|
{
|
||||||
|
if (_decompressedData == null)
|
||||||
|
{
|
||||||
|
Stream.Seek(Offset + offset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
byte[] compressedData = new byte[CompressedLength];
|
||||||
|
Stream.Read(compressedData, 0, compressedData.Length);
|
||||||
|
Console.WriteLine("compressed data: " + compressedData.ToString(" ", "x"));
|
||||||
|
|
||||||
|
byte[] decompressedData = compressedData;
|
||||||
|
if (CompressionModule != null)
|
||||||
|
{
|
||||||
|
decompressedData = CompressionModule.Decompress(compressedData);
|
||||||
|
}
|
||||||
|
_decompressedData = decompressedData;
|
||||||
|
Console.WriteLine("decompressed data: " + decompressedData.ToString(" ", "x"));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + length > _decompressedData.Length)
|
||||||
|
{
|
||||||
|
Console.WriteLine(String.Format("embedded file offset: {0}", Offset));
|
||||||
|
Console.WriteLine(String.Format("requested offset: {0}", offset));
|
||||||
|
Console.WriteLine(String.Format("requested length: {0}", length));
|
||||||
|
Console.WriteLine(String.Format("actual stream length: {0}", _decompressedData.Length));
|
||||||
|
throw new ArgumentOutOfRangeException("offset + length", "embedded file offset + requested offset + requested length extends past the actual length of the underlying stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
Array.Copy(_decompressedData, offset, data, 0, data.Length);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CompressedEmbeddedFileSource(Stream stream, long offset, long compressedLength, long decompressedLength) : base(stream, offset, decompressedLength)
|
||||||
|
{
|
||||||
|
CompressedLength = compressedLength;
|
||||||
|
DecompressedLength = decompressedLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,34 @@
|
|||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
public class EmbeddedFileSource : FileSource
|
||||||
|
{
|
||||||
|
public Stream Stream { get; }
|
||||||
|
public long Offset { get; set; }
|
||||||
|
|
||||||
|
protected virtual long ActualLength { get; }
|
||||||
|
|
||||||
|
protected override long GetLengthInternal()
|
||||||
|
{
|
||||||
|
return ActualLength;
|
||||||
|
}
|
||||||
|
protected override byte[] GetDataInternal(long offset, long length)
|
||||||
|
{
|
||||||
|
if (Offset + offset + length > Stream.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("embedded file offset + requested offset + requested length extends past the actual length of the underlying stream");
|
||||||
|
}
|
||||||
|
|
||||||
|
Stream.Seek(Offset + offset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
byte[] data = new byte[length];
|
||||||
|
Stream.Read(data, 0, data.Length);
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EmbeddedFileSource(Stream stream, long offset, long length)
|
||||||
|
{
|
||||||
|
Stream = stream;
|
||||||
|
Offset = offset;
|
||||||
|
ActualLength = length;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,59 @@
|
|||||||
|
//
|
||||||
|
// StreamFileSource.cs - provides a FileSource for retrieving file data from a System.IO.Stream
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2011-2024 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides a <see cref="FileSource" /> for retrieving file data from a <see cref="MemoryAccessor" />.
|
||||||
|
/// </summary>
|
||||||
|
public class StreamFileSource : FileSource
|
||||||
|
{
|
||||||
|
public Stream BaseStream { get; set; }
|
||||||
|
public StreamFileSource(Stream stream)
|
||||||
|
{
|
||||||
|
BaseStream = stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override byte[] GetDataInternal(long offset, long length)
|
||||||
|
{
|
||||||
|
byte[] buffer = new byte[length];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (offset + length > BaseStream.Length)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException("offset + length is out of range");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (NotSupportedException ex)
|
||||||
|
{
|
||||||
|
// continue anyway
|
||||||
|
}
|
||||||
|
|
||||||
|
BaseStream.Seek(offset, SeekOrigin.Begin);
|
||||||
|
BaseStream.Read(buffer, 0, (int)length);
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override long GetLengthInternal()
|
||||||
|
{
|
||||||
|
return BaseStream.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,29 @@
|
|||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public class FileSystemCustomDetailCollection
|
||||||
|
{
|
||||||
|
private struct _item
|
||||||
|
{
|
||||||
|
public string id;
|
||||||
|
public string title;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Dictionary<string, _item> _dict = new Dictionary<string, _item>();
|
||||||
|
|
||||||
|
public void Add(string id, string title)
|
||||||
|
{
|
||||||
|
_item item = new _item();
|
||||||
|
item.id = id;
|
||||||
|
item.title = title;
|
||||||
|
_dict[id] = item;
|
||||||
|
}
|
||||||
|
public bool Contains(string id)
|
||||||
|
{
|
||||||
|
return _dict.ContainsKey(id);
|
||||||
|
}
|
||||||
|
public string GetTitle(string id)
|
||||||
|
{
|
||||||
|
_item item = _dict[id];
|
||||||
|
return item.title;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public class FileSystemFile : FileSystemItem
|
||||||
|
{
|
||||||
|
public FileSource? Source { get; set; } = null;
|
||||||
|
|
||||||
|
public DateTime? ModificationTimestamp { get; set; } = null;
|
||||||
|
|
||||||
|
public Dictionary<string, object> CustomDetails { get; } = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
public long Size
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Source == null)
|
||||||
|
return 0;
|
||||||
|
return Source.Length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public class FileSystemFolder : FileSystemItem, IFileSystemItemContainer
|
||||||
|
{
|
||||||
|
|
||||||
|
public FileSystemItemCollection Items { get; }
|
||||||
|
|
||||||
|
public FileSystemFolder()
|
||||||
|
{
|
||||||
|
Items = new FileSystemItemCollection(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,8 @@
|
|||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public class FileSystemItem
|
||||||
|
{
|
||||||
|
public FileSystemObjectModel FileSystem { get { return Parent?.FileSystem; } }
|
||||||
|
public string? Name { get; set; } = null;
|
||||||
|
public IFileSystemItemContainer? Parent { get; internal set; }
|
||||||
|
}
|
||||||
@ -0,0 +1,191 @@
|
|||||||
|
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public class FileSystemItemCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<FileSystemItem>
|
||||||
|
{
|
||||||
|
public IFileSystemItemContainer Parent { get; }
|
||||||
|
public FileSystemItemCollection(IFileSystemItemContainer parent)
|
||||||
|
{
|
||||||
|
Parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Contains(string filename)
|
||||||
|
{
|
||||||
|
return this[filename] != null;
|
||||||
|
}
|
||||||
|
public FileSystemItem? this[string filename]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
foreach (FileSystemItem item in this)
|
||||||
|
{
|
||||||
|
if (item.Name == filename)
|
||||||
|
{
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ClearItems()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
this[i].Parent = null;
|
||||||
|
}
|
||||||
|
base.ClearItems();
|
||||||
|
}
|
||||||
|
protected override void InsertItem(int index, FileSystemItem item)
|
||||||
|
{
|
||||||
|
base.InsertItem(index, item);
|
||||||
|
item.Parent = Parent;
|
||||||
|
}
|
||||||
|
protected override void RemoveItem(int index)
|
||||||
|
{
|
||||||
|
this[index].Parent = null;
|
||||||
|
base.RemoveItem(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public FileSystemFolder AddFolder(string name)
|
||||||
|
{
|
||||||
|
string[] path = name.Split(Parent.FileSystem.PathSeparators, StringSplitOptions.None);
|
||||||
|
FileSystemFolder parent = null;
|
||||||
|
for (int i = 0; i < path.Length; i++)
|
||||||
|
{
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
parent = this[path[i]] as FileSystemFolder;
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
FileSystemFolder f = new FileSystemFolder();
|
||||||
|
f.Name = path[i];
|
||||||
|
Add(f);
|
||||||
|
parent = f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FileSystemFolder new_parent = parent.Items[path[i]] as FileSystemFolder;
|
||||||
|
if (new_parent == null)
|
||||||
|
{
|
||||||
|
new_parent = new FileSystemFolder();
|
||||||
|
new_parent.Name = path[i];
|
||||||
|
parent.Items.Add(new_parent);
|
||||||
|
}
|
||||||
|
parent = new_parent;
|
||||||
|
}
|
||||||
|
if (parent == null) throw new DirectoryNotFoundException();
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
public FileSystemFile AddFile(string name, FileSource? source = null)
|
||||||
|
{
|
||||||
|
if (name == null) name = String.Empty;
|
||||||
|
string[] path = name.Split(Parent.FileSystem.PathSeparators, StringSplitOptions.None);
|
||||||
|
FileSystemFolder parent = null;
|
||||||
|
for (int i = 0; i < path.Length - 1; i++)
|
||||||
|
{
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
if (Contains(path[i]))
|
||||||
|
{
|
||||||
|
parent = this[path[i]] as FileSystemFolder;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent = AddFolder(path[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (parent.Items.Contains(path[i]))
|
||||||
|
{
|
||||||
|
parent = parent.Items[path[i]] as FileSystemFolder;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent = parent.Items.AddFolder(path[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
throw new System.IO.DirectoryNotFoundException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FileSystemFile file = new FileSystemFile();
|
||||||
|
file.Name = path[path.Length - 1];
|
||||||
|
file.Source = source;
|
||||||
|
if (parent == null)
|
||||||
|
{
|
||||||
|
Add(file);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
parent.Items.Add(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public FileSystemFile[] GetAllFiles()
|
||||||
|
{
|
||||||
|
List<FileSystemFile> list = new List<FileSystemFile>();
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
if (this[i] is FileSystemFile Peter)
|
||||||
|
{
|
||||||
|
list.Add(Peter);
|
||||||
|
}
|
||||||
|
else if (this[i] is FileSystemFolder folder)
|
||||||
|
{
|
||||||
|
FileSystemFile[] files2 = folder.Items.GetAllFiles();
|
||||||
|
list.AddRange(files2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileSystemFile[] GetFiles()
|
||||||
|
{
|
||||||
|
List<FileSystemFile> list = new List<FileSystemFile>();
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
if (this[i] is FileSystemFile Peter)
|
||||||
|
{
|
||||||
|
list.Add(Peter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileSystemFolder[] GetFolders()
|
||||||
|
{
|
||||||
|
List<FileSystemFolder> list = new List<FileSystemFolder>();
|
||||||
|
for (int i = 0; i < Count; i++)
|
||||||
|
{
|
||||||
|
if (this[i] is FileSystemFolder folder)
|
||||||
|
{
|
||||||
|
list.Add(folder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetChild<T>(string v) where T : FileSystemItem
|
||||||
|
{
|
||||||
|
FileSystemItem? item = this[v];
|
||||||
|
if (item is T)
|
||||||
|
{
|
||||||
|
return (T)item;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
|
||||||
|
|
||||||
|
using MBS.Editor.Core.ObjectModels.FileSystem.FileSources;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public class FileSystemObjectModel : ObjectModel, IFileSystemItemContainer
|
||||||
|
{
|
||||||
|
public FileSystemObjectModel FileSystem { get { return this; } }
|
||||||
|
public FileSystemItemCollection Items { get; }
|
||||||
|
public FileSystemObjectModel()
|
||||||
|
{
|
||||||
|
Items = new FileSystemItemCollection(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public FileSystemCustomDetailCollection CustomDetails { get; } = new FileSystemCustomDetailCollection();
|
||||||
|
|
||||||
|
public string[] PathSeparators { get; set; } = { "/", "\\" }; // System.IO.Path.DirectorySeparatorChar.ToString(), System.IO.Path.AltDirectorySeparatorChar.ToString() };
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,7 @@
|
|||||||
|
namespace MBS.Editor.Core.ObjectModels.FileSystem;
|
||||||
|
|
||||||
|
public interface IFileSystemItemContainer
|
||||||
|
{
|
||||||
|
FileSystemObjectModel FileSystem { get; }
|
||||||
|
FileSystemItemCollection Items { get; }
|
||||||
|
}
|
||||||
@ -0,0 +1,9 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public interface IPropertyListContainer
|
||||||
|
{
|
||||||
|
|
||||||
|
PropertyListItem.PropertyListItemCollection Items { get; }
|
||||||
|
IPropertyListContainer? Parent { get; }
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class PropertyListComment : PropertyListItem
|
||||||
|
{
|
||||||
|
public string Value { get; set; } = "";
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class PropertyListGroup : PropertyListItem, IPropertyListContainer
|
||||||
|
{
|
||||||
|
|
||||||
|
public PropertyListItem.PropertyListItemCollection Items { get; }
|
||||||
|
|
||||||
|
public PropertyListGroup(string name)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Items = new PropertyListItemCollection(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public abstract class PropertyListItem
|
||||||
|
{
|
||||||
|
|
||||||
|
public class PropertyListItemCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<PropertyListItem>
|
||||||
|
{
|
||||||
|
private IPropertyListContainer _Parent = null;
|
||||||
|
|
||||||
|
public PropertyListItemCollection(IPropertyListContainer parent)
|
||||||
|
{
|
||||||
|
_Parent = parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void ClearItems()
|
||||||
|
{
|
||||||
|
foreach (PropertyListItem item in this)
|
||||||
|
{
|
||||||
|
item.Parent = null;
|
||||||
|
}
|
||||||
|
base.ClearItems();
|
||||||
|
}
|
||||||
|
protected override void InsertItem(int index, PropertyListItem item)
|
||||||
|
{
|
||||||
|
base.InsertItem(index, item);
|
||||||
|
item.Parent = _Parent;
|
||||||
|
}
|
||||||
|
protected override void RemoveItem(int index)
|
||||||
|
{
|
||||||
|
this[index].Parent = null;
|
||||||
|
base.RemoveItem(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name { get; set; } = "";
|
||||||
|
public IPropertyListContainer? Parent { get; internal set; }
|
||||||
|
|
||||||
|
public PropertyListObjectModel? ParentObjectModel
|
||||||
|
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
IPropertyListContainer? parent = Parent;
|
||||||
|
while (parent != null)
|
||||||
|
{
|
||||||
|
if (parent is PropertyListObjectModel)
|
||||||
|
{
|
||||||
|
return (parent as PropertyListObjectModel);
|
||||||
|
}
|
||||||
|
parent = parent.Parent;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,18 @@
|
|||||||
|
using MBS.Editor.Core.ObjectModels.PropertyList.Schema;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class PropertyListObjectModel : ObjectModel, IPropertyListContainer
|
||||||
|
{
|
||||||
|
|
||||||
|
public PropertyListItem.PropertyListItemCollection Items { get; }
|
||||||
|
public PropertyListSchema? Schema { get; set; } = null;
|
||||||
|
|
||||||
|
public IPropertyListContainer? Parent => null;
|
||||||
|
|
||||||
|
public PropertyListObjectModel()
|
||||||
|
{
|
||||||
|
Items = new PropertyListItem.PropertyListItemCollection(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
using MBS.Editor.Core.ObjectModels.PropertyList.Schema;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core;
|
||||||
|
|
||||||
|
public class PropertyListProperty : PropertyListItem
|
||||||
|
{
|
||||||
|
|
||||||
|
private object? _Value = null;
|
||||||
|
public object? Value
|
||||||
|
{
|
||||||
|
get { return _Value; }
|
||||||
|
set { _Value = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public T? GetValueAs<T>()
|
||||||
|
{
|
||||||
|
PropertyListObjectModel? plom = ParentObjectModel;
|
||||||
|
if (plom != null)
|
||||||
|
{
|
||||||
|
PropertyListSchema? schema = plom.Schema;
|
||||||
|
if (schema != null)
|
||||||
|
{
|
||||||
|
foreach (PropertyDefinition def in schema.PropertyDefinitions)
|
||||||
|
{
|
||||||
|
if (def.PropertyName == Name)
|
||||||
|
{
|
||||||
|
//return def.ConvertTo<T>(def.DataType, Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return default(T);
|
||||||
|
}
|
||||||
|
|
||||||
|
public PropertyListProperty(string name, object value)
|
||||||
|
{
|
||||||
|
Name = name;
|
||||||
|
Value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
namespace MBS.Editor.Core.ObjectModels.PropertyList.Schema;
|
||||||
|
|
||||||
|
public class PropertyValueConverter
|
||||||
|
{
|
||||||
|
public class PropertyValueConverterCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<PropertyValueConverter>
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public class PropertyValueConverter<TInput, TOutput> : PropertyValueConverter
|
||||||
|
{
|
||||||
|
private Func<TInput, TOutput> __convertTo = null;
|
||||||
|
private Func<TOutput, TInput> __convertFrom = null;
|
||||||
|
public PropertyValueConverter(Func<TInput, TOutput> convertTo, Func<TOutput, TInput> convertFrom)
|
||||||
|
{
|
||||||
|
__convertTo = convertTo;
|
||||||
|
__convertFrom = convertFrom;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TOutput? ConvertTo(TInput value)
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
using System.Diagnostics.Contracts;
|
||||||
|
using System.Text.Json.Serialization;
|
||||||
|
using MBS.Core.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.PropertyList.Schema;
|
||||||
|
|
||||||
|
public class PropertyDefinition
|
||||||
|
{
|
||||||
|
public class PropertyDefinitionCollection
|
||||||
|
: System.Collections.ObjectModel.Collection<PropertyDefinition>
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public string PropertyName { get; }
|
||||||
|
public Type DataType { get; }
|
||||||
|
public PropertyValueConverter.PropertyValueConverterCollection Converters { get; } = new PropertyValueConverter.PropertyValueConverterCollection();
|
||||||
|
|
||||||
|
public PropertyDefinition(string propertyName, string displayTitle, Type dataType, PropertyValueConverter[]? valueConverters = null)
|
||||||
|
{
|
||||||
|
PropertyName = propertyName;
|
||||||
|
DataType = dataType;
|
||||||
|
if (valueConverters != null)
|
||||||
|
{
|
||||||
|
Converters.AddRange(valueConverters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public TTo ConvertTo<TFrom, TTo>(TFrom value)
|
||||||
|
{
|
||||||
|
foreach (PropertyValueConverter converter in Converters)
|
||||||
|
{
|
||||||
|
if (converter is PropertyValueConverter<TFrom, TTo> cvt)
|
||||||
|
{
|
||||||
|
return cvt.ConvertTo(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotSupportedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
using MBS.Core.Collections.Generic;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Core.ObjectModels.PropertyList.Schema;
|
||||||
|
|
||||||
|
public class PropertyListSchema
|
||||||
|
{
|
||||||
|
public PropertyDefinition.PropertyDefinitionCollection PropertyDefinitions { get; } = new PropertyDefinition.PropertyDefinitionCollection();
|
||||||
|
|
||||||
|
public PropertyListSchema(PropertyDefinition[] propertyDefinitions)
|
||||||
|
{
|
||||||
|
PropertyDefinitions.AddRange(propertyDefinitions);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,65 @@
|
|||||||
|
using NUnit.Framework;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Testing;
|
||||||
|
|
||||||
|
public class EmbeddedResourceTest
|
||||||
|
{
|
||||||
|
private System.Collections.Generic.Dictionary<string, System.IO.Stream> testDataStreams = new System.Collections.Generic.Dictionary<string, System.IO.Stream>();
|
||||||
|
|
||||||
|
[SetUp]
|
||||||
|
public void SetUp()
|
||||||
|
{
|
||||||
|
InitializeResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void InitializeResources()
|
||||||
|
{
|
||||||
|
MBS.Core.Reflection.ManifestResourceStream[] strms = MBS.Core.Reflection.ManifestResourceStream.GetManifestResourceStreamsForAssembly(this.GetType().Assembly);
|
||||||
|
for (int i = 0; i < strms.Length; i++)
|
||||||
|
{
|
||||||
|
testDataStreams[strms[i].Name] = strms[i].Stream;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Stream? CreateResourceStream(string name)
|
||||||
|
{
|
||||||
|
if (TryCreateResourceStream(name, out Stream? st))
|
||||||
|
{
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected bool TryCreateResourceStream(string name, out System.IO.Stream? st)
|
||||||
|
{
|
||||||
|
st = null;
|
||||||
|
if (testDataStreams.ContainsKey(name))
|
||||||
|
{
|
||||||
|
System.IO.Stream TEST_STREAM = testDataStreams[name];
|
||||||
|
st = TEST_STREAM;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine("test data stream not found: '{0}'", name);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SampleStreamTest(string streamName)
|
||||||
|
{
|
||||||
|
if (TryCreateResourceStream(streamName, out System.IO.Stream? st))
|
||||||
|
{
|
||||||
|
SampleStreamTest(st);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Assert.Ignore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void SampleStreamTest(Stream st)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,19 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
|
||||||
|
<ProjectReference Include="..\MBS.Editor.Core\MBS.Editor.Core.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
<IsPackable>false</IsPackable>
|
||||||
|
<IsTestProject>false</IsTestProject>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@ -1,14 +1,38 @@
|
|||||||
namespace MBS.Editor.UserInterface;
|
namespace MBS.Editor.UserInterface;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using MBS.Core;
|
||||||
using MBS.Desktop;
|
using MBS.Desktop;
|
||||||
|
using MBS.Desktop.Controls;
|
||||||
|
|
||||||
public class EditorApplication : DesktopApplication
|
public class EditorApplication : DesktopApplication
|
||||||
{
|
{
|
||||||
|
protected override void OnStartup(EventArgs e)
|
||||||
|
{
|
||||||
|
base.OnStartup(e);
|
||||||
|
|
||||||
protected override int StartInternal()
|
Console.WriteLine("editor: OnStartup");
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
this.Commands.Add(new Command("FileExit", "E_xit"));
|
||||||
|
this.Commands.Add(new Command("File", "_File", new CommandItem[]
|
||||||
|
{
|
||||||
|
new CommandReferenceCommandItem("FileExit")
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.AttachCommandEventHandler("FileExit", delegate (object sender, CommandEventArgs e)
|
||||||
|
{
|
||||||
|
this.Stop();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnActivated(ApplicationActivatedEventArgs e)
|
||||||
|
{
|
||||||
|
base.OnActivated(e);
|
||||||
|
|
||||||
|
Console.WriteLine("editor: OnActivated");
|
||||||
|
|
||||||
|
EditorWindow window = new EditorWindow();
|
||||||
|
window.Show();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,20 @@
|
|||||||
|
namespace MBS.Editor.UserInterface;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using MBS.Core;
|
||||||
|
using MBS.Desktop;
|
||||||
|
using MBS.Desktop.Controls;
|
||||||
|
|
||||||
|
// [ContainerLayout(typeof(EditorWindow), "MBS.Editor.UserInterface.EditorWindow.glade")]
|
||||||
|
public class EditorWindow : MainWindow
|
||||||
|
{
|
||||||
|
|
||||||
|
public EditorWindow()
|
||||||
|
{
|
||||||
|
Title = "MBS Editor";
|
||||||
|
DefaultSize = new Core.Drawing.Dimension2D(1000, 700);
|
||||||
|
|
||||||
|
Controls.Add(new Label("<b>Strong Bad!</b>") { UseMarkup = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
|
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Core\MBS.Core.csproj" />
|
||||||
<ProjectReference Include="..\..\..\..\framework-dotnet\framework-dotnet\src\lib\MBS.Desktop\MBS.Desktop.csproj" />
|
<ProjectReference Include="..\..\..\..\desktop-framework-dotnet\desktop-framework-dotnet\src\lib\MBS.Desktop\MBS.Desktop.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
31
editor-dotnet/src/lib/MBS.Editor.Web/Controls/PageHeader.cs
Normal file
31
editor-dotnet/src/lib/MBS.Editor.Web/Controls/PageHeader.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
using MBS.Web.UI;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Web.Controls;
|
||||||
|
|
||||||
|
public class PageHeader : WebControl
|
||||||
|
{
|
||||||
|
protected override string TagName => "div";
|
||||||
|
protected override IEnumerable<string> GetStyleClasses()
|
||||||
|
{
|
||||||
|
return new string[] { "uwt-page-header" };
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
14
editor-dotnet/src/lib/MBS.Editor.Web/MBS.Editor.Web.csproj
Normal file
14
editor-dotnet/src/lib/MBS.Editor.Web/MBS.Editor.Web.csproj
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>net8.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="../../../../framework-dotnet/framework-dotnet/src/lib/MBS.Core/MBS.Core.csproj" />
|
||||||
|
<ProjectReference Include="../../../../web-framework-dotnet/src/lib/MBS.Web/MBS.Web.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
123
editor-dotnet/src/lib/MBS.Editor.Web/Pages/MainPage.cs
Normal file
123
editor-dotnet/src/lib/MBS.Editor.Web/Pages/MainPage.cs
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
// Copyright (C) 2024 Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// This file is part of editor-dotnet.
|
||||||
|
//
|
||||||
|
// editor-dotnet is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// editor-dotnet is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with editor-dotnet. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
using MBS.Web;
|
||||||
|
using MBS.Web.UI;
|
||||||
|
|
||||||
|
using MBS.Editor.Web.Controls;
|
||||||
|
using MBS.Web.UI.HtmlControls;
|
||||||
|
using System.Text;
|
||||||
|
using MBS.Core.Drawing;
|
||||||
|
using MBS.Web.UI.WebControls;
|
||||||
|
using MBS.Core;
|
||||||
|
|
||||||
|
namespace MBS.Editor.Web.Pages;
|
||||||
|
|
||||||
|
public class MainPage : WebPage
|
||||||
|
{
|
||||||
|
private class WebStyleSheet2
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public MainPage()
|
||||||
|
{
|
||||||
|
Dictionary<string, Dictionary<string, object>> dict = new Dictionary<string, Dictionary<string, object>>();
|
||||||
|
/*
|
||||||
|
WebStyleSheet2 wss = new WebStyleSheet2();
|
||||||
|
|
||||||
|
WebStyleSheetSelector selector = WebStyleSheetSelector.Parse("div.uwt-page-header");
|
||||||
|
|
||||||
|
wss.Selectors.Add("div", "uwt-page-header");
|
||||||
|
*/
|
||||||
|
|
||||||
|
dict["div.uwt-page-header"] = new Dictionary<string, object>();
|
||||||
|
dict["div.uwt-page-header"]["border-bottom"] = new object[] { Measurement.Parse("1px"), "solid", Color.FromString("#E0E0E0") };
|
||||||
|
|
||||||
|
StyleSheets.Add(WebStyleSheet.FromContent("text/css", FormatCss(dict)));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Control> GetHeaderControls()
|
||||||
|
{
|
||||||
|
return new Control[]
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private string FormatCss(Dictionary<string, Dictionary<string, object>> dict)
|
||||||
|
{
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
foreach (KeyValuePair<string, Dictionary<string, object>> kvp in dict)
|
||||||
|
{
|
||||||
|
sb.Append(kvp.Key);
|
||||||
|
sb.Append(" { ");
|
||||||
|
foreach (KeyValuePair<string, object> kvp2 in kvp.Value)
|
||||||
|
{
|
||||||
|
sb.Append(kvp2.Key);
|
||||||
|
sb.Append(": ");
|
||||||
|
|
||||||
|
if (kvp2.Value is Color)
|
||||||
|
{
|
||||||
|
sb.Append(((Color)kvp2.Value).ToHexadecimalHTML());
|
||||||
|
}
|
||||||
|
else if (kvp2.Value is string)
|
||||||
|
{
|
||||||
|
sb.Append("\"");
|
||||||
|
sb.Append(kvp2.Value);
|
||||||
|
sb.Append("\"");
|
||||||
|
}
|
||||||
|
else if (kvp2.Value is object[])
|
||||||
|
{
|
||||||
|
object[] objs = (object[])kvp2.Value;
|
||||||
|
for (int i = 0; i < objs.Length; i++)
|
||||||
|
{
|
||||||
|
sb.Append(objs[i]);
|
||||||
|
if (i < objs.Length - 1)
|
||||||
|
{
|
||||||
|
sb.Append(' ');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sb.Append(kvp2.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sb.Append(" } ");
|
||||||
|
}
|
||||||
|
return sb.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override IEnumerable<Control> GetBodyControls()
|
||||||
|
{
|
||||||
|
CommandBar cb = new CommandBar();
|
||||||
|
cb.ClientId = "mainToolbar";
|
||||||
|
cb.Items.Add(new CommandReferenceCommandItem("FileOpen"));
|
||||||
|
|
||||||
|
return new Control[]
|
||||||
|
{
|
||||||
|
new PageHeader(),
|
||||||
|
cb
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
namespace MBS.Editor.Plugins.CRI.DataFormats.Database.UTF.Internal;
|
||||||
|
|
||||||
|
internal struct UTFTABLEINFO
|
||||||
|
{
|
||||||
|
public long utfOffset;
|
||||||
|
|
||||||
|
public int tableSize;
|
||||||
|
public int schemaOffset;
|
||||||
|
public int rowsOffset;
|
||||||
|
public int stringTableOffset;
|
||||||
|
public int dataOffset;
|
||||||
|
public uint tableNameStringOffset;
|
||||||
|
public short tableColumns;
|
||||||
|
public short rowWidth;
|
||||||
|
public int tableRows;
|
||||||
|
public int stringTableSize;
|
||||||
|
}
|
||||||
@ -0,0 +1,77 @@
|
|||||||
|
//
|
||||||
|
// UTFColumnDataType.cs - CRI Middleware UTF table column data types
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Plugins.CRI.DataFormats.Database.UTF;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The data type for a column in a UTF table.
|
||||||
|
/// </summary>
|
||||||
|
public enum UTFColumnDataType : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Mask value for combining <see cref="UTFColumnDataType" /> with <see cref="UTFColumnStorageType" />.
|
||||||
|
/// </summary>
|
||||||
|
Mask = 0x0f,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a variable-length array of <see cref="System.Byte" /> data.
|
||||||
|
/// </summary>
|
||||||
|
Data = 0x0b,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a variable-length <see cref="System.String" />.
|
||||||
|
/// </summary>
|
||||||
|
String = 0x0a,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Single" /> value.
|
||||||
|
/// </summary>
|
||||||
|
Float = 0x08,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Int64" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Long2 = 0x07,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Int64" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Long = 0x06,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Int32" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Int2 = 0x05,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Int32" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Int = 0x04,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Int16" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Short2 = 0x03,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Int16" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Short = 0x02,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Byte" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Byte2 = 0x01,
|
||||||
|
/// <summary>
|
||||||
|
/// The column represents a <see cref="System.Byte" /> value. There may or may not be a distinction between signed and unsigned types.
|
||||||
|
/// </summary>
|
||||||
|
Byte = 0x00
|
||||||
|
}
|
||||||
@ -0,0 +1,45 @@
|
|||||||
|
//
|
||||||
|
// UTFColumnStorageType.cs - CRI Middleware UTF table column storage types
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Plugins.CRI.DataFormats.Database.UTF;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The storage type for a column in a UTF table.
|
||||||
|
/// </summary>
|
||||||
|
public enum UTFColumnStorageType : byte
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Mask value for combining <see cref="UTFColumnDataType" /> with <see cref="UTFColumnStorageType" />.
|
||||||
|
/// </summary>
|
||||||
|
Mask = 0xf0,
|
||||||
|
/// <summary>
|
||||||
|
/// Data in this column is stored per row, with a single value written for each ROW in the table.
|
||||||
|
/// </summary>
|
||||||
|
PerRow = 0x50,
|
||||||
|
/// <summary>
|
||||||
|
/// Data in this column is constant regardless of row, with a single value written for each COLUMN in the table.
|
||||||
|
/// </summary>
|
||||||
|
Constant = 0x30,
|
||||||
|
/// <summary>
|
||||||
|
/// Data in this column is declared NULL for all rows in the table. No data is written for this column.
|
||||||
|
/// </summary>
|
||||||
|
Zero = 0x10
|
||||||
|
}
|
||||||
@ -0,0 +1,644 @@
|
|||||||
|
//
|
||||||
|
// UTFDataFormat.cs - COMPLETED - Implementation of CRI Middleware UTF table (used in CPK)
|
||||||
|
//
|
||||||
|
// Author:
|
||||||
|
// Michael Becker <alcexhim@gmail.com>
|
||||||
|
//
|
||||||
|
// Copyright (c) 2019-2020 Mike Becker's Software
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
namespace MBS.Editor.Plugins.CRI.DataFormats.Database.UTF;
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
using MBS.Core;
|
||||||
|
using MBS.Core.Collections;
|
||||||
|
|
||||||
|
using MBS.Editor.Core;
|
||||||
|
using MBS.Editor.Core.IO;
|
||||||
|
using MBS.Editor.Core.ObjectModels.Database;
|
||||||
|
using MBS.Editor.Plugins.CRI.DataFormats.Database.UTF.Internal;
|
||||||
|
|
||||||
|
public class UTFDataFormat : DataFormat
|
||||||
|
{
|
||||||
|
private static DataFormatMetadata _dfr;
|
||||||
|
public static DataFormatMetadata Metadata
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (_dfr == null)
|
||||||
|
{
|
||||||
|
_dfr = new DataFormatMetadata();
|
||||||
|
}
|
||||||
|
return _dfr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private UTFTABLEINFO ReadUTFTableInfo(Reader br)
|
||||||
|
{
|
||||||
|
UTFTABLEINFO info = new UTFTABLEINFO();
|
||||||
|
info.utfOffset = br.BaseStream.Position;
|
||||||
|
info.tableSize = br.ReadInt32();
|
||||||
|
info.schemaOffset = 0x20;
|
||||||
|
info.rowsOffset = br.ReadInt32();
|
||||||
|
info.stringTableOffset = br.ReadInt32();
|
||||||
|
info.dataOffset = br.ReadInt32();
|
||||||
|
|
||||||
|
// CPK Header & UTF Header are ignored, so add 8 to each offset
|
||||||
|
|
||||||
|
info.tableNameStringOffset = br.ReadUInt32(); // 00000007
|
||||||
|
info.tableColumns = br.ReadInt16(); // 0023
|
||||||
|
info.rowWidth = br.ReadInt16(); // 007e
|
||||||
|
info.tableRows = br.ReadInt32(); // 00000001
|
||||||
|
info.stringTableSize = info.dataOffset - info.stringTableOffset;
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void LoadInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
DatabaseObjectModel? utf = objectModel as DatabaseObjectModel;
|
||||||
|
if (utf == null)
|
||||||
|
throw new ObjectModelNotSupportedException();
|
||||||
|
|
||||||
|
Reader br = new Reader(stream);
|
||||||
|
string utf_signature = br.ReadFixedLengthString(4);
|
||||||
|
|
||||||
|
if (utf_signature != "@UTF")
|
||||||
|
throw new InvalidDataFormatException(); // we are assuming passed in decrypted UTF from the CPK
|
||||||
|
|
||||||
|
DatabaseTable dt = new DatabaseTable();
|
||||||
|
|
||||||
|
br.Endianness = Endianness.BigEndian;
|
||||||
|
|
||||||
|
UTFTABLEINFO info = ReadUTFTableInfo(br);
|
||||||
|
|
||||||
|
int[] columnNameOffsets = new int[info.tableColumns];
|
||||||
|
long[] constantOffsets = new long[info.tableColumns];
|
||||||
|
UTFColumnStorageType[] storageTypes = new UTFColumnStorageType[info.tableColumns];
|
||||||
|
UTFColumnDataType[] dataTypes = new UTFColumnDataType[info.tableColumns];
|
||||||
|
|
||||||
|
// Read string table - remember, this is relative to UTF data WITH the "@UTF" signature
|
||||||
|
br.BaseStream.SavePosition();
|
||||||
|
br.BaseStream.Seek(info.utfOffset + info.stringTableOffset + 4, SeekOrigin.Begin);
|
||||||
|
/*
|
||||||
|
while (br.PeekByte() == 0)
|
||||||
|
{
|
||||||
|
br.ReadByte();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
byte[] stringTableData = br.ReadBytes(info.stringTableSize);
|
||||||
|
|
||||||
|
MemoryStream maStringTable = new MemoryStream(stringTableData);
|
||||||
|
Reader stringTableReader = new Reader(maStringTable);
|
||||||
|
|
||||||
|
stringTableReader.BaseStream.Seek(info.tableNameStringOffset, SeekOrigin.Begin);
|
||||||
|
dt.Name = stringTableReader.ReadNullTerminatedString();
|
||||||
|
br.BaseStream.LoadPosition();
|
||||||
|
|
||||||
|
for (int i = 0; i < info.tableColumns; i++)
|
||||||
|
{
|
||||||
|
byte schema = br.ReadByte();
|
||||||
|
columnNameOffsets[i] = br.ReadInt32();
|
||||||
|
storageTypes[i] = (UTFColumnStorageType)(schema & (byte)UTFColumnStorageType.Mask);
|
||||||
|
dataTypes[i] = (UTFColumnDataType)(schema & (byte)UTFColumnDataType.Mask);
|
||||||
|
|
||||||
|
object constantValue = null;
|
||||||
|
if (storageTypes[i] == UTFColumnStorageType.Constant)
|
||||||
|
{
|
||||||
|
constantOffsets[i] = br.BaseStream.Position;
|
||||||
|
switch (dataTypes[i])
|
||||||
|
{
|
||||||
|
case UTFColumnDataType.Long:
|
||||||
|
case UTFColumnDataType.Long2:
|
||||||
|
case UTFColumnDataType.Data:
|
||||||
|
{
|
||||||
|
constantValue = br.ReadInt64();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Float:
|
||||||
|
{
|
||||||
|
constantValue = br.ReadSingle();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.String:
|
||||||
|
{
|
||||||
|
int valueOffset = br.ReadInt32();
|
||||||
|
stringTableReader.BaseStream.Seek(valueOffset, SeekOrigin.Begin);
|
||||||
|
constantValue = stringTableReader.ReadNullTerminatedString();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Int:
|
||||||
|
case UTFColumnDataType.Int2:
|
||||||
|
{
|
||||||
|
constantValue = br.ReadInt32();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Short:
|
||||||
|
case UTFColumnDataType.Short2:
|
||||||
|
{
|
||||||
|
constantValue = br.ReadInt16();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Byte:
|
||||||
|
case UTFColumnDataType.Byte2:
|
||||||
|
{
|
||||||
|
constantValue = br.ReadByte();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
Console.WriteLine("cpk: ReadUTFTable: unknown data type for column " + i.ToString());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.Fields.Add("Field" + i.ToString(), constantValue, SystemDataTypeForUTFDataType(dataTypes[i]));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < info.tableColumns; i++)
|
||||||
|
{
|
||||||
|
stringTableReader.BaseStream.Seek(columnNameOffsets[i], SeekOrigin.Begin);
|
||||||
|
dt.Fields[i].Name = stringTableReader.ReadNullTerminatedString();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < info.tableRows; i++)
|
||||||
|
{
|
||||||
|
uint rowOffset = (uint)(info.utfOffset + 4 + info.rowsOffset + (i * info.rowWidth));
|
||||||
|
uint rowStartOffset = rowOffset;
|
||||||
|
br.BaseStream.Seek(rowOffset, SeekOrigin.Begin);
|
||||||
|
|
||||||
|
DatabaseRecord record = new DatabaseRecord();
|
||||||
|
|
||||||
|
for (int j = 0; j < info.tableColumns; j++)
|
||||||
|
{
|
||||||
|
UTFColumnStorageType storageType = storageTypes[j];
|
||||||
|
UTFColumnDataType dataType = dataTypes[j];
|
||||||
|
long constantOffset = constantOffsets[j] - 11;
|
||||||
|
|
||||||
|
switch (storageType)
|
||||||
|
{
|
||||||
|
case UTFColumnStorageType.PerRow:
|
||||||
|
{
|
||||||
|
switch (dataType)
|
||||||
|
{
|
||||||
|
case UTFColumnDataType.String:
|
||||||
|
{
|
||||||
|
string value = null;
|
||||||
|
if (storageType == UTFColumnStorageType.Constant)
|
||||||
|
{
|
||||||
|
value = (dt.Fields[j].Value as string);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint stringOffset = br.ReadUInt32();
|
||||||
|
if (stringOffset < stringTableData.Length)
|
||||||
|
{
|
||||||
|
stringTableReader.BaseStream.Seek(stringOffset, SeekOrigin.Begin);
|
||||||
|
value = stringTableReader.ReadNullTerminatedString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Data:
|
||||||
|
{
|
||||||
|
uint varDataOffset = br.ReadUInt32();
|
||||||
|
uint varDataSize = br.ReadUInt32();
|
||||||
|
|
||||||
|
byte[] value = null;
|
||||||
|
if (varDataOffset == 0 && varDataSize == 0)
|
||||||
|
{
|
||||||
|
value = null;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
long realOffset = info.dataOffset + 8 + varDataOffset;
|
||||||
|
br.BaseStream.SavePosition();
|
||||||
|
br.BaseStream.Seek(realOffset, SeekOrigin.Begin);
|
||||||
|
byte[] tableData = br.ReadBytes(varDataSize);
|
||||||
|
br.BaseStream.LoadPosition();
|
||||||
|
value = tableData;
|
||||||
|
}
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Long:
|
||||||
|
case UTFColumnDataType.Long2:
|
||||||
|
{
|
||||||
|
ulong value = br.ReadUInt64();
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Int:
|
||||||
|
case UTFColumnDataType.Int2:
|
||||||
|
{
|
||||||
|
uint value = br.ReadUInt32();
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, value);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Short:
|
||||||
|
case UTFColumnDataType.Short2:
|
||||||
|
{
|
||||||
|
ushort value = br.ReadUInt16();
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Float:
|
||||||
|
{
|
||||||
|
float value = br.ReadSingle();
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Byte:
|
||||||
|
case UTFColumnDataType.Byte2:
|
||||||
|
{
|
||||||
|
byte value = br.ReadByte();
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnStorageType.Constant:
|
||||||
|
{
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, dt.Fields[j].Value);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
case UTFColumnStorageType.Zero:
|
||||||
|
{
|
||||||
|
record.Fields.Add(dt.Fields[j].Name, null);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dt.Records.Add(record);
|
||||||
|
}
|
||||||
|
utf.Tables.Add(dt);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Type SystemDataTypeForUTFDataType(UTFColumnDataType dataType)
|
||||||
|
{
|
||||||
|
switch (dataType)
|
||||||
|
{
|
||||||
|
case UTFColumnDataType.Byte:
|
||||||
|
case UTFColumnDataType.Byte2:
|
||||||
|
{
|
||||||
|
return typeof(byte);
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Data:
|
||||||
|
{
|
||||||
|
return typeof(byte[]);
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Float:
|
||||||
|
{
|
||||||
|
return typeof(float);
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Int:
|
||||||
|
{
|
||||||
|
return typeof(uint);
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Int2:
|
||||||
|
{
|
||||||
|
return typeof(int);
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Long:
|
||||||
|
case UTFColumnDataType.Long2:
|
||||||
|
{
|
||||||
|
return typeof(long);
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Short:
|
||||||
|
case UTFColumnDataType.Short2:
|
||||||
|
{
|
||||||
|
return typeof(short);
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.String:
|
||||||
|
{
|
||||||
|
return typeof(string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
public static UTFColumnDataType UTFDataTypeForSystemDataType(Type dataType)
|
||||||
|
{
|
||||||
|
if (dataType == typeof(byte)) return UTFColumnDataType.Byte;
|
||||||
|
else if (dataType == typeof(sbyte)) return UTFColumnDataType.Byte;
|
||||||
|
else if (dataType == typeof(byte[])) return UTFColumnDataType.Data;
|
||||||
|
else if (dataType == typeof(float)) return UTFColumnDataType.Float;
|
||||||
|
else if (dataType == typeof(int)) return UTFColumnDataType.Int2;
|
||||||
|
else if (dataType == typeof(uint)) return UTFColumnDataType.Int;
|
||||||
|
else if (dataType == typeof(long)) return UTFColumnDataType.Long;
|
||||||
|
else if (dataType == typeof(ulong)) return UTFColumnDataType.Long;
|
||||||
|
else if (dataType == typeof(short)) return UTFColumnDataType.Short;
|
||||||
|
else if (dataType == typeof(ushort)) return UTFColumnDataType.Short;
|
||||||
|
else if (dataType == typeof(string)) return UTFColumnDataType.String;
|
||||||
|
return UTFColumnDataType.Mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void SaveInternal(ObjectModel objectModel, Stream stream)
|
||||||
|
{
|
||||||
|
DatabaseObjectModel? utf = objectModel as DatabaseObjectModel;
|
||||||
|
if (utf == null)
|
||||||
|
throw new ObjectModelNotSupportedException();
|
||||||
|
|
||||||
|
Writer bw = new Writer(stream);
|
||||||
|
bw.WriteFixedLengthString("@UTF");
|
||||||
|
|
||||||
|
DatabaseTable dt = utf.Tables[0];
|
||||||
|
|
||||||
|
bw.Endianness = Endianness.BigEndian;
|
||||||
|
|
||||||
|
// do the hard work here to determine if a field should be recorded as zero or not
|
||||||
|
UTFColumnStorageType[] columnStorageTypes = new UTFColumnStorageType[dt.Fields.Count];
|
||||||
|
UTFColumnDataType[] columnDataTypes = new UTFColumnDataType[dt.Fields.Count];
|
||||||
|
for (int i = 0; i < dt.Fields.Count; i++)
|
||||||
|
{
|
||||||
|
columnStorageTypes[i] = UTFColumnStorageType.Zero;
|
||||||
|
columnDataTypes[i] = UTFDataTypeForSystemDataType(dt.Fields[i].DataType);
|
||||||
|
|
||||||
|
if (dt.Fields[i].Value != null)
|
||||||
|
{
|
||||||
|
columnStorageTypes[i] = UTFColumnStorageType.Constant;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (int j = 0; j < dt.Records.Count; j++)
|
||||||
|
{
|
||||||
|
if (dt.Records[j].Fields[i].Value != null)
|
||||||
|
{
|
||||||
|
columnStorageTypes[i] = UTFColumnStorageType.PerRow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int tableSize = 24; // size of entire file = 32 - "@UTF".Length(4) - (size of table size field:4) = 32 - 8 = 24
|
||||||
|
tableSize += (5 * dt.Fields.Count); // 5 * 36 = 204 5 * 35 = 195
|
||||||
|
tableSize += (dt.Name.Length + 1); // 204 + "CpkHeader".Length + 1 = 214
|
||||||
|
tableSize += 7; // "<NULL>\0".Length // 214 + 7 = 221
|
||||||
|
|
||||||
|
int rowsOffset = 24 + (5 * dt.Fields.Count);
|
||||||
|
int stringTableOffset = rowsOffset;
|
||||||
|
short rowWidth = 0;
|
||||||
|
for (int i = 0; i < dt.Fields.Count; i++)
|
||||||
|
{
|
||||||
|
tableSize += (dt.Fields[i].Name.Length + 1);
|
||||||
|
if (columnStorageTypes[i] == UTFColumnStorageType.Constant)
|
||||||
|
{
|
||||||
|
int l = GetLengthForDataType(columnDataTypes[i]);
|
||||||
|
tableSize += l;
|
||||||
|
stringTableOffset += l;
|
||||||
|
rowsOffset += l;
|
||||||
|
|
||||||
|
if (columnDataTypes[i] == UTFColumnDataType.String)
|
||||||
|
{
|
||||||
|
tableSize += ((string)dt.Fields[i].Value).Length + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (columnStorageTypes[i] == UTFColumnStorageType.PerRow)
|
||||||
|
{
|
||||||
|
rowWidth += GetLengthForDataType(columnDataTypes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < dt.Records.Count; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < dt.Records[i].Fields.Count; j++)
|
||||||
|
{
|
||||||
|
if (columnStorageTypes[j] == UTFColumnStorageType.PerRow)
|
||||||
|
{
|
||||||
|
tableSize += GetLengthForDataType(columnDataTypes[j]);
|
||||||
|
stringTableOffset += GetLengthForDataType(columnDataTypes[j]);
|
||||||
|
if (columnDataTypes[j] == UTFColumnDataType.String)
|
||||||
|
{
|
||||||
|
tableSize += ((string)dt.Records[i].Fields[j].Value).Length + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is off... always at the same offset too (CpkTocInfo - 0x818 in cpk files)
|
||||||
|
// tableSize += 8; // this is correct, but, CpkFileBuilder chokes, unless it is omitted
|
||||||
|
tableSize = tableSize.Align(8);
|
||||||
|
|
||||||
|
bw.WriteInt32(tableSize);
|
||||||
|
bw.WriteInt32(rowsOffset);
|
||||||
|
bw.WriteInt32(stringTableOffset);
|
||||||
|
bw.WriteInt32(tableSize); // data offset - same as table size?
|
||||||
|
bw.WriteUInt32(7); // "<NULL>\0".Length
|
||||||
|
bw.WriteInt16((short)dt.Fields.Count); // 0023
|
||||||
|
bw.WriteInt16(rowWidth); // 007e
|
||||||
|
bw.WriteInt32(dt.Records.Count); // 00000001
|
||||||
|
|
||||||
|
int columnNameOffset = (int)8 + (int)dt.Name.Length; // add space for "<NULL>\0" string and dt.Name + 1
|
||||||
|
|
||||||
|
List<string> stringTable = new List<string>();
|
||||||
|
stringTable.Add("<NULL>");
|
||||||
|
stringTable.Add(dt.Name);
|
||||||
|
for (int i = 0; i < dt.Fields.Count; i++)
|
||||||
|
{
|
||||||
|
byte schema = 0;
|
||||||
|
schema |= (byte)((byte)columnStorageTypes[i] | (byte)columnDataTypes[i]);
|
||||||
|
|
||||||
|
bw.WriteByte(schema);
|
||||||
|
bw.WriteInt32(columnNameOffset);
|
||||||
|
|
||||||
|
columnNameOffset += dt.Fields[i].Name.Length + 1;
|
||||||
|
stringTable.Add(dt.Fields[i].Name);
|
||||||
|
|
||||||
|
if (columnStorageTypes[i] == UTFColumnStorageType.Constant)
|
||||||
|
{
|
||||||
|
WriteValue(bw, dt.Fields[i].Value, columnDataTypes[i], stringTable);
|
||||||
|
if (columnDataTypes[i] == UTFColumnDataType.String)
|
||||||
|
{
|
||||||
|
columnNameOffset += ((string)dt.Fields[i].Value).Length + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < dt.Records.Count; i++)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < dt.Fields.Count; j++)
|
||||||
|
{
|
||||||
|
if (columnStorageTypes[j] == UTFColumnStorageType.PerRow)
|
||||||
|
{
|
||||||
|
WriteValue(bw, dt.Records[i].Fields[j].Value, stringTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < stringTable.Count; i++)
|
||||||
|
{
|
||||||
|
bw.WriteNullTerminatedString(stringTable[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bw.Align(8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static short GetLengthForDataType(UTFColumnDataType columnDataType)
|
||||||
|
{
|
||||||
|
switch (columnDataType)
|
||||||
|
{
|
||||||
|
case UTFColumnDataType.String:
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Data:
|
||||||
|
case UTFColumnDataType.Long:
|
||||||
|
case UTFColumnDataType.Long2:
|
||||||
|
{
|
||||||
|
return 8;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Byte:
|
||||||
|
case UTFColumnDataType.Byte2:
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Float:
|
||||||
|
case UTFColumnDataType.Int:
|
||||||
|
case UTFColumnDataType.Int2:
|
||||||
|
{
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Short:
|
||||||
|
case UTFColumnDataType.Short2:
|
||||||
|
{
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteValue(Writer bw, object value, List<string> stringTable)
|
||||||
|
{
|
||||||
|
if (value is string)
|
||||||
|
{
|
||||||
|
WriteValue(bw, value, UTFColumnDataType.String, stringTable);
|
||||||
|
}
|
||||||
|
else if (value is byte[])
|
||||||
|
{
|
||||||
|
WriteValue(bw, value, UTFColumnDataType.Data, stringTable);
|
||||||
|
}
|
||||||
|
else if (value is long || value is ulong)
|
||||||
|
{
|
||||||
|
WriteValue(bw, value, UTFColumnDataType.Long, stringTable);
|
||||||
|
}
|
||||||
|
else if (value is int || value is uint)
|
||||||
|
{
|
||||||
|
WriteValue(bw, value, UTFColumnDataType.Int, stringTable);
|
||||||
|
}
|
||||||
|
else if (value is short || value is ushort)
|
||||||
|
{
|
||||||
|
WriteValue(bw, value, UTFColumnDataType.Short, stringTable);
|
||||||
|
}
|
||||||
|
else if (value is byte || value is byte)
|
||||||
|
{
|
||||||
|
WriteValue(bw, value, UTFColumnDataType.Byte, stringTable);
|
||||||
|
}
|
||||||
|
else if (value is float)
|
||||||
|
{
|
||||||
|
WriteValue(bw, value, UTFColumnDataType.Float, stringTable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void WriteValue(Writer bw, object value, UTFColumnDataType columnDataType, List<string> stringTable)
|
||||||
|
{
|
||||||
|
switch (columnDataType)
|
||||||
|
{
|
||||||
|
case UTFColumnDataType.String:
|
||||||
|
{
|
||||||
|
string str = (string)value;
|
||||||
|
if (stringTable.Contains(str))
|
||||||
|
{
|
||||||
|
bw.WriteUInt32((uint)stringTable.GetItemOffset(stringTable.IndexOf(str), 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stringTable.Add(str);
|
||||||
|
bw.WriteUInt32((uint)stringTable.GetItemOffset(stringTable.Count - 1, 1));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Data:
|
||||||
|
{
|
||||||
|
uint varDataOffset = 0;
|
||||||
|
uint varDataSize = 0;
|
||||||
|
bw.WriteUInt32(varDataOffset);
|
||||||
|
bw.WriteUInt32(varDataSize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Long:
|
||||||
|
case UTFColumnDataType.Long2:
|
||||||
|
{
|
||||||
|
if (value is ulong)
|
||||||
|
{
|
||||||
|
bw.WriteUInt64((ulong)value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bw.WriteInt64((long)value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Int:
|
||||||
|
case UTFColumnDataType.Int2:
|
||||||
|
{
|
||||||
|
if (value is uint)
|
||||||
|
{
|
||||||
|
bw.WriteUInt32((uint)value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bw.WriteInt32((int)value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Short:
|
||||||
|
case UTFColumnDataType.Short2:
|
||||||
|
{
|
||||||
|
if (value is ushort)
|
||||||
|
{
|
||||||
|
bw.WriteUInt16((ushort)value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bw.WriteInt16((short)value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Float:
|
||||||
|
{
|
||||||
|
bw.WriteSingle((float)value);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case UTFColumnDataType.Byte:
|
||||||
|
case UTFColumnDataType.Byte2:
|
||||||
|
{
|
||||||
|
if (value is byte)
|
||||||
|
{
|
||||||
|
bw.WriteByte((byte)value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bw.WriteSByte((sbyte)value);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user