[
  {
    "path": ".gitattributes",
    "content": "###############################################################################\n# Set default behavior to automatically normalize line endings.\n###############################################################################\n* text=auto\n\n###############################################################################\n# Set default behavior for command prompt diff.\n#\n# This is need for earlier builds of msysgit that does not have it on by\n# default for csharp files.\n# Note: This is only used by command line\n###############################################################################\n#*.cs     diff=csharp\n\n###############################################################################\n# Set the merge driver for project and solution files\n#\n# Merging from the command prompt will add diff markers to the files if there\n# are conflicts (Merging from VS is not affected by the settings below, in VS\n# the diff markers are never inserted). Diff markers may cause the following \n# file extensions to fail to load in VS. An alternative would be to treat\n# these files as binary and thus will always conflict and require user\n# intervention with every merge. To do so, just uncomment the entries below\n###############################################################################\n#*.sln       merge=binary\n#*.csproj    merge=binary\n#*.vbproj    merge=binary\n#*.vcxproj   merge=binary\n#*.vcproj    merge=binary\n#*.dbproj    merge=binary\n#*.fsproj    merge=binary\n#*.lsproj    merge=binary\n#*.wixproj   merge=binary\n#*.modelproj merge=binary\n#*.sqlproj   merge=binary\n#*.wwaproj   merge=binary\n\n###############################################################################\n# behavior for image files\n#\n# image files are treated as binary by default.\n###############################################################################\n#*.jpg   binary\n#*.png   binary\n#*.gif   binary\n\n###############################################################################\n# diff behavior for common document formats\n# \n# Convert binary document formats to text before diffing them. This feature\n# is only available from the command line. Turn it on by uncommenting the \n# entries below.\n###############################################################################\n#*.doc   diff=astextplain\n#*.DOC   diff=astextplain\n#*.docx  diff=astextplain\n#*.DOCX  diff=astextplain\n#*.dot   diff=astextplain\n#*.DOT   diff=astextplain\n#*.pdf   diff=astextplain\n#*.PDF   diff=astextplain\n#*.rtf   diff=astextplain\n#*.RTF   diff=astextplain\n"
  },
  {
    "path": ".github/workflows/msvc.yml",
    "content": "name: MSBuild\n\non:\n  push:\n  pull_request:\n    branches: [ \"main\" ]\n\nenv:\n  # Path to the solution file relative to the root of the project.\n  SOLUTION_FILE_PATH: mfcDuDownloadCodeGenerator.sln\n  BUILD_CONFIGURATION: Release\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    strategy:\n      matrix:\n        build_config:\n          - vs2019.x86_64\n          - vs2019.static.xp.x86\n          - vs2022.x86_64\n          - vs2022.static.x86_64\n\n        include:\n          - build_config: vs2019.x86_64\n            os: windows-2019\n          - build_config: vs2019.static.xp.x86\n            os: windows-2019\n          - build_config: vs2022.x86_64\n            os: windows-2022\n          - build_config: vs2022.static.x86_64\n            os: windows-2022\n\n    runs-on: \"${{ matrix.os }}\"\n\n    permissions:\n      contents: write\n\n    steps:\n    - name: 🛎️ checkout\n      uses: actions/checkout@v3\n\n    - name: 🏭 prepare MSBuild\n      uses: microsoft/setup-msbuild@v1.0.2\n\n    - name: 🏭 prepare msys2\n      uses: msys2/setup-msys2@v2\n      with:\n        update: true\n        install: >-\n          git\n          upx\n          zip\n\n    - name: 🔧 build\n      working-directory: ${{env.GITHUB_WORKSPACE}}\n      # Add additional options to the MSBuild command line here (like platform or verbosity level).\n      # See https://docs.microsoft.com/visualstudio/msbuild/msbuild-command-line-reference\n      run: |\n        Set-PSDebug -Trace 1\n\n        $config = \"${{ matrix.build_config }}\"\n        if ($config.Contains(\".static.\")) {\n          $env:_CL_ += ' /MT'\n          $mfc_type = 'Static'\n        } else {\n          $env:_CL_ += ' /MD'\n          $mfc_type = 'Dynamic'\n        }\n\n        $platform = if ($config.EndsWith('x86_64')) { \"x64\" } else { \"x86\" }\n        $toolset = if ($config.StartsWith('vs2022.')) { \"v143\" }\n          elseif ($config.Contains('.xp.')) { \"v141_xp\" }\n          else { \"v142\" }\n\n        if ($config.Contains('.xp.')) {\n          $env:_CL_ += ' /D__BUILD_FOR_XP=1'\n        }\n\n        msbuild /m `\n          /p:Configuration=${{ env.BUILD_CONFIGURATION }} `\n          /p:Platform=$platform `\n          /p:PlatformToolset=$toolset `\n          /p:UseOfMfc=$mfc_type `\n          ${{env.SOLUTION_FILE_PATH}}\n        \n        New-Item -ItemType Directory build\n        Move-Item -Path \".\\$platform\\${{ env.BUILD_CONFIGURATION }}\\*.exe\" `\n          -Destination \".\\build\\\"\n\n    - name: 🗜️ rename + optional upx\n      shell: msys2 {0}\n      run: |\n        set -ex\n\n        cd \"build\"\n        if [[ \"${{ matrix.build_config }}\" =~ \".static.\" ]]; then\n          upx -9 *.exe\n        fi\n        cp \"ducode.exe\" \"ducode.${{ matrix.build_config }}.exe\"\n\n    - name: 🗜️ archive binaries\n      uses: actions/upload-artifact@v3\n      with:\n        name: binaries\n        path: build/ducode.${{ matrix.build_config }}.exe\n\n    - name: 📦 package for release\n      if: startsWith(github.ref, 'refs/tags/v')\n      shell: msys2 {0}\n      run: |\n        set -ex\n\n        cd \"build\"\n        GIT_VERSION=\"${{github.ref}}\"\n        GIT_VERSION=\"${GIT_VERSION:10}\"\n        ZIP_NAME=\"ducode.${{ matrix.build_config }}.${GIT_VERSION}.zip\"\n        zip -9 \"../${ZIP_NAME}\" \"ducode.exe\"\n\n    - name: 📝 draft release\n      if: startsWith(github.ref, 'refs/tags/v')\n      uses: softprops/action-gh-release@v1\n      env:\n        GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n      with:\n        body: \"<to be filled>\"\n        draft: true\n        # note you'll typically need to create a personal access token\n        # with permissions to create releases in the other repo\n        token: ${{ secrets.CUSTOM_GITHUB_TOKEN }}\n        files: |\n          *.zip\n"
  },
  {
    "path": ".gitignore",
    "content": "## Ignore Visual Studio temporary files, build results, and\n## files generated by popular Visual Studio add-ons.\n\n# User-specific files\n*.suo\n*.user\n*.userosscache\n*.sln.docstates\n\n# User-specific files (MonoDevelop/Xamarin Studio)\n*.userprefs\n\n# Build results\n[Dd]ebug/\n[Dd]ebugPublic/\n[Rr]elease/\n[Rr]eleases/\nx64/\nx86/\nbld/\n[Bb]in/\n[Oo]bj/\n[Ll]og/\n\n# Visual Studio 2015 cache/options directory\n.vs/\n# Uncomment if you have tasks that create the project's static files in wwwroot\n#wwwroot/\n\n# MSTest test Results\n[Tt]est[Rr]esult*/\n[Bb]uild[Ll]og.*\n\n# NUNIT\n*.VisualState.xml\nTestResult.xml\n\n# Build Results of an ATL Project\n[Dd]ebugPS/\n[Rr]eleasePS/\ndlldata.c\n\n# DNX\nproject.lock.json\nproject.fragment.lock.json\nartifacts/\n\n*_i.c\n*_p.c\n*_i.h\n*.ilk\n*.meta\n*.obj\n*.pch\n*.pdb\n*.pgc\n*.pgd\n*.rsp\n*.sbr\n*.tlb\n*.tli\n*.tlh\n*.tmp\n*.tmp_proj\n*.log\n*.vspscc\n*.vssscc\n.builds\n*.pidb\n*.svclog\n*.scc\n\n# Chutzpah Test files\n_Chutzpah*\n\n# Visual C++ cache files\nipch/\n*.aps\n*.ncb\n*.opendb\n*.opensdf\n*.sdf\n*.cachefile\n*.VC.db\n*.VC.VC.opendb\n\n# Visual Studio profiler\n*.psess\n*.vsp\n*.vspx\n*.sap\n\n# TFS 2012 Local Workspace\n$tf/\n\n# Guidance Automation Toolkit\n*.gpState\n\n# ReSharper is a .NET coding add-in\n_ReSharper*/\n*.[Rr]e[Ss]harper\n*.DotSettings.user\n\n# JustCode is a .NET coding add-in\n.JustCode\n\n# TeamCity is a build add-in\n_TeamCity*\n\n# DotCover is a Code Coverage Tool\n*.dotCover\n\n# NCrunch\n_NCrunch_*\n.*crunch*.local.xml\nnCrunchTemp_*\n\n# MightyMoose\n*.mm.*\nAutoTest.Net/\n\n# Web workbench (sass)\n.sass-cache/\n\n# Installshield output folder\n[Ee]xpress/\n\n# DocProject is a documentation generator add-in\nDocProject/buildhelp/\nDocProject/Help/*.HxT\nDocProject/Help/*.HxC\nDocProject/Help/*.hhc\nDocProject/Help/*.hhk\nDocProject/Help/*.hhp\nDocProject/Help/Html2\nDocProject/Help/html\n\n# Click-Once directory\npublish/\n\n# Publish Web Output\n*.[Pp]ublish.xml\n*.azurePubxml\n# TODO: Comment the next line if you want to checkin your web deploy settings\n# but database connection strings (with potential passwords) will be unencrypted\n#*.pubxml\n*.publishproj\n\n# Microsoft Azure Web App publish settings. Comment the next line if you want to\n# checkin your Azure Web App publish settings, but sensitive information contained\n# in these scripts will be unencrypted\nPublishScripts/\n\n# NuGet Packages\n*.nupkg\n# The packages folder can be ignored because of Package Restore\n**/packages/*\n# except build/, which is used as an MSBuild target.\n!**/packages/build/\n# Uncomment if necessary however generally it will be regenerated when needed\n#!**/packages/repositories.config\n# NuGet v3's project.json files produces more ignoreable files\n*.nuget.props\n*.nuget.targets\n\n# Microsoft Azure Build Output\ncsx/\n*.build.csdef\n\n# Microsoft Azure Emulator\necf/\nrcf/\n\n# Windows Store app package directories and files\nAppPackages/\nBundleArtifacts/\nPackage.StoreAssociation.xml\n_pkginfo.txt\n\n# Visual Studio cache files\n# files ending in .cache can be ignored\n*.[Cc]ache\n# but keep track of directories ending in .cache\n!*.[Cc]ache/\n\n# Others\nClientBin/\n~$*\n*~\n*.dbmdl\n*.dbproj.schemaview\n*.jfm\n*.pfx\n*.publishsettings\nnode_modules/\norleans.codegen.cs\n\n# Since there are multiple workflows, uncomment next line to ignore bower_components\n# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)\n#bower_components/\n\n# RIA/Silverlight projects\nGenerated_Code/\n\n# Backup & report files from converting an old project file\n# to a newer Visual Studio version. Backup files are not needed,\n# because we have git ;-)\n_UpgradeReport_Files/\nBackup*/\nUpgradeLog*.XML\nUpgradeLog*.htm\n\n# SQL Server files\n*.mdf\n*.ldf\n\n# Business Intelligence projects\n*.rdl.data\n*.bim.layout\n*.bim_*.settings\n\n# Microsoft Fakes\nFakesAssemblies/\n\n# GhostDoc plugin setting file\n*.GhostDoc.xml\n\n# Node.js Tools for Visual Studio\n.ntvs_analysis.dat\n\n# Visual Studio 6 build log\n*.plg\n\n# Visual Studio 6 workspace options file\n*.opt\n\n# Visual Studio LightSwitch build output\n**/*.HTMLClient/GeneratedArtifacts\n**/*.DesktopClient/GeneratedArtifacts\n**/*.DesktopClient/ModelManifest.xml\n**/*.Server/GeneratedArtifacts\n**/*.Server/ModelManifest.xml\n_Pvt_Extensions\n\n# Paket dependency manager\n.paket/paket.exe\npaket-files/\n\n# FAKE - F# Make\n.fake/\n\n# JetBrains Rider\n.idea/\n*.sln.iml\n\n# CodeRush\n.cr/\n\n# Python Tools for Visual Studio (PTVS)\n__pycache__/\n*.pyc\n*.tlog\n\nvs2019_ci_static_xp/\n"
  },
  {
    "path": "LICENSE",
    "content": "BSD 3-Clause License\n\nCopyright (c) 2020, Jixun Wu\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice, this\n   list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright notice,\n   this list of conditions and the following disclaimer in the documentation\n   and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from\n   this software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\nDISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\nFOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\nSERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\nCAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\nOR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
  },
  {
    "path": "README.MD",
    "content": "# mfcDuDownloadCodeGenerator\nڰٶ̵ı׼ȡ\n\n![](https://cdn.jsdelivr.net/gh/JixunMoe/mfcDuDownloadCodeGenerator/imgs/sshot-stdcode.png)\n\n---\n\nģ\n\n* https://jixun.moe/post/du-code-gen\n* https://blog.jixun.moe/du-code-gen\n"
  },
  {
    "path": "generator/AdvEdit.cpp",
    "content": "// AdvEdit.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"AdvEdit.h\"\n\n// CAdvEdit\n\nIMPLEMENT_DYNAMIC(CAdvEdit, CEdit)\n\nCAdvEdit::CAdvEdit()\n{\n}\n\nCAdvEdit::~CAdvEdit()\n{\n}\n\nvoid CAdvEdit::Append(const CString& text)\n{\n\tstd::lock_guard<std::mutex> guard(mutex);\n\n\tauto nLength = GetWindowTextLength();\n\tSetSel(nLength, nLength);\n\tReplaceSel(text);\n}\n\nvoid CAdvEdit::SelectAll()\n{\n\tSetSel(0, GetWindowTextLength(), FALSE);\n}\n\nBEGIN_MESSAGE_MAP(CAdvEdit, CEdit)\n\tON_WM_KEYDOWN()\nEND_MESSAGE_MAP()\n\nvoid CAdvEdit::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)\n{\n\tCEdit::OnKeyDown(nChar, nRepCnt, nFlags);\n\n\tif (nChar == 'A') {\n\t\tBYTE keyState[256] = { 0 };\n\t\tGetKeyboardState(keyState);\n\t\tbool useControl = (keyState[VK_CONTROL] & 0x80) != 0;\n\t\tbool useShift = (keyState[VK_SHIFT] & 0x80) != 0;\n\t\tbool useAlt = (keyState[VK_MENU] & 0x80) != 0;\n\n\t\tif (useControl && !useShift && !useAlt) {\n\t\t\tthis->SelectAll();\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "generator/AdvEdit.h",
    "content": "#pragma once\n#include <mutex>\n\n\n// CAdvEdit\n\nclass CAdvEdit : public CEdit\n{\n\tDECLARE_DYNAMIC(CAdvEdit)\n\tstd::mutex mutex;\n\npublic:\n\tCAdvEdit();\n\tvirtual ~CAdvEdit();\n\tvoid Append(const CString &text);\n\tvoid SelectAll();\n\nprotected:\n\tDECLARE_MESSAGE_MAP()\npublic:\n\tafx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);\n};\n\n\n"
  },
  {
    "path": "generator/ClipboardHelper.cpp",
    "content": "#include \"stdafx.h\"\n#include \"ClipboardHelper.h\"\n\nvoid CopyStringToClipboard(CString& str, HWND hWnd) {\n\tauto pString = static_cast<const TCHAR*>(str);\n\tauto dwStrByteLen = (str.GetLength() + 1) * sizeof TCHAR;\n\n\tHGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, dwStrByteLen);\n\tif (!hMem) return;\n\n\tauto pLockedMem = GlobalLock(hMem);\n\tif (!pLockedMem) {\n\t\tGlobalFree(hMem);\n\t\treturn;\n\t}\n\tmemcpy(pLockedMem, pString, dwStrByteLen);\n\tGlobalUnlock(hMem);\n\n\tif (OpenClipboard(hWnd)) {\n\t\tEmptyClipboard();\n#ifndef _UNICODE\n\t\tSetClipboardData(CF_TEXT, hMem);\n#else\n\t\tSetClipboardData(CF_UNICODETEXT, hMem);\n#endif\n\t\tCloseClipboard();\n\t}\n}\n"
  },
  {
    "path": "generator/ClipboardHelper.h",
    "content": "#pragma once\n#include \"stdafx.h\"\n\nvoid CopyStringToClipboard(CString& str, HWND hWnd = nullptr);\n"
  },
  {
    "path": "generator/DPISupport.cpp",
    "content": "#include \"stdafx.h\"\n\n#include \"DPISupport.h\"\n\n#if !__BUILD_FOR_XP\n#include <ShellScalingApi.h>\n#include <VersionHelpers.h>\n\n#pragma comment(lib, \"Shcore\")\n#endif\n\nuint32_t DPISupport::GetWindowDPI(HWND hWnd) {\n  UINT xdpi = 0;\n  UINT ydpi = 0;\n\n#if !__BUILD_FOR_XP\n  // Windows 8.1 or higher\n  if (IsWindows8Point1OrGreater()) {\n    HMONITOR hMonitor = MonitorFromWindow(hWnd, MONITOR_DEFAULTTONEAREST);\n    LRESULT success =\n        GetDpiForMonitor(hMonitor, MDT_EFFECTIVE_DPI, &xdpi, &ydpi);\n    return success == S_OK ? ydpi : 96;\n  }\n#endif\n\n  HDC hDC = GetDC(hWnd);\n  ydpi = static_cast<UINT>(GetDeviceCaps(hDC, LOGPIXELSY));\n  ReleaseDC(hWnd, hDC);\n  return ydpi;\n}\n"
  },
  {
    "path": "generator/DPISupport.h",
    "content": "#pragma once\n\n#include <Windows.h>\n#include <cstdint>\n\nnamespace DPISupport {\n\tuint32_t GetWindowDPI(HWND hWnd);\n}\n"
  },
  {
    "path": "generator/FileItem.cpp",
    "content": "#include \"stdafx.h\"\n#include \"FileItem.h\"\n#include \"encoding.h\"\n#include \"base64.h\"\n#include \"resource.h\"\n\nCFileItem::CFileItem()\n{\n}\n\n\nCFileItem::~CFileItem()\n{\n\tSAFE_DELETE(m_pDirectory);\n\tSAFE_DELETE(m_pFilename);\n\tSAFE_DELETE(m_pFirstHash);\n\tSAFE_DELETE(m_pFullHash);\n\n\tif (m_hIcon)\n\t{\n\t\tDestroyIcon(m_hIcon);\n\t\tm_hIcon = nullptr;\n\t}\n}\n\nbool CFileItem::Done() const\n{\n\treturn m_pFullHash != nullptr;\n}\n\nCString CFileItem::GetSizeString() const\n{\n\tCString str;\n\tif (m_nSize == 0) {\n\t\tstr = TEXT(\"0\");\n\t\treturn str;\n\t}\n\n\tTCHAR sizes[][6] = {\n\t\t_T(\"B\"),\n\t\t_T(\"KB\"),\n\t\t_T(\"MB\"),\n\t\t_T(\"GB\"),\n\t\t_T(\"TB\"),\n\t\t_T(\"PB\")\n\t};\n\n\tauto power = log(double(m_nSize)) / log(1024);\n\tauto unit = int(floor(power));\n\tauto r = m_nSize / pow(1024, unit);\n\n\tstr.Format(_T(\"%.2f %s\"), r, sizes[unit]);\n\treturn str;\n}\n\nCString CFileItem::BDLink() const\n{\n\tCString result;\n\tCString dlCode = this->DownloadCode();\n\tutf8_str str = {};\n\tToUTF8(str, dlCode.GetBuffer());\n\tif (str.str == nullptr) {\n\t\tBOOL _ = result.LoadStringW(IDS_ERROR_ENCODE_FAIL);\n\t\treturn result;\n\t}\n\n\t// ʹ strlen ַСֹ base64 仯ݺ NUL ֽ\n\twchar_t* encoded = base64_encode(reinterpret_cast<unsigned char*>(str.str), strlen(str.str));\n\tfree(str.str);\n\n\tif (encoded == nullptr) {\n\t\tBOOL _ = result.LoadStringW(IDS_ERROR_ENCODE_FAIL);\n\t\treturn result;\n\t}\n\n\t// ƴӵַ\n\tresult.Append(_T(\"https://pan.baidu.com/#bdlink=\"));\n\tresult.Append(encoded);\n\n\tfree(encoded);\n\treturn result;\n}\n\nCString CFileItem::DownloadCode() const\n{\n\tCString str;\n\tif (Done())\n\t{\n\t\tstr.Format(_T(\"%s#%s#%llu#%s\"),\n\t\t\tm_pFullHash->GetString(),\n\t\t\tm_pFirstHash->GetString(),\n\t\t\tm_nSize,\n\t\t\tm_pFilename->GetString()\n\t\t);\n\t} else\n\t{\n\t\tstr.Format(_T(\"%s#%s#%llu#%s\\r\\n\"),\n\t\t\t_T(\"<md5(file)>\"),\n\t\t\t_T(\"<md5(256kb)>\"),\n\t\t\tm_nSize,\n\t\t\tm_pFilename->GetString()\n\t\t);\n\t}\n\treturn str;\n}\n"
  },
  {
    "path": "generator/FileItem.h",
    "content": "#pragma once\nclass CFileItem\n{\npublic:\n\tCString* m_pDirectory = nullptr;\n\tCString* m_pFilename = nullptr;\n\tHICON m_hIcon = nullptr;\n\tuint64_t m_nSize = 0;\n\n\tCString* m_pFirstHash = nullptr;\n\tCString* m_pFullHash = nullptr;\n\npublic:\n\tCFileItem();\n\t~CFileItem();\n\n\tbool Done() const;\n\tCString GetSizeString() const;\n\n\tCString BDLink() const;\n\tCString DownloadCode() const;\n};\n\n"
  },
  {
    "path": "generator/Hasher.cpp",
    "content": "﻿#include \"stdafx.h\"\n#include \"Hasher.h\"\n\n\nbool Hasher::Init()\n{\n\tauto bSuccess = false;\n\n\tif (CryptAcquireContext(&m_hCryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))\n\t{\n\t\tbSuccess = CryptCreateHash(m_hCryptProv, this->m_alg, NULL, NULL, &m_phHash);\n\n\t\tif (bSuccess) return bSuccess;\n\t}\n\tCleanup();\n\n\tif (CryptAcquireContext(&m_hCryptProv, nullptr, nullptr, PROV_RSA_FULL, NULL))\n\t{\n\t\tbSuccess = CryptCreateHash(m_hCryptProv, this->m_alg, NULL, NULL, &m_phHash);\n\n\t\tif (bSuccess) return bSuccess;\n\t}\n\tCleanup();\n\n\tif (CryptAcquireContext(&m_hCryptProv, nullptr, nullptr, PROV_RSA_FULL, CRYPT_NEWKEYSET))\n\t{\n\t\tbSuccess = CryptCreateHash(m_hCryptProv, this->m_alg, NULL, NULL, &m_phHash);\n\n\t\tif (bSuccess) return bSuccess;\n\t}\n\tCleanup();\n\n\treturn bSuccess;\n}\n\nHasher::Hasher(ALG_ID alg)\n{\n\tthis->m_alg = alg;\n}\n\n\nHasher::~Hasher()\n{\n}\n\nvoid Hasher::Cleanup()\n{\n\tif (m_hKey)\n\t{\n\t\tCryptDestroyKey(m_hKey);\n\t\tm_hKey = NULL;\n\t}\n\n\tif (m_phHash)\n\t{\n\t\tCryptDestroyHash(m_phHash);\n\t\tm_phHash = NULL;\n\t}\n\n\tif (m_hCryptProv)\n\t{\n\t\tCryptReleaseContext(m_hCryptProv, NULL);\n\t\tm_hCryptProv = NULL;\n\t}\n}\n\n\nCString* Hasher::GetHashStr()\n{\n\tDWORD dwDataLen;\n\tauto r = new CString(\"\");\n\tif (CryptGetHashParam(this->m_phHash, HP_HASHVAL, nullptr, &dwDataLen, 0))\n\t{\n\t\tBYTE* d = new BYTE[dwDataLen];\n\t\tCryptGetHashParam(this->m_phHash, HP_HASHVAL, d, &dwDataLen, 0);\n\t\tfor(DWORD i = 0; i < dwDataLen; i++)\n\t\t{\n\t\t\tr->AppendFormat(_T(\"%X%X\"), d[i] >> 4, d[i] & 0x0F);\n\t\t}\n\t\tdelete[] d;\n\t}\n\tCleanup();\n\n\treturn r;\n}\n\nvoid Hasher::Feed(char* str, int n) const\n{\n\tCryptHashData(m_phHash, LPBYTE(str), n, NULL);\n}\n"
  },
  {
    "path": "generator/Hasher.h",
    "content": "#pragma once\n#include <Wincrypt.h>\n\nclass Hasher\n{\n\tHCRYPTPROV m_hCryptProv = NULL;\n\tHCRYPTHASH m_phHash = NULL;\n\tHCRYPTKEY m_hKey = NULL;\n\tALG_ID m_alg = NULL;\n\npublic:\n\tbool Init();\n\tHasher(ALG_ID alg);\n\t~Hasher();\n\n\tvoid Cleanup();\n\n\tCString* GetHashStr();\n\tvoid Feed(char* str, int i) const;\n};\n\n"
  },
  {
    "path": "generator/ListBoxEx.cpp",
    "content": "﻿// ListBoxEx.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"ListBoxEx.h\"\n#include \"resource.h\"\n#include \"Hasher.h\"\n#include \"ClipboardHelper.h\"\n#include \"DPISupport.h\"\n\n#include <fstream>      // std::ifstream\n\n#define BD_FILE_HEADER_SIZE (256 * 1024)\nconstexpr double icon_base_dimention = 36.0;\n\n// CListBoxEx\n\nIMPLEMENT_DYNAMIC(CListBoxEx, CListBox)\nHICON CListBoxEx::m_hIconTick = nullptr;\nCString CListBoxEx::m_sPlaceholder;\nHFONT CListBoxEx::m_systemFont;\nCListBoxEx::CListBoxEx()\n{\n\t// init guard\n\tif (m_hIconTick == nullptr)\n\t{\n\t\tm_hIconTick = static_cast<HICON>(LoadImage(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_ICON_TICK), IMAGE_ICON, 16, 16, 0));\n\t\tint _ = m_sPlaceholder.LoadStringW(IDS_LIST_PLACEHOLDER);\n\n\t\tNONCLIENTMETRICS metrics = {};\n\t\tmetrics.cbSize = sizeof(metrics);\n\t\tSystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0);\n\t\tm_systemFont = CreateFontIndirect(&metrics.lfCaptionFont);\n\t\tCString placeholder;\n\t}\n}\n\nCListBoxEx::~CListBoxEx()\n{\n}\n\n\nBEGIN_MESSAGE_MAP(CListBoxEx, CListBox)\n\tON_WM_VKEYTOITEM_REFLECT()\n\tON_NOTIFY_EX_RANGE(TTN_NEEDTEXTW, 0, 0xFFFF, OnToolTipText)\n\tON_WM_PAINT()\nEND_MESSAGE_MAP()\n\n\n\n// CListBoxEx message handlers\nvoid CListBoxEx::GetVisibleRange(int& s, int& e)\n{\n\tauto maxIndex = this->GetCount() - 1;\n\te = s = GetTopIndex();\n\tRECT rect;\n\tthis->GetClientRect(&rect);\n\tauto height = rect.bottom - rect.top;\n\tauto currentHeight = 0;\n\n\twhile(e < maxIndex)\n\t{\n\t\tcurrentHeight += GetItemHeight(e);\n\t\tif (currentHeight >= height) break;\n\t\te++;\n\t}\n}\n\nbool CListBoxEx::ItemIsVisible(int nIndex)\n{\n\tint s, e;\n\tGetVisibleRange(s, e);\n\treturn s <= nIndex && nIndex <= e;\n}\n\nbool CListBoxEx::RedrawIfVisible(int i)\n{\n\tRECT rectItem;\n\tif (this->GetItemRect(i, &rectItem) != LB_ERR)\n\t{\n\t\tif (rectItem.bottom < 0) return false;\n\n\t\tRECT rectCtrl;\n\t\tthis->GetClientRect(&rectCtrl);\n\n\t\tif (rectItem.top <= rectCtrl.bottom - rectCtrl.top)\n\t\t{\n\t\t\tthis->InvalidateRect(&rectItem, FALSE);\n\t\t\treturn true;\n\t\t}\n\t}\n\n\treturn false;\n}\n\n\n// 4MB Buffer \n#define BUF_SIZE (1024*1024*4)\nvoid CListBoxEx::ProcessFiles(f_proc_file_callback cb, void* extra)\n{\n\tstd::lock_guard<std::mutex> guard(mutex);\n\tm_bStop = false;\n\n\tauto c = GetCount();\n\tchar* buffer = new char[BUF_SIZE];\n\tHasher hash(CALG_MD5);\n\tfor(auto i = 0; i < c; i++)\n\t{\n\t\tauto data = reinterpret_cast<CFileItem*>(GetItemData(i));\n\t\tif (data->Done())\n\t\t{\n\t\t\tcb(ProcType::INC_FILE, 0, data, extra);\n\t\t\tcontinue;\n\t\t}\n\n\t\tauto path(*data->m_pDirectory + _T(\"\\\\\") + *data->m_pFilename);\n\t\tstd::ifstream is(path, std::ifstream::binary);\n\n\t\tif (!is)\n\t\t{\n\t\t\tcb(ProcType::ERR_FILE, 0, nullptr, extra);\n\t\t\tis.close();\n\t\t\tbreak;\n\t\t}\n\n\t\tis.read(buffer, BD_FILE_HEADER_SIZE);\n\t\thash.Init();\n\t\thash.Feed(buffer, int(is.gcount()));\n\t\tdata->m_pFirstHash = hash.GetHashStr();\n\n\t\t// 已经读完了?\n\t\tif (is.eof()) {\n\t\t\tis.close();\n\n\t\t\t// 更新完整哈希\n\t\t\tdata->m_pFullHash = new CString(*data->m_pFirstHash);\n\n\t\t\t// 重绘 + 通知\n\t\t\tthis->RedrawIfVisible(i);\n\t\t\tcb(ProcType::INC_FILE, 0, data, extra);\n\t\t\tcontinue;\n\t\t}\n\n\t\tis.seekg(0, SEEK_SET);\n\t\thash.Init();\n\t\tdouble step = double(BUF_SIZE) / data->m_nSize;\n\t\tdouble prog = 0;\n\t\t\n\t\tdo\n\t\t{\n\t\t\tif (m_bStop)\n\t\t\t{\n\t\t\t\tis.close();\n\t\t\t\tdelete[] buffer;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tis.read(buffer, BUF_SIZE);\n\n\t\t\tauto eof = is.eof();\n\t\t\tif (!eof && is.fail())\n\t\t\t{\n#ifdef _DEBUG\n\t\t\t\tCString str;\n\t\t\t\tstr.Format(_T(\"state: %x (goodbit: 0, eof: 1, fail: 2, badbit: 4)\\n\"), is.rdstate());\n\t\t\t\tOutputDebugString(str);\n#endif\n\t\t\t\tcb(ProcType::ERR_FILE, 0, nullptr, extra);\n\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\thash.Feed(buffer, eof ? int(is.gcount()) : BUF_SIZE);\n\n\t\t\tif (eof)\n\t\t\t{\n\t\t\t\tdata->m_pFullHash = hash.GetHashStr();\n\n\t\t\t\tif (this->RedrawIfVisible(i))\n\t\t\t\t{\n#ifdef _DEBUG\n\t\t\t\t\tOutputDebugString(_T(\"Redraw item.\\n\"));\n#endif\n\n\t\t\t\t}\n\t\t\t\tcb(ProcType::INC_FILE, 0, data, extra);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tprog += step;\n\t\t\tcb(ProcType::FILE_PROG, prog, data, extra);\n\t\t} while (true);\n\t\tis.close();\n\t}\n\n\tdelete[] buffer;\n}\n\nvoid CListBoxEx::StopProcessing()\n{\n\tm_bStop = true;\n\t{\n\t\tstd::lock_guard<std::mutex> guard(mutex); \n\t}\n}\n\nvoid CListBoxEx::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)\n{\n\tuint32_t dpi = DPISupport::GetWindowDPI(GetSafeHwnd());\n\tauto dpi_scale = static_cast<double>(dpi) / 96.0;\n\n\tauto icon_height = static_cast<uint32_t>(dpi_scale * icon_base_dimention);\n\tauto icon_top_margin = static_cast<uint32_t>(dpi_scale * 8);\n\n\tlpMeasureItemStruct->itemHeight = icon_height + icon_top_margin * 2;\n}\n\nvoid CListBoxEx::DrawItemData(LPDRAWITEMSTRUCT lpDrawItemStruct, CFileItem* pItem)\n{\n\tuint32_t dpi = DPISupport::GetWindowDPI(GetSafeHwnd());\n\tauto dpi_scale = static_cast<double>(dpi) / 96.0;\n\n\tauto icon_width = static_cast<uint32_t>(dpi_scale * icon_base_dimention);\n\tauto icon_height = static_cast<uint32_t>(dpi_scale * icon_base_dimention);\n\tauto icon_tick_width = static_cast<uint32_t>(dpi_scale * 16.0);\n\tauto icon_tick_height = static_cast<uint32_t>(dpi_scale * 16.0);\n\tauto icon_right_margin = static_cast<uint32_t>(dpi_scale * 8.0);\n\tauto item_padding = static_cast<uint32_t>(dpi_scale * 4.0);\n\tauto text_line_margin = static_cast<uint32_t>(dpi_scale * 2.0);\n\n\tauto pDC = CDC::FromHandle(lpDrawItemStruct->hDC);\n\tpDC->SetBkMode(TRANSPARENT);\n\n\tCRect rectItem(lpDrawItemStruct->rcItem);\n\trectItem.DeflateRect(item_padding, item_padding, item_padding, item_padding);\n\tCRect rectIcon(rectItem.left, rectItem.top, rectItem.left + icon_width, rectItem.top + icon_height);\n\tCRect rectIconTick(\n\t\trectIcon.left,\n\t\trectIcon.top + icon_height - icon_tick_height,\n\t\trectIcon.left + icon_tick_width,\n\t\trectItem.top + icon_height - icon_tick_height\n\t);\n\tCRect rectText(rectIcon.right + icon_right_margin, rectItem.top, rectItem.right - icon_right_margin * 2, rectItem.bottom);\n\n\tauto action = lpDrawItemStruct->itemAction;\n\tauto state = lpDrawItemStruct->itemState;\n\n\tbool selected = (state & ODS_SELECTED) && (action & (ODA_SELECT | ODA_DRAWENTIRE));\n\tbool redraw = (action & ODA_DRAWENTIRE) || (!(state & ODS_SELECTED) && (action & ODA_SELECT));\n\n\tauto textColour = selected ? m_textSelected : m_text;\n\tauto descTextColour = selected ? m_descTextSelected : m_descText;\n\n\tCBrush brushBackground(selected ? m_bgSelected : m_bgClear);\n\tCBrush brushText(textColour);\n\tCBrush brushDescText(descTextColour);\n\n\tif (selected || redraw)\n\t{\n\t\tCString str;\n\t\tpDC->FillRect(&lpDrawItemStruct->rcItem, &brushBackground);\n\t\tpDC->DrawIcon(rectIcon.left, rectIcon.top, pItem->m_hIcon);\n\n\t\tif (pItem->m_pFullHash)\n\t\t{\n\t\t\tDrawIconEx(*pDC, rectIconTick.left, rectIconTick.top, m_hIconTick, icon_tick_width, icon_tick_height, NULL, nullptr, DI_NORMAL);\n\t\t}\n\n\t\tauto rect = rectText;\n\t\tpDC->SetTextColor(textColour);\n\t\trect.OffsetRect(text_line_margin, 0);\n\n\t\tstr.SetString(*pItem->m_pFilename);\n\t\tpDC->DrawText(str, str.GetLength(), rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS);\n\t\trect.OffsetRect(0, text_line_margin + pDC->GetTextExtent(str).cy);\n\n\n\t\tstr.Format(IDS_DIR, *pItem->m_pDirectory);\n\t\tpDC->SetTextColor(descTextColour);\n\t\tpDC->DrawText(str, str.GetLength(), rect, DT_LEFT | DT_SINGLELINE | DT_END_ELLIPSIS);\n\t\trect.OffsetRect(0, text_line_margin + pDC->GetTextExtent(str).cy);\n\n\t\tstr.Format(IDS_FILE_SIZE, pItem->GetSizeString());\n\t\tpDC->DrawText(str, str.GetLength(), rect, DT_LEFT | DT_SINGLELINE);\n\t\trect.OffsetRect(0, text_line_margin + pDC->GetTextExtent(str).cy);\n\t}\n}\n\nvoid CListBoxEx::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)\n{\n\tauto pData = GetItemDataPtr(lpDrawItemStruct->itemID);\n\tif (pData != (void*)-1) {\n\t\tthis->DrawItemData(lpDrawItemStruct, reinterpret_cast<CFileItem*>(pData));\n\t}\n\n}\n\nuint64_t FileSize(const wchar_t* name)\n{\n\tauto hFile = CreateFileW(\n\t\tname, GENERIC_READ, FILE_SHARE_READ, nullptr, \n\t\tOPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr\n\t);\n\tif (hFile == INVALID_HANDLE_VALUE) {\n\t\treturn 0; // could not open file\n\t}\n\tLARGE_INTEGER fs_large = {0};\n\tif (!GetFileSizeEx(hFile, &fs_large)) {\n\t\t// get file size failed\n\t\tfs_large.QuadPart = 0;\n\t}\n\tCloseHandle(hFile);\n\n\treturn static_cast<uint64_t>(fs_large.QuadPart);\n}\n\nint CListBoxEx::AddItem(const CString& srcDir, const CString& filename)\n{\n \tstd::lock_guard<std::mutex> guard(this->mutex);\n\n\tauto fullPath(srcDir + _T(\"\\\\\") + filename);\n\tauto fSize = FileSize(fullPath);\n\n\tauto index = this->AddString(_T(\"\"));\n\tauto data = new CFileItem();\n\tdata->m_pDirectory = new CString(srcDir);\n\tdata->m_pFilename = new CString(filename);\n\n\tSHFILEINFO shfi = {};\n\tSHGetFileInfo(fullPath, FILE_ATTRIBUTE_NORMAL, &shfi, sizeof(SHFILEINFO),\n\t\tSHGFI_USEFILEATTRIBUTES | SHGFI_ICON | SHGFI_SHELLICONSIZE);\n\n\tdata->m_hIcon = shfi.hIcon;\n\tdata->m_nSize = fSize;\n\n\tSetItemData(index, DWORD_PTR(data));\n\n\treturn 0;\n}\n\nvoid CListBoxEx::CopySelectedHashes()\n{\n\tCString str;\n\n\tfor (int i = 0; i < GetCount(); i++)\n\t{\n\t\tif (GetSel(i))\n\t\t{\n\t\t\tstr.AppendFormat(L\"%s\\r\\n\", reinterpret_cast<CFileItem*>(GetItemData(i))->DownloadCode().GetString());\n\t\t}\n\t}\n\n\tCopyStringToClipboard(str);\n}\n\nint CListBoxEx::VKeyToItem(UINT nKey, UINT nIndex)\n{\n\t// Returns –2 for no further action,\n\t// –1 for default action, or\n\t// a nonnegative number to specify an index of a\n\t// list box item on which to perform the default action for the keystroke.\n\n\tif(mutex.try_lock())\n\t{\n\t\tswitch (nKey)\n\t\t{\n\t\tcase 'E':\n\t\t\tfor (int i = 0; i < GetCount(); i++)\n\t\t\t\tSetSel(i, false);\n\n\t\t\tmutex.unlock();\n\t\t\treturn -2;\n\n\t\tcase 'C':\n\t\t\tthis->CopySelectedHashes();\n\t\t\tmutex.unlock();\n\t\t\treturn -2;\n\n\t\tcase 'D':\n\t\tcase VK_DELETE:\n\t\t\tfor (int i = GetCount() - 1; i >= 0; i--)\n\t\t\t{\n\t\t\t\tif (GetSel(i))\n\t\t\t\t{\n\t\t\t\t\tDeleteString(i);\n\t\t\t\t\tSetSel(i, true);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tmutex.unlock();\n\t\t\treturn -2;\n\n\t\t}\n\t\tmutex.unlock();\n\t\treturn -1;\n\t}\n\n\treturn -1;\n}\n\n\nvoid CListBoxEx::PreSubclassWindow()\n{\n\tCListBox::PreSubclassWindow();\n\tEnableToolTips(TRUE);\n}\n\nINT_PTR CListBoxEx::OnToolHitTest(CPoint point, TOOLINFO* pTI) const\n{\n\tRECT itemRect;\n\tBOOL isOutside = FALSE;\n\tint row = ItemFromPoint(point, isOutside);\n\tif (row == -1 || isOutside)\n\t\treturn -1;\n\n\tGetItemRect(row, &itemRect);\n\n\tpTI->rect = itemRect;\n\tpTI->hwnd = m_hWnd;\n\tpTI->uId = row;\n\tpTI->lpszText = LPSTR_TEXTCALLBACK;\n\treturn pTI->uId;\n}\n\nBOOL CListBoxEx::OnToolTipText(UINT id, NMHDR * pNMHDR, LRESULT * pResult)\n{\n\tauto pToolTip = AfxGetModuleThreadState()->m_pToolTip;\n\tif (pToolTip) pToolTip->SetMaxTipWidth(SHRT_MAX);\n\n\tauto ptText = reinterpret_cast<LPTOOLTIPTEXTW>(pNMHDR);\n\n\tauto pItem = reinterpret_cast<CFileItem*>(this->GetItemData(static_cast<int>(pNMHDR->idFrom)));\n\n\tCString str;\n\tstr.Format(IDS_FILE_INFO,\n\t\t*pItem->m_pFilename,\n\t\t*pItem->m_pDirectory,\n\t\t pItem->GetSizeString());\n\n\n\tauto strW = static_cast<const TCHAR*>(str);\n\tauto memSize = str.GetLength() * sizeof TCHAR + (2 * sizeof TCHAR);\n\tauto lpszText = (TCHAR*)calloc(memSize, 1);\n\tif (!lpszText) {\n\t\treturn FALSE;\n\t}\n\n\tmemcpy(lpszText, strW, memSize);\n\n\tptText->lpszText = lpszText;\n\n\t*pResult = 0;\n\n\treturn TRUE;\n\n}\n\nvoid CListBoxEx::OnPaint()\n{\n\tif (GetCount() == 0) {\n\t\tCPaintDC dc(this);\n\n\t\tCRect rect;\n\t\tthis->GetClientRect(rect);\n\t\tdc.SetTextColor(m_descText);\n\t\tdc.SelectObject(m_systemFont);\n\t\tdc.DrawText(m_sPlaceholder, m_sPlaceholder.GetLength(), rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE | DT_END_ELLIPSIS);\n\t}\n\telse {\n\t\tDefault();\n\t}\n}\n"
  },
  {
    "path": "generator/ListBoxEx.h",
    "content": "#pragma once\n#include <mutex>\n\n#include \"FileItem.h\"\n\n// CListBoxEx\n\nenum class ProcType\n{\n\tFILE_PROG,\n\tINC_FILE,\n\tERR_FILE\n};\n\ntypedef void(*f_proc_file_callback) (ProcType type, double progress, CFileItem* pItem, void* extra);\nclass CListBoxEx : public CListBox\n{\n\tDECLARE_DYNAMIC(CListBoxEx)\nprivate:\n\tstd::mutex mutex;\n\tstatic HICON m_hIconTick;\n\tstatic CString m_sPlaceholder;\n\tstatic HFONT m_systemFont;\n\tbool m_bStop = false;\n\npublic:\n\tCListBoxEx();\n\tvirtual ~CListBoxEx();\n\n\tCOLORREF m_bgSelected = RGB(204, 232, 255); // #cce8ff\n\tCOLORREF m_bgClear    = RGB(255, 255, 255);\n\tCOLORREF m_text = RGB(0, 0, 0);\n\tCOLORREF m_textSelected = RGB(0, 0, 0);\n\tCOLORREF m_descText = RGB(109, 109, 109);\n\tCOLORREF m_descTextSelected = RGB(109, 109, 109);\n\nprotected:\n\tDECLARE_MESSAGE_MAP()\n\npublic:\n\tvoid GetVisibleRange(int& s, int& e);\n\tbool ItemIsVisible(int nIndex);\n\tbool RedrawIfVisible(int i);\n\tvoid ProcessFiles(f_proc_file_callback cb, void* extra);\n\tvoid StopProcessing();\n\n\tafx_msg void OnPaint();\n\tvirtual void MeasureItem(LPMEASUREITEMSTRUCT /*lpMeasureItemStruct*/);\n\tvirtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);\n\tvirtual void PreSubclassWindow();\n\n\tvoid DrawItemData(LPDRAWITEMSTRUCT lpDrawItemStruct, CFileItem* pItem);\n\n\tint AddItem(const CString& srcDir, const CString& filename);\n\tvoid CopySelectedHashes();\n\tint VKeyToItem(UINT /*nKey*/, UINT /*nIndex*/);\n\tvirtual INT_PTR OnToolHitTest(CPoint point, TOOLINFO* pTI) const;\n\tBOOL OnToolTipText(UINT id, NMHDR* pNMHDR, LRESULT* pResult);\n};\n\n\n"
  },
  {
    "path": "generator/ProgressText.cpp",
    "content": "﻿// ProgressText.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n\n#include \"generator.h\"\n#include \"ProgressText.h\"\n#include \"DPISupport.h\"\n\nvoid inline shrink(CRect* rect) {\n\trect->left++;\n\trect->top++;\n\trect->right--;\n\trect->bottom--;\n}\n\n// CProgressText\n\nIMPLEMENT_DYNAMIC(CProgressText, CProgressCtrl)\n\nCProgressText::CProgressText()\n{\n\tInit();\n}\n\nCProgressText::~CProgressText()\n{\n\tSAFE_DELETE(text);\n}\n\nvoid CProgressText::Init()\n{\n\ttext = new CString(\"\");\n\n\tprogressForegroundBrush = new CBrush(progressForegroundColour);\n\tprogressBackgroundBrush = new CBrush(progressBackgroundColour);\n\tcomponentBorderBrush = new CBrush(componentBorderColour);\n\n\tfont = new CFont();\n}\n\nvoid CProgressText::SetCurrent(uint current)\n{\n\tthis->current = current;\n\tthis->SetPos(this->current);\n\tthis->UpdateText();\n}\n\nvoid CProgressText::SetMax(uint max)\n{\n\tthis->max = max;\n\tthis->SetRange32(0, max);\n\tthis->UpdateText();\n}\n\nvoid CProgressText::Increase()\n{\n\tthis->current++;\n\tthis->SetPos(this->current);\n\tthis->UpdateText();\n}\n\nvoid CProgressText::Reset()\n{\n\tthis->current = 0;\n\tthis->max = 0;\n\tthis->SetPos(0);\n\tthis->UpdateText();\n\tthis->RedrawWindow();\n}\n\nvoid CProgressText::UpdateText() {\n\tif (this->max == 0) {\n\t\tthis->percent = 0;\n\t\tthis->text->SetString(_T(\"\"));\n\t}\n\telse\n\t{\n\t\tthis->percent = double(this->current) / double(this->max);\n\t\tthis->text->Format(_T(\"%d / %d (%.2f%%)\"), this->current, this->max, this->percent * 100);\n\t}\n}\n\n\nBEGIN_MESSAGE_MAP(CProgressText, CProgressCtrl)\n\tON_WM_PAINT()\n\tON_WM_ERASEBKGND()\nEND_MESSAGE_MAP()\n\n\n\n// CProgressText message handlers\n\n\n\n\nvoid CProgressText::OnPaint()\n{\n\tCPaintDC dc(this); // device context for painting\n\t\t\t\t\t   // Do not call CProgressCtrl::OnPaint() for painting messages\n\n\tdouble dpi_scale = double(DPISupport::GetWindowDPI(GetSafeHwnd())) / 96.0;\n\n\tCRect rect;\n\tGetClientRect(&rect);\n\n\tCDC memDC;\n\tmemDC.CreateCompatibleDC(&dc);\n\tmemDC.SetMapMode(dc.GetMapMode());\n\tmemDC.SetViewportOrg(dc.GetViewportOrg());\n\tmemDC.IntersectClipRect(rect);\n\n\tCBitmap bmp;\n\tbmp.CreateCompatibleBitmap(&dc, rect.Width(), rect.Height());\n\tauto pOldBmp = memDC.SelectObject(&bmp);\n\n\tmemDC.SetBkMode(TRANSPARENT);\n\n\t// 绘制一圈边框\n\tmemDC.SelectObject(GetStockObject(DC_PEN));\n\tmemDC.SetDCPenColor(this->componentBorderColour);\n\tmemDC.Rectangle(rect);\n\n\t// 绘制四方形\n\t{\n\t\tauto rectProgress = rect;\n\t\tshrink(&rectProgress);\n\t\tmemDC.FillRect(rectProgress, this->progressBackgroundBrush);\n\n\t\trectProgress.right = rectProgress.left + LONG(rectProgress.Width() * this->percent);\n\t\tmemDC.FillRect(rectProgress, this->progressForegroundBrush);\n\t}\n\n\tauto font_height = static_cast<uint32_t>((rect.Height() - 4) * dpi_scale * 0.75);\n\tfont->DeleteObject();\n\tVERIFY(font->CreateFont(\n\t\tfont_height,               // nHeight\n\t\t0,                         // nWidth\n\t\t0,                         // nEscapement\n\t\t0,                         // nOrientation\n\t\tFW_NORMAL,                 // nWeight\n\t\tFALSE,                     // bItalic\n\t\tFALSE,                     // bUnderline\n\t\t0,                         // cStrikeOut\n\t\tANSI_CHARSET,              // nCharSet\n\t\tOUT_DEFAULT_PRECIS,        // nOutPrecision\n\t\tCLIP_DEFAULT_PRECIS,       // nClipPrecision\n\t\tDEFAULT_QUALITY,           // nQuality\n\t\tDEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily\n\t\t_T(\"Consolas\")));          // lpszFacename\n\n\tauto def_font = memDC.SelectObject(font);\n\tauto size = memDC.GetTextExtent(*text);\n\tauto x = rect.right - size.cx - 8;\n\tauto y = (rect.Height() - size.cy) / 2;\n\tmemDC.TextOut(x, y, *text, this->text->GetLength());\n\tmemDC.SelectObject(def_font);\n\n\t// 拷贝图片\n\tdc.BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, rect.left, rect.top, SRCCOPY);\n\n\t// 还原选择的对象\n\tmemDC.SelectObject(pOldBmp);\n}\n\n// ReSharper disable once CppMemberFunctionMayBeStatic\n// ReSharper disable once CppMemberFunctionMayBeConst\nBOOL CProgressText::OnEraseBkgnd(CDC* pDC)\n{\n\treturn TRUE;\n}\n"
  },
  {
    "path": "generator/ProgressText.h",
    "content": "#pragma once\n\n// CProgressText\n\nclass CProgressText : public CProgressCtrl\n{\n\tCFont* font;\n\tCOLORREF progressForegroundColour = RGB(62, 231, 152);\n\tCOLORREF progressBackgroundColour = RGB(0xE6, 0xE6, 0xE6);\n\tCOLORREF componentBorderColour = RGB(0xBC, 0xBC, 0xBC);\n\n\tCBrush* progressForegroundBrush;\n\tCBrush* progressBackgroundBrush;\n\tCBrush* componentBorderBrush;\n\tvoid Init();\n\n\tDECLARE_DYNAMIC(CProgressText)\n\tuint current = 0;\n\tuint max = 0;\n\tCString* text;\n\tdouble percent = 0;\n\npublic:\n\tCProgressText();\n\tvirtual ~CProgressText();\n\tvoid SetCurrent(uint current);\n\tvoid SetMax(uint max);\n\tvoid Increase();\n\tvoid Reset();\n\nprotected:\n\tDECLARE_MESSAGE_MAP()\n\tvoid UpdateText();\n\npublic:\n\tafx_msg void OnPaint();\n\tafx_msg BOOL OnEraseBkgnd(CDC* pDC);\n};\n\n\n"
  },
  {
    "path": "generator/ReadMe.txt",
    "content": "================================================================================\n    MICROSOFT FOUNDATION CLASS LIBRARY : generator Project Overview\n===============================================================================\n\nThe application wizard has created this generator application for\nyou.  This application not only demonstrates the basics of using the Microsoft\nFoundation Classes but is also a starting point for writing your application.\n\nThis file contains a summary of what you will find in each of the files that\nmake up your generator application.\n\ngenerator.vcxproj\n    This is the main project file for VC++ projects generated using an application wizard.\n    It contains information about the version of Visual C++ that generated the file, and\n    information about the platforms, configurations, and project features selected with the\n    application wizard.\n\ngenerator.vcxproj.filters\n    This is the filters file for VC++ projects generated using an Application Wizard. \n    It contains information about the assciation between the files in your project \n    and the filters. This association is used in the IDE to show grouping of files with\n    similar extensions under a specific node (for e.g. \".cpp\" files are associated with the\n    \"Source Files\" filter).\n\ngenerator.h\n    This is the main header file for the application.  It includes other\n    project specific headers (including Resource.h) and declares the\n    CApp application class.\n\ngenerator.cpp\n    This is the main application source file that contains the application\n    class CApp.\n\ngenerator.rc\n    This is a listing of all of the Microsoft Windows resources that the\n    program uses.  It includes the icons, bitmaps, and cursors that are stored\n    in the RES subdirectory.  This file can be directly edited in Microsoft\n    Visual C++. Your project resources are in 1033.\n\nres\\generator.ico\n    This is an icon file, which is used as the application's icon.  This\n    icon is included by the main resource file generator.rc.\n\nres\\generator.rc2\n    This file contains resources that are not edited by Microsoft\n    Visual C++. You should place all resources not editable by\n    the resource editor in this file.\n\n\n/////////////////////////////////////////////////////////////////////////////\n\nThe application wizard creates one dialog class:\n\nappDlg.h, appDlg.cpp - the dialog\n    These files contain your CAppDlg class.  This class defines\n    the behavior of your application's main dialog.  The dialog's template is\n    in generator.rc, which can be edited in Microsoft Visual C++.\n\n/////////////////////////////////////////////////////////////////////////////\n\nHelp Support:\n\nhlp\\generator.hhp\n    This file is a help project file. It contains the data needed to\n    compile the help files into a .chm file.\n\nhlp\\generator.hhc\n    This file lists the contents of the help project.\n\nhlp\\generator.hhk\n    This file contains an index of the help topics.\n\nhlp\\afxcore.htm\n    This file contains the standard help topics for standard MFC\n    commands and screen objects. Add your own help topics to this file.\n\nmakehtmlhelp.bat\n    This file is used by the build system to compile the help files.\n\nhlp\\Images\\*.gif\n    These are bitmap files required by the standard help file topics for\n    Microsoft Foundation Class Library standard commands.\n\n\n/////////////////////////////////////////////////////////////////////////////\n\nOther standard files:\n\nStdAfx.h, StdAfx.cpp\n    These files are used to build a precompiled header (PCH) file\n    named generator.pch and a precompiled types file named StdAfx.obj.\n\nResource.h\n    This is the standard header file, which defines new resource IDs.\n    Microsoft Visual C++ reads and updates this file.\n\ngenerator.manifest\n\tApplication manifest files are used by Windows XP to describe an applications\n\tdependency on specific versions of Side-by-Side assemblies. The loader uses this\n\tinformation to load the appropriate assembly from the assembly cache or private\n\tfrom the application. The Application manifest  maybe included for redistribution\n\tas an external .manifest file that is installed in the same folder as the application\n\texecutable or it may be included in the executable in the form of a resource.\n/////////////////////////////////////////////////////////////////////////////\n\nOther notes:\n\nThe application wizard uses \"TODO:\" to indicate parts of the source code you\nshould add to or customize.\n\nIf your application uses MFC in a shared DLL, you will need\nto redistribute the MFC DLLs. If your application is in a language\nother than the operating system's locale, you will also have to\nredistribute the corresponding localized resources MFC100XXX.DLL.\nFor more information on both of these topics, please see the section on\nredistributing Visual C++ applications in MSDN documentation.\n\n/////////////////////////////////////////////////////////////////////////////\n"
  },
  {
    "path": "generator/appDlg.cpp",
    "content": "﻿\n// appDlg.cpp : implementation file\n//\n\n#include \"stdafx.h\"\n#include \"generator.h\"\n#include \"appDlg.h\"\n#include \"afxdialogex.h\"\n#include \"utils.h\"\n#include \"base64.h\"\n#include \"ClipboardHelper.h\"\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\n// CAboutDlg dialog used for App About\n\nclass CAboutDlg : public CDialogEx\n{\npublic:\n\tCAboutDlg();\n\n// Dialog Data\n#ifdef AFX_DESIGN_TIME\n\tenum { IDD = IDD_ABOUTBOX };\n#endif\n\n\tprotected:\n\tvirtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support\n\n// Implementation\nprotected:\n\tDECLARE_MESSAGE_MAP()\npublic:\n//\tvoid AddFile(CString& srcDir, CString& filename);\n};\n\nCAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)\n{\n}\n\nvoid CAboutDlg::DoDataExchange(CDataExchange* pDX)\n{\n\tCDialogEx::DoDataExchange(pDX);\n}\n\nBEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)\nEND_MESSAGE_MAP()\n\n\n// CAppDlg dialog\n\n\n\nCAppDlg::CAppDlg(CWnd* pParent /*=NULL*/)\n\t: CDialogEx(IDD_GENERATOR_DIALOG, pParent)\n{\n\tm_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);\n}\n\nvoid CAppDlg::DoDataExchange(CDataExchange* pDX)\n{\n\tCDialogEx::DoDataExchange(pDX);\n\tDDX_Control(pDX, IDC_PROG_FILE, m_progFile);\n\tDDX_Control(pDX, IDC_PROG_ALL, m_progAll);\n\tDDX_Control(pDX, IDC_LIST_FILES, m_listFiles);\n\tDDX_Control(pDX, IDC_EDIT_OUTPUT, m_editOutput);\n\tDDX_Control(pDX, IDC_CHK_RECURSIVE, m_chkRecursive);\n\tDDX_Control(pDX, IDC_CHK_URL, m_chkUrl);\n\tDDX_Control(pDX, IDC_SYSLINK_BLOG, m_linkBlog);\n\tDDX_Control(pDX, IDC_BTN_ADD_DIR, m_btnAddDir);\n\tDDX_Control(pDX, IDC_BTN_ADD_FILE, m_btnAddFile);\n\tDDX_Control(pDX, IDC_BTN_CLEAR, m_btnClear);\n\tDDX_Control(pDX, IDC_BTN_COPY, m_btnCopy);\n\tDDX_Control(pDX, IDC_BTN_GENERATE, m_btnGenerate);\n}\n\n// NM_CLICK = -2\nconstexpr UINT NM_CLICK_WITHOUT_WARNING = UINT(-2);\n\nBEGIN_MESSAGE_MAP(CAppDlg, CDialogEx)\n\tON_WM_SYSCOMMAND()\n\tON_WM_PAINT()\n\tON_WM_QUERYDRAGICON()\n\tON_BN_CLICKED(IDC_BTN_GENERATE, &CAppDlg::OnBnClickedGenerate)\n\tON_BN_CLICKED(IDC_BTN_ADD_DIR, &CAppDlg::OnClickedBtnAddDir)\n\tON_BN_CLICKED(IDC_BTN_ADD_FILE, &CAppDlg::OnClickedBtnAddFile)\n\tON_BN_CLICKED(IDC_BTN_CLEAR, &CAppDlg::OnBnClickedBtnClear)\n\tON_WM_DROPFILES()\n\tON_NOTIFY(NM_CLICK_WITHOUT_WARNING, IDC_SYSLINK_BLOG, &CAppDlg::OnClickSyslinkBlog)\n\tON_BN_CLICKED(IDC_BTN_COPY, &CAppDlg::OnBnClickedBtnCopy)\nEND_MESSAGE_MAP()\n\n\n// CAppDlg message handlers\n\nBOOL CAppDlg::OnInitDialog()\n{\n\tCDialogEx::OnInitDialog();\n\n\tAppendVersionNumber();\n\n\t// Set the icon for this dialog.  The framework does this automatically\n\t//  when the application's main window is not a dialog\n\tSetIcon(m_hIcon, TRUE);\t\t// Set big icon\n\tSetIcon(m_hIcon, FALSE);\t\t// Set small icon\n\n\tCRegKey reg;\n\tif (reg.Open(HKEY_CURRENT_USER, _T(\"Software\\\\Jixun.Moe\\\\DuGenerator\"), KEY_READ) == ERROR_SUCCESS)\n\t{\n\t\tDWORD dwLang;\n\t\tif (reg.QueryDWORDValue(_T(\"LANG_ID\"), dwLang) == ERROR_SUCCESS)\n\t\t{\n\t\t\tSetThreadUILanguage(LANGID(dwLang));\n\t\t}\n\n\t\treg.Close();\n\t}\n\n\tstd::ignore = m_ofn_file_title.LoadString(IDS_PICK_FILE);\n\tstd::ignore = m_ofn_dir_title.LoadString(IDS_PICK_DIR);\n\n\tm_progFile.SetRange(0, 10000);\n\n\t// 初始化目录选择\n\tstd::ignore = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);\n\n\tm_editOutput.SetLimitText(0);\n\n#if _DEBUG\n\t{\n\t\tchar buffer[32];\n\t\tsprintf_s(buffer, sizeof(buffer), \"text limit: 0x%08x\\n\", m_editOutput.GetLimitText());\n\t\tOutputDebugStringA(buffer);\n\t}\n#endif\n\n\treturn TRUE;  // return TRUE  unless you set the focus to a control\n}\n\nvoid CAppDlg::OnSysCommand(UINT nID, LPARAM lParam)\n{\n\tif ((nID & 0xFFF0) == IDM_ABOUTBOX)\n\t{\n\t\tCAboutDlg dlgAbout;\n\t\tdlgAbout.DoModal();\n\t}\n\telse\n\t{\n\t\tCDialogEx::OnSysCommand(nID, lParam);\n\t}\n}\n\n// If you add a minimize button to your dialog, you will need the code below\n//  to draw the icon.  For MFC applications using the document/view model,\n//  this is automatically done for you by the framework.\n\nvoid CAppDlg::OnPaint()\n{\n\tif (IsIconic())\n\t{\n\t\tCPaintDC dc(this); // device context for painting\n\n\t\tSendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);\n\n\t\t// Center icon in client rectangle\n\t\tint cxIcon = GetSystemMetrics(SM_CXICON);\n\t\tint cyIcon = GetSystemMetrics(SM_CYICON);\n\t\tCRect rect;\n\t\tGetClientRect(&rect);\n\t\tint x = (rect.Width() - cxIcon + 1) / 2;\n\t\tint y = (rect.Height() - cyIcon + 1) / 2;\n\n\t\t// Draw the icon\n\t\tdc.DrawIcon(x, y, m_hIcon);\n\t}\n\telse\n\t{\n\t\tCDialogEx::OnPaint();\n\t}\n}\n\n// The system calls this function to obtain the cursor to display while the user drags\n//  the minimized window.\nHCURSOR CAppDlg::OnQueryDragIcon()\n{\n\treturn static_cast<HCURSOR>(m_hIcon);\n}\n\nvoid WINAPI _thread_process_file(CAppDlg* app)\n{\n\tapp->ProcessFiles();\n}\n\n\nvoid CAppDlg::OnBnClickedGenerate()\n{\n\tCreateThread(nullptr, 0, LPTHREAD_START_ROUTINE(_thread_process_file), this, 0, nullptr);\n}\n\nvoid cb_add_file(const CString &srcDir, const CString &filename, void* extra)\n{\n\tstatic_cast<CAppDlg*>(extra)->AddFile(srcDir, filename);\n}\n\nvoid CAppDlg::OnClickedBtnAddDir()\n{\n\tauto dirs = OpenDirectoryDialog(m_ofn_dir_title, GetSafeHwnd());\n\tfor(auto& dir : dirs)\n\t{\n\t\tEnumFiles(*dir, BST_CHECKED == m_chkRecursive.GetCheck(), cb_add_file, this);\n\t\tdelete dir;\n\t}\n}\n\n\nvoid CAppDlg::OnClickedBtnAddFile()\n{\n\tauto v = OpenFileDialog(this->m_ofn_file_title, GetSafeHwnd());\n\tfor(auto file : v)\n\t{\n\t\tCString path(*file);\n\t\tauto pos = path.ReverseFind(_T('\\\\'));\n\t\tm_listFiles.AddItem(path.Left(pos), path.Right(path.GetLength() - pos - 1));\n\t\tdelete file;\n\t}\n}\n\nvoid CAppDlg::AddFile(const CString& srcDir, const CString& filename)\n{\n\tm_listFiles.AddItem(srcDir, filename);\n}\n\nvoid _proc_file_callback(ProcType type, double progress, CFileItem* lpItem, void* extra)\n{\n\tstatic_cast<CAppDlg*>(extra)->ProcFile(type, progress, lpItem);\n}\n\nvoid CAppDlg::ProcessFiles()\n{\n\tstd::lock_guard<std::mutex> guard(mutex);\n\n\tOutputDebugString(_T(\"Begin read file...\"));\n\tm_progAll.SetMax(m_listFiles.GetCount());\n\tm_progAll.SetCurrent(0);\n\tm_progFile.SetPos(0);\n\t\n\tm_btnAddDir.EnableWindow(FALSE);\n\tm_btnAddFile.EnableWindow(FALSE);\n\tm_btnCopy.EnableWindow(FALSE);\n\tm_btnClear.EnableWindow(FALSE);\n\tm_btnGenerate.EnableWindow(FALSE);\n\n\tm_listFiles.ProcessFiles(_proc_file_callback, this);\n\n\tm_btnAddDir.EnableWindow(TRUE);\n\tm_btnAddFile.EnableWindow(TRUE);\n\tm_btnCopy.EnableWindow(TRUE);\n\tm_btnClear.EnableWindow(TRUE);\n\tm_btnGenerate.EnableWindow(TRUE);\n}\n\nvoid CAppDlg::AddHashEntry(CFileItem* data)\n{\n\tif (m_editOutput.GetWindowTextLengthW() > 0) {\n\t\tm_editOutput.Append(_T(\"\\r\\n\"));\n\t}\n\n\tif (m_chkUrl.GetCheck() == BST_CHECKED) {\n\t\tm_editOutput.Append(data->BDLink());\n\t}\n\telse {\n\t\tm_editOutput.Append(data->DownloadCode());\n\t}\n}\n\nvoid CAppDlg::ProcFile(ProcType proc, double progress, CFileItem* lp_item)\n{\n\tswitch(proc)\n\t{\n\tcase ProcType::FILE_PROG: \n\t\tm_progFile.SetPos(int(progress * 10000));\n\t\tbreak;\n\n\tcase ProcType::INC_FILE:\n\t\tm_progFile.SetPos(0);\n\t\tm_progAll.Increase();\n\t\tAddHashEntry(lp_item);\n\t\tbreak;\n\n\tcase ProcType::ERR_FILE:\n\t\tOutputDebugString(_T(\"Failed to process file.\\n\"));\n\t\tm_progAll.Increase(); \n\t\tbreak;\n\n\tdefault: ;\n\t}\n}\n\nvoid CAppDlg::RealExit()\n{\n\tm_listFiles.StopProcessing();\n\n\t// TODO: Clean up.\n\n\tCDialogEx::OnCancel();\n}\n\nvoid CAppDlg::AppendVersionNumber()\n{\n\tCString csEntry;\n\tHMODULE hLib = AfxGetResourceHandle();\n\n\tHRSRC hVersion = FindResource(hLib, MAKEINTRESOURCE(VS_VERSION_INFO), RT_VERSION);\n\tif (hVersion == nullptr) return;\n\n\tHGLOBAL hGlobal = LoadResource(hLib, hVersion);\n\tif (hGlobal == nullptr) {\n\t\tFreeResource(hVersion);\n\t\treturn;\n\t}\n\n\tLPVOID versionInfo = LockResource(hGlobal);\n\tif (versionInfo == nullptr) {\n\t\tUnlockResource(hGlobal);\n\t\tFreeResource(hVersion);\n\t\treturn;\n\t}\n\n\tLPVOID lpBuffer = nullptr;\n\tUINT dwCharCount = 0;\n\n\tif (VerQueryValue(versionInfo, L\"\\\\StringFileInfo\\\\080004B0\\\\FileVersion\", &lpBuffer, &dwCharCount)) {\n\t\tCString strTitle;\n\t\tGetWindowText(strTitle);\n\n\t\tauto strVersionString = new TCHAR[dwCharCount + 1];\n\t\tmemcpy(strVersionString, lpBuffer, dwCharCount * sizeof(TCHAR));\n\t\tstrVersionString[dwCharCount] = 0;\n\n\t\tauto pLastDot = _tcsrchr(strVersionString, _T('.'));\n\t\tif (pLastDot != nullptr) {\n\t\t\t*pLastDot = 0;\n\t\t}\n\n\t\tstrTitle += _T(\" (v\");\n\t\tstrTitle += strVersionString;\n\t\tstrTitle += _T(\")\");\n\t\tSetWindowText(strTitle);\n\n\t\tdelete[] strVersionString;\n\t}\n\n\tUnlockResource(hGlobal);\n\tFreeResource(hVersion);\n}\n\nDWORD WINAPI _thread_stop_process(void* param)\n{\n\tstatic_cast<CAppDlg*>(param)->RealExit();\n\treturn 0;\n}\n\nvoid CAppDlg::OnCancel()\n{\n\t// 若为 ESC 导致的关闭窗口，无视它。\n\tif ((GetKeyState(VK_ESCAPE) & 0x8000) != 0) {\n\t\treturn;\n\t}\n\n\tCreateThread(nullptr, 0, _thread_stop_process, this, 0, nullptr);\n}\n\n\nvoid CAppDlg::OnBnClickedBtnClear()\n{\n\tm_listFiles.ResetContent();\n\tm_progAll.Reset();\n\tm_editOutput.SetWindowText(_T(\"\"));\n}\n\n\nvoid CAppDlg::OnDropFiles(HDROP hDropInfo)\n{\n\tCString path;\n\n\tint nFilesDropped = DragQueryFile(hDropInfo, 0xFFFFFFFF, nullptr, 0);\n\n\tfor (int i = 0; i<nFilesDropped; i++)\n\t{\n\t\tDWORD nBuffer = DragQueryFile(hDropInfo, i, nullptr, 0) + sizeof TCHAR;\n\n\t\tDragQueryFile(hDropInfo, i, path.GetBuffer(nBuffer), nBuffer);\n\t\tpath.ReleaseBuffer();\n\n\t\tauto isDir = (GetFileAttributes(path) | FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;\n\t\tif (isDir)\n\t\t{\n\t\t\tEnumFiles(path, BST_CHECKED == m_chkRecursive.GetCheck(), cb_add_file, this);\n\t\t} else\n\t\t{\n\t\t\tauto pos = path.ReverseFind(_T('\\\\'));\n\t\t\tm_listFiles.AddItem(path.Left(pos), path.Right(path.GetLength() - pos - 1));\n\t\t}\n\n\t\tOutputDebugString(path.GetString());\n\t\tOutputDebugString(_T(\"\\r\\n\"));\n\t}\n\n\tDragFinish(hDropInfo);\n\tCDialogEx::OnDropFiles(hDropInfo);\n}\n\n\n// ReSharper disable once CppMemberFunctionMayBeStatic\n// ReSharper disable once CppMemberFunctionMayBeConst\nvoid CAppDlg::OnClickSyslinkBlog(NMHDR *pNMHDR, LRESULT *pResult)\n{\n\tShellExecute(nullptr, _T(\"open\"), PNMLINK(pNMHDR)->item.szUrl, nullptr, nullptr, SW_SHOWNORMAL);\n\t*pResult = 0;\n}\n\n\n// ReSharper disable once CppMemberFunctionMayBeConst\nvoid CAppDlg::OnBnClickedBtnCopy()\n{\n\tCString str;\n\tm_editOutput.GetWindowText(str);\n\tCopyStringToClipboard(str, GetSafeHwnd());\n}\n"
  },
  {
    "path": "generator/appDlg.h",
    "content": "\n// appDlg.h : header file\n//\n\n#pragma once\n\n#include \"ProgressText.h\"\n#include \"AdvEdit.h\"\n#include \"ListBoxEx.h\"\n#include \"afxwin.h\"\n#include \"afxcmn.h\"\n\n// CAppDlg dialog\nclass CAppDlg : public CDialogEx\n{\n\tCString m_ofn_file_title;\n\tCString m_ofn_dir_title;\n\n\tstd::mutex mutex;\n\n// Construction\npublic:\n\tCAppDlg(CWnd* pParent = NULL);\t// standard constructor\n\tvoid AddFile(const CString& srcDir, const CString& filename);\n\tvoid ProcessFiles();\n\tvoid AddHashEntry(CFileItem* lp_item);\n\tvoid ProcFile(ProcType proc, double progress, CFileItem* lp_item);\n\tvoid RealExit();\n\tvoid AppendVersionNumber();\n\tstd::vector<CString*> files;\n\n// Dialog Data\n#ifdef AFX_DESIGN_TIME\n\tenum { IDD = IDD_GENERATOR_DIALOG };\n#endif\n\n\tprotected:\n\tvirtual void DoDataExchange(CDataExchange* pDX);\t// DDX/DDV support\n\n\n// Implementation\nprotected:\n\tHICON m_hIcon;\n\n\t// Generated message map functions\n\tvirtual BOOL OnInitDialog();\n\tafx_msg void OnSysCommand(UINT nID, LPARAM lParam);\n\tafx_msg void OnPaint();\n\tafx_msg HCURSOR OnQueryDragIcon();\n\tDECLARE_MESSAGE_MAP()\npublic:\n\tafx_msg void OnBnClickedGenerate();\n\t// Current file Progress\n\tCProgressCtrl m_progFile;\n\tCProgressText m_progAll;\n\tCListBoxEx m_listFiles;\n\tCAdvEdit m_editOutput;\n\tafx_msg void OnClickedBtnAddDir();\n\tafx_msg void OnClickedBtnAddFile();\n\tvirtual void OnCancel();\n\tafx_msg void OnBnClickedBtnClear();\n\tafx_msg void OnDropFiles(HDROP hDropInfo);\n\tCButton m_chkRecursive;\n\tCButton m_chkUrl;\n\tCLinkCtrl m_linkBlog;\n\tafx_msg void OnClickSyslinkBlog(NMHDR *pNMHDR, LRESULT *pResult);\n\tafx_msg void OnBnClickedBtnCopy();\n\tCButton m_btnAddDir;\n\tCButton m_btnAddFile;\n\tCButton m_btnClear;\n\tCButton m_btnCopy;\n\tCButton m_btnGenerate;\n};\n"
  },
  {
    "path": "generator/base64.cpp",
    "content": "/*\n* Base64 encoding/decoding (RFC1341)\n* Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>\n*\n* This software may be distributed under the terms of the BSD license.\n* See README for more details.\n*/\n\n// Change log:\n// 2016-12-12 - Gaspard Petit : Slightly modified to return a std::string \n//                              instead of a buffer allocated with malloc.\n// 2020-12-08 - Jixun: Taken from StackOverflow and adapted to project.\n//                     source: https://stackoverflow.com/a/41094722\n\n#include \"stdafx.h\"\n#include \"base64.h\"\n\nstatic const wchar_t base64_table[] = L\"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\";\n\n/**\n* base64_encode - Base64 encode\n* @src:     Data to be encoded\n* @len:     Length of the data to be encoded\n* @out_len: Pointer to output length variable, or %NULL if not used\n* Returns:  Allocated buffer of out_len bytes of encoded data,\n*           or empty string on failure\n*/\nwchar_t* base64_encode(const unsigned char* src, size_t len)\n{\n    const unsigned char* end, * in;\n\n    size_t olen;\n\n    olen = 4 * ((len + 2) / 3); /* 3-byte blocks to 4-byte */\n\n    if (olen < len)\n        return nullptr;\n\n    wchar_t* out = (wchar_t*)calloc(olen + 1, sizeof(wchar_t));\n    if (out == nullptr) {\n        return nullptr;\n    }\n\n    end = src + len;\n    in = src;\n    auto pos = out;\n    while (end - in >= 3) {\n        *pos++ = base64_table[in[0] >> 2];\n        *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];\n        *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];\n        *pos++ = base64_table[in[2] & 0x3f];\n        in += 3;\n    }\n\n    if (end - in) {\n        *pos++ = base64_table[in[0] >> 2];\n        if (end - in == 1) {\n            *pos++ = base64_table[(in[0] & 0x03) << 4];\n            *pos++ = L'=';\n        }\n        else {\n            *pos++ = base64_table[((in[0] & 0x03) << 4) |\n                (in[1] >> 4)];\n            *pos++ = base64_table[(in[1] & 0x0f) << 2];\n        }\n        *pos++ = L'=';\n    }\n\n    return out;\n}\n"
  },
  {
    "path": "generator/base64.h",
    "content": "#pragma once\n#include <string>\n\nwchar_t* base64_encode(const unsigned char* src, size_t len);\n"
  },
  {
    "path": "generator/encoding.cpp",
    "content": "#include \"stdafx.h\"\n#include \"encoding.h\"\n\nvoid ToUTF8(utf8_str& output, wchar_t* input)\n{\n\tsize_t out_size = WideCharToMultiByte(CP_UTF8, 0, input, -1, nullptr, 0, NULL, NULL);\n\toutput.str = (char*)calloc(out_size + 1, sizeof(char));\n\toutput.size = out_size;\n\tWideCharToMultiByte(CP_UTF8, 0, input, -1, output.str, static_cast<int>(out_size), NULL, NULL);\n}\n"
  },
  {
    "path": "generator/encoding.h",
    "content": "#pragma once\n\nstruct utf8_str {\n\tchar* str;\n\tsize_t size;\n};\n\nvoid ToUTF8(utf8_str& output, wchar_t* input);\n"
  },
  {
    "path": "generator/generator.cpp",
    "content": "\n// generator.cpp : Defines the class behaviors for the application.\n//\n\n#include \"stdafx.h\"\n#include \"generator.h\"\n#include \"appDlg.h\"\n\n#ifdef _DEBUG\n#define new DEBUG_NEW\n#endif\n\n\n// CApp\n\nBEGIN_MESSAGE_MAP(CApp, CWinApp)\n\tON_COMMAND(ID_HELP, &CWinApp::OnHelp)\nEND_MESSAGE_MAP()\n\n\n// CApp construction\n\nCApp::CApp()\n{\n\t// support Restart Manager\n\tm_dwRestartManagerSupportFlags = AFX_RESTART_MANAGER_SUPPORT_RESTART;\n\n\t// TODO: add construction code here,\n\t// Place all significant initialization in InitInstance\n}\n\n\n// The one and only CApp object\n\nCApp theApp;\n\n\n// CApp initialization\n\nBOOL CApp::InitInstance()\n{\n\t// InitCommonControlsEx() is required on Windows XP if an application\n\t// manifest specifies use of ComCtl32.dll version 6 or later to enable\n\t// visual styles.  Otherwise, any window creation will fail.\n\tINITCOMMONCONTROLSEX InitCtrls;\n\tInitCtrls.dwSize = sizeof(InitCtrls);\n\t// Set this to include all the common control classes you want to use\n\t// in your application.\n\tInitCtrls.dwICC = ICC_WIN95_CLASSES;\n\tInitCommonControlsEx(&InitCtrls);\n\n\tCWinApp::InitInstance();\n\n\n\t// Create the shell manager, in case the dialog contains\n\t// any shell tree view or shell list view controls.\n\tCShellManager *pShellManager = new CShellManager;\n\n\t// Activate \"Windows Native\" visual manager for enabling themes in MFC controls\n\tCMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));\n\n\t// Standard initialization\n\t// If you are not using these features and wish to reduce the size\n\t// of your final executable, you should remove from the following\n\t// the specific initialization routines you do not need\n\t// Change the registry key under which our settings are stored\n\t// TODO: You should modify this string to be something appropriate\n\t// such as the name of your company or organization\n\tSetRegistryKey(_T(\"Local AppWizard-Generated Applications\"));\n\n\tCAppDlg dlg;\n\tm_pMainWnd = &dlg;\n\tINT_PTR nResponse = dlg.DoModal();\n\tif (nResponse == IDOK)\n\t{\n\t\t// TODO: Place code here to handle when the dialog is\n\t\t//  dismissed with OK\n\t}\n\telse if (nResponse == IDCANCEL)\n\t{\n\t\t// TODO: Place code here to handle when the dialog is\n\t\t//  dismissed with Cancel\n\t}\n\telse if (nResponse == -1)\n\t{\n\t\tTRACE(traceAppMsg, 0, \"Warning: dialog creation failed, so application is terminating unexpectedly.\\n\");\n\t\tTRACE(traceAppMsg, 0, \"Warning: if you are using MFC controls on the dialog, you cannot #define _AFX_NO_MFC_CONTROLS_IN_DIALOGS.\\n\");\n\t}\n\n\t// Delete the shell manager created above.\n\tif (pShellManager != NULL)\n\t{\n\t\tdelete pShellManager;\n\t}\n\n#if !defined(_AFXDLL) && !defined(_AFX_NO_MFC_CONTROLS_IN_DIALOGS)\n\tControlBarCleanUp();\n#endif\n\n\t// Since the dialog has been closed, return FALSE so that we exit the\n\t//  application, rather than start the application's message pump.\n\treturn FALSE;\n}\n\n"
  },
  {
    "path": "generator/generator.h",
    "content": "\n// generator.h : main header file for the PROJECT_NAME application\n//\n\n#pragma once\n\n#ifndef __AFXWIN_H__\n\t#error \"include 'stdafx.h' before including this file for PCH\"\n#endif\n\n#include \"resource.h\"\t\t// main symbols\n\n\n// CApp:\n// See generator.cpp for the implementation of this class\n//\n\nclass CApp : public CWinApp\n{\npublic:\n\tCApp();\n\n// Overrides\npublic:\n\tvirtual BOOL InitInstance();\n\n// Implementation\n\n\tDECLARE_MESSAGE_MAP()\n};\n\nextern CApp theApp;\n"
  },
  {
    "path": "generator/generator.vcxproj",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project DefaultTargets=\"Build\" ToolsVersion=\"15.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup Label=\"ProjectConfigurations\">\n    <ProjectConfiguration Include=\"Debug|Win32\">\n      <Configuration>Debug</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|Win32\">\n      <Configuration>Release</Configuration>\n      <Platform>Win32</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Debug|x64\">\n      <Configuration>Debug</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n    <ProjectConfiguration Include=\"Release|x64\">\n      <Configuration>Release</Configuration>\n      <Platform>x64</Platform>\n    </ProjectConfiguration>\n  </ItemGroup>\n  <PropertyGroup Label=\"Globals\">\n    <VCProjectVersion>15.0</VCProjectVersion>\n    <ProjectGuid>{52BE8E83-C47E-469F-92B7-F078C51C0EBD}</ProjectGuid>\n    <RootNamespace>generator</RootNamespace>\n    <Keyword>MFCProj</Keyword>\n    <ProjectName>ducode</ProjectName>\n    <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Static</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Dynamic</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>true</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Static</UseOfMfc>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\" Label=\"Configuration\">\n    <ConfigurationType>Application</ConfigurationType>\n    <UseDebugLibraries>false</UseDebugLibraries>\n    <PlatformToolset>v143</PlatformToolset>\n    <WholeProgramOptimization>true</WholeProgramOptimization>\n    <CharacterSet>Unicode</CharacterSet>\n    <UseOfMfc>Dynamic</UseOfMfc>\n  </PropertyGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n  <ImportGroup Label=\"ExtensionSettings\">\n  </ImportGroup>\n  <ImportGroup Label=\"Shared\">\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <ImportGroup Label=\"PropertySheets\" Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <Import Project=\"$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props\" Condition=\"exists('$(UserRootDir)\\Microsoft.Cpp.$(Platform).user.props')\" Label=\"LocalAppDataPlatform\" />\n  </ImportGroup>\n  <PropertyGroup Label=\"UserMacros\" />\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>$(SolutionDir)$(PlatformTarget)\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <LinkIncremental>true</LinkIncremental>\n    <OutDir>$(SolutionDir)$(PlatformTarget)\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)$(PlatformTarget)\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <LinkIncremental>false</LinkIncremental>\n    <OutDir>$(SolutionDir)$(PlatformTarget)\\$(Configuration)\\</OutDir>\n  </PropertyGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <ValidateAllParameters>true</ValidateAllParameters>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">\n    <ClCompile>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <WarningLevel>Level3</WarningLevel>\n      <Optimization>Disabled</Optimization>\n      <PreprocessorDefinitions>_WINDOWS;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <ValidateAllParameters>true</ValidateAllParameters>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>WIN32;_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <ValidateAllParameters>true</ValidateAllParameters>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemDefinitionGroup Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">\n    <ClCompile>\n      <WarningLevel>Level3</WarningLevel>\n      <PrecompiledHeader>Use</PrecompiledHeader>\n      <Optimization>MaxSpeed</Optimization>\n      <FunctionLevelLinking>true</FunctionLevelLinking>\n      <IntrinsicFunctions>true</IntrinsicFunctions>\n      <PreprocessorDefinitions>_WINDOWS;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <SDLCheck>true</SDLCheck>\n      <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>\n    </ClCompile>\n    <Link>\n      <SubSystem>Windows</SubSystem>\n      <EnableCOMDATFolding>true</EnableCOMDATFolding>\n      <OptimizeReferences>true</OptimizeReferences>\n      <AdditionalDependencies>Version.lib;%(AdditionalDependencies)</AdditionalDependencies>\n    </Link>\n    <Midl>\n      <MkTypLibCompatible>false</MkTypLibCompatible>\n      <ValidateAllParameters>true</ValidateAllParameters>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n    </Midl>\n    <ResourceCompile>\n      <Culture>0x0409</Culture>\n      <PreprocessorDefinitions>NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n      <AdditionalIncludeDirectories>$(IntDir);%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>\n    </ResourceCompile>\n    <Manifest>\n      <EnableDpiAwareness>PerMonitorHighDPIAware</EnableDpiAwareness>\n    </Manifest>\n  </ItemDefinitionGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"AdvEdit.h\" />\n    <ClInclude Include=\"appDlg.h\" />\n    <ClInclude Include=\"ClipboardHelper.h\" />\n    <ClInclude Include=\"DPISupport.h\" />\n    <ClInclude Include=\"encoding.h\" />\n    <ClInclude Include=\"FileItem.h\" />\n    <ClInclude Include=\"generator.h\" />\n    <ClInclude Include=\"Hasher.h\" />\n    <ClInclude Include=\"base64.h\" />\n    <ClInclude Include=\"ListBoxEx.h\" />\n    <ClInclude Include=\"ProgressText.h\" />\n    <ClInclude Include=\"Resource.h\" />\n    <ClInclude Include=\"stdafx.h\" />\n    <ClInclude Include=\"targetver.h\" />\n    <ClInclude Include=\"utils.h\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"AdvEdit.cpp\" />\n    <ClCompile Include=\"appDlg.cpp\" />\n    <ClCompile Include=\"base64.cpp\" />\n    <ClCompile Include=\"ClipboardHelper.cpp\" />\n    <ClCompile Include=\"DPISupport.cpp\" />\n    <ClCompile Include=\"encoding.cpp\" />\n    <ClCompile Include=\"FileItem.cpp\" />\n    <ClCompile Include=\"generator.cpp\" />\n    <ClCompile Include=\"Hasher.cpp\" />\n    <ClCompile Include=\"ListBoxEx.cpp\" />\n    <ClCompile Include=\"ProgressText.cpp\" />\n    <ClCompile Include=\"stdafx.cpp\">\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Debug|x64'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|Win32'\">Create</PrecompiledHeader>\n      <PrecompiledHeader Condition=\"'$(Configuration)|$(Platform)'=='Release|x64'\">Create</PrecompiledHeader>\n    </ClCompile>\n    <ClCompile Include=\"utils.cpp\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"generator.rc\" />\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"res\\generator.rc2\" />\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"res\\generator.ico\" />\n    <Image Include=\"res\\tick.ico\" />\n  </ItemGroup>\n  <Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.targets\" />\n  <ImportGroup Label=\"ExtensionTargets\">\n  </ImportGroup>\n</Project>"
  },
  {
    "path": "generator/generator.vcxproj.filters",
    "content": "﻿<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<Project ToolsVersion=\"4.0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n  <ItemGroup>\n    <Filter Include=\"Source Files\">\n      <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>\n      <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>\n    </Filter>\n    <Filter Include=\"Header Files\">\n      <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>\n      <Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>\n    </Filter>\n    <Filter Include=\"Resource Files\">\n      <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>\n      <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>\n    </Filter>\n    <Filter Include=\"Components\">\n      <UniqueIdentifier>{d8e86c5e-c09b-40e0-9359-225308efac4d}</UniqueIdentifier>\n    </Filter>\n  </ItemGroup>\n  <ItemGroup>\n    <Text Include=\"ReadMe.txt\" />\n  </ItemGroup>\n  <ItemGroup>\n    <ClInclude Include=\"generator.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"appDlg.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"stdafx.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"targetver.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Resource.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"utils.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"Hasher.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"FileItem.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"base64.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"encoding.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"AdvEdit.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ProgressText.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ListBoxEx.h\">\n      <Filter>Components</Filter>\n    </ClInclude>\n    <ClInclude Include=\"ClipboardHelper.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n    <ClInclude Include=\"DPISupport.h\">\n      <Filter>Header Files</Filter>\n    </ClInclude>\n  </ItemGroup>\n  <ItemGroup>\n    <ClCompile Include=\"AdvEdit.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ListBoxEx.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ProgressText.cpp\">\n      <Filter>Components</Filter>\n    </ClCompile>\n    <ClCompile Include=\"appDlg.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"base64.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"encoding.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"FileItem.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"generator.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"Hasher.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"stdafx.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"utils.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"ClipboardHelper.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n    <ClCompile Include=\"DPISupport.cpp\">\n      <Filter>Source Files</Filter>\n    </ClCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <ResourceCompile Include=\"generator.rc\">\n      <Filter>Resource Files</Filter>\n    </ResourceCompile>\n  </ItemGroup>\n  <ItemGroup>\n    <None Include=\"res\\generator.rc2\">\n      <Filter>Resource Files</Filter>\n    </None>\n  </ItemGroup>\n  <ItemGroup>\n    <Image Include=\"res\\generator.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n    <Image Include=\"res\\tick.ico\">\n      <Filter>Resource Files</Filter>\n    </Image>\n  </ItemGroup>\n</Project>"
  },
  {
    "path": "generator/resource.h",
    "content": "//{{NO_DEPENDENCIES}}\n// Microsoft Visual C++ generated include file.\n// Used by generator.rc\n//\n#define IDM_ABOUTBOX                    0x0010\n#define IDD_ABOUTBOX                    100\n#define IDS_ABOUTBOX                    101\n#define IDD_GENERATOR_DIALOG            102\n#define IDS_PICK_FILE                   102\n#define IDS_PICK_DIR                    103\n#define IDS_DIR                         104\n#define IDS_FILE_SIZE                   105\n#define IDS_FILE_INFO                   106\n#define IDS_LIST_PLACEHOLDER            107\n#define IDS_ERROR_ENCODE_FAIL           108\n#define IDR_MAINFRAME                   128\n#define IDI_ICON_TICK                   131\n#define IDC_LIST_FILES                  1000\n#define IDC_EDIT_OUTPUT                 1001\n#define IDC_PROG_FILE                   1002\n#define IDC_PROG_ALL                    1003\n#define IDC_BTN_ADD_DIR                 1004\n#define IDC_BTN_ADD_FILE                1005\n#define IDC_SYSLINK_BLOG                1006\n#define IDC_LB_STATUS                   1007\n#define IDC_BTN_CLEAR                   1008\n#define IDC_CHK_RECURSIVE               1009\n#define IDC_BTN_COPY                    1010\n#define IDC_GENERATE                    1011\n#define IDC_BTN_GENERATE                1011\n#define IDC_CHK_URL                     1012\n\n// Next default values for new objects\n// \n#ifdef APSTUDIO_INVOKED\n#ifndef APSTUDIO_READONLY_SYMBOLS\n#define _APS_NEXT_RESOURCE_VALUE        132\n#define _APS_NEXT_COMMAND_VALUE         32771\n#define _APS_NEXT_CONTROL_VALUE         1013\n#define _APS_NEXT_SYMED_VALUE           101\n#endif\n#endif\n"
  },
  {
    "path": "generator/stdafx.cpp",
    "content": "\n// stdafx.cpp : source file that includes just the standard includes\n// generator.pch will be the pre-compiled header\n// stdafx.obj will contain the pre-compiled type information\n\n#include \"stdafx.h\"\n\n\n"
  },
  {
    "path": "generator/stdafx.h",
    "content": "\n// stdafx.h : include file for standard system include files,\n// or project specific include files that are used frequently,\n// but are changed infrequently\n\n#pragma once\n\n#ifndef VC_EXTRALEAN\n#define VC_EXTRALEAN            // Exclude rarely-used stuff from Windows headers\n#endif\n\n#include \"targetver.h\"\n\n#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS      // some CString constructors will be explicit\n\n// turns off MFC's hiding of some common and often safely ignored warning messages\n#define _AFX_ALL_WARNINGS\n\n#include <afxwin.h>         // MFC core and standard components\n#include <afxext.h>         // MFC extensions\n\n\n\n\n\n#ifndef _AFX_NO_OLE_SUPPORT\n#include <afxdtctl.h>           // MFC support for Internet Explorer 4 Common Controls\n#endif\n#ifndef _AFX_NO_AFXCMN_SUPPORT\n#include <afxcmn.h>             // MFC support for Windows Common Controls\n#endif // _AFX_NO_AFXCMN_SUPPORT\n\n#include <afxcontrolbars.h>     // MFC support for ribbons and control bars\n\n\n\n\n\n\n\n\n\n#ifdef _UNICODE\n#if defined _M_IX86\n#pragma comment(linker,\"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#elif defined _M_X64\n#pragma comment(linker,\"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#else\n#pragma comment(linker,\"/manifestdependency:\\\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\\\"\")\n#endif\n#endif\n\n\n#ifndef uint\n#define uint unsigned int\n#endif\n\n#include <vector>\n\n#if _MSC_VER < 1930\n// less than vs2022, use the full Windows.h header\n#include <Windows.h>\n#else\n// Other: use a subset of the headers.\n#include <minwinbase.h>\n#include <fileapi.h>\n#endif\n#include \"afxcmn.h\"\n#include \"afxwin.h\"\n\n\n#define SAFE_DELETE(a)       \\\n\tif( (a) != nullptr ) {   \\\n\t\tdelete (a);          \\\n\t}                        \\\n\t(a) = nullptr;\n"
  },
  {
    "path": "generator/targetver.h",
    "content": "#pragma once\n\n// Including SDKDDKVer.h defines the highest available Windows platform.\n\n// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and\n// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.\n\n#include <SDKDDKVer.h>\n"
  },
  {
    "path": "generator/utils.cpp",
    "content": "﻿#include \"stdafx.h\"\n#include \"utils.h\"\n\nstd::vector<CString*> OldStyleFileDialog(const CString& title, HWND hwnd)\n{\n\tstd::vector<CString*> v;\n\tCString str;\n\tOPENFILENAME ofn = {0};\n\tofn.lStructSize = sizeof ofn;\n\tofn.lpstrTitle = title;\n\tofn.hwndOwner = hwnd;\n\tofn.lpstrFile = str.GetBuffer(1024);\n\tofn.nMaxFile = 1024;\n\tif (GetOpenFileName(&ofn))\n\t{\n\t\tv.push_back(new CString(str));\n\t}\n\tstr.ReleaseBuffer();\n\n\treturn v;\n}\n\ninline std::vector<CString*> OldStyleDirectoryDialog(CString &title, HWND hWnd)\n{\n\tstd::vector<CString*> v;\n\tBROWSEINFO bi;\n\tZeroMemory(&bi, sizeof bi);\n\tbi.hwndOwner = hWnd;\n\t// bi.lpfn = cb_set_initial;\n\tbi.lpszTitle = title;\n\tbi.ulFlags = BIF_EDITBOX | BIF_NEWDIALOGSTYLE;\n\n\tTCHAR szPath[1024];\n\tif (SHGetPathFromIDList(SHBrowseForFolder(&bi), szPath))\n\t{\n\t\tv.push_back(new CString(szPath));\n\t}\n\treturn v;\n}\n\nDWORD OpenFileDialog(CString &title, HWND hWnd, DWORD flag, std::vector<CString*> &v)\n{\n\tIFileOpenDialog* pFileOpen;\n\tdo\n\t{\n\t\tif (FAILED(CoCreateInstance(CLSID_FileOpenDialog,\n\t\t\tnullptr,\n\t\t\tCLSCTX_INPROC_SERVER,\n\t\t\tIID_PPV_ARGS(&pFileOpen))))\n\t\t{\n\t\t\treturn 1;\n\t\t}\n\n\t\tFILEOPENDIALOGOPTIONS fos;\n\t\tif (FAILED(pFileOpen->GetOptions(&fos))) break;\n\t\tfos |= flag | FOS_ALLOWMULTISELECT | FOS_FORCEFILESYSTEM;\n\t\tif (FAILED(pFileOpen->SetOptions(fos))) break;\n\t\tif (FAILED(pFileOpen->SetTitle(title))) break;\n\t\tif (FAILED(pFileOpen->Show(hWnd))) break;\n\n\t\tIShellItem* pShellItem;\n\t\tpFileOpen->GetResult(&pShellItem);\n\n\t\tIShellItemArray* pResults;\n\t\tif (FAILED(pFileOpen->GetResults(&pResults))) break;\n\t\tDWORD dwCount;\n\t\tif (FAILED(pResults->GetCount(&dwCount))) break;\n\n\n\t\tv.clear();\n\t\tfor (uint i = 0; i < dwCount; i++)\n\t\t{\n\t\t\tIShellItem* pItem;\n\t\t\tpResults->GetItemAt(i, &pItem);\n\n\t\t\tTCHAR* filePath;\n\t\t\tpItem->GetDisplayName(SIGDN_DESKTOPABSOLUTEPARSING, &filePath);\n\n\t\t\tv.push_back(new CString(filePath));\n\n\t\t\tCoTaskMemFree(filePath);\n\t\t\tpItem->Release();\n\t\t}\n\n\t\tif (pFileOpen) pFileOpen->Release();\n\t\treturn 0;\n\t} while (false);\n\n\tif (pFileOpen) pFileOpen->Release();\n\treturn 0;\n}\n\nstd::vector<CString*> OpenDirectoryDialog(CString &title, HWND hWnd)\n{\n\tstd::vector<CString*> r;\n\tauto err = OpenFileDialog(title, hWnd, FOS_PICKFOLDERS, r);\n\tif (err == 1) return OldStyleDirectoryDialog(title, hWnd);\n\treturn r;\n}\n\nstd::vector<CString*> OpenFileDialog(CString &title, HWND hWnd)\n{\n\tstd::vector<CString*> r;\n\tauto err = OpenFileDialog(title, hWnd, 0, r);\n\tif (err == 1) return OldStyleFileDialog(title, hWnd);\n\treturn r;\n}\n\n\nvoid EnumFiles(const CString& srcDir, bool recursive, f_file_callback cb, void* extra) {\n\tauto dir(srcDir);\n\tif (dir.Right(1).Compare(_T(\"\\\\\")) == 0)\n\t{\n\t\tdir.AppendChar(_T('*'));\n\t}\n\telse\n\t{\n\t\tdir.Append(_T(\"\\\\*\"));\n\t}\n\n\tWIN32_FIND_DATA ffd;\n\tauto hFind = FindFirstFile(dir, &ffd);\n\tif (hFind == INVALID_HANDLE_VALUE)\n\t{\n\t\treturn;\n\t}\n\n\tdo\n\t{\n\t\tif (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)\n\t\t{\n\t\t\tif (recursive)\n\t\t\t{\n\t\t\t\tif (_tcscmp(ffd.cFileName, _T(\".\")) != 0\n\t\t\t\t\t&& _tcscmp(ffd.cFileName, _T(\"..\")) != 0)\n\t\t\t\t{\n#if _DEBUG\n\t\t\t\t\tCString str;\n\t\t\t\t\tstr.Format(_T(\"enter dir: %s\\n\"), ffd.cFileName);\n\t\t\t\t\tOutputDebugString(str);\n#endif\n\t\t\t\t\tEnumFiles(srcDir + _T(\"\\\\\") + ffd.cFileName, recursive, cb, extra);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\telse\n\t\t{\n#if _DEBUG\n\t\t\tCString str;\n\t\t\tstr.Format(_T(\"add file: %s\\n\"), ffd.cFileName);\n\t\t\tOutputDebugString(str);\n#endif\n\t\t\tcb(srcDir, ffd.cFileName, extra);\n\t\t}\n\t} while (FindNextFile(hFind, &ffd) != 0);\n\tFindClose(hFind);\n}\n"
  },
  {
    "path": "generator/utils.h",
    "content": "#pragma once\n\nstd::vector<CString*> OpenFileDialog(CString &title, HWND hWnd);\nstd::vector<CString*> OpenDirectoryDialog(CString &title, HWND hWnd);\n\ntypedef void(*f_file_callback) (const CString &strDir, const CString &strName, void* extra);\nvoid EnumFiles(const CString& srcDir, bool recursive, f_file_callback cb, void* extra = nullptr);\n"
  },
  {
    "path": "mfcDuDownloadCodeGenerator.sln",
    "content": "﻿\nMicrosoft Visual Studio Solution File, Format Version 12.00\n# Visual Studio Version 17\nVisualStudioVersion = 17.3.32922.545\nMinimumVisualStudioVersion = 10.0.40219.1\nProject(\"{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}\") = \"ducode\", \"generator\\generator.vcxproj\", \"{52BE8E83-C47E-469F-92B7-F078C51C0EBD}\"\nEndProject\nGlobal\n\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n\t\tDebug|x64 = Debug|x64\n\t\tDebug|x86 = Debug|x86\n\t\tRelease|x64 = Release|x64\n\t\tRelease|x86 = Release|x86\n\tEndGlobalSection\n\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x64.ActiveCfg = Debug|x64\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x64.Build.0 = Debug|x64\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x86.ActiveCfg = Debug|Win32\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Debug|x86.Build.0 = Debug|Win32\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x64.ActiveCfg = Release|x64\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x64.Build.0 = Release|x64\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x86.ActiveCfg = Release|Win32\n\t\t{52BE8E83-C47E-469F-92B7-F078C51C0EBD}.Release|x86.Build.0 = Release|Win32\n\tEndGlobalSection\n\tGlobalSection(SolutionProperties) = preSolution\n\t\tHideSolutionNode = FALSE\n\tEndGlobalSection\n\tGlobalSection(ExtensibilityGlobals) = postSolution\n\t\tSolutionGuid = {BC2322A7-E814-48A2-93F3-2D9DF1A6A0A4}\n\tEndGlobalSection\nEndGlobal\n"
  }
]