master
xerox 5 years ago
parent 6a000298f7
commit 0d195db7d2

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30011.22
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "agent-jones", "agent-jones\agent-jones.vcxproj", "{025281A8-D91F-4CCD-B33A-4064D4353F8E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Debug|x64.ActiveCfg = Debug|x64
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Debug|x64.Build.0 = Debug|x64
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Debug|x86.ActiveCfg = Debug|Win32
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Debug|x86.Build.0 = Debug|Win32
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Release|x64.ActiveCfg = Release|x64
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Release|x64.Build.0 = Release|x64
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Release|x86.ActiveCfg = Release|Win32
{025281A8-D91F-4CCD-B33A-4064D4353F8E}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9464EB36-A8BB-4A9E-8A1B-FFEF7D8E0979}
EndGlobalSection
EndGlobal

@ -0,0 +1,110 @@
#include <string>
#include <vector>
#include <Windows.h>
#include <fstream>
#include <iostream>
#include <filesystem>
namespace pe
{
inline PIMAGE_NT_HEADERS get_nt_headers_unsafe(uint8_t* base)
{
const auto dos_header = PIMAGE_DOS_HEADER(base);
const auto nt_headers = PIMAGE_NT_HEADERS(base + dos_header->e_lfanew);
return nt_headers;
}
PIMAGE_NT_HEADERS get_nt_headers(uint8_t* base)
{
const auto dos_header = PIMAGE_DOS_HEADER(base);
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
return nullptr;
const auto nt_headers = PIMAGE_NT_HEADERS(base + dos_header->e_lfanew);
if (nt_headers->Signature != IMAGE_NT_SIGNATURE || nt_headers->FileHeader.Machine != IMAGE_FILE_MACHINE_AMD64)
return nullptr;
return nt_headers;
}
template <typename T>
T* file_rva_to_va(uint8_t* base, const uint32_t rva)
{
const auto nt_headers = get_nt_headers_unsafe(base);
const auto sections = IMAGE_FIRST_SECTION(nt_headers);
for (size_t i = 0; i < nt_headers->FileHeader.NumberOfSections; ++i)
{
const auto& section = sections[i];
if (rva >= section.VirtualAddress && rva < section.VirtualAddress + section.SizeOfRawData)
return (T*)(base + (rva - section.VirtualAddress + section.PointerToRawData));
}
return (T*)(base + rva);
}
}
std::vector<uint8_t> read_file(const std::string& file_path)
{
std::ifstream stream(file_path, std::ios::in | std::ios::ate | std::ios::binary);
if (!stream)
return {};
const auto size = stream.tellg();
stream.seekg(0, std::ios::beg);
std::vector<uint8_t> buffer(size);
stream.read((char*)buffer.data(), size);
return buffer;
}
void check_file(const std::string& file_path)
{
auto buffer = read_file(file_path);
if (buffer.empty())
{
std::printf("Failed to read file: %s.\n", file_path.c_str());
return;
}
const auto base = buffer.data();
const auto nt_headers = pe::get_nt_headers(base);
if (!nt_headers || nt_headers->OptionalHeader.Subsystem != IMAGE_SUBSYSTEM_NATIVE)
return;
const auto import_dir = nt_headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT];
if (!import_dir.Size || !import_dir.VirtualAddress)
return;
bool printed_name = false;
auto import_descriptor = pe::file_rva_to_va<IMAGE_IMPORT_DESCRIPTOR>(base, import_dir.VirtualAddress);
for (; import_descriptor->Name; ++import_descriptor)
{
const auto module_name = pe::file_rva_to_va<const char>(base, import_descriptor->Name);
auto imported_func = pe::file_rva_to_va<IMAGE_THUNK_DATA>(base,
import_descriptor->OriginalFirstThunk ? import_descriptor->OriginalFirstThunk : import_descriptor->FirstThunk);
for (; imported_func->u1.AddressOfData; ++imported_func)
{
if (imported_func->u1.Ordinal & IMAGE_ORDINAL_FLAG)
continue;
const auto import_name = pe::file_rva_to_va<IMAGE_IMPORT_BY_NAME>(base,
uint32_t(imported_func->u1.AddressOfData))->Name;
std::printf("%s,", import_name);
}
}
}
int __cdecl main(int argc, char** argv)
{
if (argc < 2)
{
std::printf("[!] please provide a path to a PE file...");
return -1;
}
check_file(argv[1]);
}

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<ProjectGuid>{025281A8-D91F-4CCD-B33A-4064D4353F8E}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>agentjones</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="agent-jones.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
</Filter>
</ItemGroup>
<ItemGroup>
<ClCompile Include="agent-jones.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

@ -0,0 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LocalDebuggerCommandArguments>C:\Users\interesting\IdeaProjects\agent-smith\drivers\4deb52d0-e845-483f-b245-965611a1e917\fbiosdrv.sys</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LocalDebuggerCommandArguments>C:\Users\interesting\IdeaProjects\agent-smith\drivers\4deb52d0-e845-483f-b245-965611a1e917\fbiosdrv.sys</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LocalDebuggerCommandArguments>C:\Users\interesting\IdeaProjects\agent-smith\drivers\4deb52d0-e845-483f-b245-965611a1e917\fbiosdrv.sys</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LocalDebuggerCommandArguments>C:\Users\interesting\IdeaProjects\agent-smith\drivers\4deb52d0-e845-483f-b245-965611a1e917\fbiosdrv.sys</LocalDebuggerCommandArguments>
<DebuggerFlavor>WindowsLocalDebugger</DebuggerFlavor>
</PropertyGroup>
</Project>

@ -0,0 +1,11 @@
<component name="ArtifactManager">
<artifact type="jar" name="agent-smith:jar">
<output-path>$PROJECT_DIR$/out/artifacts/agent_smith_jar</output-path>
<root id="archive" name="agent-smith.jar">
<element id="module-output" name="agent-smith" />
<element id="extracted-dir" path="C:/Dependancies/JarFiles/CabParser-2.9.jar" path-in-jar="/" />
<element id="extracted-dir" path="C:/Dependancies/JarFiles/Utilities-1.2.jar" path-in-jar="/" />
<element id="extracted-dir" path="C:/Dependancies/JarFiles/jsoup-1.13.1.jar" path-in-jar="/" />
</root>
</artifact>
</component>

@ -0,0 +1,11 @@
<component name="libraryTable">
<library name="CabParser-2.9">
<CLASSES>
<root url="jar://C:/Dependancies/JarFiles/CabParser-2.9.jar!/" />
<root url="jar://C:/Dependancies/JarFiles/Utilities-1.2.jar!/" />
<root url="jar://C:/Dependancies/JarFiles/jsoup-1.13.1.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />
</library>
</component>

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" languageLevel="JDK_13" default="true" project-jdk-name="13" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
</project>

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/agent-smith.iml" filepath="$PROJECT_DIR$/agent-smith.iml" />
</modules>
</component>
</project>

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.png" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.png" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.png" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.png" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

@ -0,0 +1,144 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ArtifactsWorkspaceSettings">
<artifacts-to-build>
<artifact name="agent-smith:jar" />
</artifacts-to-build>
</component>
<component name="ChangeListManager">
<list default="true" id="287ac358-a6f6-4389-a108-653a41438872" name="Default Changelist" comment="" />
<option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
<option name="LAST_RESOLUTION" value="IGNORE" />
</component>
<component name="FileTemplateManagerImpl">
<option name="RECENT_TEMPLATES">
<list>
<option value="Class" />
</list>
</option>
</component>
<component name="ProjectId" id="1beOvSLv8Q1JvpLT3sh6fAF1pU4" />
<component name="ProjectViewState">
<option name="hideEmptyMiddlePackages" value="true" />
<option name="showExcludedFiles" value="true" />
<option name="showLibraryContents" value="true" />
</component>
<component name="PropertiesComponent">
<property name="RunOnceActivity.ShowReadmeOnStart" value="true" />
<property name="last_opened_file_path" value="C:/Dependancies/JarFiles/pecoff4j-0.0.2.2.jar!/" />
<property name="project.structure.last.edited" value="Artifacts" />
<property name="project.structure.proportion" value="0.15" />
<property name="project.structure.side.proportion" value="0.2" />
<property name="settings.editor.selected.configurable" value="preferences.lookFeel" />
</component>
<component name="RecentsManager">
<key name="MoveFile.RECENT_KEYS">
<recent name="C:\Users\interesting\IdeaProjects\agent-smith\src\boris" />
</key>
<key name="CopyFile.RECENT_KEYS">
<recent name="C:\Users\interesting\IdeaProjects\agent-smith" />
<recent name="C:\Users\interesting\IdeaProjects\agent-smith\src\dorkbox" />
<recent name="C:\Users\interesting\IdeaProjects\agent-smith\src" />
</key>
</component>
<component name="RunManager">
<configuration name="Main" type="Application" factoryName="Application" temporary="true" nameIsGenerated="true">
<option name="MAIN_CLASS_NAME" value="Main" />
<module name="agent-smith" />
<option name="PROGRAM_PARAMETERS" value="&quot;hardware driver&quot; &quot;MmMapIoSpace,ZwMapViewOfSection&quot;" />
<method v="2">
<option name="Make" enabled="true" />
</method>
</configuration>
<recent_temporary>
<list>
<item itemvalue="Application.Main" />
</list>
</recent_temporary>
</component>
<component name="SvnConfiguration">
<configuration />
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="287ac358-a6f6-4389-a108-653a41438872" name="Default Changelist" comment="" />
<created>1588989322571</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
<updated>1588989322571</updated>
</task>
<servers />
</component>
<component name="WindowStateProjectService">
<state x="254" y="85" key="#com.intellij.execution.impl.EditConfigurationsDialog" timestamp="1589371940806">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="254" y="85" key="#com.intellij.execution.impl.EditConfigurationsDialog/0.0.1600.860@0.0.1600.860" timestamp="1589371940806" />
<state x="605" y="140" key="#com.intellij.ide.util.MemberChooser" timestamp="1589170793171">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="605" y="140" key="#com.intellij.ide.util.MemberChooser/0.0.1600.860@0.0.1600.860" timestamp="1589170793171" />
<state x="551" y="219" key="#com.intellij.ide.util.TreeClassChooserDialog" timestamp="1589374330140">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="551" y="219" key="#com.intellij.ide.util.TreeClassChooserDialog/0.0.1600.860@0.0.1600.860" timestamp="1589374330140" />
<state x="530" y="177" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog" timestamp="1589374098493">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="530" y="177" key="#com.intellij.refactoring.safeDelete.UnsafeUsagesDialog/0.0.1600.860@0.0.1600.860" timestamp="1589374098493" />
<state x="530" y="177" key="#com.intellij.refactoring.typeMigration.ui.FailedConversionsDialog" timestamp="1589356833349">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="530" y="177" key="#com.intellij.refactoring.typeMigration.ui.FailedConversionsDialog/0.0.1600.860@0.0.1600.860" timestamp="1589356833349" />
<state x="527" y="177" key="FileChooserDialogImpl" timestamp="1589357198434">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="527" y="177" key="FileChooserDialogImpl/0.0.1600.860@0.0.1600.860" timestamp="1589357198434" />
<state width="1557" height="276" key="GridCell.Tab.0.bottom" timestamp="1589374128571">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.0.bottom/0.0.1600.860@0.0.1600.860" timestamp="1589374128571" />
<state width="1557" height="276" key="GridCell.Tab.0.center" timestamp="1589374128571">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.0.center/0.0.1600.860@0.0.1600.860" timestamp="1589374128571" />
<state width="1557" height="276" key="GridCell.Tab.0.left" timestamp="1589374128571">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.0.left/0.0.1600.860@0.0.1600.860" timestamp="1589374128571" />
<state width="1557" height="276" key="GridCell.Tab.0.right" timestamp="1589374128571">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.0.right/0.0.1600.860@0.0.1600.860" timestamp="1589374128571" />
<state width="1557" height="276" key="GridCell.Tab.1.bottom" timestamp="1589374128572">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.1.bottom/0.0.1600.860@0.0.1600.860" timestamp="1589374128572" />
<state width="1557" height="276" key="GridCell.Tab.1.center" timestamp="1589374128571">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.1.center/0.0.1600.860@0.0.1600.860" timestamp="1589374128571" />
<state width="1557" height="276" key="GridCell.Tab.1.left" timestamp="1589374128571">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.1.left/0.0.1600.860@0.0.1600.860" timestamp="1589374128571" />
<state width="1557" height="276" key="GridCell.Tab.1.right" timestamp="1589374128571">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state width="1557" height="276" key="GridCell.Tab.1.right/0.0.1600.860@0.0.1600.860" timestamp="1589374128571" />
<state x="301" y="10" key="SettingsEditor" timestamp="1589374341873">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="301" y="10" key="SettingsEditor/0.0.1600.860@0.0.1600.860" timestamp="1589374341873" />
<state x="496" y="254" key="com.intellij.ide.util.TipDialog" timestamp="1589374235392">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="496" y="254" key="com.intellij.ide.util.TipDialog/0.0.1600.860@0.0.1600.860" timestamp="1589374235392" />
<state x="463" y="180" width="672" height="678" key="search.everywhere.popup" timestamp="1589373756712">
<screen x="0" y="0" width="1600" height="860" />
</state>
<state x="463" y="180" width="672" height="678" key="search.everywhere.popup/0.0.1600.860@0.0.1600.860" timestamp="1589373756712" />
</component>
</project>

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="CabParser-2.9" level="project" />
</component>
</module>

@ -0,0 +1,148 @@
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.extractor.CabExtractor;
import org.jsoup.Jsoup;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
public class DriverDownloader extends Thread {
private static final String url = "https://www.catalog.update.microsoft.com/DownloadDialog.aspx";
private static final String formData = "[{\"size\":0,\"languages\":\"\",\"uidInfo\":\"%s\",\"updateID\":\"%s\"}]";
private static final String downloadString = "downloadInformation[0].files[0].url = '";
private List<String> driverFilePaths = new ArrayList<>();
private String[] imports;
private String uuid;
private String downloadLink;
public DriverDownloader(String uuid, String[] imports) {
this.uuid = uuid;
this.imports = imports;
}
@Override
public void run() {
try {
// query download page
var result = Jsoup
.connect(url)
.data("updateIDs", String.format(formData, uuid, uuid))
.data("updateIDsBlockedForImport", "")
.data("wsusApiPresent", "")
.data("contentImport", "")
.data("sku", "")
.data("serverName", "")
.data("ssl", "")
.data("portNumber", "")
.data("version", "")
.post();
/**
* for some reason download link is not in the a tag so i have to parse it out of javascript.
*/
final var urlIndex = result.toString().indexOf(downloadString) + downloadString.length();
var possibleUrl = result
.toString()
.substring(
urlIndex,
result.toString().indexOf("'", urlIndex));
if(possibleUrl.endsWith(".cab")) {
this.downloadLink = possibleUrl;
downloadCabFile();
findDriverFiles();
scanFilesAndDelete();
}
else
this.downloadLink = "none";
} catch (IOException e) { }
}
private void scanFilesAndDelete() {
driverFilePaths.parallelStream().forEach(path -> {
System.out.printf("[+] checking driver at path: %s\n", path);
try {
/**
* run agent-jones.exe to get imports. this is shit code and should be replaced with
* a library that can get imports but it seems none are good enough :(
*/
Process process = Runtime.getRuntime().exec(new File("agent-jones.exe")
.getAbsolutePath()
.concat(" ")
.concat(new File(path).getAbsolutePath()));
int ch;
StringBuilder sb = new StringBuilder();
while ((ch = process.getInputStream().read()) != -1)
sb.append((char) ch);
var driverImports = sb.toString().split(",");
Arrays.stream(driverImports).parallel().forEach(driverImport -> {
Arrays.stream(this.imports).parallel().forEach(searchImport -> {
if(searchImport.equals(driverImport)) {
try {
var driverPath = path.split("\\\\");
System.out.printf("[+++] %s imports %s!!!!\n", driverPath[driverPath.length - 1], searchImport);
Arrays.stream(driverImports).parallel().forEach(v -> System.out.printf("\t[Import] %s\n", v));
// move the file to results/[uuid]/driver_name.sys
Files.move(
new File(path).toPath(),
new File("results/"
.concat(uuid)
.concat(driverPath[driverPath.length - 1])) // just in case the driver is in a sub folder
.toPath());
} catch (IOException e) { }
}
});
});
} catch (Exception e) { e.printStackTrace(); }
});
/**
* delete all the files in the unzipped folder + the cab file
*/
try {
Files.walk(new File("drivers/".concat(uuid)).toPath()).forEach(file -> new File(file.toString()).delete());
new File("drivers/".concat(uuid)).delete();
new File("drivers/".concat(uuid).concat(".cab")).delete();
} catch (IOException e) { }
}
/**
* scan the unzipped folder for driver files and append them to a list
*/
private void findDriverFiles() {
try {
this.driverFilePaths = Files.walk(Paths.get("drivers/".concat(uuid)))
.filter(Files::isRegularFile)
.map(x -> x.toString())
.collect(Collectors.toList());
this.driverFilePaths = driverFilePaths.parallelStream().filter(file -> file.endsWith(".sys")).collect(Collectors.toList());
} catch (IOException e) { }
}
/**
* download and unzip the cab file for this update
*/
private void downloadCabFile() {
try {
// downloads cab file
Files.copy(
new URL(this.downloadLink).openStream(),
Paths.get("drivers/".concat(uuid).concat(".cab")),
StandardCopyOption.REPLACE_EXISTING);
// extract driver files
new CabExtractor(
new File("drivers/".concat(uuid).concat(".cab")))
.extract();
} catch (IOException | CabException e) { }
}
}

@ -0,0 +1,3 @@
Manifest-Version: 1.0
Main-Class: Main

@ -0,0 +1,19 @@
import java.io.File;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
if(args.length < 2) {
System.out.println("[!] error, please provide a search keyword and imports separated by commas");
System.exit(-1);
}
// make folders for drivers and results
new File("drivers").mkdir();
new File("results").mkdir();
System.out.printf("[+] searching with keyword %s, Imports: %s\n", args[0], Arrays.toString(args[1].split(",")));
new UpdateScanner(args[0], args[1].split(",")).start();
}
}

@ -0,0 +1,19 @@
public class UpdatePageRow {
public String title;
public String product;
public String productType;
public String lastUpdated;
public String version;
public String size;
public String uuid;
UpdatePageRow(String title, String product, String productType, String lastUpdated, String version, String size, String uuid) {
this.title = title;
this.product = product;
this.productType = productType;
this.lastUpdated = lastUpdated;
this.version = version;
this.size = size;
this.uuid = uuid;
}
}

@ -0,0 +1,118 @@
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.HashMap;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class UpdatePageTableValues {
private HashMap<Long, UpdatePageRow> rows = new HashMap<>();
/**
* default constructor that takes any amount of elements and finds the table rows of them.
*
* @param elements any amount of elements, these dont have to be of type TR since they get filtered anyways
*/
public UpdatePageTableValues(Elements elements) {
//
// get all table rows
//
var tableRows = elements
.parallelStream()
.filter(element -> element.tagName().equals("tr") && element.attr("id").contains("_"))
.collect(Collectors.toList());
parseTableRows(tableRows);
}
/**
* returns the row number provided a row element
*
* @param element row element that is used to get row number from
* @return row number or null if none
*/
private static Optional<Long> getGetColumnNumOfTdElement(Element element) {
// only parse td tags
if(!element.tagName().equals("td"))
return Optional.of(null);
var subStrs = element.attr("id").split("_");
// We should have at least 3 sub strings
//
// bc58d56c-767a-47d6-80c3-021fd8079417 (uuid of the update)
// C2 (column number)
// R3 (row number)
if(subStrs.length >= 3) {
try {
return Optional.of(Long.parseLong(subStrs[1].replace("C", "")));
} catch (Exception e) {
e.printStackTrace();
}
}
// return null otherwise
return Optional.of(null);
}
/**
* gers row number of table row element
* @param element
* @return table row number
*/
private static Optional<Long> getRowNumOfTrElement(Element element) {
if(!element.tagName().equals("tr"))
return Optional.of(null);
var subStrs = element.attr("id").split("_");
// We should have at least 2 sub strings
//
// bc58d56c-767a-47d6-80c3-021fd8079417 (uuid of the update)
// R3 (row number)
if (subStrs.length >= 2) {
try {
return Optional.of(Long.parseLong(subStrs[1].replace("R", "")));
} catch (Exception e) {
e.printStackTrace();
}
}
// return null otherwise
return Optional.of(null);
}
/**
* fill rows hashmap with rows of data
* @param tableRows raw html table row elements
*/
private void parseTableRows(List<Element> tableRows) {
tableRows.parallelStream().forEach(tr -> {
//
// try catching for .split
//
try {
rows.put(getRowNumOfTrElement(tr).get(), new UpdatePageRow(
tr.child(1).text(),
tr.child(2).text(),
tr.child(3).text(),
tr.child(4).text(),
tr.child(5).text(),
tr.child(6).text(),
tr.child(7).attr("id").split("_")[0]
));
} catch (Exception e) {
e.printStackTrace();
}
});
}
/**
* get all the driver uuid's
* @return list of driver uuid's
*/
public List<String> getDriverUuids() {
return rows
.entrySet()
.parallelStream()
.map(v -> v.getValue().uuid)
.collect(Collectors.toList());
}
}

@ -0,0 +1,91 @@
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
public class UpdatePageValues {
private List<Element> aspNetHidden;
private long pageIndex;
private long maxPageIndex;
private UpdatePageTableValues pageTableValues;
public UpdatePageValues(Elements elements) {
pageTableValues = new UpdatePageTableValues(elements);
//
// gets hidden input values (used for accessing the next page)
//
this.aspNetHidden = elements
.parallelStream()
.filter(element -> element.tagName().equals("input") && element.attr("type")
.equals("hidden"))
.collect(Collectors.toList());
//
// get the span that contains the page index information. In theory this
// span should always be inside the DOM but just in case we are going to use Optional.
//
Optional<Element> pageIndexElement = elements
.parallelStream()
.filter(element -> element.tagName().equals("span") && element.attr("id").equals("ctl00_catalogBody_searchDuration"))
.findFirst();
//
// if the span element containing the page index information is present then
// can start filling in our classes private members.
//
try {
pageIndexElement.ifPresentOrElse(element -> {
var values = element.text().split(" ");
this.pageIndex = Integer.parseInt(values[6]);
this.maxPageIndex = Integer.parseInt(values[8].replace(")", ""));
},
() -> {
this.pageIndex = 0;
this.maxPageIndex = 0;
});
} catch (Exception e) {
System.out.println("[!] failed to parse index, this can be because there is no span containing index information on this page!");
e.printStackTrace();
}
}
public boolean hasNextPage() {
// only valid if page index and max page index are:
// 1.) both not 0
// 2.) are not the same value (meaning there is not next page)
return !((pageIndex != 0 && maxPageIndex != 0) && pageIndex == maxPageIndex);
}
public long getPageIndex() {
return pageIndex;
}
public long getMaxPageIndex() {
return maxPageIndex;
}
public Map<String, String> getAspNetHiddenUrlEncoded() {
var aspNetHeaderMap = new HashMap<String, String>();
aspNetHidden.parallelStream().forEach(element -> {
// replace event with new page event
if(element.attr("name").equals("__EVENTTARGET")) {
aspNetHeaderMap.put(
element.attr("id"),
"ctl00$catalogBody$nextPageLinkText");
} else {
aspNetHeaderMap.put(
element.attr("id"),
element.attr("value"));
}
});
return aspNetHeaderMap;
}
public UpdatePageTableValues getPageTableValues() {
return pageTableValues;
}
}

@ -0,0 +1,57 @@
import org.jsoup.Jsoup;
import java.io.IOException;
import java.util.*;
/**
* downloads all files on each page, unpacks the cab file, and scans the driver files for desired imports.
* inspection of the drivers must be done manually until further notice.
*/
public class UpdateScanner extends Thread {
private static final String searchUrl = "https://www.catalog.update.microsoft.com/Search.aspx?q=";
private String searchKey;
private Map<String, String> dataMap = new HashMap<>();
private static String[] imports;
public UpdateScanner(String searchKey) {
this.searchKey = searchKey;
}
public UpdateScanner(String searchKey, String[] imports) {
this.searchKey = searchKey;
this.imports = imports;
}
public UpdateScanner(String searchKey, Map<String, String> dataMap) {
this.searchKey = searchKey;
this.dataMap = dataMap;
}
/**
* used to scan all pages with as many threads as possible.
* Each page contains data needed to get to the next so as soon as that is obtained
* we make a new thread to scan the next page.
*/
public void run() {
try {
// get page
var result = Jsoup
.connect(this.searchUrl.concat(this.searchKey.replace(" ", "+")))
.data(this.dataMap)
.post();
// get the pages values
var pageValues = new UpdatePageValues(result.getAllElements());
System.out.printf("[+] scanning page %d of %d\n", pageValues.getPageIndex(), pageValues.getMaxPageIndex());
// if there is a next page, fork a thread to process it whilst we process this page
if (pageValues.hasNextPage())
new UpdateScanner(this.searchKey, pageValues.getAspNetHiddenUrlEncoded()).start();
// for each uuid on this page make a new thread to download and scan the file
pageValues.getPageTableValues().getDriverUuids().forEach(uuid -> {
new DriverDownloader(uuid, this.imports).start();
});
} catch (IOException e) { }
}
}

@ -0,0 +1,27 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
public class CabException extends Exception {
private static final long serialVersionUID = 1L;
public CabException(String errorMessage) {
super(errorMessage);
}
public CabException() {
}
}

@ -0,0 +1,142 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
import java.io.IOException;
import java.io.InputStream;
final class CabInputStream extends InputStream {
private InputStream inputStream;
private long position;
private long a;
private boolean markSupported;
@Override
public void close() throws IOException {
this.inputStream.close();
}
@Override
public synchronized void reset() throws IOException {
if (this.markSupported) {
this.inputStream.reset();
this.position = this.a;
return;
}
throw new IOException();
}
CabInputStream(InputStream inputStream) {
this.inputStream = inputStream;
this.position = 0L;
this.markSupported = this.inputStream.markSupported();
}
@Override
public int read() throws IOException {
int i = this.inputStream.read();
if (i >= 0) {
this.position += 1L;
}
return i;
}
@Override
public int read(byte[] bytes) throws IOException {
int i = this.inputStream.read(bytes);
if (i > 0) {
this.position += i;
}
return i;
}
@Override
public int read(byte[] bytes, int offset, int length) throws IOException {
int i = this.inputStream.read(bytes, offset, length);
if (i > 0) {
this.position += i;
}
return i;
}
@Override
public int available() throws IOException {
throw new IOException();
}
@Override
public synchronized void mark(int paramInt) {
if (this.markSupported) {
this.a = this.position;
this.inputStream.mark(paramInt);
}
}
public long getCurrentPosition() {
return this.position;
}
@Override
public boolean markSupported() {
return this.markSupported;
}
public void seek(long location) throws IOException {
if (location < this.position) {
throw new IOException("Cannot seek backwards");
}
if (location > this.position) {
skip(location - this.position);
}
}
@Override
public long skip(long ammount) throws IOException {
long l = betterSkip(this.inputStream, ammount);
this.position += (int) l;
return l;
}
/**
* Reliably skips over and discards n bytes of data from the input stream
* @param is input stream
* @param n the number of bytes to be skipped
* @return the actual number of bytes skipped
* @throws IOException
*/
public static long betterSkip(InputStream is, long n) throws IOException {
long left = n;
while(left > 0) {
long l = is.skip(left);
if(l > 0) {
left -= l;
} else if(l == 0) { // should we retry? lets read one byte
if(is.read() == -1) // EOF
break;
else
left--;
} else {
throw new IOException("skip() returned a negative value. This should never happen");
}
}
return n - left;
}
}

@ -0,0 +1,203 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.File;
import java.util.Enumeration;
import dorkbox.cabParser.decompress.CabDecompressor;
import dorkbox.cabParser.structure.CabEnumerator;
import dorkbox.cabParser.structure.CabFileEntry;
import dorkbox.cabParser.structure.CabFolderEntry;
import dorkbox.cabParser.structure.CabHeader;
public final class CabParser {
private CabInputStream cabInputStream;
private CabStreamSaver streamSaver;
private ByteArrayOutputStream outputStream = null;
public CabHeader header;
public CabFolderEntry[] folders;
public CabFileEntry[] files;
public
CabParser(InputStream inputStream, final String fileNameToExtract) throws CabException, IOException {
if (fileNameToExtract == null || fileNameToExtract.isEmpty()) {
throw new IllegalArgumentException("Filename must be valid!");
}
this.cabInputStream = new CabInputStream(inputStream);
this.streamSaver = new CabStreamSaver() {
@Override
public boolean saveReservedAreaData(byte[] data, int dataLength) {
return false;
}
@Override
public OutputStream openOutputStream(CabFileEntry cabFile) {
String name = cabFile.getName();
if (fileNameToExtract.equalsIgnoreCase(name)) {
CabParser.this.outputStream = new ByteArrayOutputStream((int) cabFile.getSize());
return CabParser.this.outputStream;
} else {
return null;
}
}
@Override
public void closeOutputStream(OutputStream outputStream, CabFileEntry cabFile) {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException ignored) {
}
}
}
};
readData();
}
public
CabParser(InputStream inputStream, CabStreamSaver streamSaver) throws CabException, IOException {
this.streamSaver = streamSaver;
this.cabInputStream = new CabInputStream(inputStream);
readData();
}
public
CabParser(InputStream inputStream, File extractPath) throws CabException, IOException {
this.streamSaver = new DefaultCabStreamSaver(extractPath);
this.cabInputStream = new CabInputStream(inputStream);
readData();
}
/**
* Gets the version number.
*/
public static
String getVersion() {
return "2.15";
}
public Enumeration<Object> entries() {
return new CabEnumerator(this, false);
}
public Enumeration<Object> entries(boolean b) {
return new CabEnumerator(this, b);
}
private void readData() throws CabException, IOException {
this.header = new CabHeader(this.streamSaver);
this.header.read(this.cabInputStream);
this.folders = new CabFolderEntry[this.header.cFolders];
for (int i = 0; i < this.header.cFolders; i++) {
this.folders[i] = new CabFolderEntry();
this.folders[i].read(this.cabInputStream);
}
this.files = new CabFileEntry[this.header.cFiles];
this.cabInputStream.seek(this.header.coffFiles);
for (int i = 0; i < this.header.cFiles; i++) {
this.files[i] = new CabFileEntry();
this.files[i].read(this.cabInputStream);
}
}
public ByteArrayOutputStream extractStream() throws CabException, IOException {
int folderCount = -1;
int currentCount = 0;
int totalCount = 0;
boolean init = true;
CabDecompressor extractor = new CabDecompressor(this.cabInputStream, this.header.cbCFData);
for (int fileIndex = 0; fileIndex < this.header.cFiles; fileIndex++) {
CabFileEntry entry = this.files[fileIndex];
if (entry.iFolder != folderCount) {
if (folderCount + 1 >= this.header.cFolders) {
throw new CorruptCabException();
}
folderCount++;
init = true;
currentCount = 0;
totalCount = 0;
}
OutputStream localOutputStream = this.streamSaver.openOutputStream(entry);
if (localOutputStream != null) {
if (init) {
CabFolderEntry cabFolderEntry = this.folders[folderCount];
this.cabInputStream.seek(cabFolderEntry.coffCabStart);
extractor.initialize(cabFolderEntry.compressionMethod);
init = false;
}
if (currentCount != totalCount) {
extractor.read(totalCount - currentCount, new OutputStream() {
@Override
public
void write(int i) throws IOException {
//do nothing
}
@Override
public
void write(byte[] b) throws IOException {
//do nothing
}
@Override
public
void write(byte[] b, int off, int len) throws IOException {
//do nothing
}
@Override
public
void flush() throws IOException {
//do nothing
}
});
currentCount = totalCount;
}
extractor.read(entry.cbFile, localOutputStream);
this.streamSaver.closeOutputStream(localOutputStream, entry);
currentCount = (int) (currentCount + entry.cbFile);
}
totalCount = (int) (totalCount + entry.cbFile);
}
return this.outputStream;
}
}

@ -0,0 +1,26 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
import java.io.OutputStream;
import dorkbox.cabParser.structure.CabFileEntry;
public interface CabStreamSaver {
OutputStream openOutputStream(CabFileEntry entry);
void closeOutputStream(OutputStream outputStream, CabFileEntry entry);
boolean saveReservedAreaData(byte[] data, int dataLength);
}

@ -0,0 +1,45 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
public final class Checksum {
@SuppressWarnings("fallthrough")
public static int calculate(byte[] bytes, int currentBlock, int seed) {
int c1 = (byte) (seed & 0xFF);
int c2 = (byte) (seed >>> 8 & 0xFF);
int c3 = (byte) (seed >>> 16 & 0xFF);
int c4 = (byte) (seed >>> 24 & 0xFF);
int j = 0;
int sizeOfBlock = currentBlock >>> 2;
while (sizeOfBlock-- > 0) {
c1 = (byte) (c1 ^ bytes[j++]);
c2 = (byte) (c2 ^ bytes[j++]);
c3 = (byte) (c3 ^ bytes[j++]);
c4 = (byte) (c4 ^ bytes[j++]);
}
switch (currentBlock & 0x3) {
case 3 :
c3 = (byte) (c3 ^ bytes[j++]);
case 2 :
c2 = (byte) (c2 ^ bytes[j++]);
case 1 :
c1 = (byte) (c1 ^ bytes[j++]);
}
return c1 & 0xFF | (c2 & 0xFF) << 8 | (c3 & 0xFF) << 16 | (c4 & 0xFF) << 24;
}
}

@ -0,0 +1,28 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
public final class CorruptCabException extends CabException {
private static final long serialVersionUID = 1L;
public CorruptCabException(String errorMessage) {
super(errorMessage);
}
public CorruptCabException() {
}
}

@ -0,0 +1,77 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser;
import dorkbox.cabParser.structure.CabFileEntry;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
/**
* provide default CabStreamSaver
*/
public class DefaultCabStreamSaver implements CabStreamSaver{
private File extractPath;
public DefaultCabStreamSaver(File extractPath) throws CabException {
this.extractPath = extractPath;
if(extractPath!=null){
if(!extractPath.exists()){
extractPath.mkdirs();
}else if(!extractPath.isDirectory()){
throw new CabException("extractPath is not directory");
}
}
}
@Override
public OutputStream openOutputStream(CabFileEntry entry) {
return new ByteArrayOutputStream((int) entry.getSize());
}
@Override
public void closeOutputStream(OutputStream outputStream, CabFileEntry entry) {
if (outputStream != null) {
try {
ByteArrayOutputStream bos = (ByteArrayOutputStream)outputStream;
File cabEntityFile = new File(extractPath, entry.getName().replace("\\", File.separator));
cabEntityFile.getParentFile().mkdirs();
FileOutputStream fileOutputStream = new FileOutputStream(cabEntityFile);
try {
bos.writeTo(fileOutputStream);
} finally {
fileOutputStream.close();
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} finally {
try {
outputStream.close();
} catch (IOException e) {
}
}
}
}
@Override
public boolean saveReservedAreaData(byte[] data, int dataLength) {
return false;
}
}

@ -0,0 +1,124 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.cabParser.decompress.lzx.DecompressLzx;
import dorkbox.cabParser.decompress.none.DecompressNone;
import dorkbox.cabParser.decompress.zip.DecompressZip;
import dorkbox.cabParser.structure.CabConstants;
import dorkbox.cabParser.structure.CfDataRecord;
public final class CabDecompressor implements CabConstants {
private byte[] readBuffer;
private byte[] bytes;
private long uncompressedDataSize;
private int outputOffset;
private int compressionMethod;
private InputStream inputStream;
private Decompressor decompressor;
private CfDataRecord cfDataRecord;
public CabDecompressor(InputStream paramInputStream, int sizeOfBlockData) {
this.inputStream = paramInputStream;
this.uncompressedDataSize = 0L;
this.outputOffset = 0;
this.compressionMethod = -1;
this.bytes = new byte[33028];
this.cfDataRecord = new CfDataRecord(sizeOfBlockData);
}
public void read(long size, OutputStream outputStream) throws IOException, CabException {
if (this.uncompressedDataSize >= size) {
outputStream.write(this.bytes, this.outputOffset, (int) size);
this.uncompressedDataSize -= size;
this.outputOffset = (int) (this.outputOffset + size);
return;
}
if (this.uncompressedDataSize > 0L) {
outputStream.write(this.bytes, this.outputOffset, (int) this.uncompressedDataSize);
}
size -= this.uncompressedDataSize;
this.outputOffset = 0;
this.uncompressedDataSize = 0L;
while (size > 0L) {
this.cfDataRecord.read(this.inputStream, this.readBuffer);
if (!this.cfDataRecord.validateCheckSum(this.readBuffer)) {
throw new CorruptCabException("Invalid CFDATA checksum");
}
this.decompressor.decompress(this.readBuffer, this.bytes, this.cfDataRecord.cbData, this.cfDataRecord.cbUncomp);
this.uncompressedDataSize = this.cfDataRecord.cbUncomp;
this.outputOffset = 0;
if (this.uncompressedDataSize >= size) {
outputStream.write(this.bytes, this.outputOffset, (int) size);
this.outputOffset = (int) (this.outputOffset + size);
this.uncompressedDataSize -= size;
size = 0L;
} else {
outputStream.write(this.bytes, this.outputOffset, (int) this.uncompressedDataSize);
size -= this.uncompressedDataSize;
this.outputOffset = 0;
this.uncompressedDataSize = 0L;
}
}
}
public void initialize(int compressionMethod) throws CabException {
this.outputOffset = 0;
this.uncompressedDataSize = 0L;
int type = compressionMethod & 0xF;
int windowBits = (compressionMethod & 0x1F00) >>> 8;
if (compressionMethod == this.compressionMethod) {
this.decompressor.reset(windowBits);
return;
}
switch (type) {
case COMPRESSION_TYPE_NONE :
this.decompressor = new DecompressNone();
break;
case COMPRESSION_TYPE_MSZIP :
this.decompressor = new DecompressZip();
break;
case COMPRESSION_TYPE_LZX :
this.decompressor = new DecompressLzx();
break;
case COMPRESSION_TYPE_QUANTUM :
default :
throw new CabException("Unknown compression type " + type);
}
this.readBuffer = new byte[CabConstants.CAB_BLOCK_SIZE + this.decompressor.getMaxGrowth()];
this.decompressor.init(windowBits);
this.compressionMethod = compressionMethod;
}
}

@ -0,0 +1,27 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.structure.CabConstants;
public interface Decompressor extends CabConstants {
void init(int windowBits) throws CabException;
void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException;
int getMaxGrowth();
void reset(int windowBits) throws CabException;
}

@ -0,0 +1,584 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress.lzx;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.cabParser.decompress.Decompressor;
public final class DecompressLzx implements Decompressor, LZXConstants {
private int[] extraBits = new int[51];
private int[] positionBase = new int[51];
private DecompressLzxTree mainTree;
private DecompressLzxTree lengthTree;
private DecompressLzxTree alignedTree;
private DecompressLzxTree preTree;
private int wndSize;
private int windowMask;
private int mainElements;
private int blocksRemaining;
private int blockType;
private int blockRemaining;
private int blockLength;
private int windowPosition;
private int R0;
private int R1;
private int R2;
private byte[] localWindow;
private int windowSize;
private boolean readHeader;
private int outputPosition;
private int index;
private int length;
private byte[] inputBytes;
private boolean abort;
int bitsLeft;
private int blockAlignOffset;
private int intelFileSize;
private int intelCursorPos;
private boolean intelStarted;
private int framesRead;
public DecompressLzx() {
int i = 4;
int j = 1;
do {
this.extraBits[i] = j;
this.extraBits[i + 1] = j;
i += 2;
j++;
} while (j <= 16);
do {
this.extraBits[i++] = 17;
} while (i < 51);
i = -2;
for (j = 0; j < this.extraBits.length; j++) {
this.positionBase[j] = i;
i += 1 << this.extraBits[j];
}
this.windowSize = -1;
}
@Override
public void init(int windowBits) throws CabException {
this.wndSize = 1 << windowBits;
this.windowMask = this.wndSize - 1;
reset(windowBits);
}
@Override
public void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException {
this.abort = false;
this.index = 0;
this.inputBytes = inputBytes;
this.length = inputBytes.length;
initBitStream();
int decompressedOutputLength = decompressLoop(outputLength);
System.arraycopy(this.localWindow, this.outputPosition, outputBytes, 0, decompressedOutputLength);
if (this.framesRead++ < E8_DISABLE_THRESHOLD && this.intelFileSize != 0) {
decodeIntelBlock(outputBytes, decompressedOutputLength);
}
}
@Override
public int getMaxGrowth() {
return MAX_GROWTH;
}
@Override
public void reset(int windowBits) throws CabException {
if (this.windowSize == windowBits) {
this.mainTree.reset();
this.lengthTree.reset();
this.alignedTree.reset();
}
else {
maybeReset();
int i = NUM_CHARS + this.mainElements * ALIGNED_NUM_ELEMENTS;
this.localWindow = new byte[this.wndSize + 261];
this.preTree = new DecompressLzxTree(PRETREE_NUM_ELEMENTS, ALIGNED_NUM_ELEMENTS, this, null);
this.mainTree = new DecompressLzxTree(i, 9, this, this.preTree);
this.lengthTree = new DecompressLzxTree(SECONDARY_NUM_ELEMENTS, 6, this, this.preTree);
this.alignedTree = new DecompressLzxTree(ALIGNED_NUM_ELEMENTS, NUM_PRIMARY_LENGTHS, this, this.preTree);
}
this.windowSize = windowBits;
this.R0 = this.R1 = this.R2 = 1;
this.blocksRemaining = 0;
this.windowPosition = 0;
this.intelCursorPos = 0;
this.readHeader = true;
this.intelStarted = false;
this.framesRead = 0;
this.blockType = BLOCKTYPE_INVALID;
}
private int decompressLoop(int bytesToRead) throws CabException {
int i = bytesToRead;
int lastWindowPosition;
int k;
int m;
if (this.readHeader) {
// read header
if (readBits(1) == 1) {
k = readBits(16);
m = readBits(16);
this.intelFileSize = k << 16 | m;
} else {
this.intelFileSize = 0;
}
this.readHeader = false;
}
lastWindowPosition = 0;
while (bytesToRead > 0) {
if (this.blocksRemaining == 0) {
if (this.blockType == BLOCKTYPE_UNCOMPRESSED) {
if ((this.blockLength & 0x1) != 0 && /* realign bitstream to word */
this.index < this.length) {
this.index++;
}
this.blockType = BLOCKTYPE_INVALID;
initBitStream();
}
this.blockType = readBits(3);
k = readBits(8);
m = readBits(8);
int n = readBits(8);
if (this.abort) {
break;
}
this.blockRemaining = this.blockLength = (k << 16) + (m << 8) + n;
if (this.blockType == BLOCKTYPE_ALIGNED) {
this.alignedTree.readLengths();
this.alignedTree.buildTable();
// rest of aligned header is same as verbatim
}
if (this.blockType == BLOCKTYPE_ALIGNED || this.blockType == BLOCKTYPE_VERBATIM) {
this.mainTree.read();
this.lengthTree.read();
this.mainTree.readLengths(0, NUM_CHARS);
this.mainTree.readLengths(NUM_CHARS, NUM_CHARS + this.mainElements * ALIGNED_NUM_ELEMENTS);
this.mainTree.buildTable();
if (this.mainTree.LENS[0xE8] != 0) {
this.intelStarted = true;
}
this.lengthTree.readLengths(0, SECONDARY_NUM_ELEMENTS);
this.lengthTree.buildTable();
}
else if (this.blockType == BLOCKTYPE_UNCOMPRESSED) {
// because we can't assume otherwise
this.intelStarted = true;
this.index -= 2; // align the bitstream
if (this.index < 0 || this.index + 12 >= this.length) {
throw new CorruptCabException();
}
this.R0 = readInt();
this.R1 = readInt();
this.R2 = readInt();
}
else {
throw new CorruptCabException();
}
}
this.blocksRemaining = 1;
while (this.blockRemaining > 0 && bytesToRead > 0) {
if (this.blockRemaining < bytesToRead) {
k = this.blockRemaining;
} else {
k = bytesToRead;
}
decompressBlockActions(k);
this.blockRemaining -= k;
bytesToRead -= k;
lastWindowPosition += k;
}
if (this.blockRemaining == 0) {
this.blocksRemaining = 0;
}
if (bytesToRead == 0 && this.blockAlignOffset != 16) {
readNumberBits(this.blockAlignOffset);
}
}
if (lastWindowPosition != i) {
throw new CorruptCabException();
}
if (this.windowPosition == 0) {
this.outputPosition = this.wndSize - lastWindowPosition;
} else {
this.outputPosition = this.windowPosition - lastWindowPosition;
}
return lastWindowPosition;
}
@SuppressWarnings("NumericCastThatLosesPrecision")
private void decodeIntelBlock(byte[] bytes, int outLength) {
if (outLength <= 10 || !this.intelStarted) {
this.intelCursorPos += outLength;
return;
}
int cursorPos = this.intelCursorPos;
int fileSize = this.intelFileSize;
int abs_off = 0;
int adjustedOutLength = outLength - 10;
int dataIndex = 0;
int cursor_pos = cursorPos + adjustedOutLength;
while (cursorPos < cursor_pos) {
while (bytes[dataIndex++] == -24) {
if (cursorPos >= cursor_pos) {
break;
}
abs_off = bytes[dataIndex] & 0xFF |
(bytes[dataIndex + 1] & 0xFF) << 8 |
(bytes[dataIndex + 2] & 0xFF) << 16 |
(bytes[dataIndex + 3] & 0xFF) << 24;
if ((abs_off >= -cursorPos) && (abs_off < fileSize)) {
int rel_off = (abs_off >= 0) ? abs_off - cursorPos : abs_off + fileSize;
bytes[dataIndex] = (byte) (rel_off & 0xFF);
bytes[dataIndex + 1] = (byte) (rel_off >>> 8 & 0xFF);
bytes[dataIndex + 2] = (byte) (rel_off >>> 16 & 0xFF);
bytes[dataIndex + 3] = (byte) (rel_off >>> 24 & 0xFF);
}
dataIndex += 4;
cursorPos += 5;
}
cursorPos++;
}
this.intelCursorPos += outLength;
}
private void decompressBlockActions(int bytesToRead) throws CabException {
this.windowPosition &= this.windowMask;
if (this.windowPosition + bytesToRead > this.wndSize) {
throw new CabException();
}
switch (this.blockType) {
case BLOCKTYPE_UNCOMPRESSED :
uncompressedAlgo(bytesToRead);
return;
case BLOCKTYPE_ALIGNED :
alignedAlgo(bytesToRead);
return;
case BLOCKTYPE_VERBATIM :
verbatimAlgo(bytesToRead);
return;
default :
throw new CorruptCabException();
}
}
void readNumberBits(int numBits) {
this.bitsLeft <<= numBits;
this.blockAlignOffset -= numBits;
if (this.blockAlignOffset <= 0) {
this.bitsLeft |= readShort() << -this.blockAlignOffset;
this.blockAlignOffset += 16;
}
}
private void initBitStream() {
if (this.blockType != BLOCKTYPE_UNCOMPRESSED) {
this.bitsLeft = readShort() << 16 | readShort();
this.blockAlignOffset = 16;
}
}
private void maybeReset() {
this.mainElements = 4;
int i = 4;
do {
i += 1 << this.extraBits[this.mainElements];
this.mainElements++;
} while (i < this.wndSize);
}
@SuppressWarnings("NumericCastThatLosesPrecision")
private void verbatimAlgo(int this_run) throws CorruptCabException {
int i = this.windowPosition;
int mask = this.windowMask;
byte[] windowPosition = this.localWindow;
int r0 = this.R0;
int r1 = this.R1;
int r2 = this.R2;
int[] arrayOfInt1 = this.extraBits;
int[] arrayOfInt2 = this.positionBase;
DecompressLzxTree mainTree = this.mainTree;
DecompressLzxTree lengthTree = this.lengthTree;
while (this_run > 0) {
int main_element = mainTree.decodeElement();
if (main_element < NUM_CHARS) {
windowPosition[i++] = (byte) main_element;
this_run--;
}
/* is a match */
else {
main_element -= NUM_CHARS;
int match_length = main_element & NUM_PRIMARY_LENGTHS;
if (match_length == NUM_PRIMARY_LENGTHS) {
match_length += lengthTree.decodeElement();
}
int matchOffset = main_element >>> 3;
/* check for repeated offsets (positions 0,1,2) */
if (matchOffset == 0) {
matchOffset = r0;
}
else if (matchOffset == 1) {
matchOffset = r1;
r1 = r0;
r0 = matchOffset;
}
else if (matchOffset > 2) {
// not repeated offset
if (matchOffset > 3) {
matchOffset = verbatimAlgo2(arrayOfInt1[matchOffset]) + arrayOfInt2[matchOffset];
} else {
matchOffset = 1;
}
r2 = r1;
r1 = r0;
r0 = matchOffset;
} else {
matchOffset = r2;
r2 = r0;
r0 = matchOffset;
}
match_length += MIN_MATCH;
this_run -= match_length;
while (match_length > 0) {
windowPosition[i] = windowPosition[i - matchOffset & mask];
i++;
match_length--;
}
}
}
if (this_run != 0) {
throw new CorruptCabException();
}
this.R0 = r0;
this.R1 = r1;
this.R2 = r2;
this.windowPosition = i;
}
private int verbatimAlgo2(int position) {
int i = this.bitsLeft >>> 32 - position;
this.bitsLeft <<= position;
this.blockAlignOffset -= position;
if (this.blockAlignOffset <= 0) {
this.bitsLeft |= readShort() << -this.blockAlignOffset;
this.blockAlignOffset += 16;
if (this.blockAlignOffset <= 0) {
this.bitsLeft |= readShort() << -this.blockAlignOffset;
this.blockAlignOffset += 16;
}
}
return i;
}
@SuppressWarnings("NumericCastThatLosesPrecision")
private void alignedAlgo(int this_run) throws CorruptCabException {
int windowPos = this.windowPosition;
int mask = this.windowMask;
byte[] window = this.localWindow;
int r0 = this.R0;
int r1 = this.R1;
int r2 = this.R2;
while (this_run > 0) {
int mainElement = this.mainTree.decodeElement();
if (mainElement < NUM_CHARS) {
window[windowPos] = (byte) mainElement;
windowPos = windowPos + 1 & mask;
this_run--;
}
/* is a match */
else {
mainElement -= NUM_CHARS;
int matchLength = mainElement & NUM_PRIMARY_LENGTHS;
if (matchLength == NUM_PRIMARY_LENGTHS) {
matchLength += this.lengthTree.decodeElement();
}
int match_offset = mainElement >>> 3;
if (match_offset > 2) {
// not repeated offset
int extra = this.extraBits[match_offset];
match_offset = this.positionBase[match_offset];
if (extra > 3) {
// verbatim and aligned bits
match_offset += (readBits(extra - 3) << 3) + this.alignedTree.decodeElement();
}
else if (extra == 3) {
// aligned bits only
match_offset += this.alignedTree.decodeElement();
}
else if (extra > 0) {
// verbatim bits only
match_offset += readBits(extra);
}
else {
match_offset = 1;
}
// update repeated offset LRU queue
r2 = r1;
r1 = r0;
r0 = match_offset;
}
else if (match_offset == 0) {
match_offset = r0;
}
else if (match_offset == 1) {
match_offset = r1;
r1 = r0;
r0 = match_offset;
} else {
match_offset = r2;
r2 = r0;
r0 = match_offset;
}
matchLength += MIN_MATCH;
this_run -= matchLength;
while (matchLength > 0) {
window[windowPos] = window[windowPos - match_offset & mask];
windowPos = windowPos + 1 & mask;
matchLength--;
}
}
}
if (this_run != 0) {
throw new CorruptCabException();
}
this.R0 = r0;
this.R1 = r1;
this.R2 = r2;
this.windowPosition = windowPos;
}
private int readShort() {
if (this.index < this.length) {
int i = this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8;
this.index += 2;
return i;
}
this.abort = true;
this.index = 0;
return 0;
}
int readBits(int numBitsToRead) {
int i = this.bitsLeft >>> 32 - numBitsToRead;
readNumberBits(numBitsToRead);
return i;
}
private void uncompressedAlgo(int length) throws CorruptCabException {
if (this.index + length > this.length || this.windowPosition + length > this.wndSize) {
throw new CorruptCabException();
}
this.intelStarted = true;
System.arraycopy(this.inputBytes, this.index, this.localWindow, this.windowPosition, length);
this.index += length;
this.windowPosition += length;
}
private int readInt() {
int i = this.inputBytes[this.index] & 0xFF |
(this.inputBytes[this.index + 1] & 0xFF) << 8 |
(this.inputBytes[this.index + 2] & 0xFF) << 16 |
(this.inputBytes[this.index + 3] & 0xFF) << 24;
this.index += 4;
return i;
}
}

@ -0,0 +1,261 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress.lzx;
import dorkbox.cabParser.CorruptCabException;
final class DecompressLzxTree implements LZXConstants {
private int size;
private int[] aa;
int[] LENS;
private int[] a1;
private int[] a2;
private int[] table;
private int b1;
private int b2;
private int b3;
private int b4;
private DecompressLzx decompressor;
private DecompressLzxTree root;
private int[] c1 = new int[17];
private int[] c2 = new int[17];
private int[] c3 = new int[18];
private static final byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
DecompressLzxTree(int size, int paramInt2, DecompressLzx decompressor, DecompressLzxTree root) {
this.size = size;
this.b1 = paramInt2;
this.decompressor = decompressor;
this.root = root;
this.b2 = 1 << this.b1;
this.b3 = this.b2 - 1;
this.b4 = 32 - this.b1;
this.a1 = new int[this.size * 2];
this.a2 = new int[this.size * 2];
this.table = new int[this.b2];
this.aa = new int[this.size];
this.LENS = new int[this.size];
}
void reset() {
for (int i = 0; i < this.size; i++) {
this.LENS[i] = 0;
this.aa[i] = 0;
}
}
void readLengths() {
for (int i = 0; i < this.size; i++) {
this.LENS[i] = this.decompressor.readBits(3);
}
}
void readLengths(int first, int last) throws CorruptCabException {
for(int i = 0;i<20;i++) {
this.root.LENS[i] = (byte) this.decompressor.readBits(4);
}
this.root.buildTable();
for (int i = first; i < last; i++) {
int k = this.root.decodeElement();
int j;
if (k == 17) {
j = this.decompressor.readBits(4) + 4;
if (i + j >= last) {
j = last - i;
}
while (j-- > 0) {
this.LENS[i++] = 0;
}
i--;
}
else if (k == 18) {
j = this.decompressor.readBits(5) + 20;
if (i + j >= last) {
j = last - i;
}
while (j-- > 0) {
this.LENS[i++] = 0;
}
i--;
}
else if (k == 19) {
j = this.decompressor.readBits(1) + 4;
if (i + j >= last) {
j = last - i;
}
k = this.root.decodeElement();
int m = array[this.aa[i] - k + 17];
while (j-- > 0) {
this.LENS[i++] = m;
}
i--;
}
else {
this.LENS[i] = array[this.aa[i] - k + 17];
}
}
}
void buildTable() throws CorruptCabException {
int[] table = this.table;
int[] c3 = this.c3;
int b1 = this.b1;
int i = 1;
do {
this.c1[i] = 0;
i++;
} while (i <= 16);
for (i = 0; i < this.size; i++) {
this.c1[this.LENS[i]]++;
}
c3[1] = 0;
i = 1;
do {
c3[i + 1] = c3[i] + (this.c1[i] << 16 - i);
i++;
} while (i <= 16);
if (c3[17] != 65536) {
if (c3[17] == 0) {
for (i = 0; i < this.b2; i++) {
table[i] = 0;
}
return;
}
throw new CorruptCabException();
}
int i2 = 16 - b1;
for (i = 1; i <= b1; i++) {
c3[i] >>>= i2;
this.c2[i] = 1 << b1 - i;
}
while (i <= 16) {
this.c2[i] = 1 << 16 - i;
i++;
}
i = c3[b1 + 1] >>> i2;
if (i != 65536) {
while (i < this.b2) {
table[i] = 0;
i++;
}
}
int k = this.size;
for (int j = 0; j < this.size; j++) {
int i1 = this.LENS[j];
if (i1 != 0) {
int m = c3[i1] + this.c2[i1];
if (i1 <= b1) {
if (m > this.b2) {
throw new CorruptCabException();
}
for (i = c3[i1]; i < m; i++) {
table[i] = j;
}
c3[i1] = m;
} else {
int n = c3[i1];
c3[i1] = m;
int i6 = n >>> i2;
int i5 = 2;
i = i1 - b1;
n <<= b1;
do {
int i4;
if (i5 == 2) {
i4 = table[i6];
}
else if (i5 == 0) {
i4 = this.a1[i6];
}
else {
i4 = this.a2[i6];
}
if (i4 == 0) {
this.a1[k] = 0;
this.a2[k] = 0;
if (i5 == 2) {
table[i6] = -k;
} else if (i5 == 0) {
this.a1[i6] = -k;
} else {
this.a2[i6] = -k;
}
i4 = -k;
k++;
}
i6 = -i4;
if ((n & 0x8000) == 0) {
i5 = 0;
} else {
i5 = 1;
}
n <<= 1;
i--;
} while (i != 0);
if (i5 == 0) {
this.a1[i6] = j;
} else {
this.a2[i6] = j;
}
}
}
}
}
void read() {
System.arraycopy(this.LENS, 0, this.aa, 0, this.size);
}
int decodeElement() {
int i = this.table[this.decompressor.bitsLeft >>> this.b4 & this.b3];
while (i < 0) {
int j = 1 << this.b4 - 1;
do {
i = -i;
if ((this.decompressor.bitsLeft & j) == 0) {
i = this.a1[i];
} else {
i = this.a2[i];
}
j >>>= 1;
} while (i < 0);
}
this.decompressor.readNumberBits(this.LENS[i]);
return i;
}
}

@ -0,0 +1,39 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress.lzx;
public interface LZXConstants {
public static final int PRETREE_NUM_ELEMENTS = 20;
public static final int NUM_CHARS = 256;
public static final int SECONDARY_NUM_ELEMENTS = 249;
public static final int ALIGNED_NUM_ELEMENTS = 8;
public static final int NUM_PRIMARY_LENGTHS = 7;
public static final int MIN_MATCH = 2;
public static final int MAX_MATCH = 257;
public static final int NUM_REPEATED_OFFSETS = 3;
public static final int MAX_GROWTH = 6144;
public static final int E8_DISABLE_THRESHOLD = 32768;
public static final int BLOCKTYPE_VERBATIM = 1;
public static final int BLOCKTYPE_ALIGNED = 2;
public static final int BLOCKTYPE_UNCOMPRESSED = 3;
public static final int BLOCKTYPE_INVALID = 4;
}

@ -0,0 +1,43 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress.none;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.cabParser.decompress.Decompressor;
public final class DecompressNone implements Decompressor {
@Override
public void init(int windowBits) {
}
@Override
public void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException {
if (inputLength != outputLength) {
throw new CorruptCabException();
}
System.arraycopy(inputBytes, 0, outputBytes, 0, outputLength);
}
@Override
public int getMaxGrowth() {
return 0;
}
@Override
public void reset(int windowBits) {
}
}

@ -0,0 +1,414 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress.zip;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.cabParser.decompress.Decompressor;
public final class DecompressZip implements Decompressor {
private static final int[] ar1 = {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};
private static final int[] ar2 = {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};
private static final int[] ar3 = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
private byte[] bytes = new byte[320];
private byte[] inputBytes;
private byte[] outputBytes;
private int index;
private int inputPlus4;
int int1;
private int int2;
private int int3;
private int outputLength;
private DecompressZipState state1;
private DecompressZipState state2;
private DecompressZipState state3;
@Override
public void init(int windowBits) {
this.state1 = new DecompressZipState(288, 9, this);
this.state2 = new DecompressZipState(32, 7, this);
this.state3 = new DecompressZipState(19, 7, this);
}
@Override
public void decompress(byte[] inputBytes, byte[] outputBytes, int inputLength, int outputLength) throws CabException {
this.inputBytes = inputBytes;
this.outputBytes = outputBytes;
if (this.inputBytes[0] != 67 || this.inputBytes[1] != 75) {
throw new CorruptCabException();
}
if (outputBytes.length < 33027) {
throw new CabException();
}
if (inputBytes.length < 28) {
throw new CabException();
}
this.index = 2;
this.inputPlus4 = inputLength + 4;
this.outputLength = outputLength;
this.int3 = 0;
maybeDecompress();
while (this.int3 < this.outputLength) {
decompressMore();
}
}
@Override
public int getMaxGrowth() {
return 28;
}
@Override
public void reset(int windowBits) {
}
private void maybeDecompress() throws CabException {
if (this.index + 4 > this.inputPlus4) {
throw new CorruptCabException();
}
this.int1 = readShort() | readShort() << 16;
this.int2 = 16;
}
void add(int paramInt) {
this.int1 >>>= paramInt;
this.int2 -= paramInt;
if (this.int2 <= 0) {
this.int2 += 16;
this.int1 |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << this.int2;
this.index += 2;
}
}
private void check() throws CabException {
if (this.index > this.inputPlus4) {
throw new CorruptCabException();
}
}
@SuppressWarnings({"NumericCastThatLosesPrecision", "Duplicates"})
private void bits() throws CabException {
int i = this.int3;
int j = this.outputLength;
byte[] arrayOfByte1 = this.outputBytes;
int[] arrayOfInt1 = this.state1.intA2;
int[] arrayOfInt2 = this.state1.intA3;
int[] arrayOfInt3 = this.state1.intA4;
byte[] arrayOfByte2 = this.state1.byteA;
int[] arrayOfInt4 = this.state2.intA2;
int[] arrayOfInt5 = this.state2.intA3;
int[] arrayOfInt6 = this.state2.intA4;
byte[] arrayOfByte3 = this.state2.byteA;
int k = this.int1;
int m = this.int2;
do {
if (this.index > this.inputPlus4) {
break;
}
int n = arrayOfInt1[k & 0x1FF];
int i2;
while (n < 0) {
i2 = 512;
do {
n = -n;
if ((k & i2) == 0) {
n = arrayOfInt2[n];
} else {
n = arrayOfInt3[n];
}
i2 <<= 1;
} while (n < 0);
}
int i1 = arrayOfByte2[n];
k >>>= i1;
m -= i1;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
if (n < 256) {
arrayOfByte1[i++] = (byte) n;
} else {
n -= 257;
if (n < 0) {
break;
}
if (n < 8) {
n += 3;
} else if (n != 28) {
int i4 = n - 4 >>> 2;
n = ar1[n] + (k & (1 << i4) - 1);
k >>>= i4;
m -= i4;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
} else {
n = 258;
}
i2 = arrayOfInt4[k & 0x7F];
while (i2 < 0) {
int i5 = 128;
do {
i2 = -i2;
if ((k & i5) == 0) {
i2 = arrayOfInt5[i2];
} else {
i2 = arrayOfInt6[i2];
}
i5 <<= 1;
} while (i2 < 0);
}
i1 = arrayOfByte3[i2];
k >>>= i1;
m -= i1;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
int i4 = i2 - 2 >> 1;
int i3;
if (i4 > 0) {
i3 = ar2[i2] + (k & (1 << i4) - 1);
k >>>= i4;
m -= i4;
if (m <= 0) {
m += 16;
k |= (this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8) << m;
this.index += 2;
}
} else {
i3 = i2 + 1;
}
do {
arrayOfByte1[i] = arrayOfByte1[i - i3 & 0x7FFF];
i++;
n--;
} while (n != 0);
}
} while (i <= j);
this.int3 = i;
this.int1 = k;
this.int2 = m;
check();
}
private void readStuffcommon() throws CabException {
this.state1.main();
this.state2.main();
}
private void setup() {
int i = 0;
do {
this.state1.byteA[i] = (byte) 8;
i++;
} while (i <= 143);
i = 144;
do {
this.state1.byteA[i] = (byte) 9;
i++;
} while (i <= 255);
i = 256;
do {
this.state1.byteA[i] = (byte) 7;
i++;
} while (i <= 279);
i = 280;
do {
this.state1.byteA[i] = (byte) 8;
i++;
} while (i <= 287);
i = 0;
do {
this.state2.byteA[i] = (byte) 5;
i++;
} while (i < 32);
}
private int makeShort(byte byte1, byte byte2) {
return byte1 & 0xFF | (byte2 & 0xFF) << 8;
}
@SuppressWarnings("NumericCastThatLosesPrecision")
private void expand() throws CabException {
check();
int i = calc(5) + 257;
int j = calc(5) + 1;
int k = calc(4) + 4;
for (int n = 0; n < k; n++) {
this.state3.byteA[ar3[n]] = (byte) calc(3);
check();
}
for (int n = k; n < ar3.length; n++) {
this.state3.byteA[ar3[n]] = (byte) 0;
}
this.state3.main();
int m = i + j;
int n = 0;
while (n < m) {
check();
int i1 = (byte) this.state3.read();
if (i1 <= 15) {
this.bytes[n++] = (byte) i1;
} else {
int i3;
int i2;
if (i1 == 16) {
if (n == 0) {
throw new CorruptCabException();
}
i3 = this.bytes[n - 1];
i2 = calc(2) + 3;
if (n + i2 > m) {
throw new CorruptCabException();
}
for (int i4 = 0; i4 < i2; i4++) {
this.bytes[n++] = (byte) i3;
}
} else if (i1 == 17) {
i2 = calc(3) + 3;
if (n + i2 > m) {
throw new CorruptCabException();
}
for (i3 = 0; i3 < i2; i3++) {
this.bytes[n++] = (byte) 0;
}
} else {
i2 = calc(7) + 11;
if (n + i2 > m) {
throw new CorruptCabException();
}
for (i3 = 0; i3 < i2; i3++) {
this.bytes[n++] = (byte) 0;
}
}
}
}
System.arraycopy(this.bytes, 0, this.state1.byteA, 0, i);
for (n = i; n < 288; n++) {
this.state1.byteA[n] = (byte) 0;
}
for (n = 0; n < j; n++) {
this.state2.byteA[n] = this.bytes[n + i];
}
for (n = j; n < 32; n++) {
this.state2.byteA[n] = (byte) 0;
}
if (this.state1.byteA[256] == 0) {
throw new CorruptCabException();
}
}
private int readShort() {
int i = this.inputBytes[this.index] & 0xFF | (this.inputBytes[this.index + 1] & 0xFF) << 8;
this.index += 2;
return i;
}
private int calc(int paramInt) {
int i = this.int1 & (1 << paramInt) - 1;
add(paramInt);
return i;
}
private void decompressMore() throws CabException {
@SuppressWarnings("unused")
int i = calc(1);
int j = calc(2);
if (j == 2) {
expand();
readStuffcommon();
bits();
return;
}
if (j == 1) {
setup();
readStuffcommon();
bits();
return;
}
if (j == 0) {
verify();
return;
}
throw new CabException();
}
private void verify() throws CabException {
mod();
if (this.index >= this.inputPlus4) {
throw new CorruptCabException();
}
int i = makeShort(this.inputBytes[this.index], this.inputBytes[this.index + 1]);
int j = makeShort(this.inputBytes[this.index + 2], this.inputBytes[this.index + 3]);
//noinspection NumericCastThatLosesPrecision
if ((short) i != (short) (~j)) {
throw new CorruptCabException();
}
if (this.index + i > this.inputPlus4 || this.int3 + i > this.outputLength) {
throw new CorruptCabException();
}
maybeDecompress();
System.arraycopy(this.inputBytes, this.index, this.outputBytes, this.int3, i);
this.int3 += i;
if (this.int3 < this.outputLength) {
maybeDecompress();
}
}
private void mod() {
if (this.int2 == 16) {
this.index -= 4;
} else if (this.int2 >= 8) {
this.index -= 3;
} else {
this.index -= 2;
}
if (this.index < 0) {
this.index = 0;
}
this.int2 = 0;
}
}

@ -0,0 +1,176 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.decompress.zip;
import dorkbox.cabParser.CorruptCabException;
final class DecompressZipState {
private int intA;
private int[] intA1;
private int intB;
private int intC;
private int intD;
private DecompressZip decompressZipImpl;
byte[] byteA;
int[] intA2;
int[] intA3;
int[] intA4;
DecompressZipState(int paramInt1, int paramInt2, DecompressZip decompressZipImpl) {
this.intA = paramInt1;
this.decompressZipImpl = decompressZipImpl;
this.byteA = new byte[paramInt1];
this.intA1 = new int[paramInt1];
this.intB = paramInt2;
this.intC = 1 << this.intB;
this.intD = this.intC - 1;
this.intA2 = new int[1 << this.intB];
this.intA3 = new int[this.intA * 2];
this.intA4 = new int[this.intA * 2];
}
void main() throws CorruptCabException {
int[] arrayOfInt1 = new int[17];
int[] arrayOfInt2 = new int[17];
int k = 0;
do {
arrayOfInt1[k] = 0;
k++;
} while (k <= 16);
for (k = 0; k < this.intA; k++) {
arrayOfInt1[this.byteA[k]] += 1;
}
int m;
for (k = this.intB; k <= 16; k++) {
if (arrayOfInt1[k] > 0) {
for (m = 0; m < this.intC; m++) {
this.intA2[m] = 0;
}
break;
}
}
int i = 0;
arrayOfInt1[0] = 0;
k = 1;
do {
i = i + arrayOfInt1[k - 1] << 1;
arrayOfInt2[k] = i;
k++;
} while (k <= 16);
for (k = 0; k < this.intA; k++) {
m = this.byteA[k];
if (m > 0) {
this.intA1[k] = shiftAndOtherStuff(arrayOfInt2[m], m);
arrayOfInt2[m] += 1;
}
}
int j = this.intA;
for (k = 0; k < this.intA; k++) {
int n = this.byteA[k];
m = this.intA1[k];
if (n > 0) {
int i1;
int i2;
int i3;
if (n <= this.intB) {
i1 = 1 << this.intB - n;
i2 = 1 << n;
if (m >= i2) {
throw new CorruptCabException();
}
for (i3 = 0; i3 < i1; i3++) {
this.intA2[m] = k;
m += i2;
}
} else {
i1 = n - this.intB;
i2 = 1 << this.intB;
int i4 = m & this.intD;
i3 = 2;
do {
int i5;
if (i3 == 2) {
i5 = this.intA2[i4];
} else if (i3 == 1) {
i5 = this.intA4[i4];
} else {
i5 = this.intA3[i4];
}
if (i5 == 0) {
this.intA3[j] = 0;
this.intA4[j] = 0;
if (i3 == 2) {
this.intA2[i4] = -j;
} else if (i3 == 1) {
this.intA4[i4] = -j;
} else {
this.intA3[i4] = -j;
}
i5 = -j;
j++;
}
i4 = -i5;
if ((m & i2) == 0) {
i3 = 0;
} else {
i3 = 1;
}
i2 <<= 1;
i1--;
} while (i1 != 0);
if (i3 == 0) {
this.intA3[i4] = k;
} else {
this.intA4[i4] = k;
}
}
}
}
}
private int shiftAndOtherStuff(int paramInt1, int paramInt2) {
int i = 0;
do {
i |= paramInt1 & 0x1;
i <<= 1;
paramInt1 >>>= 1;
paramInt2--;
} while (paramInt2 > 0);
return i >>> 1;
}
int read() {
int i = this.intA2[this.decompressZipImpl.int1 & this.intD];
while (i < 0) {
int j = 1 << this.intB;
do {
i = -i;
if ((this.decompressZipImpl.int1 & j) == 0) {
i = this.intA3[i];
} else {
i = this.intA4[i];
}
j <<= 1;
} while (i < 0);
}
this.decompressZipImpl.add(this.byteA[i]);
return i;
}
}

@ -0,0 +1,186 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.concurrent.atomic.AtomicBoolean;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CabParser;
import dorkbox.cabParser.CabStreamSaver;
import dorkbox.cabParser.structure.CabFileEntry;
import dorkbox.cabParser.structure.CabFolderEntry;
import dorkbox.cabParser.structure.CabHeader;
/**
* Extracts the content of CAB (file or stream).
*/
public class CabExtractor {
private final InputStream inputStream;
private final CabParser parser;
private final AtomicBoolean done = new AtomicBoolean(false);
/**
* To extract all files from CAB file and save to sub-directory (named after
* CAB file name) of working directory.
*
* @param cabFile
* CAB file
*/
public CabExtractor(File cabFile) throws CabException, IOException {
this(cabFile, null, new DefaultCabFileSaver( new File("drivers"), cabFile));
}
/**
* To extract some files from CAB file and save to sub-directory (named
* after CAB file name) of working directory.
*
* @param cabFile
* CAB file
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
*/
public CabExtractor(File cabFile, CabFileFilter filter) throws CabException, IOException {
this(cabFile, filter, new DefaultCabFileSaver(null, cabFile));
}
/**
* To extract some files from CAB file and save to defined extract
* directory.
*
* @param cabFile
* CAB file
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
* @param extractDirectory
* directory to extract files (no sub-directory will be created)
*/
public CabExtractor(File cabFile, CabFileFilter filter, File extractDirectory)
throws CabException, IOException {
this(cabFile, filter, new DefaultCabFileSaver(extractDirectory));
}
/**
* To extract some files from CAB file and handle (save) them using
* {@link CabFileSaver}.
*
* @param cabFile
* CAB file
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
* @param saver
* defines how to save the extracted
* {@link ByteArrayOutputStream} corresponding to
* {@link CabFileEntry}
*/
public CabExtractor(File cabFile, CabFileFilter filter, CabFileSaver saver)
throws CabException, IOException {
this.inputStream = new BufferedInputStream(new FileInputStream(cabFile));
this.parser = new CabParser(this.inputStream, new FilteredCabStreamSaver(saver, filter));
}
/**
* To extract some files from CAB {@link InputStream} and handle (save) them
* using {@link CabFileSaver}.
*
* @param inputStream
* representing CAB file
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
* @param saver
* defines how to save the extracted
* {@link ByteArrayOutputStream} corresponding to
* {@link CabFileEntry}
*/
public CabExtractor(InputStream inputStream, CabFileFilter filter, CabFileSaver saver)
throws CabException, IOException {
this(inputStream, new FilteredCabStreamSaver(saver, filter));
}
/**
* To extract files from CAB {@link InputStream} and handle (save) them
* using {@link CabStreamSaver}.
*
* @param inputStream
* representing CAB file
* @param streamSaver
* defines which files to save and how to save them
*/
public CabExtractor(InputStream inputStream, CabStreamSaver streamSaver)
throws CabException, IOException {
this.inputStream = inputStream;
this.parser = new CabParser(this.inputStream, streamSaver);
}
/**
* Extract files from CAB stream using the strategy defined by constructor
* parameter(s). Only first invocation of this method extracts files (mostly
* because we are extracting from potentially non-rewindable CAB stream, but
* also because extracting with predefined parameters is an idempotent
* operation).
*
* @return <code>true</code> if files were extracted, <code>false</code>
* otherwise (if executed second time on the same
* {@link CabExtractor) object)
*/
public boolean extract() throws CabException, IOException {
boolean result = done.compareAndSet(false, true);
if (result) {
try {
parser.extractStream();
} finally {
inputStream.close();
}
}
return result;
}
public static String getVersion() {
return CabParser.getVersion();
}
public Enumeration<Object> entries() {
return parser.entries();
}
public Enumeration<Object> entries(boolean b) {
return parser.entries(b);
}
public CabHeader getHeader() {
return parser.header;
}
public CabFolderEntry[] getFolders() {
return parser.folders;
}
public CabFileEntry[] getFiles() {
return parser.files;
}
}

@ -0,0 +1,31 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import dorkbox.cabParser.structure.CabFileEntry;
/**
* Implement it to select files to extract from CAB.
*/
public interface CabFileFilter {
/**
* Is invoked on each File Entry found in CAB file.
*
* @return <code>true</code> to extract file, <code>false</code> to ignore
*/
public boolean test(CabFileEntry cabFile);
}

@ -0,0 +1,58 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import java.util.regex.Pattern;
import dorkbox.cabParser.structure.CabFileEntry;
/**
* Selects files to extract using case-insensitive regular expression pattern.
* Note that the file names (passed to regular expression) may contain paths
* delimited with backslash character ('\\').
*/
public class CabFilePatternFilter implements CabFileFilter {
private final Pattern pattern;
/**
* Creates {@link CabFilePatternFilter}.
*
* @param regex
* regular expression to match file name to extract (will be
* compiled as case-insensitive)
*/
public CabFilePatternFilter(String regex) {
this.pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
}
/**
* Creates {@link CabFilePatternFilter}.
*
* @param pattern
* regular expression pattern to match file name to extract (will
* be turned to case-insensitive)
*/
public CabFilePatternFilter(Pattern pattern) {
this.pattern = Pattern.compile(pattern.pattern(), Pattern.CASE_INSENSITIVE);
}
@Override
public boolean test(CabFileEntry cabFile) {
return pattern.matcher(cabFile.getName()).matches();
}
}

@ -0,0 +1,47 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import java.io.ByteArrayOutputStream;
import dorkbox.cabParser.structure.CabFileEntry;
/**
* To define how to handle (save) the file content, corresponding to each
* individual file extracted from CAB.
*/
public interface CabFileSaver {
/**
* Save the extracted file content.
*
* @param fileContent
* extracted file content
* @param cabFile
* {@link CabFileEntry} defining file to be be saved
*/
void save(ByteArrayOutputStream fileContent, CabFileEntry cabFile);
/**
* @return amount successfully saved files
*/
int getSucceeded();
/**
* @return amount of failed save attempts
*/
int getFailed();
}

@ -0,0 +1,61 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import java.util.HashSet;
import java.util.Set;
import dorkbox.cabParser.structure.CabFileEntry;
/**
* Selects files to extract (case-insensitive). Note that the file names in CAB
* file may contain paths delimited with backslash character ('\\').
*/
public class CabFileSetFilter implements CabFileFilter {
private final Set<String> fileNames;
/**
* Creates {@link CabFileSetFilter}.
*
* @param fileName
* single file name to extract (case-insensitive)
*/
public CabFileSetFilter(final String fileName) {
this.fileNames = new HashSet<String>();
this.fileNames.add(fileName.toLowerCase());
}
/**
* Creates {@link CabFileSetFilter}.
*
* @param fileNames
* file names to extract (case-insensitive)
*/
public CabFileSetFilter(final Iterable<String> fileNames) {
this.fileNames = new HashSet<String>();
for (String i : fileNames) {
this.fileNames.add(i.toLowerCase());
}
}
@Override
public boolean test(CabFileEntry cabFile) {
String fileName = cabFile.getName().toLowerCase();
return fileNames.contains(fileName);
}
}

@ -0,0 +1,105 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;
import dorkbox.cabParser.structure.CabFileEntry;
/**
* Saves extracted file content to a file.
*/
public class DefaultCabFileSaver implements CabFileSaver {
private static final Pattern FILENAME_PATTERN = Pattern.compile("\\.(?=[^\\.]+$)");
private final File extractDirectory;
private AtomicInteger succeeded = new AtomicInteger(0);
private AtomicInteger failed = new AtomicInteger(0);
/**
* Creates {@link CabFileSaver}.
*
* @param baseDirectory
* base directory where a sub-directory will be created
* @param cabFile
* to define a sub-directory for extracting files from CAB
*/
public DefaultCabFileSaver(File baseDirectory, File cabFile) {
this.extractDirectory = new File(null == baseDirectory ? new File(".") : baseDirectory,
getFileNameBase(cabFile));
if (!this.extractDirectory.exists())
this.extractDirectory.mkdirs();
}
/**
* Creates {@link CabFileSaver}.
*
* @param extractDirectory
* target directory where the extracted files will be created
*/
public DefaultCabFileSaver(File extractDirectory) {
this.extractDirectory = (null == extractDirectory ? new File(".") : extractDirectory);
if (!this.extractDirectory.exists())
this.extractDirectory.mkdirs();
}
@Override
public void save(ByteArrayOutputStream outputStream, CabFileEntry cabFile) {
if (outputStream != null) {
try {
File file = new File(getExtractDirectory(), cabFile.getName().replace("\\", File.separator));
file.getParentFile().mkdirs();
FileOutputStream writer = new FileOutputStream(file);
try {
outputStream.writeTo(writer);
} finally {
writer.close();
}
succeeded.incrementAndGet();
} catch (IOException e) {
failed.incrementAndGet();
} finally {
try {
outputStream.close();
} catch (IOException e) {
}
}
}
}
@Override
public int getSucceeded() {
return succeeded.get();
}
@Override
public int getFailed() {
return failed.get();
}
public File getExtractDirectory() {
return extractDirectory;
}
public static String getFileNameBase(File file) {
return FILENAME_PATTERN.split(file.getName())[0];
}
}

@ -0,0 +1,116 @@
/*
* Copyright 2019 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.extractor;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.OutputStream;
import dorkbox.cabParser.CabStreamSaver;
import dorkbox.cabParser.structure.CabFileEntry;
/**
* Implementation of {@link CabStreamSaver} that filters files to extract.
* {@link CabFileFilter} and saves them using {@link CabFileSaver}.
*/
public class FilteredCabStreamSaver implements CabStreamSaver {
private final CabFileSaver saver;
private final CabFileFilter filter;
/**
* To save all files to defined extract directory.
*
* @param extractDirectory
* directory to extract files (no sub-directory will be created)
*/
public FilteredCabStreamSaver(File extractDirectory) {
this(extractDirectory, null);
}
/**
* To handle (save) all files using passed {@link CabFileSaver}.
*
* @param saver
* defines how to save the {@link ByteArrayOutputStream}
* corresponding to {@link CabFileEntry}
*/
public FilteredCabStreamSaver(CabFileSaver saver) {
this(saver, null);
}
/**
* To save some files to defined extract directory.
*
* @param extractDirectory
* directory to extract files (no sub-directory will be created)
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
*/
public FilteredCabStreamSaver(File extractDirectory, CabFileFilter filter) {
this(new DefaultCabFileSaver(extractDirectory), filter);
}
/**
* To handle (save) some files using passed {@link CabFileSaver}.
*
* @param saver
* defines how to save the {@link ByteArrayOutputStream}
* corresponding to {@link CabFileEntry}
* @param filter
* which files to extract (extract all files if
* <code>null</code>)
*/
public FilteredCabStreamSaver(CabFileSaver saver, CabFileFilter filter) {
this.saver = null == saver ? new DefaultCabFileSaver(null) : saver;
this.filter = null == filter ? new CabFilePatternFilter(".+") : filter;
}
@Override
public void closeOutputStream(OutputStream outputStream, CabFileEntry cabFile) {
saver.save((ByteArrayOutputStream) outputStream, cabFile);
}
@Override
public OutputStream openOutputStream(CabFileEntry cabFile) {
if (filter.test(cabFile)) {
return new ByteArrayOutputStream((int) cabFile.getSize());
} else {
return null;
}
}
@Override
public boolean saveReservedAreaData(byte[] data, int dataLength) {
return false;
}
/**
* @return amount successfully saved files
*/
public int getSucceeded() {
return saver.getSucceeded();
}
/**
* @return amount of failed save attempts
*/
public int getFailed() {
return saver.getFailed();
}
}

@ -0,0 +1,54 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
public interface CabConstants {
int CAB_BLOCK_SIZE = 32768;
int CAB_BLOCK_SIZE_THRESH = 32767;
int COMPRESSION_TYPE_NONE = 0;
int COMPRESSION_TYPE_MSZIP = 1;
int COMPRESSION_TYPE_QUANTUM = 2;
int COMPRESSION_TYPE_LZX = 3;
int RESERVED_CFHEADER = 1;
int RESERVED_CFFOLDER = 2;
int RESERVED_CFDATA = 3;
int CAB_PROGRESS_INPUT = 1;
/**
* FLAG_PREV_CABINET is set if this cabinet file is not the first in a set
* of cabinet files. When this bit is set, the szCabinetPrev and szDiskPrev
* fields are present in this CFHEADER.
*/
int FLAG_PREV_CABINET = 0x0001;
/**
* FLAG_NEXT_CABINET is set if this cabinet file is not the last in a set of
* cabinet files. When this bit is set, the szCabinetNext and szDiskNext
* fields are present in this CFHEADER.
*/
int FLAG_NEXT_CABINET = 0x0002;
/**
* FLAG_RESERVE_PRESENT is set if this cabinet file contains any reserved
* fields. When this bit is set, the cbCFHeader, cbCFFolder, and cbCFData
* fields are present in this CFHEADER.
*/
int FLAG_RESERVE_PRESENT = 0x0004;
}

@ -0,0 +1,66 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.util.Enumeration;
import java.util.NoSuchElementException;
import dorkbox.cabParser.CabParser;
public final class CabEnumerator implements Enumeration<Object> {
private int fileCount = 0;
private int folderCount = 0;
private CabParser cabParser;
private boolean b;
private int folderIndex;
@Override
public Object nextElement() {
if (!this.b) {
if (this.fileCount < this.cabParser.header.cFiles) {
return this.cabParser.files[this.fileCount++];
}
throw new NoSuchElementException();
}
if (this.cabParser.files[this.fileCount].iFolder != this.folderIndex) {
this.folderIndex = this.cabParser.files[this.fileCount].iFolder;
if (this.folderCount < this.cabParser.folders.length) {
return this.cabParser.folders[this.folderCount++];
}
}
if (this.fileCount < this.cabParser.header.cFiles) {
return this.cabParser.files[this.fileCount++];
}
throw new NoSuchElementException();
}
public CabEnumerator(CabParser decoder, boolean b) {
this.cabParser = decoder;
this.b = b;
this.folderIndex = -2;
}
@Override
public boolean hasMoreElements() {
return this.fileCount < this.cabParser.header.cFiles;
}
}

@ -0,0 +1,249 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Date;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.util.bytes.LittleEndian;
public final class CabFileEntry {
public static final Charset US_ASCII = Charset.forName("US-ASCII");
/** file is read-only (in HEX) */
static final int READONLY = 0x01;
/** file is hidden (in HEX) */
static final int HIDDEN = 0x02;
/** file is a system file (in HEX) */
static final int SYSTEM = 0x04;
/** file modified since last backup (in HEX) */
static final int ARCHIVE = 0x20;
/** szName[] contains UTF (in HEX) */
static final int NAME_IS_UTF = 0x80;
/** uncompressed size of this file in bytes , 4bytes */
public long cbFile;
/** uncompressed offset of this file in the folder , 4bytes */
public long offFolderStart;
/** index into the CFFOLDER area , 2bytes */
public int iFolder;
/** time/date stamp for this file , 2bytes */
public Date date = new Date();
/** attribute flags for this file , 2bytes */
public int attribs;
/** name of this file , 1*n bytes */
public String szName;
private Object objectOrSomething;
public void read(InputStream input) throws IOException, CabException {
byte[] arrayOfByte = new byte[256];
this.cbFile = LittleEndian.UInt_.from(input).longValue();
this.offFolderStart = LittleEndian.UInt_.from(input).longValue();
this.iFolder = LittleEndian.UShort_.from(input).intValue();
int timeA = LittleEndian.UShort_.from(input).intValue();
int timeB = LittleEndian.UShort_.from(input).intValue();
this.date = getDate(timeA, timeB);
this.attribs = LittleEndian.UShort_.from(input).intValue();
int i = 0;
for (i = 0; i < arrayOfByte.length; i++) {
int m = input.read();
if (m == -1) {
throw new CorruptCabException("EOF reading cffile");
}
arrayOfByte[i] = (byte) m;
if (m == 0) {
break;
}
}
if (i >= arrayOfByte.length) {
throw new CorruptCabException("cffile filename not null terminated");
}
if ((this.attribs & NAME_IS_UTF) == NAME_IS_UTF) {
this.szName = readUtfString(arrayOfByte);
if (this.szName == null) {
throw new CorruptCabException("invalid utf8 code");
}
} else {
this.szName = new String(arrayOfByte, 0, i, US_ASCII).trim();
}
}
public boolean isReadOnly() {
return (this.attribs & READONLY) != 0;
}
public void setReadOnly(boolean bool) {
if (bool) {
this.attribs |= 1;
return;
}
this.attribs &= -2;
}
public boolean isHidden() {
return (this.attribs & HIDDEN) != 0;
}
public void setHidden(boolean bool) {
if (bool) {
this.attribs |= 2;
return;
}
this.attribs &= -3;
}
public boolean isSystem() {
return (this.attribs & SYSTEM) != 0;
}
public void setSystem(boolean bool) {
if (bool) {
this.attribs |= 4;
return;
}
this.attribs &= -5;
}
public boolean isArchive() {
return (this.attribs & ARCHIVE) != 0;
}
public void setArchive(boolean bool) {
if (bool) {
this.attribs |= 32;
return;
}
this.attribs &= -33;
}
public String getName() {
return this.szName;
}
public long getSize() {
return this.cbFile;
}
public void setName(String name) {
this.szName = name;
}
public void setSize(long size) {
this.cbFile = (int) size;
}
public Date getDate() {
return this.date;
}
public void setDate(Date paramDate) {
this.date = paramDate;
}
@SuppressWarnings("deprecation")
private Date getDate(int dateInfo, int timeInfo) {
int i = dateInfo & 0x1F;
int j = (dateInfo >>> 5) - 1 & 0xF;
int k = (dateInfo >>> 9) + 80;
int m = (timeInfo & 0x1F) << 1;
int n = timeInfo >>> 5 & 0x3F;
int i1 = timeInfo >>> 11 & 0x1F;
return new Date(k, j, i, i1, n, m);
}
public Object getApplicationData() {
return this.objectOrSomething;
}
public void setApplicationData(Object obj) {
this.objectOrSomething = obj;
}
@Override
public String toString() {
return this.szName;
}
private static String readUtfString(byte[] stringBytes) {
int j = 0;
int stringSize = 0;
int k = 0;
// count the size of the string
for (stringSize = 0; stringBytes[stringSize] != 0; stringSize++) {}
char[] stringChars = new char[stringSize];
for (k = 0; stringBytes[j] != 0; k++) {
int m = (char) (stringBytes[j++] & 0xFF);
if (m < 128) {
stringChars[k] = (char) m;
} else {
if (m < 192) {
return null;
}
if (m < 224) {
stringChars[k] = (char) ((m & 0x1F) << 6);
m = (char) (stringBytes[j++] & 0xFF);
if (m < 128 || m > 191) {
return null;
}
stringChars[k] = (char) (stringChars[k] | (char) (m & 0x3F));
}
else if (m < 240) {
stringChars[k] = (char) ((m & 0xF) << 12);
m = (char) (stringBytes[j++] & 0xFF);
if (m < 128 || m > 191) {
return null;
}
stringChars[k] = (char) (stringChars[k] | (char) ((m & 0x3F) << 6));
m = (char) (stringBytes[j++] & 0xFF);
if (m < 128 || m > 191) {
return null;
}
stringChars[k] = (char) (stringChars[k] | (char) (m & 0x3F));
} else {
return null;
}
}
}
return new String(stringChars, 0, k);
}
}

@ -0,0 +1,72 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.IOException;
import java.io.InputStream;
import dorkbox.util.bytes.LittleEndian;
public final class CabFolderEntry implements CabConstants {
/** offset of the first CFDATA block in this folder, 4bytes */
public long coffCabStart;
/** number of CFDATA blocks in this folder, 2bytes */
public int cCFData;
/** compression type indicator , 2bytes */
public int compressionMethod = 0;
public int getCompressionMethod() {
return this.compressionMethod & 0xF;
}
public void read(InputStream input) throws IOException {
this.coffCabStart = LittleEndian.UInt_.from(input).longValue();
this.cCFData = LittleEndian.UShort_.from(input).intValue();
this.compressionMethod = LittleEndian.UShort_.from(input).intValue();
}
public int getCompressionWindowSize() {
if (this.compressionMethod == COMPRESSION_TYPE_NONE) {
return 0;
}
if (this.compressionMethod == COMPRESSION_TYPE_MSZIP) {
return 16;
}
return (this.compressionMethod & 0x1F00) >>> 8;
}
public String compressionToString() {
switch (getCompressionMethod()) {
default :
return "UNKNOWN";
case 0 :
return "NONE";
case 1 :
return "MSZIP";
case 2 :
return "QUANTUM:" + Integer.toString(getCompressionWindowSize());
case 3 :
}
return "LZX:" + Integer.toString(getCompressionWindowSize());
}
public void setCompression(int a, int b) {
this.compressionMethod = b << 8 | a;
}
}

@ -0,0 +1,161 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.CabStreamSaver;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.util.bytes.LittleEndian;
public final class CabHeader implements CabConstants {
/** reserved , 4 bytes */
public long reserved1;
/** size of this cabinet file in bytes , 4 bytes */
public long cbCabinet;
/** reserved, 4 bytes */
public long reserved2;
/** offset of the first CFFILE entry , 4 bytes */
public long coffFiles;
/** reserved, 4 bytes*/
public long reserved3;
/** cabinet file format version, minor/major , 1 bytes*2 */
public int version;
/** number of CFFOLDER entries in this cabinet , 2 bytes */
public int cFolders;
/** number of CFFILE entries in this cabinet , 2 bytes */
public int cFiles;
/** cabinet file option indicators , 2 bytes */
public int flags;
/** must be the same for all cabinets in a set , 2 bytes */
public int setID;
/** number of this cabinet file in a set , 2 bytes */
public int iCabinet;
/** (optional) size of per-cabinet reserved area , 2 bytes */
public int cbCFHeader = 0;
/** (optional) size of per-folder reserved area , 1 bytes */
public int cbCFFolder = 0;
/** (optional) size of per-datablock reserved area , 1 bytes */
public int cbCFData = 0;
/** (optional) per-cabinet reserved area , 1*n bytes */
//final short abReserve[];
/** (optional) name of previous cabinet file , 1*n bytes */
//final String szCabinetPrev;
/** (optional) name of previous disk , 1*n bytes */
//final String szDiskPrev;
/** (optional) name of next cabinet file , 1*n bytes */
//final String szCabinetNext;
/** (optional) name of next disk , 1*n bytes */
//final String szDiskNext;
private CabStreamSaver decoder;
public CabHeader(CabStreamSaver paramCabDecoderInterface) {
this.decoder = paramCabDecoderInterface;
}
public void read(InputStream input) throws IOException, CabException {
int i = input.read();
int j = input.read();
int k = input.read();
int m = input.read();
// Contains the characters "M", "S", "C", and "F" (bytes 0x4D, 0x53, 0x43, 0x46). This field is used to ensure that the file is a cabinet (.cab) file.
if (i != 77 || j != 83 || k != 67 || m != 70) {
throw new CorruptCabException("Missing header signature");
}
this.reserved1 = LittleEndian.UInt_.from(input).longValue(); // must be 0
this.cbCabinet = LittleEndian.UInt_.from(input).longValue(); // Specifies the total size of the cabinet file, in bytes.
this.reserved2 = LittleEndian.UInt_.from(input).longValue(); // must be 0
this.coffFiles = LittleEndian.UInt_.from(input).longValue(); // Specifies the absolute file offset, in bytes, of the first CFFILE field entry.
this.reserved3 = LittleEndian.UInt_.from(input).longValue(); // must be 0
// Currently, versionMajor = 1 and versionMinor = 3
this.version = LittleEndian.UShort_.from(input).intValue();
this.cFolders = LittleEndian.UShort_.from(input).intValue();
this.cFiles = LittleEndian.UShort_.from(input).intValue();
this.flags = LittleEndian.UShort_.from(input).intValue();
this.setID = LittleEndian.UShort_.from(input).intValue();
this.iCabinet = LittleEndian.UShort_.from(input).intValue();
if ((this.flags & FLAG_RESERVE_PRESENT) == FLAG_RESERVE_PRESENT) {
this.cbCFHeader = LittleEndian.UShort_.from(input).intValue();
this.cbCFFolder = input.read();
this.cbCFData = input.read();
}
if ((this.flags & FLAG_PREV_CABINET) == FLAG_PREV_CABINET ||
(this.flags & FLAG_NEXT_CABINET) == FLAG_NEXT_CABINET) {
throw new CabException("Spanned cabinets not supported");
}
// not supported
// if (prevCabinet()) {
// szCabinetPrev = bytes.readString(false);
// szDiskPrev = bytes.readString(false);
// } else {
// szCabinetPrev = null;
// szDiskPrev = null;
// }
//
// if (nextCabinet()) {
// szCabinetNext = bytes.readString(false);
// szDiskNext = bytes.readString(false);
// } else {
// szCabinetNext = null;
// szDiskNext = null;
// }
if (this.cbCFHeader != 0) {
if (this.decoder.saveReservedAreaData(null, this.cbCFHeader) == true) {
byte[] data = new byte[this.cbCFHeader];
if (this.cbCFHeader != 0) {
int readTotal = 0;
while (readTotal < this.cbCFHeader) {
int read = input.read(data, readTotal, this.cbCFHeader - readTotal);
if (read < 0) {
throw new EOFException();
}
readTotal += read;
}
}
this.decoder.saveReservedAreaData(data, this.cbCFHeader);
return;
}
input.skip(this.cbCFHeader);
}
}
}

@ -0,0 +1,80 @@
/*
* Copyright 2012 dorkbox, llc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dorkbox.cabParser.structure;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
import dorkbox.cabParser.CabException;
import dorkbox.cabParser.Checksum;
import dorkbox.cabParser.CorruptCabException;
import dorkbox.util.bytes.LittleEndian;
public final class CfDataRecord {
/** checksum of this CFDATA entry , 4bytes */
private int csum;
/** number of compressed bytes in this block , 2bytes */
public int cbData;
/** number of uncompressed bytes in this block , 2bytes */
public int cbUncomp;
private int sizeOfBlockData;
public CfDataRecord(int sizeOfBlockData) {
this.sizeOfBlockData = sizeOfBlockData;
}
public void read(InputStream input, byte[] bytes) throws IOException, CabException {
this.csum = LittleEndian.Int_.from(input); // safe to use signed here, since checksum also returns signed
this.cbData = LittleEndian.UShort_.from(input).intValue();
this.cbUncomp = LittleEndian.UShort_.from(input).intValue();
if (this.cbData > bytes.length) {
throw new CorruptCabException("Corrupt cfData record");
}
if (this.sizeOfBlockData != 0) {
input.skip(this.sizeOfBlockData);
}
int readTotal = 0;
while (readTotal < this.cbData) {
int read = input.read(bytes, readTotal, this.cbData - readTotal);
if (read < 0) {
throw new EOFException();
}
readTotal += read;
}
}
private int checksum(byte[] bytes) {
byte[] arrayOfByte = new byte[4];
arrayOfByte[0] = (byte) (this.cbData & 0xFF);
arrayOfByte[1] = (byte) (this.cbData >>> 8 & 0xFF);
arrayOfByte[2] = (byte) (this.cbUncomp & 0xFF);
arrayOfByte[3] = (byte) (this.cbUncomp >>> 8 & 0xFF);
return Checksum.calculate(bytes, this.cbData, Checksum.calculate(arrayOfByte, 4, 0));
}
public boolean validateCheckSum(byte[] bytesToCheck) {
return checksum(bytesToCheck) == this.csum;
}
}
Loading…
Cancel
Save