diff --git a/.gitignore b/.gitignore
index fcae9bf..9db2f13 100644
--- a/.gitignore
+++ b/.gitignore
@@ -183,15 +183,10 @@ packages/*
Dependencies/*
GUI.NET/*
-Windows/*
Linux/*
Libretro/*
Docs/*
-SevenZip/*
Lua/*
TestHelper/*
UpdateHelper/*
-Utilities/*
PGOHelper/*
-DependencyPacker/*
-InteropDLL/*
\ No newline at end of file
diff --git a/DependencyPacker/DependencyPacker.csproj b/DependencyPacker/DependencyPacker.csproj
new file mode 100644
index 0000000..3fc7adf
--- /dev/null
+++ b/DependencyPacker/DependencyPacker.csproj
@@ -0,0 +1,186 @@
+
+
+
+
+ Debug
+ AnyCPU
+ {AABB5225-3A49-47FF-8A48-031673CADCE9}
+ Exe
+ Properties
+ DependencyPacker
+ DependencyPacker
+ v4.5
+ 512
+
+
+ AnyCPU
+ true
+ full
+ false
+ ..\bin\Any CPU\Debug\
+ DEBUG;TRACE
+ prompt
+ 4
+ false
+
+
+ AnyCPU
+ pdbonly
+ true
+ ..\bin\Any CPU\Release\
+ TRACE
+ prompt
+ 4
+ false
+
+
+ true
+ ..\bin\x64\Debug\
+ DEBUG;TRACE
+ full
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ ..\bin\x64\Release\
+ TRACE
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ true
+ ..\bin\x86\Debug\
+ DEBUG;TRACE
+ full
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ ..\bin\x86\Release\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ ..\bin\Any CPU\PGO Profile\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ ..\bin\x64\PGO Profile\
+ TRACE
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ ..\bin\x86\PGO Profile\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ ..\bin\Any CPU\PGO Profile\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ ..\bin\x64\PGO Profile\
+ TRACE
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ ..\bin\x86\PGO Profile\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\Libretro\
+ TRACE
+ true
+ pdbonly
+ AnyCPU
+ prompt
+ MinimumRecommendedRules.ruleset
+
+
+ bin\x64\Libretro\
+ TRACE
+ true
+ pdbonly
+ x64
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+ bin\x86\Libretro\
+ TRACE
+ true
+ pdbonly
+ x86
+ prompt
+ MinimumRecommendedRules.ruleset
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/DependencyPacker/Program.cs b/DependencyPacker/Program.cs
new file mode 100644
index 0000000..ded5c35
--- /dev/null
+++ b/DependencyPacker/Program.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.IO;
+using System.IO.Compression;
+
+namespace DependencyPacker
+{
+ class Program
+ {
+ static void Main(string[] args)
+ {
+ if(File.Exists("Dependencies.zip")) {
+ File.Delete("Dependencies.zip");
+ }
+ ZipFile.CreateFromDirectory("Dependencies", "Dependencies.zip");
+ }
+ }
+}
diff --git a/DependencyPacker/Properties/AssemblyInfo.cs b/DependencyPacker/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000..4804ea4
--- /dev/null
+++ b/DependencyPacker/Properties/AssemblyInfo.cs
@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// General Information about an assembly is controlled through the following
+// set of attributes. Change these attribute values to modify the information
+// associated with an assembly.
+[assembly: AssemblyTitle("DependencyPacker")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("Mesen")]
+[assembly: AssemblyProduct("DependencyPacker")]
+[assembly: AssemblyCopyright("Copyright © Mesen 2019")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// Setting ComVisible to false makes the types in this assembly not visible
+// to COM components. If you need to access a type in this assembly from
+// COM, set the ComVisible attribute to true on that type.
+[assembly: ComVisible(false)]
+
+// The following GUID is for the ID of the typelib if this project is exposed to COM
+[assembly: Guid("2cbd9a92-f7b8-4d71-bec3-2fd8810871f5")]
+
+// Version information for an assembly consists of the following four values:
+//
+// Major Version
+// Minor Version
+// Build Number
+// Revision
+//
+// You can specify all the values or you can default the Build and Revision Numbers
+// by using the '*' as shown below:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]
diff --git a/InteropDLL/DebugApiWrapper.cpp b/InteropDLL/DebugApiWrapper.cpp
new file mode 100644
index 0000000..4e5ce9c
--- /dev/null
+++ b/InteropDLL/DebugApiWrapper.cpp
@@ -0,0 +1,48 @@
+#include "stdafx.h"
+#include "../Core/Console.h"
+#include "../Core/Debugger.h"
+#include "../Core/TraceLogger.h"
+
+extern shared_ptr _console;
+shared_ptr _debugger;
+
+shared_ptr GetDebugger()
+{
+ if(!_debugger) {
+ _debugger = _console->GetDebugger();
+ }
+
+ return _debugger;
+}
+
+extern "C"
+{
+ //Debugger wrapper
+ DllExport void __stdcall InitializeDebugger()
+ {
+ GetDebugger();
+ }
+
+ DllExport void __stdcall ReleaseDebugger()
+ {
+ _debugger.reset();
+ //_console->StopDebugger();
+ }
+
+ DllExport bool __stdcall IsDebuggerRunning()
+ {
+ return _console->GetDebugger(false).get() != nullptr;
+ }
+
+ DllExport bool __stdcall IsExecutionStopped() { return GetDebugger()->IsExecutionStopped(); }
+ DllExport void __stdcall ResumeExecution() { GetDebugger()->Run(); }
+ DllExport void __stdcall Step(uint32_t count) { GetDebugger()->Step(count); }
+ //DllExport const char* __stdcall DebugGetCode(uint32_t &length) { return GetDebugger()->GetCode(length); }
+
+ DllExport void __stdcall SetTraceOptions(TraceLoggerOptions options) { GetDebugger()->GetTraceLogger()->SetOptions(options); }
+ DllExport void __stdcall StartTraceLogger(char* filename) { GetDebugger()->GetTraceLogger()->StartLogging(filename); }
+ DllExport void __stdcall StopTraceLogger() { GetDebugger()->GetTraceLogger()->StopLogging(); }
+ DllExport const char* GetExecutionTrace(uint32_t lineCount) { return GetDebugger()->GetTraceLogger()->GetExecutionTrace(lineCount); }
+
+ DllExport void __stdcall GetState(DebugState *state) { GetDebugger()->GetState(state); }
+};
\ No newline at end of file
diff --git a/InteropDLL/EmuApiWrapper.cpp b/InteropDLL/EmuApiWrapper.cpp
new file mode 100644
index 0000000..2488312
--- /dev/null
+++ b/InteropDLL/EmuApiWrapper.cpp
@@ -0,0 +1,223 @@
+#include "stdafx.h"
+#include "../Core/Console.h"
+#include "../Core/MessageManager.h"
+#include "../Core/INotificationListener.h"
+#include "../Core/KeyManager.h"
+#include "../Utilities/SimpleLock.h"
+#include "../Utilities/ArchiveReader.h"
+
+#ifdef _WIN32
+ #include "../Windows/Renderer.h"
+ #include "../Windows/SoundManager.h"
+ #include "../Windows/WindowsKeyManager.h"
+#else
+ #include "../Linux/SdlRenderer.h"
+ #include "../Linux/SdlSoundManager.h"
+ #include "../Linux/LinuxKeyManager.h"
+#endif
+
+unique_ptr _renderer;
+unique_ptr _soundManager;
+unique_ptr _keyManager;
+//unique_ptr _shortcutKeyHandler;
+
+void* _windowHandle = nullptr;
+void* _viewerHandle = nullptr;
+string _returnString;
+string _logString;
+shared_ptr _console;
+SimpleLock _externalNotificationListenerLock;
+vector> _externalNotificationListeners;
+
+typedef void (__stdcall *NotificationListenerCallback)(int, void*);
+
+namespace InteropEmu {
+ class InteropNotificationListener : public INotificationListener
+ {
+ NotificationListenerCallback _callback;
+ public:
+ InteropNotificationListener(NotificationListenerCallback callback)
+ {
+ _callback = callback;
+ }
+
+ virtual ~InteropNotificationListener()
+ {
+ }
+
+ void ProcessNotification(ConsoleNotificationType type, void* parameter)
+ {
+ _callback((int)type, parameter);
+ }
+ };
+
+ extern "C" {
+ DllExport bool __stdcall TestDll()
+ {
+ return true;
+ }
+
+ DllExport uint32_t __stdcall GetMesenVersion() { return 0x00000100; }
+
+ DllExport void __stdcall InitDll()
+ {
+ _console.reset(new Console());
+ }
+
+ DllExport void __stdcall InitializeEmu(const char* homeFolder, void *windowHandle, void *viewerHandle, bool noAudio, bool noVideo, bool noInput)
+ {
+ FolderUtilities::SetHomeFolder(homeFolder);
+ //_shortcutKeyHandler.reset(new ShortcutKeyHandler(_console));
+
+ if(windowHandle != nullptr && viewerHandle != nullptr) {
+ _windowHandle = windowHandle;
+ _viewerHandle = viewerHandle;
+
+ if(!noVideo) {
+ #ifdef _WIN32
+ _renderer.reset(new Renderer(_console, (HWND)_viewerHandle, true));
+ #else
+ _renderer.reset(new SdlRenderer(_console, _viewerHandle, true));
+ #endif
+ }
+
+ if(!noAudio) {
+ #ifdef _WIN32
+ _soundManager.reset(new SoundManager(_console, (HWND)_windowHandle));
+ #else
+ _soundManager.reset(new SdlSoundManager(_console));
+ #endif
+ }
+
+ if(!noInput) {
+ #ifdef _WIN32
+ _keyManager.reset(new WindowsKeyManager(_console, (HWND)_windowHandle));
+ #else
+ _keyManager.reset(new LinuxKeyManager(_console));
+ #endif
+
+ KeyManager::RegisterKeyManager(_keyManager.get());
+ }
+ }
+ }
+
+ DllExport void __stdcall SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight)
+ {
+ if(_renderer) {
+ _renderer->SetFullscreenMode(fullscreen, windowHandle, monitorWidth, monitorHeight);
+ }
+ }
+
+ DllExport void __stdcall LoadRom(char* filename, char* patchFile) { _console->LoadRom((VirtualFile)filename, (VirtualFile)patchFile); }
+ //DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); }
+ //DllExport void __stdcall SetFolderOverrides(char* saveFolder, char* saveStateFolder, char* screenshotFolder) { FolderUtilities::SetFolderOverrides(saveFolder, saveStateFolder, screenshotFolder); }
+
+ DllExport const char* __stdcall GetArchiveRomList(char* filename) {
+ std::ostringstream out;
+ shared_ptr reader = ArchiveReader::GetReader(filename);
+ if(reader) {
+ for(string romName : reader->GetFileList({ ".sfc" })) {
+ out << romName << "[!|!]";
+ }
+ }
+ _returnString = out.str();
+ return _returnString.c_str();
+ }
+
+ DllExport void __stdcall SetMousePosition(double x, double y) { KeyManager::SetMousePosition(x, y); }
+ DllExport void __stdcall SetMouseMovement(int16_t x, int16_t y) { KeyManager::SetMouseMovement(x, y); }
+
+ DllExport void __stdcall UpdateInputDevices() { if(_keyManager) { _keyManager->UpdateDevices(); } }
+ DllExport void __stdcall GetPressedKeys(uint32_t *keyBuffer) {
+ vector pressedKeys = KeyManager::GetPressedKeys();
+ for(size_t i = 0; i < pressedKeys.size() && i < 3; i++) {
+ keyBuffer[i] = pressedKeys[i];
+ }
+ }
+ DllExport void __stdcall DisableAllKeys(bool disabled) {
+ if(_keyManager) {
+ _keyManager->SetDisabled(disabled);
+ }
+ }
+ DllExport void __stdcall SetKeyState(int32_t scanCode, bool state) {
+ if(_keyManager) {
+ _keyManager->SetKeyState(scanCode, state);
+ //_shortcutKeyHandler->ProcessKeys();
+ }
+ }
+ DllExport void __stdcall ResetKeyState() { if(_keyManager) { _keyManager->ResetKeyState(); } }
+ DllExport const char* __stdcall GetKeyName(uint32_t keyCode)
+ {
+ _returnString = KeyManager::GetKeyName(keyCode);
+ return _returnString.c_str();
+ }
+ DllExport uint32_t __stdcall GetKeyCode(char* keyName) {
+ if(keyName) {
+ return KeyManager::GetKeyCode(keyName);
+ } else {
+ return 0;
+ }
+ }
+
+ DllExport void __stdcall Run()
+ {
+ if(_console) {
+ _console->Run();
+ }
+ }
+
+ DllExport void __stdcall Stop()
+ {
+ if(_console) {
+ _console->Stop();
+ }
+ }
+
+ DllExport void __stdcall Release()
+ {
+ //_shortcutKeyHandler.reset();
+
+ _console->Stop();
+
+ _renderer.reset();
+ _soundManager.reset();
+ _keyManager.reset();
+
+ //_console->Release(true);
+ _console.reset();
+
+ //_shortcutKeyHandler.reset();
+ }
+
+ DllExport INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback)
+ {
+ auto lock = _externalNotificationListenerLock.AcquireSafe();
+ auto listener = shared_ptr(new InteropNotificationListener(callback));
+ _externalNotificationListeners.push_back(listener);
+ //_console->GetNotificationManager()->RegisterNotificationListener(listener);
+ return listener.get();
+ }
+
+ DllExport void __stdcall UnregisterNotificationCallback(INotificationListener *listener)
+ {
+ auto lock = _externalNotificationListenerLock.AcquireSafe();
+ _externalNotificationListeners.erase(
+ std::remove_if(
+ _externalNotificationListeners.begin(),
+ _externalNotificationListeners.end(),
+ [=](shared_ptr ptr) { return ptr.get() == listener; }
+ ),
+ _externalNotificationListeners.end()
+ );
+ }
+
+ DllExport void __stdcall DisplayMessage(char* title, char* message, char* param1) { MessageManager::DisplayMessage(title, message, param1 ? param1 : ""); }
+ DllExport const char* __stdcall GetLog()
+ {
+ _logString = MessageManager::GetLog();
+ return _logString.c_str();
+ }
+
+ DllExport void __stdcall WriteLogEntry(char* message) { MessageManager::Log(message); }
+ }
+}
\ No newline at end of file
diff --git a/InteropDLL/InteropDLL.vcxproj b/InteropDLL/InteropDLL.vcxproj
new file mode 100644
index 0000000..c543ee5
--- /dev/null
+++ b/InteropDLL/InteropDLL.vcxproj
@@ -0,0 +1,472 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Libretro
+ Win32
+
+
+ Libretro
+ x64
+
+
+ PGO Optimize
+ Win32
+
+
+ PGO Optimize
+ x64
+
+
+ PGO Profile
+ Win32
+
+
+ PGO Profile
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {37749BB2-FA78-4EC9-8990-5628FC0BBA19}
+ Win32Proj
+ InteropDLL
+ 10.0.16299.0
+
+
+
+ DynamicLibrary
+ true
+ v141
+ Unicode
+
+
+ DynamicLibrary
+ true
+ v141
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ DynamicLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ true
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\PGO Profile\
+ obj\$(Platform)\PGO Profile\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ false
+ MesenSCore
+ $(SolutionDir)\bin\$(PlatformTarget)\PGO Profile\
+ obj\$(Platform)\PGO Profile\
+
+
+
+ Use
+ Level3
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+ Cdecl
+
+
+ MultiThreadedDebug
+ true
+ false
+
+
+ Windows
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Use
+ Level3
+ Disabled
+ WIN32;_DEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+ Cdecl
+
+
+ MultiThreadedDebug
+ true
+ false
+
+
+ Windows
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ PGO;WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ PGInstrument
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ PGO;WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ PGOptimization
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ PGO;WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ PGInstrument
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+ Level3
+ Use
+ MaxSpeed
+ true
+ true
+ PGO;WIN32;NDEBUG;_WINDOWS;_USRDLL;INTEROPDLL_EXPORTS;%(PreprocessorDefinitions)
+
+
+ MultiThreaded
+ true
+
+
+ Windows
+ true
+ true
+ true
+ dinput8.lib;Xinput9_1_0.lib;d3d11.lib;d3dcompiler.lib;dxguid.lib;winmm.lib;comctl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;
+ PGOptimization
+ $(OutDir);%(AdditionalLibraryDirectories)
+ /ignore:4099 %(AdditionalOptions)
+
+
+
+
+
+
+
+
+
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+ Create
+
+
+
+
+
+
\ No newline at end of file
diff --git a/InteropDLL/InteropDLL.vcxproj.filters b/InteropDLL/InteropDLL.vcxproj.filters
new file mode 100644
index 0000000..2206318
--- /dev/null
+++ b/InteropDLL/InteropDLL.vcxproj.filters
@@ -0,0 +1,29 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ Header Files
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/InteropDLL/stdafx.cpp b/InteropDLL/stdafx.cpp
new file mode 100644
index 0000000..5de39fc
--- /dev/null
+++ b/InteropDLL/stdafx.cpp
@@ -0,0 +1,8 @@
+// stdafx.cpp : source file that includes just the standard includes
+// InteropDLL.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/InteropDLL/stdafx.h b/InteropDLL/stdafx.h
new file mode 100644
index 0000000..43d156d
--- /dev/null
+++ b/InteropDLL/stdafx.h
@@ -0,0 +1,47 @@
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#if _WIN32 || _WIN64
+ #if _WIN64
+ #define ENVIRONMENT64
+ #else
+ #define ENVIRONMENT32
+ #endif
+#endif
+
+#if __GNUC__
+ #if __x86_64__ || __ppc64__
+ #define ENVIRONMENT64
+ #else
+ #define ENVIRONMENT32
+ #endif
+#endif
+
+#ifdef _DEBUG
+ #define MESEN_LIBRARY_DEBUG_SUFFIX "Debug"
+#else
+ #define MESEN_LIBRARY_DEBUG_SUFFIX "Release"
+#endif
+
+#ifdef ENVIRONMENT32
+ #define MESEN_LIBRARY_SUFFIX "x86.lib"
+#else
+ #define MESEN_LIBRARY_SUFFIX "x64.lib"
+#endif
+
+#if _WIN32 || _WIN64
+ #pragma comment(lib, "Core.lib")
+ #pragma comment(lib, "Utilities.lib")
+ #pragma comment(lib, "Windows.lib")
+ #pragma comment(lib, "SevenZip.lib")
+ #pragma comment(lib, "Lua.lib")
+ #pragma comment(lib, "../Dependencies/DirectXTK." MESEN_LIBRARY_DEBUG_SUFFIX ".Static." MESEN_LIBRARY_SUFFIX)
+ #define DllExport __declspec(dllexport)
+#else
+ #define __stdcall
+ #define DllExport __attribute__((visibility("default")))
+#endif
\ No newline at end of file
diff --git a/SevenZip/7z.h b/SevenZip/7z.h
new file mode 100644
index 0000000..4768151
--- /dev/null
+++ b/SevenZip/7z.h
@@ -0,0 +1,202 @@
+/* 7z.h -- 7z interface
+2015-11-18 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_H
+#define __7Z_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define k7zStartHeaderSize 0x20
+#define k7zSignatureSize 6
+
+extern const Byte k7zSignature[k7zSignatureSize];
+
+typedef struct
+{
+ const Byte *Data;
+ size_t Size;
+} CSzData;
+
+/* CSzCoderInfo & CSzFolder support only default methods */
+
+typedef struct
+{
+ size_t PropsOffset;
+ UInt32 MethodID;
+ Byte NumStreams;
+ Byte PropsSize;
+} CSzCoderInfo;
+
+typedef struct
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+} CSzBond;
+
+#define SZ_NUM_CODERS_IN_FOLDER_MAX 4
+#define SZ_NUM_BONDS_IN_FOLDER_MAX 3
+#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4
+
+typedef struct
+{
+ UInt32 NumCoders;
+ UInt32 NumBonds;
+ UInt32 NumPackStreams;
+ UInt32 UnpackStream;
+ UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX];
+ CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX];
+ CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX];
+} CSzFolder;
+
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd);
+
+typedef struct
+{
+ UInt32 Low;
+ UInt32 High;
+} CNtfsFileTime;
+
+typedef struct
+{
+ Byte *Defs; /* MSB 0 bit numbering */
+ UInt32 *Vals;
+} CSzBitUi32s;
+
+typedef struct
+{
+ Byte *Defs; /* MSB 0 bit numbering */
+ // UInt64 *Vals;
+ CNtfsFileTime *Vals;
+} CSzBitUi64s;
+
+#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
+
+#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
+
+typedef struct
+{
+ UInt32 NumPackStreams;
+ UInt32 NumFolders;
+
+ UInt64 *PackPositions; // NumPackStreams + 1
+ CSzBitUi32s FolderCRCs; // NumFolders
+
+ size_t *FoCodersOffsets; // NumFolders + 1
+ UInt32 *FoStartPackStreamIndex; // NumFolders + 1
+ UInt32 *FoToCoderUnpackSizes; // NumFolders + 1
+ Byte *FoToMainUnpackSizeIndex; // NumFolders
+ UInt64 *CoderUnpackSizes; // for all coders in all folders
+
+ Byte *CodersData;
+} CSzAr;
+
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+ ILookInStream *stream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize,
+ ISzAlloc *allocMain);
+
+typedef struct
+{
+ CSzAr db;
+
+ UInt64 startPosAfterHeader;
+ UInt64 dataPos;
+
+ UInt32 NumFiles;
+
+ UInt64 *UnpackPositions; // NumFiles + 1
+ // Byte *IsEmptyFiles;
+ Byte *IsDirs;
+ CSzBitUi32s CRCs;
+
+ CSzBitUi32s Attribs;
+ // CSzBitUi32s Parents;
+ CSzBitUi64s MTime;
+ CSzBitUi64s CTime;
+
+ UInt32 *FolderToFile; // NumFolders + 1
+ UInt32 *FileToFolder; // NumFiles
+
+ size_t *FileNameOffsets; /* in 2-byte steps */
+ Byte *FileNames; /* UTF-16-LE */
+} CSzArEx;
+
+#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i))
+
+#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i])
+
+void SzArEx_Init(CSzArEx *p);
+void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc);
+UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
+int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
+
+/*
+if dest == NULL, the return value specifies the required size of the buffer,
+ in 16-bit characters, including the null-terminating character.
+if dest != NULL, the return value specifies the number of 16-bit characters that
+ are written to the dest, including the null-terminating character. */
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+*/
+
+
+
+/*
+ SzArEx_Extract extracts file from archive
+
+ *outBuffer must be 0 before first call for each new archive.
+
+ Extracting cache:
+ If you need to decompress more than one file, you can send
+ these values from previous call:
+ *blockIndex,
+ *outBuffer,
+ *outBufferSize
+ You can consider "*outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ If you use external function, you can declare these 3 cache variables
+ (blockIndex, outBuffer, outBufferSize) as static in that external function.
+
+ Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
+*/
+
+SRes SzArEx_Extract(
+ const CSzArEx *db,
+ ILookInStream *inStream,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+
+/*
+SzArEx_Open Errors:
+SZ_ERROR_NO_ARCHIVE
+SZ_ERROR_ARCHIVE
+SZ_ERROR_UNSUPPORTED
+SZ_ERROR_MEM
+SZ_ERROR_CRC
+SZ_ERROR_INPUT_EOF
+SZ_ERROR_FAIL
+*/
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
+ ISzAlloc *allocMain, ISzAlloc *allocTemp);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/7zAlloc.c b/SevenZip/7zAlloc.c
new file mode 100644
index 0000000..3e848c9
--- /dev/null
+++ b/SevenZip/7zAlloc.c
@@ -0,0 +1,78 @@
+/* 7zAlloc.c -- Allocation functions
+2015-11-09 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zAlloc.h"
+
+/* #define _SZ_ALLOC_DEBUG */
+/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
+
+#ifdef _SZ_ALLOC_DEBUG
+
+#ifdef _WIN32
+#include
+#endif
+
+#include
+int g_allocCount = 0;
+int g_allocCountTemp = 0;
+
+#endif
+
+void *SzAlloc(void *p, size_t size)
+{
+ UNUSED_VAR(p);
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount);
+ g_allocCount++;
+ #endif
+ return malloc(size);
+}
+
+void SzFree(void *p, void *address)
+{
+ UNUSED_VAR(p);
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ {
+ g_allocCount--;
+ fprintf(stderr, "\nFree; count = %10d", g_allocCount);
+ }
+ #endif
+ free(address);
+}
+
+void *SzAllocTemp(void *p, size_t size)
+{
+ UNUSED_VAR(p);
+ if (size == 0)
+ return 0;
+ #ifdef _SZ_ALLOC_DEBUG
+ fprintf(stderr, "\nAlloc_temp %10u bytes; count = %10d", (unsigned)size, g_allocCountTemp);
+ g_allocCountTemp++;
+ #ifdef _WIN32
+ return HeapAlloc(GetProcessHeap(), 0, size);
+ #endif
+ #endif
+ return malloc(size);
+}
+
+void SzFreeTemp(void *p, void *address)
+{
+ UNUSED_VAR(p);
+ #ifdef _SZ_ALLOC_DEBUG
+ if (address != 0)
+ {
+ g_allocCountTemp--;
+ fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
+ }
+ #ifdef _WIN32
+ HeapFree(GetProcessHeap(), 0, address);
+ return;
+ #endif
+ #endif
+ free(address);
+}
diff --git a/SevenZip/7zAlloc.h b/SevenZip/7zAlloc.h
new file mode 100644
index 0000000..2fd5bdb
--- /dev/null
+++ b/SevenZip/7zAlloc.h
@@ -0,0 +1,23 @@
+/* 7zAlloc.h -- Allocation functions
+2013-03-25 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_ALLOC_H
+#define __7Z_ALLOC_H
+
+#include
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void *SzAlloc(void *p, size_t size);
+void SzFree(void *p, void *address);
+
+void *SzAllocTemp(void *p, size_t size);
+void SzFreeTemp(void *p, void *address);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/SevenZip/7zArcIn.c b/SevenZip/7zArcIn.c
new file mode 100644
index 0000000..2beed3d
--- /dev/null
+++ b/SevenZip/7zArcIn.c
@@ -0,0 +1,1771 @@
+/* 7zArcIn.c -- 7z Input functions
+2016-05-16 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include
+
+#include "7z.h"
+#include "7zBuf.h"
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define MY_ALLOC(T, p, size, alloc) { \
+ if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; }
+
+#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) }
+
+#define MY_ALLOC_AND_CPY(to, size, from, alloc) \
+ { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); }
+
+#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \
+ { if ((size) == 0) p = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } }
+
+#define k7zMajorVersion 0
+
+enum EIdEnum
+{
+ k7zIdEnd,
+ k7zIdHeader,
+ k7zIdArchiveProperties,
+ k7zIdAdditionalStreamsInfo,
+ k7zIdMainStreamsInfo,
+ k7zIdFilesInfo,
+ k7zIdPackInfo,
+ k7zIdUnpackInfo,
+ k7zIdSubStreamsInfo,
+ k7zIdSize,
+ k7zIdCRC,
+ k7zIdFolder,
+ k7zIdCodersUnpackSize,
+ k7zIdNumUnpackStream,
+ k7zIdEmptyStream,
+ k7zIdEmptyFile,
+ k7zIdAnti,
+ k7zIdName,
+ k7zIdCTime,
+ k7zIdATime,
+ k7zIdMTime,
+ k7zIdWinAttrib,
+ k7zIdComment,
+ k7zIdEncodedHeader,
+ k7zIdStartPos,
+ k7zIdDummy
+ // k7zNtSecure,
+ // k7zParent,
+ // k7zIsReal
+};
+
+const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAlloc *alloc)
+{
+ if (num == 0)
+ {
+ p->Defs = NULL;
+ p->Vals = NULL;
+ }
+ else
+ {
+ MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc);
+ MY_ALLOC(UInt32, p->Vals, num, alloc);
+ }
+ return SZ_OK;
+}
+
+void SzBitUi32s_Free(CSzBitUi32s *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+ IAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+void SzBitUi64s_Free(CSzBitUi64s *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+ IAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+
+static void SzAr_Init(CSzAr *p)
+{
+ p->NumPackStreams = 0;
+ p->NumFolders = 0;
+
+ p->PackPositions = NULL;
+ SzBitUi32s_Init(&p->FolderCRCs);
+
+ p->FoCodersOffsets = NULL;
+ p->FoStartPackStreamIndex = NULL;
+ p->FoToCoderUnpackSizes = NULL;
+ p->FoToMainUnpackSizeIndex = NULL;
+ p->CoderUnpackSizes = NULL;
+
+ p->CodersData = NULL;
+}
+
+static void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->PackPositions);
+ SzBitUi32s_Free(&p->FolderCRCs, alloc);
+
+ IAlloc_Free(alloc, p->FoCodersOffsets);
+ IAlloc_Free(alloc, p->FoStartPackStreamIndex);
+ IAlloc_Free(alloc, p->FoToCoderUnpackSizes);
+ IAlloc_Free(alloc, p->FoToMainUnpackSizeIndex);
+ IAlloc_Free(alloc, p->CoderUnpackSizes);
+
+ IAlloc_Free(alloc, p->CodersData);
+
+ SzAr_Init(p);
+}
+
+
+void SzArEx_Init(CSzArEx *p)
+{
+ SzAr_Init(&p->db);
+
+ p->NumFiles = 0;
+ p->dataPos = 0;
+
+ p->UnpackPositions = NULL;
+ p->IsDirs = NULL;
+
+ p->FolderToFile = NULL;
+ p->FileToFolder = NULL;
+
+ p->FileNameOffsets = NULL;
+ p->FileNames = NULL;
+
+ SzBitUi32s_Init(&p->CRCs);
+ SzBitUi32s_Init(&p->Attribs);
+ // SzBitUi32s_Init(&p->Parents);
+ SzBitUi64s_Init(&p->MTime);
+ SzBitUi64s_Init(&p->CTime);
+}
+
+void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
+{
+ IAlloc_Free(alloc, p->UnpackPositions);
+ IAlloc_Free(alloc, p->IsDirs);
+
+ IAlloc_Free(alloc, p->FolderToFile);
+ IAlloc_Free(alloc, p->FileToFolder);
+
+ IAlloc_Free(alloc, p->FileNameOffsets);
+ IAlloc_Free(alloc, p->FileNames);
+
+ SzBitUi32s_Free(&p->CRCs, alloc);
+ SzBitUi32s_Free(&p->Attribs, alloc);
+ // SzBitUi32s_Free(&p->Parents, alloc);
+ SzBitUi64s_Free(&p->MTime, alloc);
+ SzBitUi64s_Free(&p->CTime, alloc);
+
+ SzAr_Free(&p->db, alloc);
+ SzArEx_Init(p);
+}
+
+
+static int TestSignatureCandidate(const Byte *testBytes)
+{
+ unsigned i;
+ for (i = 0; i < k7zSignatureSize; i++)
+ if (testBytes[i] != k7zSignature[i])
+ return 0;
+ return 1;
+}
+
+#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; }
+
+#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++;
+#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)
+#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++;
+
+#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); }
+#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); }
+
+#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \
+ dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4);
+
+static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value)
+{
+ Byte firstByte, mask;
+ unsigned i;
+ UInt32 v;
+
+ SZ_READ_BYTE(firstByte);
+ if ((firstByte & 0x80) == 0)
+ {
+ *value = firstByte;
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(v);
+ if ((firstByte & 0x40) == 0)
+ {
+ *value = (((UInt32)firstByte & 0x3F) << 8) | v;
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(mask);
+ *value = v | ((UInt32)mask << 8);
+ mask = 0x20;
+ for (i = 2; i < 8; i++)
+ {
+ Byte b;
+ if ((firstByte & mask) == 0)
+ {
+ UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1);
+ *value |= (highPart << (8 * i));
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(b);
+ *value |= ((UInt64)b << (8 * i));
+ mask >>= 1;
+ }
+ return SZ_OK;
+}
+
+
+static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+ Byte firstByte;
+ UInt64 value64;
+ if (sd->Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ firstByte = *sd->Data;
+ if ((firstByte & 0x80) == 0)
+ {
+ *value = firstByte;
+ sd->Data++;
+ sd->Size--;
+ return SZ_OK;
+ }
+ RINOK(ReadNumber(sd, &value64));
+ if (value64 >= (UInt32)0x80000000 - 1)
+ return SZ_ERROR_UNSUPPORTED;
+ if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4)))
+ return SZ_ERROR_UNSUPPORTED;
+ *value = (UInt32)value64;
+ return SZ_OK;
+}
+
+#define ReadID(sd, value) ReadNumber(sd, value)
+
+static SRes SkipData(CSzData *sd)
+{
+ UInt64 size;
+ RINOK(ReadNumber(sd, &size));
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA(sd, size);
+ return SZ_OK;
+}
+
+static SRes WaitId(CSzData *sd, UInt32 id)
+{
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type));
+ if (type == id)
+ return SZ_OK;
+ if (type == k7zIdEnd)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(SkipData(sd));
+ }
+}
+
+static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
+{
+ UInt32 numBytes = (numItems + 7) >> 3;
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ *v = sd->Data;
+ SKIP_DATA(sd, numBytes);
+ return SZ_OK;
+}
+
+static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
+{
+ Byte b = 0;
+ unsigned m = 0;
+ UInt32 sum = 0;
+ for (; numItems != 0; numItems--)
+ {
+ if (m == 0)
+ {
+ b = *bits++;
+ m = 8;
+ }
+ m--;
+ sum += ((b >> m) & 1);
+ }
+ return sum;
+}
+
+static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAlloc *alloc)
+{
+ Byte allAreDefined;
+ Byte *v2;
+ UInt32 numBytes = (numItems + 7) >> 3;
+ *v = NULL;
+ SZ_READ_BYTE(allAreDefined);
+ if (numBytes == 0)
+ return SZ_OK;
+ if (allAreDefined == 0)
+ {
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc);
+ SKIP_DATA(sd, numBytes);
+ return SZ_OK;
+ }
+ MY_ALLOC(Byte, *v, numBytes, alloc);
+ v2 = *v;
+ memset(v2, 0xFF, (size_t)numBytes);
+ {
+ unsigned numBits = (unsigned)numItems & 7;
+ if (numBits != 0)
+ v2[numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));
+ }
+ return SZ_OK;
+}
+
+static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)
+{
+ UInt32 i;
+ CSzData sd;
+ UInt32 *vals;
+ const Byte *defs;
+ MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc);
+ sd = *sd2;
+ defs = crcs->Defs;
+ vals = crcs->Vals;
+ for (i = 0; i < numItems; i++)
+ if (SzBitArray_Check(defs, i))
+ {
+ SZ_READ_32(vals[i]);
+ }
+ else
+ vals[i] = 0;
+ *sd2 = sd;
+ return SZ_OK;
+}
+
+static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAlloc *alloc)
+{
+ SzBitUi32s_Free(crcs, alloc);
+ RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc));
+ return ReadUi32s(sd, numItems, crcs, alloc);
+}
+
+static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)
+{
+ Byte allAreDefined;
+ UInt32 numDefined = numItems;
+ SZ_READ_BYTE(allAreDefined);
+ if (!allAreDefined)
+ {
+ size_t numBytes = (numItems + 7) >> 3;
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ numDefined = CountDefinedBits(sd->Data, numItems);
+ SKIP_DATA(sd, numBytes);
+ }
+ if (numDefined > (sd->Size >> 2))
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA(sd, (size_t)numDefined * 4);
+ return SZ_OK;
+}
+
+static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAlloc *alloc)
+{
+ RINOK(SzReadNumber32(sd, &p->NumPackStreams));
+
+ RINOK(WaitId(sd, k7zIdSize));
+ MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc);
+ {
+ UInt64 sum = 0;
+ UInt32 i;
+ UInt32 numPackStreams = p->NumPackStreams;
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt64 packSize;
+ p->PackPositions[i] = sum;
+ RINOK(ReadNumber(sd, &packSize));
+ sum += packSize;
+ if (sum < packSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+ p->PackPositions[i] = sum;
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ /* CRC of packed streams is unused now */
+ RINOK(SkipBitUi32s(sd, p->NumPackStreams));
+ continue;
+ }
+ RINOK(SkipData(sd));
+ }
+}
+
+/*
+static SRes SzReadSwitch(CSzData *sd)
+{
+ Byte external;
+ RINOK(SzReadByte(sd, &external));
+ return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
+}
+*/
+
+#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd)
+{
+ UInt32 numCoders, i;
+ UInt32 numInStreams = 0;
+ const Byte *dataStart = sd->Data;
+
+ f->NumCoders = 0;
+ f->NumBonds = 0;
+ f->NumPackStreams = 0;
+ f->UnpackStream = 0;
+
+ RINOK(SzReadNumber32(sd, &numCoders));
+ if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numCoders; i++)
+ {
+ Byte mainByte;
+ CSzCoderInfo *coder = f->Coders + i;
+ unsigned idSize, j;
+ UInt64 id;
+
+ SZ_READ_BYTE(mainByte);
+ if ((mainByte & 0xC0) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+
+ idSize = (unsigned)(mainByte & 0xF);
+ if (idSize > sizeof(id))
+ return SZ_ERROR_UNSUPPORTED;
+ if (idSize > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ id = 0;
+ for (j = 0; j < idSize; j++)
+ {
+ id = ((id << 8) | *sd->Data);
+ sd->Data++;
+ sd->Size--;
+ }
+ if (id > (UInt32)0xFFFFFFFF)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->MethodID = (UInt32)id;
+
+ coder->NumStreams = 1;
+ coder->PropsOffset = 0;
+ coder->PropsSize = 0;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 numStreams;
+
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numStreams > k_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->NumStreams = (Byte)numStreams;
+
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numStreams != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ numInStreams += coder->NumStreams;
+
+ if (numInStreams > k_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt32 propsSize = 0;
+ RINOK(SzReadNumber32(sd, &propsSize));
+ if (propsSize > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ if (propsSize >= 0x80)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->PropsOffset = sd->Data - dataStart;
+ coder->PropsSize = (Byte)propsSize;
+ sd->Data += (size_t)propsSize;
+ sd->Size -= (size_t)propsSize;
+ }
+ }
+
+ /*
+ if (numInStreams == 1 && numCoders == 1)
+ {
+ f->NumPackStreams = 1;
+ f->PackStreams[0] = 0;
+ }
+ else
+ */
+ {
+ Byte streamUsed[k_NumCodersStreams_in_Folder_MAX];
+ UInt32 numBonds, numPackStreams;
+
+ numBonds = numCoders - 1;
+ if (numInStreams < numBonds)
+ return SZ_ERROR_ARCHIVE;
+ if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->NumBonds = numBonds;
+
+ numPackStreams = numInStreams - numBonds;
+ if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->NumPackStreams = numPackStreams;
+
+ for (i = 0; i < numInStreams; i++)
+ streamUsed[i] = False;
+
+ if (numBonds != 0)
+ {
+ Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX];
+
+ for (i = 0; i < numCoders; i++)
+ coderUsed[i] = False;
+
+ for (i = 0; i < numBonds; i++)
+ {
+ CSzBond *bp = f->Bonds + i;
+
+ RINOK(SzReadNumber32(sd, &bp->InIndex));
+ if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[bp->InIndex] = True;
+
+ RINOK(SzReadNumber32(sd, &bp->OutIndex));
+ if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex])
+ return SZ_ERROR_ARCHIVE;
+ coderUsed[bp->OutIndex] = True;
+ }
+
+ for (i = 0; i < numCoders; i++)
+ if (!coderUsed[i])
+ {
+ f->UnpackStream = i;
+ break;
+ }
+
+ if (i == numCoders)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (!streamUsed[i])
+ break;
+ if (i == numInStreams)
+ return SZ_ERROR_ARCHIVE;
+ f->PackStreams[0] = i;
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index));
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+ f->PackStreams[i] = index;
+ }
+ }
+
+ f->NumCoders = numCoders;
+
+ return SZ_OK;
+}
+
+
+static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num)
+{
+ CSzData sd;
+ sd = *sd2;
+ for (; num != 0; num--)
+ {
+ Byte firstByte, mask;
+ unsigned i;
+ SZ_READ_BYTE_2(firstByte);
+ if ((firstByte & 0x80) == 0)
+ continue;
+ if ((firstByte & 0x40) == 0)
+ {
+ if (sd.Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ sd.Size--;
+ sd.Data++;
+ continue;
+ }
+ mask = 0x20;
+ for (i = 2; i < 8 && (firstByte & mask) != 0; i++)
+ mask >>= 1;
+ if (i > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, i);
+ }
+ *sd2 = sd;
+ return SZ_OK;
+}
+
+
+#define k_Scan_NumCoders_MAX 64
+#define k_Scan_NumCodersStreams_in_Folder_MAX 64
+
+
+static SRes ReadUnpackInfo(CSzAr *p,
+ CSzData *sd2,
+ UInt32 numFoldersMax,
+ const CBuf *tempBufs, UInt32 numTempBufs,
+ ISzAlloc *alloc)
+{
+ CSzData sd;
+
+ UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;
+ const Byte *startBufPtr;
+ Byte external;
+
+ RINOK(WaitId(sd2, k7zIdFolder));
+
+ RINOK(SzReadNumber32(sd2, &numFolders));
+ if (numFolders > numFoldersMax)
+ return SZ_ERROR_UNSUPPORTED;
+ p->NumFolders = numFolders;
+
+ SZ_READ_BYTE_SD(sd2, external);
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd2, &index));
+ if (index >= numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sd.Data = tempBufs[index].data;
+ sd.Size = tempBufs[index].size;
+ }
+
+ MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc);
+ MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc);
+ MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc);
+ MY_ALLOC(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc);
+
+ startBufPtr = sd.Data;
+
+ packStreamIndex = 0;
+ numCodersOutStreams = 0;
+
+ for (fo = 0; fo < numFolders; fo++)
+ {
+ UInt32 numCoders, ci, numInStreams = 0;
+
+ p->FoCodersOffsets[fo] = sd.Data - startBufPtr;
+
+ RINOK(SzReadNumber32(&sd, &numCoders));
+ if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (ci = 0; ci < numCoders; ci++)
+ {
+ Byte mainByte;
+ unsigned idSize;
+ UInt32 coderInStreams;
+
+ SZ_READ_BYTE_2(mainByte);
+ if ((mainByte & 0xC0) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ idSize = (mainByte & 0xF);
+ if (idSize > 8)
+ return SZ_ERROR_UNSUPPORTED;
+ if (idSize > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, idSize);
+
+ coderInStreams = 1;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 coderOutStreams;
+ RINOK(SzReadNumber32(&sd, &coderInStreams));
+ RINOK(SzReadNumber32(&sd, &coderOutStreams));
+ if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ numInStreams += coderInStreams;
+
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt32 propsSize;
+ RINOK(SzReadNumber32(&sd, &propsSize));
+ if (propsSize > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, propsSize);
+ }
+ }
+
+ {
+ UInt32 indexOfMainStream = 0;
+ UInt32 numPackStreams = 1;
+
+ if (numCoders != 1 || numInStreams != 1)
+ {
+ Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX];
+ Byte coderUsed[k_Scan_NumCoders_MAX];
+
+ UInt32 i;
+ UInt32 numBonds = numCoders - 1;
+ if (numInStreams < numBonds)
+ return SZ_ERROR_ARCHIVE;
+
+ if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numInStreams; i++)
+ streamUsed[i] = False;
+ for (i = 0; i < numCoders; i++)
+ coderUsed[i] = False;
+
+ for (i = 0; i < numBonds; i++)
+ {
+ UInt32 index;
+
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numCoders || coderUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ coderUsed[index] = True;
+ }
+
+ numPackStreams = numInStreams - numBonds;
+
+ if (numPackStreams != 1)
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(&sd, &index));
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+ }
+
+ for (i = 0; i < numCoders; i++)
+ if (!coderUsed[i])
+ {
+ indexOfMainStream = i;
+ break;
+ }
+
+ if (i == numCoders)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+ p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;
+ numCodersOutStreams += numCoders;
+ if (numCodersOutStreams < numCoders)
+ return SZ_ERROR_UNSUPPORTED;
+ if (numPackStreams > p->NumPackStreams - packStreamIndex)
+ return SZ_ERROR_ARCHIVE;
+ packStreamIndex += numPackStreams;
+ }
+ }
+
+ p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+
+ {
+ size_t dataSize = sd.Data - startBufPtr;
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoCodersOffsets[fo] = dataSize;
+ MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc);
+ }
+
+ if (external != 0)
+ {
+ if (sd.Size != 0)
+ return SZ_ERROR_ARCHIVE;
+ sd = *sd2;
+ }
+
+ RINOK(WaitId(&sd, k7zIdCodersUnpackSize));
+
+ MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc);
+ {
+ UInt32 i;
+ for (i = 0; i < numCodersOutStreams; i++)
+ {
+ RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i));
+ }
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(&sd, &type));
+ if (type == k7zIdEnd)
+ {
+ *sd2 = sd;
+ return SZ_OK;
+ }
+ if (type == k7zIdCRC)
+ {
+ RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc));
+ continue;
+ }
+ RINOK(SkipData(&sd));
+ }
+}
+
+
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
+{
+ return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]];
+}
+
+
+typedef struct
+{
+ UInt32 NumTotalSubStreams;
+ UInt32 NumSubDigests;
+ CSzData sdNumSubStreams;
+ CSzData sdSizes;
+ CSzData sdCRCs;
+} CSubStreamInfo;
+
+
+static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)
+{
+ UInt64 type = 0;
+ UInt32 numSubDigests = 0;
+ UInt32 numFolders = p->NumFolders;
+ UInt32 numUnpackStreams = numFolders;
+ UInt32 numUnpackSizesInData = 0;
+
+ for (;;)
+ {
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdNumUnpackStream)
+ {
+ UInt32 i;
+ ssi->sdNumSubStreams.Data = sd->Data;
+ numUnpackStreams = 0;
+ numSubDigests = 0;
+ for (i = 0; i < numFolders; i++)
+ {
+ UInt32 numStreams;
+ RINOK(SzReadNumber32(sd, &numStreams));
+ if (numUnpackStreams > numUnpackStreams + numStreams)
+ return SZ_ERROR_UNSUPPORTED;
+ numUnpackStreams += numStreams;
+ if (numStreams != 0)
+ numUnpackSizesInData += (numStreams - 1);
+ if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i))
+ numSubDigests += numStreams;
+ }
+ ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data;
+ continue;
+ }
+ if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd));
+ }
+
+ if (!ssi->sdNumSubStreams.Data)
+ {
+ numSubDigests = numFolders;
+ if (p->FolderCRCs.Defs)
+ numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders);
+ }
+
+ ssi->NumTotalSubStreams = numUnpackStreams;
+ ssi->NumSubDigests = numSubDigests;
+
+ if (type == k7zIdSize)
+ {
+ ssi->sdSizes.Data = sd->Data;
+ RINOK(SkipNumbers(sd, numUnpackSizesInData));
+ ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data;
+ RINOK(ReadID(sd, &type));
+ }
+
+ for (;;)
+ {
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ ssi->sdCRCs.Data = sd->Data;
+ RINOK(SkipBitUi32s(sd, numSubDigests));
+ ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data;
+ }
+ else
+ {
+ RINOK(SkipData(sd));
+ }
+ RINOK(ReadID(sd, &type));
+ }
+}
+
+static SRes SzReadStreamsInfo(CSzAr *p,
+ CSzData *sd,
+ UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
+ UInt64 *dataOffset,
+ CSubStreamInfo *ssi,
+ ISzAlloc *alloc)
+{
+ UInt64 type;
+
+ SzData_Clear(&ssi->sdSizes);
+ SzData_Clear(&ssi->sdCRCs);
+ SzData_Clear(&ssi->sdNumSubStreams);
+
+ *dataOffset = 0;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdPackInfo)
+ {
+ RINOK(ReadNumber(sd, dataOffset));
+ RINOK(ReadPackInfo(p, sd, alloc));
+ RINOK(ReadID(sd, &type));
+ }
+ if (type == k7zIdUnpackInfo)
+ {
+ RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc));
+ RINOK(ReadID(sd, &type));
+ }
+ if (type == k7zIdSubStreamsInfo)
+ {
+ RINOK(ReadSubStreamsInfo(p, sd, ssi));
+ RINOK(ReadID(sd, &type));
+ }
+ else
+ {
+ ssi->NumTotalSubStreams = p->NumFolders;
+ // ssi->NumSubDigests = 0;
+ }
+
+ return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED);
+}
+
+static SRes SzReadAndDecodePackedStreams(
+ ILookInStream *inStream,
+ CSzData *sd,
+ CBuf *tempBufs,
+ UInt32 numFoldersMax,
+ UInt64 baseOffset,
+ CSzAr *p,
+ ISzAlloc *allocTemp)
+{
+ UInt64 dataStartPos;
+ UInt32 fo;
+ CSubStreamInfo ssi;
+
+ RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp));
+
+ dataStartPos += baseOffset;
+ if (p->NumFolders == 0)
+ return SZ_ERROR_ARCHIVE;
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ Buf_Init(tempBufs + fo);
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ {
+ CBuf *tempBuf = tempBufs + fo;
+ UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo);
+ if ((size_t)unpackSize != unpackSize)
+ return SZ_ERROR_MEM;
+ if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))
+ return SZ_ERROR_MEM;
+ }
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ {
+ const CBuf *tempBuf = tempBufs + fo;
+ RINOK(LookInStream_SeekTo(inStream, dataStartPos));
+ RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp));
+ }
+
+ return SZ_OK;
+}
+
+static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
+{
+ size_t pos = 0;
+ *offsets++ = 0;
+ if (numFiles == 0)
+ return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
+ if (size < 2)
+ return SZ_ERROR_ARCHIVE;
+ if (data[size - 2] != 0 || data[size - 1] != 0)
+ return SZ_ERROR_ARCHIVE;
+ do
+ {
+ const Byte *p;
+ if (pos == size)
+ return SZ_ERROR_ARCHIVE;
+ for (p = data + pos;
+ #ifdef _WIN32
+ *(const UInt16 *)p != 0
+ #else
+ p[0] != 0 || p[1] != 0
+ #endif
+ ; p += 2);
+ pos = p - data + 2;
+ *offsets++ = (pos >> 1);
+ }
+ while (--numFiles);
+ return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
+ CSzData *sd2,
+ const CBuf *tempBufs, UInt32 numTempBufs,
+ ISzAlloc *alloc)
+{
+ CSzData sd;
+ UInt32 i;
+ CNtfsFileTime *vals;
+ Byte *defs;
+ Byte external;
+
+ RINOK(ReadBitVector(sd2, num, &p->Defs, alloc));
+
+ SZ_READ_BYTE_SD(sd2, external);
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd2, &index));
+ if (index >= numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sd.Data = tempBufs[index].data;
+ sd.Size = tempBufs[index].size;
+ }
+
+ MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc);
+ vals = p->Vals;
+ defs = p->Defs;
+ for (i = 0; i < num; i++)
+ if (SzBitArray_Check(defs, i))
+ {
+ if (sd.Size < 8)
+ return SZ_ERROR_ARCHIVE;
+ vals[i].Low = GetUi32(sd.Data);
+ vals[i].High = GetUi32(sd.Data + 4);
+ SKIP_DATA2(sd, 8);
+ }
+ else
+ vals[i].High = vals[i].Low = 0;
+
+ if (external == 0)
+ *sd2 = sd;
+
+ return SZ_OK;
+}
+
+
+#define NUM_ADDITIONAL_STREAMS_MAX 8
+
+
+static SRes SzReadHeader2(
+ CSzArEx *p, /* allocMain */
+ CSzData *sd,
+ ILookInStream *inStream,
+ CBuf *tempBufs, UInt32 *numTempBufs,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp
+ )
+{
+ CSubStreamInfo ssi;
+
+{
+ UInt64 type;
+
+ SzData_Clear(&ssi.sdSizes);
+ SzData_Clear(&ssi.sdCRCs);
+ SzData_Clear(&ssi.sdNumSubStreams);
+
+ ssi.NumSubDigests = 0;
+ ssi.NumTotalSubStreams = 0;
+
+ RINOK(ReadID(sd, &type));
+
+ if (type == k7zIdArchiveProperties)
+ {
+ for (;;)
+ {
+ UInt64 type2;
+ RINOK(ReadID(sd, &type2));
+ if (type2 == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd));
+ }
+ RINOK(ReadID(sd, &type));
+ }
+
+ if (type == k7zIdAdditionalStreamsInfo)
+ {
+ CSzAr tempAr;
+ SRes res;
+
+ SzAr_Init(&tempAr);
+ res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,
+ p->startPosAfterHeader, &tempAr, allocTemp);
+ *numTempBufs = tempAr.NumFolders;
+ SzAr_Free(&tempAr, allocTemp);
+
+ if (res != SZ_OK)
+ return res;
+ RINOK(ReadID(sd, &type));
+ }
+
+ if (type == k7zIdMainStreamsInfo)
+ {
+ RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs,
+ &p->dataPos, &ssi, allocMain));
+ p->dataPos += p->startPosAfterHeader;
+ RINOK(ReadID(sd, &type));
+ }
+
+ if (type == k7zIdEnd)
+ {
+ return SZ_OK;
+ }
+
+ if (type != k7zIdFilesInfo)
+ return SZ_ERROR_ARCHIVE;
+}
+
+{
+ UInt32 numFiles = 0;
+ UInt32 numEmptyStreams = 0;
+ const Byte *emptyStreams = NULL;
+ const Byte *emptyFiles = NULL;
+
+ RINOK(SzReadNumber32(sd, &numFiles));
+ p->NumFiles = numFiles;
+
+ for (;;)
+ {
+ UInt64 type;
+ UInt64 size;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(ReadNumber(sd, &size));
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+
+ if (type >= ((UInt32)1 << 8))
+ {
+ SKIP_DATA(sd, size);
+ }
+ else switch ((unsigned)type)
+ {
+ case k7zIdName:
+ {
+ size_t namesSize;
+ const Byte *namesData;
+ Byte external;
+
+ SZ_READ_BYTE(external);
+ if (external == 0)
+ {
+ namesSize = (size_t)size - 1;
+ namesData = sd->Data;
+ }
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index));
+ if (index >= *numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ namesData = (tempBufs)[index].data;
+ namesSize = (tempBufs)[index].size;
+ }
+
+ if ((namesSize & 1) != 0)
+ return SZ_ERROR_ARCHIVE;
+ MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
+ MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain);
+ RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
+ if (external == 0)
+ {
+ SKIP_DATA(sd, namesSize);
+ }
+ break;
+ }
+ case k7zIdEmptyStream:
+ {
+ RINOK(RememberBitVector(sd, numFiles, &emptyStreams));
+ numEmptyStreams = CountDefinedBits(emptyStreams, numFiles);
+ emptyFiles = NULL;
+ break;
+ }
+ case k7zIdEmptyFile:
+ {
+ RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles));
+ break;
+ }
+ case k7zIdWinAttrib:
+ {
+ Byte external;
+ CSzData sdSwitch;
+ CSzData *sdPtr;
+ SzBitUi32s_Free(&p->Attribs, allocMain);
+ RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain));
+
+ SZ_READ_BYTE(external);
+ if (external == 0)
+ sdPtr = sd;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index));
+ if (index >= *numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sdSwitch.Data = (tempBufs)[index].data;
+ sdSwitch.Size = (tempBufs)[index].size;
+ sdPtr = &sdSwitch;
+ }
+ RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain));
+ break;
+ }
+ /*
+ case k7zParent:
+ {
+ SzBitUi32s_Free(&p->Parents, allocMain);
+ RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain));
+ RINOK(SzReadSwitch(sd));
+ RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain));
+ break;
+ }
+ */
+ case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
+ case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
+ default:
+ {
+ SKIP_DATA(sd, size);
+ }
+ }
+ }
+
+ if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams)
+ return SZ_ERROR_ARCHIVE;
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type));
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd));
+ }
+
+ {
+ UInt32 i;
+ UInt32 emptyFileIndex = 0;
+ UInt32 folderIndex = 0;
+ UInt32 remSubStreams = 0;
+ UInt32 numSubStreams = 0;
+ UInt64 unpackPos = 0;
+ const Byte *digestsDefs = NULL;
+ const Byte *digestsVals = NULL;
+ UInt32 digestsValsIndex = 0;
+ UInt32 digestIndex;
+ Byte allDigestsDefined = 0;
+ Byte isDirMask = 0;
+ Byte crcMask = 0;
+ Byte mask = 0x80;
+
+ MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain);
+ MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain);
+ MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain);
+ MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain);
+
+ RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain));
+
+ if (ssi.sdCRCs.Size != 0)
+ {
+ SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined);
+ if (allDigestsDefined)
+ digestsVals = ssi.sdCRCs.Data;
+ else
+ {
+ size_t numBytes = (ssi.NumSubDigests + 7) >> 3;
+ digestsDefs = ssi.sdCRCs.Data;
+ digestsVals = digestsDefs + numBytes;
+ }
+ }
+
+ digestIndex = 0;
+
+ for (i = 0; i < numFiles; i++, mask >>= 1)
+ {
+ if (mask == 0)
+ {
+ UInt32 byteIndex = (i - 1) >> 3;
+ p->IsDirs[byteIndex] = isDirMask;
+ p->CRCs.Defs[byteIndex] = crcMask;
+ isDirMask = 0;
+ crcMask = 0;
+ mask = 0x80;
+ }
+
+ p->UnpackPositions[i] = unpackPos;
+ p->CRCs.Vals[i] = 0;
+
+ if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+ {
+ if (emptyFiles)
+ {
+ if (!SzBitArray_Check(emptyFiles, emptyFileIndex))
+ isDirMask |= mask;
+ emptyFileIndex++;
+ }
+ else
+ isDirMask |= mask;
+ if (remSubStreams == 0)
+ {
+ p->FileToFolder[i] = (UInt32)-1;
+ continue;
+ }
+ }
+
+ if (remSubStreams == 0)
+ {
+ for (;;)
+ {
+ if (folderIndex >= p->db.NumFolders)
+ return SZ_ERROR_ARCHIVE;
+ p->FolderToFile[folderIndex] = i;
+ numSubStreams = 1;
+ if (ssi.sdNumSubStreams.Data)
+ {
+ RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));
+ }
+ remSubStreams = numSubStreams;
+ if (numSubStreams != 0)
+ break;
+ {
+ UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ unpackPos += folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ folderIndex++;
+ }
+ }
+
+ p->FileToFolder[i] = folderIndex;
+
+ if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+ continue;
+
+ if (--remSubStreams == 0)
+ {
+ UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]];
+ if (folderUnpackSize < unpackPos - startFolderUnpackPos)
+ return SZ_ERROR_ARCHIVE;
+ unpackPos = startFolderUnpackPos + folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+
+ if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i))
+ {
+ p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];
+ crcMask |= mask;
+ }
+ else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
+ {
+ p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
+ digestsValsIndex++;
+ crcMask |= mask;
+ }
+
+ folderIndex++;
+ }
+ else
+ {
+ UInt64 v;
+ RINOK(ReadNumber(&ssi.sdSizes, &v));
+ unpackPos += v;
+ if (unpackPos < v)
+ return SZ_ERROR_ARCHIVE;
+ if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
+ {
+ p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
+ digestsValsIndex++;
+ crcMask |= mask;
+ }
+ }
+ }
+
+ if (mask != 0x80)
+ {
+ UInt32 byteIndex = (i - 1) >> 3;
+ p->IsDirs[byteIndex] = isDirMask;
+ p->CRCs.Defs[byteIndex] = crcMask;
+ }
+
+ p->UnpackPositions[i] = unpackPos;
+
+ if (remSubStreams != 0)
+ return SZ_ERROR_ARCHIVE;
+
+ for (;;)
+ {
+ p->FolderToFile[folderIndex] = i;
+ if (folderIndex >= p->db.NumFolders)
+ break;
+ if (!ssi.sdNumSubStreams.Data)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));
+ if (numSubStreams != 0)
+ return SZ_ERROR_ARCHIVE;
+ /*
+ {
+ UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ unpackPos += folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+ */
+ folderIndex++;
+ }
+
+ if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0)
+ return SZ_ERROR_ARCHIVE;
+ }
+}
+ return SZ_OK;
+}
+
+
+static SRes SzReadHeader(
+ CSzArEx *p,
+ CSzData *sd,
+ ILookInStream *inStream,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt32 i;
+ UInt32 numTempBufs = 0;
+ SRes res;
+ CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];
+
+ for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+ Buf_Init(tempBufs + i);
+
+ res = SzReadHeader2(p, sd, inStream,
+ tempBufs, &numTempBufs,
+ allocMain, allocTemp);
+
+ for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+ Buf_Free(tempBufs + i, allocTemp);
+
+ RINOK(res);
+
+ if (sd->Size != 0)
+ return SZ_ERROR_FAIL;
+
+ return res;
+}
+
+static SRes SzArEx_Open2(
+ CSzArEx *p,
+ ILookInStream *inStream,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ Byte header[k7zStartHeaderSize];
+ Int64 startArcPos;
+ UInt64 nextHeaderOffset, nextHeaderSize;
+ size_t nextHeaderSizeT;
+ UInt32 nextHeaderCRC;
+ CBuf buf;
+ SRes res;
+
+ startArcPos = 0;
+ RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
+
+ RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
+
+ if (!TestSignatureCandidate(header))
+ return SZ_ERROR_NO_ARCHIVE;
+ if (header[6] != k7zMajorVersion)
+ return SZ_ERROR_UNSUPPORTED;
+
+ nextHeaderOffset = GetUi64(header + 12);
+ nextHeaderSize = GetUi64(header + 20);
+ nextHeaderCRC = GetUi32(header + 28);
+
+ p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
+
+ if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
+ return SZ_ERROR_CRC;
+
+ nextHeaderSizeT = (size_t)nextHeaderSize;
+ if (nextHeaderSizeT != nextHeaderSize)
+ return SZ_ERROR_MEM;
+ if (nextHeaderSizeT == 0)
+ return SZ_OK;
+ if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
+ nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
+ return SZ_ERROR_NO_ARCHIVE;
+
+ {
+ Int64 pos = 0;
+ RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
+ if ((UInt64)pos < startArcPos + nextHeaderOffset ||
+ (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
+ (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
+ return SZ_ERROR_INPUT_EOF;
+ }
+
+ RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
+
+ if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))
+ return SZ_ERROR_MEM;
+
+ res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT);
+
+ if (res == SZ_OK)
+ {
+ res = SZ_ERROR_ARCHIVE;
+ if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC)
+ {
+ CSzData sd;
+ UInt64 type;
+ sd.Data = buf.data;
+ sd.Size = buf.size;
+
+ res = ReadID(&sd, &type);
+
+ if (res == SZ_OK && type == k7zIdEncodedHeader)
+ {
+ CSzAr tempAr;
+ CBuf tempBuf;
+ Buf_Init(&tempBuf);
+
+ SzAr_Init(&tempAr);
+ res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp);
+ SzAr_Free(&tempAr, allocTemp);
+
+ if (res != SZ_OK)
+ {
+ Buf_Free(&tempBuf, allocTemp);
+ }
+ else
+ {
+ Buf_Free(&buf, allocTemp);
+ buf.data = tempBuf.data;
+ buf.size = tempBuf.size;
+ sd.Data = buf.data;
+ sd.Size = buf.size;
+ res = ReadID(&sd, &type);
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ if (type == k7zIdHeader)
+ {
+ /*
+ CSzData sd2;
+ unsigned ttt;
+ for (ttt = 0; ttt < 40000; ttt++)
+ {
+ SzArEx_Free(p, allocMain);
+ sd2 = sd;
+ res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ break;
+ }
+ */
+ res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp);
+ }
+ else
+ res = SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+
+ Buf_Free(&buf, allocTemp);
+ return res;
+}
+
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
+ ISzAlloc *allocMain, ISzAlloc *allocTemp)
+{
+ SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ SzArEx_Free(p, allocMain);
+ return res;
+}
+
+
+SRes SzArEx_Extract(
+ const CSzArEx *p,
+ ILookInStream *inStream,
+ UInt32 fileIndex,
+ UInt32 *blockIndex,
+ Byte **tempBuf,
+ size_t *outBufferSize,
+ size_t *offset,
+ size_t *outSizeProcessed,
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp)
+{
+ UInt32 folderIndex = p->FileToFolder[fileIndex];
+ SRes res = SZ_OK;
+
+ *offset = 0;
+ *outSizeProcessed = 0;
+
+ if (folderIndex == (UInt32)-1)
+ {
+ IAlloc_Free(allocMain, *tempBuf);
+ *blockIndex = folderIndex;
+ *tempBuf = NULL;
+ *outBufferSize = 0;
+ return SZ_OK;
+ }
+
+ if (*tempBuf == NULL || *blockIndex != folderIndex)
+ {
+ UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ /*
+ UInt64 unpackSizeSpec =
+ p->UnpackPositions[p->FolderToFile[folderIndex + 1]] -
+ p->UnpackPositions[p->FolderToFile[folderIndex]];
+ */
+ size_t unpackSize = (size_t)unpackSizeSpec;
+
+ if (unpackSize != unpackSizeSpec)
+ return SZ_ERROR_MEM;
+ *blockIndex = folderIndex;
+ IAlloc_Free(allocMain, *tempBuf);
+ *tempBuf = NULL;
+
+ if (res == SZ_OK)
+ {
+ *outBufferSize = unpackSize;
+ if (unpackSize != 0)
+ {
+ *tempBuf = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
+ if (*tempBuf == NULL)
+ res = SZ_ERROR_MEM;
+ }
+
+ if (res == SZ_OK)
+ {
+ res = SzAr_DecodeFolder(&p->db, folderIndex,
+ inStream, p->dataPos, *tempBuf, unpackSize, allocTemp);
+ }
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ UInt64 unpackPos = p->UnpackPositions[fileIndex];
+ *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]);
+ *outSizeProcessed = (size_t)(p->UnpackPositions[fileIndex + 1] - unpackPos);
+ if (*offset + *outSizeProcessed > *outBufferSize)
+ return SZ_ERROR_FAIL;
+ if (SzBitWithVals_Check(&p->CRCs, fileIndex))
+ if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex])
+ res = SZ_ERROR_CRC;
+ }
+
+ return res;
+}
+
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+ size_t offs = p->FileNameOffsets[fileIndex];
+ size_t len = p->FileNameOffsets[fileIndex + 1] - offs;
+ if (dest != 0)
+ {
+ size_t i;
+ const Byte *src = p->FileNames + offs * 2;
+ for (i = 0; i < len; i++)
+ dest[i] = GetUi16(src + i * 2);
+ }
+ return len;
+}
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex)
+{
+ size_t len;
+ if (!p->FileNameOffsets)
+ return 1;
+ len = 0;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+ if SzBitWithVals_Check(&p->Parents, fileIndex)
+ parent = p->Parents.Vals[fileIndex];
+ if (parent == (UInt32)(Int32)-1)
+ return len;
+ fileIndex = parent;
+ }
+}
+
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+ Bool needSlash;
+ if (!p->FileNameOffsets)
+ {
+ *(--dest) = 0;
+ return dest;
+ }
+ needSlash = False;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+ SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen);
+ if (needSlash)
+ *(dest - 1) = '/';
+ needSlash = True;
+ dest -= curLen;
+
+ if SzBitWithVals_Check(&p->Parents, fileIndex)
+ parent = p->Parents.Vals[fileIndex];
+ if (parent == (UInt32)(Int32)-1)
+ return dest;
+ fileIndex = parent;
+ }
+}
+*/
diff --git a/SevenZip/7zBuf.c b/SevenZip/7zBuf.c
new file mode 100644
index 0000000..089a5c4
--- /dev/null
+++ b/SevenZip/7zBuf.c
@@ -0,0 +1,36 @@
+/* 7zBuf.c -- Byte Buffer
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zBuf.h"
+
+void Buf_Init(CBuf *p)
+{
+ p->data = 0;
+ p->size = 0;
+}
+
+int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc)
+{
+ p->size = 0;
+ if (size == 0)
+ {
+ p->data = 0;
+ return 1;
+ }
+ p->data = (Byte *)alloc->Alloc(alloc, size);
+ if (p->data != 0)
+ {
+ p->size = size;
+ return 1;
+ }
+ return 0;
+}
+
+void Buf_Free(CBuf *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+}
diff --git a/SevenZip/7zBuf.h b/SevenZip/7zBuf.h
new file mode 100644
index 0000000..65f1d7a
--- /dev/null
+++ b/SevenZip/7zBuf.h
@@ -0,0 +1,35 @@
+/* 7zBuf.h -- Byte Buffer
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_BUF_H
+#define __7Z_BUF_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+} CBuf;
+
+void Buf_Init(CBuf *p);
+int Buf_Create(CBuf *p, size_t size, ISzAlloc *alloc);
+void Buf_Free(CBuf *p, ISzAlloc *alloc);
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+ size_t pos;
+} CDynBuf;
+
+void DynBuf_Construct(CDynBuf *p);
+void DynBuf_SeekToBeg(CDynBuf *p);
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAlloc *alloc);
+void DynBuf_Free(CDynBuf *p, ISzAlloc *alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/7zCrc.c b/SevenZip/7zCrc.c
new file mode 100644
index 0000000..dc6d6ab
--- /dev/null
+++ b/SevenZip/7zCrc.c
@@ -0,0 +1,128 @@
+/* 7zCrc.c -- CRC32 init
+2015-03-10 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define kCrcPoly 0xEDB88320
+
+#ifdef MY_CPU_LE
+ #define CRC_NUM_TABLES 8
+#else
+ #define CRC_NUM_TABLES 9
+
+ #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
+
+ UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+
+#ifndef MY_CPU_BE
+ UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+
+typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+CRC_FUNC g_CrcUpdateT4;
+CRC_FUNC g_CrcUpdateT8;
+CRC_FUNC g_CrcUpdate;
+
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+ return g_CrcUpdate(v, data, size, g_CrcTable);
+}
+
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
+{
+ return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
+}
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ const Byte *pEnd = p + size;
+ for (; p != pEnd; p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+void MY_FAST_CALL CrcGenerateTable()
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ g_CrcTable[i] = r;
+ }
+ for (; i < 256 * CRC_NUM_TABLES; i++)
+ {
+ UInt32 r = g_CrcTable[i - 256];
+ g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+ }
+
+ #if CRC_NUM_TABLES < 4
+
+ g_CrcUpdate = CrcUpdateT1;
+
+ #else
+
+ #ifdef MY_CPU_LE
+
+ g_CrcUpdateT4 = CrcUpdateT4;
+ g_CrcUpdate = CrcUpdateT4;
+
+ #if CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT8;
+
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (!CPU_Is_InOrder())
+ g_CrcUpdate = CrcUpdateT8;
+ #endif
+ #endif
+
+ #else
+ {
+ #ifndef MY_CPU_BE
+ UInt32 k = 0x01020304;
+ const Byte *p = (const Byte *)&k;
+ if (p[0] == 4 && p[1] == 3)
+ {
+ g_CrcUpdateT4 = CrcUpdateT4;
+ g_CrcUpdate = CrcUpdateT4;
+ #if CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT8;
+ // g_CrcUpdate = CrcUpdateT8;
+ #endif
+ }
+ else if (p[0] != 1 || p[1] != 2)
+ g_CrcUpdate = CrcUpdateT1;
+ else
+ #endif
+ {
+ for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)
+ {
+ UInt32 x = g_CrcTable[i - 256];
+ g_CrcTable[i] = CRC_UINT32_SWAP(x);
+ }
+ g_CrcUpdateT4 = CrcUpdateT1_BeT4;
+ g_CrcUpdate = CrcUpdateT1_BeT4;
+ #if CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT1_BeT8;
+ // g_CrcUpdate = CrcUpdateT1_BeT8;
+ #endif
+ }
+ }
+ #endif
+
+ #endif
+}
diff --git a/SevenZip/7zCrc.h b/SevenZip/7zCrc.h
new file mode 100644
index 0000000..8fd5795
--- /dev/null
+++ b/SevenZip/7zCrc.h
@@ -0,0 +1,25 @@
+/* 7zCrc.h -- CRC32 calculation
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_CRC_H
+#define __7Z_CRC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+extern UInt32 g_CrcTable[];
+
+/* Call CrcGenerateTable one time before other CRC functions */
+void MY_FAST_CALL CrcGenerateTable(void);
+
+#define CRC_INIT_VAL 0xFFFFFFFF
+#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
+#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
+UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/7zCrcOpt.c b/SevenZip/7zCrcOpt.c
new file mode 100644
index 0000000..d1e1cd7
--- /dev/null
+++ b/SevenZip/7zCrcOpt.c
@@ -0,0 +1,115 @@
+/* 7zCrcOpt.c -- CRC32 calculation
+2015-03-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifndef MY_CPU_BE
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x300 + ((v ) & 0xFF)]
+ ^ table[0x200 + ((v >> 8) & 0xFF)]
+ ^ table[0x100 + ((v >> 16) & 0xFF)]
+ ^ table[0x000 + ((v >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ for (; size >= 8; size -= 8, p += 8)
+ {
+ UInt32 d;
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x700 + ((v ) & 0xFF)]
+ ^ table[0x600 + ((v >> 8) & 0xFF)]
+ ^ table[0x500 + ((v >> 16) & 0xFF)]
+ ^ table[0x400 + ((v >> 24))];
+ d = *((const UInt32 *)p + 1);
+ v ^=
+ table[0x300 + ((d ) & 0xFF)]
+ ^ table[0x200 + ((d >> 8) & 0xFF)]
+ ^ table[0x100 + ((d >> 16) & 0xFF)]
+ ^ table[0x000 + ((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+#endif
+
+
+#ifndef MY_CPU_LE
+
+#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
+
+#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))
+
+UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ table += 0x100;
+ v = CRC_UINT32_SWAP(v);
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x000 + ((v ) & 0xFF)]
+ ^ table[0x100 + ((v >> 8) & 0xFF)]
+ ^ table[0x200 + ((v >> 16) & 0xFF)]
+ ^ table[0x300 + ((v >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ return CRC_UINT32_SWAP(v);
+}
+
+UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ table += 0x100;
+ v = CRC_UINT32_SWAP(v);
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ for (; size >= 8; size -= 8, p += 8)
+ {
+ UInt32 d;
+ v ^= *(const UInt32 *)p;
+ v =
+ table[0x400 + ((v ) & 0xFF)]
+ ^ table[0x500 + ((v >> 8) & 0xFF)]
+ ^ table[0x600 + ((v >> 16) & 0xFF)]
+ ^ table[0x700 + ((v >> 24))];
+ d = *((const UInt32 *)p + 1);
+ v ^=
+ table[0x000 + ((d ) & 0xFF)]
+ ^ table[0x100 + ((d >> 8) & 0xFF)]
+ ^ table[0x200 + ((d >> 16) & 0xFF)]
+ ^ table[0x300 + ((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ return CRC_UINT32_SWAP(v);
+}
+
+#endif
diff --git a/SevenZip/7zDec.c b/SevenZip/7zDec.c
new file mode 100644
index 0000000..c45d6bf
--- /dev/null
+++ b/SevenZip/7zDec.c
@@ -0,0 +1,591 @@
+/* 7zDec.c -- Decoding from 7z folder
+2015-11-18 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include
+
+/* #define _7ZIP_PPMD_SUPPPORT */
+
+#include "7z.h"
+#include "7zCrc.h"
+
+#include "Bcj2.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "LzmaDec.h"
+#include "Lzma2Dec.h"
+#ifdef _7ZIP_PPMD_SUPPPORT
+#include "Ppmd7.h"
+#endif
+
+#define k_Copy 0
+#define k_Delta 3
+#define k_LZMA2 0x21
+#define k_LZMA 0x30101
+#define k_BCJ 0x3030103
+#define k_BCJ2 0x303011B
+#define k_PPC 0x3030205
+#define k_IA64 0x3030401
+#define k_ARM 0x3030501
+#define k_ARMT 0x3030701
+#define k_SPARC 0x3030805
+
+
+#ifdef _7ZIP_PPMD_SUPPPORT
+
+#define k_PPMD 0x30401
+
+typedef struct
+{
+ IByteIn p;
+ const Byte *cur;
+ const Byte *end;
+ const Byte *begin;
+ UInt64 processed;
+ Bool extra;
+ SRes res;
+ ILookInStream *inStream;
+} CByteInToLook;
+
+static Byte ReadByte(void *pp)
+{
+ CByteInToLook *p = (CByteInToLook *)pp;
+ if (p->cur != p->end)
+ return *p->cur++;
+ if (p->res == SZ_OK)
+ {
+ size_t size = p->cur - p->begin;
+ p->processed += size;
+ p->res = p->inStream->Skip(p->inStream, size);
+ size = (1 << 25);
+ p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
+ p->cur = p->begin;
+ p->end = p->begin + size;
+ if (size != 0)
+ return *p->cur++;;
+ }
+ p->extra = True;
+ return 0;
+}
+
+static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
+{
+ CPpmd7 ppmd;
+ CByteInToLook s;
+ SRes res = SZ_OK;
+
+ s.p.Read = ReadByte;
+ s.inStream = inStream;
+ s.begin = s.end = s.cur = NULL;
+ s.extra = False;
+ s.res = SZ_OK;
+ s.processed = 0;
+
+ if (propsSize != 5)
+ return SZ_ERROR_UNSUPPORTED;
+
+ {
+ unsigned order = props[0];
+ UInt32 memSize = GetUi32(props + 1);
+ if (order < PPMD7_MIN_ORDER ||
+ order > PPMD7_MAX_ORDER ||
+ memSize < PPMD7_MIN_MEM_SIZE ||
+ memSize > PPMD7_MAX_MEM_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ Ppmd7_Construct(&ppmd);
+ if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
+ return SZ_ERROR_MEM;
+ Ppmd7_Init(&ppmd, order);
+ }
+ {
+ CPpmd7z_RangeDec rc;
+ Ppmd7z_RangeDec_CreateVTable(&rc);
+ rc.Stream = &s.p;
+ if (!Ppmd7z_RangeDec_Init(&rc))
+ res = SZ_ERROR_DATA;
+ else if (s.extra)
+ res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
+ else
+ {
+ SizeT i;
+ for (i = 0; i < outSize; i++)
+ {
+ int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
+ if (s.extra || sym < 0)
+ break;
+ outBuffer[i] = (Byte)sym;
+ }
+ if (i != outSize)
+ res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
+ else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
+ res = SZ_ERROR_DATA;
+ }
+ }
+ Ppmd7_Free(&ppmd, allocMain);
+ return res;
+}
+
+#endif
+
+
+static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
+{
+ CLzmaDec state;
+ SRes res = SZ_OK;
+
+ LzmaDec_Construct(&state);
+ RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
+ state.dic = outBuffer;
+ state.dicBufSize = outSize;
+ LzmaDec_Init(&state);
+
+ for (;;)
+ {
+ const void *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = inStream->Look(inStream, &inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
+ ELzmaStatus status;
+ res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ {
+ if (outSize != state.dicPos || inSize != 0)
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ break;
+
+ if (inProcessed == 0 && dicPos == state.dicPos)
+ {
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ res = inStream->Skip((void *)inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ LzmaDec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+
+#ifndef _7Z_NO_METHOD_LZMA2
+
+static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
+{
+ CLzma2Dec state;
+ SRes res = SZ_OK;
+
+ Lzma2Dec_Construct(&state);
+ if (propsSize != 1)
+ return SZ_ERROR_DATA;
+ RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
+ state.decoder.dic = outBuffer;
+ state.decoder.dicBufSize = outSize;
+ Lzma2Dec_Init(&state);
+
+ for (;;)
+ {
+ const void *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = inStream->Look(inStream, &inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
+ ELzmaStatus status;
+ res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ {
+ if (outSize != state.decoder.dicPos || inSize != 0)
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ if (inProcessed == 0 && dicPos == state.decoder.dicPos)
+ {
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ res = inStream->Skip((void *)inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ Lzma2Dec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+#endif
+
+
+static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
+{
+ while (inSize > 0)
+ {
+ const void *inBuf;
+ size_t curSize = (1 << 18);
+ if (curSize > inSize)
+ curSize = (size_t)inSize;
+ RINOK(inStream->Look(inStream, &inBuf, &curSize));
+ if (curSize == 0)
+ return SZ_ERROR_INPUT_EOF;
+ memcpy(outBuffer, inBuf, curSize);
+ outBuffer += curSize;
+ inSize -= curSize;
+ RINOK(inStream->Skip((void *)inStream, curSize));
+ }
+ return SZ_OK;
+}
+
+static Bool IS_MAIN_METHOD(UInt32 m)
+{
+ switch (m)
+ {
+ case k_Copy:
+ case k_LZMA:
+ #ifndef _7Z_NO_METHOD_LZMA2
+ case k_LZMA2:
+ #endif
+ #ifdef _7ZIP_PPMD_SUPPPORT
+ case k_PPMD:
+ #endif
+ return True;
+ }
+ return False;
+}
+
+static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
+{
+ return
+ c->NumStreams == 1
+ /* && c->MethodID <= (UInt32)0xFFFFFFFF */
+ && IS_MAIN_METHOD((UInt32)c->MethodID);
+}
+
+#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
+
+static SRes CheckSupportedFolder(const CSzFolder *f)
+{
+ if (f->NumCoders < 1 || f->NumCoders > 4)
+ return SZ_ERROR_UNSUPPORTED;
+ if (!IS_SUPPORTED_CODER(&f->Coders[0]))
+ return SZ_ERROR_UNSUPPORTED;
+ if (f->NumCoders == 1)
+ {
+ if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return SZ_OK;
+ }
+
+
+ #ifndef _7Z_NO_METHODS_FILTERS
+
+ if (f->NumCoders == 2)
+ {
+ const CSzCoderInfo *c = &f->Coders[1];
+ if (
+ /* c->MethodID > (UInt32)0xFFFFFFFF || */
+ c->NumStreams != 1
+ || f->NumPackStreams != 1
+ || f->PackStreams[0] != 0
+ || f->NumBonds != 1
+ || f->Bonds[0].InIndex != 1
+ || f->Bonds[0].OutIndex != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ switch ((UInt32)c->MethodID)
+ {
+ case k_Delta:
+ case k_BCJ:
+ case k_PPC:
+ case k_IA64:
+ case k_SPARC:
+ case k_ARM:
+ case k_ARMT:
+ break;
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+ }
+
+ #endif
+
+
+ if (f->NumCoders == 4)
+ {
+ if (!IS_SUPPORTED_CODER(&f->Coders[1])
+ || !IS_SUPPORTED_CODER(&f->Coders[2])
+ || !IS_BCJ2(&f->Coders[3]))
+ return SZ_ERROR_UNSUPPORTED;
+ if (f->NumPackStreams != 4
+ || f->PackStreams[0] != 2
+ || f->PackStreams[1] != 6
+ || f->PackStreams[2] != 1
+ || f->PackStreams[3] != 0
+ || f->NumBonds != 3
+ || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
+ || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
+ || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
+ return SZ_ERROR_UNSUPPORTED;
+ return SZ_OK;
+ }
+
+ return SZ_ERROR_UNSUPPORTED;
+}
+
+#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
+
+static SRes SzFolder_Decode2(const CSzFolder *folder,
+ const Byte *propsData,
+ const UInt64 *unpackSizes,
+ const UInt64 *packPositions,
+ ILookInStream *inStream, UInt64 startPos,
+ Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
+ Byte *tempBuf[])
+{
+ UInt32 ci;
+ SizeT tempSizes[3] = { 0, 0, 0};
+ SizeT tempSize3 = 0;
+ Byte *tempBuf3 = 0;
+
+ RINOK(CheckSupportedFolder(folder));
+
+ for (ci = 0; ci < folder->NumCoders; ci++)
+ {
+ const CSzCoderInfo *coder = &folder->Coders[ci];
+
+ if (IS_MAIN_METHOD((UInt32)coder->MethodID))
+ {
+ UInt32 si = 0;
+ UInt64 offset;
+ UInt64 inSize;
+ Byte *outBufCur = outBuffer;
+ SizeT outSizeCur = outSize;
+ if (folder->NumCoders == 4)
+ {
+ UInt32 indices[] = { 3, 2, 0 };
+ UInt64 unpackSize = unpackSizes[ci];
+ si = indices[ci];
+ if (ci < 2)
+ {
+ Byte *temp;
+ outSizeCur = (SizeT)unpackSize;
+ if (outSizeCur != unpackSize)
+ return SZ_ERROR_MEM;
+ temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
+ if (!temp && outSizeCur != 0)
+ return SZ_ERROR_MEM;
+ outBufCur = tempBuf[1 - ci] = temp;
+ tempSizes[1 - ci] = outSizeCur;
+ }
+ else if (ci == 2)
+ {
+ if (unpackSize > outSize) /* check it */
+ return SZ_ERROR_PARAM;
+ tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
+ tempSize3 = outSizeCur = (SizeT)unpackSize;
+ }
+ else
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ offset = packPositions[si];
+ inSize = packPositions[si + 1] - offset;
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset));
+
+ if (coder->MethodID == k_Copy)
+ {
+ if (inSize != outSizeCur) /* check it */
+ return SZ_ERROR_DATA;
+ RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
+ }
+ else if (coder->MethodID == k_LZMA)
+ {
+ RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ }
+ #ifndef _7Z_NO_METHOD_LZMA2
+ else if (coder->MethodID == k_LZMA2)
+ {
+ RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ }
+ #endif
+ #ifdef _7ZIP_PPMD_SUPPPORT
+ else if (coder->MethodID == k_PPMD)
+ {
+ RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
+ }
+ #endif
+ else
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ else if (coder->MethodID == k_BCJ2)
+ {
+ UInt64 offset = packPositions[1];
+ UInt64 s3Size = packPositions[2] - offset;
+
+ if (ci != 3)
+ return SZ_ERROR_UNSUPPORTED;
+
+ tempSizes[2] = (SizeT)s3Size;
+ if (tempSizes[2] != s3Size)
+ return SZ_ERROR_MEM;
+ tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
+ if (!tempBuf[2] && tempSizes[2] != 0)
+ return SZ_ERROR_MEM;
+
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset));
+ RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));
+
+ if ((tempSizes[0] & 3) != 0 ||
+ (tempSizes[1] & 3) != 0 ||
+ tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
+ return SZ_ERROR_DATA;
+
+ {
+ CBcj2Dec p;
+
+ p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;
+ p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
+ p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
+ p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
+
+ p.dest = outBuffer;
+ p.destLim = outBuffer + outSize;
+
+ Bcj2Dec_Init(&p);
+ RINOK(Bcj2Dec_Decode(&p));
+
+ {
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ if (p.bufs[i] != p.lims[i])
+ return SZ_ERROR_DATA;
+
+ if (!Bcj2Dec_IsFinished(&p))
+ return SZ_ERROR_DATA;
+
+ if (p.dest != p.destLim
+ || p.state != BCJ2_STREAM_MAIN)
+ return SZ_ERROR_DATA;
+ }
+ }
+ }
+ #ifndef _7Z_NO_METHODS_FILTERS
+ else if (ci == 1)
+ {
+ if (coder->MethodID == k_Delta)
+ {
+ if (coder->PropsSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ {
+ Byte state[DELTA_STATE_SIZE];
+ Delta_Init(state);
+ Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
+ }
+ }
+ else
+ {
+ if (coder->PropsSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ switch (coder->MethodID)
+ {
+ case k_BCJ:
+ {
+ UInt32 state;
+ x86_Convert_Init(state);
+ x86_Convert(outBuffer, outSize, 0, &state, 0);
+ break;
+ }
+ CASE_BRA_CONV(PPC)
+ CASE_BRA_CONV(IA64)
+ CASE_BRA_CONV(SPARC)
+ CASE_BRA_CONV(ARM)
+ CASE_BRA_CONV(ARMT)
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+ #endif
+ else
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ return SZ_OK;
+}
+
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+ ILookInStream *inStream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize,
+ ISzAlloc *allocMain)
+{
+ SRes res;
+ CSzFolder folder;
+ CSzData sd;
+
+ const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
+ sd.Data = data;
+ sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
+
+ res = SzGetNextFolderItem(&folder, &sd);
+
+ if (res != SZ_OK)
+ return res;
+
+ if (sd.Size != 0
+ || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
+ || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
+ return SZ_ERROR_FAIL;
+ {
+ unsigned i;
+ Byte *tempBuf[3] = { 0, 0, 0};
+
+ res = SzFolder_Decode2(&folder, data,
+ &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
+ p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
+ inStream, startPos,
+ outBuffer, (SizeT)outSize, allocMain, tempBuf);
+
+ for (i = 0; i < 3; i++)
+ IAlloc_Free(allocMain, tempBuf[i]);
+
+ if (res == SZ_OK)
+ if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
+ if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
+ res = SZ_ERROR_CRC;
+
+ return res;
+ }
+}
diff --git a/SevenZip/7zFile.c b/SevenZip/7zFile.c
new file mode 100644
index 0000000..041e5b1
--- /dev/null
+++ b/SevenZip/7zFile.c
@@ -0,0 +1,286 @@
+/* 7zFile.c -- File IO
+2009-11-24 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zFile.h"
+
+#ifndef USE_WINDOWS_FILE
+
+#ifndef UNDER_CE
+#include
+#endif
+
+#else
+
+/*
+ ReadFile and WriteFile functions in Windows have BUG:
+ If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
+ from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
+ (Insufficient system resources exist to complete the requested service).
+ Probably in some version of Windows there are problems with other sizes:
+ for 32 MB (maybe also for 16 MB).
+ And message can be "Network connection was lost"
+*/
+
+#define kChunkSizeMax (1 << 22)
+
+#endif
+
+void File_Construct(CSzFile *p)
+{
+ #ifdef USE_WINDOWS_FILE
+ p->handle = INVALID_HANDLE_VALUE;
+ #else
+ p->file = NULL;
+ #endif
+}
+
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+static WRes File_Open(CSzFile *p, const char *name, int writeMode)
+{
+ #ifdef USE_WINDOWS_FILE
+ p->handle = CreateFileA(name,
+ writeMode ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, NULL,
+ writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+ #else
+ p->file = fopen(name, writeMode ? "wb+" : "rb");
+ return (p->file != 0) ? 0 :
+ #ifdef UNDER_CE
+ 2; /* ENOENT */
+ #else
+ errno;
+ #endif
+ #endif
+}
+
+WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
+WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
+#endif
+
+#ifdef USE_WINDOWS_FILE
+static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
+{
+ p->handle = CreateFileW(name,
+ writeMode ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, NULL,
+ writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+}
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
+#endif
+
+WRes File_Close(CSzFile *p)
+{
+ #ifdef USE_WINDOWS_FILE
+ if (p->handle != INVALID_HANDLE_VALUE)
+ {
+ if (!CloseHandle(p->handle))
+ return GetLastError();
+ p->handle = INVALID_HANDLE_VALUE;
+ }
+ #else
+ if (p->file != NULL)
+ {
+ int res = fclose(p->file);
+ if (res != 0)
+ return res;
+ p->file = NULL;
+ }
+ #endif
+ return 0;
+}
+
+WRes File_Read(CSzFile *p, void *data, size_t *size)
+{
+ size_t originalSize = *size;
+ if (originalSize == 0)
+ return 0;
+
+ #ifdef USE_WINDOWS_FILE
+
+ *size = 0;
+ do
+ {
+ DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+ DWORD processed = 0;
+ BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
+ data = (void *)((Byte *)data + processed);
+ originalSize -= processed;
+ *size += processed;
+ if (!res)
+ return GetLastError();
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+ return 0;
+
+ #else
+
+ *size = fread(data, 1, originalSize, p->file);
+ if (*size == originalSize)
+ return 0;
+ return ferror(p->file);
+
+ #endif
+}
+
+WRes File_Write(CSzFile *p, const void *data, size_t *size)
+{
+ size_t originalSize = *size;
+ if (originalSize == 0)
+ return 0;
+
+ #ifdef USE_WINDOWS_FILE
+
+ *size = 0;
+ do
+ {
+ DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+ DWORD processed = 0;
+ BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
+ data = (void *)((Byte *)data + processed);
+ originalSize -= processed;
+ *size += processed;
+ if (!res)
+ return GetLastError();
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+ return 0;
+
+ #else
+
+ *size = fwrite(data, 1, originalSize, p->file);
+ if (*size == originalSize)
+ return 0;
+ return ferror(p->file);
+
+ #endif
+}
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ LARGE_INTEGER value;
+ DWORD moveMethod;
+ value.LowPart = (DWORD)*pos;
+ value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
+ switch (origin)
+ {
+ case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
+ case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
+ case SZ_SEEK_END: moveMethod = FILE_END; break;
+ default: return ERROR_INVALID_PARAMETER;
+ }
+ value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
+ if (value.LowPart == 0xFFFFFFFF)
+ {
+ WRes res = GetLastError();
+ if (res != NO_ERROR)
+ return res;
+ }
+ *pos = ((Int64)value.HighPart << 32) | value.LowPart;
+ return 0;
+
+ #else
+
+ int moveMethod;
+ int res;
+ switch (origin)
+ {
+ case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
+ case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
+ case SZ_SEEK_END: moveMethod = SEEK_END; break;
+ default: return 1;
+ }
+ res = fseek(p->file, (long)*pos, moveMethod);
+ *pos = ftell(p->file);
+ return res;
+
+ #endif
+}
+
+WRes File_GetLength(CSzFile *p, UInt64 *length)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ DWORD sizeHigh;
+ DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
+ if (sizeLow == 0xFFFFFFFF)
+ {
+ DWORD res = GetLastError();
+ if (res != NO_ERROR)
+ return res;
+ }
+ *length = (((UInt64)sizeHigh) << 32) + sizeLow;
+ return 0;
+
+ #else
+
+ long pos = ftell(p->file);
+ int res = fseek(p->file, 0, SEEK_END);
+ *length = ftell(p->file);
+ fseek(p->file, pos, SEEK_SET);
+ return res;
+
+ #endif
+}
+
+
+/* ---------- FileSeqInStream ---------- */
+
+static SRes FileSeqInStream_Read(void *pp, void *buf, size_t *size)
+{
+ CFileSeqInStream *p = (CFileSeqInStream *)pp;
+ return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
+}
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
+{
+ p->s.Read = FileSeqInStream_Read;
+}
+
+
+/* ---------- FileInStream ---------- */
+
+static SRes FileInStream_Read(void *pp, void *buf, size_t *size)
+{
+ CFileInStream *p = (CFileInStream *)pp;
+ return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes FileInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CFileInStream *p = (CFileInStream *)pp;
+ return File_Seek(&p->file, pos, origin);
+}
+
+void FileInStream_CreateVTable(CFileInStream *p)
+{
+ p->s.Read = FileInStream_Read;
+ p->s.Seek = FileInStream_Seek;
+}
+
+
+/* ---------- FileOutStream ---------- */
+
+static size_t FileOutStream_Write(void *pp, const void *data, size_t size)
+{
+ CFileOutStream *p = (CFileOutStream *)pp;
+ File_Write(&p->file, data, &size);
+ return size;
+}
+
+void FileOutStream_CreateVTable(CFileOutStream *p)
+{
+ p->s.Write = FileOutStream_Write;
+}
diff --git a/SevenZip/7zFile.h b/SevenZip/7zFile.h
new file mode 100644
index 0000000..658987e
--- /dev/null
+++ b/SevenZip/7zFile.h
@@ -0,0 +1,83 @@
+/* 7zFile.h -- File IO
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_FILE_H
+#define __7Z_FILE_H
+
+#ifdef _WIN32
+#define USE_WINDOWS_FILE
+#endif
+
+#ifdef USE_WINDOWS_FILE
+#include
+#else
+#include
+#endif
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- File ---------- */
+
+typedef struct
+{
+ #ifdef USE_WINDOWS_FILE
+ HANDLE handle;
+ #else
+ FILE *file;
+ #endif
+} CSzFile;
+
+void File_Construct(CSzFile *p);
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+WRes InFile_Open(CSzFile *p, const char *name);
+WRes OutFile_Open(CSzFile *p, const char *name);
+#endif
+#ifdef USE_WINDOWS_FILE
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
+#endif
+WRes File_Close(CSzFile *p);
+
+/* reads max(*size, remain file's size) bytes */
+WRes File_Read(CSzFile *p, void *data, size_t *size);
+
+/* writes *size bytes */
+WRes File_Write(CSzFile *p, const void *data, size_t *size);
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
+WRes File_GetLength(CSzFile *p, UInt64 *length);
+
+
+/* ---------- FileInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream s;
+ CSzFile file;
+} CFileSeqInStream;
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
+
+
+typedef struct
+{
+ ISeekInStream s;
+ CSzFile file;
+} CFileInStream;
+
+void FileInStream_CreateVTable(CFileInStream *p);
+
+
+typedef struct
+{
+ ISeqOutStream s;
+ CSzFile file;
+} CFileOutStream;
+
+void FileOutStream_CreateVTable(CFileOutStream *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/7zMemBuffer.c b/SevenZip/7zMemBuffer.c
new file mode 100644
index 0000000..e2dbd0f
--- /dev/null
+++ b/SevenZip/7zMemBuffer.c
@@ -0,0 +1,53 @@
+#include "Precomp.h"
+#include "7zMemBuffer.h"
+#include
+
+WRes MemBuffer_Read(CSzMemBuffer *p, void *data, size_t *size)
+{
+ size_t originalSize = *size;
+ if(originalSize == 0)
+ return 0;
+
+ size_t length = (size_t)(p->pos + (Int64)(*size) > p->size ? p->size - p->pos - 1 : *size);
+ memcpy(data, (char*)(p->buffer) + p->pos, length);
+ p->pos += length;
+ return 0;
+}
+
+WRes MemBuffer_Seek(CSzMemBuffer *p, Int64 *pos, ESzSeek origin)
+{
+ switch(origin) {
+ case SZ_SEEK_SET: p->pos = 0 + *pos; break;
+ case SZ_SEEK_CUR: p->pos += *pos; break;
+ case SZ_SEEK_END: p->pos = p->size - *pos; break;
+ default: return 1;
+ }
+ *pos = p->pos;
+ return 0;
+}
+
+static SRes MemBufferInStream_Read(void *pp, void *buf, size_t *size)
+{
+ CMemBufferInStream *p = (CMemBufferInStream *)pp;
+ return (MemBuffer_Read(&p->buffer, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes MemBufferInStream_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CMemBufferInStream *p = (CMemBufferInStream *)pp;
+ return MemBuffer_Seek(&p->buffer, pos, origin);
+}
+
+void MemBufferInit(CMemBufferInStream *memBuferStream, CLookToRead *lookStream, void* buffer, size_t size)
+{
+ memBuferStream->buffer.buffer = buffer;
+ memBuferStream->buffer.pos = 0;
+ memBuferStream->buffer.size = size;
+
+ memBuferStream->s.Read = MemBufferInStream_Read;
+ memBuferStream->s.Seek = MemBufferInStream_Seek;
+
+ LookToRead_CreateVTable(lookStream, False);
+ lookStream->realStream = &memBuferStream->s;
+ LookToRead_Init(lookStream);
+}
\ No newline at end of file
diff --git a/SevenZip/7zMemBuffer.h b/SevenZip/7zMemBuffer.h
new file mode 100644
index 0000000..6226ade
--- /dev/null
+++ b/SevenZip/7zMemBuffer.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- File ---------- */
+
+typedef struct
+{
+ void* buffer;
+ Int64 size;
+ Int64 pos;
+} CSzMemBuffer;
+
+/* reads max(*size, remain file's size) bytes */
+WRes MemBuffer_Read(CSzMemBuffer *p, void *data, size_t *size);
+WRes MemBuffer_Seek(CSzMemBuffer *p, Int64 *pos, ESzSeek origin);
+
+/* ---------- FileInStream ---------- */
+typedef struct
+{
+ ISeekInStream s;
+ CSzMemBuffer buffer;
+} CMemBufferInStream;
+
+void MemBufferInit(CMemBufferInStream *memBuferStream, CLookToRead *lookStream, void* buffer, size_t size);
+
+EXTERN_C_END
diff --git a/SevenZip/7zStream.c b/SevenZip/7zStream.c
new file mode 100644
index 0000000..88f9c42
--- /dev/null
+++ b/SevenZip/7zStream.c
@@ -0,0 +1,171 @@
+/* 7zStream.c -- 7z Stream functions
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include
+
+#include "7zTypes.h"
+
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size)
+{
+ return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf)
+{
+ size_t processed = 1;
+ RINOK(stream->Read(stream, buf, &processed));
+ return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
+}
+
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset)
+{
+ Int64 t = offset;
+ return stream->Seek(stream, &t, SZ_SEEK_SET);
+}
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size)
+{
+ const void *lookBuf;
+ if (*size == 0)
+ return SZ_OK;
+ RINOK(stream->Look(stream, &lookBuf, size));
+ memcpy(buf, lookBuf, *size);
+ return stream->Skip(stream, *size);
+}
+
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(stream->Read(stream, buf, &processed));
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size)
+{
+ return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+static SRes LookToRead_Look_Lookahead(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ size2 = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, &size2);
+ p->size = size2;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Look_Exact(void *pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size > 0)
+ {
+ p->pos = 0;
+ if (*size > LookToRead_BUF_SIZE)
+ *size = LookToRead_BUF_SIZE;
+ res = p->realStream->Read(p->realStream, p->buf, size);
+ size2 = p->size = *size;
+ }
+ if (size2 < *size)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead_Skip(void *pp, size_t offset)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos += offset;
+ return SZ_OK;
+}
+
+static SRes LookToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ size_t rem = p->size - p->pos;
+ if (rem == 0)
+ return p->realStream->Read(p->realStream, buf, size);
+ if (rem > *size)
+ rem = *size;
+ memcpy(buf, p->buf + p->pos, rem);
+ p->pos += rem;
+ *size = rem;
+ return SZ_OK;
+}
+
+static SRes LookToRead_Seek(void *pp, Int64 *pos, ESzSeek origin)
+{
+ CLookToRead *p = (CLookToRead *)pp;
+ p->pos = p->size = 0;
+ return p->realStream->Seek(p->realStream, pos, origin);
+}
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead)
+{
+ p->s.Look = lookahead ?
+ LookToRead_Look_Lookahead :
+ LookToRead_Look_Exact;
+ p->s.Skip = LookToRead_Skip;
+ p->s.Read = LookToRead_Read;
+ p->s.Seek = LookToRead_Seek;
+}
+
+void LookToRead_Init(CLookToRead *p)
+{
+ p->pos = p->size = 0;
+}
+
+static SRes SecToLook_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToLook *p = (CSecToLook *)pp;
+ return LookInStream_LookRead(p->realStream, buf, size);
+}
+
+void SecToLook_CreateVTable(CSecToLook *p)
+{
+ p->s.Read = SecToLook_Read;
+}
+
+static SRes SecToRead_Read(void *pp, void *buf, size_t *size)
+{
+ CSecToRead *p = (CSecToRead *)pp;
+ return p->realStream->Read(p->realStream, buf, size);
+}
+
+void SecToRead_CreateVTable(CSecToRead *p)
+{
+ p->s.Read = SecToRead_Read;
+}
diff --git a/SevenZip/7zTypes.h b/SevenZip/7zTypes.h
new file mode 100644
index 0000000..778413e
--- /dev/null
+++ b/SevenZip/7zTypes.h
@@ -0,0 +1,256 @@
+/* 7zTypes.h -- Basic types
+2013-11-12 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#ifdef _WIN32
+/* #include */
+#endif
+
+#include
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+#ifdef _WIN32
+/* typedef DWORD WRes; */
+typedef unsigned WRes;
+#else
+typedef int WRes;
+#endif
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#define UINT64_CONST(n) n
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#define UINT64_CONST(n) n ## ULL
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define MY_STD_CALL __stdcall
+#else
+#define MY_STD_CALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_CDECL __cdecl
+#define MY_FAST_CALL __fastcall
+
+#else
+
+#define MY_NO_INLINE
+#define MY_CDECL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ Byte (*Read)(void *p); /* reads one byte, returns 0 in case of EOF or error */
+} IByteIn;
+
+typedef struct
+{
+ void (*Write)(void *p, Byte b);
+} IByteOut;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *p, const void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Bcj2.c b/SevenZip/Bcj2.c
new file mode 100644
index 0000000..3c88e44
--- /dev/null
+++ b/SevenZip/Bcj2.c
@@ -0,0 +1,256 @@
+/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
+2015-08-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bcj2.h"
+#include "CpuArch.h"
+
+#define CProb UInt16
+
+#define kTopValue ((UInt32)1 << 24)
+#define kNumModelBits 11
+#define kBitModelTotal (1 << kNumModelBits)
+#define kNumMoveBits 5
+
+#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound)
+#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits));
+
+void Bcj2Dec_Init(CBcj2Dec *p)
+{
+ unsigned i;
+
+ p->state = BCJ2_DEC_STATE_OK;
+ p->ip = 0;
+ p->temp[3] = 0;
+ p->range = 0;
+ p->code = 0;
+ for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
+ p->probs[i] = kBitModelTotal >> 1;
+}
+
+SRes Bcj2Dec_Decode(CBcj2Dec *p)
+{
+ if (p->range <= 5)
+ {
+ p->state = BCJ2_DEC_STATE_OK;
+ for (; p->range != 5; p->range++)
+ {
+ if (p->range == 1 && p->code != 0)
+ return SZ_ERROR_DATA;
+
+ if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+ {
+ p->state = BCJ2_STREAM_RC;
+ return SZ_OK;
+ }
+
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ }
+
+ if (p->code == 0xFFFFFFFF)
+ return SZ_ERROR_DATA;
+
+ p->range = 0xFFFFFFFF;
+ }
+ else if (p->state >= BCJ2_DEC_STATE_ORIG_0)
+ {
+ while (p->state <= BCJ2_DEC_STATE_ORIG_3)
+ {
+ Byte *dest = p->dest;
+ if (dest == p->destLim)
+ return SZ_OK;
+ *dest = p->temp[p->state++ - BCJ2_DEC_STATE_ORIG_0];
+ p->dest = dest + 1;
+ }
+ }
+
+ /*
+ if (BCJ2_IS_32BIT_STREAM(p->state))
+ {
+ const Byte *cur = p->bufs[p->state];
+ if (cur == p->lims[p->state])
+ return SZ_OK;
+ p->bufs[p->state] = cur + 4;
+
+ {
+ UInt32 val;
+ Byte *dest;
+ SizeT rem;
+
+ p->ip += 4;
+ val = GetBe32(cur) - p->ip;
+ dest = p->dest;
+ rem = p->destLim - dest;
+ if (rem < 4)
+ {
+ SizeT i;
+ SetUi32(p->temp, val);
+ for (i = 0; i < rem; i++)
+ dest[i] = p->temp[i];
+ p->dest = dest + rem;
+ p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
+ return SZ_OK;
+ }
+ SetUi32(dest, val);
+ p->temp[3] = (Byte)(val >> 24);
+ p->dest = dest + 4;
+ p->state = BCJ2_DEC_STATE_OK;
+ }
+ }
+ */
+
+ for (;;)
+ {
+ if (BCJ2_IS_32BIT_STREAM(p->state))
+ p->state = BCJ2_DEC_STATE_OK;
+ else
+ {
+ if (p->range < kTopValue)
+ {
+ if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+ {
+ p->state = BCJ2_STREAM_RC;
+ return SZ_OK;
+ }
+ p->range <<= 8;
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ }
+
+ {
+ const Byte *src = p->bufs[BCJ2_STREAM_MAIN];
+ const Byte *srcLim;
+ Byte *dest;
+ SizeT num = p->lims[BCJ2_STREAM_MAIN] - src;
+
+ if (num == 0)
+ {
+ p->state = BCJ2_STREAM_MAIN;
+ return SZ_OK;
+ }
+
+ dest = p->dest;
+ if (num > (SizeT)(p->destLim - dest))
+ {
+ num = p->destLim - dest;
+ if (num == 0)
+ {
+ p->state = BCJ2_DEC_STATE_ORIG;
+ return SZ_OK;
+ }
+ }
+
+ srcLim = src + num;
+
+ if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80)
+ *dest = src[0];
+ else for (;;)
+ {
+ Byte b = *src;
+ *dest = b;
+ if (b != 0x0F)
+ {
+ if ((b & 0xFE) == 0xE8)
+ break;
+ dest++;
+ if (++src != srcLim)
+ continue;
+ break;
+ }
+ dest++;
+ if (++src == srcLim)
+ break;
+ if ((*src & 0xF0) != 0x80)
+ continue;
+ *dest = *src;
+ break;
+ }
+
+ num = src - p->bufs[BCJ2_STREAM_MAIN];
+
+ if (src == srcLim)
+ {
+ p->temp[3] = src[-1];
+ p->bufs[BCJ2_STREAM_MAIN] = src;
+ p->ip += (UInt32)num;
+ p->dest += num;
+ p->state =
+ p->bufs[BCJ2_STREAM_MAIN] ==
+ p->lims[BCJ2_STREAM_MAIN] ?
+ (unsigned)BCJ2_STREAM_MAIN :
+ (unsigned)BCJ2_DEC_STATE_ORIG;
+ return SZ_OK;
+ }
+
+ {
+ UInt32 bound, ttt;
+ CProb *prob;
+ Byte b = src[0];
+ Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]);
+
+ p->temp[3] = b;
+ p->bufs[BCJ2_STREAM_MAIN] = src + 1;
+ num++;
+ p->ip += (UInt32)num;
+ p->dest += num;
+
+ prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0));
+
+ _IF_BIT_0
+ {
+ _UPDATE_0
+ continue;
+ }
+ _UPDATE_1
+
+ }
+ }
+ }
+
+ {
+ UInt32 val;
+ unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
+ const Byte *cur = p->bufs[cj];
+ Byte *dest;
+ SizeT rem;
+
+ if (cur == p->lims[cj])
+ {
+ p->state = cj;
+ break;
+ }
+
+ val = GetBe32(cur);
+ p->bufs[cj] = cur + 4;
+
+ p->ip += 4;
+ val -= p->ip;
+ dest = p->dest;
+ rem = p->destLim - dest;
+
+ if (rem < 4)
+ {
+ SizeT i;
+ SetUi32(p->temp, val);
+ for (i = 0; i < rem; i++)
+ dest[i] = p->temp[i];
+ p->dest = dest + rem;
+ p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
+ break;
+ }
+
+ SetUi32(dest, val);
+ p->temp[3] = (Byte)(val >> 24);
+ p->dest = dest + 4;
+ }
+ }
+
+ if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])
+ {
+ p->range <<= 8;
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ }
+
+ return SZ_OK;
+}
diff --git a/SevenZip/Bcj2.h b/SevenZip/Bcj2.h
new file mode 100644
index 0000000..8824080
--- /dev/null
+++ b/SevenZip/Bcj2.h
@@ -0,0 +1,146 @@
+/* Bcj2.h -- BCJ2 Converter for x86 code
+2014-11-10 : Igor Pavlov : Public domain */
+
+#ifndef __BCJ2_H
+#define __BCJ2_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define BCJ2_NUM_STREAMS 4
+
+enum
+{
+ BCJ2_STREAM_MAIN,
+ BCJ2_STREAM_CALL,
+ BCJ2_STREAM_JUMP,
+ BCJ2_STREAM_RC
+};
+
+enum
+{
+ BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS,
+ BCJ2_DEC_STATE_ORIG_1,
+ BCJ2_DEC_STATE_ORIG_2,
+ BCJ2_DEC_STATE_ORIG_3,
+
+ BCJ2_DEC_STATE_ORIG,
+ BCJ2_DEC_STATE_OK
+};
+
+enum
+{
+ BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,
+ BCJ2_ENC_STATE_OK
+};
+
+
+#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP)
+
+/*
+CBcj2Dec / CBcj2Enc
+bufs sizes:
+ BUF_SIZE(n) = lims[n] - bufs[n]
+bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4:
+ (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0
+ (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0
+*/
+
+/*
+CBcj2Dec:
+dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions:
+ bufs[BCJ2_STREAM_MAIN] >= dest &&
+ bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv +
+ BUF_SIZE(BCJ2_STREAM_CALL) +
+ BUF_SIZE(BCJ2_STREAM_JUMP)
+ tempReserv = 0 : for first call of Bcj2Dec_Decode
+ tempReserv = 4 : for any other calls of Bcj2Dec_Decode
+ overlap with offset = 1 is not allowed
+*/
+
+typedef struct
+{
+ const Byte *bufs[BCJ2_NUM_STREAMS];
+ const Byte *lims[BCJ2_NUM_STREAMS];
+ Byte *dest;
+ const Byte *destLim;
+
+ unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
+
+ UInt32 ip;
+ Byte temp[4];
+ UInt32 range;
+ UInt32 code;
+ UInt16 probs[2 + 256];
+} CBcj2Dec;
+
+void Bcj2Dec_Init(CBcj2Dec *p);
+
+/* Returns: SZ_OK or SZ_ERROR_DATA */
+SRes Bcj2Dec_Decode(CBcj2Dec *p);
+
+#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0)
+
+
+
+typedef enum
+{
+ BCJ2_ENC_FINISH_MODE_CONTINUE,
+ BCJ2_ENC_FINISH_MODE_END_BLOCK,
+ BCJ2_ENC_FINISH_MODE_END_STREAM
+} EBcj2Enc_FinishMode;
+
+typedef struct
+{
+ Byte *bufs[BCJ2_NUM_STREAMS];
+ const Byte *lims[BCJ2_NUM_STREAMS];
+ const Byte *src;
+ const Byte *srcLim;
+
+ unsigned state;
+ EBcj2Enc_FinishMode finishMode;
+
+ Byte prevByte;
+
+ Byte cache;
+ UInt32 range;
+ UInt64 low;
+ UInt64 cacheSize;
+
+ UInt32 ip;
+
+ /* 32-bit ralative offset in JUMP/CALL commands is
+ - (mod 4 GB) in 32-bit mode
+ - signed Int32 in 64-bit mode
+ We use (mod 4 GB) check for fileSize.
+ Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */
+ UInt32 fileIp;
+ UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */
+ UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */
+
+ UInt32 tempTarget;
+ unsigned tempPos;
+ Byte temp[4 * 2];
+
+ unsigned flushPos;
+
+ UInt16 probs[2 + 256];
+} CBcj2Enc;
+
+void Bcj2Enc_Init(CBcj2Enc *p);
+void Bcj2Enc_Encode(CBcj2Enc *p);
+
+#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos)
+#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5)
+
+
+#define BCJ2_RELAT_LIMIT_NUM_BITS 26
+#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS)
+
+/* limit for CBcj2Enc::fileSize variable */
+#define BCJ2_FileSize_MAX ((UInt32)1 << 31)
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Bra.c b/SevenZip/Bra.c
new file mode 100644
index 0000000..cdb9456
--- /dev/null
+++ b/SevenZip/Bra.c
@@ -0,0 +1,135 @@
+/* Bra.c -- Converters for RISC code
+2010-04-16 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 8;
+ for (i = 0; i <= size; i += 4)
+ {
+ if (data[i + 3] == 0xEB)
+ {
+ UInt32 dest;
+ UInt32 src = ((UInt32)data[i + 2] << 16) | ((UInt32)data[i + 1] << 8) | (data[i + 0]);
+ src <<= 2;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 2;
+ data[i + 2] = (Byte)(dest >> 16);
+ data[i + 1] = (Byte)(dest >> 8);
+ data[i + 0] = (Byte)dest;
+ }
+ }
+ return i;
+}
+
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ ip += 4;
+ for (i = 0; i <= size; i += 2)
+ {
+ if ((data[i + 1] & 0xF8) == 0xF0 &&
+ (data[i + 3] & 0xF8) == 0xF8)
+ {
+ UInt32 dest;
+ UInt32 src =
+ (((UInt32)data[i + 1] & 0x7) << 19) |
+ ((UInt32)data[i + 0] << 11) |
+ (((UInt32)data[i + 3] & 0x7) << 8) |
+ (data[i + 2]);
+
+ src <<= 1;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ dest >>= 1;
+
+ data[i + 1] = (Byte)(0xF0 | ((dest >> 19) & 0x7));
+ data[i + 0] = (Byte)(dest >> 11);
+ data[i + 3] = (Byte)(0xF8 | ((dest >> 8) & 0x7));
+ data[i + 2] = (Byte)dest;
+ i += 2;
+ }
+ }
+ return i;
+}
+
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] >> 2) == 0x12 && (data[i + 3] & 3) == 1)
+ {
+ UInt32 src = ((UInt32)(data[i + 0] & 3) << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3] & (~3));
+
+ UInt32 dest;
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+ data[i + 0] = (Byte)(0x48 | ((dest >> 24) & 0x3));
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] &= 0x3;
+ data[i + 3] |= dest;
+ }
+ }
+ return i;
+}
+
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ UInt32 i;
+ if (size < 4)
+ return 0;
+ size -= 4;
+ for (i = 0; i <= size; i += 4)
+ {
+ if ((data[i] == 0x40 && (data[i + 1] & 0xC0) == 0x00) ||
+ (data[i] == 0x7F && (data[i + 1] & 0xC0) == 0xC0))
+ {
+ UInt32 src =
+ ((UInt32)data[i + 0] << 24) |
+ ((UInt32)data[i + 1] << 16) |
+ ((UInt32)data[i + 2] << 8) |
+ ((UInt32)data[i + 3]);
+ UInt32 dest;
+
+ src <<= 2;
+ if (encoding)
+ dest = ip + i + src;
+ else
+ dest = src - (ip + i);
+ dest >>= 2;
+
+ dest = (((0 - ((dest >> 22) & 1)) << 22) & 0x3FFFFFFF) | (dest & 0x3FFFFF) | 0x40000000;
+
+ data[i + 0] = (Byte)(dest >> 24);
+ data[i + 1] = (Byte)(dest >> 16);
+ data[i + 2] = (Byte)(dest >> 8);
+ data[i + 3] = (Byte)dest;
+ }
+ }
+ return i;
+}
diff --git a/SevenZip/Bra.h b/SevenZip/Bra.h
new file mode 100644
index 0000000..855e37a
--- /dev/null
+++ b/SevenZip/Bra.h
@@ -0,0 +1,64 @@
+/* Bra.h -- Branch converters for executables
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __BRA_H
+#define __BRA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+These functions convert relative addresses to absolute addresses
+in CALL instructions to increase the compression ratio.
+
+ In:
+ data - data buffer
+ size - size of data
+ ip - current virtual Instruction Pinter (IP) value
+ state - state variable for x86 converter
+ encoding - 0 (for decoding), 1 (for encoding)
+
+ Out:
+ state - state variable for x86 converter
+
+ Returns:
+ The number of processed bytes. If you call these functions with multiple calls,
+ you must start next call with first byte after block of processed bytes.
+
+ Type Endian Alignment LookAhead
+
+ x86 little 1 4
+ ARMT little 2 2
+ ARM little 4 0
+ PPC big 4 0
+ SPARC big 4 0
+ IA64 little 16 0
+
+ size must be >= Alignment + LookAhead, if it's not last block.
+ If (size < Alignment + LookAhead), converter returns 0.
+
+ Example:
+
+ UInt32 ip = 0;
+ for ()
+ {
+ ; size must be >= Alignment + LookAhead, if it's not last block
+ SizeT processed = Convert(data, size, ip, 1);
+ data += processed;
+ size -= processed;
+ ip += processed;
+ }
+*/
+
+#define x86_Convert_Init(state) { state = 0; }
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Bra86.c b/SevenZip/Bra86.c
new file mode 100644
index 0000000..6db15e7
--- /dev/null
+++ b/SevenZip/Bra86.c
@@ -0,0 +1,82 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0)
+
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
+{
+ SizeT pos = 0;
+ UInt32 mask = *state & 7;
+ if (size < 5)
+ return 0;
+ size -= 4;
+ ip += 5;
+
+ for (;;)
+ {
+ Byte *p = data + pos;
+ const Byte *limit = data + size;
+ for (; p < limit; p++)
+ if ((*p & 0xFE) == 0xE8)
+ break;
+
+ {
+ SizeT d = (SizeT)(p - data - pos);
+ pos = (SizeT)(p - data);
+ if (p >= limit)
+ {
+ *state = (d > 2 ? 0 : mask >> (unsigned)d);
+ return pos;
+ }
+ if (d > 2)
+ mask = 0;
+ else
+ {
+ mask >>= (unsigned)d;
+ if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(mask >> 1) + 1])))
+ {
+ mask = (mask >> 1) | 4;
+ pos++;
+ continue;
+ }
+ }
+ }
+
+ if (Test86MSByte(p[4]))
+ {
+ UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+ UInt32 cur = ip + (UInt32)pos;
+ pos += 5;
+ if (encoding)
+ v += cur;
+ else
+ v -= cur;
+ if (mask != 0)
+ {
+ unsigned sh = (mask & 6) << 2;
+ if (Test86MSByte((Byte)(v >> sh)))
+ {
+ v ^= (((UInt32)0x100 << sh) - 1);
+ if (encoding)
+ v += cur;
+ else
+ v -= cur;
+ }
+ mask = 0;
+ }
+ p[1] = (Byte)v;
+ p[2] = (Byte)(v >> 8);
+ p[3] = (Byte)(v >> 16);
+ p[4] = (Byte)(0 - ((v >> 24) & 1));
+ }
+ else
+ {
+ mask = (mask >> 1) | 4;
+ pos++;
+ }
+ }
+}
diff --git a/SevenZip/BraIA64.c b/SevenZip/BraIA64.c
new file mode 100644
index 0000000..fa60356
--- /dev/null
+++ b/SevenZip/BraIA64.c
@@ -0,0 +1,69 @@
+/* BraIA64.c -- Converter for IA-64 code
+2013-11-12 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+
+static const Byte kBranchTable[32] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 4, 4, 6, 6, 0, 0, 7, 7,
+ 4, 4, 0, 0, 4, 4, 0, 0
+};
+
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
+{
+ SizeT i;
+ if (size < 16)
+ return 0;
+ size -= 16;
+ for (i = 0; i <= size; i += 16)
+ {
+ UInt32 instrTemplate = data[i] & 0x1F;
+ UInt32 mask = kBranchTable[instrTemplate];
+ UInt32 bitPos = 5;
+ int slot;
+ for (slot = 0; slot < 3; slot++, bitPos += 41)
+ {
+ UInt32 bytePos, bitRes;
+ UInt64 instruction, instNorm;
+ int j;
+ if (((mask >> slot) & 1) == 0)
+ continue;
+ bytePos = (bitPos >> 3);
+ bitRes = bitPos & 0x7;
+ instruction = 0;
+ for (j = 0; j < 6; j++)
+ instruction += (UInt64)data[i + j + bytePos] << (8 * j);
+
+ instNorm = instruction >> bitRes;
+ if (((instNorm >> 37) & 0xF) == 0x5 && ((instNorm >> 9) & 0x7) == 0)
+ {
+ UInt32 src = (UInt32)((instNorm >> 13) & 0xFFFFF);
+ UInt32 dest;
+ src |= ((UInt32)(instNorm >> 36) & 1) << 20;
+
+ src <<= 4;
+
+ if (encoding)
+ dest = ip + (UInt32)i + src;
+ else
+ dest = src - (ip + (UInt32)i);
+
+ dest >>= 4;
+
+ instNorm &= ~((UInt64)(0x8FFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0xFFFFF) << 13);
+ instNorm |= ((UInt64)(dest & 0x100000) << (36 - 20));
+
+ instruction &= (1 << bitRes) - 1;
+ instruction |= (instNorm << bitRes);
+ for (j = 0; j < 6; j++)
+ data[i + j + bytePos] = (Byte)(instruction >> (8 * j));
+ }
+ }
+ }
+ return i;
+}
diff --git a/SevenZip/Compiler.h b/SevenZip/Compiler.h
new file mode 100644
index 0000000..5bba7ee
--- /dev/null
+++ b/SevenZip/Compiler.h
@@ -0,0 +1,32 @@
+/* Compiler.h
+2015-08-02 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_COMPILER_H
+#define __7Z_COMPILER_H
+
+#ifdef _MSC_VER
+
+ #ifdef UNDER_CE
+ #define RPC_NO_WINDOWS_H
+ /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
+ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+ #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
+ #endif
+
+ #if _MSC_VER >= 1300
+ #pragma warning(disable : 4996) // This function or variable may be unsafe
+ #else
+ #pragma warning(disable : 4511) // copy constructor could not be generated
+ #pragma warning(disable : 4512) // assignment operator could not be generated
+ #pragma warning(disable : 4514) // unreferenced inline function has been removed
+ #pragma warning(disable : 4702) // unreachable code
+ #pragma warning(disable : 4710) // not inlined
+ #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
+ #endif
+
+#endif
+
+#define UNUSED_VAR(x) (void)x;
+/* #define UNUSED_VAR(x) x=x; */
+
+#endif
diff --git a/SevenZip/CpuArch.c b/SevenZip/CpuArch.c
new file mode 100644
index 0000000..554ffa4
--- /dev/null
+++ b/SevenZip/CpuArch.c
@@ -0,0 +1,200 @@
+/* CpuArch.c -- CPU specific code
+2016-02-25: Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
+#define USE_ASM
+#endif
+
+#if !defined(USE_ASM) && _MSC_VER >= 1500
+#include
+#endif
+
+#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
+static UInt32 CheckFlag(UInt32 flag)
+{
+ #ifdef _MSC_VER
+ __asm pushfd;
+ __asm pop EAX;
+ __asm mov EDX, EAX;
+ __asm xor EAX, flag;
+ __asm push EAX;
+ __asm popfd;
+ __asm pushfd;
+ __asm pop EAX;
+ __asm xor EAX, EDX;
+ __asm push EDX;
+ __asm popfd;
+ __asm and flag, EAX;
+ #else
+ __asm__ __volatile__ (
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "movl %%EAX,%%EDX\n\t"
+ "xorl %0,%%EAX\n\t"
+ "push %%EAX\n\t"
+ "popf\n\t"
+ "pushf\n\t"
+ "pop %%EAX\n\t"
+ "xorl %%EDX,%%EAX\n\t"
+ "push %%EDX\n\t"
+ "popf\n\t"
+ "andl %%EAX, %0\n\t":
+ "=c" (flag) : "c" (flag) :
+ "%eax", "%edx");
+ #endif
+ return flag;
+}
+#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
+#else
+#define CHECK_CPUID_IS_SUPPORTED
+#endif
+
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
+{
+ #ifdef USE_ASM
+
+ #ifdef _MSC_VER
+
+ UInt32 a2, b2, c2, d2;
+ __asm xor EBX, EBX;
+ __asm xor ECX, ECX;
+ __asm xor EDX, EDX;
+ __asm mov EAX, function;
+ __asm cpuid;
+ __asm mov a2, EAX;
+ __asm mov b2, EBX;
+ __asm mov c2, ECX;
+ __asm mov d2, EDX;
+
+ *a = a2;
+ *b = b2;
+ *c = c2;
+ *d = d2;
+
+ #else
+
+ __asm__ __volatile__ (
+ #if defined(MY_CPU_AMD64) && defined(__PIC__)
+ "mov %%rbx, %%rdi;"
+ "cpuid;"
+ "xchg %%rbx, %%rdi;"
+ : "=a" (*a) ,
+ "=D" (*b) ,
+ #elif defined(MY_CPU_X86) && defined(__PIC__)
+ "mov %%ebx, %%edi;"
+ "cpuid;"
+ "xchgl %%ebx, %%edi;"
+ : "=a" (*a) ,
+ "=D" (*b) ,
+ #else
+ "cpuid"
+ : "=a" (*a) ,
+ "=b" (*b) ,
+ #endif
+ "=c" (*c) ,
+ "=d" (*d)
+ : "0" (function)) ;
+
+ #endif
+
+ #else
+
+ int CPUInfo[4];
+ __cpuid(CPUInfo, function);
+ *a = CPUInfo[0];
+ *b = CPUInfo[1];
+ *c = CPUInfo[2];
+ *d = CPUInfo[3];
+
+ #endif
+}
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p)
+{
+ CHECK_CPUID_IS_SUPPORTED
+ MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
+ MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
+ return True;
+}
+
+static const UInt32 kVendors[][3] =
+{
+ { 0x756E6547, 0x49656E69, 0x6C65746E},
+ { 0x68747541, 0x69746E65, 0x444D4163},
+ { 0x746E6543, 0x48727561, 0x736C7561}
+};
+
+int x86cpuid_GetFirm(const Cx86cpuid *p)
+{
+ unsigned i;
+ for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
+ {
+ const UInt32 *v = kVendors[i];
+ if (v[0] == p->vendor[0] &&
+ v[1] == p->vendor[1] &&
+ v[2] == p->vendor[2])
+ return (int)i;
+ }
+ return -1;
+}
+
+Bool CPU_Is_InOrder()
+{
+ Cx86cpuid p;
+ int firm;
+ UInt32 family, model;
+ if (!x86cpuid_CheckAndRead(&p))
+ return True;
+
+ family = x86cpuid_GetFamily(p.ver);
+ model = x86cpuid_GetModel(p.ver);
+
+ firm = x86cpuid_GetFirm(&p);
+
+ switch (firm)
+ {
+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
+ /* In-Order Atom CPU */
+ model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
+ || model == 0x26 /* 45 nm, Z6xx */
+ || model == 0x27 /* 32 nm, Z2460 */
+ || model == 0x35 /* 32 nm, Z2760 */
+ || model == 0x36 /* 32 nm, N2xxx, D2xxx */
+ )));
+ case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
+ case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
+ }
+ return True;
+}
+
+#if !defined(MY_CPU_AMD64) && defined(_WIN32)
+#include
+static Bool CPU_Sys_Is_SSE_Supported()
+{
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ if (!GetVersionEx(&vi))
+ return False;
+ return (vi.dwMajorVersion >= 5);
+}
+#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
+#else
+#define CHECK_SYS_SSE_SUPPORT
+#endif
+
+Bool CPU_Is_Aes_Supported()
+{
+ Cx86cpuid p;
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_CheckAndRead(&p))
+ return False;
+ return (p.c >> 25) & 1;
+}
+
+#endif
diff --git a/SevenZip/CpuArch.h b/SevenZip/CpuArch.h
new file mode 100644
index 0000000..f6a28ba
--- /dev/null
+++ b/SevenZip/CpuArch.h
@@ -0,0 +1,222 @@
+/* CpuArch.h -- CPU specific code
+2015-12-01: Igor Pavlov : Public domain */
+
+#ifndef __CPU_ARCH_H
+#define __CPU_ARCH_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+MY_CPU_LE means that CPU is LITTLE ENDIAN.
+MY_CPU_BE means that CPU is BIG ENDIAN.
+If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+*/
+
+#if defined(_M_X64) \
+ || defined(_M_AMD64) \
+ || defined(__x86_64__) \
+ || defined(__AMD64__) \
+ || defined(__amd64__)
+ #define MY_CPU_AMD64
+#endif
+
+#if defined(MY_CPU_AMD64) \
+ || defined(_M_IA64) \
+ || defined(__AARCH64EL__) \
+ || defined(__AARCH64EB__)
+ #define MY_CPU_64BIT
+#endif
+
+#if defined(_M_IX86) || defined(__i386__)
+#define MY_CPU_X86
+#endif
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+#if defined(MY_CPU_X86) \
+ || defined(_M_ARM) \
+ || defined(__ARMEL__) \
+ || defined(__THUMBEL__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEB__)
+ #define MY_CPU_32BIT
+#endif
+
+#if defined(_WIN32) && defined(_M_ARM)
+#define MY_CPU_ARM_LE
+#endif
+
+#if defined(_WIN32) && defined(_M_IA64)
+#define MY_CPU_IA64_LE
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM_LE) \
+ || defined(MY_CPU_IA64_LE) \
+ || defined(__LITTLE_ENDIAN__) \
+ || defined(__ARMEL__) \
+ || defined(__THUMBEL__) \
+ || defined(__AARCH64EL__) \
+ || defined(__MIPSEL__) \
+ || defined(__MIPSEL) \
+ || defined(_MIPSEL) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+ #define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEB__) \
+ || defined(__AARCH64EB__) \
+ || defined(__MIPSEB__) \
+ || defined(__MIPSEB) \
+ || defined(_MIPSEB) \
+ || defined(__m68k__) \
+ || defined(__s390__) \
+ || defined(__s390x__) \
+ || defined(__zarch__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+ #define MY_CPU_BE
+#endif
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+Stop_Compiling_Bad_Endian
+#endif
+
+
+#ifdef MY_CPU_LE
+ #if defined(MY_CPU_X86_OR_AMD64) \
+ /* || defined(__AARCH64EL__) */
+ #define MY_CPU_LE_UNALIGN
+ #endif
+#endif
+
+
+#ifdef MY_CPU_LE_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
+#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
+#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
+
+#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
+#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
+#define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
+
+#else
+
+#define GetUi16(p) ( (UInt16) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt16)((const Byte *)(p))[1] << 8) ))
+
+#define GetUi32(p) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((UInt32)((const Byte *)(p))[2] << 16) | \
+ ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+
+#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); }
+
+#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); \
+ _ppp_[2] = (Byte)(_vvv_ >> 16); \
+ _ppp_[3] = (Byte)(_vvv_ >> 24); }
+
+#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
+ SetUi32(_ppp2_ , (UInt32)_vvv2_); \
+ SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
+
+#endif
+
+
+#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)
+
+/* Note: we use bswap instruction, that is unsupported in 386 cpu */
+
+#include
+
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
+
+#elif defined(MY_CPU_LE_UNALIGN) && defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))
+
+#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))
+
+#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
+
+#else
+
+#define GetBe32(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 24) | \
+ ((UInt32)((const Byte *)(p))[1] << 16) | \
+ ((UInt32)((const Byte *)(p))[2] << 8) | \
+ ((const Byte *)(p))[3] )
+
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+
+#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)(_vvv_ >> 24); \
+ _ppp_[1] = (Byte)(_vvv_ >> 16); \
+ _ppp_[2] = (Byte)(_vvv_ >> 8); \
+ _ppp_[3] = (Byte)_vvv_; }
+
+#endif
+
+
+#define GetBe16(p) ( (UInt16) ( \
+ ((UInt16)((const Byte *)(p))[0] << 8) | \
+ ((const Byte *)(p))[1] ))
+
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+typedef struct
+{
+ UInt32 maxFunc;
+ UInt32 vendor[3];
+ UInt32 ver;
+ UInt32 b;
+ UInt32 c;
+ UInt32 d;
+} Cx86cpuid;
+
+enum
+{
+ CPU_FIRM_INTEL,
+ CPU_FIRM_AMD,
+ CPU_FIRM_VIA
+};
+
+void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
+
+Bool x86cpuid_CheckAndRead(Cx86cpuid *p);
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+
+#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
+#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
+#define x86cpuid_GetStepping(ver) (ver & 0xF)
+
+Bool CPU_Is_InOrder();
+Bool CPU_Is_Aes_Supported();
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Delta.c b/SevenZip/Delta.c
new file mode 100644
index 0000000..e3edd21
--- /dev/null
+++ b/SevenZip/Delta.c
@@ -0,0 +1,64 @@
+/* Delta.c -- Delta converter
+2009-05-26 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Delta.h"
+
+void Delta_Init(Byte *state)
+{
+ unsigned i;
+ for (i = 0; i < DELTA_STATE_SIZE; i++)
+ state[i] = 0;
+}
+
+static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)
+{
+ unsigned i;
+ for (i = 0; i < size; i++)
+ dest[i] = src[i];
+}
+
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ Byte b = data[i];
+ data[i] = (Byte)(b - buf[j]);
+ buf[j] = b;
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
+
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte buf[DELTA_STATE_SIZE];
+ unsigned j = 0;
+ MyMemCpy(buf, state, delta);
+ {
+ SizeT i;
+ for (i = 0; i < size;)
+ {
+ for (j = 0; j < delta && i < size; i++, j++)
+ {
+ buf[j] = data[i] = (Byte)(buf[j] + data[i]);
+ }
+ }
+ }
+ if (j == delta)
+ j = 0;
+ MyMemCpy(state, buf + j, delta - j);
+ MyMemCpy(state + delta - j, buf, j);
+}
diff --git a/SevenZip/Delta.h b/SevenZip/Delta.h
new file mode 100644
index 0000000..2fa54ad
--- /dev/null
+++ b/SevenZip/Delta.h
@@ -0,0 +1,19 @@
+/* Delta.h -- Delta converter
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __DELTA_H
+#define __DELTA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define DELTA_STATE_SIZE 256
+
+void Delta_Init(Byte *state);
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Lzma2Dec.c b/SevenZip/Lzma2Dec.c
new file mode 100644
index 0000000..b84f88a
--- /dev/null
+++ b/SevenZip/Lzma2Dec.c
@@ -0,0 +1,378 @@
+/* Lzma2Dec.c -- LZMA2 Decoder
+2015-11-09 : Igor Pavlov : Public domain */
+
+/* #define SHOW_DEBUG_INFO */
+
+#include "Precomp.h"
+
+#ifdef SHOW_DEBUG_INFO
+#include
+#endif
+
+#include
+
+#include "Lzma2Dec.h"
+
+/*
+00000000 - EOS
+00000001 U U - Uncompressed Reset Dic
+00000010 U U - Uncompressed No Reset
+100uuuuu U U P P - LZMA no reset
+101uuuuu U U P P - LZMA reset state
+110uuuuu U U P P S - LZMA reset state + new prop
+111uuuuu U U P P S - LZMA reset state + new prop + reset dic
+
+ u, U - Unpack Size
+ P - Pack Size
+ S - Props
+*/
+
+#define LZMA2_CONTROL_LZMA (1 << 7)
+#define LZMA2_CONTROL_COPY_NO_RESET 2
+#define LZMA2_CONTROL_COPY_RESET_DIC 1
+#define LZMA2_CONTROL_EOF 0
+
+#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & LZMA2_CONTROL_LZMA) == 0)
+
+#define LZMA2_GET_LZMA_MODE(p) (((p)->control >> 5) & 3)
+#define LZMA2_IS_THERE_PROP(mode) ((mode) >= 2)
+
+#define LZMA2_LCLP_MAX 4
+#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+typedef enum
+{
+ LZMA2_STATE_CONTROL,
+ LZMA2_STATE_UNPACK0,
+ LZMA2_STATE_UNPACK1,
+ LZMA2_STATE_PACK0,
+ LZMA2_STATE_PACK1,
+ LZMA2_STATE_PROP,
+ LZMA2_STATE_DATA,
+ LZMA2_STATE_DATA_CONT,
+ LZMA2_STATE_FINISHED,
+ LZMA2_STATE_ERROR
+} ELzma2State;
+
+static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
+{
+ UInt32 dicSize;
+ if (prop > 40)
+ return SZ_ERROR_UNSUPPORTED;
+ dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
+ props[0] = (Byte)LZMA2_LCLP_MAX;
+ props[1] = (Byte)(dicSize);
+ props[2] = (Byte)(dicSize >> 8);
+ props[3] = (Byte)(dicSize >> 16);
+ props[4] = (Byte)(dicSize >> 24);
+ return SZ_OK;
+}
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props));
+ return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+void Lzma2Dec_Init(CLzma2Dec *p)
+{
+ p->state = LZMA2_STATE_CONTROL;
+ p->needInitDic = True;
+ p->needInitState = True;
+ p->needInitProp = True;
+ LzmaDec_Init(&p->decoder);
+}
+
+static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
+{
+ switch (p->state)
+ {
+ case LZMA2_STATE_CONTROL:
+ p->control = b;
+ PRF(printf("\n %4X ", (unsigned)p->decoder.dicPos));
+ PRF(printf(" %2X", (unsigned)b));
+ if (p->control == 0)
+ return LZMA2_STATE_FINISHED;
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if ((p->control & 0x7F) > 2)
+ return LZMA2_STATE_ERROR;
+ p->unpackSize = 0;
+ }
+ else
+ p->unpackSize = (UInt32)(p->control & 0x1F) << 16;
+ return LZMA2_STATE_UNPACK0;
+
+ case LZMA2_STATE_UNPACK0:
+ p->unpackSize |= (UInt32)b << 8;
+ return LZMA2_STATE_UNPACK1;
+
+ case LZMA2_STATE_UNPACK1:
+ p->unpackSize |= (UInt32)b;
+ p->unpackSize++;
+ PRF(printf(" %8u", (unsigned)p->unpackSize));
+ return (LZMA2_IS_UNCOMPRESSED_STATE(p)) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
+
+ case LZMA2_STATE_PACK0:
+ p->packSize = (UInt32)b << 8;
+ return LZMA2_STATE_PACK1;
+
+ case LZMA2_STATE_PACK1:
+ p->packSize |= (UInt32)b;
+ p->packSize++;
+ PRF(printf(" %8u", (unsigned)p->packSize));
+ return LZMA2_IS_THERE_PROP(LZMA2_GET_LZMA_MODE(p)) ? LZMA2_STATE_PROP:
+ (p->needInitProp ? LZMA2_STATE_ERROR : LZMA2_STATE_DATA);
+
+ case LZMA2_STATE_PROP:
+ {
+ unsigned lc, lp;
+ if (b >= (9 * 5 * 5))
+ return LZMA2_STATE_ERROR;
+ lc = b % 9;
+ b /= 9;
+ p->decoder.prop.pb = b / 5;
+ lp = b % 5;
+ if (lc + lp > LZMA2_LCLP_MAX)
+ return LZMA2_STATE_ERROR;
+ p->decoder.prop.lc = lc;
+ p->decoder.prop.lp = lp;
+ p->needInitProp = False;
+ return LZMA2_STATE_DATA;
+ }
+ }
+ return LZMA2_STATE_ERROR;
+}
+
+static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
+{
+ memcpy(p->dic + p->dicPos, src, size);
+ p->dicPos += size;
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
+ p->checkDicSize = p->prop.dicSize;
+ p->processedPos += (UInt32)size;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState);
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->state != LZMA2_STATE_FINISHED)
+ {
+ SizeT dicPos = p->decoder.dicPos;
+
+ if (p->state == LZMA2_STATE_ERROR)
+ return SZ_ERROR_DATA;
+
+ if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+
+ if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ (*srcLen)++;
+ p->state = Lzma2Dec_UpdateState(p, *src++);
+
+ if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED)
+ {
+ p->state = LZMA2_STATE_ERROR;
+ return SZ_ERROR_DATA;
+ }
+ continue;
+ }
+
+ {
+ SizeT destSizeCur = dicLimit - dicPos;
+ SizeT srcSizeCur = inSize - *srcLen;
+ ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
+
+ if (p->unpackSize <= destSizeCur)
+ {
+ destSizeCur = (SizeT)p->unpackSize;
+ curFinishMode = LZMA_FINISH_END;
+ }
+
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ Bool initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
+ if (initDic)
+ p->needInitProp = p->needInitState = True;
+ else if (p->needInitDic)
+ {
+ p->state = LZMA2_STATE_ERROR;
+ return SZ_ERROR_DATA;
+ }
+ p->needInitDic = False;
+ LzmaDec_InitDicAndState(&p->decoder, initDic, False);
+ }
+
+ if (srcSizeCur > destSizeCur)
+ srcSizeCur = destSizeCur;
+
+ if (srcSizeCur == 0)
+ {
+ p->state = LZMA2_STATE_ERROR;
+ return SZ_ERROR_DATA;
+ }
+
+ LzmaDec_UpdateWithUncompressed(&p->decoder, src, srcSizeCur);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->unpackSize -= (UInt32)srcSizeCur;
+ p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
+ }
+ else
+ {
+ SizeT outSizeProcessed;
+ SRes res;
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ unsigned mode = LZMA2_GET_LZMA_MODE(p);
+ Bool initDic = (mode == 3);
+ Bool initState = (mode != 0);
+ if ((!initDic && p->needInitDic) || (!initState && p->needInitState))
+ {
+ p->state = LZMA2_STATE_ERROR;
+ return SZ_ERROR_DATA;
+ }
+
+ LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
+ p->needInitDic = False;
+ p->needInitState = False;
+ p->state = LZMA2_STATE_DATA_CONT;
+ }
+
+ if (srcSizeCur > p->packSize)
+ srcSizeCur = (SizeT)p->packSize;
+
+ res = LzmaDec_DecodeToDic(&p->decoder, dicPos + destSizeCur, src, &srcSizeCur, curFinishMode, status);
+
+ src += srcSizeCur;
+ *srcLen += srcSizeCur;
+ p->packSize -= (UInt32)srcSizeCur;
+
+ outSizeProcessed = p->decoder.dicPos - dicPos;
+ p->unpackSize -= (UInt32)outSizeProcessed;
+
+ RINOK(res);
+ if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ return res;
+
+ if (srcSizeCur == 0 && outSizeProcessed == 0)
+ {
+ if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ || p->unpackSize != 0
+ || p->packSize != 0)
+ {
+ p->state = LZMA2_STATE_ERROR;
+ return SZ_ERROR_DATA;
+ }
+ p->state = LZMA2_STATE_CONTROL;
+ }
+
+ if (*status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ *status = LZMA_STATUS_NOT_FINISHED;
+ }
+ }
+ }
+
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+}
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT srcSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->decoder.dicPos == p->decoder.dicBufSize)
+ p->decoder.dicPos = 0;
+ dicPos = p->decoder.dicPos;
+ if (outSize > p->decoder.dicBufSize - dicPos)
+ {
+ outSizeCur = p->decoder.dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = Lzma2Dec_DecodeToDic(p, outSizeCur, src, &srcSizeCur, curFinishMode, status);
+ src += srcSizeCur;
+ inSize -= srcSizeCur;
+ *srcLen += srcSizeCur;
+ outSizeCur = p->decoder.dicPos - dicPos;
+ memcpy(dest, p->decoder.dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzma2Dec p;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ Lzma2Dec_Construct(&p);
+ RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc));
+ p.decoder.dic = dest;
+ p.decoder.dicBufSize = outSize;
+ Lzma2Dec_Init(&p);
+ *srcLen = inSize;
+ res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+ *destLen = p.decoder.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+ Lzma2Dec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/SevenZip/Lzma2Dec.h b/SevenZip/Lzma2Dec.h
new file mode 100644
index 0000000..e6a0f6e
--- /dev/null
+++ b/SevenZip/Lzma2Dec.h
@@ -0,0 +1,80 @@
+/* Lzma2Dec.h -- LZMA2 Decoder
+2015-05-13 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA2_DEC_H
+#define __LZMA2_DEC_H
+
+#include "LzmaDec.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- State Interface ---------- */
+
+typedef struct
+{
+ CLzmaDec decoder;
+ UInt32 packSize;
+ UInt32 unpackSize;
+ unsigned state;
+ Byte control;
+ Bool needInitDic;
+ Bool needInitState;
+ Bool needInitProp;
+} CLzma2Dec;
+
+#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder)
+#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc);
+#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc);
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAlloc *alloc);
+void Lzma2Dec_Init(CLzma2Dec *p);
+
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAlloc *alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/LzmaDec.c b/SevenZip/LzmaDec.c
new file mode 100644
index 0000000..12dce11
--- /dev/null
+++ b/SevenZip/LzmaDec.c
@@ -0,0 +1,1100 @@
+/* LzmaDec.c -- LZMA Decoder
+2016-05-16 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "LzmaDec.h"
+
+#include
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMAL_LITER_DEC GET_BIT(prob + symbol, symbol)
+#define MATCHED_LITER_DEC \
+ matchByte <<= 1; \
+ bit = (matchByte & offs); \
+ probLit = prob + offs + bit + symbol; \
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 0x300
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#define LzmaProps_GetNumProbs(p) (Literal + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker (unused now)
+ = kMatchSpecLenStart + 2 : State Init Marker (unused now)
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.lc;
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (processedPos != 0 || checkDicSize != 0)
+ prob += ((UInt32)LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+ processedPos++;
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ #ifdef _LZMA_SIZE_OPT
+ do { NORMAL_LITER_DEC } while (symbol < 0x100);
+ #else
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ #endif
+ }
+ else
+ {
+ unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ #ifdef _LZMA_SIZE_OPT
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ }
+ while (symbol < 0x100);
+ #else
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ }
+ #endif
+ }
+
+ dic[dicPos++] = (Byte)symbol;
+ continue;
+ }
+
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+
+ #ifdef _LZMA_SIZE_OPT
+ {
+ unsigned lim, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ lim = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ lim = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ lim = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, lim, len);
+ len += offset;
+ }
+ #else
+ {
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ len -= 8;
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ len = 1;
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ TREE_GET_BIT(probLen, len);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ TREE_DECODE(probLen, (1 << kLenNumHighBits), len);
+ len += kLenNumLowSymbols + kLenNumMidSymbols;
+ }
+ }
+ }
+ #endif
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ {
+ p->dicPos = dicPos;
+ return SZ_ERROR_DATA;
+ }
+ }
+ else if (distance >= checkDicSize)
+ {
+ p->dicPos = dicPos;
+ return SZ_ERROR_DATA;
+ }
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ }
+
+ len += kMatchMinLen;
+
+ {
+ SizeT rem;
+ unsigned curLen;
+ SizeT pos;
+
+ if ((rem = limit - dicPos) == 0)
+ {
+ p->dicPos = dicPos;
+ return SZ_ERROR_DATA;
+ }
+
+ curLen = ((rem < len) ? (unsigned)rem : len);
+ pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (curLen <= dicBufSize - pos)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *(dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+
+ NORMALIZE;
+
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = len;
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = state;
+
+ return SZ_OK;
+}
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+ {
+ Byte *dic = p->dic;
+ SizeT dicPos = p->dicPos;
+ SizeT dicBufSize = p->dicBufSize;
+ unsigned len = p->remainLen;
+ SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */
+ SizeT rem = limit - dicPos;
+ if (rem < len)
+ len = (unsigned)(rem);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len != 0)
+ {
+ len--;
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ do
+ {
+ SizeT limit2 = limit;
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit2 = p->dicPos + rem;
+ }
+
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+
+ if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ p->remainLen = kMatchSpecLenStart;
+
+ return 0;
+}
+
+typedef enum
+{
+ DUMMY_ERROR, /* unexpected end of input stream */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = buf + inSize;
+ const CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ const CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += ((UInt32)LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ (p->dicPos < p->reps[0] ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ const CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ NORMALIZE_CHECK;
+ return DUMMY_REP;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ const CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ unsigned numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ SizeT numProbs = LzmaProps_GetNumProbs(&p->prop);
+ SizeT i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ p->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+ p->code =
+ ((UInt32)p->tempBuf[1] << 24)
+ | ((UInt32)p->tempBuf[2] << 16)
+ | ((UInt32)p->tempBuf[3] << 8)
+ | ((UInt32)p->tempBuf[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+ p->tempBufSize = 0;
+ }
+
+ checkEndMarkNow = 0;
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ if (p->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ if (p->tempBufSize == 0)
+ {
+ SizeT processed;
+ const Byte *bufLimit;
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ memcpy(p->tempBuf, src, inSize);
+ p->tempBufSize = (unsigned)inSize;
+ (*srcLen) += inSize;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ bufLimit = src;
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+ p->buf = src;
+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+ return SZ_ERROR_DATA;
+ processed = (SizeT)(p->buf - src);
+ (*srcLen) += processed;
+ src += processed;
+ inSize -= processed;
+ }
+ else
+ {
+ unsigned rem = p->tempBufSize, lookAhead = 0;
+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+ p->tempBuf[rem++] = src[lookAhead++];
+ p->tempBufSize = rem;
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += lookAhead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ }
+ p->buf = p->tempBuf;
+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+ return SZ_ERROR_DATA;
+
+ {
+ unsigned kkk = (unsigned)(p->buf - p->tempBuf);
+ if (rem < kkk)
+ return SZ_ERROR_FAIL; /* some internal error */
+ rem -= kkk;
+ if (lookAhead < rem)
+ return SZ_ERROR_FAIL; /* some internal error */
+ lookAhead -= rem;
+ }
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = NULL;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = NULL;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (!p->probs || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (!p->probs)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+
+ {
+ UInt32 dictSize = propNew.dicSize;
+ SizeT mask = ((UInt32)1 << 12) - 1;
+ if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1;
+ else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;;
+ dicBufSize = ((SizeT)dictSize + mask) & ~mask;
+ if (dicBufSize < dictSize)
+ dicBufSize = dictSize;
+ }
+
+ if (!p->dic || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (!p->dic)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ LzmaDec_Construct(&p);
+ RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc));
+ p.dic = dest;
+ p.dicBufSize = outSize;
+ LzmaDec_Init(&p);
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+ *destLen = p.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/SevenZip/LzmaDec.h b/SevenZip/LzmaDec.h
new file mode 100644
index 0000000..cc44dae
--- /dev/null
+++ b/SevenZip/LzmaDec.h
@@ -0,0 +1,227 @@
+/* LzmaDec.h -- LZMA Decoder
+2013-01-18 : Igor Pavlov : Public domain */
+
+#ifndef __LZMA_DEC_H
+#define __LZMA_DEC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Constr()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Ppmd.h b/SevenZip/Ppmd.h
new file mode 100644
index 0000000..5655b26
--- /dev/null
+++ b/SevenZip/Ppmd.h
@@ -0,0 +1,85 @@
+/* Ppmd.h -- PPMD codec common code
+2016-05-16 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#ifndef __PPMD_H
+#define __PPMD_H
+
+#include "CpuArch.h"
+
+EXTERN_C_BEGIN
+
+#ifdef MY_CPU_32BIT
+ #define PPMD_32BIT
+#endif
+
+#define PPMD_INT_BITS 7
+#define PPMD_PERIOD_BITS 7
+#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
+
+#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
+#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
+#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
+#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
+
+#define PPMD_N1 4
+#define PPMD_N2 4
+#define PPMD_N3 4
+#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
+#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
+
+#pragma pack(push, 1)
+/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */
+
+/* SEE-contexts for PPM-contexts with masked symbols */
+typedef struct
+{
+ UInt16 Summ; /* Freq */
+ Byte Shift; /* Speed of Freq change; low Shift is for fast change */
+ Byte Count; /* Count to next change of Shift */
+} CPpmd_See;
+
+#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
+ { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
+
+typedef struct
+{
+ Byte Symbol;
+ Byte Freq;
+ UInt16 SuccessorLow;
+ UInt16 SuccessorHigh;
+} CPpmd_State;
+
+#pragma pack(pop)
+
+typedef
+ #ifdef PPMD_32BIT
+ CPpmd_State *
+ #else
+ UInt32
+ #endif
+ CPpmd_State_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ void *
+ #else
+ UInt32
+ #endif
+ CPpmd_Void_Ref;
+
+typedef
+ #ifdef PPMD_32BIT
+ Byte *
+ #else
+ UInt32
+ #endif
+ CPpmd_Byte_Ref;
+
+#define PPMD_SetAllBitsIn256Bytes(p) \
+ { unsigned z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \
+ p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }}
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Ppmd7.c b/SevenZip/Ppmd7.c
new file mode 100644
index 0000000..eda8eb7
--- /dev/null
+++ b/SevenZip/Ppmd7.c
@@ -0,0 +1,710 @@
+/* Ppmd7.c -- PPMdH codec
+2016-05-21 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include
+
+#include "Ppmd7.h"
+
+const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(nu) - 1])
+#define I2U(indx) (p->Indx2Units[indx])
+
+#ifdef PPMD_32BIT
+ #define REF(ptr) (ptr)
+#else
+ #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+#endif
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+#define STATS(ctx) Ppmd7_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd7_Context * CTX_PTR;
+
+struct CPpmd7_Node_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Node_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Node_Ref;
+
+typedef struct CPpmd7_Node_
+{
+ UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
+ UInt16 NU;
+ CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
+ CPpmd7_Node_Ref Prev;
+} CPpmd7_Node;
+
+#ifdef PPMD_32BIT
+ #define NODE(ptr) (ptr)
+#else
+ #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
+#endif
+
+void Ppmd7_Construct(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = 0;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while (--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 3; i++)
+ p->NS2Indx[i] = (Byte)i;
+ for (m = i, k = 1; i < 256; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 2;
+ }
+
+ memset(p->HB2Flag, 0, 0x40);
+ memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
+}
+
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = 0;
+}
+
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc)
+{
+ if (p->Base == 0 || p->Size != size)
+ {
+ Ppmd7_Free(p, alloc);
+ p->AlignOffset =
+ #ifdef PPMD_32BIT
+ (4 - size) & 3;
+ #else
+ 4 - (size & 3);
+ #endif
+ if ((p->Base = (Byte *)alloc->Alloc(alloc, p->AlignOffset + size
+ #ifndef PPMD_32BIT
+ + UNIT_SIZE
+ #endif
+ )) == 0)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
+{
+ *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
+ p->FreeList[indx] = REF(node);
+}
+
+static void *RemoveNode(CPpmd7 *p, unsigned indx)
+{
+ CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
+ p->FreeList[indx] = *node;
+ return node;
+}
+
+static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ InsertNode(p, ptr, i);
+}
+
+static void GlueFreeBlocks(CPpmd7 *p)
+{
+ #ifdef PPMD_32BIT
+ CPpmd7_Node headItem;
+ CPpmd7_Node_Ref head = &headItem;
+ #else
+ CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
+ #endif
+
+ CPpmd7_Node_Ref n = head;
+ unsigned i;
+
+ p->GlueCount = 255;
+
+ /* create doubly-linked list of free blocks */
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ UInt16 nu = I2U(i);
+ CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd7_Node *node = NODE(next);
+ node->Next = n;
+ n = NODE(n)->Prev = next;
+ next = *(const CPpmd7_Node_Ref *)node;
+ node->Stamp = 0;
+ node->NU = (UInt16)nu;
+ }
+ }
+ NODE(head)->Stamp = 1;
+ NODE(head)->Next = n;
+ NODE(n)->Prev = head;
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
+
+ /* Glue free blocks */
+ while (n != head)
+ {
+ CPpmd7_Node *node = NODE(n);
+ UInt32 nu = (UInt32)node->NU;
+ for (;;)
+ {
+ CPpmd7_Node *node2 = NODE(n) + nu;
+ nu += node2->NU;
+ if (node2->Stamp != 0 || nu >= 0x10000)
+ break;
+ NODE(node2->Prev)->Next = node2->Next;
+ NODE(node2->Next)->Prev = node2->Prev;
+ node->NU = (UInt16)nu;
+ }
+ n = node->Next;
+ }
+
+ /* Fill lists of free blocks */
+ for (n = NODE(head)->Next; n != head;)
+ {
+ CPpmd7_Node *node = NODE(n);
+ unsigned nu;
+ CPpmd7_Node_Ref next = node->Next;
+ for (nu = node->NU; nu > 128; nu -= 128, node += 128)
+ InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ InsertNode(p, node + k, nu - k - 1);
+ }
+ InsertNode(p, node, i);
+ n = next;
+ }
+}
+
+static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
+{
+ unsigned i;
+ void *retVal;
+ if (p->GlueCount == 0)
+ {
+ GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ }
+ i = indx;
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ p->GlueCount--;
+ return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+ retVal = RemoveNode(p, i);
+ SplitBlock(p, retVal, i, indx);
+ return retVal;
+}
+
+static void *AllocUnits(CPpmd7 *p, unsigned indx)
+{
+ UInt32 numBytes;
+ if (p->FreeList[indx] != 0)
+ return RemoveNode(p, indx);
+ numBytes = U2B(I2U(indx));
+ if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
+ {
+ void *retVal = p->LoUnit;
+ p->LoUnit += numBytes;
+ return retVal;
+ }
+ return AllocUnitsRare(p, indx);
+}
+
+#define MyMem12Cpy(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); }
+
+static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = RemoveNode(p, i1);
+ MyMem12Cpy(ptr, oldPtr, newNU);
+ InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
+
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
+ (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
+}
+
+static void RestartModel(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ p->Text = p->Base + p->AlignOffset;
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ p->MinContext->Suffix = 0;
+ p->MinContext->NumStats = 256;
+ p->MinContext->SummFreq = 256 + 1;
+ p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+ p->LoUnit += U2B(256 / 2);
+ p->MinContext->Stats = REF(p->FoundState);
+ for (i = 0; i < 256; i++)
+ {
+ CPpmd_State *s = &p->FoundState[i];
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ for (i = 0; i < 128; i++)
+ for (k = 0; k < 8; k++)
+ {
+ UInt16 *dest = p->BinSumm[i] + k;
+ UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
+ for (m = 0; m < 64; m += 8)
+ dest[m] = val;
+ }
+
+ for (i = 0; i < 25; i++)
+ for (k = 0; k < 16; k++)
+ {
+ CPpmd_See *s = &p->See[i][k];
+ s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
+ s->Count = 4;
+ }
+}
+
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
+{
+ p->MaxOrder = maxOrder;
+ RestartModel(p);
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Count = 64; /* unused */
+}
+
+static CTX_PTR CreateSuccessors(CPpmd7 *p, Bool skip)
+{
+ CPpmd_State upState;
+ CTX_PTR c = p->MinContext;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ CPpmd_State *ps[PPMD7_MAX_ORDER];
+ unsigned numPs = 0;
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+ if (c->NumStats != 1)
+ {
+ for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
+ }
+ else
+ s = ONE_STATE(c);
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ c = CTX(successor);
+ if (numPs == 0)
+ return c;
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
+ SetSuccessor(&upState, upBranch + 1);
+
+ if (c->NumStats == 1)
+ upState.Freq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != upState.Symbol; s++);
+ cf = s->Freq - 1;
+ s0 = c->SummFreq - c->NumStats - cf;
+ upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
+ }
+
+ do
+ {
+ /* Create Child */
+ CTX_PTR c1; /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (CTX_PTR)RemoveNode(p, 0);
+ else
+ {
+ c1 = (CTX_PTR)AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->NumStats = 1;
+ *ONE_STATE(c1) = upState;
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+static void UpdateModel(CPpmd7 *p)
+{
+ CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
+ CTX_PTR c;
+ unsigned s0, ns;
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 1)
+ {
+ CPpmd_State *s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ CPpmd_State *s = STATS(c);
+ if (s->Symbol != p->FoundState->Symbol)
+ {
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ s--;
+ }
+ }
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq += 2;
+ c->SummFreq += 2;
+ }
+ }
+ }
+
+ if (p->OrderFall == 0)
+ {
+ p->MinContext = p->MaxContext = CreateSuccessors(p, True);
+ if (p->MinContext == 0)
+ {
+ RestartModel(p);
+ return;
+ }
+ SetSuccessor(p->FoundState, REF(p->MinContext));
+ return;
+ }
+
+ *p->Text++ = p->FoundState->Symbol;
+ successor = REF(p->Text);
+ if (p->Text >= p->UnitsStart)
+ {
+ RestartModel(p);
+ return;
+ }
+
+ if (fSuccessor)
+ {
+ if (fSuccessor <= successor)
+ {
+ CTX_PTR cs = CreateSuccessors(p, False);
+ if (cs == NULL)
+ {
+ RestartModel(p);
+ return;
+ }
+ fSuccessor = REF(cs);
+ }
+ if (--p->OrderFall == 0)
+ {
+ successor = fSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ }
+ else
+ {
+ SetSuccessor(p->FoundState, successor);
+ fSuccessor = REF(p->MinContext);
+ }
+
+ s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
+
+ for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 cf, sf;
+ if ((ns1 = c->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = ns1 >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I(oldNU + 1))
+ {
+ void *ptr = AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RestartModel(p);
+ return;
+ }
+ oldPtr = STATS(c);
+ MyMem12Cpy(ptr, oldPtr, oldNU);
+ InsertNode(p, oldPtr, i);
+ c->Stats = STATS_REF(ptr);
+ }
+ }
+ c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
+ }
+ else
+ {
+ CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
+ if (!s)
+ {
+ RestartModel(p);
+ return;
+ }
+ *s = *ONE_STATE(c);
+ c->Stats = REF(s);
+ if (s->Freq < MAX_FREQ / 4 - 1)
+ s->Freq <<= 1;
+ else
+ s->Freq = MAX_FREQ - 4;
+ c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
+ }
+ cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
+ sf = (UInt32)s0 + c->SummFreq;
+ if (cf < 6 * sf)
+ {
+ cf = 1 + (cf > sf) + (cf >= 4 * sf);
+ c->SummFreq += 3;
+ }
+ else
+ {
+ cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
+ c->SummFreq = (UInt16)(c->SummFreq + cf);
+ }
+ {
+ CPpmd_State *s = STATS(c) + ns1;
+ SetSuccessor(s, successor);
+ s->Symbol = p->FoundState->Symbol;
+ s->Freq = (Byte)cf;
+ c->NumStats = (UInt16)(ns1 + 1);
+ }
+ }
+ p->MaxContext = p->MinContext = CTX(fSuccessor);
+}
+
+static void Rescale(CPpmd7 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+ {
+ CPpmd_State tmp = *s;
+ for (; s != stats; s--)
+ s[0] = s[-1];
+ *s = tmp;
+ }
+ escFreq = p->MinContext->SummFreq - s->Freq;
+ s->Freq += 4;
+ adder = (p->OrderFall != 0);
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq = s->Freq;
+
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ escFreq -= (++s)->Freq;
+ s->Freq = (Byte)((s->Freq + adder) >> 1);
+ sumFreq += s->Freq;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ CPpmd_State *s1 = s;
+ CPpmd_State tmp = *s1;
+ do
+ s1[0] = s1[-1];
+ while (--s1 != stats && tmp.Freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ unsigned numStats = p->MinContext->NumStats;
+ unsigned n0, n1;
+ do { i++; } while ((--s)->Freq == 0);
+ escFreq += i;
+ p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
+ if (p->MinContext->NumStats == 1)
+ {
+ CPpmd_State tmp = *stats;
+ do
+ {
+ tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
+ escFreq >>= 1;
+ }
+ while (escFreq > 1);
+ InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
+ *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
+ return;
+ }
+ n0 = (numStats + 1) >> 1;
+ n1 = (p->MinContext->NumStats + 1) >> 1;
+ if (n0 != n1)
+ p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ }
+ p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ p->FoundState = STATS(p->MinContext);
+}
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ unsigned nonMasked = p->MinContext->NumStats - numMasked;
+ if (p->MinContext->NumStats != 256)
+ {
+ see = p->See[(unsigned)p->NS2Indx[nonMasked - 1]] +
+ (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
+ 2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
+ 4 * (unsigned)(numMasked > nonMasked) +
+ p->HiBitsFlag;
+ {
+ unsigned r = (see->Summ >> see->Shift);
+ see->Summ = (UInt16)(see->Summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+static void NextContext(CPpmd7 *p)
+{
+ CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (Byte *)c > p->Text)
+ p->MinContext = p->MaxContext = c;
+ else
+ UpdateModel(p);
+}
+
+void Ppmd7_Update1(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ s->Freq += 4;
+ p->MinContext->SummFreq += 4;
+ if (s[0].Freq > s[-1].Freq)
+ {
+ SwapStates(&s[0], &s[-1]);
+ p->FoundState = --s;
+ if (s->Freq > MAX_FREQ)
+ Rescale(p);
+ }
+ NextContext(p);
+}
+
+void Ppmd7_Update1_0(CPpmd7 *p)
+{
+ p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
+ p->RunLength += p->PrevSuccess;
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ NextContext(p);
+}
+
+void Ppmd7_UpdateBin(CPpmd7 *p)
+{
+ p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ NextContext(p);
+}
+
+void Ppmd7_Update2(CPpmd7 *p)
+{
+ p->MinContext->SummFreq += 4;
+ if ((p->FoundState->Freq += 4) > MAX_FREQ)
+ Rescale(p);
+ p->RunLength = p->InitRL;
+ UpdateModel(p);
+}
diff --git a/SevenZip/Ppmd7.h b/SevenZip/Ppmd7.h
new file mode 100644
index 0000000..87eefde
--- /dev/null
+++ b/SevenZip/Ppmd7.h
@@ -0,0 +1,140 @@
+/* Ppmd7.h -- PPMdH compression codec
+2016-05-21 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+/* This code supports virtual RangeDecoder and includes the implementation
+of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
+If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
+
+#ifndef __PPMD7_H
+#define __PPMD7_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD7_MIN_ORDER 2
+#define PPMD7_MAX_ORDER 64
+
+#define PPMD7_MIN_MEM_SIZE (1 << 11)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+
+struct CPpmd7_Context_;
+
+typedef
+ #ifdef PPMD_32BIT
+ struct CPpmd7_Context_ *
+ #else
+ UInt32
+ #endif
+ CPpmd7_Context_Ref;
+
+typedef struct CPpmd7_Context_
+{
+ UInt16 NumStats;
+ UInt16 SummFreq;
+ CPpmd_State_Ref Stats;
+ CPpmd7_Context_Ref Suffix;
+} CPpmd7_Context;
+
+#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
+
+typedef struct
+{
+ CPpmd7_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+ UInt32 AlignOffset;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES];
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
+ CPpmd_See DummySee, See[25][16];
+ UInt16 BinSumm[128][64];
+} CPpmd7;
+
+void Ppmd7_Construct(CPpmd7 *p);
+Bool Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAlloc *alloc);
+void Ppmd7_Free(CPpmd7 *p, ISzAlloc *alloc);
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
+#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+extern const Byte PPMD7_kExpEscape[16];
+
+#ifdef PPMD_32BIT
+ #define Ppmd7_GetPtr(p, ptr) (ptr)
+ #define Ppmd7_GetContext(p, ptr) (ptr)
+ #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
+#else
+ #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
+ #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
+#endif
+
+void Ppmd7_Update1(CPpmd7 *p);
+void Ppmd7_Update1_0(CPpmd7 *p);
+void Ppmd7_Update2(CPpmd7 *p);
+void Ppmd7_UpdateBin(CPpmd7 *p);
+
+#define Ppmd7_GetBinSumm(p) \
+ &p->BinSumm[(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
+ p->NS2BSIndx[Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
+ (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
+ 2 * p->HB2Flag[(unsigned)Ppmd7Context_OneState(p->MinContext)->Symbol] + \
+ ((p->RunLength >> 26) & 0x20)]
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* ---------- Decode ---------- */
+
+typedef struct
+{
+ UInt32 (*GetThreshold)(void *p, UInt32 total);
+ void (*Decode)(void *p, UInt32 start, UInt32 size);
+ UInt32 (*DecodeBit)(void *p, UInt32 size0);
+} IPpmd7_RangeDec;
+
+typedef struct
+{
+ IPpmd7_RangeDec p;
+ UInt32 Range;
+ UInt32 Code;
+ IByteIn *Stream;
+} CPpmd7z_RangeDec;
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);
+#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc);
+
+
+/* ---------- Encode ---------- */
+
+typedef struct
+{
+ UInt64 Low;
+ UInt32 Range;
+ Byte Cache;
+ UInt64 CacheSize;
+ IByteOut *Stream;
+} CPpmd7z_RangeEnc;
+
+void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p);
+void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p);
+
+void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
+
+EXTERN_C_END
+
+#endif
diff --git a/SevenZip/Ppmd7Dec.c b/SevenZip/Ppmd7Dec.c
new file mode 100644
index 0000000..04b4b09
--- /dev/null
+++ b/SevenZip/Ppmd7Dec.c
@@ -0,0 +1,189 @@
+/* Ppmd7Dec.c -- PPMdH Decoder
+2010-03-12 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include "Ppmd7.h"
+
+#define kTopValue (1 << 24)
+
+Bool Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ if (p->Stream->Read((void *)p->Stream) != 0)
+ return False;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+static UInt32 Range_GetThreshold(void *pp, UInt32 total)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ return (p->Code) / (p->Range /= total);
+}
+
+static void Range_Normalize(CPpmd7z_RangeDec *p)
+{
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ if (p->Range < kTopValue)
+ {
+ p->Code = (p->Code << 8) | p->Stream->Read((void *)p->Stream);
+ p->Range <<= 8;
+ }
+ }
+}
+
+static void Range_Decode(void *pp, UInt32 start, UInt32 size)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ p->Code -= start * p->Range;
+ p->Range *= size;
+ Range_Normalize(p);
+}
+
+static UInt32 Range_DecodeBit(void *pp, UInt32 size0)
+{
+ CPpmd7z_RangeDec *p = (CPpmd7z_RangeDec *)pp;
+ UInt32 newBound = (p->Range >> 14) * size0;
+ UInt32 symbol;
+ if (p->Code < newBound)
+ {
+ symbol = 0;
+ p->Range = newBound;
+ }
+ else
+ {
+ symbol = 1;
+ p->Code -= newBound;
+ p->Range -= newBound;
+ }
+ Range_Normalize(p);
+ return symbol;
+}
+
+void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
+{
+ p->p.GetThreshold = Range_GetThreshold;
+ p->p.Decode = Range_Decode;
+ p->p.DecodeBit = Range_DecodeBit;
+}
+
+
+#define MASK(sym) ((signed char *)charMask)[sym]
+
+int Ppmd7_DecodeSymbol(CPpmd7 *p, IPpmd7_RangeDec *rc)
+{
+ size_t charMask[256 / sizeof(size_t)];
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
+ {
+ Byte symbol;
+ rc->Decode(rc, 0, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1_0(p);
+ return symbol;
+ }
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats - 1;
+ do
+ {
+ if ((hiCnt += (++s)->Freq) > count)
+ {
+ Byte symbol;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update1(p);
+ return symbol;
+ }
+ }
+ while (--i);
+ if (count >= p->MinContext->SummFreq)
+ return -2;
+ p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
+ rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(s->Symbol) = 0;
+ i = p->MinContext->NumStats - 1;
+ do { MASK((--s)->Symbol) = 0; } while (--i);
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ if (rc->DecodeBit(rc, *prob) == 0)
+ {
+ Byte symbol;
+ *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
+ symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
+ Ppmd7_UpdateBin(p);
+ return symbol;
+ }
+ *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
+ p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
+ PPMD_SetAllBitsIn256Bytes(charMask);
+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+ for (;;)
+ {
+ CPpmd_State *ps[256], *s;
+ UInt32 freqSum, count, hiCnt;
+ CPpmd_See *see;
+ unsigned i, num, numMasked = p->MinContext->NumStats;
+ do
+ {
+ p->OrderFall++;
+ if (!p->MinContext->Suffix)
+ return -1;
+ p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
+ }
+ while (p->MinContext->NumStats == numMasked);
+ hiCnt = 0;
+ s = Ppmd7_GetStats(p, p->MinContext);
+ i = 0;
+ num = p->MinContext->NumStats - numMasked;
+ do
+ {
+ int k = (int)(MASK(s->Symbol));
+ hiCnt += (s->Freq & k);
+ ps[i] = s++;
+ i -= k;
+ }
+ while (i != num);
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ count = rc->GetThreshold(rc, freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte symbol;
+ CPpmd_State **pps = ps;
+ for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
+ s = *pps;
+ rc->Decode(rc, hiCnt - s->Freq, s->Freq);
+ Ppmd_See_Update(see);
+ p->FoundState = s;
+ symbol = s->Symbol;
+ Ppmd7_Update2(p);
+ return symbol;
+ }
+ if (count >= freqSum)
+ return -2;
+ rc->Decode(rc, hiCnt, freqSum - hiCnt);
+ see->Summ = (UInt16)(see->Summ + freqSum);
+ do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
+ }
+}
diff --git a/SevenZip/Precomp.c b/SevenZip/Precomp.c
new file mode 100644
index 0000000..01605e3
--- /dev/null
+++ b/SevenZip/Precomp.c
@@ -0,0 +1,4 @@
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/SevenZip/Precomp.h b/SevenZip/Precomp.h
new file mode 100644
index 0000000..e8ff8b4
--- /dev/null
+++ b/SevenZip/Precomp.h
@@ -0,0 +1,10 @@
+/* Precomp.h -- StdAfx
+2013-11-12 : Igor Pavlov : Public domain */
+
+#ifndef __7Z_PRECOMP_H
+#define __7Z_PRECOMP_H
+
+#include "Compiler.h"
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/SevenZip/SevenZip.vcxproj b/SevenZip/SevenZip.vcxproj
new file mode 100644
index 0000000..3fc2fb8
--- /dev/null
+++ b/SevenZip/SevenZip.vcxproj
@@ -0,0 +1,416 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Libretro
+ Win32
+
+
+ Libretro
+ x64
+
+
+ PGO Optimize
+ Win32
+
+
+ PGO Optimize
+ x64
+
+
+ PGO Profile
+ Win32
+
+
+ PGO Profile
+ x64
+
+
+ Release
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ x64
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {52C4BA3A-E699-4305-B23F-C9083FD07AB6}
+ Win32Proj
+ SevenZip
+ 10.0.16299.0
+
+
+
+ StaticLibrary
+ true
+ v141
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ StaticLibrary
+ true
+ v141
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+ StaticLibrary
+ false
+ v141
+ true
+ Unicode
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\PGO Profile\
+ obj\$(Platform)\PGO Profile\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\
+ obj\$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)\bin\$(PlatformTarget)\PGO Profile\
+ obj\$(Platform)\PGO Profile\
+
+
+
+
+
+ Level3
+ Disabled
+ WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+
+
+ Windows
+
+
+
+
+
+
+ Level3
+ Disabled
+ _DEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreadedDebug
+
+
+ Windows
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+
+
+ Windows
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ CompileAsC
+
+
+ Windows
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ CompileAsC
+
+
+ Windows
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ CompileAsC
+
+
+ Windows
+ true
+ true
+
+
+
+
+ Level3
+
+
+ MaxSpeed
+ true
+ true
+ NDEBUG;_LIB;%(PreprocessorDefinitions)
+ true
+ MultiThreaded
+ CompileAsC
+
+
+ Windows
+ true
+ true
+
+
+
+
+
+
\ No newline at end of file
diff --git a/SevenZip/SevenZip.vcxproj.filters b/SevenZip/SevenZip.vcxproj.filters
new file mode 100644
index 0000000..b4894d2
--- /dev/null
+++ b/SevenZip/SevenZip.vcxproj.filters
@@ -0,0 +1,128 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {93995380-89BD-4b04-88EB-625FBE52EBFB}
+ h;hh;hpp;hxx;hm;inl;inc;xsd
+
+
+
+
+ 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
+
+
+ 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
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/Utilities/ArchiveReader.cpp b/Utilities/ArchiveReader.cpp
new file mode 100644
index 0000000..7dcda01
--- /dev/null
+++ b/Utilities/ArchiveReader.cpp
@@ -0,0 +1,125 @@
+#include "stdafx.h"
+#include "ArchiveReader.h"
+#include
+#include
+#include
+#include "FolderUtilities.h"
+#include "ZipReader.h"
+#include "SZReader.h"
+
+ArchiveReader::~ArchiveReader()
+{
+ if(_buffer) {
+ delete[] _buffer;
+ _buffer = nullptr;
+ }
+}
+
+bool ArchiveReader::GetStream(string filename, std::stringstream &stream)
+{
+ if(_initialized) {
+ vector fileData;
+ if(ExtractFile(filename, fileData)) {
+ stream.write((char*)fileData.data(), fileData.size());
+ return true;
+ }
+ }
+ return false;
+}
+
+vector ArchiveReader::GetFileList(std::initializer_list extensions)
+{
+ if(extensions.size() == 0) {
+ return InternalGetFileList();
+ }
+
+ vector filenames;
+ for(string filename : InternalGetFileList()) {
+ string lcFilename = filename;
+ std::transform(lcFilename.begin(), lcFilename.end(), lcFilename.begin(), ::tolower);
+ for(string ext : extensions) {
+ if(lcFilename.size() >= ext.size()) {
+ if(lcFilename.substr(lcFilename.length() - ext.size(), ext.size()).compare(ext) == 0) {
+ filenames.push_back(filename);
+ }
+ }
+ }
+ }
+
+ return filenames;
+}
+
+bool ArchiveReader::CheckFile(string filename)
+{
+ vector files = InternalGetFileList();
+ return std::find(files.begin(), files.end(), filename) != files.end();
+}
+
+bool ArchiveReader::LoadArchive(std::istream &in)
+{
+ in.seekg(0, std::ios::end);
+ std::streampos filesize = in.tellg();
+ in.seekg(0, std::ios::beg);
+
+ if(_buffer) {
+ delete[] _buffer;
+ _buffer = nullptr;
+ }
+
+ _buffer = new uint8_t[(uint32_t)filesize];
+ in.read((char*)_buffer, filesize);
+ in.seekg(0, std::ios::beg);
+ bool result = LoadArchive(_buffer, (size_t)filesize);
+ return result;
+}
+
+bool ArchiveReader::LoadArchive(vector &data)
+{
+ return LoadArchive(data.data(), data.size());
+}
+
+bool ArchiveReader::LoadArchive(void* buffer, size_t size)
+{
+ if(InternalLoadArchive(buffer, size)) {
+ _initialized = true;
+ return true;
+ }
+ return false;
+}
+
+bool ArchiveReader::LoadArchive(string filename)
+{
+ ifstream in(filename, std::ios::binary | std::ios::in);
+ if(in.good()) {
+ LoadArchive(in);
+ in.close();
+ }
+ return false;
+}
+
+shared_ptr ArchiveReader::GetReader(std::istream &in)
+{
+ uint8_t header[2] = { 0,0 };
+ in.read((char*)header, 2);
+
+ shared_ptr reader;
+ if(memcmp(header, "PK", 2) == 0) {
+ reader.reset(new ZipReader());
+ } else if(memcmp(header, "7z", 2) == 0) {
+ reader.reset(new SZReader());
+ }
+
+ if(reader) {
+ reader->LoadArchive(in);
+ }
+ return reader;
+}
+
+shared_ptr ArchiveReader::GetReader(string filepath)
+{
+ ifstream in(filepath, std::ios::in | std::ios::binary);
+ if(in) {
+ return GetReader(in);
+ }
+ return nullptr;
+}
\ No newline at end of file
diff --git a/Utilities/ArchiveReader.h b/Utilities/ArchiveReader.h
new file mode 100644
index 0000000..a2076c8
--- /dev/null
+++ b/Utilities/ArchiveReader.h
@@ -0,0 +1,28 @@
+#pragma once
+#include "stdafx.h"
+
+class ArchiveReader
+{
+protected:
+ bool _initialized = false;
+ uint8_t* _buffer = nullptr;
+ virtual bool InternalLoadArchive(void* buffer, size_t size) = 0;
+ virtual vector InternalGetFileList() = 0;
+public:
+ ~ArchiveReader();
+
+ bool LoadArchive(void* buffer, size_t size);
+ bool LoadArchive(vector& data);
+ bool LoadArchive(string filename);
+ bool LoadArchive(std::istream &in);
+
+ bool GetStream(string filename, std::stringstream &stream);
+
+ vector GetFileList(std::initializer_list extensions = {});
+ bool CheckFile(string filename);
+
+ virtual bool ExtractFile(string filename, vector &output) = 0;
+
+ static shared_ptr GetReader(std::istream &in);
+ static shared_ptr GetReader(string filepath);
+};
\ No newline at end of file
diff --git a/Utilities/AutoResetEvent.cpp b/Utilities/AutoResetEvent.cpp
new file mode 100644
index 0000000..f04943c
--- /dev/null
+++ b/Utilities/AutoResetEvent.cpp
@@ -0,0 +1,40 @@
+#include "stdafx.h"
+#include "AutoResetEvent.h"
+
+AutoResetEvent::AutoResetEvent()
+{
+ _signaled = false;
+}
+
+AutoResetEvent::~AutoResetEvent()
+{
+ //Can't signal here, seems to cause process crashes when this occurs while the
+ //application is exiting.
+}
+
+void AutoResetEvent::Wait(int timeoutDelay)
+{
+ std::unique_lock lock(_mutex);
+ if(timeoutDelay == 0) {
+ //Wait until signaled
+ _signal.wait(lock, [this] { return _signaled; });
+ } else {
+ //Wait until signaled or timeout
+ auto timeoutTime = std::chrono::system_clock::now() + std::chrono::duration(timeoutDelay);
+ _signal.wait_until(lock, timeoutTime, [this] { return _signaled; });
+ }
+ _signaled = false;
+}
+
+void AutoResetEvent::Reset()
+{
+ std::unique_lock lock(_mutex);
+ _signaled = false;
+}
+
+void AutoResetEvent::Signal()
+{
+ std::unique_lock lock(_mutex);
+ _signaled = true;
+ _signal.notify_all();
+}
diff --git a/Utilities/AutoResetEvent.h b/Utilities/AutoResetEvent.h
new file mode 100644
index 0000000..b272f1d
--- /dev/null
+++ b/Utilities/AutoResetEvent.h
@@ -0,0 +1,21 @@
+#pragma once
+#include "stdafx.h"
+
+#include
+#include
+
+class AutoResetEvent
+{
+private:
+ std::condition_variable _signal;
+ std::mutex _mutex;
+ bool _signaled;
+
+public:
+ AutoResetEvent();
+ ~AutoResetEvent();
+
+ void Reset();
+ void Wait(int timeoutDelay = 0);
+ void Signal();
+};
diff --git a/Utilities/AviWriter.cpp b/Utilities/AviWriter.cpp
new file mode 100644
index 0000000..fdd63fc
--- /dev/null
+++ b/Utilities/AviWriter.cpp
@@ -0,0 +1,273 @@
+// This file is a part of Mesen
+// It is a heavily modified version of the hardware.h/cpp file found in DOSBox's code.
+
+/*
+* Copyright (C) 2002-2011 The DOSBox Team
+*
+* 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 2 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, write to the Free Software
+* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+*/
+
+#include "stdafx.h"
+#include
+#include
+#include "AviWriter.h"
+#include "BaseCodec.h"
+#include "RawCodec.h"
+#include "ZmbvCodec.h"
+#include "CamstudioCodec.h"
+
+void AviWriter::WriteAviChunk(const char *tag, uint32_t size, void *data, uint32_t flags)
+{
+ uint8_t chunk[8] = { (uint8_t)tag[0], (uint8_t)tag[1], (uint8_t)tag[2], (uint8_t)tag[3] };
+ host_writed(&chunk[4], size);
+ _file.write((char*)chunk, 8);
+
+ uint32_t writesize = (size + 1)&~1;
+ _file.write((char*)data, writesize);
+
+ uint32_t pos = _written + 4;
+ _written += writesize + 8;
+
+ _aviIndex.push_back(tag[0]);
+ _aviIndex.push_back(tag[1]);
+ _aviIndex.push_back(tag[2]);
+ _aviIndex.push_back(tag[3]);
+ _aviIndex.insert(_aviIndex.end(), 12, 0);
+ host_writed(_aviIndex.data() + _aviIndex.size() - 12, flags);
+ host_writed(_aviIndex.data() + _aviIndex.size() - 8, pos);
+ host_writed(_aviIndex.data() + _aviIndex.size() - 4, size);
+}
+
+void AviWriter::host_writew(uint8_t* buffer, uint16_t value)
+{
+ buffer[0] = value & 0xFF;
+ buffer[1] = value >> 8;
+}
+
+void AviWriter::host_writed(uint8_t* buffer, uint32_t value)
+{
+ buffer[0] = value;
+ buffer[1] = value >> 8;
+ buffer[2] = value >> 16;
+ buffer[3] = value >> 24;
+}
+
+bool AviWriter::StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel)
+{
+ _codecType = codec;
+ _file.open(filename, std::ios::out | std::ios::binary);
+ if(!_file) {
+ return false;
+ }
+
+ switch(_codecType) {
+ default:
+ case VideoCodec::None: _codec.reset(new RawCodec()); break;
+ case VideoCodec::ZMBV: _codec.reset(new ZmbvCodec()); break;
+ case VideoCodec::CSCD: _codec.reset(new CamstudioCodec()); break;
+ }
+
+ if(!_codec->SetupCompress(width, height, compressionLevel)) {
+ return false;
+ }
+
+ _frameBuffer = new uint8_t[width*height*bpp];
+
+ _aviIndex.clear();
+ _aviIndex.insert(_aviIndex.end(), 8, 0);
+
+ _width = width;
+ _height = height;
+ _bpp = bpp;
+ _fps = fps;
+
+ _audiorate = audioSampleRate;
+
+ for(int i = 0; i < AviWriter::AviHeaderSize; i++) {
+ _file.put(0);
+ }
+ _frames = 0;
+ _written = 0;
+ _audioPos = 0;
+ _audiowritten = 0;
+
+ return true;
+}
+
+void AviWriter::EndWrite()
+{
+ /* Close the video */
+ uint8_t avi_header[AviWriter::AviHeaderSize];
+ uint32_t main_list;
+ uint32_t header_pos = 0;
+#define AVIOUT4(_S_) memcpy(&avi_header[header_pos],_S_,4);header_pos+=4;
+#define AVIOUTw(_S_) host_writew(&avi_header[header_pos], _S_);header_pos+=2;
+#define AVIOUTd(_S_) host_writed(&avi_header[header_pos], _S_);header_pos+=4;
+ /* Try and write an avi header */
+ AVIOUT4("RIFF"); // Riff header
+ AVIOUTd(AviWriter::AviHeaderSize + _written - 8 + (uint32_t)_aviIndex.size());
+ AVIOUT4("AVI ");
+ AVIOUT4("LIST"); // List header
+ main_list = header_pos;
+ AVIOUTd(0); // TODO size of list
+ AVIOUT4("hdrl");
+
+ AVIOUT4("avih");
+ AVIOUTd(56); /* # of bytes to follow */
+ AVIOUTd((uint32_t)(1000000 / _fps)); /* Microseconds per frame */
+ AVIOUTd(0);
+ AVIOUTd(0); /* PaddingGranularity (whatever that might be) */
+ AVIOUTd(0x110); /* Flags,0x10 has index, 0x100 interleaved */
+ AVIOUTd(_frames); /* TotalFrames */
+ AVIOUTd(0); /* InitialFrames */
+ AVIOUTd(2); /* Stream count */
+ AVIOUTd(0); /* SuggestedBufferSize */
+ AVIOUTd(_width); /* Width */
+ AVIOUTd(_height); /* Height */
+ AVIOUTd(0); /* TimeScale: Unit used to measure time */
+ AVIOUTd(0); /* DataRate: Data rate of playback */
+ AVIOUTd(0); /* StartTime: Starting time of AVI data */
+ AVIOUTd(0); /* DataLength: Size of AVI data chunk */
+
+ /* Video stream list */
+ AVIOUT4("LIST");
+ AVIOUTd(4 + 8 + 56 + 8 + 40); /* Size of the list */
+ AVIOUT4("strl");
+ /* video stream header */
+ AVIOUT4("strh");
+ AVIOUTd(56); /* # of bytes to follow */
+ AVIOUT4("vids"); /* Type */
+ AVIOUT4(_codec->GetFourCC()); /* Handler */
+ AVIOUTd(0); /* Flags */
+ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */
+ AVIOUTd(0); /* InitialFrames */
+ AVIOUTd(1000000); /* Scale */
+ AVIOUTd(_fps); /* Rate: Rate/Scale == samples/second */
+ AVIOUTd(0); /* Start */
+ AVIOUTd(_frames); /* Length */
+ AVIOUTd(0); /* SuggestedBufferSize */
+ AVIOUTd(~0); /* Quality */
+ AVIOUTd(0); /* SampleSize */
+ AVIOUTd(0); /* Frame */
+ AVIOUTd(0); /* Frame */
+ /* The video stream format */
+ AVIOUT4("strf");
+ AVIOUTd(40); /* # of bytes to follow */
+ AVIOUTd(40); /* Size */
+ AVIOUTd(_width); /* Width */
+ AVIOUTd(_height); /* Height */
+ // OUTSHRT(1); OUTSHRT(24); /* Planes, Count */
+ AVIOUTw(1); //number of planes
+ AVIOUTw(24); //bits for colors
+ AVIOUT4(_codec->GetFourCC()); /* Compression */
+ AVIOUTd(_width * _height * 4); /* SizeImage (in bytes?) */
+ AVIOUTd(0); /* XPelsPerMeter */
+ AVIOUTd(0); /* YPelsPerMeter */
+ AVIOUTd(0); /* ClrUsed: Number of colors used */
+ AVIOUTd(0); /* ClrImportant: Number of colors important */
+
+ /* Audio stream list */
+ AVIOUT4("LIST");
+ AVIOUTd(4 + 8 + 56 + 8 + 16); /* Length of list in bytes */
+ AVIOUT4("strl");
+ /* The audio stream header */
+ AVIOUT4("strh");
+ AVIOUTd(56); /* # of bytes to follow */
+ AVIOUT4("auds");
+ AVIOUTd(0); /* Format (Optionally) */
+ AVIOUTd(0); /* Flags */
+ AVIOUTd(0); /* Reserved, MS says: wPriority, wLanguage */
+ AVIOUTd(0); /* InitialFrames */
+ AVIOUTd(4); /* Scale */
+ AVIOUTd(_audiorate * 4); /* Rate, actual rate is scale/rate */
+ AVIOUTd(0); /* Start */
+ if(!_audiorate)
+ _audiorate = 1;
+ AVIOUTd(_audiowritten / 4); /* Length */
+ AVIOUTd(0); /* SuggestedBufferSize */
+ AVIOUTd(~0); /* Quality */
+ AVIOUTd(4); /* SampleSize */
+ AVIOUTd(0); /* Frame */
+ AVIOUTd(0); /* Frame */
+ /* The audio stream format */
+ AVIOUT4("strf");
+ AVIOUTd(16); /* # of bytes to follow */
+ AVIOUTw(1); /* Format, WAVE_ZMBV_FORMAT_PCM */
+ AVIOUTw(2); /* Number of channels */
+ AVIOUTd(_audiorate); /* SamplesPerSec */
+ AVIOUTd(_audiorate * 4); /* AvgBytesPerSec*/
+ AVIOUTw(4); /* BlockAlign */
+ AVIOUTw(16); /* BitsPerSample */
+ int nmain = header_pos - main_list - 4;
+ /* Finish stream list, i.e. put number of bytes in the list to proper pos */
+
+ int njunk = AviWriter::AviHeaderSize - 8 - 12 - header_pos;
+ AVIOUT4("JUNK");
+ AVIOUTd(njunk);
+ /* Fix the size of the main list */
+ header_pos = main_list;
+ AVIOUTd(nmain);
+ header_pos = AviWriter::AviHeaderSize - 12;
+ AVIOUT4("LIST");
+ AVIOUTd(_written + 4); /* Length of list in bytes */
+ AVIOUT4("movi");
+ /* First add the index table to the end */
+ memcpy(_aviIndex.data(), "idx1", 4);
+ host_writed(_aviIndex.data() + 4, (uint32_t)_aviIndex.size() - 8);
+
+ _file.write((char*)_aviIndex.data(), _aviIndex.size());
+ _file.seekp(std::ios::beg);
+ _file.write((char*)avi_header, AviWriter::AviHeaderSize);
+ _file.close();
+}
+
+void AviWriter::AddFrame(uint8_t *frameData)
+{
+ if(!_file) {
+ return;
+ }
+
+ bool isKeyFrame = (_frames % 120 == 0) ? 1 : 0;
+
+ uint8_t* compressedData = nullptr;
+ int written = _codec->CompressFrame(isKeyFrame, frameData, &compressedData);
+ if(written < 0) {
+ return;
+ }
+
+ if(_codecType == VideoCodec::None) {
+ isKeyFrame = true;
+ }
+ WriteAviChunk(_codecType == VideoCodec::None ? "00db" : "00dc", written, compressedData, isKeyFrame ? 0x10 : 0);
+ _frames++;
+
+ if(_audioPos) {
+ auto lock = _audioLock.AcquireSafe();
+ WriteAviChunk("01wb", _audioPos, _audiobuf, 0);
+ _audiowritten += _audioPos;
+ _audioPos = 0;
+ }
+}
+
+void AviWriter::AddSound(int16_t *data, uint32_t sampleCount)
+{
+ if(!_file) {
+ return;
+ }
+
+ auto lock = _audioLock.AcquireSafe();
+ memcpy(_audiobuf+_audioPos/2, data, sampleCount * 4);
+ _audioPos += sampleCount * 4;
+}
\ No newline at end of file
diff --git a/Utilities/AviWriter.h b/Utilities/AviWriter.h
new file mode 100644
index 0000000..3941c9c
--- /dev/null
+++ b/Utilities/AviWriter.h
@@ -0,0 +1,56 @@
+// This file is a part of Mesen
+// It is a heavily modified version of the hardware.h/cpp file found in DOSBox's code.
+
+#pragma once
+#include "stdafx.h"
+#include "SimpleLock.h"
+#include "BaseCodec.h"
+
+enum class VideoCodec
+{
+ None = 0,
+ ZMBV = 1,
+ CSCD = 2,
+};
+
+class AviWriter
+{
+private:
+ static constexpr int WaveBufferSize = 16 * 1024;
+ static constexpr int AviHeaderSize = 500;
+
+ std::unique_ptr _codec;
+ ofstream _file;
+
+ VideoCodec _codecType;
+
+ int16_t _audiobuf[WaveBufferSize];
+ uint32_t _audioPos = 0;
+ uint32_t _audiorate = 0;
+ uint32_t _audiowritten = 0;
+
+ uint32_t _frames = 0;
+ uint32_t _width = 0;
+ uint32_t _height = 0;
+ uint32_t _bpp = 0;
+ uint32_t _written = 0;
+ uint32_t _fps = 0;
+
+ uint8_t* _frameBuffer = nullptr;
+
+ vector _aviIndex;
+
+ SimpleLock _audioLock;
+
+private:
+ void host_writew(uint8_t* buffer, uint16_t value);
+ void host_writed(uint8_t* buffer, uint32_t value);
+ void WriteAviChunk(const char * tag, uint32_t size, void * data, uint32_t flags);
+
+public:
+ void AddFrame(uint8_t* frameData);
+ void AddSound(int16_t * data, uint32_t sampleCount);
+
+ bool StartWrite(string filename, VideoCodec codec, uint32_t width, uint32_t height, uint32_t bpp, uint32_t fps, uint32_t audioSampleRate, uint32_t compressionLevel);
+ void EndWrite();
+};
\ No newline at end of file
diff --git a/Utilities/Base64.h b/Utilities/Base64.h
new file mode 100644
index 0000000..eb6c6ec
--- /dev/null
+++ b/Utilities/Base64.h
@@ -0,0 +1,44 @@
+#pragma once
+#include "stdafx.h"
+
+class Base64
+{
+public:
+ static string Encode(const vector data)
+ {
+ std::string out;
+
+ int val = 0, valb = -6;
+ for(uint8_t c : data) {
+ val = (val << 8) + c;
+ valb += 8;
+ while(valb >= 0) {
+ out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[(val >> valb) & 0x3F]);
+ valb -= 6;
+ }
+ }
+ if(valb>-6) out.push_back("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[((val << 8) >> (valb + 8)) & 0x3F]);
+ while(out.size() % 4) out.push_back('=');
+ return out;
+ }
+
+ static vector Decode(string in)
+ {
+ vector out;
+
+ vector T(256, -1);
+ for(int i = 0; i < 64; i++) T["ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"[i]] = i;
+
+ int val = 0, valb = -8;
+ for(uint8_t c : in) {
+ if(T[c] == -1) break;
+ val = (val << 6) + T[c];
+ valb += 6;
+ if(valb >= 0) {
+ out.push_back(val >> valb);
+ valb -= 8;
+ }
+ }
+ return out;
+ }
+};
diff --git a/Utilities/BaseCodec.h b/Utilities/BaseCodec.h
new file mode 100644
index 0000000..6133378
--- /dev/null
+++ b/Utilities/BaseCodec.h
@@ -0,0 +1,12 @@
+#pragma once
+#include "stdafx.h"
+
+class BaseCodec
+{
+public:
+ virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) = 0;
+ virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) = 0;
+ virtual const char* GetFourCC() = 0;
+
+ virtual ~BaseCodec() { }
+};
\ No newline at end of file
diff --git a/Utilities/BpsPatcher.cpp b/Utilities/BpsPatcher.cpp
new file mode 100644
index 0000000..f958f19
--- /dev/null
+++ b/Utilities/BpsPatcher.cpp
@@ -0,0 +1,128 @@
+#include "stdafx.h"
+#include
+#include
+#include "BpsPatcher.h"
+#include "CRC32.h"
+
+int64_t BpsPatcher::ReadBase128Number(std::istream &file)
+{
+ int64_t result = 0;
+ int shift = 0;
+ uint8_t buffer;
+ while(true) {
+ file.read((char*)&buffer, 1);
+ if(file.eof()) {
+ return -1;
+ }
+ result += (buffer & 0x7F) << shift;
+ shift += 7;
+ if(buffer & 0x80) {
+ break;
+ }
+ result += (int64_t)1 << shift;
+ }
+
+ return result;
+}
+
+bool BpsPatcher::PatchBuffer(string bpsFilepath, vector &input, vector &output)
+{
+ ifstream bpsFile(bpsFilepath, std::ios::in | std::ios::binary);
+ if(bpsFile) {
+ return PatchBuffer(bpsFile, input, output);
+ }
+ return false;
+}
+
+bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector &input, vector &output)
+{
+ bpsFile.seekg(0, std::ios::end);
+ size_t fileSize = (size_t)bpsFile.tellg();
+ bpsFile.seekg(0, std::ios::beg);
+
+ char header[4];
+ bpsFile.read((char*)&header, 4);
+ if(memcmp((char*)&header, "BPS1", 4) != 0) {
+ //Invalid BPS file
+ return false;
+ }
+
+ int64_t inputFileSize = ReadBase128Number(bpsFile);
+ int64_t outputFileSize = ReadBase128Number(bpsFile);
+ if(inputFileSize == -1 || outputFileSize == -1) {
+ //Invalid file
+ return false;
+ }
+
+ int64_t metadataSize = ReadBase128Number(bpsFile);
+ bpsFile.seekg(metadataSize, std::ios::cur);
+
+ output.resize((size_t)outputFileSize);
+
+ uint32_t outputOffset = 0;
+ uint32_t inputRelativeOffset = 0;
+ uint32_t outputRelativeOffset = 0;
+ while((size_t)bpsFile.tellg() < fileSize - 12) {
+ int64_t data = ReadBase128Number(bpsFile);
+ if(data == -1) {
+ //Invalid file
+ return false;
+ }
+
+ uint8_t command = data & 0x03;
+ uint64_t length = (data >> 2) + 1;
+ switch(command) {
+ case 0:
+ //SourceRead
+ while(length--) {
+ output[outputOffset] = input[outputOffset];
+ outputOffset++;
+ }
+ break;
+
+ case 1:
+ //TargetRead
+ while(length--) {
+ uint8_t value = 0;
+ bpsFile.read((char*)&value, 1);
+
+ output[outputOffset++] = value;
+ }
+ break;
+
+ case 2: {
+ //SourceCopy
+ int32_t data = (int32_t)ReadBase128Number(bpsFile);
+ inputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
+ while(length--) {
+ output[outputOffset++] = input[inputRelativeOffset++];
+ }
+ break;
+ }
+
+ case 3: {
+ //TargetCopy
+ int32_t data = (int32_t)ReadBase128Number(bpsFile);
+ outputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
+ while(length--) {
+ output[outputOffset++] = output[outputRelativeOffset++];
+ }
+ break;
+ }
+ }
+ }
+
+ uint8_t inputChecksum[4];
+ uint8_t outputChecksum[4];
+ bpsFile.read((char*)inputChecksum, 4);
+ bpsFile.read((char*)outputChecksum, 4);
+ uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
+ uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
+ uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
+ uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
+
+ if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
+ return false;
+ }
+ return true;
+}
diff --git a/Utilities/BpsPatcher.h b/Utilities/BpsPatcher.h
new file mode 100644
index 0000000..f10bb13
--- /dev/null
+++ b/Utilities/BpsPatcher.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "stdafx.h"
+
+class BpsPatcher
+{
+private:
+ static int64_t ReadBase128Number(std::istream &file);
+
+public:
+ static bool PatchBuffer(std::istream &bpsFile, vector &input, vector &output);
+ static bool PatchBuffer(string bpsFilepath, vector &input, vector &output);
+};
\ No newline at end of file
diff --git a/Utilities/CRC32.cpp b/Utilities/CRC32.cpp
new file mode 100644
index 0000000..89aab9b
--- /dev/null
+++ b/Utilities/CRC32.cpp
@@ -0,0 +1,40 @@
+#include "stdafx.h"
+
+#include "CRC32.h"
+
+void CRC32::AddData(const uint8_t* pData, const std::streamoff length)
+{
+ uint8_t* pCur = (uint8_t*)pData;
+ for(std::streamoff remaining = length; remaining--; ++pCur) {
+ _crc = (_crc >> 8) ^ kCrc32Table[(_crc ^ *pCur) & 0xff];
+ }
+}
+
+uint32_t CRC32::GetCRC(uint8_t *buffer, std::streamoff length)
+{
+ CRC32 crc;
+ crc.AddData(buffer, length);
+ return ~(crc._crc);
+}
+
+uint32_t CRC32::GetCRC(string filename)
+{
+ uint32_t crc = 0;
+
+ ifstream file(filename, std::ios::in | std::ios::binary);
+
+ if(file) {
+ file.seekg(0, std::ios::end);
+ std::streamoff fileSize = file.tellg();
+ file.seekg(0, std::ios::beg);
+ uint8_t* buffer = new uint8_t[(uint32_t)fileSize];
+
+ file.read((char*)buffer, fileSize);
+ file.close();
+
+ crc = GetCRC(buffer, fileSize);
+
+ delete[] buffer;
+ }
+ return ~crc;
+}
\ No newline at end of file
diff --git a/Utilities/CRC32.h b/Utilities/CRC32.h
new file mode 100644
index 0000000..836f1a4
--- /dev/null
+++ b/Utilities/CRC32.h
@@ -0,0 +1,83 @@
+//From: http://tdistler.com/2011/06/22/crc32-a-simple-c-class
+//"You are free to use and adapt this code however you likec that goes for anyone."
+#pragma once
+#include "stdafx.h"
+
+static const uint32_t kCrc32Table[256] = {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
+ 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
+ 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
+ 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
+ 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
+ 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
+ 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
+ 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
+ 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
+ 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
+ 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
+ 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
+ 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
+ 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
+ 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
+ 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
+ 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
+ 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
+ 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
+ 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
+ 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
+ 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
+ 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
+ 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
+ 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
+ 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
+ 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
+ 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
+ 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
+ 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
+ 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
+ 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
+ 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
+ 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
+ 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
+ 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
+ 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
+ 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
+ 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
+ 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
+ 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
+ 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
+ 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
+ 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
+ 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
+ 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
+ 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
+ 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
+ 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
+ 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
+ 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
+ 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d,
+}; // kCrc32Table
+
+class CRC32
+{
+private:
+ uint32_t _crc = 0xFFFFFFFF;
+
+ void AddData(const uint8_t* pData, const std::streamoff length);
+
+public:
+ static uint32_t GetCRC(uint8_t *buffer, std::streamoff length);
+ static uint32_t GetCRC(string filename);
+};
\ No newline at end of file
diff --git a/Utilities/CamstudioCodec.cpp b/Utilities/CamstudioCodec.cpp
new file mode 100644
index 0000000..d8fba5b
--- /dev/null
+++ b/Utilities/CamstudioCodec.cpp
@@ -0,0 +1,110 @@
+//This is based on the code in lsnes' cscd.cpp file
+//A few modifications were done to improve compression speed
+#include "stdafx.h"
+#include
+#include "CamstudioCodec.h"
+#include "miniz.h"
+
+CamstudioCodec::~CamstudioCodec()
+{
+ if(_prevFrame) {
+ delete[] _prevFrame;
+ _prevFrame = nullptr;
+ }
+
+ if(_currentFrame) {
+ delete[] _currentFrame;
+ _currentFrame = nullptr;
+ }
+
+ if(_buffer) {
+ delete[] _buffer;
+ _buffer = nullptr;
+ }
+
+ if(_compressBuffer) {
+ delete[] _compressBuffer;
+ _compressBuffer = nullptr;
+ }
+
+ deflateEnd(&_compressor);
+}
+
+bool CamstudioCodec::SetupCompress(int width, int height, uint32_t compressionLevel)
+{
+ _compressionLevel = compressionLevel;
+ _orgWidth = width;
+
+ if(width % 4 != 0) {
+ _rowStride = ((int)((width * 24 + 31) / 32 * 4));
+ } else {
+ _rowStride = width*3;
+ }
+ _height = height;
+
+ _prevFrame = new uint8_t[_rowStride*_height]; //24-bit RGB
+ _currentFrame = new uint8_t[_rowStride*_height]; //24-bit RGB
+ _buffer = new uint8_t[_rowStride*_height]; //24-bit RGB
+
+ _compressBufferLength = compressBound(_rowStride*_height) + 2;
+ _compressBuffer = new uint8_t[_compressBufferLength];
+
+ memset(_prevFrame, 0, _rowStride * _height);
+ memset(_currentFrame, 0, _rowStride * _height);
+ memset(_buffer, 0, _rowStride * _height);
+ memset(_compressBuffer, 0, _compressBufferLength);
+
+ deflateInit(&_compressor, compressionLevel);
+
+ return true;
+}
+
+void CamstudioCodec::LoadRow(uint8_t* inPointer, uint8_t* outPointer)
+{
+ for(int x = 0; x < _orgWidth; x++) {
+ outPointer[0] = inPointer[0];
+ outPointer[1] = inPointer[1];
+ outPointer[2] = inPointer[2];
+ outPointer += 3;
+ inPointer += 4;
+ }
+}
+
+int CamstudioCodec::CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData)
+{
+ deflateReset(&_compressor);
+
+ _compressor.next_out = _compressBuffer + 2;
+ _compressor.avail_out = _compressBufferLength - 2;
+
+ _compressBuffer[0] = (isKeyFrame ? 0x03 : 0x02) | (_compressionLevel << 4);
+ _compressBuffer[1] = 8; //8-bit per color
+
+ uint8_t* rowBuffer = _currentFrame;
+ for(int y = 0; y < _height; y++) {
+ LoadRow(frameData + (_height - y - 1) * _orgWidth * 4, rowBuffer);
+ rowBuffer += _rowStride;
+ }
+
+ if(isKeyFrame) {
+ _compressor.next_in = _currentFrame;
+ } else {
+ for(int i = 0, len = _rowStride * _height; i < len; i++) {
+ _buffer[i] = _currentFrame[i] - _prevFrame[i];
+ }
+ _compressor.next_in = _buffer;
+ }
+
+ memcpy(_prevFrame, _currentFrame, _rowStride*_height);
+
+ _compressor.avail_in = _height * _rowStride;
+ deflate(&_compressor, MZ_FINISH);
+
+ *compressedData = _compressBuffer;
+ return _compressor.total_out + 2;
+}
+
+const char* CamstudioCodec::GetFourCC()
+{
+ return "CSCD";
+}
\ No newline at end of file
diff --git a/Utilities/CamstudioCodec.h b/Utilities/CamstudioCodec.h
new file mode 100644
index 0000000..4e5eede
--- /dev/null
+++ b/Utilities/CamstudioCodec.h
@@ -0,0 +1,30 @@
+#pragma once
+#include "stdafx.h"
+#include "BaseCodec.h"
+#include "miniz.h"
+
+class CamstudioCodec : public BaseCodec
+{
+private:
+ uint8_t* _prevFrame = nullptr;
+ uint8_t* _currentFrame = nullptr;
+ uint8_t* _buffer = nullptr;
+
+ uint32_t _compressBufferLength = 0;
+ uint8_t* _compressBuffer = nullptr;
+ z_stream _compressor = {};
+ int _compressionLevel = 0;
+
+ int _orgWidth = 0;
+ int _rowStride = 0;
+ int _height = 0;
+
+ void LoadRow(uint8_t* inPointer, uint8_t* outPointer);
+
+public:
+ virtual ~CamstudioCodec();
+
+ virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) override;
+ virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override;
+ virtual const char* GetFourCC() override;
+};
\ No newline at end of file
diff --git a/Utilities/FastString.h b/Utilities/FastString.h
new file mode 100644
index 0000000..26a3e7a
--- /dev/null
+++ b/Utilities/FastString.h
@@ -0,0 +1,62 @@
+#pragma once
+#include "stdafx.h"
+
+class FastString
+{
+private:
+ char _buffer[1000];
+ uint16_t _pos = 0;
+
+ void Write() {}
+
+public:
+ FastString() {}
+ FastString(const char* str, uint16_t size) { Write(str, size); }
+ FastString(string &str) { Write(str); }
+
+ void Write(char c)
+ {
+ _buffer[_pos++] = c;
+ }
+
+ void Write(const char* str, uint16_t size)
+ {
+ memcpy(_buffer + _pos, str, size);
+ _pos += size;
+ }
+
+ void Write(const char* str)
+ {
+ Write(str, (uint16_t)strlen(str));
+ }
+
+ void Write(string &str)
+ {
+ memcpy(_buffer + _pos, str.c_str(), str.size());
+ _pos += (uint16_t)str.size();
+ }
+
+ void Write(FastString &str)
+ {
+ memcpy(_buffer + _pos, str._buffer, str._pos);
+ _pos += str._pos;
+ }
+
+ const char* ToString()
+ {
+ _buffer[_pos] = 0;
+ return _buffer;
+ }
+
+ template
+ void Write(T first, Args... args)
+ {
+ Write(first);
+ Write(args...);
+ }
+
+ const char operator[](int idx)
+ {
+ return _buffer[idx];
+ }
+};
diff --git a/Utilities/FolderUtilities.cpp b/Utilities/FolderUtilities.cpp
new file mode 100644
index 0000000..bb4d4f3
--- /dev/null
+++ b/Utilities/FolderUtilities.cpp
@@ -0,0 +1,269 @@
+#include "stdafx.h"
+
+//TODO: Use non-experimental namespace (once it is officially supported by VC & GCC)
+#ifndef LIBRETRO
+#include
+namespace fs = std::experimental::filesystem;
+#endif
+
+#include
+#include
+#include "FolderUtilities.h"
+#include "UTF8Util.h"
+
+string FolderUtilities::_homeFolder = "";
+string FolderUtilities::_saveFolderOverride = "";
+string FolderUtilities::_saveStateFolderOverride = "";
+string FolderUtilities::_screenshotFolderOverride = "";
+vector FolderUtilities::_gameFolders = vector();
+
+void FolderUtilities::SetHomeFolder(string homeFolder)
+{
+ _homeFolder = homeFolder;
+ CreateFolder(homeFolder);
+}
+
+string FolderUtilities::GetHomeFolder()
+{
+ if(_homeFolder.size() == 0) {
+ throw std::runtime_error("Home folder not specified");
+ }
+ return _homeFolder;
+}
+
+void FolderUtilities::AddKnownGameFolder(string gameFolder)
+{
+ bool alreadyExists = false;
+ string lowerCaseFolder = gameFolder;
+ std::transform(lowerCaseFolder.begin(), lowerCaseFolder.end(), lowerCaseFolder.begin(), ::tolower);
+
+ for(string folder : _gameFolders) {
+ std::transform(folder.begin(), folder.end(), folder.begin(), ::tolower);
+ if(folder.compare(lowerCaseFolder) == 0) {
+ alreadyExists = true;
+ break;
+ }
+ }
+
+ if(!alreadyExists) {
+ _gameFolders.push_back(gameFolder);
+ }
+}
+
+vector FolderUtilities::GetKnownGameFolders()
+{
+ return _gameFolders;
+}
+
+void FolderUtilities::SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder)
+{
+ _saveFolderOverride = saveFolder;
+ _saveStateFolderOverride = saveStateFolder;
+ _screenshotFolderOverride = screenshotFolder;
+}
+
+string FolderUtilities::GetSaveFolder()
+{
+ string folder;
+ if(_saveFolderOverride.empty()) {
+ folder = CombinePath(GetHomeFolder(), "Saves");
+ } else {
+ folder = _saveFolderOverride;
+ }
+ CreateFolder(folder);
+ return folder;
+}
+
+string FolderUtilities::GetHdPackFolder()
+{
+ string folder = CombinePath(GetHomeFolder(), "HdPacks");
+ CreateFolder(folder);
+ return folder;
+}
+
+string FolderUtilities::GetDebuggerFolder()
+{
+ string folder = CombinePath(GetHomeFolder(), "Debugger");
+ CreateFolder(folder);
+ return folder;
+}
+
+string FolderUtilities::GetSaveStateFolder()
+{
+ string folder;
+ if(_saveStateFolderOverride.empty()) {
+ folder = CombinePath(GetHomeFolder(), "SaveStates");
+ } else {
+ folder = _saveStateFolderOverride;
+ }
+ CreateFolder(folder);
+ return folder;
+}
+
+string FolderUtilities::GetScreenshotFolder()
+{
+ string folder;
+ if(_screenshotFolderOverride.empty()) {
+ folder = CombinePath(GetHomeFolder(), "Screenshots");
+ } else {
+ folder = _screenshotFolderOverride;
+ }
+ CreateFolder(folder);
+ return folder;
+}
+
+string FolderUtilities::GetRecentGamesFolder()
+{
+ string folder = CombinePath(GetHomeFolder(), "RecentGames");
+ CreateFolder(folder);
+ return folder;
+}
+
+#ifndef LIBRETRO
+void FolderUtilities::CreateFolder(string folder)
+{
+ std::error_code errorCode;
+ fs::create_directory(fs::u8path(folder), errorCode);
+}
+
+vector FolderUtilities::GetFolders(string rootFolder)
+{
+ vector folders;
+
+ std::error_code errorCode;
+ if(!fs::is_directory(fs::u8path(rootFolder), errorCode)) {
+ return folders;
+ }
+
+ for(fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) {
+ if(i.depth() > 1) {
+ //Prevent excessive recursion
+ i.disable_recursion_pending();
+ } else {
+ if(fs::is_directory(i->path(), errorCode)) {
+ folders.push_back(i->path().u8string());
+ }
+ }
+ }
+
+ return folders;
+}
+
+vector FolderUtilities::GetFilesInFolder(string rootFolder, std::unordered_set extensions, bool recursive)
+{
+ vector files;
+ vector folders = { { rootFolder } };
+
+ std::error_code errorCode;
+ if(!fs::is_directory(fs::u8path(rootFolder), errorCode)) {
+ return files;
+ }
+
+ if(recursive) {
+ for(fs::recursive_directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) {
+ if(i.depth() > 1) {
+ //Prevent excessive recursion
+ i.disable_recursion_pending();
+ } else {
+ string extension = i->path().extension().u8string();
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+ if(extensions.empty() || extensions.find(extension) != extensions.end()) {
+ files.push_back(i->path().u8string());
+ }
+ }
+ }
+ } else {
+ for(fs::directory_iterator i(fs::u8path(rootFolder)), end; i != end; i++) {
+ string extension = i->path().extension().u8string();
+ std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
+ if(extensions.empty() || extensions.find(extension) != extensions.end()) {
+ files.push_back(i->path().u8string());
+ }
+ }
+ }
+
+ return files;
+}
+
+string FolderUtilities::GetFilename(string filepath, bool includeExtension)
+{
+ fs::path filename = fs::u8path(filepath).filename();
+ if(!includeExtension) {
+ filename.replace_extension("");
+ }
+ return filename.u8string();
+}
+
+string FolderUtilities::GetFolderName(string filepath)
+{
+ return fs::u8path(filepath).remove_filename().u8string();
+}
+
+string FolderUtilities::CombinePath(string folder, string filename)
+{
+ //Windows supports forward slashes for paths, too. And fs::u8path is abnormally slow.
+ if(folder[folder.length() - 1] != '/') {
+ return folder + "/" + filename;
+ } else {
+ return folder + filename;
+ }
+}
+
+int64_t FolderUtilities::GetFileModificationTime(string filepath)
+{
+ std::error_code errorCode;
+ return fs::last_write_time(fs::u8path(filepath), errorCode).time_since_epoch() / std::chrono::seconds(1);
+}
+#else
+
+//Libretro: Avoid using filesystem API.
+
+#ifdef _WIN32
+static const char* PATHSEPARATOR = "\\";
+#else
+static const char* PATHSEPARATOR = "/";
+#endif
+
+void FolderUtilities::CreateFolder(string folder)
+{
+}
+
+vector FolderUtilities::GetFolders(string rootFolder)
+{
+ return vector();
+}
+
+vector FolderUtilities::GetFilesInFolder(string rootFolder, std::unordered_set extensions, bool recursive)
+{
+ return vector();
+}
+
+string FolderUtilities::GetFilename(string filepath, bool includeExtension)
+{
+ size_t index = filepath.find_last_of(PATHSEPARATOR);
+ string filename = (index == std::string::basic_string::npos) ? filepath : filepath.substr(index + 1);
+ if(!includeExtension) {
+ filename = filename.substr(0, filename.find_last_of("."));
+ }
+ return filename;
+}
+
+string FolderUtilities::GetFolderName(string filepath)
+{
+ size_t index = filepath.find_last_of(PATHSEPARATOR);
+ return filepath.substr(0, index);
+}
+
+string FolderUtilities::CombinePath(string folder, string filename)
+{
+ if(folder.find_last_of(PATHSEPARATOR) != folder.length() - 1) {
+ folder += PATHSEPARATOR;
+ }
+ return folder + filename;
+}
+
+int64_t FolderUtilities::GetFileModificationTime(string filepath)
+{
+ return 0;
+}
+#endif
\ No newline at end of file
diff --git a/Utilities/FolderUtilities.h b/Utilities/FolderUtilities.h
new file mode 100644
index 0000000..6d6d141
--- /dev/null
+++ b/Utilities/FolderUtilities.h
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "stdafx.h"
+#include
+
+class FolderUtilities
+{
+private:
+ static string _homeFolder;
+ static string _saveFolderOverride;
+ static string _saveStateFolderOverride;
+ static string _screenshotFolderOverride;
+ static vector _gameFolders;
+
+public:
+ static void SetHomeFolder(string homeFolder);
+ static string GetHomeFolder();
+
+ static void SetFolderOverrides(string saveFolder, string saveStateFolder, string screenshotFolder);
+
+ static void AddKnownGameFolder(string gameFolder);
+ static vector GetKnownGameFolders();
+
+ static string GetSaveFolder();
+ static string GetSaveStateFolder();
+ static string GetScreenshotFolder();
+ static string GetHdPackFolder();
+ static string GetDebuggerFolder();
+ static string GetRecentGamesFolder();
+
+ static vector GetFolders(string rootFolder);
+ static vector GetFilesInFolder(string rootFolder, std::unordered_set extensions, bool recursive);
+
+ static string GetFilename(string filepath, bool includeExtension);
+ static string GetFolderName(string filepath);
+
+ static void CreateFolder(string folder);
+
+ static int64_t GetFileModificationTime(string filepath);
+
+ static string CombinePath(string folder, string filename);
+};
\ No newline at end of file
diff --git a/Utilities/HQX/common.h b/Utilities/HQX/common.h
new file mode 100644
index 0000000..dbd6c33
--- /dev/null
+++ b/Utilities/HQX/common.h
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2003 Maxim Stepin ( maxst@hiend3d.com )
+ *
+ * Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net)
+ * Copyright (C) 2011 Francois Gannaz
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __HQX_COMMON_H_
+#define __HQX_COMMON_H_
+
+#include
+#include
+#include
+
+#define MASK_2 0x0000FF00
+#define MASK_13 0x00FF00FF
+#define MASK_RGB 0x00FFFFFF
+#define MASK_ALPHA 0xFF000000
+
+#define Ymask 0x00FF0000
+#define Umask 0x0000FF00
+#define Vmask 0x000000FF
+#define trY 0x00300000
+#define trU 0x00000700
+#define trV 0x00000006
+
+/* RGB to YUV lookup table */
+extern uint32_t RGBtoYUV[16777216];
+
+static inline uint32_t rgb_to_yuv(uint32_t c)
+{
+ // Mask against MASK_RGB to discard the alpha channel
+ return RGBtoYUV[MASK_RGB & c];
+}
+
+/* Test if there is difference in color */
+static inline int yuv_diff(uint32_t yuv1, uint32_t yuv2) {
+ return (( std::abs((int)((yuv1 & Ymask) - (yuv2 & Ymask))) > trY ) ||
+ ( std::abs((int)((yuv1 & Umask) - (yuv2 & Umask))) > trU ) ||
+ ( std::abs((int)((yuv1 & Vmask) - (yuv2 & Vmask))) > trV ) );
+}
+
+static inline int Diff(uint32_t c1, uint32_t c2)
+{
+ return yuv_diff(rgb_to_yuv(c1), rgb_to_yuv(c2));
+}
+
+/* Interpolate functions */
+static inline uint32_t Interpolate_2(uint32_t c1, int w1, uint32_t c2, int w2, int s)
+{
+ if (c1 == c2) {
+ return c1;
+ }
+ return
+ (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2) << (24-s)) & MASK_ALPHA) +
+ ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2) >> s) & MASK_2) +
+ ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2) >> s) & MASK_13);
+}
+
+static inline uint32_t Interpolate_3(uint32_t c1, int w1, uint32_t c2, int w2, uint32_t c3, int w3, int s)
+{
+ return
+ (((((c1 & MASK_ALPHA) >> 24) * w1 + ((c2 & MASK_ALPHA) >> 24) * w2 + ((c3 & MASK_ALPHA) >> 24) * w3) << (24-s)) & MASK_ALPHA) +
+ ((((c1 & MASK_2) * w1 + (c2 & MASK_2) * w2 + (c3 & MASK_2) * w3) >> s) & MASK_2) +
+ ((((c1 & MASK_13) * w1 + (c2 & MASK_13) * w2 + (c3 & MASK_13) * w3) >> s) & MASK_13);
+}
+
+static inline uint32_t Interp1(uint32_t c1, uint32_t c2)
+{
+ //(c1*3+c2) >> 2;
+ return Interpolate_2(c1, 3, c2, 1, 2);
+}
+
+static inline uint32_t Interp2(uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ //(c1*2+c2+c3) >> 2;
+ return Interpolate_3(c1, 2, c2, 1, c3, 1, 2);
+}
+
+static inline uint32_t Interp3(uint32_t c1, uint32_t c2)
+{
+ //(c1*7+c2)/8;
+ return Interpolate_2(c1, 7, c2, 1, 3);
+}
+
+static inline uint32_t Interp4(uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ //(c1*2+(c2+c3)*7)/16;
+ return Interpolate_3(c1, 2, c2, 7, c3, 7, 4);
+}
+
+static inline uint32_t Interp5(uint32_t c1, uint32_t c2)
+{
+ //(c1+c2) >> 1;
+ return Interpolate_2(c1, 1, c2, 1, 1);
+}
+
+static inline uint32_t Interp6(uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ //(c1*5+c2*2+c3)/8;
+ return Interpolate_3(c1, 5, c2, 2, c3, 1, 3);
+}
+
+static inline uint32_t Interp7(uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ //(c1*6+c2+c3)/8;
+ return Interpolate_3(c1, 6, c2, 1, c3, 1, 3);
+}
+
+static inline uint32_t Interp8(uint32_t c1, uint32_t c2)
+{
+ //(c1*5+c2*3)/8;
+ return Interpolate_2(c1, 5, c2, 3, 3);
+}
+
+static inline uint32_t Interp9(uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ //(c1*2+(c2+c3)*3)/8;
+ return Interpolate_3(c1, 2, c2, 3, c3, 3, 3);
+}
+
+static inline uint32_t Interp10(uint32_t c1, uint32_t c2, uint32_t c3)
+{
+ //(c1*14+c2+c3)/16;
+ return Interpolate_3(c1, 14, c2, 1, c3, 1, 4);
+}
+
+#endif
diff --git a/Utilities/HQX/hq2x.cpp b/Utilities/HQX/hq2x.cpp
new file mode 100644
index 0000000..0aa7fff
--- /dev/null
+++ b/Utilities/HQX/hq2x.cpp
@@ -0,0 +1,2810 @@
+/*
+ * Copyright (C) 2003 Maxim Stepin ( maxst@hiend3d.com )
+ *
+ * Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "../stdafx.h"
+#include
+#include "common.h"
+#include "hqx.h"
+
+#define PIXEL00_0 *dp = w[5];
+#define PIXEL00_10 *dp = Interp1(w[5], w[1]);
+#define PIXEL00_11 *dp = Interp1(w[5], w[4]);
+#define PIXEL00_12 *dp = Interp1(w[5], w[2]);
+#define PIXEL00_20 *dp = Interp2(w[5], w[4], w[2]);
+#define PIXEL00_21 *dp = Interp2(w[5], w[1], w[2]);
+#define PIXEL00_22 *dp = Interp2(w[5], w[1], w[4]);
+#define PIXEL00_60 *dp = Interp6(w[5], w[2], w[4]);
+#define PIXEL00_61 *dp = Interp6(w[5], w[4], w[2]);
+#define PIXEL00_70 *dp = Interp7(w[5], w[4], w[2]);
+#define PIXEL00_90 *dp = Interp9(w[5], w[4], w[2]);
+#define PIXEL00_100 *dp = Interp10(w[5], w[4], w[2]);
+#define PIXEL01_0 *(dp+1) = w[5];
+#define PIXEL01_10 *(dp+1) = Interp1(w[5], w[3]);
+#define PIXEL01_11 *(dp+1) = Interp1(w[5], w[2]);
+#define PIXEL01_12 *(dp+1) = Interp1(w[5], w[6]);
+#define PIXEL01_20 *(dp+1) = Interp2(w[5], w[2], w[6]);
+#define PIXEL01_21 *(dp+1) = Interp2(w[5], w[3], w[6]);
+#define PIXEL01_22 *(dp+1) = Interp2(w[5], w[3], w[2]);
+#define PIXEL01_60 *(dp+1) = Interp6(w[5], w[6], w[2]);
+#define PIXEL01_61 *(dp+1) = Interp6(w[5], w[2], w[6]);
+#define PIXEL01_70 *(dp+1) = Interp7(w[5], w[2], w[6]);
+#define PIXEL01_90 *(dp+1) = Interp9(w[5], w[2], w[6]);
+#define PIXEL01_100 *(dp+1) = Interp10(w[5], w[2], w[6]);
+#define PIXEL10_0 *(dp+dpL) = w[5];
+#define PIXEL10_10 *(dp+dpL) = Interp1(w[5], w[7]);
+#define PIXEL10_11 *(dp+dpL) = Interp1(w[5], w[8]);
+#define PIXEL10_12 *(dp+dpL) = Interp1(w[5], w[4]);
+#define PIXEL10_20 *(dp+dpL) = Interp2(w[5], w[8], w[4]);
+#define PIXEL10_21 *(dp+dpL) = Interp2(w[5], w[7], w[4]);
+#define PIXEL10_22 *(dp+dpL) = Interp2(w[5], w[7], w[8]);
+#define PIXEL10_60 *(dp+dpL) = Interp6(w[5], w[4], w[8]);
+#define PIXEL10_61 *(dp+dpL) = Interp6(w[5], w[8], w[4]);
+#define PIXEL10_70 *(dp+dpL) = Interp7(w[5], w[8], w[4]);
+#define PIXEL10_90 *(dp+dpL) = Interp9(w[5], w[8], w[4]);
+#define PIXEL10_100 *(dp+dpL) = Interp10(w[5], w[8], w[4]);
+#define PIXEL11_0 *(dp+dpL+1) = w[5];
+#define PIXEL11_10 *(dp+dpL+1) = Interp1(w[5], w[9]);
+#define PIXEL11_11 *(dp+dpL+1) = Interp1(w[5], w[6]);
+#define PIXEL11_12 *(dp+dpL+1) = Interp1(w[5], w[8]);
+#define PIXEL11_20 *(dp+dpL+1) = Interp2(w[5], w[6], w[8]);
+#define PIXEL11_21 *(dp+dpL+1) = Interp2(w[5], w[9], w[8]);
+#define PIXEL11_22 *(dp+dpL+1) = Interp2(w[5], w[9], w[6]);
+#define PIXEL11_60 *(dp+dpL+1) = Interp6(w[5], w[8], w[6]);
+#define PIXEL11_61 *(dp+dpL+1) = Interp6(w[5], w[6], w[8]);
+#define PIXEL11_70 *(dp+dpL+1) = Interp7(w[5], w[6], w[8]);
+#define PIXEL11_90 *(dp+dpL+1) = Interp9(w[5], w[6], w[8]);
+#define PIXEL11_100 *(dp+dpL+1) = Interp10(w[5], w[6], w[8]);
+
+void HQX_CALLCONV hq2x_32_rb( uint32_t * sp, uint32_t srb, uint32_t * dp, uint32_t drb, int Xres, int Yres )
+{
+ int i, j, k;
+ int prevline, nextline;
+ uint32_t w[10];
+ int dpL = (drb >> 2);
+ int spL = (srb >> 2);
+ uint8_t *sRowP = (uint8_t *) sp;
+ uint8_t *dRowP = (uint8_t *) dp;
+ uint32_t yuv1, yuv2;
+
+ // +----+----+----+
+ // | | | |
+ // | w1 | w2 | w3 |
+ // +----+----+----+
+ // | | | |
+ // | w4 | w5 | w6 |
+ // +----+----+----+
+ // | | | |
+ // | w7 | w8 | w9 |
+ // +----+----+----+
+
+ for (j=0; j0) prevline = -spL; else prevline = 0;
+ if (j0)
+ {
+ w[1] = *(sp + prevline - 1);
+ w[4] = *(sp - 1);
+ w[7] = *(sp + nextline - 1);
+ }
+ else
+ {
+ w[1] = w[2];
+ w[4] = w[5];
+ w[7] = w[8];
+ }
+
+ if (i
+#include "common.h"
+#include "hqx.h"
+
+#define PIXEL00_1M *dp = Interp1(w[5], w[1]);
+#define PIXEL00_1U *dp = Interp1(w[5], w[2]);
+#define PIXEL00_1L *dp = Interp1(w[5], w[4]);
+#define PIXEL00_2 *dp = Interp2(w[5], w[4], w[2]);
+#define PIXEL00_4 *dp = Interp4(w[5], w[4], w[2]);
+#define PIXEL00_5 *dp = Interp5(w[4], w[2]);
+#define PIXEL00_C *dp = w[5];
+
+#define PIXEL01_1 *(dp+1) = Interp1(w[5], w[2]);
+#define PIXEL01_3 *(dp+1) = Interp3(w[5], w[2]);
+#define PIXEL01_6 *(dp+1) = Interp1(w[2], w[5]);
+#define PIXEL01_C *(dp+1) = w[5];
+
+#define PIXEL02_1M *(dp+2) = Interp1(w[5], w[3]);
+#define PIXEL02_1U *(dp+2) = Interp1(w[5], w[2]);
+#define PIXEL02_1R *(dp+2) = Interp1(w[5], w[6]);
+#define PIXEL02_2 *(dp+2) = Interp2(w[5], w[2], w[6]);
+#define PIXEL02_4 *(dp+2) = Interp4(w[5], w[2], w[6]);
+#define PIXEL02_5 *(dp+2) = Interp5(w[2], w[6]);
+#define PIXEL02_C *(dp+2) = w[5];
+
+#define PIXEL10_1 *(dp+dpL) = Interp1(w[5], w[4]);
+#define PIXEL10_3 *(dp+dpL) = Interp3(w[5], w[4]);
+#define PIXEL10_6 *(dp+dpL) = Interp1(w[4], w[5]);
+#define PIXEL10_C *(dp+dpL) = w[5];
+
+#define PIXEL11 *(dp+dpL+1) = w[5];
+
+#define PIXEL12_1 *(dp+dpL+2) = Interp1(w[5], w[6]);
+#define PIXEL12_3 *(dp+dpL+2) = Interp3(w[5], w[6]);
+#define PIXEL12_6 *(dp+dpL+2) = Interp1(w[6], w[5]);
+#define PIXEL12_C *(dp+dpL+2) = w[5];
+
+#define PIXEL20_1M *(dp+dpL+dpL) = Interp1(w[5], w[7]);
+#define PIXEL20_1D *(dp+dpL+dpL) = Interp1(w[5], w[8]);
+#define PIXEL20_1L *(dp+dpL+dpL) = Interp1(w[5], w[4]);
+#define PIXEL20_2 *(dp+dpL+dpL) = Interp2(w[5], w[8], w[4]);
+#define PIXEL20_4 *(dp+dpL+dpL) = Interp4(w[5], w[8], w[4]);
+#define PIXEL20_5 *(dp+dpL+dpL) = Interp5(w[8], w[4]);
+#define PIXEL20_C *(dp+dpL+dpL) = w[5];
+
+#define PIXEL21_1 *(dp+dpL+dpL+1) = Interp1(w[5], w[8]);
+#define PIXEL21_3 *(dp+dpL+dpL+1) = Interp3(w[5], w[8]);
+#define PIXEL21_6 *(dp+dpL+dpL+1) = Interp1(w[8], w[5]);
+#define PIXEL21_C *(dp+dpL+dpL+1) = w[5];
+
+#define PIXEL22_1M *(dp+dpL+dpL+2) = Interp1(w[5], w[9]);
+#define PIXEL22_1D *(dp+dpL+dpL+2) = Interp1(w[5], w[8]);
+#define PIXEL22_1R *(dp+dpL+dpL+2) = Interp1(w[5], w[6]);
+#define PIXEL22_2 *(dp+dpL+dpL+2) = Interp2(w[5], w[6], w[8]);
+#define PIXEL22_4 *(dp+dpL+dpL+2) = Interp4(w[5], w[6], w[8]);
+#define PIXEL22_5 *(dp+dpL+dpL+2) = Interp5(w[6], w[8]);
+#define PIXEL22_C *(dp+dpL+dpL+2) = w[5];
+
+void HQX_CALLCONV hq3x_32_rb( uint32_t * sp, uint32_t srb, uint32_t * dp, uint32_t drb, int Xres, int Yres )
+{
+ int i, j, k;
+ int prevline, nextline;
+ uint32_t w[10];
+ int dpL = (drb >> 2);
+ int spL = (srb >> 2);
+ uint8_t *sRowP = (uint8_t *) sp;
+ uint8_t *dRowP = (uint8_t *) dp;
+ uint32_t yuv1, yuv2;
+
+ // +----+----+----+
+ // | | | |
+ // | w1 | w2 | w3 |
+ // +----+----+----+
+ // | | | |
+ // | w4 | w5 | w6 |
+ // +----+----+----+
+ // | | | |
+ // | w7 | w8 | w9 |
+ // +----+----+----+
+
+ for (j=0; j0) prevline = -spL; else prevline = 0;
+ if (j0)
+ {
+ w[1] = *(sp + prevline - 1);
+ w[4] = *(sp - 1);
+ w[7] = *(sp + nextline - 1);
+ }
+ else
+ {
+ w[1] = w[2];
+ w[4] = w[5];
+ w[7] = w[8];
+ }
+
+ if (i
+#include "common.h"
+#include "hqx.h"
+
+#define PIXEL00_0 *dp = w[5];
+#define PIXEL00_11 *dp = Interp1(w[5], w[4]);
+#define PIXEL00_12 *dp = Interp1(w[5], w[2]);
+#define PIXEL00_20 *dp = Interp2(w[5], w[2], w[4]);
+#define PIXEL00_50 *dp = Interp5(w[2], w[4]);
+#define PIXEL00_80 *dp = Interp8(w[5], w[1]);
+#define PIXEL00_81 *dp = Interp8(w[5], w[4]);
+#define PIXEL00_82 *dp = Interp8(w[5], w[2]);
+#define PIXEL01_0 *(dp+1) = w[5];
+#define PIXEL01_10 *(dp+1) = Interp1(w[5], w[1]);
+#define PIXEL01_12 *(dp+1) = Interp1(w[5], w[2]);
+#define PIXEL01_14 *(dp+1) = Interp1(w[2], w[5]);
+#define PIXEL01_21 *(dp+1) = Interp2(w[2], w[5], w[4]);
+#define PIXEL01_31 *(dp+1) = Interp3(w[5], w[4]);
+#define PIXEL01_50 *(dp+1) = Interp5(w[2], w[5]);
+#define PIXEL01_60 *(dp+1) = Interp6(w[5], w[2], w[4]);
+#define PIXEL01_61 *(dp+1) = Interp6(w[5], w[2], w[1]);
+#define PIXEL01_82 *(dp+1) = Interp8(w[5], w[2]);
+#define PIXEL01_83 *(dp+1) = Interp8(w[2], w[4]);
+#define PIXEL02_0 *(dp+2) = w[5];
+#define PIXEL02_10 *(dp+2) = Interp1(w[5], w[3]);
+#define PIXEL02_11 *(dp+2) = Interp1(w[5], w[2]);
+#define PIXEL02_13 *(dp+2) = Interp1(w[2], w[5]);
+#define PIXEL02_21 *(dp+2) = Interp2(w[2], w[5], w[6]);
+#define PIXEL02_32 *(dp+2) = Interp3(w[5], w[6]);
+#define PIXEL02_50 *(dp+2) = Interp5(w[2], w[5]);
+#define PIXEL02_60 *(dp+2) = Interp6(w[5], w[2], w[6]);
+#define PIXEL02_61 *(dp+2) = Interp6(w[5], w[2], w[3]);
+#define PIXEL02_81 *(dp+2) = Interp8(w[5], w[2]);
+#define PIXEL02_83 *(dp+2) = Interp8(w[2], w[6]);
+#define PIXEL03_0 *(dp+3) = w[5];
+#define PIXEL03_11 *(dp+3) = Interp1(w[5], w[2]);
+#define PIXEL03_12 *(dp+3) = Interp1(w[5], w[6]);
+#define PIXEL03_20 *(dp+3) = Interp2(w[5], w[2], w[6]);
+#define PIXEL03_50 *(dp+3) = Interp5(w[2], w[6]);
+#define PIXEL03_80 *(dp+3) = Interp8(w[5], w[3]);
+#define PIXEL03_81 *(dp+3) = Interp8(w[5], w[2]);
+#define PIXEL03_82 *(dp+3) = Interp8(w[5], w[6]);
+#define PIXEL10_0 *(dp+dpL) = w[5];
+#define PIXEL10_10 *(dp+dpL) = Interp1(w[5], w[1]);
+#define PIXEL10_11 *(dp+dpL) = Interp1(w[5], w[4]);
+#define PIXEL10_13 *(dp+dpL) = Interp1(w[4], w[5]);
+#define PIXEL10_21 *(dp+dpL) = Interp2(w[4], w[5], w[2]);
+#define PIXEL10_32 *(dp+dpL) = Interp3(w[5], w[2]);
+#define PIXEL10_50 *(dp+dpL) = Interp5(w[4], w[5]);
+#define PIXEL10_60 *(dp+dpL) = Interp6(w[5], w[4], w[2]);
+#define PIXEL10_61 *(dp+dpL) = Interp6(w[5], w[4], w[1]);
+#define PIXEL10_81 *(dp+dpL) = Interp8(w[5], w[4]);
+#define PIXEL10_83 *(dp+dpL) = Interp8(w[4], w[2]);
+#define PIXEL11_0 *(dp+dpL+1) = w[5];
+#define PIXEL11_30 *(dp+dpL+1) = Interp3(w[5], w[1]);
+#define PIXEL11_31 *(dp+dpL+1) = Interp3(w[5], w[4]);
+#define PIXEL11_32 *(dp+dpL+1) = Interp3(w[5], w[2]);
+#define PIXEL11_70 *(dp+dpL+1) = Interp7(w[5], w[4], w[2]);
+#define PIXEL12_0 *(dp+dpL+2) = w[5];
+#define PIXEL12_30 *(dp+dpL+2) = Interp3(w[5], w[3]);
+#define PIXEL12_31 *(dp+dpL+2) = Interp3(w[5], w[2]);
+#define PIXEL12_32 *(dp+dpL+2) = Interp3(w[5], w[6]);
+#define PIXEL12_70 *(dp+dpL+2) = Interp7(w[5], w[6], w[2]);
+#define PIXEL13_0 *(dp+dpL+3) = w[5];
+#define PIXEL13_10 *(dp+dpL+3) = Interp1(w[5], w[3]);
+#define PIXEL13_12 *(dp+dpL+3) = Interp1(w[5], w[6]);
+#define PIXEL13_14 *(dp+dpL+3) = Interp1(w[6], w[5]);
+#define PIXEL13_21 *(dp+dpL+3) = Interp2(w[6], w[5], w[2]);
+#define PIXEL13_31 *(dp+dpL+3) = Interp3(w[5], w[2]);
+#define PIXEL13_50 *(dp+dpL+3) = Interp5(w[6], w[5]);
+#define PIXEL13_60 *(dp+dpL+3) = Interp6(w[5], w[6], w[2]);
+#define PIXEL13_61 *(dp+dpL+3) = Interp6(w[5], w[6], w[3]);
+#define PIXEL13_82 *(dp+dpL+3) = Interp8(w[5], w[6]);
+#define PIXEL13_83 *(dp+dpL+3) = Interp8(w[6], w[2]);
+#define PIXEL20_0 *(dp+dpL+dpL) = w[5];
+#define PIXEL20_10 *(dp+dpL+dpL) = Interp1(w[5], w[7]);
+#define PIXEL20_12 *(dp+dpL+dpL) = Interp1(w[5], w[4]);
+#define PIXEL20_14 *(dp+dpL+dpL) = Interp1(w[4], w[5]);
+#define PIXEL20_21 *(dp+dpL+dpL) = Interp2(w[4], w[5], w[8]);
+#define PIXEL20_31 *(dp+dpL+dpL) = Interp3(w[5], w[8]);
+#define PIXEL20_50 *(dp+dpL+dpL) = Interp5(w[4], w[5]);
+#define PIXEL20_60 *(dp+dpL+dpL) = Interp6(w[5], w[4], w[8]);
+#define PIXEL20_61 *(dp+dpL+dpL) = Interp6(w[5], w[4], w[7]);
+#define PIXEL20_82 *(dp+dpL+dpL) = Interp8(w[5], w[4]);
+#define PIXEL20_83 *(dp+dpL+dpL) = Interp8(w[4], w[8]);
+#define PIXEL21_0 *(dp+dpL+dpL+1) = w[5];
+#define PIXEL21_30 *(dp+dpL+dpL+1) = Interp3(w[5], w[7]);
+#define PIXEL21_31 *(dp+dpL+dpL+1) = Interp3(w[5], w[8]);
+#define PIXEL21_32 *(dp+dpL+dpL+1) = Interp3(w[5], w[4]);
+#define PIXEL21_70 *(dp+dpL+dpL+1) = Interp7(w[5], w[4], w[8]);
+#define PIXEL22_0 *(dp+dpL+dpL+2) = w[5];
+#define PIXEL22_30 *(dp+dpL+dpL+2) = Interp3(w[5], w[9]);
+#define PIXEL22_31 *(dp+dpL+dpL+2) = Interp3(w[5], w[6]);
+#define PIXEL22_32 *(dp+dpL+dpL+2) = Interp3(w[5], w[8]);
+#define PIXEL22_70 *(dp+dpL+dpL+2) = Interp7(w[5], w[6], w[8]);
+#define PIXEL23_0 *(dp+dpL+dpL+3) = w[5];
+#define PIXEL23_10 *(dp+dpL+dpL+3) = Interp1(w[5], w[9]);
+#define PIXEL23_11 *(dp+dpL+dpL+3) = Interp1(w[5], w[6]);
+#define PIXEL23_13 *(dp+dpL+dpL+3) = Interp1(w[6], w[5]);
+#define PIXEL23_21 *(dp+dpL+dpL+3) = Interp2(w[6], w[5], w[8]);
+#define PIXEL23_32 *(dp+dpL+dpL+3) = Interp3(w[5], w[8]);
+#define PIXEL23_50 *(dp+dpL+dpL+3) = Interp5(w[6], w[5]);
+#define PIXEL23_60 *(dp+dpL+dpL+3) = Interp6(w[5], w[6], w[8]);
+#define PIXEL23_61 *(dp+dpL+dpL+3) = Interp6(w[5], w[6], w[9]);
+#define PIXEL23_81 *(dp+dpL+dpL+3) = Interp8(w[5], w[6]);
+#define PIXEL23_83 *(dp+dpL+dpL+3) = Interp8(w[6], w[8]);
+#define PIXEL30_0 *(dp+dpL+dpL+dpL) = w[5];
+#define PIXEL30_11 *(dp+dpL+dpL+dpL) = Interp1(w[5], w[8]);
+#define PIXEL30_12 *(dp+dpL+dpL+dpL) = Interp1(w[5], w[4]);
+#define PIXEL30_20 *(dp+dpL+dpL+dpL) = Interp2(w[5], w[8], w[4]);
+#define PIXEL30_50 *(dp+dpL+dpL+dpL) = Interp5(w[8], w[4]);
+#define PIXEL30_80 *(dp+dpL+dpL+dpL) = Interp8(w[5], w[7]);
+#define PIXEL30_81 *(dp+dpL+dpL+dpL) = Interp8(w[5], w[8]);
+#define PIXEL30_82 *(dp+dpL+dpL+dpL) = Interp8(w[5], w[4]);
+#define PIXEL31_0 *(dp+dpL+dpL+dpL+1) = w[5];
+#define PIXEL31_10 *(dp+dpL+dpL+dpL+1) = Interp1(w[5], w[7]);
+#define PIXEL31_11 *(dp+dpL+dpL+dpL+1) = Interp1(w[5], w[8]);
+#define PIXEL31_13 *(dp+dpL+dpL+dpL+1) = Interp1(w[8], w[5]);
+#define PIXEL31_21 *(dp+dpL+dpL+dpL+1) = Interp2(w[8], w[5], w[4]);
+#define PIXEL31_32 *(dp+dpL+dpL+dpL+1) = Interp3(w[5], w[4]);
+#define PIXEL31_50 *(dp+dpL+dpL+dpL+1) = Interp5(w[8], w[5]);
+#define PIXEL31_60 *(dp+dpL+dpL+dpL+1) = Interp6(w[5], w[8], w[4]);
+#define PIXEL31_61 *(dp+dpL+dpL+dpL+1) = Interp6(w[5], w[8], w[7]);
+#define PIXEL31_81 *(dp+dpL+dpL+dpL+1) = Interp8(w[5], w[8]);
+#define PIXEL31_83 *(dp+dpL+dpL+dpL+1) = Interp8(w[8], w[4]);
+#define PIXEL32_0 *(dp+dpL+dpL+dpL+2) = w[5];
+#define PIXEL32_10 *(dp+dpL+dpL+dpL+2) = Interp1(w[5], w[9]);
+#define PIXEL32_12 *(dp+dpL+dpL+dpL+2) = Interp1(w[5], w[8]);
+#define PIXEL32_14 *(dp+dpL+dpL+dpL+2) = Interp1(w[8], w[5]);
+#define PIXEL32_21 *(dp+dpL+dpL+dpL+2) = Interp2(w[8], w[5], w[6]);
+#define PIXEL32_31 *(dp+dpL+dpL+dpL+2) = Interp3(w[5], w[6]);
+#define PIXEL32_50 *(dp+dpL+dpL+dpL+2) = Interp5(w[8], w[5]);
+#define PIXEL32_60 *(dp+dpL+dpL+dpL+2) = Interp6(w[5], w[8], w[6]);
+#define PIXEL32_61 *(dp+dpL+dpL+dpL+2) = Interp6(w[5], w[8], w[9]);
+#define PIXEL32_82 *(dp+dpL+dpL+dpL+2) = Interp8(w[5], w[8]);
+#define PIXEL32_83 *(dp+dpL+dpL+dpL+2) = Interp8(w[8], w[6]);
+#define PIXEL33_0 *(dp+dpL+dpL+dpL+3) = w[5];
+#define PIXEL33_11 *(dp+dpL+dpL+dpL+3) = Interp1(w[5], w[6]);
+#define PIXEL33_12 *(dp+dpL+dpL+dpL+3) = Interp1(w[5], w[8]);
+#define PIXEL33_20 *(dp+dpL+dpL+dpL+3) = Interp2(w[5], w[8], w[6]);
+#define PIXEL33_50 *(dp+dpL+dpL+dpL+3) = Interp5(w[8], w[6]);
+#define PIXEL33_80 *(dp+dpL+dpL+dpL+3) = Interp8(w[5], w[9]);
+#define PIXEL33_81 *(dp+dpL+dpL+dpL+3) = Interp8(w[5], w[6]);
+#define PIXEL33_82 *(dp+dpL+dpL+dpL+3) = Interp8(w[5], w[8]);
+
+void HQX_CALLCONV hq4x_32_rb( uint32_t * sp, uint32_t srb, uint32_t * dp, uint32_t drb, int Xres, int Yres )
+{
+ int i, j, k;
+ int prevline, nextline;
+ uint32_t w[10];
+ int dpL = (drb >> 2);
+ int spL = (srb >> 2);
+ uint8_t *sRowP = (uint8_t *) sp;
+ uint8_t *dRowP = (uint8_t *) dp;
+ uint32_t yuv1, yuv2;
+
+ // +----+----+----+
+ // | | | |
+ // | w1 | w2 | w3 |
+ // +----+----+----+
+ // | | | |
+ // | w4 | w5 | w6 |
+ // +----+----+----+
+ // | | | |
+ // | w7 | w8 | w9 |
+ // +----+----+----+
+
+ for (j=0; j0) prevline = -spL; else prevline = 0;
+ if (j0)
+ {
+ w[1] = *(sp + prevline - 1);
+ w[4] = *(sp - 1);
+ w[7] = *(sp + nextline - 1);
+ }
+ else
+ {
+ w[1] = w[2];
+ w[4] = w[5];
+ w[7] = w[8];
+ }
+
+ if (i
+
+#if defined( __GNUC__ )
+ #ifdef __MINGW32__
+ #define HQX_CALLCONV __stdcall
+ #else
+ #define HQX_CALLCONV
+ #endif
+#else
+ #define HQX_CALLCONV
+#endif
+
+#if defined(_WIN32)
+ #ifdef DLL_EXPORT
+ #define HQX_API __declspec(dllexport)
+ #else
+ #define HQX_API __declspec(dllimport)
+ #endif
+#else
+ #define HQX_API
+#endif
+
+void HQX_CALLCONV hqxInit(void);
+void HQX_CALLCONV hqx(uint32_t scale, uint32_t * src, uint32_t * dest, int width, int height);
+
+void HQX_CALLCONV hq2x_32( uint32_t * src, uint32_t * dest, int width, int height );
+void HQX_CALLCONV hq3x_32( uint32_t * src, uint32_t * dest, int width, int height );
+void HQX_CALLCONV hq4x_32( uint32_t * src, uint32_t * dest, int width, int height );
+
+void HQX_CALLCONV hq2x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
+void HQX_CALLCONV hq3x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
+void HQX_CALLCONV hq4x_32_rb( uint32_t * src, uint32_t src_rowBytes, uint32_t * dest, uint32_t dest_rowBytes, int width, int height );
+
+#endif
diff --git a/Utilities/HQX/init.cpp b/Utilities/HQX/init.cpp
new file mode 100644
index 0000000..be9de48
--- /dev/null
+++ b/Utilities/HQX/init.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2010 Cameron Zemek ( grom@zeminvaders.net)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "../stdafx.h"
+#include
+#include "hqx.h"
+
+uint32_t RGBtoYUV[16777216];
+uint32_t YUV1, YUV2;
+
+void HQX_CALLCONV hqxInit(void)
+{
+ /* Initalize RGB to YUV lookup table */
+ uint32_t c, r, g, b, y, u, v;
+ for (c = 0; c < 16777215; c++) {
+ r = (c & 0xFF0000) >> 16;
+ g = (c & 0x00FF00) >> 8;
+ b = c & 0x0000FF;
+ y = (uint32_t)(0.299*r + 0.587*g + 0.114*b);
+ u = (uint32_t)(-0.169*r - 0.331*g + 0.5*b) + 128;
+ v = (uint32_t)(0.5*r - 0.419*g - 0.081*b) + 128;
+ RGBtoYUV[c] = (y << 16) + (u << 8) + v;
+ }
+}
+
+void HQX_CALLCONV hqx(uint32_t scale, uint32_t * src, uint32_t * dest, int width, int height)
+{
+ switch(scale) {
+ case 2: hq2x_32(src, dest, width, height); break;
+ case 3: hq3x_32(src, dest, width, height); break;
+ case 4: hq4x_32(src, dest, width, height); break;
+ }
+}
\ No newline at end of file
diff --git a/Utilities/HexUtilities.cpp b/Utilities/HexUtilities.cpp
new file mode 100644
index 0000000..0697b33
--- /dev/null
+++ b/Utilities/HexUtilities.cpp
@@ -0,0 +1,75 @@
+#include "stdafx.h"
+#include "HexUtilities.h"
+
+const vector HexUtilities::_hexCache = { {
+ "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F",
+ "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F",
+ "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F",
+ "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F",
+ "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F",
+ "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F",
+ "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F",
+ "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F",
+ "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F",
+ "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F",
+ "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF",
+ "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF",
+ "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF",
+ "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF",
+ "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF",
+ "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
+} };
+
+int HexUtilities::FromHex(string hex)
+{
+ int value = 0;
+ for(size_t i = 0, len = hex.size(); i < len; i++) {
+ value <<= 4;
+ if(hex[i] >= '0' && hex[i] <= '9') {
+ value |= hex[i] - '0';
+ } else if(hex[i] >= 'A' && hex[i] <= 'F') {
+ value |= hex[i] - 'A' + 10;
+ } else if(hex[i] >= 'a' && hex[i] <= 'f') {
+ value |= hex[i] - 'a' + 10;
+ }
+ }
+ return value;
+}
+
+string HexUtilities::ToHex(uint8_t value)
+{
+ return _hexCache[value];
+}
+
+string HexUtilities::ToHex(uint16_t value)
+{
+ return _hexCache[value >> 8] + _hexCache[value & 0xFF];
+}
+
+string HexUtilities::ToHex(int32_t value, bool fullSize)
+{
+ return HexUtilities::ToHex((uint32_t)value, fullSize);
+}
+
+string HexUtilities::ToHex(uint32_t value, bool fullSize)
+{
+ if(fullSize || value > 0xFFFFFF) {
+ return _hexCache[value >> 24] + _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF];
+ } else if(value <= 0xFF) {
+ return ToHex((uint8_t)value);
+ } else if(value <= 0xFFFF) {
+ return ToHex((uint16_t)value);
+ } else {
+ return _hexCache[(value >> 16) & 0xFF] + _hexCache[(value >> 8) & 0xFF] + _hexCache[value & 0xFF];
+ }
+}
+
+string HexUtilities::ToHex(vector &data)
+{
+ string result;
+ result.reserve(data.size() * 2);
+ for(uint8_t value : data) {
+ result += HexUtilities::ToHex(value);
+ }
+ return result;
+}
\ No newline at end of file
diff --git a/Utilities/HexUtilities.h b/Utilities/HexUtilities.h
new file mode 100644
index 0000000..b6f1a98
--- /dev/null
+++ b/Utilities/HexUtilities.h
@@ -0,0 +1,17 @@
+#pragma once
+#include "stdafx.h"
+
+class HexUtilities
+{
+private:
+ const static vector _hexCache;
+
+public:
+ static string ToHex(uint8_t value);
+ static string ToHex(uint16_t value);
+ static string ToHex(uint32_t value, bool fullSize = false);
+ static string ToHex(int32_t value, bool fullSize = false);
+ static string ToHex(vector &data);
+
+ static int FromHex(string hex);
+};
\ No newline at end of file
diff --git a/Utilities/IpsPatcher.cpp b/Utilities/IpsPatcher.cpp
new file mode 100644
index 0000000..5d9dd4e
--- /dev/null
+++ b/Utilities/IpsPatcher.cpp
@@ -0,0 +1,188 @@
+#include "stdafx.h"
+#include
+#include
+#include
+#include "IpsPatcher.h"
+
+class IpsRecord
+{
+public:
+ uint32_t Address = 0;
+ uint16_t Length = 0;
+ vector Replacement;
+
+ //For RLE records (when length == 0)
+ uint16_t RepeatCount = 0;
+ uint8_t Value = 0;
+
+ bool ReadRecord(std::istream &ipsFile)
+ {
+ uint8_t buffer[3];
+
+ ipsFile.read((char*)buffer, 3);
+ if(memcmp(buffer, "EOF", 3) == 0) {
+ //EOF reached
+ return false;
+ } else {
+ Address = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16);
+
+ ipsFile.read((char*)buffer, 2);
+ Length = buffer[1] | (buffer[0] << 8);
+
+ if(Length == 0) {
+ //RLE record
+ ipsFile.read((char*)buffer, 3);
+ RepeatCount = buffer[1] | (buffer[0] << 8);
+ Value = buffer[2];
+ } else {
+ Replacement.resize(Length);
+ ipsFile.read((char*)Replacement.data(), Length);
+ }
+ return true;
+ }
+ }
+
+ void WriteRecord(vector &output)
+ {
+ output.push_back((Address >> 16) & 0xFF);
+ output.push_back((Address >> 8) & 0xFF);
+ output.push_back(Address & 0xFF);
+
+ output.push_back((Length >> 8) & 0xFF);
+ output.push_back(Length & 0xFF);
+
+ if(Length == 0) {
+ output.push_back((RepeatCount >> 8) & 0xFF);
+ output.push_back(RepeatCount & 0xFF);
+ output.push_back(Value);
+ } else {
+ output.insert(output.end(), Replacement.data(), Replacement.data() + Replacement.size());
+ }
+ }
+};
+
+bool IpsPatcher::PatchBuffer(string ipsFilepath, vector &input, vector &output)
+{
+ ifstream ipsFile(ipsFilepath, std::ios::in | std::ios::binary);
+ if(ipsFile) {
+ return PatchBuffer(ipsFile, input, output);
+ }
+ return false;
+}
+
+bool IpsPatcher::PatchBuffer(vector &ipsData, vector &input, vector &output)
+{
+ std::stringstream ss;
+ ss.write((char*)ipsData.data(), ipsData.size());
+ return PatchBuffer(ss, input, output);
+}
+
+bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector &input, vector &output)
+{
+ char header[5];
+ ipsFile.read((char*)&header, 5);
+ if(memcmp((char*)&header, "PATCH", 5) != 0) {
+ //Invalid ips file
+ return false;
+ }
+
+ vector records;
+ int32_t truncateOffset = -1;
+ size_t maxOutputSize = input.size();
+ while(!ipsFile.eof()) {
+ IpsRecord record;
+ if(record.ReadRecord(ipsFile)) {
+ if(record.Address + record.Length + record.RepeatCount > maxOutputSize) {
+ maxOutputSize = record.Address + record.Length + record.RepeatCount;
+ }
+ records.push_back(record);
+ } else {
+ //EOF, try to read truncate offset record if it exists
+ uint8_t buffer[3];
+ ipsFile.read((char*)buffer, 3);
+ if(!ipsFile.eof()) {
+ truncateOffset = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16);
+ }
+ break;
+ }
+ }
+
+ output.resize(maxOutputSize);
+ std::copy(input.begin(), input.end(), output.begin());
+
+ for(IpsRecord record : records) {
+ if(record.Length == 0) {
+ std::fill(&output[record.Address], &output[record.Address]+record.RepeatCount, record.Value);
+ } else {
+ std::copy(record.Replacement.begin(), record.Replacement.end(), output.begin()+record.Address);
+ }
+ }
+
+ if(truncateOffset != -1 && (int32_t)output.size() > truncateOffset) {
+ output.resize(truncateOffset);
+ }
+
+ return true;
+}
+
+vector IpsPatcher::CreatePatch(vector originalData, vector newData)
+{
+ assert(originalData.size() == newData.size());
+
+ vector patchFile;
+ uint8_t header[5] = { 'P', 'A', 'T', 'C', 'H' };
+ patchFile.insert(patchFile.end(), header, header + sizeof(header));
+
+ size_t i = 0, len = originalData.size();
+ while(i < len) {
+ while(i < len && originalData[i] == newData[i]) {
+ i++;
+ }
+ if(i < len) {
+ IpsRecord patchRecord;
+ uint8_t rleByte = newData[i];
+ uint8_t rleCount = 0;
+ bool createRleRecord = false;
+ patchRecord.Address = (uint32_t)i;
+ patchRecord.Length = 0;
+ while(i < len && patchRecord.Length < 65535 && originalData[i] != newData[i]) {
+ if(newData[i] == rleByte) {
+ rleCount++;
+ } else if(createRleRecord) {
+ break;
+ } else {
+ rleByte = newData[i];
+ rleCount = 1;
+ }
+
+ patchRecord.Length++;
+ i++;
+
+ if((patchRecord.Length == rleCount && rleCount > 3) || rleCount > 13) {
+ //Making a RLE entry would probably save space, so write the current entry and create a RLE entry after it
+ if(patchRecord.Length == rleCount) {
+ //Same character since the start of this entry, make the RLE entry now
+ createRleRecord = true;
+ } else {
+ patchRecord.Length -= rleCount;
+ i -= rleCount;
+ break;
+ }
+ }
+ }
+ if(createRleRecord) {
+ patchRecord.Length = 0;
+ patchRecord.RepeatCount = rleCount;
+ patchRecord.Value = rleByte;
+ } else {
+ patchRecord.Replacement = vector(&newData[patchRecord.Address], &newData[patchRecord.Address + patchRecord.Length]);
+ }
+ patchRecord.WriteRecord(patchFile);
+ }
+ }
+
+ uint8_t endOfFile[3] = { 'E', 'O', 'F' };
+ patchFile.insert(patchFile.end(), endOfFile, endOfFile + sizeof(endOfFile));
+
+ return patchFile;
+}
\ No newline at end of file
diff --git a/Utilities/IpsPatcher.h b/Utilities/IpsPatcher.h
new file mode 100644
index 0000000..d88081a
--- /dev/null
+++ b/Utilities/IpsPatcher.h
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "stdafx.h"
+
+class IpsPatcher
+{
+public:
+ static bool PatchBuffer(string ipsFilepath, vector &input, vector &output);
+ static bool PatchBuffer(vector& ipsData, vector& input, vector& output);
+ static bool PatchBuffer(std::istream &ipsFile, vector &input, vector &output);
+ static vector CreatePatch(vector originalData, vector newData);
+};
\ No newline at end of file
diff --git a/Utilities/KreedSaiEagle/2xSai.cpp b/Utilities/KreedSaiEagle/2xSai.cpp
new file mode 100644
index 0000000..d35e055
--- /dev/null
+++ b/Utilities/KreedSaiEagle/2xSai.cpp
@@ -0,0 +1,168 @@
+/* This is a heavily modified version of the file used in RetroArch */
+
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2014 - Daniel De Matteis
+ *
+ * RetroArch 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch 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 RetroArch.
+ * If not, see .
+ */
+
+#include "../stdafx.h"
+
+#define twoxsai_interpolate_xrgb8888(A, B) ((((A) & 0xFEFEFEFE) >> 1) + (((B) & 0xFEFEFEFE) >> 1) + ((A) & (B) & 0x01010101))
+
+#define twoxsai_interpolate2_xrgb8888(A, B, C, D) ((((A) & 0xFCFCFCFC) >> 2) + (((B) & 0xFCFCFCFC) >> 2) + (((C) & 0xFCFCFCFC) >> 2) + (((D) & 0xFCFCFCFC) >> 2) + (((((A) & 0x03030303) + ((B) & 0x03030303) + ((C) & 0x03030303) + ((D) & 0x03030303)) >> 2) & 0x03030303))
+
+#define twoxsai_result(A, B, C, D) (((A) != (C) || (A) != (D)) - ((B) != (C) || (B) != (D)));
+
+#define twoxsai_declare_variables(typename_t, in) \
+ typename_t product, product1, product2; \
+ typename_t colorI = *(in - prevline - prevcolumn); \
+ typename_t colorE = *(in - prevline + 0); \
+ typename_t colorF = *(in - prevline + nextcolumn); \
+ typename_t colorJ = *(in - prevline + nextcolumn2); \
+ typename_t colorG = *(in - prevcolumn); \
+ typename_t colorA = *(in + 0); \
+ typename_t colorB = *(in + nextcolumn); \
+ typename_t colorK = *(in + nextcolumn2); \
+ typename_t colorH = *(in + nextline - prevcolumn); \
+ typename_t colorC = *(in + nextline + 0); \
+ typename_t colorD = *(in + nextline + nextcolumn); \
+ typename_t colorL = *(in + nextline + nextcolumn2); \
+ typename_t colorM = *(in + nextline2 - prevcolumn); \
+ typename_t colorN = *(in + nextline2 + 0); \
+ typename_t colorO = *(in + nextline2 + nextcolumn); \
+
+#ifndef twoxsai_function
+#define twoxsai_function(result_cb, interpolate_cb, interpolate2_cb) \
+ if (colorA == colorD && colorB != colorC) \
+ { \
+ if ((colorA == colorE && colorB == colorL) || (colorA == colorC && colorA == colorF && colorB != colorE && colorB == colorJ)) \
+ product = colorA; \
+ else \
+ { \
+ product = interpolate_cb(colorA, colorB); \
+ } \
+ if ((colorA == colorG && colorC == colorO) || (colorA == colorB && colorA == colorH && colorG != colorC && colorC == colorM)) \
+ product1 = colorA; \
+ else \
+ { \
+ product1 = interpolate_cb(colorA, colorC); \
+ } \
+ product2 = colorA; \
+ } else if (colorB == colorC && colorA != colorD) \
+ { \
+ if ((colorB == colorF && colorA == colorH) || (colorB == colorE && colorB == colorD && colorA != colorF && colorA == colorI)) \
+ product = colorB; \
+ else \
+ { \
+ product = interpolate_cb(colorA, colorB); \
+ } \
+ if ((colorC == colorH && colorA == colorF) || (colorC == colorG && colorC == colorD && colorA != colorH && colorA == colorI)) \
+ product1 = colorC; \
+ else \
+ { \
+ product1 = interpolate_cb(colorA, colorC); \
+ } \
+ product2 = colorB; \
+ } \
+ else if (colorA == colorD && colorB == colorC) \
+ { \
+ if (colorA == colorB) \
+ { \
+ product = colorA; \
+ product1 = colorA; \
+ product2 = colorA; \
+ } \
+ else \
+ { \
+ int r = 0; \
+ product1 = interpolate_cb(colorA, colorC); \
+ product = interpolate_cb(colorA, colorB); \
+ r += result_cb(colorA, colorB, colorG, colorE); \
+ r += result_cb(colorB, colorA, colorK, colorF); \
+ r += result_cb(colorB, colorA, colorH, colorN); \
+ r += result_cb(colorA, colorB, colorL, colorO); \
+ if (r > 0) \
+ product2 = colorA; \
+ else if (r < 0) \
+ product2 = colorB; \
+ else \
+ { \
+ product2 = interpolate2_cb(colorA, colorB, colorC, colorD); \
+ } \
+ } \
+ } \
+ else \
+ { \
+ product2 = interpolate2_cb(colorA, colorB, colorC, colorD); \
+ if (colorA == colorC && colorA == colorF && colorB != colorE && colorB == colorJ) \
+ product = colorA; \
+ else if (colorB == colorE && colorB == colorD && colorA != colorF && colorA == colorI) \
+ product = colorB; \
+ else \
+ { \
+ product = interpolate_cb(colorA, colorB); \
+ } \
+ if (colorA == colorB && colorA == colorH && colorG != colorC && colorC == colorM) \
+ product1 = colorA; \
+ else if (colorC == colorG && colorC == colorD && colorA != colorH && colorA == colorI) \
+ product1 = colorC; \
+ else \
+ { \
+ product1 = interpolate_cb(colorA, colorC); \
+ } \
+ } \
+ out[0] = colorA; \
+ out[1] = product; \
+ out[dst_stride] = product1; \
+ out[dst_stride + 1] = product2; \
+ ++in; \
+ out += 2
+#endif
+
+void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride)
+{
+ unsigned finish;
+ int y = 0;
+ int x = 0;
+ for(; height; height--) {
+ uint32_t *in = (uint32_t*)src;
+ uint32_t *out = (uint32_t*)dst;
+
+ int prevline = (y > 0 ? src_stride : 0);
+ int nextline = (height > 1 ? src_stride : 0);
+ int nextline2 = (height > 2 ? src_stride * 2 : nextline);
+
+ for(finish = width; finish; finish -= 1) {
+ int prevcolumn = (x > 0 ? 1 : 0);
+ int nextcolumn = (finish > 1 ? 1 : 0);
+ int nextcolumn2 = (finish > 2 ? 2 : nextcolumn);
+ twoxsai_declare_variables(uint32_t, in);
+
+ /*
+ * Map of the pixels: I|E F|J
+ * G|A B|K
+ * H|C D|L
+ * M|N O|P
+ */
+
+ twoxsai_function(twoxsai_result, twoxsai_interpolate_xrgb8888, twoxsai_interpolate2_xrgb8888);
+ x++;
+ }
+
+ src += src_stride;
+ dst += 2 * dst_stride;
+ y++;
+ x = 0;
+ }
+}
diff --git a/Utilities/KreedSaiEagle/SaiEagle.h b/Utilities/KreedSaiEagle/SaiEagle.h
new file mode 100644
index 0000000..129f6b1
--- /dev/null
+++ b/Utilities/KreedSaiEagle/SaiEagle.h
@@ -0,0 +1,7 @@
+#pragma once
+#include "../stdafx.h"
+
+extern void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride);
+extern void twoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride);
+extern void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride);
+
diff --git a/Utilities/KreedSaiEagle/Super2xSai.cpp b/Utilities/KreedSaiEagle/Super2xSai.cpp
new file mode 100644
index 0000000..ee9d7b2
--- /dev/null
+++ b/Utilities/KreedSaiEagle/Super2xSai.cpp
@@ -0,0 +1,145 @@
+/* This is a heavily modified version of the file used in RetroArch */
+
+/* RetroArch - A frontend for libretro.
+* Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+* Copyright (C) 2010-2014 - Daniel De Matteis
+*
+* RetroArch 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 Found-
+* ation, either version 3 of the License, or (at your option) any later version.
+*
+* RetroArch 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 RetroArch.
+* If not, see .
+*/
+
+#include "../stdafx.h"
+
+#define supertwoxsai_interpolate_xrgb8888(A, B) ((((A) & 0xFEFEFEFE) >> 1) + (((B) & 0xFEFEFEFE) >> 1) + ((A) & (B) & 0x01010101))
+
+#define supertwoxsai_interpolate2_xrgb8888(A, B, C, D) ((((A) & 0xFCFCFCFC) >> 2) + (((B) & 0xFCFCFCFC) >> 2) + (((C) & 0xFCFCFCFC) >> 2) + (((D) & 0xFCFCFCFC) >> 2) + (((((A) & 0x03030303) + ((B) & 0x03030303) + ((C) & 0x03030303) + ((D) & 0x03030303)) >> 2) & 0x03030303))
+
+#define supertwoxsai_result(A, B, C, D) (((A) != (C) || (A) != (D)) - ((B) != (C) || (B) != (D)))
+
+#ifndef supertwoxsai_declare_variables
+#define supertwoxsai_declare_variables(typename_t, in) \
+ typename_t product1a, product1b, product2a, product2b; \
+ const typename_t colorB0 = *(in - prevline - prevcolumn); \
+ const typename_t colorB1 = *(in - prevline + 0); \
+ const typename_t colorB2 = *(in - prevline + nextcolumn); \
+ const typename_t colorB3 = *(in - prevline + nextcolumn2); \
+ const typename_t color4 = *(in - prevcolumn); \
+ const typename_t color5 = *(in + 0); \
+ const typename_t color6 = *(in + nextcolumn); \
+ const typename_t colorS2 = *(in + nextcolumn2); \
+ const typename_t color1 = *(in + nextline - prevcolumn); \
+ const typename_t color2 = *(in + nextline + 0); \
+ const typename_t color3 = *(in + nextline + nextcolumn); \
+ const typename_t colorS1 = *(in + nextline + nextcolumn2); \
+ const typename_t colorA0 = *(in + nextline2 - prevcolumn); \
+ const typename_t colorA1 = *(in + nextline2 + 0); \
+ const typename_t colorA2 = *(in + nextline2 + nextcolumn); \
+ const typename_t colorA3 = *(in + nextline2 + nextcolumn2)
+#endif
+
+#ifndef supertwoxsai_function
+#define supertwoxsai_function(result_cb, interpolate_cb, interpolate2_cb) \
+ if (color2 == color6 && color5 != color3) \
+ product2b = product1b = color2; \
+ else if (color5 == color3 && color2 != color6) \
+ product2b = product1b = color5; \
+ else if (color5 == color3 && color2 == color6) \
+ { \
+ int r = 0; \
+ r += result_cb(color6, color5, color1, colorA1); \
+ r += result_cb(color6, color5, color4, colorB1); \
+ r += result_cb(color6, color5, colorA2, colorS1); \
+ r += result_cb(color6, color5, colorB2, colorS2); \
+ if (r > 0) \
+ product2b = product1b = color6; \
+ else if (r < 0) \
+ product2b = product1b = color5; \
+ else \
+ product2b = product1b = interpolate_cb(color5, color6); \
+ } \
+ else \
+ { \
+ if (color6 == color3 && color3 == colorA1 && color2 != colorA2 && color3 != colorA0) \
+ product2b = interpolate2_cb(color3, color3, color3, color2); \
+ else if ((color5 == color2 && color2 == colorA2) & (colorA1 != color3 && color2 != colorA3)) \
+ product2b = interpolate2_cb(color2, color2, color2, color3); \
+ else \
+ product2b = interpolate_cb(color2, color3); \
+ if (color6 == color3 && color6 == colorB1 && color5 != colorB2 && color6 != colorB0) \
+ product1b = interpolate2_cb(color6, color6, color6, color5); \
+ else if (color5 == color2 && color5 == colorB2 && colorB1 != color6 && color5 != colorB3) \
+ product1b = interpolate2_cb(color6, color5, color5, color5); \
+ else \
+ product1b = interpolate_cb(color5, color6); \
+ } \
+ if (color5 == color3 && color2 != color6 && color4 == color5 && color5 != colorA2) \
+ { \
+ product2a = interpolate_cb(color2, color5); \
+ } \
+ else if (color5 == color1 && color6 == color5 && color4 != color2 && color5 != colorA0) \
+ { \
+ product2a = interpolate_cb(color2, color5); \
+ } \
+ else \
+ product2a = color2; \
+ if (color2 == color6 && color5 != color3 && color1 == color2 && color2 != colorB2) \
+ { \
+ product1a = interpolate_cb(color2, color5); \
+ } \
+ else if (color4 == color2 && color3 == color2 && color1 != color5 && color2 != colorB0) \
+ { \
+ product1a = interpolate_cb(color2, color5); \
+ } \
+ else \
+ product1a = color5; \
+ out[0] = product1a; \
+ out[1] = product1b; \
+ out[dst_stride] = product2a; \
+ out[dst_stride + 1] = product2b; \
+ ++in; \
+ out += 2
+#endif
+
+void supertwoxsai_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride)
+{
+ unsigned finish;
+ int y = 0;
+ int x = 0;
+ for(; height; height--) {
+ uint32_t *in = (uint32_t*)src;
+ uint32_t *out = (uint32_t*)dst;
+
+ int prevline = (y > 0 ? src_stride : 0);
+ int nextline = (height > 1 ? src_stride : 0);
+ int nextline2 = (height > 2 ? src_stride * 2 : nextline);
+
+ for(finish = width; finish; finish -= 1) {
+ int prevcolumn = (x > 0 ? 1 : 0);
+ int nextcolumn = (finish > 1 ? 1 : 0);
+ int nextcolumn2 = (finish > 2 ? 2 : nextcolumn);
+ supertwoxsai_declare_variables(uint32_t, in);
+
+ //--------------------------- B1 B2
+ // 4 5 6 S2
+ // 1 2 3 S1
+ // A1 A2
+ //--------------------------------------
+
+ supertwoxsai_function(supertwoxsai_result, supertwoxsai_interpolate_xrgb8888, supertwoxsai_interpolate2_xrgb8888);
+ x++;
+ }
+
+ src += src_stride;
+ dst += 2 * dst_stride;
+ y++;
+ x = 0;
+ }
+}
\ No newline at end of file
diff --git a/Utilities/KreedSaiEagle/SuperEagle.cpp b/Utilities/KreedSaiEagle/SuperEagle.cpp
new file mode 100644
index 0000000..11c15d7
--- /dev/null
+++ b/Utilities/KreedSaiEagle/SuperEagle.cpp
@@ -0,0 +1,156 @@
+/* This is a heavily modified version of the file used in RetroArch */
+
+/* RetroArch - A frontend for libretro.
+ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen
+ * Copyright (C) 2011-2014 - Daniel De Matteis
+ *
+ * RetroArch 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 Found-
+ * ation, either version 3 of the License, or (at your option) any later version.
+ *
+ * RetroArch 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 RetroArch.
+ * If not, see .
+ */
+
+#include "../stdafx.h"
+
+#define supereagle_interpolate_xrgb8888(A, B) ((((A) & 0xFEFEFEFE) >> 1) + (((B) & 0xFEFEFEFE) >> 1) + ((A) & (B) & 0x01010101))
+
+#define supereagle_interpolate2_xrgb8888(A, B, C, D) ((((A) & 0xFCFCFCFC) >> 2) + (((B) & 0xFCFCFCFC) >> 2) + (((C) & 0xFCFCFCFC) >> 2) + (((D) & 0xFCFCFCFC) >> 2) + (((((A) & 0x03030303) + ((B) & 0x03030303) + ((C) & 0x03030303) + ((D) & 0x03030303)) >> 2) & 0x03030303))
+
+#define supereagle_result(A, B, C, D) (((A) != (C) || (A) != (D)) - ((B) != (C) || (B) != (D)));
+
+#define supereagle_declare_variables(typename_t, in) \
+ typename_t product1a, product1b, product2a, product2b; \
+ const typename_t colorB1 = *(in - prevline + 0); \
+ const typename_t colorB2 = *(in - prevline + nextcolumn); \
+ const typename_t color4 = *(in - prevcolumn); \
+ const typename_t color5 = *(in + 0); \
+ const typename_t color6 = *(in + nextcolumn); \
+ const typename_t colorS2 = *(in + nextcolumn2); \
+ const typename_t color1 = *(in + nextline - prevcolumn); \
+ const typename_t color2 = *(in + nextline + 0); \
+ const typename_t color3 = *(in + nextline + nextcolumn); \
+ const typename_t colorS1 = *(in + nextline + nextcolumn2); \
+ const typename_t colorA1 = *(in + nextline2 + 0); \
+ const typename_t colorA2 = *(in + nextline2 + nextcolumn)
+
+#ifndef supereagle_function
+#define supereagle_function(result_cb, interpolate_cb, interpolate2_cb) \
+ if (color2 == color6 && color5 != color3) \
+ { \
+ product1b = product2a = color2; \
+ if ((color1 == color2) || (color6 == colorB2)) \
+ { \
+ product1a = interpolate_cb(color2, color5); \
+ product1a = interpolate_cb(color2, product1a); \
+ } \
+ else \
+ { \
+ product1a = interpolate_cb(color5, color6); \
+ } \
+ if ((color6 == colorS2) || (color2 == colorA1)) \
+ { \
+ product2b = interpolate_cb(color2, color3); \
+ product2b = interpolate_cb(color2, product2b); \
+ } \
+ else \
+ { \
+ product2b = interpolate_cb(color2, color3); \
+ } \
+ } \
+ else if (color5 == color3 && color2 != color6) \
+ { \
+ product2b = product1a = color5; \
+ if ((colorB1 == color5) || (color3 == colorS1)) \
+ { \
+ product1b = interpolate_cb(color5, color6); \
+ product1b = interpolate_cb(color5, product1b); \
+ } \
+ else \
+ { \
+ product1b = interpolate_cb(color5, color6); \
+ } \
+ if ((color3 == colorA2) || (color4 == color5)) \
+ { \
+ product2a = interpolate_cb(color5, color2); \
+ product2a = interpolate_cb(color5, product2a); \
+ } \
+ else \
+ { \
+ product2a = interpolate_cb(color2, color3); \
+ } \
+ } \
+ else if (color5 == color3 && color2 == color6) \
+ { \
+ int r = 0; \
+ r += supereagle_result(color6, color5, color1, colorA1); \
+ r += supereagle_result(color6, color5, color4, colorB1); \
+ r += supereagle_result(color6, color5, colorA2, colorS1); \
+ r += supereagle_result(color6, color5, colorB2, colorS2); \
+ if (r > 0) \
+ { \
+ product1b = product2a = color2; \
+ product1a = product2b = interpolate_cb(color5, color6); \
+ } \
+ else if (r < 0) \
+ { \
+ product2b = product1a = color5; \
+ product1b = product2a = interpolate_cb(color5, color6); \
+ } \
+ else \
+ { \
+ product2b = product1a = color5; \
+ product1b = product2a = color2; \
+ } \
+ } \
+ else \
+ { \
+ product2b = product1a = interpolate_cb(color2, color6); \
+ product2b = interpolate2_cb(color3, color3, color3, product2b); \
+ product1a = interpolate2_cb(color5, color5, color5, product1a); \
+ product2a = product1b = interpolate_cb(color5, color3); \
+ product2a = interpolate2_cb(color2, color2, color2, product2a); \
+ product1b = interpolate2_cb(color6, color6, color6, product1b); \
+ } \
+ out[0] = product1a; \
+ out[1] = product1b; \
+ out[dst_stride] = product2a; \
+ out[dst_stride + 1] = product2b; \
+ ++in; \
+ out += 2
+#endif
+
+void supereagle_generic_xrgb8888(unsigned width, unsigned height, uint32_t *src, unsigned src_stride, uint32_t *dst, unsigned dst_stride)
+{
+ unsigned finish;
+ int y = 0;
+ int x = 0;
+ for(; height; height--) {
+ uint32_t *in = (uint32_t*)src;
+ uint32_t *out = (uint32_t*)dst;
+
+ int prevline = (y > 0 ? src_stride : 0);
+ int nextline = (height > 1 ? src_stride : 0);
+ int nextline2 = (height > 2 ? src_stride * 2 : nextline);
+
+ for(finish = width; finish; finish -= 1) {
+ int prevcolumn = (x > 0 ? 1 : 0);
+ int nextcolumn = (finish > 1 ? 1 : 0);
+ int nextcolumn2 = (finish > 2 ? 2 : nextcolumn);
+ supereagle_declare_variables(uint32_t, in);
+
+ supereagle_function(supereagle_result, supereagle_interpolate_xrgb8888, supereagle_interpolate2_xrgb8888);
+ x++;
+ }
+
+ src += src_stride;
+ dst += 2 * dst_stride;
+ y++;
+ x = 0;
+ }
+}
\ No newline at end of file
diff --git a/Utilities/LowPassFilter.h b/Utilities/LowPassFilter.h
new file mode 100644
index 0000000..4550ecb
--- /dev/null
+++ b/Utilities/LowPassFilter.h
@@ -0,0 +1,37 @@
+#pragma once
+#include "stdafx.h"
+#include
+#include
+
+class LowPassFilter
+{
+private:
+ uint8_t _prevSampleCounter = 0;
+ int16_t _prevSamplesLeft[10] = { 0,0,0,0,0,0,0,0,0,0 };
+ int16_t _prevSamplesRight[10] = { 0,0,0,0,0,0,0,0,0,0 };
+
+ void UpdateSample(int16_t *buffer, size_t index, int strength, double volume, int16_t *_prevSamples)
+ {
+ if(strength > 0) {
+ int32_t sum = std::accumulate(_prevSamples, _prevSamples + strength, 0);
+ buffer[index] = (int16_t)((sum + buffer[index]) / (strength + 1) * volume);
+ _prevSamples[_prevSampleCounter] = buffer[index];
+ } else {
+ buffer[index] = (int16_t)(buffer[index] * volume);
+ }
+ }
+
+public:
+ void ApplyFilter(int16_t *buffer, size_t sampleCount, int strength, double volume = 1.0f)
+ {
+ assert(strength <= 10);
+
+ for(size_t i = 0; i < sampleCount*2; i+=2) {
+ UpdateSample(buffer, i, strength, volume, _prevSamplesLeft);
+ UpdateSample(buffer, i+1, strength, volume, _prevSamplesRight);
+ if(strength > 0) {
+ _prevSampleCounter = (_prevSampleCounter + 1) % strength;
+ }
+ }
+ }
+};
\ No newline at end of file
diff --git a/Utilities/PNGHelper.cpp b/Utilities/PNGHelper.cpp
new file mode 100644
index 0000000..eaf6cf9
--- /dev/null
+++ b/Utilities/PNGHelper.cpp
@@ -0,0 +1,612 @@
+#include "stdafx.h"
+#include
+#include "PNGHelper.h"
+#include "miniz.h"
+
+bool PNGHelper::WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel)
+{
+ size_t pngSize = 0;
+
+ //ARGB -> ABGR
+ uint32_t size = xSize * ySize * bitsPerPixel / 8 / 4;
+ for(uint32_t i = 0; i < size; i++) {
+ buffer[i] = (buffer[i] & 0xFF00FF00) | ((buffer[i] & 0xFF0000) >> 16) | ((buffer[i] & 0xFF) << 16);
+ }
+
+ void *pngData = tdefl_write_image_to_png_file_in_memory_ex(buffer, xSize, ySize, bitsPerPixel / 8, &pngSize, MZ_DEFAULT_LEVEL, MZ_FALSE);
+ if(!pngData) {
+ std::cout << "tdefl_write_image_to_png_file_in_memory_ex() failed!" << std::endl;
+ return false;
+ } else {
+ stream.write((char*)pngData, pngSize);
+ mz_free(pngData);
+ return true;
+ }
+}
+
+bool PNGHelper::WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel)
+{
+ std::stringstream stream;
+ if(WritePNG(stream, buffer, xSize, ySize, bitsPerPixel)) {
+ ofstream file(filename, std::ios::out | std::ios::binary);
+ if(file.good()) {
+ file << stream.rdbuf();
+ }
+ file.close();
+ return true;
+ }
+ return false;
+}
+
+bool PNGHelper::ReadPNG(vector input, vector &output, uint32_t &pngWidth, uint32_t &pngHeight)
+{
+ unsigned long width = 0;
+ unsigned long height = 0;
+
+ pngWidth = 0;
+ pngHeight = 0;
+
+ if(DecodePNG(output, width, height, input.data(), input.size()) == 0) {
+ uint32_t *pngDataPtr = (uint32_t*)output.data();
+ for(size_t i = 0, len = output.size() / 4; i < len; i++) {
+ //ABGR to ARGB
+ pngDataPtr[i] = (pngDataPtr[i] & 0xFF00FF00) | ((pngDataPtr[i] & 0xFF0000) >> 16) | ((pngDataPtr[i] & 0xFF) << 16);
+ }
+ pngWidth = width;
+ pngHeight = height;
+
+ return true;
+ } else {
+ return false;
+ }
+}
+
+bool PNGHelper::ReadPNG(string filename, vector &pngData, uint32_t &pngWidth, uint32_t &pngHeight)
+{
+ pngWidth = 0;
+ pngHeight = 0;
+
+ ifstream pngFile(filename, std::ios::in | std::ios::binary);
+ if(pngFile) {
+ pngFile.seekg(0, std::ios::end);
+ size_t fileSize = (size_t)pngFile.tellg();
+ pngFile.seekg(0, std::ios::beg);
+
+ vector fileData(fileSize, 0);
+ pngFile.read((char*)fileData.data(), fileData.size());
+ return ReadPNG(fileData, pngData, pngWidth, pngHeight);
+ }
+
+ return false;
+}
+
+/*
+decodePNG: The picoPNG function, decodes a PNG file buffer in memory, into a raw pixel buffer.
+out_image: output parameter, this will contain the raw pixels after decoding.
+ By default the output is 32-bit RGBA color.
+ The std::vector is automatically resized to the correct size.
+image_width: output_parameter, this will contain the width of the image in pixels.
+image_height: output_parameter, this will contain the height of the image in pixels.
+in_png: pointer to the buffer of the PNG file in memory. To get it from a file on
+ disk, load it and store it in a memory buffer yourself first.
+in_size: size of the input PNG file in bytes.
+convert_to_rgba32: optional parameter, true by default.
+ Set to true to get the output in RGBA 32-bit (8 bit per channel) color format
+ no matter what color type the original PNG image had. This gives predictable,
+ useable data from any random input PNG.
+ Set to false to do no color conversion at all. The result then has the same data
+ type as the PNG image, which can range from 1 bit to 64 bits per pixel.
+ Information about the color type or palette colors are not provided. You need
+ to know this information yourself to be able to use the data so this only
+ works for trusted PNG files. Use LodePNG instead of picoPNG if you need this information.
+return: 0 if success, not 0 if some error occured.
+*/
+int PNGHelper::DecodePNG(vector& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32)
+{
+ // picoPNG version 20101224
+ // Copyright (c) 2005-2010 Lode Vandevenne
+ //
+ // This software is provided 'as-is', without any express or implied
+ // warranty. In no event will the authors be held liable for any damages
+ // arising from the use of this software.
+ //
+ // Permission is granted to anyone to use this software for any purpose,
+ // including commercial applications, and to alter it and redistribute it
+ // freely, subject to the following restrictions:
+ //
+ // 1. The origin of this software must not be misrepresented; you must not
+ // claim that you wrote the original software. If you use this software
+ // in a product, an acknowledgment in the product documentation would be
+ // appreciated but is not required.
+ // 2. Altered source versions must be plainly marked as such, and must not be
+ // misrepresented as being the original software.
+ // 3. This notice may not be removed or altered from any source distribution.
+
+ // picoPNG is a PNG decoder in one C++ function of around 500 lines. Use picoPNG for
+ // programs that need only 1 .cpp file. Since it's a single function, it's very limited,
+ // it can convert a PNG to raw pixel data either converted to 32-bit RGBA color or
+ // with no color conversion at all. For anything more complex, another tiny library
+ // is available: LodePNG (lodepng.c(pp)), which is a single source and header file.
+ // Apologies for the compact code style, it's to make this tiny.
+
+ static const unsigned long LENBASE[29] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258};
+ static const unsigned long LENEXTRA[29] = {0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0};
+ static const unsigned long DISTBASE[30] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
+ static const unsigned long DISTEXTRA[30] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13};
+ static const unsigned long CLCL[19] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; //code length code lengths
+ struct Zlib //nested functions for zlib decompression
+ {
+ static unsigned long readBitFromStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (bitp & 0x7)) & 1; bitp++; return result;}
+ static unsigned long readBitsFromStream(size_t& bitp, const unsigned char* bits, size_t nbits)
+ {
+ unsigned long result = 0;
+ for(size_t i = 0; i < nbits; i++) result += (readBitFromStream(bitp, bits)) << i;
+ return result;
+ }
+ struct HuffmanTree
+ {
+ int makeFromLengths(const std::vector& bitlen, unsigned long maxbitlen)
+ { //make tree given the lengths
+ unsigned long numcodes = (unsigned long)(bitlen.size()), treepos = 0, nodefilled = 0;
+ std::vector tree1d(numcodes), blcount(maxbitlen + 1, 0), nextcode(maxbitlen + 1, 0);
+ for(unsigned long bits = 0; bits < numcodes; bits++) blcount[bitlen[bits]]++; //count number of instances of each code length
+ for(unsigned long bits = 1; bits <= maxbitlen; bits++) nextcode[bits] = (nextcode[bits - 1] + blcount[bits - 1]) << 1;
+ for(unsigned long n = 0; n < numcodes; n++) if(bitlen[n] != 0) tree1d[n] = nextcode[bitlen[n]]++; //generate all the codes
+ tree2d.clear(); tree2d.resize(numcodes * 2, 32767); //32767 here means the tree2d isn't filled there yet
+ for(unsigned long n = 0; n < numcodes; n++) //the codes
+ for(unsigned long i = 0; i < bitlen[n]; i++) //the bits for this code
+ {
+ unsigned long bit = (tree1d[n] >> (bitlen[n] - i - 1)) & 1;
+ if(treepos > numcodes - 2) return 55;
+ if(tree2d[2 * treepos + bit] == 32767) //not yet filled in
+ {
+ if(i + 1 == bitlen[n]) { tree2d[2 * treepos + bit] = n; treepos = 0; } //last bit
+ else { tree2d[2 * treepos + bit] = ++nodefilled + numcodes; treepos = nodefilled; } //addresses are encoded as values > numcodes
+ }
+ else treepos = tree2d[2 * treepos + bit] - numcodes; //subtract numcodes from address to get address value
+ }
+ return 0;
+ }
+ int decode(bool& decoded, unsigned long& result, size_t& treepos, unsigned long bit) const
+ { //Decodes a symbol from the tree
+ unsigned long numcodes = (unsigned long)tree2d.size() / 2;
+ if(treepos >= numcodes) return 11; //error: you appeared outside the codetree
+ result = tree2d[2 * treepos + bit];
+ decoded = (result < numcodes);
+ treepos = decoded ? 0 : result - numcodes;
+ return 0;
+ }
+ std::vector tree2d; //2D representation of a huffman tree: The one dimension is "0" or "1", the other contains all nodes and leaves of the tree.
+ };
+ struct Inflator
+ {
+ int error;
+ void inflate(std::vector& out, const std::vector& in, size_t inpos = 0)
+ {
+ size_t bp = 0, pos = 0; //bit pointer and byte pointer
+ error = 0;
+ unsigned long BFINAL = 0;
+ while(!BFINAL && !error)
+ {
+ if(bp >> 3 >= in.size()) { error = 52; return; } //error, bit pointer will jump past memory
+ BFINAL = readBitFromStream(bp, &in[inpos]);
+ unsigned long BTYPE = readBitFromStream(bp, &in[inpos]); BTYPE += 2 * readBitFromStream(bp, &in[inpos]);
+ if(BTYPE == 3) { error = 20; return; } //error: invalid BTYPE
+ else if(BTYPE == 0) inflateNoCompression(out, &in[inpos], bp, pos, in.size());
+ else inflateHuffmanBlock(out, &in[inpos], bp, pos, in.size(), BTYPE);
+ }
+ if(!error) out.resize(pos); //Only now we know the true size of out, resize it to that
+ }
+ void generateFixedTrees(HuffmanTree& tree, HuffmanTree& treeD) //get the tree of a deflated block with fixed tree
+ {
+ std::vector bitlen(288, 8), bitlenD(32, 5);;
+ for(size_t i = 144; i <= 255; i++) bitlen[i] = 9;
+ for(size_t i = 256; i <= 279; i++) bitlen[i] = 7;
+ tree.makeFromLengths(bitlen, 15);
+ treeD.makeFromLengths(bitlenD, 15);
+ }
+ HuffmanTree codetree, codetreeD, codelengthcodetree; //the code tree for Huffman codes, dist codes, and code length codes
+ unsigned long huffmanDecodeSymbol(const unsigned char* in, size_t& bp, const HuffmanTree& codetree, size_t inlength)
+ { //decode a single symbol from given list of bits with given code tree. return value is the symbol
+ bool decoded; unsigned long ct;
+ for(size_t treepos = 0;;)
+ {
+ if((bp & 0x07) == 0 && (bp >> 3) > inlength) { error = 10; return 0; } //error: end reached without endcode
+ error = codetree.decode(decoded, ct, treepos, readBitFromStream(bp, in)); if(error) return 0; //stop, an error happened
+ if(decoded) return ct;
+ }
+ }
+ void getTreeInflateDynamic(HuffmanTree& tree, HuffmanTree& treeD, const unsigned char* in, size_t& bp, size_t inlength)
+ { //get the tree of a deflated block with dynamic tree, the tree itself is also Huffman compressed with a known tree
+ std::vector bitlen(288, 0), bitlenD(32, 0);
+ if(bp >> 3 >= inlength - 2) { error = 49; return; } //the bit pointer is or will go past the memory
+ size_t HLIT = readBitsFromStream(bp, in, 5) + 257; //number of literal/length codes + 257
+ size_t HDIST = readBitsFromStream(bp, in, 5) + 1; //number of dist codes + 1
+ size_t HCLEN = readBitsFromStream(bp, in, 4) + 4; //number of code length codes + 4
+ std::vector codelengthcode(19); //lengths of tree to decode the lengths of the dynamic tree
+ for(size_t i = 0; i < 19; i++) codelengthcode[CLCL[i]] = (i < HCLEN) ? readBitsFromStream(bp, in, 3) : 0;
+ error = codelengthcodetree.makeFromLengths(codelengthcode, 7); if(error) return;
+ size_t i = 0, replength;
+ while(i < HLIT + HDIST)
+ {
+ unsigned long code = huffmanDecodeSymbol(in, bp, codelengthcodetree, inlength); if(error) return;
+ if(code <= 15) { if(i < HLIT) bitlen[i++] = code; else bitlenD[i++ - HLIT] = code; } //a length code
+ else if(code == 16) //repeat previous
+ {
+ if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
+ replength = 3 + readBitsFromStream(bp, in, 2);
+ unsigned long value; //set value to the previous code
+ if((i - 1) < HLIT) value = bitlen[i - 1];
+ else value = bitlenD[i - HLIT - 1];
+ for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
+ {
+ if(i >= HLIT + HDIST) { error = 13; return; } //error: i is larger than the amount of codes
+ if(i < HLIT) bitlen[i++] = value; else bitlenD[i++ - HLIT] = value;
+ }
+ }
+ else if(code == 17) //repeat "0" 3-10 times
+ {
+ if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
+ replength = 3 + readBitsFromStream(bp, in, 3);
+ for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
+ {
+ if(i >= HLIT + HDIST) { error = 14; return; } //error: i is larger than the amount of codes
+ if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
+ }
+ }
+ else if(code == 18) //repeat "0" 11-138 times
+ {
+ if(bp >> 3 >= inlength) { error = 50; return; } //error, bit pointer jumps past memory
+ replength = 11 + readBitsFromStream(bp, in, 7);
+ for(size_t n = 0; n < replength; n++) //repeat this value in the next lengths
+ {
+ if(i >= HLIT + HDIST) { error = 15; return; } //error: i is larger than the amount of codes
+ if(i < HLIT) bitlen[i++] = 0; else bitlenD[i++ - HLIT] = 0;
+ }
+ }
+ else { error = 16; return; } //error: somehow an unexisting code appeared. This can never happen.
+ }
+ if(bitlen[256] == 0) { error = 64; return; } //the length of the end code 256 must be larger than 0
+ error = tree.makeFromLengths(bitlen, 15); if(error) return; //now we've finally got HLIT and HDIST, so generate the code trees, and the function is done
+ error = treeD.makeFromLengths(bitlenD, 15); if(error) return;
+ }
+ void inflateHuffmanBlock(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength, unsigned long btype)
+ {
+ if(btype == 1) { generateFixedTrees(codetree, codetreeD); }
+ else if(btype == 2) { getTreeInflateDynamic(codetree, codetreeD, in, bp, inlength); if(error) return; }
+ for(;;)
+ {
+ unsigned long code = huffmanDecodeSymbol(in, bp, codetree, inlength); if(error) return;
+ if(code == 256) return; //end code
+ else if(code <= 255) //literal symbol
+ {
+ if(pos >= out.size()) out.resize((pos + 1) * 2); //reserve more room
+ out[pos++] = (unsigned char)(code);
+ }
+ else if(code >= 257 && code <= 285) //length code
+ {
+ size_t length = LENBASE[code - 257], numextrabits = LENEXTRA[code - 257];
+ if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
+ length += readBitsFromStream(bp, in, numextrabits);
+ unsigned long codeD = huffmanDecodeSymbol(in, bp, codetreeD, inlength); if(error) return;
+ if(codeD > 29) { error = 18; return; } //error: invalid dist code (30-31 are never used)
+ unsigned long dist = DISTBASE[codeD], numextrabitsD = DISTEXTRA[codeD];
+ if((bp >> 3) >= inlength) { error = 51; return; } //error, bit pointer will jump past memory
+ dist += readBitsFromStream(bp, in, numextrabitsD);
+ size_t start = pos, back = start - dist; //backwards
+ if(pos + length >= out.size()) out.resize((pos + length) * 2); //reserve more room
+ for(size_t i = 0; i < length; i++) { out[pos++] = out[back++]; if(back >= start) back = start - dist; }
+ }
+ }
+ }
+ void inflateNoCompression(std::vector& out, const unsigned char* in, size_t& bp, size_t& pos, size_t inlength)
+ {
+ while((bp & 0x7) != 0) bp++; //go to first boundary of byte
+ size_t p = bp / 8;
+ if(p >= inlength - 4) { error = 52; return; } //error, bit pointer will jump past memory
+ unsigned long LEN = in[p] + 256 * in[p + 1], NLEN = in[p + 2] + 256 * in[p + 3]; p += 4;
+ if(LEN + NLEN != 65535) { error = 21; return; } //error: NLEN is not one's complement of LEN
+ if(pos + LEN >= out.size()) out.resize(pos + LEN);
+ if(p + LEN > inlength) { error = 23; return; } //error: reading outside of in buffer
+ for(unsigned long n = 0; n < LEN; n++) out[pos++] = in[p++]; //read LEN bytes of literal data
+ bp = p * 8;
+ }
+ };
+ int decompress(std::vector& out, const std::vector& in) //returns error value
+ {
+ Inflator inflator;
+ if(in.size() < 2) { return 53; } //error, size of zlib data too small
+ if((in[0] * 256 + in[1]) % 31 != 0) { return 24; } //error: 256 * in[0] + in[1] must be a multiple of 31, the FCHECK value is supposed to be made that way
+ unsigned long CM = in[0] & 15, CINFO = (in[0] >> 4) & 15, FDICT = (in[1] >> 5) & 1;
+ if(CM != 8 || CINFO > 7) { return 25; } //error: only compression method 8: inflate with sliding window of 32k is supported by the PNG spec
+ if(FDICT != 0) { return 26; } //error: the specification of PNG says about the zlib stream: "The additional flags shall not specify a preset dictionary."
+ inflator.inflate(out, in, 2);
+ return inflator.error; //note: adler32 checksum was skipped and ignored
+ }
+ };
+ struct PNG //nested functions for PNG decoding
+ {
+ struct Info
+ {
+ unsigned long width, height, colorType, bitDepth, compressionMethod, filterMethod, interlaceMethod, key_r, key_g, key_b;
+ bool key_defined; //is a transparent color key given?
+ std::vector palette;
+ } info;
+ int error;
+ void decode(std::vector& out, const unsigned char* in, size_t size, bool convert_to_rgba32)
+ {
+ error = 0;
+ if(size == 0 || in == 0) { error = 48; return; } //the given data is empty
+ readPngHeader(&in[0], size); if(error) return;
+ size_t pos = 33; //first byte of the first chunk after the header
+ std::vector idat; //the data from idat chunks
+ bool IEND = false;
+ info.key_defined = false;
+ while(!IEND) //loop through the chunks, ignoring unknown chunks and stopping at IEND chunk. IDAT data is put at the start of the in buffer
+ {
+ if(pos + 8 >= size) { error = 30; return; } //error: size of the in buffer too small to contain next chunk
+ size_t chunkLength = read32bitInt(&in[pos]); pos += 4;
+ if(chunkLength > 2147483647) { error = 63; return; }
+ if(pos + chunkLength >= size) { error = 35; return; } //error: size of the in buffer too small to contain next chunk
+ if(in[pos + 0] == 'I' && in[pos + 1] == 'D' && in[pos + 2] == 'A' && in[pos + 3] == 'T') //IDAT chunk, containing compressed image data
+ {
+ idat.insert(idat.end(), &in[pos + 4], &in[pos + 4 + chunkLength]);
+ pos += (4 + chunkLength);
+ }
+ else if(in[pos + 0] == 'I' && in[pos + 1] == 'E' && in[pos + 2] == 'N' && in[pos + 3] == 'D') { pos += 4; IEND = true; }
+ else if(in[pos + 0] == 'P' && in[pos + 1] == 'L' && in[pos + 2] == 'T' && in[pos + 3] == 'E') //palette chunk (PLTE)
+ {
+ pos += 4; //go after the 4 letters
+ info.palette.resize(4 * (chunkLength / 3));
+ if(info.palette.size() > (4 * 256)) { error = 38; return; } //error: palette too big
+ for(size_t i = 0; i < info.palette.size(); i += 4)
+ {
+ for(size_t j = 0; j < 3; j++) info.palette[i + j] = in[pos++]; //RGB
+ info.palette[i + 3] = 255; //alpha
+ }
+ }
+ else if(in[pos + 0] == 't' && in[pos + 1] == 'R' && in[pos + 2] == 'N' && in[pos + 3] == 'S') //palette transparency chunk (tRNS)
+ {
+ pos += 4; //go after the 4 letters
+ if(info.colorType == 3)
+ {
+ if(4 * chunkLength > info.palette.size()) { error = 39; return; } //error: more alpha values given than there are palette entries
+ for(size_t i = 0; i < chunkLength; i++) info.palette[4 * i + 3] = in[pos++];
+ }
+ else if(info.colorType == 0)
+ {
+ if(chunkLength != 2) { error = 40; return; } //error: this chunk must be 2 bytes for greyscale image
+ info.key_defined = 1; info.key_r = info.key_g = info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2;
+ }
+ else if(info.colorType == 2)
+ {
+ if(chunkLength != 6) { error = 41; return; } //error: this chunk must be 6 bytes for RGB image
+ info.key_defined = 1;
+ info.key_r = 256 * in[pos] + in[pos + 1]; pos += 2;
+ info.key_g = 256 * in[pos] + in[pos + 1]; pos += 2;
+ info.key_b = 256 * in[pos] + in[pos + 1]; pos += 2;
+ }
+ else { error = 42; return; } //error: tRNS chunk not allowed for other color models
+ }
+ else //it's not an implemented chunk type, so ignore it: skip over the data
+ {
+ if(!(in[pos + 0] & 32)) { error = 69; return; } //error: unknown critical chunk (5th bit of first byte of chunk type is 0)
+ pos += (chunkLength + 4); //skip 4 letters and uninterpreted data of unimplemented chunk
+ }
+ pos += 4; //step over CRC (which is ignored)
+ }
+ unsigned long bpp = getBpp(info);
+ std::vector scanlines(((info.width * (info.height * bpp + 7)) / 8) + info.height); //now the out buffer will be filled
+ Zlib zlib; //decompress with the Zlib decompressor
+ error = zlib.decompress(scanlines, idat); if(error) return; //stop if the zlib decompressor returned an error
+ size_t bytewidth = (bpp + 7) / 8, outlength = (info.height * info.width * bpp + 7) / 8;
+ out.resize(outlength); //time to fill the out buffer
+ unsigned char* out_ = outlength ? &out[0] : 0; //use a regular pointer to the std::vector for faster code if compiled without optimization
+ if(info.interlaceMethod == 0) //no interlace, just filter
+ {
+ size_t linestart = 0, linelength = (info.width * bpp + 7) / 8; //length in bytes of a scanline, excluding the filtertype byte
+ if(bpp >= 8) //byte per byte
+ for(unsigned long y = 0; y < info.height; y++)
+ {
+ unsigned long filterType = scanlines[linestart];
+ const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth];
+ unFilterScanline(&out_[linestart - y], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return;
+ linestart += (1 + linelength); //go to start of next scanline
+ }
+ else //less than 8 bits per pixel, so fill it up bit per bit
+ {
+ std::vector templine((info.width * bpp + 7) >> 3); //only used if bpp < 8
+ for(size_t y = 0, obp = 0; y < info.height; y++)
+ {
+ unsigned long filterType = scanlines[linestart];
+ const unsigned char* prevline = (y == 0) ? 0 : &out_[(y - 1) * info.width * bytewidth];
+ unFilterScanline(&templine[0], &scanlines[linestart + 1], prevline, bytewidth, filterType, linelength); if(error) return;
+ for(size_t bp = 0; bp < info.width * bpp;) setBitOfReversedStream(obp, out_, readBitFromReversedStream(bp, &templine[0]));
+ linestart += (1 + linelength); //go to start of next scanline
+ }
+ }
+ }
+ else //interlaceMethod is 1 (Adam7)
+ {
+ size_t passw[7] = { (info.width + 7) / 8, (info.width + 3) / 8, (info.width + 3) / 4, (info.width + 1) / 4, (info.width + 1) / 2, (info.width + 0) / 2, (info.width + 0) / 1 };
+ size_t passh[7] = { (info.height + 7) / 8, (info.height + 7) / 8, (info.height + 3) / 8, (info.height + 3) / 4, (info.height + 1) / 4, (info.height + 1) / 2, (info.height + 0) / 2 };
+ size_t passstart[7] = {0};
+ size_t pattern[28] = {0,4,0,2,0,1,0,0,0,4,0,2,0,1,8,8,4,4,2,2,1,8,8,8,4,4,2,2}; //values for the adam7 passes
+ for(int i = 0; i < 6; i++) passstart[i + 1] = passstart[i] + passh[i] * ((passw[i] ? 1 : 0) + (passw[i] * bpp + 7) / 8);
+ std::vector scanlineo((info.width * bpp + 7) / 8), scanlinen((info.width * bpp + 7) / 8); //"old" and "new" scanline
+ for(int i = 0; i < 7; i++)
+ adam7Pass(&out_[0], &scanlinen[0], &scanlineo[0], &scanlines[passstart[i]], info.width, pattern[i], pattern[i + 7], pattern[i + 14], pattern[i + 21], passw[i], passh[i], bpp);
+ }
+ if(convert_to_rgba32 && (info.colorType != 6 || info.bitDepth != 8)) //conversion needed
+ {
+ std::vector data = out;
+ error = convert(out, &data[0], info, info.width, info.height);
+ }
+ }
+ void readPngHeader(const unsigned char* in, size_t inlength) //read the information from the header and store it in the Info
+ {
+ if(inlength < 29) { error = 27; return; } //error: the data length is smaller than the length of the header
+ if(in[0] != 137 || in[1] != 80 || in[2] != 78 || in[3] != 71 || in[4] != 13 || in[5] != 10 || in[6] != 26 || in[7] != 10) { error = 28; return; } //no PNG signature
+ if(in[12] != 'I' || in[13] != 'H' || in[14] != 'D' || in[15] != 'R') { error = 29; return; } //error: it doesn't start with a IHDR chunk!
+ info.width = read32bitInt(&in[16]); info.height = read32bitInt(&in[20]);
+ info.bitDepth = in[24]; info.colorType = in[25];
+ info.compressionMethod = in[26]; if(in[26] != 0) { error = 32; return; } //error: only compression method 0 is allowed in the specification
+ info.filterMethod = in[27]; if(in[27] != 0) { error = 33; return; } //error: only filter method 0 is allowed in the specification
+ info.interlaceMethod = in[28]; if(in[28] > 1) { error = 34; return; } //error: only interlace methods 0 and 1 exist in the specification
+ error = checkColorValidity(info.colorType, info.bitDepth);
+ }
+ void unFilterScanline(unsigned char* recon, const unsigned char* scanline, const unsigned char* precon, size_t bytewidth, unsigned long filterType, size_t length)
+ {
+ switch(filterType)
+ {
+ case 0: for(size_t i = 0; i < length; i++) recon[i] = scanline[i]; break;
+ case 1:
+ for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i];
+ for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth];
+ break;
+ case 2:
+ if(precon) for(size_t i = 0; i < length; i++) recon[i] = scanline[i] + precon[i];
+ else for(size_t i = 0; i < length; i++) recon[i] = scanline[i];
+ break;
+ case 3:
+ if(precon)
+ {
+ for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + precon[i] / 2;
+ for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + ((recon[i - bytewidth] + precon[i]) / 2);
+ }
+ else
+ {
+ for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i];
+ for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + recon[i - bytewidth] / 2;
+ }
+ break;
+ case 4:
+ if(precon)
+ {
+ for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i] + paethPredictor(0, precon[i], 0);
+ for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], precon[i], precon[i - bytewidth]);
+ }
+ else
+ {
+ for(size_t i = 0; i < bytewidth; i++) recon[i] = scanline[i];
+ for(size_t i = bytewidth; i < length; i++) recon[i] = scanline[i] + paethPredictor(recon[i - bytewidth], 0, 0);
+ }
+ break;
+ default: error = 36; return; //error: unexisting filter type given
+ }
+ }
+ void adam7Pass(unsigned char* out, unsigned char* linen, unsigned char* lineo, const unsigned char* in, unsigned long w, size_t passleft, size_t passtop, size_t spacex, size_t spacey, size_t passw, size_t passh, unsigned long bpp)
+ { //filter and reposition the pixels into the output when the image is Adam7 interlaced. This function can only do it after the full image is already decoded. The out buffer must have the correct allocated memory size already.
+ if(passw == 0) return;
+ size_t bytewidth = (bpp + 7) / 8, linelength = 1 + ((bpp * passw + 7) / 8);
+ for(unsigned long y = 0; y < passh; y++)
+ {
+ unsigned char filterType = in[y * linelength], *prevline = (y == 0) ? 0 : lineo;
+ unFilterScanline(linen, &in[y * linelength + 1], prevline, bytewidth, filterType, (w * bpp + 7) / 8); if(error) return;
+ if(bpp >= 8) for(size_t i = 0; i < passw; i++) for(size_t b = 0; b < bytewidth; b++) //b = current byte of this pixel
+ out[bytewidth * w * (passtop + spacey * y) + bytewidth * (passleft + spacex * i) + b] = linen[bytewidth * i + b];
+ else for(size_t i = 0; i < passw; i++)
+ {
+ size_t obp = bpp * w * (passtop + spacey * y) + bpp * (passleft + spacex * i), bp = i * bpp;
+ for(size_t b = 0; b < bpp; b++) setBitOfReversedStream(obp, out, readBitFromReversedStream(bp, &linen[0]));
+ }
+ unsigned char* temp = linen; linen = lineo; lineo = temp; //swap the two buffer pointers "line old" and "line new"
+ }
+ }
+ static unsigned long readBitFromReversedStream(size_t& bitp, const unsigned char* bits) { unsigned long result = (bits[bitp >> 3] >> (7 - (bitp & 0x7))) & 1; bitp++; return result;}
+ static unsigned long readBitsFromReversedStream(size_t& bitp, const unsigned char* bits, unsigned long nbits)
+ {
+ unsigned long result = 0;
+ for(size_t i = nbits - 1; i < nbits; i--) result += ((readBitFromReversedStream(bitp, bits)) << i);
+ return result;
+ }
+ void setBitOfReversedStream(size_t& bitp, unsigned char* bits, unsigned long bit) { bits[bitp >> 3] |= (bit << (7 - (bitp & 0x7))); bitp++; }
+ unsigned long read32bitInt(const unsigned char* buffer) { return (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; }
+ int checkColorValidity(unsigned long colorType, unsigned long bd) //return type is a LodePNG error code
+ {
+ if((colorType == 2 || colorType == 4 || colorType == 6)) { if(!(bd == 8 || bd == 16)) return 37; else return 0; }
+ else if(colorType == 0) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 || bd == 16)) return 37; else return 0; }
+ else if(colorType == 3) { if(!(bd == 1 || bd == 2 || bd == 4 || bd == 8 )) return 37; else return 0; }
+ else return 31; //unexisting color type
+ }
+ unsigned long getBpp(const Info& info)
+ {
+ if(info.colorType == 2) return (3 * info.bitDepth);
+ else if(info.colorType >= 4) return (info.colorType - 2) * info.bitDepth;
+ else return info.bitDepth;
+ }
+ int convert(std::vector& out, const unsigned char* in, Info& infoIn, unsigned long w, unsigned long h)
+ { //converts from any color type to 32-bit. return value = LodePNG error code
+ size_t numpixels = w * h, bp = 0;
+ out.resize(numpixels * 4);
+ unsigned char* out_ = out.empty() ? 0 : &out[0]; //faster if compiled without optimization
+ if(infoIn.bitDepth == 8 && infoIn.colorType == 0) //greyscale
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[i];
+ out_[4 * i + 3] = (infoIn.key_defined && in[i] == infoIn.key_r) ? 0 : 255;
+ }
+ else if(infoIn.bitDepth == 8 && infoIn.colorType == 2) //RGB color
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ for(size_t c = 0; c < 3; c++) out_[4 * i + c] = in[3 * i + c];
+ out_[4 * i + 3] = (infoIn.key_defined == 1 && in[3 * i + 0] == infoIn.key_r && in[3 * i + 1] == infoIn.key_g && in[3 * i + 2] == infoIn.key_b) ? 0 : 255;
+ }
+ else if(infoIn.bitDepth == 8 && infoIn.colorType == 3) //indexed color (palette)
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ if(4U * in[i] >= infoIn.palette.size()) return 46;
+ for(size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * in[i] + c]; //get rgb colors from the palette
+ }
+ else if(infoIn.bitDepth == 8 && infoIn.colorType == 4) //greyscale with alpha
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i + 0];
+ out_[4 * i + 3] = in[2 * i + 1];
+ }
+ else if(infoIn.bitDepth == 8 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out_[4 * i + c] = in[4 * i + c]; //RGB with alpha
+ else if(infoIn.bitDepth == 16 && infoIn.colorType == 0) //greyscale
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[2 * i];
+ out_[4 * i + 3] = (infoIn.key_defined && 256U * in[i] + in[i + 1] == infoIn.key_r) ? 0 : 255;
+ }
+ else if(infoIn.bitDepth == 16 && infoIn.colorType == 2) //RGB color
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ for(size_t c = 0; c < 3; c++) out_[4 * i + c] = in[6 * i + 2 * c];
+ out_[4 * i + 3] = (infoIn.key_defined && 256U*in[6*i+0]+in[6*i+1] == infoIn.key_r && 256U*in[6*i+2]+in[6*i+3] == infoIn.key_g && 256U*in[6*i+4]+in[6*i+5] == infoIn.key_b) ? 0 : 255;
+ }
+ else if(infoIn.bitDepth == 16 && infoIn.colorType == 4) //greyscale with alpha
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = in[4 * i]; //most significant byte
+ out_[4 * i + 3] = in[4 * i + 2];
+ }
+ else if(infoIn.bitDepth == 16 && infoIn.colorType == 6) for(size_t i = 0; i < numpixels; i++) for(size_t c = 0; c < 4; c++) out_[4 * i + c] = in[8 * i + 2 * c]; //RGB with alpha
+ else if(infoIn.bitDepth < 8 && infoIn.colorType == 0) //greyscale
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ unsigned long value = (readBitsFromReversedStream(bp, in, infoIn.bitDepth) * 255) / ((1 << infoIn.bitDepth) - 1); //scale value from 0 to 255
+ out_[4 * i + 0] = out_[4 * i + 1] = out_[4 * i + 2] = (unsigned char)(value);
+ out_[4 * i + 3] = (infoIn.key_defined && value && ((1U << infoIn.bitDepth) - 1U) == infoIn.key_r && ((1U << infoIn.bitDepth) - 1U)) ? 0 : 255;
+ }
+ else if(infoIn.bitDepth < 8 && infoIn.colorType == 3) //palette
+ for(size_t i = 0; i < numpixels; i++)
+ {
+ unsigned long value = readBitsFromReversedStream(bp, in, infoIn.bitDepth);
+ if(4 * value >= infoIn.palette.size()) return 47;
+ for(size_t c = 0; c < 4; c++) out_[4 * i + c] = infoIn.palette[4 * value + c]; //get rgb colors from the palette
+ }
+ return 0;
+ }
+ unsigned char paethPredictor(short a, short b, short c) //Paeth predicter, used by PNG filter type 4
+ {
+ short p = a + b - c, pa = p > a ? (p - a) : (a - p), pb = p > b ? (p - b) : (b - p), pc = p > c ? (p - c) : (c - p);
+ return (unsigned char)((pa <= pb && pa <= pc) ? a : pb <= pc ? b : c);
+ }
+ };
+ PNG decoder = { }; decoder.decode(out_image, in_png, in_size, convert_to_rgba32);
+ image_width = decoder.info.width; image_height = decoder.info.height;
+ return decoder.error;
+}
\ No newline at end of file
diff --git a/Utilities/PNGHelper.h b/Utilities/PNGHelper.h
new file mode 100644
index 0000000..531a709
--- /dev/null
+++ b/Utilities/PNGHelper.h
@@ -0,0 +1,14 @@
+#pragma once
+#include "stdafx.h"
+
+class PNGHelper
+{
+private:
+ static int DecodePNG(vector& out_image, unsigned long& image_width, unsigned long& image_height, const unsigned char* in_png, size_t in_size, bool convert_to_rgba32 = true);
+
+public:
+ static bool WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
+ static bool WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
+ static bool ReadPNG(string filename, vector &pngData, uint32_t &pngWidth, uint32_t &pngHeight);
+ static bool ReadPNG(vector input, vector &output, uint32_t &pngWidth, uint32_t &pngHeight);
+};
\ No newline at end of file
diff --git a/Utilities/PlatformUtilities.cpp b/Utilities/PlatformUtilities.cpp
new file mode 100644
index 0000000..d129c07
--- /dev/null
+++ b/Utilities/PlatformUtilities.cpp
@@ -0,0 +1,45 @@
+#include "stdafx.h"
+#include "PlatformUtilities.h"
+
+#if !defined(LIBRETRO) && defined(_WIN32)
+#include
+#endif
+
+bool PlatformUtilities::_highResTimerEnabled = false;
+
+void PlatformUtilities::DisableScreensaver()
+{
+ //Prevent screensaver/etc from starting while using the emulator
+ //DirectInput devices apparently do not always count as user input
+ #if !defined(LIBRETRO) && defined(_WIN32)
+ SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_CONTINUOUS);
+ #endif
+}
+
+void PlatformUtilities::EnableScreensaver()
+{
+ #if !defined(LIBRETRO) && defined(_WIN32)
+ SetThreadExecutionState(ES_CONTINUOUS);
+ #endif
+}
+
+void PlatformUtilities::EnableHighResolutionTimer()
+{
+#if !defined(LIBRETRO) && defined(_WIN32)
+ //Request a 1ms timer resolution on Windows while a game is running
+ if(!_highResTimerEnabled) {
+ timeBeginPeriod(1);
+ _highResTimerEnabled = true;
+ }
+ #endif
+}
+
+void PlatformUtilities::RestoreTimerResolution()
+{
+ #if !defined(LIBRETRO) && defined(_WIN32)
+ if(_highResTimerEnabled) {
+ timeEndPeriod(1);
+ _highResTimerEnabled = false;
+ }
+ #endif
+}
\ No newline at end of file
diff --git a/Utilities/PlatformUtilities.h b/Utilities/PlatformUtilities.h
new file mode 100644
index 0000000..e5a0fd1
--- /dev/null
+++ b/Utilities/PlatformUtilities.h
@@ -0,0 +1,15 @@
+#pragma once
+#include "stdafx.h"
+
+class PlatformUtilities
+{
+private:
+ static bool _highResTimerEnabled;
+
+public:
+ static void DisableScreensaver();
+ static void EnableScreensaver();
+
+ static void EnableHighResolutionTimer();
+ static void RestoreTimerResolution();
+};
\ No newline at end of file
diff --git a/Utilities/RawCodec.h b/Utilities/RawCodec.h
new file mode 100644
index 0000000..ea32899
--- /dev/null
+++ b/Utilities/RawCodec.h
@@ -0,0 +1,51 @@
+#pragma once
+#include "stdafx.h"
+#include
+#include "BaseCodec.h"
+
+class RawCodec : public BaseCodec
+{
+private:
+ int _width = 0;
+ int _height = 0;
+ uint32_t _bufferSize = 0;
+ uint8_t* _buffer = nullptr;
+
+public:
+ virtual bool SetupCompress(int width, int height, uint32_t compressionLevel) override
+ {
+ _height = height;
+ _width = width;
+
+ _bufferSize = width * height * 3;
+ _buffer = new uint8_t[(_bufferSize + 1) & ~1];
+ memset(_buffer, 0, (_bufferSize + 1) & ~1);
+
+ return true;
+ }
+
+ virtual int CompressFrame(bool isKeyFrame, uint8_t *frameData, uint8_t** compressedData) override
+ {
+ *compressedData = _buffer;
+
+ //Convert raw frame to BMP/DIB format (row order is reversed)
+ uint8_t* buffer = _buffer;
+ frameData += (_height - 1) * _width * 4;
+ for(int y = 0; y < _height; y++) {
+ for(int x = 0; x < _width; x++) {
+ buffer[0] = frameData[0];
+ buffer[1] = frameData[1];
+ buffer[2] = frameData[2];
+ frameData += 4;
+ buffer += 3;
+ }
+ frameData -= _width * 2 * 4;
+ }
+ return _bufferSize;
+ }
+
+ virtual const char* GetFourCC() override
+ {
+ return "\0\0\0\0";
+ }
+};
\ No newline at end of file
diff --git a/Utilities/SZReader.cpp b/Utilities/SZReader.cpp
new file mode 100644
index 0000000..71daade
--- /dev/null
+++ b/Utilities/SZReader.cpp
@@ -0,0 +1,90 @@
+#include "stdafx.h"
+#include
+#include
+#include "SZReader.h"
+#include "UTF8Util.h"
+#include "../SevenZip/7zMemBuffer.h"
+
+SZReader::SZReader()
+{
+}
+
+SZReader::~SZReader()
+{
+ SzArEx_Free(&_archive, &_allocImp);
+}
+
+bool SZReader::InternalLoadArchive(void* buffer, size_t size)
+{
+ if(_initialized) {
+ SzArEx_Free(&_archive, &_allocImp);
+ _initialized = false;
+ }
+
+ ISzAlloc allocImp{ SzAlloc, SzFree };
+ ISzAlloc allocTempImp{ SzAllocTemp, SzFreeTemp };
+
+ MemBufferInit(&_memBufferStream, &_lookStream, buffer, size);
+ CrcGenerateTable();
+ SzArEx_Init(&_archive);
+
+ return !SzArEx_Open(&_archive, &_lookStream.s, &allocImp, &allocTempImp);
+}
+
+bool SZReader::ExtractFile(string filename, vector &output)
+{
+ bool result = false;
+ if(_initialized) {
+ char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000);
+
+ uint32_t blockIndex = 0xFFFFFFFF;
+ uint8_t *outBuffer = 0;
+ size_t outBufferSize = 0;
+
+ for(uint32_t i = 0; i < _archive.NumFiles; i++) {
+ size_t offset = 0;
+ size_t outSizeProcessed = 0;
+ unsigned isDir = SzArEx_IsDir(&_archive, i);
+ if(isDir) {
+ continue;
+ }
+
+ SzArEx_GetFileNameUtf16(&_archive, i, (uint16_t*)utf16Filename);
+ string entryName = utf8::utf8::encode(std::u16string(utf16Filename));
+ if(filename == entryName) {
+ WRes res = SzArEx_Extract(&_archive, &_lookStream.s, i, &blockIndex, &outBuffer, &outBufferSize, &offset, &outSizeProcessed, &_allocImp, &_allocTempImp);
+ if(res == SZ_OK) {
+ output = vector(outBuffer+offset, outBuffer+offset+outSizeProcessed);
+ result = true;
+ }
+ IAlloc_Free(&_allocImp, outBuffer);
+ break;
+ }
+ }
+ SzFree(nullptr, utf16Filename);
+ }
+
+ return result;
+}
+
+vector SZReader::InternalGetFileList()
+{
+ vector filenames;
+ char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000);
+
+ if(_initialized) {
+ for(uint32_t i = 0; i < _archive.NumFiles; i++) {
+ unsigned isDir = SzArEx_IsDir(&_archive, i);
+ if(isDir) {
+ continue;
+ }
+
+ SzArEx_GetFileNameUtf16(&_archive, i, (uint16_t*)utf16Filename);
+ string filename = utf8::utf8::encode(std::u16string(utf16Filename));
+ filenames.push_back(filename);
+ }
+ }
+ SzFree(nullptr, utf16Filename);
+
+ return filenames;
+}
\ No newline at end of file
diff --git a/Utilities/SZReader.h b/Utilities/SZReader.h
new file mode 100644
index 0000000..9c3634f
--- /dev/null
+++ b/Utilities/SZReader.h
@@ -0,0 +1,28 @@
+#pragma once
+#include "stdafx.h"
+#include "ArchiveReader.h"
+#include "../SevenZip/7z.h"
+#include "../SevenZip/7zAlloc.h"
+#include "../SevenZip/7zCrc.h"
+#include "../SevenZip/7zTypes.h"
+#include "../SevenZip/7zMemBuffer.h"
+
+class SZReader : public ArchiveReader
+{
+private:
+ CMemBufferInStream _memBufferStream;
+ CLookToRead _lookStream;
+ CSzArEx _archive;
+ ISzAlloc _allocImp{ SzAlloc, SzFree };
+ ISzAlloc _allocTempImp{ SzAllocTemp, SzFreeTemp };
+
+protected:
+ bool InternalLoadArchive(void* buffer, size_t size);
+ vector InternalGetFileList();
+
+public:
+ SZReader();
+ virtual ~SZReader();
+
+ bool ExtractFile(string filename, vector &output);
+};
\ No newline at end of file
diff --git a/Utilities/Scale2x/scale2x.cpp b/Utilities/Scale2x/scale2x.cpp
new file mode 100644
index 0000000..43f31b1
--- /dev/null
+++ b/Utilities/Scale2x/scale2x.cpp
@@ -0,0 +1,484 @@
+/*
+ * This file is part of the Scale2x project.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
+ *
+ * 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 2 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.
+ */
+
+/*
+ * This file contains a C and MMX implementation of the Scale2x effect.
+ *
+ * You can find an high level description of the effect at :
+ *
+ * http://www.scale2x.it/
+ */
+
+#include "../stdafx.h"
+
+#if HAVE_CONFIG_H
+#include
+#endif
+
+#include "scale2x.h"
+
+#include
+
+/***************************************************************************/
+/* Scale2x C implementation */
+
+/**
+ * Define the macro USE_SCALE_RANDOMWRITE to enable
+ * an optimized version which writes memory in random order.
+ * This version is a little faster if you write in system memory.
+ * But it's a lot slower if you write in video memory.
+ * So, enable it only if you are sure to never write directly in video memory.
+ */
+/* #define USE_SCALE_RANDOMWRITE */
+
+static inline void scale2x_8_def_border(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[0] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+}
+
+static inline void scale2x_8_def_center(scale2x_uint8* dst, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0];
+ dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+}
+
+static inline void scale2x_16_def_border(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[0] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+}
+
+static inline void scale2x_16_def_center(scale2x_uint16* dst, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0];
+ dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+}
+
+static inline void scale2x_32_def_border(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[1] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = src1[-1] == src0[0] ? src0[0] : src1[0];
+ dst[1] = src1[0] == src0[0] ? src0[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+}
+
+static inline void scale2x_32_def_center(scale2x_uint32* dst, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0];
+ dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 2;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ }
+}
+
+/**
+ * Scale by a factor of 2 a row of pixels of 8 bits.
+ * The function is implemented in C.
+ * The pixels over the left and right borders are assumed of the same color of
+ * the pixels on the border.
+ * Note that the implementation is optimized to write data sequentially to
+ * maximize the bandwidth on video memory.
+ * \param src0 Pointer at the first pixel of the previous row.
+ * \param src1 Pointer at the first pixel of the current row.
+ * \param src2 Pointer at the first pixel of the next row.
+ * \param count Length in pixels of the src0, src1 and src2 rows.
+ * It must be at least 2.
+ * \param dst0 First destination row, double length in pixels.
+ * \param dst1 Second destination row, double length in pixels.
+ */
+void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_8_def_whole(dst0, dst1, src0, src1, src2, count);
+#else
+ scale2x_8_def_border(dst0, src0, src1, src2, count);
+ scale2x_8_def_border(dst1, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2 a row of pixels of 16 bits.
+ * This function operates like scale2x_8_def() but for 16 bits pixels.
+ * \param src0 Pointer at the first pixel of the previous row.
+ * \param src1 Pointer at the first pixel of the current row.
+ * \param src2 Pointer at the first pixel of the next row.
+ * \param count Length in pixels of the src0, src1 and src2 rows.
+ * It must be at least 2.
+ * \param dst0 First destination row, double length in pixels.
+ * \param dst1 Second destination row, double length in pixels.
+ */
+void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_16_def_whole(dst0, dst1, src0, src1, src2, count);
+#else
+ scale2x_16_def_border(dst0, src0, src1, src2, count);
+ scale2x_16_def_border(dst1, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2 a row of pixels of 32 bits.
+ * This function operates like scale2x_8_def() but for 32 bits pixels.
+ * \param src0 Pointer at the first pixel of the previous row.
+ * \param src1 Pointer at the first pixel of the current row.
+ * \param src2 Pointer at the first pixel of the next row.
+ * \param count Length in pixels of the src0, src1 and src2 rows.
+ * It must be at least 2.
+ * \param dst0 First destination row, double length in pixels.
+ * \param dst1 Second destination row, double length in pixels.
+ */
+void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_32_def_whole(dst0, dst1, src0, src1, src2, count);
+#else
+ scale2x_32_def_border(dst0, src0, src1, src2, count);
+ scale2x_32_def_border(dst1, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2x3 a row of pixels of 8 bits.
+ * \note Like scale2x_8_def();
+ */
+void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_8_def_whole(dst0, dst2, src0, src1, src2, count);
+ scale2x_8_def_center(dst1, src0, src1, src2, count);
+#else
+ scale2x_8_def_border(dst0, src0, src1, src2, count);
+ scale2x_8_def_center(dst1, src0, src1, src2, count);
+ scale2x_8_def_border(dst2, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2x3 a row of pixels of 16 bits.
+ * \note Like scale2x_16_def();
+ */
+void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_16_def_whole(dst0, dst2, src0, src1, src2, count);
+ scale2x_16_def_center(dst1, src0, src1, src2, count);
+#else
+ scale2x_16_def_border(dst0, src0, src1, src2, count);
+ scale2x_16_def_center(dst1, src0, src1, src2, count);
+ scale2x_16_def_border(dst2, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2x3 a row of pixels of 32 bits.
+ * \note Like scale2x_32_def();
+ */
+void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_32_def_whole(dst0, dst2, src0, src1, src2, count);
+ scale2x_32_def_center(dst1, src0, src1, src2, count);
+#else
+ scale2x_32_def_border(dst0, src0, src1, src2, count);
+ scale2x_32_def_center(dst1, src0, src1, src2, count);
+ scale2x_32_def_border(dst2, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2x4 a row of pixels of 8 bits.
+ * \note Like scale2x_8_def();
+ */
+void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_8_def_whole(dst0, dst3, src0, src1, src2, count);
+ scale2x_8_def_center(dst1, src0, src1, src2, count);
+ scale2x_8_def_center(dst2, src0, src1, src2, count);
+#else
+ scale2x_8_def_border(dst0, src0, src1, src2, count);
+ scale2x_8_def_center(dst1, src0, src1, src2, count);
+ scale2x_8_def_center(dst2, src0, src1, src2, count);
+ scale2x_8_def_border(dst3, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2x4 a row of pixels of 16 bits.
+ * \note Like scale2x_16_def();
+ */
+void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_16_def_whole(dst0, dst3, src0, src1, src2, count);
+ scale2x_16_def_center(dst1, src0, src1, src2, count);
+ scale2x_16_def_center(dst2, src0, src1, src2, count);
+#else
+ scale2x_16_def_border(dst0, src0, src1, src2, count);
+ scale2x_16_def_center(dst1, src0, src1, src2, count);
+ scale2x_16_def_center(dst2, src0, src1, src2, count);
+ scale2x_16_def_border(dst3, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 2x4 a row of pixels of 32 bits.
+ * \note Like scale2x_32_def();
+ */
+void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale2x_32_def_whole(dst0, dst3, src0, src1, src2, count);
+ scale2x_32_def_center(dst1, src0, src1, src2, count);
+ scale2x_32_def_center(dst2, src0, src1, src2, count);
+#else
+ scale2x_32_def_border(dst0, src0, src1, src2, count);
+ scale2x_32_def_center(dst1, src0, src1, src2, count);
+ scale2x_32_def_center(dst2, src0, src1, src2, count);
+ scale2x_32_def_border(dst3, src2, src1, src0, count);
+#endif
+}
diff --git a/Utilities/Scale2x/scale2x.h b/Utilities/Scale2x/scale2x.h
new file mode 100644
index 0000000..e1431c4
--- /dev/null
+++ b/Utilities/Scale2x/scale2x.h
@@ -0,0 +1,37 @@
+/*
+ * This file is part of the Scale2x project.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
+ *
+ * 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 2 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.
+ */
+
+#ifndef __SCALE2X_H
+#define __SCALE2X_H
+
+typedef unsigned char scale2x_uint8;
+typedef unsigned short scale2x_uint16;
+typedef unsigned scale2x_uint32;
+
+void scale2x_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
+void scale2x_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
+void scale2x_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
+
+void scale2x3_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
+void scale2x3_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
+void scale2x3_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
+
+void scale2x4_8_def(scale2x_uint8* dst0, scale2x_uint8* dst1, scale2x_uint8* dst2, scale2x_uint8* dst3, const scale2x_uint8* src0, const scale2x_uint8* src1, const scale2x_uint8* src2, unsigned count);
+void scale2x4_16_def(scale2x_uint16* dst0, scale2x_uint16* dst1, scale2x_uint16* dst2, scale2x_uint16* dst3, const scale2x_uint16* src0, const scale2x_uint16* src1, const scale2x_uint16* src2, unsigned count);
+void scale2x4_32_def(scale2x_uint32* dst0, scale2x_uint32* dst1, scale2x_uint32* dst2, scale2x_uint32* dst3, const scale2x_uint32* src0, const scale2x_uint32* src1, const scale2x_uint32* src2, unsigned count);
+
+#endif
+
diff --git a/Utilities/Scale2x/scale3x.cpp b/Utilities/Scale2x/scale3x.cpp
new file mode 100644
index 0000000..8bfe328
--- /dev/null
+++ b/Utilities/Scale2x/scale3x.cpp
@@ -0,0 +1,423 @@
+/*
+ * This file is part of the Scale2x project.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
+ *
+ * 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 2 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.
+ */
+
+/*
+ * This file contains a C and MMX implementation of the Scale2x effect.
+ *
+ * You can find an high level description of the effect at :
+ *
+ * http://www.scale2x.it/
+ */
+
+#include "../stdafx.h"
+
+#if HAVE_CONFIG_H
+#include
+#endif
+
+#include "scale3x.h"
+
+#include
+
+/***************************************************************************/
+/* Scale3x C implementation */
+
+/**
+ * Define the macro USE_SCALE_RANDOMWRITE to enable
+ * an optimized version which writes memory in random order.
+ * This version is a little faster if you write in system memory.
+ * But it's a lot slower if you write in video memory.
+ * So, enable it only if you are sure to never write directly in video memory.
+ */
+/* #define USE_SCALE_RANDOMWRITE */
+
+static inline void scale3x_8_def_border(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0];
+ dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
+ dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
+ dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
+ dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
+ dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
+ dst[2] = src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+}
+
+static inline void scale3x_8_def_center(scale3x_uint8* dst, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+}
+
+static inline void scale3x_16_def_border(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0];
+ dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
+ dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
+ dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
+ dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
+ dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
+ dst[2] = src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+}
+
+static inline void scale3x_16_def_center(scale3x_uint16* dst, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+}
+
+static inline void scale3x_32_def_border(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = src1[0];
+ dst[1] = (src1[0] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[0]) ? src0[0] : src1[0];
+ dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
+ dst[1] = (src1[-1] == src0[0] && src1[0] != src0[1]) || (src1[1] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
+ dst[2] = src1[1] == src0[0] ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = src1[-1] == src0[0] ? src1[-1] : src1[0];
+ dst[1] = (src1[-1] == src0[0] && src1[0] != src0[0]) || (src1[0] == src0[0] && src1[0] != src0[-1]) ? src0[0] : src1[0];
+ dst[2] = src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+}
+
+static inline void scale3x_32_def_center(scale3x_uint32* dst, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
+{
+ assert(count >= 2);
+
+ /* first pixel */
+ if (src0[0] != src2[0] && src1[0] != src1[1]) {
+ dst[0] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+
+ /* central pixels */
+ count -= 2;
+ while (count) {
+ if (src0[0] != src2[0] && src1[-1] != src1[1]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[1] == src0[0] && src1[0] != src2[1]) || (src1[1] == src2[0] && src1[0] != src0[1]) ? src1[1] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+
+ ++src0;
+ ++src1;
+ ++src2;
+ dst += 3;
+ --count;
+ }
+
+ /* last pixel */
+ if (src0[0] != src2[0] && src1[-1] != src1[0]) {
+ dst[0] = (src1[-1] == src0[0] && src1[0] != src2[-1]) || (src1[-1] == src2[0] && src1[0] != src0[-1]) ? src1[-1] : src1[0];
+ dst[1] = src1[0];
+ dst[2] = (src1[0] == src0[0] && src1[0] != src2[0]) || (src1[0] == src2[0] && src1[0] != src0[0]) ? src1[0] : src1[0];
+ } else {
+ dst[0] = src1[0];
+ dst[1] = src1[0];
+ dst[2] = src1[0];
+ }
+}
+
+/**
+ * Scale by a factor of 3 a row of pixels of 8 bits.
+ * The function is implemented in C.
+ * The pixels over the left and right borders are assumed of the same color of
+ * the pixels on the border.
+ * \param src0 Pointer at the first pixel of the previous row.
+ * \param src1 Pointer at the first pixel of the current row.
+ * \param src2 Pointer at the first pixel of the next row.
+ * \param count Length in pixels of the src0, src1 and src2 rows.
+ * It must be at least 2.
+ * \param dst0 First destination row, triple length in pixels.
+ * \param dst1 Second destination row, triple length in pixels.
+ * \param dst2 Third destination row, triple length in pixels.
+ */
+void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale3x_8_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
+#else
+ scale3x_8_def_border(dst0, src0, src1, src2, count);
+ scale3x_8_def_center(dst1, src0, src1, src2, count);
+ scale3x_8_def_border(dst2, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 3 a row of pixels of 16 bits.
+ * This function operates like scale3x_8_def() but for 16 bits pixels.
+ * \param src0 Pointer at the first pixel of the previous row.
+ * \param src1 Pointer at the first pixel of the current row.
+ * \param src2 Pointer at the first pixel of the next row.
+ * \param count Length in pixels of the src0, src1 and src2 rows.
+ * It must be at least 2.
+ * \param dst0 First destination row, triple length in pixels.
+ * \param dst1 Second destination row, triple length in pixels.
+ * \param dst2 Third destination row, triple length in pixels.
+ */
+void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale3x_16_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
+#else
+ scale3x_16_def_border(dst0, src0, src1, src2, count);
+ scale3x_16_def_center(dst1, src0, src1, src2, count);
+ scale3x_16_def_border(dst2, src2, src1, src0, count);
+#endif
+}
+
+/**
+ * Scale by a factor of 3 a row of pixels of 32 bits.
+ * This function operates like scale3x_8_def() but for 32 bits pixels.
+ * \param src0 Pointer at the first pixel of the previous row.
+ * \param src1 Pointer at the first pixel of the current row.
+ * \param src2 Pointer at the first pixel of the next row.
+ * \param count Length in pixels of the src0, src1 and src2 rows.
+ * It must be at least 2.
+ * \param dst0 First destination row, triple length in pixels.
+ * \param dst1 Second destination row, triple length in pixels.
+ * \param dst2 Third destination row, triple length in pixels.
+ */
+void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count)
+{
+#ifdef USE_SCALE_RANDOMWRITE
+ scale3x_32_def_whole(dst0, dst1, dst2, src0, src1, src2, count);
+#else
+ scale3x_32_def_border(dst0, src0, src1, src2, count);
+ scale3x_32_def_center(dst1, src0, src1, src2, count);
+ scale3x_32_def_border(dst2, src2, src1, src0, count);
+#endif
+}
+
diff --git a/Utilities/Scale2x/scale3x.h b/Utilities/Scale2x/scale3x.h
new file mode 100644
index 0000000..895752a
--- /dev/null
+++ b/Utilities/Scale2x/scale3x.h
@@ -0,0 +1,29 @@
+/*
+ * This file is part of the Scale2x project.
+ *
+ * Copyright (C) 2001, 2002, 2003, 2004 Andrea Mazzoleni
+ *
+ * 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 2 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.
+ */
+
+#ifndef __SCALE3X_H
+#define __SCALE3X_H
+
+typedef unsigned char scale3x_uint8;
+typedef unsigned short scale3x_uint16;
+typedef unsigned scale3x_uint32;
+
+void scale3x_8_def(scale3x_uint8* dst0, scale3x_uint8* dst1, scale3x_uint8* dst2, const scale3x_uint8* src0, const scale3x_uint8* src1, const scale3x_uint8* src2, unsigned count);
+void scale3x_16_def(scale3x_uint16* dst0, scale3x_uint16* dst1, scale3x_uint16* dst2, const scale3x_uint16* src0, const scale3x_uint16* src1, const scale3x_uint16* src2, unsigned count);
+void scale3x_32_def(scale3x_uint32* dst0, scale3x_uint32* dst1, scale3x_uint32* dst2, const scale3x_uint32* src0, const scale3x_uint32* src1, const scale3x_uint32* src2, unsigned count);
+
+#endif
+
diff --git a/Utilities/Scale2x/scalebit.cpp b/Utilities/Scale2x/scalebit.cpp
new file mode 100644
index 0000000..e556dc3
--- /dev/null
+++ b/Utilities/Scale2x/scalebit.cpp
@@ -0,0 +1,473 @@
+/*
+ * This file is part of the Scale2x project.
+ *
+ * Copyright (C) 2003, 2004 Andrea Mazzoleni
+ *
+ * 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 2 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.
+ */
+
+/*
+ * This file contains an example implementation of the Scale effect
+ * applyed to a generic bitmap.
+ *
+ * You can find an high level description of the effect at :
+ *
+ * http://www.scale2x.it/
+ */
+
+#include "../stdafx.h"
+
+#if HAVE_CONFIG_H
+#include
+#endif
+
+#include "scale2x.h"
+#include "scale3x.h"
+
+#if HAVE_ALLOCA_H
+#include
+#endif
+
+#include
+#include
+
+#if !(defined(__MACH__) || defined(__FreeBSD__))
+#include
+#endif
+
+#define SSDST(bits, num) (scale2x_uint##bits *)dst##num
+#define SSSRC(bits, num) (const scale2x_uint##bits *)src##num
+
+/**
+ * Apply the Scale2x effect on a group of rows. Used internally.
+ */
+static inline void stage_scale2x(void* dst0, void* dst1, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
+{
+ switch (pixel) {
+ case 1 : scale2x_8_def(SSDST(8,0), SSDST(8,1), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
+ case 2 : scale2x_16_def(SSDST(16,0), SSDST(16,1), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
+ case 4 : scale2x_32_def(SSDST(32,0), SSDST(32,1), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
+ }
+}
+
+/**
+ * Apply the Scale2x3 effect on a group of rows. Used internally.
+ */
+static inline void stage_scale2x3(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
+{
+ switch (pixel) {
+ case 1 : scale2x3_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
+ case 2 : scale2x3_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
+ case 4 : scale2x3_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
+ }
+}
+
+/**
+ * Apply the Scale2x4 effect on a group of rows. Used internally.
+ */
+static inline void stage_scale2x4(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
+{
+ switch (pixel) {
+ case 1 : scale2x4_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSDST(8,3), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
+ case 2 : scale2x4_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSDST(16,3), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
+ case 4 : scale2x4_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSDST(32,3), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
+ }
+}
+
+/**
+ * Apply the Scale3x effect on a group of rows. Used internally.
+ */
+static inline void stage_scale3x(void* dst0, void* dst1, void* dst2, const void* src0, const void* src1, const void* src2, unsigned pixel, unsigned pixel_per_row)
+{
+ switch (pixel) {
+ case 1 : scale3x_8_def(SSDST(8,0), SSDST(8,1), SSDST(8,2), SSSRC(8,0), SSSRC(8,1), SSSRC(8,2), pixel_per_row); break;
+ case 2 : scale3x_16_def(SSDST(16,0), SSDST(16,1), SSDST(16,2), SSSRC(16,0), SSSRC(16,1), SSSRC(16,2), pixel_per_row); break;
+ case 4 : scale3x_32_def(SSDST(32,0), SSDST(32,1), SSDST(32,2), SSSRC(32,0), SSSRC(32,1), SSSRC(32,2), pixel_per_row); break;
+ }
+}
+
+/**
+ * Apply the Scale4x effect on a group of rows. Used internally.
+ */
+static inline void stage_scale4x(void* dst0, void* dst1, void* dst2, void* dst3, const void* src0, const void* src1, const void* src2, const void* src3, unsigned pixel, unsigned pixel_per_row)
+{
+ stage_scale2x(dst0, dst1, src0, src1, src2, pixel, 2 * pixel_per_row);
+ stage_scale2x(dst2, dst3, src1, src2, src3, pixel, 2 * pixel_per_row);
+}
+
+#define SCDST(i) (dst+(i)*dst_slice)
+#define SCSRC(i) (src+(i)*src_slice)
+#define SCMID(i) (mid[(i)])
+
+/**
+ * Apply the Scale2x effect on a bitmap.
+ * The destination bitmap is filled with the scaled version of the source bitmap.
+ * The source bitmap isn't modified.
+ * The destination bitmap must be manually allocated before calling the function,
+ * note that the resulting size is exactly 2x2 times the size of the source bitmap.
+ * \param void_dst Pointer at the first pixel of the destination bitmap.
+ * \param dst_slice Size in bytes of a destination bitmap row.
+ * \param void_src Pointer at the first pixel of the source bitmap.
+ * \param src_slice Size in bytes of a source bitmap row.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ */
+static void scale2x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
+{
+ unsigned char* dst = (unsigned char*)void_dst;
+ const unsigned char* src = (const unsigned char*)void_src;
+ unsigned count;
+
+ assert(height >= 2);
+
+ count = height;
+
+ stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
+
+ dst = SCDST(2);
+
+ count -= 2;
+ while (count) {
+ stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
+
+ dst = SCDST(2);
+ src = SCSRC(1);
+
+ --count;
+ }
+
+ stage_scale2x(SCDST(0), SCDST(1), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
+}
+
+/**
+ * Apply the Scale2x3 effect on a bitmap.
+ * The destination bitmap is filled with the scaled version of the source bitmap.
+ * The source bitmap isn't modified.
+ * The destination bitmap must be manually allocated before calling the function,
+ * note that the resulting size is exactly 2x3 times the size of the source bitmap.
+ * \param void_dst Pointer at the first pixel of the destination bitmap.
+ * \param dst_slice Size in bytes of a destination bitmap row.
+ * \param void_src Pointer at the first pixel of the source bitmap.
+ * \param src_slice Size in bytes of a source bitmap row.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ */
+static void scale2x3(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
+{
+ unsigned char* dst = (unsigned char*)void_dst;
+ const unsigned char* src = (const unsigned char*)void_src;
+ unsigned count;
+
+ assert(height >= 2);
+
+ count = height;
+
+ stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
+
+ dst = SCDST(3);
+
+ count -= 2;
+ while (count) {
+ stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
+
+ dst = SCDST(3);
+ src = SCSRC(1);
+
+ --count;
+ }
+
+ stage_scale2x3(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
+}
+
+/**
+ * Apply the Scale2x4 effect on a bitmap.
+ * The destination bitmap is filled with the scaled version of the source bitmap.
+ * The source bitmap isn't modified.
+ * The destination bitmap must be manually allocated before calling the function,
+ * note that the resulting size is exactly 2x4 times the size of the source bitmap.
+ * \param void_dst Pointer at the first pixel of the destination bitmap.
+ * \param dst_slice Size in bytes of a destination bitmap row.
+ * \param void_src Pointer at the first pixel of the source bitmap.
+ * \param src_slice Size in bytes of a source bitmap row.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ */
+static void scale2x4(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
+{
+ unsigned char* dst = (unsigned char*)void_dst;
+ const unsigned char* src = (const unsigned char*)void_src;
+ unsigned count;
+
+ assert(height >= 2);
+
+ count = height;
+
+ stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
+
+ dst = SCDST(4);
+
+ count -= 2;
+ while (count) {
+ stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
+
+ dst = SCDST(4);
+ src = SCSRC(1);
+
+ --count;
+ }
+
+ stage_scale2x4(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
+}
+
+/**
+ * Apply the Scale3x effect on a bitmap.
+ * The destination bitmap is filled with the scaled version of the source bitmap.
+ * The source bitmap isn't modified.
+ * The destination bitmap must be manually allocated before calling the function,
+ * note that the resulting size is exactly 3x3 times the size of the source bitmap.
+ * \param void_dst Pointer at the first pixel of the destination bitmap.
+ * \param dst_slice Size in bytes of a destination bitmap row.
+ * \param void_src Pointer at the first pixel of the source bitmap.
+ * \param src_slice Size in bytes of a source bitmap row.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ */
+static void scale3x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
+{
+ unsigned char* dst = (unsigned char*)void_dst;
+ const unsigned char* src = (const unsigned char*)void_src;
+ unsigned count;
+
+ assert(height >= 2);
+
+ count = height;
+
+ stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
+
+ dst = SCDST(3);
+
+ count -= 2;
+ while (count) {
+ stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
+
+ dst = SCDST(3);
+ src = SCSRC(1);
+
+ --count;
+ }
+
+ stage_scale3x(SCDST(0), SCDST(1), SCDST(2), SCSRC(0), SCSRC(1), SCSRC(1), pixel, width);
+}
+
+/**
+ * Apply the Scale4x effect on a bitmap.
+ * The destination bitmap is filled with the scaled version of the source bitmap.
+ * The source bitmap isn't modified.
+ * The destination bitmap must be manually allocated before calling the function,
+ * note that the resulting size is exactly 4x4 times the size of the source bitmap.
+ * \note This function requires also a small buffer bitmap used internally to store
+ * intermediate results. This bitmap must have at least an horizontal size in bytes of 2*width*pixel,
+ * and a vertical size of 6 rows. The memory of this buffer must not be allocated
+ * in video memory because it's also read and not only written. Generally
+ * a heap (malloc) or a stack (alloca) buffer is the best choice.
+ * \param void_dst Pointer at the first pixel of the destination bitmap.
+ * \param dst_slice Size in bytes of a destination bitmap row.
+ * \param void_mid Pointer at the first pixel of the buffer bitmap.
+ * \param mid_slice Size in bytes of a buffer bitmap row.
+ * \param void_src Pointer at the first pixel of the source bitmap.
+ * \param src_slice Size in bytes of a source bitmap row.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ */
+static void scale4x_buf(void* void_dst, unsigned dst_slice, void* void_mid, unsigned mid_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
+{
+ unsigned char* dst = (unsigned char*)void_dst;
+ const unsigned char* src = (const unsigned char*)void_src;
+ unsigned count;
+ unsigned char* mid[6];
+
+ assert(height >= 4);
+
+ count = height;
+
+ /* set the 6 buffer pointers */
+ mid[0] = (unsigned char*)void_mid;
+ mid[1] = mid[0] + mid_slice;
+ mid[2] = mid[1] + mid_slice;
+ mid[3] = mid[2] + mid_slice;
+ mid[4] = mid[3] + mid_slice;
+ mid[5] = mid[4] + mid_slice;
+
+ stage_scale2x(SCMID(-2+6), SCMID(-1+6), SCSRC(0), SCSRC(0), SCSRC(1), pixel, width);
+ stage_scale2x(SCMID(0), SCMID(1), SCSRC(0), SCSRC(1), SCSRC(2), pixel, width);
+ stage_scale2x(SCMID(2), SCMID(3), SCSRC(1), SCSRC(2), SCSRC(3), pixel, width);
+ stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-2+6), SCMID(-2+6), SCMID(-1+6), SCMID(0), pixel, width);
+
+ dst = SCDST(4);
+
+ stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(-1+6), SCMID(0), SCMID(1), SCMID(2), pixel, width);
+
+ dst = SCDST(4);
+
+ count -= 4;
+ while (count) {
+ unsigned char* tmp;
+
+ stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(4), pixel, width);
+ stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
+
+ dst = SCDST(4);
+ src = SCSRC(1);
+
+ tmp = SCMID(0); /* shift by 2 position */
+ SCMID(0) = SCMID(2);
+ SCMID(2) = SCMID(4);
+ SCMID(4) = tmp;
+ tmp = SCMID(1);
+ SCMID(1) = SCMID(3);
+ SCMID(3) = SCMID(5);
+ SCMID(5) = tmp;
+
+ --count;
+ }
+
+ stage_scale2x(SCMID(4), SCMID(5), SCSRC(2), SCSRC(3), SCSRC(3), pixel, width);
+ stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(1), SCMID(2), SCMID(3), SCMID(4), pixel, width);
+
+ dst = SCDST(4);
+
+ stage_scale4x(SCDST(0), SCDST(1), SCDST(2), SCDST(3), SCMID(3), SCMID(4), SCMID(5), SCMID(5), pixel, width);
+}
+
+/**
+ * Apply the Scale4x effect on a bitmap.
+ * The destination bitmap is filled with the scaled version of the source bitmap.
+ * The source bitmap isn't modified.
+ * The destination bitmap must be manually allocated before calling the function,
+ * note that the resulting size is exactly 4x4 times the size of the source bitmap.
+ * \note This function operates like ::scale4x_buf() but the intermediate buffer is
+ * automatically allocated in the stack.
+ * \param void_dst Pointer at the first pixel of the destination bitmap.
+ * \param dst_slice Size in bytes of a destination bitmap row.
+ * \param void_src Pointer at the first pixel of the source bitmap.
+ * \param src_slice Size in bytes of a source bitmap row.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ */
+static void scale4x(void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
+{
+ unsigned mid_slice;
+ void* mid;
+
+ mid_slice = 2 * pixel * width; /* required space for 1 row buffer */
+
+ mid_slice = (mid_slice + 0x7) & ~0x7; /* align to 8 bytes */
+
+#if HAVE_ALLOCA
+ mid = alloca(6 * mid_slice); /* allocate space for 6 row buffers */
+
+ assert(mid != 0); /* alloca should never fails */
+#else
+ mid = malloc(6 * mid_slice); /* allocate space for 6 row buffers */
+
+ if (!mid)
+ return;
+#endif
+
+ scale4x_buf(void_dst, dst_slice, mid, mid_slice, void_src, src_slice, pixel, width, height);
+
+#if !HAVE_ALLOCA
+ free(mid);
+#endif
+}
+
+/**
+ * Check if the scale implementation is applicable at the given arguments.
+ * \param scale Scale factor. 2, 203 (fox 2x3), 204 (for 2x4), 3 or 4.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ * \return
+ * - -1 on precondition violated.
+ * - 0 on success.
+ */
+int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height)
+{
+ if (pixel != 1 && pixel != 2 && pixel != 4)
+ return -1;
+
+ switch (scale) {
+ case 202 :
+ case 203 :
+ case 204 :
+ case 2 :
+ case 303 :
+ case 3 :
+ if (height < 2)
+ return -1;
+ break;
+ case 404 :
+ case 4 :
+ if (height < 4)
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ if (width < 2)
+ return -1;
+
+ return 0;
+}
+
+/**
+ * Apply the Scale effect on a bitmap.
+ * This function is simply a common interface for ::scale2x(), ::scale3x() and ::scale4x().
+ * \param scale Scale factor. 2, 203 (fox 2x3), 204 (for 2x4), 3 or 4.
+ * \param void_dst Pointer at the first pixel of the destination bitmap.
+ * \param dst_slice Size in bytes of a destination bitmap row.
+ * \param void_src Pointer at the first pixel of the source bitmap.
+ * \param src_slice Size in bytes of a source bitmap row.
+ * \param pixel Bytes per pixel of the source and destination bitmap.
+ * \param width Horizontal size in pixels of the source bitmap.
+ * \param height Vertical size in pixels of the source bitmap.
+ */
+void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height)
+{
+ switch (scale) {
+ case 202 :
+ case 2 :
+ scale2x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
+ break;
+ case 203 :
+ scale2x3(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
+ break;
+ case 204 :
+ scale2x4(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
+ break;
+ case 303 :
+ case 3 :
+ scale3x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
+ break;
+ case 404 :
+ case 4 :
+ scale4x(void_dst, dst_slice, void_src, src_slice, pixel, width, height);
+ break;
+ }
+}
+
diff --git a/Utilities/Scale2x/scalebit.h b/Utilities/Scale2x/scalebit.h
new file mode 100644
index 0000000..29dd5f5
--- /dev/null
+++ b/Utilities/Scale2x/scalebit.h
@@ -0,0 +1,33 @@
+/*
+ * This file is part of the Scale2x project.
+ *
+ * Copyright (C) 2003 Andrea Mazzoleni
+ *
+ * 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 2 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.
+ */
+
+/*
+ * This file contains an example implementation of the Scale effect
+ * applyed to a generic bitmap.
+ *
+ * You can find an high level description of the effect at :
+ *
+ * http://www.scale2x.it/
+ */
+
+#ifndef __SCALEBIT_H
+#define __SCALEBIT_H
+
+int scale_precondition(unsigned scale, unsigned pixel, unsigned width, unsigned height);
+void scale(unsigned scale, void* void_dst, unsigned dst_slice, const void* void_src, unsigned src_slice, unsigned pixel, unsigned width, unsigned height);
+
+#endif
+
diff --git a/Utilities/SimpleLock.cpp b/Utilities/SimpleLock.cpp
new file mode 100644
index 0000000..b3f6946
--- /dev/null
+++ b/Utilities/SimpleLock.cpp
@@ -0,0 +1,70 @@
+#include "stdafx.h"
+#include
+#include "SimpleLock.h"
+
+thread_local std::thread::id SimpleLock::_threadID = std::this_thread::get_id();
+
+SimpleLock::SimpleLock()
+{
+ _lock.clear();
+ _lockCount = 0;
+ _holderThreadID = std::thread::id();
+}
+
+SimpleLock::~SimpleLock()
+{
+}
+
+LockHandler SimpleLock::AcquireSafe()
+{
+ return LockHandler(this);
+}
+
+void SimpleLock::Acquire()
+{
+ if(_lockCount == 0 || _holderThreadID != _threadID) {
+ while(_lock.test_and_set());
+ _holderThreadID = _threadID;
+ _lockCount = 1;
+ } else {
+ //Same thread can acquire the same lock multiple times
+ _lockCount++;
+ }
+}
+
+bool SimpleLock::IsFree()
+{
+ return _lockCount == 0;
+}
+
+void SimpleLock::WaitForRelease()
+{
+ //Wait until we are able to grab a lock, and then release it again
+ Acquire();
+ Release();
+}
+
+void SimpleLock::Release()
+{
+ if(_lockCount > 0 && _holderThreadID == _threadID) {
+ _lockCount--;
+ if(_lockCount == 0) {
+ _holderThreadID = std::thread::id();
+ _lock.clear();
+ }
+ } else {
+ assert(false);
+ }
+}
+
+
+LockHandler::LockHandler(SimpleLock *lock)
+{
+ _lock = lock;
+ _lock->Acquire();
+}
+
+LockHandler::~LockHandler()
+{
+ _lock->Release();
+}
\ No newline at end of file
diff --git a/Utilities/SimpleLock.h b/Utilities/SimpleLock.h
new file mode 100644
index 0000000..630a3ab
--- /dev/null
+++ b/Utilities/SimpleLock.h
@@ -0,0 +1,36 @@
+#pragma once
+#include "stdafx.h"
+#include
+
+class SimpleLock;
+
+class LockHandler
+{
+private:
+ SimpleLock *_lock;
+public:
+ LockHandler(SimpleLock *lock);
+ ~LockHandler();
+};
+
+class SimpleLock
+{
+private:
+ thread_local static std::thread::id _threadID;
+
+ std::thread::id _holderThreadID;
+ uint32_t _lockCount;
+ atomic_flag _lock;
+
+public:
+ SimpleLock();
+ ~SimpleLock();
+
+ LockHandler AcquireSafe();
+
+ void Acquire();
+ bool IsFree();
+ void WaitForRelease();
+ void Release();
+};
+
diff --git a/Utilities/Socket.cpp b/Utilities/Socket.cpp
new file mode 100644
index 0000000..65c7236
--- /dev/null
+++ b/Utilities/Socket.cpp
@@ -0,0 +1,367 @@
+#include "stdafx.h"
+#include
+#include
+#include "Socket.h"
+
+#ifndef LIBRETRO
+#include "UPnPPortMapper.h"
+using namespace std;
+
+#ifdef _WIN32
+ #pragma comment(lib,"ws2_32.lib") //Winsock Library
+ #define WIN32_LEAN_AND_MEAN
+ #include
+ #include
+ #include
+#else
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+ #include
+
+ #define INVALID_SOCKET (uintptr_t)-1
+ #define SOCKET_ERROR -1
+ #define WSAGetLastError() errno
+ #define SOCKADDR_IN sockaddr_in
+ #define SOCKADDR sockaddr
+ #define TIMEVAL timeval
+ #define SD_SEND SHUT_WR
+ #define closesocket close
+ #define WSAEWOULDBLOCK EWOULDBLOCK
+ #define ioctlsocket ioctl
+#endif
+
+#define BUFFER_SIZE 200000
+
+Socket::Socket()
+{
+ _sendBuffer = new char[BUFFER_SIZE];
+ _bufferPosition = 0;
+
+ #ifdef _WIN32
+ WSADATA wsaDat;
+ if(WSAStartup(MAKEWORD(2, 2), &wsaDat) != 0) {
+ std::cout << "WSAStartup failed." << std::endl;
+ SetConnectionErrorFlag();
+ return;
+ }
+ _cleanupWSA = true;
+ #endif
+
+ _socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
+ if(_socket == INVALID_SOCKET) {
+ std::cout << "Socket creation failed." << std::endl;
+ SetConnectionErrorFlag();
+ } else {
+ SetSocketOptions();
+ }
+}
+
+Socket::Socket(uintptr_t socket)
+{
+ _socket = socket;
+
+ if(socket == INVALID_SOCKET) {
+ SetConnectionErrorFlag();
+ } else {
+ SetSocketOptions();
+ }
+
+ _sendBuffer = new char[BUFFER_SIZE];
+ _bufferPosition = 0;
+}
+
+Socket::~Socket()
+{
+ if(_UPnPPort != -1) {
+ UPnPPortMapper::RemoveNATPortMapping(_UPnPPort, IPProtocol::TCP);
+ }
+
+ if(_socket != INVALID_SOCKET) {
+ Close();
+ }
+
+ #ifdef _WIN32
+ if(_cleanupWSA) {
+ WSACleanup();
+ }
+ #endif
+
+ delete[] _sendBuffer;
+}
+
+void Socket::SetSocketOptions()
+{
+ //Non-blocking mode
+ u_long iMode = 1;
+ ioctlsocket(_socket, FIONBIO, &iMode);
+
+ //Set send/recv buffers to 256k
+ int bufferSize = 0x40000;
+ setsockopt(_socket, SOL_SOCKET, SO_RCVBUF, (char*)&bufferSize, sizeof(int));
+ setsockopt(_socket, SOL_SOCKET, SO_SNDBUF, (char*)&bufferSize, sizeof(int));
+
+ //Disable nagle's algorithm to improve latency
+ u_long value = 1;
+ setsockopt(_socket, IPPROTO_TCP, TCP_NODELAY, (char*)&value, sizeof(value));
+}
+
+void Socket::SetConnectionErrorFlag()
+{
+ _connectionError = true;
+}
+
+void Socket::Close()
+{
+ std::cout << "Socket closed." << std::endl;
+ shutdown(_socket, SD_SEND);
+ closesocket(_socket);
+ SetConnectionErrorFlag();
+}
+
+bool Socket::ConnectionError()
+{
+ return _connectionError;
+}
+
+void Socket::Bind(uint16_t port)
+{
+ SOCKADDR_IN serverInf;
+ serverInf.sin_family = AF_INET;
+ serverInf.sin_addr.s_addr = INADDR_ANY;
+ serverInf.sin_port = htons(port);
+
+ if(UPnPPortMapper::AddNATPortMapping(port, port, IPProtocol::TCP)) {
+ _UPnPPort = port;
+ }
+
+ if(::bind(_socket, (SOCKADDR*)(&serverInf), sizeof(serverInf)) == SOCKET_ERROR) {
+ std::cout << "Unable to bind socket." << std::endl;
+ SetConnectionErrorFlag();
+ }
+}
+
+bool Socket::Connect(const char* hostname, uint16_t port)
+{
+ // Resolve IP address for hostname
+ bool result = false;
+ addrinfo hint;
+ memset((void*)&hint, 0, sizeof(hint));
+ hint.ai_family = AF_INET;
+ hint.ai_protocol = IPPROTO_TCP;
+ hint.ai_socktype = SOCK_STREAM;
+ addrinfo *addrInfo;
+
+ if(getaddrinfo(hostname, std::to_string(port).c_str(), &hint, &addrInfo) != 0) {
+ std::cout << "Failed to resolve hostname." << std::endl;
+ SetConnectionErrorFlag();
+ } else {
+ //Set socket in non-blocking mode
+ u_long iMode = 1;
+ ioctlsocket(_socket, FIONBIO, &iMode);
+
+ // Attempt to connect to server
+ connect(_socket, addrInfo->ai_addr, (int)addrInfo->ai_addrlen);
+
+ fd_set writeSockets;
+ #ifdef _WIN32
+ writeSockets.fd_count = 1;
+ writeSockets.fd_array[0] = _socket;
+ #else
+ FD_ZERO(&writeSockets);
+ FD_SET(_socket, &writeSockets);
+ #endif
+
+ //Timeout after 3 seconds
+ TIMEVAL timeout;
+ timeout.tv_sec = 3;
+ timeout.tv_usec = 0;
+
+ // check if the socket is ready
+ int returnVal = select((int)_socket+1, nullptr, &writeSockets, nullptr, &timeout);
+ if(returnVal > 0) {
+ result = true;
+ } else {
+ //Could not connect
+ if(returnVal == SOCKET_ERROR) {
+ //int nError = WSAGetLastError();
+ //std::cout << "select failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl;
+ }
+ SetConnectionErrorFlag();
+ }
+
+ freeaddrinfo(addrInfo);
+ }
+
+ return result;
+}
+
+void Socket::Listen(int backlog)
+{
+ if(listen(_socket, backlog) == SOCKET_ERROR) {
+ std::cout << "listen failed." << std::endl;
+ SetConnectionErrorFlag();
+ }
+}
+
+shared_ptr Socket::Accept()
+{
+ uintptr_t socket = accept(_socket, nullptr, nullptr);
+ return shared_ptr(new Socket(socket));
+}
+
+bool WouldBlock(int nError)
+{
+ return nError == WSAEWOULDBLOCK || nError == EAGAIN;
+}
+
+int Socket::Send(char *buf, int len, int flags)
+{
+ int retryCount = 15;
+ int nError = 0;
+ int returnVal;
+ do {
+ //Loop until everything has been sent (shouldn't loop at all in the vast majority of cases)
+ returnVal = send(_socket, buf, len, flags);
+
+ if(returnVal > 0) {
+ //Sent partial data, adjust pointer & length
+ buf += returnVal;
+ len -= returnVal;
+ } else if(returnVal == SOCKET_ERROR) {
+ nError = WSAGetLastError();
+ if(nError != 0) {
+ if(!WouldBlock(nError)) {
+ SetConnectionErrorFlag();
+ } else {
+ retryCount--;
+ if(retryCount == 0) {
+ //Connection seems dead, close it.
+ std::cout << "Unable to send data, closing socket." << std::endl;
+ Close();
+ return 0;
+ }
+
+ std::this_thread::sleep_for(std::chrono::duration(10));
+ }
+ }
+ }
+ } while(WouldBlock(nError) && len > 0);
+
+ return returnVal;
+}
+
+void Socket::BufferedSend(char *buf, int len)
+{
+ if(_bufferPosition+len < BUFFER_SIZE) {
+ memcpy(_sendBuffer+_bufferPosition, buf, len);
+ _bufferPosition += len;
+ } else {
+ std::cout << "prevented buffer overflow";
+ }
+}
+
+void Socket::SendBuffer()
+{
+ Send(_sendBuffer, _bufferPosition, 0);
+ _bufferPosition = 0;
+}
+
+int Socket::Recv(char *buf, int len, int flags)
+{
+ int returnVal = recv(_socket, buf, len, flags);
+
+ if(returnVal == SOCKET_ERROR) {
+ int nError = WSAGetLastError();
+ if(nError && !WouldBlock(nError)) {
+ std::cout << "recv failed: nError " << std::to_string(nError) << " returnVal" << std::to_string(returnVal) << std::endl;
+ SetConnectionErrorFlag();
+ }
+ } else if(returnVal == 0) {
+ //Socket closed
+ std::cout << "Socket closed by peer." << std::endl;
+ Close();
+ }
+
+ return returnVal;
+}
+
+#else
+
+//Libretro port does not need sockets.
+
+Socket::Socket()
+{
+}
+
+Socket::Socket(uintptr_t socket)
+{
+}
+
+Socket::~Socket()
+{
+}
+
+void Socket::SetSocketOptions()
+{
+}
+
+void Socket::SetConnectionErrorFlag()
+{
+}
+
+void Socket::Close()
+{
+}
+
+bool Socket::ConnectionError()
+{
+ return true;
+}
+
+void Socket::Bind(uint16_t port)
+{
+}
+
+bool Socket::Connect(const char* hostname, uint16_t port)
+{
+ return false;
+}
+
+void Socket::Listen(int backlog)
+{
+}
+
+shared_ptr Socket::Accept()
+{
+ return shared_ptr(new Socket(0));
+}
+
+bool WouldBlock(int nError)
+{
+ return false;
+}
+
+int Socket::Send(char *buf, int len, int flags)
+{
+ return 0;
+}
+
+void Socket::BufferedSend(char *buf, int len)
+{
+}
+
+void Socket::SendBuffer()
+{
+}
+
+int Socket::Recv(char *buf, int len, int flags)
+{
+ return 0;
+}
+#endif
diff --git a/Utilities/Socket.h b/Utilities/Socket.h
new file mode 100644
index 0000000..acecb10
--- /dev/null
+++ b/Utilities/Socket.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "stdafx.h"
+
+class Socket
+{
+private:
+#ifndef LIBRETRO
+ #ifdef _WIN32
+ bool _cleanupWSA = false;
+ #endif
+
+ uintptr_t _socket = ~0;
+ bool _connectionError = false;
+ char* _sendBuffer;
+ int _bufferPosition;
+ int32_t _UPnPPort = -1;
+#endif
+
+public:
+ Socket();
+ Socket(uintptr_t socket);
+ ~Socket();
+
+ void SetSocketOptions();
+ void SetConnectionErrorFlag();
+
+ void Close();
+ bool ConnectionError();
+
+ void Bind(uint16_t port);
+ bool Connect(const char* hostname, uint16_t port);
+ void Listen(int backlog);
+ shared_ptr Accept();
+
+ int Send(char *buf, int len, int flags);
+ void BufferedSend(char *buf, int len);
+ void SendBuffer();
+ int Recv(char *buf, int len, int flags);
+};
diff --git a/Utilities/StringUtilities.h b/Utilities/StringUtilities.h
new file mode 100644
index 0000000..22658be
--- /dev/null
+++ b/Utilities/StringUtilities.h
@@ -0,0 +1,20 @@
+#pragma once
+#include "stdafx.h"
+
+class StringUtilities
+{
+public:
+ static vector Split(string input, char delimiter)
+ {
+ vector result;
+ size_t index = 0;
+ size_t lastIndex = 0;
+ while((index = input.find(delimiter, index)) != string::npos) {
+ result.push_back(input.substr(lastIndex, index - lastIndex));
+ index++;
+ lastIndex = index;
+ }
+ result.push_back(input.substr(lastIndex));
+ return result;
+ }
+};
diff --git a/Utilities/Timer.cpp b/Utilities/Timer.cpp
new file mode 100644
index 0000000..9a155e1
--- /dev/null
+++ b/Utilities/Timer.cpp
@@ -0,0 +1,97 @@
+#include "stdafx.h"
+#include "Timer.h"
+
+#ifndef LIBRETRO
+
+#include
+
+#ifdef _WIN32
+#include
+
+Timer::Timer()
+{
+ LARGE_INTEGER li;
+ if(!QueryPerformanceFrequency(&li)) {
+ throw;
+ }
+
+ _frequency = double(li.QuadPart) / 1000.0;
+
+ QueryPerformanceCounter(&li);
+ _start = li.QuadPart;
+}
+
+void Timer::Reset()
+{
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ _start = li.QuadPart;
+}
+
+double Timer::GetElapsedMS()
+{
+ LARGE_INTEGER li;
+ QueryPerformanceCounter(&li);
+ return double(li.QuadPart - _start) / _frequency;
+}
+
+#else
+#include
+
+Timer::Timer()
+{
+ Reset();
+}
+
+void Timer::Reset()
+{
+ timespec start;
+ clock_gettime(CLOCK_MONOTONIC, &start);
+
+ _start = start.tv_sec * 1000000000 + start.tv_nsec;
+}
+
+double Timer::GetElapsedMS()
+{
+ timespec end;
+ clock_gettime(CLOCK_MONOTONIC, &end);
+
+ uint64_t currentTime = end.tv_sec * 1000000000 + end.tv_nsec;
+
+ return (double)(currentTime - _start) / 1000000.0;
+}
+
+#endif
+
+void Timer::WaitUntil(double targetMillisecond)
+{
+ if(targetMillisecond > 0) {
+ double elapsedTime = GetElapsedMS();
+ if(targetMillisecond - elapsedTime > 1) {
+ std::this_thread::sleep_for(std::chrono::duration((int)(targetMillisecond - elapsedTime)));
+ }
+ }
+}
+
+#else
+
+//This is not used by Libretro port, remove its dependencies
+
+Timer::Timer()
+{
+}
+
+void Timer::Reset()
+{
+}
+
+double Timer::GetElapsedMS()
+{
+ return 0.0;
+}
+
+void Timer::WaitUntil(double targetMillisecond)
+{
+}
+
+#endif
\ No newline at end of file
diff --git a/Utilities/Timer.h b/Utilities/Timer.h
new file mode 100644
index 0000000..19888fc
--- /dev/null
+++ b/Utilities/Timer.h
@@ -0,0 +1,18 @@
+#pragma once
+#include "stdafx.h"
+
+class Timer
+{
+ private:
+#ifndef LIBRETRO
+ #ifdef WIN32
+ double _frequency = 0.0;
+ #endif
+ uint64_t _start;
+#endif
+ public:
+ Timer();
+ void Reset();
+ double GetElapsedMS();
+ void WaitUntil(double targetMillisecond);
+};
\ No newline at end of file
diff --git a/Utilities/UPnPPortMapper.cpp b/Utilities/UPnPPortMapper.cpp
new file mode 100644
index 0000000..2b5bc8e
--- /dev/null
+++ b/Utilities/UPnPPortMapper.cpp
@@ -0,0 +1,156 @@
+#include "stdafx.h"
+#include "UPnPPortMapper.h"
+
+#ifdef _WIN32
+#include
+#include
+#include
+
+bool UPnPPortMapper::AddNATPortMapping(uint16_t internalPort, uint16_t externalPort, IPProtocol protocol)
+{
+ bool result = false;
+
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+
+ IUPnPNAT *nat = nullptr;
+ HRESULT hResult = CoCreateInstance(__uuidof(UPnPNAT), nullptr, CLSCTX_ALL, __uuidof(IUPnPNAT), (void**)&nat);
+
+ BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP");
+
+ if(SUCCEEDED(hResult) && nat) {
+ IStaticPortMappingCollection *spmc = nullptr;
+ hResult = nat->get_StaticPortMappingCollection(&spmc);
+ if(SUCCEEDED(hResult) && spmc) {
+ IStaticPortMapping *spm = nullptr;
+ hResult = spmc->get_Item(externalPort, proto, &spm);
+ if(spm != nullptr) {
+ //An identical mapping already exists, remove it
+ if(RemoveNATPortMapping(externalPort, protocol)) {
+ std::cout << "Removed existing UPnP mapping." << std::endl;
+ spm->Release();
+ spm = nullptr;
+ }
+ }
+
+ if(!SUCCEEDED(hResult) || spm == nullptr) {
+ std::cout << "Attempting to automatically forward port via UPnP..." << std::endl;
+
+ vector localIPs = GetLocalIPs();
+ BSTR desc = SysAllocString(L"Mesen NetPlay");
+ spm = nullptr;
+
+ for(size_t i = 0, len = localIPs.size(); i < len; i++) {
+ BSTR clientStr = SysAllocString(localIPs[i].c_str());
+ hResult = spmc->Add(externalPort, proto, internalPort, clientStr, true, desc, &spm);
+ SysFreeString(clientStr);
+ SysFreeString(desc);
+
+ if(SUCCEEDED(hResult) && spm) {
+ //Successfully added a new port mapping
+ std::cout << std::dec << "Forwarded port " << externalPort << " to IP " << utf8::utf8::encode(localIPs[i]) << std::endl;
+ result = true;
+ } else {
+ std::cout << "Unable to add UPnP port mapping. IP: " << utf8::utf8::encode(localIPs[i]) << " HRESULT: 0x" << std::hex << hResult << std::endl;
+ }
+
+ if(spm) {
+ spm->Release();
+ }
+ }
+ } else {
+ std::cout << "Unable to add UPnP port mapping." << std::endl;
+ }
+ spmc->Release();
+ }
+ nat->Release();
+ }
+
+ SysFreeString(proto);
+
+ CoUninitialize();
+
+ return result;
+}
+
+bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol protocol)
+{
+ IUPnPNAT *nat = nullptr;
+ IStaticPortMappingCollection *spmc;
+ bool result = false;
+
+ CoInitializeEx(nullptr, COINIT_MULTITHREADED);
+
+ HRESULT hResult = ::CoCreateInstance(__uuidof(UPnPNAT), nullptr, CLSCTX_ALL, __uuidof(IUPnPNAT), (void**)&nat);
+
+ BSTR proto = SysAllocString((protocol == IPProtocol::TCP) ? L"TCP" : L"UDP");
+
+ if(SUCCEEDED(hResult) && nat) {
+ hResult = nat->get_StaticPortMappingCollection(&spmc);
+ if(SUCCEEDED(hResult) && spmc) {
+ spmc->Remove(externalPort, proto);
+ spmc->Release();
+ result = true;
+ }
+ nat->Release();
+ }
+
+ SysFreeString(proto);
+
+ CoUninitialize();
+
+ return result;
+}
+
+vector UPnPPortMapper::GetLocalIPs()
+{
+ vector localIPs;
+ ADDRINFOW *result = nullptr;
+ ADDRINFOW *current = nullptr;
+ ADDRINFOW hints;
+
+ ZeroMemory(&hints, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+
+ wchar_t hostName[255];
+ DWORD hostSize = 255;
+ GetComputerName(hostName, &hostSize);
+
+ if(GetAddrInfoW(hostName, nullptr, &hints, &result) == 0) {
+ current = result;
+ while(current != nullptr) {
+ wchar_t ipAddr[255];
+ DWORD ipSize = 255;
+
+ if(WSAAddressToString(current->ai_addr, (DWORD)current->ai_addrlen, nullptr, ipAddr, &ipSize) == 0) {
+ if(std::find(localIPs.begin(), localIPs.end(), ipAddr) == localIPs.end()) {
+ localIPs.push_back(ipAddr);
+ }
+ }
+ current = current->ai_next;
+ }
+ FreeAddrInfoW(result);
+ }
+
+ return localIPs;
+}
+
+#else
+
+bool UPnPPortMapper::AddNATPortMapping(uint16_t internalPort, uint16_t externalPort, IPProtocol protocol)
+{
+ return false;
+}
+
+bool UPnPPortMapper::RemoveNATPortMapping(uint16_t externalPort, IPProtocol protocol)
+{
+ return false;
+}
+
+vector UPnPPortMapper::GetLocalIPs()
+{
+ return vector();
+}
+
+#endif
\ No newline at end of file
diff --git a/Utilities/UPnPPortMapper.h b/Utilities/UPnPPortMapper.h
new file mode 100644
index 0000000..82f1301
--- /dev/null
+++ b/Utilities/UPnPPortMapper.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "stdafx.h"
+
+using std::wstring;
+
+enum class IPProtocol
+{
+ TCP = 0,
+ UDP = 1
+};
+
+class UPnPPortMapper
+{
+private:
+ static vector GetLocalIPs();
+
+public:
+ static bool AddNATPortMapping(uint16_t internalPort, uint16_t externalPort, IPProtocol protocol);
+ static bool RemoveNATPortMapping(uint16_t externalPort, IPProtocol protocol);
+};
\ No newline at end of file
diff --git a/Utilities/UTF8Util.cpp b/Utilities/UTF8Util.cpp
new file mode 100644
index 0000000..0a99fea
--- /dev/null
+++ b/Utilities/UTF8Util.cpp
@@ -0,0 +1,31 @@
+#include "stdafx.h"
+#include "UTF8Util.h"
+#include
+#include
+
+namespace utf8
+{
+ std::wstring utf8::decode(const std::string &str)
+ {
+ std::wstring_convert> conv;
+ return conv.from_bytes(str);
+ }
+
+ std::string utf8::encode(const std::wstring &wstr)
+ {
+ std::wstring_convert> conv;
+ return conv.to_bytes(wstr);
+ }
+
+ std::string utf8::encode(const std::u16string &wstr)
+ {
+ #ifdef _MSC_VER
+ std::wstring_convert, int16_t> conv;
+ auto p = reinterpret_cast(wstr.data());
+ return conv.to_bytes(p, p + wstr.size());
+ #else
+ std::wstring_convert, char16_t> conv;
+ return conv.to_bytes(wstr);
+ #endif
+ }
+}
\ No newline at end of file
diff --git a/Utilities/UTF8Util.h b/Utilities/UTF8Util.h
new file mode 100644
index 0000000..c60c966
--- /dev/null
+++ b/Utilities/UTF8Util.h
@@ -0,0 +1,34 @@
+#pragma once
+
+#include
+
+namespace utf8 {
+ class utf8
+ {
+ public:
+ static std::wstring decode(const std::string &str);
+ static std::string encode(const std::wstring &wstr);
+ static std::string encode(const std::u16string &wstr);
+ };
+
+#if defined(_WIN32) && !defined(LIBRETRO)
+ class ifstream : public std::ifstream
+ {
+ public:
+ ifstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) : std::ifstream(utf8::decode(_Str), _Mode, _Prot) { }
+ ifstream() : std::ifstream() { }
+ void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) { std::ifstream::open(utf8::decode(_Str), _Mode, _Prot); }
+ };
+
+ class ofstream : public std::ofstream
+ {
+ public:
+ ofstream(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) : std::ofstream(utf8::decode(_Str), _Mode, _Prot) { }
+ ofstream() : std::ofstream() { }
+ void open(const std::string& _Str, ios_base::openmode _Mode = ios_base::in, int _Prot = (int)ios_base::_Openprot) { std::ofstream::open(utf8::decode(_Str), _Mode, _Prot); }
+ };
+#else
+ using std::ifstream;
+ using std::ofstream;
+#endif
+}
\ No newline at end of file
diff --git a/Utilities/UpsPatcher.cpp b/Utilities/UpsPatcher.cpp
new file mode 100644
index 0000000..1c3a72b
--- /dev/null
+++ b/Utilities/UpsPatcher.cpp
@@ -0,0 +1,100 @@
+#include "stdafx.h"
+#include
+#include
+#include "UpsPatcher.h"
+#include "CRC32.h"
+
+int64_t UpsPatcher::ReadBase128Number(std::istream &file)
+{
+ int64_t result = 0;
+ int shift = 0;
+ uint8_t buffer;
+ while(true) {
+ file.read((char*)&buffer, 1);
+ if(file.eof()) {
+ return -1;
+ }
+ result += (buffer & 0x7F) << shift;
+ shift += 7;
+ if(buffer & 0x80) {
+ break;
+ }
+ result += (int64_t)1 << shift;
+ }
+
+ return result;
+}
+
+bool UpsPatcher::PatchBuffer(string upsFilepath, vector &input, vector &output)
+{
+ ifstream upsFile(upsFilepath, std::ios::in | std::ios::binary);
+ if(upsFile) {
+ return PatchBuffer(upsFile, input, output);
+ }
+ return false;
+}
+
+bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector &input, vector &output)
+{
+ upsFile.seekg(0, std::ios::end);
+ size_t fileSize = (size_t)upsFile.tellg();
+ upsFile.seekg(0, std::ios::beg);
+
+ char header[4];
+ upsFile.read((char*)&header, 4);
+ if(memcmp((char*)&header, "UPS1", 4) != 0) {
+ //Invalid UPS file
+ return false;
+ }
+
+ int64_t inputFileSize = ReadBase128Number(upsFile);
+ int64_t outputFileSize = ReadBase128Number(upsFile);
+ if(inputFileSize == -1 || outputFileSize == -1) {
+ //Invalid file
+ return false;
+ }
+
+ output.resize((size_t)outputFileSize);
+ std::copy(input.begin(), input.end(), output.begin());
+
+ uint32_t pos = 0;
+ while((size_t)upsFile.tellg() < fileSize - 12) {
+ int32_t offset = (int32_t)ReadBase128Number(upsFile);
+ if(offset == -1) {
+ //Invalid file
+ return false;
+ }
+
+ pos += offset;
+
+ while(true) {
+ uint8_t xorValue = 0;
+ upsFile.read((char*)&xorValue, 1);
+ if((size_t)upsFile.tellg() > fileSize - 12) {
+ //Invalid file
+ return false;
+ }
+
+ output[pos] ^= xorValue;
+ pos++;
+
+ if(!xorValue) {
+ break;
+ }
+ }
+ }
+
+ uint8_t inputChecksum[4];
+ uint8_t outputChecksum[4];
+ upsFile.read((char*)inputChecksum, 4);
+ upsFile.read((char*)outputChecksum, 4);
+ uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
+ uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
+ uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
+ uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
+
+ if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
+ return false;
+ }
+ return true;
+}
diff --git a/Utilities/UpsPatcher.h b/Utilities/UpsPatcher.h
new file mode 100644
index 0000000..bf75b1e
--- /dev/null
+++ b/Utilities/UpsPatcher.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include "stdafx.h"
+
+class UpsPatcher
+{
+private:
+ static int64_t ReadBase128Number(std::istream &file);
+
+public:
+ static bool PatchBuffer(std::istream &upsFile, vector &input, vector &output);
+ static bool PatchBuffer(string upsFilepath, vector &input, vector &output);
+};
\ No newline at end of file
diff --git a/Utilities/Utilities.vcxproj b/Utilities/Utilities.vcxproj
new file mode 100644
index 0000000..8a133d7
--- /dev/null
+++ b/Utilities/Utilities.vcxproj
@@ -0,0 +1,627 @@
+
+
+