added failing repo
diff --git a/tests/resources/issue_3020/.cproject b/tests/resources/issue_3020/.cproject new file mode 100644 index 0000000..31be124 --- /dev/null +++ b/tests/resources/issue_3020/.cproject
@@ -0,0 +1,145 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> + <storageModule moduleId="org.eclipse.cdt.core.settings"> + <cconfiguration id="cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575" moduleId="org.eclipse.cdt.core.settings" name="Debug"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.debug" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575" name="Debug" parent="cdt.managedbuild.config.gnu.mingw.exe.debug" prebuildStep="windres --language 0x0C09 ../resource.rc -o resource.o"> + <folderInfo id="cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575." name="/" resourcePath=""> + <toolChain id="cdt.managedbuild.toolchain.gnu.mingw.exe.debug.1212365933" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.exe.debug"> + <targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.exe.debug.441467939" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.exe.debug"/> + <builder buildPath="${workspace_loc:/HashCheck}/Debug" id="cdt.managedbuild.tool.gnu.builder.mingw.base.314434993" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="CDT Internal Builder" superClass="cdt.managedbuild.tool.gnu.builder.mingw.base"/> + <tool id="cdt.managedbuild.tool.gnu.assembler.mingw.exe.debug.399759892" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.exe.debug"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.128467239" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.964797068" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.exe.debug.577493578" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.exe.debug"> + <option id="gnu.cpp.compiler.mingw.exe.debug.option.optimization.level.1572524904" name="Optimization Level" superClass="gnu.cpp.compiler.mingw.exe.debug.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.none" valueType="enumerated"/> + <option id="gnu.cpp.compiler.mingw.exe.debug.option.debugging.level.1751158473" name="Debug Level" superClass="gnu.cpp.compiler.mingw.exe.debug.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.max" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.dialect.std.261474219" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" value="gnu.cpp.compiler.dialect.c++11" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.preprocessor.def.426458244" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" valueType="definedSymbols"> + <listOptionValue builtIn="false" value="WINVER=0x0500"/> + <listOptionValue builtIn="false" value="UNICODE"/> + <listOptionValue builtIn="false" value="_UNICODE"/> + </option> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.999351736" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.compiler.mingw.exe.debug.190088868" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.mingw.exe.debug"> + <option defaultValue="gnu.c.optimization.level.none" id="gnu.c.compiler.mingw.exe.debug.option.optimization.level.2111319354" name="Optimization Level" superClass="gnu.c.compiler.mingw.exe.debug.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/> + <option id="gnu.c.compiler.mingw.exe.debug.option.debugging.level.1477168937" name="Debug Level" superClass="gnu.c.compiler.mingw.exe.debug.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.max" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.2145578564" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.linker.mingw.exe.debug.223724342" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.exe.debug"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.exe.debug.778390294" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.exe.debug"> + <option id="gnu.cpp.link.option.flags.1379394346" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-static -mwindows" valueType="string"/> + <option id="gnu.cpp.link.option.userobjs.1507009136" name="Other objects" superClass="gnu.cpp.link.option.userobjs" valueType="userObjs"> + <listOptionValue builtIn="false" value="Debug\resource.o"/> + </option> + <option id="gnu.cpp.link.option.libs.109316457" name="Libraries (-l)" superClass="gnu.cpp.link.option.libs" valueType="libs"> + <listOptionValue builtIn="false" value="comctl32"/> + <listOptionValue builtIn="false" value="ole32"/> + </option> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.1851156384" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + <cconfiguration id="cdt.managedbuild.config.gnu.mingw.exe.release.107885674"> + <storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="cdt.managedbuild.config.gnu.mingw.exe.release.107885674" moduleId="org.eclipse.cdt.core.settings" name="Release"> + <externalSettings/> + <extensions> + <extension id="org.eclipse.cdt.core.PE" point="org.eclipse.cdt.core.BinaryParser"/> + <extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + <extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> + </extensions> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <configuration artifactName="${ProjName}" buildArtefactType="org.eclipse.cdt.build.core.buildArtefactType.exe" buildProperties="org.eclipse.cdt.build.core.buildArtefactType=org.eclipse.cdt.build.core.buildArtefactType.exe,org.eclipse.cdt.build.core.buildType=org.eclipse.cdt.build.core.buildType.release" cleanCommand="rm -rf" description="" id="cdt.managedbuild.config.gnu.mingw.exe.release.107885674" name="Release" parent="cdt.managedbuild.config.gnu.mingw.exe.release" postbuildStep="../Tools/upx -9 HashCheck.exe" prebuildStep="windres --language 0x0C09 ../resource.rc -o resource.o"> + <folderInfo id="cdt.managedbuild.config.gnu.mingw.exe.release.107885674." name="/" resourcePath=""> + <toolChain id="cdt.managedbuild.toolchain.gnu.mingw.exe.release.730226646" name="MinGW GCC" superClass="cdt.managedbuild.toolchain.gnu.mingw.exe.release"> + <targetPlatform id="cdt.managedbuild.target.gnu.platform.mingw.exe.release.550680648" name="Debug Platform" superClass="cdt.managedbuild.target.gnu.platform.mingw.exe.release"/> + <builder buildPath="${workspace_loc:/HashCheck}/Release" id="cdt.managedbuild.tool.gnu.builder.mingw.base.1824334986" keepEnvironmentInBuildfile="false" managedBuildOn="true" name="CDT Internal Builder" superClass="cdt.managedbuild.tool.gnu.builder.mingw.base"/> + <tool id="cdt.managedbuild.tool.gnu.assembler.mingw.exe.release.690093994" name="GCC Assembler" superClass="cdt.managedbuild.tool.gnu.assembler.mingw.exe.release"> + <inputType id="cdt.managedbuild.tool.gnu.assembler.input.1352127665" superClass="cdt.managedbuild.tool.gnu.assembler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.archiver.mingw.base.1854173426" name="GCC Archiver" superClass="cdt.managedbuild.tool.gnu.archiver.mingw.base"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.exe.release.420350693" name="GCC C++ Compiler" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.mingw.exe.release"> + <option id="gnu.cpp.compiler.mingw.exe.release.option.optimization.level.1631452254" name="Optimization Level" superClass="gnu.cpp.compiler.mingw.exe.release.option.optimization.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.optimization.level.most" valueType="enumerated"/> + <option id="gnu.cpp.compiler.mingw.exe.release.option.debugging.level.1439656061" name="Debug Level" superClass="gnu.cpp.compiler.mingw.exe.release.option.debugging.level" useByScannerDiscovery="false" value="gnu.cpp.compiler.debugging.level.none" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.preprocessor.def.404719786" name="Defined symbols (-D)" superClass="gnu.cpp.compiler.option.preprocessor.def" useByScannerDiscovery="false" valueType="definedSymbols"> + <listOptionValue builtIn="false" value="WINVER=0x0500"/> + <listOptionValue builtIn="false" value="UNICODE"/> + <listOptionValue builtIn="false" value="_UNICODE"/> + </option> + <option id="gnu.cpp.compiler.option.dialect.std.1173067960" name="Language standard" superClass="gnu.cpp.compiler.option.dialect.std" useByScannerDiscovery="true" value="gnu.cpp.compiler.dialect.c++11" valueType="enumerated"/> + <option id="gnu.cpp.compiler.option.other.other.1902866398" name="Other flags" superClass="gnu.cpp.compiler.option.other.other" useByScannerDiscovery="false" value="-c -fmessage-length=0" valueType="string"/> + <inputType id="cdt.managedbuild.tool.gnu.cpp.compiler.input.1293697913" superClass="cdt.managedbuild.tool.gnu.cpp.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.compiler.mingw.exe.release.685010761" name="GCC C Compiler" superClass="cdt.managedbuild.tool.gnu.c.compiler.mingw.exe.release"> + <option defaultValue="gnu.c.optimization.level.most" id="gnu.c.compiler.mingw.exe.release.option.optimization.level.61395149" name="Optimization Level" superClass="gnu.c.compiler.mingw.exe.release.option.optimization.level" useByScannerDiscovery="false" valueType="enumerated"/> + <option id="gnu.c.compiler.mingw.exe.release.option.debugging.level.953333000" name="Debug Level" superClass="gnu.c.compiler.mingw.exe.release.option.debugging.level" useByScannerDiscovery="false" value="gnu.c.debugging.level.none" valueType="enumerated"/> + <inputType id="cdt.managedbuild.tool.gnu.c.compiler.input.998887372" superClass="cdt.managedbuild.tool.gnu.c.compiler.input"/> + </tool> + <tool id="cdt.managedbuild.tool.gnu.c.linker.mingw.exe.release.221308893" name="MinGW C Linker" superClass="cdt.managedbuild.tool.gnu.c.linker.mingw.exe.release"/> + <tool id="cdt.managedbuild.tool.gnu.cpp.linker.mingw.exe.release.1671425636" name="MinGW C++ Linker" superClass="cdt.managedbuild.tool.gnu.cpp.linker.mingw.exe.release"> + <option id="gnu.cpp.link.option.flags.2092716378" name="Linker flags" superClass="gnu.cpp.link.option.flags" value="-static -mwindows" valueType="string"/> + <option id="gnu.cpp.link.option.userobjs.1119100108" name="Other objects" superClass="gnu.cpp.link.option.userobjs" valueType="userObjs"> + <listOptionValue builtIn="false" value=""Release\resource.o""/> + </option> + <option id="gnu.cpp.link.option.strip.1903154219" name="Omit all symbol information (-s)" superClass="gnu.cpp.link.option.strip" value="true" valueType="boolean"/> + <inputType id="cdt.managedbuild.tool.gnu.cpp.linker.input.206988463" superClass="cdt.managedbuild.tool.gnu.cpp.linker.input"> + <additionalInput kind="additionalinputdependency" paths="$(USER_OBJS)"/> + <additionalInput kind="additionalinput" paths="$(LIBS)"/> + </inputType> + </tool> + </toolChain> + </folderInfo> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> + </cconfiguration> + </storageModule> + <storageModule moduleId="cdtBuildSystem" version="4.0.0"> + <project id="HashCheck.cdt.managedbuild.target.gnu.mingw.exe.1855875242" name="Executable" projectType="cdt.managedbuild.target.gnu.mingw.exe"/> + </storageModule> + <storageModule moduleId="scannerConfiguration"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575;cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.exe.debug.577493578;cdt.managedbuild.tool.gnu.cpp.compiler.input.999351736"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575;cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575.;cdt.managedbuild.tool.gnu.c.compiler.mingw.exe.debug.190088868;cdt.managedbuild.tool.gnu.c.compiler.input.2145578564"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.exe.release.107885674;cdt.managedbuild.config.gnu.mingw.exe.release.107885674.;cdt.managedbuild.tool.gnu.cpp.compiler.mingw.exe.release.420350693;cdt.managedbuild.tool.gnu.cpp.compiler.input.1293697913"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + <scannerConfigBuildInfo instanceId="cdt.managedbuild.config.gnu.mingw.exe.release.107885674;cdt.managedbuild.config.gnu.mingw.exe.release.107885674.;cdt.managedbuild.tool.gnu.c.compiler.mingw.exe.release.685010761;cdt.managedbuild.tool.gnu.c.compiler.input.998887372"> + <autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> + </scannerConfigBuildInfo> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> + <storageModule moduleId="refreshScope" versionNumber="2"> + <configuration configurationName="Debug"> + <resource resourceType="PROJECT" workspacePath="/HashCheck"/> + </configuration> + <configuration configurationName="Release"> + <resource resourceType="PROJECT" workspacePath="/HashCheck"/> + </configuration> + </storageModule> + <storageModule moduleId="org.eclipse.cdt.internal.ui.text.commentOwnerProjectMappings"/> +</cproject>
diff --git a/tests/resources/issue_3020/.gitignore b/tests/resources/issue_3020/.gitignore new file mode 100644 index 0000000..0bec05e --- /dev/null +++ b/tests/resources/issue_3020/.gitignore
@@ -0,0 +1,10 @@ +/Release/ +/Debug/ +/Test/ +*.user +*.suo +*.sdf +*.opensdf +*.aps +checksum.* +scratch.txt
diff --git a/tests/resources/issue_3020/.gitted/FETCH_HEAD b/tests/resources/issue_3020/.gitted/FETCH_HEAD new file mode 100644 index 0000000..fad9a6c --- /dev/null +++ b/tests/resources/issue_3020/.gitted/FETCH_HEAD
@@ -0,0 +1 @@ +77e8039fba38e532bea5fba5f4f3be9940ea521b branch 'master' of https://github.com/macote/HashCheck
diff --git a/tests/resources/issue_3020/.gitted/HEAD b/tests/resources/issue_3020/.gitted/HEAD new file mode 100644 index 0000000..cb089cd --- /dev/null +++ b/tests/resources/issue_3020/.gitted/HEAD
@@ -0,0 +1 @@ +ref: refs/heads/master
diff --git a/tests/resources/issue_3020/.gitted/config b/tests/resources/issue_3020/.gitted/config new file mode 100644 index 0000000..5d565d2 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/config
@@ -0,0 +1,8 @@ +[core] + repositoryformatversion = 0 + filemode = false + bare = false + logallrefupdates = true + symlinks = false + ignorecase = true + hideDotFiles = dotGitOnly \ No newline at end of file
diff --git a/tests/resources/issue_3020/.gitted/description b/tests/resources/issue_3020/.gitted/description new file mode 100644 index 0000000..498b267 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/description
@@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository.
diff --git a/tests/resources/issue_3020/.gitted/hooks/applypatch-msg.sample b/tests/resources/issue_3020/.gitted/hooks/applypatch-msg.sample new file mode 100644 index 0000000..8b2a2fe --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/applypatch-msg.sample
@@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +:
diff --git a/tests/resources/issue_3020/.gitted/hooks/commit-msg.sample b/tests/resources/issue_3020/.gitted/hooks/commit-msg.sample new file mode 100644 index 0000000..b58d118 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/commit-msg.sample
@@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +}
diff --git a/tests/resources/issue_3020/.gitted/hooks/post-update.sample b/tests/resources/issue_3020/.gitted/hooks/post-update.sample new file mode 100644 index 0000000..ec17ec1 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/post-update.sample
@@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info
diff --git a/tests/resources/issue_3020/.gitted/hooks/pre-applypatch.sample b/tests/resources/issue_3020/.gitted/hooks/pre-applypatch.sample new file mode 100644 index 0000000..b1f187c --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/pre-applypatch.sample
@@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +:
diff --git a/tests/resources/issue_3020/.gitted/hooks/pre-commit.sample b/tests/resources/issue_3020/.gitted/hooks/pre-commit.sample new file mode 100644 index 0000000..68d62d5 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/pre-commit.sample
@@ -0,0 +1,49 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ASCII filenames set this variable to true. +allownonascii=$(git config --bool hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ASCII filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + cat <<\EOF +Error: Attempt to add a non-ASCII file name. + +This can cause problems if you want to work with people on other platforms. + +To be portable it is advisable to rename the file. + +If you know what you are doing you can disable this check using: + + git config hooks.allownonascii true +EOF + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against --
diff --git a/tests/resources/issue_3020/.gitted/hooks/pre-push.sample b/tests/resources/issue_3020/.gitted/hooks/pre-push.sample new file mode 100644 index 0000000..1f3bceb --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/pre-push.sample
@@ -0,0 +1,54 @@ +#!/bin/sh + +# An example hook script to verify what is about to be pushed. Called by "git +# push" after it has checked the remote status, but before anything has been +# pushed. If this script exits with a non-zero status nothing will be pushed. +# +# This hook is called with the following parameters: +# +# $1 -- Name of the remote to which the push is being done +# $2 -- URL to which the push is being done +# +# If pushing without using a named remote those arguments will be equal. +# +# Information about the commits which are being pushed is supplied as lines to +# the standard input in the form: +# +# <local ref> <local sha1> <remote ref> <remote sha1> +# +# This sample shows how to prevent push of commits where the log message starts +# with "WIP" (work in progress). + +remote="$1" +url="$2" + +z40=0000000000000000000000000000000000000000 + +IFS=' ' +while read local_ref local_sha remote_ref remote_sha +do + if [ "$local_sha" = $z40 ] + then + # Handle delete + : + else + if [ "$remote_sha" = $z40 ] + then + # New branch, examine all commits + range="$local_sha" + else + # Update to existing branch, examine new commits + range="$remote_sha..$local_sha" + fi + + # Check for WIP commit + commit=`git rev-list -n 1 --grep '^WIP' "$range"` + if [ -n "$commit" ] + then + echo "Found WIP commit in $local_ref, not pushing" + exit 1 + fi + fi +done + +exit 0
diff --git a/tests/resources/issue_3020/.gitted/hooks/pre-rebase.sample b/tests/resources/issue_3020/.gitted/hooks/pre-rebase.sample new file mode 100644 index 0000000..9773ed4 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/pre-rebase.sample
@@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +exit 0 + +################################################################ + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master".
diff --git a/tests/resources/issue_3020/.gitted/hooks/prepare-commit-msg.sample b/tests/resources/issue_3020/.gitted/hooks/prepare-commit-msg.sample new file mode 100644 index 0000000..f093a02 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/prepare-commit-msg.sample
@@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1"
diff --git a/tests/resources/issue_3020/.gitted/hooks/update.sample b/tests/resources/issue_3020/.gitted/hooks/update.sample new file mode 100644 index 0000000..d847583 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/hooks/update.sample
@@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0
diff --git a/tests/resources/issue_3020/.gitted/index b/tests/resources/issue_3020/.gitted/index new file mode 100644 index 0000000..a66a2de --- /dev/null +++ b/tests/resources/issue_3020/.gitted/index Binary files differ
diff --git a/tests/resources/issue_3020/.gitted/info/exclude b/tests/resources/issue_3020/.gitted/info/exclude new file mode 100644 index 0000000..a5196d1 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/info/exclude
@@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~
diff --git a/tests/resources/issue_3020/.gitted/logs/HEAD b/tests/resources/issue_3020/.gitted/logs/HEAD new file mode 100644 index 0000000..9ea36cf --- /dev/null +++ b/tests/resources/issue_3020/.gitted/logs/HEAD
@@ -0,0 +1 @@ +0000000000000000000000000000000000000000 77e8039fba38e532bea5fba5f4f3be9940ea521b Brendan Forster <brendan@github.com> 1427606421 +0200 clone: from https://github.com/macote/HashCheck.git
diff --git a/tests/resources/issue_3020/.gitted/logs/refs/heads/master b/tests/resources/issue_3020/.gitted/logs/refs/heads/master new file mode 100644 index 0000000..9ea36cf --- /dev/null +++ b/tests/resources/issue_3020/.gitted/logs/refs/heads/master
@@ -0,0 +1 @@ +0000000000000000000000000000000000000000 77e8039fba38e532bea5fba5f4f3be9940ea521b Brendan Forster <brendan@github.com> 1427606421 +0200 clone: from https://github.com/macote/HashCheck.git
diff --git a/tests/resources/issue_3020/.gitted/logs/refs/remotes/origin/HEAD b/tests/resources/issue_3020/.gitted/logs/refs/remotes/origin/HEAD new file mode 100644 index 0000000..9ea36cf --- /dev/null +++ b/tests/resources/issue_3020/.gitted/logs/refs/remotes/origin/HEAD
@@ -0,0 +1 @@ +0000000000000000000000000000000000000000 77e8039fba38e532bea5fba5f4f3be9940ea521b Brendan Forster <brendan@github.com> 1427606421 +0200 clone: from https://github.com/macote/HashCheck.git
diff --git a/tests/resources/issue_3020/.gitted/objects/07/998b2304ff33b23683b63135dc36ba9f68ac57 b/tests/resources/issue_3020/.gitted/objects/07/998b2304ff33b23683b63135dc36ba9f68ac57 new file mode 100644 index 0000000..0d5592b --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/07/998b2304ff33b23683b63135dc36ba9f68ac57
@@ -0,0 +1,2 @@ +xÁÂ0D÷ܯð±ØIÖÕ +írà?âÆ´jBúÿd?À·yÏåVÁþ£Um"ã¸)0©FÒgDYTqÝ=]+h9I°£:kDkÂ¥>YQæ0$]Øê58µT+syT-ð%/ð}¹Õë&s^@}ÛCh½¶ëm+ÿüï廿ýEW-¡j óïvWíhÉúÉø ÿOO¢V¦ \ No newline at end of file
diff --git a/tests/resources/issue_3020/.gitted/objects/3a/ea65954a4a13370a1f47df920d24cdef74cb49 b/tests/resources/issue_3020/.gitted/objects/3a/ea65954a4a13370a1f47df920d24cdef74cb49 new file mode 100644 index 0000000..841afce --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/3a/ea65954a4a13370a1f47df920d24cdef74cb49 Binary files differ
diff --git a/tests/resources/issue_3020/.gitted/objects/56/0e1db218db90db538be31f8d568465ac3362c2 b/tests/resources/issue_3020/.gitted/objects/56/0e1db218db90db538be31f8d568465ac3362c2 new file mode 100644 index 0000000..50cc0d2 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/56/0e1db218db90db538be31f8d568465ac3362c2
@@ -0,0 +1,2 @@ +xAnÃ0{ö+x/ÒiKF´9ä¢E%A`+PäÿW îrç¼,÷ +f>jQg Rð¤I#Z}L$â½Q¸{¢k qTÖ' Ö)[#¸-údE½ï±CÒ ÞrssŰÂ%WÕß²ë½Þ6ùórê[>±M×hkùÿ¿ûÝj>\uÕªF0?¶'ì± =4Hè&ÄiÜÔ¢ÖV¦ \ No newline at end of file
diff --git a/tests/resources/issue_3020/.gitted/objects/76/7dea87ec830714d0199d84deca33aee304735e b/tests/resources/issue_3020/.gitted/objects/76/7dea87ec830714d0199d84deca33aee304735e new file mode 100644 index 0000000..8ea38fa --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/76/7dea87ec830714d0199d84deca33aee304735e
@@ -0,0 +1 @@ +xÁNÄ0D9÷+|G°vR7u pà?âÆÙ]¡6«þ?YíàÛ<Íg-ÛvmàÂôÔªÌ>XyFBf,¡ÇUR&UQÓ <Übµ½A6£¬ÑÏÆÞ©Eîó½È8Ò!íR*|õT;|úÛ¬Â>ÀÇùÚ.¾®e{ûb±ßÐi_y÷ÿ/?|¼m·%иþ7xÔ.þäää0,ìîÄ?£V§ \ No newline at end of file
diff --git a/tests/resources/issue_3020/.gitted/objects/83/f1265b5801a91eed1ed030c9df1bb999beb7b5 b/tests/resources/issue_3020/.gitted/objects/83/f1265b5801a91eed1ed030c9df1bb999beb7b5 new file mode 100644 index 0000000..f86b2cd --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/83/f1265b5801a91eed1ed030c9df1bb999beb7b5 Binary files differ
diff --git a/tests/resources/issue_3020/.gitted/objects/ab/027b9968d0363df52e7b26ac68b3cd69ef4342 b/tests/resources/issue_3020/.gitted/objects/ab/027b9968d0363df52e7b26ac68b3cd69ef4342 new file mode 100644 index 0000000..6c9679f --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/ab/027b9968d0363df52e7b26ac68b3cd69ef4342 Binary files differ
diff --git a/tests/resources/issue_3020/.gitted/objects/d8/91425b7207c6685fdd97ce26ffcb3c64577d82 b/tests/resources/issue_3020/.gitted/objects/d8/91425b7207c6685fdd97ce26ffcb3c64577d82 new file mode 100644 index 0000000..5d4f54e --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/d8/91425b7207c6685fdd97ce26ffcb3c64577d82 Binary files differ
diff --git a/tests/resources/issue_3020/.gitted/objects/pack/pack-00716425456a3c9f631eae470013b68e941d6212.idx b/tests/resources/issue_3020/.gitted/objects/pack/pack-00716425456a3c9f631eae470013b68e941d6212.idx new file mode 100644 index 0000000..4594f96 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/pack/pack-00716425456a3c9f631eae470013b68e941d6212.idx Binary files differ
diff --git a/tests/resources/issue_3020/.gitted/objects/pack/pack-00716425456a3c9f631eae470013b68e941d6212.pack b/tests/resources/issue_3020/.gitted/objects/pack/pack-00716425456a3c9f631eae470013b68e941d6212.pack new file mode 100644 index 0000000..95b1765 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/objects/pack/pack-00716425456a3c9f631eae470013b68e941d6212.pack Binary files differ
diff --git a/tests/resources/issue_3020/.gitted/packed-refs b/tests/resources/issue_3020/.gitted/packed-refs new file mode 100644 index 0000000..8fa3d95 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/packed-refs
@@ -0,0 +1,2 @@ +# pack-refs with: peeled fully-peeled +77e8039fba38e532bea5fba5f4f3be9940ea521b refs/remotes/origin/master
diff --git a/tests/resources/issue_3020/.gitted/refs/heads/master b/tests/resources/issue_3020/.gitted/refs/heads/master new file mode 100644 index 0000000..4d35026 --- /dev/null +++ b/tests/resources/issue_3020/.gitted/refs/heads/master
@@ -0,0 +1 @@ +77e8039fba38e532bea5fba5f4f3be9940ea521b
diff --git a/tests/resources/issue_3020/.gitted/refs/remotes/origin/HEAD b/tests/resources/issue_3020/.gitted/refs/remotes/origin/HEAD new file mode 100644 index 0000000..6efe28f --- /dev/null +++ b/tests/resources/issue_3020/.gitted/refs/remotes/origin/HEAD
@@ -0,0 +1 @@ +ref: refs/remotes/origin/master
diff --git a/tests/resources/issue_3020/.project b/tests/resources/issue_3020/.project new file mode 100644 index 0000000..e3668ca --- /dev/null +++ b/tests/resources/issue_3020/.project
@@ -0,0 +1,74 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>HashCheck</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> + <triggers>clean,full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> + <triggers>full,incremental,</triggers> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>org.eclipse.cdt.core.cnature</nature> + <nature>org.eclipse.cdt.core.ccnature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> + <nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> + </natures> + <filteredResources> + <filter> + <id>1417569914325</id> + <name></name> + <type>6</type> + <matcher> + <id>org.eclipse.ui.ide.multiFilter</id> + <arguments>1.0-name-matches-false-false-*.sln</arguments> + </matcher> + </filter> + <filter> + <id>1417569914328</id> + <name></name> + <type>6</type> + <matcher> + <id>org.eclipse.ui.ide.multiFilter</id> + <arguments>1.0-name-matches-false-false-*.vcxproj*</arguments> + </matcher> + </filter> + <filter> + <id>1417569914330</id> + <name></name> + <type>6</type> + <matcher> + <id>org.eclipse.ui.ide.multiFilter</id> + <arguments>1.0-name-matches-false-false-*.*sdf</arguments> + </matcher> + </filter> + <filter> + <id>1417569914333</id> + <name></name> + <type>6</type> + <matcher> + <id>org.eclipse.ui.ide.multiFilter</id> + <arguments>1.0-name-matches-false-false-*.suo</arguments> + </matcher> + </filter> + <filter> + <id>1417569914338</id> + <name></name> + <type>6</type> + <matcher> + <id>org.eclipse.ui.ide.multiFilter</id> + <arguments>1.0-name-matches-false-false-checksum.*</arguments> + </matcher> + </filter> + </filteredResources> +</projectDescription>
diff --git a/tests/resources/issue_3020/.settings/language.settings.xml b/tests/resources/issue_3020/.settings/language.settings.xml new file mode 100644 index 0000000..534786b --- /dev/null +++ b/tests/resources/issue_3020/.settings/language.settings.xml
@@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<project> + <configuration id="cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575" name="Debug"> + <extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> + <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> + <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> + <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> + <provider class="org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorMinGW" console="false" env-hash="-682947582912623951" id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetectorMinGW" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings MinGW" parameter="${COMMAND} ${FLAGS} -E -P -v -dD -std=c++11 "${INPUTS}""> + <language-scope id="org.eclipse.cdt.core.gcc"/> + <language-scope id="org.eclipse.cdt.core.g++"/> + </provider> + </extension> + </configuration> + <configuration id="cdt.managedbuild.config.gnu.mingw.exe.release.107885674" name="Release"> + <extension point="org.eclipse.cdt.core.LanguageSettingsProvider"> + <provider copy-of="extension" id="org.eclipse.cdt.ui.UserLanguageSettingsProvider"/> + <provider-reference id="org.eclipse.cdt.core.ReferencedProjectsLanguageSettingsProvider" ref="shared-provider"/> + <provider-reference id="org.eclipse.cdt.managedbuilder.core.MBSLanguageSettingsProvider" ref="shared-provider"/> + <provider class="org.eclipse.cdt.managedbuilder.internal.language.settings.providers.GCCBuiltinSpecsDetectorMinGW" console="false" env-hash="-682947582912623951" id="org.eclipse.cdt.managedbuilder.core.GCCBuiltinSpecsDetectorMinGW" keep-relative-paths="false" name="CDT GCC Built-in Compiler Settings MinGW" parameter="${COMMAND} ${FLAGS} -E -P -v -dD -std=c++11 "${INPUTS}""> + <language-scope id="org.eclipse.cdt.core.gcc"/> + <language-scope id="org.eclipse.cdt.core.g++"/> + </provider> + </extension> + </configuration> +</project>
diff --git a/tests/resources/issue_3020/.settings/org.eclipse.cdt.managedbuilder.core.prefs b/tests/resources/issue_3020/.settings/org.eclipse.cdt.managedbuilder.core.prefs new file mode 100644 index 0000000..b1e46bc --- /dev/null +++ b/tests/resources/issue_3020/.settings/org.eclipse.cdt.managedbuilder.core.prefs
@@ -0,0 +1,25 @@ +eclipse.preferences.version=1 +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/CPATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/CPATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/CPLUS_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/CPLUS_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/C_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/C_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/append=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/appendContributed=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/CPATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/CPATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/CPLUS_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/CPLUS_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/C_INCLUDE_PATH/delimiter=; +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/C_INCLUDE_PATH/operation=remove +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/append=true +environment/buildEnvironmentInclude/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/appendContributed=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/LIBRARY_PATH/delimiter=; +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/LIBRARY_PATH/operation=remove +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/append=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.debug.1091074575/appendContributed=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/LIBRARY_PATH/delimiter=; +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/LIBRARY_PATH/operation=remove +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/append=true +environment/buildEnvironmentLibrary/cdt.managedbuild.config.gnu.mingw.exe.release.107885674/appendContributed=true
diff --git a/tests/resources/issue_3020/CRC32FileHash.cpp b/tests/resources/issue_3020/CRC32FileHash.cpp new file mode 100644 index 0000000..c34a275 --- /dev/null +++ b/tests/resources/issue_3020/CRC32FileHash.cpp
@@ -0,0 +1,100 @@ +/* Author: macote */ + +#include "CRC32FileHash.h" + +const UINT32 CRC32FileHash::kCRC32Table[] = { + 0x000000000L, 0x077073096L, 0x0EE0E612CL, 0x0990951BAL, + 0x0076DC419L, 0x0706AF48FL, 0x0E963A535L, 0x09E6495A3L, + 0x00EDB8832L, 0x079DCB8A4L, 0x0E0D5E91EL, 0x097D2D988L, + 0x009B64C2BL, 0x07EB17CBDL, 0x0E7B82D07L, 0x090BF1D91L, + 0x01DB71064L, 0x06AB020F2L, 0x0F3B97148L, 0x084BE41DEL, + 0x01ADAD47DL, 0x06DDDE4EBL, 0x0F4D4B551L, 0x083D385C7L, + 0x0136C9856L, 0x0646BA8C0L, 0x0FD62F97AL, 0x08A65C9ECL, + 0x014015C4FL, 0x063066CD9L, 0x0FA0F3D63L, 0x08D080DF5L, + 0x03B6E20C8L, 0x04C69105EL, 0x0D56041E4L, 0x0A2677172L, + 0x03C03E4D1L, 0x04B04D447L, 0x0D20D85FDL, 0x0A50AB56BL, + 0x035B5A8FAL, 0x042B2986CL, 0x0DBBBC9D6L, 0x0ACBCF940L, + 0x032D86CE3L, 0x045DF5C75L, 0x0DCD60DCFL, 0x0ABD13D59L, + 0x026D930ACL, 0x051DE003AL, 0x0C8D75180L, 0x0BFD06116L, + 0x021B4F4B5L, 0x056B3C423L, 0x0CFBA9599L, 0x0B8BDA50FL, + 0x02802B89EL, 0x05F058808L, 0x0C60CD9B2L, 0x0B10BE924L, + 0x02F6F7C87L, 0x058684C11L, 0x0C1611DABL, 0x0B6662D3DL, + 0x076DC4190L, 0x001DB7106L, 0x098D220BCL, 0x0EFD5102AL, + 0x071B18589L, 0x006B6B51FL, 0x09FBFE4A5L, 0x0E8B8D433L, + 0x07807C9A2L, 0x00F00F934L, 0x09609A88EL, 0x0E10E9818L, + 0x07F6A0DBBL, 0x0086D3D2DL, 0x091646C97L, 0x0E6635C01L, + 0x06B6B51F4L, 0x01C6C6162L, 0x0856530D8L, 0x0F262004EL, + 0x06C0695EDL, 0x01B01A57BL, 0x08208F4C1L, 0x0F50FC457L, + 0x065B0D9C6L, 0x012B7E950L, 0x08BBEB8EAL, 0x0FCB9887CL, + 0x062DD1DDFL, 0x015DA2D49L, 0x08CD37CF3L, 0x0FBD44C65L, + 0x04DB26158L, 0x03AB551CEL, 0x0A3BC0074L, 0x0D4BB30E2L, + 0x04ADFA541L, 0x03DD895D7L, 0x0A4D1C46DL, 0x0D3D6F4FBL, + 0x04369E96AL, 0x0346ED9FCL, 0x0AD678846L, 0x0DA60B8D0L, + 0x044042D73L, 0x033031DE5L, 0x0AA0A4C5FL, 0x0DD0D7CC9L, + 0x05005713CL, 0x0270241AAL, 0x0BE0B1010L, 0x0C90C2086L, + 0x05768B525L, 0x0206F85B3L, 0x0B966D409L, 0x0CE61E49FL, + 0x05EDEF90EL, 0x029D9C998L, 0x0B0D09822L, 0x0C7D7A8B4L, + 0x059B33D17L, 0x02EB40D81L, 0x0B7BD5C3BL, 0x0C0BA6CADL, + 0x0EDB88320L, 0x09ABFB3B6L, 0x003B6E20CL, 0x074B1D29AL, + 0x0EAD54739L, 0x09DD277AFL, 0x004DB2615L, 0x073DC1683L, + 0x0E3630B12L, 0x094643B84L, 0x00D6D6A3EL, 0x07A6A5AA8L, + 0x0E40ECF0BL, 0x09309FF9DL, 0x00A00AE27L, 0x07D079EB1L, + 0x0F00F9344L, 0x08708A3D2L, 0x01E01F268L, 0x06906C2FEL, + 0x0F762575DL, 0x0806567CBL, 0x0196C3671L, 0x06E6B06E7L, + 0x0FED41B76L, 0x089D32BE0L, 0x010DA7A5AL, 0x067DD4ACCL, + 0x0F9B9DF6FL, 0x08EBEEFF9L, 0x017B7BE43L, 0x060B08ED5L, + 0x0D6D6A3E8L, 0x0A1D1937EL, 0x038D8C2C4L, 0x04FDFF252L, + 0x0D1BB67F1L, 0x0A6BC5767L, 0x03FB506DDL, 0x048B2364BL, + 0x0D80D2BDAL, 0x0AF0A1B4CL, 0x036034AF6L, 0x041047A60L, + 0x0DF60EFC3L, 0x0A867DF55L, 0x0316E8EEFL, 0x04669BE79L, + 0x0CB61B38CL, 0x0BC66831AL, 0x0256FD2A0L, 0x05268E236L, + 0x0CC0C7795L, 0x0BB0B4703L, 0x0220216B9L, 0x05505262FL, + 0x0C5BA3BBEL, 0x0B2BD0B28L, 0x02BB45A92L, 0x05CB36A04L, + 0x0C2D7FFA7L, 0x0B5D0CF31L, 0x02CD99E8BL, 0x05BDEAE1DL, + 0x09B64C2B0L, 0x0EC63F226L, 0x0756AA39CL, 0x0026D930AL, + 0x09C0906A9L, 0x0EB0E363FL, 0x072076785L, 0x005005713L, + 0x095BF4A82L, 0x0E2B87A14L, 0x07BB12BAEL, 0x00CB61B38L, + 0x092D28E9BL, 0x0E5D5BE0DL, 0x07CDCEFB7L, 0x00BDBDF21L, + 0x086D3D2D4L, 0x0F1D4E242L, 0x068DDB3F8L, 0x01FDA836EL, + 0x081BE16CDL, 0x0F6B9265BL, 0x06FB077E1L, 0x018B74777L, + 0x088085AE6L, 0x0FF0F6A70L, 0x066063BCAL, 0x011010B5CL, + 0x08F659EFFL, 0x0F862AE69L, 0x0616BFFD3L, 0x0166CCF45L, + 0x0A00AE278L, 0x0D70DD2EEL, 0x04E048354L, 0x03903B3C2L, + 0x0A7672661L, 0x0D06016F7L, 0x04969474DL, 0x03E6E77DBL, + 0x0AED16A4AL, 0x0D9D65ADCL, 0x040DF0B66L, 0x037D83BF0L, + 0x0A9BCAE53L, 0x0DEBB9EC5L, 0x047B2CF7FL, 0x030B5FFE9L, + 0x0BDBDF21CL, 0x0CABAC28AL, 0x053B39330L, 0x024B4A3A6L, + 0x0BAD03605L, 0x0CDD70693L, 0x054DE5729L, 0x023D967BFL, + 0x0B3667A2EL, 0x0C4614AB8L, 0x05D681B02L, 0x02A6F2B94L, + 0x0B40BBE37L, 0x0C30C8EA1L, 0x05A05DF1BL, 0x02D02EF8DL +}; + +void CRC32FileHash::Initialize() +{ + hash_ = 0; + hash_ = ~hash_; +} + +void CRC32FileHash::Update(const UINT32 bytecount) +{ + PBYTE buffer = buffer_; + UINT32 bytesleft = bytecount; + while (bytesleft > 0) + { + hash_ = kCRC32Table[(hash_ ^ *buffer) & 0xFF] ^ (hash_ >> 8); + ++buffer; + --bytesleft; + } +} + +void CRC32FileHash::Finalize() +{ + hash_ = ~hash_; +} + +void CRC32FileHash::ConvertHashToDigestString() +{ + std::wstringstream wss; + wss << std::hex << std::setw(8) << std::setfill(L'0') << std::uppercase << hash_; + digest_.append(wss.str()); +}
diff --git a/tests/resources/issue_3020/CRC32FileHash.h b/tests/resources/issue_3020/CRC32FileHash.h new file mode 100644 index 0000000..37fe12c --- /dev/null +++ b/tests/resources/issue_3020/CRC32FileHash.h
@@ -0,0 +1,30 @@ +/* Author: macote */ + +#ifndef CRC32FILEHASH_H_ +#define CRC32FILEHASH_H_ + +#include "FileHash.h" +#include <iomanip> +#include <sstream> +#include <string> +#include <Windows.h> + +class CRC32FileHash : public FileHash +{ +public: +#if _MSC_VER < 1900 + CRC32FileHash(const std::wstring& filepath, const DWORD buffersize) : FileHash(filepath, buffersize) { }; + CRC32FileHash(const std::wstring& filepath) : FileHash(filepath) { }; +#else + using FileHash::FileHash; +#endif +private: + void Initialize(); + void Update(const UINT32 bytecount); + void Finalize(); + void ConvertHashToDigestString(); + const static UINT32 kCRC32Table[]; + UINT32 hash_; +}; + +#endif /* CRC32FILEHASH_H_ */
diff --git a/tests/resources/issue_3020/FileHash.cpp b/tests/resources/issue_3020/FileHash.cpp new file mode 100644 index 0000000..9f6d70c --- /dev/null +++ b/tests/resources/issue_3020/FileHash.cpp
@@ -0,0 +1,49 @@ +/* Author: macote */ + +#include "FileHash.h" + +void FileHash::AllocateBuffer() +{ + buffer_ = (PBYTE)VirtualAlloc(NULL, buffersize_, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +} + +void FileHash::FreeBuffer() +{ + if (buffer_ != NULL) + { + VirtualFree(buffer_, 0, MEM_RELEASE); + } +} + +void FileHash::Compute() +{ + Initialize(); + DWORD bytesread = 0; + FileHashBytesProcessedEventArgs fhbpea; + fhbpea.bytesprocessed.QuadPart = 0; + DWORD runningnotificationblocksize = 0; + do + { + bytesread = filestream_.Read(buffer_, buffersize_); + if (bytesread > 0) + { + Update(bytesread); + } + if (bytesprocessedevent_ != nullptr) + { + fhbpea.bytesprocessed.QuadPart += bytesread; + runningnotificationblocksize += bytesread; + if (runningnotificationblocksize >= bytesprocessednotificationblocksize_ || bytesread == 0) + { + if (bytesread > 0) + { + runningnotificationblocksize -= bytesprocessednotificationblocksize_; + } + bytesprocessedevent_(fhbpea); + } + } + } + while (bytesread > 0); + Finalize(); + ConvertHashToDigestString(); +}
diff --git a/tests/resources/issue_3020/FileHash.h b/tests/resources/issue_3020/FileHash.h new file mode 100644 index 0000000..4867dd9 --- /dev/null +++ b/tests/resources/issue_3020/FileHash.h
@@ -0,0 +1,61 @@ +/* Author: macote */ + +#ifndef FILEHASH_H_ +#define FILEHASH_H_ + +#include "FileStream.h" +#include <string> +#include <functional> +#include <Windows.h> + +struct FileHashBytesProcessedEventArgs +{ + LARGE_INTEGER bytesprocessed; +}; + +class FileHash +{ +public: + static const DWORD kDefaultBufferSize = 32768; + static const DWORD kDefaultBytesProcessedNotificationBlockSize = 1048576; +public: + FileHash(const std::wstring& filepath) : FileHash(filepath, kDefaultBufferSize) { }; + FileHash(const std::wstring& filepath, const DWORD buffersize) + : buffersize_(buffersize), filestream_(FileStream(filepath, FileStream::Mode::OpenNoBuffering, buffersize)) + { + bytesprocessedevent_ = nullptr; + AllocateBuffer(); + } + virtual ~FileHash() + { + FreeBuffer(); + }; + void Compute(); + std::wstring digest() const { return digest_; } + void SetBytesProcessedEventHandler(std::function<void(FileHashBytesProcessedEventArgs)> handler) + { + SetBytesProcessedEventHandler(handler, kDefaultBytesProcessedNotificationBlockSize); + } + void SetBytesProcessedEventHandler(std::function<void(FileHashBytesProcessedEventArgs)> handler, + const DWORD bytesprocessednotificationblocksize) + { + bytesprocessedevent_ = handler; + bytesprocessednotificationblocksize_ = bytesprocessednotificationblocksize; + } +protected: + virtual void Initialize() = 0; + virtual void Update(const UINT32 bytes) = 0; + virtual void Finalize() = 0; + virtual void ConvertHashToDigestString() = 0; + PBYTE buffer_ = NULL; + std::wstring digest_; +private: + void AllocateBuffer(); + void FreeBuffer(); + DWORD buffersize_; + FileStream filestream_; + DWORD bytesprocessednotificationblocksize_; + std::function<void(FileHashBytesProcessedEventArgs)> bytesprocessedevent_; +}; + +#endif /* FILEHASH_H_ */
diff --git a/tests/resources/issue_3020/FileHashFactory.h b/tests/resources/issue_3020/FileHashFactory.h new file mode 100644 index 0000000..90bd27b --- /dev/null +++ b/tests/resources/issue_3020/FileHashFactory.h
@@ -0,0 +1,42 @@ +/* Author: macote */ + +#ifndef FILEHASHFACTORY_H_ +#define FILEHASHFACTORY_H_ + +#include "FileHash.h" +#include "HashType.h" +#include "CRC32FileHash.h" +#include "MD5FileHash.h" +#include "SHA1FileHash.h" +#include <string> +#include <memory> +#include <Windows.h> + +class FileHashFactory +{ +public: + static std::unique_ptr<FileHash> Create(HashType hashtype, const std::wstring& filepath) + { + if (hashtype == HashType::SHA1) + { + //return std::make_unique<SHA1FileHash>(filepath); + return std::unique_ptr<SHA1FileHash>(new SHA1FileHash(filepath)); + } + else if (hashtype == HashType::MD5) + { + //return std::make_unique<MD5FileHash>(filepath); + return std::unique_ptr<MD5FileHash>(new MD5FileHash(filepath)); + } + else if (hashtype == HashType::CRC32) + { + //return std::make_unique<CRC32FileHash>(filepath); + return std::unique_ptr<CRC32FileHash>(new CRC32FileHash(filepath)); + } + else + { + throw std::runtime_error("FileHashFactory.Create(): selected hash type is not supported."); + } + }; +}; + +#endif /* FILEHASHFACTORY_H_ */
diff --git a/tests/resources/issue_3020/FileStream.cpp b/tests/resources/issue_3020/FileStream.cpp new file mode 100644 index 0000000..a92e09a --- /dev/null +++ b/tests/resources/issue_3020/FileStream.cpp
@@ -0,0 +1,184 @@ +/* Author: macote */ +/* Portions of this code was inspired by dotnet/corefx's Win32FileStream.cs */ +/* + +The MIT License (MIT) + +Copyright (c) Microsoft Corporation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +*/ + +#include "FileStream.h" + +void FileStream::AllocateBuffer() +{ + buffer_ = (PBYTE)VirtualAlloc(NULL, buffersize_, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +} + +void FileStream::FreeBuffer() +{ + if (buffer_ != NULL) + { + VirtualFree(buffer_, 0, MEM_RELEASE); + } +} + +void FileStream::OpenFile() +{ + DWORD desiredaccess = (mode_ >= Mode::Create) ? GENERIC_WRITE : GENERIC_READ; + DWORD createdisposition; + switch (mode_) + { + case FileStream::Mode::Create: + createdisposition = CREATE_NEW; + break; + case FileStream::Mode::Truncate: + createdisposition = CREATE_ALWAYS; + break; + default: + createdisposition = OPEN_EXISTING; + break; + } + DWORD flagsandattributes = FILE_ATTRIBUTE_NORMAL; + if (mode_ == Mode::OpenNoBuffering) + { + flagsandattributes |= FILE_FLAG_NO_BUFFERING; + } + filehandle_ = CreateFileW(filepath_.c_str(), desiredaccess, FILE_SHARE_READ, + NULL, createdisposition, flagsandattributes, NULL); + if (filehandle_ == INVALID_HANDLE_VALUE) + { + std::stringstream ss; + ss << "FileStream.Open(CreateFileW()) failed with error "; + ss << "0x" << std::hex << std::setw(8) << std::setfill('0') << std::uppercase; + ss << GetLastError(); + throw std::runtime_error(ss.str()); + } +} + +DWORD FileStream::Read(PBYTE buffer, DWORD offset, DWORD count) +{ + DWORD bytesread = 0; + ReadFile(filehandle_, buffer + offset, count, &bytesread, NULL); + return bytesread; +} + +DWORD FileStream::Write(PBYTE buffer, DWORD offset, DWORD count) +{ + DWORD byteswritten = 0; + WriteFile(filehandle_, buffer + offset, count, &byteswritten, NULL); + return byteswritten; +} + +void FileStream::FlushWrite() +{ + Write(buffer_, 0, writeindex_); + writeindex_ = 0; +} + +void FileStream::CloseFile() +{ + if (filehandle_ != INVALID_HANDLE_VALUE) + { + CloseHandle(filehandle_); + filehandle_ = INVALID_HANDLE_VALUE; + } +} + +DWORD FileStream::Read(PBYTE buffer, DWORD count) +{ + DWORD bufferbytes = readlength_ - readindex_; + BOOL eof = FALSE; + if (bufferbytes == 0) + { + DWORD bytesread; + if (count >= buffersize_) + { + bytesread = Read(buffer, 0, count); + readindex_ = readlength_ = 0; + return bytesread; + } + bytesread = Read(buffer_, 0, buffersize_); + if (bytesread == 0) return 0; + readindex_ = 0; + readlength_ = bufferbytes = bytesread; + eof = bytesread < buffersize_; + } + if (bufferbytes > count) + { + bufferbytes = count; + } + CopyMemory(buffer, buffer_ + readindex_, bufferbytes); + readindex_ += bufferbytes; + if (bufferbytes < count && !eof) + { + DWORD bytesread = Read(buffer, bufferbytes, count - bufferbytes); + bufferbytes += bytesread; + readindex_ = readlength_ = 0; + } + return bufferbytes; +} + +void FileStream::Write(PBYTE buffer, DWORD count) +{ + DWORD bufferindex = 0; + if (writeindex_ > 0) + { + DWORD bufferbytes = buffersize_ - writeindex_; + if (bufferbytes > 0) + { + if (bufferbytes > count) + { + bufferbytes = count; + } + CopyMemory(buffer_ + writeindex_, buffer, bufferbytes); + writeindex_ += bufferbytes; + if (bufferbytes == count) return; + bufferindex = bufferbytes; + count -= bufferbytes; + } + Write(buffer_, 0, writeindex_); + writeindex_ = 0; + } + if (count >= buffersize_) + { + Write(buffer, 0, count); + } + else if (count > 0) + { + CopyMemory(buffer_ + writeindex_, buffer + bufferindex, count); + writeindex_ = count; + } +} + +void FileStream::Flush() +{ + if (writeindex_ > 0) + { + FlushWrite(); + } +} + +void FileStream::Close() +{ + Flush(); + CloseFile(); +}
diff --git a/tests/resources/issue_3020/FileStream.h b/tests/resources/issue_3020/FileStream.h new file mode 100644 index 0000000..baf8c29 --- /dev/null +++ b/tests/resources/issue_3020/FileStream.h
@@ -0,0 +1,61 @@ +/* Author: macote */ + +#ifndef FILESTREAM_H_ +#define FILESTREAM_H_ + +#include <iomanip> +#include <sstream> +#include <stdexcept> +#include <string> +#include <Windows.h> + +class FileStream +{ +public: + static const DWORD kDefaultBufferSize = 32768; +public: + enum class Mode + { + Open, + OpenNoBuffering, + Create, + Truncate, + Append + }; + FileStream(const std::wstring& filepath, Mode mode) : FileStream(filepath, mode, kDefaultBufferSize) { }; + FileStream(const std::wstring& filepath, Mode mode, const DWORD buffersize) : filepath_(filepath), mode_(mode), buffersize_(buffersize) + { + AllocateBuffer(); + OpenFile(); + }; + virtual ~FileStream() + { + Flush(); + CloseFile(); + FreeBuffer(); + }; + DWORD Read(PBYTE buffer, DWORD count); + void Write(PBYTE buffer, DWORD count); + void Flush(); + void Close(); + DWORD lasterror() const { return lasterror_; } +private: + void AllocateBuffer(); + void OpenFile(); + DWORD Read(PBYTE buffer, DWORD offset, DWORD count); + DWORD Write(PBYTE buffer, DWORD offset, DWORD count); + void FlushWrite(); + void CloseFile(); + void FreeBuffer(); + DWORD readindex_ = 0; + DWORD readlength_ = 0; + DWORD writeindex_ = 0; + PBYTE buffer_ = NULL; + const std::wstring filepath_; + Mode mode_; + const DWORD buffersize_; + HANDLE filehandle_ = NULL; + DWORD lasterror_ = 0; +}; + +#endif /* FILESTREAM_H_ */
diff --git a/tests/resources/issue_3020/FileTree.cpp b/tests/resources/issue_3020/FileTree.cpp new file mode 100644 index 0000000..85e5021 --- /dev/null +++ b/tests/resources/issue_3020/FileTree.cpp
@@ -0,0 +1,31 @@ +/* Author: macote */ + +#include "FileTree.h" + +void FileTree::ProcessTree(const std::wstring& path) const +{ + WIN32_FIND_DATAW findfiledata; + HANDLE hFind; + std::wstring pattern = path + L"*"; + hFind = FindFirstFileW(pattern.c_str(), &findfiledata); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + if (findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + if (lstrcmpW(findfiledata.cFileName, L".") != 0 && lstrcmpW(findfiledata.cFileName, L"..") != 0) + { + std::wstring currentpath(path + findfiledata.cFileName + L"\\"); + ProcessTree(currentpath); + } + } + else + { + std::wstring currentfile(path + findfiledata.cFileName); + fileaction_.ProcessFile(currentfile); + } + } while (FindNextFileW(hFind, &findfiledata)); + FindClose(hFind); + } +}
diff --git a/tests/resources/issue_3020/FileTree.h b/tests/resources/issue_3020/FileTree.h new file mode 100644 index 0000000..48b7781 --- /dev/null +++ b/tests/resources/issue_3020/FileTree.h
@@ -0,0 +1,30 @@ +/* Author: macote */ + +#ifndef FILETREE_H_ +#define FILETREE_H_ + +#include <string> +#include <Windows.h> + +class IFileTreeAction +{ +public: + virtual ~IFileTreeAction() { } + virtual void ProcessFile(const std::wstring& filepath) = 0; +}; + +class FileTree +{ +public: + FileTree(const std::wstring basepath, IFileTreeAction& fileaction) : basepath_(basepath), fileaction_(fileaction) { }; + void Process() const + { + ProcessTree(basepath_); + } +private: + void ProcessTree(const std::wstring& path) const; + const std::wstring basepath_; + IFileTreeAction& fileaction_; +}; + +#endif /* FILETREE_H_ */
diff --git a/tests/resources/issue_3020/HashCheck.cpp b/tests/resources/issue_3020/HashCheck.cpp new file mode 100644 index 0000000..9edc029 --- /dev/null +++ b/tests/resources/issue_3020/HashCheck.cpp
@@ -0,0 +1,259 @@ +/* Author: macote */ + +#include "HashCheck.h" + +LPCWSTR HashCheck::kHashFileBaseName = L"checksum"; + +void HashCheck::Initialize() +{ + silent_ = checking_ = updating_ = skipcheck_ = FALSE; + hashtype_ = HashType::Undefined; + appfilename_ = GetAppFileName(args_[0].c_str()); + + args_.erase(args_.begin()); + if (args_.size() > 0) + { + std::vector<std::wstring>::iterator it; + it = std::find(args_.begin(), args_.end(), L"-u"); + if (it != args_.end()) + { + updating_ = TRUE; + args_.erase(it); + } + it = std::find(args_.begin(), args_.end(), L"-sm"); + if (it != args_.end()) + { + skipcheck_ = TRUE; + args_.erase(it); + } + it = std::find(args_.begin(), args_.end(), L"-sha1"); + if (it != args_.end()) + { + hashtype_ = HashType::SHA1; + args_.erase(it); + } + it = std::find(args_.begin(), args_.end(), L"-md5"); + if (it != args_.end()) + { + hashtype_ = HashType::MD5; + args_.erase(it); + } + it = std::find(args_.begin(), args_.end(), L"-crc32"); + if (it != args_.end()) + { + hashtype_ = HashType::CRC32; + args_.erase(it); + } + } + + WIN32_FIND_DATAW findfiledata; + HANDLE hFind; + + if (args_.size() > 0) + { + std::wstring tmp(args_[0]); + if (*(tmp.end() - 1) != L'\\') + { + tmp += L'\\'; + } + tmp += L"*"; + hFind = FindFirstFileW(tmp.c_str(), &findfiledata); + if (hFind != INVALID_HANDLE_VALUE) { + FindClose(hFind); + basepath_ = args_[0] + L'\\'; + } + else + { + silent_ = TRUE; + } + } + + std::wstring baseFilename = kHashFileBaseName; + if (hashtype_ == HashType::SHA1) + hashfilename_ = baseFilename + L".sha1"; + else if (hashtype_ == HashType::MD5) + hashfilename_ = baseFilename + L".md5"; + else if (hashtype_ == HashType::CRC32) + hashfilename_ = baseFilename + L".crc32"; + else + { + hashfilename_ = baseFilename + L".sha1"; + hFind = FindFirstFileW(hashfilename_.c_str(), &findfiledata); + if (hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + hashtype_ = HashType::SHA1; + } + else + { + hashfilename_ = baseFilename + L".md5"; + hFind = FindFirstFileW(hashfilename_.c_str(), &findfiledata); + if (hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + hashtype_ = HashType::MD5; + } + else + { + hashfilename_ = baseFilename + L".crc32"; + hFind = FindFirstFileW(hashfilename_.c_str(), &findfiledata); + if (hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + hashtype_ = HashType::CRC32; + } + else + { + hashfilename_ = baseFilename + L".sha1"; + hashtype_ = HashType::SHA1; + } + } + } + } + + hFind = FindFirstFileW(hashfilename_.c_str(), &findfiledata); + if (hFind != INVALID_HANDLE_VALUE) + { + FindClose(hFind); + if (!(findfiledata.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) + { + checking_ = !updating_; + } + else + { + if (!silent_) + { + std::wstring msg = L"Error: Can't create hash file. Delete '" + hashfilename_ + L"' folder."; + MessageBoxW(NULL, msg.c_str(), L"HashCheck", MB_ICONERROR | MB_SYSTEMMODAL); + } + else + { + // ... + } + ExitProcess(0); + } + } + else + { + updating_ = FALSE; + } + +} + +int HashCheck::Process() const +{ + auto mode = HashFileProcessor::Mode::Create; + if (checking_) + { + mode = HashFileProcessor::Mode::Verify; + } + else if (updating_) + { + mode = HashFileProcessor::Mode::Update; + } + + auto hashtype = HashType::Undefined; + switch (hashtype_) + { + case HashType::CRC32: + hashtype = HashType::CRC32; + break; + case HashType::MD5: + hashtype = HashType::MD5; + break; + case HashType::SHA1: + hashtype = HashType::SHA1; + break; + default: + break; + } + + HashFileProcessor hashfileprocessor(mode, hashtype, hashfilename_, appfilename_, basepath_); + auto result = hashfileprocessor.ProcessTree(); + BOOL viewreport = FALSE; + int exitcode = 0; + switch (result) + { + case HashFileProcessor::ProcessResult::FilesAreMissing: + if (updating_) + { + MessageBoxW(NULL, L"Error: Can't update because files are missing.", L"HashCheck", MB_ICONERROR | MB_SYSTEMMODAL); + } + viewreport = TRUE; + exitcode = -1; + break; + case HashFileProcessor::ProcessResult::ErrorsOccurredWhileProcessing: + viewreport = TRUE; + exitcode = -2; + break; + case HashFileProcessor::ProcessResult::CouldNotOpenHashFile: + MessageBoxW(NULL, L"Error: Could not open hash file.", L"HashCheck", MB_ICONERROR | MB_SYSTEMMODAL); + exitcode = -3; + break; + case HashFileProcessor::ProcessResult::NoFileToProcess: + MessageBoxW(NULL, L"Error: No file to process.", L"HashCheck", MB_ICONERROR | MB_SYSTEMMODAL); + exitcode = -4; + break; + case HashFileProcessor::ProcessResult::NothingToUpdate: + MessageBoxW(NULL, L"Error: Nothing to update.", L"HashCheck", MB_ICONERROR | MB_SYSTEMMODAL); + exitcode = -5; + break; + case HashFileProcessor::ProcessResult::Success: + if (checking_) + { + MessageBoxW(NULL, L"All files OK.", L"HashCheck", MB_ICONINFORMATION | MB_SYSTEMMODAL); + } + else if (updating_) + { + MessageBoxW(NULL, L"Hash file was updated successfully.", L"HashCheck", MB_ICONINFORMATION | MB_SYSTEMMODAL); + } + else + { + MessageBoxW(NULL, L"Hash file was created successfully.", L"HashCheck", MB_ICONINFORMATION | MB_SYSTEMMODAL); + } + break; + default: + break; + } + + if (viewreport) + { + WCHAR tempfile[MAX_PATH]; + WCHAR tempfolder[MAX_PATH]; + GetTempPathW(MAX_PATH, tempfolder); + GetTempFileNameW(tempfolder, L"HashCheck", 0, tempfile); + hashfileprocessor.SaveReport(tempfile); + ViewReport(tempfile); + } + + return exitcode; +} + +std::wstring HashCheck::GetAppFileName(LPCWSTR apptitle) const +{ + std::wstring temp = apptitle; + auto pos1 = temp.rfind(L"\\") + 1; + auto pos2 = temp.rfind(L".") + 4 - pos1; + return temp.substr(pos1, pos2); +} + +BOOL HashCheck::ViewReport(LPCWSTR filepath) const +{ + WCHAR cmdline[255]; + lstrcpyW(cmdline, L"notepad.exe "); + lstrcatW(cmdline, filepath); + STARTUPINFOW si; + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(pi)); + if (CreateProcessW(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) + { + WaitForSingleObject(pi.hProcess, INFINITE); + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + return TRUE; + } + return FALSE; +} +
diff --git a/tests/resources/issue_3020/HashCheck.h b/tests/resources/issue_3020/HashCheck.h new file mode 100644 index 0000000..91d7869 --- /dev/null +++ b/tests/resources/issue_3020/HashCheck.h
@@ -0,0 +1,41 @@ +/* Author: macote */ + +#ifndef HASHCHECK_H_ +#define HASHCHECK_H_ + +#define _CRT_SECURE_NO_WARNINGS + +#include "HashType.h" +#include "HashFileProcessor.h" +#include <vector> +#include <string> +#include <algorithm> +#include <Windows.h> + +class HashCheck +{ +private: + static LPCWSTR kHashFileBaseName; +public: + HashCheck(std::vector<std::wstring> args) : args_(args) + { + Initialize(); + }; + int Process() const; +private: + void Initialize(); + std::wstring GetAppFileName(LPCWSTR apptitle) const; + BOOL ViewReport(LPCWSTR filepath) const; +private: + std::vector<std::wstring> args_; + std::wstring hashfilename_; + std::wstring basepath_; + std::wstring appfilename_; + HashType hashtype_; + BOOL silent_; + BOOL checking_; + BOOL updating_; + BOOL skipcheck_; +}; + +#endif /* HASHCHECK_H_ */
diff --git a/tests/resources/issue_3020/HashCheck.ico b/tests/resources/issue_3020/HashCheck.ico new file mode 100644 index 0000000..766cc89 --- /dev/null +++ b/tests/resources/issue_3020/HashCheck.ico Binary files differ
diff --git a/tests/resources/issue_3020/HashCheckWindow.cpp b/tests/resources/issue_3020/HashCheckWindow.cpp new file mode 100644 index 0000000..bedbaa4 --- /dev/null +++ b/tests/resources/issue_3020/HashCheckWindow.cpp
@@ -0,0 +1,50 @@ +/* Author: macote */ + +#include "HashCheckWindow.h" + +LRESULT HashCheckWindow::OnCreate() +{ + return 0; +} + +LRESULT HashCheckWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + return OnCreate(); + case WM_NCDESTROY: + // Death of the root window ends the thread + PostQuitMessage(0); + break; + case WM_SIZE: + if (hwndChild_) + { + SetWindowPos(hwndChild_, NULL, 0, 0, GET_X_LPARAM(lParam), + GET_Y_LPARAM(lParam), SWP_NOZORDER | SWP_NOACTIVATE); + } + return 0; + case WM_SETFOCUS: + if (hwndChild_) + { + SetFocus(hwndChild_); + } + return 0; + } + return Window::HandleMessage(uMsg, wParam, lParam); +} + +HashCheckWindow* HashCheckWindow::Create(HINSTANCE hInst) +{ + auto self = new HashCheckWindow(hInst); + if (self != NULL) + { + if (self->WinCreateWindow(0, L"HashCheckWindow", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL)) + { + return self; + } + delete self; + } + return NULL; +}
diff --git a/tests/resources/issue_3020/HashCheckWindow.h b/tests/resources/issue_3020/HashCheckWindow.h new file mode 100644 index 0000000..f0ea3d6 --- /dev/null +++ b/tests/resources/issue_3020/HashCheckWindow.h
@@ -0,0 +1,27 @@ +/* Author: macote */ + +#ifndef HASHCHECKWINDOW_H_ +#define HASHCHECKWINDOW_H_ + +#include "Window.h" +#include <Windows.h> +#include <windowsx.h> + +class HashCheckWindow : public Window +{ +public: +#if _MSC_VER < 1900 + HashCheckWindow(HINSTANCE hinst) : Window(hinst) { }; +#else + using Window::Window; +#endif + virtual LPCWSTR ClassName() { return L"HashCheckWindow"; } + static HashCheckWindow *Create(HINSTANCE hInst); +protected: + LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); + LRESULT OnCreate(); +private: + HWND hwndChild_; +}; + +#endif /* HASHCHECKWINDOW_H_ */ \ No newline at end of file
diff --git a/tests/resources/issue_3020/HashFile.cpp b/tests/resources/issue_3020/HashFile.cpp new file mode 100644 index 0000000..c0f2aef --- /dev/null +++ b/tests/resources/issue_3020/HashFile.cpp
@@ -0,0 +1,110 @@ +/* Author: macote */ + +#include "HashFile.h" + +const FileEntry HashFile::kFileEntryNull = FileEntry(L"", LARGE_INTEGER(), L""); + +void HashFile::Load(const std::wstring& hashfilepath) +{ + FileStream hashfile(hashfilepath.c_str(), FileStream::Mode::Open); + StreamLineReader hashfilereader(hashfile); + WCHAR buffer[2048]; + std::wstring line, key, sizetemp, filepath, digest; + std::wstring::size_type pos1, pos2; + LARGE_INTEGER size; + // hash line format: <filepath>|<size>|<digest> + do + { + line = hashfilereader.ReadLine(); + if (IsValidHashLine(line)) + { + pos1 = line.find('|', 0); + filepath = line.substr(0, pos1); + lstrcpyW(buffer, filepath.c_str()); + key = CharUpperW(buffer); + pos2 = line.find('|', pos1 + 1); + sizetemp = line.substr(pos1 + 1, pos2 - (pos1 + 1)); + std::wstringstream wss(sizetemp); + wss >> size.QuadPart; + digest = line.substr(pos2 + 1, line.size() - pos2); + files_.insert(std::pair<std::wstring, FileEntry>(key, FileEntry(filepath, size, digest))); + } + } while (!hashfilereader.EndOfStream()); +} + +void HashFile::Save(const std::wstring& hashfilepath) const +{ + FileStream hashfile(hashfilepath, FileStream::Mode::Create); + StreamLineWriter hashfilewriter(hashfile); + for (auto& item : files_) + { + auto fileentry = item.second; + hashfilewriter.WriteLine(fileentry.filepath() + L"|" + LargeIntToString(fileentry.size()) + L"|" + fileentry.digest()); + } +} + +void HashFile::AddFileEntry(const std::wstring filepath, const LARGE_INTEGER size, const std::wstring digest) +{ + files_.insert(std::pair<std::wstring, FileEntry>(filepath, FileEntry(filepath, size, digest))); +} + +std::map<std::wstring, FileEntry, std::less<std::wstring>>::const_iterator HashFile::FindEntry(const std::wstring& filepath) const +{ + WCHAR key[2048]; + lstrcpyW(key, filepath.c_str()); + CharUpperW(key); + return files_.find(key); +} + +void HashFile::RemoveFileEntry(const std::wstring& filepath) +{ + auto i = FindEntry(filepath); + if (i != files_.end()) + { + files_.erase(i); + } +} + +BOOL HashFile::ContainsFileEntry(const std::wstring& filepath) const +{ + auto i = FindEntry(filepath); + return i != files_.end(); +} + +const FileEntry& HashFile::GetFileEntry(const std::wstring& filepath) const +{ + auto i = FindEntry(filepath); + if (i != files_.end()) + { + return (*i).second; + } + else + { + return kFileEntryNull; + } +} + +std::list<std::wstring> HashFile::GetFilePaths() const +{ + std::list<std::wstring> filepaths; + for (auto& item : files_) + { + filepaths.push_back(item.second.filepath()); + } + return filepaths; +} + +BOOL HashFile::IsValidHashLine(const std::wstring& fileentryline) const +{ + if (fileentryline.size() == 0) return FALSE; + if (fileentryline.size() > 2176) return FALSE; + // TODO: implement proper hash line validation + return TRUE; +} + +std::wstring HashFile::LargeIntToString(const LARGE_INTEGER& li) const +{ + std::wstringstream wss; + wss << li.QuadPart; + return wss.str(); +}
diff --git a/tests/resources/issue_3020/HashFile.h b/tests/resources/issue_3020/HashFile.h new file mode 100644 index 0000000..f6bb6b6 --- /dev/null +++ b/tests/resources/issue_3020/HashFile.h
@@ -0,0 +1,55 @@ +/* Author: macote */ + +#ifndef HASHFILE_H_ +#define HASHFILE_H_ + +#include "FileStream.h" +#include "StreamLineReader.h" +#include "StreamLineWriter.h" +#include <sstream> +#include <list> +#include <map> +#include <string> +#include <Windows.h> + +class FileEntry +{ +public: + FileEntry(const std::wstring filepath, const LARGE_INTEGER size, const std::wstring digest) + : filepath_(filepath), size_(size), digest_(digest) { }; + std::wstring filepath() const { return filepath_; } + LARGE_INTEGER size() const { return size_; } + std::wstring digest() const { return digest_; } +private: + const std::wstring filepath_; + const LARGE_INTEGER size_; + const std::wstring digest_; +}; + +class HashFile +{ +public: + static const FileEntry kFileEntryNull; +public: + HashFile() { }; + ~HashFile() + { + files_.clear(); + } + void Save(const std::wstring& hashfilepath) const; + void Load(const std::wstring& hashfilepath); + void AddFileEntry(const std::wstring filepath, const LARGE_INTEGER li, const std::wstring digest); + void RemoveFileEntry(const std::wstring& filepath); + BOOL IsEmpty() const { return files_.size() == 0; } + BOOL ContainsFileEntry(const std::wstring& filepath) const; + const FileEntry& GetFileEntry(const std::wstring& filepath) const; + std::list<std::wstring> GetFilePaths() const; +private: + std::map<std::wstring, FileEntry, std::less<std::wstring>>::const_iterator FindEntry(const std::wstring& filepath) const; + BOOL IsValidHashLine(const std::wstring& fileentryline) const; + std::wstring LargeIntToString(const LARGE_INTEGER& li) const; +private: + std::map<std::wstring, FileEntry, std::less<std::wstring>> files_; +}; + +#endif /* HASHFILE_H_ */
diff --git a/tests/resources/issue_3020/HashFileProcessor.cpp b/tests/resources/issue_3020/HashFileProcessor.cpp new file mode 100644 index 0000000..772f1a9 --- /dev/null +++ b/tests/resources/issue_3020/HashFileProcessor.cpp
@@ -0,0 +1,157 @@ +/* Author: macote */ + +#include "HashFileProcessor.h" + +HashFileProcessor::ProcessResult HashFileProcessor::ProcessTree() +{ + auto result = ProcessResult::Success; + newfilesupdated_ = FALSE; + if (mode_ == HashFileProcessor::Mode::Verify || mode_ == HashFileProcessor::Mode::Update) + { + try + { + hashfile_.Load(hashfilename_); + } + catch (...) + { + result = ProcessResult::CouldNotOpenHashFile; + return result; + } + } + FileTree filetree(basepath_, *this); + filetree.Process(); + if (mode_ == HashFileProcessor::Mode::Create) + { + if (hashfile_.IsEmpty()) + { + result = ProcessResult::NoFileToProcess; + } + else if (!report_.IsEmpty()) + { + result = ProcessResult::ErrorsOccurredWhileProcessing; + } + else + { + hashfile_.Save(hashfilename_); + } + } + else if (mode_ == HashFileProcessor::Mode::Verify || mode_ == HashFileProcessor::Mode::Update) + { + if (!hashfile_.IsEmpty()) + { + for (auto& relativefilepath : hashfile_.GetFilePaths()) + { + // TODO: replace hardcoded text + report_.AddLine(L"Missing : " + relativefilepath); + } + result = ProcessResult::FilesAreMissing; + } + else if (!report_.IsEmpty()) + { + result = ProcessResult::ErrorsOccurredWhileProcessing; + } + else if (mode_ == HashFileProcessor::Mode::Update) + { + if (!newfilesupdated_) + { + result = ProcessResult::NothingToUpdate; + } + else + { + // replace old hash file + DeleteFileW(hashfilename_.c_str()); + newhashfile_.Save(hashfilename_); + } + } + } + return result; +} + +void HashFileProcessor::ProcessFile(const std::wstring& filepath) +{ + if (lstrcmpiW(appfilepath_.c_str(), filepath.c_str()) == 0 || lstrcmpiW(hashfilename_.c_str(), filepath.c_str()) == 0) + { + // skip self and current hash file + return; + } + auto relativefilepath = filepath.substr(basepath_.length(), filepath.length()); + const FileEntry& fileentry = hashfile_.GetFileEntry(relativefilepath); + if (mode_ == HashFileProcessor::Mode::Verify) + { + if (&fileentry == &HashFile::kFileEntryNull) + { + report_.AddLine(L"Unknown : " + relativefilepath); + return; + } + } + else if (mode_ == HashFileProcessor::Mode::Update) + { + if (&fileentry == &HashFile::kFileEntryNull) + { + newhashfile_.AddFileEntry(fileentry.filepath(), fileentry.size(), fileentry.digest()); + hashfile_.RemoveFileEntry(relativefilepath); + return; + } + } + LARGE_INTEGER size; + size.QuadPart = 0; + auto file = CreateFileW(filepath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (file != INVALID_HANDLE_VALUE) + { + GetFileSizeEx(file, &size); + CloseHandle(file); + } + else + { + report_.AddLine(L"Error opening file : " + relativefilepath); + if (mode_ == HashFileProcessor::Mode::Verify) + { + hashfile_.RemoveFileEntry(relativefilepath); + } + return; + } + if (mode_ == HashFileProcessor::Mode::Verify) + { + if (size.QuadPart != fileentry.size().QuadPart) + { + report_.AddLine(L"Incorrect file size : " + relativefilepath); + hashfile_.RemoveFileEntry(relativefilepath); + return; + } + } + auto filehash = FileHashFactory::Create(hashtype_, filepath); + if (progressevent_ != nullptr) + { + hfppea_.bytesprocessed.QuadPart = 0; + hfppea_.relativefilepath = relativefilepath; + progressevent_(hfppea_); + filehash->SetBytesProcessedEventHandler([this](FileHashBytesProcessedEventArgs fhbea) { + this->hfppea_.bytesprocessed = fhbea.bytesprocessed; + this->progressevent_(hfppea_); + }, bytesprocessednotificationblocksize_); + } + filehash->Compute(); + std::wstring digest = filehash->digest(); + if (mode_ == HashFileProcessor::Mode::Create) + { + hashfile_.AddFileEntry(relativefilepath, size, digest); + } + else if (mode_ == HashFileProcessor::Mode::Update) + { + newhashfile_.AddFileEntry(relativefilepath, size, digest); + newfilesupdated_ = TRUE; + } + else if (mode_ == HashFileProcessor::Mode::Verify) + { + if (size.QuadPart != fileentry.size().QuadPart) + { + report_.AddLine(L"Incorrect file size : " + relativefilepath); + } + else if (digest != fileentry.digest()) + { + report_.AddLine(L"Incorrect hash : " + relativefilepath); + } + hashfile_.RemoveFileEntry(relativefilepath); + } +}
diff --git a/tests/resources/issue_3020/HashFileProcessor.h b/tests/resources/issue_3020/HashFileProcessor.h new file mode 100644 index 0000000..98c9967 --- /dev/null +++ b/tests/resources/issue_3020/HashFileProcessor.h
@@ -0,0 +1,67 @@ +/* Author: macote */ + +#include "HashFile.h" +#include "FileTree.h" +#include "HashType.h" +#include "FileHashFactory.h" +#include "Report.h" + +struct HashFileProcessorProgressEventArgs +{ + std::wstring relativefilepath; + LARGE_INTEGER bytesprocessed; +}; + +class HashFileProcessor : public IFileTreeAction +{ +public: + static const DWORD kDefaultBytesProcessedNotificationBlockSize = 1048576; +public: + enum class Mode + { + Create, + Update, + Verify, + Undefined + }; + enum class ProcessResult + { + FilesAreMissing, + NothingToUpdate, + CouldNotOpenHashFile, + ErrorsOccurredWhileProcessing, + NoFileToProcess, + Success + }; + HashFileProcessor(Mode mode, HashType hashtype, std::wstring hashfilename, std::wstring appfilepath, std::wstring basepath) + : mode_(mode), hashtype_(hashtype), hashfilename_(hashfilename), appfilepath_(appfilepath), basepath_(basepath) + { + progressevent_ = nullptr; + }; + ProcessResult ProcessTree(); + void ProcessFile(const std::wstring& filepath); + void SaveReport(const std::wstring& reportpath) const { report_.Save(reportpath); } + void SetProgressEventHandler(std::function<void(HashFileProcessorProgressEventArgs)> handler) + { + SetProgressEventHandler(handler, kDefaultBytesProcessedNotificationBlockSize); + } + void SetProgressEventHandler(std::function<void(HashFileProcessorProgressEventArgs)> handler, + const DWORD bytesprocessednotificationblocksize) + { + progressevent_ = handler; + bytesprocessednotificationblocksize_ = bytesprocessednotificationblocksize; + } +private: + Mode mode_; + HashType hashtype_; + HashFile hashfile_; + HashFile newhashfile_; + std::wstring hashfilename_; + std::wstring appfilepath_; + std::wstring basepath_; + BOOL newfilesupdated_ = FALSE; + Report report_; + HashFileProcessorProgressEventArgs hfppea_; + DWORD bytesprocessednotificationblocksize_; + std::function<void(HashFileProcessorProgressEventArgs)> progressevent_; +};
diff --git a/tests/resources/issue_3020/HashType.h b/tests/resources/issue_3020/HashType.h new file mode 100644 index 0000000..5ee9c51 --- /dev/null +++ b/tests/resources/issue_3020/HashType.h
@@ -0,0 +1,14 @@ +/* Author: macote */ + +#ifndef HASHTYPE_H_ +#define HASHTYPE_H_ + +enum class HashType +{ + CRC32, + MD5, + SHA1, + Undefined +}; + +#endif /* HASHTYPE_H_ */
diff --git a/tests/resources/issue_3020/MD5FileHash.cpp b/tests/resources/issue_3020/MD5FileHash.cpp new file mode 100644 index 0000000..3aea659 --- /dev/null +++ b/tests/resources/issue_3020/MD5FileHash.cpp
@@ -0,0 +1,177 @@ + + +void MD5FileHash::Update(const UINT32 bytecount) +{ + UINT32 index = context_.count[0]; // update bitcount + context_.count[0] = index + (bytecount << 3); + if (context_.count[0] < index) + { + context_.count[1]++; // carry from low to high + } + context_.count[1] += bytecount >> 29; + index = (index >> 3) & 63; // bytes already in shsInfo->data + UINT32 bytesleft = bytecount; + if (index > 0) + { + // handle any leading odd-sized chunks + PBYTE ctxbuffer = (PBYTE)context_.buffer + index; + index = 64 - index; + if (bytecount < index) + { + CopyMemory(ctxbuffer, buffer_, bytecount); + return; + } + CopyMemory(ctxbuffer, buffer_, index); + Transform(context_.state, (PUINT32)context_.buffer); + ctxbuffer += index; + bytesleft -= index; + } + // process data in 64-byte chunks + PBYTE buffer = buffer_; + while (bytesleft >= 64) + { + CopyMemory(context_.buffer, buffer, sizeof(context_.buffer)); + Transform(context_.state, (PUINT32)context_.buffer); + buffer += 64; + bytesleft -= 64; + } + // handle any remaining bytes of data. + CopyMemory(context_.buffer, buffer, bytesleft); +} + +void MD5FileHash::Finalize() +{ + UINT32 index = (context_.count[0] >> 3) & 63; // compute number of bytes mod 64 + // set the first char of padding to 0x80. this is safe since there is + // always at least one byte free + PBYTE ctxbuffer = context_.buffer + index; + *ctxbuffer++ = 0x80; + index = 64 - 1 - index; // bytes of padding needed to make 64 bytes + // pad out to 56 mod 64 + if (index < 8) + { + // two lots of padding: pad the first block to 64 bytes + ZeroMemory(ctxbuffer, index); + Transform(context_.state, (PUINT32)context_.buffer); + // now fill the next block with 56 bytes + ZeroMemory(context_.buffer, 56); + } + else + { + ZeroMemory(ctxbuffer, index - 8); // pad block to 56 bytes + } + // append length in bits and transform + typedef union + { + BYTE c[64]; + UINT32 l[16]; + } CHAR64LONG16, *PCHAR64LONG16; + PCHAR64LONG16 bufferlong = (PCHAR64LONG16)context_.buffer; + bufferlong->l[14] = context_.count[0]; + bufferlong->l[15] = context_.count[1]; + Transform(context_.state, (PUINT32)context_.buffer); + CopyMemory(hash_, context_.state, sizeof(hash_)); +} + +void MD5FileHash::ConvertHashToDigestString() +{ + std::wstringstream wss; + wss << std::hex << std::setw(2) << std::setfill(L'0') << std::uppercase; + for (UINT i = 0; i < sizeof(hash_); i++) + { + wss << hash_[i]; + } + digest_.append(wss.str()); +} + +void MD5FileHash::Transform(UINT32 state[4], PUINT32 buffer) +{ + register UINT32 a, b, c, d; + + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + +#define F1(x, y, z) (z ^ (x & (y ^ z))) +#define F2(x, y, z) F1(z, x, y) +#define F3(x, y, z) (x ^ y ^ z) +#define F4(x, y, z) (y ^ (x | ~z)) + +#define MD5STEP(f, w, x, y, z, data, s) (w += f(x, y, z) + data, w = w << s | w >> (32 - s), w += x) + + MD5STEP(F1, a, b, c, d, buffer[0] + 0xD76AA478L, 7); + MD5STEP(F1, d, a, b, c, buffer[1] + 0xE8C7B756L, 12); + MD5STEP(F1, c, d, a, b, buffer[2] + 0x242070DBL, 17); + MD5STEP(F1, b, c, d, a, buffer[3] + 0xC1BDCEEEL, 22); + MD5STEP(F1, a, b, c, d, buffer[4] + 0xF57C0FAFL, 7); + MD5STEP(F1, d, a, b, c, buffer[5] + 0x4787C62AL, 12); + MD5STEP(F1, c, d, a, b, buffer[6] + 0xA8304613L, 17); + MD5STEP(F1, b, c, d, a, buffer[7] + 0xFD469501L, 22); + MD5STEP(F1, a, b, c, d, buffer[8] + 0x698098D8L, 7); + MD5STEP(F1, d, a, b, c, buffer[9] + 0x8B44F7AFL, 12); + MD5STEP(F1, c, d, a, b, buffer[10] + 0xFFFF5BB1L, 17); + MD5STEP(F1, b, c, d, a, buffer[11] + 0x895CD7BEL, 22); + MD5STEP(F1, a, b, c, d, buffer[12] + 0x6B901122L, 7); + MD5STEP(F1, d, a, b, c, buffer[13] + 0xFD987193L, 12); + MD5STEP(F1, c, d, a, b, buffer[14] + 0xA679438EL, 17); + MD5STEP(F1, b, c, d, a, buffer[15] + 0x49B40821L, 22); + + MD5STEP(F2, a, b, c, d, buffer[1] + 0xF61E2562L, 5); + MD5STEP(F2, d, a, b, c, buffer[6] + 0xC040B340L, 9); + MD5STEP(F2, c, d, a, b, buffer[11] + 0x265E5A51L, 14); + MD5STEP(F2, b, c, d, a, buffer[0] + 0xE9B6C7AAL, 20); + MD5STEP(F2, a, b, c, d, buffer[5] + 0xD62F105DL, 5); + MD5STEP(F2, d, a, b, c, buffer[10] + 0x02441453L, 9); + MD5STEP(F2, c, d, a, b, buffer[15] + 0xD8A1E681L, 14); + MD5STEP(F2, b, c, d, a, buffer[4] + 0xE7D3FBC8L, 20); + MD5STEP(F2, a, b, c, d, buffer[9] + 0x21E1CDE6L, 5); + MD5STEP(F2, d, a, b, c, buffer[14] + 0xC33707D6L, 9); + MD5STEP(F2, c, d, a, b, buffer[3] + 0xF4D50D87L, 14); + MD5STEP(F2, b, c, d, a, buffer[8] + 0x455A14EDL, 20); + MD5STEP(F2, a, b, c, d, buffer[13] + 0xA9E3E905L, 5); + MD5STEP(F2, d, a, b, c, buffer[2] + 0xFCEFA3F8L, 9); + MD5STEP(F2, c, d, a, b, buffer[7] + 0x676F02D9L, 14); + MD5STEP(F2, b, c, d, a, buffer[12] + 0x8D2A4C8AL, 20); + + MD5STEP(F3, a, b, c, d, buffer[5] + 0xFFFA3942L, 4); + MD5STEP(F3, d, a, b, c, buffer[8] + 0x8771F681L, 11); + MD5STEP(F3, c, d, a, b, buffer[11] + 0x6D9D6122L, 16); + MD5STEP(F3, b, c, d, a, buffer[14] + 0xFDE5380CL, 23); + MD5STEP(F3, a, b, c, d, buffer[1] + 0xA4BEEA44L, 4); + MD5STEP(F3, d, a, b, c, buffer[4] + 0x4BDECFA9L, 11); + MD5STEP(F3, c, d, a, b, buffer[7] + 0xF6BB4B60L, 16); + MD5STEP(F3, b, c, d, a, buffer[10] + 0xBEBFBC70L, 23); + MD5STEP(F3, a, b, c, d, buffer[13] + 0x289B7EC6L, 4); + MD5STEP(F3, d, a, b, c, buffer[0] + 0xEAA127FAL, 11); + MD5STEP(F3, c, d, a, b, buffer[3] + 0xD4EF3085L, 16); + MD5STEP(F3, b, c, d, a, buffer[6] + 0x04881D05L, 23); + MD5STEP(F3, a, b, c, d, buffer[9] + 0xD9D4D039L, 4); + MD5STEP(F3, d, a, b, c, buffer[12] + 0xE6DB99E5L, 11); + MD5STEP(F3, c, d, a, b, buffer[15] + 0x1FA27CF8L, 16); + MD5STEP(F3, b, c, d, a, buffer[2] + 0xC4AC5665L, 23); + + MD5STEP(F4, a, b, c, d, buffer[0] + 0xF4292244L, 6); + MD5STEP(F4, d, a, b, c, buffer[7] + 0x432AFF97L, 10); + MD5STEP(F4, c, d, a, b, buffer[14] + 0xAB9423A7L, 15); + MD5STEP(F4, b, c, d, a, buffer[5] + 0xFC93A039L, 21); + MD5STEP(F4, a, b, c, d, buffer[12] + 0x655B59C3L, 6); + MD5STEP(F4, d, a, b, c, buffer[3] + 0x8F0CCC92L, 10); + MD5STEP(F4, c, d, a, b, buffer[10] + 0xFFEFF47DL, 15); + MD5STEP(F4, b, c, d, a, buffer[1] + 0x85845DD1L, 21); + MD5STEP(F4, a, b, c, d, buffer[8] + 0x6FA87E4FL, 6); + MD5STEP(F4, d, a, b, c, buffer[15] + 0xFE2CE6E0L, 10); + MD5STEP(F4, c, d, a, b, buffer[6] + 0xA3014314L, 15); + MD5STEP(F4, b, c, d, a, buffer[13] + 0x4E0811A1L, 21); + MD5STEP(F4, a, b, c, d, buffer[4] + 0xF7537E82L, 6); + MD5STEP(F4, d, a, b, c, buffer[11] + 0xBD3AF235L, 10); + MD5STEP(F4, c, d, a, b, buffer[2] + 0x2AD7D2BBL, 15); + MD5STEP(F4, b, c, d, a, buffer[9] + 0xEB86D391L, 21); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + a = b = c = d = 0; +}
diff --git a/tests/resources/issue_3020/MD5FileHash.h b/tests/resources/issue_3020/MD5FileHash.h new file mode 100644 index 0000000..b008070 --- /dev/null +++ b/tests/resources/issue_3020/MD5FileHash.h
@@ -0,0 +1,38 @@ +/* Author: macote */ + +#ifndef MD5FILEHASH_H_ +#define MD5FILEHASH_H_ + +#include "FileHash.h" +#include <iomanip> +#include <sstream> +#include <string> +#include <Windows.h> + +struct MD5Context +{ + UINT32 state[4]; // state (ABCD) + UINT32 count[2]; // number of bits, modulo 2^64 (lsb first) + BYTE buffer[64]; // input buffer +}; + +class MD5FileHash : public FileHash +{ +public: +#if _MSC_VER < 1900 + MD5FileHash(const std::wstring& filepath, const DWORD buffersize) : FileHash(filepath, buffersize) { }; + MD5FileHash(const std::wstring& filepath) : FileHash(filepath) { }; +#else + using FileHash::FileHash; +#endif +private: + void Initialize(); + void Update(const UINT32 bytecount); + void Finalize(); + void Transform(UINT32 state[4], PUINT32 buffer); + void ConvertHashToDigestString(); + BYTE hash_[16]; + MD5Context context_; +}; + +#endif /* MD5FILEHASH_H_ */
diff --git a/tests/resources/issue_3020/Program.cpp b/tests/resources/issue_3020/Program.cpp new file mode 100644 index 0000000..b765e0c --- /dev/null +++ b/tests/resources/issue_3020/Program.cpp
@@ -0,0 +1,53 @@ +/* Author: macote */ + +#ifndef UNICODE +#define UNICODE +#endif +#ifndef _UNICODE +#define _UNICODE +#endif + +#define WIN32_LEAN_AND_MEAN + +#include "HashCheck.h" +#include "HashCheckWindow.h" +#include <string> +#include <vector> +#include <Windows.h> +#include <Ole2.h> +#include <CommCtrl.h> +#include <shellapi.h> + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) +{ + int argscount; + auto args = CommandLineToArgvW(GetCommandLineW(), &argscount); + std::vector<std::wstring> argsvector; + for (int i = 0; i < argscount; ++i) + { + argsvector.push_back(args[i]); + } + LocalFree(args); + + //if (SUCCEEDED(CoInitialize(NULL))) + //{ + // InitCommonControls(); + // HashCheckWindow *hcw = HashCheckWindow::Create(hInstance); + // if (hcw) + // { + // ShowWindow(hcw->GetHWND(), nCmdShow); + // MSG msg; + // while (GetMessage(&msg, NULL, 0, 0)) + // { + // TranslateMessage(&msg); + // DispatchMessage(&msg); + // } + // } + // CoUninitialize(); + //} + + HashCheck hc(argsvector); + auto result = hc.Process(); + + return result; +}
diff --git a/tests/resources/issue_3020/README.md b/tests/resources/issue_3020/README.md new file mode 100644 index 0000000..37e3522 --- /dev/null +++ b/tests/resources/issue_3020/README.md
@@ -0,0 +1,48 @@ +HashCheck for Windows +===================== + +HashCheck is a Windows application that creates and verifies file checksums. + + +How to build +------------ + +This project is compatible with: +- Visual Studio 2013 +- Eclipse Luna CDT with MinGW (GCC 4.8.1) + + +Usage +----- + +Launch the executable to create a checksum file if it does not already exists. + +Launch the executable to verify file integrity against a checksum file if it exists. + + +License +------- + +Hashing code found on the Internet is in the public domain: + +MD5: Colin Plumb (1993) / John Walker (2003) + +SHA1: Steve Reid (199?) / ... / Ralph Giles (2002) + +FileStream code inspired by dotnet/corefx's Win32FileStream.cs. See FileStream.cpp for licensing information. + + +FAQ +--- + +### Why MinGW? + +I wanted to have an executable having the least runtime dependencies possible. + +### Why FileStream? + +MinGW's fstream can't open WCHAR filenames and I was not interested in changing fstream's implementation. + +### What's the coding style? + +The coding style is inspired from Google C++ [coding style guide](http://google-styleguide.googlecode.com/svn/trunk/cppguide.html "Google C++ Style Guide").
diff --git a/tests/resources/issue_3020/Report.h b/tests/resources/issue_3020/Report.h new file mode 100644 index 0000000..98b0b0d --- /dev/null +++ b/tests/resources/issue_3020/Report.h
@@ -0,0 +1,30 @@ +/* Author: macote */ + +#ifndef REPORT_H_ +#define REPORT_H_ + +#include "FileStream.h" +#include "StreamLineWriter.h" +#include <string> +#include <list> +#include <Windows.h> + +class Report +{ +public: + void AddLine(const std::wstring line) { report_.push_back(line); }; + void Save(const std::wstring& reportpath) const + { + FileStream reportfile(reportpath, FileStream::Mode::Truncate); + StreamLineWriter reportfilewriter(reportfile); + for (auto& item : report_) + { + reportfilewriter.WriteLine(item); + } + }; + BOOL IsEmpty() { return report_.size() == 0; } +private: + std::list<std::wstring> report_; +}; + +#endif /* REPORT_H_ */ \ No newline at end of file
diff --git a/tests/resources/issue_3020/SHA1FileHash.cpp b/tests/resources/issue_3020/SHA1FileHash.cpp new file mode 100644 index 0000000..661e27a --- /dev/null +++ b/tests/resources/issue_3020/SHA1FileHash.cpp
@@ -0,0 +1,132 @@ +/* Author: macote */ + +#include "SHA1FileHash.h" + +void SHA1FileHash::Initialize() +{ + context_.state[0] = 0x67452301; + context_.state[1] = 0xEFCDAB89; + context_.state[2] = 0x98BADCFE; + context_.state[3] = 0x10325476; + context_.state[4] = 0xC3D2E1F0; + context_.count[0] = context_.count[1] = 0; +} + +void SHA1FileHash::Update(const UINT32 bytecount) +{ + UINT32 i, index = (context_.count[0] >> 3) & 63; + if ((context_.count[0] += bytecount << 3) < (bytecount << 3)) + { + context_.count[1]++; + } + context_.count[1] += (bytecount >> 29); + if ((index + bytecount) > 63) + { + i = 64 - index; + CopyMemory(&context_.buffer[index], buffer_, i); + Transform(context_.state, (PUINT32)context_.buffer); + for (; i + 63 < bytecount; i += 64) + { + Transform(context_.state, (PUINT32)(buffer_ + i)); + } + index = 0; + } + else + { + i = 0; + } + CopyMemory(&context_.buffer[index], buffer_ + i, bytecount - i); +} + +void SHA1FileHash::Finalize() +{ + BYTE finalcount[8]; + for (UINT i = 0; i < 8; i++) + { + finalcount[i] = (BYTE)((context_.count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); + } + CopyMemory(buffer_, "\200", 1); + Update(1); + CopyMemory(buffer_, "\0", 1); + while ((context_.count[0] & 504) != 448) + { + Update(1); + } + CopyMemory(buffer_, finalcount, sizeof(finalcount)); + Update(8); + for (UINT i = 0; i < sizeof(hash_); i++) + { + hash_[i] = (BYTE)((context_.state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } +} + +void SHA1FileHash::ConvertHashToDigestString() +{ + std::wstringstream wss; + wss << std::hex << std::setw(2) << std::setfill(L'0') << std::uppercase; + for (UINT i = 0; i < sizeof(hash_); i++) + { + wss << hash_[i]; + } + digest_.append(wss.str()); +} + +void SHA1FileHash::Transform(UINT32 state[5], PUINT32 buffer) +{ + typedef union { + BYTE c[64]; + UINT32 l[16]; + } CHAR64LONG16, *PCHAR64LONG16; + PCHAR64LONG16 block; + block = (PCHAR64LONG16)buffer; + + register UINT32 a, b, c, d, e; + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) +#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \ + | (rol(block->l[i], 8) & 0x00FF00FF)) +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \ + ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) +#define R0(v, w, x, y, z, i) z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); +#define R1(v, w, x, y, z, i) z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); w = rol(w, 30); +#define R2(v, w, x, y, z, i) z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30); +#define R3(v, w, x, y, z, i) z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); w = rol(w, 30); +#define R4(v, w, x, y, z, i) z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); w = rol(w, 30); + + R0(a, b, c, d, e, 0); R0(e, a, b, c, d, 1); R0(d, e, a, b, c, 2); R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); R0(a, b, c, d, e, 5); R0(e, a, b, c, d, 6); R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); R0(b, c, d, e, a, 9); R0(a, b, c, d, e, 10); R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); R0(c, d, e, a, b, 13); R0(b, c, d, e, a, 14); R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); R1(d, e, a, b, c, 17); R1(c, d, e, a, b, 18); R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); R2(e, a, b, c, d, 21); R2(d, e, a, b, c, 22); R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); R2(a, b, c, d, e, 25); R2(e, a, b, c, d, 26); R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); R2(b, c, d, e, a, 29); R2(a, b, c, d, e, 30); R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); R2(c, d, e, a, b, 33); R2(b, c, d, e, a, 34); R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); R2(d, e, a, b, c, 37); R2(c, d, e, a, b, 38); R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); R3(e, a, b, c, d, 41); R3(d, e, a, b, c, 42); R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); R3(a, b, c, d, e, 45); R3(e, a, b, c, d, 46); R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); R3(b, c, d, e, a, 49); R3(a, b, c, d, e, 50); R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); R3(c, d, e, a, b, 53); R3(b, c, d, e, a, 54); R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); R3(d, e, a, b, c, 57); R3(c, d, e, a, b, 58); R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); R4(e, a, b, c, d, 61); R4(d, e, a, b, c, 62); R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); R4(a, b, c, d, e, 65); R4(e, a, b, c, d, 66); R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); R4(b, c, d, e, a, 69); R4(a, b, c, d, e, 70); R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); R4(c, d, e, a, b, 73); R4(b, c, d, e, a, 74); R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); R4(d, e, a, b, c, 77); R4(c, d, e, a, b, 78); R4(b, c, d, e, a, 79); + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + + a = b = c = d = e = 0; +} + + +
diff --git a/tests/resources/issue_3020/SHA1FileHash.h b/tests/resources/issue_3020/SHA1FileHash.h new file mode 100644 index 0000000..ff147ae --- /dev/null +++ b/tests/resources/issue_3020/SHA1FileHash.h
@@ -0,0 +1,38 @@ +/* Author: macote */ + +#ifndef SHA1FILEHASH_H_ +#define SHA1FILEHASH_H_ + +#include "FileHash.h" +#include <iomanip> +#include <sstream> +#include <string> +#include <Windows.h> + +struct SHA1Context +{ + UINT32 state[5]; // state (ABCDE) + UINT32 count[2]; // bits + BYTE buffer[64]; // input buffer +}; + +class SHA1FileHash : public FileHash +{ +public: +#if _MSC_VER < 1900 + SHA1FileHash(const std::wstring& filepath, const DWORD buffersize) : FileHash(filepath, buffersize) { }; + SHA1FileHash(const std::wstring& filepath) : FileHash(filepath) { }; +#else + using FileHash::FileHash; +#endif +private: + void Initialize(); + void Update(const UINT32 bytecount); + void Finalize(); + void Transform(UINT32 state[5], PUINT32 buffer); + void ConvertHashToDigestString(); + BYTE hash_[20]; + SHA1Context context_; +}; + +#endif /* SHA1FILEHASH_H_ */
diff --git a/tests/resources/issue_3020/StreamLineReader.cpp b/tests/resources/issue_3020/StreamLineReader.cpp new file mode 100644 index 0000000..fcdcac4 --- /dev/null +++ b/tests/resources/issue_3020/StreamLineReader.cpp
@@ -0,0 +1,78 @@ +/* Author: macote */ + +#include "StreamLineReader.h" + +void StreamLineReader::AllocateBuffer() +{ + buffer_ = (PBYTE)VirtualAlloc(NULL, buffersize_, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +} + +void StreamLineReader::FreeBuffer() +{ + if (buffer_ != NULL) + { + VirtualFree(buffer_, 0, MEM_RELEASE); + } +} + +DWORD StreamLineReader::ReadBytes() +{ + if (readlength_ - readindex_ == 0) + { + readindex_ = 0; + readlength_ = filestream_.Read(buffer_, buffersize_); + } + return readlength_; +} + +std::wstring StreamLineReader::ReadLine() +{ + BOOL eol = FALSE; + std::string raw; + while (!eol) + { + DWORD bufferbytes = readlength_ - readindex_; + if (bufferbytes == 0) + { + bufferbytes = ReadBytes(); + if (bufferbytes == 0) break; + } + char* p = (char *)buffer_ + readindex_; + while (*p != '\r' && *p != '\n' && p <= (char *)buffer_ + readindex_) + { + raw.append(p, 1); + readindex_++; + if (readlength_ - readindex_ == 0) break; + p++; + } + if (*p == '\r' || *p == '\n') + { + eol = TRUE; + readindex_++; + if (*p == '\r' && (readlength_ - readindex_ > 0) && *(p + 1) == '\n') + { + readindex_++; + } + } + } + if (raw.size() > 0) + { + DWORD cchWideChar = MultiByteToWideChar(CP_UTF8, 0, raw.c_str(), -1, NULL, 0); + WCHAR* wideChars = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, cchWideChar * sizeof(WCHAR)); + cchWideChar = MultiByteToWideChar(CP_UTF8, 0, raw.c_str(), -1, wideChars, cchWideChar); + std::wstring line(wideChars); + HeapFree(GetProcessHeap(), 0, wideChars); + return line; + } + return L""; +} + +BOOL StreamLineReader::EndOfStream() +{ + return ReadBytes() == 0; +} + +void StreamLineReader::Close() +{ + filestream_.Close(); +} \ No newline at end of file
diff --git a/tests/resources/issue_3020/StreamLineReader.h b/tests/resources/issue_3020/StreamLineReader.h new file mode 100644 index 0000000..1312b84 --- /dev/null +++ b/tests/resources/issue_3020/StreamLineReader.h
@@ -0,0 +1,44 @@ +/* Author: macote */ + +#ifndef STREAMLINEREADER_H_ +#define STREAMLINEREADER_H_ + +#include "FileStream.h" +#include <string> +#include <Windows.h> + +class StreamLineReader +{ +private: + static const DWORD kDefaultBufferSize = 32768; +public: + enum class Encoding + { + UTF8 + }; + StreamLineReader(FileStream& filestream, Encoding encoding, const DWORD buffersize) : filestream_(filestream), encoding_(encoding), buffersize_(buffersize) + { + AllocateBuffer(); + } + StreamLineReader(FileStream& filestream, Encoding encoding) : StreamLineReader(filestream, Encoding::UTF8, kDefaultBufferSize) { } + StreamLineReader(FileStream& filestream) : StreamLineReader(filestream, Encoding::UTF8) { } + ~StreamLineReader() + { + FreeBuffer(); + } + std::wstring ReadLine(); + BOOL EndOfStream(); + void Close(); +private: + void AllocateBuffer(); + void FreeBuffer(); + DWORD ReadBytes(); + FileStream& filestream_; + Encoding encoding_; + PBYTE buffer_; + DWORD buffersize_; + DWORD readindex_ = 0; + DWORD readlength_ = 0; +}; + +#endif /* STREAMLINEREADER_H_ */
diff --git a/tests/resources/issue_3020/StreamLineWriter.cpp b/tests/resources/issue_3020/StreamLineWriter.cpp new file mode 100644 index 0000000..6fd1a32 --- /dev/null +++ b/tests/resources/issue_3020/StreamLineWriter.cpp
@@ -0,0 +1,31 @@ +/* Author: macote */ + +#include "StreamLineWriter.h" + +void StreamLineWriter::Write(std::wstring line) +{ + if (line.size() > 0) + { + DWORD cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, line.c_str(), -1, NULL, 0, NULL, NULL); + LPSTR bytes = (LPSTR)HeapAlloc(GetProcessHeap(), 0, cbMultiByte); + cbMultiByte = WideCharToMultiByte(CP_UTF8, 0, line.c_str(), -1, bytes, cbMultiByte, NULL, NULL); + filestream_.Write((PBYTE)bytes, cbMultiByte - 1); + HeapFree(GetProcessHeap(), 0, bytes); + } +} + +void StreamLineWriter::WriteLine(std::wstring line) +{ + Write(line); + WriteEOL(); +} + +void StreamLineWriter::WriteEOL() +{ + filestream_.Write((PBYTE)"\r\n", 2); +} + +void StreamLineWriter::Close() +{ + filestream_.Close(); +} \ No newline at end of file
diff --git a/tests/resources/issue_3020/StreamLineWriter.h b/tests/resources/issue_3020/StreamLineWriter.h new file mode 100644 index 0000000..310d4ec --- /dev/null +++ b/tests/resources/issue_3020/StreamLineWriter.h
@@ -0,0 +1,32 @@ +/* Author: macote */ + +#ifndef STREAMLINEWRITER_H_ +#define STREAMLINEWRITER_H_ + +#include "FileStream.h" +#include <string> +#include <Windows.h> + +class StreamLineWriter +{ +public: + enum class Encoding + { + UTF8 + }; + StreamLineWriter(FileStream& filestream, Encoding encoding) : filestream_(filestream), encoding_(encoding) { } + StreamLineWriter(FileStream& filestream) : StreamLineWriter(filestream, Encoding::UTF8) { } + ~StreamLineWriter() + { + Close(); + } + void Write(std::wstring line); + void WriteLine(std::wstring line); + void Close(); +private: + void WriteEOL(); + FileStream& filestream_; + Encoding encoding_; +}; + +#endif /* STREAMLINEWRITER_H_ */
diff --git a/tests/resources/issue_3020/Window.cpp b/tests/resources/issue_3020/Window.cpp new file mode 100644 index 0000000..b5da400 --- /dev/null +++ b/tests/resources/issue_3020/Window.cpp
@@ -0,0 +1,79 @@ +/* Author: macote */ + +#include "Window.h" + +void Window::Register() +{ + WNDCLASS wc; + wc.style = 0; + wc.lpfnWndProc = Window::WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hinst_; + wc.hIcon = NULL; + wc.hCursor = LoadCursorW(NULL, IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); + wc.lpszMenuName = NULL; + wc.lpszClassName = ClassName(); + WinRegisterClass(&wc); +} + +LRESULT CALLBACK Window::WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + Window *self; + if (uMsg == WM_NCCREATE) + { + auto lpcs = reinterpret_cast<LPCREATESTRUCT>(lParam); + self = reinterpret_cast<Window *>(lpcs->lpCreateParams); + self->hwnd_ = hwnd; + SetWindowLongPtrW(hwnd, GWLP_USERDATA, reinterpret_cast<LPARAM>(self)); + } + else + { + self = reinterpret_cast<Window *>(GetWindowLongPtrW(hwnd, GWLP_USERDATA)); + } + if (self) + { + return self->HandleMessage(uMsg, wParam, lParam); + } + else + { + return DefWindowProcW(hwnd, uMsg, wParam, lParam); + } +} + +LRESULT Window::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + LRESULT lres; + switch (uMsg) + { + case WM_NCDESTROY: + lres = DefWindowProcW(hwnd_, uMsg, wParam, lParam); + SetWindowLongPtrW(hwnd_, GWLP_USERDATA, 0); + delete this; + return lres; + case WM_PAINT: + OnPaint(); + return 0; + case WM_PRINTCLIENT: + OnPrintClient(reinterpret_cast<HDC>(wParam)); + return 0; + } + return DefWindowProcW(hwnd_, uMsg, wParam, lParam); +} + +void Window::OnPaint() +{ + PAINTSTRUCT ps; + BeginPaint(hwnd_, &ps); + PaintContent(&ps); + EndPaint(hwnd_, &ps); +} + +void Window::OnPrintClient(HDC hdc) +{ + PAINTSTRUCT ps; + ps.hdc = hdc; + GetClientRect(hwnd_, &ps.rcPaint); + PaintContent(&ps); +} \ No newline at end of file
diff --git a/tests/resources/issue_3020/Window.h b/tests/resources/issue_3020/Window.h new file mode 100644 index 0000000..296246e --- /dev/null +++ b/tests/resources/issue_3020/Window.h
@@ -0,0 +1,38 @@ +/* Author: macote */ + +#ifndef WINDOW_H_ +#define WINDOW_H_ + +#include <Windows.h> + +class Window +{ +public: + HWND GetHWND() const { return hwnd_; } + Window(HINSTANCE hinst) : hinst_(hinst) { } +protected: + virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam); + virtual void PaintContent(PAINTSTRUCT *pps) { } + virtual LPCWSTR ClassName() = 0; + virtual BOOL WinRegisterClass(WNDCLASS *pwc) + { + return RegisterClassW(pwc); + } + virtual ~Window() { } + HWND WinCreateWindow(DWORD dwExStyle, LPCWSTR pszName, DWORD dwStyle, + int x, int y, int cx, int cy, HWND hwndParent, HMENU hmenu) + { + Register(); + return CreateWindowExW(dwExStyle, ClassName(), pszName, dwStyle, + x, y, cx, cy, hwndParent, hmenu, hinst_, this); + } + HWND hwnd_; + HINSTANCE hinst_; +private: + void Register(); + void OnPaint(); + void OnPrintClient(HDC hdc); + static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); +}; + +#endif /* WINDOW_H_ */ \ No newline at end of file
diff --git a/tests/resources/issue_3020/application.manifest b/tests/resources/issue_3020/application.manifest new file mode 100644 index 0000000..7f607eb --- /dev/null +++ b/tests/resources/issue_3020/application.manifest
@@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"> + <security> + <requestedPrivileges> + <requestedExecutionLevel level="asInvoker" uiAccess="false"/> + </requestedPrivileges> + </security> + </trustInfo> + <dependency> + <dependentAssembly> + <assemblyIdentity type="Win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" + processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/> + </dependentAssembly> + </dependency> +</assembly> \ No newline at end of file
diff --git a/tests/resources/issue_3020/resource.h b/tests/resources/issue_3020/resource.h new file mode 100644 index 0000000..b7c1818 --- /dev/null +++ b/tests/resources/issue_3020/resource.h
@@ -0,0 +1,8 @@ +/* Author: macote */ + +#ifndef RESOURCE_H_ +#define RESOURCE_H_ + +#define IDI_ICON1 101 + +#endif /* RESOURCE_H_ */
diff --git a/tests/resources/issue_3020/resource.rc b/tests/resources/issue_3020/resource.rc new file mode 100644 index 0000000..aedff65 --- /dev/null +++ b/tests/resources/issue_3020/resource.rc
@@ -0,0 +1,6 @@ +#include "resource.h" + +IDI_ICON1 ICON "HashCheck.ico" + +CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "application.manifest" +