parent
6a000298f7
commit
0d195db7d2
@ -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=""hardware driver" "MmMapIoSpace,ZwMapViewOfSection"" />
|
||||||
|
<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…
Reference in new issue