Merge branch 'master' of gitea.azcona-becker.net:universaleditor/editor-dotnet

This commit is contained in:
Michael Becker 2025-03-25 15:25:59 -04:00
commit f6525b7744
176 changed files with 16198 additions and 19 deletions

1
.gitignore vendored
View File

@ -1,4 +1,5 @@
# ---> VisualStudioCode
.vscode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json

6
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "framework-dotnet"]
path = 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

@ -0,0 +1 @@
Subproject commit 57316e3557c1c3a566d1a24bd60675c02d1f8744

11
editor
View File

@ -5,12 +5,23 @@ SRC_PATH=editor-dotnet/src/app/$APP_NAME
APP_PATH=$SRC_PATH/bin/Debug/net$DOTNET_VERSION
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
pushd $SRC_PATH
dotnet build
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
$APP_PATH/$APP_NAME

214
editor-dotnet.sln Normal file
View 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

View File

@ -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>

View 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();
}
}

View File

@ -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>

View 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();
}
}

View 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

View File

@ -3,8 +3,8 @@
<ItemGroup>
<ProjectReference Include="..\..\lib\MBS.Editor.Core\MBS.Editor.Core.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="..\..\..\..\desktop-framework-dotnet\desktop-framework-dotnet\src\lib\MBS.Desktop\MBS.Desktop.csproj" />
</ItemGroup>
<PropertyGroup>

View File

@ -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();

View 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

View 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

View 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;
}
}

View File

@ -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);
}
}

View File

@ -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++]);
}
}
}

View File

@ -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) { }
}

View File

@ -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);
}

View File

@ -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();
}
}

View File

@ -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);
}
*/
}

View File

@ -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;
}

View File

@ -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)
{
}
}

View File

@ -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);
}
}

View File

@ -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);
}
*/
}

View File

@ -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()
{
}
}

View File

@ -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
}

View File

@ -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);
}
}

View File

@ -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)
{
}
}

View File

@ -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);
}
}

View File

@ -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
}

View File

@ -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");
}
}

View File

@ -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;
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;
}
}

View File

@ -0,0 +1,10 @@
namespace MBS.Editor.Core;
using MBS.Core.Settings;
public class DataFormatMetadata
{
public SettingsProvider ExportSettings { get; }
public SettingsProvider ImportSettings { get; }
}

View File

@ -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;
}
}

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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)
{
}
}

View File

@ -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();
}
}

View File

@ -0,0 +1,9 @@
namespace MBS.Editor.Core;
public enum INIDataFormatToken
{
None = 0,
Comment,
String,
Group
}

View 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;
}
}

View File

@ -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; } }
}

View File

@ -0,0 +1,9 @@
namespace MBS.Editor.Core.Hosting;
public enum HostApplicationMessageSeverity
{
None = 0,
Notice = 1,
Warning = 2,
Error = 3
}

View File

@ -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;
}
}

View File

@ -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();
}

View File

@ -0,0 +1,6 @@
namespace MBS.Editor.Core.Hosting;
public interface IHostApplication
{
HostServices HostServices { get; }
}

View File

@ -0,0 +1,7 @@
namespace MBS.Editor.Core.IO;
public enum Endianness
{
LittleEndian,
BigEndian
}

View File

@ -0,0 +1,11 @@
namespace MBS.Editor.Core.IO;
public enum NewLineSequence
{
Automatic,
SystemDefault,
CarriageReturn,
LineFeed,
CarriageReturnLineFeed,
LineFeedCarriageReturn
}

File diff suppressed because it is too large Load Diff

View 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();
}
}

File diff suppressed because it is too large Load Diff

View File

@ -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) { }
}

View File

@ -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>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -4,4 +4,42 @@ public class ObjectModel
{
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;
}
}

View File

@ -0,0 +1,6 @@
namespace MBS.Editor.Core;
public class ObjectModelMetadata
{
public string[] Path { get; set; }
}

View File

@ -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;
}
}

View File

@ -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; }
}

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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; }
}

View File

@ -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);
}
}
}

View File

@ -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;
}
*/
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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; }
}

View File

@ -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;
}
}

View File

@ -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() };
}

View File

@ -0,0 +1,7 @@
namespace MBS.Editor.Core.ObjectModels.FileSystem;
public interface IFileSystemItemContainer
{
FileSystemObjectModel FileSystem { get; }
FileSystemItemCollection Items { get; }
}

View File

@ -0,0 +1,9 @@
namespace MBS.Editor.Core;
public interface IPropertyListContainer
{
PropertyListItem.PropertyListItemCollection Items { get; }
IPropertyListContainer? Parent { get; }
}

View File

@ -0,0 +1,6 @@
namespace MBS.Editor.Core;
public class PropertyListComment : PropertyListItem
{
public string Value { get; set; } = "";
}

View File

@ -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);
}
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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)
{
}
}

View File

@ -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>

View File

@ -1,14 +1,38 @@
namespace MBS.Editor.UserInterface;
using System;
using MBS.Core;
using MBS.Desktop;
using MBS.Desktop.Controls;
public class EditorApplication : DesktopApplication
{
protected override void OnStartup(EventArgs e)
{
base.OnStartup(e);
protected override int StartInternal()
{
return 0;
}
Console.WriteLine("editor: OnStartup");
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();
}
}

View File

@ -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 });
}
}

View File

@ -2,7 +2,7 @@
<ItemGroup>
<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>
<PropertyGroup>

View 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" };
}
}

View 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>

View 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
};
}
}

View File

@ -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;
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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