diff --git a/ctrtool/build/visualstudio/CTRTool.sln b/ctrtool/build/visualstudio/CTRTool.sln
new file mode 100644
index 0000000..0612a16
--- /dev/null
+++ b/ctrtool/build/visualstudio/CTRTool.sln
@@ -0,0 +1,90 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31229.75
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CTRTool", "CTRTool\CTRTool.vcxproj", "{CADDA22C-5FED-4DAB-A87E-AFBD279DB367}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "..\..\deps\libfmt\build\visualstudio\libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtoolchain", "..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj", "{E194E4B8-1482-40A2-901B-75D4387822E9}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbroadon-es", "..\..\deps\libbroadon-es\build\visualstudio\libbroadon-es\libbroadon-es.vcxproj", "{8A35D7DC-293A-4669-9C1E-4F45ABFE8838}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libnintendo-n3ds", "..\..\deps\libnintendo-n3ds\build\visualstudio\libnintendo-n3ds\libnintendo-n3ds.vcxproj", "{7789491C-5403-4613-B06B-DB0C58E19A01}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "deps", "deps", "{1AF77D36-45A2-412E-A540-F559B78A6471}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x64.ActiveCfg = Debug|x64
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x64.Build.0 = Debug|x64
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x86.ActiveCfg = Debug|Win32
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Debug|x86.Build.0 = Debug|Win32
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x64.ActiveCfg = Release|x64
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x64.Build.0 = Release|x64
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x86.ActiveCfg = Release|Win32
+ {CADDA22C-5FED-4DAB-A87E-AFBD279DB367}.Release|x86.Build.0 = Release|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.ActiveCfg = Debug|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.Build.0 = Debug|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.ActiveCfg = Debug|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.Build.0 = Debug|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.ActiveCfg = Release|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.ActiveCfg = Debug|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.Build.0 = Debug|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.ActiveCfg = Debug|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.Build.0 = Debug|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.ActiveCfg = Release|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.Build.0 = Release|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.ActiveCfg = Release|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.Build.0 = Release|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.ActiveCfg = Debug|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.Build.0 = Debug|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.ActiveCfg = Debug|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.Build.0 = Debug|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.ActiveCfg = Release|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.Build.0 = Release|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.ActiveCfg = Release|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.Build.0 = Release|Win32
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.ActiveCfg = Debug|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.Build.0 = Debug|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.ActiveCfg = Debug|Win32
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.Build.0 = Debug|Win32
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.ActiveCfg = Release|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.Build.0 = Release|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.ActiveCfg = Release|Win32
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.Build.0 = Release|Win32
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x64.ActiveCfg = Debug|x64
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x64.Build.0 = Debug|x64
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x86.ActiveCfg = Debug|Win32
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Debug|x86.Build.0 = Debug|Win32
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x64.ActiveCfg = Release|x64
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x64.Build.0 = Release|x64
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x86.ActiveCfg = Release|Win32
+ {7789491C-5403-4613-B06B-DB0C58E19A01}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {F4B0540E-0AAE-4006-944B-356944EF61FA} = {1AF77D36-45A2-412E-A540-F559B78A6471}
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C} = {1AF77D36-45A2-412E-A540-F559B78A6471}
+ {E194E4B8-1482-40A2-901B-75D4387822E9} = {1AF77D36-45A2-412E-A540-F559B78A6471}
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838} = {1AF77D36-45A2-412E-A540-F559B78A6471}
+ {7789491C-5403-4613-B06B-DB0C58E19A01} = {1AF77D36-45A2-412E-A540-F559B78A6471}
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {10D725B5-08F6-43F3-A28F-7B034F1ADEFC}
+ EndGlobalSection
+EndGlobal
diff --git a/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj
new file mode 100644
index 0000000..69ff2fe
--- /dev/null
+++ b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj
@@ -0,0 +1,192 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {cadda22c-5fed-4dab-a87e-afbd279db367}
+ CTRTool
+ 10.0
+
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+ Application
+ true
+ v142
+ Unicode
+
+
+ Application
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include
+ MultiThreadedDebug
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include
+ MultiThreaded
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include
+ MultiThreadedDebug
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ $(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(SolutionDir)..\..\deps\libbroadon-es\include;$(SolutionDir)..\..\deps\libnintendo-n3ds\include;$(ProjectDir)..\..\..\include
+ MultiThreaded
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {f4b0540e-0aae-4006-944b-356944ef61fa}
+
+
+ {7a7c66f3-2b5b-4e23-85d8-2a74fedad92c}
+
+
+ {8a35d7dc-293a-4669-9c1e-4f45abfe8838}
+
+
+ {7789491c-5403-4613-b06b-db0c58e19a01}
+
+
+ {e194e4b8-1482-40a2-901b-75d4387822e9}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj.filters b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj.filters
new file mode 100644
index 0000000..947c47c
--- /dev/null
+++ b/ctrtool/build/visualstudio/CTRTool/CTRTool.vcxproj.filters
@@ -0,0 +1,111 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/LICENSE b/ctrtool/deps/libbroadon-es/LICENSE
new file mode 100644
index 0000000..38e64e9
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2021 Jack
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/ctrtool/deps/libbroadon-es/README.md b/ctrtool/deps/libbroadon-es/README.md
new file mode 100644
index 0000000..8066897
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/README.md
@@ -0,0 +1,2 @@
+# libbroadon-es
+C++ Library for processing Nintendo's ES DRM formats.
diff --git a/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es.sln b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es.sln
new file mode 100644
index 0000000..d1cc8fc
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es.sln
@@ -0,0 +1,62 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31229.75
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libbroadon-es", "libbroadon-es\libbroadon-es.vcxproj", "{8A35D7DC-293A-4669-9C1E-4F45ABFE8838}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "..\..\deps\libfmt\build\visualstudio\libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libmbedtls", "..\..\deps\libmbedtls\build\visualstudio\libmbedtls\libmbedtls.vcxproj", "{7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libtoolchain", "..\..\deps\libtoolchain\build\visualstudio\libtoolchain\libtoolchain.vcxproj", "{E194E4B8-1482-40A2-901B-75D4387822E9}"
+EndProject
+
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.ActiveCfg = Debug|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x64.Build.0 = Debug|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.ActiveCfg = Debug|Win32
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Debug|x86.Build.0 = Debug|Win32
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.ActiveCfg = Release|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x64.Build.0 = Release|x64
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.ActiveCfg = Release|Win32
+ {8A35D7DC-293A-4669-9C1E-4F45ABFE8838}.Release|x86.Build.0 = Release|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.ActiveCfg = Debug|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x64.Build.0 = Debug|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.ActiveCfg = Debug|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Debug|x86.Build.0 = Debug|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.ActiveCfg = Release|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x64.Build.0 = Release|x64
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.ActiveCfg = Release|Win32
+ {7A7C66F3-2B5B-4E23-85D8-2A74FEDAD92C}.Release|x86.Build.0 = Release|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.ActiveCfg = Debug|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x64.Build.0 = Debug|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.ActiveCfg = Debug|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Debug|x86.Build.0 = Debug|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.ActiveCfg = Release|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x64.Build.0 = Release|x64
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.ActiveCfg = Release|Win32
+ {E194E4B8-1482-40A2-901B-75D4387822E9}.Release|x86.Build.0 = Release|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.ActiveCfg = Debug|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.Build.0 = Debug|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.ActiveCfg = Debug|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.Build.0 = Debug|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.ActiveCfg = Release|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {76A6C1B6-F1C0-467F-B3A1-D7BDCBAA4FC0}
+ EndGlobalSection
+EndGlobal
diff --git a/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj
new file mode 100644
index 0000000..a83e05a
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj
@@ -0,0 +1,151 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {8a35d7dc-293a-4669-9c1e-4f45abfe8838}
+ libnintendoesdrm
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v142
+ Unicode
+
+
+ StaticLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v142
+ Unicode
+
+
+ StaticLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include
+ MultiThreadedDebug
+
+
+
+
+ Level3
+ Disabled
+ true
+ true
+ $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include
+ MultiThreadedDebug
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include
+ MultiThreaded
+
+
+ true
+ true
+
+
+
+
+ Level3
+ MaxSpeed
+ true
+ true
+ true
+ true
+ $(SolutionDir)..\..\deps\libfmt\include;$(SolutionDir)..\..\deps\libmbedtls\include;$(SolutionDir)..\..\deps\libtoolchain\include;$(ProjectDir)..\..\..\include
+ MultiThreaded
+
+
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {7a7c66f3-2b5b-4e23-85d8-2a74fedad92c}
+
+
+ {e194e4b8-1482-40a2-901b-75d4387822e9}
+
+
+ {f4b0540e-0aae-4006-944b-356944ef61fa}
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj.filters b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj.filters
new file mode 100644
index 0000000..ec5de4d
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/build/visualstudio/libbroadon-es/libbroadon-es.vcxproj.filters
@@ -0,0 +1,48 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+ {ba10896d-aa46-41de-9331-2c89a9ddf64a}
+
+
+ {c67a3de1-eb64-4733-a6e6-cdcb7be43b60}
+
+
+
+
+ Source Files
+
+
+
+
+ Header Files\brd\es
+
+
+ Header Files\brd\es
+
+
+ Header Files\brd\es
+
+
+ Header Files\brd\es
+
+
+ Header Files\brd\es
+
+
+ Header Files\brd
+
+
+
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/include/brd/es.h b/ctrtool/deps/libbroadon-es/include/brd/es.h
new file mode 100644
index 0000000..1ccf8f8
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/include/brd/es.h
@@ -0,0 +1,7 @@
+#pragma once
+
+// definitions
+#include
+#include
+#include
+#include
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_cert.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_cert.h
new file mode 100644
index 0000000..f5a7a05
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_cert.h
@@ -0,0 +1,101 @@
+#pragma once
+#include
+
+namespace brd { namespace es {
+ /**
+ @enum ESCertPubKeyType
+ @brief ES Certificate public key type definition
+ */
+enum class ESCertPubKeyType : uint32_t
+{
+ RSA4096 = 0, /* RSA 4096 bit key */
+ RSA2048 = 1, /* RSA 2048 bit key */
+ ECC = 2, /* ECC pub key 512 bits */
+};
+
+static const size_t ES_CERT_NAME_SIZE = 64;
+using ESCertName = tc::bn::string;
+using ESServerId = ESCertName;
+using ESDeviceId = ESCertName;
+
+template
+using ESPubKeyPad = std::array;
+
+/* pack to 4 byte boundaries */
+#pragma pack(push,4)
+
+struct ESCertHeader
+{
+ tc::bn::be32 pubKeyType; // ESCertPubKeyType
+ union {
+ ESServerId serverId;
+ ESDeviceId deviceId;
+ } name;
+ tc::bn::be32 date; // unix time-stamp
+};
+static_assert(sizeof(ESCertHeader) == 72, "ESCertHeader size");
+
+struct ESCertRsa2048PublicKey
+{
+ Rsa2048PublicKey pubKey;
+ ESPubKeyPad<52> pad;
+};
+static_assert(sizeof(ESCertRsa2048PublicKey) == 312, "ESCertRsa2048PublicKey size");
+
+struct ESCertRsa4096PublicKey
+{
+ Rsa4096PublicKey pubKey;
+ ESPubKeyPad<52> pad;
+};
+static_assert(sizeof(ESCertRsa4096PublicKey) == 568, "ESCertRsa4096PublicKey size");
+
+struct ESCertEcc233PublicKey
+{
+ Ecc233PublicKey pubKey;
+ ESPubKeyPad<60> pad;
+};
+static_assert(sizeof(ESCertEcc233PublicKey) == 120, "ESCertEcc233PublicKey size");
+
+struct ESRootCert
+{
+ ESSigRsa4096 sig;
+ ESCertHeader head;
+ ESCertRsa4096PublicKey body;
+};
+static_assert(sizeof(ESRootCert) == 1280, "ESRootCert size");
+
+struct ESCACert
+{
+ ESSigRsa4096 sig;
+ ESCertHeader head;
+ ESCertRsa2048PublicKey body;
+};
+static_assert(sizeof(ESCACert) == 1024, "ESCACert size");
+
+struct ESCASignedCert
+{
+ ESSigRsa2048 sig;
+ ESCertHeader head;
+ ESCertRsa2048PublicKey body;
+};
+static_assert(sizeof(ESCASignedCert) == 768, "ESCASignedCert size");
+
+struct ESDeviceCert
+{
+ ESSigRsa2048 sig;
+ ESCertHeader head;
+ ESCertEcc233PublicKey body;
+};
+static_assert(sizeof(ESDeviceCert) == 576, "ESDeviceCert size");
+
+struct ESDeviceSignedCert
+{
+ ESSigEcc233 sig;
+ ESCertHeader head;
+ ESCertEcc233PublicKey body;
+};
+static_assert(sizeof(ESDeviceSignedCert) == 384, "ESDeviceSignedCert size");
+
+#pragma pack(pop)
+
+}} // namespace brd::es
diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_sign.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_sign.h
new file mode 100644
index 0000000..4f313ea
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_sign.h
@@ -0,0 +1,73 @@
+#pragma once
+#include
+
+namespace brd { namespace es {
+ /**
+ @enum ESSigType
+ @brief ES Signature type definition
+ */
+enum class ESSigType : uint32_t
+{
+ RSA4096_SHA1 = 0x00010000, /* RSA 4096 bit signature */
+ RSA2048_SHA1 = 0x00010001, /* RSA 2048 bit signature */
+ ECC_SHA1 = 0x00010002, /* ECC signature 512 bits */
+ RSA4096_SHA256 = 0x00010003, /* RSA 4096 bit sig using SHA-256 */
+ RSA2048_SHA256 = 0x00010004, /* RSA 2048 bit sig using SHA-256 */ // note that Switch Ticket has this word swapped
+ ECC_SHA256 = 0x00010005, /* ECC sig 512 bits using SHA-256 */
+ HMAC_SHA1 = 0x00010006, /* HMAC-SHA1 160 bit signature */
+};
+
+static const size_t ES_ISSUER_SIZE = 64;
+
+ /**
+ * @class ESIssuer
+ * @brief The signature issuer ASCII encoded certificate hierarchy. Padded with nulls.
+ *
+ * Examples:
+ * Root (issued by Root)
+ * Root-CAxxxxxxxx (issued by Certifcate Authority server xxxxxxxx)
+ * Root-CAxxxxxxxx-XSxxxxxxxx (issued by Ticket/Transaction server xxxxxxxx)
+ * Root-CAxxxxxxxx-CPxxxxxxxx (issued by Content Publishing server xxxxxxxx)
+ * Root-CAxxxxxxxx-MSxxxxxxxx (issued by Manufacturing server xxxxxxxx)
+ * Root-CAxxxxxxxx-MSxxxxxxxx-YYxxxxxxxx (issued by Device with of type YY and serial number xxxxxxxx)
+ *
+ * xxxxxxxx represents the server/device serial number encoded in hex. (e.g. XS0000000f is ticket server 15).
+ */
+using ESIssuer = tc::bn::string;
+
+template
+using ESSigPad = tc::bn::pad<_size>;
+
+/* pack to 4 byte boundaries */
+#pragma pack(push,4)
+
+struct ESSigRsa2048
+{
+ tc::bn::be32 sigType;
+ Rsa2048Sig sig;
+ ESSigPad<60> pad;
+ ESIssuer issuer;
+};
+static_assert(sizeof(ESSigRsa2048) == 384, "ESSigRsa2048 size");
+
+struct ESSigRsa4096
+{
+ tc::bn::be32 sigType;
+ Rsa4096Sig sig;
+ ESSigPad<60> pad;
+ ESIssuer issuer;
+};
+static_assert(sizeof(ESSigRsa4096) == 640, "ESSigRsa4096 size");
+
+struct ESSigEcc233
+{
+ tc::bn::be32 sigType;
+ Ecc233Sig sig;
+ ESSigPad<64> pad;
+ ESIssuer issuer;
+};
+static_assert(sizeof(ESSigEcc233) == 192, "ESSigEcc233 size");
+
+#pragma pack(pop)
+
+}} // namespace brd::es
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_ticket.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_ticket.h
new file mode 100644
index 0000000..e9a38fe
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_ticket.h
@@ -0,0 +1,232 @@
+#pragma once
+#include
+
+namespace brd { namespace es {
+
+// ES license types
+enum class ESLicenseType : uint8_t
+{
+ PERMANENT = 0,
+ DEMO = 1,
+ TRIAL = 2,
+ RENTAL = 3,
+ SUBSCRIPTION = 4,
+ SERVICE = 5,
+};
+static const uint8_t ES_LICENSE_MASK = 0xf;
+
+// ES title-level limit codes
+enum class ESLimitCode : uint32_t
+{
+ DURATION_TIME = 1,
+ ABSOLUTE_TIME = 2,
+ NUM_TITLES = 3,
+ NUM_LAUNCH = 4,
+ ELAPSED_TIME = 5,
+};
+static const uint32_t ES_MAX_LIMIT_TYPE = 8;
+
+// ES item-level rights
+enum class ESItemType : uint32_t
+{
+ PERMANENT = 1,
+ SUBSCRIPTION = 2,
+ CONTENT = 3,
+ CONTENT_CONSUMPTION = 4,
+ ACCESS_TITLE = 5,
+ LIMITED_RESOURCE = 6,
+};
+
+enum class ESPropertyMaskFlag : uint16_t
+{
+ PRE_INSTALL = 0x1, // bit0
+ SHARED_TITLE = 0x2, // bit1
+ ALLOW_ALL_CONTENT = 0x4, // bit2
+ DEVICE_LINK_INDEPENDENT = 0x8, // bit3
+ VOLATILE = 0x10, // bit4
+ ELICENSE_REQUIRED = 0x20, // bit5
+};
+
+enum class ESV1SectionHeaderFlag : uint16_t
+{
+ COMPRESSED = 0x1 // ironically this is defined but not supported, probably for future use
+};
+
+enum class ESV2TitleKekType : byte_t
+{
+ AES128_CBC,
+ RSA2048
+};
+
+#pragma pack(push, 4)
+
+#ifdef _WIN32
+#pragma warning(disable : 4200) // silence warnings for usage of empty arrays in stucts
+#endif
+
+struct ESLimitedPlayEntry
+{
+ tc::bn::be32 code; //ESLimitCode
+ tc::bn::be32 limit;
+};
+static_assert(sizeof(ESLimitedPlayEntry) == 8, "ESLimitedPlayEntry size");
+
+using ESSysAccessMask = std::array;
+using ESTicketCustomData = std::array;
+using ESTicketReserved = std::array;
+using ESCidxMask = std::array;
+using ESLimitedPlayArray = std::array;
+
+using ESReferenceId = std::array;
+
+using ESV1CidxMask = std::array;
+
+using ESV2TitleKey = std::array;
+using ESRightsId = std::array;
+using ESV2TicketReserved = std::array;
+
+struct ESTicket
+{
+ ESSigRsa2048 sig; // RSA 2048-bit sign of the ticket
+ Ecc233PublicKey serverPubKey; // Ticketing server public key
+ uint8_t version; // Ticket data structure version number
+ uint8_t caCrlVersion; // CA CRL version number
+ uint8_t signerCrlVersion; // Signer CRL version number
+ Aes128Key titleKey; // Published title key
+ /* 1 byte alignment padding */
+ tc::bn::be64 ticketId; // Unique 64bit ticket ID
+ tc::bn::be32 deviceId; // Unique 32bit device ID
+ tc::bn::be64 titleId; // Unique 64bit title ID
+ ESSysAccessMask sysAccessMask; // 16-bit cidx mask to indicate which
+ // of the first 16 pieces of contents
+ // can be accessed by the system app
+ tc::bn::be16 ticketVersion; // 16-bit ticket version
+ tc::bn::be32 accessTitleId; // 32-bit title ID for access control
+ tc::bn::be32 accessTitleMask; // 32-bit title ID mask
+ uint8_t licenseType; //
+ uint8_t keyId; // Common key ID
+ tc::bn::be16 propertyMask; // 16-bit property mask
+ ESTicketCustomData customData; // 20-byte custom data
+ ESTicketReserved reserved; // 25-byte reserved info
+ uint8_t audit; //
+ /* 2 bytes alignment padding */
+ ESCidxMask cidxMask; // Bit-mask of the content indices
+ ESLimitedPlayArray limits; // Limited play entries
+};
+static_assert(sizeof(ESTicket) == 676, "ESTicket size");
+
+struct ESV1TicketHeader
+{
+ tc::bn::be16 hdrVersion; // Version of the ticket header
+ tc::bn::be16 hdrSize; // Size of ticket header
+ tc::bn::be32 ticketSize; // Size of the v1 portion of the ticket
+ tc::bn::be32 sectHdrOfst; // Offset of the section header table
+ tc::bn::be16 nSectHdrs; // Number of section headers
+ tc::bn::be16 sectHdrEntrySize; // Size of each section header
+ tc::bn::be32 flags; // Miscellaneous attributes
+};
+static_assert(sizeof(ESV1TicketHeader) == 20, "ESV1TicketHeader size");
+
+struct ESV1SectionHeader
+{
+ tc::bn::be32 sectOfst; // Offset of this section
+ tc::bn::be32 nRecords; // Number of records in this section
+ tc::bn::be32 recordSize; // Size of each record
+ tc::bn::be32 sectionSize; // Total size of this section
+ tc::bn::be16 sectionType; // Type code of this section
+ tc::bn::be16 flags; // Miscellaneous attributes
+};
+static_assert(sizeof(ESV1SectionHeader) == 20, "ESV1SectionHeader size");
+
+struct ESV1Ticket
+{
+ ESTicket head;
+ ESV1TicketHeader v1Head;
+ ESV1SectionHeader sectHdrs[];
+};
+static_assert(sizeof(ESV1Ticket) == 696, "ESV1Ticket size");
+
+struct ESV1PermanentRecord
+{
+ ESReferenceId referenceId; // Reference ID
+ tc::bn::be32 referenceIdAttr; // Reference ID attributes
+};
+static_assert(sizeof(ESV1PermanentRecord) == 20, "ESV1PermanentRecord size");
+
+struct ESV1SubscriptionRecord
+{
+ tc::bn::be32 limit; // Expiration time
+ ESReferenceId referenceId; // Reference ID
+ tc::bn::be32 referenceIdAttr; // Reference ID attributes
+};
+static_assert(sizeof(ESV1SubscriptionRecord) == 24, "ESV1SubscriptionRecord size");
+
+struct ESV1ContentRecord
+{
+ tc::bn::be32 offset; // Offset content index
+ ESV1CidxMask accessMask; // Access mask
+};
+static_assert(sizeof(ESV1ContentRecord) == 132, "ESV1ContentRecord size");
+
+struct ESV1ContentConsumptionRecord
+{
+ tc::bn::be16 index; // Content index
+ tc::bn::be16 code; // Limit code
+ tc::bn::be32 limit; // Limit value
+};
+static_assert(sizeof(ESV1ContentConsumptionRecord) == 8, "ESV1ContentConsumptionRecord size");
+
+struct ESV1AccessTitleRecord
+{
+ tc::bn::be64 accessTitleId; // Access title ID
+ tc::bn::be64 accessTitleMask; // Access title mask
+};
+static_assert(sizeof(ESV1AccessTitleRecord) == 16, "ESV1AccessTitleRecord size");
+
+struct ESV1LimitedResourceRecord
+{
+ tc::bn::be32 limit; // Expiration time
+ ESReferenceId referenceId; // Reference ID
+ tc::bn::be32 referenceIdAttr; // Reference ID attributes
+};
+static_assert(sizeof(ESV1LimitedResourceRecord) == 24, "ESV1LimitedResourceRecord size");
+
+struct ESV2Ticket
+{
+ ESSigRsa2048 sig; // RSA 2048-bit sign of the ticket
+ ESV2TitleKey titleKey; // Published title key
+ uint8_t version; // Ticket data structure version number
+ uint8_t keyType; // Title key encryption key type
+ tc::bn::le16 ticketVersion; // 16-bit ticket version
+ uint8_t licenseType;
+ uint8_t keyId; // Common key ID
+ tc::bn::le16 propertyMask; // 16-bit property mask
+ ESV2TicketReserved reservedRegion; // probably the accessTitleId & mask
+ tc::bn::le64 ticketId; // Unique 64bit ticket ID
+ tc::bn::le64 deviceId; // Unique 64bit device ID
+ ESRightsId rightsId; // Unique 128bit rights ID
+ tc::bn::le32 accountId; // Unique 32bit account ID
+ tc::bn::le32 sectTotalSize; // Total size of sections
+ tc::bn::le32 sectHdrOffset; // Offset of the section header table
+ tc::bn::le16 nSectHdrs; // Number of section headers
+ tc::bn::le16 nSectHdrEntrySize; // Size of each section header
+};
+static_assert(sizeof(ESV2Ticket) == 704, "ESV2Ticket size");
+
+struct ESV2SectionHeader
+{
+ tc::bn::le32 sectOfst; // Offset of this section
+ tc::bn::le32 recordSize; // Size of each record
+ tc::bn::le32 sectionSize; // Total size of this section
+ tc::bn::le16 nRecords; // Number of records in this section
+ tc::bn::le16 sectionType; // Type code of this section
+};
+static_assert(sizeof(ESV2SectionHeader) == 16, "ESV2SectionHeader size");
+
+#ifdef _WIN32
+#pragma warning(default : 4200)
+#endif
+
+#pragma pack(pop)
+
+}} // namespace brd::es
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/es_tmd.h b/ctrtool/deps/libbroadon-es/include/brd/es/es_tmd.h
new file mode 100644
index 0000000..8bab843
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/include/brd/es/es_tmd.h
@@ -0,0 +1,129 @@
+#pragma once
+#include
+
+namespace brd { namespace es {
+
+// ES title type
+enum class ESTitleType : uint32_t
+{
+ NC_TITLE = 0x1, // bit0 NetCard - End-of-life
+ NG_TITLE = 0x2, // bit1 Wii/NDEV
+ DS_TITLE = 0x4, // bit2 TWL/DSi
+ DATA = 0x8, // bit3 boring data title
+ CT_TITLE = 0x40, // bit6 CTR/3DS
+ GVM_TITLE = 0x80, // bit7 GVM = ? (from BroadOn libraries)
+ CAFE_TITLE = 0x100, // bit8 WiiU (from WiiU sdk)
+};
+
+// ES content type
+enum ESContentType : uint16_t
+{
+ ESContentType_ENCRYPTED = 0x1, // bit0 (from broadOn & b4)
+ ESContentType_DISC = 0x2, // bit1 (from broadOn & b4)
+ ESContentType_HASHED = 0x2, // bit1 (from b4)
+ ESContentType_CFM = 0x4, // bit3 (from broadOn & b4)
+ ESContentType_SHA1_HASH = 0x2000, // bit13 from b4 (wiiu sdk)
+ ESContentType_OPTIONAL = 0x4000, // bit14 (from broadOn & b4)
+ ESContentType_SHARED = 0x8000, // bit15 (from broadOn & b4)
+};
+
+//
+// Maximum possible content index value is 64K - 2, since
+// the maximum number of contents per title is 64K - 1
+//
+static const size_t ES_CONTENT_INDEX_MAX = 65534;
+
+
+// There are a maximum of 64 CMD groups, each with a maximum of 1K CMDs
+static const size_t ES_MAX_CMDS_IN_GROUP = 1024;
+static const size_t ES_MAX_CMD_GROUPS = 64;
+
+#pragma pack(push, 4)
+
+#ifdef _WIN32
+#pragma warning(disable : 4200) // silence warnings for usage of empty arrays in stucts
+#endif
+
+struct ESContentMeta
+{
+ tc::bn::be32 cid; // 32-bit content ID
+ tc::bn::be16 index; // Content index, unique per title
+ tc::bn::be16 type; // Content type
+ tc::bn::be64 size; // Unencrypted content size in bytes
+ Sha1Hash hash; // Hash of the content
+};
+static_assert(sizeof(ESContentMeta) == 36, "ESContentMeta size");
+
+struct ESV1ContentMeta
+{
+ tc::bn::be32 cid; // 32-bit content ID
+ tc::bn::be16 index; // Content index, unique per title
+ tc::bn::be16 type; // Content type
+ tc::bn::be64 size; // Unencrypted content size in bytes
+ Sha256Hash hash; // Hash of the content
+};
+static_assert(sizeof(ESV1ContentMeta) == 48, "ESV1ContentMeta size");
+
+struct ESTitleMetaHeader
+{
+ using ESTmdCustomData = std::array;
+ using ESTmdReserved = std::array;
+
+ uint8_t version; // TMD version number
+ uint8_t caCrlVersion; // CA CRL version number
+ uint8_t signerCrlVersion; // Signer CRL version number
+ tc::bn::be64 sysVersion; // System software version number
+ tc::bn::be64 titleId; // 64-bit title id
+ tc::bn::be32 type; // 32-bit title type
+ tc::bn::be16 groupId;
+ ESTmdCustomData customData; // 32-byte custom data
+ ESTmdReserved reserved; // 30-byte reserved info
+ tc::bn::be32 accessRights; // Rights to system resources
+ tc::bn::be16 titleVersion; // 16-bit title version
+ tc::bn::be16 numContents; // Number of contents
+ tc::bn::be16 bootIndex; // Boot content index
+ tc::bn::be16 minorTitleVersion; // 16-bit minor title version
+};
+static_assert(sizeof(ESTitleMetaHeader) == 100, "ESTitleMetaHeader size");
+
+struct ESV1ContentMetaGroup
+{
+ tc::bn::be16 offset; // Offset content index
+ tc::bn::be16 nCmds; // Number of CMDs in this group
+ Sha256Hash groupHash; // Hash for this group of CMDs
+};
+static_assert(sizeof(ESV1ContentMetaGroup) == 36, "ESV1ContentMetaGroup size");
+
+struct ESV1TitleMetaHeader
+{
+ using ESV1ContentMetaGroupArray = std::array;
+
+ Sha256Hash hash; // Hash for the CMD groups
+ ESV1ContentMetaGroupArray cmdGroups;
+};
+static_assert(sizeof(ESV1TitleMetaHeader) == 2336, "ESV1TitleMetaHeader size");
+
+struct ESTitleMeta
+{
+ ESSigRsa2048 sig; // RSA 2048-bit sign of the TMD header
+ ESTitleMetaHeader head;
+ ESContentMeta contents[]; // CMD array sorted by content index
+};
+static_assert(sizeof(ESTitleMeta) == 484, "ESTitleMeta size");
+
+struct ESV1TitleMeta
+{
+ ESSigRsa2048 sig; // RSA 2048-bit sign of the TMD header
+ ESTitleMetaHeader head;
+ ESV1TitleMetaHeader v1Head; // Extension to the v0 TMD header
+ ESV1ContentMeta contents[]; // CMD array sorted by content index
+};
+static_assert(sizeof(ESV1TitleMeta) == 2820, "ESV1TitleMeta size");
+
+#ifdef _WIN32
+#pragma warning(default : 4200)
+#endif
+
+#pragma pack(pop)
+
+}} // namespace brd::es
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/include/brd/es/types.h b/ctrtool/deps/libbroadon-es/include/brd/es/types.h
new file mode 100644
index 0000000..2a94407
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/include/brd/es/types.h
@@ -0,0 +1,73 @@
+#pragma once
+#include
+
+namespace brd { namespace es {
+
+#pragma pack(push,4)
+
+static const size_t kAes128KeySize = 16;
+using Aes128Key = std::array;
+
+static const size_t kAes192KeySize = 24;
+using Aes192Key = std::array;
+
+static const size_t kAes256KeySize = 32;
+using Aes256Key = std::array;
+
+static const size_t kSha1Size = 20;
+using Sha1Hash = std::array;
+using Sha1Hmac = std::array;
+
+static const size_t kSha256Size = 32;
+using Sha256Hash = std::array;
+using Sha256Hmac = std::array;
+
+static const size_t kRsaPublicExponentSize = 4;
+using RsaPublicExponent = std::array;
+
+static const size_t kRsa2048Size = 0x100;
+using Rsa2048Integer = std::array;
+struct Rsa2048PublicKey
+{
+ Rsa2048Integer m; // modulus
+ RsaPublicExponent e; // public_exponent
+};
+struct Rsa2048PrivateKey
+{
+ Rsa2048Integer m; // modulus
+ Rsa2048Integer d; // private_exponent
+};
+using Rsa2048Sig = Rsa2048Integer;
+
+static const size_t kRsa4096Size = 0x200;
+using Rsa4096Integer = std::array;
+struct Rsa4096PublicKey
+{
+ Rsa4096Integer m; // modulus
+ RsaPublicExponent e; // public_exponent
+};
+struct Rsa4096PrivateKey
+{
+ Rsa4096Integer m; // modulus
+ Rsa4096Integer d; // private_exponent
+};
+using Rsa4096Sig = Rsa4096Integer;
+
+static const size_t kEcc233Size = 60;
+using Ecc233Integer = std::array;
+struct Ecc233Point
+{
+ Ecc233Integer x;
+ Ecc233Integer y;
+};
+using Ecc233PrivateKey = Ecc233Integer;
+using Ecc233PublicKey = Ecc233Point;
+struct Ecc233Sig
+{
+ Ecc233Integer r;
+ Ecc233Integer s;
+};
+
+#pragma pack(pop)
+
+}} // namespace brd::es
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/makefile b/ctrtool/deps/libbroadon-es/makefile
new file mode 100644
index 0000000..87521a4
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/makefile
@@ -0,0 +1,193 @@
+# C++/C Recursive Project Makefile
+# (c) Jack
+# Version 5
+
+# Project Name
+PROJECT_NAME = libbroadon-es
+
+# Project Relative Paths
+PROJECT_PATH = $(CURDIR)
+PROJECT_SRC_PATH = src
+PROJECT_SRC_SUBDIRS = $(PROJECT_SRC_PATH)
+PROJECT_INCLUDE_PATH = include
+#PROJECT_TESTSRC_PATH = test
+#PROJECT_TESTSRC_SUBDIRS = $(PROJECT_TESTSRC_PATH)
+PROJECT_BIN_PATH = bin
+#PROJECT_DOCS_PATH = docs
+#PROJECT_DOXYFILE_PATH = Doxyfile
+
+# Determine if the root makefile has been established, and if not establish this makefile as the root makefile
+ifeq ($(ROOT_PROJECT_NAME),)
+ export ROOT_PROJECT_NAME = $(PROJECT_NAME)
+ export ROOT_PROJECT_PATH = $(PROJECT_PATH)
+ export ROOT_PROJECT_DEPENDENCY_PATH = $(ROOT_PROJECT_PATH)/deps
+endif
+
+# Shared Library Definitions
+PROJECT_SO_VER_MAJOR = 0
+PROJECT_SO_VER_MINOR = 1
+PROJECT_SO_VER_PATCH = 0
+PROJECT_SONAME = $(PROJECT_NAME).so.$(PROJECT_SO_VER_MAJOR)
+PROJECT_SO_FILENAME = $(PROJECT_SONAME).$(PROJECT_SO_VER_MINOR).$(PROJECT_SO_VER_PATCH)
+
+# Project Dependencies
+PROJECT_DEPEND = mbedtls toolchain
+PROJECT_DEPEND_LOCAL_DIR = libmbedtls libtoolchain
+
+# Generate compiler flags for including project include path
+ifneq ($(PROJECT_INCLUDE_PATH),)
+ INC += -I"$(PROJECT_INCLUDE_PATH)"
+endif
+
+# Generate compiler flags for local included dependencies
+ifneq ($(PROJECT_DEPEND_LOCAL_DIR),)
+ LIB += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -L"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/bin")
+ INC += $(foreach dep,$(PROJECT_DEPEND_LOCAL_DIR), -I"$(ROOT_PROJECT_DEPENDENCY_PATH)/$(dep)/include")
+endif
+
+# Generate compiler flags for external dependencies
+ifneq ($(PROJECT_DEPEND),)
+ LIB += $(foreach dep,$(PROJECT_DEPEND), -l$(dep))
+endif
+
+# Detect Platform
+ifeq ($(PROJECT_PLATFORM),)
+ ifeq ($(OS), Windows_NT)
+ export PROJECT_PLATFORM = WIN32
+ else
+ UNAME = $(shell uname -s)
+ ifeq ($(UNAME), Darwin)
+ export PROJECT_PLATFORM = MACOS
+ else
+ export PROJECT_PLATFORM = GNU
+ endif
+ endif
+endif
+
+# Detect Architecture
+ifeq ($(PROJECT_PLATFORM_ARCH),)
+ ifeq ($(PROJECT_PLATFORM), WIN32)
+ export PROJECT_PLATFORM_ARCH = x86_64
+ else ifeq ($(PROJECT_PLATFORM), GNU)
+ export PROJECT_PLATFORM_ARCH = $(shell uname -m)
+ else ifeq ($(PROJECT_PLATFORM), MACOS)
+ export PROJECT_PLATFORM_ARCH = $(shell uname -m)
+ else
+ export PROJECT_PLATFORM_ARCH = x86_64
+ endif
+endif
+
+# Generate platform specific compiler flags
+ifeq ($(PROJECT_PLATFORM), WIN32)
+ # Windows Flags/Libs
+ CC = x86_64-w64-mingw32-gcc
+ CXX = x86_64-w64-mingw32-g++
+ WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-but-set-variable
+ ARCHFLAGS =
+ INC +=
+ LIB += -static
+ ARFLAGS = cr -o
+else ifeq ($(PROJECT_PLATFORM), GNU)
+ # GNU/Linux Flags/Libs
+ #CC =
+ #CXX =
+ WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-but-set-variable
+ ARCHFLAGS =
+ INC +=
+ LIB +=
+ ARFLAGS = cr -o
+else ifeq ($(PROJECT_PLATFORM), MACOS)
+ # MacOS Flags/Libs
+ #CC =
+ #CXX =
+ WARNFLAGS = -Wall -Wno-unused-value -Wno-unused-private-field
+ ARCHFLAGS = -arch $(PROJECT_PLATFORM_ARCH)
+ INC +=
+ LIB +=
+ ARFLAGS = rc
+endif
+
+# Compiler Flags
+CXXFLAGS = -std=c++11 $(INC) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
+CFLAGS = -std=c11 $(INC) $(WARNFLAGS) $(ARCHFLAGS) -fPIC
+
+# Object Files
+SRC_OBJ = $(foreach dir,$(PROJECT_SRC_SUBDIRS),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(PROJECT_SRC_SUBDIRS),$(subst .c,.o,$(wildcard $(dir)/*.c)))
+TESTSRC_OBJ = $(foreach dir,$(PROJECT_TESTSRC_SUBDIRS),$(subst .cpp,.o,$(wildcard $(dir)/*.cpp))) $(foreach dir,$(PROJECT_TESTSRC_SUBDIRS),$(subst .c,.o,$(wildcard $(dir)/*.c)))
+
+# all is the default, user should specify what the default should do
+# - 'static_lib' for building static library
+# - 'shared_lib' for building shared library
+# - 'program' for building the program
+# - 'test_program' for building the test program
+# These can typically be used together however *_lib and program should not be used together
+all: static_lib
+
+clean: clean_object_files remove_binary_dir
+
+# Object Compile Rules
+%.o: %.c
+ @echo CC $<
+ @$(CC) $(CFLAGS) -c $< -o $@
+
+%.o: %.cpp
+ @echo CXX $<
+ @$(CXX) $(CXXFLAGS) -c $< -o $@
+
+# Binary Directory
+.PHONY: create_binary_dir
+create_binary_dir:
+ @mkdir -p "$(PROJECT_BIN_PATH)"
+
+.PHONY: remove_binary_dir
+remove_binary_dir:
+ifneq ($(PROJECT_BIN_PATH),)
+ @rm -rf "$(PROJECT_BIN_PATH)"
+endif
+
+.PHONY: clean_object_files
+clean_object_files:
+ @rm -f $(SRC_OBJ) $(TESTSRC_OBJ)
+
+# Build Library
+static_lib: $(SRC_OBJ) create_binary_dir
+ @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME).a
+ @ar $(ARFLAGS) "$(PROJECT_BIN_PATH)/$(PROJECT_NAME).a" $(SRC_OBJ)
+
+shared_lib: $(SRC_OBJ) create_binary_dir
+ @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_SO_FILENAME)
+ @gcc -shared -Wl,-soname,$(PROJECT_SONAME) -o "$(PROJECT_BIN_PATH)/$(PROJECT_SO_FILENAME)" $(SRC_OBJ)
+
+# Build Program
+program: $(SRC_OBJ) create_binary_dir
+ @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME)
+ @$(CXX) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)"
+
+# Build Test Program
+test_program: $(TESTSRC_OBJ) $(SRC_OBJ) create_binary_dir
+ifneq ($(PROJECT_TESTSRC_PATH),)
+ @echo LINK $(PROJECT_BIN_PATH)/$(PROJECT_NAME)_test
+ @$(CXX) $(TESTSRC_OBJ) $(SRC_OBJ) $(LIB) -o "$(PROJECT_BIN_PATH)/$(PROJECT_NAME)_test"
+endif
+
+# Documentation
+.PHONY: docs
+docs:
+ifneq ($(PROJECT_DOCS_PATH),)
+ doxygen "$(PROJECT_DOXYFILE_PATH)"
+endif
+
+.PHONY: clean_docs
+clean_docs:
+ifneq ($(PROJECT_DOCS_PATH),)
+ @rm -rf "$(PROJECT_DOCS_PATH)"
+endif
+
+# Dependencies
+.PHONY: deps
+deps:
+ @$(foreach lib,$(PROJECT_DEPEND_LOCAL_DIR), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/$(lib)" && $(MAKE) static_lib && cd "$(PROJECT_PATH)";)
+
+.PHONY: clean_deps
+clean_deps:
+ @$(foreach lib,$(PROJECT_DEPEND_LOCAL_DIR), cd "$(ROOT_PROJECT_DEPENDENCY_PATH)/$(lib)" && $(MAKE) clean && cd "$(PROJECT_PATH)";)
\ No newline at end of file
diff --git a/ctrtool/deps/libbroadon-es/src/Dummy.cpp b/ctrtool/deps/libbroadon-es/src/Dummy.cpp
new file mode 100644
index 0000000..0e29ff2
--- /dev/null
+++ b/ctrtool/deps/libbroadon-es/src/Dummy.cpp
@@ -0,0 +1,138 @@
+#include
+#include
+
+#ifdef _WIN32
+#pragma warning(disable : 4101) // silence warnings for unused local variables
+#endif
+
+namespace brd {
+ namespace es {
+
+ int dummy_method1a()
+ {
+ // types
+ brd::es::Aes128Key Aes128Key_var;
+ brd::es::Aes192Key Aes192Key_var;
+ brd::es::Aes256Key Aes256Key_var;
+ brd::es::Sha1Hash Sha1Hash_var;
+ brd::es::Sha1Hmac Sha1Hmac_var;
+ brd::es::Sha256Hash Sha256Hash_var;
+ brd::es::Sha256Hmac Sha256Hmac_var;
+ brd::es::RsaPublicExponent RsaPublicExponent_var;
+ brd::es::Rsa2048Integer Rsa2048Integer_var;
+ brd::es::Rsa2048PublicKey Rsa2048PublicKey_var;
+ brd::es::Rsa2048PrivateKey Rsa2048PrivateKey_var;
+ brd::es::Rsa2048Sig Rsa2048Sig_var;
+ return 11;
+ }
+
+ int dummy_method1b()
+ {
+ // types
+ brd::es::Rsa4096Integer Rsa4096Integer_var;
+ brd::es::Rsa4096PublicKey Rsa4096PublicKey_var;
+ brd::es::Rsa4096PrivateKey Rsa4096PrivateKey_var;
+ brd::es::Rsa4096Sig Rsa4096Sig_var;
+ brd::es::Ecc233Integer Ecc233Integer_var;
+ brd::es::Ecc233Point Ecc233Point_var;
+ brd::es::Ecc233PrivateKey Ecc233PrivateKey_var;
+ brd::es::Ecc233PublicKey Ecc233PublicKey_var;
+ brd::es::Ecc233Sig Ecc233Sig_var;
+
+ return 01323;
+ }
+
+ int dummy_method2()
+ {
+ // sign
+ brd::es::ESSigType ESSigType_var;
+ size_t ES_ISSUER_SIZE_var = brd::es::ES_ISSUER_SIZE;
+ brd::es::ESIssuer ESIssuer_var;
+ brd::es::ESSigRsa2048 ESSigRsa2048_struct;
+ brd::es::ESSigRsa4096 ESSigRsa4096_struct;
+ brd::es::ESSigEcc233 ESSigEcc233_struct;
+
+ return 1232;
+ }
+
+ int dummy_method3()
+ {
+ // cert
+ brd::es::ESCertPubKeyType ESCertPubKeyType_var;
+ size_t ES_CERT_NAME_SIZE_var = brd::es::ES_CERT_NAME_SIZE;
+ brd::es::ESCertName ESCertName_var;
+ brd::es::ESServerId ESServerId_var;
+ brd::es::ESDeviceId ESDeviceId_var;
+ brd::es::ESCertHeader ESCertHeader_struct;
+ brd::es::ESCertRsa2048PublicKey ESCertRsa2048PublicKey_struct;
+ brd::es::ESCertRsa4096PublicKey ESCertRsa4096PublicKey_struct;
+ brd::es::ESCertEcc233PublicKey ESCertEcc233PublicKey_struct;
+ brd::es::ESRootCert ESRootCert_struct;
+ brd::es::ESCACert ESCACert_struct;
+ brd::es::ESCASignedCert ESCASignedCert_struct;
+ brd::es::ESDeviceCert ESDeviceCert_struct;
+ brd::es::ESDeviceSignedCert ESDeviceSignedCert_struct;
+
+ return 55;
+ }
+
+ int dummy_method4()
+ {
+ // tik
+ brd::es::ESLicenseType ESLicenseType_var;
+ uint8_t ES_LICENSE_MASK_var = brd::es::ES_LICENSE_MASK;
+ brd::es::ESLimitCode ESLimitCode_var;
+ uint32_t ES_MAX_LIMIT_TYPE_var = brd::es::ES_MAX_LIMIT_TYPE;
+ brd::es::ESItemType ESItemType_var;
+ brd::es::ESPropertyMaskFlag ESPropertyMaskFlag_var;
+ brd::es::ESV1SectionHeaderFlag ESV1SectionHeaderFlag_var;
+ brd::es::ESV2TitleKekType ESV2TitleKekType_var;
+ brd::es::ESLimitedPlayEntry ESLimitedPlayEntry_struct;
+ brd::es::ESSysAccessMask ESSysAccessMask_var;
+ brd::es::ESTicketCustomData ESTicketCustomData_var;
+ brd::es::ESTicketReserved ESTicketReserved_var;
+ brd::es::ESCidxMask ESCidxMask_var;
+ brd::es::ESLimitedPlayArray ESLimitedPlayArray_var;
+ brd::es::ESReferenceId ESReferenceId_var;
+ brd::es::ESV1CidxMask ESV1CidxMask_var;
+ brd::es::ESV2TitleKey ESV2TitleKey_var;
+ brd::es::ESRightsId ESRightsId_var;
+ brd::es::ESV2TicketReserved ESV2TicketReserved_var;
+ brd::es::ESTicket ESTicket_struct;
+ brd::es::ESV1TicketHeader ESV1TicketHeader_struct;
+ brd::es::ESV1SectionHeader ESV1SectionHeader_struct;
+ brd::es::ESV1Ticket ESV1Ticket_struct;
+ brd::es::ESV1PermanentRecord ESV1PermanentRecord_struct;
+ brd::es::ESV1SubscriptionRecord ESV1SubscriptionRecord_struct;
+ brd::es::ESV1ContentRecord ESV1ContentRecord_struct;
+ brd::es::ESV1ContentConsumptionRecord ESV1ContentConsumptionRecord_struct;
+ brd::es::ESV1AccessTitleRecord ESV1AccessTitleRecord_struct;
+ brd::es::ESV1LimitedResourceRecord ESV1LimitedResourceRecord_struct;
+ brd::es::ESV2Ticket ESV2Ticket_struct;
+ brd::es::ESV2SectionHeader ESV2SectionHeader_struct;
+
+ return 0;
+ }
+
+ int dummy_method5()
+ {
+ // tmd
+ brd::es::ESTitleType ESTitleType_var;
+ brd::es::ESContentType ESContentType_var;
+ size_t ES_CONTENT_INDEX_MAX_var = brd::es::ES_CONTENT_INDEX_MAX;
+ size_t ES_MAX_CMDS_IN_GROUP_var = brd::es::ES_MAX_CMDS_IN_GROUP;
+ brd::es::ESContentMeta ESContentMeta_struct;
+ brd::es::ESV1ContentMeta ESV1ContentMeta_struct;
+ brd::es::ESTitleMetaHeader ESTitleMetaHeader_struct;
+ brd::es::ESV1ContentMetaGroup ESV1ContentMetaGroup_struct;
+ brd::es::ESV1TitleMetaHeader ESV1TitleMetaHeader_struct;
+ brd::es::ESTitleMeta ESTitleMeta_struct;
+ brd::es::ESV1TitleMeta ESV1TitleMeta_struct;
+ return 54;
+ }
+
+ }
+}
+#ifdef _WIN32
+#pragma warning(default : 4101)
+#endif
\ No newline at end of file
diff --git a/ctrtool/deps/libfmt/LICENSE.rst b/ctrtool/deps/libfmt/LICENSE.rst
new file mode 100644
index 0000000..8f92168
--- /dev/null
+++ b/ctrtool/deps/libfmt/LICENSE.rst
@@ -0,0 +1,27 @@
+Copyright (c) 2012 - present, Victor Zverovich
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+--- Optional exception to the license ---
+
+As an exception, if, as a result of your compiling your source code, portions
+of this Software are embedded into a machine-executable object form of such
+source code, you may redistribute such embedded portions in such object form
+without including the above copyright and permission notices.
\ No newline at end of file
diff --git a/ctrtool/deps/libfmt/README.md b/ctrtool/deps/libfmt/README.md
new file mode 100644
index 0000000..ce8069f
--- /dev/null
+++ b/ctrtool/deps/libfmt/README.md
@@ -0,0 +1,2 @@
+# libfmt
+Clone of {fmt} (https://github.com/fmtlib/fmt)
diff --git a/ctrtool/deps/libfmt/build/visualstudio/libfmt.sln b/ctrtool/deps/libfmt/build/visualstudio/libfmt.sln
new file mode 100644
index 0000000..368aee4
--- /dev/null
+++ b/ctrtool/deps/libfmt/build/visualstudio/libfmt.sln
@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31229.75
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libfmt", "libfmt\libfmt.vcxproj", "{F4B0540E-0AAE-4006-944B-356944EF61FA}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.ActiveCfg = Debug|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x64.Build.0 = Debug|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.ActiveCfg = Debug|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Debug|x86.Build.0 = Debug|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.ActiveCfg = Release|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x64.Build.0 = Release|x64
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.ActiveCfg = Release|Win32
+ {F4B0540E-0AAE-4006-944B-356944EF61FA}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {EA4E4F87-6367-4723-8641-6767757CD6DD}
+ EndGlobalSection
+EndGlobal
diff --git a/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj
new file mode 100644
index 0000000..61a5ca3
--- /dev/null
+++ b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj
@@ -0,0 +1,171 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+ 16.0
+ Win32Proj
+ {f4b0540e-0aae-4006-944b-356944ef61fa}
+ libfmt
+ 10.0
+
+
+
+ StaticLibrary
+ true
+ v142
+ Unicode
+
+
+ StaticLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v142
+ Unicode
+
+
+ StaticLibrary
+ false
+ v142
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+ false
+
+
+ true
+
+
+ false
+
+
+
+ Level3
+ true
+ WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+ $(ProjectDir)..\..\..\include
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ $(ProjectDir)..\..\..\include
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+ Level3
+ true
+ _DEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+ $(ProjectDir)..\..\..\include
+
+
+ Console
+ true
+
+
+
+
+ Level3
+ true
+ true
+ true
+ NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ $(ProjectDir)..\..\..\include
+
+
+ Console
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj.filters b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj.filters
new file mode 100644
index 0000000..61b8ad1
--- /dev/null
+++ b/ctrtool/deps/libfmt/build/visualstudio/libfmt/libfmt.vcxproj.filters
@@ -0,0 +1,66 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd
+
+
+ {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
+ rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
+
+
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/ctrtool/deps/libfmt/include/fmt/args.h b/ctrtool/deps/libfmt/include/fmt/args.h
new file mode 100644
index 0000000..9a8e4ed
--- /dev/null
+++ b/ctrtool/deps/libfmt/include/fmt/args.h
@@ -0,0 +1,234 @@
+// Formatting library for C++ - dynamic format arguments
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_ARGS_H_
+#define FMT_ARGS_H_
+
+#include // std::reference_wrapper
+#include // std::unique_ptr
+#include
+
+#include "core.h"
+
+FMT_BEGIN_NAMESPACE
+
+namespace detail {
+
+template struct is_reference_wrapper : std::false_type {};
+template
+struct is_reference_wrapper> : std::true_type {};
+
+template const T& unwrap(const T& v) { return v; }
+template const T& unwrap(const std::reference_wrapper& v) {
+ return static_cast(v);
+}
+
+class dynamic_arg_list {
+ // Workaround for clang's -Wweak-vtables. Unlike for regular classes, for
+ // templates it doesn't complain about inability to deduce single translation
+ // unit for placing vtable. So storage_node_base is made a fake template.
+ template struct node {
+ virtual ~node() = default;
+ std::unique_ptr> next;
+ };
+
+ template struct typed_node : node<> {
+ T value;
+
+ template
+ FMT_CONSTEXPR typed_node(const Arg& arg) : value(arg) {}
+
+ template
+ FMT_CONSTEXPR typed_node(const basic_string_view& arg)
+ : value(arg.data(), arg.size()) {}
+ };
+
+ std::unique_ptr> head_;
+
+ public:
+ template const T& push(const Arg& arg) {
+ auto new_node = std::unique_ptr>(new typed_node(arg));
+ auto& value = new_node->value;
+ new_node->next = std::move(head_);
+ head_ = std::move(new_node);
+ return value;
+ }
+};
+} // namespace detail
+
+/**
+ \rst
+ A dynamic version of `fmt::format_arg_store`.
+ It's equipped with a storage to potentially temporary objects which lifetimes
+ could be shorter than the format arguments object.
+
+ It can be implicitly converted into `~fmt::basic_format_args` for passing
+ into type-erased formatting functions such as `~fmt::vformat`.
+ \endrst
+ */
+template
+class dynamic_format_arg_store
+#if FMT_GCC_VERSION && FMT_GCC_VERSION < 409
+ // Workaround a GCC template argument substitution bug.
+ : public basic_format_args
+#endif
+{
+ private:
+ using char_type = typename Context::char_type;
+
+ template struct need_copy {
+ static constexpr detail::type mapped_type =
+ detail::mapped_type_constant::value;
+
+ enum {
+ value = !(detail::is_reference_wrapper::value ||
+ std::is_same>::value ||
+ std::is_same>::value ||
+ (mapped_type != detail::type::cstring_type &&
+ mapped_type != detail::type::string_type &&
+ mapped_type != detail::type::custom_type))
+ };
+ };
+
+ template
+ using stored_type = conditional_t::value &&
+ !has_formatter::value &&
+ !detail::is_reference_wrapper::value,
+ std::basic_string, T>;
+
+ // Storage of basic_format_arg must be contiguous.
+ std::vector> data_;
+ std::vector> named_info_;
+
+ // Storage of arguments not fitting into basic_format_arg must grow
+ // without relocation because items in data_ refer to it.
+ detail::dynamic_arg_list dynamic_args_;
+
+ friend class basic_format_args;
+
+ unsigned long long get_types() const {
+ return detail::is_unpacked_bit | data_.size() |
+ (named_info_.empty()
+ ? 0ULL
+ : static_cast(detail::has_named_args_bit));
+ }
+
+ const basic_format_arg* data() const {
+ return named_info_.empty() ? data_.data() : data_.data() + 1;
+ }
+
+ template void emplace_arg(const T& arg) {
+ data_.emplace_back(detail::make_arg(arg));
+ }
+
+ template
+ void emplace_arg(const detail::named_arg& arg) {
+ if (named_info_.empty()) {
+ constexpr const detail::named_arg_info* zero_ptr{nullptr};
+ data_.insert(data_.begin(), {zero_ptr, 0});
+ }
+ data_.emplace_back(detail::make_arg(detail::unwrap(arg.value)));
+ auto pop_one = [](std::vector>* data) {
+ data->pop_back();
+ };
+ std::unique_ptr>, decltype(pop_one)>
+ guard{&data_, pop_one};
+ named_info_.push_back({arg.name, static_cast(data_.size() - 2u)});
+ data_[0].value_.named_args = {named_info_.data(), named_info_.size()};
+ guard.release();
+ }
+
+ public:
+ constexpr dynamic_format_arg_store() = default;
+
+ /**
+ \rst
+ Adds an argument into the dynamic store for later passing to a formatting
+ function.
+
+ Note that custom types and string types (but not string views) are copied
+ into the store dynamically allocating memory if necessary.
+
+ **Example**::
+
+ fmt::dynamic_format_arg_store store;
+ store.push_back(42);
+ store.push_back("abc");
+ store.push_back(1.5f);
+ std::string result = fmt::vformat("{} and {} and {}", store);
+ \endrst
+ */
+ template void push_back(const T& arg) {
+ if (detail::const_check(need_copy::value))
+ emplace_arg(dynamic_args_.push>(arg));
+ else
+ emplace_arg(detail::unwrap(arg));
+ }
+
+ /**
+ \rst
+ Adds a reference to the argument into the dynamic store for later passing to
+ a formatting function.
+
+ **Example**::
+
+ fmt::dynamic_format_arg_store store;
+ char band[] = "Rolling Stones";
+ store.push_back(std::cref(band));
+ band[9] = 'c'; // Changing str affects the output.
+ std::string result = fmt::vformat("{}", store);
+ // result == "Rolling Scones"
+ \endrst
+ */
+ template void push_back(std::reference_wrapper arg) {
+ static_assert(
+ need_copy::value,
+ "objects of built-in types and string views are always copied");
+ emplace_arg(arg.get());
+ }
+
+ /**
+ Adds named argument into the dynamic store for later passing to a formatting
+ function. ``std::reference_wrapper`` is supported to avoid copying of the
+ argument. The name is always copied into the store.
+ */
+ template
+ void push_back(const detail::named_arg& arg) {
+ const char_type* arg_name =
+ dynamic_args_.push>(arg.name).c_str();
+ if (detail::const_check(need_copy::value)) {
+ emplace_arg(
+ fmt::arg(arg_name, dynamic_args_.push>(arg.value)));
+ } else {
+ emplace_arg(fmt::arg(arg_name, arg.value));
+ }
+ }
+
+ /** Erase all elements from the store */
+ void clear() {
+ data_.clear();
+ named_info_.clear();
+ dynamic_args_ = detail::dynamic_arg_list();
+ }
+
+ /**
+ \rst
+ Reserves space to store at least *new_cap* arguments including
+ *new_cap_named* named arguments.
+ \endrst
+ */
+ void reserve(size_t new_cap, size_t new_cap_named) {
+ FMT_ASSERT(new_cap >= new_cap_named,
+ "Set of arguments includes set of named arguments");
+ data_.reserve(new_cap);
+ named_info_.reserve(new_cap_named);
+ }
+};
+
+FMT_END_NAMESPACE
+
+#endif // FMT_ARGS_H_
diff --git a/ctrtool/deps/libfmt/include/fmt/chrono.h b/ctrtool/deps/libfmt/include/fmt/chrono.h
new file mode 100644
index 0000000..682efd8
--- /dev/null
+++ b/ctrtool/deps/libfmt/include/fmt/chrono.h
@@ -0,0 +1,2067 @@
+// Formatting library for C++ - chrono support
+//
+// Copyright (c) 2012 - present, Victor Zverovich
+// All rights reserved.
+//
+// For the license information refer to format.h.
+
+#ifndef FMT_CHRONO_H_
+#define FMT_CHRONO_H_
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "format.h"
+
+FMT_BEGIN_NAMESPACE
+
+// Enable tzset.
+#ifndef FMT_USE_TZSET
+// UWP doesn't provide _tzset.
+# if FMT_HAS_INCLUDE("winapifamily.h")
+# include
+# endif
+# if defined(_WIN32) && (!defined(WINAPI_FAMILY) || \
+ (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP))
+# define FMT_USE_TZSET 1
+# else
+# define FMT_USE_TZSET 0
+# endif
+#endif
+
+// Enable safe chrono durations, unless explicitly disabled.
+#ifndef FMT_SAFE_DURATION_CAST
+# define FMT_SAFE_DURATION_CAST 1
+#endif
+#if FMT_SAFE_DURATION_CAST
+
+// For conversion between std::chrono::durations without undefined
+// behaviour or erroneous results.
+// This is a stripped down version of duration_cast, for inclusion in fmt.
+// See https://github.com/pauldreik/safe_duration_cast
+//
+// Copyright Paul Dreik 2019
+namespace safe_duration_cast {
+
+template ::value &&
+ std::numeric_limits::is_signed ==
+ std::numeric_limits::is_signed)>
+FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
+ ec = 0;
+ using F = std::numeric_limits;
+ using T = std::numeric_limits;
+ static_assert(F::is_integer, "From must be integral");
+ static_assert(T::is_integer, "To must be integral");
+
+ // A and B are both signed, or both unsigned.
+ if (detail::const_check(F::digits <= T::digits)) {
+ // From fits in To without any problem.
+ } else {
+ // From does not always fit in To, resort to a dynamic check.
+ if (from < (T::min)() || from > (T::max)()) {
+ // outside range.
+ ec = 1;
+ return {};
+ }
+ }
+ return static_cast(from);
+}
+
+/**
+ * converts From to To, without loss. If the dynamic value of from
+ * can't be converted to To without loss, ec is set.
+ */
+template ::value &&
+ std::numeric_limits::is_signed !=
+ std::numeric_limits::is_signed)>
+FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
+ ec = 0;
+ using F = std::numeric_limits;
+ using T = std::numeric_limits;
+ static_assert(F::is_integer, "From must be integral");
+ static_assert(T::is_integer, "To must be integral");
+
+ if (detail::const_check(F::is_signed && !T::is_signed)) {
+ // From may be negative, not allowed!
+ if (fmt::detail::is_negative(from)) {
+ ec = 1;
+ return {};
+ }
+ // From is positive. Can it always fit in To?
+ if (detail::const_check(F::digits > T::digits) &&
+ from > static_cast(detail::max_value())) {
+ ec = 1;
+ return {};
+ }
+ }
+
+ if (detail::const_check(!F::is_signed && T::is_signed &&
+ F::digits >= T::digits) &&
+ from > static_cast(detail::max_value())) {
+ ec = 1;
+ return {};
+ }
+ return static_cast(from); // Lossless conversion.
+}
+
+template ::value)>
+FMT_CONSTEXPR To lossless_integral_conversion(const From from, int& ec) {
+ ec = 0;
+ return from;
+} // function
+
+// clang-format off
+/**
+ * converts From to To if possible, otherwise ec is set.
+ *
+ * input | output
+ * ---------------------------------|---------------
+ * NaN | NaN
+ * Inf | Inf
+ * normal, fits in output | converted (possibly lossy)
+ * normal, does not fit in output | ec is set
+ * subnormal | best effort
+ * -Inf | -Inf
+ */
+// clang-format on
+template ::value)>
+FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
+ ec = 0;
+ using T = std::numeric_limits;
+ static_assert(std::is_floating_point::value, "From must be floating");
+ static_assert(std::is_floating_point::value, "To must be floating");
+
+ // catch the only happy case
+ if (std::isfinite(from)) {
+ if (from >= T::lowest() && from <= (T::max)()) {
+ return static_cast(from);
+ }
+ // not within range.
+ ec = 1;
+ return {};
+ }
+
+ // nan and inf will be preserved
+ return static_cast(from);
+} // function
+
+template ::value)>
+FMT_CONSTEXPR To safe_float_conversion(const From from, int& ec) {
+ ec = 0;
+ static_assert(std::is_floating_point::value, "From must be floating");
+ return from;
+}
+
+/**
+ * safe duration cast between integral durations
+ */
+template ::value),
+ FMT_ENABLE_IF(std::is_integral::value)>
+To safe_duration_cast(std::chrono::duration from,
+ int& ec) {
+ using From = std::chrono::duration;
+ ec = 0;
+ // the basic idea is that we need to convert from count() in the from type
+ // to count() in the To type, by multiplying it with this:
+ struct Factor
+ : std::ratio_divide {};
+
+ static_assert(Factor::num > 0, "num must be positive");
+ static_assert(Factor::den > 0, "den must be positive");
+
+ // the conversion is like this: multiply from.count() with Factor::num
+ // /Factor::den and convert it to To::rep, all this without
+ // overflow/underflow. let's start by finding a suitable type that can hold
+ // both To, From and Factor::num
+ using IntermediateRep =
+ typename std::common_type::type;
+
+ // safe conversion to IntermediateRep
+ IntermediateRep count =
+ lossless_integral_conversion(from.count(), ec);
+ if (ec) return {};
+ // multiply with Factor::num without overflow or underflow
+ if (detail::const_check(Factor::num != 1)) {
+ const auto max1 = detail::max_value() / Factor::num;
+ if (count > max1) {
+ ec = 1;
+ return {};
+ }
+ const auto min1 =
+ (std::numeric_limits::min)() / Factor::num;
+ if (count < min1) {
+ ec = 1;
+ return {};
+ }
+ count *= Factor::num;
+ }
+
+ if (detail::const_check(Factor::den != 1)) count /= Factor::den;
+ auto tocount = lossless_integral_conversion(count, ec);
+ return ec ? To() : To(tocount);
+}
+
+/**
+ * safe duration_cast between floating point durations
+ */
+template ::value),
+ FMT_ENABLE_IF(std::is_floating_point::value)>
+To safe_duration_cast(std::chrono::duration from,
+ int& ec) {
+ using From = std::chrono::duration;
+ ec = 0;
+ if (std::isnan(from.count())) {
+ // nan in, gives nan out. easy.
+ return To{std::numeric_limits::quiet_NaN()};
+ }
+ // maybe we should also check if from is denormal, and decide what to do about
+ // it.
+
+ // +-inf should be preserved.
+ if (std::isinf(from.count())) {
+ return To{from.count()};
+ }
+
+ // the basic idea is that we need to convert from count() in the from type
+ // to count() in the To type, by multiplying it with this:
+ struct Factor
+ : std::ratio_divide {};
+
+ static_assert(Factor::num > 0, "num must be positive");
+ static_assert(Factor::den > 0, "den must be positive");
+
+ // the conversion is like this: multiply from.count() with Factor::num
+ // /Factor::den and convert it to To::rep, all this without
+ // overflow/underflow. let's start by finding a suitable type that can hold
+ // both To, From and Factor::num
+ using IntermediateRep =
+ typename std::common_type::type;
+
+ // force conversion of From::rep -> IntermediateRep to be safe,
+ // even if it will never happen be narrowing in this context.
+ IntermediateRep count =
+ safe_float_conversion(from.count(), ec);
+ if (ec) {
+ return {};
+ }
+
+ // multiply with Factor::num without overflow or underflow
+ if (detail::const_check(Factor::num != 1)) {
+ constexpr auto max1 = detail::max_value() /
+ static_cast(Factor::num);
+ if (count > max1) {
+ ec = 1;
+ return {};
+ }
+ constexpr auto min1 = std::numeric_limits::lowest() /
+ static_cast(Factor::num);
+ if (count < min1) {
+ ec = 1;
+ return {};
+ }
+ count *= static_cast(Factor::num);
+ }
+
+ // this can't go wrong, right? den>0 is checked earlier.
+ if (detail::const_check(Factor::den != 1)) {
+ using common_t = typename std::common_type::type;
+ count /= static_cast(Factor::den);
+ }
+
+ // convert to the to type, safely
+ using ToRep = typename To::rep;
+
+ const ToRep tocount = safe_float_conversion(count, ec);
+ if (ec) {
+ return {};
+ }
+ return To{tocount};
+}
+} // namespace safe_duration_cast
+#endif
+
+// Prevents expansion of a preceding token as a function-style macro.
+// Usage: f FMT_NOMACRO()
+#define FMT_NOMACRO
+
+namespace detail {
+template struct null {};
+inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
+inline null<> localtime_s(...) { return null<>(); }
+inline null<> gmtime_r(...) { return null<>(); }
+inline null<> gmtime_s(...) { return null<>(); }
+
+inline const std::locale& get_classic_locale() {
+ static const auto& locale = std::locale::classic();
+ return locale;
+}
+
+template struct codecvt_result {
+ static constexpr const size_t max_size = 32;
+ CodeUnit buf[max_size];
+ CodeUnit* end;
+};
+template
+constexpr const size_t codecvt_result::max_size;
+
+template
+void write_codecvt(codecvt_result& out, string_view in_buf,
+ const std::locale& loc) {
+ using codecvt = std::codecvt;
+#if FMT_CLANG_VERSION
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wdeprecated"
+ auto& f = std::use_facet(loc);
+# pragma clang diagnostic pop
+#else
+ auto& f = std::use_facet(loc);
+#endif
+ auto mb = std::mbstate_t();
+ const char* from_next = nullptr;
+ auto result = f.in(mb, in_buf.begin(), in_buf.end(), from_next,
+ std::begin(out.buf), std::end(out.buf), out.end);
+ if (result != std::codecvt_base::ok)
+ FMT_THROW(format_error("failed to format time"));
+}
+
+template
+auto write_encoded_tm_str(OutputIt out, string_view in, const std::locale& loc)
+ -> OutputIt {
+ if (detail::is_utf8() && loc != get_classic_locale()) {
+ // char16_t and char32_t codecvts are broken in MSVC (linkage errors) and
+ // gcc-4.
+#if FMT_MSC_VER != 0 || \
+ (defined(__GLIBCXX__) && !defined(_GLIBCXX_USE_DUAL_ABI))
+ // The _GLIBCXX_USE_DUAL_ABI macro is always defined in libstdc++ from gcc-5
+ // and newer.
+ using code_unit = wchar_t;
+#else
+ using code_unit = char32_t;
+#endif
+
+ using unit_t = codecvt_result;
+ unit_t unit;
+ write_codecvt(unit, in, loc);
+ // In UTF-8 is used one to four one-byte code units.
+ auto&& buf = basic_memory_buffer();
+ for (code_unit* p = unit.buf; p != unit.end; ++p) {
+ uint32_t c = static_cast(*p);
+ if (sizeof(code_unit) == 2 && c >= 0xd800 && c <= 0xdfff) {
+ // surrogate pair
+ ++p;
+ if (p == unit.end || (c & 0xfc00) != 0xd800 ||
+ (*p & 0xfc00) != 0xdc00) {
+ FMT_THROW(format_error("failed to format time"));
+ }
+ c = (c << 10) + static_cast(*p) - 0x35fdc00;
+ }
+ if (c < 0x80) {
+ buf.push_back(static_cast(c));
+ } else if (c < 0x800) {
+ buf.push_back(static_cast(0xc0 | (c >> 6)));
+ buf.push_back(static_cast(0x80 | (c & 0x3f)));
+ } else if ((c >= 0x800 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xffff)) {
+ buf.push_back(static_cast(0xe0 | (c >> 12)));
+ buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6)));
+ buf.push_back(static_cast(0x80 | (c & 0x3f)));
+ } else if (c >= 0x10000 && c <= 0x10ffff) {
+ buf.push_back(static_cast(0xf0 | (c >> 18)));
+ buf.push_back(static_cast(0x80 | ((c & 0x3ffff) >> 12)));
+ buf.push_back(static_cast(0x80 | ((c & 0xfff) >> 6)));
+ buf.push_back(static_cast(0x80 | (c & 0x3f)));
+ } else {
+ FMT_THROW(format_error("failed to format time"));
+ }
+ }
+ return copy_str(buf.data(), buf.data() + buf.size(), out);
+ }
+ return copy_str