From a3d7b58b832ada5dc99c3da887fe3fec7ef99065 Mon Sep 17 00:00:00 2001 From: Dan Stillman Date: Sun, 23 Apr 2023 03:57:55 -0400 Subject: [PATCH] Add zotero-standalone-build repo as `app` folder Minus obsolete 4.0 files --- .gitmodules | 9 + app/.gitignore | 10 + app/README.md | 4 + app/assets/application.ini | 18 + app/assets/branding/content/icon48.png | Bin 0 -> 4031 bytes app/assets/branding/content/icon64.png | Bin 0 -> 5884 bytes app/assets/branding/locale/brand.dtd | 1 + app/assets/branding/locale/brand.ftl | 6 + app/assets/branding/locale/brand.properties | 3 + app/assets/chrome.manifest | 3 + app/assets/icons/default/default16.png | Bin 0 -> 1322 bytes app/assets/icons/default/default256.png | Bin 0 -> 52956 bytes app/assets/icons/default/default32.png | Bin 0 -> 2988 bytes app/assets/icons/default/default48.png | Bin 0 -> 4031 bytes app/assets/icons/default/main-window.ico | Bin 0 -> 70882 bytes .../chrome/skin/preferences/preferences.css | 242 + app/assets/multilocale.txt | 1 + app/assets/prefs.js | 186 + .../unix/skin/preferences/preferences.css | 188 + app/assets/updater.ini | 4 + .../win/skin/preferences/preferences.css | 178 + app/build.sh | 845 +++ app/config.sh | 76 + app/fetch_mar_tools | 21 + app/fetch_pdftools | 35 + app/fetch_xulrunner.sh | 398 ++ app/linux/set_launcher_icon | 13 + app/linux/updater-i686 | Bin 0 -> 92164 bytes app/linux/updater-x86_64 | Bin 0 -> 93904 bytes app/linux/zotero | 16 + app/linux/zotero.desktop | 9 + app/mac/Contents/Info.plist | 204 + app/mac/Contents/PkgInfo | 1 + app/mac/Contents/Resources/zotero.icns | Bin 0 -> 211494 bytes app/mac/DSStore | Bin 0 -> 6148 bytes app/mac/build-and-unify | 68 + app/mac/entitlements.xml | 34 + app/mac/mozconfig | 27 + app/mac/mozilla-102.patch | 124 + app/mac/pkg-dmg | 1520 +++++ app/mac/updater.tar.bz2 | Bin 0 -> 253440 bytes app/mac/zotero.xz | Bin 0 -> 10724 bytes app/modules/zotero-libreoffice-integration | 1 + app/modules/zotero-word-for-mac-integration | 1 + .../zotero-word-for-windows-integration | 1 + app/scripts/5.0_beta_build_and_deploy | 23 + app/scripts/5.0_dev_build_and_deploy | 24 + app/scripts/5.0_release_build_and_deploy | 23 + app/scripts/add_omni_file | 52 + app/scripts/bootstrap.sh | 14 + app/scripts/build_and_deploy | 162 + app/scripts/build_and_run | 92 + app/scripts/check_requirements | 144 + app/scripts/codesign_local | 42 + app/scripts/dir_build | 82 + app/scripts/fetch_rcedit | 11 + app/scripts/get_commit_files | 21 + app/scripts/get_repo_branch_hash | 14 + app/scripts/manage_incrementals | 83 + app/scripts/notarization_info | 18 + app/scripts/notarization_stapler | 19 + app/scripts/notarization_status | 18 + app/scripts/notarize_mac_app | 19 + app/scripts/optimizejars.py | 376 ++ app/scripts/upload_builds | 24 + app/update-packaging/add_version_info | 66 + app/update-packaging/build_autoupdate.sh | 326 + app/update-packaging/common.sh | 215 + app/update-packaging/make_full_update.sh | 124 + .../make_incremental_update.sh | 326 + .../make_incremental_updates.py | 550 ++ app/update-packaging/removed-files_linux-i686 | 19 + .../removed-files_linux-x86_64 | 19 + app/update-packaging/removed-files_mac | 49 + app/update-packaging/removed-files_win32 | 46 + app/update-packaging/removed-files_win64 | 0 app/win/VersionInfo1.rc | Bin 0 -> 1604 bytes app/win/download-nsis-plugins | 53 + app/win/installer/7zstub/firefox/7zSD.sfx | Bin 0 -> 122368 bytes .../src/7zip/Archive/7z/7zCompressionMode.cpp | 3 + .../src/7zip/Archive/7z/7zCompressionMode.h | 64 + .../7zstub/src/7zip/Archive/7z/7zDecode.cpp | 443 ++ .../7zstub/src/7zip/Archive/7z/7zDecode.h | 71 + .../7zstub/src/7zip/Archive/7z/7zExtract.cpp | 265 + .../src/7zip/Archive/7z/7zFolderOutStream.cpp | 161 + .../src/7zip/Archive/7z/7zFolderOutStream.h | 57 + .../7zstub/src/7zip/Archive/7z/7zHandler.cpp | 757 +++ .../7zstub/src/7zip/Archive/7z/7zHandler.h | 234 + .../7zstub/src/7zip/Archive/7z/7zHeader.cpp | 19 + .../7zstub/src/7zip/Archive/7z/7zHeader.h | 96 + .../7zstub/src/7zip/Archive/7z/7zIn.cpp | 1294 ++++ .../7zstub/src/7zip/Archive/7z/7zIn.h | 288 + .../7zstub/src/7zip/Archive/7z/7zItem.h | 181 + .../7zstub/src/7zip/Archive/7z/7zMethodID.cpp | 76 + .../7zstub/src/7zip/Archive/7z/7zMethodID.h | 29 + .../7zstub/src/7zip/Archive/7z/7zMethods.cpp | 174 + .../7zstub/src/7zip/Archive/7z/7zMethods.h | 36 + .../src/7zip/Archive/7z/7zProperties.cpp | 166 + .../7zstub/src/7zip/Archive/7z/7zProperties.h | 22 + .../7zstub/src/7zip/Archive/Archive.def | 3 + .../src/7zip/Archive/Common/CoderMixer2.cpp | 121 + .../src/7zip/Archive/Common/CoderMixer2.h | 168 + .../src/7zip/Archive/Common/CoderMixer2MT.cpp | 359 ++ .../src/7zip/Archive/Common/CoderMixer2MT.h | 121 + .../Archive/Common/CrossThreadProgress.cpp | 15 + .../7zip/Archive/Common/CrossThreadProgress.h | 31 + .../src/7zip/Archive/Common/FilterCoder.cpp | 242 + .../src/7zip/Archive/Common/FilterCoder.h | 130 + .../src/7zip/Archive/Common/ItemNameUtils.cpp | 59 + .../src/7zip/Archive/Common/ItemNameUtils.h | 24 + .../7zip/Archive/Common/OutStreamWithCRC.cpp | 23 + .../7zip/Archive/Common/OutStreamWithCRC.h | 33 + .../7zstub/src/7zip/Archive/IArchive.h | 173 + .../Bundles/SFXSetup-moz/ExtractCallback.cpp | 249 + .../Bundles/SFXSetup-moz/ExtractCallback.h | 96 + .../Bundles/SFXSetup-moz/ExtractEngine.cpp | 139 + .../7zip/Bundles/SFXSetup-moz/ExtractEngine.h | 17 + .../src/7zip/Bundles/SFXSetup-moz/Main.cpp | 344 + .../Bundles/SFXSetup-moz/SFXSetup-moz.dsp | 696 ++ .../Bundles/SFXSetup-moz/SFXSetup-moz.dsw | 29 + .../src/7zip/Bundles/SFXSetup-moz/StdAfx.cpp | 3 + .../src/7zip/Bundles/SFXSetup-moz/StdAfx.h | 10 + .../src/7zip/Bundles/SFXSetup-moz/makefile | 156 + .../src/7zip/Bundles/SFXSetup-moz/resource.h | 6 + .../src/7zip/Bundles/SFXSetup-moz/resource.rc | 16 + .../src/7zip/Bundles/SFXSetup-moz/setup.ico | Bin 0 -> 25214 bytes .../src/7zip/Common/FilePathAutoRename.cpp | 57 + .../src/7zip/Common/FilePathAutoRename.h | 10 + .../7zstub/src/7zip/Common/FileStreams.cpp | 251 + .../7zstub/src/7zip/Common/FileStreams.h | 98 + .../7zstub/src/7zip/Common/InBuffer.cpp | 80 + .../7zstub/src/7zip/Common/InBuffer.h | 76 + .../src/7zip/Common/InOutTempBuffer.cpp | 122 + .../7zstub/src/7zip/Common/InOutTempBuffer.h | 55 + .../7zstub/src/7zip/Common/LSBFDecoder.cpp | 34 + .../7zstub/src/7zip/Common/LSBFDecoder.h | 127 + .../7zstub/src/7zip/Common/LSBFEncoder.cpp | 29 + .../7zstub/src/7zip/Common/LSBFEncoder.h | 51 + .../7zstub/src/7zip/Common/LimitedStreams.cpp | 24 + .../7zstub/src/7zip/Common/LimitedStreams.h | 23 + .../7zstub/src/7zip/Common/LockedStream.cpp | 23 + .../7zstub/src/7zip/Common/LockedStream.h | 38 + .../7zstub/src/7zip/Common/MSBFDecoder.h | 69 + .../7zstub/src/7zip/Common/MSBFEncoder.h | 59 + .../7zstub/src/7zip/Common/OffsetStream.cpp | 35 + .../7zstub/src/7zip/Common/OffsetStream.h | 25 + .../7zstub/src/7zip/Common/OutBuffer.cpp | 116 + .../7zstub/src/7zip/Common/OutBuffer.h | 64 + .../7zstub/src/7zip/Common/ProgressUtils.cpp | 58 + .../7zstub/src/7zip/Common/ProgressUtils.h | 43 + .../installer/7zstub/src/7zip/Common/StdAfx.h | 9 + .../7zstub/src/7zip/Common/StreamBinder.cpp | 162 + .../7zstub/src/7zip/Common/StreamBinder.h | 37 + .../7zstub/src/7zip/Common/StreamObjects.cpp | 102 + .../7zstub/src/7zip/Common/StreamObjects.h | 156 + .../7zstub/src/7zip/Common/StreamUtils.cpp | 44 + .../7zstub/src/7zip/Common/StreamUtils.h | 11 + .../src/7zip/Compress/Branch/BranchCoder.cpp | 18 + .../src/7zip/Compress/Branch/BranchCoder.h | 54 + .../src/7zip/Compress/Branch/BranchTypes.h | 15 + .../src/7zip/Compress/Branch/BranchX86.c | 101 + .../src/7zip/Compress/Branch/BranchX86.h | 13 + .../7zstub/src/7zip/Compress/Branch/x86.cpp | 18 + .../7zstub/src/7zip/Compress/Branch/x86.h | 19 + .../7zstub/src/7zip/Compress/Branch/x86_2.cpp | 412 ++ .../7zstub/src/7zip/Compress/Branch/x86_2.h | 133 + .../src/7zip/Compress/Copy/CopyCoder.cpp | 52 + .../7zstub/src/7zip/Compress/Copy/CopyCoder.h | 31 + .../src/7zip/Compress/LZ/LZOutWindow.cpp | 17 + .../7zstub/src/7zip/Compress/LZ/LZOutWindow.h | 56 + .../7zstub/src/7zip/Compress/LZMA/LZMA.h | 82 + .../src/7zip/Compress/LZMA/LZMADecoder.cpp | 337 + .../src/7zip/Compress/LZMA/LZMADecoder.h | 251 + .../src/7zip/Compress/RangeCoder/RangeCoder.h | 205 + .../Compress/RangeCoder/RangeCoderBit.cpp | 80 + .../7zip/Compress/RangeCoder/RangeCoderBit.h | 120 + .../Compress/RangeCoder/RangeCoderBitTree.h | 161 + .../7zip/Compress/RangeCoder/RangeCoderOpt.h | 31 + .../src/7zip/FileManager/FormatUtils.cpp | 40 + .../7zstub/src/7zip/FileManager/FormatUtils.h | 18 + .../ProgressDialog/ProgressDialog.cpp | 175 + .../Resource/ProgressDialog/ProgressDialog.h | 129 + .../Resource/ProgressDialog/StdAfx.h | 16 + .../Resource/ProgressDialog/resource.h | 3 + .../Resource/ProgressDialog/resource.rc | 20 + .../installer/7zstub/src/7zip/GuiCommon.rc | 37 + app/win/installer/7zstub/src/7zip/ICoder.h | 163 + app/win/installer/7zstub/src/7zip/IPassword.h | 26 + app/win/installer/7zstub/src/7zip/IProgress.h | 32 + app/win/installer/7zstub/src/7zip/IStream.h | 62 + app/win/installer/7zstub/src/7zip/MyVersion.h | 8 + .../7zstub/src/7zip/MyVersionInfo.rc | 41 + app/win/installer/7zstub/src/7zip/PropID.h | 51 + .../7zip/UI/Common/ArchiveOpenCallback.cpp | 117 + .../src/7zip/UI/Common/ArchiveOpenCallback.h | 87 + .../src/7zip/UI/Common/ArchiverInfo.cpp | 359 ++ .../7zstub/src/7zip/UI/Common/ArchiverInfo.h | 66 + .../7zstub/src/7zip/UI/Common/DefaultName.cpp | 23 + .../7zstub/src/7zip/UI/Common/DefaultName.h | 11 + .../7zstub/src/7zip/UI/Common/OpenArchive.cpp | 528 ++ .../7zstub/src/7zip/UI/Common/OpenArchive.h | 134 + .../src/7zip/UI/Explorer/MyMessages.cpp | 45 + .../7zstub/src/7zip/UI/Explorer/MyMessages.h | 24 + .../src/7zip/UI/GUI/OpenCallbackGUI.cpp | 53 + .../7zstub/src/7zip/UI/GUI/OpenCallbackGUI.h | 30 + app/win/installer/7zstub/src/Common/Alloc.cpp | 118 + app/win/installer/7zstub/src/Common/Alloc.h | 29 + app/win/installer/7zstub/src/Common/Buffer.h | 77 + app/win/installer/7zstub/src/Common/CRC.cpp | 61 + app/win/installer/7zstub/src/Common/CRC.h | 36 + app/win/installer/7zstub/src/Common/ComTry.h | 17 + .../7zstub/src/Common/CommandLineParser.cpp | 232 + .../7zstub/src/Common/CommandLineParser.h | 72 + app/win/installer/7zstub/src/Common/Defs.h | 20 + .../7zstub/src/Common/DynamicBuffer.h | 47 + .../7zstub/src/Common/IntToString.cpp | 63 + .../installer/7zstub/src/Common/IntToString.h | 15 + app/win/installer/7zstub/src/Common/MyCom.h | 203 + .../installer/7zstub/src/Common/MyUnknown.h | 24 + .../installer/7zstub/src/Common/MyWindows.cpp | 113 + .../installer/7zstub/src/Common/MyWindows.h | 200 + .../7zstub/src/Common/NewHandler.cpp | 116 + .../installer/7zstub/src/Common/NewHandler.h | 16 + .../installer/7zstub/src/Common/Random.cpp | 17 + app/win/installer/7zstub/src/Common/Random.h | 16 + .../7zstub/src/Common/StdInStream.cpp | 78 + .../installer/7zstub/src/Common/StdInStream.h | 31 + .../7zstub/src/Common/StdOutStream.cpp | 87 + .../7zstub/src/Common/StdOutStream.h | 35 + .../installer/7zstub/src/Common/String.cpp | 198 + app/win/installer/7zstub/src/Common/String.h | 631 ++ .../7zstub/src/Common/StringConvert.cpp | 93 + .../7zstub/src/Common/StringConvert.h | 71 + .../7zstub/src/Common/TextConfig.cpp | 137 + .../installer/7zstub/src/Common/TextConfig.h | 22 + app/win/installer/7zstub/src/Common/Types.h | 19 + .../7zstub/src/Common/UTFConvert.cpp | 91 + .../installer/7zstub/src/Common/UTFConvert.h | 11 + .../installer/7zstub/src/Common/Vector.cpp | 74 + app/win/installer/7zstub/src/Common/Vector.h | 228 + .../installer/7zstub/src/Common/Wildcard.cpp | 462 ++ .../installer/7zstub/src/Common/Wildcard.h | 78 + app/win/installer/7zstub/src/DOC/7zC.txt | 235 + app/win/installer/7zstub/src/DOC/copying.txt | 504 ++ app/win/installer/7zstub/src/DOC/lzma.txt | 630 ++ app/win/installer/7zstub/src/DOC/readme.txt | 226 + app/win/installer/7zstub/src/Windows/COM.cpp | 37 + app/win/installer/7zstub/src/Windows/COM.h | 57 + .../7zstub/src/Windows/Control/Dialog.cpp | 145 + .../7zstub/src/Windows/Control/Dialog.h | 141 + .../7zstub/src/Windows/Control/ProgressBar.h | 41 + app/win/installer/7zstub/src/Windows/DLL.cpp | 115 + app/win/installer/7zstub/src/Windows/DLL.h | 54 + app/win/installer/7zstub/src/Windows/Defs.h | 18 + .../installer/7zstub/src/Windows/Error.cpp | 50 + app/win/installer/7zstub/src/Windows/Error.h | 33 + .../installer/7zstub/src/Windows/FileDir.cpp | 672 ++ .../installer/7zstub/src/Windows/FileDir.h | 189 + .../installer/7zstub/src/Windows/FileFind.cpp | 365 ++ .../installer/7zstub/src/Windows/FileFind.h | 176 + .../installer/7zstub/src/Windows/FileIO.cpp | 245 + app/win/installer/7zstub/src/Windows/FileIO.h | 98 + .../installer/7zstub/src/Windows/FileName.cpp | 111 + .../installer/7zstub/src/Windows/FileName.h | 43 + app/win/installer/7zstub/src/Windows/Handle.h | 37 + .../7zstub/src/Windows/PropVariant.cpp | 310 + .../7zstub/src/Windows/PropVariant.h | 57 + .../src/Windows/PropVariantConversions.cpp | 145 + .../src/Windows/PropVariantConversions.h | 14 + .../7zstub/src/Windows/ResourceString.cpp | 53 + .../7zstub/src/Windows/ResourceString.h | 20 + .../7zstub/src/Windows/Synchronization.cpp | 17 + .../7zstub/src/Windows/Synchronization.h | 114 + app/win/installer/7zstub/src/Windows/Thread.h | 52 + app/win/installer/7zstub/src/Windows/Time.h | 66 + .../installer/7zstub/src/Windows/Window.cpp | 169 + app/win/installer/7zstub/src/Windows/Window.h | 211 + app/win/installer/LICENSE | 9 + app/win/installer/app.tag | 4 + app/win/installer/baseLocale.nlf | Bin 0 -> 398 bytes app/win/installer/baseLocale.nsh | Bin 0 -> 7700 bytes app/win/installer/branding.nsi | 14 + app/win/installer/common.nsh | 5620 +++++++++++++++++ app/win/installer/customLocale.nsh | Bin 0 -> 9024 bytes app/win/installer/defines.nsi | 81 + app/win/installer/installer.nsi | 1069 ++++ app/win/installer/locales.nsi | 17 + app/win/installer/overrideLocale.nsh | Bin 0 -> 7148 bytes app/win/installer/overrides.nsh | 591 ++ app/win/installer/setup.ico | Bin 0 -> 25214 bytes app/win/installer/shared.nsh | 366 ++ app/win/installer/uninstaller.nsi | 779 +++ app/win/installer/updater_append.ini | 12 + app/win/mozconfig | 26 + app/win/mozilla-102.patch | 80 + app/win/resource-hacker-config.txt | 9 + app/win/update_exe | 43 + app/win/updater.exe | Bin 0 -> 282624 bytes app/win/zotero.exe.tar.xz | Bin 0 -> 398180 bytes 299 files changed, 39600 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/README.md create mode 100644 app/assets/application.ini create mode 100644 app/assets/branding/content/icon48.png create mode 100644 app/assets/branding/content/icon64.png create mode 100644 app/assets/branding/locale/brand.dtd create mode 100644 app/assets/branding/locale/brand.ftl create mode 100644 app/assets/branding/locale/brand.properties create mode 100644 app/assets/chrome.manifest create mode 100644 app/assets/icons/default/default16.png create mode 100644 app/assets/icons/default/default256.png create mode 100644 app/assets/icons/default/default32.png create mode 100644 app/assets/icons/default/default48.png create mode 100644 app/assets/icons/default/main-window.ico create mode 100644 app/assets/mac/chrome/skin/preferences/preferences.css create mode 100644 app/assets/multilocale.txt create mode 100644 app/assets/prefs.js create mode 100644 app/assets/unix/skin/preferences/preferences.css create mode 100644 app/assets/updater.ini create mode 100644 app/assets/win/skin/preferences/preferences.css create mode 100755 app/build.sh create mode 100644 app/config.sh create mode 100755 app/fetch_mar_tools create mode 100755 app/fetch_pdftools create mode 100755 app/fetch_xulrunner.sh create mode 100755 app/linux/set_launcher_icon create mode 100755 app/linux/updater-i686 create mode 100755 app/linux/updater-x86_64 create mode 100755 app/linux/zotero create mode 100755 app/linux/zotero.desktop create mode 100644 app/mac/Contents/Info.plist create mode 100644 app/mac/Contents/PkgInfo create mode 100644 app/mac/Contents/Resources/zotero.icns create mode 100644 app/mac/DSStore create mode 100755 app/mac/build-and-unify create mode 100644 app/mac/entitlements.xml create mode 100644 app/mac/mozconfig create mode 100644 app/mac/mozilla-102.patch create mode 100755 app/mac/pkg-dmg create mode 100644 app/mac/updater.tar.bz2 create mode 100644 app/mac/zotero.xz create mode 160000 app/modules/zotero-libreoffice-integration create mode 160000 app/modules/zotero-word-for-mac-integration create mode 160000 app/modules/zotero-word-for-windows-integration create mode 100755 app/scripts/5.0_beta_build_and_deploy create mode 100755 app/scripts/5.0_dev_build_and_deploy create mode 100755 app/scripts/5.0_release_build_and_deploy create mode 100755 app/scripts/add_omni_file create mode 100644 app/scripts/bootstrap.sh create mode 100755 app/scripts/build_and_deploy create mode 100755 app/scripts/build_and_run create mode 100755 app/scripts/check_requirements create mode 100755 app/scripts/codesign_local create mode 100755 app/scripts/dir_build create mode 100755 app/scripts/fetch_rcedit create mode 100755 app/scripts/get_commit_files create mode 100755 app/scripts/get_repo_branch_hash create mode 100755 app/scripts/manage_incrementals create mode 100755 app/scripts/notarization_info create mode 100755 app/scripts/notarization_stapler create mode 100755 app/scripts/notarization_status create mode 100755 app/scripts/notarize_mac_app create mode 100644 app/scripts/optimizejars.py create mode 100755 app/scripts/upload_builds create mode 100755 app/update-packaging/add_version_info create mode 100755 app/update-packaging/build_autoupdate.sh create mode 100644 app/update-packaging/common.sh create mode 100755 app/update-packaging/make_full_update.sh create mode 100755 app/update-packaging/make_incremental_update.sh create mode 100755 app/update-packaging/make_incremental_updates.py create mode 100755 app/update-packaging/removed-files_linux-i686 create mode 100755 app/update-packaging/removed-files_linux-x86_64 create mode 100755 app/update-packaging/removed-files_mac create mode 100755 app/update-packaging/removed-files_win32 create mode 100644 app/update-packaging/removed-files_win64 create mode 100644 app/win/VersionInfo1.rc create mode 100755 app/win/download-nsis-plugins create mode 100644 app/win/installer/7zstub/firefox/7zSD.sfx create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zExtract.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zItem.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Archive.def create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.h create mode 100644 app/win/installer/7zstub/src/7zip/Archive/IArchive.h create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.h create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.h create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/Main.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsp create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsw create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.h create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/makefile create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.h create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.rc create mode 100644 app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/setup.ico create mode 100644 app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/FileStreams.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/FileStreams.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/InBuffer.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/InBuffer.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/LimitedStreams.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/LimitedStreams.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/LockedStream.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/LockedStream.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/MSBFDecoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/MSBFEncoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/OffsetStream.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/OffsetStream.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/OutBuffer.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/OutBuffer.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/ProgressUtils.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/ProgressUtils.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/StdAfx.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/StreamBinder.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/StreamBinder.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/StreamObjects.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/StreamObjects.h create mode 100644 app/win/installer/7zstub/src/7zip/Common/StreamUtils.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Common/StreamUtils.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/BranchTypes.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.c create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/x86.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/x86.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMA.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoder.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.cpp create mode 100644 app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBitTree.h create mode 100644 app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderOpt.h create mode 100644 app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.cpp create mode 100644 app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.h create mode 100644 app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.cpp create mode 100644 app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.h create mode 100644 app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/StdAfx.h create mode 100644 app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.h create mode 100644 app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.rc create mode 100644 app/win/installer/7zstub/src/7zip/GuiCommon.rc create mode 100644 app/win/installer/7zstub/src/7zip/ICoder.h create mode 100644 app/win/installer/7zstub/src/7zip/IPassword.h create mode 100644 app/win/installer/7zstub/src/7zip/IProgress.h create mode 100644 app/win/installer/7zstub/src/7zip/IStream.h create mode 100644 app/win/installer/7zstub/src/7zip/MyVersion.h create mode 100644 app/win/installer/7zstub/src/7zip/MyVersionInfo.rc create mode 100644 app/win/installer/7zstub/src/7zip/PropID.h create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.cpp create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.h create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.cpp create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.h create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.cpp create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.h create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.cpp create mode 100644 app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.h create mode 100644 app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.cpp create mode 100644 app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.h create mode 100644 app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.cpp create mode 100644 app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.h create mode 100644 app/win/installer/7zstub/src/Common/Alloc.cpp create mode 100644 app/win/installer/7zstub/src/Common/Alloc.h create mode 100644 app/win/installer/7zstub/src/Common/Buffer.h create mode 100644 app/win/installer/7zstub/src/Common/CRC.cpp create mode 100644 app/win/installer/7zstub/src/Common/CRC.h create mode 100644 app/win/installer/7zstub/src/Common/ComTry.h create mode 100644 app/win/installer/7zstub/src/Common/CommandLineParser.cpp create mode 100644 app/win/installer/7zstub/src/Common/CommandLineParser.h create mode 100644 app/win/installer/7zstub/src/Common/Defs.h create mode 100644 app/win/installer/7zstub/src/Common/DynamicBuffer.h create mode 100644 app/win/installer/7zstub/src/Common/IntToString.cpp create mode 100644 app/win/installer/7zstub/src/Common/IntToString.h create mode 100644 app/win/installer/7zstub/src/Common/MyCom.h create mode 100644 app/win/installer/7zstub/src/Common/MyUnknown.h create mode 100644 app/win/installer/7zstub/src/Common/MyWindows.cpp create mode 100644 app/win/installer/7zstub/src/Common/MyWindows.h create mode 100644 app/win/installer/7zstub/src/Common/NewHandler.cpp create mode 100644 app/win/installer/7zstub/src/Common/NewHandler.h create mode 100644 app/win/installer/7zstub/src/Common/Random.cpp create mode 100644 app/win/installer/7zstub/src/Common/Random.h create mode 100644 app/win/installer/7zstub/src/Common/StdInStream.cpp create mode 100644 app/win/installer/7zstub/src/Common/StdInStream.h create mode 100644 app/win/installer/7zstub/src/Common/StdOutStream.cpp create mode 100644 app/win/installer/7zstub/src/Common/StdOutStream.h create mode 100644 app/win/installer/7zstub/src/Common/String.cpp create mode 100644 app/win/installer/7zstub/src/Common/String.h create mode 100644 app/win/installer/7zstub/src/Common/StringConvert.cpp create mode 100644 app/win/installer/7zstub/src/Common/StringConvert.h create mode 100644 app/win/installer/7zstub/src/Common/TextConfig.cpp create mode 100644 app/win/installer/7zstub/src/Common/TextConfig.h create mode 100644 app/win/installer/7zstub/src/Common/Types.h create mode 100644 app/win/installer/7zstub/src/Common/UTFConvert.cpp create mode 100644 app/win/installer/7zstub/src/Common/UTFConvert.h create mode 100644 app/win/installer/7zstub/src/Common/Vector.cpp create mode 100644 app/win/installer/7zstub/src/Common/Vector.h create mode 100644 app/win/installer/7zstub/src/Common/Wildcard.cpp create mode 100644 app/win/installer/7zstub/src/Common/Wildcard.h create mode 100644 app/win/installer/7zstub/src/DOC/7zC.txt create mode 100644 app/win/installer/7zstub/src/DOC/copying.txt create mode 100644 app/win/installer/7zstub/src/DOC/lzma.txt create mode 100644 app/win/installer/7zstub/src/DOC/readme.txt create mode 100644 app/win/installer/7zstub/src/Windows/COM.cpp create mode 100644 app/win/installer/7zstub/src/Windows/COM.h create mode 100644 app/win/installer/7zstub/src/Windows/Control/Dialog.cpp create mode 100644 app/win/installer/7zstub/src/Windows/Control/Dialog.h create mode 100644 app/win/installer/7zstub/src/Windows/Control/ProgressBar.h create mode 100644 app/win/installer/7zstub/src/Windows/DLL.cpp create mode 100644 app/win/installer/7zstub/src/Windows/DLL.h create mode 100644 app/win/installer/7zstub/src/Windows/Defs.h create mode 100644 app/win/installer/7zstub/src/Windows/Error.cpp create mode 100644 app/win/installer/7zstub/src/Windows/Error.h create mode 100644 app/win/installer/7zstub/src/Windows/FileDir.cpp create mode 100644 app/win/installer/7zstub/src/Windows/FileDir.h create mode 100644 app/win/installer/7zstub/src/Windows/FileFind.cpp create mode 100644 app/win/installer/7zstub/src/Windows/FileFind.h create mode 100644 app/win/installer/7zstub/src/Windows/FileIO.cpp create mode 100644 app/win/installer/7zstub/src/Windows/FileIO.h create mode 100644 app/win/installer/7zstub/src/Windows/FileName.cpp create mode 100644 app/win/installer/7zstub/src/Windows/FileName.h create mode 100644 app/win/installer/7zstub/src/Windows/Handle.h create mode 100644 app/win/installer/7zstub/src/Windows/PropVariant.cpp create mode 100644 app/win/installer/7zstub/src/Windows/PropVariant.h create mode 100644 app/win/installer/7zstub/src/Windows/PropVariantConversions.cpp create mode 100644 app/win/installer/7zstub/src/Windows/PropVariantConversions.h create mode 100644 app/win/installer/7zstub/src/Windows/ResourceString.cpp create mode 100644 app/win/installer/7zstub/src/Windows/ResourceString.h create mode 100644 app/win/installer/7zstub/src/Windows/Synchronization.cpp create mode 100644 app/win/installer/7zstub/src/Windows/Synchronization.h create mode 100644 app/win/installer/7zstub/src/Windows/Thread.h create mode 100644 app/win/installer/7zstub/src/Windows/Time.h create mode 100644 app/win/installer/7zstub/src/Windows/Window.cpp create mode 100644 app/win/installer/7zstub/src/Windows/Window.h create mode 100644 app/win/installer/LICENSE create mode 100644 app/win/installer/app.tag create mode 100644 app/win/installer/baseLocale.nlf create mode 100644 app/win/installer/baseLocale.nsh create mode 100644 app/win/installer/branding.nsi create mode 100755 app/win/installer/common.nsh create mode 100644 app/win/installer/customLocale.nsh create mode 100644 app/win/installer/defines.nsi create mode 100755 app/win/installer/installer.nsi create mode 100755 app/win/installer/locales.nsi create mode 100644 app/win/installer/overrideLocale.nsh create mode 100755 app/win/installer/overrides.nsh create mode 100644 app/win/installer/setup.ico create mode 100755 app/win/installer/shared.nsh create mode 100755 app/win/installer/uninstaller.nsi create mode 100644 app/win/installer/updater_append.ini create mode 100644 app/win/mozconfig create mode 100644 app/win/mozilla-102.patch create mode 100644 app/win/resource-hacker-config.txt create mode 100755 app/win/update_exe create mode 100644 app/win/updater.exe create mode 100644 app/win/zotero.exe.tar.xz diff --git a/.gitmodules b/.gitmodules index 9883f028bb..9f01abdd82 100644 --- a/.gitmodules +++ b/.gitmodules @@ -47,3 +47,12 @@ [submodule "chrome/content/zotero/xpcom/translate"] path = chrome/content/zotero/xpcom/translate url = https://github.com/zotero/translate.git +[submodule "app/modules/zotero-word-for-mac-integration"] + path = app/modules/zotero-word-for-mac-integration + url = https://github.com/zotero/zotero-word-for-mac-integration.git +[submodule "app/modules/zotero-word-for-windows-integration"] + path = app/modules/zotero-word-for-windows-integration + url = https://github.com/zotero/zotero-word-for-windows-integration.git +[submodule "app/modules/zotero-libreoffice-integration"] + path = app/modules/zotero-libreoffice-integration + url = https://github.com/zotero/zotero-libreoffice-integration.git diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000000..07e2949ebc --- /dev/null +++ b/app/.gitignore @@ -0,0 +1,10 @@ +*~ +cache +config-custom.sh +dist +staging +xulrunner +pdftools +win/resource_hacker +win/firefox-*.win32.zip +win/firefox-*.win64.zip diff --git a/app/README.md b/app/README.md new file mode 100644 index 0000000000..f96b3a3d69 --- /dev/null +++ b/app/README.md @@ -0,0 +1,4 @@ +# Zotero Standalone build utility +These files are used to bundle the [Zotero core](https://github.com/zotero/zotero) into distributable bundles for Mac, Windows, and Linux. + +Instructions for building and packaging are available on the [Zotero wiki](https://www.zotero.org/support/dev/client_coding/building_the_standalone_client). diff --git a/app/assets/application.ini b/app/assets/application.ini new file mode 100644 index 0000000000..edc50ea24b --- /dev/null +++ b/app/assets/application.ini @@ -0,0 +1,18 @@ +[App] +Vendor=Zotero +Name=Zotero +Version={{VERSION}} +BuildID={{BUILDID}} +Copyright=Copyright (c) 2006-2022 Contributors +ID=zotero@zotero.org + +[Gecko] +MinVersion=102.0 +MaxVersion=102.99.* + +[XRE] +EnableExtensionManager=1 +EnableProfileMigrator=1 + +[AppUpdate] +URL=https://www.zotero.org/download/client/update/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/update.xml diff --git a/app/assets/branding/content/icon48.png b/app/assets/branding/content/icon48.png new file mode 100644 index 0000000000000000000000000000000000000000..a24992b84385a53eca054d0c616df9544de972bf GIT binary patch literal 4031 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 literal 0 HcmV?d00001 diff --git a/app/assets/branding/content/icon64.png b/app/assets/branding/content/icon64.png new file mode 100644 index 0000000000000000000000000000000000000000..9ccf228ff479a4c76151590f966c63d7a633d10f GIT binary patch literal 5884 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 literal 0 HcmV?d00001 diff --git a/app/assets/branding/locale/brand.dtd b/app/assets/branding/locale/brand.dtd new file mode 100644 index 0000000000..cba785bc63 --- /dev/null +++ b/app/assets/branding/locale/brand.dtd @@ -0,0 +1 @@ + diff --git a/app/assets/branding/locale/brand.ftl b/app/assets/branding/locale/brand.ftl new file mode 100644 index 0000000000..3afa9eddd1 --- /dev/null +++ b/app/assets/branding/locale/brand.ftl @@ -0,0 +1,6 @@ +-brand-shorter-name = Zotero +-brand-short-name = Zotero +-brand-full-name = Zotero +-brand-product-name = Zotero +-vendor-short-name = Zotero +trademarkInfo = Zotero is a trademark of the Corporation for Digital Scholarship. \ No newline at end of file diff --git a/app/assets/branding/locale/brand.properties b/app/assets/branding/locale/brand.properties new file mode 100644 index 0000000000..5adb572994 --- /dev/null +++ b/app/assets/branding/locale/brand.properties @@ -0,0 +1,3 @@ +brandShorterName=Zotero +brandShortName=Zotero +brandFullName=Zotero diff --git a/app/assets/chrome.manifest b/app/assets/chrome.manifest new file mode 100644 index 0000000000..3844885506 --- /dev/null +++ b/app/assets/chrome.manifest @@ -0,0 +1,3 @@ +locale branding en-US chrome/en-US/locale/branding/ +content branding chrome/branding/content/ +skin browser preferences chrome/skin/ diff --git a/app/assets/icons/default/default16.png b/app/assets/icons/default/default16.png new file mode 100644 index 0000000000000000000000000000000000000000..0fd6f5476aab965a98c1b739b2c21ac28827eade GIT binary patch literal 1322 zcmV+_1=aeAP)4Tx0C)j~RL^S@K@|QrZmG~B2wH0nvUrdpNm;9CMbtL^5n^i$+aIn^?(HA4aZWV5ov6ELTdbo0FI&wK{O>*+w4vx20?>!`FrQsdJlnHR>OPy zcd~b_n$otK2Za4V;76L-DzNVtaSB-y0*E}{p()372;bw_^6ZZ}PI-92wGS&j#91PI zKs7DSe@(bk%_Y-7gGe}(^>I=@oY#w#*Bu9GZf3^F5WP>3rn}7Ut74&?PWBFvy`A)a zPP5)V!Xd&78LdA?xQ(9mjMYElVd13a#D+Z_7&Y|xU=_C-srWU*6kiZcC!$nw*)9$7 zn6CX+@=AhmkT}X@VSsa5NKe;HZuq)~1$`#h6R+ZTR#D-3j}vF!)ZOnz+5)dI4jl{{ z44Mr{P!L4~VVJN`K!!XTF*LGrKO?IK8z<8w`3e3jI8lUGNUta*C8 zn(P`s>{pjD=7Kek#B;Fw@hxAK%$F&Q6vg9J^Xf~4by_hu-=A!MJ3Znq&n~srbFGPs zH&&aMXZ>nO`|hf|ljc?VPhR!${AbO?W8x_>CU%PFA&Hm8F7cAsOREdwU~R_;ot1_u z(ruCYB-LPGn!NQdT|ZlRy+(fw^-+`=%+gee_kY4FWHg<*4sZI8+sFJD270UUORdLHO0nA4V) z%{fwsET5CQ>B?eK%uw4yQc~9?*JVo2}ze(;aRcp*ceL#HUJSllrgm5wQKR zQu+C;QrUh^8rFfA`ftFz{YAidi-`aL010qNS#tmY3ljhU3ljkVnw%H_00H7jL_t(I z5rtDRYuiu|K3TSGMduVF+mOVihW>|6U9+}ZvIP&NLr6l0k{^(@rGyenheAWQ(y5R! zbD*BPbW6a7Sfqy9&yKBFQod936sa-I!Rby<-*@-D_fAF>MI?6UIDeD)?fyq=G%^I0 z*U%8j^R+dKf`G!SD+*>a3VlEJ8Da##?Du2%kJD34yDcE?yX`hjyWQmDyrj6YLTRZP z1tGRmSYFQXM2+ux$(mq9t+u3qRBfM~>Ge3e%v6If)ax|8DH7nzTm>(04kcaTqvN!2 z$e)|8OVZhf{J~@*3Ve-A6zByVKQOP8VSK8T%j9DlCRF^vLH_c*0P7nXm(xi)9xy*c zmoJa&b+cqyG{enY0?<=Ry1&>|>Z``zDe#_o6`*g;TFtVHMVgMsHM-cssN zlO<*f>@zD0Pq~X9~Pyegg7Q!*y-8Z5nhsWMcmy zitoKr>dn7oc{lVZzh#adRw`6+98w^QS&NI5!!`Dx5Tij?(6){eO1tbIj0D$oIYgg_806d4MJbOdg=zUx77sGgsTFElQMR12EXH}skhS*niT*sBG_g*XJ`rSK2k z#q3dYi`^3&?Ea0_;N3O^yR88Ij=P2B43zXAtq1<(_RX^UWL+?;1dQ7#Zhw}`Nw;Ku zv`pPN&Lz# zI{W5`y&?17+b~wAxd(2w2j@1w;a?i!ZlN>x#xA`=@%zR;ZXqSO3J;r%;(;iK4Z$KA@O4CnBtG>jLwK0xcEz;~3_1Pk9R|>l8D|dj) zLJVZtDX`aOIcw`0`^-}`NlDTI@ZAfG0DH{ZD8@bRH&-dJu4ny^)|$JAZ+hJk2<1CH zo86V|#$gX|(et>!g}7HcP3XM>>>l*ID`J1T&sHSY>JgiWS3t75$FZ$&bnB`wCnH9z zrKv^OLuH#w;4-D*d)R|guI9cc>$7L-!FDP3pl|=MSbb$;TEu3mnQ|I=a+b4G!JQg7 zm>Mrt9;#TFY(AKbCrMvNJkMw4K=yK`tC(}M+=E%HMKj}OvtJ2!X5+xVr@>HfEt|8P zeSRHiL;`9_Z=RJ_BY-b=iK7R0(F2S9fw-;3Hlx+H%WHolK~C;%rJTQ|9yoSSGun5v z3+}1h7sM|WaQ2RSvGyM)Q5LiGxIj0fb+VDi1pPlkpW3ZL?pLXw zS2z%fmHI2w9FSAWSnWEG+QUar!qS`nBal*GLFhz5pDLRS+pX2b&1{#{)GZlq)Um>) znc;TzhZjL)lylp#Oh|*y(I^%WMhlbmO7>cMKEjQiWyUu6Wi#Jr>k$3|Vn2+BuKQ;9 z8LoTB+XXNqT+HPd(^7zv&oTbbC*S^8rYu*Q3op6h@D{h7x$1~5b@SdK_Kqia=Y&r3 z0GBDTN?V` zzxPnX&nD#^kD;AZ5r6D%{iN|$<}52yS{IDZhPH>!=`g{eqk*BLmpEXagW7-e`M|>U zqp_Sx7>5=$`>#}+)`Q2i8r*iVHj-h6tn|L~Yc6zVDRfaP*;{KQe<|G`tj(atg}D$p zg3UC+_#D-jp&@6{p_L(h*xf*E;1+_r#GMi?3p%WozBiFv7&zy{!)j>WZ|E}*{ny-` zGmPD{Y}hy6x_QVn^@2yalVbSE>Gc5LaWf@+dYqT*>>g$ZZkyWrkfn#C=6xV8FLXe+ z%B1(p8c-&fRYz%k$Q$lKGk14=tu$g@3^OMduzY&H5P9&oPj@Lp-Eyjw-Cf$4A-fS! z)8LL_rC@_B&5J>Cp{c`7q9+%(!@{>_qvVLf+6{6vy(F+n zVRPCj?WS^*pYQy8xCe$VhV>>B`!ffT2O~lA1*l(KWkT`a=$So3l^?&a2RxRLkz zrzY@)_Y5v)mYaTzDT1VnY|+}7`_0^aNvmHYC3l&Db(Ex=FkL@vcvE?}M-*iON{#Sn z(_#uL)dJRn96A4%WfO#@`;sBtGtL=hte@F?KQAnOyl*j{f#tA<*BN=LCEN%EGor5m z^S5AqeND8cwtaERcOY|5<`DNq?E!x)Jd(SOoc*SG&Ei^3cgYuJ^qinJ_)5*favbOL zp^`5iD)RkH<_t*iV1!omz+_lTBSr51k=KZWVML~n?28)xl>cZqjgm|Q@4Sm|XhZB* zAksY>=Eti=W)zzbqEl;*&BQStUC!E?i}mo!ztVe<_O-O;=*~?J4w!3I)zqLL7IUj) zl3a2=$uH7dP_H24phFwy9Vc?dxWhS==U9LiF8vclYLt3+Rn?56f{sRyF^KYU-)Jw7VS#7IovEfUa)0f+JGYDVeqYy%YYv)HNzfekDH_%J^ z&KZU`k3FjYL=-=$_gGchAtN|scteeDiz#d~K{sYbs*mQ|W6sF(u1yc__s#O);Z1#dT-i24K|!PQd_PNU?sLw8hH}gR3lW<7##ys znIU9rtzrgiTeCI4*F4lIQCe&N)Z7r3)kKwA+$pZBFpV-_@n}bZ>u^aYNy+!sdqG^UKHSv@h{2d3~b(6E^Jl#b;JtVn3+F1ImYBSHz|) zqWtMi9Y}SE;88I@^Xhr)$x;p;9HymR0!!cEayGL0H?$t|`fa;7@;gn2YmHkwhL)3~ zfC|k)T~57ky+zV%o@VWF|AT4WJ&$z3z9u_Kkw&`ZT`#=*KAdl-Qqn1+Y*H`qm`wVZ zPod59E72dV96W@L4{D%-J11pa9VTC}ku-j!N@(SJ=t*VeQdGNwRzWtV{v12(ZmqNM zgt~dd`+wHm-@$5|kf+AoIa2FhQL&aT_(RE_?X`IjIb#zZyrXlvx56KK4y(WD3}IWw zH@y7-ErQ*{EIMNr7u%IF^pDH!?&V8r_gz=czh+ZlFtbe6uW&ILm(DQ)k z>29>-YvjB+MLDlM-XyvGFDCT-{MvgUT9UKDJ!syFOGGp_`8ZSiN2R34-FQ}gpZX;f z%UH}jGOsDIo2G|L0W37&lT90;8?goZuvgbL3JQ}?qaaIKgUOqkGO_%{HAh#jHkr|A z?OiK|X~~U+eDzH7%fn*qIw~A>kZ$&>EKJ^wM{u_g2;k;_8rNWTgy)9nnVIIiVinS= zd*~uSY+xb;RUI1juU?i&>!^)nKxl961)J^s^eUt?ucf*5~PqCAa1pT)ifz z&d%YzGy|)Wos3Qw*1nPtgD3q)Q)b5Rqj?}|9hREBv8M{PFLHqrQ(f&5A)YYXA_=on10p_Ba{`?na z*5?gqYZg6rKU@8B7-euH*5)pjyK6pX*?-Y@-(oDyw2OZsfc)f5gH)YEDSpbNdgdXM z(WcJVxGxM}uQA>f|9jzoPWRc1CwqX}{PWk1GIp(-;zjO&coX=D+&O8^)BfofL6C(j zoI%LJ;1hOf$n=Vq(e6VgbTRz#0RN3RqXGCEgZ7QT4MtIS*u=2H_X7upbnIqwwt=^R zY|!zQ$CuLxo|$MXeTd22IP~{Q12DQ7^eyzw%TU7uLpMHp-Da$QYD3&kdcF+z*=ed( z{AB~P#K8qoWbQ?muEG{w=D8;4b4`ft@#+^?0eh2>lDWUXUu>ArK?28a8?qBZd&2ii zhU`N-&Nv$cL5YE0?amPmiqd7{jsy2?AF@6dd(1TiPh^9#!e&Jf#v6~$)cQVP0}eje zGxBtI=8MA`y<}2=IAwaGG%IoI_@o>Z2+6mU4z$1*sI!Rd)B*Hj2cb4PJJzrJX?+Lh z1${C_6AjbqHgVkReqP>KY`m15W5n}rU=kswO>$qCoT0tF5CN?dYLwHG4t%^-$2SuZ z2CM@ngyD~b!BahgvbT$z`|89X*D_j@5CkgM!*)ErEfK~XDP^VIzgo5*@NRck`rC24 z5vIbdzu87KVHd4rGQAEQ;J2k0U$|$*?2v*kf>k!{hNj)GcTlC|nSVSjl+y9<4z@bj ztIF7QU#`PHam}`JkVdbiQ;CJYD^1yh-n+gJpKf@5wtaXZWUxU*CxgP#a zp-JIm>-H}&gqovrRY55_)vZ#bS`$Q&+CUM4%or-e1sWnD)ugkh3?+{+ce)KRbjXntWXC*;X$!^!A$ud zpg3N`+u=O?-v_Hp>!Zcj8Q!id(Hq^R2`mxI$R<(5tPR1{&cMw_nk#7Y>xwD%U#9#nAQ|4BNXv%75c&$e-Q zi2Dk$v2^zB8qnAl?esIO=D7_pcm)jD>%^1iQk*r`kCs=Mnn9o{s4nqFPgsEA%U&!K zHW1V=dA^07(i23|^9GvevF3qBn-uwt*a1L?2-o8f2G!_gb=G^t z>AO}>Fsh~3MDpSlr}OkR^kobN@3R4+1MH}1KhNMg-NpIe4 z?{K!$+`sZIJ_Fs-UjOWG;ST|U+RY;_opMpOjBV$ZWiEM8HAy)9Md~W6NAWp->;%)O)ltrtUi=49Gf-PYFf)cF(TdJdf*@L)x?B zgmiQ6$Ftnk-D=R=QHB&ACk^1058pm{WkcO*w)>URO9R%1LhVp1(h3~rUC5Qo$HR1^ z=Z8<g1dGS`h>E*LYQCV)GfZ4Nro>QNs zV!c7HgUsB8Xu}n}Q2DsvcF3#=sifVPH!56NH21ogep0F>RVt*(Wo)yzEUIE-=RRV4 zw6K5WFY}8LKp^jmsPX%APYt(sYevJDfUx6xrVs;{zwrw|2ZJ$v|8obx4kJ6d=PYhB z;=t;XKyv))oYKF0-9JmqtT(!Cb2o(>=kexQWxSUw_9Wcz&M|FV7?O!VEr}%S8?xMgbypD^IM+WviI1{J%I&apXwT$Td<_9EI~Xu~FL-n`Ae1 z-3hSaRV0soO2|yy?eoHaI!StXR3zL!*9w~K()a+i*wLOh?=};>(bDxao^``CzOITk z*9llto?aWyuty6Rsnj4=Brq#Dp+%Vl>7BQ4?bb3k2FZbs*YMe~oc9rnPY%28Id)d=CsM zbZNMJGx++NY$FF{_AEcLR6hBBnF24F^3^m~zP9Rdac-%@7=X6tbKFisV$1JV9=*H+ zbQ^Si#qZ(+HT;cPsBmYs?ipnY4+@m4teQxU{~!7dGn$T9*=IQAuX(+ZO)u@3a0PKz z!}q)B%Pr5Fb<{MW4a$VyJf#15KbNWHO!Ohito@awuQ~JnBU>qs9NbK4^?wKS^(M!WG?Pi`kNAEKkfXbN7r^FqZpXuHuR^YpxOuJob0s)inPFP7+Q*m77!Md53O0E^er6VwR{p zSDbv^zJ@ve6;+h$tYE{SOO_7W-86GH3>m-dp+%ZpL@ur7IgdQ=wJ?6fVLWt14+g>P(n{=!vN$G0DFD0hUTfwvB2BB z#v}RmB1OY95MRCdn?s}zG^Y>$V%^UXfmb)PG;fgo_T=)MKBHDYS9;+2NGH|EKT^%|^CCGt^hD9EdSo zWrp3_92_O(R~#uy{FE77yQBTSLr|JtuwleJac1Bcdo?wCyVX)FbuE|v*!SX0U}w{Y z^3*P_S)F3^!a#)`OMz|d?%?l+3dvuyIx@|JvRvA7v#c?s@?dy6OYs63d{lTFd;a|- z*|oMNs73xjA(rP5xZX)MBBq(^u1GQQvCP6L(6)NSuFM6nk|^n=NxD zm`SnO(mGiiQSOPgUHo8%`PYn7COigbxs3e}E{N&eFH|)Op@tBd_4M`ozq?S1p>^Lk z0AL0{-k2XPO#6#%xtx!+lm_I}5I*NpCfWOOzZs^`;RnYEoReRg7Ekt%DdKEGtuQ)f zum@1;+?FZ-aXZXw5dF-Ov?GSMOZ9DAl#=8e)n+-pE!P$6G$xDLNq#Qnv{W7HBwxS! zfZ0_cYIw%Yy$?DV6^CvL(xA?bIozst=Epr-jlogJaM&=RxO6v#Tu`9xoZ;Oe^x)W8mvt~3mzI4D=tZ2pf4Dlyo}YPsjw5Sc z9vaRopL*k7^(WHFoA-F7U4#2`Y5T5?%;J1?0y6ha&Cx zgZL-x8Eyrqq|#RZ{(YILNMwv>fomVW4RRef#@5e|*2EdPc)E2T@f)fXbM*rAc+)=T zAg-TxH5_|n=ho*LF+2JpTW^Bgp)G`r+?Y5r`W}d1OLr(n1gT%}IocS>*ge1V+e6rH|CA|aoZcd5x;P+Y=ZvLWav9HO z@7S!OEQL$eL1Bm^%Lw4yt!8e`0Wx%fvb{T1`d&W_S2}L{W3OTZfF|UdgET)(>C*#Z3 zcW6}!JI3H3Ke+lCDZsd6w#fJ^?cmBVA)hWj^ryZK7k%UNEns2Wu>K5i-xp!Zk?|xP zs%S}Bdo#$ySw%w=OMlRC-w z(o!lLbM9(uz(Get8-)%p$~+Ic>T;tOlO@=6I0~Yt*}x?$#h4<|{I&r_D?>{_*Hypc zIodlvla}~!4p-pF9&?<-htF<18=dUQv)#ylIE;|Z@Hzi^z;PkcQo_N;1^!s_!P^F| z!4MZsUdk{W+3pI9Ke`nEHb!9;((U~WIUe+Xh0DJK3b@GV_=rI=Y&>|gQJ!+9lQHA8M)K#|}S=RXbw{EV~ zi*MZArZe0OCsx0SS-P^WXS)}cyc|P4*}eO;Ld0F|(Zp)5cG?KMnB4W5xw1^ZaM}WvTTIF z-x^-S(`*JEfm;=e@m!tu=VMKp8zUMhiNAQ2d8!2NzZMVaq=?QsGd);xZ=+I)^p{TZ z0-^2qPTVXP@SirXROlCndA8pR|M*eF)QoX59zPd>lxw$g83?7^W>1z&TquYLQZDo-|vGH8S zV!H>aUlOzTGk3r;rO99%G%Y<00)Tiy_!P`?N3$wA6>9{Uxm-7|RR zg|+){GfE|V4oY>m5N8tjcom*d2hY8`qV^deFe_%sUIJ6c@@aBV`>h>kyAyN6AeSyP zS3f#4q>oT?~!yI>;+~9oC z1KjxN4rk`Za|mM@h1`6^UOuatX|A|@=`kgg+M9$VxTk`*o*x4L6`HAJl+?ozWve7%!=I~WHZ ztR7vh`RqAf#=Ey;{Fxr?Qk8YEIDXASZ&kq{WN=&96e4sWm&eUgI4D$7t6ZIVKZJlx zjhnU)<7h7}_1WkAHQBFX;txM1#q>|%m$#5FeABo`PsDJs7~JTtx&ux?=*Gt=!_}u- zU_5(v?>64MaD!X8+dMzx%77n>F&3eooOo|pQX_Zrc1y#23V^z1e(xiIN=hfgCGih$ zZTmi5i8MfqBpIc4brThdU1B8^Il*(II?(YP{jk-3+^UOVa1`v$14`=>NGo6vpPFxa zDs;2U!8w>V_awIgpi|!YJ}$$l)aWG^wIzjV99qbBqOKvNbIdFHhY}REJGBDfq&R#y z-f}!?+W*4;X91ku7vu^LAVVjEI7kq=!~w}EjacdB!P7Z|1T2lZ%iSM1uKU2}-+bUA z@1_`8o3~V`W0o}QUW9lyh&`|S`iakH`9%TP(XTcL>}T{|ZJ)U^ov-d|vC8>2RLiWj znar{ISc~RZb#t57pRc(nd?gZ{%CWH?hDPtJGttDki{gg1sPZc2vYDlJXvYrU;F)29 zN4arGH0GZavGPe%^0R0+#hqs#Ew)4^Jav4Hm0+Q@JD)E36)J7Hr&}GY3C1@~Xy*X? z&05;K;2_*9s4&jRTG5J@(4>yQ(h$DA(t)Fg&VS)HR?2o5grB=f@N45V>)dV{-Ms5C z$VIKFZ;P-md-dDVJCuW|rj}=}dvVJ!#4dOi3SN8i_v5hBjbXZ1&c$%;pWLyOHruEH z6@`!%{%5r*kfR!W+xwc#dy~()@^=@V8b4ku6z)LXurQ#kblrkTFs=7?F5Xk47i7m4 z+I4sheNE3~e3KLoW#4?^Fa@LM4JSnugq96wOflv)kBqlyw-1d4?<{FE)@H4PW0F&Z z7ySwlK`4M-?Di_KLn76MRx|n#Zs_z1wGfm2YpV&;e3PUtB!b2LLogal0wKH#z`D-h zQ0F+$6eDaA7r%7q#d2meDApXG2UsD-`V8;2BaugSB#*xJ1nzCLhVyP`Ni$17Nz=kW zz4W~ccoY`<;q1yvRKBzpbIFsM48P`gTE+3UL&m&Q!+Z$dT$x6cwPEmHpaO(#SLhn> z2FjCURH-VAeNr~TsY@V*<9>#EL#eXZbIV51%4Y&%lN{cWVOS_k%uk$J6El25oKV(} z9X|olGg!o1*AESU>LrrGo1XM6vQ@+gAI6ew+{zIlNguM@eD`>LnImtBq-A(E$4wPE zI=H_MdcxRe4n`Jn8Nc;r00=$dtYSwbR*yNrX*@Js3mN}m8wddT0BR@d^AMD?kktOg zYh>wzA?fK%Ul@VKC5jYr|G9PCUdsr}oj&YQu;bcXTO!gBWvTdB&bek6I`dS_zHmLK9eMK8SGSyGDH&_Oq1OC@oA<7MfHc8syWdpIQW%K_ss=Utdrb?KfF`OLtV*`t&PkR$(Ddjs6j^$$4e2dz?Z z>cID=*JFb}@5(>3ZC3*&I6L*ZZ9p4 z1o>_8s6>s@S|`QESr_)_2E+Xa7Tt{Fk5nQyix>1YBswvBY35P0!DX)T&)gMfomWn) z*!PknKV(Z0%M(3&i<5;{g*_zy9P^xYYB>{PL5jC5o4W&jt>a zt*>{rT^1{64n4O z;~@Z3Cenbx)G$+5rT28aoH@i?8=noC3)ggH?qp;V=l)FElUnLG*s+*M|Ey5Af>P6H zbaiV4JHwC|78E@A!g)XQ3R$k9bJ^In5Bk{DJWh0`?Q&pa)=xlrk0!3WpB))ULh3jf zE)K)E%-OVC$$oPnUoThJVOVpto?Ho##AM=EPYd6MLf9gh=$^i&o|9h0UV)*aY=xb<^ zJf9`qH^ca2E#-lR6QB~Rs6q`7s_&J%VSJT=vKpVPT%<&N2LCB~07?h9MQbLn; zx^AdRmqRnJ$r9@M4XOU%&bhft)6qpB{`n*NtV1Kbewdja29Lju$q=py3I&tDrYSVe zj%<-7E$(XYhT-PPzaD}?KtJBkzS}vi3l0FJkGPndnu!U#rtPg1ap+I;pIAps1#8E1 zHU|DO`Gpb;J1z#Hg*c$i+&jE%HD)w07VCfL*N-13Xj*myT`8m!Sn@MFr5x2G#EX8F z#+)k((s|*^1Ej8$VdD18NmK~Q6Wr;?qp;Cw);#f3>BzJk`5E)nVN}l!=i7L&eIjr2 zVORaqSugim;GLKM+pH`=94vb>2wJ#R@^a&CF>ylz3R_Aw9NdC6BmZ46W;79&w#H3t@)2|S*g3p~6Jw$^a20q3foClGo?1wPO0 z8QC=EH@`-H_DH!pR#~d~()M>xc1PbgeMrKnt^5m-j4#noBa6gbLvNRS4D|UrP-%#4cyXz4@P&9MUz5CsL`7A_%I0UCzaS zHEE2*hydYB)~MjYuMp*+xn=KrrD{u0RhSm2Kgj_fq@`@)+ca0geclk0?YGkU`m$NQ zed&jWUSDpaBav6N@Ym^-$6ev`agUM(7X<1zbN$h2nnBMll@ig%;z3xJT+NWa0bA~W z^|b5-RLG$Av#!>NezT$6xzQM?C>hQGBfm}jYqV{(5BN32uLn>nzmT1{_vgxNzpsLm zcf8hIVXs9WQVPyh-I1#ynV&m*V%*VzT71Q*4HJT zFY`A63H}Xy24uKSJ_?xlfNZQop?&-~Oz!!mr-sxX$Vket-dzwYTGZwNmebUIXz>io4yy0?S)M2EUO=!@4vYs#LdG=^+YioLI z{QTi_hA9jsho`7m-(9%Y-hV9Px#P-WC;1jb_kT0i7KKr=fouFJ771<)enMJULW8Jg zT3C$c<3*?2dvyCX%3<~*1(FhDXD4T&7PlLMa!{Q2Z#1i4xv8NrEj~~smEm3KYe30R zc{cy!D7MfU5wi9DFnim_BE$cNGgE**1@jwg;hJS}v(U^srq$}gBfo{i5l6Ra6Klur zNZmrJ?M+NwJX}Ie->+kmk~*~?v~S6IKJHnKP!X=W9vk8IPPP}QlU|zZYBz8;gU9D` ze#utolUBR@HHeAnkjT&KF~XpAQP zvqC%0z?QsrJZxkB?)qnhy0fkP5kCh%6ZLqHlQClD;|ttj2Vk1hRrPhi4x3uKoxcW| z2YjjaO1Q0n2A7=$_sr@3&S)!MxK!Km#;nj>@Zv-V%?q^>JKoZ=46kvRe=4b$AY_sw z$O+~(#Qb7>r4QZS*e7S-I{fzR;At!`#++z7ZN=k+WKD_m)^+K==no!IFS^CcQrXW6 z#(D!gw(f}6p6W>P^3cR!=Y@Bhxr={VY>eI&8_08dD<1Vf8SU=cyqwq#uiU(HvZCAZv$wBh+zMfVO`G73fgSg&?t7NlUb|Djg;46g`T$q~(NG zK^$VRZu~H?x()}bf7dVjoW5cM(0u~yjNLR-o+0)Khp3l2%*7^q-ZpXVpz!z_Yh!b2 zvMy!E45dsF86ciRAsj0_&gL7Fm1cF;nMjtgMuxObX17w_R4s*Bn7Yb|eN5NhOGZpjQFj8bwI?3<{E@Ds*&8JniTs)`xiIf-u9JZl zcSc8V4A2O48JbwOb7MR*KnP`>i6EiSVz=zuxX%S5eF z=r*U8)=&Sc6$>fTQd-=+@iYzS8V*hRpirV}MD|gh(R8*+c63#IFy>;&_c0&LBOTlJ zB>ue3P6eWII6q-*u}m#M(#OMW^u^#@Ul+8$4$4;}sug9`$SlgYk#fy!9+f7eC+=dV!-Te6^1sbJ551W@FMI%BtjH&+-W-ibx`Rb6F zK0A(>876Mg2#bBKGDGJ!0>vZMLR=kJ!47Clb)6HMwfJX9X;ZE;lifYP>Di}UPx<@^ zJ#LTrXh~eCs@}}kRCewwfLv|<^Lfi|Dlh+3sj{%#Y@6@OkP{cPZSD`CWGJZ3`yK}B z0<@uuOACJKwg}$d_qxgiugeKr=__6K5I!G$XiS%?_M)F-T<;M5J0dlBPfw`VL~b?< z>%)y>^P256Hbd;%VASDm|Kb6=j7s^cyO6k_7j{dmJ(nQ4eX1W2HQg0*gxpaPq z^`ANhI=2ZTnXN2!5^l{YU*vgQXRiCL>^2<(^I|knUxpTu@zJo$4ycgRWnx}^^|PkW zkl+zLHLLV*Wp5_kBLX93omaX;SYNW=T1Hg_Li%BUZfD0-S$GXE=UMOP!7(1K+MBI#1l}{<|G3U3%J)*jF zT~C>@U0>GJU<^tjch;SoH$Z@Vqya9r-6h@YXzj!jD*eqUAUJ{Ct8kgwk?|~6J-LO& ze^imw3$@7^8ir7>2e!zDC}J24JWv!??PC#$+-Y4?f=M4;KVko+LMmHN2pmf>;te3a zB?pFjHd!LiyQ`kn4;Dm`0{ldWSvg)LB0J5e<3q+BhlPi_6ZHlyVx3}j{Evb*zuA_> z_1k(pV%v3%X53Vgq@Ex41*iqA)s*^YtFGN|_5>M6_A1RfRv$~h$JThwVHTcOBSe~;?VU)rN0aj&)hSi($dS}Bk}rVS;LTX ztcR(^RviCZ9UgN+na|)H9}{IzQHt}zXIq7SVr5AyO_Q;C1-S6Vw&q2gvLr>WiQ>5= zjSh-|Sh@=!@F{JC@sS4!Z6|#X!@<5D_!m<=lpiCx#EWi++iA9SOC0dw)FM}CUr@$F zhhCHZ^A$2AWTqvqdXsDyarW-+s}-9F|34oR3SZ-02AJ9)Fk7Q;vE zZr=Re$ZMt$)vc-FlaS$LeY2!$vqulJ67G*;__^3!imed7y-A)f<&;lLNB)ME_3h1( z^~bcb+9nK^7K{xigKQCEHR#EblMO@N(0 z$NCo3nj{8OW>0yCDVsl*9G?C<9kmLUc! zec|EmuVti@VCS`5R{b~a4FOql3U+)_;QsnYS1mZGI3;=EN0riPYL7_eLb*ZmO#m`7 zt9SFK!KK;!_#Oj(QRt1qqQeAj0{>__JqEb7prEo`hU^yq; zigWzE9xKZS@9_Ff2xT-uJqe8v3esD|xemU#**1|TJM;)qJ6ep zc(nB?E@N?TGf_zQ)~-owI25p3HxT;0&+g%EJ%0TWw|^IPnn^i5*E{eM<`kz;i+Pn5 z$~iHmoKv{A@Ax)JSN`!@Q(4Z-(Ju+8MyW}o1lfhRPytf+g*pdVCi(|;uKT|3r!n_lrK=tH@k$4T4w6)&9Rz z89A0wbUjPYN_u*-FztJR>h!XiD>x3xDwQ-kelzHN^@R0fn#g<%>v7cmH=FlMK1vUD z+xgI5E(l^0vV5j8pus)Yn=)+t&z+JE-UFZ9*#@`_YyEpwr)=2Gzq~K^ZWuLOHKWfJ z`UZ@LE3oEP_)Ts?mgeC#fJC0`P?U*DuGsBza48IHNHmmLY=7+bp#o>{z>RuQ&(Ip} z({1aKGiqGt5-0Z2wS&0efTny^*QLfLe=G2(ln8S2k_n{+_mkyUmd^pfp)JNYvt(Wf?zwE!mQ@M9&=N^lf}@YQeG$vi)?31g z(cwbxO83!d)Km;p#&$n(MGYm|;97cmz!8hVJ|rL;bS!0!Bwwkr(;eoh>)~(B-}6M| zpEE1plP4E-`@cADJBe0~j63C2m4pYYRe<`@BjaNddMc3Ap;AxaVk_9A)Vr2^P(=XF z!*M>AQ|+jZ064bzlTDG5GsRi=eoM6ia`4H<(bk@UO)Y!Z&7>@!!nW2qz=k$}v5>9$ z`1!5hM$OO>DFFPH)e)^f=ZCy+6cqN&AuX?vA9_SK&38VgQ$!y)R`Qq16tTx6ju;)# zy5vC0(2)2x|2E(=JB#Qh=Bti*JBtbTI)`HDogY58fi$l!l}AOWnBlwj!@`j6KA%zB zwq%RV@hcpY){%N(?LTce&Pp?8^ods2F)ieAx0952T3MzHt=X6Ft6QtDiV}{VK11>O z0(-3NbxPGY-CdHsrQ|^HP#YzCO4;axN0lHSJ&V*t_vdle)<&Nk ziIfipgKcC5N`RQ;fxqZVp;@KL=2@{>%@V&F4-){uv$ z#vJiKgr9Tjw3vBl`DP-{-~>V79$Vp&?tLSYLU#RNLeruh>xl>XYy@mGcCK<$ZU4`Q z{ymd6oXfAWrm*`uPwi?hq*t1xZ+z`F(UpLhi}G#i{`B`%ON#A>;)iY;!5nZYrb8ua z6{&`kzb1U@s@#98>dfj#6G&HgRGzFxH{+)M_inEKsK#eWCdEAHYNfZY;TfOX3bT?n zE8%DDnSQNSOurQ0u7m-v@kng*+$$-7?o;Lbi^S-+_lJDH3%6MP8cIqgCl!y6flS#&J(qq97P#l`*$XD^%ArOMbZ)9cHlU8{k6|y>lQiUOOKn=*65#)@&}>9{qIi z(5wBSQs?`sAH^*%H(mQoy+3I$#Az~COv0{Oz@yw8%Oz5rsY#KLX+291S0aSBgeZmo zbjC?NEZ^rwfk%Ntn$|@bg~~aR?BS%?6gC*hc8d5kkYR8eF!)$oTNLW+Sl)Tt!s=iO zv0s)II=77S40GMbj0ZCHFi$i{zi-Yws4Z?y0R^+duYx-T4ZwT=Pa!z6TN1r6FhM>G z`a0PNylMp0Q6teMolOtU8HAwVj9~D8ok+8q8O?N^aqWMf`YA^6B@*UtVqA z0K3q9O#1!& zww!WM*VNa(B@Kp;6hlv^^w#%~!glg&T(FzuPV{fXz4Y9Er z)h>a1PB*a11Xi+2+#uXX^$N+}w@co~pNCM)?$~#OSaM5@1zv+JYIiavm!CP71(ul%7ZvBx%K&5$iac z?I%4ym)k%LqONr5RV67u9s?@Tp)6FnKlrw?Wv@+v;6ECm}HxRSD@qtp9o z{13*(>ejRWr2yxv7Q^Zc65tD!xIE1)u{URLLgMX#J_1?2pQ3D0D^8v2zGS>aJ#*{} zu4&T{cR(#A^8E66rn&f^<&$yIAie5XrFG=X3U_f;iT*2&F*P~gqLN7f-C}Z23w=dX zuhTmGHmXzRloT|G|Fn`FDzdP;TaQRk7mk9wm3?8eJH~wcx7|@Wc={keMYf(os(K5CG*A?z034aQA75+271UP$+gQ4E#J%LT zXTFHF>)yzPj4*RZHqb}hz}BL$wy&!^tHf*EhBTJR-Z8dNv}2lBojlMgawSZR**{8O zLNgP%*69(3_Tc-gWnRL0C7o|qk+&1?&nr|D7w(X0K9_CCo=`iKp$w=rBhI5;vL|;_ zNp}&o5ZL%%{CV#8qTfhzUAET)5WYd3^xp>ZrK@fqfjXM-$#=qk=PE_4$w$E?@r3&q zyTLrJy5`xojX61K$vlGz!*lo4@M0MZi@h#?mUjcc!~bUiQkqIM2m*1VHSX@E>P=Bx z=Vs8f)@+scjD5FK`;qSU&0DJrX=9#ZUo#RR^bXm;Jj?I8gDF;hORfFZy2zPi&zN|0 zY%Kk}_L=?ZjY(6y5D~Hc({ftT&4Qv5ntrwIdi15GbXOP6xF;VH?(2Z4R`9k3CW}xO?R@KC;|8vxv+~pO6bK4+${e{iM{2xu{9?#_e|9^*=94qgfnNn18J~O8j zl|reU4>^Q}Va{ewML8Fd<496DCFj%77;_v#&WAC_u{mxt{Py|YZohx`*RJh$y{_l= zINYBn<$K^wzN2{N+=hx@gJtg_%At*XpTR3#*_A6J4;@Uj#5FB@6pv(de=mz@>}GLl zjOWT=Yz{s~eY5RyI}vxB-)8W;Ah8qFcKq1JtAK0jwp3)i6~tMC)$8pnUJ4bgV3aAw zeTf0;rx)J9J`D<4#PS#Hk0kLu<~}+b8HjxuItsz zP2Vbh^hT!>+M0j9(hO(apQe zDB^<8UqJiDJ1>;LvFJQWls8YwE2BtSGuR&!10_~>O4Z7)3!-)`9SxDMni~V^)~nkB9(*V}yq~NfR8U`e_=wfY`hlw_PrJIj2^?IW zX@+0KVx99%{3$BJJuSq%of+CFFTHUzVKetz!^$==n{5V0tM}%iHl$3??Bdm={P<<7 zJ^2F)VkC?Y6`xDPMT;6-woV9#L91G(^V49RB^=GxHr|!;rY`qC1fJ@o&l;NQi5sVA z*|`+njN7o0GhOJo6?Bz*;r}G$Y82~`=4P2hJo0W$)khVnv@tZ4TO^Ko5OW33a$e^9 zzkZdyT!{UbQ4Trr<@MT6f$So3o(2Z|@RlviU^KEf4y>)QNc{NV#o`g|aPP4~UkT~Mdsd{n z5vo3kGHr?QY+C3q>Pue!1_XZB!2+*sO*3NA0?k5R64quN>(Z>;GUCH4!O8Ctwjfb% z_eJbE4Zb;b`H5TTXv_8&nsptU7{?q1F{rAGk!HVzR*&>|_bFzTfCruBkYn6E7vG#ePyVA05}7aCT#5Y0y02n1bhNfFe!6ro zrAi&ABx^!ObyU*aU$}>N5xRpNxFfxA>X=x4?q7v#iPt^fe%R}0Y|8aCdC}tj@j*(X z%HTCME3#1KE_N}Ewrt3Z;BI007NEXK%8D5$0Wcnj#evDWIeJO7C}97vmWmR3H!r3a ziunL*7YYq@?{b>0CzTqJ+Hl2kdG}14mfGgr)dX4)5y#UI6VaB{EfB9|C3SDIy}-eD zV)>t#TO+59MJv%WY?|2h7MInP1f*gI9%!8@shqvbo0~hRg}Hj)rg!`xD`L7}{8F@` zjkA}C9oV0-HP#|URS36~peo#RYhsayNw#mQD0L2h4cw{SoGW5L&7a>~SUOi|dZ)Kmc6a(B_9MM$iC zxhC6$26IU^gyh@ST%X!VajE_g9&CRGZmSEKrTb3!YwtDom!Nr2HrUj9y|C$t>0Arx zG2H?V#k|!05dPS}Vy|_7P(+|G!BFnwjsU!E!BA~#Cb)%5`{n+jn6m6REd#Q@cp!$Y z%^2D*5UAiGb#g4+?CvU2FVoQ1IZhC6+Ko$eSuEz&ZUivWwNjc*5=L;-(CaFo_KJUQ zs;%(g%i+JP>CsW$>PD5&d%rd1nne1!Lx&elb?q=#JlA1s2kSX+t9fCtMN)Up-105} zNlUed2CG(|UwAuY*g`1@cPW+X#@un!&c5l{@@q#XV&5poLi=Prhc~X`fo>>^|I#lC zFTG)`R^QTb;6`fOT$12%P~?{6dZ2UZ)|y0>7R%5!NlvKMd4slCACxS8`hzE=2mg`I zx*52RE5Hp!@~G%6B4|Law%4$Vp~^00jZje6M1w$OO)2N^wVLF)2Ft2AI~R9;Tc3_+ zEEXm%xYsCnV#)>sx&FqhUtE6Cj|IS9Uqg~5l;Q+euMI}6a)zhwS%6BSqf@y^za)gz zcYEY6{`;tNSS$hG7ZSwWL9qguTgUfZuIuJ+^#Ug?5T?H$Bed7u2SB3BAFG%|_YEO= zNf1hD+f<7m?RB+NoBzU#iWG7r&%c&4I;tmRv|$&r6aFb2iyQm)oF8^P^R3Zw>p;{w zVnTPXf8e|`5OzNPGLpvFT}e-7Wc&V3Fb9p>5-90BQNAr`+U2ur0&@Eu*Lm_qp!?*$ z%;4&x1{+fozoY8;OgDyUR*Ix}k(Z=fkwRr0KqHRVraq$x^I=P)N2sZmVZLQ1Eql@-ka8 z#zW*)q7IDPyZny)P}cC;`Y+a=`%*duLxb-H^Kq@)$%%Gc*h$pr04c4Vm%OSO?jS{Cwds_LbGj4nn z<54EZ>XL2K?O^g&t%Uh;prM6*W*DaaNE&R8eGb#e&9eBg-rJ)TD8uR;EPP2^cpz(B zIXQ+|q^NN9S9BEmGiTBxbraS43^*=Y|65h<?lL-nX`M#sv+rMDo{pD;idk$ABZ$^JlJkFRukJ!DLvl+3yYU1E|+-Uh8fQWHVq_}wv z{|AH*?D!;M?g#pnNj2Mo%kyQ;Dg+a(LLM4Y#3SORn_{BrTArViq0U~`P;PSVlbl~S zTSIc>evp**0VRRCx$o=iV=JP;60}q z9|7-!7#TI~pGrFB0Xu_l{4+NqdmPx-Jb02LJhy4DWPzoN@CdZUImprg3R4q|tWVinjRxk&$Cabiv2H3pr{U~YD9 zV5Y?rYFn4MvWTNOTIJ_M7vWVlsB=!OM|-1>kVe@0-53W{2|rthf(iGj3r@il;TzT2 z%#`O@4FJ1*k-3Q-F-Fic>KHtEpgfEDca7IO?^)er((j;yAHIiWREM+NRnNhb*7=;S zXVe=7n_M=!fw1w2;b5@O;Na1*TuFqmFW2B?k9`=%dxL%o#UwyQWY3r&D}2 z2kCgF*%lH%obmM?k8K<><+Ol@9zHufL6d&8UpLSx9hZE#Nh?5ePG^XEt3xUXgWZvK z`G;*#n3HcWoz|v7`fDC^1fHjKs_Ujpbs37pzpWh~=I7V!5+2ly$TR|jUWg7S04bjD z$8$aRF`k@l7PNm1W!I18U!6G|(PesPIy|W8Td}G;vqn?eCDCq%%{9M3b(R`UDWe4? z)^&+Y&Ty8PeiEo`Qj!zJVLE*MKJzq$<_-PxBp*2{T6D zIfcNHzr!%4b~?D@X}`B$GDM+%A?v>WPq!CpNUB68ZTIBG&7L8dJ>)PHaUtzyd_B!@ zcz!{je%(8C6w86psYC*Bmqmk;sH<{8`|SPfL+9MKE+H;komHhhc2QlS;LuTzT-%!A z4k?ttTuZK_LtuuRk9bI&+woE8Wbxtao|!)N!5a^}E-l|MQLq>76U;@7V)`FoDy90= zDQipBhB|SV(;Gj7$9IFKI%(y@KFgYYl{ZYX3SZrc&{Yg}2;^hTwtx?mGfwWb2+U)7U-Y-YQ zRWZdm6*NCj{vJI%u-Y9ScX(r)M{p+#5*lN!2GLm^$l;I^vAFa6P|RJ*Hp+xd(MP}w z6_AcJg%K_E#=%a+*}!|8gz;&Q8dy#zQZA|715ard!3D_(!O$?9#jMIEY^U=hqs^7< z1E(b5+WG)e1+lo4*Qq7vDLEY)lHc;lTNh2Ah2`bcakM3#5X!~!{n@mrU`Nhsq;_F-#P>}72$@Rw^jgUi2IOjY~el9)1Qeb%t!pM528v_6g}s$dZy#ph`gB%X zD7gb#a_SL(Pgc%CF8N^3(6NU!z|P0ER(5DdA?fnGaW^zCY!(XLjf1c4R|zm4uR>2R z8|cVwca=31sL7Tjb`^^J5$0;d$O6eBIrA+CP9Gjo7ki9K;+&;~mmbSe#uxkYJXPX! zZ~V)wX9yFVFoY&Q_Jp`_J$tLq*X{R^`%m|K=_FsqlA=4~Uac=zFq=sy z(LrRxr>F4~p(Mag7)}`Ct>m2*-gP93b89<{jxjFps}V((G<(ju3(wo`*ueA2knOl&+)8VCm?h*mHj%N*p-{ZSWb|={f;^AF&cGF&VZS0+AtcDx5s`>jJqRENj;%I zHU2LR3_i za8v8cfFV?~d~-AbG6jmKe!@v3cS2FZiUIX)lMNg5-ZNB$7JPNbYc+3GGptdv_~_4$ zRI+{;hC??uxKp!b>Bt7238$0TOhh131YLw+0z%{LKP{c8>Q`ljT;sX@Ddn393WDw! z7Jo|vUTq=L_xEx_e&t!+S^zD-#00n9{ryFyIwW471{m9!7S$WXm@!)Bbr<@m_B|=@ zcz#z^F0#CcD-JD?ToJtQ(wS+nIq97E&84F#>SL64WU^fFN)OM3*zakPU#=`r@Y+0X>Elk*N|#xhq&Vth;R@KMAS>J zp-lPEdKNh2I?*bz^48(#T*<-zE{oO;F+pzHxhcFq|Gj~75pufBqXQTgLM3FX$b_@k zsPFmijbq-@@61V;ib&SB3@)^PMoK7cU4rMX?w-5R4I#y2JHVmshi%b}(pfu#76Yrd z@T8=bMd9Ql7N<1Q+5ps=TYu=vc==_KWC_5WCI}8AmXC_+hLv%cgpwG@F0Rs=zsnvs z6@uq}qqxEgI`7vb?|wdqD;7^{+elJ_Q8Dej?W@M*VWWuT57E&!K(UxUD=s2rQ0>r3WB7 zEnr>3;eZD%%jsIfmM8~PS)I_X9)T2%e5V;r9d#}_p?x8doDnUk_amZmegc5#_ZPr` zt7#QCnilD?8XyTmnJh)Ee9A1axu0b>$vx-%7gz6srs}+c7w8r29=$joS))-EK73k0 zJ!x+ozV<6$1m?0nieY7lt5Z=|oVM89GLg*Q&ve-oE3Z}xJ|X{avahGrEvCO5jY}D# z&TE|htb|a!fD98;OTZl8>4;PE@td^mkfDL|5|Uj#I+QFPN}ODL{l66@|CP4^NLK3e z43#~fF9|KQzmX?-t!}xktg<#+1uq*R30$;oB`vBlYsp0>*z>LIg z&fX6!MO-UH^1;-G`=AUqluK66R8~r;9!*(CIp^bWkHvJ(>&d|noBj-y9$PXK*UAK^ z4bD5xf@TS&j!PU1Ur;GLWw@=nlKll~k2EkLiJqCk=hE4qojZrzrCM`%)xGj4IV#!z zrRTysRl?LCuThb|GdtWLwU0%o@sNw$BF%FeOTHcC$I)rs^B;0SbASG$zr7SqbOsQH zNxUH4)#~6fW>BPDIVpl&iV}Q7`^)F ztHYr@rmXq?+1=*im`k3HTry(2Eat#;WsJDo+$Xes`KQ#<{;j&eZOADepG2oS(hKU` zvRx3l3fe?nC3!bAAAx%bS#Uq<*4_aTY6cz@k=2UG2@-897CKhYXyBf-6$~P_V{J*Y zido$Z#yhrjPTTU7ESgp{TBb5X@?~*be@C6Uw8fprMB$&J2Iq*F+BLe0bx2_Nb)E}$ zM7I1num$v zs`#TeYlE>Lx+Q;CUj$M^{oO~dkkOc`!^6xLm%U2Uu&HG$hp*#=?s^*SPl|Lz+}uN` zn;$VfD832T16&YL9H<_$ zWgh-?-+crjvo$UKnLO+kp}1HVu;Ab-%-n)pI^G~*<)-PDPahy9g-Q#loZo3nor#Jt zRmN`>2X*(Oz*?l_K?~RrZ+#^>e&D?`kdOuGd>$AKR?Q9QEX>=vRpa-ja!F+_qnpo{ zb7+;+1LR7*$Tg{lu!s6BEO*DpRkN13Nr(@L6eyI~Fk`A9;B~20y6MIf88AA{dMlOv zQr^ItM$y&scb+X@WEj>K*?mmj;KWT5y4B+$Ay~lvL z`_#QhC57JskXH3VZ+H<>xn&9nx&Fo}=yJ=#r^*>x!Wr0iD~vvC%qh*g(0-=KQEdy% z4kIOkS^*t81%Z{@Hou!jO!xl<`BOty_|w8>oS`G+zfM8(KFs8=0;{D<>t+i;hp59t zfLGN>TCpH*5&HYf1LRz`q^1qPKuEK@ z-_&MjoM596c;AjT%^*L_HAZ`T$w*9j!a@FU%QVbX0C-^6w0C)){Y^^vDEB*N2L>J6 zRan{00`owp*cXEzT+3V9dF1%Ox!-nz`~X}?r{sK@P_r$}J%FyWMri0b3f1trs5Tkl z3G$hYPVPT^V4>Ob9&jqY@V}tDQYR~r^p1|wUIjIr-g+&0wB(<|66!DVba5H9iFRkd zV0%7l$QovVO@AB9HO*}V7~*S*yv-#eBBVHcZCVJq-`OXrjL}!)b?Q-It$60XCD)d& zJUN^zn)75|?ks;N%YjZB%gD@0fly|t;qyVz?S|d9aM)ZM{}$i8eZujZ((mPt?x6m~3Na+Iy1xm=$Tt${Y*Ul5%YBeN=!ISy8Xjy@YEW>)D4;-$9#Y0JmXp2)p`GJcXW2J}>=oC(N#*nc)KfX>H+vKcQ0Z{;dtb){sWuCvYfZ)10^T!N*Vw76sWZaB*nR8xM|7i_He z8SeIsyt4jx=I;G?7MYp2Y-DU$SJQpyXsSdsh;tydy3a6rqLR=NGrrSw%IDq-`bVl~ zsZyv+r$t}{&tmmyg6<-(>cnyXP_6==2RXiFHzWruxeQQG+F6JeD6SnXY%x2 zuia&8Fs1qPH*+517nG@_wR5}JrpuTcLgc=jHSSYBXHB**4Q+jhsy7_eM~&$)OwrGg z-YAhL?LrW(iI#%YuEJnt=S`st;=%j8vCMB%po@RhCc447k39kS>w5mn9Os0n`uk~y z*x1|kyX?r?Px*O~G*1PoOdu9*q?>oDRT@F*0M6K|!+S>a#{*F$nYPjHv(O^qkf<&m zLnYvas*|R7C}ve9$;4{laiN+S&HH#>1>Su2X6U$OT`er9OXCo>ZZboTf!w;IgHdy_ zS~YDiS?iPvCBuZu^TmQ*<^#(}w+-Dpi)(jXc9UzD;w1I@ko&3E)v(q!dxA*;w5|GA z4rn3)GuIKQVYIzABa>i2fXLHMz(>}GL%P(8{WBT$jEqiy` zu7#t_^M9{ez$$fVK5-B+s`@(wRh?fO(zkP_qhQ3)#3R_XV;VZIJa@DcaIbBg?kuisx<=U{ z*Px3H(8^|h7Hu{?Gf7F(TGG4=GQSf@ZTcgyf2QD^S5%0MA- zb^e#W;QkZ#Fjr;s{P!=L^#wBbQxTTArrHs|^-Bbt>rObU4q6>zoVQLgYQYCwJ`#AGzC_{$`xkR1Dh5mPY)o7;|m5_G&IG_wpjljA>59M_wf| zm%aQ?|J7YK=XUWose&JAbCoBsIXcH4f;_skeKNN!IoCQKGFUT2-$hV;^gom>YV^UV zN!BUH#ze^aNH;?H`Z!a_(igja!L|ji*EE;Pb45Qzy0cKTp z)=-37PAWN6fzwc1VtQpC_TJuTWjF!9OLtao#4*Bw8J~Cu`u0*<$&(!QpGf8?iG$iw zjyC7?j+Kha_x%-^!WFz$8x(4u2=u3+>%>xM-m)*6{`m3@*)DY0#1P}`;m8YC%)4cU zg|36@pGL+E&zL}zi~y6k?P#@i?7gC(D&h!FbV16C13vpgubj9z9zv<{3JW)FSA1R} zA!+k&$N9p3#xfR1$AN^K+GgC=Qjc%QRJQ*O8iP#NNr*6-Bq1OE`c^FZGW%;`CcMU( z?7nHOL0s@WGjfBD&vQR1K2xS$`9+)o={ixj{~M%3^i_GtV6J(_M;Jn2mgJ0 z=(_nD^oJ|czKPOfdh!=(O3{|Dr*3CFAFVsnG`V#blHz##_+VPWWcJI~k@nt*PmMiM z^8*ygmqS`Tk+(7LKQt*b;q_k+vOXOu=mE-$?^$=-NqjMBu0E{ahtue`oz&+KeffmJ(^0 z`p&GrLnfArd3g{t#au`9=eBQODzbwq_w_w)?A|fRSCeabWYjlwvir1O`**DJA*QeN-S4i43vT)P|2ddqsM%f=?XJww|G zKT=xKUKrUs2C_d0D$C34ZJhS=?;rC<-ofF|IU)yU1@TJjN_;xRXl}E4ir0Mam}w*F zT*TuD3;vcm1=bbxi>ZCozu_nL`NI~mK`Y4fYzry2Po?ZaKFx`XE)4nZFmO7(@&E6e zys0{o^Jlb>^MhveIha5>OB)j(>K?OL)46kOk2Un#Vx=5%E7Ug_th>N%D`~&Y^z`%0 z?u|l1vYN12V;rq4!0?lb5a6moBNTWxLJJ#7I)+tj&V{rbA$=Jvmh}-}?^PpM(n~qd z$FFWCiDdJK^$u-B;HnX=jT&dOMkb$f#?n1C=w5~{t6&HLue>4>-L%a|)AtBsRf@o* zm70YQ&&?Fb-7mqNpF&im+^e@0`X{(hP93FO4mveXgI_AEw)_2EOq~0W8Yzg5Ni3; zqQyoyaF_N+C!#mR+kPuV&z`8Uu1k+4TfTfyT&jdSN}pdv9M%jBq(snqe5BG`^SzTn z>OBfDzXv&*tbSL!?*x2Jj%=~RnZ6q=xWaJq8M4dwb-jDdW@Epwg|=Z~%FRl^d$LhoP4bcwR3IJJi>i8eQdQzXPGjbBHJnwZ@Z(b z4&2=jnw2_;167GoOs-`u+|;cw?w)CLNpD7w_d*0Q@y%U5PZiO8 zAp(`kYZ6E`5N$ChhfeGk)S5hxk7^lsTp2#V(r9`=Z0}l*A1?%zM<=M zfVP=^I$ofy=~AdICXLwT1{B1Y(*A4;)Yk%z!yaixo>*G)JPYS?O#-)v0gN4|OhQ<1 zL$E6D0he0@xLou8TUY64PmRt%0oM4_t-1tHZw!n;-f~YYN6*b$d=nMJZtGu_D$G-? z2_1|)Rljie>CrHKy~e=m+%8`uieb~f+N#8|RXMn66?=k}JLKd6yQ_$t0pM2#D}QbyJYM;? zIHZ&+U_-p6<<%dw`rJNGFZONoUBGhL!jIhQcY|szb?eCnTKW{sK969r2xK}y{l#f9-z(e`rWTWXYLb3gB2 z+0(q+=9(n2oac)JC+gPUf>7!33YZRVt0iEt$Cp!g_eV^{qw)qNHfe6{kRiKUk<$ZtA`%ZbfPdq$D-yc>C2J?Ynl#Kb>5ETku z_oQT18YxJ#txqW5N~BYQMcF9*u9q9Hr^--b1}6kUh!0b?FakOvp^Tck0my1+XqcS( zX4=VM<>6G~;B_zW^yfx&@I>&+wS|DfNNJvVff|ppycWt|B=;-y2Tj`eTCGtDd3Te6 zCnflsIiHCum5Hi;(dQBOf_tLC-~a8%I*?}+PSh8?AbxJ0`(fU1`jQ5n&^Obn8`i49 zKLBqmobLu{FG_w3cW*8#_F}T7tvO_WXKC2=Imd3K@aS47QSjtO*hVP>nX)xKS4ZiL zprsV`?}8h|O(`Bb?K`np`RIU#)}*!;Zc}Mo=Fz(ym8?=>=s<+E7>Pw z4-s*9G04ZAQ?%#)IGmh#Q=P&pppnJQvsJe0GbMN6o^5b2^*Lo%zC5$>b0de$0n^k5 zCZGAW1F>H>y9m6P0`(5Rl=gxreY5fa{rsd*!u>lh$68;egDa8rSJOk>K}%lsgiVT_ zyPr|Ok!4qVp3Ws^d^s1nfmyilm3G6(aQrv--*)LO?v_6W9P)L_BAQbj6DHxlW70-# zcg6yDFE%`2*m%VhZNY40aJ+3+^Mm)I5^WOxt#!SFM+m)ake_+7Z@P2*Zs%mzeQVN6 z`%GQ#$aeK+8@5&Z&V1wibp5VfUR61{SqF;Ojirmtkhz)M)yoWxK9P9nQX=BwGuLKe zKfCfup~~4v)u|NHwMtQq!FVx=D4gB9N#Ei@P@(bQr&^5(vGQSI^rh?=UZEfV4xZS9 zBZJpXzEbrwu^oN;!q!uT=Zy-?-QO9d#FXj=M=LyX@V^oH4J6XS-o-yEg;fjz{T17n z$YoQ%@RPNkl_GSV@xe3;o7+7KBg)Bz_0%%!+UHG!n z2tAs@qLatblI3-{)#f3Yw(v?7^eMkz?J&p%iBFqr|hHurW7X z%Nsiu0gkRlPm2R6{gXe9A|?n4I%@xmU*^!o$q!uj^6e~%0&$n&t)WVPKRloEL*qXr zx>bw>ErSK8@m$VBO?FWNSEQXHcHEn zN4sI_W@#Z$8};Gw12@}Ix89$XNy9SmgL`6U)U~grOQh9nJ;qcVFw+HwJvfZ%+i_3yGu+Wyh^{YW-qdRj2iEtUVjCe2}!=d zvT~kb%-IN!#HpivNv^-gq)Tq3f8KqfSu$R%*31ZU?K%riJd538IQ%oa8)R{`ci92B z+kXO|A#h2ddUc;F)m@GV@7?((rR@QA&fm|;d+xG4(*Cb2&q5*Oo8v0yH*bY(-~XPR zKB430boJ(NHJKV$f~eT%7Bf1p*PtGXL%{CwoIsLja@~l_NP`x>*F#fd0b%eWF!BxJ zcxH7wvDzjgMt~<%U+ET;qWd2+`o|*#t>Pc{#IObpOJcCYN zrrXG5rv_XlOyo^S=h0qB?@mpE++0Pfpxla7Cactr*y@4utYD&M0H>Er)57GHeqQ+0 ztL+jmr@?2lWitthn9E%LB&U2TC!@hv=^|a1N-v*pkBR-&Ax3Q`!rbyY1gShA^!?%5 z+@DpLxp=UFb736*wiyN-6WgU{qaU8s=32D5F>FWN=P+fEDam9Z{Nv0n7%YIAx5UKr z{AKjlb7Df(=(#_3w$)y1pXN5vt`4PSt+DmHT;eukH3d#(-)`7_9;yFG)Yc59ekUY* z>}q`JBjCBGEGkbVed?-jPUybwhF&#AHtY4ztW8T zM2<0fOuRBrRiv{u)cU%?r~$fL-FRu#D2|lRhzwqq7r*he8c{e#iyD9j*=mTYLuFyUu6sSL_*h z{-*Fuu`XdiT8PTe(^?ZVuUJF8@flHp%rzRtr^&vS8?V<4uOY1c^!+9#5OZ2;wEq|j z$o*h2WnuBEf7GwfG(d#wWiSU4zP!$kg)gW1H8ULSKfj&J_U{mun0|iCz5O58h5RVN zMEy&V{!;8o>`$y4VJx4Rx(o~i#Zw=YR79)kuRVQ1m{y}rUX3?5S`c}oJSFLy4qFH4 zSSx+F8Iw}-gpVwkfUNAdNwGlURj@qF2X!YCZb1vu$nY}%B!7QQxdM-lcI@w~HY}aY6t@7=EPh{xkcT15K`&@uyOc`$W`h0sd^Gb> zMkr~tv%gEO=KQJiLSjJfU8=fF!!mgL6};chhe+QsDo4He)tA%%r4G{CH*{8r2mGR>%qS86zbFK?-Rs z>8(OfK6UuN5%{^5VmOVD$02{W`O5rtbvfWJNXulQtn4oO(JQpJR#YNEwxfDQYR9TJ zGt}evouEX`;ER81CU~wR8r`1V1kQBg8N*lEa=Qeq-G8cS<(?DUuk>Ck@uoW7raIsQ z@sM@spx8(Jx&3l&J!YK~?2EHe?+3Ui@)5nwZ1=$>xws2!7*OSf5Uid0Mvj;uzzEpO zvcI;r-$s;>vsAAoFijnz$c$(75t-}+a{Qdi=JO_-wKp&}L;1=-{9iM!hJ)Va$8awG zauqXB@MZ4Mbx-Q(i+1M16h)8RP$popqE-4WaZ}8JE{(OaA${c5+rctVOvH9MWY+c+ zs;lO8bULGphFo`|rN=xeH)sIeZmZDhQAQpX)yt+3T>$_0yU0TQ5CUg{jb0%p{|%S+ zM%P$mhdCMro>p0c9{wlze&|tti-1tbhf#1X>V^Os_y`wpY_jUsP&E3>oDmbR13mg9% zUpoLiG=RG=D!p{MJh#{vBtq4>=wq8n&uLlnG$c;+EDFtpiXXs5%Nn9B+?E93NmkQB z)ymA3;w3xx97i+cGch79Sf%y9cZ44@@pzS-ge}Pbd-=d$Kz?o@|-lMtGiIqIW5?zO#>e-~VOa>WNoD8s7xf>+AeKbca$08I> z6+XJvlXKsX%^wOSf=2U)5omENhq|&Tv)6P@(UdH|$ac~wdj))0>8zxr75;azYb9HQ zC0EV1a4(S`7o)cSkrl01vKF5gW5-BkqSY!`J5pD_jH(~(e+%}H^G;|jWFs=YZgBD| zdy+O^W7_5v;Lf!BbX>K(WHp-hK9bp2`ZFKUGrhVmtrv z*nM3?fx)n=U`)wTJ$>UF){*vgj#&rFZVDFxO#J}#TWJv_$mglqO0fdTzZb8ox9)!? zfP|>_1Bk|NYWR5(FxbthM1lHW=>Fr@5Wv8w_Fn&Rft6-2tDHZ$$4PlD3I4VF3PIsT zlX2$S-a<*rIso4L=@Vbc)k+6L2NVSKNQ5qO5*Xy0fR2Yo^j?k8cjvqMe%b~-qMrjV z%PwAg%JQKz`L?y>5B2JJIi~GpLSlf&J%t5}hW{Lo+%6TC51#w1o~CHhe)n40u~^f( zutQM~<>O8OCH=^rcx4F6d-~4;b`)|>;I!}}!7Kb1Md+{n&&}Oh#e<6uS{bG%BXW?z zWY3{T4Vxb41rKbQWIDH-dRj|avsZr@e~~&LcTin({Pc?oWF(9^&nhk@f-vE!lXE5l zl89wqdy+?8-is+2M)mKAsK3$~&<@XS`a60(JPS;HGV7hy(9ClJ=GX_cndob|vNROW zDr({tFLDJ;)#$?N&ZfA9q}Y?Q`~>Gxs*c=pW}+-C&-I)y>sXkGaZL=k#94D^j4#pR z)mKKZ^Y7{__u5B2pYTTw-aS{6)>E)pz{O+v{#AWs#bJy82&ggmg&^TlMgL}NSjT(- zB4=#A961!y3t0~nJ?ezn1%{O*9qb8?jtQ=+OxU$G=8r6e+diLpJ`zUpMv@8@^yY7o zNND^sy^?kG@i2U0bN-ixT8c$;jgREZdZx8m0U6wb$$sbF^>oor+t|B7{nhvG0V8!@ z*Kb#wl$R=p7e?51b@>oWv?m!sSp6zZ0>@fV;*w_iVR>S!zeum?x&KK6Gs6oXDA$zH zT=9Br3F4ickL;q%&}Qa(sVzZLsDgv*-+9LaHinJo?#l_EXOD zaxhW8MU*Q4lmg`(k>K#th|=#i`r?2pW4yfBqAZ7j4{PpN&=UTIhFjI%O^byf@0cWTDm^Ib41SX!HB{wMfN>61A@zeiyQS zO;{d31;AOzMWWL*+7SjB!I5{3;|qla@LW9zpnpN0V*^fw7nL?A`1;N3JLs2p)fr6k zV$YX58dv^tp>^fOQuO=2@~(3w{PA}xxy`Fv|K-w<%h!lxJ?d0Yi!;>u1vwgAy9Zqh zddm}nr}JpNxf6a2!dL3utls=SiHD%~8+(?j)s|bXyCxf93fQZjHxt|^)|1Z;-wmLI zG*?U9WPu;2f4jMWIBP;*+HxY0oL^h1vtM2o-nUx6KU#Y@>NgmhKlX3U#<0fZih} zSPknX)D=+peyBZg^TE!G2uTUD(iKUKyLhWJY?RW8WO;Zh-p^nvaALz}Wz(U}IqvGr z*(uLI+kkDWiXVeF7$~e z^6(Y+>QhOWV7)>^OvmB`wlqNr`FB*oBUGY7CwcGN@fPe}95kE-`dRZEA?pBB>bm#&1vb!=$h`6J}wSb5>`>Q~yv zW`!tD7xq{v-B)({FXkY@VuJQZs`|C&-@V;IK@Fl-p2X+iNv^vBIJS{kTgh`4Epyj< zq{}!yxBPC`Y?Wy|Xv0^E&lY&vS%@_GY`bQ9iP3<4EBODP1xOC^)}g-X-tn1X|0;n_ z-jTz;#X=|5Ol2kQTJL~mIiBKw+&#fw(F1;)-;d$jUMmUpJ-8rN)IId(p4)n^>8H_q zD@8d!PziPJrD=Q|K7l4|yiyF@e;EZVqx3I50zBXO#<_Lwm-6=~eRXy$zb2j}G8(Bj zzc+4^%>EFhVpMr_L@F2n-4cpx|A+dw@bsM5EB=p%N*ar^FGtGQ7TsP%5R@L!hczAL zT(T*G<1C5$LBVw?qeQtBvi;s$VYSSz5Z@q?_BV+~iRui4j=6dpb(t*FV;_E-_V5_Y zuLP|;tn;~1>ovOT{JwkPp;`;3zHA+De5RujiQL`}nzn^6zO5pcmo8xkv|EL=OY;rI z@>#@lW^FelD8sF5=s{v8(g@+)V^VQ(#9Y~3o7&w7LS z9U@-NquCgg8{@;E3s_ojZu8vd5#Egg`>5k1cuC|pI zFaO*v(TaNZTGMMmMb~R24q5IlnH@Bd&-?j&&vH^6w_W(3LghO5^>%S)7E{@Y92ZG9I5G6zzqhoA@iV6aX3P>ta(gLHqL`nq&q(wxfrF(QUQW^#$ zMvi6-HlBTdc>aU?zF*gU&biL{oX?w_sB&dg`3ckSUB!a_{`fWLKeY8TT|uCQRL|9) z2Jt?fL+PZRpL1nHbS5poIZ&h`sb!2(;$KUz~2f_CKGHxBH z_o2f6GVMvWPq_WFV@O*T%!+JhGfcjA{n_-2l7Qe5BKn{oy!hl9zyM_< z*aymywtRCtnDL97p`sjV|C{#gzce=c9mJ5J?9%twf0cd4KfFPO|Im|w+DZk8K6$EB z6lL`6L;2vuG$BZ+1`l0bpBbvT_$d&Z{Z^{4idAni$^~~EbYqr;4<4N6!kFnTa>D^q zx|Y+FwcEK@D~KrkZ?h6+pp3645+`5PVL$7?)#+d~sduK~5LaRGEj~DN-$kauf2(82 zQPLNaE{`MCm(H7JYkh0|*Z3wCQf9mp)?SBV((Z5M;cOb|zQbl`t<&_gK<};2B>Fkn z&#W|iQ^C2wX+?L@ui#O`Ot|-vg8zrvQpAphF*O0e(!KIhN|Kj>engOB=^>Ax6lkMb z0Am(wGz~hll$^AB#L3CG0hvlN$=+^ZtqAPVM6sby54i3L7pYnLnn^{h%?0P@}tMX#swBFS~I8&|k@cpBZC zu)>hTpW$@$>gE(PaU&uq4#f9{1LkLeXep~ohhaN5!cjv~f~}r_IV$t6N#Fc==Gfv7 zCH6uB^x#{w5{?(9C)+x zNKThRk3mjSxeRE#YQoIf#o%2zeKDHf@JSOd*MjHgd#n-@*$8=Vm4`la*4B&d!J3Pc5Bq=TXYc7geOYr+g7+ttyn_&o&t!%w z*lo7JK=abe?i`IU_j|TY#DWXq!jAIFo%qK=2d=^ft2x%S?z@;-Lf4X? zpquC0wdX!-k*(iktYs|J7xt^2lsr%|n81faG_VX6>T1%E>t0XVK)z*{o&tyjGTAh} zK77kJk|`1x^>kKl_%qky9~Wqn9v$;y+ww|~V=(Vg(|5zn=kS`F1__d|4$m9;Dsim% zbtEtHTW`VoRymx^P?x4wpda=<<8BFwAAO5n_PrOD{X(gYuFqEb#&dg#GwGc#s`UmAN13z+5dP|7~wyxyK)fKR0rwZ2ZD z6X5y6T#2jlE?<~1E9?A02X;rJKFoO1!LVTXe#zPA&qF{^{4C{o*`)s&c`x@O;c}lj zQr%OVx*$|W%E^z9wX|{^VoJrEv9i7tQ)z+O!+J7@10JZ4{`>eK0BthS(X?QD6qYV+ z4>jIb{3z&bn5r}Ck7kd%rIV*>Z@sDaV9)#SUQ}JIlD-jhVWdi5@tvhIkN&UTn@dIg zkZOhO?`gK~pQR3*Uctx>;SF6DpEZ^tDmleUThD-Hj&-N|XPG58ogxryMJ+y7QuR`b z{3p>1IobkIwgIBUoIW01`pLHju?_C}0D#t!MKfWJPu;D|@s1jgdUn;d>Zh;5Jc8lf z+Y~mT@kn}`%Mmz1tKn7FxE1o++qlfVcT=B6Zrgnu{b z${j8CkQv&6Fu@OZs06@wn~v;ntVOUh{u|m2c6;*LmL8xK*#jCVJ-X3gW_%DOUPM5~ zbDrfp_8D%-72CgczV#K>nTWb5>K{CghaH7`20nc2oCz7QZ67TlY$js3SE|J@-_7D?qpOT2`mKk5U3Z8ocs`KPAuY za$@I)Bh#q^lZSLD0K7n`C!2CekBIq{bHK0C{;BQJeK$5$%j zocLeyhG_$mY%~&e0kem}=z(@{>qeh6M%a_XOIH%o zbF-Y+>PHYi9rJ^v_Ceh0J9M$QSKaa znFZWm6~Z)j&yYGA_zLRs{PBNQzDJiVD_UNip7b>2stapCAaqk$IsQ>Rh!5}Q(J+ywqy)xbfy2865H=IJj`h=iL6lv)SQ6cbVk#%ii$3Rj9 z*nf#xKk)9=Gwu>~6hcMg_AgOhCp2Z28x1pDgEzOJB>uaT&+&8Jy6B%Yjb~zppLFQJ z{NW5R7=xAtjhR*U1bh`6;EXZ}+;P}?`Hd+}vscA*Q_Uw~uKBIvSNTF+pgro3s~)={ zbCC18wYiI~ui}%Ll3`u7z!J<3-S@Dksp5I8!OrpOV1j!hA*rqz08Adi9>dyy8YWsW z^TPtDIienTF>g~6o60Pv%`-5)0zE(^GQ15;S_V6_$XYWSOASM2lDLvC>UGYiH>2qN zeKaT?O6|X_LFUHK9h~ev{GLQsCkK|4k6tI+ZB({aOr)cp<_{6k(^qJ0C0U+mh0GiXoEsiVd||w#6J$J&a6( zZ4P4vbYQ*{$>wR*WDOi4jTYkVm+NuzRp2?P7D2&>4;=Ul{XOp0VhgBp#b zjNAf$24;%NwpLKswTASU?J#o7_;YmhBpH#&Kq$I z^Ne{KY(qW}SeIe%D+mX?XDCZa6u2Nuq~nK-eeDYl8R2!=(Bu)A)&t}VF0Ne zUE*BsEwvFhOrNJD-Le!OsrV`sB9+i!&QC~_T}2#jn`UAg??+KqPZ|HdsnmA zdEManq3hY^cImaHL~b6;OJI$!qHorF316`0vDP~Gm^QL3LYc*B!;EsU+KLDN8Gfbk zIM;mk9MT24<3H&YFe&Busjq3|rjsBGT~SF`a!EVdjVWBTTZYpX`0km!XoI+@(Im0@ zLU=o$88&?K4b=SNa+`j9(JbxxX{0I@ZySdW$`p3*Q5$x5!16-|p-xlV5_llJZni}1 z&SA~-mFn>&i^*thXYwEDDTSf#8``1l^!K)bm0V$3qMq*2pJX-pRau63uZrlQLi(RK zL>e1?j|xjM;s-{l2X+6xNjEsQxSOhVT5v-C#^mCl=bs~yTo}OR$;;SqDD_j^U1jPl z&Uar7ZT4Q;Qi<<{2fwCPiBRI8-=(+QkF;9B=DdFP@&Pk^G$Xo97@r3P>`Hb2!!hr94&Tw=Z2;i#L~BO%1@hZXFB9(##59EhkYq? z+=kzD?_=uvxStdS^|0js>U};W{ZbF}{eQDs!e$nR^v6jVAwe@~$$nRgD&Ol`(xjdo zKqYf;Pp<2<-DrFSh8m4H?Q|WAG)vbUfXXygQBJM=;?PQG9NSGPl6==T)MD@uXTRI8^C8#o_lnMjFa>Pm#Z12Fa)6d|+@+|O-+(}V>OfVqTIs;!R8fjBcLvL0;UD?s$`2fGT79@Or5KHN zkg2h`L63YbWh&dymPnIuyL!eVWgIq^}S>xRx{28cHsD2OgKk8VvtaS#t)2Op}dpGusT{UZxChhE5^L@odyalJjeHhyn)>bcc&%dRQ>G0q>krq7QqhYOiopNlIo|XSwO@ z#l-KGM}i?~Em(>zH!eZAm*1NnOa87$O2O?yvCa1N51UJ9h#^!mjw2-9(8~LR0g;QIO49ZVK^Atrae$i3WVXjo&`&0mf_X+uZ0?=QG*~MR~Xe5Wj#36vj8vkegWS;(6?u5G~Br_phU+4 zolzOO8DQ@sAZ;2B6V}s`*%+-RiO?u&E7E$gGrW}?l*s%hlZ%byQ`b8+;~&-oGrCdi zZS$Jl7^XfODYo{E>~~wK8-cjiu6GL6I;~gid!!AuQeUs$Q1LmTK+`kx@~eLR2LuKt zw?-57yKb+%ERX8jC-PQMBggM^nmv#Fw=XrL&XwBQ!=q0-+WU(wsU0G1-FR2e?*;JK zKLu6QloP*1t&3z#xb8|PC0da<>x;nA3|M8^16=SAXTon*0*1H*QV_xC$F!3Bq)DF!BHDts?7Y;-UR0Y7e%tP{78PCWxPU@BY{J4!3+se zq8Qkrw$}HrZ>1cNSpzQQ*jzKGQ_XU|qFC?BFi}wCSb9N?Q~ley9551Ubx!B)>N8vM z(0!M_HZmIk?a0l4^2vsMEsqWVIPFoeLR0`&WMDqLV_wP5_6N(@#uu0R{bqLi)!+E= zN0zn>S{to%QqGa9{qVJv-Ql>AgpM47^}+^NlM|Ku+M^PGJ#C&En#*+5>Qj4FHHxDr z>^?80Eym(UNngn8I13%z#@Sv{;7SO!d%%0fHvw(Y^Oo%F?K9GiiXkfrT=Bh>*q!e& zlD9dQJ$-p8+B+`12bp!vEiaB8v23aDt@P3*9*>kUyY!)eJXM_oQQ|K-Z2_CDqk zI{A@2+=hgTt%Q5g*pJFRJR5#8dXw2{HOK!aZ~S@t{^QyDyo;9WKyLOj zKlY_d_rRT+9K#bi-RYAj8`qn5by-M7;{U0r7b?>zY$?YiZ1^QYO~ znlH?=;y3Gp&i6)!kDnWErkbd=MyVub{rz0&-zTx({-ece@A>lEPr-HKMPo1hS^d*4 zA@~kSu8l|qYMh3x^y2S1N$yPCiY-78$YK&ec;JGie-(0)h9|9C@+lmCB z8iQ95-&2OMsvu&1&_)F?XEi@jn~`55Rmkou68z$B;>G9^Ip~xBkIJu3e#QGShb4p8 zBg#?l8Z963+$>>08`MQC@7w{1&9H%%hK{E+!q{y7j?w|c_&y+4Y(?2}6ZSNMs_oMB zQz$UWVPoeFDqUf$7enq;2f3U#geRm_IigXIYs(RqE`cV#o2MsVg6o<(GlqqHzbMo3 zI;3-kIRD@fclj{7V-Ec0ev?p!{c4sE7tL*moo&;c+?}C)ci#cQun}WEN*pbS@-W%+ zxUGdo*}V62*{i1(gYmE>ZAk#bi{DeklCE2F?ggAPUta&<$4EYB+qqBE*{xhbwuYo)%p)395i7zd#(?9V$@b=<1K$MB_;%K#_`d8U%KkWPkPi+ZGM;mhsuUo zQHh85(qaM(L~2y@J8VS;OhOz$882EFF8*vjKal^5M98yx)+?Y!(hqlcv0*QQ3Z5RQ zm*)%2KVi<6`BVxS)$7u^{Bc(Y@wabgDD)QGiQUkpaCWE?JqNy=M$(yH_m{LaH=Byo z^-gPG8=3C}GUtY5Z|S11!@!<3+`u-XWfBmszbE#D6`j^oTob%X#T^O9p}qIs$6ouE;-55 zidC)Gf^)4m0tXnv=|m~e4IFCj*xiN64^htE$f$lZ0&e%8CjY^wK`q$9XK?}keYWA0 z<_eSQonmUs3jkI37RBw?v5%NWjl=KP0a_e4@)qf$*_3_55dc z9KhqQOBoH-4gzF&)Z8>@o>9*ZOKj>|!lMNFI}Hc5uG-?*U_G%r4|@&HdbWgBjkj2%OxZJD7P_5vC6XKG2yvOrM} zm!E=gy2J%@cC5e7<(gQT*!lycm1E>|rvE1imy(_7B0@d)2=5S0(_+D=KSFWN&!K%OyA2z74o3p$N`4 za^d}-jIgFM+eQbs<(Z@}t- zCG$(3AqqCJU-}{#(aI5lgp6oci^aF!KKvW3hEY{fd2dg)4*Ii02Ynolvsi<17H^N= zO2q~Z(R}s)o_XX|6POgyC9cSD^V69G?_($Jm32$+5n*L2?Dusl-(JP~PcM9ul#i0y zlLYw2w9f4_l$oLvJ`C&Co7sN)vlA~%^o{R)t>E3QvRLOcmc9s$LLV8bI4Q=N!COsc z^|8)rupg0{Ti!wOlaxj0qM{)z^LB!C$Pe8-52UP8wPUJ2&9UG!7tb;Wc^2_qgN7@A z(e`>ieZ0V#D|UsMy;L+hcFM~yY~OQ1HD$#a><;_f#Xo_-yun&(ny!At>wqy$b#E*% zZrFMpn|GHkuBL7WmlUxpuBdc#IL!$4VqITH^pDD#H@~2^G46QwAVKCsbFBKGnC6=@ z%8G!%{^d6v2AmlulUqc|=SLQV1)ratyQiKm-tB8nE`GD1=J%Eplboh%D3f*ekloQs zbY*&1SWqJzutXtM3FJkx{D*6{I4UDEsW0Q!{pfOeQbAJk@vp-hy_^2EVEAxTjl>=D z0>)WN(AnAsCmEB73)q!Op_^R&jfCJMy4W-%URS>fPpW*xh0)8>D#f6WkKqYquQ7gs zUCx-j1cH~S>(+gi60I2YDo zr)LEElMF^dMQR#)`kHukUP?#vlk^s)Q|;_5>UJ&ihM5dQ^MyeOyP&B~j>8wn)AfIg z8txf1-E575v6I;;fulHHf_0k`OCO|<9i}7Y+jJATD6Z&p%ay6nsC@HLqu<*XKZV!a zcNy=yfQX=6pMt89FehE{LMI4lI39o8A!bL-}7OG zuKy_*rKL;a|Iqe-Edc9qrC@Gyprqd-SyVh~*g}{9_iK3h{0Z1w-lVBsQDZ)5zJG_; zspmIona$XLLw2s3qR@<@opTL{WIrFPtl(&bY#d=4!`%9~ctPz;6iq@$tr`AL^Q`sh!7X0=6qWu-E0O%=_*hLDOpQN6Pv+}xbX=?v~0 z2Y$?|NTCxu)Dz&%?UqthU)0+srFVMkrwMQ9JaQY9a+K3K%%wtvf)k2O8W)aty>W6p|3HFt~U;Qb(k)y$R0-(|ndO%x3DNxF!7pOOuO=WtgNrslSC zS?4o8Q!6zz7Tug>YaFX^N_ZA0)F6Rowxjy?Naof0J&%X3-rlFf`^z&XftRP<_znK~ z2)$Cp&@LgF9NqI<%}S@l#e@HNAGaVRFPc{QmIv9%b}s`|>?2*a!16bN=(34Rc`phj zYI;@^Bc+i0{RrKhhL9@ZJw$?~7Lv=AW*tTtNeJxwk3G5m--jRxx#{DdIG3i@Fti-EH_LK7zfE!M{ zzZ+lxzta9(bj&3-frQn3U02xT)I5AGdtV081qPYN!FzXH9WEH-tpR0bB2}=!R3CaS z$X&;|yG*PiQ$zH04l(YlehY_LD3M0-1Wnj&KqLxf)utCmv2L%?X6lmuV~d{NoYbyl zcZQCFRr**0nRn>dkWxU*j3dUW#n640W?Y|nnBUGzb+#5^wDekP# zJIiKP7w&^oz5ievt-Y-LBiUy64xo#m3q;$x#RobqpT0;|S+(V-%xC$rn8Y>9S9Dd3 zElvpUbGavS4T04?i54{u0oI|_l?SadBK{!vzK@IEF_n8|m91MPxJsT^h5Ngku@1_Q zVo!VJwhGI`K$H01{uk!cW5;6%tj+ z(;0U~Z(8GU4jartOjs4jvp6SAy1+6-jVb44N?!&6LraQt4?Ie)Wi}oBm+lJ5M?C0K z;c)I!G^~4Xqh%t{>BynIbjQ-cNSpaOrL#=;A&)9?)V|n@LfK-6s*maJJCNT)^E*Xe zG?J{o(Zgn~KI_>*BiBEA+q|oRM#iQE* zs&*nhnPEO6!OsdZWhhf9-E$Iq%L#Ap+*_j*Y>3=)XK*!;lql&Vhm48ARd!3n)m9#B z9hLItkxXfOK|P@qm{zaB+~LQk!}&wZv6LcUv-@61njnWS4;S8-Ja{?=1g?TDdgC>` z*efSqnG&oX=GWaeWbI02@3*hnin-XI*l#tSN$TFPeIbzKBl7-fNIPG68p%Uz#$7H*@nqF~;y{qib^@-rd*xRm!O0CQ_vF*ZU zZeG3~Y77Lk;=G?5Drs`=8S;Nd+8Pqq4)63^|5suJZQXV8=`Z{)T7sLL^^ZiMCrtth z16Z=i0tj2em&I1!V?*ydDrBuRh4SSMT?$5?nDopt1dXcb)E52j=agH!iSD5;1BW!I z!I0jwBn=}AU}e!zZuxr`GgXnOh=hI_+N%f=QMw>a=!q%a6ban7-3w=2k^1EBs_3m* zvR^WYz#aM+w(eR6F9X08s=0j*mR3cZR0nzbNw=-{KB_nYB;Z>IZ+CeAMOJmqD_wQs zY^?M6G=UK33=uaWyeznEw`2V`s_WaDJYF6DhVZIy7?P!2{kDeK;kx%10}04gs2$aA zrYp=Oh-a_#UAft^7ND;w5C~2l$5CVk|Ed|l#s?UX;-rTb1&7?Vn-sqcx;)K8z;q{@A?m%Kxa6vUl z^=Bmqd2_SgRzoSw;h^u}*vIpXX_`f6K2)25cIUwc$LwqL>zXloXT!bQXCN)_1tuCu z;ay>dob>Fg&ZXcH%6U~Co7Uv4_3K}>g7EC3@Wv`9yIey>o%G0ukB_)gldnpCbFwgw zsy;aGONlQ4JF)U$H1y8u;kp!{!yjM3P4?Lbeau<5CuTp3U+*R5(zXOdbNp=Sn0a-K z8k#MzUC;en;qJZu7TyPuAY%3LaM2jrfI1s}hE#UINhrpi5PD=h)AznMs9*$^21%hO6wjfa%Sko2bkj zs~RKBE~tJ-)UP3wfBRN5Z1Oav@odl~(2W-39bil=X*~ z>&?7Hp_^{$N)&onK9;{6Q!7i^gJA*}maKcJg>tej6X63-ZzoSMj9>B4LQ=Xi&R-kI z3?pazgGYM4qfGx@Gh*^A4{2|37-$JT+3$d!gB(P@x=Xd5q7ZxKb+X?2FX@6fVI16H z*$OmP;|teN%q}JUKxCBqT3YD+Xh@@Z+`11H{^>(v5sOVMc-7mu#y*hw26RZybNMOa z0S}0`>qj7K+}CJY{XFixx4a=$@5V$oJ zjIYK#lQXkA%X7qmQJcH}mh#^7>*^fAlo0_70{8DltI4Fs)$OP`?4#J1Io?Bn{(WAr}k~moGzuFl%kNw`pDc7Q#R%_5^JW4 zPYi4t^{eS*@RxSKB%L+!G-1Xx$&87*1s0EV>fmt)EHO>GNM^nAwR3LNiSF*|M4;NM8uazu0eChdv8T##)XEqnZoP<17i zxoylmwc)n5k}Wou3$i0$mxxlN$jc;g;JV89*dHJo(Z5ren0X`v_u!}4D@?#Fq~bsH zrzS0AW(?XaXnlnpeKFvmo1h>tXqK6<0x`Q>2}>B={gaU8abB?lHm^Pnv)-Lc^n=ms=MyWA46zxzin94-SgYN6r)8(Sf z(md?M+QVw~^Z25^L)9&$_I|rq(|XW!NnPA+)D76PN!H;bp}D-&r$N+tPfNg7cZ#n$ z&&oQR$mTcP6##H5TO~=DD>5H--&T%iOQ)Xdh^=vod+O(p76_0ImBINUJKZzdA5sOn z?kx-D_^lo-=Cue6T)!Mm2ypD``TPs_rx`)TS1R3=eG%uAyY5vnNY33eetJ{0=jfpk z;EBzj(VwATT^_z?f(N#ovuwRT9WaW&=IjN~Up>B!Gda|_x4Vim3dEfTx+HELrzwVl zI})AWr|X^QFI7KlR)6G0J%7c+uX_9OITk~D<-1qt}@O!0%*cu~?**zCAc zG%$|)wtoTcrGmF4ZC6k7mZ;k`&TP4%tRocThtgnJe*H%WmBzatOPec~7O9@GULbU% zY_NI4s*!IRwX;`poh4t7i^4HxD<)ZcaX(31NAa8iKTQJ+y)W9wCilwsMWLlm~Z?}4#& zA!loRYT4%On#_SG@>LDt5&!(2P_W7m>R(?Rqsr2}&eF}h;Uo;a`7Bp}kn1_3Q^eQ4 zi028iI`kq9El$5%5Q<%M$b4hXi&P%J;z}_Z#RoF?7`e}iDnZY_7dxvIL)IEGLLS$O zCG)k4J>@p&gIOkRuQe-)dV6HF68|P2eJD4hT+P%D?O-Fi%1E#x*$*1gRG%eO;O?h3wAZGzYk$ z656Yc=eZWC$lPC8`00|u@lEOXua+EaI>sdTL9e@HYjY!TpIt_I!z#5Iy*)p;@^1Qk zJlsty)U)kA$tA}!N%zhkbru1aObH10m=-pzC4(|R#H-BwxX-ZpVD-%Rc-6ihHsua{ zk!Qiv%uu{v$`VvaGn)&rX4<+&c9OyAlW*wJyY%d{loS?6``=a$vo9}viYIk*oS>Nn zL$<8}+(k9Jfj7uVIFGZ{m?~y2_+UcGO$#l-5@90?{_!hE8OYVvI-gr-p|+}9#*5!- zKvp}kCdOM9`TCKz*3Nt|k)e0Hy!U#^GqL*YXKmTnCi69tqT520KlZK^F!s1s zQeOQGk?v69vzU=KsvNbeu5~AtJlU(Fbm#g~J8KC6-8E%)vQ5gZh!nTLLc~0r^7H$7 zvL3q+F}0;j`%mQNL<>Ykxa)KCcNhRIG!|Ra5CmpW;ZxqBiLYPlm4B(5&&Z4}Ck#CE zLFk@wU9O&WkpNbB7;2(!{OjSizsH0E%zfmn$95C`ZR}0%B?uFxBVO#%banWgUVPuZQuV&~$ zMQu6UEgu?-85lw@47eYMigxMkOQJHv;PGGPRpVoXz3ocCnKl+F?Hb2P=L6$$S0b`N z_}UJNx(M^JtoxGyz;}2;)^Y^pa;t$ovTxU5&AWW_Wi#`B(NO`*LQ~(zctUQPG?6Ra zJW6+TIW*=f#DCN1Nz50i4Jt1p|o9_4}> zIq&hO)eJO4Tknc^0ntgoh=TFh$7!}q2nk!lFRR~AOk98HPUGpUp86ijr2y)_#`PO> zCu%VQxc&fvm41HILq=w!O7>^AD|t5qZs>Aly8T#bIx3x4Oju=C3u-s8>*VrZ8r22| zxR>B8zSSHor2paYEi1s8Fx4Cb(cy{|5`O&S(-%nA3uKo9>0b?t>Mi^-XN&jYBx%NC z_TotI@<@kZaS;>bc8LFv3?NL_<5y5Cek*g15Y8d8WCSA_jC4DB)iXn=+v}j-n+Dm0 zju>z=-sHe?gu_7I|HV@-m0zv${Ov|pPp@#{@+u^1y{hw)MpB|m6At2{K1x69(J-)@ zV>U2j5r*84(tJHzQ@x|dO?u77y>%Eyo)46>BNU|1KqHDjhV>`;S{11;f`<#KKdZi4 zoPiht-|#-!8yF+_;4lntsVDtE zNE8mCVx71W2uFTSCAc7!*^88wx0iVvLmyif)`G+Vewo2tG8rZng907G7jxpgNQHng zg~4n-#ZhDZ{R(X`tlGYc#~r0gg##F7;!e+rCi8iH%F~mjz$jewEMJ4p~y3g zEiysD;u9c7GX6&9^aR^tmp*N>4K}AMcUy?nAKf({#`InsL!`7O?I?09KmHc#lz~w7 z{_%@>{G&3nC>^2t<2ww`ag)1LvfnBwgZn!ogVLAzZw(J54>kunhTk#6eg83%H z7y#&cTI?lM*t~>siFJm^J5^?+0ZaI(7XXIV6fT}dW*d_aVr>s@38(NIcI>I<;iPra ze12631zD9W6^>P}PQMNmvA_hZmR|IgdS9FDmOKAd;zVMAPsuEpFnQSlh8e2ApLdY2 zn4Fi(7LKG{vQ?f;U|}(F&26jKZ8Bzy_<;;KWjUF*Dha@_Lg_A{lpKpp<*lgEE2 z+(>73kglggV%~JnkIJ!;@{P)gT}c5it2=wT9)h^rnVxU-Kb)1b$l%tF3k#vdY&3ep z9#`x;V%mA85}GHtfXeRA1ZI*`{&LI2XEI^Cf%$)znSB{3y4xT_QnK)`v);Ht8A1te z3}WapvJQi=!cU73qrny?+bmufEM$8m&CB9*GDf&b3%M-*M36I;za0DJeSUaxgw6VUiCh?=#o}{RsNUK)H3~NU z*KBh2vDA`k2sK^LzHD4q#qk_cjk+KB?x##xzT<7>u>@Ux)g)`_!Hh3F_{^R{Z+mNJ zh*D{s0a+UI`~sJ^Lw?(hNwAR!=X<=^K_97d(1_`Df_1_A0Oy%qsVD+0GU^ zZ>|TE)o`t$os3*krf@u~XWl2jMxS z!Im=x1$d%na|^-nauXE7;CXpzK`aca>JR#@65JG^mwmqYAR_|NS}LsH^-76Gg>pkV zbeBHk3jMn3`80|&1D#u8Xpf0aXJ>SO!V?aO2ZcZ};hH{NVU;c%-jo~8y60i-J)nXH zN{29}-^IDlt3MkE1g2?IPBw3F4su_$YKtLlW^m_mu9y@p%zURr#0y!Q4Xz(py{mz{ zQkcg@@2%nfvgbY11RC_x_62=$fW>j;V1^<{l}`yJr%f)0B*)`8O`ZUR<3YYbL1a9E zJii8K=LJ3D*YLCW=zw=-p^qg!j7$iapY-cfxLFs0X=(;%=5^LoQBO&}(86HpJzr!H z|2SOuL<4oAP*VN_1@q!M{$i5D@y zvuGBQ{5pW?vkcz!Ws-%Sw^Nq6zke5*Xhfcw>cz5aiPlJPyMg--jsvpH9VG0hIyfztZOK?{P6|ZbdiDy7YBe z&fF}KaV>OX8H3S=qhZa>-D>TqH%1M$K+3F~;w^U!FTaKrKaep_JQ3XVBlDI{kX?a4 z|H7l`s?U_u^n{Z3@#}ojWuu(8g{7Ymt9%ZRs(db2^3S~H6X$Q z*+#i_0Dwh8OMkSVT`saTmRi4yvWU94LKv&0o-K9s4O8cngKhh-_5(6!^INNq;km_1 zJ+Ar2-YT?V(VeHA77utqx^>q2nHu`BN$j`?KL+zwy<-(@&AXt6adKwXZJ=s23lv{x zR`U_xRb*Ia3OP3TSW%^yHqpF_tq&JVsBMKyohSt}!$jMB#1kV?b#91-E`Jw~R?(W^ z`uG_4U(m|-^v23hQ3J3{fS37x;eWe%o~y}*yIy5pH`{TKgPw7d_-p`DGKlbO-R}&< zsLMS8XHqL14@f7Yz_K%Xi3>R5!kNPJCtUt+Ez*$`m&IB+KG4o%H2JNWa+%e#fQCwn zG$9XWZ%r$|r$W${2=mtbXpP)eo1;#U40ikPB~ca*NtinY48Hp)G0P>V15% z^6UM+E0qb>O7lDPNwegp9l6}m@S;7L3N;In3H4Ky8fe!;^`>>ZA670A#XYapm@Id7 znFY7+75OHh@>?+ir?tk%Tv^Ix=9D9r`VIsvB&XzCzG}I$gdH}7`_GZ-yE{j(O8xh& zIwJPtnNZcZ4BAgw+NtBYvll-&`A3$SNqeK(3b;On6H~^2QzOU|8}Ye^AN9pRM06Pa5~F1U$bmlEgpT(}i(h<{cuA9&1dH^R zJx)@aNR*v>R8Cc<_gR=Cwb;A~hd?XW@TqcyGL;W7*Z@uQBf-Pc+d1o&ccj9V3Kj40 zeb3}%XUlOQvpC$UlvnHmN(*i38B*a5}m4AG*u`#=oKj@kFw~G23k@=%n73@ zx@L=}=DidYK$A!J)Sm|t?pe-OUQ{C}c1~X^hVIgJ+|k6wtIhF+7|5g82WlAp^7xwa z`vt0-KMH)4q#^*Eajxl1YLuw6ACM1+vFZHJF;~PcVpuH(O;nidp%l7#x-`xG5upeCx@}`anSjY-T=dd;DKxTl zvE;y0&~*zx&bkvTiqGzo5i0G;UzRwGYw90MxwcppP>ORnTCQ4>IZ>%xin-C)Z%z3r;?1JLCEuU{bXoiS5 zAtI|QwPHReXZf$I8OJq3b7l#e&Z^cM-F<^+uI%nS;GLyF>B!3xe=8id(ughI?zYxg zUqTDrPJadIkcFsCv>I|D{&OKB>Q4lGm=`{}6tLyTp zU6iSF!XXNzqU}ZE{9@A?jvRFssRpfD_%Deb&eW^sghuuZzuG*(np2=9xI)W~X8wxZ z8%}*&!KTS8uJoQX4b+;YH@l5tlW-B4S6#@m+a{51c1h7(ZY=#Jn~!`#{uibTS@g<* zq36ei!Qr9I5QD9OH_a#kM*z^)7d$*DuQNbXJ7uoxU4G2;EZ6NFwDnHpOGgFpMS4=-Rlu`1U2;FjI78@ zU^sAE&N!ctTc{W3(`w|}k92szs4|BuJ?&$BNlbcf(JcmAT&MN=V5sn&;P*u(27h+8 z`5xTyD)-xR&XW&m%!&^eU*%gK)ajtlxdi8iyomRvynp}exz7K?pzJ-^WBlFfyKPaU z7k8!K3gD38-=U2@KLRT4Z6ZNFD@RVZ=NGyxW1ZvU3MbxkIlY44{mYfXft>x z`*_qw3`&bLS;`&kz3R2EeeG{%xA5_x>@|EwU&CK-^XmW@c^yCvzHzGVINSVT_6R?B z3J2h2pL}RxhUkmH`RCtT47bXdS2X9^U*0XkC&xM5QQ!!U0Q(Fdh*?~nK;t?BF=uet zfnmN~_^_}0y03dd&PbjS<2#E{kq<-cHoYrt4LLNXp20dW{F-MxWAlhSa@^V&Z(?^4|B4BY2(z!x-XuHQYJ^G6apKdx=1{E(th- zr(`!K-*WXBKC-{7}x>WaeOXcIC7}>!5F`TJgdIG{CNsqwC&}BH0X+-gS`*t z5%1r~BjLZ3;y$rg!{7Uieph)h!*4Lah9q~_`O+udJ^W$nIDhUG4!{{eZv#>)%4P-f z1X$j)KTJd~deMt!CGn6DxFb4%4(L`m0;r6>&Oo}(fCE@Ng548_G5CAslWEV1Tpbu* zVC&tLpEHoJa}W!4u;gAxaPd>0ItPY~nSpC3cA5_uFM6NyuQ}Q3e=?8kYHy3rz;kPE zcS)gKA7}`R^SC)}-j=uVd}_-U@YKQHNcPtM+-V#Dg{TsWf9%J8Z1ea3{@))-$b+sp z|K-2@m(BNn@AppG9oYfQ0G6L4ID_s6U@?Aq&ftq37;*+~Bc7LMCN9o<6EDc_;E^?S z@~lHp#;C=Nw3iQX+%0%={-5EQ`C}GNfw3#E1NcM?{?Z)od4S9Io}n|9TDwKNvpuUf=(TKG=&qZZ+H~9KiY#;L>a#FTC)=`9#=77hN=8 z2lkbqy$<5P{kQ+N`JV6jo;&moV82;DiX(tt2e94|bXQg50@&{ev|%mH{KPn{h@{wHCRGlot60AsH2;o0ho(cvtl8GpC>XyhwTpY+7u zYhLr3SElaM;bXspJ%<8Tc4Y#!epjamayb(xQfR*F#{k^}p`KSN% zpUx-2oc7oF)&Jbj{oE#>+}gbEb+6lO@^@i(Mu=k@VXPd%RybS3Fl2cSfT1vw?g|)@ zoj_Mp+i8bs!sqfZ%@w(m^1-a+KbL<$dR}&04h-+fU>SN1Ik>w6I*vgdW4GFO#g{i% z0;utK=MYEn!F*ivWik9qQvKNkJa}raFX!|&p4b=~YW!m3Y)JCXf3RneCo3G&+ki(K z4CVRH|M@>}{?cFiOS?0G|MZ{!)8w^Nf7xZ1?OqA?pMih*FaPEFG?@B3>kh!!*06E} zE#6w))(JFiCs0SwOM~tP#C8OSJz*HbzE>QOF()XGB{&pGFuIb8ZD|Ky)+{^$SvpY#0ypA-L+;sDk%If66b1lEo~ znltF-K^=kJLC*+!c`z>^Wf%6;Jcsdu82VQPXI6aj7dQhC3~|72>)8b`cn-tvEa@9^ zegB3$pa0^-m!^4d0clRYPGRz=er`VroDc`#fX_9(zyAUp0{H&#|Ncq)XCMxsj^VHT zmA|s@Hv^{8pP-)_#t|GrjfQdA2{1alfjR=|I)wE(flrqSZ_i=ugK``3J92RN%*@Hz z9DtSIjv%N1AJ47(-}*oQ=l{GSC;C@}7ANxmw|54)ZNoqmwOhBFE^{F-+e7#mzE;oC z>l7%mFx<5NDS63&uwuKY6)PqIdWOTXNR2R`)R2-K>7h7&8`z_5`X%j-A7jiZUGx?} zL*%V4!*>Dz0^SkGegHv15I`6HtzHOXU$2Q4Ah27HNcs{da8@uDCvYi|IKhy!3h*Tl z9o^+COkcBd@GYB*eg?3=2b6yV5Pk&^vIXFt;GXyPb;QTPo$kY%0ReN^KH_79e@Ro{ z0$c0alLbxy0yLQc00e*nGds#q^AIb@ zrk^1t2Jk5>2cNSiV42&1eS(1ZiTdwyE3gaiW4Jgwqdp_N8Ar$QDU%L5zO$J}mHvCG z1>P+HoN9p0W-}~Tq0cO#X7`yZt7UmjB83jbPS=2Da8N-K|UEw_9vtBZ`B zm#sPrut~~hWX=Yp008^|3fY#uN&t41V|~bMATJzV@tU%HxOks;dp_(F5X@K1b~rv+ zM|Y%`dcxKDqrO;dx7&Q;;AJUMzO}#QO6B2%yXgmT~-# znFcHa1|H)NYyQc)?ZG47}bpV**MQggO6Dzh1 zm9Jo+e3^X$$QeZ+5(Lz_p*lO1WS#sVeEPWx$G1Zr0JOwuv;)9tcAA5h&R+YfOsA(# z-a7Slavj<-^~%&8lhyh+;X44FXLjxjdwL%hs7|VLE0Zc01nQZiqn@8uvq*BosS|v TtR(j)00000NkvXXu0mjfm5*Zg literal 0 HcmV?d00001 diff --git a/app/assets/icons/default/default32.png b/app/assets/icons/default/default32.png new file mode 100644 index 0000000000000000000000000000000000000000..c8c09687a7993ee7b37711e4cdd67218449889df GIT binary patch literal 2988 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 literal 0 HcmV?d00001 diff --git a/app/assets/icons/default/main-window.ico b/app/assets/icons/default/main-window.ico new file mode 100644 index 0000000000000000000000000000000000000000..ab37a7544ab73679b3204b3ae9d8df6a09c205af GIT binary patch literal 70882 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ℜPkR%b3tSY* z(()tub(Zl8O^yT(#RW4YM2TWxhuT`-zrK}nKxPfNkYjVroK7{%`HEt_E5k%Vkz?rv zHBR+!=W@VEsMR^0x2w-=#Y6X9`r62B0JI}F|H&sC_O(1V{NuDo!3t3USdoGG@Q!&U zJKG;DV;f&w>i3)3?N@)}!yj4NGH7kI&Ph2(uJ*&%Qg(;qMiM%52-XW5U`Suuj4Fqa2scPNr5XN)b0WA8Q%o7MbBHZ zv$xMkH!6m#Byh#|Qet<$$4K7hSoZYgrD*TC@E&B=HMhJtcEqx!zPCocBR8?bzOFY! zwG5{vs~mOt-29g-o7(%BOX%cB@^BjxDz*~tMPolI_wa1^$>>dHr_~()pS+>#NQfR3wz3^1g4h9Z1YUyG7pxepbeFj>r&mavNJ zqC#;bEy+tguYCwmv~4RAfNBh0L3~dc#;Ssd`9T{Mz?{|mL~TZXjZ`7KuSoEVyNMU0 zOXQ$W{y!?eI{6jv#~hXnUXLh8y=%05#B;NR0c}thvAlB!AU4AWS{gc@(gh-lv0ew_ddY7x^8KPr$Lo;J8RGndL)_)V=#Dw?oBK^d8TPALK3p`nA$GP+b8>fv z_T7C41j9y*`6zL;Aj-pJ&*Qch8fEj|&tK@hvxDZSi(z)4Pgd(cjBwC|+3dMK=!sEVosGBr!IYQ~ycx$w z_kHQA7eDDyOSSo71{^9IW<@0)-b;%KFc7Ix(eJPo888WP0A;*rUAXwO`TRisD-t2k z>RGRV8c9Fg-NlBz2r77bpkAIYF#m)(Tjo)^G#cD7SZ*6O~*{N{X+y z@8n3x*>M1myDnukR6l$SyArO4AhhM^MWowy6aApKp-whT00F)b zVR~oN4Rm{Ev^j!io=?iPPpXE?08lMy8U2JYH2 zBrymd6{M&V5|d3BCwB|xRSml8b7JALw|)$t?3dM%-OO2I+tr=WsJM@FLN>;e0<+!LVXo4nSUm}≪ZH8IB!!Tl)hs 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 R*X92^|BvuJx`+SP^ +# Kevin Gerich +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +*/ + +.windowDialog { + padding: 12px; + font: -moz-dialog; +} + +.paneSelector { + list-style-image: url("chrome://browser/skin/preferences/Options.png"); +} + +/* ----- GENERAL BUTTON ----- */ + +radio[pane=paneGeneral], +radio[pane=paneMain] { + -moz-image-region: rect(0px, 32px, 32px, 0px); +} + +/* ----- TABS BUTTON ----- */ + +radio[pane=paneTabs] { + -moz-image-region: rect(0px, 64px, 32px, 32px); +} + +/* ----- CONTENT BUTTON ----- */ + +radio[pane=paneContent] { + -moz-image-region: rect(0px, 96px, 32px, 64px); +} + +/* ----- APPLICATIONS BUTTON ----- */ + +radio[pane=paneApplications] { + -moz-image-region: rect(0px, 128px, 32px, 96px); +} + +/* ----- PRIVACY BUTTON ----- */ + +radio[pane=panePrivacy] { + -moz-image-region: rect(0px, 160px, 32px, 128px); +} + +/* ----- SECURITY BUTTON ----- */ + +radio[pane=paneSecurity] { + -moz-image-region: rect(0px, 192px, 32px, 160px); +} + +/* ----- ADVANCED BUTTON ----- */ + +radio[pane=paneAdvanced] { + -moz-image-region: rect(0px, 224px, 32px, 192px); +} + +/* ----- SYNC BUTTON ----- */ + +radio[pane=paneSync] { + list-style-image: url("chrome://browser/skin/preferences/Options-sync.png"); +} + + +/* ----- APPLICATIONS PREFPANE ----- */ +#BrowserPreferences[animated="true"] #handlersView { + height: 25em; +} + +#BrowserPreferences[animated="false"] #handlersView { + -moz-box-flex: 1; +} + +description { + font: small-caption; + font-weight: normal; + line-height: 1.3em; + margin-bottom: 4px !important; +} + +prefpane .groupbox-body { + -moz-appearance: none; + padding: 8px 4px 4px 4px; +} + +#paneTabs > groupbox { + margin: 0; +} + +#tabPrefsBox { + margin: 12px 4px; +} + +prefpane .groupbox-title { + background: url("chrome://global/skin/50pct_transparent_grey.png") repeat-x bottom left; + margin-bottom: 4px; +} + +tabpanels { + padding: 20px 7px 7px; +} + +caption { + -moz-padding-start: 5px; + padding-top: 4px; + padding-bottom: 2px; +} + +#paneMain description, +#paneContent description, +#paneAdvanced description, +#paneSecurity description { + font: -moz-dialog; +} + +#paneContent { + padding-top: 8px; +} + +#paneContent row { + padding: 2px 4px; + -moz-box-align: center; +} + +#popupPolicyRow, +#enableSoftwareInstallRow, +#enableImagesRow { + margin-bottom: 4px !important; + padding-bottom: 4px !important; + border-bottom: 1px solid #ccc; +} + +#browserUseCurrent, +#browserUseBookmark, +#browserUseBlank { + margin-top: 10px; +} + +#advancedPrefs { + margin: 0 8px; +} + +#privacyPrefs { + padding: 0 4px; +} + +#privacyPrefs > tabpanels { + padding: 18px 10px 10px; +} + +#OCSPDialogPane { + font: message-box !important; +} + +/** + * Privacy Pane + */ + +/* styles for the link elements copied from .text-link in global.css */ +.inline-link { + color: -moz-nativehyperlinktext; + text-decoration: underline; +} + +.inline-link:not(:focus) { + outline: 1px dotted transparent; +} + +/** + * Update Preferences + */ +#autoInstallOptions { + -moz-margin-start: 20px; +} + +.updateControls { + -moz-margin-start: 10px; +} + +/** + * Clear Private Data + */ +#SanitizeDialogPane > groupbox { + margin-top: 0; +} + + +/* ----- SYNC PANE ----- */ + +#syncDesc { + padding: 0 8em; +} + +#accountCaptionImage { + list-style-image: url("chrome://mozapps/skin/profile/profileicon.png"); +} + +#syncAddDeviceLabel { + margin-top: 1em; + margin-bottom: 1em; +} + +#syncEnginesList { + height: 10em; +} + diff --git a/app/assets/multilocale.txt b/app/assets/multilocale.txt new file mode 100644 index 0000000000..616d8de29d --- /dev/null +++ b/app/assets/multilocale.txt @@ -0,0 +1 @@ +en-US,ar,bg-BG,br,ca-AD,cs-CZ,da-DK,de,el-GR,en-AU,en-CA,en-GB,en-NZ,es-ES,et-EE,eu-ES,fa,fi-FI,fr-FR,gl-ES,hu-HU,id-ID,is-IS,it-IT,ja-JP,km,ko-KR,lt-LT,nb-NO,nl-NL,pl-PL,pt-BR,pt-PT,ro-RO,ru-RU,sk-SK,sl-SI,sr-RS,sv-SE,th-TH,tr-TR,uk-UA,vi-VN,zh-CN,zh-TW diff --git a/app/assets/prefs.js b/app/assets/prefs.js new file mode 100644 index 0000000000..5b2ada59b6 --- /dev/null +++ b/app/assets/prefs.js @@ -0,0 +1,186 @@ +// We only want a single window, I think +pref("toolkit.singletonWindowType", "navigator:browser"); + +// For debugging purposes, show errors in console by default +pref("javascript.options.showInConsole", true); + +// Don't retrieve unrequested links when performing standalone translation +pref("network.prefetch-next", false); + +// Let operations run as long as necessary +pref("dom.max_chrome_script_run_time", 0); + +// .dotm Word plugin VBA uses this to find the running Zotero instance +pref("ui.window_class_override", "ZoteroWindowClass"); + +pref("intl.locale.requested", ''); +pref("intl.regional_prefs.use_os_locales", false); + +// Fix error initializing login manager after this was changed in Firefox 57 +// Could also disable this with MOZ_LOADER_SHARE_GLOBAL, supposedly +pref("jsloader.shareGlobal", false); + +// Needed due to https://bugzilla.mozilla.org/show_bug.cgi?id=1181977 +pref("browser.hiddenWindowChromeURL", "chrome://zotero/content/standalone/hiddenWindow.xhtml"); +// Use basicViewer for opening new DOM windows from content (for TinyMCE) +pref("browser.chromeURL", "chrome://zotero/content/standalone/basicViewer.xhtml"); +// We need these to get the save dialog working with contentAreaUtils.js +pref("browser.download.useDownloadDir", false); +pref("browser.download.manager.showWhenStarting", false); +pref("browser.download.folderList", 1); + +// Don't show add-on selection dialog +pref("extensions.shownSelectionUI", true); +pref("extensions.autoDisableScope", 11); + +pref("network.protocol-handler.expose-all", false); +pref("network.protocol-handler.expose.zotero", true); +pref("network.protocol-handler.expose.http", true); +pref("network.protocol-handler.expose.https", true); + +// Never go offline +pref("offline.autoDetect", false); +pref("network.manage-offline-status", false); + +// Without this, we will throw up dialogs if asked to translate strange pages +pref("browser.xul.error_pages.enabled", true); + +// Without this, scripts may decide to open popups +pref("dom.disable_open_during_load", true); + +// Don't show security warning. The "warn_viewing_mixed" warning just lets the user know that some +// page elements were loaded over an insecure connection. This doesn't matter if all we're doing is +// scraping the page, since we don't provide any information to the site. +pref("security.warn_viewing_mixed", false); + +// Preferences for add-on discovery +pref("extensions.getAddons.cache.enabled", false); +//pref("extensions.getAddons.maxResults", 15); +//pref("extensions.getAddons.get.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/guid:%IDS%?src=thunderbird&appOS=%OS%&appVersion=%VERSION%&tMain=%TIME_MAIN%&tFirstPaint=%TIME_FIRST_PAINT%&tSessionRestored=%TIME_SESSION_RESTORED%"); +//pref("extensions.getAddons.search.browseURL", "https://addons.mozilla.org/%LOCALE%/%APP%/search?q=%TERMS%"); +//pref("extensions.getAddons.search.url", "https://services.addons.mozilla.org/%LOCALE%/%APP%/api/%API_VERSION%/search/%TERMS%/all/%MAX_RESULTS%/%OS%/%VERSION%?src=thunderbird"); +//pref("extensions.webservice.discoverURL", "https://www.zotero.org/support/plugins"); + +// Check Windows certificate store for custom CAs +pref("security.enterprise_roots.enabled", true); + +// Disable add-on signature checking with unbranded Firefox build +pref("xpinstall.signatures.required", false); +// Allow legacy extensions (though this might not be necessary) +pref("extensions.legacy.enabled", true); +// Allow installing XPIs from any host +pref("xpinstall.whitelist.required", false); +// Allow installing XPIs when using a custom CA +pref("extensions.install.requireBuiltInCerts", false); +pref("extensions.update.requireBuiltInCerts", false); + +// Don't connect to the Mozilla extensions blocklist +pref("extensions.blocklist.enabled", false); +// Avoid warning in console when opening Tools -> Add-ons +pref("extensions.getAddons.link.url", ""); + +// Disable places +pref("places.history.enabled", false); + +// Probably not used, but prevent an error in the console +pref("app.support.baseURL", "https://www.zotero.org/support/"); + +// Disable Telemetry, Health Report, error reporting, and remote settings +pref("toolkit.telemetry.unified", false); +pref("toolkit.telemetry.enabled", false); +pref("datareporting.policy.dataSubmissionEnabled", false); +pref("toolkit.crashreporter.enabled", false); +pref("extensions.remoteSettings.disabled", true); + +pref("extensions.update.url", ""); + +// Don't try to load the "Get Add-ons" tab on first load of Add-ons window +pref("extensions.ui.lastCategory", "addons://list/extension"); + +/** The below is imported from https://developer.mozilla.org/en/XULRunner/Application_Update **/ +// Whether or not app updates are enabled +pref("app.update.enabled", true); + +// This preference turns on app.update.mode and allows automatic download and +// install to take place. We use a separate boolean toggle for this to make +// the UI easier to construct. +pref("app.update.auto", true); + +// Defines how the Application Update Service notifies the user about updates: +// +// AUM Set to: Minor Releases: Major Releases: +// 0 download no prompt download no prompt +// 1 download no prompt download no prompt if no incompatibilities +// 2 download no prompt prompt +// +// See chart in nsUpdateService.js.in for more details +// +pref("app.update.mode", 2); + +// If set to true, the Update Service will present no UI for any event. +pref("app.update.silent", false); + +// URL user can browse to manually if for some reason all update installation +// attempts fail. +pref("app.update.url.manual", "https://www.zotero.org/download"); + +// A default value for the "More information about this update" link +// supplied in the "An update is available" page of the update wizard. +pref("app.update.url.details", "https://www.zotero.org/support/changelog"); + +// User-settable override to app.update.url for testing purposes. +//pref("app.update.url.override", ""); + +// Interval: Time between checks for a new version (in seconds) +// default=1 day +pref("app.update.interval", 86400); + +// Interval: Time before prompting the user to download a new version that +// is available (in seconds) default=1 day +pref("app.update.nagTimer.download", 86400); + +// Interval: Time before prompting the user to restart to install the latest +// download (in seconds) default=30 minutes +pref("app.update.nagTimer.restart", 1800); + +// The minimum delay in seconds for the timer to fire. +// default=2 minutes +pref("app.update.timerMinimumDelay", 120); + +// Whether or not we show a dialog box informing the user that the update was +// successfully applied. This is off in Firefox by default since we show a +// upgrade start page instead! Other apps may wish to show this UI, and supply +// a whatsNewURL field in their brand.properties that contains a link to a page +// which tells users what's new in this new update. + +// This needs to be disabled since it makes us error out on update for some +// unknown reason +pref("app.update.showInstalledUI", false); + +// 0 = suppress prompting for incompatibilities if there are updates available +// to newer versions of installed addons that resolve them. +// 1 = suppress prompting for incompatibilities only if there are VersionInfo +// updates available to installed addons that resolve them, not newer +// versions. +pref("app.update.incompatible.mode", 0); + +// update channel for this build +pref("app.update.channel", "default"); + +// This should probably not be a preference that's used in toolkit.... +pref("browser.preferences.instantApply", false); + +// Allow elements to be displayed full-screen +pref("full-screen-api.enabled", true); + +// Allow chrome access in DevTools +// This enables the input field in the Browser Console tool +pref("devtools.chrome.enabled", true); + +// Default mousewheel action with Alt/Option is History Back/Forward in Firefox +// We don't have History navigation and users want to scroll the tree with Option +// key held down +pref("mousewheel.with_alt.action", 1); + +// Use the system print dialog instead of the new tab-based print dialog in Firefox +pref("print.prefer_system_dialog", true); diff --git a/app/assets/unix/skin/preferences/preferences.css b/app/assets/unix/skin/preferences/preferences.css new file mode 100644 index 0000000000..3a19fbb185 --- /dev/null +++ b/app/assets/unix/skin/preferences/preferences.css @@ -0,0 +1,188 @@ +%if 0 +/* +# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Firefox Preferences System. +# +# The Initial Developer of the Original Code is +# Ben Goodger. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Ben Goodger +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +*/ +%endif + +/* Global Styles */ +#BrowserPreferences radio[pane] { + list-style-image: url("chrome://browser/skin/preferences/Options.png"); +} + +radio[pane=paneMain] { + -moz-image-region: rect(0px, 32px, 32px, 0px) +} + +radio[pane=paneTabs] { + -moz-image-region: rect(0px, 64px, 32px, 32px) +} + +radio[pane=paneContent] { + -moz-image-region: rect(0px, 96px, 32px, 64px) +} + +radio[pane=paneApplications] { + -moz-image-region: rect(0px, 128px, 32px, 96px) +} + +radio[pane=panePrivacy] { + -moz-image-region: rect(0px, 160px, 32px, 128px) +} + +radio[pane=paneSecurity] { + -moz-image-region: rect(0px, 192px, 32px, 160px) +} + +radio[pane=paneAdvanced] { + -moz-image-region: rect(0px, 224px, 32px, 192px) +} + +%ifdef MOZ_SERVICES_SYNC +radio[pane=paneSync] { + list-style-image: url("chrome://browser/skin/preferences/Options-sync.png") !important; +} +%endif + +/* Applications Pane */ +#BrowserPreferences[animated="true"] #handlersView { + height: 25em; +} + +#BrowserPreferences[animated="false"] #handlersView { + -moz-box-flex: 1; +} + +/* Privacy Pane */ + +/* styles for the link elements copied from .text-link in global.css */ +.inline-link { + color: -moz-nativehyperlinktext; + text-decoration: underline; +} + +.inline-link:not(:focus) { + outline: 1px dotted transparent; +} + +/* Modeless Window Dialogs */ +.windowDialog, +.windowDialog prefpane { + padding: 0px; +} + +.contentPane { + margin: 9px 8px 5px 8px; +} + +.actionButtons { + margin: 0px 3px 6px 3px !important; +} + +/* Cookies Manager */ +#cookiesChildren::-moz-tree-image(domainCol) { + width: 16px; + height: 16px; + margin: 0px 2px; + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png"); +} + +#paneApplications { + margin-left: 4px; + margin-right: 4px; + padding-left: 0; + padding-right: 0; +} + +#linksOpenInBox { + margin-top: 5px; +} + +#paneAdvanced { + padding-bottom: 10px; +} +#advancedPrefs { + margin-left: 0; + margin-right: 0; +} + +#cookiesChildren::-moz-tree-image(domainCol, container) { + list-style-image: url("moz-icon://stock/gtk-directory?size=menu"); +} + +#cookieInfoBox { + border: 1px solid ThreeDShadow; + border-radius: 0px; + margin: 4px; + padding: 0px; +} + +/* bottom-most box containing a groupbox in a prefpane. Prevents the bottom + of the groupbox from being cutoff */ +.bottomBox { + padding-bottom: 4px; +} + +/** + * Clear Private Data + */ +#SanitizeDialogPane > groupbox { + margin-top: 0; +} + +%ifdef MOZ_SERVICES_SYNC +/* Sync Pane */ + +#syncDesc { + padding: 0 8em; +} + +#accountCaptionImage { + list-style-image: url("chrome://mozapps/skin/profile/profileicon.png"); +} + +#syncAddDeviceLabel { + margin-top: 1em; + margin-bottom: 1em; +} + +#syncEnginesList { + height: 10em; +} + +%endif diff --git a/app/assets/updater.ini b/app/assets/updater.ini new file mode 100644 index 0000000000..e68c8edc2e --- /dev/null +++ b/app/assets/updater.ini @@ -0,0 +1,4 @@ +; This file is in the UTF-8 encoding +[Strings] +Title=Zotero Update +Info=Zotero is installing your updates and will start in a few moments… \ No newline at end of file diff --git a/app/assets/win/skin/preferences/preferences.css b/app/assets/win/skin/preferences/preferences.css new file mode 100644 index 0000000000..d36cb7c285 --- /dev/null +++ b/app/assets/win/skin/preferences/preferences.css @@ -0,0 +1,178 @@ +/* +# -*- Mode: Java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is the Firefox Preferences System. +# +# The Initial Developer of the Original Code is +# Ben Goodger. +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Ben Goodger +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** +*/ + +/* Global Styles */ +#BrowserPreferences radio[pane] { + list-style-image: url("chrome://browser/skin/preferences/Options.png"); + padding: 5px 3px 1px; +} + +radio[pane=paneMain] { + -moz-image-region: rect(0, 32px, 32px, 0); +} + +radio[pane=paneTabs] { + -moz-image-region: rect(0, 64px, 32px, 32px); +} + +radio[pane=paneContent] { + -moz-image-region: rect(0, 96px, 32px, 64px); +} + +radio[pane=paneApplications] { + -moz-image-region: rect(0, 128px, 32px, 96px); +} + +radio[pane=panePrivacy] { + -moz-image-region: rect(0, 160px, 32px, 128px); +} + +radio[pane=paneSecurity] { + -moz-image-region: rect(0, 192px, 32px, 160px); +} + +radio[pane=paneAdvanced] { + -moz-image-region: rect(0, 224px, 32px, 192px); +} + +%ifdef MOZ_SERVICES_SYNC +radio[pane=paneSync] { + list-style-image: url("chrome://browser/skin/preferences/Options-sync.png") !important; +} +%endif + +/* Applications Pane */ +#BrowserPreferences[animated="true"] #handlersView { + height: 25em; +} + +#BrowserPreferences[animated="false"] #handlersView { + -moz-box-flex: 1; +} + +/* Privacy Pane */ + +/* styles for the link elements copied from .text-link in global.css */ +.inline-link { + color: -moz-nativehyperlinktext; + text-decoration: underline; +} + +.inline-link:not(:focus) { + outline: 1px dotted transparent; +} + +/* Modeless Window Dialogs */ +.windowDialog, +.windowDialog prefpane { + padding: 0; +} + +.contentPane { + margin: 9px 8px 5px; +} + +.actionButtons { + margin: 0 3px 6px !important; +} + +/* Cookies Manager */ +#cookiesChildren::-moz-tree-image(domainCol) { + width: 16px; + height: 16px; + margin: 0 2px; + list-style-image: url("chrome://mozapps/skin/places/defaultFavicon.png") !important; +} + +#cookiesChildren::-moz-tree-image(domainCol, container) { + list-style-image: url("chrome://global/skin/icons/folder-item.png") !important; + -moz-image-region: rect(0, 32px, 16px, 16px); +} + +#cookiesChildren::-moz-tree-image(domainCol, container, open) { + -moz-image-region: rect(16px, 32px, 32px, 16px); +} + +#cookieInfoBox { + border: 1px solid ThreeDShadow; + border-radius: 0; + margin: 4px; + padding: 0; +} + +/* Advanced Pane */ + +/* Adding padding-bottom prevents the bottom of the tabpanel from being cutoff + when browser.preferences.animateFadeIn = true */ +#advancedPrefs { + padding-bottom: 8px; +} + +/* bottom-most box containing a groupbox in a prefpane. Prevents the bottom + of the groupbox from being cutoff */ +.bottomBox { + padding-bottom: 4px; +} + +%ifdef MOZ_SERVICES_SYNC +/* Sync Pane */ + +#syncDesc { + padding: 0 8em; +} + +.syncGroupBox { + padding: 10px; +} + +#accountCaptionImage { + list-style-image: url("chrome://mozapps/skin/profile/profileicon.png"); +} + +#syncAddDeviceLabel { + margin-top: 1em; + margin-bottom: 1em; + } + +#syncEnginesList { + height: 11em; +} + +%endif diff --git a/app/build.sh b/app/build.sh new file mode 100755 index 0000000000..893f9fba65 --- /dev/null +++ b/app/build.sh @@ -0,0 +1,845 @@ +#!/bin/bash -e + +# Copyright (c) 2011 Zotero +# Center for History and New Media +# George Mason University, Fairfax, Virginia, USA +# http://zotero.org +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +. "$CALLDIR/config.sh" + +if [ "`uname`" = "Darwin" ]; then + MAC_NATIVE=1 +else + MAC_NATIVE=0 +fi +if [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then + WIN_NATIVE=1 +else + WIN_NATIVE=0 +fi + +function usage { + cat >&2 < "$DIST_DIR/build_id" + +cd "$app_dir" + +# Copy 'browser' files from Firefox +# +# omni.ja is left uncompressed within the Firefox application files by fetch_xulrunner +set +e +if [ $BUILD_MAC == 1 ]; then + cp -Rp "$MAC_RUNTIME_PATH"/Contents/Resources/browser/omni "$app_dir" +elif [ $BUILD_WIN == 1 ]; then + # Non-arch-specific files, so just use 64-bit version + cp -Rp "${WIN_RUNTIME_PATH_PREFIX}win64"/browser/omni "$app_dir" +elif [ $BUILD_LINUX == 1 ]; then + # Non-arch-specific files, so just use 64-bit version + cp -Rp "${LINUX_RUNTIME_PATH_PREFIX}x86_64"/browser/omni "$app_dir" +fi +set -e +cd $omni_dir +# Move some Firefox files that would be overwritten out of the way +mv chrome.manifest chrome.manifest-fx +mv components components-fx +mv defaults defaults-fx + +# Extract Zotero files +if [ -n "$ZIP_FILE" ]; then + ZIP_FILE="`abspath $ZIP_FILE`" + echo "Building from $ZIP_FILE" + unzip -q $ZIP_FILE -d "$omni_dir" +else + rsync_params="" + if [ $include_tests -eq 0 ]; then + rsync_params="--exclude /test" + fi + rsync -a $rsync_params "$SOURCE_DIR/" ./ +fi + +# +# Merge preserved files from Firefox +# +# components +mv components/* components-fx +rmdir components +mv components-fx components + +mv defaults defaults-z +mv defaults-fx defaults +prefs_file=defaults/preferences/zotero.js + +# Transfer Firefox prefs, omitting some with undesirable overrides from the base prefs +# +# - network.captive-portal-service.enabled +# Disable the captive portal check against Mozilla servers +egrep -v '(network.captive-portal-service.enabled)' defaults/preferences/firefox.js > $prefs_file +rm defaults/preferences/firefox.js + +# Combine app and "extension" Zotero prefs +echo "" >> $prefs_file +echo "#" >> $prefs_file +echo "# Zotero app prefs" >> $prefs_file +echo "#" >> $prefs_file +echo "" >> $prefs_file +cat "$CALLDIR/assets/prefs.js" >> $prefs_file +echo "" >> $prefs_file +echo "# Zotero extension prefs" >> $prefs_file +echo "" >> $prefs_file +cat defaults-z/preferences/zotero.js >> $prefs_file + +rm -rf defaults-z + +# Platform-specific prefs +if [ $BUILD_MAC == 1 ]; then + perl -pi -e 's/pref\("browser\.preferences\.instantApply", false\);/pref\("browser\.preferences\.instantApply", true);/' $prefs_file + perl -pi -e 's/%GECKO_VERSION%/'"$GECKO_VERSION_MAC"'/g' $prefs_file + # Fix horizontal mousewheel scrolling (this is set to 4 in the Fx60 .app greprefs.js, but + # defaults to 1 in later versions of Firefox, and needs to be 1 to work on macOS) + echo 'pref("mousewheel.with_shift.action", 1);' >> $prefs_file +elif [ $BUILD_WIN == 1 ]; then + perl -pi -e 's/%GECKO_VERSION%/'"$GECKO_VERSION_WIN"'/g' $prefs_file +elif [ $BUILD_LINUX == 1 ]; then + # Modify platform-specific prefs + perl -pi -e 's/pref\("browser\.preferences\.instantApply", false\);/pref\("browser\.preferences\.instantApply", true);/' $prefs_file + perl -pi -e 's/%GECKO_VERSION%/'"$GECKO_VERSION_LINUX"'/g' $prefs_file +fi + +# Clear list of built-in add-ons +echo '{"dictionaries": {"en-US": "dictionaries/en-US.dic"}, "system": []}' > chrome/browser/content/browser/built_in_addons.json + +# chrome.manifest +mv chrome.manifest zotero.manifest +mv chrome.manifest-fx chrome.manifest +# TEMP +#echo "manifest zotero.manifest" >> "$base_dir/chrome.manifest" +cat zotero.manifest >> chrome.manifest +rm zotero.manifest + +# Update channel +perl -pi -e 's/pref\("app\.update\.channel", "[^"]*"\);/pref\("app\.update\.channel", "'"$UPDATE_CHANNEL"'");/' $prefs_file +echo -n "Channel: " +grep app.update.channel $prefs_file +echo + +# Add devtools prefs +if [ $DEVTOOLS -eq 1 ]; then + echo >> $prefs_file + echo "// Dev Tools" >> $prefs_file + echo 'pref("devtools.debugger.remote-enabled", true);' >> $prefs_file + echo 'pref("devtools.debugger.remote-port", 6100);' >> $prefs_file + if [ $UPDATE_CHANNEL != "beta" ]; then + echo 'pref("devtools.debugger.prompt-connection", false);' >> $prefs_file + fi +fi + +# 5.0.96.3 / 5.0.97-beta.37+ddc7be75c +VERSION=`perl -ne 'print and last if s/.*(.+)<\/em:version>.*/\1/;' install.rdf` +# 5.0.96 / 5.0.97 +VERSION_NUMERIC=`perl -ne 'print and last if s/.*(\d+\.\d+(\.\d+)?).*<\/em:version>.*/\1/;' install.rdf` +if [ -z "$VERSION" ]; then + echo "Version number not found in install.rdf" + exit 1 +fi +rm install.rdf + +echo +echo "Version: $VERSION" + +# Delete Mozilla signing info if present +rm -rf META-INF + +# Copy branding +#cp -R "$CALLDIR/assets/branding/content" chrome/branding/content +cp -R "$CALLDIR"/assets/branding/locale/brand.{dtd,properties} chrome/en-US/locale/branding/ +cp "$CALLDIR/assets/branding/locale/brand.ftl" localization/en-US/branding/brand.ftl + +# Copy localization .ftl files +for locale in `ls chrome/locale/`; do + mkdir -p localization/$locale/mozilla + cp chrome/locale/$locale/zotero/mozilla/*.ftl localization/$locale/mozilla/ + # TEMP: Until we've created zotero.ftl in all locales + touch chrome/locale/$locale/zotero/zotero.ftl + cp chrome/locale/$locale/zotero/*.ftl localization/$locale/ +done + +# Add to chrome manifest +echo "" >> chrome.manifest +cat "$CALLDIR/assets/chrome.manifest" >> chrome.manifest + +# Move test files to root directory +if [ $include_tests -eq 1 ]; then + cat test/chrome.manifest >> chrome.manifest + rm test/chrome.manifest + cp -R test/tests "$base_dir/tests" +fi + +# Copy platform-specific assets +if [ $BUILD_MAC == 1 ]; then + rsync -a "$CALLDIR/assets/mac/" ./ +elif [ $BUILD_WIN == 1 ]; then + rsync -a "$CALLDIR/assets/win/" ./ +elif [ $BUILD_LINUX == 1 ]; then + rsync -a "$CALLDIR/assets/unix/" ./ +fi + +# Add word processor plug-ins +if [ $BUILD_MAC == 1 ]; then + pluginDir="$CALLDIR/modules/zotero-word-for-mac-integration" + mkdir -p "integration/word-for-mac" + cp -RH "$pluginDir/components" \ + "$pluginDir/resource" \ + "$pluginDir/chrome.manifest" \ + "integration/word-for-mac" + echo -n "Word for Mac plugin version: " + cat "integration/word-for-mac/resource/version.txt" + echo + echo >> $prefs_file + cat "$CALLDIR/modules/zotero-word-for-mac-integration/defaults/preferences/zoteroMacWordIntegration.js" >> $prefs_file + echo >> $prefs_file +elif [ $BUILD_WIN == 1 ]; then + pluginDir="$CALLDIR/modules/zotero-word-for-windows-integration" + mkdir -p "integration/word-for-windows" + cp -RH "$pluginDir/components" \ + "$pluginDir/resource" \ + "$pluginDir/chrome.manifest" \ + "integration/word-for-windows" + echo -n "Word for Windows plugin version: " + cat "integration/word-for-windows/resource/version.txt" + echo + echo >> $prefs_file + cat "$CALLDIR/modules/zotero-word-for-windows-integration/defaults/preferences/zoteroWinWordIntegration.js" >> $prefs_file + echo >> $prefs_file +fi +# Libreoffice plugin for all platforms +pluginDir="$CALLDIR/modules/zotero-libreoffice-integration" +mkdir -p "integration/libreoffice" +cp -RH "$pluginDir/chrome" \ + "$pluginDir/components" \ + "$pluginDir/resource" \ + "$pluginDir/chrome.manifest" \ + "integration/libreoffice" +echo -n "LibreOffice plugin version: " +cat "integration/libreoffice/resource/version.txt" +echo +echo >> $prefs_file +cat "$CALLDIR/modules/zotero-libreoffice-integration/defaults/preferences/zoteroLibreOfficeIntegration.js" >> $prefs_file +echo >> $prefs_file + +# Delete files that shouldn't be distributed +find chrome -name .DS_Store -exec rm -f {} \; + +# Zip browser and Zotero files into omni.ja +if [ $quick_build -eq 1 ]; then + # If quick build, don't compress or optimize + zip -qrXD omni.ja * +else + zip -qr9XD omni.ja * + python3 "$CALLDIR/scripts/optimizejars.py" --optimize ./ ./ ./ +fi + +mv omni.ja .. +cd "$CALLDIR" +rm -rf "$omni_dir" + +# Copy updater.ini +cp "$CALLDIR/assets/updater.ini" "$base_dir" + +# Adjust chrome.manifest +#perl -pi -e 's^(chrome|resource)/^jar:zotero.jar\!/$1/^g' "$BUILD_DIR/zotero/chrome.manifest" + +# Copy icons +mkdir "$base_dir/chrome" +cp -R "$CALLDIR/assets/icons" "$base_dir/chrome/icons" + +# Copy application.ini and modify +cp "$CALLDIR/assets/application.ini" "$app_dir/application.ini" +perl -pi -e "s/\{\{VERSION}}/$VERSION/" "$app_dir/application.ini" +perl -pi -e "s/\{\{BUILDID}}/$BUILD_ID/" "$app_dir/application.ini" + +# Remove unnecessary files +find "$BUILD_DIR" -name .DS_Store -exec rm -f {} \; + +# Mac +if [ $BUILD_MAC == 1 ]; then + echo 'Building Zotero.app' + + # Set up directory structure + APPDIR="$STAGE_DIR/Zotero.app" + rm -rf "$APPDIR" + mkdir "$APPDIR" + chmod 755 "$APPDIR" + cp -r "$CALLDIR/mac/Contents" "$APPDIR" + CONTENTSDIR="$APPDIR/Contents" + + # Merge relevant assets from Firefox + mkdir "$CONTENTSDIR/MacOS" + cp -r "$MAC_RUNTIME_PATH/Contents/MacOS/"!(firefox|firefox-bin|crashreporter.app|pingsender|updater.app) "$CONTENTSDIR/MacOS" + cp -r "$MAC_RUNTIME_PATH/Contents/Resources/"!(application.ini|browser|defaults|precomplete|removed-files|updater.ini|update-settings.ini|webapprt*|*.icns|*.lproj) "$CONTENTSDIR/Resources" + + # Use our own launcher + xz -d --stdout "$CALLDIR/mac/zotero.xz" > "$CONTENTSDIR/MacOS/zotero" + chmod 755 "$CONTENTSDIR/MacOS/zotero" + + # TEMP: Modified versions of some Firefox components for Big Sur, placed in xulrunner/MacOS + #cp "$MAC_RUNTIME_PATH/../MacOS/"{libc++.1.dylib,libnss3.dylib,XUL} "$CONTENTSDIR/MacOS/" + + # Use our own updater, because Mozilla's requires updates signed by Mozilla + cd "$CONTENTSDIR/MacOS" + tar -xjf "$CALLDIR/mac/updater.tar.bz2" + + # Copy PDF tools and data + cp "$CALLDIR/pdftools/pdftotext-mac" "$CONTENTSDIR/MacOS/pdftotext" + cp "$CALLDIR/pdftools/pdfinfo-mac" "$CONTENTSDIR/MacOS/pdfinfo" + cp -R "$CALLDIR/pdftools/poppler-data" "$CONTENTSDIR/Resources/" + + # Modify Info.plist + perl -pi -e "s/\{\{VERSION\}\}/$VERSION/" "$CONTENTSDIR/Info.plist" + perl -pi -e "s/\{\{VERSION_NUMERIC\}\}/$VERSION_NUMERIC/" "$CONTENTSDIR/Info.plist" + if [ $UPDATE_CHANNEL == "beta" ] || [ $UPDATE_CHANNEL == "dev" ] || [ $UPDATE_CHANNEL == "source" ]; then + perl -pi -e "s/org\.zotero\.zotero/org.zotero.zotero-$UPDATE_CHANNEL/" "$CONTENTSDIR/Info.plist" + fi + perl -pi -e "s/\{\{VERSION\}\}/$VERSION/" "$CONTENTSDIR/Info.plist" + # Needed for "monkeypatch" Windows builds: + # http://www.nntp.perl.org/group/perl.perl5.porters/2010/08/msg162834.html + rm -f "$CONTENTSDIR/Info.plist.bak" + + echo + grep -B 1 org.zotero.zotero "$CONTENTSDIR/Info.plist" + echo + grep -A 1 CFBundleShortVersionString "$CONTENTSDIR/Info.plist" + echo + grep -A 1 CFBundleVersion "$CONTENTSDIR/Info.plist" + echo + + # Copy app files + rsync -a "$base_dir/" "$CONTENTSDIR/Resources/" + + # Add word processor plug-ins + mkdir "$CONTENTSDIR/Resources/integration" + cp -RH "$CALLDIR/modules/zotero-libreoffice-integration/install" "$CONTENTSDIR/Resources/integration/libreoffice" + cp -RH "$CALLDIR/modules/zotero-word-for-mac-integration/install" "$CONTENTSDIR/Resources/integration/word-for-mac" + + # Delete extraneous files + find "$CONTENTSDIR" -depth -type d -name .git -exec rm -rf {} \; + find "$CONTENTSDIR" \( -name .DS_Store -or -name update.rdf \) -exec rm -f {} \; + + # Copy over removed-files and make a precomplete file here since it needs to be stable for the + # signature. This is done in build_autocomplete.sh for other platforms. + cp "$CALLDIR/update-packaging/removed-files_mac" "$CONTENTSDIR/Resources/removed-files" + touch "$CONTENTSDIR/Resources/precomplete" + + # Sign + if [ $SIGN == 1 ]; then + # Unlock keychain if a password is provided (necessary for building from a shell) + if [ -n "$KEYCHAIN_PASSWORD" ]; then + security -v unlock-keychain -p "$KEYCHAIN_PASSWORD" ~/Library/Keychains/$KEYCHAIN.keychain-db + fi + # Clear extended attributes, which can cause codesign to fail + /usr/bin/xattr -cr "$APPDIR" + + # Sign app + entitlements_file="$CALLDIR/mac/entitlements.xml" + /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" \ + "$APPDIR/Contents/MacOS/pdftotext" \ + "$APPDIR/Contents/MacOS/pdfinfo" \ + "$APPDIR/Contents/MacOS/XUL" \ + "$APPDIR/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater" + find "$APPDIR/Contents" -name '*.dylib' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \; + find "$APPDIR/Contents" -name '*.app' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \; + /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" "$APPDIR/Contents/MacOS/zotero" + + # Bundle and sign Safari App Extension + # + # Even though it's signed by Xcode, we sign it again to make sure it matches the parent app signature + if [[ -n "$SAFARI_APPEX" ]] && [[ -d "$SAFARI_APPEX" ]]; then + echo + # Extract entitlements, which differ from parent app + /usr/bin/codesign -d --entitlements :"$BUILD_DIR/safari-entitlements.plist" $SAFARI_APPEX + mkdir "$APPDIR/Contents/PlugIns" + cp -R $SAFARI_APPEX "$APPDIR/Contents/PlugIns/ZoteroSafariExtension.appex" + # Add suffix to appex bundle identifier + if [ $UPDATE_CHANNEL == "beta" ] || [ $UPDATE_CHANNEL == "dev" ] || [ $UPDATE_CHANNEL == "source" ]; then + perl -pi -e "s/org\.zotero\.SafariExtensionApp\.SafariExtension/org.zotero.SafariExtensionApp.SafariExtension-$UPDATE_CHANNEL/" "$APPDIR/Contents/PlugIns/ZoteroSafariExtension.appex/Contents/Info.plist" + fi + find "$APPDIR/Contents/PlugIns/ZoteroSafariExtension.appex/Contents" -name '*.dylib' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \; + /usr/bin/codesign --force --options runtime --entitlements "$BUILD_DIR/safari-entitlements.plist" --sign "$DEVELOPER_ID" "$APPDIR/Contents/PlugIns/ZoteroSafariExtension.appex" + fi + + # Sign final app package + echo + /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" "$APPDIR" + + # Verify app + /usr/bin/codesign --verify -vvvv "$APPDIR" + # Verify Safari App Extension + if [[ -n "$SAFARI_APPEX" ]] && [[ -d "$SAFARI_APPEX" ]]; then + echo + /usr/bin/codesign --verify -vvvv "$APPDIR/Contents/PlugIns/ZoteroSafariExtension.appex" + fi + fi + + # Build and notarize disk image + if [ $PACKAGE == 1 ]; then + if [ $MAC_NATIVE == 1 ]; then + echo "Creating Mac installer" + dmg="$DIST_DIR/Zotero-$VERSION.dmg" + "$CALLDIR/mac/pkg-dmg" --source "$STAGE_DIR/Zotero.app" \ + --target "$dmg" \ + --sourcefile --volname Zotero --copy "$CALLDIR/mac/DSStore:/.DS_Store" \ + --symlink /Applications:"/Drag Here to Install" > /dev/null + + # Upload disk image to Apple + output=$("$CALLDIR/scripts/notarize_mac_app" "$dmg") + echo + echo "$output" + echo + id=$(echo "$output" | plutil -extract notarization-upload.RequestUUID xml1 -o - - | sed -n "s/.*\(.*\)<\/string>.*/\1/p") + echo "Notarization request identifier: $id" + echo + + sleep 60 + + # Check back every 30 seconds, for up to an hour + i="0" + while [ $i -lt 120 ] + do + status=$("$CALLDIR/scripts/notarization_status" $id) + if [[ $status != "in progress" ]]; then + break + fi + echo "Notarization in progress" + sleep 30 + i=$[$i+1] + done + + # Staple notarization info to disk image + if [ $status == "success" ]; then + "$CALLDIR/scripts/notarization_stapler" "$dmg" + else + echo "Notarization failed!" + "$CALLDIR/scripts/notarization_status" $id + exit 1 + fi + + echo "Notarization complete" + else + echo 'Not building on Mac; creating Mac distribution as a zip file' + rm -f "$DIST_DIR/Zotero_mac.zip" + cd "$STAGE_DIR" && zip -rqX "$DIST_DIR/Zotero-${VERSION}_mac.zip" Zotero.app + fi + fi +fi + +# Windows +if [ $BUILD_WIN == 1 ]; then + echo "Building Windows common" + + COMMON_APPDIR="$STAGE_DIR/Zotero_common" + mkdir "$COMMON_APPDIR" + + # Copy PDF tools and data + cp "$CALLDIR/pdftools/pdftotext-win.exe" "$COMMON_APPDIR/pdftotext.exe" + cp "$CALLDIR/pdftools/pdfinfo-win.exe" "$COMMON_APPDIR/pdfinfo.exe" + + # Package non-arch-specific components + if [ $PACKAGE -eq 1 ]; then + # Copy installer files + cp -r "$CALLDIR/win/installer" "$BUILD_DIR/win_installer" + + perl -pi -e "s/\{\{VERSION}}/$VERSION/" "$BUILD_DIR/win_installer/defines.nsi" + mkdir "$COMMON_APPDIR/uninstall" + + # Use our own updater, because Mozilla's requires updates signed by Mozilla + cp "$CALLDIR/win/updater.exe" "$COMMON_APPDIR" + cat "$CALLDIR/win/installer/updater_append.ini" >> "$COMMON_APPDIR/updater.ini" + + # Sign PDF tools and updater + if [ $SIGN -eq 1 ]; then + "`cygpath -u \"$SIGNTOOL\"`" \ + sign /n "$SIGNTOOL_CERT_SUBJECT" \ + /d "$SIGNATURE_DESC PDF Converter" \ + /fd SHA256 \ + /tr "$SIGNTOOL_TIMESTAMP_SERVER" \ + /td SHA256 \ + "`cygpath -w \"$COMMON_APPDIR/pdftotext.exe\"`" + sleep $SIGNTOOL_DELAY + "`cygpath -u \"$SIGNTOOL\"`" \ + sign /n "$SIGNTOOL_CERT_SUBJECT" \ + /d "$SIGNATURE_DESC PDF Info" \ + /fd SHA256 \ + /tr "$SIGNTOOL_TIMESTAMP_SERVER" \ + /td SHA256 \ + "`cygpath -w \"$COMMON_APPDIR/pdfinfo.exe\"`" + sleep $SIGNTOOL_DELAY + "`cygpath -u \"$SIGNTOOL\"`" \ + sign /n "$SIGNTOOL_CERT_SUBJECT" \ + /d "$SIGNATURE_DESC Updater" \ + /fd SHA256 \ + /tr "$SIGNTOOL_TIMESTAMP_SERVER" \ + /td SHA256 \ + "`cygpath -w \"$COMMON_APPDIR/updater.exe\"`" + fi + + # Compress 7zSD.sfx + upx --best -o "`cygpath -w \"$BUILD_DIR/7zSD.sfx\"`" \ + "`cygpath -w \"$CALLDIR/win/installer/7zstub/firefox/7zSD.sfx\"`" > /dev/null + + fi + + for arch in "win32" "win64"; do + echo "Building Zotero_$arch" + + runtime_path="${WIN_RUNTIME_PATH_PREFIX}${arch}" + + # Set up directory + APPDIR="$STAGE_DIR/Zotero_$arch" + mkdir "$APPDIR" + + # Copy relevant assets from Firefox + cp -R "$runtime_path"/!(application.ini|browser|defaults|devtools-files|crashreporter*|firefox.exe|maintenanceservice*|precomplete|removed-files|uninstall|update*) "$APPDIR" + + # Copy vcruntime140_1.dll + if [ $arch = "win64" ]; then + cp "$CALLDIR/xulrunner/vc-$arch/vcruntime140_1.dll" "$APPDIR" + fi + + # Copy zotero.exe, which is built directly from Firefox source and then modified by + # ResourceHacker to add icons + tar xf "$CALLDIR/win/zotero.exe.tar.xz" --to-stdout zotero_$arch.exe > "$APPDIR/zotero.exe" + + # Update .exe version number (only possible on Windows) + if [ $WIN_NATIVE == 1 ]; then + # FileVersion is limited to four integers, so it won't be properly updated for non-release + # builds (e.g., we'll show 5.0.97.0 for 5.0.97-beta.37). ProductVersion will be the full + # version string. + rcedit "`cygpath -w \"$APPDIR/zotero.exe\"`" \ + --set-file-version "$VERSION_NUMERIC" \ + --set-product-version "$VERSION" + fi + + # Copy app files + rsync -a "$base_dir/" "$APPDIR/" + #mv "$APPDIR/app/application.ini" "$APPDIR/" + + # Copy in common files + rsync -a "$COMMON_APPDIR/" "$APPDIR/" + + # Add devtools + #if [ $DEVTOOLS -eq 1 ]; then + # # Create devtools.jar + # cd "$BUILD_DIR" + # mkdir -p devtools/locale + # cp -r "$runtime_path"/devtools-files/chrome/devtools/* devtools/ + # cp -r "$runtime_path"/devtools-files/chrome/locale/* devtools/locale/ + # cd devtools + # zip -r -q ../devtools.jar * + # cd .. + # rm -rf devtools + # mv devtools.jar "$APPDIR" + # + # cp "$runtime_path/devtools-files/components/interfaces.xpt" "$APPDIR/components/" + #fi + + # Add word processor plug-ins + mkdir -p "$APPDIR/integration" + cp -RH "$CALLDIR/modules/zotero-libreoffice-integration/install" "$APPDIR/integration/libreoffice" + cp -RH "$CALLDIR/modules/zotero-word-for-windows-integration/install" "$APPDIR/integration/word-for-windows" + + # Copy PDF tools data + cp -R "$CALLDIR/pdftools/poppler-data" "$APPDIR/" + + # Delete extraneous files + find "$APPDIR" -depth -type d -name .git -exec rm -rf {} \; + find "$APPDIR" \( -name .DS_Store -or -name '.git*' -or -name '.travis.yml' -or -name update.rdf -or -name '*.bak' \) -exec rm -f {} \; + find "$APPDIR" \( -name '*.exe' -or -name '*.dll' \) -exec chmod 755 {} \; + + if [ $PACKAGE -eq 1 ]; then + if [ $WIN_NATIVE -eq 1 ]; then + echo "Creating Windows installer" + # Build uninstaller + if [ "$arch" = "win32" ]; then + "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /V1 "`cygpath -w \"$BUILD_DIR/win_installer/uninstaller.nsi\"`" + elif [ "$arch" = "win64" ]; then + "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /DHAVE_64BIT_OS /V1 "`cygpath -w \"$BUILD_DIR/win_installer/uninstaller.nsi\"`" + fi + + mv "$BUILD_DIR/win_installer/helper.exe" "$APPDIR/uninstall" + + if [ $SIGN -eq 1 ]; then + "`cygpath -u \"$SIGNTOOL\"`" \ + sign /n "$SIGNTOOL_CERT_SUBJECT" \ + /d "$SIGNATURE_DESC Uninstaller" \ + /fd SHA256 \ + /tr "$SIGNTOOL_TIMESTAMP_SERVER" \ + /td SHA256 \ + "`cygpath -w \"$APPDIR/uninstall/helper.exe\"`" + sleep $SIGNTOOL_DELAY + fi + + + if [ "$arch" = "win32" ]; then + INSTALLER_PATH="$DIST_DIR/Zotero-${VERSION}_win32_setup.exe" + elif [ "$arch" = "win64" ]; then + INSTALLER_PATH="$DIST_DIR/Zotero-${VERSION}_x64_setup.exe" + fi + + if [ $SIGN -eq 1 ]; then + # Sign zotero.exe + "`cygpath -u \"$SIGNTOOL\"`" \ + sign /n "$SIGNTOOL_CERT_SUBJECT" \ + /d "$SIGNATURE_DESC" \ + /du "$SIGNATURE_URL" \ + /fd SHA256 \ + /tr "$SIGNTOOL_TIMESTAMP_SERVER" \ + /td SHA256 \ + "`cygpath -w \"$APPDIR/zotero.exe\"`" + sleep $SIGNTOOL_DELAY + fi + + # Stage installer + INSTALLER_STAGE_DIR="$BUILD_DIR/win_installer/staging" + rm -rf "$INSTALLER_STAGE_DIR" + mkdir "$INSTALLER_STAGE_DIR" + cp -r "$APPDIR" "$INSTALLER_STAGE_DIR/core" + + # Build and sign setup.exe + if [ "$arch" = "win32" ]; then + "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /V1 "`cygpath -w \"$BUILD_DIR/win_installer/installer.nsi\"`" + elif [ "$arch" = "win64" ]; then + "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" /DHAVE_64BIT_OS /V1 "`cygpath -w \"$BUILD_DIR/win_installer/installer.nsi\"`" + fi + + mv "$BUILD_DIR/win_installer/setup.exe" "$INSTALLER_STAGE_DIR" + + if [ $SIGN == 1 ]; then + "`cygpath -u \"$SIGNTOOL\"`" \ + sign /n "$SIGNTOOL_CERT_SUBJECT" \ + /d "$SIGNATURE_DESC Setup" \ + /du "$SIGNATURE_URL" \ + /fd SHA256 \ + /tr "$SIGNTOOL_TIMESTAMP_SERVER" \ + /td SHA256 \ + "`cygpath -w \"$INSTALLER_STAGE_DIR/setup.exe\"`" + sleep $SIGNTOOL_DELAY + fi + + # Compress application + cd "$INSTALLER_STAGE_DIR" && 7z a -r -t7z "`cygpath -w \"$BUILD_DIR/app_$arch.7z\"`" \ + -mx -m0=BCJ2 -m1=LZMA:d24 -m2=LZMA:d19 -m3=LZMA:d19 -mb0:1 -mb0s1:2 -mb0s2:3 > /dev/null + + # Combine 7zSD.sfx and app.tag into setup.exe + cat "$BUILD_DIR/7zSD.sfx" "$CALLDIR/win/installer/app.tag" \ + "$BUILD_DIR/app_$arch.7z" > "$INSTALLER_PATH" + + # Sign installer .exe + if [ $SIGN == 1 ]; then + "`cygpath -u \"$SIGNTOOL\"`" \ + sign /n "$SIGNTOOL_CERT_SUBJECT" \ + /d "$SIGNATURE_DESC Setup" \ + /du "$SIGNATURE_URL" \ + /fd SHA256 \ + /tr "$SIGNTOOL_TIMESTAMP_SERVER" \ + /td SHA256 \ + "`cygpath -w \"$INSTALLER_PATH\"`" + fi + + chmod 755 "$INSTALLER_PATH" + else + echo 'Not building on Windows; only building zip file' + fi + cd "$STAGE_DIR" + if [ $arch = "win32" ]; then + zip -rqX "$DIST_DIR/Zotero-${VERSION}_$arch.zip" Zotero_$arch + elif [ $arch = "win64" ]; then + zip -rqX "$DIST_DIR/Zotero-${VERSION}_win-x64.zip" Zotero_$arch + fi + fi + done + + rm -rf "$COMMON_APPDIR" +fi + +# Linux +if [ $BUILD_LINUX == 1 ]; then + for arch in "i686" "x86_64"; do + runtime_path="${LINUX_RUNTIME_PATH_PREFIX}${arch}" + + # Set up directory + echo 'Building Zotero_linux-'$arch + APPDIR="$STAGE_DIR/Zotero_linux-$arch" + rm -rf "$APPDIR" + mkdir "$APPDIR" + + # Merge relevant assets from Firefox + cp -r "$runtime_path/"!(application.ini|browser|defaults|devtools-files|crashreporter|crashreporter.ini|firefox|pingsender|precomplete|removed-files|run-mozilla.sh|update-settings.ini|updater|updater.ini) "$APPDIR" + + # Use our own launcher that calls the original Firefox executable with -app + mv "$APPDIR"/firefox-bin "$APPDIR"/zotero-bin + cp "$CALLDIR/linux/zotero" "$APPDIR"/zotero + + # Copy Ubuntu launcher files + cp "$CALLDIR/linux/zotero.desktop" "$APPDIR" + cp "$CALLDIR/linux/set_launcher_icon" "$APPDIR" + + # Use our own updater, because Mozilla's requires updates signed by Mozilla + cp "$CALLDIR/linux/updater-$arch" "$APPDIR"/updater + + # Copy PDF tools and data + cp "$CALLDIR/pdftools/pdftotext-linux-$arch" "$APPDIR/pdftotext" + cp "$CALLDIR/pdftools/pdfinfo-linux-$arch" "$APPDIR/pdfinfo" + cp -R "$CALLDIR/pdftools/poppler-data" "$APPDIR/" + + # Copy app files + rsync -a "$base_dir/" "$APPDIR/" + + # Add word processor plug-ins + mkdir "$APPDIR/integration" + cp -RH "$CALLDIR/modules/zotero-libreoffice-integration/install" "$APPDIR/integration/libreoffice" + + # Delete extraneous files + find "$APPDIR" -depth -type d -name .git -exec rm -rf {} \; + find "$APPDIR" \( -name .DS_Store -or -name update.rdf \) -exec rm -f {} \; + + if [ $PACKAGE == 1 ]; then + # Create tar + rm -f "$DIST_DIR/Zotero-${VERSION}_linux-$arch.tar.bz2" + cd "$STAGE_DIR" + tar -cjf "$DIST_DIR/Zotero-${VERSION}_linux-$arch.tar.bz2" "Zotero_linux-$arch" + fi + done +fi + +rm -rf $BUILD_DIR diff --git a/app/config.sh b/app/config.sh new file mode 100644 index 0000000000..a88dfbf931 --- /dev/null +++ b/app/config.sh @@ -0,0 +1,76 @@ +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# Version of Gecko to build with +GECKO_VERSION_MAC="102.9.0esr" +GECKO_VERSION_LINUX="102.9.0esr" +GECKO_VERSION_WIN="102.9.0esr" +RUST_VERSION=1.60.0 + +# URL prefix for custom builds of Firefox components +custom_components_url="https://download.zotero.org/dev/" + +APP_NAME="Zotero" +APP_ID="zotero\@zotero.org" + +PDF_TOOLS_VERSION="0.0.5" +PDF_TOOLS_URL="https://zotero-download.s3.amazonaws.com/pdftools/pdftools-$PDF_TOOLS_VERSION.tar.gz" + +# Whether to sign builds +SIGN=0 + +# OS X Developer ID certificate information +DEVELOPER_ID=F0F1FE48DB909B263AC51C8215374D87FDC12121 +# Keychain and keychain password, if not building via the GUI +KEYCHAIN="" +KEYCHAIN_PASSWORD="" +NOTARIZATION_BUNDLE_ID="" +NOTARIZATION_USER="" +NOTARIZATION_PASSWORD="" + +# Paths for Windows installer build +NSIS_DIR='C:\Program Files (x86)\NSIS\Unicode\' + +# Paths for Windows installer build only necessary for signed binaries +SIGNTOOL='C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe' +SIGNATURE_DESC='Zotero' +SIGNATURE_URL='https://www.zotero.org/' +SIGNTOOL_CERT_SUBJECT="Corporation for Digital Scholarship" +SIGNTOOL_TIMESTAMP_SERVER="http://timestamp.sectigo.com" +SIGNTOOL_DELAY=15 + +# Directory for Zotero code repos +repo_dir=$( cd "$DIR"/.. && pwd ) +# Directory for Zotero source code +ZOTERO_SOURCE_DIR="$repo_dir"/zotero-client +# Directory for Zotero build files (needed for scripts/*_build_and_deploy) +ZOTERO_BUILD_DIR="$repo_dir"/zotero-build +# Directory for unpacked binaries +STAGE_DIR="$DIR/staging" +# Directory for packed binaries +DIST_DIR="$DIR/dist" + +SOURCE_REPO_URL="https://github.com/zotero/zotero" +S3_BUCKET="zotero-download" +S3_CI_ZIP_PATH="ci/client" +S3_DIST_PATH="client" + +DEPLOY_HOST="deploy.zotero" +DEPLOY_PATH="www/www-production/public/download/client/manifests" +DEPLOY_CMD="ssh $DEPLOY_HOST update-site-files" + +BUILD_PLATFORMS="" +NUM_INCREMENTALS=6 + +if [ "`uname`" = "Darwin" ]; then + alias mktemp='mktemp -t tmp' + shopt -s expand_aliases +fi + +# Make utilities (mar/mbsdiff) available in the path +PATH="$DIR/xulrunner/bin:$PATH" + +if [ -f "$DIR/config-custom.sh" ]; then + . "$DIR/config-custom.sh" +fi + +unset DIR diff --git a/app/fetch_mar_tools b/app/fetch_mar_tools new file mode 100755 index 0000000000..3921d6c05d --- /dev/null +++ b/app/fetch_mar_tools @@ -0,0 +1,21 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$SCRIPT_DIR" + +cd "$ROOT_DIR" + +mkdir -p "xulrunner/bin" +if [ "`uname`" = "Darwin" ]; then + # Mozilla has Linux executables where the Mac files should be, so supply our own Mac builds + curl -o "xulrunner/bin/mar" https://zotero-download.s3.us-east-1.amazonaws.com/tools/mac/60.8.0esr/mar + curl -o "xulrunner/bin/mbsdiff" https://zotero-download.s3.us-east-1.amazonaws.com/tools/mac/60.8.0esr/mbsdiff +elif [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then + curl -o "xulrunner/bin/mar.exe" https://ftp.mozilla.org/pub/firefox/nightly/2018/03/2018-03-01-10-01-39-mozilla-central/mar-tools/win64/mar.exe + curl -o "xulrunner/bin/mbsdiff.exe" https://ftp.mozilla.org/pub/firefox/nightly/2018/03/2018-03-01-10-01-39-mozilla-central/mar-tools/win64/mbsdiff.exe +else + curl -o "xulrunner/bin/mar" https://ftp.mozilla.org/pub/firefox/nightly/2018/03/2018-03-01-10-01-39-mozilla-central/mar-tools/linux64/mar + curl -o "xulrunner/bin/mbsdiff" https://ftp.mozilla.org/pub/firefox/nightly/2018/03/2018-03-01-10-01-39-mozilla-central/mar-tools/linux64/mbsdiff +fi +chmod 755 xulrunner/bin/mar xulrunner/bin/mbsdiff diff --git a/app/fetch_pdftools b/app/fetch_pdftools new file mode 100755 index 0000000000..906ecd605c --- /dev/null +++ b/app/fetch_pdftools @@ -0,0 +1,35 @@ +#!/bin/bash +set -euo pipefail + +# Copyright (c) 2018 Zotero +# Center for History and New Media +# George Mason University, Fairfax, Virginia, USA +# http://zotero.org +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +cd "$SCRIPT_DIR" +. config.sh + +rm -rf pdftools +mkdir pdftools +cd pdftools + +curl -o pdftools.tar.gz $PDF_TOOLS_URL +tar -zxvf pdftools.tar.gz +rm pdftools.tar.gz + +echo Done diff --git a/app/fetch_xulrunner.sh b/app/fetch_xulrunner.sh new file mode 100755 index 0000000000..b1e812f1c9 --- /dev/null +++ b/app/fetch_xulrunner.sh @@ -0,0 +1,398 @@ +#!/bin/bash +set -euo pipefail + +# Copyright (c) 2011 Zotero +# Center for History and New Media +# George Mason University, Fairfax, Virginia, USA +# http://zotero.org +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +CALLDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +. "$CALLDIR/config.sh" + +function usage { + cat >&2 <&1 + exit 1 + fi +} + +function remove_line { + pattern=$1 + file=$2 + + if egrep -q "$pattern" "$file"; then + egrep -v "$pattern" "$file" > "$file.tmp" + mv "$file.tmp" "$file" + else + echo "$pattern" not found in "$infile" -- aborting 2>&1 + exit 1 + fi +} + +# +# Make various modifications to the stock Firefox app +# +function modify_omni { + local platform=$1 + + mkdir omni + mv omni.ja omni + cd omni + # omni.ja is an "optimized" ZIP file, so use a script from Mozilla to avoid a warning from unzip + # here and to make it work after rezipping below + python3 "$CALLDIR/scripts/optimizejars.py" --deoptimize ./ ./ ./ + rm -f omni.ja.log + unzip omni.ja + rm omni.ja + + replace_line 'BROWSER_CHROME_URL:.+' 'BROWSER_CHROME_URL: "chrome:\/\/zotero\/content\/zoteroPane.xhtml",' modules/AppConstants.jsm + + # https://firefox-source-docs.mozilla.org/toolkit/components/telemetry/internals/preferences.html + # + # It's not clear that most of these do anything anymore when not compiled in, but just in case + replace_line 'MOZ_REQUIRE_SIGNING:' 'MOZ_REQUIRE_SIGNING: false \&\&' modules/AppConstants.jsm + replace_line 'MOZ_DATA_REPORTING:' 'MOZ_DATA_REPORTING: false \&\&' modules/AppConstants.jsm + replace_line 'MOZ_SERVICES_HEALTHREPORT:' 'MOZ_SERVICES_HEALTHREPORT: false \&\&' modules/AppConstants.jsm + replace_line 'MOZ_TELEMETRY_REPORTING:' 'MOZ_TELEMETRY_REPORTING: false \&\&' modules/AppConstants.jsm + replace_line 'MOZ_TELEMETRY_ON_BY_DEFAULT:' 'MOZ_TELEMETRY_ON_BY_DEFAULT: false \&\&' modules/AppConstants.jsm + replace_line 'MOZ_CRASHREPORTER:' 'MOZ_CRASHREPORTER: false \&\&' modules/AppConstants.jsm + replace_line 'MOZ_UPDATE_CHANNEL:.+' 'MOZ_UPDATE_CHANNEL: "none",' modules/AppConstants.jsm + replace_line '"https:\/\/[^\/]+mozilla.com.+"' '""' modules/AppConstants.jsm + + replace_line 'if \(!updateAuto\) \{' 'if (update.type == "major") { + LOG("UpdateService:_selectAndInstallUpdate - prompting because it is a major update"); + AUSTLMY.pingCheckCode(this._pingSuffix, AUSTLMY.CHK_SHOWPROMPT_PREF); + Services.obs.notifyObservers(update, "update-available", "show-prompt"); + return; + } + if (!updateAuto) {' modules/UpdateService.jsm + + replace_line 'pref\("network.captive-portal-service.enabled".+' 'pref("network.captive-portal-service.enabled", false);' greprefs.js + replace_line 'pref\("network.connectivity-service.enabled".+' 'pref("network.connectivity-service.enabled", false);' greprefs.js + replace_line 'pref\("toolkit.telemetry.server".+' 'pref("toolkit.telemetry.server", "");' greprefs.js + replace_line 'pref\("toolkit.telemetry.unified".+' 'pref("toolkit.telemetry.unified", false);' greprefs.js + + # + # # Disable transaction timeout + # perl -pi -e 's/let timeoutPromise/\/*let timeoutPromise/' modules/Sqlite.jsm + # perl -pi -e 's/return Promise.race\(\[transactionPromise, timeoutPromise\]\);/*\/return transactionPromise;/' modules/Sqlite.jsm + # rm -f jsloader/resource/gre/modules/Sqlite.jsm + # + # Disable unwanted components + remove_line '(RemoteSettings|services-|telemetry|Telemetry|URLDecorationAnnotationsService)' components/components.manifest + + # Remove unwanted files + rm modules/FxAccounts* + # Causes a startup error -- try an empty file or a shim instead? + #rm modules/Telemetry* + rm modules/URLDecorationAnnotationsService.jsm + rm -rf modules/services-* + + # Clear most WebExtension manifest properties + replace_line 'manifest = normalized.value;' 'manifest = normalized.value; + if (this.type == "extension") { + if (!manifest.applications?.zotero?.id) { + this.manifestError("applications.zotero.id not provided"); + } + if (!manifest.applications?.zotero?.update_url) { + this.manifestError("applications.zotero.update_url not provided"); + } + if (!manifest.applications?.zotero?.strict_max_version) { + this.manifestError("applications.zotero.strict_max_version not provided"); + } + manifest.browser_specific_settings = undefined; + manifest.content_scripts = []; + manifest.permissions = []; + manifest.host_permissions = []; + manifest.web_accessible_resources = undefined; + manifest.experiment_apis = {}; + }' modules/Extension.jsm + + # Use applications.zotero instead of applications.gecko + replace_line 'let bss = manifest.applications\?.gecko' 'let bss = manifest.applications?.zotero' modules/addons/XPIInstall.jsm + replace_line 'manifest.applications\?.gecko' 'manifest.applications?.zotero' modules/Extension.jsm + + # When installing addon, use app version instead of toolkit version for targetApplication + replace_line "id: TOOLKIT_ID," "id: '$APP_ID'," modules/addons/XPIInstall.jsm + + # Accept zotero@chnm.gmu.edu for target application to allow Zotero 6 plugins to remain + # installed in Zotero 7 + replace_line "if \(targetApp.id == Services.appinfo.ID\) \{" "if (targetApp.id == 'zotero\@chnm.gmu.edu') targetApp.id = '$APP_ID'; if (targetApp.id == Services.appinfo.ID) {" modules/addons/XPIDatabase.jsm + + # For updates, look for applications.zotero instead of applications.gecko in manifest.json and + # use the app id and version for strict_min_version/strict_max_version comparisons + replace_line 'gecko: \{\},' 'zotero: {},' modules/addons/AddonUpdateChecker.jsm + replace_line 'if \(!\("gecko" in applications\)\) \{' 'if (!("zotero" in applications)) {' modules/addons/AddonUpdateChecker.jsm + replace_line '"gecko not in application entry' '"zotero not in application entry' modules/addons/AddonUpdateChecker.jsm + replace_line 'let app = getProperty\(applications, "gecko", "object"\);' 'let app = getProperty(applications, "zotero", "object");' modules/addons/AddonUpdateChecker.jsm + replace_line "id: TOOLKIT_ID," "id: '$APP_ID'," modules/addons/AddonUpdateChecker.jsm + replace_line 'AddonManagerPrivate.webExtensionsMinPlatformVersion' '7.0' modules/addons/AddonUpdateChecker.jsm + replace_line 'result.targetApplications.push' 'false && result.targetApplications.push' modules/addons/AddonUpdateChecker.jsm + + # Allow addon installation by bypassing confirmation dialogs. If we want a confirmation dialog, + # we need to either add gXPInstallObserver from browser-addons.js [1][2] or provide our own with + # Ci.amIWebInstallPrompt [3]. + # + # [1] https://searchfox.org/mozilla-esr102/rev/5a6d529652045050c5cdedc0558238949b113741/browser/base/content/browser.js#1902-1923 + # [2] https://searchfox.org/mozilla-esr102/rev/5a6d529652045050c5cdedc0558238949b113741/browser/base/content/browser-addons.js#201 + # [3] https://searchfox.org/mozilla-esr102/rev/5a6d529652045050c5cdedc0558238949b113741/toolkit/mozapps/extensions/AddonManager.jsm#3114-3124 + replace_line 'if \(info.addon.userPermissions\) \{' 'if (false) {' modules/AddonManager.jsm + replace_line '\} else if \(info.addon.sitePermissions\) \{' '} else if (false) {' modules/AddonManager.jsm + replace_line '\} else if \(requireConfirm\) \{' '} else if (false) {' modules/AddonManager.jsm + + # No idea why this is necessary, but without it initialization fails with "TypeError: "constructor" is read-only" + replace_line 'LoginStore.prototype.constructor = LoginStore;' '\/\/LoginStore.prototype.constructor = LoginStore;' modules/LoginStore.jsm + # + # # Allow proxy password saving + # perl -pi -e 's/get _inPrivateBrowsing\(\) \{/get _inPrivateBrowsing() {if (true) { return false; }/' components/nsLoginManagerPrompter.js + # + # # Change text in update dialog + # perl -pi -e 's/A security and stability update for/A new version of/' chrome/en-US/locale/en-US/mozapps/update/updates.properties + # perl -pi -e 's/updateType_major=New Version/updateType_major=New Major Version/' chrome/en-US/locale/en-US/mozapps/update/updates.properties + # perl -pi -e 's/updateType_minor=Security Update/updateType_minor=New Version/' chrome/en-US/locale/en-US/mozapps/update/updates.properties + # perl -pi -e 's/update for &brandShortName; as soon as possible/update as soon as possible/' chrome/en-US/locale/en-US/mozapps/update/updates.dtd + # + # Set available locales + cp "$CALLDIR/assets/multilocale.txt" res/multilocale.txt + # + # # Force Lucida Grande on non-Retina displays, since San Francisco is used otherwise starting in + # # Catalina, and it looks terrible + # if [[ $platform == 'mac' ]]; then + # echo "* { font-family: Lucida Grande, Lucida Sans Unicode, Lucida Sans, Geneva, -apple-system, sans-serif !important; }" >> chrome/toolkit/skin/classic/global/global.css + # fi + + # Use Zotero URL opening in Mozilla dialogs (e.g., app update dialog) + replace_line 'function openURL\(aURL\) \{' 'function openURL(aURL) {let {Zotero} = ChromeUtils.import("chrome:\/\/zotero\/content\/include.jsm"); Zotero.launchURL(aURL); return;' chrome/toolkit/content/global/contentAreaUtils.js + + # + # Modify Add-ons window + # + file="chrome/toolkit/content/mozapps/extensions/aboutaddons.css" + echo >> $file + # Hide search bar, Themes and Plugins tabs, and sidebar footer + echo '.main-search, button[name="theme"], button[name="plugin"], sidebar-footer { display: none; }' >> $file + echo '.main-heading { margin-top: 2em; }' >> $file + # Hide Details/Permissions tabs in addon details so we only show details + echo 'addon-details > button-group { display: none !important; }' >> $file + # Hide "Debug Addons" and "Manage Extension Shortcuts" + echo 'panel-item[action="debug-addons"], panel-item[action="reset-update-states"] + panel-item-separator, panel-item[action="manage-shortcuts"] { display: none }' >> $file + + file="chrome/toolkit/content/mozapps/extensions/aboutaddons.js" + # Hide unsigned-addon warning + replace_line 'if \(!isCorrectlySigned\(addon\)\) \{' 'if (!isCorrectlySigned(addon)) {return {};' $file + # Hide Private Browsing setting in addon details + replace_line 'pbRow\.' '\/\/pbRow.' $file + replace_line 'let isAllowed = await isAllowedInPrivateBrowsing' '\/\/let isAllowed = await isAllowedInPrivateBrowsing' $file + # Use our own strings for the removal prompt + replace_line 'let \{ BrowserAddonUI \} = windowRoot.ownerGlobal;' '' $file + replace_line 'await BrowserAddonUI.promptRemoveExtension' 'promptRemoveExtension' $file + + # Customize empty-list message + replace_line 'createEmptyListMessage\(\) {' 'createEmptyListMessage() { + var p = document.createElement("p"); + p.id = "empty-list-message"; + return p;' $file + # Swap in include.js, which we need for Zotero.getString(), for abuse-reports.js, which we don't need + + # Hide Recommendations tab in sidebar and recommendations in main pane + replace_line 'function isDiscoverEnabled\(\) \{' 'function isDiscoverEnabled() {return false;' chrome/toolkit/content/mozapps/extensions/aboutaddonsCommon.js + replace_line 'pref\("extensions.htmlaboutaddons.recommendations.enabled".+' 'pref("extensions.htmlaboutaddons.recommendations.enabled", false);' greprefs.js + + # Hide Report option + replace_line 'pref\("extensions.abuseReport.enabled".+' 'pref("extensions.abuseReport.enabled", false);' greprefs.js + + # The first displayed Services.prompt dialog's size jumps around because sizeToContent() is called twice + # Fix by preventing the first sizeToContent() call if the icon hasn't been loaded yet + replace_line 'window.sizeToContent\(\);' 'if (ui.infoIcon.complete) window.sizeToContent();' chrome/toolkit/content/global/commonDialog.js + replace_line 'ui.infoIcon.addEventListener' 'if (!ui.infoIcon.complete) ui.infoIcon.addEventListener' chrome/toolkit/content/global/commonDialog.js + + # Use native checkbox instead of Firefox-themed version in prompt dialogs + replace_line '/dev/null + set -e + hdiutil attach -quiet Firefox.dmg + cp -a /Volumes/Firefox/Firefox.app . + hdiutil detach -quiet /Volumes/Firefox + fi + + # Download custom components + #echo + #rm -rf MacOS + #if [ -e "Firefox $GECKO_VERSION MacOS.zip" ]; then + # echo "Using Firefox $GECKO_VERSION MacOS.zip" + # unzip "Firefox $GECKO_VERSION MacOS.zip" + #else + # echo "Downloading Firefox $GECKO_VERSION MacOS.zip" + # curl -o MacOS.zip "${custom_components_url}Firefox%20$GECKO_VERSION%20MacOS.zip" + # unzip MacOS.zip + #fi + #echo + + pushd Firefox.app/Contents/Resources + modify_omni mac + popd + + if [ ! -e "Firefox $GECKO_VERSION.app.zip" ]; then + rm "Firefox.dmg" + fi + + #if [ ! -e "Firefox $GECKO_VERSION MacOS.zip" ]; then + # rm "MacOS.zip" + #fi +fi + +if [ $BUILD_WIN == 1 ]; then + GECKO_VERSION="$GECKO_VERSION_WIN" + DOWNLOAD_URL="https://ftp.mozilla.org/pub/firefox/releases/$GECKO_VERSION" + + for arch in win32 win64; do + xdir=firefox-$arch + + rm -rf $xdir + mkdir $xdir + + curl -O "$DOWNLOAD_URL/$arch/en-US/Firefox%20Setup%20$GECKO_VERSION.exe" + + 7z x Firefox%20Setup%20$GECKO_VERSION.exe -o$xdir 'core/*' + mv $xdir/core $xdir-core + rm -rf $xdir + mv $xdir-core $xdir + + pushd $xdir + modify_omni $arch + popd + + rm "Firefox%20Setup%20$GECKO_VERSION.exe" + echo + echo + done +fi + +if [ $BUILD_LINUX == 1 ]; then + GECKO_VERSION="$GECKO_VERSION_LINUX" + DOWNLOAD_URL="https://ftp.mozilla.org/pub/firefox/releases/$GECKO_VERSION" + + rm -rf firefox + + curl -O "$DOWNLOAD_URL/linux-i686/en-US/firefox-$GECKO_VERSION.tar.bz2" + rm -rf firefox-i686 + tar xvf firefox-$GECKO_VERSION.tar.bz2 + mv firefox firefox-i686 + + pushd firefox-i686 + modify_omni linux32 + popd + + rm "firefox-$GECKO_VERSION.tar.bz2" + + curl -O "$DOWNLOAD_URL/linux-x86_64/en-US/firefox-$GECKO_VERSION.tar.bz2" + rm -rf firefox-x86_64 + tar xvf firefox-$GECKO_VERSION.tar.bz2 + mv firefox firefox-x86_64 + + pushd firefox-x86_64 + modify_omni linux64 + popd + + rm "firefox-$GECKO_VERSION.tar.bz2" +fi + +echo Done diff --git a/app/linux/set_launcher_icon b/app/linux/set_launcher_icon new file mode 100755 index 0000000000..4054bbba66 --- /dev/null +++ b/app/linux/set_launcher_icon @@ -0,0 +1,13 @@ +#!/bin/bash -e + +# +# Run this to update the launcher file with the current path to the application icon +# + +APPDIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +if [ -w "$APPDIR"/zotero.desktop ]; then + sed -i -e "s@^Icon=.*@Icon=$APPDIR/chrome/icons/default/default256.png@" "$APPDIR"/zotero.desktop +else + echo "$APPDIR"/zotero.desktop is not writable + exit 1 +fi diff --git a/app/linux/updater-i686 b/app/linux/updater-i686 new file mode 100755 index 0000000000000000000000000000000000000000..60fe8db56314b4e8c5303b1c167f9c1e698a621b GIT binary patch literal 92164 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 literal 0 HcmV?d00001 diff --git a/app/linux/updater-x86_64 b/app/linux/updater-x86_64 new file mode 100755 index 0000000000000000000000000000000000000000..862b2cb286e0537636c67ee0630806edcf3e3936 GIT binary patch literal 93904 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%0A4lXL$P|Gi>!E|z z7-D))5z9HXl@rm6CBHr@J&w3s#_t0n=IdKr@cON0ThrNlg0Ri z#hVw)t1FJc3u;y^hK#jY@3;jrwvmer11+E6gyt3T9)Ve zaO%gxQ@9~*--*WE%Q=y}JU8*08b=}*p`?d3c7{R6a$8NDqvpf3fp2mKs^_7!8q#;> z@2i^;#-67g&UHoJ-s9{6Ba`GJP;d8@mZbh{U3odx3jQ*i_=_2t9Du#kWKB0Ul)E^E zX~rCTL_(Qkjde$0N0GxDnaQkgx=zpTU2zAw)7l(9!ne@5(1u38zutxv$CaSfU!(6C zzRU%NW6*;9tt7!A=441~SvFq-tF4?OwEwGDNVu@e$rL#jgvUU!M=}0+8CGXFw zi|N?-k=^&WB=_9YET1zfSh0nUXvxp@lmmuZoD}lH{!4zAer`j{ zuE5I~z1FL8H$}DZTH}g9?g>;PL}(A)Cv!#D@9}<(*nX^}N%6j|=A90yNuzA6OSPZ` z&GxUk(J+k4$Y=U?_{T4nd3qLgvVHN1=(a8Ookeku)OQwiw(qVA7r}C2r|Cq-+vOqz zriKnNQy0gb500K6XDvA@xpve|2y^uGGYh&hK$~qCwhdQWMSxW~#3Kd)J1XK9$p;x( zx45{z>Xw=(#KZK8U-TJTxn!qY7%+&fA~#3E(WlH+$8~fS*nM|N0ZJpw#-4>M`Gb1|S98r;dgPn9nCH@*?^Vo>WucyN#5U(joR3)Pvy=D=YQ`x8P=x?=CC1t`R#O&&bp-v?D#k` zJM4d~K}K@QlCMc-$41#BvO6*e*(=EGuw%YeTjA5Ucsu_i{wnT>rQ*)2do)p^$lCEy z0R z#Qt8sfWuWf3xKK{@z?BwTk=KO1}R|QKy^~ z^?;M29@vcfca{7VzgH%Mo5lTGC4c2fQKy|0_0U$-zghB*-fIXEw>2uMHHz=bwv0ZdHHs@sTT%^djk=;Wim#Nm40vU0R9b7) z(AFqNYgA@yl(RMJ>ei_2)~J!KQ8}$qqg$hLTcgIcMvZTcy1q4PVr$go)~Km1QI27> zLsenAK2}FHo@ae3CQ}A)b+u+KT@h6ma|(w57Jg*s=0xTK8~Uof7HSSHe4*?-DOqD< zyv&z`F8`^30pa%%oW5qzZp=FT=|<)Nedjx&8S2Yj&j~iJZBv9?Efsj)e-{3Z)B=XJ zN1VPhE`&_o)aLZ{_b(`C%IaN)@K1MPh|93Qc(06X^(;YF-NrLz_$w38S#?`GN;BtQ zlMjm5diDdca&dJ-8_dH`mRE_Io zv)FEO$MOI};kuM)wtd?dZym50U+x7Fudu*Q&ku2KIs-b86LId>?7mD_^1E~?w#5t1 zOEb2ZyThC24CP)J$MZ1g`7zFYm;xTkEhDnxPcdeBeu{H{+4!dn@5jmSvR6EEXkBD4 zW6Q@n((S0y4ULSrPH=0fMD<4Fw&2W+Okkb=7n@9Axloh0r&%n>6|C&T{;ZUBMz+eT z15M0XX84L++1_vb|0E*s(QV9>sF}=rcx@c05)V#y)`CMLWRCfB>n4wsoIUl01@AP^ zU6Dj|h<#Iuss06T2AS##Q#F4MGBp{dV2B;r@H8HtL~xWk^ISGq;LMIX;&Df!6w|g2 z23MrZcK|vFYva_dlIlZhWCB5a$(^F<)=gEtmAdR&@Sn!`XJi5`Nb<7(mF6UiI3Z%@ zjY%Z`V|dFcnD|9cu}#dTHAZB`l%CC6I}5!EW=CZF^r~QX?#fd#mMvoBrv_5VkMN5U z+I?$f(g=M_5V6=(-?Y{}%ff-ZE+e__>OksVCy69jN9?d}`kT}lRrjKw+a}6<8*7fr zW*CwGu{+w!L8qghADGb@RhKxOy$Dl?###KXsCGKd&U9okqOP}ei)ZI{XWfMQ(^CXu z_vNmYjoeZGdhQ&BG<$kDv~AP*?=xv4+ozGMP*pq~+ozde(lDphURr-LX`mrWXOrD!jnf0#6U*{nSpk4eMbB<;~mF=@_hpJtFrlh8iRStiXn z?bCeooX-1s?bEz&(s0Radptj4(%9OkS!U8))ILqVNt4(<%~d8%_x5SdHEB4U&>qj< zZPR(bw0)WbCQa}5Y5r-_^lhKUXVN6KPcz-5>EAw0x=EALK22AXW%MT=8E=do-}C&w@%WVcUKX3~sopJup8lhZ!UB__@2_Guzan%wqj{i)=*4;2RR43& z(Lr06e)nw)v*7PFL9^gCR=6;|xUx#jf*T9De1Ab=KZ{j9q-EK5mSNTS-yo%J75b%K zUSwY&+4DamF9Y?x;T+ck4#WiqHy6fi4oW5(=G%!48d1P1($H5~0 z6&6UJ8*pM#MK}X#ctr%#_*P(qXKtd!y*-fDqj8J9(;Eb})~U4MYfkG3an6 zxd;r6Q@7FubFfXaW9C4XNJZk-s(&c-@6JmtHvb>b%LTtPFG^ivEN)aME-*Z9Ls)}s z9_aLf6pSlbsY)-cDu$3=_&4Qt9Ph~Ho6ys&Yj!tA`_ju((@PedXUR$opO8}((l;~f*%xZd+ixZ7jk80;$Cs=#Z;)pGZNz$Igyjz?7-Km902FkN@6c!Ul2Rc0JL zRUAo;7ZQg^(D?kOjWzZ2d}CaxW9F)K7g!r_*RK-%=KT|l&GcNEXKXl@UEBYYtL1Xo z-sr1MTnv@9>T~`hZoai>t@;2r`|PYM4k_e*uGzL$y@H$5aO&*GcHDM#9|_-R<4lM` zKBAD{b7jW8xXcqFtkrWOI6<8dRr&yVoF>UT|*{K;sT+o;YG zijW=ba-V1vdvX#*6tbJ17wN;~h4Ux+-chzAEju7eo>@knX@N%<@+8x^<_k;UX$RW!hpL31< zX^BF5AhtIq*n93!!+nR0gDFjQ5s3elDYEy3eI7Dj6vaI(uJFb|%&#db|3ZA1ZdYF5 zFGhW+mZK3@!@cA{?vJXSC=J3Of3Bi*ohwX{;ZuHq$k??jt_G=ABC$?B&w6-b3%yKLOQ~Ls7B^IJh~y;dIT|mdTO@ z_bm-0;X}xpXm+702_raY%IbqIJpbd;zwbyK$PT$#m^~~ar*kX_)^F(vNt-0 zVC*~F@28EHIf@vI>tcm6rmVd0CkOnulCbCo%A7RtZGZlb7M9LvY=rIRde(TcXNx+$TG;S#IoER^3^^r_! zg$B*a-;NzAw<55KF1zkLW}_S9BXXBS_KIKPs2d#!+n?c$_YiSLUA#q7|F69+Elgje z5LWLD+f9HtU+%IKb-Aa7_sXsQ$;$)19eM}!A5BoZWYzUG`fj&%aKP7nvwc?2iD>K6 zZ+NX=mMG_fl&eS3)jQ})3c6B)u7N?<;Giol=yC*I&Y&wh=*kJYa)Yk%LD$5fYiiI{ z5OmE5x=Mns@}SG5UC#PtbDNxto18V;>F}+VTseFm$)?92?eJ|8Avk2`*P>Nc-)eI zaZkl90uc8M>$2nA|0NfAba;pP?%+3nv1a7poo{%e=lfF@#{1H3o`xvz@WccD!9!h{ z4KEYOG!v`7QZI3w#`Nsqx}ejzLk7xDUwb*T84$9dNv?um#y*G{+jt*oFv4szjq6Ec zdT1JTe>{ztcG8$Z8WEvs^!(##uxZiE$AuyXLsnmKh8~Z)%-1=1H#^H)*`whv=Y;qlXijSwA8bP^ZZOJB7<9w}rN~uR+Z*gT0 zIjt)PxamYa+U+jTvIR3juuvlpxIf*C+flYR-a{A}fb3rfN-q@@7_~LUq zwoDG`TMI^7 zvb58dzS=40VJdoKSW{*HgK3eUxOURGjx_#zPDp;a#m{W*n6*&%y?5H{Rbd+K zL6!X>L6SKcwr`W#yM`ps_=8C<`{PNT`3IAX|KmwgzyFY6?^O-M9}+CgN|K!VIh&#k z?5R&52*#p1F3*v$n)LXP0!%&Wbk<7&-c13bv1ZoJ7o8b1unmPt9~hF@D-^)VY0KS` z*xyKuDtMBKP5I-A(KeciCAOC{<^j?N&dY503Ox>1heq{sGNraoGPt^UjOv^`JEK$g zT36mhEE&m6M@7*$>Y}_z6=hcbTYN;yEJ?d3V6CY-eE}WsqVz^qn04D;c+y-LU8>xr z7qLJZ1?*;hi5};EIo(yicx!|tV{t9aNIvfHa#bR8YEjqp~y7 zmt0#{%upk_xw-{Q-YyKviz@+x4+mTF0y}G}I@iLr*T4kxbin5k66TSrE`vR;D#l`P zksp~0QmtV4!tM@k+we3*AZz=9qjt}S%s_A}6ILzfpqL?;o!Ri6j0sJdf2CedrsUU3 zKL1RrUCmTu7fLC68my{-&1-10tyOhIj@&7V5Xmk&=@kDaDgKpDk=ebwN!KRnwko}f z^v0ZEuFh3yM2R(Llpa=|a1z&IgzR|vXmC#x@y|lbGM*JJkwQl0tpt^3X*F9@1Xk^Le^68N3guT*nIJwu2cBmEM5n3_Da)8(z*dtQ0&;Jo0&20yA=yQ6f8UoYvY3a9Q4W zvb^uI5A6<^X1S{NbO~fn-Q%!kbA9sbT*&sl+)B_{zBRPR{+tamLc10na2CHMi+y6) zxSZ7H9?s%`Yyy+WE-oMaE| z67$RHC{9=HyS&V;cSJaZR$tf(lkU%oHXpM#CVRhg)a>c`R!=@C#C^%k(ESisQ#+`Z z@q_y#yZ4qCQE!hwPHtKpatx#kG1Qe?9d%A?rEFk?~ZtOD2P9 zF&(KNEa>We$v4xcmJitRRkM$V;=t#Qnhy>f3A}jW3n9w98{SW@_S`ATypD^f;;k!} z5L$|2Jl7uD2lc+iy28UO6kkn(n{Ea-SUy~aHU`rt?DJqf=9Y7rCg}8L<5NM!AAHiB z+$)^iA?eRh_x`26XRW$W()auvW?go(Ou;)6%aO6b6qJLjDL!|{h@zJ}!kE`+Ou)(P z2JaGv-G8I489R|?3RgmxQ;H6Ydj@rb2@{zqLAwWA>+0ylq-qV8^6XFK?177rA~s8q z@HwHS_&W=bdds8>1&-`kB0uSp{7E|6ld}FpOY$i~hnD2RQlk_v`CX;BC0L5HPnwIS zQk?2NYVQ?)3-{~|38U1k%P!JPsp3_oT73mAlQZ8_i@YfqRdy*-08%lno7O~#i9tWb z*<(uB<6tIJCMLL^qb`0aS)spcoWQK6z(o1H_grh8>}YlRo*YkNltBt#2XKbHR^(Nm zcL+xbQY?$!Y`B|QdQD$z(95(!kp7@IMtu#!AV1hp-b6kLa(ms_faeD*U)@~xlnC@m z;lFNhfA0^=*PJe_*W@Oi)tFxwpTw=(4z?&}=kMpj;-SlHJB#nonp#E0-0LqR^7n&Q zub`DT0e+?(;@o)~VRQmRYt|@QR>J12V;^L|bL6L<^^Iq62a|WF$;2AfzIp3YzjJ@e z(ekrs_iCyXt|5{F@$U6}Xx+iJ;Bw=+PqGlk&GOg;D(0GOvT$zQO%%`m?EKd=HQJ$h z_x_Oj^&;+R-y7KN-MCr;bHN9Pr{QnvE*w?p;2m0`zWY5l8-B1^^176LWJr+WSSD1J*{q{`wNvfA`$48ghi^%>Q26 z@=Tp)M~#tb_gl2)bva?)wbHW7m4-tCBvwvCvx}O$#x8nMMgztWr>K+zgrWp&7xK9KQ7&34{7PGqfn3P-)iN$)Q| z)<|+W46r658$^gu{(soHT0gcVvF3 z-nbubH@C&rd&;FD;YYhKI|9^o2(Rbcu!4rfTrP!>q^6Dhl~>UOVGP+AV9};ot1gFJ zGbG%KsAToW_|%Osq?OTIzfbIRnmx8Bb7T8K4%^G!2M>m^4!b&rD;hcpgj%Lr`Rr)e zTRXmwTYi@3!()xH<_jD0sr{W^A}2L83Mt0hIb>t`MEMAap*cjvwzsJ>V|gS*tl zs1{c<;o)rifiGz~IAV3R-Ser{zT?w4d#AV9+|E`?qt@{CWx2Rt$HkqPW@IT{hStSA zD}|$?`NH~CY>}7i;yxjkPl)9;`|)}<*C-Z*|9v}7#4Ycl`8QrTN-z9lY@Mj-;uti4 zpnKWk`K(5H=W}f5Nh#ENk3(yKYf*i=Ox!RikU>90?C(MF{+l<5J*tv{J8yd0zN3u4 zS!E05@4!(=q!EzT^20dx!rf>@EtW_p#^r;3XM9>{lgI@lBlQIKqpaC!-LyY>C$~B_ z<^&UrQ3 zmL_@e0RxdG3AwVGOD;$zIrZ*TGnYG#GHyi%|1D@o25_9#cy_a(3`a=>*%+B=uu6HQ zM_o#+YL1}AickeJx*xNzC1{rXN4=a(YZhD)>eWsf8Kki!G>!RxJdNJ%q%n{*&JRuF ztUsPcpLWv7Aq}|`DJZKa)yp4}Ro`~fSVbCRL(>@bN7L|>po#LM^!ovH=^OLp;@8Hs zrwS7?=GiZbeo|dqaGpHr4<+%8<%t;#9k*;#Owi=nA(Blp=K5egd zrR7mhvM+gue7BxrD9i3Q(RC?6cj?5XLY$Y8YNi zQ*W)3E521>+juz*0@;e_y2j~COISW8rY6p(>>4f`{He&s7d^O8oezRuHay04A12% zH$|Lhj&6+!xMPI zKhdz{{e|}}_-B?(cF8ecX7fjq14=uA>%pu~rHu0K+t)z&$k@7=zY@Z*iu`u^em=d5 zJ#@@LKdCp_5u8is;C+nnUOGv5=Nn+Ym?xI}AZ$CV8SKm(ejYp;ypIh>t(C0d{X>KI z)0%kSX;0os+I-gF9pQaUTEqVs?7}+=A-p4XF_ze+^p|elJWS-Cl^TT2O@+T$=^WO({_)@kl`Cc>6b)hg{3G?Y9_y|+*d_o7o zrz7~W@W)2NFzcEf$ve@>#_&uxWGrlsjZ~8Q)Rgp#!k^-H&CX;o1i8$ToyAI!{!`$It!Y?A zsO$Yw-dcDcwky2m49%O+MxmPw`NaA(O;Enw(t*@zHbn!JHQI0{?Q5{6_h2y7UQItO z|NlWve~K2zy7B@38#R4+vzk7fny%DL*Yv~d|8PxLl@`TI{lL&5Reh{g;k1+tXZVoG zOIqEJwOLg~&nJ`muhdeCJsf4%WqzPpeU*wPRhDS1RVzq=G+)d>QK@2R>H;IpwyK!l zf8Xz`T~axW8fIj$)7O$$UDd2rXOo1o&mE~RQa#es)K}>^I!<#$%i~`{GLkt(!#J~f zQxvQrqTAl|I8mgKyoOd8rTNqv_FwlQPBpGM5~A7h!yMit`}{_;5ZO`d;sHOcn>n6Q zU+XdYp$BQgsIAgZE}Ew&8Xi*goHL?oriG1fho#8!XXZRw0 ziIg(!#QgKJ>rVafS{vWc`7}_^_a^UM5>S1J;|K5j^Q6t?!woDZ&?cyUB=EXD^(*gu z8ne^TM^8XH5q1&3O+(D>qo$S|Z_-S@t;0uf-mx>-T1w+F#!R%stfoXG?`fWBx{+vF zIQzS$`b(n6RHAnhv61NZjAX9C+r*yJ7ezJEk|j;5ndyt?Ba-|0^tVcMxS8nrC&mSH zdft7_6P;irI-VJq+s#D3QHl025>4ZPh$H!+l$IlPH=0?Q)^I9be9g_9!G|UgtmF`} zUZlF`AwHGZ!N6|55pt{UnjK$zE6*cVUu8nw+(_>hmC|b*<)GsrfqF;s>m(5H)JJ;f z#|`zxEaCf1l8fWs`DtGAagk4TKuIcUuC*NMOQ|+`AkHcn{SW;bjKVny(N#^!>Zt-Tp1vCZnVMb57-Gap4!|GB_p)bnterv7jj5%cI97=z? z_a}}zUB<_xvgEIBV6rl1@jCOW3^!y(b8U z4L4ANB)>%{YL5uY2bqsH;GOKd>+PNVXj! zP6xG;E+|ou4@}DMDSsU) zF*`)!G9klH9_T{;g2d>;8E1*0`4u`Tu}&!0cydG<76&XrjLD9eTjXT2(LE(I<$;uD0D$+)?bcjzy&&;~lX2o+8R=*D{MhdOIm>(8x#Q=EEbm+X#*2(hoR|Er zwQCyT_#hSA#=f)%;txALyTY8QjTKB;a~rVJSCSZ)%^GxqeDTsI2ikgMbCQcMXFor1 zm$mC+VbI8rnh0*-^W5^m0q-xy>xJC|fmNaY_w)<|sOBG!*%FnL$LhpqB+(%q<~gDg zaK&4@I*8B1=MH7RoZ#GFkyI3?k&0Fcwg0NVBmicYq-^}cu#=LK`(KuF`G7wSOzqXj zV(Z<>GH05lyrR%DVyGi4Gc!5K(yg*@acQxD^3v&+g2IwQSK*Yx*@dMp9m{oT7EA5W zifO$pg{775ioz-7c@_9hDJZVE!d8@5TvAwIbCuchD+=>mg*LE-`L42xc~{uFRra)Mr{={!Djy^LVC^l)Iv`SYmXS z=1nUp6h_L*3rkzF(K6D$eaUdYZk4|$KFwi^jJ1prk>t%PoMPmoNh%1XKxNKW>B@7t zD{aN4MPl~*yn z&?Vdi)sXiov-3)d3s7R$j8Ls9Km9WxAG?JhWELxCXR_e+tF120Kx9=s2 z-l!AQf=VhJoEYy$NfeY7R+e7kvZ;bq)R|c$v&J}WIriLir=*rMIwQwEI-?0ejc}J2 zkgL+^{kj$OCH4Fn79Gm&a7dVp@fqo3b2DuE)r>;FYTD5mBSwwOaAb`pL_bTDEK194 zC1s`43o8t!DhJsrXBL;2lbofrth7&2o-40JN~)~FP&*M)FtlW$UvFE>YG*RkJWZ3Y z=Gah`McIN;w_i0?iMLT3gF%&G^YZfxD=T$V2!_Us7O$BwGPANXLgi;LW@4q$u;u5K zN+CDZIh^@d^(!~Y)D%ISC zbQ4Mdt?EW=z0zHs1aH+!sp4w4Id3PV>XoF8QlY8)=(x&|s8CaH_q#*SsVEj1{;trf z6Ef5OT_GfPI#bPVyFo%b;HGZFv;;!>m}V8`SEU^qr7EmqL-F&P>Z`#{%a$O!EU#cp znY$vtFjLtQO$LD!m91ru*E~-x1Gl8MRTke=NVRIJh_j@1q#-NE+Q9(Q{+5;zna!D@ zyDg&?CRzn)NrYvU|7%Gb-od6h*uFOjz_5ryio>k#O?uayZ{3zznxfEUDjjU=z+)@( zri%$Cod>Nu#g;##4@Hi#gX~L6lsm7yykuSO>? zH@cCp#SlJSUq*WFsL|I+@n(%2lWWh;w&!Mz8fk0hbM2_n!?Q*XYmOW_YD&h4DWfw8 zG&*;P%4W8G?8tOyhGR;)Gb`IMB-wIpUWGKeSJ?7rh?I>CHJ8W`OW~|?*F0NZzOwO3 zusqpM01iRU!&-os&TUzsjOxU5@BcpW{jF7#J6RPBg^LW#%7%-F^F7D zzNE^A#A-&Uxo+XBRkVpu6{{XtNiSmrvy2wei!gLFEtv^c^S-n4DuR`s09vG=4Ku}J zRMy#-wZv5ROEUfXH~Bfr#;UfOTzZepC-y*(>2$;@d;hqBgisvJ6@-BFB3ynM%S!|swr?Shya*y3& zSvwTSyur4iV`x@Nr&n5Xi(Ms!mMliU79oRp5?^M|v&^wvdg-OMV2dVi(Uy$SqeqRV zc?*t2RSzbO5M2s2wPFetKR?f5PHUpZ*dr0z~xeQJCMSe^Sx_ zOLX+Kn~KZ(_bVx$rW{uwZOkIcwP6jGx@S$pOk#)~ojU{bmcKlvdZvqRHxJ4{va)Y< zPDx=N!$53}vI>`s2Bj%xDuJnu8!8KB4k1l~^)0KI-q&W!D#C6j${F-Sg%n@(oEda= z^UB<|IfWI4Hg}~|_sTLNKs~2d%Sf}5$rFQTTOK?`OLtmUij;b*@Rc)^ zaPmqjWr|5Lqf!#qVM*HYJhy8`Sw)Y^p3!v3t{K?fIuRJt*_f3#6S`7cVG%{E^3o!% zLD8<_S%oFoE@Fq|Q&2LmD2W(^%;w1Kq??v&o(<8c*~b~h(`OV`MBfOu7_+CctjL96 z3Q0D1MqcU6N*q_aONvQ%jFMPyTk_?$%))6E?mYT7%I)&L(b1M@X^ZT(N{sqqii@@Z zR;QIQ3)glLCMPBR$tEpUbOr+f?5EQFLR+PK`gE#qrIG(UTCrKPm}WD^@`$ClFKkK3 zXiCXlT2TmFGIcqN&JSJ~8I~c+3JS2IAee_j6@p@^EUb_!6n%rtLm6dEN;3UgR$196 ze@3Bn%ajCF*j-{6Ml;;gnHp0{Cx%kAPDq-l%6@93#{g7>O}WzRRoZ&EF)y*JFkMRK z^;Eim5iDIpv@}d&Y@tsTCdZZYDqV%MkYARWcf~ z^QJSQ)jPTz-ixPEoCvCzxh$bkiX-zX)Cwl&uvTqzikTdhuzhCFwiT7+O()Gu4TUe% zbt`lhg&1f=3Ym@}bN!I3DJ~ff78ey!9ZFr%Hd}caxmD=|c`Pe6RDM?8JVL2?JJOp8 zgGM2lSw_7mvOJCMqomWM@mWS#Y8H)X;VkhTIDiCu%$YN%FEJU2zNFd{{j^gV$eSp? zNLUZ>rM{ylG|7dw9>a373wrh?hG1+qiGw*pgRNO^Dl%FmL-(?ZGWT>uN-b2?zrr>& zYt)!Zm0wzdKB%OGHA-IcSyYS)h{eSmzgAx1M?$G)kJ-dF!R57V{TIVG16=l@5S++iXlr~A#Hkv<}DK4R3qJ<2uBovpp&34V0WrQ*^+Kr_JnZOt#Y$pwbeQLurrr`^0>7&y_&}xEZ zNJuW=O!`adz7=4pnd4 z1fuNQ7w4qjs_1xC;d*pS>6={Cts8cxAruS?f0tdEjyZ{jI8`cS$ZO1;3QiKoq@ znq7g>s%E-XLY7Ka*<_JSV(D$Oz$)t=g{9MFx<80%Dl%#&y-}NjL8WaL`6t|8VVmJD zD(W@M#XjN+SFeha0*h_FDOUsDY!HXW1#@cspddur_?Nq7Udt>O%c$X&F&Wp4%@~=U zF-4hG%yo>mkI?QB%vl&%reo}_oKr^Fhh?Q(vY6Wt%ic0}WXAX$rbw96$QYGr88tR{ z=-AB6DVbxlvn}bPMrLLW(}Y)DbrmCueoqDht9icTnXoYssN{m&|L~-9yW>B2IzJT% zl<}O!y@1PkeEIuQ6T&u|uxH}iDc5(qrbGi+-haQ?Hz$J1e3AaL4qfxt?huXslB zm5uj!&VD`+xQ}PXi-Ew`Ja#Uzyq~AjYk|Nlo_#!5ap&p3c)INk1lIAurtImlMDlR3 z*3yG#9#09#43K--C30hTizT2W2a9DB^y?x6 zfkU{XVgi8&xv$}2YalR{+ddMzkOo^juVGhP67Yf31A)1~4Zu~v#qoi_i@^OrKXBC< zfj}HPP#^;QpB)IKaXRfK;CNt$zyx3pFbOyn=mZu5rvhIGt^;=HN<6?#z!ShPfC=oax7Y%KfxtLm4)7viIdBoM z1{irE`3H^z`hkB3Mo~83vGkt<%w&7SD&S(^24FAN?T-LI0mf0VP8RNyfOi3NfG+{d zf#+R9IAAGogZKmYia+oeFsTRpvBRhWm;<~8I0M+DC;0)618xRB43t|EHUpzLrF-UCP89^hYxkPiC%N(Siw_XAe}4*?$pz7O0E{0MjmcocXH_!&^{-U`n| z9>BAJ1A#VR4zN3L1~3I!0~`u`5SRme5jYv>2QCI$xMJx&U;=P<7U6(Lfa`#M;09pz z)uao&2N-u2^$6GlIDR4m01hjD?^7_%p8+beL9^lzyi4W+y zmh#{Vsw3mcKXAl#@Cp1Ya4)bCm~f88((`)q2do0t0I!>XKky@<2tIlvRZ_Nd)seD4!}1S!XL19G4Xb#+<m9|rCPJ_qyzU#}wnHjCwZU=DE7{m=t%co05-Pd$V_T!_9sj6d*<$A|}*4BQLc z06YOa{h!2h5qtv21G{b@U%fr}~B6G};n2H!kelm{X!wh0$h%MWo!d{!5^ow$>6Gml>OIwYBq{ zsKu76&KY#+Wr=V=-QscZoYy%J=tDTm(Ac=z@L{nD)e-hsn^?`O&>8<)2|308kJ2~nHTD89E6 zPxn&;0h-X@F9p{dJPF`m7p&sP9^@xGc0*+N=2%;LGp>xh%2o6m2sc{7!LuhkJV&#w z(mW8;R!MrCw% zNXbM=zF&cEJan^#j(pdJXT&DdMnGIGa`lK@!zU_fB9IIvO)0;~aOxQ0o|ACoyE;5u z@-;ekLsO4dAKDir)zo(qNpgfd4o6FMvk=k!G#vq0axX z*dtjHhr(lfq{rHjKudj!iLhAmu|eosgFoRT5&SstVgi^y!4C%S1b>5x1PVSE{NLJ$ zrv&_pHt<#8Z)pR62l&}-;5UN5p$+^i;3v0%{|NkO@R(-7pYZt;_%!fzxxt^{<0EN9 z+Q9b)pVS6kwzc##U5vR(egn)8*SManw`Mm!I&@z<-1IH`N!Ssg6|f4vXC$7QU)^ z#6rtY;vXz_FX8_r2o=BEY%Y}lMEqaFA5%m7X9xX7&I|D0j(@29CEhjQH~&hwjrc!| z|0Id`>e#sOt9AVc|0VdPf>-&W9S+t14C;T0s{b^9hV~~yDtC$x#^yHLy+ zzCy3c;ksz)F-Jlq{QZRgTKva|zlsk|sw3zeJdq22g})R!f`1W?p;7QBd}o7yumxV^ zRRI1j@H2#3=^N>I#2yHrthh#O622C?_n`}I4+Os+{J|D@$=_D+uYtb^w~@c8X7-hy z9L9ey{yl>J<5d2KLnYyV!v9b^{)6#955wvR{z~3Wd=HCFT8MNEeI3@h1UEJac^HE& zA|)wWAo-q1_{?*4JJl3k@_mgWOplF{a;<`H0dxV}hJ0wAq&{MQd=ZRMJdJi{BlOwl z1p*@k(Nu0q4=O{;E!3^z37U_Jzn_R_H1T*Po+kc?Cwz(745<2#L9h|JBx#QnU68+s z^TSL^iA4ARLVtchZk7uEvT>Dwe;E9!LAy!Wg-v!7_E~jDhuDQ!Dq-Ot#SWy!#ByuH zE)>4xO0((ADf~-PQG8u1a?6U{5EWkAoGoRyeFl94^j#vMM{X;{K5S*T>GY3vi8vb3 zzTqbM85~1?n0r_f%n$aKwsVyosPd!i+!3*~*b^}XLA9A72l3Ss-{Fe`fgg2zZI25^ zN>uN(*MCTTd4qUXb<_PW@A6CG`3(Gc4wd~KyQihz(A7sp{3SwJ5Qs9UC{j-nspzAL zk0Gp*vnPCfu%1bJ4*auCf1%;mn`a{Uk>E=Nq4cz={R_`)u8_i?+-kQR`Wj8I`@JUn zbtwJ!Y}0-xLb#N0&lBz)!WA?Rr|cLyS;Ouh**u)o@1F?Qu{(2-L3?>zb9(`y#6_Il zroAlrle-){F&9)TlXSDe9|q4yLP=l$1n&Sp7re4ZH9i|S5&W~@Z`1mv z+nem*II*dHaKx5Jl!yODd-o{ub-XOJAEo{DL|lVGiS?rm)eyc8L!Sn{sGIo{z5f<` z68O6WNi}NK&L}$-Q?QMB2a$6MbBZen-(Gu=i+>INs+=SZe$pS7fL{pyVL{Nycre^) z=I;!(o1|W?fzFZ=2<*~y)!}xdKRgx|zOhArDEWCF`Zdrm*X?GV%%_Cf{lggcM9jus zrYRvRqvepujdoG)R(}8TK;UnJXlkc0T0P8H++z!$+j_o4@-vulY0Rx&A>ma2!xWL4 z54k~cN%yY$odW1aLw7{CyDMdWLH9cuGGCzdK=(WMghxC^K=wjt>% ze#um|%)@vh%akz^Y`#_cA3^^O^b3P}*lxcodN}^q^icFVg}LAhnG>E6j8FBWYJNxM z2j+wQ_|%9b;%l$lQ~gpE@%6rvenOXDZTN^_ezK(KhKIFk7ex;8QM0L6v92R>Q1Vyp zFLqO0_~;h(LCWhh=LX7y9^MOB1fH59u? z($hb(Vz~o+Wx5`3YrK@>M)3atpDQ?3?&ymrB0MdmA(8Nhp*sLwjL_+y;J*c54?eVg z5_}A62G4@WObq^{923EB06$suJyY7Ph-<^O;Kkp8{}&moPf94o&lur{#)du-Q~~~H zux4Rn+-c~OvJ;!^-lqD3?w%F#W5+gCionFhvyu2dW)0&{*e@aa*%V(>dvbN`s%{Yn zW1`zKWHUO?Y(E|0`#jb}HeSb#0=isRO1m0rFE{mH!8_a6z!$ zz#eSX4k~+jXlz0#A$2OCh)i$vCbW=+!LObNp;g=aAMIp7xwqA7jKJ$!n5>5E)lgxf~A z;X%35d+TvSi~d05a1nBCuRBn3eV+K9p3J&{(RZu^x8rG69;UqN1Q9$VHG#;Ad~9`{$_|9AZ7iX8P%UVx3ow2?^Ky*~rSFR-|(!a!mxDLFk*Qz~N z_9yc`;gza&KyO8^gQ431UB1q5omkPj)P~N_VRBB0jT5_3 z{O{o32l&5_Tly91&0*c`sCvH@|GVp$XT1>rCOv7<52*I^YMC?`dSUwl5&e!~L21L| zfxzuCzZsv{iHl;|5<5ZVC;Bjv_-0N#Oq^ z5R|~^foaMe&_C0o<-3W`zQnGaqcohX;SCzPG+dMm-geD&*T$`Du zoDXW4nPa>=#u@OLu?8&BP!WgxTdu=x*6>Unz9iQO7pvinF~)mHP~|Mr;rwR$qYS#^ zqYYT9;V;)1?K#+v_;JIM{4m|r&m0>> z>i4PPY072J9UqA|-dXZizr7ue_h|k8jdqx0euh%&7i#+pLTAhJ;#ebn(`Ja%0i}PJ zpA7Nk#}HHf;x0;4(8Mpk(0DibUZs3lN6^qr{};AJE0m_E-Ba%-AIJ3j8(od~bnyS* zz=k|SE-e|@FuHC0I9<*~8qU_RTEn#(KA_pJP{U6&Jg#BKzJ@%`)UdmT12oLk zaGZuk8qU_RTEn#(KA_pJP{U6&Jg#BKemZ>(yK6W=!%PjwX;`G;Yz?b5T&v*& z8g9~Xw}uBb{6xd!8g@+5>1)_s!vPv*YB)~AA`NG2Sgqk&4Ij{OlZLxBJgDI(8XniM zW3o-073uHgU;Gc_Ei zVUdQjHLTWft%eV1xJkp^8XnZ}6Ah1R*zq!*zJ}d39H3#QhT}9W(r~th)f%qV@Bs}s zX}DX%gBpIK;c*Q+>VE1>4ZCYNK*LN8$7xuk;cN}7HC(IV0~%Ud{iMY;TV0D~CJo|V z9vL%#5N5I5M?;mw(}$-4+yMN(14{q#2JTmJ?}ly)?~TBZ!F>(x-@G3LzQ_9n+_DGi zdEB#juH?zWZw2rjoP}{&suO_@C@Ra56z?CWe#3T7Vjd%G_{8;Fp!u>t?XL*mnT?g($pj?!D zEAAV3-odW|DD&^5!58o>;kgjpVZ#2M=Q7-fct(H^2cMF7CU4k3b`PX6N9382B-8B{cECY54U7cOP&X?|;KBHpYXvWnY}6 zQN;Uy@s~1u7u++rizFVggYLm^DDM3{qi`pJ zn+m**aC^W#%6l#F0pLqKay{ggJb65#yZ7K%4t*EgOL2>?U(7QZe;@csJR+lfU<&wJ zo;>Ixfqw&c8h#GmC2x{`1@75ApYYW2oP+-lK+#9h^=qKHo3KK62JmLyZ-=H6?+^1X z`?oI#js$-#?tcOo^ZdXgdfE{`*+Y9eexCvt5l-|(=%)e~0?hkO}tBelzfec zrW@|VJpaW{HXp16_T_yfZmA9fS-exdG@<`WWD*H;I{Jo3;(--t9YjIe8^LSzl4!` zCb}nOwjXE*pN6}bN6P9r?+d~I1NS$iDf8}9o@L;6@;(^%VjgKXh0lTDL~kYCT|Bqq z-b0ujJn|i-UA&(K?2F$MK#8{}e$rN5%QFz%9tp>D2Y6|V#sOu0OUkQ+N9JB-J$4T8 z4c?`l^5B*|U|Bq(KY4-&ehL07;1xV?5%+AM)XjT%YN3((Dearo@i)L7k+^~H^Dg0& zc|`xh1&>?yw-3R8G`MSlPxGt?cbxYd@t3+L_5TZS(k>6;k@omZpbh-(K&h)Y;eHGJ zVB9&-p3VE^z+ODNc_jYD_+7ED*(mUM1~ZW-?}zz#g~!HJ*fMFDuxuWjJ($9)3)I@}v@@8A&~kow#S z{L8%e=eYx%l)t3&K7JDZ1>S#wrjSSK{b=yl^GI1e2wVt_{GK|0M`Y=sTROenJ^j?f zvm;NRIrD|H{xzcdoDMm|F4+8eRCnvKJr^B3xV&H9%fovW+#YlJf$CS2qwiTU_}OPi z4J?1ROLqP4z0M1ctj>7o=h5~@A3I~pxf|Y?uygIL`A9V&g`)Z6pB z#9co|SKW%G|;Juolu?eQx= zNN)^${I^%P`ups?`Lj9Y)hXL&4NE$Ec;t}B$GwpHNXJ_)Iq%%`i(eRG>04pjap~)K zt~hP(;!$Vb`#{XOXKs15>*S&bn{)j=`U+P{8ztTk1by}pk#$T zuAk@lsb4JnX3|5qInrj_d1q0tRhP~`y5`gKHy+91qtD*%0~)Rz^xfx!W^VYVcJ__m zjm_!*!-pfj`DMznt-Jl7-@G&VtHL z&#%r}{O*dWf7(5&p#R#ao0j_aES&h*^2){y!{>}UHFDGkaW4!XIG{RnWv^jFm(RCM z98$Dn{6}fGj2$y6{hGT5o!_lz_rn(+v)tW#*!h!t3>|UyfdAzj>fd|z?N{AC^ZG&E z51tY6=a=6&#rgTI(Sc**Vt=@&OWcTO_r|Zeef8NFSC2kFc3i)&o*w?i|EA7*?8IB; zB|q)A_4=@I$k9)>p8HT^=Z-VJ+_dGAx56IyYjylS3bLERp9BkOqz!amVA(zn%sT(z~H;>Ct~l6 z)D-nJbxdsUs~*^T(UY3GY-;fNPfx`<>qbiAW5*{qee>eb z>$Tk-Z|zSm>B{K;XWKq!a&P(-O?yt}E#4I_y3pIOeqiX^_SV5UYl=P`Femnvm7)xs zr)SXcVC?OMbquxFFx{sl>hL51?*`w0jG3#Vp@qqd-^niWSj4|-A2Piu7>T8-M)`UvW51%-i%4PjvfV;gYezv^3} z!XO_Msc1&sm05}(`%u0mK!DzAjI>a=dbBO5A|?#nyI+rePoOknKp3I0e?3a>g#6(k zSk@Hb4@9GZm@s5v00gJ{0K#}|9UKX!NH~rhRiL4M9Y%t3VAL2gs0vWq3vw} zbCD?t=OWn&&Vv%4frp)c5;mHmKHbxKUbh!U2***HHM5{Bt>~=0sq=lN=H)%Q45N4I zZSLdHt$ec3lpaZXVL|R3S3S4Pu} + + + + CFBundleDevelopmentRegion + English + CFBundleDocumentTypes + + + + CFBundleTypeExtensions + + ris + + + CFBundleTypeMIMETypes + + application/x-research-info-systems + text/x-research-info-systems + text/ris + ris + application/x-endnote-refer + + CFBundleTypeName + Research Information Systems Document + CFBundleTypeRole + Viewer + + + CFBundleTypeExtensions + + ciw + isi + + + CFBundleTypeMIMETypes + + application/x-inst-for-Scientific-info + + CFBundleTypeName + ISI Common Export Format Document + CFBundleTypeRole + Viewer + + + CFBundleTypeExtensions + + mods + + + CFBundleTypeMIMETypes + + application/mods+xml + + CFBundleTypeName + Metadata Object Description Schema Document + CFBundleTypeRole + Viewer + + + CFBundleTypeExtensions + + rdf + + + CFBundleTypeMIMETypes + + application/rdf+xml + + CFBundleTypeName + Resource Description Framework Document + CFBundleTypeRole + Viewer + + + CFBundleTypeExtensions + + bib + bibtex + + + CFBundleTypeMIMETypes + + application/x-bibtex + text/x-bibtex + + CFBundleTypeName + BibTeX Document + CFBundleTypeRole + Viewer + + + CFBundleTypeExtensions + + mrc + marc + + + CFBundleTypeMIMETypes + + application/marc + + CFBundleTypeName + MARC Document + CFBundleTypeRole + Viewer + + + + + CFBundleTypeExtensions + + csl + csl.txt + + + CFBundleTypeMIMETypes + + application/vnd.citationstyles.style+xml + + CFBundleTypeName + CSL Citation Style + CFBundleTypeRole + Viewer + + + + + CFBundleTypeExtensions + + xml + + + CFBundleTypeName + XML Document + CFBundleTypeRole + Viewer + + + CFBundleTypeExtensions + + txt + + + CFBundleTypeName + Text File + CFBundleTypeRole + Viewer + + + CFBundleExecutable + zotero + CFBundleGetInfoString + Zotero {{VERSION}}, © 2006-2018 Contributors + CFBundleIconFile + zotero + CFBundleIdentifier + org.zotero.zotero + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Zotero + CFBundlePackageType + APPL + CFBundleShortVersionString + {{VERSION_NUMERIC}} + CFBundleSignature + ZOTR + CFBundleURLTypes + + + + CFBundleURLName + zotero URL + CFBundleURLSchemes + + zotero + + + + CFBundleVersion + {{VERSION_NUMERIC}} + NSAppleScriptEnabled + + CGDisableCoalescedUpdates + + NSHighResolutionCapable + + NSSupportsAutomaticGraphicsSwitching + + LSMinimumSystemVersion + 10.9.0 + + diff --git a/app/mac/Contents/PkgInfo b/app/mac/Contents/PkgInfo new file mode 100644 index 0000000000..7591ec70b1 --- /dev/null +++ b/app/mac/Contents/PkgInfo @@ -0,0 +1 @@ +APPLZOTR \ No newline at end of file diff --git a/app/mac/Contents/Resources/zotero.icns b/app/mac/Contents/Resources/zotero.icns new file mode 100644 index 0000000000000000000000000000000000000000..4aec04140b3b81e3731378908955853d905dc51b GIT binary patch literal 211494 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 kJ%stgiXT`%sAVo3 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 p+D1hytU+y&vyklb@1xwFeGuMWV8(EY?16+P24A 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 + + + + com.apple.security.cs.allow-unsigned-executable-memory + + + + com.apple.security.cs.disable-library-validation + + + + com.apple.security.device.audio-input + + + + com.apple.security.device.camera + + + + com.apple.security.personal-information.location + + + + com.apple.security.smartcard + + + com.apple.security.automation.apple-events + + diff --git a/app/mac/mozconfig b/app/mac/mozconfig new file mode 100644 index 0000000000..96b45de79e --- /dev/null +++ b/app/mac/mozconfig @@ -0,0 +1,27 @@ +if [ "$Z_ARCH" == "x64" ]; then + ac_add_options --target=x86_64-apple-darwin +elif [ "$Z_ARCH" == "aarch64" ]; then + ac_add_options --target=aarch64-apple-darwin +fi +ac_add_options --enable-bootstrap +ac_add_options --with-macos-sdk=$HOME/tmp/MacOSX11.0.sdk + +mk_add_options AUTOCLOBBER=1 + +# These don't all affect the stub, but they can't hurt, and we'll want them if +# we switch to custom XUL builds +ac_add_options MOZ_ENABLE_JS_DUMP=1 +ac_add_options MOZ_ENABLE_FORKSERVER= +ac_add_options MOZ_TELEMETRY_REPORTING= +ac_add_options MOZ_DATA_REPORTING= +ac_add_options --disable-tests +ac_add_options --disable-debug +ac_add_options --disable-debug-symbols +ac_add_options --disable-webrtc +ac_add_options --disable-eme + +export MOZILLA_OFFICIAL=1 +export RELEASE_OR_BETA=1 +MOZ_REQUIRE_SIGNING= + +ac_add_options --enable-official-branding diff --git a/app/mac/mozilla-102.patch b/app/mac/mozilla-102.patch new file mode 100644 index 0000000000..b19221642f --- /dev/null +++ b/app/mac/mozilla-102.patch @@ -0,0 +1,124 @@ +diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp +--- a/browser/app/nsBrowserApp.cpp ++++ b/browser/app/nsBrowserApp.cpp +@@ -149,19 +149,29 @@ static bool IsArg(const char* arg, const + #endif + + return false; + } + + Bootstrap::UniquePtr gBootstrap; + + static int do_main(int argc, char* argv[], char* envp[]) { ++ // Allow profile downgrade for Zotero ++ setenv("MOZ_ALLOW_DOWNGRADE", "1", 1); ++ + // Allow firefox.exe to launch XULRunner apps via -app + // Note that -app must be the *first* argument. +- const char* appDataFile = getenv("XUL_APP_FILE"); ++ UniqueFreePtr iniPath = BinaryPath::GetApplicationIni(); ++ if (!iniPath) { ++ Output("Couldn't find application.ini.\n"); ++ return 255; ++ } ++ char *appDataFile = iniPath.get(); ++ ++ + if ((!appDataFile || !*appDataFile) && (argc > 1 && IsArg(argv[1], "app"))) { + if (argc == 2) { + Output("Incorrect number of arguments passed to -app"); + return 255; + } + appDataFile = argv[2]; + + char appEnv[MAXPATHLEN]; +diff --git a/xpcom/build/BinaryPath.h b/xpcom/build/BinaryPath.h +--- a/xpcom/build/BinaryPath.h ++++ b/xpcom/build/BinaryPath.h +@@ -128,16 +128,56 @@ class BinaryPath { + } else { + rv = NS_ERROR_FAILURE; + } + + CFRelease(executableURL); + return rv; + } + ++ static nsresult GetApplicationIni(char aResult[MAXPATHLEN]) ++ { ++ // Works even if we're not bundled. ++ CFBundleRef appBundle = CFBundleGetMainBundle(); ++ if (!appBundle) { ++ return NS_ERROR_FAILURE; ++ } ++ ++ CFURLRef iniURL = CFBundleCopyResourceURL(appBundle, CFSTR("application.ini"), ++ NULL, CFSTR("app")); ++ if (!iniURL) { ++ return NS_ERROR_FAILURE; ++ } ++ ++ nsresult rv; ++ if (CFURLGetFileSystemRepresentation(iniURL, false, (UInt8*)aResult, ++ MAXPATHLEN)) { ++ // Sanitize path in case the app was launched from Terminal via ++ // './firefox' for example. ++ size_t readPos = 0; ++ size_t writePos = 0; ++ while (aResult[readPos] != '\0') { ++ if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') { ++ readPos += 2; ++ } else { ++ aResult[writePos] = aResult[readPos]; ++ readPos++; ++ writePos++; ++ } ++ } ++ aResult[writePos] = '\0'; ++ rv = NS_OK; ++ } else { ++ rv = NS_ERROR_FAILURE; ++ } ++ ++ CFRelease(iniURL); ++ return rv; ++ } ++ + #elif defined(ANDROID) + static nsresult Get(char aResult[MAXPATHLEN]) { + // On Android, we use the MOZ_ANDROID_LIBDIR variable that is set by the + // Java bootstrap code. + const char* libDir = getenv("MOZ_ANDROID_LIBDIR"); + if (!libDir) { + return NS_ERROR_FAILURE; + } +@@ -267,16 +307,29 @@ class BinaryPath { + if (NS_FAILED(Get(path))) { + return nullptr; + } + UniqueFreePtr result; + result.reset(strdup(path)); + return result; + } + ++#if defined(XP_MACOSX) ++ static UniqueFreePtr GetApplicationIni() ++ { ++ char path[MAXPATHLEN]; ++ if (NS_FAILED(GetApplicationIni(path))) { ++ return nullptr; ++ } ++ UniqueFreePtr result; ++ result.reset(strdup(path)); ++ return result; ++ } ++#endif ++ + #ifdef MOZILLA_INTERNAL_API + static nsresult GetFile(nsIFile** aResult) { + nsCOMPtr lf; + # ifdef XP_WIN + wchar_t exePath[MAXPATHLEN]; + nsresult rv = GetW(exePath); + # else + char exePath[MAXPATHLEN]; diff --git a/app/mac/pkg-dmg b/app/mac/pkg-dmg new file mode 100755 index 0000000000..f84ba962ca --- /dev/null +++ b/app/mac/pkg-dmg @@ -0,0 +1,1520 @@ +#!/usr/bin/perl +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is pkg-dmg, a Mac OS X disk image (.dmg) packager +# +# The Initial Developer of the Original Code is +# Mark Mentovai . +# Portions created by the Initial Developer are Copyright (C) 2005 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +use strict; +use warnings; + +=pod + +=head1 NAME + +B - Mac OS X disk image (.dmg) packager + +=head1 SYNOPSIS + +B +B<--source> I +B<--target> I +[B<--format> I] +[B<--volname> I] +[B<--tempdir> I] +[B<--mkdir> I] +[B<--copy> I[:I]] +[B<--symlink> I[:I]] +[B<--license> I] +[B<--resource> I] +[B<--icon> I] +[B<--attribute> I:I[:I...] +[B<--idme>] +[B<--sourcefile>] +[B<--verbosity> I] +[B<--dry-run>] + +=head1 DESCRIPTION + +I takes a directory identified by I and transforms +it into a disk image stored as I. The disk image will +occupy the least space possible for its format, or the least space that the +authors have been able to figure out how to achieve. + +=head1 OPTIONS + +=over 5 + +==item B<--source> I + +Identifies the directory that will be packaged up. This directory is not +touched, a copy will be made in a temporary directory for staging purposes. +See B<--tempdir>. + +==item B<--target> I + +The disk image to create. If it exists and is not in use, it will be +overwritten. If I already contains a suitable extension, +it will be used unmodified. If no extension is present, or the extension +is incorrect for the selected format, the proper extension will be added. +See B<--format>. + +==item B<--format> I + +The format to create the disk image in. Valid values for I are: + - UDZO - zlib-compressed, read-only; extension I<.dmg> + - UDBZ - bzip2-compressed, read-only; extension I<.dmg>; + create and use on 10.4 ("Tiger") and later only + - UDRW - read-write; extension I<.dmg> + - UDSP - read-write, sparse; extension I<.sparseimage> + +UDBZ is the default format. + +See L for a description of these formats. + +=item B<--volname> I + +The name of the volume in the disk image. If not specified, I +defaults to the name of the source directory from B<--source>. + +=item B<--tempdir> I + +A temporary directory to stage intermediate files in. I must +have enough space available to accommodate twice the size of the files +being packaged. If not specified, defaults to the same directory that +the I is to be placed in. B will remove any +temporary files it places in I. + +=item B<--mkdir> I + +Specifies a directory that should be created in the disk image. +I and any ancestor directories will be created. This is +useful in conjunction with B<--copy>, when copying files to directories +that may not exist in I. B<--mkdir> may appear multiple +times. + +=item B<--copy> I[:I] + +Additional files to copy into the disk image. If I is +specified, I is copied to the location I identifies, +otherwise, I is copied to the root of the new volume. B<--copy> +provides a way to package up a I by adding files to it +without modifying the original I. B<--copy> may appear +multiple times. + +This option is useful for adding .DS_Store files and window backgrounds +to disk images. + +=item B<--symlink> I[:I] + +Like B<--copy>, but allows symlinks to point out of the volume. Empty symlink +destinations are interpreted as "like the source path, but inside the dmg" + +This option is useful for adding symlinks to external resources, +e.g. to /Applications. + +=item B<--license> I + +A plain text file containing a license agreement to be displayed before +the disk image is mounted. English is the only supported language. To +include license agreements in other languages, in multiple languages, +or to use formatted text, prepare a resource and use L<--resource>. + +=item B<--resource> I + +A resource file to merge into I. If I is UDZO or +UDBZ, the disk image will be flattened to a single-fork file that contains +the resource but may be freely transferred without any special encodings. +I must be in a format suitable for L. See L for a +description of the format, and L for a discussion on flattened +disk images. B<--resource> may appear multiple times. + +This option is useful for adding license agreements and other messages +to disk images. + +=item B<--icon> I + +Specifies an I file that will be used as the icon for the root of +the volume. This file will be copied to the new volume and the custom +icon attribute will be set on the root folder. + +=item B<--attribute> I:I[:I...] + +Sets the attributes of I to the attribute list in I. See +L + +=item B<--idme> + +Enable IDME to make the disk image "Internet-enabled." The first time +the image is mounted, if IDME processing is enabled on the system, the +contents of the image will be copied out of the image and the image will +be placed in the trash with IDME disabled. + +=item B<--sourcefile> + +If this option is present, I is treated as a file, and is +placed as a file within the volume's root folder. Without this option, +I is treated as the volume root itself. + +=item B<--verbosity> I + +Adjusts the level of loudness of B. The possible values for +I are: + 0 - Only error messages are displayed. + 1 - Print error messages and command invocations. + 2 - Print everything, including command output. + +The default I is 2. + +=item B<--dry-run> + +When specified, the commands that would be executed are printed, without +actually executing them. When commands depend on the output of previous +commands, dummy values are displayed. + +=back + +=head1 NON-OPTIONS + +=over 5 + +=item + +Resource forks aren't copied. + +=item + +The root folder of the created volume is designated as the folder +to open when the volume is mounted. See L. + +=item + +All files in the volume are set to be world-readable, only writable +by the owner, and world-executable when appropriate. All other +permissions bits are cleared. + +=item + +When possible, disk images are created without any partition tables. This +is what L refers to as I<-layout NONE>, and saves a handful of +kilobytes. The alternative, I, contains a partition table that +is not terribly handy on disk images that are not intended to represent any +physical disk. + +=item + +Read-write images are created with journaling off. Any read-write image +created by this tool is expected to be transient, and the goal of this tool +is to create images which consume a minimum of space. + +=back + +=head1 EXAMPLE + +pkg-dmg --source /Applications/DeerPark.app --target ~/DeerPark.dmg + --sourcefile --volname DeerPark --icon ~/DeerPark.icns + --mkdir /.background + --copy DeerParkBackground.png:/.background/background.png + --copy DeerParkDSStore:/.DS_Store + --symlink /Applications:"/Drag to here" + +=head1 REQUIREMENTS + +I has been tested with Mac OS X releases 10.2 ("Jaguar") +through 10.4 ("Tiger"). Certain adjustments to behavior are made +depending on the host system's release. Mac OS X 10.3 ("Panther") or +later are recommended. + +=head1 LICENSE + +MPL 1.1/GPL 2.0/LGPL 2.1. Your choice. + +=head1 AUTHOR + +Mark Mentovai + +=head1 SEE ALSO + +L, L, L, L, L, +L, L + +=cut + +use Fcntl; +use POSIX; +use Getopt::Long; + +sub argumentEscape(@); +sub cleanupDie($); +sub command(@); +sub commandInternal($@); +sub commandInternalVerbosity($$@); +sub commandOutput(@); +sub commandOutputVerbosity($@); +sub commandVerbosity($@); +sub copyFiles($@); +sub diskImageMaker($$$$$$$$); +sub giveExtension($$); +sub hdidMountImage($@); +sub isFormatCompressed($); +sub licenseMaker($$); +sub pathSplit($); +sub setAttributes($@); +sub trapSignal($); +sub usage(); + +# Variables used as globals +my(@gCleanup, %gConfig, $gDarwinMajor, $gDryRun, $gVerbosity); + +# Use the commands by name if they're expected to be in the user's +# $PATH (/bin:/sbin:/usr/bin:/usr/sbin). Otherwise, go by absolute +# path. These may be overridden with --config. +%gConfig = ('cmd_bless' => 'bless', + 'cmd_chmod' => 'chmod', + 'cmd_diskutil' => 'diskutil', + 'cmd_du' => 'du', + 'cmd_hdid' => 'hdid', + 'cmd_hdiutil' => 'hdiutil', + 'cmd_mkdir' => 'mkdir', + 'cmd_mktemp' => 'mktemp', + 'cmd_Rez' => '/Developer/Tools/Rez', + 'cmd_rm' => 'rm', + 'cmd_rsync' => 'rsync', + 'cmd_SetFile' => '/Developer/Tools/SetFile', + + # create_directly indicates whether hdiutil create supports + # -srcfolder and -srcdevice. It does on >= 10.3 (Panther). + # This is fixed up for earlier systems below. If false, + # hdiutil create is used to create empty disk images that + # are manually filled. + 'create_directly' => 1, + + # If hdiutil attach -mountpoint exists, use it to avoid + # mounting disk images in the default /Volumes. This reduces + # the likelihood that someone will notice a mounted image and + # interfere with it. Only available on >= 10.3 (Panther), + # fixed up for earlier systems below. + # + # This is presently turned off for all systems, because there + # is an infrequent synchronization problem during ejection. + # diskutil eject might return before the image is actually + # unmounted. If pkg-dmg then attempts to clean up its + # temporary directory, it could remove items from a read-write + # disk image or attempt to remove items from a read-only disk + # image (or a read-only item from a read-write image) and fail, + # causing pkg-dmg to abort. This problem is experienced + # under Tiger, which appears to eject asynchronously where + # previous systems treated it as a synchronous operation. + # Using hdiutil attach -mountpoint didn't always keep images + # from showing up on the desktop anyway. + 'hdiutil_mountpoint' => 0, + + # hdiutil makehybrid results in optimized disk images that + # consume less space and mount more quickly. Use it when + # it's available, but that's only on >= 10.3 (Panther). + # If false, hdiutil create is used instead. Fixed up for + # earlier systems below. + 'makehybrid' => 1, + + # hdiutil create doesn't allow specifying a folder to open + # at volume mount time, so those images are mounted and + # their root folders made holy with bless -openfolder. But + # only on >= 10.3 (Panther). Earlier systems are out of luck. + # Even on Panther, bless refuses to run unless root. + # Fixed up below. + 'openfolder_bless' => 1, + + # It's possible to save a few more kilobytes by including the + # partition only without any partition table in the image. + # This is a good idea on any system, so turn this option off. + # + # Except it's buggy. "-layout NONE" seems to be creating + # disk images with more data than just the partition table + # stripped out. You might wind up losing the end of the + # filesystem - the last file (or several) might be incomplete. + 'partition_table' => 1, + + # To create a partition table-less image from something + # created by makehybrid, the hybrid image needs to be + # mounted and a new image made from the device associated + # with the relevant partition. This requires >= 10.4 + # (Tiger), presumably because earlier systems have + # problems creating images from devices themselves attached + # to images. If this is false, makehybrid images will + # have partition tables, regardless of the partition_table + # setting. Fixed up for earlier systems below. + 'recursive_access' => 1); + +# --verbosity +$gVerbosity = 2; + +# --dry-run +$gDryRun = 0; + +# %gConfig fix-ups based on features and bugs present in certain releases. +my($ignore, $uname_r, $uname_s); +($uname_s, $ignore, $uname_r, $ignore, $ignore) = POSIX::uname(); +if($uname_s eq 'Darwin') { + ($gDarwinMajor, $ignore) = split(/\./, $uname_r, 2); + + # $major is the Darwin major release, which for our purposes, is 4 higher + # than the interesting digit in a Mac OS X release. + if($gDarwinMajor <= 6) { + # <= 10.2 (Jaguar) + # hdiutil create does not support -srcfolder or -srcdevice + $gConfig{'create_directly'} = 0; + # hdiutil attach does not support -mountpoint + $gConfig{'hdiutil_mountpoint'} = 0; + # hdiutil mkhybrid does not exist + $gConfig{'makehybrid'} = 0; + } + if($gDarwinMajor <= 7) { + # <= 10.3 (Panther) + # Can't mount a disk image and then make a disk image from the device + $gConfig{'recursive_access'} = 0; + # bless does not support -openfolder on 10.2 (Jaguar) and must run + # as root under 10.3 (Panther) + $gConfig{'openfolder_bless'} = 0; + } +} +else { + # If it's not Mac OS X, just assume all of those good features are + # available. They're not, but things will fail long before they + # have a chance to make a difference. + # + # Now, if someone wanted to document some of these private formats... + print STDERR ($0.": warning, not running on Mac OS X, ". + "this could be interesting.\n"); +} + +# Non-global variables used in Getopt +my(@attributes, @copyFiles, @createSymlinks, $iconFile, $idme, $licenseFile, + @makeDirs, $outputFormat, @resourceFiles, $sourceFile, $sourceFolder, + $targetImage, $tempDir, $volumeName); + +# --format +$outputFormat = 'UDBZ'; + +# --idme +$idme = 0; + +# --sourcefile +$sourceFile = 0; + +# Leaving this might screw up the Apple tools. +delete $ENV{'NEXT_ROOT'}; + +# This script can get pretty messy, so trap a few signals. +$SIG{'INT'} = \&trapSignal; +$SIG{'HUP'} = \&trapSignal; +$SIG{'TERM'} = \&trapSignal; + +Getopt::Long::Configure('pass_through'); +GetOptions('source=s' => \$sourceFolder, + 'target=s' => \$targetImage, + 'volname=s' => \$volumeName, + 'format=s' => \$outputFormat, + 'tempdir=s' => \$tempDir, + 'mkdir=s' => \@makeDirs, + 'copy=s' => \@copyFiles, + 'symlink=s' => \@createSymlinks, + 'license=s' => \$licenseFile, + 'resource=s' => \@resourceFiles, + 'icon=s' => \$iconFile, + 'attribute=s' => \@attributes, + 'idme' => \$idme, + 'sourcefile' => \$sourceFile, + 'verbosity=i' => \$gVerbosity, + 'dry-run' => \$gDryRun, + 'config=s' => \%gConfig); # "hidden" option not in usage() + +if(@ARGV) { + # All arguments are parsed by Getopt + usage(); + exit(1); +} + +if($gVerbosity<0 || $gVerbosity>2) { + usage(); + exit(1); +} + +if(!defined($sourceFolder) || $sourceFolder eq '' || + !defined($targetImage) || $targetImage eq '') { + # --source and --target are required arguments + usage(); + exit(1); +} + +# Make sure $sourceFolder doesn't contain trailing slashes. It messes with +# rsync. +while(substr($sourceFolder, -1) eq '/') { + chop($sourceFolder); +} + +if(!defined($volumeName)) { + # Default volumeName is the name of the source directory. + my(@components); + @components = pathSplit($sourceFolder); + $volumeName = pop(@components); +} + +my(@tempDirComponents, $targetImageFilename); +@tempDirComponents = pathSplit($targetImage); +$targetImageFilename = pop(@tempDirComponents); + +if(defined($tempDir)) { + @tempDirComponents = pathSplit($tempDir); +} +else { + # Default tempDir is the same directory as what is specified for + # targetImage + $tempDir = join('/', @tempDirComponents); +} + +# Ensure that the path of the target image has a suitable extension. If +# it didn't, hdiutil would add one, and we wouldn't be able to find the +# file. +# +# Note that $targetImageFilename is not being reset. This is because it's +# used to build other names below, and we don't need to be adding all sorts +# of extra unnecessary extensions to the name. +my($originalTargetImage, $requiredExtension); +$originalTargetImage = $targetImage; +if($outputFormat eq 'UDSP') { + $requiredExtension = '.sparseimage'; +} +else { + $requiredExtension = '.dmg'; +} +$targetImage = giveExtension($originalTargetImage, $requiredExtension); + +if($targetImage ne $originalTargetImage) { + print STDERR ($0.": warning: target image extension is being added\n"); + print STDERR (' The new filename is '. + giveExtension($targetImageFilename,$requiredExtension)."\n"); +} + +# Make a temporary directory in $tempDir for our own nefarious purposes. +my(@output, $tempSubdir, $tempSubdirTemplate); +$tempSubdirTemplate=join('/', @tempDirComponents, + 'pkg-dmg.'.$$.'.XXXXXXXX'); +if(!(@output = commandOutput($gConfig{'cmd_mktemp'}, '-d', + $tempSubdirTemplate)) || $#output != 0) { + cleanupDie('mktemp failed'); +} + +if($gDryRun) { + (@output)=($tempSubdirTemplate); +} + +($tempSubdir) = @output; + +push(@gCleanup, + sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempSubdir);}); + +my($tempMount, $tempRoot, @tempsToMake); +$tempRoot = $tempSubdir.'/stage'; +$tempMount = $tempSubdir.'/mount'; +push(@tempsToMake, $tempRoot); +if($gConfig{'hdiutil_mountpoint'}) { + push(@tempsToMake, $tempMount); +} + +if(command($gConfig{'cmd_mkdir'}, @tempsToMake) != 0) { + cleanupDie('mkdir tempRoot/tempMount failed'); +} + +# This cleanup object is not strictly necessary, because $tempRoot is inside +# of $tempSubdir, but the rest of the script relies on this object being +# on the cleanup stack and expects to remove it. +push(@gCleanup, + sub {commandVerbosity(0, $gConfig{'cmd_rm'}, '-rf', $tempRoot);}); + +# If $sourceFile is true, it means that $sourceFolder is to be treated as +# a file and placed as a file within the volume root, as opposed to being +# treated as the volume root itself. rsync will do this by default, if no +# trailing '/' is present. With a trailing '/', $sourceFolder becomes +# $tempRoot, instead of becoming an entry in $tempRoot. +if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', + $sourceFolder.($sourceFile?'':'/'),$tempRoot) != 0) { + cleanupDie('rsync failed'); +} + +if(@makeDirs) { + my($makeDir, @tempDirsToMake); + foreach $makeDir (@makeDirs) { + if($makeDir =~ /^\//) { + push(@tempDirsToMake, $tempRoot.$makeDir); + } + else { + push(@tempDirsToMake, $tempRoot.'/'.$makeDir); + } + } + if(command($gConfig{'cmd_mkdir'}, '-p', @tempDirsToMake) != 0) { + cleanupDie('mkdir failed'); + } +} + +# copy files and/or create symlinks +copyFiles($tempRoot, 'copy', @copyFiles); +copyFiles($tempRoot, 'symlink', @createSymlinks); + +if($gConfig{'create_directly'}) { + # If create_directly is false, the contents will be rsynced into a + # disk image and they would lose their attributes. + setAttributes($tempRoot, @attributes); +} + +if(defined($iconFile)) { + if(command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', $iconFile, + $tempRoot.'/.VolumeIcon.icns') != 0) { + cleanupDie('rsync failed for volume icon'); + } + + # It's pointless to set the attributes of the root when diskutil create + # -srcfolder is being used. In that case, the attributes will be set + # later, after the image is already created. + if(isFormatCompressed($outputFormat) && + (command($gConfig{'cmd_SetFile'}, '-a', 'C', $tempRoot) != 0)) { + cleanupDie('SetFile failed'); + } +} + +if(command($gConfig{'cmd_chmod'}, '-R', 'a+rX,a-st,u+w,go-w', + $tempRoot) != 0) { + cleanupDie('chmod failed'); +} + +my($unflattenable); +if(isFormatCompressed($outputFormat)) { + $unflattenable = 1; +} +else { + $unflattenable = 0; +} + +diskImageMaker($tempRoot, $targetImage, $outputFormat, $volumeName, + $tempSubdir, $tempMount, $targetImageFilename, defined($iconFile)); + +if(defined($licenseFile) && $licenseFile ne '') { + my($licenseResource); + $licenseResource = $tempSubdir.'/license.r'; + if(!licenseMaker($licenseFile, $licenseResource)) { + cleanupDie('licenseMaker failed'); + } + push(@resourceFiles, $licenseResource); + # Don't add a cleanup object because licenseResource is in tempSubdir. +} + +if(@resourceFiles) { + # Add resources, such as a license agreement. + + # Only unflatten read-only and compressed images. It's not supported + # on other image times. + if($unflattenable && + (command($gConfig{'cmd_hdiutil'}, 'unflatten', $targetImage)) != 0) { + cleanupDie('hdiutil unflatten failed'); + } + # Don't push flatten onto the cleanup stack. If we fail now, we'll be + # removing $targetImage anyway. + + # Type definitions come from Carbon.r. + if(command($gConfig{'cmd_Rez'}, 'Carbon.r', @resourceFiles, '-a', '-o', + $targetImage) != 0) { + cleanupDie('Rez failed'); + } + + # Flatten. This merges the resource fork into the data fork, so no + # special encoding is needed to transfer the file. + if($unflattenable && + (command($gConfig{'cmd_hdiutil'}, 'flatten', $targetImage)) != 0) { + cleanupDie('hdiutil flatten failed'); + } +} + +# $tempSubdir is no longer needed. It's buried on the stack below the +# rm of the fresh image file. Splice in this fashion is equivalent to +# pop-save, pop, push-save. +splice(@gCleanup, -2, 1); +# No need to remove licenseResource separately, it's in tempSubdir. +if(command($gConfig{'cmd_rm'}, '-rf', $tempSubdir) != 0) { + cleanupDie('rm -rf tempSubdir failed'); +} + +if($idme) { + if(command($gConfig{'cmd_hdiutil'}, 'internet-enable', '-yes', + $targetImage) != 0) { + cleanupDie('hdiutil internet-enable failed'); + } +} + +# Done. + +exit(0); + +# argumentEscape(@arguments) +# +# Takes a list of @arguments and makes them shell-safe. +sub argumentEscape(@) { + my(@arguments); + @arguments = @_; + my($argument, @argumentsOut); + foreach $argument (@arguments) { + $argument =~ s%([^A-Za-z0-9_\-/.=+,])%\\$1%g; + push(@argumentsOut, $argument); + } + return @argumentsOut; +} + +# cleanupDie($message) +# +# Displays $message as an error message, and then runs through the +# @gCleanup stack, performing any cleanup operations needed before +# exiting. Does not return, exits with exit status 1. +sub cleanupDie($) { + my($message); + ($message) = @_; + print STDERR ($0.': '.$message.(@gCleanup?' (cleaning up)':'')."\n"); + while(@gCleanup) { + my($subroutine); + $subroutine = pop(@gCleanup); + &$subroutine; + } + exit(1); +} + +# command(@arguments) +# +# Runs the specified command at the verbosity level defined by $gVerbosity. +# Returns nonzero on failure, returning the exit status if appropriate. +# Discards command output. +sub command(@) { + my(@arguments); + @arguments = @_; + return commandVerbosity($gVerbosity,@arguments); +} + +# commandInternal($command, @arguments) +# +# Runs the specified internal command at the verbosity level defined by +# $gVerbosity. +# Returns zero(!) on failure, because commandInternal is supposed to be a +# direct replacement for the Perl system call wrappers, which, unlike shell +# commands and C equivalent system calls, return true (instead of 0) to +# indicate success. +sub commandInternal($@) { + my(@arguments, $command); + ($command, @arguments) = @_; + return commandInternalVerbosity($gVerbosity, $command, @arguments); +} + +# commandInternalVerbosity($verbosity, $command, @arguments) +# +# Run an internal command, printing a bogus command invocation message if +# $verbosity is true. +# +# If $command is unlink: +# Removes the files specified by @arguments. Wraps unlink. +# +# If $command is symlink: +# Creates the symlink specified by @arguments. Wraps symlink. +sub commandInternalVerbosity($$@) { + my(@arguments, $command, $verbosity); + ($verbosity, $command, @arguments) = @_; + if($command eq 'unlink') { + if($verbosity || $gDryRun) { + print(join(' ', 'rm', '-f', argumentEscape(@arguments))."\n"); + } + if($gDryRun) { + return $#arguments+1; + } + return unlink(@arguments); + } + elsif($command eq 'symlink') { + if($verbosity || $gDryRun) { + print(join(' ', 'ln', '-s', argumentEscape(@arguments))."\n"); + } + if($gDryRun) { + return 1; + } + my($source, $target); + ($source, $target) = @arguments; + return symlink($source, $target); + } +} + +# commandOutput(@arguments) +# +# Runs the specified command at the verbosity level defined by $gVerbosity. +# Output is returned in an array of lines. undef is returned on failure. +# The exit status is available in $?. +sub commandOutput(@) { + my(@arguments); + @arguments = @_; + return commandOutputVerbosity($gVerbosity, @arguments); +} + +# commandOutputVerbosity($verbosity, @arguments) +# +# Runs the specified command at the verbosity level defined by the +# $verbosity argument. Output is returned in an array of lines. undef is +# returned on failure. The exit status is available in $?. +# +# If an error occurs in fork or exec, an error message is printed to +# stderr and undef is returned. +# +# If $verbosity is 0, the command invocation is not printed, and its +# stdout is not echoed back to stdout. +# +# If $verbosity is 1, the command invocation is printed. +# +# If $verbosity is 2, the command invocation is printed and the output +# from stdout is echoed back to stdout. +# +# Regardless of $verbosity, stderr is left connected. +sub commandOutputVerbosity($@) { + my(@arguments, $verbosity); + ($verbosity, @arguments) = @_; + my($pid); + if($verbosity || $gDryRun) { + print(join(' ', argumentEscape(@arguments))."\n"); + } + if($gDryRun) { + return(1); + } + if (!defined($pid = open(*COMMAND, '-|'))) { + printf STDERR ($0.': fork: '.$!."\n"); + return undef; + } + elsif ($pid) { + # parent + my(@lines); + while(!eof(*COMMAND)) { + my($line); + chop($line = ); + if($verbosity > 1) { + print($line."\n"); + } + push(@lines, $line); + } + close(*COMMAND); + if ($? == -1) { + printf STDERR ($0.': fork: '.$!."\n"); + return undef; + } + elsif ($? & 127) { + printf STDERR ($0.': exited on signal '.($? & 127). + ($? & 128 ? ', core dumped' : '')."\n"); + return undef; + } + return @lines; + } + else { + # child; this form of exec is immune to shell games + if(!exec {$arguments[0]} (@arguments)) { + printf STDERR ($0.': exec: '.$!."\n"); + exit(-1); + } + } +} + +# commandVerbosity($verbosity, @arguments) +# +# Runs the specified command at the verbosity level defined by the +# $verbosity argument. Returns nonzero on failure, returning the exit +# status if appropriate. Discards command output. +sub commandVerbosity($@) { + my(@arguments, $verbosity); + ($verbosity, @arguments) = @_; + if(!defined(commandOutputVerbosity($verbosity, @arguments))) { + return -1; + } + return $?; +} + +# copyFiles($tempRoot, $method, @arguments) +# +# Copies files or create symlinks in the disk image. +# See --copy and --symlink descriptions for details. +# If $method is 'copy', @arguments are interpreted as source:target, if $method +# is 'symlink', @arguments are interpreted as symlink:target. +sub copyFiles($@) { + my(@fileList, $method, $tempRoot); + ($tempRoot, $method, @fileList) = @_; + my($file, $isSymlink); + $isSymlink = ($method eq 'symlink'); + foreach $file (@fileList) { + my($source, $target); + ($source, $target) = split(/:/, $file); + if(!defined($target) and $isSymlink) { + # empty symlink targets would result in an invalid target and fail, + # but they shall be interpreted as "like source path, but inside dmg" + $target = $source; + } + if(!defined($target)) { + $target = $tempRoot; + } + elsif($target =~ /^\//) { + $target = $tempRoot.$target; + } + else { + $target = $tempRoot.'/'.$target; + } + + my($success); + if($isSymlink) { + $success = commandInternal('symlink', $source, $target); + } + else { + $success = !command($gConfig{'cmd_rsync'}, '-a', '--copy-unsafe-links', + $source, $target); + } + if(!$success) { + cleanupDie('copyFiles failed for method '.$method); + } + } +} + +# diskImageMaker($source, $destination, $format, $name, $tempDir, $tempMount, +# $baseName, $setRootIcon) +# +# Creates a disk image in $destination of format $format corresponding to the +# source directory $source. $name is the volume name. $tempDir is a good +# place to write temporary files, which should be empty (aside from the other +# things that this script might create there, like stage and mount). +# $tempMount is a mount point for temporary disk images. $baseName is the +# name of the disk image, and is presently unused. $setRootIcon is true if +# a volume icon was added to the staged $source and indicates that the +# custom volume icon bit on the volume root needs to be set. +sub diskImageMaker($$$$$$$$) { + my($baseName, $destination, $format, $name, $setRootIcon, $source, + $tempDir, $tempMount); + ($source, $destination, $format, $name, $tempDir, $tempMount, + $baseName, $setRootIcon) = @_; + if(isFormatCompressed($format)) { + my($uncompressedImage); + + if($gConfig{'makehybrid'}) { + my($hybridImage); + $hybridImage = giveExtension($tempDir.'/hybrid', '.dmg'); + + if(command($gConfig{'cmd_hdiutil'}, 'makehybrid', '-hfs', + '-hfs-volume-name', $name, '-hfs-openfolder', $source, '-ov', + $source, '-o', $hybridImage) != 0) { + cleanupDie('hdiutil makehybrid failed'); + } + + $uncompressedImage = $hybridImage; + + # $source is no longer needed and will be removed before anything + # else can fail. splice in this form is the same as pop/push. + splice(@gCleanup, -1, 1, + sub {commandInternalVerbosity(0, 'unlink', $hybridImage);}); + + if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { + cleanupDie('rm -rf failed'); + } + + if(!$gConfig{'partition_table'} && $gConfig{'recursive_access'}) { + # Even if we do want to create disk images without partition tables, + # it's impossible unless recursive_access is set. + my($rootDevice, $partitionDevice, $partitionMountPoint); + + if(!(($rootDevice, $partitionDevice, $partitionMountPoint) = + hdidMountImage($tempMount, '-readonly', $hybridImage))) { + cleanupDie('hdid mount failed'); + } + + push(@gCleanup, sub {commandVerbosity(0, + $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);}); + + my($udrwImage); + $udrwImage = giveExtension($tempDir.'/udrw', '.dmg'); + + if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', 'UDRW', + '-ov', '-srcdevice', $partitionDevice, $udrwImage) != 0) { + cleanupDie('hdiutil create failed'); + } + + $uncompressedImage = $udrwImage; + + # Going to eject before anything else can fail. Get the eject off + # the stack. + pop(@gCleanup); + + # $hybridImage will be removed soon, but until then, it needs to + # stay on the cleanup stack. It needs to wait until after + # ejection. $udrwImage is staying around. Make it appear as + # though it's been done before $hybridImage. + # + # splice in this form is the same as popping one element to + # @tempCleanup and pushing the subroutine. + my(@tempCleanup); + @tempCleanup = splice(@gCleanup, -1, 1, + sub {commandInternalVerbosity(0, 'unlink', $udrwImage);}); + push(@gCleanup, @tempCleanup); + + if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) { + cleanupDie('diskutil eject failed'); + } + + # Pop unlink of $uncompressedImage + pop(@gCleanup); + + if(commandInternal('unlink', $hybridImage) != 1) { + cleanupDie('unlink hybridImage failed: '.$!); + } + } + } + else { + # makehybrid is not available, fall back to making a UDRW and + # converting to a compressed image. It ought to be possible to + # create a compressed image directly, but those come out far too + # large (journaling?) and need to be read-write to fix up the + # volume icon anyway. Luckily, we can take advantage of a single + # call back into this function. + my($udrwImage); + $udrwImage = giveExtension($tempDir.'/udrw', '.dmg'); + + diskImageMaker($source, $udrwImage, 'UDRW', $name, $tempDir, + $tempMount, $baseName, $setRootIcon); + + # The call back into diskImageMaker already removed $source. + + $uncompressedImage = $udrwImage; + } + + # The uncompressed disk image is now in its final form. Compress it. + # Jaguar doesn't support hdiutil convert -ov, but it always allows + # overwriting. + # bzip2-compressed UDBZ images can only be created and mounted on 10.4 + # and later. The bzip2-level imagekey is only effective when creating + # images in 10.5. In 10.4, bzip2-level is harmlessly ignored, and the + # default value of 1 is always used. + if(command($gConfig{'cmd_hdiutil'}, 'convert', '-format', $format, + '-imagekey', ($format eq 'UDBZ' ? 'bzip2-level=9' : 'zlib-level=9'), + (defined($gDarwinMajor) && $gDarwinMajor <= 6 ? () : ('-ov')), + $uncompressedImage, '-o', $destination) != 0) { + cleanupDie('hdiutil convert failed'); + } + + # $uncompressedImage is going to be unlinked before anything else can + # fail. splice in this form is the same as pop/push. + splice(@gCleanup, -1, 1, + sub {commandInternalVerbosity(0, 'unlink', $destination);}); + + if(commandInternal('unlink', $uncompressedImage) != 1) { + cleanupDie('unlink uncompressedImage failed: '.$!); + } + + # At this point, the only thing that the compressed block has added to + # the cleanup stack is the removal of $destination. $source has already + # been removed, and its cleanup entry has been removed as well. + } + elsif($format eq 'UDRW' || $format eq 'UDSP') { + my(@extraArguments); + if(!$gConfig{'partition_table'}) { + @extraArguments = ('-layout', 'NONE'); + } + + if($gConfig{'create_directly'}) { + # Use -fs HFS+ to suppress the journal. + if(command($gConfig{'cmd_hdiutil'}, 'create', '-format', $format, + @extraArguments, '-fs', 'HFS+', '-volname', $name, + '-ov', '-srcfolder', $source, $destination) != 0) { + cleanupDie('hdiutil create failed'); + } + + # $source is no longer needed and will be removed before anything + # else can fail. splice in this form is the same as pop/push. + splice(@gCleanup, -1, 1, + sub {commandInternalVerbosity(0, 'unlink', $destination);}); + + if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { + cleanupDie('rm -rf failed'); + } + } + else { + # hdiutil create does not support -srcfolder or -srcdevice, it only + # knows how to create blank images. Figure out how large an image + # is needed, create it, and fill it. This is needed for Jaguar. + + # Use native block size for hdiutil create -sectors. + delete $ENV{'BLOCKSIZE'}; + + my(@duOutput, $ignore, $sizeBlocks, $sizeOverhead, $sizeTotal, $type); + if(!(@output = commandOutput($gConfig{'cmd_du'}, '-s', $tempRoot)) || + $? != 0) { + cleanupDie('du failed'); + } + ($sizeBlocks, $ignore) = split(' ', $output[0], 2); + + # The filesystem itself takes up 152 blocks of its own blocks for the + # filesystem up to 8192 blocks, plus 64 blocks for every additional + # 4096 blocks or portion thereof. + $sizeOverhead = 152 + 64 * POSIX::ceil( + (($sizeBlocks - 8192) > 0) ? (($sizeBlocks - 8192) / (4096 - 64)) : 0); + + # The number of blocks must be divisible by 8. + my($mod); + if($mod = ($sizeOverhead % 8)) { + $sizeOverhead += 8 - $mod; + } + + # sectors is taken as the size of a disk, not a filesystem, so the + # partition table eats into it. + if($gConfig{'partition_table'}) { + $sizeOverhead += 80; + } + + # That was hard. Leave some breathing room anyway. Use 1024 sectors + # (512kB). These read-write images wouldn't be useful if they didn't + # have at least a little free space. + $sizeTotal = $sizeBlocks + $sizeOverhead + 1024; + + # Minimum sizes - these numbers are larger on Jaguar than on later + # systems. Just use the Jaguar numbers, since it's unlikely to wind + # up here on any other release. + if($gConfig{'partition_table'} && $sizeTotal < 8272) { + $sizeTotal = 8272; + } + if(!$gConfig{'partition_table'} && $sizeTotal < 8192) { + $sizeTotal = 8192; + } + + # hdiutil create without -srcfolder or -srcdevice will not accept + # -format. It uses -type. Fortunately, the two supported formats + # here map directly to the only two supported types. + if ($format eq 'UDSP') { + $type = 'SPARSE'; + } + else { + $type = 'UDIF'; + } + + if(command($gConfig{'cmd_hdiutil'}, 'create', '-type', $type, + @extraArguments, '-fs', 'HFS+', '-volname', $name, + '-ov', '-sectors', $sizeTotal, $destination) != 0) { + cleanupDie('hdiutil create failed'); + } + + push(@gCleanup, + sub {commandInternalVerbosity(0, 'unlink', $destination);}); + + # The rsync will occur shortly. + } + + my($mounted, $rootDevice, $partitionDevice, $partitionMountPoint); + + $mounted=0; + if(!$gConfig{'create_directly'} || $gConfig{'openfolder_bless'} || + $setRootIcon) { + # The disk image only needs to be mounted if: + # create_directly is false, because the content needs to be copied + # openfolder_bless is true, because bless -openfolder needs to run + # setRootIcon is true, because the root needs its attributes set. + if(!(($rootDevice, $partitionDevice, $partitionMountPoint) = + hdidMountImage($tempMount, $destination))) { + cleanupDie('hdid mount failed'); + } + + $mounted=1; + + push(@gCleanup, sub {commandVerbosity(0, + $gConfig{'cmd_diskutil'}, 'eject', $rootDevice);}); + } + + if(!$gConfig{'create_directly'}) { + # Couldn't create and copy directly in one fell swoop. Now that + # the volume is mounted, copy the files. --copy-unsafe-links is + # unnecessary since it was used to copy everything to the staging + # area. There can be no more unsafe links. + if(command($gConfig{'cmd_rsync'}, '-a', + $source.'/',$partitionMountPoint) != 0) { + cleanupDie('rsync to new volume failed'); + } + + # We need to get the rm -rf of $source off the stack, because it's + # being cleaned up here. There are two items now on top of it: + # removing the target image and, above that, ejecting it. Splice it + # out. + my(@tempCleanup); + @tempCleanup = splice(@gCleanup, -2); + # The next splice is the same as popping once and pushing @tempCleanup. + splice(@gCleanup, -1, 1, @tempCleanup); + + if(command($gConfig{'cmd_rm'}, '-rf', $source) != 0) { + cleanupDie('rm -rf failed'); + } + } + + if($gConfig{'openfolder_bless'}) { + # On Tiger, the bless docs say to use --openfolder, but only + # --openfolder is accepted on Panther. Tiger takes it with a single + # dash too. Jaguar is out of luck. + if(command($gConfig{'cmd_bless'}, '-openfolder', + $partitionMountPoint) != 0) { + cleanupDie('bless failed'); + } + } + + setAttributes($partitionMountPoint, @attributes); + + if($setRootIcon) { + # When "hdiutil create -srcfolder" is used, the root folder's + # attributes are not copied to the new volume. Fix up. + + if(command($gConfig{'cmd_SetFile'}, '-a', 'C', + $partitionMountPoint) != 0) { + cleanupDie('SetFile failed'); + } + } + + if($mounted) { + # Pop diskutil eject + pop(@gCleanup); + + if(command($gConfig{'cmd_diskutil'}, 'eject', $rootDevice) != 0) { + cleanupDie('diskutil eject failed'); + } + } + + # End of UDRW/UDSP section. At this point, $source has been removed + # and its cleanup entry has been removed from the stack. + } + else { + cleanupDie('unrecognized format'); + print STDERR ($0.": unrecognized format\n"); + exit(1); + } +} + +# giveExtension($file, $extension) +# +# If $file does not end in $extension, $extension is added. The new +# filename is returned. +sub giveExtension($$) { + my($extension, $file); + ($file, $extension) = @_; + if(substr($file, -length($extension)) ne $extension) { + return $file.$extension; + } + return $file; +} + +# hdidMountImage($mountPoint, @arguments) +# +# Runs the hdid command with arguments specified by @arguments. +# @arguments may be a single-element array containing the name of the +# disk image to mount. Returns a three-element array, with elements +# corresponding to: +# - The root device of the mounted image, suitable for ejection +# - The device corresponding to the mounted partition +# - The mounted partition's mount point +# +# If running on a system that supports easy mounting at points outside +# of the default /Volumes with hdiutil attach, it is used instead of hdid, +# and $mountPoint is used as the mount point. +# +# The root device will differ from the partition device when the disk +# image contains a partition table, otherwise, they will be identical. +# +# If hdid fails, undef is returned. +sub hdidMountImage($@) { + my(@arguments, @command, $mountPoint); + ($mountPoint, @arguments) = @_; + my(@output); + + if($gConfig{'hdiutil_mountpoint'}) { + @command=($gConfig{'cmd_hdiutil'}, 'attach', @arguments, + '-mountpoint', $mountPoint); + } + else { + @command=($gConfig{'cmd_hdid'}, @arguments); + } + + if(!(@output = commandOutput(@command)) || + $? != 0) { + return undef; + } + + if($gDryRun) { + return('/dev/diskX','/dev/diskXsY','/Volumes/'.$volumeName); + } + + my($line, $restOfLine, $rootDevice); + + foreach $line (@output) { + my($device, $mountpoint); + if($line !~ /^\/dev\//) { + # Consider only lines that correspond to /dev entries + next; + } + ($device, $restOfLine) = split(' ', $line, 2); + + if(!defined($rootDevice) || $rootDevice eq '') { + # If this is the first device seen, it's the root device to be + # used for ejection. Keep it. + $rootDevice = $device; + } + + if($restOfLine =~ /(\/.*)/) { + # The first partition with a mount point is the interesting one. It's + # usually Apple_HFS and usually the last one in the list, but beware of + # the possibility of other filesystem types and the Apple_Free partition. + # If the disk image contains no partition table, the partition will not + # have a type, so look for the mount point by looking for a slash. + $mountpoint = $1; + return($rootDevice, $device, $mountpoint); + } + } + + # No mount point? This is bad. If there's a root device, eject it. + if(defined($rootDevice) && $rootDevice ne '') { + # Failing anyway, so don't care about failure + commandVerbosity(0, $gConfig{'cmd_diskutil'}, 'eject', $rootDevice); + } + + return undef; +} + +# isFormatCompressed($format) +# +# Returns true if $format corresponds to a compressed disk image format. +# Returns false otherwise. +sub isFormatCompressed($) { + my($format); + ($format) = @_; + return $format eq 'UDZO' || $format eq 'UDBZ'; +} + +# licenseMaker($text, $resource) +# +# Takes a plain text file at path $text and creates a license agreement +# resource containing the text at path $license. English-only, and +# no special formatting. This is the bare-bones stuff. For more +# intricate license agreements, create your own resource. +# +# ftp://ftp.apple.com/developer/Development_Kits/SLAs_for_UDIFs_1.0.dmg +sub licenseMaker($$) { + my($resource, $text); + ($text, $resource) = @_; + if(!sysopen(*TEXT, $text, O_RDONLY)) { + print STDERR ($0.': licenseMaker: sysopen text: '.$!."\n"); + return 0; + } + if(!sysopen(*RESOURCE, $resource, O_WRONLY|O_CREAT|O_EXCL)) { + print STDERR ($0.': licenseMaker: sysopen resource: '.$!."\n"); + return 0; + } + print RESOURCE << '__EOT__'; +// See /System/Library/Frameworks/CoreServices.framework/Frameworks/CarbonCore.framework/Headers/Script.h for language IDs. +data 'LPic' (5000) { + // Default language ID, 0 = English + $"0000" + // Number of entries in list + $"0001" + + // Entry 1 + // Language ID, 0 = English + $"0000" + // Resource ID, 0 = STR#/TEXT/styl 5000 + $"0000" + // Multibyte language, 0 = no + $"0000" +}; + +resource 'STR#' (5000, "English") { + { + // Language (unused?) = English + "English", + // Agree + "Agree", + // Disagree + "Disagree", +__EOT__ + # This stuff needs double-quotes for interpolations to work. + print RESOURCE (" // Print, ellipsis is 0xC9\n"); + print RESOURCE (" \"Print\xc9\",\n"); + print RESOURCE (" // Save As, ellipsis is 0xC9\n"); + print RESOURCE (" \"Save As\xc9\",\n"); + print RESOURCE (' // Descriptive text, curly quotes are 0xD2 and 0xD3'. + "\n"); + print RESOURCE (' "If you agree to the terms of this license '. + "agreement, click \xd2Agree\xd3 to access the software. If you ". + "do not agree, press \xd2Disagree.\xd3\"\n"); +print RESOURCE << '__EOT__'; + }; +}; + +// Beware of 1024(?) byte (character?) line length limitation. Split up long +// lines. +// If straight quotes are used ("), remember to escape them (\"). +// Newline is \n, to leave a blank line, use two of them. +// 0xD2 and 0xD3 are curly double-quotes ("), 0xD4 and 0xD5 are curly +// single quotes ('), 0xD5 is also the apostrophe. +data 'TEXT' (5000, "English") { +__EOT__ + + while(!eof(*TEXT)) { + my($line); + chop($line = ); + + while(defined($line)) { + my($chunk); + + # Rez doesn't care for lines longer than (1024?) characters. Split + # at less than half of that limit, in case everything needs to be + # backwhacked. + if(length($line)>500) { + $chunk = substr($line, 0, 500); + $line = substr($line, 500); + } + else { + $chunk = $line; + $line = undef; + } + + if(length($chunk) > 0) { + # Unsafe characters are the double-quote (") and backslash (\), escape + # them with backslashes. + $chunk =~ s/(["\\])/\\$1/g; + + print RESOURCE ' "'.$chunk.'"'."\n"; + } + } + print RESOURCE ' "\n"'."\n"; + } + close(*TEXT); + + print RESOURCE << '__EOT__'; +}; + +data 'styl' (5000, "English") { + // Number of styles following = 1 + $"0001" + + // Style 1. This is used to display the first two lines in bold text. + // Start character = 0 + $"0000 0000" + // Height = 16 + $"0010" + // Ascent = 12 + $"000C" + // Font family = 1024 (Lucida Grande) + $"0400" + // Style bitfield, 0x1=bold 0x2=italic 0x4=underline 0x8=outline + // 0x10=shadow 0x20=condensed 0x40=extended + $"00" + // Style, unused? + $"02" + // Size = 12 point + $"000C" + // Color, RGB + $"0000 0000 0000" +}; +__EOT__ + close(*RESOURCE); + + return 1; +} + +# pathSplit($pathname) +# +# Splits $pathname into an array of path components. +sub pathSplit($) { + my($pathname); + ($pathname) = @_; + return split(/\//, $pathname); +} + +# setAttributes($root, @attributeList) +# +# @attributeList is an array, each element of which must be in the form +# :. is a list of attributes, per SetFile. is a file +# which is taken as relative to $root (even if it appears as an absolute +# path.) SetFile is called to set the attributes on each file in +# @attributeList. +sub setAttributes($@) { + my(@attributes, $root); + ($root, @attributes) = @_; + my($attribute); + foreach $attribute (@attributes) { + my($attrList, $file, @fileList, @fixedFileList); + ($attrList, @fileList) = split(/:/, $attribute); + if(!defined($attrList) || !@fileList) { + cleanupDie('--attribute requires :'); + } + @fixedFileList=(); + foreach $file (@fileList) { + if($file =~ /^\//) { + push(@fixedFileList, $root.$file); + } + else { + push(@fixedFileList, $root.'/'.$file); + } + } + if(command($gConfig{'cmd_SetFile'}, '-a', $attrList, @fixedFileList)) { + cleanupDie('SetFile failed to set attributes'); + } + } + return; +} + +sub trapSignal($) { + my($signalName); + ($signalName) = @_; + cleanupDie('exiting on SIG'.$signalName); +} + +sub usage() { + print STDERR ( +"usage: pkg-dmg --source \n". +" --target \n". +" [--format ] (default: UDZO)\n". +" [--volname ] (default: same name as source)\n". +" [--tempdir ] (default: same dir as target)\n". +" [--mkdir ] (make directory in image)\n". +" [--copy [:]] (extra files to add)\n". +" [--symlink [:]] (extra symlinks to add)\n". +" [--license ] (plain text license agreement)\n". +" [--resource ] (flat .r files to merge)\n". +" [--icon ] (volume icon)\n". +" [--attribute :] (set file attributes)\n". +" [--idme] (make Internet-enabled image)\n". +" [--sourcefile] (treat --source as a file)\n". +" [--verbosity ] (0, 1, 2; default=2)\n". +" [--dry-run] (print what would be done)\n"); + return; +} diff --git a/app/mac/updater.tar.bz2 b/app/mac/updater.tar.bz2 new file mode 100644 index 0000000000000000000000000000000000000000..60a8289579258c317cf66d4eb5e20f8d8e4f38e7 GIT binary patch literal 253440 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
_qApP z_J^A{dlo+-2wz!tZ|C%R-5Qmw&5h+B)%e7rh~tdpCZ<*us@D4SbGznkI&|&T|GSZ4 zlc&$dPVx9$9QF}IP%9#%ljdlmCaFULNBRx<*2}X~TW9-*^=ehEU}a_^H~JUsNd?e> z!qmdLB1EX)$j+%%Ti32Vu$ke|;iH1X)Ywy#KCw7_=#YVZzV7bPrDOZHt(@$>sBcrV zYDJ}msRCu^K5Fa{i!b~O35?{%rsh@^Dp#vn=hONP8`(KFb8gwjrF}=4QrJ^nc4-ssi^?K*XB>ec(~ zGu!&Y&-Sy=>eaKUTc>u7YE>&&P+D1-nh^7Ur+7UL&?yHIpax?TGjj_|Yo)3}g^HCb zRjMrfa8j{C1(nj;(!$)##2CE)!^|Zupe`YUTw!c%Y-)y|dC`xqP-ulh4&F%ipHX`$ z6_j6=YoJ^M^lVqsr`f0VfNqnhXsd+`ud02cMcjJ7!WqX zE-)lCc%;3Zw@1*h;9j_+whL2-1_TX%N3?(_hl7Jdi{{O37>+GlI15JyC-EA$92}fl zINCTmIk#-lqIt9CPR=$CPR>rvTQVDm_b5hbVK94j_wlvq>1EU3M*7h`Mwq4({-)uNuD9XuJ$|medw(M(qa64qEGr#v zPP3nMzlv}0Xlj0e{&r)+eL{VL)B!>MY>Yj$>Dbn}g`

Fz4oNy99*#4+|dOR-#*e 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

Up$qa4AbvhzZ{$4(NV<63A^NHt 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 XUX{q1u=lT*1HByRxc2lS|+RietdgUWG_T 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 WsRsa{Dms0!#Ao{g000001X)_G1JC#X literal 0 HcmV?d00001 diff --git a/app/modules/zotero-libreoffice-integration b/app/modules/zotero-libreoffice-integration new file mode 160000 index 0000000000..dc73919eff --- /dev/null +++ b/app/modules/zotero-libreoffice-integration @@ -0,0 +1 @@ +Subproject commit dc73919eff2b940918399fb220e5fb7595fed3d2 diff --git a/app/modules/zotero-word-for-mac-integration b/app/modules/zotero-word-for-mac-integration new file mode 160000 index 0000000000..7e24a3d9f2 --- /dev/null +++ b/app/modules/zotero-word-for-mac-integration @@ -0,0 +1 @@ +Subproject commit 7e24a3d9f2f57ccefce09162fc357a958d94be34 diff --git a/app/modules/zotero-word-for-windows-integration b/app/modules/zotero-word-for-windows-integration new file mode 160000 index 0000000000..c3bca35acd --- /dev/null +++ b/app/modules/zotero-word-for-windows-integration @@ -0,0 +1 @@ +Subproject commit c3bca35acd153455e138f30a191e46407b2e9162 diff --git a/app/scripts/5.0_beta_build_and_deploy b/app/scripts/5.0_beta_build_and_deploy new file mode 100755 index 0000000000..ac71df49cf --- /dev/null +++ b/app/scripts/5.0_beta_build_and_deploy @@ -0,0 +1,23 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +CHANNEL="beta" +export SAFARI_APPEX="$ROOT_DIR/../safari-app-extension-builds/beta/ZoteroSafariExtension.appex" + +cd "$SCRIPT_DIR" +./check_requirements + +hash=`./get_repo_branch_hash master` +source_dir=`./get_commit_files $hash` + +function cleanup { + rm -rf $source_dir +} +trap cleanup EXIT + +"$ZOTERO_BUILD_DIR/xpi/build_xpi" -s "$source_dir" -c $CHANNEL -m $hash +./build_and_deploy -d "$ZOTERO_BUILD_DIR/xpi/build/staging" -p $BUILD_PLATFORMS -c $CHANNEL diff --git a/app/scripts/5.0_dev_build_and_deploy b/app/scripts/5.0_dev_build_and_deploy new file mode 100755 index 0000000000..05fe4254ce --- /dev/null +++ b/app/scripts/5.0_dev_build_and_deploy @@ -0,0 +1,24 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +CHANNEL="dev" +BRANCH="master" +export SAFARI_APPEX="$ROOT_DIR/../safari-app-extension-builds/dev/ZoteroSafariExtension.appex" + +cd "$SCRIPT_DIR" +./check_requirements + +hash=`./get_repo_branch_hash $BRANCH` +source_dir=`./get_commit_files $hash` + +function cleanup { + rm -rf $source_dir +} +trap cleanup EXIT + +"$ZOTERO_BUILD_DIR/xpi/build_xpi" -s "$source_dir" -c $CHANNEL -m $hash +./build_and_deploy -d "$ZOTERO_BUILD_DIR/xpi/build/staging" -p $BUILD_PLATFORMS -c $CHANNEL -i 1 diff --git a/app/scripts/5.0_release_build_and_deploy b/app/scripts/5.0_release_build_and_deploy new file mode 100755 index 0000000000..357caf7939 --- /dev/null +++ b/app/scripts/5.0_release_build_and_deploy @@ -0,0 +1,23 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +CHANNEL="release" +BRANCH="master" + +cd "$SCRIPT_DIR" +./check_requirements + +hash=`./get_repo_branch_hash $BRANCH` +source_dir=`./get_commit_files $hash` + +function cleanup { + rm -rf $source_dir +} +trap cleanup EXIT + +"$ZOTERO_BUILD_DIR/xpi/build_xpi" -s "$source_dir" -c $CHANNEL -m $hash +./build_and_deploy -d "$ZOTERO_BUILD_DIR/xpi/build/staging" -p $BUILD_PLATFORMS -c $CHANNEL diff --git a/app/scripts/add_omni_file b/app/scripts/add_omni_file new file mode 100755 index 0000000000..7824be6f73 --- /dev/null +++ b/app/scripts/add_omni_file @@ -0,0 +1,52 @@ +#!/bin/bash +set -euo pipefail + +# +# Zip a file directly into app/omni.ja in staging/ +# +# Zip paths are relative to the current directory, so this should be run from +# the client build/ directory +# + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +function usage { + cat >&2 <&2 <&2 + exit 1 + fi +done + +# Set ZOTERO_PROFILE environment variable to choose profile +if [ -n "${ZOTERO_PROFILE:-}" ]; then + profile="-p $ZOTERO_PROFILE" +fi + +REBUILD=0 +SKIP_BUNDLED_FILES=0 +DEBUGGER=0 +while getopts "rbd" opt; do + case $opt in + r) + REBUILD=1 + ;; + + b) + SKIP_BUNDLED_FILES=1 + ;; + + d) + DEBUGGER=1 + ;; + + \?) + echo "Invalid option: -$OPTARG" >&2 + exit 1 + ;; + esac +done + +if [ $REBUILD -eq 1 ]; then + PARAMS="" + if [ $DEBUGGER -eq 1 ]; then + PARAMS="-t" + fi + + # Check if build watch is running + # If not, run now + if ! ps u | grep scripts/build.js | grep -v grep > /dev/null; then + echo "Running JS build process" + echo + cd $repos_dir/zotero-client + npm run build + echo + fi + + $repos_dir/zotero-standalone-build/scripts/dir_build -q $PARAMS + + if [ "`uname`" = "Darwin" ]; then + # Sign the Word dylib so it works on Apple Silicon + $SCRIPT_DIR/codesign_local $repos_dir/zotero-standalone-build/staging/Zotero.app + fi +fi + +PARAMS="" +if [ $SKIP_BUNDLED_FILES -eq 1 ]; then + PARAMS="$PARAMS -ZoteroSkipBundledFiles" +fi +if [ $DEBUGGER -eq 1 ]; then + PARAMS="$PARAMS -debugger" +fi + +if [ "`uname`" = "Darwin" ]; then + command="Zotero.app/Contents/MacOS/zotero" +elif [ "`uname`" = "Linux" ]; then + command="Zotero_linux-x86_64/zotero" +elif [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then + command="Zotero_win64/zotero.exe" +else + echo "Unknown platform" >&2 + exit 1 +fi + +$repos_dir/zotero-standalone-build/staging/$command $profile -ZoteroDebugText -jsconsole -purgecaches $PARAMS "$@" diff --git a/app/scripts/check_requirements b/app/scripts/check_requirements new file mode 100755 index 0000000000..599ada46ff --- /dev/null +++ b/app/scripts/check_requirements @@ -0,0 +1,144 @@ +#!/bin/bash +set -uo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" +. "$SCRIPT_DIR/bootstrap.sh" + +platform=`get_current_platform` + +FAIL_CMD='echo -e \033[31;1mFAIL\033[0m' +FAILED=0 + +hdr_start=`tput smul` +hdr_stop=`tput rmul` + +echo "${hdr_start}Checking build requirements:${hdr_stop}" +echo + +echo -n "Checking for perl: " +which perl || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for python3: " +which python3 || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for curl: " +which curl || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for wget: " +which wget || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for zip: " +which zip || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for unzip: " +which unzip || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for xz: " +which xz || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for awk: " +which awk || { $FAIL_CMD; FAILED=1; } + +if [ $platform = "w" ]; then + echo -n "Checking for 7z: " + which 7z || { $FAIL_CMD; FAILED=1; } + + echo "Checking for vcruntime140_1.dll: " + for arch in win64; do + echo -n " xulrunner/vc-$arch/vcruntime140_1.dll " + [ -f "$ROOT_DIR/xulrunner/vc-$arch/vcruntime140_1.dll" ] || { $FAIL_CMD; FAILED=1; } + done + echo + + echo -n "Checking for rcedit: " + which rcedit || { $FAIL_CMD; FAILED=1; echo " -- Install with scripts/fetch_rcedit"; } +fi + +echo -n "Checking for PDF tools: " +if [ $platform = "w" ]; then + [ -f "$ROOT_DIR/pdftools/pdftotext-win.exe" ] && ls "$ROOT_DIR/pdftools/pdftotext-win.exe" || { $FAIL_CMD; FAILED=1; } +elif [ $platform = "m" ]; then + [ -f "$ROOT_DIR/pdftools/pdftotext-mac" ] && ls "$ROOT_DIR/pdftools/pdftotext-mac" || { $FAIL_CMD; FAILED=1; } +elif [ $platform = "l" ]; then + [ -f "$ROOT_DIR/pdftools/pdftotext-linux-x86_64" ] && ls "$ROOT_DIR/pdftools/pdftotext-linux-x86_64" || { $FAIL_CMD; FAILED=1; } +fi + +if [ $platform = "w" ]; then + echo + echo "${hdr_start}Checking Windows packaging requirements:${hdr_stop}" + echo + + echo -n "Checking for upx: " + which upx || { $FAIL_CMD; FAILED=1; } + + echo -n "Checking for uuidgen: " + which uuidgen || { $FAIL_CMD; FAILED=1; } + + echo -n "Checking for signtool: " + if [ -x "`cygpath -u \"$SIGNTOOL\"`" ]; then + echo "`cygpath -u \"$SIGNTOOL\"`" + else + $FAIL_CMD + FAILED=1 + fi + + echo -n "Checking for Unicode NSIS: " + if [ -x "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" ]; then + echo "`cygpath -u \"${NSIS_DIR}makensis.exe\"`" + else + $FAIL_CMD + FAILED=1 + fi + + plugin_path=$(cd "$NSIS_DIR\\Plugins" && pwd) + plugins="AppAssocReg ApplicationID InvokeShellVerb ShellLink UAC" + echo "Checking for NSIS plugins in $plugin_path" + for i in $plugins; do + echo -n " $i.dll: " + if [ -f "$plugin_path/$i.dll" ]; then + echo OK + else + $FAIL_CMD + FAILED=1 + fi + done +fi + +if [ $platform = "m" ]; then + echo + echo "${hdr_start}Checking Mac packaging requirements:${hdr_stop}" + echo + + echo -n "Checking for codesign: " + which /usr/bin/codesign || { $FAIL_CMD; FAILED=1; } +fi + +echo +echo "${hdr_start}Checking distribution requirements:${hdr_stop}" +echo + +echo -n "Checking for Mozilla ARchive (MAR) tool: " +which mar || { $FAIL_CMD; FAILED=1; echo " -- Install with fetch_mar_tools"; } + +echo -n "Checking for mbsdiff: " +which mbsdiff || { $FAIL_CMD; FAILED=1; echo " -- Install with fetch_mar_tools"; } + +echo -n "Checking for rsync: " +which rsync || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for sha512sum/shasum: " +which sha512sum 2>/dev/null || which shasum 2>/dev/null || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for AWS CLI: " +which aws || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for AWS S3 access: " +aws s3 ls $S3_BUCKET/$S3_DIST_PATH | sed 's/^[[:blank:]]*//' || { $FAIL_CMD; FAILED=1; } + +echo -n "Checking for deploy host directory access: " +ssh $DEPLOY_HOST ls -d $DEPLOY_PATH || { $FAIL_CMD; FAILED=1; } + + +exit $FAILED diff --git a/app/scripts/codesign_local b/app/scripts/codesign_local new file mode 100755 index 0000000000..6b1c239633 --- /dev/null +++ b/app/scripts/codesign_local @@ -0,0 +1,42 @@ +#!/bin/bash +set -euo pipefail + +# Perform ad-hoc code signing of Zotero.app for local usage +# +# Currently we sign only the Word dylib, since that's necessary for Zotero developers to work on +# Word integration on Apple Silicon. If we discover other problems, we can uncomment some of the +# other lines. If you're making a custom build, you can modify this file to sign the entire build +# instead of just the bare minimum needed for development. + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +if [ -z "${1:-}" ]; then + echo "Usage: $0 path/to/staging/Zotero.app" + exit 1 +fi + +APPDIR=$1 +DEVELOPER_ID="-" + +entitlements_file="$ROOT_DIR/mac/entitlements.xml" +#/usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" \ +# "$APPDIR/Contents/MacOS/pdftotext" \ +# "$APPDIR/Contents/MacOS/pdfinfo" \ +# "$APPDIR/Contents/MacOS/XUL" \ +# "$APPDIR/Contents/MacOS/updater.app/Contents/MacOS/org.mozilla.updater" +#find "$APPDIR/Contents" -name '*.dylib' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \; +#find "$APPDIR/Contents" -name '*.app' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \; +#/usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" "$APPDIR/Contents/MacOS/zotero" + +# Skip signing of Safari extension, since it's not present for local builds + +# Sign final app package +#echo +#/usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" "$APPDIR" + +# Verify app +#/usr/bin/codesign --verify -vvvv "$APPDIR" + +find "$APPDIR/Contents" -name 'libZoteroWordIntegration.dylib' -exec /usr/bin/codesign --force --options runtime --entitlements "$entitlements_file" --sign "$DEVELOPER_ID" {} \; diff --git a/app/scripts/dir_build b/app/scripts/dir_build new file mode 100755 index 0000000000..41606ff245 --- /dev/null +++ b/app/scripts/dir_build @@ -0,0 +1,82 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +function usage { + cat >&2 <&2 + exit 1 + ;; + esac +done + +if [[ -z $PLATFORM ]]; then + if [ "`uname`" = "Darwin" ]; then + PLATFORM="m" + elif [ "`uname`" = "Linux" ]; then + PLATFORM="l" + elif [ "`uname -o 2> /dev/null`" = "Cygwin" ]; then + PLATFORM="w" + fi +fi + +CHANNEL="source" + +VERSION=`perl -ne 'print and last if s/.*(.{3}).+/\1/;' "$ZOTERO_SOURCE_DIR/install.rdf"` +if [ $VERSION = "4.0" ]; then + "$ZOTERO_BUILD_DIR/xpi/build_xpi_4.0" "$ZOTERO_SOURCE_DIR" $CHANNEL + "$ROOT_DIR/build.sh" -f "$ZOTERO_BUILD_DIR/xpi/build/zotero-build.xpi" -p $PLATFORM -c $CHANNEL -s +else + PARAMS="" + if [ $DEVTOOLS -eq 1 ]; then + PARAMS+=" -t" + fi + if [ $quick_build -eq 1 ]; then + PARAMS+=" -q" + fi + + hash=`git -C "$ZOTERO_SOURCE_DIR" rev-parse --short HEAD` + + "$ZOTERO_BUILD_DIR/xpi/build_xpi" -s "$ZOTERO_SOURCE_DIR/build" -c $CHANNEL -m $hash + "$ROOT_DIR/build.sh" -d "$ZOTERO_BUILD_DIR/xpi/build/staging" -p $PLATFORM -c $CHANNEL -s $PARAMS +fi + +echo Done diff --git a/app/scripts/fetch_rcedit b/app/scripts/fetch_rcedit new file mode 100755 index 0000000000..89ac62bd10 --- /dev/null +++ b/app/scripts/fetch_rcedit @@ -0,0 +1,11 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" + +cd "$ROOT_DIR" + +mkdir -p "xulrunner/bin" +curl -L -o "xulrunner/bin/rcedit.exe" https://github.com/electron/rcedit/releases/download/v1.1.1/rcedit-x86.exe +chmod 755 xulrunner/bin/rcedit diff --git a/app/scripts/get_commit_files b/app/scripts/get_commit_files new file mode 100755 index 0000000000..53368e4a32 --- /dev/null +++ b/app/scripts/get_commit_files @@ -0,0 +1,21 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +if [ -z "${1:-}" ]; then + echo "Commit hash not provided" + exit 1 +fi +hash="$1" + +tmpdir=`mktemp -d` + +cd $tmpdir +wget -O build.zip "https://$S3_BUCKET.s3.amazonaws.com/$S3_CI_ZIP_PATH/$hash.zip" >&2 \ + || (echo "ZIP file not found for commit '$hash'" && exit 1) +unzip build.zip >&2 +rm build.zip +echo $tmpdir \ No newline at end of file diff --git a/app/scripts/get_repo_branch_hash b/app/scripts/get_repo_branch_hash new file mode 100755 index 0000000000..aedfbaa00a --- /dev/null +++ b/app/scripts/get_repo_branch_hash @@ -0,0 +1,14 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +if [ -z "${1:-}" ]; then + echo "Usage: $0 branch" + exit 1 +fi +branch=$1 + +git ls-remote --exit-code $SOURCE_REPO_URL $branch | cut -f 1 diff --git a/app/scripts/manage_incrementals b/app/scripts/manage_incrementals new file mode 100755 index 0000000000..5127df859d --- /dev/null +++ b/app/scripts/manage_incrementals @@ -0,0 +1,83 @@ +#!/bin/bash +# +# Manage list of deployed version numbers for a channel in order to generate incremental builds +# +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +function usage { + cat >&2 <&2 + +# Add version to file and reupload +if [ "$VERSION" ]; then + echo "Adding $VERSION to incrementals-$PLATFORM" + echo $VERSION >> $INCR_PATH + aws s3 cp $INCR_PATH $S3_URL +# Show last n versions +elif [ "$NUM_VERSIONS" ]; then + tail -n $NUM_VERSIONS $INCR_PATH +fi +rm $INCR_PATH diff --git a/app/scripts/notarization_info b/app/scripts/notarization_info new file mode 100755 index 0000000000..8865be4614 --- /dev/null +++ b/app/scripts/notarization_info @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +function usage { + echo "Usage: $0 id" + exit 1 +} + +id=${1:-} +if [[ -z "$id" ]]; then + usage +fi + +xcrun altool --notarization-info "$id" -u "$NOTARIZATION_USER" -p "$NOTARIZATION_PASSWORD" --output-format xml diff --git a/app/scripts/notarization_stapler b/app/scripts/notarization_stapler new file mode 100755 index 0000000000..0ef087c790 --- /dev/null +++ b/app/scripts/notarization_stapler @@ -0,0 +1,19 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +function usage { + echo "Usage: $0 file" + exit 1 +} + +file=${1:-} +if [[ -z "$file" ]]; then + usage +fi + +echo "Stapling $file" +xcrun stapler staple $file diff --git a/app/scripts/notarization_status b/app/scripts/notarization_status new file mode 100755 index 0000000000..dd6aba6431 --- /dev/null +++ b/app/scripts/notarization_status @@ -0,0 +1,18 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +function usage { + echo "Usage: $0 id" + exit 1 +} + +id=${1:-} +if [[ -z "$id" ]]; then + usage +fi + +$SCRIPT_DIR/notarization_info "$id" | plutil -extract notarization-info.Status xml1 -o - - | sed -n "s/.*\(.*\)<\/string>.*/\1/p" diff --git a/app/scripts/notarize_mac_app b/app/scripts/notarize_mac_app new file mode 100755 index 0000000000..fcfa8d1603 --- /dev/null +++ b/app/scripts/notarize_mac_app @@ -0,0 +1,19 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +function usage { + echo "Usage: $0 file" + exit 1 +} + +file=${1:-} +if [[ -z "$file" ]]; then + usage +fi + +echo "Uploading ${file##*/} to Apple for notarization" >&2 +xcrun altool --notarize-app --primary-bundle-id "$NOTARIZATION_BUNDLE_ID" --username "$NOTARIZATION_USER" --password "$NOTARIZATION_PASSWORD" --file $file --output-format xml diff --git a/app/scripts/optimizejars.py b/app/scripts/optimizejars.py new file mode 100644 index 0000000000..99d04a8d75 --- /dev/null +++ b/app/scripts/optimizejars.py @@ -0,0 +1,376 @@ +# ***** BEGIN LICENSE BLOCK ***** +# Version: MPL 1.1/GPL 2.0/LGPL 2.1 +# +# The contents of this file are subject to the Mozilla Public License Version +# 1.1 (the "License"); you may not use this file except in compliance with +# the License. You may obtain a copy of the License at +# http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS IS" basis, +# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +# for the specific language governing rights and limitations under the +# License. +# +# The Original Code is mozilla.org code +# +# The Initial Developer of the Original Code is +# Mozilla Foundation. +# Portions created by the Initial Developer are Copyright (C) 2010 +# the Initial Developer. All Rights Reserved. +# +# Contributor(s): +# Taras Glek +# +# Alternatively, the contents of this file may be used under the terms of +# either the GNU General Public License Version 2 or later (the "GPL"), or +# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +# in which case the provisions of the GPL or the LGPL are applicable instead +# of those above. If you wish to allow use of your version of this file only +# under the terms of either the GPL or the LGPL, and not to allow others to +# use your version of this file under the terms of the MPL, indicate your +# decision by deleting the provisions above and replace them with the notice +# and other provisions required by the GPL or the LGPL. If you do not delete +# the provisions above, a recipient may use your version of this file under +# the terms of any one of the MPL, the GPL or the LGPL. +# +# ***** END LICENSE BLOCK ***** + +import sys, os, subprocess, struct, re + +local_file_header = [ + ("signature", "uint32"), + ("min_version", "uint16"), + ("general_flag", "uint16"), + ("compression", "uint16"), + ("lastmod_time", "uint16"), + ("lastmod_date", "uint16"), + ("crc32", "uint32"), + ("compressed_size", "uint32"), + ("uncompressed_size", "uint32"), + ("filename_size", "uint16"), + ("extra_field_size", "uint16"), + ("filename", "filename_size"), + ("extra_field", "extra_field_size"), + ("data", "compressed_size") +] + +cdir_entry = [ + ("signature", "uint32"), + ("creator_version", "uint16"), + ("min_version", "uint16"), + ("general_flag", "uint16"), + ("compression", "uint16"), + ("lastmod_time", "uint16"), + ("lastmod_date", "uint16"), + ("crc32", "uint32"), + ("compressed_size", "uint32"), + ("uncompressed_size", "uint32"), + ("filename_size", "uint16"), + ("extrafield_size", "uint16"), + ("filecomment_size", "uint16"), + ("disknum", "uint16"), + ("internal_attr", "uint16"), + ("external_attr", "uint32"), + ("offset", "uint32"), + ("filename", "filename_size"), + ("extrafield", "extrafield_size"), + ("filecomment", "filecomment_size"), +] + +cdir_end = [ + ("signature", "uint32"), + ("disk_num", "uint16"), + ("cdir_disk", "uint16"), + ("disk_entries", "uint16"), + ("cdir_entries", "uint16"), + ("cdir_size", "uint32"), + ("cdir_offset", "uint32"), + ("comment_size", "uint16"), +] + +type_mapping = { "uint32":"I", "uint16":"H"} + +def format_struct (format): + string_fields = {} + fmt = "<" + for (name,value) in iter(format): + try: + fmt += type_mapping[value][0] + except KeyError: + string_fields[name] = value + return (fmt, string_fields) + +def size_of(format): + return struct.calcsize(format_struct(format)[0]) + +class MyStruct: + def __init__(self, format, string_fields): + self.__dict__["struct_members"] = {} + self.__dict__["format"] = format + self.__dict__["string_fields"] = string_fields + + def addMember(self, name, value): + self.__dict__["struct_members"][name] = value + + def __getattr__(self, item): + try: + return self.__dict__["struct_members"][item] + except: + pass + print("no %s" %item) + print(self.__dict__["struct_members"]) + raise AttributeError + + def __setattr__(self, item, value): + if item in self.__dict__["struct_members"]: + self.__dict__["struct_members"][item] = value + else: + raise AttributeError + + def pack(self): + extra_data = b"" + values = [] + string_fields = self.__dict__["string_fields"] + struct_members = self.__dict__["struct_members"] + format = self.__dict__["format"] + for (name,_) in format: + if name in string_fields: + if not isinstance(struct_members[name], bytes): + struct_members[name] = struct_members[name].encode('utf-8') + extra_data = extra_data + struct_members[name] + else: + values.append(struct_members[name]); + return struct.pack(format_struct(format)[0], *values) + extra_data + +ENDSIG = 0x06054b50 + +def assert_true(cond, msg): + if not cond: + raise Exception(msg) + exit(1) + +class BinaryBlob: + def __init__(self, f): + self.data = open(f, "rb").read() + self.offset = 0 + self.length = len(self.data) + + def readAt(self, pos, length): + self.offset = pos + length + return self.data[pos:self.offset] + + def read_struct (self, format, offset = None): + if offset == None: + offset = self.offset + (fstr, string_fields) = format_struct(format) + size = struct.calcsize(fstr) + data = self.readAt(offset, size) + ret = struct.unpack(fstr, data) + retstruct = MyStruct(format, string_fields) + i = 0 + for (name,_) in iter(format): + member_desc = None + if not name in string_fields: + member_data = ret[i] + i = i + 1 + else: + # zip has data fields which are described by other struct fields, this does + # additional reads to fill em in + member_desc = string_fields[name] + member_data = self.readAt(self.offset, retstruct.__getattr__(member_desc)) + retstruct.addMember(name, member_data) + # sanity check serialization code + data = self.readAt(offset, self.offset - offset) + out_data = retstruct.pack() + assert_true(out_data == data, "Serialization fail %d !=%d"% (len(out_data), len(data))) + return retstruct + +def optimizejar(jar, outjar, inlog = None): + if inlog is not None: + inlog = open(inlog).read().rstrip() + # in the case of an empty log still move the index forward + if len(inlog) == 0: + inlog = [] + else: + inlog = inlog.split("\n") + outlog = [] + jarblob = BinaryBlob(jar) + dirend = jarblob.read_struct(cdir_end, jarblob.length - size_of(cdir_end)) + assert_true(dirend.signature == ENDSIG, "no signature in the end"); + cdir_offset = dirend.cdir_offset + readahead = 0 + if inlog is None and cdir_offset == 4: + readahead = struct.unpack("= old_entry_offset + len(data): + outlog.append(entry.filename) + reordered_count += 1 + + if inlog is None: + dirend.cdir_offset = out_offset + + if dups_found > 0: + print("WARNING: Found %d duplicate files taking %d bytes"%(dups_found, dupe_bytes)) + + dirend.cdir_size = len(cdir_data) + dirend.disk_entries = dirend.cdir_entries + dirend_data = dirend.pack() + assert_true(size_of(cdir_end) == len(dirend_data), "Failed to serialize directory end correctly. Serialized size;%d, expected:%d"%(len(dirend_data), size_of(cdir_end))); + + outfd.seek(dirend.cdir_offset) + outfd.write(cdir_data) + outfd.write(dirend_data) + + # for ordered jars the central directory is written in the begining of the file, so a second central-directory + # entry has to be written in the end of the file + if inlog is not None: + outfd.seek(0) + outfd.write(struct.pack("&2 + exit 1 +} + +CHANNEL="${1:-}" +VERSION="${2:-}" + +if [[ -z "$CHANNEL" ]] || [[ -z "$VERSION" ]]; then + usage +fi + +url="s3://$S3_BUCKET/$S3_DIST_PATH/$CHANNEL/$VERSION/" +aws s3 sync --exclude "files-*" --exclude build_id "$DIST_DIR" $url diff --git a/app/update-packaging/add_version_info b/app/update-packaging/add_version_info new file mode 100755 index 0000000000..5f07932d4b --- /dev/null +++ b/app/update-packaging/add_version_info @@ -0,0 +1,66 @@ +#!/usr/bin/env python3 +""" +Update a builds manifest with info on a given build +""" +import argparse +import os +import sys +import shutil +import json +import traceback + +DETAILS_URLS = { + '4.0': 'https://www.zotero.org/support/4.0_changelog', + '5.0': 'https://www.zotero.org/support/5.0_changelog', + '6.0': 'https://www.zotero.org/support/6.0_changelog', + '7.0': 'https://www.zotero.org/support/7.0_changelog' +} +MAJOR = None + +parser = argparse.ArgumentParser( + description='Update a builds manifest with info on a given build', + formatter_class=argparse.ArgumentDefaultsHelpFormatter) + +parser.add_argument('-f', '--file', required=True, help="path to updates.json") +parser.add_argument('-v', '--version', required=True, help='version number of build') +parser.add_argument('-b', '--build_id', required=True, help="build ID ('20160801142343')") + +args = parser.parse_args() + +def main(): + try: + file = args.file + version = args.version + + # Back up JSON file + shutil.copy2(file, file + '.bak') + + # Read in existing file + with open(file) as f: + updates = json.loads(f.read()) + + updates.append({ + 'version': version, + 'buildID': args.build_id, + 'detailsURL': DETAILS_URLS[version[0:3]], + 'major': MAJOR + }) + + # Keep last 5 entries + updates = updates[-5:] + + # Write new file + updates = json.dumps(updates, indent=2) + with open(file, 'w') as f: + f.write(updates + "\n") + + print(updates) + + return 0 + + except Exception as err: + sys.stderr.write("\n" + traceback.format_exc()) + return 1 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/app/update-packaging/build_autoupdate.sh b/app/update-packaging/build_autoupdate.sh new file mode 100755 index 0000000000..f01740faaa --- /dev/null +++ b/app/update-packaging/build_autoupdate.sh @@ -0,0 +1,326 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" +UPDATE_STAGE_DIR="$SCRIPT_DIR/staging" + +function usage { + cat >&2 < /dev/null`" = "Cygwin" ]; then + WIN_NATIVE=1 +else + WIN_NATIVE=0 +fi + +BUILD_FULL=0 +BUILD_INCREMENTAL=0 +FROM="" +CHANNEL="" +BUILD_MAC=0 +BUILD_WIN=0 +BUILD_LINUX=0 +USE_LOCAL_TO=0 +while getopts "i:c:p:fl" opt; do + case $opt in + i) + FROM="$OPTARG" + BUILD_INCREMENTAL=1 + ;; + c) + CHANNEL="$OPTARG" + ;; + p) + for i in `seq 0 1 $((${#OPTARG}-1))` + do + case ${OPTARG:i:1} in + m) BUILD_MAC=1;; + w) BUILD_WIN=1;; + l) BUILD_LINUX=1;; + *) + echo "$0: Invalid platform option ${OPTARG:i:1}" + usage + ;; + esac + done + ;; + f) + BUILD_FULL=1 + ;; + l) + USE_LOCAL_TO=1 + ;; + *) + usage + ;; + esac + shift $((OPTIND-1)); OPTIND=1 +done + +shift $(($OPTIND - 1)) +TO=${1:-} + +if [ -z "$TO" ]; then + usage +fi + +if [ -z "$FROM" ] && [ $BUILD_FULL -eq 0 ]; then + usage +fi + +if [[ $BUILD_INCREMENTAL -eq 1 ]] && [[ -z "$CHANNEL" ]]; then + echo "Channel not provided for incremental builds" >&2 + exit 1 +fi + +# Require at least one platform +if [[ $BUILD_MAC == 0 ]] && [[ $BUILD_WIN == 0 ]] && [[ $BUILD_LINUX == 0 ]]; then + usage +fi + +rm -rf "$UPDATE_STAGE_DIR" +mkdir "$UPDATE_STAGE_DIR" + +INCREMENTALS_FOUND=0 +for version in "$FROM" "$TO"; do + if [[ $version == "$TO" ]] && [[ $INCREMENTALS_FOUND == 0 ]] && [[ $BUILD_FULL == 0 ]]; then + exit + fi + + if [ -z "$version" ]; then + continue + fi + + echo "Getting Zotero version $version" + + versiondir="$UPDATE_STAGE_DIR/$version" + + # + # Use main build script's staging directory for TO files rather than downloading the given version. + # + # The caller must ensure that the files in ../staging match the platforms and version given. + if [[ $version == $TO && $USE_LOCAL_TO == "1" ]]; then + if [ ! -d "$STAGE_DIR" ]; then + echo "Can't find local TO dir $STAGE_DIR" + exit 1 + fi + + echo "Using files from $STAGE_DIR" + ln -s "$STAGE_DIR" "$versiondir" + continue + fi + + # + # Otherwise, download version from S3 + # + mkdir -p "$versiondir" + cd "$versiondir" + + MAC_ARCHIVE="Zotero-${version}.dmg" + WIN32_ARCHIVE="Zotero-${version}_win32.zip" + WIN64_ARCHIVE="Zotero-${version}_x64.zip" + LINUX_X86_ARCHIVE="Zotero-${version}_linux-i686.tar.bz2" + LINUX_X86_64_ARCHIVE="Zotero-${version}_linux-x86_64.tar.bz2" + + CACHE_DIR="$ROOT_DIR/cache" + if [ ! -e "$CACHE_DIR" ]; then + mkdir "$CACHE_DIR" + fi + + for archive in "$MAC_ARCHIVE" "$WIN32_ARCHIVE" "$WIN64_ARCHIVE" "$LINUX_X86_ARCHIVE" "$LINUX_X86_64_ARCHIVE"; do + if [[ $archive = "$MAC_ARCHIVE" ]] && [[ $BUILD_MAC != 1 ]]; then + continue + fi + if [[ $archive = "$WIN32_ARCHIVE" ]] && [[ $BUILD_WIN != 1 ]]; then + continue + fi + if [[ $archive = "$WIN64_ARCHIVE" ]] && [[ $BUILD_WIN != 1 ]]; then + continue + fi + if [[ $archive = "$LINUX_X86_ARCHIVE" ]] && [[ $BUILD_LINUX != 1 ]]; then + continue + fi + if [[ $archive = "$LINUX_X86_64_ARCHIVE" ]] && [[ $BUILD_LINUX != 1 ]]; then + continue + fi + + ETAG_FILE="$CACHE_DIR/$archive.etag" + + # Check cache for archive + if [[ -f "$CACHE_DIR/$archive" ]] && [[ -f "$CACHE_DIR/$archive.etag" ]]; then + ETAG="`cat $ETAG_FILE | tr '\n' ' '`" + else + ETAG="" + fi + + rm -f $archive + # URL-encode '+' in beta version numbers + ENCODED_VERSION=`urlencode $version` + ENCODED_ARCHIVE=`urlencode $archive` + URL="https://$S3_BUCKET.s3.amazonaws.com/$S3_DIST_PATH/$CHANNEL/$ENCODED_VERSION/$ENCODED_ARCHIVE" + echo "Fetching $URL" + set +e + # Cached version is available + if [ -n "$ETAG" ]; then + NEW_ETAG=$(wget -nv -S --header "If-None-Match: $ETAG" $URL 2>&1 | awk '/ *ETag: */ {print $2}') + + # If ETag didn't match, cache newly downloaded version + if [ -f $archive ]; then + echo "ETag for $archive didn't match! -- using new version" + rm -f "$CACHE_DIR/$archive.etag" + cp $archive "$CACHE_DIR/" + echo "$NEW_ETAG" > "$CACHE_DIR/$archive.etag" + # If ETag matched (or there was another error), use cached version + else + echo "Using cached $archive" + cp "$CACHE_DIR/$archive" . + fi + else + NEW_ETAG=$(wget -nv -S $URL 2>&1 | awk '/ *ETag: */ {print $2}') + + # Save archive to cache + rm -f "$CACHE_DIR/$archive.etag" + cp $archive "$CACHE_DIR/" + echo "$NEW_ETAG" > "$CACHE_DIR/$archive.etag" + fi + set -e + done + + # Delete cached files older than 14 days + find "$CACHE_DIR" -ctime +14 -delete + + # Unpack Zotero.app + if [ $BUILD_MAC == 1 ]; then + if [ -f "$MAC_ARCHIVE" ]; then + set +e + hdiutil detach -quiet /Volumes/Zotero 2>/dev/null + set -e + hdiutil attach -quiet "$MAC_ARCHIVE" + cp -R /Volumes/Zotero/Zotero.app "$versiondir" + rm "$MAC_ARCHIVE" + hdiutil detach -quiet /Volumes/Zotero + INCREMENTALS_FOUND=1 + else + echo "$MAC_ARCHIVE not found" + fi + fi + + # Unpack Windows zips + if [ $BUILD_WIN == 1 ]; then + if [[ -f "$WIN32_ARCHIVE" ]] && [[ -f "$WIN64_ARCHIVE" ]]; then + for build in "$WIN32_ARCHIVE" "$WIN64_ARCHIVE"; do + unzip -q "$build" + rm "$build" + done + INCREMENTALS_FOUND=1 + else + echo "$WIN32_ARCHIVE/$WIN64_ARCHIVE not found" + fi + fi + + # Unpack Linux tarballs + if [ $BUILD_LINUX == 1 ]; then + if [[ -f "$LINUX_X86_ARCHIVE" ]] && [[ -f "$LINUX_X86_64_ARCHIVE" ]]; then + for build in "$LINUX_X86_ARCHIVE" "$LINUX_X86_64_ARCHIVE"; do + tar -xjf "$build" + rm "$build" + done + INCREMENTALS_FOUND=1 + else + echo "$LINUX_X86_ARCHIVE/$LINUX_X86_64_ARCHIVE not found" + fi + fi + + echo +done + +CHANGES_MADE=0 +for build in "mac" "win32" "win64" "linux-i686" "linux-x86_64"; do + if [[ $build == "mac" ]]; then + if [[ $BUILD_MAC == 0 ]]; then + continue + fi + dir="Zotero.app" + else + if [[ $build == "win32" ]] || [[ $build == "win64" ]] && [[ $BUILD_WIN == 0 ]]; then + continue + fi + if [[ $build == "linux-i686" ]] || [[ $build == "linux-x86_64" ]] && [[ $BUILD_LINUX == 0 ]]; then + continue + fi + dir="Zotero_$build" + touch "$UPDATE_STAGE_DIR/$TO/$dir/precomplete" + cp "$SCRIPT_DIR/removed-files_$build" "$UPDATE_STAGE_DIR/$TO/$dir/removed-files" + fi + if [[ $BUILD_INCREMENTAL == 1 ]] && [[ -d "$UPDATE_STAGE_DIR/$FROM/$dir" ]]; then + echo + echo "Building incremental $build update from $FROM to $TO" + + # mbsdiff fails on paths with symlink + if [ $WIN_NATIVE == 1 ]; then + cur=`pwd` + from_dir="`realpath --relative-to=\"$cur\" \"$UPDATE_STAGE_DIR/$FROM/$dir\"`" + to_dir="`realpath --relative-to=\"$cur\" \"$UPDATE_STAGE_DIR/$TO/$dir\"`" + else + from_dir="$UPDATE_STAGE_DIR/$FROM/$dir" + to_dir="$UPDATE_STAGE_DIR/$TO/$dir" + fi + + "$SCRIPT_DIR/make_incremental_update.sh" "$DIST_DIR/Zotero-${TO}-${FROM}_$build.mar" "$from_dir" "$to_dir" + CHANGES_MADE=1 + fi + if [[ $BUILD_FULL == 1 ]]; then + echo + echo "Building full $build update for $TO" + "$SCRIPT_DIR/make_full_update.sh" "$DIST_DIR/Zotero-${TO}-full_$build.mar" "$UPDATE_STAGE_DIR/$TO/$dir" + CHANGES_MADE=1 + fi +done + +rm -rf "$UPDATE_STAGE_DIR" + +# Update file manifests +if [ $CHANGES_MADE -eq 1 ]; then + # Cygwin has sha512sum, macOS has shasum, Linux has both + if [[ -n "`which sha512sum 2> /dev/null`" ]]; then + SHACMD="sha512sum" + else + SHACMD="shasum -a 512" + fi + + cd "$DIST_DIR" + for platform in "mac" "win" "linux"; do + file=files-$platform + rm -f $file + for fn in `find . -name "*$platform*.mar" -exec basename {} \;`; do + size=`wc -c "$fn" | awk '{print $1}'` + hash=`$SHACMD "$fn" | awk '{print $1}'` + echo $fn $hash $size >> $file + done + done +fi diff --git a/app/update-packaging/common.sh b/app/update-packaging/common.sh new file mode 100644 index 0000000000..abb0e572dd --- /dev/null +++ b/app/update-packaging/common.sh @@ -0,0 +1,215 @@ +#!/bin/bash +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# +# Code shared by update packaging scripts. +# Author: Darin Fisher +# + +# ----------------------------------------------------------------------------- +# By default just assume that these tools exist on our path +MAR=${MAR:-mar} +BZIP2=${BZIP2:-bzip2} +MBSDIFF=${MBSDIFF:-mbsdiff} + +# ----------------------------------------------------------------------------- +# Helper routines + +notice() { + echo "$*" 1>&2 +} + +get_file_size() { + info=($(ls -ln "$1")) + echo ${info[4]} +} + +copy_perm() { + reference="$1" + target="$2" + + if [ -x "$reference" ]; then + chmod 0755 "$target" + else + chmod 0644 "$target" + fi +} + +make_add_instruction() { + f="$1" + filev2="$2" + # The third param will be an empty string when a file add instruction is only + # needed in the version 2 manifest. This only happens when the file has an + # add-if-not instruction in the version 3 manifest. This is due to the + # precomplete file prior to the version 3 manifest having a remove instruction + # for this file so the file is removed before applying a complete update. + filev3="$3" + + # Used to log to the console + if [ $4 ]; then + forced=" (forced)" + else + forced= + fi + + # Changed by Zotero for -e + is_extension=$(echo "$f" | grep -c 'distribution/extensions/.*/') || true + if [ $is_extension = "1" ]; then + # Use the subdirectory of the extensions folder as the file to test + # before performing this add instruction. + testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/') + notice " add-if \"$testdir\" \"$f\"" + echo "add-if \"$testdir\" \"$f\"" >> $filev2 + if [ ! $filev3 = "" ]; then + echo "add-if \"$testdir\" \"$f\"" >> $filev3 + fi + else + notice " add \"$f\"$forced" + echo "add \"$f\"" >> $filev2 + if [ ! $filev3 = "" ]; then + echo "add \"$f\"" >> $filev3 + fi + fi +} + +check_for_add_if_not_update() { + add_if_not_file_chk="$1" + + if [ `basename $add_if_not_file_chk` = "channel-prefs.js" -o \ + `basename $add_if_not_file_chk` = "update-settings.ini" ]; then + ## "true" *giggle* + return 0; + fi + ## 'false'... because this is bash. Oh yay! + return 1; +} + +check_for_add_to_manifestv2() { + add_if_not_file_chk="$1" + + if [ `basename $add_if_not_file_chk` = "update-settings.ini" ]; then + ## "true" *giggle* + return 0; + fi + ## 'false'... because this is bash. Oh yay! + return 1; +} + +make_add_if_not_instruction() { + f="$1" + filev3="$2" + + notice " add-if-not \"$f\" \"$f\"" + echo "add-if-not \"$f\" \"$f\"" >> $filev3 +} + +make_patch_instruction() { + f="$1" + filev2="$2" + filev3="$3" + + is_extension=$(echo "$f" | grep -c 'distribution/extensions/.*/') || true + if [ $is_extension = "1" ]; then + # Use the subdirectory of the extensions folder as the file to test + # before performing this add instruction. + testdir=$(echo "$f" | sed 's/\(.*distribution\/extensions\/[^\/]*\)\/.*/\1/') + notice " patch-if \"$testdir\" \"$f.patch\" \"$f\"" + echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> $filev2 + echo "patch-if \"$testdir\" \"$f.patch\" \"$f\"" >> $filev3 + else + notice " patch \"$f.patch\" \"$f\"" + echo "patch \"$f.patch\" \"$f\"" >> $filev2 + echo "patch \"$f.patch\" \"$f\"" >> $filev3 + fi +} + +append_remove_instructions() { + dir="$1" + filev2="$2" + filev3="$3" + + if [ -f "$dir/removed-files" ]; then + listfile="$dir/removed-files" + elif [ -f "$dir/Contents/Resources/removed-files" ]; then + listfile="$dir/Contents/Resources/removed-files" + fi + if [ -n "$listfile" ]; then + # Changed by Zotero: Use subshell and disable filename globbing to prevent bash from expanding + # entries in removed-files with paths from the root (e.g., 'xulrunner/*') + ( + set -f + # Map spaces to pipes so that we correctly handle filenames with spaces. + files=($(cat "$listfile" | tr " " "|" | sort -r)) + num_files=${#files[*]} + for ((i=0; $i<$num_files; i=$i+1)); do + # Map pipes back to whitespace and remove carriage returns + f=$(echo ${files[$i]} | tr "|" " " | tr -d '\r') + # Trim whitespace + f=$(echo $f) + # Exclude blank lines. + if [ -n "$f" ]; then + # Exclude comments + if [ ! $(echo "$f" | grep -c '^#') = 1 ]; then + if [ $(echo "$f" | grep -c '\/$') = 1 ]; then + notice " rmdir \"$f\"" + echo "rmdir \"$f\"" >> $filev2 + echo "rmdir \"$f\"" >> $filev3 + elif [ $(echo "$f" | grep -c '\/\*$') = 1 ]; then + # Remove the * + f=$(echo "$f" | sed -e 's:\*$::') + notice " rmrfdir \"$f\"" + echo "rmrfdir \"$f\"" >> $filev2 + echo "rmrfdir \"$f\"" >> $filev3 + else + notice " remove \"$f\"" + echo "remove \"$f\"" >> $filev2 + echo "remove \"$f\"" >> $filev3 + fi + fi + fi + done + ) + fi +} + +# List all files in the current directory, stripping leading "./" +# Pass a variable name and it will be filled as an array. +list_files() { + count=0 + + find . -type f \ + ! -name "update.manifest" \ + ! -name "updatev2.manifest" \ + ! -name "updatev3.manifest" \ + ! -name "temp-dirlist" \ + ! -name "temp-filelist" \ + | sed 's/\.\/\(.*\)/\1/' \ + | sort -r > "temp-filelist" + while read file; do + eval "${1}[$count]=\"$file\"" + # Changed for Zotero to avoid eval as 1 + #(( count++ )) + (( ++count )) + done < "temp-filelist" + rm "temp-filelist" +} + +# List all directories in the current directory, stripping leading "./" +list_dirs() { + count=0 + + find . -type d \ + ! -name "." \ + ! -name ".." \ + | sed 's/\.\/\(.*\)/\1/' \ + | sort -r > "temp-dirlist" + while read dir; do + eval "${1}[$count]=\"$dir\"" + # Changed for Zotero + #(( count++ )) + (( ++count )) + done < "temp-dirlist" + rm "temp-dirlist" +} diff --git a/app/update-packaging/make_full_update.sh b/app/update-packaging/make_full_update.sh new file mode 100755 index 0000000000..de07cb3103 --- /dev/null +++ b/app/update-packaging/make_full_update.sh @@ -0,0 +1,124 @@ +#!/bin/bash +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# +# This tool generates full update packages for the update system. +# Author: Darin Fisher +# + +# Added for Zotero +set -eo pipefail + +. $(dirname "$0")/common.sh + +# ----------------------------------------------------------------------------- + +print_usage() { + notice "Usage: $(basename $0) [OPTIONS] ARCHIVE DIRECTORY" +} + +if [ $# = 0 ]; then + print_usage + exit 1 +fi + +if [ $1 = -h ]; then + print_usage + notice "" + notice "The contents of DIRECTORY will be stored in ARCHIVE." + notice "" + notice "Options:" + notice " -h show this help text" + notice "" + exit 1 +fi + +# ----------------------------------------------------------------------------- + +archive="$1" +targetdir="$2" +# Prevent the workdir from being inside the targetdir so it isn't included in +# the update mar. +if [ $(echo "$targetdir" | grep -c '\/$') = 1 ]; then + # Remove the / + targetdir=$(echo "$targetdir" | sed -e 's:\/$::') +fi +workdir="$targetdir.work" +updatemanifestv2="$workdir/updatev2.manifest" +updatemanifestv3="$workdir/updatev3.manifest" +targetfiles="updatev2.manifest updatev3.manifest" + +mkdir -p "$workdir" + +# Generate a list of all files in the target directory. +pushd "$targetdir" +if test $? -ne 0 ; then + exit 1 +fi + +if [ ! -f "precomplete" ]; then + if [ ! -f "Contents/Resources/precomplete" ]; then + notice "precomplete file is missing!" + exit 1 + fi +fi + +list_files files + +popd + +# Add the type of update to the beginning of the update manifests. +> $updatemanifestv2 +> $updatemanifestv3 +notice "" +notice "Adding type instruction to update manifests" +notice " type complete" +echo "type \"complete\"" >> $updatemanifestv2 +echo "type \"complete\"" >> $updatemanifestv3 + +notice "" +notice "Adding file add instructions to update manifests" +num_files=${#files[*]} + +for ((i=0; $i<$num_files; i=$i+1)); do + f="${files[$i]}" + + if check_for_add_if_not_update "$f"; then + make_add_if_not_instruction "$f" "$updatemanifestv3" + if check_for_add_to_manifestv2 "$f"; then + make_add_instruction "$f" "$updatemanifestv2" "" 1 + fi + else + make_add_instruction "$f" "$updatemanifestv2" "$updatemanifestv3" + fi + + dir=$(dirname "$f") + mkdir -p "$workdir/$dir" + $BZIP2 -cz9 "$targetdir/$f" > "$workdir/$f" + copy_perm "$targetdir/$f" "$workdir/$f" + + targetfiles="$targetfiles \"$f\"" +done + +# Append remove instructions for any dead files. +notice "" +notice "Adding file and directory remove instructions from file 'removed-files'" +append_remove_instructions "$targetdir" "$updatemanifestv2" "$updatemanifestv3" + +$BZIP2 -z9 "$updatemanifestv2" && mv -f "$updatemanifestv2.bz2" "$updatemanifestv2" +$BZIP2 -z9 "$updatemanifestv3" && mv -f "$updatemanifestv3.bz2" "$updatemanifestv3" + +# Changed for Zotero -- -C is unreliable +pushd $workdir > /dev/null +eval "$MAR -c output.mar $targetfiles" +popd > /dev/null +mv -f "$workdir/output.mar" "$archive" + +# cleanup +rm -fr "$workdir" + +notice "" +notice "Finished" +notice "" diff --git a/app/update-packaging/make_incremental_update.sh b/app/update-packaging/make_incremental_update.sh new file mode 100755 index 0000000000..7e5c890001 --- /dev/null +++ b/app/update-packaging/make_incremental_update.sh @@ -0,0 +1,326 @@ +#!/bin/bash +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# +# This tool generates incremental update packages for the update system. +# Author: Darin Fisher +# + +set -eo pipefail + +. $(dirname "$0")/common.sh + +# ----------------------------------------------------------------------------- + +print_usage() { + notice "Usage: $(basename $0) [OPTIONS] ARCHIVE FROMDIR TODIR" + notice "" + notice "The differences between FROMDIR and TODIR will be stored in ARCHIVE." + notice "" + notice "Options:" + notice " -h show this help text" + notice " -f clobber this file in the installation" + notice " Must be a path to a file to clobber in the partial update." + notice "" +} + +check_for_forced_update() { + force_list="$1" + forced_file_chk="$2" + + local f + + if [ "$forced_file_chk" = "precomplete" ]; then + ## "true" *giggle* + return 0; + fi + + if [ "$forced_file_chk" = "Contents/Resources/precomplete" ]; then + ## "true" *giggle* + return 0; + fi + + if [ "$forced_file_chk" = "removed-files" ]; then + ## "true" *giggle* + return 0; + fi + + if [ "$forced_file_chk" = "Contents/Resources/removed-files" ]; then + ## "true" *giggle* + return 0; + fi + + if [ "${forced_file_chk##*.}" = "chk" ]; then + ## "true" *giggle* + return 0; + fi + + for f in $force_list; do + #echo comparing $forced_file_chk to $f + if [ "$forced_file_chk" = "$f" ]; then + ## "true" *giggle* + return 0; + fi + done + ## 'false'... because this is bash. Oh yay! + return 1; +} + +if [ $# = 0 ]; then + print_usage + exit 1 +fi + +requested_forced_updates='Contents/MacOS/firefox' + +while getopts "hf:" flag +do + case "$flag" in + h) print_usage; exit 0 + ;; + f) requested_forced_updates="$requested_forced_updates $OPTARG" + ;; + ?) print_usage; exit 1 + ;; + esac +done + +# ----------------------------------------------------------------------------- + +set +e +let arg_start=$OPTIND-1 +shift $arg_start +set -e + +archive="$1" +olddir="$2" +newdir="$3" +# Prevent the workdir from being inside the targetdir so it isn't included in +# the update mar. +if [ $(echo "$newdir" | grep -c '\/$') = 1 ]; then + # Remove the / + newdir=$(echo "$newdir" | sed -e 's:\/$::') +fi +workdir="$newdir.work" +updatemanifestv2="$workdir/updatev2.manifest" +updatemanifestv3="$workdir/updatev3.manifest" +archivefiles="updatev2.manifest updatev3.manifest" + +mkdir -p "$workdir" + +# Generate a list of all files in the target directory. +pushd "$olddir" +if test $? -ne 0 ; then + exit 1 +fi + +list_files oldfiles +list_dirs olddirs + +popd + +pushd "$newdir" +if test $? -ne 0 ; then + exit 1 +fi + +if [ ! -f "precomplete" ]; then + if [ ! -f "Contents/Resources/precomplete" ]; then + notice "precomplete file is missing!" + exit 1 + fi +fi + +list_dirs newdirs +list_files newfiles + +popd + +# Add the type of update to the beginning of the update manifests. +notice "" +notice "Adding type instruction to update manifests" +> $updatemanifestv2 +> $updatemanifestv3 +notice " type partial" +echo "type \"partial\"" >> $updatemanifestv2 +echo "type \"partial\"" >> $updatemanifestv3 + +notice "" +notice "Adding file patch and add instructions to update manifests" + +num_oldfiles=${#oldfiles[*]} +remove_array= +num_removes=0 + +for ((i=0; $i<$num_oldfiles; i=$i+1)); do + f="${oldfiles[$i]}" + + # If this file exists in the new directory as well, then check if it differs. + if [ -f "$newdir/$f" ]; then + + if check_for_add_if_not_update "$f"; then + # The full workdir may not exist yet, so create it if necessary. + mkdir -p `dirname "$workdir/$f"` + $BZIP2 -cz9 "$newdir/$f" > "$workdir/$f" + copy_perm "$newdir/$f" "$workdir/$f" + make_add_if_not_instruction "$f" "$updatemanifestv3" + archivefiles="$archivefiles \"$f\"" + continue 1 + fi + + if check_for_forced_update "$requested_forced_updates" "$f"; then + # The full workdir may not exist yet, so create it if necessary. + mkdir -p `dirname "$workdir/$f"` + $BZIP2 -cz9 "$newdir/$f" > "$workdir/$f" + copy_perm "$newdir/$f" "$workdir/$f" + make_add_instruction "$f" "$updatemanifestv2" "$updatemanifestv3" 1 + archivefiles="$archivefiles \"$f\"" + continue 1 + fi + + if ! diff "$olddir/$f" "$newdir/$f" > /dev/null; then + # Compute both the compressed binary diff and the compressed file, and + # compare the sizes. Then choose the smaller of the two to package. + dir=$(dirname "$workdir/$f") + mkdir -p "$dir" + notice "diffing \"$f\"" + # MBSDIFF_HOOK represents the communication interface with funsize and, + # if enabled, caches the intermediate patches for future use and + # compute avoidance + # + # An example of MBSDIFF_HOOK env variable could look like this: + # export MBSDIFF_HOOK="myscript.sh -A https://funsize/api -c /home/user" + # where myscript.sh has the following usage: + # myscript.sh -A SERVER-URL [-c LOCAL-CACHE-DIR-PATH] [-g] [-u] \ + # PATH-FROM-URL PATH-TO-URL PATH-PATCH SERVER-URL + # + # Note: patches are bzipped stashed in funsize to gain more speed + + # if service is not enabled then default to old behavior + if [ -z "$MBSDIFF_HOOK" ]; then + $MBSDIFF "$olddir/$f" "$newdir/$f" "$workdir/$f.patch" + $BZIP2 -z9 "$workdir/$f.patch" + else + # if service enabled then check patch existence for retrieval + if $MBSDIFF_HOOK -g "$olddir/$f" "$newdir/$f" "$workdir/$f.patch.bz2"; then + notice "file \"$f\" found in funsize, diffing skipped" + else + # if not found already - compute it and cache it for future use + $MBSDIFF "$olddir/$f" "$newdir/$f" "$workdir/$f.patch" + $BZIP2 -z9 "$workdir/$f.patch" + $MBSDIFF_HOOK -u "$olddir/$f" "$newdir/$f" "$workdir/$f.patch.bz2" + fi + fi + $BZIP2 -cz9 "$newdir/$f" > "$workdir/$f" + copy_perm "$newdir/$f" "$workdir/$f" + patchfile="$workdir/$f.patch.bz2" + patchsize=$(get_file_size "$patchfile") + fullsize=$(get_file_size "$workdir/$f") + + if [ $patchsize -lt $fullsize ]; then + make_patch_instruction "$f" "$updatemanifestv2" "$updatemanifestv3" + mv -f "$patchfile" "$workdir/$f.patch" + rm -f "$workdir/$f" + archivefiles="$archivefiles \"$f.patch\"" + else + make_add_instruction "$f" "$updatemanifestv2" "$updatemanifestv3" + rm -f "$patchfile" + archivefiles="$archivefiles \"$f\"" + fi + fi + else + # remove instructions are added after add / patch instructions for + # consistency with make_incremental_updates.py + remove_array[$num_removes]=$f + # Changed by Zotero for -e + #(( num_removes++ )) + (( ++num_removes )) + fi +done + +# Newly added files +notice "" +notice "Adding file add instructions to update manifests" +num_newfiles=${#newfiles[*]} + +for ((i=0; $i<$num_newfiles; i=$i+1)); do + f="${newfiles[$i]}" + + # If we've already tested this file, then skip it + for ((j=0; $j<$num_oldfiles; j=$j+1)); do + if [ "$f" = "${oldfiles[j]}" ]; then + continue 2 + fi + done + + dir=$(dirname "$workdir/$f") + mkdir -p "$dir" + + $BZIP2 -cz9 "$newdir/$f" > "$workdir/$f" + copy_perm "$newdir/$f" "$workdir/$f" + + if check_for_add_if_not_update "$f"; then + make_add_if_not_instruction "$f" "$updatemanifestv3" + else + make_add_instruction "$f" "$updatemanifestv2" "$updatemanifestv3" + fi + + + archivefiles="$archivefiles \"$f\"" +done + +notice "" +notice "Adding file remove instructions to update manifests" +for ((i=0; $i<$num_removes; i=$i+1)); do + f="${remove_array[$i]}" + notice " remove \"$f\"" + echo "remove \"$f\"" >> $updatemanifestv2 + echo "remove \"$f\"" >> $updatemanifestv3 +done + +# Add remove instructions for any dead files. +notice "" +notice "Adding file and directory remove instructions from file 'removed-files'" +append_remove_instructions "$newdir" "$updatemanifestv2" "$updatemanifestv3" + +notice "" +notice "Adding directory remove instructions for directories that no longer exist" +num_olddirs=${#olddirs[*]} + +for ((i=0; $i<$num_olddirs; i=$i+1)); do + f="${olddirs[$i]}" + # If this dir doesn't exist in the new directory remove it. + if [ ! -d "$newdir/$f" ]; then + notice " rmdir $f/" + echo "rmdir \"$f/\"" >> $updatemanifestv2 + echo "rmdir \"$f/\"" >> $updatemanifestv3 + fi +done + +$BZIP2 -z9 "$updatemanifestv2" && mv -f "$updatemanifestv2.bz2" "$updatemanifestv2" +$BZIP2 -z9 "$updatemanifestv3" && mv -f "$updatemanifestv3.bz2" "$updatemanifestv3" + +mar_command="$MAR" +if [[ -n $MOZ_PRODUCT_VERSION ]] +then + mar_command="$mar_command -V $MOZ_PRODUCT_VERSION" +fi +if [[ -n $MOZ_CHANNEL_ID ]] +then + mar_command="$mar_command -H $MOZ_CHANNEL_ID" +fi +# Changed for Zotero -- -C is unreliable +pushd $workdir > /dev/null +mar_command="$mar_command -c output.mar" +eval "$mar_command $archivefiles" +popd > /dev/null +mv -f "$workdir/output.mar" "$archive" + +# cleanup +rm -fr "$workdir" + +notice "" +notice "Finished" +notice "" diff --git a/app/update-packaging/make_incremental_updates.py b/app/update-packaging/make_incremental_updates.py new file mode 100755 index 0000000000..922fb9697c --- /dev/null +++ b/app/update-packaging/make_incremental_updates.py @@ -0,0 +1,550 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os +import shutil +import sha +from os.path import join, getsize +from stat import * +import re +import sys +import getopt +import time +import datetime +import bz2 +import string +import tempfile + +class PatchInfo: + """ Represents the meta-data associated with a patch + work_dir = working dir where files are stored for this patch + archive_files = list of files to include in this patch + manifestv2 = set of manifest version 2 patch instructions + manifestv3 = set of manifest version 3 patch instructions + file_exclusion_list = + files to exclude from this patch. names without slashes will be + excluded anywhere in the directory hiearchy. names with slashes + will only be excluded at that exact path + """ + def __init__(self, work_dir, file_exclusion_list, path_exclusion_list): + self.work_dir=work_dir + self.archive_files=[] + self.manifestv2=[] + self.manifestv3=[] + self.file_exclusion_list=file_exclusion_list + self.path_exclusion_list=path_exclusion_list + + def append_add_instruction(self, filename): + """ Appends an add instruction for this patch. + if filename starts with distribution/extensions/.*/ this will add an + add-if instruction that will add the file if the parent directory + of the file exists. This was ported from + mozilla/tools/update-packaging/common.sh's make_add_instruction. + """ + m = re.match("((?:|.*/)distribution/extensions/.*)/", filename) + if m: + # Directory immediately following extensions is used for the test + testdir = m.group(1) + print ' add-if "'+testdir+'" "'+filename+'"' + self.manifestv2.append('add-if "'+testdir+'" "'+filename+'"') + self.manifestv3.append('add-if "'+testdir+'" "'+filename+'"') + else: + print ' add "'+filename+'"' + self.manifestv2.append('add "'+filename+'"') + self.manifestv3.append('add "'+filename+'"') + + def append_add_if_not_instruction(self, filename): + """ Appends an add-if-not instruction to the version 3 manifest for this patch. + This was ported from mozilla/tools/update-packaging/common.sh's + make_add_if_not_instruction. + """ + print ' add-if-not "'+filename+'" "'+filename+'"' + self.manifestv3.append('add-if-not "'+filename+'" "'+filename+'"') + + def append_patch_instruction(self, filename, patchname): + """ Appends a patch instruction for this patch. + + filename = file to patch + patchname = patchfile to apply to file + + if filename starts with distribution/extensions/.*/ this will add a + patch-if instruction that will patch the file if the parent + directory of the file exists. This was ported from + mozilla/tools/update-packaging/common.sh's make_patch_instruction. + """ + m = re.match("((?:|.*/)distribution/extensions/.*)/", filename) + if m: + testdir = m.group(1) + print ' patch-if "'+testdir+'" "'+patchname+'" "'+filename+'"' + self.manifestv2.append('patch-if "'+testdir+'" "'+patchname+'" "'+filename+'"') + self.manifestv3.append('patch-if "'+testdir+'" "'+patchname+'" "'+filename+'"') + else: + print ' patch "'+patchname+'" "'+filename+'"' + self.manifestv2.append('patch "'+patchname+'" "'+filename+'"') + self.manifestv3.append('patch "'+patchname+'" "'+filename+'"') + + def append_remove_instruction(self, filename): + """ Appends an remove instruction for this patch. + This was ported from + mozilla/tools/update-packaging/common.sh/make_remove_instruction + """ + if filename.endswith("/"): + print ' rmdir "'+filename+'"' + self.manifestv2.append('rmdir "'+filename+'"') + self.manifestv3.append('rmdir "'+filename+'"') + elif filename.endswith("/*"): + filename = filename[:-1] + print ' rmrfdir "'+filename+'"' + self.manifestv2.append('rmrfdir "'+filename+'"') + self.manifestv3.append('rmrfdir "'+filename+'"') + else: + print ' remove "'+filename+'"' + self.manifestv2.append('remove "'+filename+'"') + self.manifestv3.append('remove "'+filename+'"') + + def create_manifest_files(self): + """ Create the v2 manifest file in the root of the work_dir """ + manifest_file_path = os.path.join(self.work_dir,"updatev2.manifest") + manifest_file = open(manifest_file_path, "wb") + manifest_file.writelines("type \"partial\"\n") + manifest_file.writelines(string.join(self.manifestv2, '\n')) + manifest_file.writelines("\n") + manifest_file.close() + + bzip_file(manifest_file_path) + self.archive_files.append('"updatev2.manifest"') + + """ Create the v3 manifest file in the root of the work_dir """ + manifest_file_path = os.path.join(self.work_dir,"updatev3.manifest") + manifest_file = open(manifest_file_path, "wb") + manifest_file.writelines("type \"partial\"\n") + manifest_file.writelines(string.join(self.manifestv3, '\n')) + manifest_file.writelines("\n") + manifest_file.close() + + bzip_file(manifest_file_path) + self.archive_files.append('"updatev3.manifest"') + + def build_marfile_entry_hash(self, root_path): + """ Iterates through the root_path, creating a MarFileEntry for each file + and directory in that path. Excludes any filenames in the file_exclusion_list + """ + mar_entry_hash = {} + filename_set = set() + dirname_set = set() + for root, dirs, files in os.walk(root_path): + for name in files: + # filename is the relative path from root directory + partial_path = root[len(root_path)+1:] + if name not in self.file_exclusion_list: + filename = os.path.join(partial_path, name) + if "/"+filename not in self.path_exclusion_list: + mar_entry_hash[filename]=MarFileEntry(root_path, filename) + filename_set.add(filename) + + for name in dirs: + # dirname is the relative path from root directory + partial_path = root[len(root_path)+1:] + if name not in self.file_exclusion_list: + dirname = os.path.join(partial_path, name) + if "/"+dirname not in self.path_exclusion_list: + dirname = dirname+"/" + mar_entry_hash[dirname]=MarFileEntry(root_path, dirname) + dirname_set.add(dirname) + + return mar_entry_hash, filename_set, dirname_set + + +class MarFileEntry: + """Represents a file inside a Mozilla Archive Format (MAR) + abs_path = abspath to the the file + name = relative path within the mar. e.g. + foo.mar/dir/bar.txt extracted into /tmp/foo: + abs_path=/tmp/foo/dir/bar.txt + name = dir/bar.txt + """ + def __init__(self, root, name): + """root = path the the top of the mar + name = relative path within the mar""" + self.name=name.replace("\\", "/") + self.abs_path=os.path.join(root,name) + self.sha_cache=None + + def __str__(self): + return 'Name: %s FullPath: %s' %(self.name,self.abs_path) + + def calc_file_sha_digest(self, filename): + """ Returns sha digest of given filename""" + file_content = open(filename, 'r').read() + return sha.new(file_content).digest() + + def sha(self): + """ Returns sha digest of file repreesnted by this _marfile_entry""" + if not self.sha_cache: + self.sha_cache=self.calc_file_sha_digest(self.abs_path) + return self.sha_cache + +def exec_shell_cmd(cmd): + """Execs shell cmd and raises an exception if the cmd fails""" + if (os.system(cmd)): + raise Exception, "cmd failed "+cmd + + +def copy_file(src_file_abs_path, dst_file_abs_path): + """ Copies src to dst creating any parent dirs required in dst first """ + dst_file_dir=os.path.dirname(dst_file_abs_path) + if not os.path.exists(dst_file_dir): + os.makedirs(dst_file_dir) + # Copy the file over + shutil.copy2(src_file_abs_path, dst_file_abs_path) + +def bzip_file(filename): + """ Bzip's the file in place. The original file is replaced with a bzip'd version of itself + assumes the path is absolute""" + exec_shell_cmd('bzip2 -z9 "' + filename+'"') + os.rename(filename+".bz2",filename) + +def bunzip_file(filename): + """ Bzip's the file in palce. The original file is replaced with a bunzip'd version of itself. + doesn't matter if the filename ends in .bz2 or not""" + if not filename.endswith(".bz2"): + os.rename(filename, filename+".bz2") + filename=filename+".bz2" + exec_shell_cmd('bzip2 -d "' + filename+'"') + + +def extract_mar(filename, work_dir): + """ Extracts the marfile intot he work_dir + assumes work_dir already exists otherwise will throw osError""" + print "Extracting "+filename+" to "+work_dir + saved_path = os.getcwd() + try: + os.chdir(work_dir) + exec_shell_cmd("mar -x "+filename) + finally: + os.chdir(saved_path) + +def create_partial_patch_for_file(from_marfile_entry, to_marfile_entry, shas, patch_info): + """ Creates the partial patch file and manifest entry for the pair of files passed in + """ + if not (from_marfile_entry.sha(),to_marfile_entry.sha()) in shas: + print 'diffing "'+from_marfile_entry.name+'\"' + #bunzip to/from + bunzip_file(from_marfile_entry.abs_path) + bunzip_file(to_marfile_entry.abs_path) + + # The patch file will be created in the working directory with the + # name of the file in the mar + .patch + patch_file_abs_path = os.path.join(patch_info.work_dir,from_marfile_entry.name+".patch") + patch_file_dir=os.path.dirname(patch_file_abs_path) + if not os.path.exists(patch_file_dir): + os.makedirs(patch_file_dir) + + # Create bzip'd patch file + exec_shell_cmd("mbsdiff "+from_marfile_entry.abs_path+" "+to_marfile_entry.abs_path+" "+patch_file_abs_path) + bzip_file(patch_file_abs_path) + + # Create bzip's full file + full_file_abs_path = os.path.join(patch_info.work_dir, to_marfile_entry.name) + shutil.copy2(to_marfile_entry.abs_path, full_file_abs_path) + bzip_file(full_file_abs_path) + + if os.path.getsize(patch_file_abs_path) < os.path.getsize(full_file_abs_path): + # Patch is smaller than file. Remove the file and add patch to manifest + os.remove(full_file_abs_path) + file_in_manifest_name = from_marfile_entry.name+".patch" + file_in_manifest_abspath = patch_file_abs_path + patch_info.append_patch_instruction(to_marfile_entry.name, file_in_manifest_name) + else: + # File is smaller than patch. Remove the patch and add file to manifest + os.remove(patch_file_abs_path) + file_in_manifest_name = from_marfile_entry.name + file_in_manifest_abspath = full_file_abs_path + patch_info.append_add_instruction(file_in_manifest_name) + + shas[from_marfile_entry.sha(),to_marfile_entry.sha()] = (file_in_manifest_name,file_in_manifest_abspath) + patch_info.archive_files.append('"'+file_in_manifest_name+'"') + else: + filename, src_file_abs_path = shas[from_marfile_entry.sha(),to_marfile_entry.sha()] + # We've already calculated the patch for this pair of files. + if (filename.endswith(".patch")): + # print "skipping diff: "+from_marfile_entry.name + # Patch was smaller than file - add patch instruction to manifest + file_in_manifest_name = to_marfile_entry.name+'.patch'; + patch_info.append_patch_instruction(to_marfile_entry.name, file_in_manifest_name) + else: + # File was smaller than file - add file to manifest + file_in_manifest_name = to_marfile_entry.name + patch_info.append_add_instruction(file_in_manifest_name) + # Copy the pre-calculated file into our new patch work aread + copy_file(src_file_abs_path, os.path.join(patch_info.work_dir, file_in_manifest_name)) + patch_info.archive_files.append('"'+file_in_manifest_name+'"') + +def create_add_patch_for_file(to_marfile_entry, patch_info): + """ Copy the file to the working dir, add the add instruction, and add it to the list of archive files """ + copy_file(to_marfile_entry.abs_path, os.path.join(patch_info.work_dir, to_marfile_entry.name)) + patch_info.append_add_instruction(to_marfile_entry.name) + patch_info.archive_files.append('"'+to_marfile_entry.name+'"') + +def create_add_if_not_patch_for_file(to_marfile_entry, patch_info): + """ Copy the file to the working dir, add the add-if-not instruction, and add it to the list of archive files """ + copy_file(to_marfile_entry.abs_path, os.path.join(patch_info.work_dir, to_marfile_entry.name)) + patch_info.append_add_if_not_instruction(to_marfile_entry.name) + patch_info.archive_files.append('"'+to_marfile_entry.name+'"') + +def process_explicit_remove_files(dir_path, patch_info): + """ Looks for a 'removed-files' file in the dir_path. If the removed-files does not exist + this will throw. If found adds the removed-files + found in that file to the patch_info""" + + # Windows and linux have this file at the root of the dir + list_file_path = os.path.join(dir_path, "removed-files") + if not os.path.exists(list_file_path): + list_file_path = os.path.join(dir_path, "Contents/Resources/removed-files") + + if (os.path.exists(list_file_path)): + list_file = bz2.BZ2File(list_file_path,"r") # throws if doesn't exist + + lines = [] + for line in list_file: + lines.append(line.strip()) + list_file.close() + + lines.sort(reverse=True) + for line in lines: + # Exclude any blank and comment lines. + if line and not line.startswith("#"): + # Python on windows uses \ for path separators and the update + # manifests expects / for path separators on all platforms. + line = line.replace("\\", "/") + patch_info.append_remove_instruction(line) + +def create_partial_patch(from_dir_path, to_dir_path, patch_filename, shas, patch_info, forced_updates, add_if_not_list): + """ Builds a partial patch by comparing the files in from_dir_path to those of to_dir_path""" + # Cannocolize the paths for safey + from_dir_path = os.path.abspath(from_dir_path) + to_dir_path = os.path.abspath(to_dir_path) + # Create a hashtable of the from and to directories + from_dir_hash,from_file_set,from_dir_set = patch_info.build_marfile_entry_hash(from_dir_path) + to_dir_hash,to_file_set,to_dir_set = patch_info.build_marfile_entry_hash(to_dir_path) + # Create a list of the forced updates + forced_list = forced_updates.strip().split('|') + # Require that the precomplete file is included in the complete update + if "precomplete" in to_file_set: + forced_list.append("precomplete") + elif "Contents/Resources/precomplete" in to_file_set: + forced_list.append("Contents/Resources/precomplete") + # The check with \ file separators allows tests for Mac to run on Windows + elif "Contents\Resources\precomplete" in to_file_set: + forced_list.append("Contents\Resources\precomplete") + else: + raise Exception, "missing precomplete file in: "+to_dir_path + + if "removed-files" in to_file_set: + forced_list.append("removed-files") + elif "Contents/Resources/removed-files" in to_file_set: + forced_list.append("Contents/Resources/removed-files") + # The check with \ file separators allows tests for Mac to run on Windows + elif "Contents\Resources\\removed-files" in to_file_set: + forced_list.append("Contents\Resources\\removed-files") + else: + raise Exception, "missing removed-files file in: "+to_dir_path + + # Files which exist in both sets need to be patched + patch_filenames = list(from_file_set.intersection(to_file_set)) + patch_filenames.sort(reverse=True) + for filename in patch_filenames: + from_marfile_entry = from_dir_hash[filename] + to_marfile_entry = to_dir_hash[filename] + if os.path.basename(filename) in add_if_not_list: + # This filename is in the add if not list, explicitly add-if-not + create_add_if_not_patch_for_file(to_dir_hash[filename], patch_info) + elif filename in forced_list: + print 'Forcing "'+filename+'"' + # This filename is in the forced list, explicitly add + create_add_patch_for_file(to_dir_hash[filename], patch_info) + else: + if from_marfile_entry.sha() != to_marfile_entry.sha(): + # Not the same - calculate a patch + create_partial_patch_for_file(from_marfile_entry, to_marfile_entry, shas, patch_info) + + # files in to_dir not in from_dir need to added + add_filenames = list(to_file_set - from_file_set) + add_filenames.sort(reverse=True) + for filename in add_filenames: + if os.path.basename(filename) in add_if_not_list: + create_add_if_not_patch_for_file(to_dir_hash[filename], patch_info) + else: + create_add_patch_for_file(to_dir_hash[filename], patch_info) + + # files in from_dir not in to_dir need to be removed + remove_filenames = list(from_file_set - to_file_set) + remove_filenames.sort(reverse=True) + for filename in remove_filenames: + patch_info.append_remove_instruction(from_dir_hash[filename].name) + + process_explicit_remove_files(to_dir_path, patch_info) + + # directories in from_dir not in to_dir need to be removed + remove_dirnames = list(from_dir_set - to_dir_set) + remove_dirnames.sort(reverse=True) + for dirname in remove_dirnames: + patch_info.append_remove_instruction(from_dir_hash[dirname].name) + + # Construct the Manifest files + patch_info.create_manifest_files() + + # And construct the mar + mar_cmd = 'mar -C '+patch_info.work_dir+' -c output.mar '+string.join(patch_info.archive_files, ' ') + exec_shell_cmd(mar_cmd) + + # Copy mar to final destination + patch_file_dir = os.path.split(patch_filename)[0] + if not os.path.exists(patch_file_dir): + os.makedirs(patch_file_dir) + shutil.copy2(os.path.join(patch_info.work_dir,"output.mar"), patch_filename) + + return patch_filename + +def usage(): + print "-h for help" + print "-f for patchlist_file" + +def get_buildid(work_dir): + """ extracts buildid from MAR + """ + ini = '%s/application.ini' % work_dir + if not os.path.exists(ini): + ini = '%s/Contents/Resources/application.ini' % work_dir + if not os.path.exists(ini): + print 'WARNING: application.ini not found, cannot find build ID' + return '' + + file = bz2.BZ2File(ini) + for line in file: + if line.find('BuildID') == 0: + return line.strip().split('=')[1] + print 'WARNING: cannot find build ID in application.ini' + return '' + +def decode_filename(filepath): + """ Breaks filename/dir structure into component parts based on regex + for example: firefox-3.0b3pre.en-US.linux-i686.complete.mar + Or linux-i686/en-US/firefox-3.0b3.complete.mar + Returns dict with keys product, version, locale, platform, type + """ + try: + m = re.search( + '(?P\w+)(-)(?P\w+\.\w+(\.\w+){0,2})(\.)(?P.+?)(\.)(?P.+?)(\.)(?P\w+)(.mar)', + os.path.basename(filepath)) + return m.groupdict() + except Exception, exc: + try: + m = re.search( + '(?P.+?)\/(?P.+?)\/(?P\w+)-(?P\w+\.\w+)\.(?P\w+).mar', + filepath) + return m.groupdict() + except: + raise Exception("could not parse filepath %s: %s" % (filepath, exc)) + +def create_partial_patches(patches): + """ Given the patches generates a set of partial patches""" + shas = {} + + work_dir_root = None + metadata = [] + try: + work_dir_root = tempfile.mkdtemp('-fastmode', 'tmp', os.getcwd()) + print "Building patches using work dir: %s" % (work_dir_root) + + # Iterate through every patch set in the patch file + patch_num = 1 + for patch in patches: + startTime = time.time() + + from_filename,to_filename,patch_filename,forced_updates = patch.split(",") + from_filename,to_filename,patch_filename = os.path.abspath(from_filename),os.path.abspath(to_filename),os.path.abspath(patch_filename) + + # Each patch iteration uses its own work dir + work_dir = os.path.join(work_dir_root,str(patch_num)) + os.mkdir(work_dir) + + # Extract from mar into from dir + work_dir_from = os.path.join(work_dir,"from"); + os.mkdir(work_dir_from) + extract_mar(from_filename,work_dir_from) + from_decoded = decode_filename(from_filename) + from_buildid = get_buildid(work_dir_from) + from_shasum = sha.sha(open(from_filename).read()).hexdigest() + from_size = str(os.path.getsize(to_filename)) + + # Extract to mar into to dir + work_dir_to = os.path.join(work_dir,"to") + os.mkdir(work_dir_to) + extract_mar(to_filename, work_dir_to) + to_decoded = decode_filename(from_filename) + to_buildid = get_buildid(work_dir_to) + to_shasum = sha.sha(open(to_filename).read()).hexdigest() + to_size = str(os.path.getsize(to_filename)) + + mar_extract_time = time.time() + + partial_filename = create_partial_patch(work_dir_from, work_dir_to, patch_filename, shas, PatchInfo(work_dir, ['update.manifest','updatev2.manifest','updatev3.manifest'],[]),forced_updates,['channel-prefs.js','update-settings.ini']) + partial_buildid = to_buildid + partial_shasum = sha.sha(open(partial_filename).read()).hexdigest() + partial_size = str(os.path.getsize(partial_filename)) + + metadata.append({ + 'to_filename': os.path.basename(to_filename), + 'from_filename': os.path.basename(from_filename), + 'partial_filename': os.path.basename(partial_filename), + 'to_buildid':to_buildid, + 'from_buildid':from_buildid, + 'to_sha1sum':to_shasum, + 'from_sha1sum':from_shasum, + 'partial_sha1sum':partial_shasum, + 'to_size':to_size, + 'from_size':from_size, + 'partial_size':partial_size, + 'to_version':to_decoded['version'], + 'from_version':from_decoded['version'], + 'locale':from_decoded['locale'], + 'platform':from_decoded['platform'], + }) + print "done with patch %s/%s time (%.2fs/%.2fs/%.2fs) (mar/patch/total)" % (str(patch_num),str(len(patches)),mar_extract_time-startTime,time.time()-mar_extract_time,time.time()-startTime) + patch_num += 1 + return metadata + finally: + # If we fail or get a ctrl-c during run be sure to clean up temp dir + if (work_dir_root and os.path.exists(work_dir_root)): + shutil.rmtree(work_dir_root) + +def main(argv): + patchlist_file = None + try: + opts, args = getopt.getopt(argv, "hf:", ["help", "patchlist_file="]) + for opt, arg in opts: + if opt in ("-h", "--help"): + usage() + sys.exit() + elif opt in ("-f", "--patchlist_file"): + patchlist_file = arg + except getopt.GetoptError: + usage() + sys.exit(2) + + if not patchlist_file: + usage() + sys.exit(2) + + patches = [] + f = open(patchlist_file, 'r') + for line in f.readlines(): + patches.append(line) + f.close() + create_partial_patches(patches) + +if __name__ == "__main__": + main(sys.argv[1:]) + diff --git a/app/update-packaging/removed-files_linux-i686 b/app/update-packaging/removed-files_linux-i686 new file mode 100755 index 0000000000..5e7643368a --- /dev/null +++ b/app/update-packaging/removed-files_linux-i686 @@ -0,0 +1,19 @@ +xulrunner/* +pingsender +translators.zip +translators.index +styles.zip +resource/schema/userdata.sql +resource/schema/triggers.sql +resource/schema/system.sql +resource/schema/repotime.txt +resource/schema/renamed-styles.json +resource/schema/engines.json +resource/schema/abbreviations.json +resource/q.js +resource/csl-validator.js +resource/concurrent-caller.js +install.rdf +deleted.txt +test/* +run-zotero.sh diff --git a/app/update-packaging/removed-files_linux-x86_64 b/app/update-packaging/removed-files_linux-x86_64 new file mode 100755 index 0000000000..5e7643368a --- /dev/null +++ b/app/update-packaging/removed-files_linux-x86_64 @@ -0,0 +1,19 @@ +xulrunner/* +pingsender +translators.zip +translators.index +styles.zip +resource/schema/userdata.sql +resource/schema/triggers.sql +resource/schema/system.sql +resource/schema/repotime.txt +resource/schema/renamed-styles.json +resource/schema/engines.json +resource/schema/abbreviations.json +resource/q.js +resource/csl-validator.js +resource/concurrent-caller.js +install.rdf +deleted.txt +test/* +run-zotero.sh diff --git a/app/update-packaging/removed-files_mac b/app/update-packaging/removed-files_mac new file mode 100755 index 0000000000..234fa5aa19 --- /dev/null +++ b/app/update-packaging/removed-files_mac @@ -0,0 +1,49 @@ +Contents/Frameworks/* +Contents/MacOS/active-update.xml +Contents/MacOS/components/ +Contents/MacOS/chrome.manifest +Contents/MacOS/crashreporter.app/* +Contents/MacOS/defaults/* +Contents/MacOS/dependentlibs.list +Contents/MacOS/dictionaries/ +Contents/MacOS/gmp-fake/* +Contents/MacOS/Info.plist +Contents/MacOS/js-gdb.py +Contents/MacOS/libfreebl.chk +Contents/MacOS/libnssdbm3.chk +Contents/MacOS/libsoftokn3.chk +Contents/MacOS/libmozsqlite3.dylib +Contents/MacOS/libnspr4.dylib +Contents/MacOS/libnssutil3.dylib +Contents/MacOS/libplc4.dylib +Contents/MacOS/libplds4.dylib +Contents/MacOS/libsmime3.dylib +Contents/MacOS/libssl3.dylib +Contents/MacOS/libxpcom.dylib +Contents/MacOS/LICENSE +Contents/MacOS/omni.ja +Contents/MacOS/pingsender +Contents/MacOS/platform.ini +Contents/MacOS/precomplete +Contents/MacOS/README.xulrunner +Contents/MacOS/res/* +Contents/MacOS/Resources/* +Contents/MacOS/update-settings.ini +Contents/MacOS/updater.app/Contents/MacOS/updater-bin +Contents/MacOS/updates.xml +Contents/MacOS/updates/* +Contents/MacOS/zotero-bin +Contents/Resources/translators.zip +Contents/Resources/translators.index +Contents/Resources/styles.zip +Contents/Resources/install.rdf +Contents/Resources/deleted.txt +Contents/Resources/extensions/pythonext@mozdev.org/* +Contents/Resources/extensions/zoteroMacWordIntegration@zotero.org/components/install.py +Contents/Resources/extensions/zoteroMacWordIntegration@zotero.org/components/install.pyo +Contents/Resources/extensions/zoteroMacWordIntegration@zotero.org/components/zoteroIntegrationApplication.py +Contents/Resources/extensions/zoteroMacWordIntegration@zotero.org/components/zoteroIntegrationApplication.pyo +Contents/Resources/extensions/zoteroMacWordIntegration@zotero.org/pylib/* +Contents/Resources/resource/* +Contents/Resources/chrome/zotero.jar +Contents/Resources/test/* diff --git a/app/update-packaging/removed-files_win32 b/app/update-packaging/removed-files_win32 new file mode 100755 index 0000000000..eb11c5c8fc --- /dev/null +++ b/app/update-packaging/removed-files_win32 @@ -0,0 +1,46 @@ +deleted.txt +gkmedias.dll +install.rdf +mozcrt19.dll +mozutils.dll +msvcp80.dll +msvcr80.dll +translators.zip +translators.index +styles.zip +Microsoft.VC80.CRT.manifest +resource/schema/userdata.sql +resource/schema/triggers.sql +resource/schema/system.sql +resource/schema/repotime.txt +resource/schema/renamed-styles.json +resource/schema/engines.json +resource/schema/abbreviations.json +resource/q.js +resource/csl-validator.js +resource/concurrent-caller.js +resource/ +xulrunner/* +extensions/zoteroWinWordIntegration@zotero.org/components/zoteroWinWordIntegration.dll +extensions/zoteroWinWordIntegration@zotero.org/components-5.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-6.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-7.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-8.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-9.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-10.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-12.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-13.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-14.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-17.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-18.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-20.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-22.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-23.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-25.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-26.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-28.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-30.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-32.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-33.0/* +extensions/zoteroWinWordIntegration@zotero.org/components-35.0/* +test/* diff --git a/app/update-packaging/removed-files_win64 b/app/update-packaging/removed-files_win64 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/app/win/VersionInfo1.rc b/app/win/VersionInfo1.rc new file mode 100644 index 0000000000000000000000000000000000000000..53eda813304f2233862af96314d1d6b0f8135c3e GIT binary patch literal 1604 zcmb`HUvCmY6vfXgCVqzv&!$1`i}4A%wh~E~2qn=pAuCWM(uFM8R2#l}^>=47%d)zW zm}WCOvvbcq_wU|ckI(f?J+*bI3th2a=$)eCX3UpKdg^MR_j-YB0IpMu7$Y6XSYLu2 zq5qNZt`c~3^birLg^m3(WFLk^F}!CQ9)SB{-g#NJA`JTthr+JLt#Hw(Qgz6Wxy6n{)}tsl)s3;Z!CR~Py2w@V;WJs;g2>tb z#WZrb4Lp|Zz|bOozv}e+j(tjAC)oO57VA>)X+|EGe`NERNcLSe#HZ9%`IbG`w^EOm znIfXyQ1R6DLRBXs6E{xcyX0vqTHj9zp8C%AIS4hjuX1PoELHV{s@=1Wt4_5?%ekmy z=ulbvgQiT9xaf-qW>4CoH)Ls_D9;k a9A<*=Qk#ike)$R6Vt#hGi+Id>)tld%wC6zp literal 0 HcmV?d00001 diff --git a/app/win/download-nsis-plugins b/app/win/download-nsis-plugins new file mode 100755 index 0000000000..f02c60e77b --- /dev/null +++ b/app/win/download-nsis-plugins @@ -0,0 +1,53 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +# +# Turns out we need older versions from Mozilla, not the official ZIPs +# +#plugins=$(cat < $plugin.dll +done + +echo +echo +echo "Files downloaded to ./Plugins -- move to ${NSIS_DIR}Plugins" +echo +ls -la diff --git a/app/win/installer/7zstub/firefox/7zSD.sfx b/app/win/installer/7zstub/firefox/7zSD.sfx new file mode 100644 index 0000000000000000000000000000000000000000..463aa42a2f047ac8d3038478abb46ebde9d0a88f GIT binary patch literal 122368 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

eaAM8%_MaEhs{( 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 literal 0 HcmV?d00001 diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.cpp new file mode 100644 index 0000000000..232c638203 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.cpp @@ -0,0 +1,3 @@ +// CompressionMethod.cpp + +#include "StdAfx.h" diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.h new file mode 100644 index 0000000000..215d5cbfb4 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zCompressionMode.h @@ -0,0 +1,64 @@ +// 7zCompressionMode.h + +#ifndef __7Z_COMPRESSION_MODE_H +#define __7Z_COMPRESSION_MODE_H + +#include "../../../Windows/PropVariant.h" + +#include "7zMethodID.h" + +namespace NArchive { +namespace N7z { + +struct CProperty +{ + PROPID PropID; + NWindows::NCOM::CPropVariant Value; +}; + +struct CMethodFull +{ + CMethodID MethodID; + UInt32 NumInStreams; + UInt32 NumOutStreams; + bool IsSimpleCoder() const + { return (NumInStreams == 1) && (NumOutStreams == 1); } + + #ifdef EXCLUDE_COM + #else + CLSID EncoderClassID; + CSysString FilePath; + #endif + + CObjectVector CoderProperties; +}; + +struct CBind +{ + UInt32 InCoder; + UInt32 InStream; + UInt32 OutCoder; + UInt32 OutStream; +}; + +struct CCompressionMethodMode +{ + CObjectVector Methods; + CRecordVector Binds; + #ifdef COMPRESS_MT + UInt32 NumThreads; + #endif + bool PasswordIsDefined; + UString Password; + + bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); } + CCompressionMethodMode(): PasswordIsDefined(false) + #ifdef COMPRESS_MT + , NumThreads(1) + #endif + {} +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.cpp new file mode 100644 index 0000000000..7f8f149657 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.cpp @@ -0,0 +1,443 @@ +// 7zDecode.cpp + +#include "StdAfx.h" + +#include "7zDecode.h" + +#include "../../IPassword.h" +#include "../../Common/LockedStream.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/LimitedStreams.h" +#include "../Common/FilterCoder.h" + +#include "7zMethods.h" + +#ifdef COMPRESS_LZMA +#include "../../Compress/LZMA/LZMADecoder.h" +static NArchive::N7z::CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 }; +#endif + +#ifdef COMPRESS_PPMD +#include "../../Compress/PPMD/PPMDDecoder.h" +static NArchive::N7z::CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 }; +#endif + +#ifdef COMPRESS_BCJ_X86 +#include "../../Compress/Branch/x86.h" +static NArchive::N7z::CMethodID k_BCJ_X86 = { { 0x3, 0x3, 0x1, 0x3 }, 4 }; +#endif + +#ifdef COMPRESS_BCJ2 +#include "../../Compress/Branch/x86_2.h" +static NArchive::N7z::CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 }; +#endif + +#ifdef COMPRESS_DEFLATE +#ifndef COMPRESS_DEFLATE_DECODER +#define COMPRESS_DEFLATE_DECODER +#endif +#endif + +#ifdef COMPRESS_DEFLATE_DECODER +#include "../../Compress/Deflate/DeflateDecoder.h" +static NArchive::N7z::CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 }; +#endif + +#ifdef COMPRESS_BZIP2 +#ifndef COMPRESS_BZIP2_DECODER +#define COMPRESS_BZIP2_DECODER +#endif +#endif + +#ifdef COMPRESS_BZIP2_DECODER +#include "../../Compress/BZip2/BZip2Decoder.h" +static NArchive::N7z::CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 }; +#endif + +#ifdef COMPRESS_COPY +#include "../../Compress/Copy/CopyCoder.h" +static NArchive::N7z::CMethodID k_Copy = { { 0x0 }, 1 }; +#endif + +#ifdef CRYPTO_7ZAES +#include "../../Crypto/7zAES/7zAES.h" +static NArchive::N7z::CMethodID k_7zAES = { { 0x6, 0xF1, 0x07, 0x01 }, 4 }; +#endif + +namespace NArchive { +namespace N7z { + +static void ConvertFolderItemInfoToBindInfo(const CFolder &folder, + CBindInfoEx &bindInfo) +{ + bindInfo.Clear(); + int i; + for (i = 0; i < folder.BindPairs.Size(); i++) + { + NCoderMixer2::CBindPair bindPair; + bindPair.InIndex = (UInt32)folder.BindPairs[i].InIndex; + bindPair.OutIndex = (UInt32)folder.BindPairs[i].OutIndex; + bindInfo.BindPairs.Add(bindPair); + } + UInt32 outStreamIndex = 0; + for (i = 0; i < folder.Coders.Size(); i++) + { + NCoderMixer2::CCoderStreamsInfo coderStreamsInfo; + const CCoderInfo &coderInfo = folder.Coders[i]; + coderStreamsInfo.NumInStreams = (UInt32)coderInfo.NumInStreams; + coderStreamsInfo.NumOutStreams = (UInt32)coderInfo.NumOutStreams; + bindInfo.Coders.Add(coderStreamsInfo); + const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); + bindInfo.CoderMethodIDs.Add(altCoderInfo.MethodID); + for (UInt32 j = 0; j < coderStreamsInfo.NumOutStreams; j++, outStreamIndex++) + if (folder.FindBindPairForOutStream(outStreamIndex) < 0) + bindInfo.OutStreams.Add(outStreamIndex); + } + for (i = 0; i < folder.PackStreams.Size(); i++) + bindInfo.InStreams.Add((UInt32)folder.PackStreams[i]); +} + +static bool AreCodersEqual(const NCoderMixer2::CCoderStreamsInfo &a1, + const NCoderMixer2::CCoderStreamsInfo &a2) +{ + return (a1.NumInStreams == a2.NumInStreams) && + (a1.NumOutStreams == a2.NumOutStreams); +} + +static bool AreBindPairsEqual(const NCoderMixer2::CBindPair &a1, const NCoderMixer2::CBindPair &a2) +{ + return (a1.InIndex == a2.InIndex) && + (a1.OutIndex == a2.OutIndex); +} + +static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2) +{ + if (a1.Coders.Size() != a2.Coders.Size()) + return false; + int i; + for (i = 0; i < a1.Coders.Size(); i++) + if (!AreCodersEqual(a1.Coders[i], a2.Coders[i])) + return false; + if (a1.BindPairs.Size() != a2.BindPairs.Size()) + return false; + for (i = 0; i < a1.BindPairs.Size(); i++) + if (!AreBindPairsEqual(a1.BindPairs[i], a2.BindPairs[i])) + return false; + for (i = 0; i < a1.CoderMethodIDs.Size(); i++) + if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i]) + return false; + if (a1.InStreams.Size() != a2.InStreams.Size()) + return false; + if (a1.OutStreams.Size() != a2.OutStreams.Size()) + return false; + return true; +} + +CDecoder::CDecoder(bool multiThread) +{ + #ifndef _ST_MODE + multiThread = true; + #endif + _multiThread = multiThread; + _bindInfoExPrevIsDefinded = false; + #ifndef EXCLUDE_COM + LoadMethodMap(); + #endif +} + +HRESULT CDecoder::Decode(IInStream *inStream, + UInt64 startPos, + const UInt64 *packSizes, + const CFolder &folderInfo, + ISequentialOutStream *outStream, + ICompressProgressInfo *compressProgress + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword + #endif + #ifdef COMPRESS_MT + , bool mtMode, UInt32 numThreads + #endif + ) +{ + CObjectVector< CMyComPtr > inStreams; + + CLockedInStream lockedInStream; + lockedInStream.Init(inStream); + + for (int j = 0; j < folderInfo.PackStreams.Size(); j++) + { + CLockedSequentialInStreamImp *lockedStreamImpSpec = new + CLockedSequentialInStreamImp; + CMyComPtr lockedStreamImp = lockedStreamImpSpec; + lockedStreamImpSpec->Init(&lockedInStream, startPos); + startPos += packSizes[j]; + + CLimitedSequentialInStream *streamSpec = new + CLimitedSequentialInStream; + CMyComPtr inStream = streamSpec; + streamSpec->Init(lockedStreamImp, packSizes[j]); + inStreams.Add(inStream); + } + + int numCoders = folderInfo.Coders.Size(); + + CBindInfoEx bindInfo; + ConvertFolderItemInfoToBindInfo(folderInfo, bindInfo); + bool createNewCoders; + if (!_bindInfoExPrevIsDefinded) + createNewCoders = true; + else + createNewCoders = !AreBindInfoExEqual(bindInfo, _bindInfoExPrev); + if (createNewCoders) + { + int i; + _decoders.Clear(); + // _decoders2.Clear(); + + _mixerCoder.Release(); + + if (_multiThread) + { + _mixerCoderMTSpec = new NCoderMixer2::CCoderMixer2MT; + _mixerCoder = _mixerCoderMTSpec; + _mixerCoderCommon = _mixerCoderMTSpec; + } + else + { + #ifdef _ST_MODE + _mixerCoderSTSpec = new NCoderMixer2::CCoderMixer2ST; + _mixerCoder = _mixerCoderSTSpec; + _mixerCoderCommon = _mixerCoderSTSpec; + #endif + } + _mixerCoderCommon->SetBindInfo(bindInfo); + + for (i = 0; i < numCoders; i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); + #ifndef EXCLUDE_COM + CMethodInfo methodInfo; + if (!GetMethodInfo(altCoderInfo.MethodID, methodInfo)) + return E_NOTIMPL; + #endif + + if (coderInfo.IsSimpleCoder()) + { + CMyComPtr decoder; + CMyComPtr filter; + + #ifdef COMPRESS_LZMA + if (altCoderInfo.MethodID == k_LZMA) + decoder = new NCompress::NLZMA::CDecoder; + #endif + + #ifdef COMPRESS_PPMD + if (altCoderInfo.MethodID == k_PPMD) + decoder = new NCompress::NPPMD::CDecoder; + #endif + + #ifdef COMPRESS_BCJ_X86 + if (altCoderInfo.MethodID == k_BCJ_X86) + filter = new CBCJ_x86_Decoder; + #endif + + #ifdef COMPRESS_DEFLATE_DECODER + if (altCoderInfo.MethodID == k_Deflate) + decoder = new NCompress::NDeflate::NDecoder::CCOMCoder; + #endif + + #ifdef COMPRESS_BZIP2_DECODER + if (altCoderInfo.MethodID == k_BZip2) + decoder = new NCompress::NBZip2::CDecoder; + #endif + + #ifdef COMPRESS_COPY + if (altCoderInfo.MethodID == k_Copy) + decoder = new NCompress::CCopyCoder; + #endif + + #ifdef CRYPTO_7ZAES + if (altCoderInfo.MethodID == k_7zAES) + filter = new NCrypto::NSevenZ::CDecoder; + #endif + + if (filter) + { + CFilterCoder *coderSpec = new CFilterCoder; + decoder = coderSpec; + coderSpec->Filter = filter; + } + #ifndef EXCLUDE_COM + if (decoder == 0) + { + RINOK(_libraries.CreateCoderSpec(methodInfo.FilePath, + methodInfo.Decoder, &decoder)); + } + #endif + + if (decoder == 0) + return E_NOTIMPL; + + _decoders.Add((IUnknown *)decoder); + + if (_multiThread) + _mixerCoderMTSpec->AddCoder(decoder); + #ifdef _ST_MODE + else + _mixerCoderSTSpec->AddCoder(decoder, false); + #endif + } + else + { + CMyComPtr decoder; + + #ifdef COMPRESS_BCJ2 + if (altCoderInfo.MethodID == k_BCJ2) + decoder = new CBCJ2_x86_Decoder; + #endif + + #ifndef EXCLUDE_COM + if (decoder == 0) + { + RINOK(_libraries.CreateCoder2(methodInfo.FilePath, + methodInfo.Decoder, &decoder)); + } + #endif + + if (decoder == 0) + return E_NOTIMPL; + + _decoders.Add((IUnknown *)decoder); + if (_multiThread) + _mixerCoderMTSpec->AddCoder2(decoder); + #ifdef _ST_MODE + else + _mixerCoderSTSpec->AddCoder2(decoder, false); + #endif + } + } + _bindInfoExPrev = bindInfo; + _bindInfoExPrevIsDefinded = true; + } + int i; + _mixerCoderCommon->ReInit(); + + UInt32 packStreamIndex = 0, unPackStreamIndex = 0; + UInt32 coderIndex = 0; + // UInt32 coder2Index = 0; + + for (i = 0; i < numCoders; i++) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders.Front(); + CMyComPtr &decoder = _decoders[coderIndex]; + + { + CMyComPtr setDecoderProperties; + HRESULT result = decoder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecoderProperties); + if (setDecoderProperties) + { + const CByteBuffer &properties = altCoderInfo.Properties; + size_t size = properties.GetCapacity(); + if (size > 0xFFFFFFFF) + return E_NOTIMPL; + if (size > 0) + { + RINOK(setDecoderProperties->SetDecoderProperties2((const Byte *)properties, (UInt32)size)); + } + } + } + + #ifdef COMPRESS_MT + if (mtMode) + { + CMyComPtr setCoderMt; + decoder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt); + if (setCoderMt) + { + RINOK(setCoderMt->SetNumberOfThreads(numThreads)); + } + } + #endif + + #ifndef _NO_CRYPTO + { + CMyComPtr cryptoSetPassword; + HRESULT result = decoder.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword); + if (cryptoSetPassword) + { + if (getTextPassword == 0) + return E_FAIL; + CMyComBSTR password; + RINOK(getTextPassword->CryptoGetTextPassword(&password)); + CByteBuffer buffer; + UString unicodePassword(password); + const UInt32 sizeInBytes = unicodePassword.Length() * 2; + buffer.SetCapacity(sizeInBytes); + for (int i = 0; i < unicodePassword.Length(); i++) + { + wchar_t c = unicodePassword[i]; + ((Byte *)buffer)[i * 2] = (Byte)c; + ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8); + } + RINOK(cryptoSetPassword->CryptoSetPassword( + (const Byte *)buffer, sizeInBytes)); + } + } + #endif + + coderIndex++; + + UInt32 numInStreams = (UInt32)coderInfo.NumInStreams; + UInt32 numOutStreams = (UInt32)coderInfo.NumOutStreams; + CRecordVector packSizesPointers; + CRecordVector unPackSizesPointers; + packSizesPointers.Reserve(numInStreams); + unPackSizesPointers.Reserve(numOutStreams); + UInt32 j; + for (j = 0; j < numOutStreams; j++, unPackStreamIndex++) + unPackSizesPointers.Add(&folderInfo.UnPackSizes[unPackStreamIndex]); + + for (j = 0; j < numInStreams; j++, packStreamIndex++) + { + int bindPairIndex = folderInfo.FindBindPairForInStream(packStreamIndex); + if (bindPairIndex >= 0) + packSizesPointers.Add( + &folderInfo.UnPackSizes[(UInt32)folderInfo.BindPairs[bindPairIndex].OutIndex]); + else + { + int index = folderInfo.FindPackStreamArrayIndex(packStreamIndex); + if (index < 0) + return E_FAIL; + packSizesPointers.Add(&packSizes[index]); + } + } + + _mixerCoderCommon->SetCoderInfo(i, + &packSizesPointers.Front(), + &unPackSizesPointers.Front()); + } + UInt32 mainCoder, temp; + bindInfo.FindOutStream(bindInfo.OutStreams[0], mainCoder, temp); + + if (_multiThread) + _mixerCoderMTSpec->SetProgressCoderIndex(mainCoder); + /* + else + _mixerCoderSTSpec->SetProgressCoderIndex(mainCoder);; + */ + + if (numCoders == 0) + return 0; + CRecordVector inStreamPointers; + inStreamPointers.Reserve(inStreams.Size()); + for (i = 0; i < inStreams.Size(); i++) + inStreamPointers.Add(inStreams[i]); + ISequentialOutStream *outStreamPointer = outStream; + return _mixerCoder->Code(&inStreamPointers.Front(), NULL, + inStreams.Size(), &outStreamPointer, NULL, 1, compressProgress); +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.h new file mode 100644 index 0000000000..6620c2ed8d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zDecode.h @@ -0,0 +1,71 @@ +// 7zDecode.h + +#ifndef __7Z_DECODE_H +#define __7Z_DECODE_H + +#include "../../IStream.h" +#include "../../IPassword.h" + +#include "../Common/CoderMixer2.h" +#include "../Common/CoderMixer2MT.h" +#ifdef _ST_MODE +#include "../Common/CoderMixer2ST.h" +#endif +#ifndef EXCLUDE_COM +#include "../Common/CoderLoader.h" +#endif + +#include "7zItem.h" + +namespace NArchive { +namespace N7z { + +struct CBindInfoEx: public NCoderMixer2::CBindInfo +{ + CRecordVector CoderMethodIDs; + void Clear() + { + CBindInfo::Clear(); + CoderMethodIDs.Clear(); + } +}; + +class CDecoder +{ + #ifndef EXCLUDE_COM + CCoderLibraries _libraries; + #endif + + bool _bindInfoExPrevIsDefinded; + CBindInfoEx _bindInfoExPrev; + + bool _multiThread; + #ifdef _ST_MODE + NCoderMixer2::CCoderMixer2ST *_mixerCoderSTSpec; + #endif + NCoderMixer2::CCoderMixer2MT *_mixerCoderMTSpec; + NCoderMixer2::CCoderMixer2 *_mixerCoderCommon; + + CMyComPtr _mixerCoder; + CObjectVector > _decoders; + // CObjectVector > _decoders2; +public: + CDecoder(bool multiThread); + HRESULT Decode(IInStream *inStream, + UInt64 startPos, + const UInt64 *packSizes, + const CFolder &folder, + ISequentialOutStream *outStream, + ICompressProgressInfo *compressProgress + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPasswordSpec + #endif + #ifdef COMPRESS_MT + , bool mtMode, UInt32 numThreads + #endif + ); +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zExtract.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zExtract.cpp new file mode 100644 index 0000000000..cc892bc9df --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zExtract.cpp @@ -0,0 +1,265 @@ +// 7zExtract.cpp + +#include "StdAfx.h" + +#include "7zHandler.h" +#include "7zFolderOutStream.h" +#include "7zMethods.h" +#include "7zDecode.h" +// #include "7z1Decode.h" + +#include "../../../Common/ComTry.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/ProgressUtils.h" +#include "../../Common/LimitedStreams.h" + +namespace NArchive { +namespace N7z { + +struct CExtractFolderInfo +{ + #ifdef _7Z_VOL + int VolumeIndex; + #endif + CNum FileIndex; + CNum FolderIndex; + CBoolVector ExtractStatuses; + UInt64 UnPackSize; + CExtractFolderInfo( + #ifdef _7Z_VOL + int volumeIndex, + #endif + CNum fileIndex, CNum folderIndex): + #ifdef _7Z_VOL + VolumeIndex(volumeIndex), + #endif + FileIndex(fileIndex), + FolderIndex(folderIndex), + UnPackSize(0) + { + if (fileIndex != kNumNoIndex) + { + ExtractStatuses.Reserve(1); + ExtractStatuses.Add(true); + } + }; +}; + +STDMETHODIMP CHandler::Extract(const UInt32* indices, UInt32 numItems, + Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec) +{ + COM_TRY_BEGIN + bool testMode = (testModeSpec != 0); + CMyComPtr extractCallback = extractCallbackSpec; + UInt64 importantTotalUnPacked = 0; + + bool allFilesMode = (numItems == UInt32(-1)); + if (allFilesMode) + numItems = + #ifdef _7Z_VOL + _refs.Size(); + #else + _database.Files.Size(); + #endif + + if(numItems == 0) + return S_OK; + + /* + if(_volumes.Size() != 1) + return E_FAIL; + const CVolume &volume = _volumes.Front(); + const CArchiveDatabaseEx &_database = volume.Database; + IInStream *_inStream = volume.Stream; + */ + + CObjectVector extractFolderInfoVector; + for(UInt32 ii = 0; ii < numItems; ii++) + { + // UInt32 fileIndex = allFilesMode ? indexIndex : indices[indexIndex]; + UInt32 ref2Index = allFilesMode ? ii : indices[ii]; + // const CRef2 &ref2 = _refs[ref2Index]; + + // for(UInt32 ri = 0; ri < ref2.Refs.Size(); ri++) + { + #ifdef _7Z_VOL + // const CRef &ref = ref2.Refs[ri]; + const CRef &ref = _refs[ref2Index]; + + int volumeIndex = ref.VolumeIndex; + const CVolume &volume = _volumes[volumeIndex]; + const CArchiveDatabaseEx &database = volume.Database; + UInt32 fileIndex = ref.ItemIndex; + #else + const CArchiveDatabaseEx &database = _database; + UInt32 fileIndex = ref2Index; + #endif + + CNum folderIndex = database.FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex == kNumNoIndex) + { + extractFolderInfoVector.Add(CExtractFolderInfo( + #ifdef _7Z_VOL + volumeIndex, + #endif + fileIndex, kNumNoIndex)); + continue; + } + if (extractFolderInfoVector.IsEmpty() || + folderIndex != extractFolderInfoVector.Back().FolderIndex + #ifdef _7Z_VOL + || volumeIndex != extractFolderInfoVector.Back().VolumeIndex + #endif + ) + { + extractFolderInfoVector.Add(CExtractFolderInfo( + #ifdef _7Z_VOL + volumeIndex, + #endif + kNumNoIndex, folderIndex)); + const CFolder &folderInfo = database.Folders[folderIndex]; + UInt64 unPackSize = folderInfo.GetUnPackSize(); + importantTotalUnPacked += unPackSize; + extractFolderInfoVector.Back().UnPackSize = unPackSize; + } + + CExtractFolderInfo &efi = extractFolderInfoVector.Back(); + + // const CFolderInfo &folderInfo = m_dam_Folders[folderIndex]; + CNum startIndex = database.FolderStartFileIndex[folderIndex]; + for (CNum index = efi.ExtractStatuses.Size(); + index <= fileIndex - startIndex; index++) + { + // UInt64 unPackSize = _database.Files[startIndex + index].UnPackSize; + // Count partial_folder_size + // efi.UnPackSize += unPackSize; + // importantTotalUnPacked += unPackSize; + efi.ExtractStatuses.Add(index == fileIndex - startIndex); + } + } + } + + extractCallback->SetTotal(importantTotalUnPacked); + + CDecoder decoder( + #ifdef _ST_MODE + false + #else + true + #endif + ); + // CDecoder1 decoder; + + UInt64 currentImportantTotalUnPacked = 0; + UInt64 totalFolderUnPacked; + + for(int i = 0; i < extractFolderInfoVector.Size(); i++, + currentImportantTotalUnPacked += totalFolderUnPacked) + { + const CExtractFolderInfo &efi = extractFolderInfoVector[i]; + totalFolderUnPacked = efi.UnPackSize; + + RINOK(extractCallback->SetCompleted(¤tImportantTotalUnPacked)); + + CFolderOutStream *folderOutStream = new CFolderOutStream; + CMyComPtr outStream(folderOutStream); + + #ifdef _7Z_VOL + const CVolume &volume = _volumes[efi.VolumeIndex]; + const CArchiveDatabaseEx &database = volume.Database; + #else + const CArchiveDatabaseEx &database = _database; + #endif + + CNum startIndex; + if (efi.FileIndex != kNumNoIndex) + startIndex = efi.FileIndex; + else + startIndex = database.FolderStartFileIndex[efi.FolderIndex]; + + + HRESULT result = folderOutStream->Init(&database, + #ifdef _7Z_VOL + volume.StartRef2Index, + #else + 0, + #endif + startIndex, + &efi.ExtractStatuses, extractCallback, testMode); + + RINOK(result); + + if (efi.FileIndex != kNumNoIndex) + continue; + + CNum folderIndex = efi.FolderIndex; + const CFolder &folderInfo = database.Folders[folderIndex]; + + CLocalProgress *localProgressSpec = new CLocalProgress; + CMyComPtr progress = localProgressSpec; + localProgressSpec->Init(extractCallback, false); + + CLocalCompressProgressInfo *localCompressProgressSpec = + new CLocalCompressProgressInfo; + CMyComPtr compressProgress = localCompressProgressSpec; + localCompressProgressSpec->Init(progress, NULL, ¤tImportantTotalUnPacked); + + CNum packStreamIndex = database.FolderStartPackStreamIndex[folderIndex]; + UInt64 folderStartPackPos = database.GetFolderStreamPos(folderIndex, 0); + + #ifndef _NO_CRYPTO + CMyComPtr getTextPassword; + if (extractCallback) + extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword); + #endif + + try + { + HRESULT result = decoder.Decode( + #ifdef _7Z_VOL + volume.Stream, + #else + _inStream, + #endif + folderStartPackPos, + &database.PackSizes[packStreamIndex], + folderInfo, + outStream, + compressProgress + #ifndef _NO_CRYPTO + , getTextPassword + #endif + #ifdef COMPRESS_MT + , true, _numThreads + #endif + ); + + if (result == S_FALSE) + { + RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError)); + continue; + } + if (result == E_NOTIMPL) + { + RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kUnSupportedMethod)); + continue; + } + if (result != S_OK) + return result; + if (folderOutStream->WasWritingFinished() != S_OK) + { + RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError)); + continue; + } + } + catch(...) + { + RINOK(folderOutStream->FlushCorrupted(NArchive::NExtract::NOperationResult::kDataError)); + continue; + } + } + return S_OK; + COM_TRY_END +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.cpp new file mode 100644 index 0000000000..94afc6905e --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.cpp @@ -0,0 +1,161 @@ +// 7zFolderOutStream.cpp + +#include "StdAfx.h" + +#include "7zFolderOutStream.h" + +namespace NArchive { +namespace N7z { + +CFolderOutStream::CFolderOutStream() +{ + _outStreamWithHashSpec = new COutStreamWithCRC; + _outStreamWithHash = _outStreamWithHashSpec; +} + +HRESULT CFolderOutStream::Init( + const CArchiveDatabaseEx *archiveDatabase, + UInt32 ref2Offset, + UInt32 startIndex, + const CBoolVector *extractStatuses, + IArchiveExtractCallback *extractCallback, + bool testMode) +{ + _archiveDatabase = archiveDatabase; + _ref2Offset = ref2Offset; + _startIndex = startIndex; + + _extractStatuses = extractStatuses; + _extractCallback = extractCallback; + _testMode = testMode; + + _currentIndex = 0; + _fileIsOpen = false; + return WriteEmptyFiles(); +} + +HRESULT CFolderOutStream::OpenFile() +{ + Int32 askMode; + if((*_extractStatuses)[_currentIndex]) + askMode = _testMode ? + NArchive::NExtract::NAskMode::kTest : + NArchive::NExtract::NAskMode::kExtract; + else + askMode = NArchive::NExtract::NAskMode::kSkip; + CMyComPtr realOutStream; + + UInt32 index = _startIndex + _currentIndex; + RINOK(_extractCallback->GetStream(_ref2Offset + index, &realOutStream, askMode)); + + _outStreamWithHashSpec->Init(realOutStream); + if (askMode == NArchive::NExtract::NAskMode::kExtract && + (!realOutStream)) + { + const CFileItem &fileInfo = _archiveDatabase->Files[index]; + if (!fileInfo.IsAnti && !fileInfo.IsDirectory) + askMode = NArchive::NExtract::NAskMode::kSkip; + } + return _extractCallback->PrepareOperation(askMode); +} + +HRESULT CFolderOutStream::WriteEmptyFiles() +{ + for(;_currentIndex < _extractStatuses->Size(); _currentIndex++) + { + UInt32 index = _startIndex + _currentIndex; + const CFileItem &fileInfo = _archiveDatabase->Files[index]; + if (!fileInfo.IsAnti && !fileInfo.IsDirectory && fileInfo.UnPackSize != 0) + return S_OK; + RINOK(OpenFile()); + RINOK(_extractCallback->SetOperationResult( + NArchive::NExtract::NOperationResult::kOK)); + _outStreamWithHashSpec->ReleaseStream(); + } + return S_OK; +} + +STDMETHODIMP CFolderOutStream::Write(const void *data, + UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize = 0; + while(_currentIndex < _extractStatuses->Size()) + { + if (_fileIsOpen) + { + UInt32 index = _startIndex + _currentIndex; + const CFileItem &fileInfo = _archiveDatabase->Files[index]; + UInt64 fileSize = fileInfo.UnPackSize; + + UInt32 numBytesToWrite = (UInt32)MyMin(fileSize - _filePos, + UInt64(size - realProcessedSize)); + + UInt32 processedSizeLocal; + RINOK(_outStreamWithHash->Write((const Byte *)data + realProcessedSize, + numBytesToWrite, &processedSizeLocal)); + + _filePos += processedSizeLocal; + realProcessedSize += processedSizeLocal; + if (_filePos == fileSize) + { + bool digestsAreEqual; + if (fileInfo.IsFileCRCDefined) + digestsAreEqual = fileInfo.FileCRC == _outStreamWithHashSpec->GetCRC(); + else + digestsAreEqual = true; + + RINOK(_extractCallback->SetOperationResult( + digestsAreEqual ? + NArchive::NExtract::NOperationResult::kOK : + NArchive::NExtract::NOperationResult::kCRCError)); + _outStreamWithHashSpec->ReleaseStream(); + _fileIsOpen = false; + _currentIndex++; + } + if (realProcessedSize == size) + { + if (processedSize != NULL) + *processedSize = realProcessedSize; + return WriteEmptyFiles(); + } + } + else + { + RINOK(OpenFile()); + _fileIsOpen = true; + _filePos = 0; + } + } + if (processedSize != NULL) + *processedSize = size; + return S_OK; +} + +HRESULT CFolderOutStream::FlushCorrupted(Int32 resultEOperationResult) +{ + while(_currentIndex < _extractStatuses->Size()) + { + if (_fileIsOpen) + { + RINOK(_extractCallback->SetOperationResult(resultEOperationResult)); + _outStreamWithHashSpec->ReleaseStream(); + _fileIsOpen = false; + _currentIndex++; + } + else + { + RINOK(OpenFile()); + _fileIsOpen = true; + } + } + return S_OK; +} + +HRESULT CFolderOutStream::WasWritingFinished() +{ + if (_currentIndex == _extractStatuses->Size()) + return S_OK; + return E_FAIL; +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.h new file mode 100644 index 0000000000..05a6358c7e --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zFolderOutStream.h @@ -0,0 +1,57 @@ +// 7zFolderOutStream.h + +#ifndef __7Z_FOLDEROUTSTREAM_H +#define __7Z_FOLDEROUTSTREAM_H + +#include "7zIn.h" + +#include "../../IStream.h" +#include "../IArchive.h" +#include "../Common/OutStreamWithCRC.h" + +namespace NArchive { +namespace N7z { + +class CFolderOutStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + CFolderOutStream(); + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +private: + + COutStreamWithCRC *_outStreamWithHashSpec; + CMyComPtr _outStreamWithHash; + const CArchiveDatabaseEx *_archiveDatabase; + const CBoolVector *_extractStatuses; + UInt32 _startIndex; + UInt32 _ref2Offset; + int _currentIndex; + // UInt64 _currentDataPos; + CMyComPtr _extractCallback; + bool _testMode; + + bool _fileIsOpen; + UInt64 _filePos; + + HRESULT OpenFile(); + HRESULT WriteEmptyFiles(); +public: + HRESULT Init( + const CArchiveDatabaseEx *archiveDatabase, + UInt32 ref2Offset, + UInt32 startIndex, + const CBoolVector *extractStatuses, + IArchiveExtractCallback *extractCallback, + bool testMode); + HRESULT FlushCorrupted(Int32 resultEOperationResult); + HRESULT WasWritingFinished(); +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.cpp new file mode 100644 index 0000000000..b6f492aea8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.cpp @@ -0,0 +1,757 @@ +// 7zHandler.cpp + +#include "StdAfx.h" + +#include "7zHandler.h" +#include "7zProperties.h" + +#include "../../../Common/IntToString.h" +#include "../../../Common/ComTry.h" +#include "../../../Windows/Defs.h" + +#include "../Common/ItemNameUtils.h" +#ifdef _7Z_VOL +#include "../Common/MultiStream.h" +#endif + +#ifdef __7Z_SET_PROPERTIES +#ifdef EXTRACT_ONLY +#include "../Common/ParseProperties.h" +#endif +#endif + +using namespace NWindows; + +namespace NArchive { +namespace N7z { + +CHandler::CHandler() +{ + #ifdef COMPRESS_MT + _numThreads = NWindows::NSystem::GetNumberOfProcessors(); + #endif + #ifndef EXTRACT_ONLY + Init(); + #endif + #ifndef EXCLUDE_COM + LoadMethodMap(); + #endif +} + +STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems) +{ + COM_TRY_BEGIN + *numItems = + #ifdef _7Z_VOL + _refs.Size(); + #else + *numItems = _database.Files.Size(); + #endif + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value) +{ + value->vt = VT_EMPTY; + return S_OK; +} + +#ifdef _SFX + +STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) +{ + return E_NOTIMPL; +} + +STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType) +{ + return E_NOTIMPL; +} + +#endif + + +STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProperties) +{ + *numProperties = 0; + return S_OK; +} + +STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType) +{ + return E_NOTIMPL; +} + + +static void MySetFileTime(bool timeDefined, FILETIME unixTime, + NWindows::NCOM::CPropVariant &propVariant) +{ + if (timeDefined) + propVariant = unixTime; +} + +/* +inline static wchar_t GetHex(Byte value) +{ + return (value < 10) ? ('0' + value) : ('A' + (value - 10)); +} + +static UString ConvertBytesToHexString(const Byte *data, UInt32 size) +{ + UString result; + for (UInt32 i = 0; i < size; i++) + { + Byte b = data[i]; + result += GetHex(b >> 4); + result += GetHex(b & 0xF); + } + return result; +} +*/ + + +#ifndef _SFX + +static UString ConvertUInt32ToString(UInt32 value) +{ + wchar_t buffer[32]; + ConvertUInt64ToString(value, buffer); + return buffer; +} + +static UString GetStringForSizeValue(UInt32 value) +{ + for (int i = 31; i >= 0; i--) + if ((UInt32(1) << i) == value) + return ConvertUInt32ToString(i); + UString result; + if (value % (1 << 20) == 0) + { + result += ConvertUInt32ToString(value >> 20); + result += L"m"; + } + else if (value % (1 << 10) == 0) + { + result += ConvertUInt32ToString(value >> 10); + result += L"k"; + } + else + { + result += ConvertUInt32ToString(value); + result += L"b"; + } + return result; +} + +static CMethodID k_Copy = { { 0x0 }, 1 }; +static CMethodID k_LZMA = { { 0x3, 0x1, 0x1 }, 3 }; +static CMethodID k_BCJ = { { 0x3, 0x3, 0x1, 0x3 }, 4 }; +static CMethodID k_BCJ2 = { { 0x3, 0x3, 0x1, 0x1B }, 4 }; +static CMethodID k_PPMD = { { 0x3, 0x4, 0x1 }, 3 }; +static CMethodID k_Deflate = { { 0x4, 0x1, 0x8 }, 3 }; +static CMethodID k_BZip2 = { { 0x4, 0x2, 0x2 }, 3 }; + +static inline char GetHex(Byte value) +{ + return (value < 10) ? ('0' + value) : ('A' + (value - 10)); +} +static inline UString GetHex2(Byte value) +{ + UString result; + result += GetHex(value >> 4); + result += GetHex(value & 0xF); + return result; +} + +#endif + +static inline UInt32 GetUInt32FromMemLE(const Byte *p) +{ + return p[0] | (((UInt32)p[1]) << 8) | (((UInt32)p[2]) << 16) | (((UInt32)p[3]) << 24); +} + +STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value) +{ + COM_TRY_BEGIN + NWindows::NCOM::CPropVariant propVariant; + + /* + const CRef2 &ref2 = _refs[index]; + if (ref2.Refs.IsEmpty()) + return E_FAIL; + const CRef &ref = ref2.Refs.Front(); + */ + + #ifdef _7Z_VOL + const CRef &ref = _refs[index]; + const CVolume &volume = _volumes[ref.VolumeIndex]; + const CArchiveDatabaseEx &_database = volume.Database; + UInt32 index2 = ref.ItemIndex; + const CFileItem &item = _database.Files[index2]; + #else + const CFileItem &item = _database.Files[index]; + UInt32 index2 = index; + #endif + + switch(propID) + { + case kpidPath: + { + if (!item.Name.IsEmpty()) + propVariant = NItemName::GetOSName(item.Name); + break; + } + case kpidIsFolder: + propVariant = item.IsDirectory; + break; + case kpidSize: + { + propVariant = item.UnPackSize; + // propVariant = ref2.UnPackSize; + break; + } + case kpidPosition: + { + /* + if (ref2.Refs.Size() > 1) + propVariant = ref2.StartPos; + else + */ + if (item.IsStartPosDefined) + propVariant = item.StartPos; + break; + } + case kpidPackedSize: + { + // propVariant = ref2.PackSize; + { + CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + { + if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2) + propVariant = _database.GetFolderFullPackSize(folderIndex); + /* + else + propVariant = UInt64(0); + */ + } + else + propVariant = UInt64(0); + } + break; + } + case kpidLastAccessTime: + MySetFileTime(item.IsLastAccessTimeDefined, item.LastAccessTime, propVariant); + break; + case kpidCreationTime: + MySetFileTime(item.IsCreationTimeDefined, item.CreationTime, propVariant); + break; + case kpidLastWriteTime: + MySetFileTime(item.IsLastWriteTimeDefined, item.LastWriteTime, propVariant); + break; + case kpidAttributes: + if (item.AreAttributesDefined) + propVariant = item.Attributes; + break; + case kpidCRC: + if (item.IsFileCRCDefined) + propVariant = item.FileCRC; + break; + #ifndef _SFX + case kpidMethod: + { + CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + { + const CFolder &folderInfo = _database.Folders[folderIndex]; + UString methodsString; + for (int i = folderInfo.Coders.Size() - 1; i >= 0; i--) + { + const CCoderInfo &coderInfo = folderInfo.Coders[i]; + if (!methodsString.IsEmpty()) + methodsString += L' '; + CMethodInfo methodInfo; + + bool methodIsKnown; + + for (int j = 0; j < coderInfo.AltCoders.Size(); j++) + { + if (j > 0) + methodsString += L"|"; + const CAltCoderInfo &altCoderInfo = coderInfo.AltCoders[j]; + + UString methodName; + #ifdef NO_REGISTRY + + methodIsKnown = true; + if (altCoderInfo.MethodID == k_Copy) + methodName = L"Copy"; + else if (altCoderInfo.MethodID == k_LZMA) + methodName = L"LZMA"; + else if (altCoderInfo.MethodID == k_BCJ) + methodName = L"BCJ"; + else if (altCoderInfo.MethodID == k_BCJ2) + methodName = L"BCJ2"; + else if (altCoderInfo.MethodID == k_PPMD) + methodName = L"PPMD"; + else if (altCoderInfo.MethodID == k_Deflate) + methodName = L"Deflate"; + else if (altCoderInfo.MethodID == k_BZip2) + methodName = L"BZip2"; + else + methodIsKnown = false; + + #else + + methodIsKnown = GetMethodInfo( + altCoderInfo.MethodID, methodInfo); + methodName = methodInfo.Name; + + #endif + + if (methodIsKnown) + { + methodsString += methodName; + if (altCoderInfo.MethodID == k_LZMA) + { + if (altCoderInfo.Properties.GetCapacity() >= 5) + { + methodsString += L":"; + UInt32 dicSize = GetUInt32FromMemLE( + ((const Byte *)altCoderInfo.Properties + 1)); + methodsString += GetStringForSizeValue(dicSize); + } + } + else if (altCoderInfo.MethodID == k_PPMD) + { + if (altCoderInfo.Properties.GetCapacity() >= 5) + { + Byte order = *(const Byte *)altCoderInfo.Properties; + methodsString += L":o"; + methodsString += ConvertUInt32ToString(order); + methodsString += L":mem"; + UInt32 dicSize = GetUInt32FromMemLE( + ((const Byte *)altCoderInfo.Properties + 1)); + methodsString += GetStringForSizeValue(dicSize); + } + } + else + { + if (altCoderInfo.Properties.GetCapacity() > 0) + { + methodsString += L":["; + for (size_t bi = 0; bi < altCoderInfo.Properties.GetCapacity(); bi++) + { + if (bi > 2 && bi + 1 < altCoderInfo.Properties.GetCapacity()) + { + methodsString += L".."; + break; + } + else + methodsString += GetHex2(altCoderInfo.Properties[bi]); + } + methodsString += L"]"; + } + } + } + else + { + methodsString += altCoderInfo.MethodID.ConvertToString(); + } + } + } + propVariant = methodsString; + } + } + break; + case kpidBlock: + { + CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + propVariant = (UInt32)folderIndex; + } + break; + case kpidPackedSize0: + case kpidPackedSize1: + case kpidPackedSize2: + case kpidPackedSize3: + case kpidPackedSize4: + { + CNum folderIndex = _database.FileIndexToFolderIndexMap[index2]; + if (folderIndex != kNumNoIndex) + { + const CFolder &folderInfo = _database.Folders[folderIndex]; + if (_database.FolderStartFileIndex[folderIndex] == (CNum)index2 && + folderInfo.PackStreams.Size() > (int)(propID - kpidPackedSize0)) + { + propVariant = _database.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0); + } + else + propVariant = UInt64(0); + } + else + propVariant = UInt64(0); + } + break; + #endif + case kpidIsAnti: + propVariant = item.IsAnti; + break; + } + propVariant.Detach(value); + return S_OK; + COM_TRY_END +} + +static const wchar_t *kExt = L"7z"; +static const wchar_t *kAfterPart = L".7z"; + +#ifdef _7Z_VOL + +class CVolumeName +{ + bool _first; + UString _unchangedPart; + UString _changedPart; + UString _afterPart; +public: + bool InitName(const UString &name) + { + _first = true; + int dotPos = name.ReverseFind('.'); + UString basePart = name; + if (dotPos >= 0) + { + UString ext = name.Mid(dotPos + 1); + if (ext.CompareNoCase(kExt)==0 || + ext.CompareNoCase(L"EXE") == 0) + { + _afterPart = kAfterPart; + basePart = name.Left(dotPos); + } + } + + int numLetters = 1; + bool splitStyle = false; + if (basePart.Right(numLetters) == L"1") + { + while (numLetters < basePart.Length()) + { + if (basePart[basePart.Length() - numLetters - 1] != '0') + break; + numLetters++; + } + } + else + return false; + _unchangedPart = basePart.Left(basePart.Length() - numLetters); + _changedPart = basePart.Right(numLetters); + return true; + } + + UString GetNextName() + { + UString newName; + // if (_newStyle || !_first) + { + int i; + int numLetters = _changedPart.Length(); + for (i = numLetters - 1; i >= 0; i--) + { + wchar_t c = _changedPart[i]; + if (c == L'9') + { + c = L'0'; + newName = c + newName; + if (i == 0) + newName = UString(L'1') + newName; + continue; + } + c++; + newName = UString(c) + newName; + i--; + for (; i >= 0; i--) + newName = _changedPart[i] + newName; + break; + } + _changedPart = newName; + } + _first = false; + return _unchangedPart + _changedPart + _afterPart; + } +}; + +#endif + +STDMETHODIMP CHandler::Open(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openArchiveCallback) +{ + COM_TRY_BEGIN + Close(); + #ifndef _SFX + _fileInfoPopIDs.Clear(); + #endif + try + { + CMyComPtr openArchiveCallbackTemp = openArchiveCallback; + #ifdef _7Z_VOL + CVolumeName seqName; + + CMyComPtr openVolumeCallback; + #endif + + #ifndef _NO_CRYPTO + CMyComPtr getTextPassword; + if (openArchiveCallback) + { + openArchiveCallbackTemp.QueryInterface( + IID_ICryptoGetTextPassword, &getTextPassword); + } + #endif + #ifdef _7Z_VOL + if (openArchiveCallback) + { + openArchiveCallbackTemp.QueryInterface(IID_IArchiveOpenVolumeCallback, &openVolumeCallback); + } + while(true) + { + CMyComPtr inStream; + if (!_volumes.IsEmpty()) + { + if (!openVolumeCallback) + break; + if(_volumes.Size() == 1) + { + UString baseName; + { + NCOM::CPropVariant propVariant; + RINOK(openVolumeCallback->GetProperty(kpidName, &propVariant)); + if (propVariant.vt != VT_BSTR) + break; + baseName = propVariant.bstrVal; + } + seqName.InitName(baseName); + } + + UString fullName = seqName.GetNextName(); + HRESULT result = openVolumeCallback->GetStream(fullName, &inStream); + if (result == S_FALSE) + break; + if (result != S_OK) + return result; + if (!stream) + break; + } + else + inStream = stream; + + CInArchive archive; + RINOK(archive.Open(inStream, maxCheckStartPosition)); + + _volumes.Add(CVolume()); + CVolume &volume = _volumes.Back(); + CArchiveDatabaseEx &database = volume.Database; + volume.Stream = inStream; + volume.StartRef2Index = _refs.Size(); + + HRESULT result = archive.ReadDatabase(database + #ifndef _NO_CRYPTO + , getTextPassword + #endif + ); + if (result != S_OK) + { + _volumes.Clear(); + return result; + } + database.Fill(); + for(int i = 0; i < database.Files.Size(); i++) + { + CRef refNew; + refNew.VolumeIndex = _volumes.Size() - 1; + refNew.ItemIndex = i; + _refs.Add(refNew); + /* + const CFileItem &file = database.Files[i]; + int j; + */ + /* + for (j = _refs.Size() - 1; j >= 0; j--) + { + CRef2 &ref2 = _refs[j]; + const CRef &ref = ref2.Refs.Back(); + const CVolume &volume2 = _volumes[ref.VolumeIndex]; + const CArchiveDatabaseEx &database2 = volume2.Database; + const CFileItem &file2 = database2.Files[ref.ItemIndex]; + if (file2.Name.CompareNoCase(file.Name) == 0) + { + if (!file.IsStartPosDefined) + continue; + if (file.StartPos != ref2.StartPos + ref2.UnPackSize) + continue; + ref2.Refs.Add(refNew); + break; + } + } + */ + /* + j = -1; + if (j < 0) + { + CRef2 ref2New; + ref2New.Refs.Add(refNew); + j = _refs.Add(ref2New); + } + CRef2 &ref2 = _refs[j]; + ref2.UnPackSize += file.UnPackSize; + ref2.PackSize += database.GetFilePackSize(i); + if (ref2.Refs.Size() == 1 && file.IsStartPosDefined) + ref2.StartPos = file.StartPos; + */ + } + if (database.Files.Size() != 1) + break; + const CFileItem &file = database.Files.Front(); + if (!file.IsStartPosDefined) + break; + } + #else + CInArchive archive; + RINOK(archive.Open(stream, maxCheckStartPosition)); + HRESULT result = archive.ReadDatabase(_database + #ifndef _NO_CRYPTO + , getTextPassword + #endif + ); + RINOK(result); + _database.Fill(); + _inStream = stream; + #endif + } + catch(...) + { + Close(); + return S_FALSE; + } + // _inStream = stream; + #ifndef _SFX + FillPopIDs(); + #endif + return S_OK; + COM_TRY_END +} + +STDMETHODIMP CHandler::Close() +{ + COM_TRY_BEGIN + #ifdef _7Z_VOL + _volumes.Clear(); + _refs.Clear(); + #else + _inStream.Release(); + _database.Clear(); + #endif + return S_OK; + COM_TRY_END +} + +#ifdef _7Z_VOL +STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream) +{ + if (index != 0) + return E_INVALIDARG; + *stream = 0; + CMultiStream *streamSpec = new CMultiStream; + CMyComPtr streamTemp = streamSpec; + + UInt64 pos = 0; + const UString *fileName; + for (int i = 0; i < _refs.Size(); i++) + { + const CRef &ref = _refs[i]; + const CVolume &volume = _volumes[ref.VolumeIndex]; + const CArchiveDatabaseEx &database = volume.Database; + const CFileItem &file = database.Files[ref.ItemIndex]; + if (i == 0) + fileName = &file.Name; + else + if (fileName->Compare(file.Name) != 0) + return S_FALSE; + if (!file.IsStartPosDefined) + return S_FALSE; + if (file.StartPos != pos) + return S_FALSE; + CNum folderIndex = database.FileIndexToFolderIndexMap[ref.ItemIndex]; + if (folderIndex == kNumNoIndex) + { + if (file.UnPackSize != 0) + return E_FAIL; + continue; + } + if (database.NumUnPackStreamsVector[folderIndex] != 1) + return S_FALSE; + const CFolder &folder = database.Folders[folderIndex]; + if (folder.Coders.Size() != 1) + return S_FALSE; + const CCoderInfo &coder = folder.Coders.Front(); + if (coder.NumInStreams != 1 || coder.NumOutStreams != 1) + return S_FALSE; + const CAltCoderInfo &altCoder = coder.AltCoders.Front(); + if (altCoder.MethodID.IDSize != 1 || altCoder.MethodID.ID[0] != 0) + return S_FALSE; + + pos += file.UnPackSize; + CMultiStream::CSubStreamInfo subStreamInfo; + subStreamInfo.Stream = volume.Stream; + subStreamInfo.Pos = database.GetFolderStreamPos(folderIndex, 0); + subStreamInfo.Size = file.UnPackSize; + streamSpec->Streams.Add(subStreamInfo); + } + streamSpec->Init(); + *stream = streamTemp.Detach(); + return S_OK; +} +#endif + + +#ifdef __7Z_SET_PROPERTIES +#ifdef EXTRACT_ONLY + +STDMETHODIMP CHandler::SetProperties(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) +{ + COM_TRY_BEGIN + const UInt32 numProcessors = NSystem::GetNumberOfProcessors(); + _numThreads = numProcessors; + + for (int i = 0; i < numProperties; i++) + { + UString name = names[i]; + name.MakeUpper(); + if (name.IsEmpty()) + return E_INVALIDARG; + const PROPVARIANT &value = values[i]; + UInt32 number; + int index = ParseStringToUInt32(name, number); + if (index == 0) + { + if(name.Left(2).CompareNoCase(L"MT") == 0) + { + RINOK(ParseMtProp(name.Mid(2), value, numProcessors, _numThreads)); + continue; + } + else + return E_INVALIDARG; + } + } + return S_OK; + COM_TRY_END +} + +#endif +#endif + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.h new file mode 100644 index 0000000000..3da9b88599 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHandler.h @@ -0,0 +1,234 @@ +// 7z/Handler.h + +#ifndef __7Z_HANDLER_H +#define __7Z_HANDLER_H + +#include "../IArchive.h" +#include "7zIn.h" + +#include "7zCompressionMode.h" + +#ifndef _SFX +#include "7zMethods.h" +#endif + +#ifdef COMPRESS_MT +#include "../../../Windows/System.h" +#endif + +namespace NArchive { +namespace N7z { + +#ifdef _7Z_VOL +struct CRef +{ + int VolumeIndex; + int ItemIndex; +}; + +/* +struct CRef2 +{ + CRecordVector Refs; + UInt64 UnPackSize; + UInt64 PackSize; + UInt64 StartPos; + CRef2(): UnPackSize(0), PackSize(0), StartPos(0) {} +}; +*/ + +struct CVolume +{ + int StartRef2Index; + CMyComPtr Stream; + CArchiveDatabaseEx Database; +}; +#endif + +#ifndef EXTRACT_ONLY + +struct COneMethodInfo +{ + CObjectVector CoderProperties; + UString MethodName; +}; +#endif + +// {23170F69-40C1-278A-1000-000110070000} +DEFINE_GUID(CLSID_CFormat7z, + 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00); + +#ifndef __7Z_SET_PROPERTIES + +#ifdef EXTRACT_ONLY +#ifdef COMPRESS_MT +#define __7Z_SET_PROPERTIES +#endif +#else +#define __7Z_SET_PROPERTIES +#endif + +#endif + + +class CHandler: + public IInArchive, + #ifdef _7Z_VOL + public IInArchiveGetStream, + #endif + #ifdef __7Z_SET_PROPERTIES + public ISetProperties, + #endif + #ifndef EXTRACT_ONLY + public IOutArchive, + #endif + public CMyUnknownImp +{ +public: + MY_QUERYINTERFACE_BEGIN + #ifdef _7Z_VOL + MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream) + #endif + #ifdef __7Z_SET_PROPERTIES + MY_QUERYINTERFACE_ENTRY(ISetProperties) + #endif + #ifndef EXTRACT_ONLY + MY_QUERYINTERFACE_ENTRY(IOutArchive) + #endif + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + + STDMETHOD(Open)(IInStream *stream, + const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openArchiveCallback); + STDMETHOD(Close)(); + + STDMETHOD(GetNumberOfItems)(UInt32 *numItems); + STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value); + STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback); + + STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value); + + STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties); + STDMETHOD(GetPropertyInfo)(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType); + + STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties); + STDMETHOD(GetArchivePropertyInfo)(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType); + + #ifdef _7Z_VOL + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream); + #endif + + #ifdef __7Z_SET_PROPERTIES + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties); + #endif + + #ifndef EXTRACT_ONLY + // IOutArchiveHandler + STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback); + + STDMETHOD(GetFileTimeType)(UInt32 *type); + + // ISetProperties + + HRESULT SetSolidSettings(const UString &s); + HRESULT SetSolidSettings(const PROPVARIANT &value); + #endif + + CHandler(); + +private: + #ifdef _7Z_VOL + CObjectVector _volumes; + CObjectVector _refs; + #else + CMyComPtr _inStream; + NArchive::N7z::CArchiveDatabaseEx _database; + #endif + + #ifdef COMPRESS_MT + UInt32 _numThreads; + #endif + + #ifndef EXTRACT_ONLY + CObjectVector _methods; + CRecordVector _binds; + bool _removeSfxBlock; + UInt64 _numSolidFiles; + UInt64 _numSolidBytes; + bool _numSolidBytesDefined; + bool _solidExtension; + + bool _compressHeaders; + bool _compressHeadersFull; + bool _encryptHeaders; + + bool _autoFilter; + UInt32 _level; + + bool _volumeMode; + + + HRESULT SetParam(COneMethodInfo &oneMethodInfo, const UString &name, const UString &value); + HRESULT SetParams(COneMethodInfo &oneMethodInfo, const UString &srcString); + + HRESULT SetPassword(CCompressionMethodMode &methodMode, + IArchiveUpdateCallback *updateCallback); + + HRESULT SetCompressionMethod(CCompressionMethodMode &method, + CObjectVector &methodsInfo + #ifdef COMPRESS_MT + , UInt32 numThreads + #endif + ); + + HRESULT SetCompressionMethod( + CCompressionMethodMode &method, + CCompressionMethodMode &headerMethod); + + #endif + + #ifndef _SFX + + CRecordVector _fileInfoPopIDs; + void FillPopIDs(); + + #endif + + #ifndef EXTRACT_ONLY + + void InitSolidFiles() { _numSolidFiles = UInt64(Int64(-1)); } + void InitSolidSize() { _numSolidBytes = UInt64(Int64(-1)); } + void InitSolid() + { + InitSolidFiles(); + InitSolidSize(); + _solidExtension = false; + _numSolidBytesDefined = false; + } + + void Init() + { + _removeSfxBlock = false; + _compressHeaders = true; + _compressHeadersFull = true; + _encryptHeaders = false; + #ifdef COMPRESS_MT + _numThreads = NWindows::NSystem::GetNumberOfProcessors(); + #endif + + _level = 5; + _autoFilter = true; + _volumeMode = false; + InitSolid(); + } + #endif +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.cpp new file mode 100644 index 0000000000..7aff58fa47 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.cpp @@ -0,0 +1,19 @@ +// 7z/Header.cpp + +#include "StdAfx.h" +#include "7zHeader.h" + +namespace NArchive { +namespace N7z { + +Byte kSignature[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C}; +Byte kFinishSignature[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C + 1}; + +class SignatureInitializer +{ +public: + SignatureInitializer() { kSignature[0]--; kFinishSignature[0]--;}; +} g_SignatureInitializer; + +}} + diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.h new file mode 100644 index 0000000000..f301677267 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zHeader.h @@ -0,0 +1,96 @@ +// 7z/7zHeader.h + +#ifndef __7Z_HEADER_H +#define __7Z_HEADER_H + +#include "7zMethodID.h" + +namespace NArchive { +namespace N7z { + +const int kSignatureSize = 6; +extern Byte kSignature[kSignatureSize]; + +// #define _7Z_VOL +// 7z-MultiVolume is not finished yet. +// It can work already, but I still do not like some +// things of that new multivolume format. +// So please keep it commented. + +#ifdef _7Z_VOL +extern Byte kFinishSignature[kSignatureSize]; +#endif + +struct CArchiveVersion +{ + Byte Major; + Byte Minor; +}; + +const Byte kMajorVersion = 0; + +struct CStartHeader +{ + UInt64 NextHeaderOffset; + UInt64 NextHeaderSize; + UInt32 NextHeaderCRC; +}; + +const UInt32 kStartHeaderSize = 20; + +#ifdef _7Z_VOL +struct CFinishHeader: public CStartHeader +{ + UInt64 ArchiveStartOffset; // data offset from end if that struct + UInt64 AdditionalStartBlockSize; // start signature & start header size +}; + +const UInt32 kFinishHeaderSize = kStartHeaderSize + 16; +#endif + +namespace NID +{ + enum EEnum + { + kEnd, + + kHeader, + + kArchiveProperties, + + kAdditionalStreamsInfo, + kMainStreamsInfo, + kFilesInfo, + + kPackInfo, + kUnPackInfo, + kSubStreamsInfo, + + kSize, + kCRC, + + kFolder, + + kCodersUnPackSize, + kNumUnPackStream, + + kEmptyStream, + kEmptyFile, + kAnti, + + kName, + kCreationTime, + kLastAccessTime, + kLastWriteTime, + kWinAttributes, + kComment, + + kEncodedHeader, + + kStartPos + }; +} + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.cpp new file mode 100644 index 0000000000..86709d36d8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.cpp @@ -0,0 +1,1294 @@ +// 7zIn.cpp + +#include "StdAfx.h" + +#include "7zIn.h" +#include "7zMethods.h" +#include "7zDecode.h" +#include "../../Common/StreamObjects.h" +#include "../../Common/StreamUtils.h" +#include "../../../Common/CRC.h" + +namespace NArchive { +namespace N7z { + +class CStreamSwitch +{ + CInArchive *_archive; + bool _needRemove; +public: + CStreamSwitch(): _needRemove(false) {} + ~CStreamSwitch() { Remove(); } + void Remove(); + void Set(CInArchive *archive, const Byte *data, size_t size); + void Set(CInArchive *archive, const CByteBuffer &byteBuffer); + HRESULT Set(CInArchive *archive, const CObjectVector *dataVector); +}; + +void CStreamSwitch::Remove() +{ + if (_needRemove) + { + _archive->DeleteByteStream(); + _needRemove = false; + } +} + +void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size) +{ + Remove(); + _archive = archive; + _archive->AddByteStream(data, size); + _needRemove = true; +} + +void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer) +{ + Set(archive, byteBuffer, byteBuffer.GetCapacity()); +} + +HRESULT CStreamSwitch::Set(CInArchive *archive, const CObjectVector *dataVector) +{ + Remove(); + Byte external; + RINOK(archive->ReadByte(external)); + if (external != 0) + { + CNum dataIndex; + RINOK(archive->ReadNum(dataIndex)); + Set(archive, (*dataVector)[dataIndex]); + } + return S_OK; +} + + +CInArchiveException::CInArchiveException(CCauseType cause): + Cause(cause) +{} + +HRESULT CInArchive::ReadDirect(IInStream *stream, void *data, UInt32 size, + UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result = ReadStream(stream, data, size, &realProcessedSize); + if(processedSize != NULL) + *processedSize = realProcessedSize; + _position += realProcessedSize; + return result; +} + +HRESULT CInArchive::ReadDirect(void *data, UInt32 size, UInt32 *processedSize) +{ + return ReadDirect(_stream, data, size, processedSize); +} + +HRESULT CInArchive::SafeReadDirect(void *data, UInt32 size) +{ + UInt32 realProcessedSize; + RINOK(ReadDirect(data, size, &realProcessedSize)); + if (realProcessedSize != size) + throw CInArchiveException(CInArchiveException::kUnexpectedEndOfArchive); + return S_OK; +} + +HRESULT CInArchive::SafeReadDirectByte(Byte &b) +{ + return SafeReadDirect(&b, 1); +} + +HRESULT CInArchive::SafeReadDirectUInt32(UInt32 &value) +{ + value = 0; + for (int i = 0; i < 4; i++) + { + Byte b; + RINOK(SafeReadDirectByte(b)); + value |= (UInt32(b) << (8 * i)); + } + return S_OK; +} + +HRESULT CInArchive::SafeReadDirectUInt64(UInt64 &value) +{ + value = 0; + for (int i = 0; i < 8; i++) + { + Byte b; + RINOK(SafeReadDirectByte(b)); + value |= (UInt64(b) << (8 * i)); + } + return S_OK; +} + +HRESULT CInArchive::ReadNumber(UInt64 &value) +{ + Byte firstByte; + RINOK(ReadByte(firstByte)); + Byte mask = 0x80; + value = 0; + for (int i = 0; i < 8; i++) + { + if ((firstByte & mask) == 0) + { + UInt64 highPart = firstByte & (mask - 1); + value += (highPart << (i * 8)); + return S_OK; + } + Byte b; + RINOK(ReadByte(b)); + value |= (UInt64(b) << (8 * i)); + mask >>= 1; + } + return S_OK; +} + +HRESULT CInArchive::ReadNum(CNum &value) +{ + UInt64 value64; + RINOK(ReadNumber(value64)); + if (value64 > kNumMax) + return E_FAIL; + value = (CNum)value64; + return S_OK; +} + +HRESULT CInArchive::ReadUInt32(UInt32 &value) +{ + value = 0; + for (int i = 0; i < 4; i++) + { + Byte b; + RINOK(ReadByte(b)); + value |= (UInt32(b) << (8 * i)); + } + return S_OK; +} + +HRESULT CInArchive::ReadUInt64(UInt64 &value) +{ + value = 0; + for (int i = 0; i < 8; i++) + { + Byte b; + RINOK(ReadByte(b)); + value |= (UInt64(b) << (8 * i)); + } + return S_OK; +} + +static inline bool TestSignatureCandidate(const void *testBytes) +{ + for (int i = 0; i < kSignatureSize; i++) + if (((const Byte *)testBytes)[i] != kSignature[i]) + return false; + return true; +} + +#ifdef _7Z_VOL +static inline bool TestFinishSignatureCandidate(const void *testBytes) +{ + for (int i = 0; i < kSignatureSize; i++) + if (((const Byte *)testBytes)[i] != kFinishSignature[i]) + return false; + return true; +} +#endif + +HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + _position = _arhiveBeginStreamPosition; + RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL)); + + Byte signature[kSignatureSize]; + UInt32 processedSize; + RINOK(ReadDirect(stream, signature, kSignatureSize, &processedSize)); + if(processedSize != kSignatureSize) + return S_FALSE; + if (TestSignatureCandidate(signature)) + return S_OK; + + CByteBuffer byteBuffer; + const UInt32 kBufferSize = (1 << 16); + byteBuffer.SetCapacity(kBufferSize); + Byte *buffer = byteBuffer; + UInt32 numPrevBytes = kSignatureSize - 1; + memmove(buffer, signature + 1, numPrevBytes); + UInt64 curTestPos = _arhiveBeginStreamPosition + 1; + while(true) + { + if (searchHeaderSizeLimit != NULL) + if (curTestPos - _arhiveBeginStreamPosition > *searchHeaderSizeLimit) + return S_FALSE; + UInt32 numReadBytes = kBufferSize - numPrevBytes; + RINOK(ReadDirect(stream, buffer + numPrevBytes, numReadBytes, &processedSize)); + UInt32 numBytesInBuffer = numPrevBytes + processedSize; + if (numBytesInBuffer < kSignatureSize) + return S_FALSE; + UInt32 numTests = numBytesInBuffer - kSignatureSize + 1; + for(UInt32 pos = 0; pos < numTests; pos++, curTestPos++) + { + if (TestSignatureCandidate(buffer + pos)) + { + _arhiveBeginStreamPosition = curTestPos; + _position = curTestPos + kSignatureSize; + return stream->Seek(_position, STREAM_SEEK_SET, NULL); + } + } + numPrevBytes = numBytesInBuffer - numTests; + memmove(buffer, buffer + numTests, numPrevBytes); + } +} + +// Out: _position must point to end of signature + +#ifdef _7Z_VOL +HRESULT CInArchive::FindFinishSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + RINOK(stream->Seek(0, STREAM_SEEK_END, &_position)); + if (_position < kSignatureSize) + return S_FALSE; + + CByteBuffer byteBuffer; + const UInt32 kBufferSize = (1 << 18); + byteBuffer.SetCapacity(kBufferSize); + Byte *buffer = byteBuffer; + UInt32 numPrevBytes = 0; + UInt64 limitPos = 0; + if (searchHeaderSizeLimit != NULL) + if (*searchHeaderSizeLimit < _position) + limitPos = _position - *searchHeaderSizeLimit; + + while(_position >= limitPos) + { + UInt32 numReadBytes = kBufferSize - numPrevBytes; + if (numReadBytes > _position) + numReadBytes = (UInt32)_position; + UInt32 numBytesInBuffer = numPrevBytes + numReadBytes; + if (numBytesInBuffer < kSignatureSize) + return S_FALSE; + _position -= numReadBytes; + RINOK(stream->Seek(_position, STREAM_SEEK_SET, &_position)); + UInt32 startPos = kBufferSize - numBytesInBuffer; + UInt32 processedSize; + RINOK(ReadDirect(stream, buffer + startPos, numReadBytes, &processedSize)); + if (processedSize != numReadBytes) + return S_FALSE; + _position -= processedSize; + for(UInt32 pos = kBufferSize; pos >= startPos + kSignatureSize; pos--) + { + if (TestFinishSignatureCandidate(buffer + pos - kSignatureSize)) + { + _position += pos - startPos; + return stream->Seek(_position, STREAM_SEEK_SET, NULL); + } + } + numPrevBytes = kSignatureSize - 1; + memmove(buffer + kBufferSize - numPrevBytes, buffer + startPos + 1, numPrevBytes); + } + return S_FALSE; +} +#endif + +// S_FALSE means that file is not archive +HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit) +{ + Close(); + RINOK(stream->Seek(0, STREAM_SEEK_CUR, &_arhiveBeginStreamPosition)) + _position = _arhiveBeginStreamPosition; + #ifdef _7Z_VOL + HRESULT result = FindFinishSignature(stream, searchHeaderSizeLimit); + if (result == S_OK) + _finishSignature = true; + else + { + if (result != S_FALSE) + return result; + _finishSignature = false; + RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); + } + #else + RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit)); + #endif + _stream = stream; + return S_OK; +} + +void CInArchive::Close() +{ + _stream.Release(); +} + +HRESULT CInArchive::SkeepData(UInt64 size) +{ + for (UInt64 i = 0; i < size; i++) + { + Byte temp; + RINOK(ReadByte(temp)); + } + return S_OK; +} + +HRESULT CInArchive::SkeepData() +{ + UInt64 size; + RINOK(ReadNumber(size)); + return SkeepData(size); +} + +HRESULT CInArchive::ReadArchiveProperties(CInArchiveInfo &archiveInfo) +{ + while(true) + { + UInt64 type; + RINOK(ReadID(type)); + if (type == NID::kEnd) + break; + SkeepData(); + } + return S_OK; +} + +HRESULT CInArchive::GetNextFolderItem(CFolder &folder) +{ + CNum numCoders; + RINOK(ReadNum(numCoders)); + + folder.Coders.Clear(); + folder.Coders.Reserve((int)numCoders); + CNum numInStreams = 0; + CNum numOutStreams = 0; + CNum i; + for (i = 0; i < numCoders; i++) + { + folder.Coders.Add(CCoderInfo()); + CCoderInfo &coder = folder.Coders.Back(); + + while (true) + { + coder.AltCoders.Add(CAltCoderInfo()); + CAltCoderInfo &altCoder = coder.AltCoders.Back(); + Byte mainByte; + RINOK(ReadByte(mainByte)); + altCoder.MethodID.IDSize = mainByte & 0xF; + RINOK(ReadBytes(altCoder.MethodID.ID, altCoder.MethodID.IDSize)); + if ((mainByte & 0x10) != 0) + { + RINOK(ReadNum(coder.NumInStreams)); + RINOK(ReadNum(coder.NumOutStreams)); + } + else + { + coder.NumInStreams = 1; + coder.NumOutStreams = 1; + } + if ((mainByte & 0x20) != 0) + { + CNum propertiesSize = 0; + RINOK(ReadNum(propertiesSize)); + altCoder.Properties.SetCapacity((size_t)propertiesSize); + RINOK(ReadBytes((Byte *)altCoder.Properties, (size_t)propertiesSize)); + } + if ((mainByte & 0x80) == 0) + break; + } + numInStreams += coder.NumInStreams; + numOutStreams += coder.NumOutStreams; + } + + CNum numBindPairs; + // RINOK(ReadNumber(numBindPairs)); + numBindPairs = numOutStreams - 1; + folder.BindPairs.Clear(); + folder.BindPairs.Reserve(numBindPairs); + for (i = 0; i < numBindPairs; i++) + { + CBindPair bindPair; + RINOK(ReadNum(bindPair.InIndex)); + RINOK(ReadNum(bindPair.OutIndex)); + folder.BindPairs.Add(bindPair); + } + + CNum numPackedStreams = numInStreams - numBindPairs; + folder.PackStreams.Reserve(numPackedStreams); + if (numPackedStreams == 1) + { + for (CNum j = 0; j < numInStreams; j++) + if (folder.FindBindPairForInStream(j) < 0) + { + folder.PackStreams.Add(j); + break; + } + } + else + for(i = 0; i < numPackedStreams; i++) + { + CNum packStreamInfo; + RINOK(ReadNum(packStreamInfo)); + folder.PackStreams.Add(packStreamInfo); + } + + return S_OK; +} + +HRESULT CInArchive::WaitAttribute(UInt64 attribute) +{ + while(true) + { + UInt64 type; + RINOK(ReadID(type)); + if (type == attribute) + return S_OK; + if (type == NID::kEnd) + return S_FALSE; + RINOK(SkeepData()); + } +} + +HRESULT CInArchive::ReadHashDigests(int numItems, + CRecordVector &digestsDefined, + CRecordVector &digests) +{ + RINOK(ReadBoolVector2(numItems, digestsDefined)); + digests.Clear(); + digests.Reserve(numItems); + for(int i = 0; i < numItems; i++) + { + UInt32 crc; + if (digestsDefined[i]) + RINOK(ReadUInt32(crc)); + digests.Add(crc); + } + return S_OK; +} + +HRESULT CInArchive::ReadPackInfo( + UInt64 &dataOffset, + CRecordVector &packSizes, + CRecordVector &packCRCsDefined, + CRecordVector &packCRCs) +{ + RINOK(ReadNumber(dataOffset)); + CNum numPackStreams; + RINOK(ReadNum(numPackStreams)); + + RINOK(WaitAttribute(NID::kSize)); + packSizes.Clear(); + packSizes.Reserve(numPackStreams); + for(CNum i = 0; i < numPackStreams; i++) + { + UInt64 size; + RINOK(ReadNumber(size)); + packSizes.Add(size); + } + + UInt64 type; + while(true) + { + RINOK(ReadID(type)); + if (type == NID::kEnd) + break; + if (type == NID::kCRC) + { + RINOK(ReadHashDigests(numPackStreams, packCRCsDefined, packCRCs)); + continue; + } + RINOK(SkeepData()); + } + if (packCRCsDefined.IsEmpty()) + { + packCRCsDefined.Reserve(numPackStreams); + packCRCsDefined.Clear(); + packCRCs.Reserve(numPackStreams); + packCRCs.Clear(); + for(CNum i = 0; i < numPackStreams; i++) + { + packCRCsDefined.Add(false); + packCRCs.Add(0); + } + } + return S_OK; +} + +HRESULT CInArchive::ReadUnPackInfo( + const CObjectVector *dataVector, + CObjectVector &folders) +{ + RINOK(WaitAttribute(NID::kFolder)); + CNum numFolders; + RINOK(ReadNum(numFolders)); + + { + CStreamSwitch streamSwitch; + RINOK(streamSwitch.Set(this, dataVector)); + folders.Clear(); + folders.Reserve((UInt32)numFolders); + for(CNum i = 0; i < numFolders; i++) + { + folders.Add(CFolder()); + RINOK(GetNextFolderItem(folders.Back())); + } + } + + RINOK(WaitAttribute(NID::kCodersUnPackSize)); + + CNum i; + for(i = 0; i < numFolders; i++) + { + CFolder &folder = folders[i]; + CNum numOutStreams = folder.GetNumOutStreams(); + folder.UnPackSizes.Reserve(numOutStreams); + for(CNum j = 0; j < numOutStreams; j++) + { + UInt64 unPackSize; + RINOK(ReadNumber(unPackSize)); + folder.UnPackSizes.Add(unPackSize); + } + } + + while(true) + { + UInt64 type; + RINOK(ReadID(type)); + if (type == NID::kEnd) + return S_OK; + if (type == NID::kCRC) + { + CRecordVector crcsDefined; + CRecordVector crcs; + RINOK(ReadHashDigests(numFolders, crcsDefined, crcs)); + for(i = 0; i < numFolders; i++) + { + CFolder &folder = folders[i]; + folder.UnPackCRCDefined = crcsDefined[i]; + folder.UnPackCRC = crcs[i]; + } + continue; + } + RINOK(SkeepData()); + } +} + +HRESULT CInArchive::ReadSubStreamsInfo( + const CObjectVector &folders, + CRecordVector &numUnPackStreamsInFolders, + CRecordVector &unPackSizes, + CRecordVector &digestsDefined, + CRecordVector &digests) +{ + numUnPackStreamsInFolders.Clear(); + numUnPackStreamsInFolders.Reserve(folders.Size()); + UInt64 type; + while(true) + { + RINOK(ReadID(type)); + if (type == NID::kNumUnPackStream) + { + for(int i = 0; i < folders.Size(); i++) + { + CNum value; + RINOK(ReadNum(value)); + numUnPackStreamsInFolders.Add(value); + } + continue; + } + if (type == NID::kCRC || type == NID::kSize) + break; + if (type == NID::kEnd) + break; + RINOK(SkeepData()); + } + + if (numUnPackStreamsInFolders.IsEmpty()) + for(int i = 0; i < folders.Size(); i++) + numUnPackStreamsInFolders.Add(1); + + int i; + for(i = 0; i < numUnPackStreamsInFolders.Size(); i++) + { + // v3.13 incorrectly worked with empty folders + // v4.07: we check that folder is empty + CNum numSubstreams = numUnPackStreamsInFolders[i]; + if (numSubstreams == 0) + continue; + UInt64 sum = 0; + for (CNum j = 1; j < numSubstreams; j++) + { + UInt64 size; + if (type == NID::kSize) + { + RINOK(ReadNumber(size)); + unPackSizes.Add(size); + sum += size; + } + } + unPackSizes.Add(folders[i].GetUnPackSize() - sum); + } + if (type == NID::kSize) + { + RINOK(ReadID(type)); + } + + int numDigests = 0; + int numDigestsTotal = 0; + for(i = 0; i < folders.Size(); i++) + { + CNum numSubstreams = numUnPackStreamsInFolders[i]; + if (numSubstreams != 1 || !folders[i].UnPackCRCDefined) + numDigests += numSubstreams; + numDigestsTotal += numSubstreams; + } + + while(true) + { + if (type == NID::kCRC) + { + CRecordVector digestsDefined2; + CRecordVector digests2; + RINOK(ReadHashDigests(numDigests, digestsDefined2, digests2)); + int digestIndex = 0; + for (i = 0; i < folders.Size(); i++) + { + CNum numSubstreams = numUnPackStreamsInFolders[i]; + const CFolder &folder = folders[i]; + if (numSubstreams == 1 && folder.UnPackCRCDefined) + { + digestsDefined.Add(true); + digests.Add(folder.UnPackCRC); + } + else + for (CNum j = 0; j < numSubstreams; j++, digestIndex++) + { + digestsDefined.Add(digestsDefined2[digestIndex]); + digests.Add(digests2[digestIndex]); + } + } + } + else if (type == NID::kEnd) + { + if (digestsDefined.IsEmpty()) + { + digestsDefined.Clear(); + digests.Clear(); + for (int i = 0; i < numDigestsTotal; i++) + { + digestsDefined.Add(false); + digests.Add(0); + } + } + return S_OK; + } + else + { + RINOK(SkeepData()); + } + RINOK(ReadID(type)); + } +} + +HRESULT CInArchive::ReadStreamsInfo( + const CObjectVector *dataVector, + UInt64 &dataOffset, + CRecordVector &packSizes, + CRecordVector &packCRCsDefined, + CRecordVector &packCRCs, + CObjectVector &folders, + CRecordVector &numUnPackStreamsInFolders, + CRecordVector &unPackSizes, + CRecordVector &digestsDefined, + CRecordVector &digests) +{ + while(true) + { + UInt64 type; + RINOK(ReadID(type)); + switch(type) + { + case NID::kEnd: + return S_OK; + case NID::kPackInfo: + { + RINOK(ReadPackInfo(dataOffset, packSizes, + packCRCsDefined, packCRCs)); + break; + } + case NID::kUnPackInfo: + { + RINOK(ReadUnPackInfo(dataVector, folders)); + break; + } + case NID::kSubStreamsInfo: + { + RINOK(ReadSubStreamsInfo(folders, numUnPackStreamsInFolders, + unPackSizes, digestsDefined, digests)); + break; + } + } + } +} + +HRESULT CInArchive::ReadFileNames(CObjectVector &files) +{ + for(int i = 0; i < files.Size(); i++) + { + UString &name = files[i].Name; + name.Empty(); + while (true) + { + wchar_t c; + RINOK(ReadWideCharLE(c)); + if (c == L'\0') + break; + name += c; + } + } + return S_OK; +} + +HRESULT CInArchive::ReadBoolVector(int numItems, CBoolVector &v) +{ + v.Clear(); + v.Reserve(numItems); + Byte b; + Byte mask = 0; + for(int i = 0; i < numItems; i++) + { + if (mask == 0) + { + RINOK(ReadByte(b)); + mask = 0x80; + } + v.Add((b & mask) != 0); + mask >>= 1; + } + return S_OK; +} + +HRESULT CInArchive::ReadBoolVector2(int numItems, CBoolVector &v) +{ + Byte allAreDefined; + RINOK(ReadByte(allAreDefined)); + if (allAreDefined == 0) + return ReadBoolVector(numItems, v); + v.Clear(); + v.Reserve(numItems); + for (int i = 0; i < numItems; i++) + v.Add(true); + return S_OK; +} + +HRESULT CInArchive::ReadTime(const CObjectVector &dataVector, + CObjectVector &files, UInt64 type) +{ + CBoolVector boolVector; + RINOK(ReadBoolVector2(files.Size(), boolVector)) + + CStreamSwitch streamSwitch; + RINOK(streamSwitch.Set(this, &dataVector)); + + for(int i = 0; i < files.Size(); i++) + { + CFileItem &file = files[i]; + CArchiveFileTime fileTime; + bool defined = boolVector[i]; + if (defined) + { + UInt32 low, high; + RINOK(ReadUInt32(low)); + RINOK(ReadUInt32(high)); + fileTime.dwLowDateTime = low; + fileTime.dwHighDateTime = high; + } + switch(type) + { + case NID::kCreationTime: + file.IsCreationTimeDefined = defined; + if (defined) + file.CreationTime = fileTime; + break; + case NID::kLastWriteTime: + file.IsLastWriteTimeDefined = defined; + if (defined) + file.LastWriteTime = fileTime; + break; + case NID::kLastAccessTime: + file.IsLastAccessTimeDefined = defined; + if (defined) + file.LastAccessTime = fileTime; + break; + } + } + return S_OK; +} + +HRESULT CInArchive::ReadAndDecodePackedStreams(UInt64 baseOffset, + UInt64 &dataOffset, CObjectVector &dataVector + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword + #endif + ) +{ + CRecordVector packSizes; + CRecordVector packCRCsDefined; + CRecordVector packCRCs; + CObjectVector folders; + + CRecordVector numUnPackStreamsInFolders; + CRecordVector unPackSizes; + CRecordVector digestsDefined; + CRecordVector digests; + + RINOK(ReadStreamsInfo(NULL, + dataOffset, + packSizes, + packCRCsDefined, + packCRCs, + folders, + numUnPackStreamsInFolders, + unPackSizes, + digestsDefined, + digests)); + + // database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader; + + CNum packIndex = 0; + CDecoder decoder( + #ifdef _ST_MODE + false + #else + true + #endif + ); + UInt64 dataStartPos = baseOffset + dataOffset; + for(int i = 0; i < folders.Size(); i++) + { + const CFolder &folder = folders[i]; + dataVector.Add(CByteBuffer()); + CByteBuffer &data = dataVector.Back(); + UInt64 unPackSize = folder.GetUnPackSize(); + if (unPackSize > kNumMax) + return E_FAIL; + if (unPackSize > 0xFFFFFFFF) + return E_FAIL; + data.SetCapacity((size_t)unPackSize); + + CSequentialOutStreamImp2 *outStreamSpec = new CSequentialOutStreamImp2; + CMyComPtr outStream = outStreamSpec; + outStreamSpec->Init(data, (size_t)unPackSize); + + HRESULT result = decoder.Decode(_stream, dataStartPos, + &packSizes[packIndex], folder, outStream, NULL + #ifndef _NO_CRYPTO + , getTextPassword + #endif + #ifdef COMPRESS_MT + , false, 1 + #endif + ); + RINOK(result); + + if (folder.UnPackCRCDefined) + if (!CCRC::VerifyDigest(folder.UnPackCRC, data, (UInt32)unPackSize)) + throw CInArchiveException(CInArchiveException::kIncorrectHeader); + for (int j = 0; j < folder.PackStreams.Size(); j++) + dataStartPos += packSizes[packIndex++]; + } + return S_OK; +} + +HRESULT CInArchive::ReadHeader(CArchiveDatabaseEx &database + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword + #endif + ) +{ + UInt64 type; + RINOK(ReadID(type)); + + if (type == NID::kArchiveProperties) + { + RINOK(ReadArchiveProperties(database.ArchiveInfo)); + RINOK(ReadID(type)); + } + + CObjectVector dataVector; + + if (type == NID::kAdditionalStreamsInfo) + { + HRESULT result = ReadAndDecodePackedStreams( + database.ArchiveInfo.StartPositionAfterHeader, + database.ArchiveInfo.DataStartPosition2, + dataVector + #ifndef _NO_CRYPTO + , getTextPassword + #endif + ); + RINOK(result); + database.ArchiveInfo.DataStartPosition2 += database.ArchiveInfo.StartPositionAfterHeader; + RINOK(ReadID(type)); + } + + CRecordVector unPackSizes; + CRecordVector digestsDefined; + CRecordVector digests; + + if (type == NID::kMainStreamsInfo) + { + RINOK(ReadStreamsInfo(&dataVector, + database.ArchiveInfo.DataStartPosition, + database.PackSizes, + database.PackCRCsDefined, + database.PackCRCs, + database.Folders, + database.NumUnPackStreamsVector, + unPackSizes, + digestsDefined, + digests)); + database.ArchiveInfo.DataStartPosition += database.ArchiveInfo.StartPositionAfterHeader; + RINOK(ReadID(type)); + } + else + { + for(int i = 0; i < database.Folders.Size(); i++) + { + database.NumUnPackStreamsVector.Add(1); + CFolder &folder = database.Folders[i]; + unPackSizes.Add(folder.GetUnPackSize()); + digestsDefined.Add(folder.UnPackCRCDefined); + digests.Add(folder.UnPackCRC); + } + } + + database.Files.Clear(); + + if (type == NID::kEnd) + return S_OK; + if (type != NID::kFilesInfo) + throw CInArchiveException(CInArchiveException::kIncorrectHeader); + + CNum numFiles; + RINOK(ReadNum(numFiles)); + database.Files.Reserve(numFiles); + CNum i; + for(i = 0; i < numFiles; i++) + database.Files.Add(CFileItem()); + + database.ArchiveInfo.FileInfoPopIDs.Add(NID::kSize); + if (!database.PackSizes.IsEmpty()) + database.ArchiveInfo.FileInfoPopIDs.Add(NID::kPackInfo); + if (numFiles > 0 && !digests.IsEmpty()) + database.ArchiveInfo.FileInfoPopIDs.Add(NID::kCRC); + + CBoolVector emptyStreamVector; + emptyStreamVector.Reserve((int)numFiles); + for(i = 0; i < numFiles; i++) + emptyStreamVector.Add(false); + CBoolVector emptyFileVector; + CBoolVector antiFileVector; + CNum numEmptyStreams = 0; + + // int sizePrev = -1; + // int posPrev = 0; + + while(true) + { + /* + if (sizePrev >= 0) + if (sizePrev != _inByteBack->GetProcessedSize() - posPrev) + throw 2; + */ + UInt64 type; + RINOK(ReadID(type)); + if (type == NID::kEnd) + break; + UInt64 size; + RINOK(ReadNumber(size)); + + // sizePrev = size; + // posPrev = _inByteBack->GetProcessedSize(); + + database.ArchiveInfo.FileInfoPopIDs.Add(type); + switch(type) + { + case NID::kName: + { + CStreamSwitch streamSwitch; + RINOK(streamSwitch.Set(this, &dataVector)); + RINOK(ReadFileNames(database.Files)) + break; + } + case NID::kWinAttributes: + { + CBoolVector boolVector; + RINOK(ReadBoolVector2(database.Files.Size(), boolVector)) + CStreamSwitch streamSwitch; + RINOK(streamSwitch.Set(this, &dataVector)); + for(i = 0; i < numFiles; i++) + { + CFileItem &file = database.Files[i]; + if (file.AreAttributesDefined = boolVector[i]) + { + RINOK(ReadUInt32(file.Attributes)); + } + } + break; + } + case NID::kStartPos: + { + CBoolVector boolVector; + RINOK(ReadBoolVector2(database.Files.Size(), boolVector)) + CStreamSwitch streamSwitch; + RINOK(streamSwitch.Set(this, &dataVector)); + for(i = 0; i < numFiles; i++) + { + CFileItem &file = database.Files[i]; + if (file.IsStartPosDefined = boolVector[i]) + { + RINOK(ReadUInt64(file.StartPos)); + } + } + break; + } + case NID::kEmptyStream: + { + RINOK(ReadBoolVector(numFiles, emptyStreamVector)) + for (i = 0; i < (CNum)emptyStreamVector.Size(); i++) + if (emptyStreamVector[i]) + numEmptyStreams++; + emptyFileVector.Reserve(numEmptyStreams); + antiFileVector.Reserve(numEmptyStreams); + for (i = 0; i < numEmptyStreams; i++) + { + emptyFileVector.Add(false); + antiFileVector.Add(false); + } + break; + } + case NID::kEmptyFile: + { + RINOK(ReadBoolVector(numEmptyStreams, emptyFileVector)) + break; + } + case NID::kAnti: + { + RINOK(ReadBoolVector(numEmptyStreams, antiFileVector)) + break; + } + case NID::kCreationTime: + case NID::kLastWriteTime: + case NID::kLastAccessTime: + { + RINOK(ReadTime(dataVector, database.Files, type)) + break; + } + default: + { + database.ArchiveInfo.FileInfoPopIDs.DeleteBack(); + RINOK(SkeepData(size)); + } + } + } + + CNum emptyFileIndex = 0; + CNum sizeIndex = 0; + for(i = 0; i < numFiles; i++) + { + CFileItem &file = database.Files[i]; + file.HasStream = !emptyStreamVector[i]; + if(file.HasStream) + { + file.IsDirectory = false; + file.IsAnti = false; + file.UnPackSize = unPackSizes[sizeIndex]; + file.FileCRC = digests[sizeIndex]; + file.IsFileCRCDefined = digestsDefined[sizeIndex]; + sizeIndex++; + } + else + { + file.IsDirectory = !emptyFileVector[emptyFileIndex]; + file.IsAnti = antiFileVector[emptyFileIndex]; + emptyFileIndex++; + file.UnPackSize = 0; + file.IsFileCRCDefined = false; + } + } + return S_OK; +} + + +void CArchiveDatabaseEx::FillFolderStartPackStream() +{ + FolderStartPackStreamIndex.Clear(); + FolderStartPackStreamIndex.Reserve(Folders.Size()); + CNum startPos = 0; + for(int i = 0; i < Folders.Size(); i++) + { + FolderStartPackStreamIndex.Add(startPos); + startPos += (CNum)Folders[i].PackStreams.Size(); + } +} + +void CArchiveDatabaseEx::FillStartPos() +{ + PackStreamStartPositions.Clear(); + PackStreamStartPositions.Reserve(PackSizes.Size()); + UInt64 startPos = 0; + for(int i = 0; i < PackSizes.Size(); i++) + { + PackStreamStartPositions.Add(startPos); + startPos += PackSizes[i]; + } +} + +void CArchiveDatabaseEx::FillFolderStartFileIndex() +{ + FolderStartFileIndex.Clear(); + FolderStartFileIndex.Reserve(Folders.Size()); + FileIndexToFolderIndexMap.Clear(); + FileIndexToFolderIndexMap.Reserve(Files.Size()); + + int folderIndex = 0; + CNum indexInFolder = 0; + for (int i = 0; i < Files.Size(); i++) + { + const CFileItem &file = Files[i]; + bool emptyStream = !file.HasStream; + if (emptyStream && indexInFolder == 0) + { + FileIndexToFolderIndexMap.Add(kNumNoIndex); + continue; + } + if (indexInFolder == 0) + { + // v3.13 incorrectly worked with empty folders + // v4.07: Loop for skipping empty folders + while(true) + { + if (folderIndex >= Folders.Size()) + throw CInArchiveException(CInArchiveException::kIncorrectHeader); + FolderStartFileIndex.Add(i); // check it + if (NumUnPackStreamsVector[folderIndex] != 0) + break; + folderIndex++; + } + } + FileIndexToFolderIndexMap.Add(folderIndex); + if (emptyStream) + continue; + indexInFolder++; + if (indexInFolder >= NumUnPackStreamsVector[folderIndex]) + { + folderIndex++; + indexInFolder = 0; + } + } +} + +HRESULT CInArchive::ReadDatabase(CArchiveDatabaseEx &database + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword + #endif + ) +{ + database.Clear(); + database.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; + + + RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Major, 1)); + RINOK(SafeReadDirect(&database.ArchiveInfo.Version.Minor, 1)); + if (database.ArchiveInfo.Version.Major != kMajorVersion) + throw CInArchiveException(CInArchiveException::kUnsupportedVersion); + + #ifdef _7Z_VOL + if (_finishSignature) + { + RINOK(_stream->Seek(_position - (4 + kFinishHeaderSize) - + (kSignatureSize + 2), STREAM_SEEK_SET, &_position)); + } + #endif + + UInt32 crcFromArchive; + RINOK(SafeReadDirectUInt32(crcFromArchive)); + + UInt64 nextHeaderOffset; + UInt64 nextHeaderSize; + UInt32 nextHeaderCRC; + CCRC crc; + RINOK(SafeReadDirectUInt64(nextHeaderOffset)); + crc.UpdateUInt64(nextHeaderOffset); + RINOK(SafeReadDirectUInt64(nextHeaderSize)); + crc.UpdateUInt64(nextHeaderSize); + RINOK(SafeReadDirectUInt32(nextHeaderCRC)); + crc.UpdateUInt32(nextHeaderCRC); + + #ifdef _7Z_VOL + UInt64 archiveStartOffset; // data offset from end if that struct + UInt64 additionalStartBlockSize; // start signature & start header size + if (_finishSignature) + { + RINOK(SafeReadDirectUInt64(archiveStartOffset)); + crc.UpdateUInt64(archiveStartOffset); + RINOK(SafeReadDirectUInt64(additionalStartBlockSize)); + crc.UpdateUInt64(additionalStartBlockSize); + database.ArchiveInfo.StartPositionAfterHeader = _position + archiveStartOffset; + } + else + #endif + { + database.ArchiveInfo.StartPositionAfterHeader = _position; + } + if (crc.GetDigest() != crcFromArchive) + throw CInArchiveException(CInArchiveException::kIncorrectHeader); + + if (nextHeaderSize == 0) + return S_OK; + + if (nextHeaderSize >= 0xFFFFFFFF) + return E_FAIL; + + RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, &_position)); + + CByteBuffer buffer2; + buffer2.SetCapacity((size_t)nextHeaderSize); + RINOK(SafeReadDirect(buffer2, (UInt32)nextHeaderSize)); + if (!CCRC::VerifyDigest(nextHeaderCRC, buffer2, (UInt32)nextHeaderSize)) + throw CInArchiveException(CInArchiveException::kIncorrectHeader); + + CStreamSwitch streamSwitch; + streamSwitch.Set(this, buffer2); + + CObjectVector dataVector; + + while (true) + { + UInt64 type; + RINOK(ReadID(type)); + if (type == NID::kHeader) + break; + if (type != NID::kEncodedHeader) + throw CInArchiveException(CInArchiveException::kIncorrectHeader); + HRESULT result = ReadAndDecodePackedStreams( + database.ArchiveInfo.StartPositionAfterHeader, + database.ArchiveInfo.DataStartPosition2, + dataVector + #ifndef _NO_CRYPTO + , getTextPassword + #endif + ); + RINOK(result); + if (dataVector.Size() == 0) + return S_OK; + if (dataVector.Size() > 1) + throw CInArchiveException(CInArchiveException::kIncorrectHeader); + streamSwitch.Remove(); + streamSwitch.Set(this, dataVector.Front()); + } + + return ReadHeader(database + #ifndef _NO_CRYPTO + , getTextPassword + #endif + ); +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.h new file mode 100644 index 0000000000..a6c5ef032d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zIn.h @@ -0,0 +1,288 @@ +// 7zIn.h + +#ifndef __7Z_IN_H +#define __7Z_IN_H + +#include "../../IStream.h" +#include "../../IPassword.h" +#include "../../../Common/MyCom.h" +#include "../../Common/InBuffer.h" + +#include "7zHeader.h" +#include "7zItem.h" + +namespace NArchive { +namespace N7z { + +class CInArchiveException +{ +public: + enum CCauseType + { + kUnsupportedVersion = 0, + kUnexpectedEndOfArchive = 0, + kIncorrectHeader, + } Cause; + CInArchiveException(CCauseType cause); +}; + +struct CInArchiveInfo +{ + CArchiveVersion Version; + UInt64 StartPosition; + UInt64 StartPositionAfterHeader; + UInt64 DataStartPosition; + UInt64 DataStartPosition2; + CRecordVector FileInfoPopIDs; + void Clear() + { + FileInfoPopIDs.Clear(); + } +}; + + +struct CArchiveDatabaseEx: public CArchiveDatabase +{ + CInArchiveInfo ArchiveInfo; + CRecordVector PackStreamStartPositions; + CRecordVector FolderStartPackStreamIndex; + CRecordVector FolderStartFileIndex; + CRecordVector FileIndexToFolderIndexMap; + + void Clear() + { + CArchiveDatabase::Clear(); + ArchiveInfo.Clear(); + PackStreamStartPositions.Clear(); + FolderStartPackStreamIndex.Clear(); + FolderStartFileIndex.Clear(); + FileIndexToFolderIndexMap.Clear(); + } + + void FillFolderStartPackStream(); + void FillStartPos(); + void FillFolderStartFileIndex(); + + void Fill() + { + FillFolderStartPackStream(); + FillStartPos(); + FillFolderStartFileIndex(); + } + + UInt64 GetFolderStreamPos(int folderIndex, int indexInFolder) const + { + return ArchiveInfo.DataStartPosition + + PackStreamStartPositions[FolderStartPackStreamIndex[folderIndex] + + indexInFolder]; + } + + UInt64 GetFolderFullPackSize(int folderIndex) const + { + CNum packStreamIndex = FolderStartPackStreamIndex[folderIndex]; + const CFolder &folder = Folders[folderIndex]; + UInt64 size = 0; + for (int i = 0; i < folder.PackStreams.Size(); i++) + size += PackSizes[packStreamIndex + i]; + return size; + } + + UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const + { + return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; + } + + UInt64 GetFilePackSize(CNum fileIndex) const + { + CNum folderIndex = FileIndexToFolderIndexMap[fileIndex]; + if (folderIndex >= 0) + { + if (FolderStartFileIndex[folderIndex] == fileIndex) + return GetFolderFullPackSize(folderIndex); + } + return 0; + } +}; + +class CInByte2 +{ + const Byte *_buffer; + size_t _size; + size_t _pos; +public: + void Init(const Byte *buffer, size_t size) + { + _buffer = buffer; + _size = size; + _pos = 0; + } + bool ReadByte(Byte &b) + { + if(_pos >= _size) + return false; + b = _buffer[_pos++]; + return true; + } + void ReadBytes(void *data, size_t size, size_t &processedSize) + { + for(processedSize = 0; processedSize < size && _pos < _size; processedSize++) + ((Byte *)data)[processedSize] = _buffer[_pos++]; + } + + bool ReadBytes(void *data, size_t size) + { + size_t processedSize; + ReadBytes(data, size, processedSize); + return (processedSize == size); + } + + size_t GetProcessedSize() const { return _pos; } +}; + +class CStreamSwitch; +class CInArchive +{ + friend class CStreamSwitch; + + CMyComPtr _stream; + #ifdef _7Z_VOL + bool _finishSignature; + #endif + + CObjectVector _inByteVector; + CInByte2 *_inByteBack; + + UInt64 _arhiveBeginStreamPosition; + UInt64 _position; + + void AddByteStream(const Byte *buffer, size_t size) + { + _inByteVector.Add(CInByte2()); + _inByteBack = &_inByteVector.Back(); + _inByteBack->Init(buffer, size); + } + + void DeleteByteStream() + { + _inByteVector.DeleteBack(); + if (!_inByteVector.IsEmpty()) + _inByteBack = &_inByteVector.Back(); + } + +private: + HRESULT FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive + #ifdef _7Z_VOL + HRESULT FindFinishSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive + #endif + + HRESULT ReadFileNames(CObjectVector &files); + + HRESULT ReadDirect(IInStream *stream, void *data, UInt32 size, + UInt32 *processedSize); + HRESULT ReadDirect(void *data, UInt32 size, UInt32 *processedSize); + HRESULT SafeReadDirect(void *data, UInt32 size); + HRESULT SafeReadDirectByte(Byte &b); + HRESULT SafeReadDirectUInt32(UInt32 &value); + HRESULT SafeReadDirectUInt64(UInt64 &value); + + HRESULT ReadBytes(void *data, size_t size) + { + if (!_inByteBack->ReadBytes(data, size)) + return E_FAIL; + return S_OK; + } + + HRESULT ReadByte(Byte &b) + { + if (!_inByteBack->ReadByte(b)) + return E_FAIL; + return S_OK; + } + + HRESULT ReadWideCharLE(wchar_t &c) + { + Byte b1; + if (!_inByteBack->ReadByte(b1)) + return E_FAIL; + Byte b2; + if (!_inByteBack->ReadByte(b2)) + return E_FAIL; + c = (wchar_t(b2) << 8) + b1; + return S_OK; + } + + HRESULT ReadNumber(UInt64 &value); + HRESULT ReadNum(CNum &value); + HRESULT ReadID(UInt64 &value) { return ReadNumber(value); } + HRESULT ReadUInt32(UInt32 &value); + HRESULT ReadUInt64(UInt64 &value); + + HRESULT SkeepData(UInt64 size); + HRESULT SkeepData(); + HRESULT WaitAttribute(UInt64 attribute); + + HRESULT ReadArchiveProperties(CInArchiveInfo &archiveInfo); + HRESULT GetNextFolderItem(CFolder &itemInfo); + HRESULT ReadHashDigests(int numItems, + CRecordVector &digestsDefined, CRecordVector &digests); + + HRESULT ReadPackInfo( + UInt64 &dataOffset, + CRecordVector &packSizes, + CRecordVector &packCRCsDefined, + CRecordVector &packCRCs); + + HRESULT ReadUnPackInfo( + const CObjectVector *dataVector, + CObjectVector &folders); + + HRESULT ReadSubStreamsInfo( + const CObjectVector &folders, + CRecordVector &numUnPackStreamsInFolders, + CRecordVector &unPackSizes, + CRecordVector &digestsDefined, + CRecordVector &digests); + + HRESULT ReadStreamsInfo( + const CObjectVector *dataVector, + UInt64 &dataOffset, + CRecordVector &packSizes, + CRecordVector &packCRCsDefined, + CRecordVector &packCRCs, + CObjectVector &folders, + CRecordVector &numUnPackStreamsInFolders, + CRecordVector &unPackSizes, + CRecordVector &digestsDefined, + CRecordVector &digests); + + + HRESULT GetNextFileItem(CFileItem &itemInfo); + HRESULT ReadBoolVector(int numItems, CBoolVector &v); + HRESULT ReadBoolVector2(int numItems, CBoolVector &v); + HRESULT ReadTime(const CObjectVector &dataVector, + CObjectVector &files, UInt64 type); + HRESULT ReadAndDecodePackedStreams(UInt64 baseOffset, UInt64 &dataOffset, + CObjectVector &dataVector + #ifndef _NO_CRYPTO + , ICryptoGetTextPassword *getTextPassword + #endif + ); + HRESULT ReadHeader(CArchiveDatabaseEx &database + #ifndef _NO_CRYPTO + ,ICryptoGetTextPassword *getTextPassword + #endif + ); +public: + HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive + void Close(); + + HRESULT ReadDatabase(CArchiveDatabaseEx &database + #ifndef _NO_CRYPTO + ,ICryptoGetTextPassword *getTextPassword + #endif + ); +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zItem.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zItem.h new file mode 100644 index 0000000000..c50a0bcf41 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zItem.h @@ -0,0 +1,181 @@ +// 7zItem.h + +#ifndef __7Z_ITEM_H +#define __7Z_ITEM_H + +#include "../../../Common/Buffer.h" +#include "7zMethodID.h" +#include "7zHeader.h" + +namespace NArchive { +namespace N7z { + +struct CAltCoderInfo +{ + CMethodID MethodID; + CByteBuffer Properties; +}; + +typedef UInt32 CNum; +const CNum kNumMax = 0x7FFFFFFF; +const CNum kNumNoIndex = 0xFFFFFFFF; + +struct CCoderInfo +{ + CNum NumInStreams; + CNum NumOutStreams; + CObjectVector AltCoders; + bool IsSimpleCoder() const { return (NumInStreams == 1) && (NumOutStreams == 1); } +}; + +struct CBindPair +{ + CNum InIndex; + CNum OutIndex; +}; + +struct CFolder +{ + CObjectVector Coders; + CRecordVector BindPairs; + CRecordVector PackStreams; + CRecordVector UnPackSizes; + UInt32 UnPackCRC; + bool UnPackCRCDefined; + + CFolder(): UnPackCRCDefined(false) {} + + UInt64 GetUnPackSize() const // test it + { + if (UnPackSizes.IsEmpty()) + return 0; + for (int i = UnPackSizes.Size() - 1; i >= 0; i--) + if (FindBindPairForOutStream(i) < 0) + return UnPackSizes[i]; + throw 1; + } + + CNum GetNumOutStreams() const + { + CNum result = 0; + for (int i = 0; i < Coders.Size(); i++) + result += Coders[i].NumOutStreams; + return result; + } + + int FindBindPairForInStream(CNum inStreamIndex) const + { + for(int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].InIndex == inStreamIndex) + return i; + return -1; + } + int FindBindPairForOutStream(CNum outStreamIndex) const + { + for(int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].OutIndex == outStreamIndex) + return i; + return -1; + } + int FindPackStreamArrayIndex(CNum inStreamIndex) const + { + for(int i = 0; i < PackStreams.Size(); i++) + if (PackStreams[i] == inStreamIndex) + return i; + return -1; + } +}; + +typedef FILETIME CArchiveFileTime; + +class CFileItem +{ +public: + CArchiveFileTime CreationTime; + CArchiveFileTime LastWriteTime; + CArchiveFileTime LastAccessTime; + UInt64 UnPackSize; + UInt64 StartPos; + UInt32 Attributes; + UInt32 FileCRC; + UString Name; + + bool HasStream; // Test it !!! it means that there is + // stream in some folder. It can be empty stream + bool IsDirectory; + bool IsAnti; + bool IsFileCRCDefined; + bool AreAttributesDefined; + bool IsCreationTimeDefined; + bool IsLastWriteTimeDefined; + bool IsLastAccessTimeDefined; + bool IsStartPosDefined; + + /* + const bool HasStream() const { + return !IsDirectory && !IsAnti && UnPackSize != 0; } + */ + CFileItem(): + HasStream(true), + IsDirectory(false), + IsAnti(false), + IsFileCRCDefined(false), + AreAttributesDefined(false), + IsCreationTimeDefined(false), + IsLastWriteTimeDefined(false), + IsLastAccessTimeDefined(false), + IsStartPosDefined(false) + {} + void SetAttributes(UInt32 attributes) + { + AreAttributesDefined = true; + Attributes = attributes; + } + void SetCreationTime(const CArchiveFileTime &creationTime) + { + IsCreationTimeDefined = true; + CreationTime = creationTime; + } + void SetLastWriteTime(const CArchiveFileTime &lastWriteTime) + { + IsLastWriteTimeDefined = true; + LastWriteTime = lastWriteTime; + } + void SetLastAccessTime(const CArchiveFileTime &lastAccessTime) + { + IsLastAccessTimeDefined = true; + LastAccessTime = lastAccessTime; + } +}; + +struct CArchiveDatabase +{ + CRecordVector PackSizes; + CRecordVector PackCRCsDefined; + CRecordVector PackCRCs; + CObjectVector Folders; + CRecordVector NumUnPackStreamsVector; + CObjectVector Files; + void Clear() + { + PackSizes.Clear(); + PackCRCsDefined.Clear(); + PackCRCs.Clear(); + Folders.Clear(); + NumUnPackStreamsVector.Clear(); + Files.Clear(); + } + bool IsEmpty() const + { + return (PackSizes.IsEmpty() && + PackCRCsDefined.IsEmpty() && + PackCRCs.IsEmpty() && + Folders.IsEmpty() && + NumUnPackStreamsVector.IsEmpty() && + Files.IsEmpty()); + } +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.cpp new file mode 100644 index 0000000000..a7b1296e9f --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.cpp @@ -0,0 +1,76 @@ +// 7zMethodID.cpp + +#include "StdAfx.h" + +#include "7zMethodID.h" + +namespace NArchive { +namespace N7z { + +static wchar_t GetHex(Byte value) +{ + return (value < 10) ? ('0' + value) : ('A' + (value - 10)); +} + +static bool HexCharToInt(wchar_t value, Byte &result) +{ + if (value >= '0' && value <= '9') + result = value - '0'; + else if (value >= 'a' && value <= 'f') + result = 10 + value - 'a'; + else if (value >= 'A' && value <= 'F') + result = 10 + value - 'A'; + else + return false; + return true; +} + +static bool TwoHexCharsToInt(wchar_t valueHigh, wchar_t valueLow, Byte &result) +{ + Byte resultHigh, resultLow; + if (!HexCharToInt(valueHigh, resultHigh)) + return false; + if (!HexCharToInt(valueLow, resultLow)) + return false; + result = (resultHigh << 4) + resultLow; + return true; +} + +UString CMethodID::ConvertToString() const +{ + UString result; + for (int i = 0; i < IDSize; i++) + { + Byte b = ID[i]; + result += GetHex(b >> 4); + result += GetHex(b & 0xF); + } + return result; +} + +bool CMethodID::ConvertFromString(const UString &srcString) +{ + int length = srcString.Length(); + if ((length & 1) != 0 || (length >> 1) > kMethodIDSize) + return false; + IDSize = length / 2; + UInt32 i; + for(i = 0; i < IDSize; i++) + if (!TwoHexCharsToInt(srcString[i * 2], srcString[i * 2 + 1], ID[i])) + return false; + for(; i < kMethodIDSize; i++) + ID[i] = 0; + return true; +} + +bool operator==(const CMethodID &a1, const CMethodID &a2) +{ + if (a1.IDSize != a2.IDSize) + return false; + for (UInt32 i = 0; i < a1.IDSize; i++) + if (a1.ID[i] != a2.ID[i]) + return false; + return true; +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.h new file mode 100644 index 0000000000..6bff152d6c --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethodID.h @@ -0,0 +1,29 @@ +// 7zMethodID.h + +#ifndef __7Z_METHOD_ID_H +#define __7Z_METHOD_ID_H + +#include "../../../Common/String.h" +#include "../../../Common/Types.h" + +namespace NArchive { +namespace N7z { + +const int kMethodIDSize = 15; + +struct CMethodID +{ + Byte ID[kMethodIDSize]; + Byte IDSize; + UString ConvertToString() const; + bool ConvertFromString(const UString &srcString); +}; + +bool operator==(const CMethodID &a1, const CMethodID &a2); + +inline bool operator!=(const CMethodID &a1, const CMethodID &a2) + { return !(a1 == a2); } + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.cpp new file mode 100644 index 0000000000..32f59003b2 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.cpp @@ -0,0 +1,174 @@ +// 7zMethods.cpp + +#include "StdAfx.h" + +#include "7zMethods.h" + +#include "../../../Windows/FileFind.h" +#include "../../../Windows/DLL.h" +#include "../../../Windows/PropVariant.h" +#include "../../../Windows/Synchronization.h" + +#include "../../ICoder.h" +#include "../Common/CodecsPath.h" + +using namespace NWindows; + +namespace NArchive { +namespace N7z { + +static CObjectVector g_Methods; +static bool g_Loaded = false; + +typedef UInt32 (WINAPI *GetNumberOfMethodsFunc)(UInt32 *numMethods); + +typedef UInt32 (WINAPI *GetMethodPropertyFunc)( + UInt32 index, PROPID propID, PROPVARIANT *value); + +static void Load(const CSysString &folderPrefix) +{ + NFile::NFind::CEnumerator enumerator(folderPrefix + CSysString(TEXT("*"))); + NFile::NFind::CFileInfo fileInfo; + while (enumerator.Next(fileInfo)) + { + if (fileInfo.IsDirectory()) + continue; + CSysString filePath = folderPrefix + fileInfo.Name; + { + NDLL::CLibrary library; + if (!library.LoadEx(filePath, LOAD_LIBRARY_AS_DATAFILE)) + continue; + } + NDLL::CLibrary library; + if (!library.Load(filePath)) + continue; + GetMethodPropertyFunc getMethodProperty = (GetMethodPropertyFunc) + library.GetProcAddress("GetMethodProperty"); + if (getMethodProperty == NULL) + continue; + + UInt32 numMethods = 1; + GetNumberOfMethodsFunc getNumberOfMethodsFunc = (GetNumberOfMethodsFunc) + library.GetProcAddress("GetNumberOfMethods"); + if (getNumberOfMethodsFunc != NULL) + if (getNumberOfMethodsFunc(&numMethods) != S_OK) + continue; + + for(UInt32 i = 0; i < numMethods; i++) + { + CMethodInfo2 info; + info.FilePath = filePath; + + NWindows::NCOM::CPropVariant propVariant; + if (getMethodProperty(i, NMethodPropID::kID, &propVariant) != S_OK) + continue; + if (propVariant.vt != VT_BSTR) + continue; + info.MethodID.IDSize = SysStringByteLen(propVariant.bstrVal); + memmove(info.MethodID.ID, propVariant.bstrVal, info.MethodID.IDSize); + propVariant.Clear(); + + if (getMethodProperty(i, NMethodPropID::kName, &propVariant) != S_OK) + continue; + if (propVariant.vt == VT_EMPTY) + { + } + else if (propVariant.vt == VT_BSTR) + info.Name = propVariant.bstrVal; + else + continue; + propVariant.Clear(); + + if (getMethodProperty (i, NMethodPropID::kEncoder, &propVariant) != S_OK) + continue; + if (propVariant.vt == VT_EMPTY) + info.EncoderIsAssigned = false; + else if (propVariant.vt == VT_BSTR) + { + info.EncoderIsAssigned = true; + info.Encoder = *(const GUID *)propVariant.bstrVal; + } + else + continue; + propVariant.Clear(); + + if (getMethodProperty (i, NMethodPropID::kDecoder, &propVariant) != S_OK) + continue; + if (propVariant.vt == VT_EMPTY) + info.DecoderIsAssigned = false; + else if (propVariant.vt == VT_BSTR) + { + info.DecoderIsAssigned = true; + info.Decoder = *(const GUID *)propVariant.bstrVal; + } + else + continue; + propVariant.Clear(); + + if (getMethodProperty (i, NMethodPropID::kInStreams, &propVariant) != S_OK) + continue; + if (propVariant.vt == VT_EMPTY) + info.NumInStreams = 1; + else if (propVariant.vt == VT_UI4) + info.NumInStreams = propVariant.ulVal; + else + continue; + propVariant.Clear(); + + if (getMethodProperty (i, NMethodPropID::kOutStreams, &propVariant) != S_OK) + continue; + if (propVariant.vt == VT_EMPTY) + info.NumOutStreams = 1; + else if (propVariant.vt == VT_UI4) + info.NumOutStreams = propVariant.ulVal; + else + continue; + propVariant.Clear(); + + g_Methods.Add(info); + } + } +} + +static NSynchronization::CCriticalSection g_CriticalSection; + +void LoadMethodMap() +{ + NSynchronization::CCriticalSectionLock lock(g_CriticalSection); + if (g_Loaded) + return; + g_Loaded = true; + Load(GetCodecsFolderPrefix()); +} + +bool GetMethodInfo(const CMethodID &methodID, CMethodInfo &methodInfo) +{ + for(int i = 0; i < g_Methods.Size(); i++) + { + const CMethodInfo2 &method = g_Methods[i]; + if (method.MethodID == methodID) + { + methodInfo = (CMethodInfo)method; + return true; + } + } + return false; +} + +bool GetMethodInfo(const UString &name, CMethodInfo2 &methodInfo) +{ + for(int i = 0; i < g_Methods.Size(); i++) + { + const CMethodInfo2 &method = g_Methods[i]; + if (method.Name.CompareNoCase(name) == 0) + { + methodInfo = method; + return true; + } + } + return false; +} + +}} + + diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.h new file mode 100644 index 0000000000..429199d044 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zMethods.h @@ -0,0 +1,36 @@ +// 7zMethods.h + +#ifndef __7Z_METHODS_H +#define __7Z_METHODS_H + +#include "7zMethodID.h" + +namespace NArchive { +namespace N7z { + +struct CMethodInfo +{ + UString Name; + bool EncoderIsAssigned; + bool DecoderIsAssigned; + UInt32 NumInStreams; + UInt32 NumOutStreams; + CLSID Encoder; + CLSID Decoder; + // UString Description; + CSysString FilePath; +}; + +struct CMethodInfo2: public CMethodInfo +{ + CMethodID MethodID; +}; + +void LoadMethodMap(); +bool GetMethodInfo(const CMethodID &methodID, CMethodInfo &methodInfo); +bool GetMethodInfo(const UString &name, CMethodInfo2 &methodInfo); + +}} + +#endif + diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.cpp b/app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.cpp new file mode 100644 index 0000000000..d474be0957 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.cpp @@ -0,0 +1,166 @@ +// 7zProperties.cpp + +#include "StdAfx.h" + +#include "7zProperties.h" +#include "7zHeader.h" +#include "7zHandler.h" + +// #define _MULTI_PACK + +namespace NArchive { +namespace N7z { + +struct CPropMap +{ + UInt64 FilePropID; + STATPROPSTG StatPROPSTG; +}; + +CPropMap kPropMap[] = +{ + { NID::kName, NULL, kpidPath, VT_BSTR}, + { NID::kSize, NULL, kpidSize, VT_UI8}, + { NID::kPackInfo, NULL, kpidPackedSize, VT_UI8}, + + #ifdef _MULTI_PACK + { 100, L"Pack0", kpidPackedSize0, VT_UI8}, + { 101, L"Pack1", kpidPackedSize1, VT_UI8}, + { 102, L"Pack2", kpidPackedSize2, VT_UI8}, + { 103, L"Pack3", kpidPackedSize3, VT_UI8}, + { 104, L"Pack4", kpidPackedSize4, VT_UI8}, + #endif + + { NID::kCreationTime, NULL, kpidCreationTime, VT_FILETIME}, + { NID::kLastWriteTime, NULL, kpidLastWriteTime, VT_FILETIME}, + { NID::kLastAccessTime, NULL, kpidLastAccessTime, VT_FILETIME}, + { NID::kWinAttributes, NULL, kpidAttributes, VT_UI4}, + { NID::kStartPos, NULL, kpidPosition, VT_UI4}, + + + { NID::kCRC, NULL, kpidCRC, VT_UI4}, + + { NID::kAnti, L"Anti", kpidIsAnti, VT_BOOL}, + // { 97, NULL, kpidSolid, VT_BOOL}, + #ifndef _SFX + { 98, NULL, kpidMethod, VT_BSTR}, + { 99, L"Block", kpidBlock, VT_UI4} + #endif + // { L"ID", kpidID, VT_BSTR}, + // { L"UnPack Version", kpidUnPackVersion, VT_UI1}, + // { L"Host OS", kpidHostOS, VT_BSTR} +}; + +static const int kPropMapSize = sizeof(kPropMap) / sizeof(kPropMap[0]); + +static int FindPropInMap(UInt64 filePropID) +{ + for (int i = 0; i < kPropMapSize; i++) + if (kPropMap[i].FilePropID == filePropID) + return i; + return -1; +} + +static void CopyOneItem(CRecordVector &src, + CRecordVector &dest, UInt32 item) +{ + for (int i = 0; i < src.Size(); i++) + if (src[i] == item) + { + dest.Add(item); + src.Delete(i); + return; + } +} + +static void RemoveOneItem(CRecordVector &src, UInt32 item) +{ + for (int i = 0; i < src.Size(); i++) + if (src[i] == item) + { + src.Delete(i); + return; + } +} + +static void InsertToHead(CRecordVector &dest, UInt32 item) +{ + for (int i = 0; i < dest.Size(); i++) + if (dest[i] == item) + { + dest.Delete(i); + break; + } + dest.Insert(0, item); +} + +void CHandler::FillPopIDs() +{ + _fileInfoPopIDs.Clear(); + + #ifdef _7Z_VOL + if(_volumes.Size() < 1) + return; + const CVolume &volume = _volumes.Front(); + const CArchiveDatabaseEx &_database = volume.Database; + #endif + + CRecordVector fileInfoPopIDs = _database.ArchiveInfo.FileInfoPopIDs; + + RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream); + RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile); + + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kName); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kAnti); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kSize); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kPackInfo); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCreationTime); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kLastWriteTime); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kLastAccessTime); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kWinAttributes); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kCRC); + CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::kComment); + _fileInfoPopIDs += fileInfoPopIDs; + + #ifndef _SFX + _fileInfoPopIDs.Add(98); + _fileInfoPopIDs.Add(99); + #endif + #ifdef _MULTI_PACK + _fileInfoPopIDs.Add(100); + _fileInfoPopIDs.Add(101); + _fileInfoPopIDs.Add(102); + _fileInfoPopIDs.Add(103); + _fileInfoPopIDs.Add(104); + #endif + + #ifndef _SFX + InsertToHead(_fileInfoPopIDs, NID::kLastWriteTime); + InsertToHead(_fileInfoPopIDs, NID::kPackInfo); + InsertToHead(_fileInfoPopIDs, NID::kSize); + InsertToHead(_fileInfoPopIDs, NID::kName); + #endif +} + +STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProperties) +{ + *numProperties = _fileInfoPopIDs.Size(); + return S_OK; +} + +STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType) +{ + if((int)index >= _fileInfoPopIDs.Size()) + return E_INVALIDARG; + int indexInMap = FindPropInMap(_fileInfoPopIDs[index]); + if (indexInMap == -1) + return E_INVALIDARG; + const STATPROPSTG &srcItem = kPropMap[indexInMap].StatPROPSTG; + *propID = srcItem.propid; + *varType = srcItem.vt; + *name = 0; + return S_OK; +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.h b/app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.h new file mode 100644 index 0000000000..2149e327ea --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/7z/7zProperties.h @@ -0,0 +1,22 @@ +// 7zProperties.h + +#ifndef __7Z_PROPERTIES_H +#define __7Z_PROPERTIES_H + +#include "../../PropID.h" + +namespace NArchive { +namespace N7z { + +enum // PropID +{ + kpidPackedSize0 = kpidUserDefined, + kpidPackedSize1, + kpidPackedSize2, + kpidPackedSize3, + kpidPackedSize4, +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/Archive.def b/app/win/installer/7zstub/src/7zip/Archive/Archive.def new file mode 100644 index 0000000000..f06b0816d7 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Archive.def @@ -0,0 +1,3 @@ +EXPORTS + CreateObject PRIVATE + GetHandlerProperty PRIVATE diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.cpp b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.cpp new file mode 100644 index 0000000000..4a552bf097 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.cpp @@ -0,0 +1,121 @@ +// CoderMixer2.cpp + +#include "StdAfx.h" + +#include "CoderMixer2.h" + +namespace NCoderMixer2 { + +CBindReverseConverter::CBindReverseConverter(const CBindInfo &srcBindInfo): + _srcBindInfo(srcBindInfo) +{ + srcBindInfo.GetNumStreams(NumSrcInStreams, _numSrcOutStreams); + + UInt32 j; + for (j = 0; j < NumSrcInStreams; j++) + { + _srcInToDestOutMap.Add(0); + DestOutToSrcInMap.Add(0); + } + for (j = 0; j < _numSrcOutStreams; j++) + { + _srcOutToDestInMap.Add(0); + _destInToSrcOutMap.Add(0); + } + + UInt32 destInOffset = 0; + UInt32 destOutOffset = 0; + UInt32 srcInOffset = NumSrcInStreams; + UInt32 srcOutOffset = _numSrcOutStreams; + + for (int i = srcBindInfo.Coders.Size() - 1; i >= 0; i--) + { + const CCoderStreamsInfo &srcCoderInfo = srcBindInfo.Coders[i]; + + srcInOffset -= srcCoderInfo.NumInStreams; + srcOutOffset -= srcCoderInfo.NumOutStreams; + + UInt32 j; + for (j = 0; j < srcCoderInfo.NumInStreams; j++, destOutOffset++) + { + UInt32 index = srcInOffset + j; + _srcInToDestOutMap[index] = destOutOffset; + DestOutToSrcInMap[destOutOffset] = index; + } + for (j = 0; j < srcCoderInfo.NumOutStreams; j++, destInOffset++) + { + UInt32 index = srcOutOffset + j; + _srcOutToDestInMap[index] = destInOffset; + _destInToSrcOutMap[destInOffset] = index; + } + } +} + +void CBindReverseConverter::CreateReverseBindInfo(CBindInfo &destBindInfo) +{ + destBindInfo.Coders.Clear(); + destBindInfo.BindPairs.Clear(); + destBindInfo.InStreams.Clear(); + destBindInfo.OutStreams.Clear(); + + int i; + for (i = _srcBindInfo.Coders.Size() - 1; i >= 0; i--) + { + const CCoderStreamsInfo &srcCoderInfo = _srcBindInfo.Coders[i]; + CCoderStreamsInfo destCoderInfo; + destCoderInfo.NumInStreams = srcCoderInfo.NumOutStreams; + destCoderInfo.NumOutStreams = srcCoderInfo.NumInStreams; + destBindInfo.Coders.Add(destCoderInfo); + } + for (i = _srcBindInfo.BindPairs.Size() - 1; i >= 0; i--) + { + const CBindPair &srcBindPair = _srcBindInfo.BindPairs[i]; + CBindPair destBindPair; + destBindPair.InIndex = _srcOutToDestInMap[srcBindPair.OutIndex]; + destBindPair.OutIndex = _srcInToDestOutMap[srcBindPair.InIndex]; + destBindInfo.BindPairs.Add(destBindPair); + } + for (i = 0; i < _srcBindInfo.InStreams.Size(); i++) + destBindInfo.OutStreams.Add(_srcInToDestOutMap[_srcBindInfo.InStreams[i]]); + for (i = 0; i < _srcBindInfo.OutStreams.Size(); i++) + destBindInfo.InStreams.Add(_srcOutToDestInMap[_srcBindInfo.OutStreams[i]]); +} + +CCoderInfo::CCoderInfo(UInt32 numInStreams, UInt32 numOutStreams): + NumInStreams(numInStreams), + NumOutStreams(numOutStreams) +{ + InSizes.Reserve(NumInStreams); + InSizePointers.Reserve(NumInStreams); + OutSizePointers.Reserve(NumOutStreams); + OutSizePointers.Reserve(NumOutStreams); +} + +static void SetSizes(const UInt64 **srcSizes, CRecordVector &sizes, + CRecordVector &sizePointers, UInt32 numItems) +{ + sizes.Clear(); + sizePointers.Clear(); + for(UInt32 i = 0; i < numItems; i++) + { + if (srcSizes == 0 || srcSizes[i] == NULL) + { + sizes.Add(0); + sizePointers.Add(NULL); + } + else + { + sizes.Add(*srcSizes[i]); + sizePointers.Add(&sizes.Back()); + } + } +} + +void CCoderInfo::SetCoderInfo(const UInt64 **inSizes, + const UInt64 **outSizes) +{ + SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); + SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); +} + +} diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.h b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.h new file mode 100644 index 0000000000..00cca2190d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2.h @@ -0,0 +1,168 @@ +// CoderMixer2.h + +#ifndef __CODER_MIXER2_H +#define __CODER_MIXER2_H + +#include "../../../Common/Vector.h" +#include "../../../Common/Types.h" +#include "../../../Common/MyCom.h" +#include "../../ICoder.h" + +namespace NCoderMixer2 { + +struct CBindPair +{ + UInt32 InIndex; + UInt32 OutIndex; +}; + +struct CCoderStreamsInfo +{ + UInt32 NumInStreams; + UInt32 NumOutStreams; +}; + +struct CBindInfo +{ + CRecordVector Coders; + CRecordVector BindPairs; + CRecordVector InStreams; + CRecordVector OutStreams; + + void Clear() + { + Coders.Clear(); + BindPairs.Clear(); + InStreams.Clear(); + OutStreams.Clear(); + } + + /* + UInt32 GetCoderStartOutStream(UInt32 coderIndex) const + { + UInt32 numOutStreams = 0; + for (UInt32 i = 0; i < coderIndex; i++) + numOutStreams += Coders[i].NumOutStreams; + return numOutStreams; + } + */ + + + void GetNumStreams(UInt32 &numInStreams, UInt32 &numOutStreams) const + { + numInStreams = 0; + numOutStreams = 0; + for (int i = 0; i < Coders.Size(); i++) + { + const CCoderStreamsInfo &coderStreamsInfo = Coders[i]; + numInStreams += coderStreamsInfo.NumInStreams; + numOutStreams += coderStreamsInfo.NumOutStreams; + } + } + + int FindBinderForInStream(UInt32 inStream) const + { + for (int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].InIndex == inStream) + return i; + return -1; + } + int FindBinderForOutStream(UInt32 outStream) const + { + for (int i = 0; i < BindPairs.Size(); i++) + if (BindPairs[i].OutIndex == outStream) + return i; + return -1; + } + + UInt32 GetCoderInStreamIndex(UInt32 coderIndex) const + { + UInt32 streamIndex = 0; + for (UInt32 i = 0; i < coderIndex; i++) + streamIndex += Coders[i].NumInStreams; + return streamIndex; + } + + UInt32 GetCoderOutStreamIndex(UInt32 coderIndex) const + { + UInt32 streamIndex = 0; + for (UInt32 i = 0; i < coderIndex; i++) + streamIndex += Coders[i].NumOutStreams; + return streamIndex; + } + + + void FindInStream(UInt32 streamIndex, UInt32 &coderIndex, + UInt32 &coderStreamIndex) const + { + for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) + { + UInt32 curSize = Coders[coderIndex].NumInStreams; + if (streamIndex < curSize) + { + coderStreamIndex = streamIndex; + return; + } + streamIndex -= curSize; + } + throw 1; + } + void FindOutStream(UInt32 streamIndex, UInt32 &coderIndex, + UInt32 &coderStreamIndex) const + { + for (coderIndex = 0; coderIndex < (UInt32)Coders.Size(); coderIndex++) + { + UInt32 curSize = Coders[coderIndex].NumOutStreams; + if (streamIndex < curSize) + { + coderStreamIndex = streamIndex; + return; + } + streamIndex -= curSize; + } + throw 1; + } +}; + +class CBindReverseConverter +{ + UInt32 _numSrcOutStreams; + const NCoderMixer2::CBindInfo _srcBindInfo; + CRecordVector _srcInToDestOutMap; + CRecordVector _srcOutToDestInMap; + CRecordVector _destInToSrcOutMap; +public: + UInt32 NumSrcInStreams; + CRecordVector DestOutToSrcInMap; + + CBindReverseConverter(const NCoderMixer2::CBindInfo &srcBindInfo); + void CreateReverseBindInfo(NCoderMixer2::CBindInfo &destBindInfo); +}; + +struct CCoderInfo +{ + CMyComPtr Coder; + CMyComPtr Coder2; + UInt32 NumInStreams; + UInt32 NumOutStreams; + + CRecordVector InSizes; + CRecordVector OutSizes; + CRecordVector InSizePointers; + CRecordVector OutSizePointers; + + CCoderInfo(UInt32 numInStreams, UInt32 numOutStreams); + void SetCoderInfo(const UInt64 **inSizes, const UInt64 **outSizes); +}; + +class CCoderMixer2 +{ +public: + virtual void SetBindInfo(const CBindInfo &bindInfo) = 0; + virtual void ReInit() = 0; + virtual void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) = 0; +}; + +} +#endif + diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.cpp b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.cpp new file mode 100644 index 0000000000..7b3ff73835 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.cpp @@ -0,0 +1,359 @@ +// CoderMixer2MT.cpp + +#include "StdAfx.h" + +#include "CoderMixer2MT.h" +#include "CrossThreadProgress.h" + +using namespace NWindows; +using namespace NSynchronization; + +namespace NCoderMixer2 { + +CThreadCoderInfo::CThreadCoderInfo(UInt32 numInStreams, UInt32 numOutStreams): + ExitEvent(NULL), + CompressEvent(NULL), + CompressionCompletedEvent(NULL), + CCoderInfo(numInStreams, numOutStreams) +{ + InStreams.Reserve(NumInStreams); + InStreamPointers.Reserve(NumInStreams); + OutStreams.Reserve(NumOutStreams); + OutStreamPointers.Reserve(NumOutStreams); +} + +void CThreadCoderInfo::CreateEvents() +{ + CompressEvent = new CAutoResetEvent(false); + CompressionCompletedEvent = new CAutoResetEvent(false); +} + +CThreadCoderInfo::~CThreadCoderInfo() +{ + if (CompressEvent != NULL) + delete CompressEvent; + if (CompressionCompletedEvent != NULL) + delete CompressionCompletedEvent; +} + +class CCoderInfoFlusher2 +{ + CThreadCoderInfo *m_CoderInfo; +public: + CCoderInfoFlusher2(CThreadCoderInfo *coderInfo): m_CoderInfo(coderInfo) {} + ~CCoderInfoFlusher2() + { + int i; + for (i = 0; i < m_CoderInfo->InStreams.Size(); i++) + m_CoderInfo->InStreams[i].Release(); + for (i = 0; i < m_CoderInfo->OutStreams.Size(); i++) + m_CoderInfo->OutStreams[i].Release(); + m_CoderInfo->CompressionCompletedEvent->Set(); + } +}; + +bool CThreadCoderInfo::WaitAndCode() +{ + HANDLE events[2] = { ExitEvent, *CompressEvent }; + DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE); + if (waitResult == WAIT_OBJECT_0 + 0) + return false; + + { + InStreamPointers.Clear(); + OutStreamPointers.Clear(); + UInt32 i; + for (i = 0; i < NumInStreams; i++) + { + if (InSizePointers[i] != NULL) + InSizePointers[i] = &InSizes[i]; + InStreamPointers.Add(InStreams[i]); + } + for (i = 0; i < NumOutStreams; i++) + { + if (OutSizePointers[i] != NULL) + OutSizePointers[i] = &OutSizes[i]; + OutStreamPointers.Add(OutStreams[i]); + } + CCoderInfoFlusher2 coderInfoFlusher(this); + if (Coder) + Result = Coder->Code(InStreamPointers[0], + OutStreamPointers[0], + InSizePointers[0], + OutSizePointers[0], + Progress); + else + Result = Coder2->Code(&InStreamPointers.Front(), + &InSizePointers.Front(), + NumInStreams, + &OutStreamPointers.Front(), + &OutSizePointers.Front(), + NumOutStreams, + Progress); + } + return true; +} + +static void SetSizes(const UInt64 **srcSizes, CRecordVector &sizes, + CRecordVector &sizePointers, UInt32 numItems) +{ + sizes.Clear(); + sizePointers.Clear(); + for(UInt32 i = 0; i < numItems; i++) + { + if (srcSizes == 0 || srcSizes[i] == NULL) + { + sizes.Add(0); + sizePointers.Add(NULL); + } + else + { + sizes.Add(*srcSizes[i]); + sizePointers.Add(&sizes.Back()); + } + } +} + + +void CThreadCoderInfo::SetCoderInfo(const UInt64 **inSizes, + const UInt64 **outSizes, ICompressProgressInfo *progress) +{ + Progress = progress; + SetSizes(inSizes, InSizes, InSizePointers, NumInStreams); + SetSizes(outSizes, OutSizes, OutSizePointers, NumOutStreams); +} + +static DWORD WINAPI CoderThread(void *threadCoderInfo) +{ + while(true) + { + if (!((CThreadCoderInfo *)threadCoderInfo)->WaitAndCode()) + return 0; + } +} + +////////////////////////////////////// +// CCoderMixer2MT + +static DWORD WINAPI MainCoderThread(void *threadCoderInfo) +{ + while(true) + { + if (!((CCoderMixer2MT *)threadCoderInfo)->MyCode()) + return 0; + } +} + +CCoderMixer2MT::CCoderMixer2MT() +{ + if (!_mainThread.Create(MainCoderThread, this)) + throw 271825; +} + +CCoderMixer2MT::~CCoderMixer2MT() +{ + _exitEvent.Set(); + _mainThread.Wait(); + for(int i = 0; i < _threads.Size(); i++) + { + _threads[i].Wait(); + _threads[i].Close(); + } +} + +void CCoderMixer2MT::SetBindInfo(const CBindInfo &bindInfo) +{ + _bindInfo = bindInfo; + _streamBinders.Clear(); + for(int i = 0; i < _bindInfo.BindPairs.Size(); i++) + { + _streamBinders.Add(CStreamBinder()); + _streamBinders.Back().CreateEvents(); + } +} + +void CCoderMixer2MT::AddCoderCommon() +{ + int index = _coderInfoVector.Size(); + const CCoderStreamsInfo &CoderStreamsInfo = _bindInfo.Coders[index]; + + CThreadCoderInfo threadCoderInfo(CoderStreamsInfo.NumInStreams, + CoderStreamsInfo.NumOutStreams); + _coderInfoVector.Add(threadCoderInfo); + _coderInfoVector.Back().CreateEvents(); + _coderInfoVector.Back().ExitEvent = _exitEvent; + _compressingCompletedEvents.Add(*_coderInfoVector.Back().CompressionCompletedEvent); + + NWindows::CThread newThread; + _threads.Add(newThread); + if (!_threads.Back().Create(CoderThread, &_coderInfoVector.Back())) + throw 271824; +} + +void CCoderMixer2MT::AddCoder(ICompressCoder *coder) +{ + AddCoderCommon(); + _coderInfoVector.Back().Coder = coder; +} + +void CCoderMixer2MT::AddCoder2(ICompressCoder2 *coder) +{ + AddCoderCommon(); + _coderInfoVector.Back().Coder2 = coder; +} + +/* +void CCoderMixer2MT::FinishAddingCoders() +{ + for(int i = 0; i < _coderInfoVector.Size(); i++) + { + DWORD id; + HANDLE newThread = ::CreateThread(NULL, 0, CoderThread, + &_coderInfoVector[i], 0, &id); + if (newThread == 0) + throw 271824; + _threads.Add(newThread); + } +} +*/ + +void CCoderMixer2MT::ReInit() +{ + for(int i = 0; i < _streamBinders.Size(); i++) + _streamBinders[i].ReInit(); +} + + +STDMETHODIMP CCoderMixer2MT::Init(ISequentialInStream **inStreams, + ISequentialOutStream **outStreams) +{ + if (_coderInfoVector.Size() != _bindInfo.Coders.Size()) + throw 0; + int i; + for(i = 0; i < _coderInfoVector.Size(); i++) + { + CThreadCoderInfo &coderInfo = _coderInfoVector[i]; + const CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[i]; + coderInfo.InStreams.Clear(); + UInt32 j; + for(j = 0; j < coderStreamsInfo.NumInStreams; j++) + coderInfo.InStreams.Add(NULL); + coderInfo.OutStreams.Clear(); + for(j = 0; j < coderStreamsInfo.NumOutStreams; j++) + coderInfo.OutStreams.Add(NULL); + } + + for(i = 0; i < _bindInfo.BindPairs.Size(); i++) + { + const CBindPair &bindPair = _bindInfo.BindPairs[i]; + UInt32 inCoderIndex, inCoderStreamIndex; + UInt32 outCoderIndex, outCoderStreamIndex; + _bindInfo.FindInStream(bindPair.InIndex, inCoderIndex, inCoderStreamIndex); + _bindInfo.FindOutStream(bindPair.OutIndex, outCoderIndex, outCoderStreamIndex); + + _streamBinders[i].CreateStreams( + &_coderInfoVector[inCoderIndex].InStreams[inCoderStreamIndex], + &_coderInfoVector[outCoderIndex].OutStreams[outCoderStreamIndex]); + } + + for(i = 0; i < _bindInfo.InStreams.Size(); i++) + { + UInt32 inCoderIndex, inCoderStreamIndex; + _bindInfo.FindInStream(_bindInfo.InStreams[i], inCoderIndex, inCoderStreamIndex); + _coderInfoVector[inCoderIndex].InStreams[inCoderStreamIndex] = inStreams[i]; + } + + for(i = 0; i < _bindInfo.OutStreams.Size(); i++) + { + UInt32 outCoderIndex, outCoderStreamIndex; + _bindInfo.FindOutStream(_bindInfo.OutStreams[i], outCoderIndex, outCoderStreamIndex); + _coderInfoVector[outCoderIndex].OutStreams[outCoderStreamIndex] = outStreams[i]; + } + return S_OK; +} + + +bool CCoderMixer2MT::MyCode() +{ + HANDLE events[2] = { _exitEvent, _startCompressingEvent }; + DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE); + if (waitResult == WAIT_OBJECT_0 + 0) + return false; + + for(int i = 0; i < _coderInfoVector.Size(); i++) + _coderInfoVector[i].CompressEvent->Set(); + DWORD result = ::WaitForMultipleObjects(_compressingCompletedEvents.Size(), + &_compressingCompletedEvents.Front(), TRUE, INFINITE); + + _compressingFinishedEvent.Set(); + + return true; +} + + +STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || + numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) + return E_INVALIDARG; + + Init(inStreams, outStreams); + + _compressingFinishedEvent.Reset(); // ? + + CCrossThreadProgress *progressSpec = new CCrossThreadProgress; + CMyComPtr crossProgress = progressSpec; + progressSpec->Init(); + _coderInfoVector[_progressCoderIndex].Progress = crossProgress; + + _startCompressingEvent.Set(); + + + while (true) + { + HANDLE events[2] = {_compressingFinishedEvent, progressSpec->ProgressEvent }; + DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE); + if (waitResult == WAIT_OBJECT_0 + 0) + break; + if (progress != NULL) + progressSpec->Result = progress->SetRatioInfo(progressSpec->InSize, + progressSpec->OutSize); + else + progressSpec->Result = S_OK; + progressSpec->WaitEvent.Set(); + } + + int i; + for(i = 0; i < _coderInfoVector.Size(); i++) + { + HRESULT result = _coderInfoVector[i].Result; + if (result == S_FALSE) + return result; + } + for(i = 0; i < _coderInfoVector.Size(); i++) + { + HRESULT result = _coderInfoVector[i].Result; + if (result != S_OK && result != E_FAIL) + return result; + } + for(i = 0; i < _coderInfoVector.Size(); i++) + { + HRESULT result = _coderInfoVector[i].Result; + if (result != S_OK) + return result; + } + return S_OK; +} + +UInt64 CCoderMixer2MT::GetWriteProcessedSize(UInt32 binderIndex) const +{ + return _streamBinders[binderIndex].ProcessedSize; +} + +} diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.h b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.h new file mode 100644 index 0000000000..9a72219654 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/CoderMixer2MT.h @@ -0,0 +1,121 @@ +// CoderMixer2MT.h + +#ifndef __CODER_MIXER2_MT_H +#define __CODER_MIXER2_MT_H + +#include "CoderMixer2.h" +#include "../../../Common/MyCom.h" +#include "../../../Windows/Thread.h" +#include "../../Common/StreamBinder.h" + +namespace NCoderMixer2 { + +// CreateEvents(); +// { +// SetCoderInfo() +// Init Streams +// set CompressEvent() +// wait CompressionCompletedEvent +// } + +struct CThreadCoderInfo: public CCoderInfo +{ + NWindows::NSynchronization::CAutoResetEvent *CompressEvent; + HANDLE ExitEvent; + NWindows::NSynchronization::CAutoResetEvent *CompressionCompletedEvent; + + CObjectVector< CMyComPtr > InStreams; + CObjectVector< CMyComPtr > OutStreams; + CRecordVector InStreamPointers; + CRecordVector OutStreamPointers; + + CMyComPtr Progress; // CMyComPtr + HRESULT Result; + + CThreadCoderInfo(UInt32 numInStreams, UInt32 numOutStreams); + void SetCoderInfo(const UInt64 **inSizes, + const UInt64 **outSizes, ICompressProgressInfo *progress); + ~CThreadCoderInfo(); + bool WaitAndCode(); + void CreateEvents(); +}; + + +// SetBindInfo() +// for each coder +// { +// AddCoder[2]() +// } +// +// for each file +// { +// ReInit() +// for each coder +// { +// SetCoderInfo +// } +// SetProgressIndex(UInt32 coderIndex); +// Code +// } + + +class CCoderMixer2MT: + public ICompressCoder2, + public CCoderMixer2, + public CMyUnknownImp +{ + MY_UNKNOWN_IMP + +public: + STDMETHOD(Init)(ISequentialInStream **inStreams, + ISequentialOutStream **outStreams); + + STDMETHOD(Code)(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress); + + + CCoderMixer2MT(); + ~CCoderMixer2MT(); + void AddCoderCommon(); + void AddCoder(ICompressCoder *coder); + void AddCoder2(ICompressCoder2 *coder); + + void ReInit(); + void SetCoderInfo(UInt32 coderIndex, const UInt64 **inSizes, const UInt64 **outSizes) + { _coderInfoVector[coderIndex].SetCoderInfo(inSizes, outSizes, NULL); } + void SetProgressCoderIndex(UInt32 coderIndex) + { _progressCoderIndex = coderIndex; } + + + UInt64 GetWriteProcessedSize(UInt32 binderIndex) const; + + + bool MyCode(); + +private: + CBindInfo _bindInfo; + CObjectVector _streamBinders; + CObjectVector _coderInfoVector; + CRecordVector _threads; + NWindows::CThread _mainThread; + + NWindows::NSynchronization::CAutoResetEvent _startCompressingEvent; + CRecordVector _compressingCompletedEvents; + NWindows::NSynchronization::CAutoResetEvent _compressingFinishedEvent; + + NWindows::NSynchronization::CManualResetEvent _exitEvent; + UInt32 _progressCoderIndex; + +public: + void SetBindInfo(const CBindInfo &bindInfo); + +}; + +} +#endif + diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.cpp b/app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.cpp new file mode 100644 index 0000000000..62d05afdd7 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.cpp @@ -0,0 +1,15 @@ +// CrossThreadProgress.cpp + +#include "StdAfx.h" + +#include "CrossThreadProgress.h" + +STDMETHODIMP CCrossThreadProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) +{ + InSize = inSize; + OutSize = outSize; + ProgressEvent.Set(); + WaitEvent.Lock(); + return Result; +} + diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.h b/app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.h new file mode 100644 index 0000000000..0504b93064 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/CrossThreadProgress.h @@ -0,0 +1,31 @@ +// CrossThreadProgress.h + +#ifndef __CROSSTHREADPROGRESS_H +#define __CROSSTHREADPROGRESS_H + +#include "../../ICoder.h" +#include "../../../Windows/Synchronization.h" +#include "../../../Common/MyCom.h" + +class CCrossThreadProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ +public: + const UInt64 *InSize; + const UInt64 *OutSize; + HRESULT Result; + NWindows::NSynchronization::CAutoResetEvent ProgressEvent; + NWindows::NSynchronization::CAutoResetEvent WaitEvent; + void Init() + { + ProgressEvent.Reset(); + WaitEvent.Reset(); + } + + MY_UNKNOWN_IMP + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.cpp b/app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.cpp new file mode 100644 index 0000000000..fa8aba2e4b --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.cpp @@ -0,0 +1,242 @@ +// FilterCoder.cpp + +#include "StdAfx.h" + +#include "FilterCoder.h" +#include "../../../Common/Alloc.h" +#include "../../../Common/Defs.h" +#include "../../Common/StreamUtils.h" + +static const int kBufferSize = 1 << 17; + +CFilterCoder::CFilterCoder() +{ + _buffer = (Byte *)::MidAlloc(kBufferSize); +} + +CFilterCoder::~CFilterCoder() +{ + ::MidFree(_buffer); +} + +HRESULT CFilterCoder::WriteWithLimit(ISequentialOutStream *outStream, UInt32 size) +{ + if (_outSizeIsDefined) + { + UInt64 remSize = _outSize - _nowPos64; + if (size > remSize) + size = (UInt32)remSize; + } + UInt32 processedSize = 0; + RINOK(WriteStream(outStream, _buffer, size, &processedSize)); + if (size != processedSize) + return E_FAIL; + _nowPos64 += processedSize; + return S_OK; +} + + +STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + RINOK(Init()); + UInt32 bufferPos = 0; + if (_outSizeIsDefined = (outSize != 0)) + _outSize = *outSize; + + while(NeedMore()) + { + UInt32 processedSize; + + // Change it: It can be optimized using ReadPart + RINOK(ReadStream(inStream, _buffer + bufferPos, kBufferSize - bufferPos, &processedSize)); + + UInt32 endPos = bufferPos + processedSize; + + bufferPos = Filter->Filter(_buffer, endPos); + if (bufferPos > endPos) + { + for (; endPos< bufferPos; endPos++) + _buffer[endPos] = 0; + bufferPos = Filter->Filter(_buffer, endPos); + } + + if (bufferPos == 0) + { + if (endPos > 0) + return WriteWithLimit(outStream, endPos); + return S_OK; + } + RINOK(WriteWithLimit(outStream, bufferPos)); + if (progress != NULL) + { + RINOK(progress->SetRatioInfo(&_nowPos64, &_nowPos64)); + } + UInt32 i = 0; + while(bufferPos < endPos) + _buffer[i++] = _buffer[bufferPos++]; + bufferPos = i; + } + return S_OK; +} + +// #ifdef _ST_MODE +STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream) +{ + _bufferPos = 0; + _outStream = outStream; + return Init(); +} + +STDMETHODIMP CFilterCoder::ReleaseOutStream() +{ + _outStream.Release(); + return S_OK; +}; + + +STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 processedSizeTotal = 0; + while(size > 0) + { + UInt32 sizeMax = kBufferSize - _bufferPos; + UInt32 sizeTemp = size; + if (sizeTemp > sizeMax) + sizeTemp = sizeMax; + memmove(_buffer + _bufferPos, data, sizeTemp); + size -= sizeTemp; + processedSizeTotal += sizeTemp; + data = (const Byte *)data + sizeTemp; + UInt32 endPos = _bufferPos + sizeTemp; + _bufferPos = Filter->Filter(_buffer, endPos); + if (_bufferPos == 0) + { + _bufferPos = endPos; + break; + } + if (_bufferPos > endPos) + { + if (size != 0) + return E_FAIL; + break; + } + RINOK(WriteWithLimit(_outStream, _bufferPos)); + UInt32 i = 0; + while(_bufferPos < endPos) + _buffer[i++] = _buffer[_bufferPos++]; + _bufferPos = i; + } + if (processedSize != NULL) + *processedSize = processedSizeTotal; + return S_OK; +} + +STDMETHODIMP CFilterCoder::Flush() +{ + if (_bufferPos != 0) + { + UInt32 endPos = Filter->Filter(_buffer, _bufferPos); + if (endPos > _bufferPos) + { + for (; _bufferPos < endPos; _bufferPos++) + _buffer[_bufferPos] = 0; + if (Filter->Filter(_buffer, endPos) != endPos) + return E_FAIL; + } + UInt32 processedSize; + RINOK(WriteStream(_outStream, _buffer, _bufferPos, &processedSize)); + if (_bufferPos != processedSize) + return E_FAIL; + _bufferPos = 0; + } + CMyComPtr flush; + _outStream.QueryInterface(IID_IOutStreamFlush, &flush); + if (flush) + return flush->Flush(); + return S_OK; +} + + +STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream) +{ + _convertedPosBegin = _convertedPosEnd = _bufferPos = 0; + _inStream = inStream; + return Init(); +} + +STDMETHODIMP CFilterCoder::ReleaseInStream() +{ + _inStream.Release(); + return S_OK; +}; + +STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 processedSizeTotal = 0; + while(size > 0) + { + if (_convertedPosBegin != _convertedPosEnd) + { + UInt32 sizeTemp = MyMin(size, _convertedPosEnd - _convertedPosBegin); + memmove(data, _buffer + _convertedPosBegin, sizeTemp); + _convertedPosBegin += sizeTemp; + data = (void *)((Byte *)data + sizeTemp); + size -= sizeTemp; + processedSizeTotal += sizeTemp; + break; + } + int i; + for (i = 0; _convertedPosEnd + i < _bufferPos; i++) + _buffer[i] = _buffer[i + _convertedPosEnd]; + _bufferPos = i; + _convertedPosBegin = _convertedPosEnd = 0; + UInt32 processedSizeTemp; + UInt32 size0 = kBufferSize - _bufferPos; + // Optimize it: + RINOK(ReadStream(_inStream, _buffer + _bufferPos, size0, &processedSizeTemp)); + _bufferPos = _bufferPos + processedSizeTemp; + _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); + if (_convertedPosEnd == 0) + { + if (_bufferPos == 0) + break; + else + { + _convertedPosEnd = _bufferPos; // check it + continue; + } + } + if (_convertedPosEnd > _bufferPos) + { + for (; _bufferPos < _convertedPosEnd; _bufferPos++) + _buffer[_bufferPos] = 0; + _convertedPosEnd = Filter->Filter(_buffer, _bufferPos); + } + } + if (processedSize != NULL) + *processedSize = processedSizeTotal; + return S_OK; +} + +// #endif // _ST_MODE + +#ifndef _NO_CRYPTO +STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size) +{ + return _setPassword->CryptoSetPassword(data, size); +} +#endif + +#ifndef EXTRACT_ONLY +STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream) +{ + return _writeCoderProperties->WriteCoderProperties(outStream); +} +#endif + +STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size) +{ + return _setDecoderProperties->SetDecoderProperties2(data, size); +} diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.h b/app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.h new file mode 100644 index 0000000000..cf0033ab6e --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/FilterCoder.h @@ -0,0 +1,130 @@ +// FilterCoder.h + +#ifndef __FILTERCODER_H +#define __FILTERCODER_H + +#include "../../../Common/MyCom.h" +#include "../../ICoder.h" +#include "../../IPassword.h" + +#define MY_QUERYINTERFACE_ENTRY_AG(i, sub0, sub) if (iid == IID_ ## i) \ +{ if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \ +*outObject = (void *)(i *)this; AddRef(); return S_OK; } + +class CFilterCoder: + public ICompressCoder, + // #ifdef _ST_MODE + public ICompressSetInStream, + public ISequentialInStream, + public ICompressSetOutStream, + public ISequentialOutStream, + public IOutStreamFlush, + // #endif + + #ifndef _NO_CRYPTO + public ICryptoSetPassword, + #endif + #ifndef EXTRACT_ONLY + public ICompressWriteCoderProperties, + #endif + public ICompressSetDecoderProperties2, + public CMyUnknownImp +{ +protected: + Byte *_buffer; + // #ifdef _ST_MODE + CMyComPtr _inStream; + CMyComPtr _outStream; + UInt32 _bufferPos; + UInt32 _convertedPosBegin; + UInt32 _convertedPosEnd; + // #endif + bool _outSizeIsDefined; + UInt64 _outSize; + UInt64 _nowPos64; + + HRESULT Init() + { + _nowPos64 = 0; + _outSizeIsDefined = false; + return Filter->Init(); + } + + CMyComPtr _setPassword; + #ifndef EXTRACT_ONLY + CMyComPtr _writeCoderProperties; + #endif + CMyComPtr _setDecoderProperties; +public: + CMyComPtr Filter; + + CFilterCoder(); + ~CFilterCoder(); + HRESULT WriteWithLimit(ISequentialOutStream *outStream, UInt32 size); + bool NeedMore() const + { return (!_outSizeIsDefined || (_nowPos64 < _outSize)); } + +public: + MY_QUERYINTERFACE_BEGIN + MY_QUERYINTERFACE_ENTRY(ICompressCoder) + // #ifdef _ST_MODE + MY_QUERYINTERFACE_ENTRY(ICompressSetInStream) + MY_QUERYINTERFACE_ENTRY(ISequentialInStream) + + MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream) + MY_QUERYINTERFACE_ENTRY(ISequentialOutStream) + MY_QUERYINTERFACE_ENTRY(IOutStreamFlush) + // #endif + + #ifndef _NO_CRYPTO + MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword) + #endif + + #ifndef EXTRACT_ONLY + MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties) + #endif + + MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties) + MY_QUERYINTERFACE_END + MY_ADDREF_RELEASE + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + // #ifdef _ST_MODE + STDMETHOD(ReleaseInStream)(); + STDMETHOD(SetInStream)(ISequentialInStream *inStream); + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); \ + STDMETHOD(SetOutStream)(ISequentialOutStream *outStream); + STDMETHOD(ReleaseOutStream)(); + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Flush)(); + // #endif + + #ifndef _NO_CRYPTO + STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size); + #endif + #ifndef EXTRACT_ONLY + STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream); + #endif + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); +}; + +// #ifdef _ST_MODE +class CInStreamReleaser +{ +public: + CFilterCoder *FilterCoder; + CInStreamReleaser(): FilterCoder(0) {} + ~CInStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); } +}; + +class COutStreamReleaser +{ +public: + CFilterCoder *FilterCoder; + COutStreamReleaser(): FilterCoder(0) {} + ~COutStreamReleaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); } +}; +// #endif + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.cpp b/app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.cpp new file mode 100644 index 0000000000..46f2cee3e1 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.cpp @@ -0,0 +1,59 @@ +// Archive/Common/ItemNameUtils.cpp + +#include "StdAfx.h" + +#include "ItemNameUtils.h" + +namespace NArchive { +namespace NItemName { + +static const wchar_t kOSDirDelimiter = WCHAR_PATH_SEPARATOR; +static const wchar_t kDirDelimiter = L'/'; + +UString MakeLegalName(const UString &name) +{ + UString zipName = name; + zipName.Replace(kOSDirDelimiter, kDirDelimiter); + return zipName; +} + +UString GetOSName(const UString &name) +{ + UString newName = name; + newName.Replace(kDirDelimiter, kOSDirDelimiter); + return newName; +} + +UString GetOSName2(const UString &name) +{ + if (name.IsEmpty()) + return UString(); + UString newName = GetOSName(name); + if (newName[newName.Length() - 1] == kOSDirDelimiter) + newName.Delete(newName.Length() - 1); + return newName; +} + +bool HasTailSlash(const AString &name, UINT codePage) +{ + if (name.IsEmpty()) + return false; + LPCSTR prev = + #ifdef _WIN32 + CharPrevExA(codePage, name, &name[name.Length()], 0); + #else + (LPCSTR)(name) + (name.Length() - 1); + #endif + return (*prev == '/'); +} + +#ifndef _WIN32 +UString WinNameToOSName(const UString &name) +{ + UString newName = name; + newName.Replace(L'\\', kOSDirDelimiter); + return newName; +} +#endif + +}} diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.h b/app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.h new file mode 100644 index 0000000000..51e5d93f03 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/ItemNameUtils.h @@ -0,0 +1,24 @@ +// Archive/Common/ItemNameUtils.h + +#ifndef __ARCHIVE_ITEMNAMEUTILS_H +#define __ARCHIVE_ITEMNAMEUTILS_H + +#include "../../../Common/String.h" + +namespace NArchive { +namespace NItemName { + + UString MakeLegalName(const UString &name); + UString GetOSName(const UString &name); + UString GetOSName2(const UString &name); + bool HasTailSlash(const AString &name, UINT codePage); + + #ifdef _WIN32 + inline UString WinNameToOSName(const UString &name) { return name; } + #else + UString WinNameToOSName(const UString &name); + #endif + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.cpp b/app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.cpp new file mode 100644 index 0000000000..6199562ee1 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.cpp @@ -0,0 +1,23 @@ +// OutStreamWithCRC.cpp + +#include "StdAfx.h" + +#include "OutStreamWithCRC.h" + +STDMETHODIMP COutStreamWithCRC::Write(const void *data, + UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result; + if(!_stream) + { + realProcessedSize = size; + result = S_OK; + } + else + result = _stream->Write(data, size, &realProcessedSize); + _crc.Update(data, realProcessedSize); + if(processedSize != NULL) + *processedSize = realProcessedSize; + return result; +} diff --git a/app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.h b/app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.h new file mode 100644 index 0000000000..11c5c579bf --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/Common/OutStreamWithCRC.h @@ -0,0 +1,33 @@ +// OutStreamWithCRC.h + +#ifndef __OUTSTREAMWITHCRC_H +#define __OUTSTREAMWITHCRC_H + +#include "../../../Common/CRC.h" +#include "../../../Common/MyCom.h" +#include "../../IStream.h" + +class COutStreamWithCRC: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +private: + CCRC _crc; + CMyComPtr _stream; +public: + void Init(ISequentialOutStream *stream) + { + _stream = stream; + _crc.Init(); + } + void ReleaseStream() { _stream.Release(); } + UInt32 GetCRC() const { return _crc.GetDigest(); } + void InitCRC() { _crc.Init(); } + +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Archive/IArchive.h b/app/win/installer/7zstub/src/7zip/Archive/IArchive.h new file mode 100644 index 0000000000..12f9a3c4af --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Archive/IArchive.h @@ -0,0 +1,173 @@ +// IArchive.h + +#ifndef __IARCHIVE_H +#define __IARCHIVE_H + +#include "../IStream.h" +#include "../IProgress.h" +#include "../PropID.h" + +// MIDL_INTERFACE("23170F69-40C1-278A-0000-000600xx0000") +#define ARCHIVE_INTERFACE_SUB(i, base, x) \ +DEFINE_GUID(IID_ ## i, \ +0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x06, 0x00, x, 0x00, 0x00); \ +struct i: public base + +#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x) + +namespace NFileTimeType +{ + enum EEnum + { + kWindows, + kUnix, + kDOS + }; +} + +namespace NArchive +{ + enum + { + kName = 0, + kClassID, + kExtension, + kAddExtension, + kUpdate, + kKeepName, + kStartSignature, + kFinishSignature, + kAssociate + }; + + namespace NExtract + { + namespace NAskMode + { + enum + { + kExtract = 0, + kTest, + kSkip, + }; + } + namespace NOperationResult + { + enum + { + kOK = 0, + kUnSupportedMethod, + kDataError, + kCRCError, + }; + } + } + namespace NUpdate + { + namespace NOperationResult + { + enum + { + kOK = 0, + kError, + }; + } + } +} + +ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10) +{ + STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) PURE; + STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) PURE; +}; + + +ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20) +{ + STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, + Int32 askExtractMode) PURE; + // GetStream OUT: S_OK - OK, S_FALSE - skeep this file + STDMETHOD(PrepareOperation)(Int32 askExtractMode) PURE; + STDMETHOD(SetOperationResult)(Int32 resultEOperationResult) PURE; +}; + + +ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30) +{ + STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) PURE; + STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) PURE; +}; + + +ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40) +{ + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE; +}; + + +ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50) +{ + STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE; +}; + + +ARCHIVE_INTERFACE(IInArchive, 0x60) +{ + STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, + IArchiveOpenCallback *openArchiveCallback) PURE; + STDMETHOD(Close)() PURE; + STDMETHOD(GetNumberOfItems)(UInt32 *numItems) PURE; + STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; + STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, + Int32 testMode, IArchiveExtractCallback *extractCallback) PURE; + // indices must be sorted + // numItems = 0xFFFFFFFF means all files + // testMode != 0 means "test files operation" + + STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) PURE; + + STDMETHOD(GetNumberOfProperties)(UInt32 *numProperties) PURE; + STDMETHOD(GetPropertyInfo)(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType) PURE; + + STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProperties) PURE; + STDMETHOD(GetArchivePropertyInfo)(UInt32 index, + BSTR *name, PROPID *propID, VARTYPE *varType) PURE; +}; + + +ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80) +{ + STDMETHOD(GetUpdateItemInfo)(UInt32 index, + Int32 *newData, // 1 - new data, 0 - old data + Int32 *newProperties, // 1 - new properties, 0 - old properties + UInt32 *indexInArchive // -1 if there is no in archive, or if doesn't matter + ) PURE; + STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE; + STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) PURE; + STDMETHOD(SetOperationResult)(Int32 operationResult) PURE; +}; + + +ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82) +{ + STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) PURE; + STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) PURE; +}; + + +ARCHIVE_INTERFACE(IOutArchive, 0xA0) +{ + STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, + IArchiveUpdateCallback *updateCallback) PURE; + STDMETHOD(GetFileTimeType)(UInt32 *type) PURE; +}; + + +ARCHIVE_INTERFACE(ISetProperties, 0x03) +{ + STDMETHOD(SetProperties)(const wchar_t **names, const PROPVARIANT *values, Int32 numProperties) PURE; +}; + + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.cpp b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.cpp new file mode 100644 index 0000000000..caec696a21 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.cpp @@ -0,0 +1,249 @@ +// ExtractCallback.h + +#include "StdAfx.h" + +#include "ExtractCallback.h" + +#include "Common/Wildcard.h" +#include "Common/StringConvert.h" + +#include "Windows/COM.h" +#include "Windows/FileDir.h" +#include "Windows/FileFind.h" +#include "Windows/Time.h" +#include "Windows/Defs.h" +#include "Windows/PropVariant.h" + +#include "Windows/PropVariantConversions.h" + +using namespace NWindows; +using namespace NFile; + +static LPCWSTR kErrorTitle = L"7-Zip"; +static LPCWSTR kCantDeleteFile = L"Can not delete output file"; +static LPCWSTR kCantOpenFile = L"Can not open output file"; +static LPCWSTR kUnsupportedMethod = L"Unsupported Method"; +// static LPCWSTR kCRCFailed = L"CRC Failed"; +// static LPCWSTR kDataError = L"Data Error"; +// static LPCWSTR kUnknownError = L""Unknown Error"; + +void CExtractCallbackImp::Init(IInArchive *archiveHandler, + const UString &directoryPath, + const UString &itemDefaultName, + const FILETIME &utcLastWriteTimeDefault, + UInt32 attributesDefault) +{ + _message.Empty(); + _isCorrupt = false; + _itemDefaultName = itemDefaultName; + _utcLastWriteTimeDefault = utcLastWriteTimeDefault; + _attributesDefault = attributesDefault; + _archiveHandler = archiveHandler; + _directoryPath = directoryPath; + NName::NormalizeDirPathPrefix(_directoryPath); +} + +STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size) +{ + #ifndef _NO_PROGRESS + ProgressDialog.ProgressSynch.SetProgress(size, 0); + #endif + return S_OK; +} + +STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *completeValue) +{ + #ifndef _NO_PROGRESS + while(true) + { + if(ProgressDialog.ProgressSynch.GetStopped()) + return E_ABORT; + if(!ProgressDialog.ProgressSynch.GetPaused()) + break; + ::Sleep(100); + } + if (completeValue != NULL) + ProgressDialog.ProgressSynch.SetPos(*completeValue); + #endif + return S_OK; +} + +void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts) +{ + UString fullPath = _directoryPath; + for(int i = 0; i < dirPathParts.Size(); i++) + { + fullPath += dirPathParts[i]; + NDirectory::MyCreateDirectory(fullPath); + fullPath += NName::kDirDelimiter; + } +} + +STDMETHODIMP CExtractCallbackImp::GetStream(UInt32 index, + ISequentialOutStream **outStream, Int32 askExtractMode) +{ + #ifndef _NO_PROGRESS + if(ProgressDialog.ProgressSynch.GetStopped()) + return E_ABORT; + #endif + _outFileStream.Release(); + NCOM::CPropVariant propVariantName; + RINOK(_archiveHandler->GetProperty(index, kpidPath, &propVariantName)); + UString fullPath; + if(propVariantName.vt == VT_EMPTY) + fullPath = _itemDefaultName; + else + { + if(propVariantName.vt != VT_BSTR) + return E_FAIL; + fullPath = propVariantName.bstrVal; + } + _filePath = fullPath; + + // m_CurrentFilePath = GetSystemString(fullPath, _codePage); + + if(askExtractMode == NArchive::NExtract::NAskMode::kExtract) + { + NCOM::CPropVariant propVariant; + RINOK(_archiveHandler->GetProperty(index, kpidAttributes, &propVariant)); + if (propVariant.vt == VT_EMPTY) + _processedFileInfo.Attributes = _attributesDefault; + else + { + if (propVariant.vt != VT_UI4) + return E_FAIL; + _processedFileInfo.Attributes = propVariant.ulVal; + } + + RINOK(_archiveHandler->GetProperty(index, kpidIsFolder, &propVariant)); + _processedFileInfo.IsDirectory = VARIANT_BOOLToBool(propVariant.boolVal); + + bool isAnti = false; + { + NCOM::CPropVariant propVariantTemp; + RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, + &propVariantTemp)); + if (propVariantTemp.vt == VT_BOOL) + isAnti = VARIANT_BOOLToBool(propVariantTemp.boolVal); + } + + RINOK(_archiveHandler->GetProperty(index, kpidLastWriteTime, &propVariant)); + switch(propVariant.vt) + { + case VT_EMPTY: + _processedFileInfo.UTCLastWriteTime = _utcLastWriteTimeDefault; + break; + case VT_FILETIME: + _processedFileInfo.UTCLastWriteTime = propVariant.filetime; + break; + default: + return E_FAIL; + } + + UStringVector pathParts; + SplitPathToParts(fullPath, pathParts); + if(pathParts.IsEmpty()) + return E_FAIL; + + UString processedPath = fullPath; + + if(!_processedFileInfo.IsDirectory) + pathParts.DeleteBack(); + if (!pathParts.IsEmpty()) + { + if (!isAnti) + CreateComplexDirectory(pathParts); + } + + UString fullProcessedPath = _directoryPath + processedPath; + + if(_processedFileInfo.IsDirectory) + { + _diskFilePath = fullProcessedPath; + + if (isAnti) + NDirectory::MyRemoveDirectory(_diskFilePath); + return S_OK; + } + + NFind::CFileInfoW fileInfo; + if(NFind::FindFile(fullProcessedPath, fileInfo)) + { + if (!NDirectory::DeleteFileAlways(fullProcessedPath)) + { + _message = kCantDeleteFile; + return E_FAIL; + } + } + + if (!isAnti) + { + _outFileStreamSpec = new COutFileStream; + CMyComPtr outStreamLoc(_outFileStreamSpec); + if (!_outFileStreamSpec->Create(fullProcessedPath, true)) + { + _message = kCantOpenFile; + return E_FAIL; + } + _outFileStream = outStreamLoc; + *outStream = outStreamLoc.Detach(); + } + _diskFilePath = fullProcessedPath; + } + else + { + *outStream = NULL; + } + return S_OK; +} + +STDMETHODIMP CExtractCallbackImp::PrepareOperation(Int32 askExtractMode) +{ + _extractMode = false; + switch (askExtractMode) + { + case NArchive::NExtract::NAskMode::kExtract: + _extractMode = true; + break; + }; + return S_OK; +} + +STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult) +{ + switch(resultEOperationResult) + { + case NArchive::NExtract::NOperationResult::kOK: + { + break; + } + default: + { + _outFileStream.Release(); + switch(resultEOperationResult) + { + case NArchive::NExtract::NOperationResult::kUnSupportedMethod: + _message = kUnsupportedMethod; + break; + case NArchive::NExtract::NOperationResult::kCRCError: + _isCorrupt = true; + // _message = kCRCFailed; + break; + case NArchive::NExtract::NOperationResult::kDataError: + _isCorrupt = true; + // _message = kDataError; + break; + default: + _isCorrupt = true; + } + return E_FAIL; + } + } + if(_outFileStream != NULL) + _outFileStreamSpec->File.SetLastWriteTime(&_processedFileInfo.UTCLastWriteTime); + _outFileStream.Release(); + if (_extractMode) + NDirectory::MySetFileAttributes(_diskFilePath, _processedFileInfo.Attributes); + return S_OK; +} + diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.h b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.h new file mode 100644 index 0000000000..d77ffd74e5 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractCallback.h @@ -0,0 +1,96 @@ +// ExtractCallback.h + +#ifndef __EXTRACTCALLBACK_H +#define __EXTRACTCALLBACK_H + +#include "resource.h" + +#include "Common/String.h" +#include "Windows/ResourceString.h" + +#include "../../Archive/IArchive.h" + +#include "../../Common/FileStreams.h" +#include "../../ICoder.h" + +#ifndef _NO_PROGRESS +#include "../../FileManager/Resource/ProgressDialog/ProgressDialog.h" +#endif + +class CExtractCallbackImp: + public IArchiveExtractCallback, + public CMyUnknownImp +{ +public: + + MY_UNKNOWN_IMP + + // IProgress + STDMETHOD(SetTotal)(UInt64 size); + STDMETHOD(SetCompleted)(const UInt64 *completeValue); + + // IExtractCallback + STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, + Int32 askExtractMode); + STDMETHOD(PrepareOperation)(Int32 askExtractMode); + STDMETHOD(SetOperationResult)(Int32 resultEOperationResult); + +private: + CMyComPtr _archiveHandler; + UString _directoryPath; + + UString _filePath; + + UString _diskFilePath; + + bool _extractMode; + struct CProcessedFileInfo + { + FILETIME UTCLastWriteTime; + bool IsDirectory; + UInt32 Attributes; + } _processedFileInfo; + + COutFileStream *_outFileStreamSpec; + CMyComPtr _outFileStream; + + UString _itemDefaultName; + FILETIME _utcLastWriteTimeDefault; + UInt32 _attributesDefault; + + void CreateComplexDirectory(const UStringVector &dirPathParts); +public: + #ifndef _NO_PROGRESS + CProgressDialog ProgressDialog; + #endif + + bool _isCorrupt; + UString _message; + + void Init(IInArchive *archiveHandler, + const UString &directoryPath, + const UString &itemDefaultName, + const FILETIME &utcLastWriteTimeDefault, + UInt32 attributesDefault); + + #ifndef _NO_PROGRESS + HRESULT StartProgressDialog(const UString &title) + { + ProgressDialog.Create(title, 0); + { + #ifdef LANG + ProgressDialog.SetText(LangLoadString(IDS_PROGRESS_EXTRACTING, 0x02000890)); + #else + ProgressDialog.SetText(NWindows::MyLoadStringW(IDS_PROGRESS_EXTRACTING)); + #endif + } + + ProgressDialog.Show(SW_SHOWNORMAL); + return S_OK; + } + virtual ~CExtractCallbackImp() { ProgressDialog.Destroy(); } + #endif + +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.cpp b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.cpp new file mode 100644 index 0000000000..855f7aea91 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.cpp @@ -0,0 +1,139 @@ +// ExtractEngine.cpp + +#include "StdAfx.h" + +#include "ExtractEngine.h" + +#include "Common/StringConvert.h" + +#include "Windows/FileDir.h" +#include "Windows/FileFind.h" +#include "Windows/Thread.h" + +#include "../../UI/Common/OpenArchive.h" + +#include "../../UI/Explorer/MyMessages.h" +#include "../../FileManager/FormatUtils.h" + +#include "ExtractCallback.h" + +using namespace NWindows; + +struct CThreadExtracting +{ + CArchiveLink ArchiveLink; + + CExtractCallbackImp *ExtractCallbackSpec; + CMyComPtr ExtractCallback; + + #ifndef _NO_PROGRESS + HRESULT Result; + + HRESULT Extract() + { + return ArchiveLink.GetArchive()->Extract(0, (UInt32)-1 , BoolToInt(false), ExtractCallback); + } + DWORD Process() + { + ExtractCallbackSpec->ProgressDialog.WaitCreating(); + Result = Extract(); + ExtractCallbackSpec->ProgressDialog.MyClose(); + return 0; + } + static DWORD WINAPI MyThreadFunction(void *param) + { + return ((CThreadExtracting *)param)->Process(); + } + #endif +}; + +static const LPCWSTR kCantFindArchive = L"Can not find archive file"; +static const LPCWSTR kCantOpenArchive = L"File is not correct archive"; + +HRESULT ExtractArchive( + const UString &fileName, + const UString &folderName, + COpenCallbackGUI *openCallback, + bool showProgress, + bool &isCorrupt, + UString &errorMessage) +{ + isCorrupt = false; + NFile::NFind::CFileInfoW archiveFileInfo; + if (!NFile::NFind::FindFile(fileName, archiveFileInfo)) + { + errorMessage = kCantFindArchive; + return E_FAIL; + } + + CThreadExtracting extracter; + + HRESULT result = MyOpenArchive(fileName, extracter.ArchiveLink, openCallback); + + if (result != S_OK) + { + errorMessage = kCantOpenArchive; + return result; + } + + UString directoryPath = folderName; + NFile::NName::NormalizeDirPathPrefix(directoryPath); + + /* + UString directoryPath; + { + UString fullPath; + int fileNamePartStartIndex; + if (!NWindows::NFile::NDirectory::MyGetFullPathName(fileName, fullPath, fileNamePartStartIndex)) + { + MessageBox(NULL, "Error 1329484", "7-Zip", 0); + return E_FAIL; + } + directoryPath = fullPath.Left(fileNamePartStartIndex); + } + */ + + if(!NFile::NDirectory::CreateComplexDirectory(directoryPath)) + { + errorMessage = MyFormatNew(IDS_CANNOT_CREATE_FOLDER, + #ifdef LANG + 0x02000603, + #endif + directoryPath); + return E_FAIL; + } + + extracter.ExtractCallbackSpec = new CExtractCallbackImp; + extracter.ExtractCallback = extracter.ExtractCallbackSpec; + + extracter.ExtractCallbackSpec->Init( + extracter.ArchiveLink.GetArchive(), + directoryPath, L"Default", archiveFileInfo.LastWriteTime, 0); + + #ifndef _NO_PROGRESS + + if (showProgress) + { + CThread thread; + if (!thread.Create(CThreadExtracting::MyThreadFunction, &extracter)) + throw 271824; + + UString title; + #ifdef LANG + title = LangLoadString(IDS_PROGRESS_EXTRACTING, 0x02000890); + #else + title = NWindows::MyLoadStringW(IDS_PROGRESS_EXTRACTING); + #endif + extracter.ExtractCallbackSpec->StartProgressDialog(title); + result = extracter.Result; + } + else + + #endif + { + result = extracter.Extract(); + } + errorMessage = extracter.ExtractCallbackSpec->_message; + isCorrupt = extracter.ExtractCallbackSpec->_isCorrupt; + return result; +} diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.h b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.h new file mode 100644 index 0000000000..609cd7290e --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/ExtractEngine.h @@ -0,0 +1,17 @@ +// ExtractEngine.h + +#ifndef __EXTRACTENGINE_H +#define __EXTRACTENGINE_H + +#include "Common/String.h" +#include "../../UI/GUI/OpenCallbackGUI.h" + +HRESULT ExtractArchive( + const UString &fileName, + const UString &folderName, + COpenCallbackGUI *openCallback, + bool showProgress, + bool &isCorrupt, + UString &errorMessage); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/Main.cpp b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/Main.cpp new file mode 100644 index 0000000000..21c348eda1 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/Main.cpp @@ -0,0 +1,344 @@ +// Main.cpp + +#include "StdAfx.h" + +#include + +#include "Common/StringConvert.h" +#include "Common/Random.h" +#include "Common/TextConfig.h" +#include "Common/CommandLineParser.h" + +#include "Windows/FileDir.h" +#include "Windows/FileIO.h" +#include "Windows/FileFind.h" +#include "Windows/FileName.h" +#include "Windows/DLL.h" +#include "Windows/ResourceString.h" + +#include "../../IPassword.h" +#include "../../ICoder.h" +#include "../../Archive/IArchive.h" +#include "../../UI/Explorer/MyMessages.h" + +// #include "../../UI/GUI/ExtractGUI.h" + +#include "ExtractEngine.h" + +#include "resource.h" + +using namespace NWindows; + +HINSTANCE g_hInstance; + +static LPCTSTR kTempDirPrefix = TEXT("7zS"); + +#define _SHELL_EXECUTE + +static bool ReadDataString(LPCWSTR fileName, LPCSTR startID, + LPCSTR endID, AString &stringResult) +{ + stringResult.Empty(); + NFile::NIO::CInFile inFile; + if (!inFile.Open(fileName)) + return false; + const int kBufferSize = (1 << 12); + + Byte buffer[kBufferSize]; + int signatureStartSize = lstrlenA(startID); + int signatureEndSize = lstrlenA(endID); + + UInt32 numBytesPrev = 0; + bool writeMode = false; + UInt64 posTotal = 0; + while(true) + { + if (posTotal > (1 << 20)) + return (stringResult.IsEmpty()); + UInt32 numReadBytes = kBufferSize - numBytesPrev; + UInt32 processedSize; + if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize)) + return false; + if (processedSize == 0) + return true; + UInt32 numBytesInBuffer = numBytesPrev + processedSize; + UInt32 pos = 0; + while (true) + { + if (writeMode) + { + if (pos > numBytesInBuffer - signatureEndSize) + break; + if (memcmp(buffer + pos, endID, signatureEndSize) == 0) + return true; + char b = buffer[pos]; + if (b == 0) + return false; + stringResult += b; + pos++; + } + else + { + if (pos > numBytesInBuffer - signatureStartSize) + break; + if (memcmp(buffer + pos, startID, signatureStartSize) == 0) + { + writeMode = true; + pos += signatureStartSize; + } + else + pos++; + } + } + numBytesPrev = numBytesInBuffer - pos; + posTotal += pos; + memmove(buffer, buffer + pos, numBytesPrev); + } +} + +static char kStartID[] = ",!@Install@!UTF-8!"; +static char kEndID[] = ",!@InstallEnd@!"; + +class CInstallIDInit +{ +public: + CInstallIDInit() + { + kStartID[0] = ';'; + kEndID[0] = ';'; + }; +} g_CInstallIDInit; + + +class CCurrentDirRestorer +{ + CSysString m_CurrentDirectory; +public: + CCurrentDirRestorer() + { NFile::NDirectory::MyGetCurrentDirectory(m_CurrentDirectory); } + ~CCurrentDirRestorer() + { RestoreDirectory();} + bool RestoreDirectory() + { return BOOLToBool(::SetCurrentDirectory(m_CurrentDirectory)); } +}; + +#ifndef _UNICODE +bool g_IsNT = false; +static inline bool IsItWindowsNT() +{ + OSVERSIONINFO versionInfo; + versionInfo.dwOSVersionInfoSize = sizeof(versionInfo); + if (!::GetVersionEx(&versionInfo)) + return false; + return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); +} +#endif + +int APIENTRY WinMain( + HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + g_hInstance = (HINSTANCE)hInstance; + #ifndef _UNICODE + g_IsNT = IsItWindowsNT(); + #endif + InitCommonControls(); + + UString archiveName, switches; + #ifdef _SHELL_EXECUTE + UString executeFile, executeParameters; + #endif + NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches); + + UString fullPath; + NDLL::MyGetModuleFileName(g_hInstance, fullPath); + + switches.Trim(); + bool assumeYes = false; + if (switches.Left(2).CompareNoCase(UString(L"-y")) == 0) + { + assumeYes = true; + switches = switches.Mid(2); + switches.Trim(); + } + + /* BEGIN Mozilla customizations */ + bool showProgress = true; + if (switches.Left(3).CompareNoCase(UString(L"-ms")) == 0 || + switches.Left(4).CompareNoCase(UString(L"/INI")) == 0 || + switches.Left(2).CompareNoCase(UString(L"/S")) == 0) + showProgress = false; + /* END Mozilla customizations */ + + AString config; + if (!ReadDataString(fullPath, kStartID, kEndID, config)) + { + if (!assumeYes) + MyMessageBox(L"Can't load config info"); + return 1; + } + + UString dirPrefix = L".\\"; + UString appLaunched; + if (!config.IsEmpty()) + { + CObjectVector pairs; + if (!GetTextConfig(config, pairs)) + { + if (!assumeYes) + MyMessageBox(L"Config failed"); + return 1; + } + UString friendlyName = GetTextConfigValue(pairs, L"Title"); + UString installPrompt = GetTextConfigValue(pairs, L"BeginPrompt"); + UString progress = GetTextConfigValue(pairs, L"Progress"); + if (progress.CompareNoCase(L"no") == 0) + showProgress = false; + int index = FindTextConfigItem(pairs, L"Directory"); + if (index >= 0) + dirPrefix = pairs[index].String; + if (!installPrompt.IsEmpty() && !assumeYes) + { + if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO | + MB_ICONQUESTION) != IDYES) + return 0; + } + appLaunched = GetTextConfigValue(pairs, L"RunProgram"); + + #ifdef _SHELL_EXECUTE + executeFile = GetTextConfigValue(pairs, L"ExecuteFile"); + executeParameters = GetTextConfigValue(pairs, L"ExecuteParameters") + switches; + #endif + } + + NFile::NDirectory::CTempDirectory tempDir; + if (!tempDir.Create(kTempDirPrefix)) + { + if (!assumeYes) + MyMessageBox(L"Can not create temp folder archive"); + return 1; + } + + COpenCallbackGUI openCallback; + + UString tempDirPath = GetUnicodeString(tempDir.GetPath()); + bool isCorrupt = false; + UString errorMessage; + HRESULT result = ExtractArchive(fullPath, tempDirPath, &openCallback, showProgress, + isCorrupt, errorMessage); + + if (result != S_OK) + { + if (!assumeYes) + { + if (result == S_FALSE || isCorrupt) + { + errorMessage = NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_MESSAGE); + result = E_FAIL; + } + if (result != E_ABORT && !errorMessage.IsEmpty()) + ::MessageBoxW(0, errorMessage, NWindows::MyLoadStringW(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR); + } + return 1; + } + + CCurrentDirRestorer currentDirRestorer; + + if (!SetCurrentDirectory(tempDir.GetPath())) + return 1; + + HANDLE hProcess = 0; +#ifdef _SHELL_EXECUTE + if (!executeFile.IsEmpty()) + { + CSysString filePath = GetSystemString(executeFile); + SHELLEXECUTEINFO execInfo; + execInfo.cbSize = sizeof(execInfo); + execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT; + execInfo.hwnd = NULL; + execInfo.lpVerb = NULL; + execInfo.lpFile = filePath; + + if (!switches.IsEmpty()) + executeParameters += switches; + + CSysString parametersSys = GetSystemString(executeParameters); + if (parametersSys.IsEmpty()) + execInfo.lpParameters = NULL; + else + execInfo.lpParameters = parametersSys; + + execInfo.lpDirectory = NULL; + execInfo.nShow = SW_SHOWNORMAL; + execInfo.hProcess = 0; + bool success = BOOLToBool(::ShellExecuteEx(&execInfo)); + result = (UINT32)execInfo.hInstApp; + if(result <= 32) + { + if (!assumeYes) + MyMessageBox(L"Can not open file"); + return 1; + } + hProcess = execInfo.hProcess; + } + else +#endif + { + if (appLaunched.IsEmpty()) + { + appLaunched = L"setup.exe"; + if (!NFile::NFind::DoesFileExist(GetSystemString(appLaunched))) + { + if (!assumeYes) + MyMessageBox(L"Can not find setup.exe"); + return 1; + } + } + + { + UString s2 = tempDirPath; + NFile::NName::NormalizeDirPathPrefix(s2); + appLaunched.Replace(L"%%T\\", s2); + } + + appLaunched.Replace(L"%%T", tempDirPath); + + if (!switches.IsEmpty()) + { + appLaunched += L' '; + appLaunched += switches; + } + STARTUPINFO startupInfo; + startupInfo.cb = sizeof(startupInfo); + startupInfo.lpReserved = 0; + startupInfo.lpDesktop = 0; + startupInfo.lpTitle = 0; + startupInfo.dwFlags = 0; + startupInfo.cbReserved2 = 0; + startupInfo.lpReserved2 = 0; + + PROCESS_INFORMATION processInformation; + + CSysString appLaunchedSys = GetSystemString(dirPrefix + appLaunched); + + BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys, + NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */, + &startupInfo, &processInformation); + if (createResult == 0) + { + if (!assumeYes) + ShowLastErrorMessage(); + return 1; + } + ::CloseHandle(processInformation.hThread); + hProcess = processInformation.hProcess; + } + if (hProcess != 0) + { + WaitForSingleObject(hProcess, INFINITE); + ::CloseHandle(hProcess); + } + return 0; +} diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsp b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsp new file mode 100644 index 0000000000..ffa6286560 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsp @@ -0,0 +1,696 @@ +# Microsoft Developer Studio Project File - Name="SFXSetup-moz" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=SFXSetup-moz - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "SFXSetup-moz.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "SFXSetup-moz.mak" CFG="SFXSetup-moz - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "SFXSetup-moz - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "SFXSetup-moz - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "SFXSetup-moz - Win32 ReleaseD" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "SFXSetup-moz - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c +# ADD CPP /nologo /Gz /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "_SFX" /D "_NO_CRYPTO" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zS.sfx" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ELSEIF "$(CFG)" == "SFXSetup-moz - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c +# ADD CPP /nologo /Gz /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "_SFX" /D "_NO_CRYPTO" /Yu"StdAfx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "_DEBUG" +# ADD RSC /l 0x419 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zSfxS.exe" /pdbtype:sept + +!ELSEIF "$(CFG)" == "SFXSetup-moz - Win32 ReleaseD" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "ReleaseD" +# PROP BASE Intermediate_Dir "ReleaseD" +# PROP BASE Ignore_Export_Lib 0 +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "ReleaseD" +# PROP Intermediate_Dir "ReleaseD" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "_SFX" /Yu"StdAfx.h" /FD /c +# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "FORMAT_7Z" /D "COMPRESS_LZMA" /D "COMPRESS_BCJ_X86" /D "COMPRESS_BCJ2" /D "COMPRESS_COPY" /D "_SFX" /D "_NO_CRYPTO" /Yu"StdAfx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x419 /d "NDEBUG" +# ADD RSC /l 0x419 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe" +# SUBTRACT BASE LINK32 /debug /nodefaultlib +# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"ReleaseD\7zSD.sfx" /opt:NOWIN98 +# SUBTRACT LINK32 /pdb:none + +!ENDIF + +# Begin Target + +# Name "SFXSetup-moz - Win32 Release" +# Name "SFXSetup-moz - Win32 Debug" +# Name "SFXSetup-moz - Win32 ReleaseD" +# Begin Group "Spec" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=.\resource.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"StdAfx.h" +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Interface" + +# PROP Default_Filter "" +# End Group +# Begin Group "7z" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zDecode.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zExtract.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderOutStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zFolderOutStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zHeader.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zIn.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zItem.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zMethodID.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\7z\7zMethodID.h +# End Source File +# End Group +# Begin Group "Archive Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2MT.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CoderMixer2MT.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CrossThreadProgress.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\CrossThreadProgress.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FilterCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\FilterCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\ItemNameUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Archive\Common\OutStreamWithCRC.h +# End Source File +# End Group +# Begin Group "Compress" + +# PROP Default_Filter "" +# Begin Group "LZMA" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\LZMA\LZMADecoder.cpp +# End Source File +# End Group +# Begin Group "Branch" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Branch\BranchCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Branch\BranchCoder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Branch\x86.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Branch\x86_2.cpp +# End Source File +# End Group +# Begin Group "Copy" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\Copy\CopyCoder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\Copy\CopyCoder.h +# End Source File +# End Group +# Begin Group "LZ" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Compress\LZ\LZOutWindow.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Compress\LZ\LZOutWindow.h +# End Source File +# End Group +# End Group +# Begin Group "SDK" + +# PROP Default_Filter "" +# End Group +# Begin Group "Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Common\Alloc.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Alloc.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CommandLineParser.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\CRC.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\IntToString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\NewHandler.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\String.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\String.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\StringConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\TextConfig.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\TextConfig.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\UTFConvert.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Vector.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Vector.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Common\Wildcard.h +# End Source File +# End Group +# Begin Group "Windows" + +# PROP Default_Filter "" +# Begin Group "Control" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Control\Dialog.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\DLL.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Error.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Error.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileDir.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileFind.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileIO.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\FileName.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\PropVariant.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\ResourceString.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Synchronization.h +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\..\Windows\Window.h +# End Source File +# End Group +# Begin Group "7z Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\Common\FileStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\FileStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\InBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LimitedStreams.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\LockedStream.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\OutBuffer.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\ProgressUtils.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamBinder.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamObjects.h +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\Common\StreamUtils.h +# End Source File +# End Group +# Begin Group "UI" + +# PROP Default_Filter "" +# Begin Group "Explorer" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Explorer\MyMessages.h +# End Source File +# End Group +# Begin Group "UI Common" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiveOpenCallback.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiverInfo.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ArchiverInfo.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\DefaultName.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\ExtractMode.h +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\Common\OpenArchive.h +# End Source File +# End Group +# Begin Group "GUI" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\UI\GUI\OpenCallbackGUI.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\UI\GUI\OpenCallbackGUI.h +# End Source File +# End Group +# End Group +# Begin Group "File Manager" + +# PROP Default_Filter "" +# Begin Group "Dialog" + +# PROP Default_Filter "" +# Begin Source File + +SOURCE=..\..\FileManager\Resource\ProgressDialog\ProgressDialog.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\FileManager\Resource\ProgressDialog\ProgressDialog.h +# End Source File +# End Group +# Begin Source File + +SOURCE=..\..\FileManager\FormatUtils.cpp +# End Source File +# Begin Source File + +SOURCE=..\..\FileManager\FormatUtils.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ExtractCallback.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractCallback.h +# End Source File +# Begin Source File + +SOURCE=.\ExtractEngine.cpp +# End Source File +# Begin Source File + +SOURCE=.\ExtractEngine.h +# End Source File +# Begin Source File + +SOURCE=.\Main.cpp +# End Source File +# Begin Source File + +SOURCE=.\setup.ico +# End Source File +# End Target +# End Project diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsw b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsw new file mode 100644 index 0000000000..2b6b8243c4 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/SFXSetup-moz.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "SFXSetup-moz"=.\SFXSetup-moz.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.cpp b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.cpp new file mode 100644 index 0000000000..c6d3b1fa62 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.cpp @@ -0,0 +1,3 @@ +// StdAfx.cpp + +#include "StdAfx.h" diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.h b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.h new file mode 100644 index 0000000000..85536206d0 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/StdAfx.h @@ -0,0 +1,10 @@ +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../../Common/MyWindows.h" +#include "../../../Common/NewHandler.h" +#include + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/makefile b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/makefile new file mode 100644 index 0000000000..89cae1d5bc --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/makefile @@ -0,0 +1,156 @@ +PROG = 7zS.sfx +LIBS = $(LIBS) user32.lib oleaut32.lib shell32.lib ole32.lib comctl32.lib +CFLAGS = $(CFLAGS) -I ../../../ \ + -DEXCLUDE_COM \ + -DNO_REGISTRY \ + -DEXTRACT_ONLY \ + -D_SFX \ + -DFORMAT_7Z \ + -DCOMPRESS_BCJ_X86 \ + -DCOMPRESS_BCJ2 \ + -DCOMPRESS_COPY \ + -DCOMPRESS_LZMA \ + -D_NO_CRYPTO + +SFX_WIN_OBJS = \ + $O\Main.obj \ + $O\ExtractCallback.obj \ + $O\ExtractEngine.obj \ + +GUI_OBJS = \ + $O\OpenCallbackGUI.obj \ + +COMMON_OBJS = \ + $O\Alloc.obj \ + $O\CommandLineParser.obj \ + $O\CRC.obj \ + $O\IntToString.obj \ + $O\NewHandler.obj \ + $O\String.obj \ + $O\StringConvert.obj \ + $O\TextConfig.obj \ + $O\UTFConvert.obj \ + $O\Vector.obj \ + $O\Wildcard.obj \ + +WIN_OBJS = \ + $O\DLL.obj \ + $O\Error.obj \ + $O\FileDir.obj \ + $O\FileFind.obj \ + $O\FileIO.obj \ + $O\FileName.obj \ + $O\PropVariant.obj \ + $O\ResourceString.obj \ + $O\Synchronization.obj \ + $O\Window.obj \ + +WIN_CTRL_OBJS = \ + $O\Dialog.obj \ + +7ZIP_COMMON_OBJS = \ + $O\FileStreams.obj \ + $O\InBuffer.obj \ + $O\LimitedStreams.obj \ + $O\LockedStream.obj \ + $O\OutBuffer.obj \ + $O\ProgressUtils.obj \ + $O\StreamBinder.obj \ + $O\StreamObjects.obj \ + $O\StreamUtils.obj \ + +UI_COMMON_OBJS = \ + $O\ArchiveOpenCallback.obj \ + $O\ArchiverInfo.obj \ + $O\DefaultName.obj \ + $O\OpenArchive.obj \ + +FM_OBJS = \ + $O\FormatUtils.obj \ + +AR_COMMON_OBJS = \ + $O\CoderMixer2.obj \ + $O\CoderMixer2MT.obj \ + $O\CrossThreadProgress.obj \ + $O\FilterCoder.obj \ + $O\ItemNameUtils.obj \ + $O\OutStreamWithCRC.obj \ + +7Z_OBJS = \ + $O\7zDecode.obj \ + $O\7zExtract.obj \ + $O\7zFolderOutStream.obj \ + $O\7zHandler.obj \ + $O\7zHeader.obj \ + $O\7zIn.obj \ + $O\7zMethodID.obj \ + +BRANCH_OPT_OBJS = \ + $O\BranchCoder.obj \ + $O\x86.obj \ + $O\x86_2.obj \ + +LZ_OBJS = \ + $O\LZOutWindow.obj \ + +LZMA_OPT_OBJS = \ + $O\LZMADecoder.obj \ + +OBJS = \ + $O\StdAfx.obj \ + $(SFX_WIN_OBJS) \ + $(GUI_OBJS) \ + $(COMMON_OBJS) \ + $(WIN_OBJS) \ + $(WIN_CTRL_OBJS) \ + $(7ZIP_COMMON_OBJS) \ + $(UI_COMMON_OBJS) \ + $(FM_OBJS)\ + $(AR_COMMON_OBJS) \ + $(7Z_OBJS) \ + $(BRANCH_OPT_OBJS) \ + $(LZ_OBJS) \ + $(LZMA_OPT_OBJS) \ + $O\CopyCoder.obj \ + $O\MyMessages.obj \ + $O\ProgressDialog.obj \ + $O\resource.res + + +!include "../../../Build.mak" + +$(SFX_WIN_OBJS): $(*B).cpp + $(COMPL) + +$(GUI_OBJS): ../../UI/GUI/$(*B).cpp + $(COMPL) +$(COMMON_OBJS): ../../../Common/$(*B).cpp + $(COMPL) +$(WIN_OBJS): ../../../Windows/$(*B).cpp + $(COMPL) +$(WIN_CTRL_OBJS): ../../../Windows/Control/$(*B).cpp + $(COMPL) +$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp + $(COMPL) +$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp + $(COMPL) +$(FM_OBJS): ../../FileManager/$(*B).cpp + $(COMPL) +$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp + $(COMPL) + +$(7Z_OBJS): ../../Archive/7z/$(*B).cpp + $(COMPL) +$(BRANCH_OPT_OBJS): ../../Compress/Branch/$(*B).cpp + $(COMPL) +$(LZ_OBJS): ../../Compress/LZ/$(*B).cpp + $(COMPL) +$(LZMA_OPT_OBJS): ../../Compress/LZMA/$(*B).cpp + $(COMPL) + +$O\CopyCoder.obj: ../../Compress/Copy/$(*B).cpp + $(COMPL) +$O\MyMessages.obj: ../../UI/Explorer/MyMessages.cpp + $(COMPL) +$O\ProgressDialog.obj: ../../FileManager/Resource/ProgressDialog/$(*B).cpp + $(COMPL) diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.h b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.h new file mode 100644 index 0000000000..650cb07081 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.h @@ -0,0 +1,6 @@ +#define IDI_ICON3 159 + +#define IDS_EXTRACTION_ERROR_TITLE 7 +#define IDS_EXTRACTION_ERROR_MESSAGE 8 +#define IDS_CANNOT_CREATE_FOLDER 9 +#define IDS_PROGRESS_EXTRACTING 69 diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.rc b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.rc new file mode 100644 index 0000000000..8b25305139 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/resource.rc @@ -0,0 +1,16 @@ +#include "../../MyVersionInfo.rc" +#include "resource.h" + +MY_VERSION_INFO_APP("7z Setup SFX", "7zS.sfx") + +IDI_ICON3 ICON "setup.ico" + +STRINGTABLE +BEGIN + IDS_EXTRACTION_ERROR_TITLE "Extraction Failed" + IDS_EXTRACTION_ERROR_MESSAGE "File is corrupt" + IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'" + IDS_PROGRESS_EXTRACTING "Extracting" +END + +#include "../../FileManager/Resource/ProgressDialog/resource.rc" diff --git a/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/setup.ico b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/setup.ico new file mode 100644 index 0000000000000000000000000000000000000000..9801fed54fbaf217537693e628497a5002d20a77 GIT binary patch literal 25214 zcmeIacU)Ch6E-@C22<5H#y7@Tg1y9&*b+6?C>l#*i8aR9dyEaNphm$4R_r1wph&Y( zL=rgjLx8J#}3-^cyCD**_)^ha6lHJS@eTS2tLZ+*Znae!hbR`QAhZT zNAmIUA)m)SlpADAHEY(S+O=!bM<0De_3G851`Qg}mtTHK^nv{e{3o(AT#f&vXJlq* zXk>Uo&q&|!ppofn#7kEhnMrKe+TIXx7em9<2N8d2WVCTB;#G!brma!_zyUK;slRHK zq2UQ>#|+Jpo*@EaLsP`tPLL7OjZ9CFBpVtM#hU_8U7(IJR!9&ss)M9Uz8;{C8VJt{ z;9bV48K56PJ5DB;v)2a`G=LlojuPQ79swrGSP`-EpP1zdfPa!Ce_jcOhD)la>6w<8 zN(#nLNj5S?HB&<)vyu{!NP1@SZf0a|VPU~2hWC=z7>cyCk`gXfzw7I_wl_xsE?J`F z>+8?AKa-Y*dM288BYS&uyrP2CZ>Mi$X3u8KCF=K+Co#AsWWg3@l5gIwxsjPgu34Ru zk`j4OJLzFmQiAtNb$;5BBgW{AEP#Vj-b3=aQlCmR9TB_-SJ6?{`tva^jOf7=;_p2Y~MAg09Zgz_FoDJdz2px;D29>y5e#fz0y zpyUf-gfgizu6kI8hG<&t06hR@(v7UOGON^Ow^?W#vsIL!EQxl>( z06l=N26Pa=4YcK?j?|Sl1lhhCkY^Skq-z21#_aP4%R282mf*m)e-VV&ur9Y<_Kq zsWPpMoZ6|W#l^*%jN0ny=3+x5^Y!bEjWKT~>SomC4Gm3G5ioyjRF!UK%$RW}b$N9K zr5%0!Hl}9wcAD}^1x>oX{x*C2^-=*1l?ZOquRbau9TlW~rJ<_y)%H?BipxG!mv7fj zzl|X>?37dmBc=SwllpT(s=cu~y%?A(=_oHlV95B-piP^O@}?L9V~`4Zi;IC!Re2OM zF4ilq^Sr!y<;jz$q&yev8Dha#mCtEs?_sJgZ=_ef{JA4Xl=48_v>3!`+RyRu@Gw(G zpxDs362z(TF|RywN2 z(!pO4vdyG8I*{T@x^N(vGQ`R1`xU z6LoQE9~@X66wXqWE=Qf2sqsshwT�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 slashPos && dotPos > 0) + { + name = fullProcessedPath.Left(dotPos); + extension = fullProcessedPath.Mid(dotPos); + } + else + name = fullProcessedPath; + name += L'_'; + int indexLeft = 1, indexRight = (1 << 30); + while (indexLeft != indexRight) + { + int indexMid = (indexLeft + indexRight) / 2; + if (MakeAutoName(name, extension, indexMid, path)) + indexLeft = indexMid + 1; + else + indexRight = indexMid; + } + if (MakeAutoName(name, extension, indexRight, fullProcessedPath)) + return false; + return true; +} diff --git a/app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.h b/app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.h new file mode 100644 index 0000000000..10197428d8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.h @@ -0,0 +1,10 @@ +// Util/FilePathAutoRename.h + +#ifndef __FILEPATHAUTORENAME_H +#define __FILEPATHAUTORENAME_H + +#include "Common/String.h" + +bool AutoRenamePath(UString &fullProcessedPath); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/FileStreams.cpp b/app/win/installer/7zstub/src/7zip/Common/FileStreams.cpp new file mode 100644 index 0000000000..7a32c6e702 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/FileStreams.cpp @@ -0,0 +1,251 @@ +// FileStreams.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 +#include +#include +#include +#endif + +#include "FileStreams.h" + +static inline HRESULT ConvertBoolToHRESULT(bool result) +{ + // return result ? S_OK: E_FAIL; + #ifdef _WIN32 + return result ? S_OK: (::GetLastError()); + #else + return result ? S_OK: E_FAIL; + #endif +} + +bool CInFileStream::Open(LPCTSTR fileName) +{ + return File.Open(fileName); +} + +#ifdef _WIN32 +#ifndef _UNICODE +bool CInFileStream::Open(LPCWSTR fileName) +{ + return File.Open(fileName); +} +#endif +#endif + +STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + #ifdef _WIN32 + + UInt32 realProcessedSize; + bool result = File.ReadPart(data, size, realProcessedSize); + if(processedSize != NULL) + *processedSize = realProcessedSize; + return ConvertBoolToHRESULT(result); + + #else + + if(processedSize != NULL) + *processedSize = 0; + ssize_t res = File.Read(data, (size_t)size); + if (res == -1) + return E_FAIL; + if(processedSize != NULL) + *processedSize = (UInt32)res; + return S_OK; + + #endif +} + +#ifndef _WIN32_WCE +STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + #ifdef _WIN32 + UInt32 realProcessedSize; + BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), + data, size, (DWORD *)&realProcessedSize, NULL); + if(processedSize != NULL) + *processedSize = realProcessedSize; + if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE) + return S_OK; + return ConvertBoolToHRESULT(res != FALSE); + + #else + + if(processedSize != NULL) + *processedSize = 0; + ssize_t res; + do + { + res = read(0, data, (size_t)size); + } + while (res < 0 && (errno == EINTR)); + if (res == -1) + return E_FAIL; + if(processedSize != NULL) + *processedSize = (UInt32)res; + return S_OK; + + #endif +} + +#endif + +STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, + UInt64 *newPosition) +{ + if(seekOrigin >= 3) + return STG_E_INVALIDFUNCTION; + + #ifdef _WIN32 + + UInt64 realNewPosition; + bool result = File.Seek(offset, seekOrigin, realNewPosition); + if(newPosition != NULL) + *newPosition = realNewPosition; + return ConvertBoolToHRESULT(result); + + #else + + off_t res = File.Seek(offset, seekOrigin); + if (res == -1) + return E_FAIL; + if(newPosition != NULL) + *newPosition = (UInt64)res; + return S_OK; + + #endif +} + +STDMETHODIMP CInFileStream::GetSize(UInt64 *size) +{ + return ConvertBoolToHRESULT(File.GetLength(*size)); +} + + +////////////////////////// +// COutFileStream + +bool COutFileStream::Create(LPCTSTR fileName, bool createAlways) +{ + return File.Create(fileName, createAlways); +} + +#ifdef _WIN32 +#ifndef _UNICODE +bool COutFileStream::Create(LPCWSTR fileName, bool createAlways) +{ + return File.Create(fileName, createAlways); +} +#endif +#endif + +STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + #ifdef _WIN32 + + UInt32 realProcessedSize; + bool result = File.WritePart(data, size, realProcessedSize); + if(processedSize != NULL) + *processedSize = realProcessedSize; + return ConvertBoolToHRESULT(result); + + #else + + if(processedSize != NULL) + *processedSize = 0; + ssize_t res = File.Write(data, (size_t)size); + if (res == -1) + return E_FAIL; + if(processedSize != NULL) + *processedSize = (UInt32)res; + return S_OK; + + #endif +} + +STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, + UInt64 *newPosition) +{ + if(seekOrigin >= 3) + return STG_E_INVALIDFUNCTION; + #ifdef _WIN32 + + UInt64 realNewPosition; + bool result = File.Seek(offset, seekOrigin, realNewPosition); + if(newPosition != NULL) + *newPosition = realNewPosition; + return ConvertBoolToHRESULT(result); + + #else + + off_t res = File.Seek(offset, seekOrigin); + if (res == -1) + return E_FAIL; + if(newPosition != NULL) + *newPosition = (UInt64)res; + return S_OK; + + #endif +} + +STDMETHODIMP COutFileStream::SetSize(Int64 newSize) +{ + #ifdef _WIN32 + UInt64 currentPos; + if(!File.Seek(0, FILE_CURRENT, currentPos)) + return E_FAIL; + bool result = File.SetLength(newSize); + UInt64 currentPos2; + result = result && File.Seek(currentPos, currentPos2); + return result ? S_OK : E_FAIL; + #else + return E_FAIL; + #endif +} + +#ifndef _WIN32_WCE +STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if(processedSize != NULL) + *processedSize = 0; + + #ifdef _WIN32 + UInt32 realProcessedSize; + BOOL res = TRUE; + if (size > 0) + { + // Seems that Windows doesn't like big amounts writing to stdout. + // So we limit portions by 32KB. + UInt32 sizeTemp = (1 << 15); + if (sizeTemp > size) + sizeTemp = size; + res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), + data, sizeTemp, (DWORD *)&realProcessedSize, NULL); + size -= realProcessedSize; + data = (const void *)((const Byte *)data + realProcessedSize); + if(processedSize != NULL) + *processedSize += realProcessedSize; + } + return ConvertBoolToHRESULT(res != FALSE); + + #else + + ssize_t res; + do + { + res = write(1, data, (size_t)size); + } + while (res < 0 && (errno == EINTR)); + if (res == -1) + return E_FAIL; + if(processedSize != NULL) + *processedSize = (UInt32)res; + return S_OK; + + return S_OK; + #endif +} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/FileStreams.h b/app/win/installer/7zstub/src/7zip/Common/FileStreams.h new file mode 100644 index 0000000000..e6494f679b --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/FileStreams.h @@ -0,0 +1,98 @@ +// FileStreams.h + +#ifndef __FILESTREAMS_H +#define __FILESTREAMS_H + +#ifdef _WIN32 +#include "../../Windows/FileIO.h" +#else +#include "../../Common/C_FileIO.h" +#endif + +#include "../IStream.h" +#include "../../Common/MyCom.h" + +class CInFileStream: + public IInStream, + public IStreamGetSize, + public CMyUnknownImp +{ +public: + #ifdef _WIN32 + NWindows::NFile::NIO::CInFile File; + #else + NC::NFile::NIO::CInFile File; + #endif + CInFileStream() {} + virtual ~CInFileStream() {} + + bool Open(LPCTSTR fileName); + #ifdef _WIN32 + #ifndef _UNICODE + bool Open(LPCWSTR fileName); + #endif + #endif + + MY_UNKNOWN_IMP2(IInStream, IStreamGetSize) + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + + STDMETHOD(GetSize)(UInt64 *size); +}; + +#ifndef _WIN32_WCE +class CStdInFileStream: + public ISequentialInStream, + public CMyUnknownImp +{ +public: + // HANDLE File; + // CStdInFileStream() File(INVALID_HANDLE_VALUE): {} + // void Open() { File = GetStdHandle(STD_INPUT_HANDLE); }; + MY_UNKNOWN_IMP + + virtual ~CStdInFileStream() {} + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; +#endif + +class COutFileStream: + public IOutStream, + public CMyUnknownImp +{ +public: + #ifdef _WIN32 + NWindows::NFile::NIO::COutFile File; + #else + NC::NFile::NIO::COutFile File; + #endif + virtual ~COutFileStream() {} + bool Create(LPCTSTR fileName, bool createAlways); + #ifdef _WIN32 + #ifndef _UNICODE + bool Create(LPCWSTR fileName, bool createAlways); + #endif + #endif + + MY_UNKNOWN_IMP1(IOutStream) + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + STDMETHOD(SetSize)(Int64 newSize); +}; + +#ifndef _WIN32_WCE +class CStdOutFileStream: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + virtual ~CStdOutFileStream() {} + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; +#endif + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/InBuffer.cpp b/app/win/installer/7zstub/src/7zip/Common/InBuffer.cpp new file mode 100644 index 0000000000..17280b5b6c --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/InBuffer.cpp @@ -0,0 +1,80 @@ +// InBuffer.cpp + +#include "StdAfx.h" + +#include "InBuffer.h" + +#include "../../Common/Alloc.h" + +CInBuffer::CInBuffer(): + _buffer(0), + _bufferLimit(0), + _bufferBase(0), + _stream(0), + _bufferSize(0) +{} + +bool CInBuffer::Create(UInt32 bufferSize) +{ + const UInt32 kMinBlockSize = 1; + if (bufferSize < kMinBlockSize) + bufferSize = kMinBlockSize; + if (_bufferBase != 0 && _bufferSize == bufferSize) + return true; + Free(); + _bufferSize = bufferSize; + _bufferBase = (Byte *)::MidAlloc(bufferSize); + return (_bufferBase != 0); +} + +void CInBuffer::Free() +{ + ::MidFree(_bufferBase); + _bufferBase = 0; +} + +void CInBuffer::SetStream(ISequentialInStream *stream) +{ + _stream = stream; +} + +void CInBuffer::Init() +{ + _processedSize = 0; + _buffer = _bufferBase; + _bufferLimit = _buffer; + _wasFinished = false; + #ifdef _NO_EXCEPTIONS + ErrorCode = S_OK; + #endif +} + +bool CInBuffer::ReadBlock() +{ + #ifdef _NO_EXCEPTIONS + if (ErrorCode != S_OK) + return false; + #endif + if (_wasFinished) + return false; + _processedSize += (_buffer - _bufferBase); + UInt32 numProcessedBytes; + HRESULT result = _stream->Read(_bufferBase, _bufferSize, &numProcessedBytes); + #ifdef _NO_EXCEPTIONS + ErrorCode = result; + #else + if (result != S_OK) + throw CInBufferException(result); + #endif + _buffer = _bufferBase; + _bufferLimit = _buffer + numProcessedBytes; + _wasFinished = (numProcessedBytes == 0); + return (!_wasFinished); +} + +Byte CInBuffer::ReadBlock2() +{ + if(!ReadBlock()) + return 0xFF; + return *_buffer++; +} diff --git a/app/win/installer/7zstub/src/7zip/Common/InBuffer.h b/app/win/installer/7zstub/src/7zip/Common/InBuffer.h new file mode 100644 index 0000000000..a59ecefacd --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/InBuffer.h @@ -0,0 +1,76 @@ +// InBuffer.h + +#ifndef __INBUFFER_H +#define __INBUFFER_H + +#include "../IStream.h" +#include "../../Common/MyCom.h" + +#ifndef _NO_EXCEPTIONS +class CInBufferException +{ +public: + HRESULT ErrorCode; + CInBufferException(HRESULT errorCode): ErrorCode(errorCode) {} +}; +#endif + +class CInBuffer +{ + Byte *_buffer; + Byte *_bufferLimit; + Byte *_bufferBase; + CMyComPtr _stream; + UInt64 _processedSize; + UInt32 _bufferSize; + bool _wasFinished; + + bool ReadBlock(); + Byte ReadBlock2(); + +public: + #ifdef _NO_EXCEPTIONS + HRESULT ErrorCode; + #endif + + CInBuffer(); + ~CInBuffer() { Free(); } + + bool Create(UInt32 bufferSize); + void Free(); + + void SetStream(ISequentialInStream *stream); + void Init(); + void ReleaseStream() { _stream.Release(); } + + bool ReadByte(Byte &b) + { + if(_buffer >= _bufferLimit) + if(!ReadBlock()) + return false; + b = *_buffer++; + return true; + } + Byte ReadByte() + { + if(_buffer >= _bufferLimit) + return ReadBlock2(); + return *_buffer++; + } + void ReadBytes(void *data, UInt32 size, UInt32 &processedSize) + { + for(processedSize = 0; processedSize < size; processedSize++) + if (!ReadByte(((Byte *)data)[processedSize])) + return; + } + bool ReadBytes(void *data, UInt32 size) + { + UInt32 processedSize; + ReadBytes(data, size, processedSize); + return (processedSize == size); + } + UInt64 GetProcessedSize() const { return _processedSize + (_buffer - _bufferBase); } + bool WasFinished() const { return _wasFinished; } +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.cpp b/app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.cpp new file mode 100644 index 0000000000..06fde8ff33 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.cpp @@ -0,0 +1,122 @@ +// InOutTempBuffer.cpp + +#include "StdAfx.h" + +#include "InOutTempBuffer.h" +#include "../../Common/Defs.h" +// #include "Windows/Defs.h" + +#include "StreamUtils.h" + +using namespace NWindows; +using namespace NFile; +using namespace NDirectory; + +static UInt32 kTmpBufferMemorySize = (1 << 20); + +static LPCTSTR kTempFilePrefixString = TEXT("iot"); + +CInOutTempBuffer::CInOutTempBuffer(): + _buffer(NULL) +{ +} + +void CInOutTempBuffer::Create() +{ + _buffer = new Byte[kTmpBufferMemorySize]; +} + +CInOutTempBuffer::~CInOutTempBuffer() +{ + delete []_buffer; +} +void CInOutTempBuffer::InitWriting() +{ + _bufferPosition = 0; + _tmpFileCreated = false; + _fileSize = 0; +} + +bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size) +{ + if (size == 0) + return true; + if(!_tmpFileCreated) + { + CSysString tempDirPath; + if(!MyGetTempPath(tempDirPath)) + return false; + if (_tempFile.Create(tempDirPath, kTempFilePrefixString, _tmpFileName) == 0) + return false; + // _outFile.SetOpenCreationDispositionCreateAlways(); + if(!_outFile.Create(_tmpFileName, true)) + return false; + _tmpFileCreated = true; + } + UInt32 processedSize; + if(!_outFile.Write(data, size, processedSize)) + return false; + _fileSize += processedSize; + return (processedSize == size); +} + +bool CInOutTempBuffer::FlushWrite() +{ + return _outFile.Close(); +} + +bool CInOutTempBuffer::Write(const void *data, UInt32 size) +{ + if(_bufferPosition < kTmpBufferMemorySize) + { + UInt32 curSize = MyMin(kTmpBufferMemorySize - _bufferPosition, size); + memmove(_buffer + _bufferPosition, (const Byte *)data, curSize); + _bufferPosition += curSize; + size -= curSize; + data = ((const Byte *)data) + curSize; + _fileSize += curSize; + } + return WriteToFile(data, size); +} + +bool CInOutTempBuffer::InitReading() +{ + _currentPositionInBuffer = 0; + if(_tmpFileCreated) + return _inFile.Open(_tmpFileName); + return true; +} + +HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream) +{ + if (_currentPositionInBuffer < _bufferPosition) + { + UInt32 sizeToWrite = _bufferPosition - _currentPositionInBuffer; + RINOK(WriteStream(stream, _buffer + _currentPositionInBuffer, sizeToWrite, NULL)); + _currentPositionInBuffer += sizeToWrite; + } + if (!_tmpFileCreated) + return true; + while(true) + { + UInt32 localProcessedSize; + if (!_inFile.ReadPart(_buffer, kTmpBufferMemorySize, localProcessedSize)) + return E_FAIL; + if (localProcessedSize == 0) + return S_OK; + RINOK(WriteStream(stream, _buffer, localProcessedSize, NULL)); + } +} + +STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (!_buffer->Write(data, size)) + { + if (processedSize != NULL) + *processedSize = 0; + return E_FAIL; + } + if (processedSize != NULL) + *processedSize = size; + return S_OK; +} diff --git a/app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.h b/app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.h new file mode 100644 index 0000000000..17f3e8826a --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/InOutTempBuffer.h @@ -0,0 +1,55 @@ +// Util/InOutTempBuffer.h + +#ifndef __IN_OUT_TEMP_BUFFER_H +#define __IN_OUT_TEMP_BUFFER_H + +#include "../../Windows/FileIO.h" +#include "../../Windows/FileDir.h" +#include "../../Common/MyCom.h" + +#include "../IStream.h" + +class CInOutTempBuffer +{ + NWindows::NFile::NDirectory::CTempFile _tempFile; + NWindows::NFile::NIO::COutFile _outFile; + NWindows::NFile::NIO::CInFile _inFile; + Byte *_buffer; + UInt32 _bufferPosition; + UInt32 _currentPositionInBuffer; + CSysString _tmpFileName; + bool _tmpFileCreated; + + UInt64 _fileSize; + + bool WriteToFile(const void *data, UInt32 size); +public: + CInOutTempBuffer(); + ~CInOutTempBuffer(); + void Create(); + + void InitWriting(); + bool Write(const void *data, UInt32 size); + UInt64 GetDataSize() const { return _fileSize; } + bool FlushWrite(); + bool InitReading(); + HRESULT WriteToStream(ISequentialOutStream *stream); +}; + +class CSequentialOutTempBufferImp: + public ISequentialOutStream, + public CMyUnknownImp +{ + CInOutTempBuffer *_buffer; +public: + // CSequentialOutStreamImp(): _size(0) {} + // UInt32 _size; + void Init(CInOutTempBuffer *buffer) { _buffer = buffer; } + // UInt32 GetSize() const { return _size; } + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.cpp b/app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.cpp new file mode 100644 index 0000000000..ada5890be8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.cpp @@ -0,0 +1,34 @@ +// Stream/LSBFDecoder.cpp + +#include "StdAfx.h" + +#include "LSBFDecoder.h" + +namespace NStream { +namespace NLSBF { + +Byte kInvertTable[256]; + +class CInverterTableInitializer +{ +public: + CInverterTableInitializer() + { + for(int i = 0; i < 256; i++) + { + Byte b = Byte(i); + Byte bInvert = 0; + for(int j = 0; j < 8; j++) + { + bInvert <<= 1; + if (b & 1) + bInvert |= 1; + b >>= 1; + } + kInvertTable[i] = bInvert; + } + } +} g_InverterTableInitializer; + + +}} diff --git a/app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.h b/app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.h new file mode 100644 index 0000000000..6e506859c6 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LSBFDecoder.h @@ -0,0 +1,127 @@ +// LSBFDecoder.h + +#ifndef __STREAM_LSBFDECODER_H +#define __STREAM_LSBFDECODER_H + +#include "../IStream.h" + +namespace NStream { +namespace NLSBF { + +const int kNumBigValueBits = 8 * 4; + +const int kNumValueBytes = 3; +const int kNumValueBits = 8 * kNumValueBytes; + +const UInt32 kMask = (1 << kNumValueBits) - 1; + +extern Byte kInvertTable[256]; +// the Least Significant Bit of byte is First + +template +class CBaseDecoder +{ +protected: + int m_BitPos; + UInt32 m_Value; + TInByte m_Stream; +public: + UInt32 NumExtraBytes; + bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } + void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream); } + void ReleaseStream() { m_Stream.ReleaseStream(); } + void Init() + { + m_Stream.Init(); + m_BitPos = kNumBigValueBits; + m_Value = 0; + NumExtraBytes = 0; + } + UInt64 GetProcessedSize() const + { return m_Stream.GetProcessedSize() - (kNumBigValueBits - m_BitPos) / 8; } + UInt64 GetProcessedBitsSize() const + { return (m_Stream.GetProcessedSize() << 3) - (kNumBigValueBits - m_BitPos); } + int GetBitPosition() const { return (m_BitPos & 7); } + + void Normalize() + { + for (;m_BitPos >= 8; m_BitPos -= 8) + { + Byte b; + if (!m_Stream.ReadByte(b)) + { + b = 0xFF; // check it + NumExtraBytes++; + } + m_Value = (b << (kNumBigValueBits - m_BitPos)) | m_Value; + } + } + + UInt32 ReadBits(int numBits) + { + Normalize(); + UInt32 res = m_Value & ((1 << numBits) - 1); + m_BitPos += numBits; + m_Value >>= numBits; + return res; + } + + bool ExtraBitsWereRead() const + { + if (NumExtraBytes == 0) + return false; + return ((UInt32)(kNumBigValueBits - m_BitPos) < (NumExtraBytes << 3)); + } +}; + +template +class CDecoder: public CBaseDecoder +{ + UInt32 m_NormalValue; + +public: + void Init() + { + CBaseDecoder::Init(); + m_NormalValue = 0; + } + + void Normalize() + { + for (;this->m_BitPos >= 8; this->m_BitPos -= 8) + { + Byte b; + if (!this->m_Stream.ReadByte(b)) + { + b = 0xFF; // check it + this->NumExtraBytes++; + } + m_NormalValue = (b << (kNumBigValueBits - this->m_BitPos)) | m_NormalValue; + this->m_Value = (this->m_Value << 8) | kInvertTable[b]; + } + } + + UInt32 GetValue(int numBits) + { + Normalize(); + return ((this->m_Value >> (8 - this->m_BitPos)) & kMask) >> (kNumValueBits - numBits); + } + + void MovePos(int numBits) + { + this->m_BitPos += numBits; + m_NormalValue >>= numBits; + } + + UInt32 ReadBits(int numBits) + { + Normalize(); + UInt32 res = m_NormalValue & ( (1 << numBits) - 1); + MovePos(numBits); + return res; + } +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.cpp b/app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.cpp new file mode 100644 index 0000000000..a0ed300c6e --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.cpp @@ -0,0 +1,29 @@ +// LSBFEncoder.cpp + +#include "StdAfx.h" + +#include "LSBFEncoder.h" +#include "Common/Defs.h" + +namespace NStream { +namespace NLSBF { + +void CEncoder::WriteBits(UInt32 value, int numBits) +{ + while(numBits > 0) + { + if (numBits < m_BitPos) + { + m_CurByte |= (value & ((1 << numBits) - 1)) << (8 - m_BitPos); + m_BitPos -= numBits; + return; + } + numBits -= m_BitPos; + m_Stream.WriteByte((Byte)(m_CurByte | (value << (8 - m_BitPos)))); + value >>= m_BitPos; + m_BitPos = 8; + m_CurByte = 0; + } +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.h b/app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.h new file mode 100644 index 0000000000..1c50b8e766 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LSBFEncoder.h @@ -0,0 +1,51 @@ +// Stream/LSBFEncoder.h + +#ifndef __STREAM_LSBFENCODER_H +#define __STREAM_LSBFENCODER_H + +#include "../IStream.h" +#include "OutBuffer.h" + +namespace NStream { +namespace NLSBF { + +class CEncoder +{ + COutBuffer m_Stream; + int m_BitPos; + Byte m_CurByte; +public: + bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } + void SetStream(ISequentialOutStream *outStream) { m_Stream.SetStream(outStream); } + void ReleaseStream() { m_Stream.ReleaseStream(); } + void Init() + { + m_Stream.Init(); + m_BitPos = 8; + m_CurByte = 0; + } + HRESULT Flush() + { + FlushByte(); + return m_Stream.Flush(); + } + + void FlushByte() + { + if(m_BitPos < 8) + m_Stream.WriteByte(m_CurByte); + m_BitPos = 8; + m_CurByte = 0; + } + + void WriteBits(UInt32 value, int numBits); + UInt32 GetBitPosition() const { return (8 - m_BitPos); } + UInt64 GetProcessedSize() const { + return m_Stream.GetProcessedSize() + (8 - m_BitPos + 7) /8; } + void WriteByte(Byte b) { m_Stream.WriteByte(b);} +}; + + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/LimitedStreams.cpp b/app/win/installer/7zstub/src/7zip/Common/LimitedStreams.cpp new file mode 100644 index 0000000000..c210c9560d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LimitedStreams.cpp @@ -0,0 +1,24 @@ +// LimitedStreams.cpp + +#include "StdAfx.h" + +#include "LimitedStreams.h" +#include "../../Common/Defs.h" + +void CLimitedSequentialInStream::Init(ISequentialInStream *stream, UInt64 streamSize) +{ + _stream = stream; + _size = streamSize; +} + +STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 processedSizeReal; + UInt32 sizeToRead = UInt32(MyMin(_size, UInt64(size))); + HRESULT result = _stream->Read(data, sizeToRead, &processedSizeReal); + _size -= processedSizeReal; + if(processedSize != NULL) + *processedSize = processedSizeReal; + return result; +} + diff --git a/app/win/installer/7zstub/src/7zip/Common/LimitedStreams.h b/app/win/installer/7zstub/src/7zip/Common/LimitedStreams.h new file mode 100644 index 0000000000..7658b620d1 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LimitedStreams.h @@ -0,0 +1,23 @@ +// LimitedStreams.h + +#ifndef __LIMITEDSTREAMS_H +#define __LIMITEDSTREAMS_H + +#include "../../Common/MyCom.h" +#include "../IStream.h" + +class CLimitedSequentialInStream: + public ISequentialInStream, + public CMyUnknownImp +{ + UInt64 _size; + CMyComPtr _stream; +public: + void Init(ISequentialInStream *stream, UInt64 streamSize); + + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/LockedStream.cpp b/app/win/installer/7zstub/src/7zip/Common/LockedStream.cpp new file mode 100644 index 0000000000..637c8980cd --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LockedStream.cpp @@ -0,0 +1,23 @@ +// LockedStream.cpp + +#include "StdAfx.h" + +#include "LockedStream.h" + +HRESULT CLockedInStream::Read(UInt64 startPos, void *data, UInt32 size, + UInt32 *processedSize) +{ + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + RINOK(_stream->Seek(startPos, STREAM_SEEK_SET, NULL)); + return _stream->Read(data, size, processedSize); +} + +STDMETHODIMP CLockedSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize = 0; + HRESULT result = _lockedInStream->Read(_pos, data, size, &realProcessedSize); + _pos += realProcessedSize; + if (processedSize != NULL) + *processedSize = realProcessedSize; + return result; +} diff --git a/app/win/installer/7zstub/src/7zip/Common/LockedStream.h b/app/win/installer/7zstub/src/7zip/Common/LockedStream.h new file mode 100644 index 0000000000..d61f6a3723 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/LockedStream.h @@ -0,0 +1,38 @@ +// LockedStream.h + +#ifndef __LOCKEDSTREAM_H +#define __LOCKEDSTREAM_H + +#include "../../Windows/Synchronization.h" +#include "../../Common/MyCom.h" +#include "../IStream.h" + +class CLockedInStream +{ + CMyComPtr _stream; + NWindows::NSynchronization::CCriticalSection _criticalSection; +public: + void Init(IInStream *stream) + { _stream = stream; } + HRESULT Read(UInt64 startPos, void *data, UInt32 size, UInt32 *processedSize); +}; + +class CLockedSequentialInStreamImp: + public ISequentialInStream, + public CMyUnknownImp +{ + CLockedInStream *_lockedInStream; + UInt64 _pos; +public: + void Init(CLockedInStream *lockedInStream, UInt64 startPos) + { + _lockedInStream = lockedInStream; + _pos = startPos; + } + + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/MSBFDecoder.h b/app/win/installer/7zstub/src/7zip/Common/MSBFDecoder.h new file mode 100644 index 0000000000..dad00ecab6 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/MSBFDecoder.h @@ -0,0 +1,69 @@ +// MSBFDecoder.h +// the Most Significant Bit of byte is First + +#ifndef __STREAM_MSBFDECODER_H +#define __STREAM_MSBFDECODER_H + +#include "../../Common/Types.h" +#include "../IStream.h" + +namespace NStream { +namespace NMSBF { + +const int kNumBigValueBits = 8 * 4; +const int kNumValueBytes = 3; +const int kNumValueBits = 8 * kNumValueBytes; + +const UInt32 kMask = (1 << kNumValueBits) - 1; + +template +class CDecoder +{ + UInt32 m_BitPos; + UInt32 m_Value; +public: + TInByte m_Stream; + bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } + void SetStream(ISequentialInStream *inStream) { m_Stream.SetStream(inStream);} + void ReleaseStream() { m_Stream.ReleaseStream();} + + void Init() + { + m_Stream.Init(); + m_BitPos = kNumBigValueBits; + Normalize(); + } + + UInt64 GetProcessedSize() const + { return m_Stream.GetProcessedSize() - (kNumBigValueBits - m_BitPos) / 8; } + UInt32 GetBitPosition() const { return (m_BitPos & 7); } + + void Normalize() + { + for (;m_BitPos >= 8; m_BitPos -= 8) + m_Value = (m_Value << 8) | m_Stream.ReadByte(); + } + + UInt32 GetValue(UInt32 numBits) const + { + // return (m_Value << m_BitPos) >> (kNumBigValueBits - numBits); + return ((m_Value >> (8 - m_BitPos)) & kMask) >> (kNumValueBits - numBits); + } + + void MovePos(UInt32 numBits) + { + m_BitPos += numBits; + Normalize(); + } + + UInt32 ReadBits(UInt32 numBits) + { + UInt32 res = GetValue(numBits); + MovePos(numBits); + return res; + } +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/MSBFEncoder.h b/app/win/installer/7zstub/src/7zip/Common/MSBFEncoder.h new file mode 100644 index 0000000000..b141e55459 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/MSBFEncoder.h @@ -0,0 +1,59 @@ +// Stream/MSBFEncoder.h + +#ifndef __STREAM_MSBFENCODER_H +#define __STREAM_MSBFENCODER_H + +#include "Common/Defs.h" +#include "../IStream.h" +#include "OutBuffer.h" + +namespace NStream { +namespace NMSBF { + +template +class CEncoder +{ + TOutByte m_Stream; + int m_BitPos; + Byte m_CurByte; +public: + bool Create(UInt32 bufferSize) { return m_Stream.Create(bufferSize); } + void SetStream(ISequentialOutStream *outStream) { m_Stream.SetStream(outStream);} + void ReleaseStream() { m_Stream.ReleaseStream(); } + void Init() + { + m_Stream.Init(); + m_BitPos = 8; + m_CurByte = 0; + } + HRESULT Flush() + { + if(m_BitPos < 8) + WriteBits(0, m_BitPos); + return m_Stream.Flush(); + } + + void WriteBits(UInt32 value, int numBits) + { + while(numBits > 0) + { + if (numBits < m_BitPos) + { + m_CurByte |= ((Byte)value << (m_BitPos -= numBits)); + return; + } + numBits -= m_BitPos; + UInt32 newBits = (value >> numBits); + value -= (newBits << numBits); + m_Stream.WriteByte(m_CurByte | (Byte)newBits); + m_BitPos = 8; + m_CurByte = 0; + } + } + UInt64 GetProcessedSize() const { + return m_Stream.GetProcessedSize() + (8 - m_BitPos + 7) / 8; } +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/OffsetStream.cpp b/app/win/installer/7zstub/src/7zip/Common/OffsetStream.cpp new file mode 100644 index 0000000000..177401f383 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/OffsetStream.cpp @@ -0,0 +1,35 @@ +// OffsetStream.cpp + +#include "StdAfx.h" + +#include "Common/Defs.h" +#include "OffsetStream.h" + +HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset) +{ + _offset = offset; + _stream = stream; + return _stream->Seek(offset, STREAM_SEEK_SET, NULL); +} + +STDMETHODIMP COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + return _stream->Write(data, size, processedSize); +} + +STDMETHODIMP COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, + UInt64 *newPosition) +{ + UInt64 absoluteNewPosition; + if (seekOrigin == STREAM_SEEK_SET) + offset += _offset; + HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition); + if (newPosition != NULL) + *newPosition = absoluteNewPosition - _offset; + return result; +} + +STDMETHODIMP COffsetOutStream::SetSize(Int64 newSize) +{ + return _stream->SetSize(_offset + newSize); +} diff --git a/app/win/installer/7zstub/src/7zip/Common/OffsetStream.h b/app/win/installer/7zstub/src/7zip/Common/OffsetStream.h new file mode 100644 index 0000000000..6eaa25928e --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/OffsetStream.h @@ -0,0 +1,25 @@ +// OffsetStream.h + +#ifndef __OFFSETSTREAM_H +#define __OFFSETSTREAM_H + +#include "Common/MyCom.h" +#include "../IStream.h" + +class COffsetOutStream: + public IOutStream, + public CMyUnknownImp +{ + UInt64 _offset; + CMyComPtr _stream; +public: + HRESULT Init(IOutStream *stream, UInt64 offset); + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition); + STDMETHOD(SetSize)(Int64 newSize); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/OutBuffer.cpp b/app/win/installer/7zstub/src/7zip/Common/OutBuffer.cpp new file mode 100644 index 0000000000..45da6d7f00 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/OutBuffer.cpp @@ -0,0 +1,116 @@ +// OutByte.cpp + +#include "StdAfx.h" + +#include "OutBuffer.h" + +#include "../../Common/Alloc.h" + +bool COutBuffer::Create(UInt32 bufferSize) +{ + const UInt32 kMinBlockSize = 1; + if (bufferSize < kMinBlockSize) + bufferSize = kMinBlockSize; + if (_buffer != 0 && _bufferSize == bufferSize) + return true; + Free(); + _bufferSize = bufferSize; + _buffer = (Byte *)::MidAlloc(bufferSize); + return (_buffer != 0); +} + +void COutBuffer::Free() +{ + ::MidFree(_buffer); + _buffer = 0; +} + +void COutBuffer::SetStream(ISequentialOutStream *stream) +{ + _stream = stream; +} + +void COutBuffer::Init() +{ + _streamPos = 0; + _limitPos = _bufferSize; + _pos = 0; + _processedSize = 0; + _overDict = false; + #ifdef _NO_EXCEPTIONS + ErrorCode = S_OK; + #endif +} + +UInt64 COutBuffer::GetProcessedSize() const +{ + UInt64 res = _processedSize + _pos - _streamPos; + if (_streamPos > _pos) + res += _bufferSize; + return res; +} + + +HRESULT COutBuffer::FlushPart() +{ + // _streamPos < _bufferSize + UInt32 size = (_streamPos >= _pos) ? (_bufferSize - _streamPos) : (_pos - _streamPos); + HRESULT result = S_OK; + #ifdef _NO_EXCEPTIONS + result = ErrorCode; + #endif + if (_buffer2 != 0) + { + memmove(_buffer2, _buffer + _streamPos, size); + _buffer2 += size; + } + + if (_stream != 0 + #ifdef _NO_EXCEPTIONS + && (ErrorCode == S_OK) + #endif + ) + { + UInt32 processedSize = 0; + result = _stream->Write(_buffer + _streamPos, size, &processedSize); + size = processedSize; + } + _streamPos += size; + if (_streamPos == _bufferSize) + _streamPos = 0; + if (_pos == _bufferSize) + { + _overDict = true; + _pos = 0; + } + _limitPos = (_streamPos > _pos) ? _streamPos : _bufferSize; + _processedSize += size; + return result; +} + +HRESULT COutBuffer::Flush() +{ + #ifdef _NO_EXCEPTIONS + if (ErrorCode != S_OK) + return ErrorCode; + #endif + + while(_streamPos != _pos) + { + HRESULT result = FlushPart(); + if (result != S_OK) + return result; + } + return S_OK; +} + +void COutBuffer::FlushWithCheck() +{ + HRESULT result = FlushPart(); + #ifdef _NO_EXCEPTIONS + ErrorCode = result; + #else + if (result != S_OK) + throw COutBufferException(result); + #endif +} diff --git a/app/win/installer/7zstub/src/7zip/Common/OutBuffer.h b/app/win/installer/7zstub/src/7zip/Common/OutBuffer.h new file mode 100644 index 0000000000..37eefbdfcd --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/OutBuffer.h @@ -0,0 +1,64 @@ +// OutBuffer.h + +#ifndef __OUTBUFFER_H +#define __OUTBUFFER_H + +#include "../IStream.h" +#include "../../Common/MyCom.h" + +#ifndef _NO_EXCEPTIONS +struct COutBufferException +{ + HRESULT ErrorCode; + COutBufferException(HRESULT errorCode): ErrorCode(errorCode) {} +}; +#endif + +class COutBuffer +{ +protected: + Byte *_buffer; + UInt32 _pos; + UInt32 _limitPos; + UInt32 _streamPos; + UInt32 _bufferSize; + CMyComPtr _stream; + UInt64 _processedSize; + Byte *_buffer2; + bool _overDict; + + HRESULT FlushPart(); + void FlushWithCheck(); +public: + #ifdef _NO_EXCEPTIONS + HRESULT ErrorCode; + #endif + + COutBuffer(): _buffer(0), _pos(0), _stream(0), _buffer2(0) {} + ~COutBuffer() { Free(); } + + bool Create(UInt32 bufferSize); + void Free(); + + void SetMemStream(Byte *buffer) { _buffer2 = buffer; } + void SetStream(ISequentialOutStream *stream); + void Init(); + HRESULT Flush(); + void ReleaseStream() { _stream.Release(); } + + void WriteByte(Byte b) + { + _buffer[_pos++] = b; + if(_pos == _limitPos) + FlushWithCheck(); + } + void WriteBytes(const void *data, size_t size) + { + for (size_t i = 0; i < size; i++) + WriteByte(((const Byte *)data)[i]); + } + + UInt64 GetProcessedSize() const; +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/ProgressUtils.cpp b/app/win/installer/7zstub/src/7zip/Common/ProgressUtils.cpp new file mode 100644 index 0000000000..ac598cd545 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/ProgressUtils.cpp @@ -0,0 +1,58 @@ +// ProgressUtils.h + +#include "StdAfx.h" + +#include "ProgressUtils.h" + +void CLocalCompressProgressInfo::Init(ICompressProgressInfo *progress, + const UInt64 *inStartValue, const UInt64 *outStartValue) +{ + _progress = progress; + _inStartValueIsAssigned = (inStartValue != NULL); + if (_inStartValueIsAssigned) + _inStartValue = *inStartValue; + _outStartValueIsAssigned = (outStartValue != NULL); + if (_outStartValueIsAssigned) + _outStartValue = *outStartValue; +} + +STDMETHODIMP CLocalCompressProgressInfo::SetRatioInfo( + const UInt64 *inSize, const UInt64 *outSize) +{ + UInt64 inSizeNew, outSizeNew; + const UInt64 *inSizeNewPointer; + const UInt64 *outSizeNewPointer; + if (_inStartValueIsAssigned && inSize != NULL) + { + inSizeNew = _inStartValue + (*inSize); + inSizeNewPointer = &inSizeNew; + } + else + inSizeNewPointer = NULL; + + if (_outStartValueIsAssigned && outSize != NULL) + { + outSizeNew = _outStartValue + (*outSize); + outSizeNewPointer = &outSizeNew; + } + else + outSizeNewPointer = NULL; + return _progress->SetRatioInfo(inSizeNewPointer, outSizeNewPointer); +} + + +/////////////////////////////////// +// + +void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain) +{ + _progress = progress; + _inSizeIsMain = inSizeIsMain; +} + +STDMETHODIMP CLocalProgress::SetRatioInfo( + const UInt64 *inSize, const UInt64 *outSize) +{ + return _progress->SetCompleted(_inSizeIsMain ? inSize : outSize); +} + diff --git a/app/win/installer/7zstub/src/7zip/Common/ProgressUtils.h b/app/win/installer/7zstub/src/7zip/Common/ProgressUtils.h new file mode 100644 index 0000000000..92e628528d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/ProgressUtils.h @@ -0,0 +1,43 @@ +// ProgressUtils.h + +#ifndef __PROGRESSUTILS_H +#define __PROGRESSUTILS_H + +#include "../../Common/MyCom.h" + +#include "../ICoder.h" +#include "../IProgress.h" + +class CLocalCompressProgressInfo: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr _progress; + bool _inStartValueIsAssigned; + bool _outStartValueIsAssigned; + UInt64 _inStartValue; + UInt64 _outStartValue; +public: + void Init(ICompressProgressInfo *progress, + const UInt64 *inStartValue, const UInt64 *outStartValue); + + MY_UNKNOWN_IMP + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +class CLocalProgress: + public ICompressProgressInfo, + public CMyUnknownImp +{ + CMyComPtr _progress; + bool _inSizeIsMain; +public: + void Init(IProgress *progress, bool inSizeIsMain); + + MY_UNKNOWN_IMP + + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/StdAfx.h b/app/win/installer/7zstub/src/7zip/Common/StdAfx.h new file mode 100644 index 0000000000..d7d9211b09 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/StdAfx.h @@ -0,0 +1,9 @@ +// StdAfx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#include "../../Common/MyWindows.h" +#include "../../Common/NewHandler.h" + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/StreamBinder.cpp b/app/win/installer/7zstub/src/7zip/Common/StreamBinder.cpp new file mode 100644 index 0000000000..dc11de8e5a --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/StreamBinder.cpp @@ -0,0 +1,162 @@ +// StreamBinder.cpp + +#include "StdAfx.h" + +#include "StreamBinder.h" +#include "../../Common/Defs.h" +#include "../../Common/MyCom.h" + +using namespace NWindows; +using namespace NSynchronization; + +class CSequentialInStreamForBinder: + public ISequentialInStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +private: + CStreamBinder *m_StreamBinder; +public: + ~CSequentialInStreamForBinder() { m_StreamBinder->CloseRead(); } + void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; } +}; + +STDMETHODIMP CSequentialInStreamForBinder::Read(void *data, UInt32 size, UInt32 *processedSize) + { return m_StreamBinder->Read(data, size, processedSize); } + +class CSequentialOutStreamForBinder: + public ISequentialOutStream, + public CMyUnknownImp +{ +public: + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); + +private: + CStreamBinder *m_StreamBinder; +public: + ~CSequentialOutStreamForBinder() { m_StreamBinder->CloseWrite(); } + void SetBinder(CStreamBinder *streamBinder) { m_StreamBinder = streamBinder; } +}; + +STDMETHODIMP CSequentialOutStreamForBinder::Write(const void *data, UInt32 size, UInt32 *processedSize) + { return m_StreamBinder->Write(data, size, processedSize); } + + +////////////////////////// +// CStreamBinder +// (_thereAreBytesToReadEvent && _bufferSize == 0) means that stream is finished. + +void CStreamBinder::CreateEvents() +{ + _allBytesAreWritenEvent = new CManualResetEvent(true); + _thereAreBytesToReadEvent = new CManualResetEvent(false); + _readStreamIsClosedEvent = new CManualResetEvent(false); +} + +void CStreamBinder::ReInit() +{ + _thereAreBytesToReadEvent->Reset(); + _readStreamIsClosedEvent->Reset(); + ProcessedSize = 0; +} + +CStreamBinder::~CStreamBinder() +{ + if (_allBytesAreWritenEvent != NULL) + delete _allBytesAreWritenEvent; + if (_thereAreBytesToReadEvent != NULL) + delete _thereAreBytesToReadEvent; + if (_readStreamIsClosedEvent != NULL) + delete _readStreamIsClosedEvent; +} + + + + +void CStreamBinder::CreateStreams(ISequentialInStream **inStream, + ISequentialOutStream **outStream) +{ + CSequentialInStreamForBinder *inStreamSpec = new + CSequentialInStreamForBinder; + CMyComPtr inStreamLoc(inStreamSpec); + inStreamSpec->SetBinder(this); + *inStream = inStreamLoc.Detach(); + + CSequentialOutStreamForBinder *outStreamSpec = new + CSequentialOutStreamForBinder; + CMyComPtr outStreamLoc(outStreamSpec); + outStreamSpec->SetBinder(this); + *outStream = outStreamLoc.Detach(); + + _buffer = NULL; + _bufferSize= 0; + ProcessedSize = 0; +} + +HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 sizeToRead = size; + if (size > 0) + { + if(!_thereAreBytesToReadEvent->Lock()) + return E_FAIL; + sizeToRead = MyMin(_bufferSize, size); + if (_bufferSize > 0) + { + MoveMemory(data, _buffer, sizeToRead); + _buffer = ((const Byte *)_buffer) + sizeToRead; + _bufferSize -= sizeToRead; + if (_bufferSize == 0) + { + _thereAreBytesToReadEvent->Reset(); + _allBytesAreWritenEvent->Set(); + } + } + } + if (processedSize != NULL) + *processedSize = sizeToRead; + ProcessedSize += sizeToRead; + return S_OK; +} + +void CStreamBinder::CloseRead() +{ + _readStreamIsClosedEvent->Set(); +} + +HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + if (size > 0) + { + _buffer = data; + _bufferSize = size; + _allBytesAreWritenEvent->Reset(); + _thereAreBytesToReadEvent->Set(); + + HANDLE events[2]; + events[0] = *_allBytesAreWritenEvent; + events[1] = *_readStreamIsClosedEvent; + DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE); + if (waitResult != WAIT_OBJECT_0 + 0) + { + // ReadingWasClosed = true; + return E_FAIL; + } + // if(!_allBytesAreWritenEvent.Lock()) + // return E_FAIL; + } + if (processedSize != NULL) + *processedSize = size; + return S_OK; +} + +void CStreamBinder::CloseWrite() +{ + // _bufferSize must be = 0 + _thereAreBytesToReadEvent->Set(); +} diff --git a/app/win/installer/7zstub/src/7zip/Common/StreamBinder.h b/app/win/installer/7zstub/src/7zip/Common/StreamBinder.h new file mode 100644 index 0000000000..7899f0ff04 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/StreamBinder.h @@ -0,0 +1,37 @@ +// StreamBinder.h + +#ifndef __STREAMBINDER_H +#define __STREAMBINDER_H + +#include "../IStream.h" +#include "../../Windows/Synchronization.h" + +class CStreamBinder +{ + NWindows::NSynchronization::CManualResetEvent *_allBytesAreWritenEvent; + NWindows::NSynchronization::CManualResetEvent *_thereAreBytesToReadEvent; + NWindows::NSynchronization::CManualResetEvent *_readStreamIsClosedEvent; + UInt32 _bufferSize; + const void *_buffer; +public: + // bool ReadingWasClosed; + UInt64 ProcessedSize; + CStreamBinder(): + _allBytesAreWritenEvent(NULL), + _thereAreBytesToReadEvent(NULL), + _readStreamIsClosedEvent(NULL) + {} + ~CStreamBinder(); + void CreateEvents(); + + void CreateStreams(ISequentialInStream **inStream, + ISequentialOutStream **outStream); + HRESULT Read(void *data, UInt32 size, UInt32 *processedSize); + void CloseRead(); + + HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize); + void CloseWrite(); + void ReInit(); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/StreamObjects.cpp b/app/win/installer/7zstub/src/7zip/Common/StreamObjects.cpp new file mode 100644 index 0000000000..459df66cf8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/StreamObjects.cpp @@ -0,0 +1,102 @@ +// StreamObjects.cpp + +#include "StdAfx.h" + +#include "StreamObjects.h" +#include "../../Common/Defs.h" + + +STDMETHODIMP CSequentialInStreamImp::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 numBytesToRead = (UInt32)(MyMin(_pos + size, _size) - _pos); + memmove(data, _dataPointer + _pos, numBytesToRead); + _pos += numBytesToRead; + if(processedSize != NULL) + *processedSize = numBytesToRead; + return S_OK; +} + + +void CWriteBuffer::Write(const void *data, size_t size) +{ + size_t newCapacity = _size + size; + _buffer.EnsureCapacity(newCapacity); + memmove(_buffer + _size, data, size); + _size += size; +} + +STDMETHODIMP CSequentialOutStreamImp::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + _writeBuffer.Write(data, size); + if(processedSize != NULL) + *processedSize = size; + return S_OK; +} + +STDMETHODIMP CSequentialOutStreamImp2::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 newSize = size; + if (_pos + size > _size) + newSize = (UInt32)(_size - _pos); + memmove(_buffer + _pos, data, newSize); + if(processedSize != NULL) + *processedSize = newSize; + _pos += newSize; + if (newSize != size) + return E_FAIL; + return S_OK; +} + +STDMETHODIMP CSequentialInStreamSizeCount::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result = _stream->Read(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize != 0) + *processedSize = realProcessedSize; + return result; +} + +STDMETHODIMP CSequentialInStreamRollback::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + if (_currentPos != _currentSize) + { + size_t curSize = _currentSize - _currentPos; + if (size > curSize) + size = (UInt32)curSize; + memmove(data, _buffer + _currentPos, size); + _currentPos += size; + if (processedSize != 0) + *processedSize = size; + return S_OK; + } + UInt32 realProcessedSize; + if (size > _bufferSize) + size = (UInt32)_bufferSize; + HRESULT result = _stream->Read(_buffer, size, &realProcessedSize); + memmove(data, _buffer, realProcessedSize); + _size += realProcessedSize; + _currentSize = realProcessedSize; + _currentPos = realProcessedSize; + if (processedSize != 0) + *processedSize = realProcessedSize; + return result; +} + +HRESULT CSequentialInStreamRollback::Rollback(size_t rollbackSize) +{ + if (rollbackSize > _currentPos) + return E_INVALIDARG; + _currentPos -= rollbackSize; + return S_OK; +} + +STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize) +{ + UInt32 realProcessedSize; + HRESULT result = _stream->Write(data, size, &realProcessedSize); + _size += realProcessedSize; + if (processedSize != 0) + *processedSize = realProcessedSize; + return result; +} diff --git a/app/win/installer/7zstub/src/7zip/Common/StreamObjects.h b/app/win/installer/7zstub/src/7zip/Common/StreamObjects.h new file mode 100644 index 0000000000..b028a2114c --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/StreamObjects.h @@ -0,0 +1,156 @@ +// StreamObjects.h + +#ifndef __STREAMOBJECTS_H +#define __STREAMOBJECTS_H + +#include "../../Common/DynamicBuffer.h" +#include "../../Common/MyCom.h" +#include "../IStream.h" + +class CSequentialInStreamImp: + public ISequentialInStream, + public CMyUnknownImp +{ + const Byte *_dataPointer; + size_t _size; + size_t _pos; + +public: + void Init(const Byte *dataPointer, size_t size) + { + _dataPointer = dataPointer; + _size = size; + _pos = 0; + } + + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + + +class CWriteBuffer +{ + CByteDynamicBuffer _buffer; + size_t _size; +public: + CWriteBuffer(): _size(0) {} + void Init() { _size = 0; } + void Write(const void *data, size_t size); + size_t GetSize() const { return _size; } + const CByteDynamicBuffer& GetBuffer() const { return _buffer; } +}; + +class CSequentialOutStreamImp: + public ISequentialOutStream, + public CMyUnknownImp +{ + CWriteBuffer _writeBuffer; +public: + void Init() { _writeBuffer.Init(); } + size_t GetSize() const { return _writeBuffer.GetSize(); } + const CByteDynamicBuffer& GetBuffer() const { return _writeBuffer.GetBuffer(); } + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +class CSequentialOutStreamImp2: + public ISequentialOutStream, + public CMyUnknownImp +{ + Byte *_buffer; +public: + size_t _size; + size_t _pos; + + void Init(Byte *buffer, size_t size) + { + _buffer = buffer; + _pos = 0; + _size = size; + } + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +class CSequentialInStreamSizeCount: + public ISequentialInStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt64 _size; +public: + void Init(ISequentialInStream *stream) + { + _stream = stream; + _size = 0; + } + UInt64 GetSize() const { return _size; } + + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); +}; + +class CSequentialInStreamRollback: + public ISequentialInStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + Byte *_buffer; + size_t _bufferSize; + UInt64 _size; + + size_t _currentSize; + size_t _currentPos; +public: + CSequentialInStreamRollback(size_t bufferSize): + _bufferSize(bufferSize), + _buffer(0) + { + _buffer = new Byte[bufferSize]; + } + ~CSequentialInStreamRollback() + { + delete _buffer; + } + + void Init(ISequentialInStream *stream) + { + _stream = stream; + _size = 0; + _currentSize = 0; + _currentPos = 0; + } + UInt64 GetSize() const { return _size; } + + MY_UNKNOWN_IMP + + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + HRESULT Rollback(size_t rollbackSize); +}; + +class CSequentialOutStreamSizeCount: + public ISequentialOutStream, + public CMyUnknownImp +{ + CMyComPtr _stream; + UInt64 _size; +public: + void Init(ISequentialOutStream *stream) + { + _stream = stream; + _size = 0; + } + UInt64 GetSize() const { return _size; } + + MY_UNKNOWN_IMP + + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Common/StreamUtils.cpp b/app/win/installer/7zstub/src/7zip/Common/StreamUtils.cpp new file mode 100644 index 0000000000..712a78585a --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/StreamUtils.cpp @@ -0,0 +1,44 @@ +// StreamUtils.cpp + +#include "StdAfx.h" + +#include "../../Common/MyCom.h" +#include "StreamUtils.h" + +HRESULT ReadStream(ISequentialInStream *stream, void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize != 0) + *processedSize = 0; + while(size != 0) + { + UInt32 processedSizeLoc; + HRESULT res = stream->Read(data, size, &processedSizeLoc); + if (processedSize != 0) + *processedSize += processedSizeLoc; + data = (Byte *)((Byte *)data + processedSizeLoc); + size -= processedSizeLoc; + RINOK(res); + if (processedSizeLoc == 0) + return S_OK; + } + return S_OK; +} + +HRESULT WriteStream(ISequentialOutStream *stream, const void *data, UInt32 size, UInt32 *processedSize) +{ + if (processedSize != 0) + *processedSize = 0; + while(size != 0) + { + UInt32 processedSizeLoc; + HRESULT res = stream->Write(data, size, &processedSizeLoc); + if (processedSize != 0) + *processedSize += processedSizeLoc; + data = (const void *)((const Byte *)data + processedSizeLoc); + size -= processedSizeLoc; + RINOK(res); + if (processedSizeLoc == 0) + break; + } + return S_OK; +} diff --git a/app/win/installer/7zstub/src/7zip/Common/StreamUtils.h b/app/win/installer/7zstub/src/7zip/Common/StreamUtils.h new file mode 100644 index 0000000000..c8cd8cef1a --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/StreamUtils.h @@ -0,0 +1,11 @@ +// StreamUtils.h + +#ifndef __STREAMUTILS_H +#define __STREAMUTILS_H + +#include "../IStream.h" + +HRESULT ReadStream(ISequentialInStream *stream, void *data, UInt32 size, UInt32 *processedSize); +HRESULT WriteStream(ISequentialOutStream *stream, const void *data, UInt32 size, UInt32 *processedSize); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.cpp b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.cpp new file mode 100644 index 0000000000..68e938bde9 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.cpp @@ -0,0 +1,18 @@ +// BranchCoder.cpp + +#include "StdAfx.h" +#include "BranchCoder.h" + +STDMETHODIMP CBranchConverter::Init() +{ + _bufferPos = 0; + SubInit(); + return S_OK; +} + +STDMETHODIMP_(UInt32) CBranchConverter::Filter(Byte *data, UInt32 size) +{ + UInt32 processedSize = SubFilter(data, size); + _bufferPos += processedSize; + return processedSize; +} diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.h b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.h new file mode 100644 index 0000000000..b64562dfc3 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchCoder.h @@ -0,0 +1,54 @@ +// BranchCoder.h + +#ifndef __BRANCH_CODER_H +#define __BRANCH_CODER_H + +#include "Common/MyCom.h" +#include "Common/Types.h" +#include "Common/Alloc.h" + +#include "../../ICoder.h" + +class CBranchConverter: + public ICompressFilter, + public CMyUnknownImp +{ +protected: + UInt32 _bufferPos; + virtual void SubInit() {} + virtual UInt32 SubFilter(Byte *data, UInt32 size) = 0; +public: + MY_UNKNOWN_IMP; + STDMETHOD(Init)(); + STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size); +}; + +#define MyClassEncoderA(Name) class C ## Name: public CBranchConverter \ + { public: UInt32 SubFilter(Byte *data, UInt32 size); }; + +#define MyClassDecoderA(Name) class C ## Name: public CBranchConverter \ + { public: UInt32 SubFilter(Byte *data, UInt32 size); }; + +#define MyClassEncoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \ + { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; + +#define MyClassDecoderB(Name, ADD_ITEMS, ADD_INIT) class C ## Name: public CBranchConverter, public ADD_ITEMS \ + { public: UInt32 SubFilter(Byte *data, UInt32 size); ADD_INIT}; + +#define MyClass2b(Name, id, subId, encodingId) \ +DEFINE_GUID(CLSID_CCompressConvert ## Name, \ +0x23170F69, 0x40C1, 0x278B, 0x03, 0x03, id, subId, 0x00, 0x00, encodingId, 0x00); + +#define MyClassA(Name, id, subId) \ +MyClass2b(Name ## _Encoder, id, subId, 0x01) \ +MyClassEncoderA(Name ## _Encoder) \ +MyClass2b(Name ## _Decoder, id, subId, 0x00) \ +MyClassDecoderA(Name ## _Decoder) + +#define MyClassB(Name, id, subId, ADD_ITEMS, ADD_INIT) \ +MyClass2b(Name ## _Encoder, id, subId, 0x01) \ +MyClassEncoderB(Name ## _Encoder, ADD_ITEMS, ADD_INIT) \ +MyClass2b(Name ## _Decoder, id, subId, 0x00) \ +MyClassDecoderB(Name ## _Decoder, ADD_ITEMS, ADD_INIT) + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchTypes.h b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchTypes.h new file mode 100644 index 0000000000..7300875625 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchTypes.h @@ -0,0 +1,15 @@ +/* BranchTypes.h */ + +#ifndef __BRANCHTYPES_H +#define __BRANCHTYPES_H + +typedef unsigned char Byte; +typedef unsigned short UInt16; + +#ifdef _LZMA_UINT32_IS_ULONG +typedef unsigned long UInt32; +#else +typedef unsigned int UInt32; +#endif + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.c b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.c new file mode 100644 index 0000000000..2d2c03d2d8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.c @@ -0,0 +1,101 @@ +/* BranchX86.c */ + +#include "BranchX86.h" + +/* +static int inline Test86MSByte(Byte b) +{ + return (b == 0 || b == 0xFF); +} +*/ +#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF) + +const int kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0}; +const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3}; + +/* +void x86_Convert_Init(UInt32 *prevMask, UInt32 *prevPos) +{ + *prevMask = 0; + *prevPos = (UInt32)(-5); +} +*/ + +UInt32 x86_Convert(Byte *buffer, UInt32 endPos, UInt32 nowPos, + UInt32 *prevMask, UInt32 *prevPos, int encoding) +{ + UInt32 bufferPos = 0; + UInt32 limit; + + if (endPos < 5) + return 0; + + if (nowPos - *prevPos > 5) + *prevPos = nowPos - 5; + + limit = endPos - 5; + while(bufferPos <= limit) + { + Byte b = buffer[bufferPos]; + UInt32 offset; + if (b != 0xE8 && b != 0xE9) + { + bufferPos++; + continue; + } + offset = (nowPos + bufferPos - *prevPos); + *prevPos = (nowPos + bufferPos); + if (offset > 5) + *prevMask = 0; + else + { + UInt32 i; + for (i = 0; i < offset; i++) + { + *prevMask &= 0x77; + *prevMask <<= 1; + } + } + b = buffer[bufferPos + 4]; + if (Test86MSByte(b) && kMaskToAllowedStatus[(*prevMask >> 1) & 0x7] && + (*prevMask >> 1) < 0x10) + { + UInt32 src = + ((UInt32)(b) << 24) | + ((UInt32)(buffer[bufferPos + 3]) << 16) | + ((UInt32)(buffer[bufferPos + 2]) << 8) | + (buffer[bufferPos + 1]); + + UInt32 dest; + while(1) + { + UInt32 index; + if (encoding) + dest = (nowPos + bufferPos + 5) + src; + else + dest = src - (nowPos + bufferPos + 5); + if (*prevMask == 0) + break; + index = kMaskToBitNumber[*prevMask >> 1]; + b = (Byte)(dest >> (24 - index * 8)); + if (!Test86MSByte(b)) + break; + src = dest ^ ((1 << (32 - index * 8)) - 1); + } + buffer[bufferPos + 4] = (Byte)(~(((dest >> 24) & 1) - 1)); + buffer[bufferPos + 3] = (Byte)(dest >> 16); + buffer[bufferPos + 2] = (Byte)(dest >> 8); + buffer[bufferPos + 1] = (Byte)dest; + bufferPos += 5; + *prevMask = 0; + } + else + { + bufferPos++; + *prevMask |= 1; + if (Test86MSByte(b)) + *prevMask |= 0x10; + } + } + return bufferPos; +} diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.h b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.h new file mode 100644 index 0000000000..ff9c71cbe8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/BranchX86.h @@ -0,0 +1,13 @@ +/* BranchX86.h */ + +#ifndef __BRANCHX86_H +#define __BRANCHX86_H + +#include "BranchTypes.h" + +#define x86_Convert_Init(prevMask, prevPos) { prevMask = 0; prevPos = (UInt32)(-5); } + +UInt32 x86_Convert(Byte *buffer, UInt32 endPos, UInt32 nowPos, + UInt32 *prevMask, UInt32 *prevPos, int encoding); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/x86.cpp b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86.cpp new file mode 100644 index 0000000000..929484ad6d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86.cpp @@ -0,0 +1,18 @@ +// x86.cpp + +#include "StdAfx.h" +#include "x86.h" + +#include "Windows/Defs.h" + +#include "BranchX86.c" + +UInt32 CBCJ_x86_Encoder::SubFilter(Byte *data, UInt32 size) +{ + return ::x86_Convert(data, size, _bufferPos, &_prevMask, &_prevPos, 1); +} + +UInt32 CBCJ_x86_Decoder::SubFilter(Byte *data, UInt32 size) +{ + return ::x86_Convert(data, size, _bufferPos, &_prevMask, &_prevPos, 0); +} diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/x86.h b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86.h new file mode 100644 index 0000000000..85882d9149 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86.h @@ -0,0 +1,19 @@ +// x86.h + +#ifndef __X86_H +#define __X86_H + +#include "BranchCoder.h" +#include "BranchX86.h" + +struct CBranch86 +{ + UInt32 _prevMask; + UInt32 _prevPos; + void x86Init() { x86_Convert_Init(_prevMask, _prevPos); } +}; + +MyClassB(BCJ_x86, 0x01, 3, CBranch86 , + virtual void SubInit() { x86Init(); }) + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.cpp b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.cpp new file mode 100644 index 0000000000..fc87bd937d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.cpp @@ -0,0 +1,412 @@ +// x86_2.cpp + +#include "StdAfx.h" +#include "x86_2.h" + +#include "../../../Common/Alloc.h" + +static const int kBufferSize = 1 << 17; + +inline bool IsJcc(Byte b0, Byte b1) +{ + return (b0 == 0x0F && (b1 & 0xF0) == 0x80); +} + +#ifndef EXTRACT_ONLY + +static bool inline Test86MSByte(Byte b) +{ + return (b == 0 || b == 0xFF); +} + +bool CBCJ2_x86_Encoder::Create() +{ + if (!_mainStream.Create(1 << 16)) + return false; + if (!_callStream.Create(1 << 20)) + return false; + if (!_jumpStream.Create(1 << 20)) + return false; + if (!_rangeEncoder.Create(1 << 20)) + return false; + if (_buffer == 0) + { + _buffer = (Byte *)MidAlloc(kBufferSize); + if (_buffer == 0) + return false; + } + return true; +} + +CBCJ2_x86_Encoder::~CBCJ2_x86_Encoder() +{ + ::MidFree(_buffer); +} + +HRESULT CBCJ2_x86_Encoder::Flush() +{ + RINOK(_mainStream.Flush()); + RINOK(_callStream.Flush()); + RINOK(_jumpStream.Flush()); + _rangeEncoder.FlushData(); + return _rangeEncoder.FlushStream(); +} + +const UInt32 kDefaultLimit = (1 << 24); + +HRESULT CBCJ2_x86_Encoder::CodeReal(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + if (numInStreams != 1 || numOutStreams != 4) + return E_INVALIDARG; + + if (!Create()) + return E_OUTOFMEMORY; + + bool sizeIsDefined = false; + UInt64 inSize; + if (inSizes != NULL) + if (inSizes[0] != NULL) + { + inSize = *inSizes[0]; + if (inSize <= kDefaultLimit) + sizeIsDefined = true; + } + + ISequentialInStream *inStream = inStreams[0]; + + _mainStream.SetStream(outStreams[0]); + _mainStream.Init(); + _callStream.SetStream(outStreams[1]); + _callStream.Init(); + _jumpStream.SetStream(outStreams[2]); + _jumpStream.Init(); + _rangeEncoder.SetStream(outStreams[3]); + _rangeEncoder.Init(); + for (int i = 0; i < 256; i++) + _statusE8Encoder[i].Init(); + _statusE9Encoder.Init(); + _statusJccEncoder.Init(); + CCoderReleaser releaser(this); + + CMyComPtr getSubStreamSize; + { + inStream->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize); + } + + UInt32 nowPos = 0; + UInt64 nowPos64 = 0; + UInt32 bufferPos = 0; + + Byte prevByte = 0; + + UInt64 subStreamIndex = 0; + UInt64 subStreamStartPos = 0; + UInt64 subStreamEndPos = 0; + + while(true) + { + UInt32 processedSize = 0; + while(true) + { + UInt32 size = kBufferSize - (bufferPos + processedSize); + UInt32 processedSizeLoc; + if (size == 0) + break; + RINOK(inStream->Read(_buffer + bufferPos + processedSize, size, &processedSizeLoc)); + if (processedSizeLoc == 0) + break; + processedSize += processedSizeLoc; + } + UInt32 endPos = bufferPos + processedSize; + + if (endPos < 5) + { + // change it + for (bufferPos = 0; bufferPos < endPos; bufferPos++) + { + Byte b = _buffer[bufferPos]; + _mainStream.WriteByte(b); + if (b == 0xE8) + _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 0); + else if (b == 0xE9) + _statusE9Encoder.Encode(&_rangeEncoder, 0); + else if (IsJcc(prevByte, b)) + _statusJccEncoder.Encode(&_rangeEncoder, 0); + prevByte = b; + } + return Flush(); + } + + bufferPos = 0; + + UInt32 limit = endPos - 5; + while(bufferPos <= limit) + { + Byte b = _buffer[bufferPos]; + _mainStream.WriteByte(b); + if (b != 0xE8 && b != 0xE9 && !IsJcc(prevByte, b)) + { + bufferPos++; + prevByte = b; + continue; + } + Byte nextByte = _buffer[bufferPos + 4]; + UInt32 src = + (UInt32(nextByte) << 24) | + (UInt32(_buffer[bufferPos + 3]) << 16) | + (UInt32(_buffer[bufferPos + 2]) << 8) | + (_buffer[bufferPos + 1]); + UInt32 dest = (nowPos + bufferPos + 5) + src; + // if (Test86MSByte(nextByte)) + bool convert; + if (getSubStreamSize != NULL) + { + UInt64 currentPos = (nowPos64 + bufferPos); + while (subStreamEndPos < currentPos) + { + UInt64 subStreamSize; + HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize); + if (result == S_OK) + { + subStreamStartPos = subStreamEndPos; + subStreamEndPos += subStreamSize; + subStreamIndex++; + } + else if (result == S_FALSE || result == E_NOTIMPL) + { + getSubStreamSize.Release(); + subStreamStartPos = 0; + subStreamEndPos = subStreamStartPos - 1; + } + else + return result; + } + if (getSubStreamSize == NULL) + { + if (sizeIsDefined) + convert = (dest < inSize); + else + convert = Test86MSByte(nextByte); + } + else if (subStreamEndPos - subStreamStartPos > kDefaultLimit) + convert = Test86MSByte(nextByte); + else + { + UInt64 dest64 = (currentPos + 5) + Int64(Int32(src)); + convert = (dest64 >= subStreamStartPos && dest64 < subStreamEndPos); + } + } + else if (sizeIsDefined) + convert = (dest < inSize); + else + convert = Test86MSByte(nextByte); + if (convert) + { + if (b == 0xE8) + _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 1); + else if (b == 0xE9) + _statusE9Encoder.Encode(&_rangeEncoder, 1); + else + _statusJccEncoder.Encode(&_rangeEncoder, 1); + + bufferPos += 5; + if (b == 0xE8) + { + _callStream.WriteByte((Byte)(dest >> 24)); + _callStream.WriteByte((Byte)(dest >> 16)); + _callStream.WriteByte((Byte)(dest >> 8)); + _callStream.WriteByte((Byte)(dest)); + } + else + { + _jumpStream.WriteByte((Byte)(dest >> 24)); + _jumpStream.WriteByte((Byte)(dest >> 16)); + _jumpStream.WriteByte((Byte)(dest >> 8)); + _jumpStream.WriteByte((Byte)(dest)); + } + prevByte = nextByte; + } + else + { + if (b == 0xE8) + _statusE8Encoder[prevByte].Encode(&_rangeEncoder, 0); + else if (b == 0xE9) + _statusE9Encoder.Encode(&_rangeEncoder, 0); + else + _statusJccEncoder.Encode(&_rangeEncoder, 0); + bufferPos++; + prevByte = b; + } + } + nowPos += bufferPos; + nowPos64 += bufferPos; + + if (progress != NULL) + { + RINOK(progress->SetRatioInfo(&nowPos64, NULL)); + } + + UInt32 i = 0; + while(bufferPos < endPos) + _buffer[i++] = _buffer[bufferPos++]; + bufferPos = i; + } +} + +STDMETHODIMP CBCJ2_x86_Encoder::Code(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + try + { + return CodeReal(inStreams, inSizes, numInStreams, + outStreams, outSizes,numOutStreams, progress); + } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} + +#endif + +HRESULT CBCJ2_x86_Decoder::CodeReal(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + if (numInStreams != 4 || numOutStreams != 1) + return E_INVALIDARG; + + if (!_mainInStream.Create(1 << 16)) + return E_OUTOFMEMORY; + if (!_callStream.Create(1 << 20)) + return E_OUTOFMEMORY; + if (!_jumpStream.Create(1 << 16)) + return E_OUTOFMEMORY; + if (!_rangeDecoder.Create(1 << 20)) + return E_OUTOFMEMORY; + if (!_outStream.Create(1 << 16)) + return E_OUTOFMEMORY; + + _mainInStream.SetStream(inStreams[0]); + _callStream.SetStream(inStreams[1]); + _jumpStream.SetStream(inStreams[2]); + _rangeDecoder.SetStream(inStreams[3]); + _outStream.SetStream(outStreams[0]); + + _mainInStream.Init(); + _callStream.Init(); + _jumpStream.Init(); + _rangeDecoder.Init(); + _outStream.Init(); + + for (int i = 0; i < 256; i++) + _statusE8Decoder[i].Init(); + _statusE9Decoder.Init(); + _statusJccDecoder.Init(); + + CCoderReleaser releaser(this); + + Byte prevByte = 0; + UInt32 processedBytes = 0; + while(true) + { + if (processedBytes > (1 << 20) && progress != NULL) + { + UInt64 nowPos64 = _outStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(NULL, &nowPos64)); + processedBytes = 0; + } + processedBytes++; + Byte b; + if (!_mainInStream.ReadByte(b)) + return Flush(); + _outStream.WriteByte(b); + if (b != 0xE8 && b != 0xE9 && !IsJcc(prevByte, b)) + { + prevByte = b; + continue; + } + bool status; + if (b == 0xE8) + status = (_statusE8Decoder[prevByte].Decode(&_rangeDecoder) == 1); + else if (b == 0xE9) + status = (_statusE9Decoder.Decode(&_rangeDecoder) == 1); + else + status = (_statusJccDecoder.Decode(&_rangeDecoder) == 1); + if (status) + { + UInt32 src; + if (b == 0xE8) + { + Byte b0; + if(!_callStream.ReadByte(b0)) + return S_FALSE; + src = ((UInt32)b0) << 24; + if(!_callStream.ReadByte(b0)) + return S_FALSE; + src |= ((UInt32)b0) << 16; + if(!_callStream.ReadByte(b0)) + return S_FALSE; + src |= ((UInt32)b0) << 8; + if(!_callStream.ReadByte(b0)) + return S_FALSE; + src |= ((UInt32)b0); + } + else + { + Byte b0; + if(!_jumpStream.ReadByte(b0)) + return S_FALSE; + src = ((UInt32)b0) << 24; + if(!_jumpStream.ReadByte(b0)) + return S_FALSE; + src |= ((UInt32)b0) << 16; + if(!_jumpStream.ReadByte(b0)) + return S_FALSE; + src |= ((UInt32)b0) << 8; + if(!_jumpStream.ReadByte(b0)) + return S_FALSE; + src |= ((UInt32)b0); + } + UInt32 dest = src - (UInt32(_outStream.GetProcessedSize()) + 4) ; + _outStream.WriteByte((Byte)(dest)); + _outStream.WriteByte((Byte)(dest >> 8)); + _outStream.WriteByte((Byte)(dest >> 16)); + _outStream.WriteByte((Byte)(dest >> 24)); + prevByte = (dest >> 24); + processedBytes += 4; + } + else + prevByte = b; + } +} + +STDMETHODIMP CBCJ2_x86_Decoder::Code(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress) +{ + try + { + return CodeReal(inStreams, inSizes, numInStreams, + outStreams, outSizes,numOutStreams, progress); + } + catch(const COutBufferException &e) { return e.ErrorCode; } + catch(...) { return S_FALSE; } +} diff --git a/app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.h b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.h new file mode 100644 index 0000000000..9e7780c80b --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Branch/x86_2.h @@ -0,0 +1,133 @@ +// x86_2.h + +#ifndef __BRANCH_X86_2_H +#define __BRANCH_X86_2_H + +#include "../../../Common/MyCom.h" +#include "../RangeCoder/RangeCoderBit.h" +#include "../../ICoder.h" + +// {23170F69-40C1-278B-0303-010100000100} +#define MyClass2_a(Name, id, subId, encodingId) \ +DEFINE_GUID(CLSID_CCompressConvert ## Name, \ +0x23170F69, 0x40C1, 0x278B, 0x03, 0x03, id, subId, 0x00, 0x00, encodingId, 0x00); + +#define MyClass_a(Name, id, subId) \ +MyClass2_a(Name ## _Encoder, id, subId, 0x01) \ +MyClass2_a(Name ## _Decoder, id, subId, 0x00) + +MyClass_a(BCJ2_x86, 0x01, 0x1B) + +const int kNumMoveBits = 5; + +#ifndef EXTRACT_ONLY + +class CBCJ2_x86_Encoder: + public ICompressCoder2, + public CMyUnknownImp +{ + Byte *_buffer; +public: + CBCJ2_x86_Encoder(): _buffer(0) {}; + ~CBCJ2_x86_Encoder(); + bool Create(); + + COutBuffer _mainStream; + COutBuffer _callStream; + COutBuffer _jumpStream; + NCompress::NRangeCoder::CEncoder _rangeEncoder; + NCompress::NRangeCoder::CBitEncoder _statusE8Encoder[256]; + NCompress::NRangeCoder::CBitEncoder _statusE9Encoder; + NCompress::NRangeCoder::CBitEncoder _statusJccEncoder; + + HRESULT Flush(); + void ReleaseStreams() + { + _mainStream.ReleaseStream(); + _callStream.ReleaseStream(); + _jumpStream.ReleaseStream(); + _rangeEncoder.ReleaseStream(); + } + + class CCoderReleaser + { + CBCJ2_x86_Encoder *_coder; + public: + CCoderReleaser(CBCJ2_x86_Encoder *coder): _coder(coder) {} + ~CCoderReleaser() { _coder->ReleaseStreams(); } + }; + +public: + + MY_UNKNOWN_IMP + + HRESULT CodeReal(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress); + STDMETHOD(Code)(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress); +}; + +#endif + +class CBCJ2_x86_Decoder: + public ICompressCoder2, + public CMyUnknownImp +{ +public: + CInBuffer _mainInStream; + CInBuffer _callStream; + CInBuffer _jumpStream; + NCompress::NRangeCoder::CDecoder _rangeDecoder; + NCompress::NRangeCoder::CBitDecoder _statusE8Decoder[256]; + NCompress::NRangeCoder::CBitDecoder _statusE9Decoder; + NCompress::NRangeCoder::CBitDecoder _statusJccDecoder; + + COutBuffer _outStream; + + void ReleaseStreams() + { + _mainInStream.ReleaseStream(); + _callStream.ReleaseStream(); + _jumpStream.ReleaseStream(); + _rangeDecoder.ReleaseStream(); + _outStream.ReleaseStream(); + } + + HRESULT Flush() { return _outStream.Flush(); } + class CCoderReleaser + { + CBCJ2_x86_Decoder *_coder; + public: + CCoderReleaser(CBCJ2_x86_Decoder *coder): _coder(coder) {} + ~CCoderReleaser() { _coder->ReleaseStreams(); } + }; + +public: + MY_UNKNOWN_IMP + HRESULT CodeReal(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress); + STDMETHOD(Code)(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.cpp b/app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.cpp new file mode 100644 index 0000000000..9ced211586 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.cpp @@ -0,0 +1,52 @@ +// Compress/CopyCoder.cpp + +#include "StdAfx.h" + +#include "CopyCoder.h" +#include "../../../Common/Alloc.h" +#include "../../Common/StreamUtils.h" + +namespace NCompress { + +static const UInt32 kBufferSize = 1 << 17; + +CCopyCoder::~CCopyCoder() +{ + ::MidFree(_buffer); +} + +STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + if (_buffer == 0) + { + _buffer = (Byte *)::MidAlloc(kBufferSize); + if (_buffer == 0) + return E_OUTOFMEMORY; + } + + TotalSize = 0; + while(true) + { + UInt32 realProcessedSize; + UInt32 size = kBufferSize; + if (outSize != 0) + if (size > *outSize - TotalSize) + size = (UInt32)(*outSize - TotalSize); + RINOK(inStream->Read(_buffer, size, &realProcessedSize)); + if(realProcessedSize == 0) + break; + RINOK(WriteStream(outStream, _buffer, realProcessedSize, NULL)); + TotalSize += realProcessedSize; + if (progress != NULL) + { + RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize)); + } + } + return S_OK; +} + +} + diff --git a/app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.h b/app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.h new file mode 100644 index 0000000000..c82e469a45 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/Copy/CopyCoder.h @@ -0,0 +1,31 @@ +// Compress/CopyCoder.h + +#ifndef __COMPRESS_COPYCODER_H +#define __COMPRESS_COPYCODER_H + +#include "../../ICoder.h" +#include "../../../Common/MyCom.h" + +namespace NCompress { + +class CCopyCoder: + public ICompressCoder, + public CMyUnknownImp +{ + Byte *_buffer; +public: + UInt64 TotalSize; + CCopyCoder(): TotalSize(0) , _buffer(0) {}; + ~CCopyCoder(); + + MY_UNKNOWN_IMP + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, + const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); +}; + +} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.cpp b/app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.cpp new file mode 100644 index 0000000000..329a7db35b --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.cpp @@ -0,0 +1,17 @@ +// LZOutWindow.cpp + +#include "StdAfx.h" + +#include "../../../Common/Alloc.h" +#include "LZOutWindow.h" + +void CLZOutWindow::Init(bool solid) +{ + if(!solid) + COutBuffer::Init(); + #ifdef _NO_EXCEPTIONS + ErrorCode = S_OK; + #endif +} + + diff --git a/app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.h b/app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.h new file mode 100644 index 0000000000..b64cb927f8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/LZ/LZOutWindow.h @@ -0,0 +1,56 @@ +// LZOutWindow.h + +#ifndef __LZ_OUT_WINDOW_H +#define __LZ_OUT_WINDOW_H + +#include "../../IStream.h" +#include "../../Common/OutBuffer.h" + +#ifndef _NO_EXCEPTIONS +typedef COutBufferException CLZOutWindowException; +#endif + +class CLZOutWindow: public COutBuffer +{ +public: + void Init(bool solid = false); + + // distance >= 0, len > 0, + bool CopyBlock(UInt32 distance, UInt32 len) + { + UInt32 pos = _pos - distance - 1; + if (distance >= _pos) + { + if (!_overDict || distance >= _bufferSize) + return false; + pos += _bufferSize; + } + do + { + if (pos == _bufferSize) + pos = 0; + _buffer[_pos++] = _buffer[pos++]; + if (_pos == _limitPos) + FlushWithCheck(); + } + while(--len != 0); + return true; + } + + void PutByte(Byte b) + { + _buffer[_pos++] = b; + if (_pos == _limitPos) + FlushWithCheck(); + } + + Byte GetByte(UInt32 distance) const + { + UInt32 pos = _pos - distance - 1; + if (pos >= _bufferSize) + pos += _bufferSize; + return _buffer[pos]; + } +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMA.h b/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMA.h new file mode 100644 index 0000000000..d53296ee70 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMA.h @@ -0,0 +1,82 @@ +// LZMA.h + +#ifndef __LZMA_H +#define __LZMA_H + +namespace NCompress { +namespace NLZMA { + +const UInt32 kNumRepDistances = 4; + +const int kNumStates = 12; + +const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5}; +const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10}; +const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11}; +const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11}; + +class CState +{ +public: + Byte Index; + void Init() { Index = 0; } + void UpdateChar() { Index = kLiteralNextStates[Index]; } + void UpdateMatch() { Index = kMatchNextStates[Index]; } + void UpdateRep() { Index = kRepNextStates[Index]; } + void UpdateShortRep() { Index = kShortRepNextStates[Index]; } + bool IsCharState() const { return Index < 7; } +}; + +const int kNumPosSlotBits = 6; +const int kDicLogSizeMin = 0; +const int kDicLogSizeMax = 32; +const int kDistTableSizeMax = kDicLogSizeMax * 2; + +const UInt32 kNumLenToPosStates = 4; + +inline UInt32 GetLenToPosState(UInt32 len) +{ + len -= 2; + if (len < kNumLenToPosStates) + return len; + return kNumLenToPosStates - 1; +} + +namespace NLength { + +const int kNumPosStatesBitsMax = 4; +const UInt32 kNumPosStatesMax = (1 << kNumPosStatesBitsMax); + +const int kNumPosStatesBitsEncodingMax = 4; +const UInt32 kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax); + +const int kNumLowBits = 3; +const int kNumMidBits = 3; +const int kNumHighBits = 8; +const UInt32 kNumLowSymbols = 1 << kNumLowBits; +const UInt32 kNumMidSymbols = 1 << kNumMidBits; +const UInt32 kNumSymbolsTotal = kNumLowSymbols + kNumMidSymbols + (1 << kNumHighBits); + +} + +const UInt32 kMatchMinLen = 2; +const UInt32 kMatchMaxLen = kMatchMinLen + NLength::kNumSymbolsTotal - 1; + +const int kNumAlignBits = 4; +const UInt32 kAlignTableSize = 1 << kNumAlignBits; +const UInt32 kAlignMask = (kAlignTableSize - 1); + +const UInt32 kStartPosModelIndex = 4; +const UInt32 kEndPosModelIndex = 14; +const UInt32 kNumPosModels = kEndPosModelIndex - kStartPosModelIndex; + +const UInt32 kNumFullDistances = 1 << (kEndPosModelIndex / 2); + +const int kNumLitPosStatesBitsEncodingMax = 4; +const int kNumLitContextBitsMax = 8; + +const int kNumMoveBits = 5; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.cpp b/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.cpp new file mode 100644 index 0000000000..e5dfb27027 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.cpp @@ -0,0 +1,337 @@ +// LZMADecoder.cpp + +#include "StdAfx.h" + +#include "LZMADecoder.h" +#include "../../../Common/Defs.h" + +namespace NCompress { +namespace NLZMA { + +const int kLenIdFinished = -1; +const int kLenIdNeedInit = -2; + +void CDecoder::Init() +{ + { + for(int i = 0; i < kNumStates; i++) + { + for (UInt32 j = 0; j <= _posStateMask; j++) + { + _isMatch[i][j].Init(); + _isRep0Long[i][j].Init(); + } + _isRep[i].Init(); + _isRepG0[i].Init(); + _isRepG1[i].Init(); + _isRepG2[i].Init(); + } + } + { + for (UInt32 i = 0; i < kNumLenToPosStates; i++) + _posSlotDecoder[i].Init(); + } + { + for(UInt32 i = 0; i < kNumFullDistances - kEndPosModelIndex; i++) + _posDecoders[i].Init(); + } + _posAlignDecoder.Init(); + _lenDecoder.Init(_posStateMask + 1); + _repMatchLenDecoder.Init(_posStateMask + 1); + _literalDecoder.Init(); + + _state.Init(); + _reps[0] = _reps[1] = _reps[2] = _reps[3] = 0; +} + +HRESULT CDecoder::CodeSpec(UInt32 curSize) +{ + if (_outSizeDefined) + { + const UInt64 rem = _outSize - _outWindowStream.GetProcessedSize(); + if (curSize > rem) + curSize = (UInt32)rem; + } + + if (_remainLen == kLenIdFinished) + return S_OK; + if (_remainLen == kLenIdNeedInit) + { + _rangeDecoder.Init(); + Init(); + _remainLen = 0; + } + if (curSize == 0) + return S_OK; + + UInt32 rep0 = _reps[0]; + UInt32 rep1 = _reps[1]; + UInt32 rep2 = _reps[2]; + UInt32 rep3 = _reps[3]; + CState state = _state; + Byte previousByte; + + while(_remainLen > 0 && curSize > 0) + { + previousByte = _outWindowStream.GetByte(rep0); + _outWindowStream.PutByte(previousByte); + _remainLen--; + curSize--; + } + UInt64 nowPos64 = _outWindowStream.GetProcessedSize(); + if (nowPos64 == 0) + previousByte = 0; + else + previousByte = _outWindowStream.GetByte(0); + + while(curSize > 0) + { + { + #ifdef _NO_EXCEPTIONS + if (_rangeDecoder.Stream.ErrorCode != S_OK) + return _rangeDecoder.Stream.ErrorCode; + #endif + if (_rangeDecoder.Stream.WasFinished()) + return S_FALSE; + UInt32 posState = UInt32(nowPos64) & _posStateMask; + if (_isMatch[state.Index][posState].Decode(&_rangeDecoder) == 0) + { + if(!state.IsCharState()) + previousByte = _literalDecoder.DecodeWithMatchByte(&_rangeDecoder, + (UInt32)nowPos64, previousByte, _outWindowStream.GetByte(rep0)); + else + previousByte = _literalDecoder.DecodeNormal(&_rangeDecoder, + (UInt32)nowPos64, previousByte); + _outWindowStream.PutByte(previousByte); + state.UpdateChar(); + curSize--; + nowPos64++; + } + else + { + UInt32 len; + if(_isRep[state.Index].Decode(&_rangeDecoder) == 1) + { + len = 0; + if(_isRepG0[state.Index].Decode(&_rangeDecoder) == 0) + { + if(_isRep0Long[state.Index][posState].Decode(&_rangeDecoder) == 0) + { + state.UpdateShortRep(); + len = 1; + } + } + else + { + UInt32 distance; + if(_isRepG1[state.Index].Decode(&_rangeDecoder) == 0) + distance = rep1; + else + { + if (_isRepG2[state.Index].Decode(&_rangeDecoder) == 0) + distance = rep2; + else + { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + if (len == 0) + { + len = _repMatchLenDecoder.Decode(&_rangeDecoder, posState) + kMatchMinLen; + state.UpdateRep(); + } + } + else + { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + len = kMatchMinLen + _lenDecoder.Decode(&_rangeDecoder, posState); + state.UpdateMatch(); + UInt32 posSlot = _posSlotDecoder[GetLenToPosState(len)].Decode(&_rangeDecoder); + if (posSlot >= kStartPosModelIndex) + { + UInt32 numDirectBits = (posSlot >> 1) - 1; + rep0 = ((2 | (posSlot & 1)) << numDirectBits); + + if (posSlot < kEndPosModelIndex) + rep0 += NRangeCoder::ReverseBitTreeDecode(_posDecoders + + rep0 - posSlot - 1, &_rangeDecoder, numDirectBits); + else + { + rep0 += (_rangeDecoder.DecodeDirectBits( + numDirectBits - kNumAlignBits) << kNumAlignBits); + rep0 += _posAlignDecoder.ReverseDecode(&_rangeDecoder); + if (rep0 == 0xFFFFFFFF) + { + _remainLen = kLenIdFinished; + return S_OK; + } + } + } + else + rep0 = posSlot; + } + UInt32 locLen = len; + if (len > curSize) + locLen = (UInt32)curSize; + if (!_outWindowStream.CopyBlock(rep0, locLen)) + return S_FALSE; + previousByte = _outWindowStream.GetByte(0); + curSize -= locLen; + nowPos64 += locLen; + len -= locLen; + if (len != 0) + { + _remainLen = (Int32)len; + break; + } + + #ifdef _NO_EXCEPTIONS + if (_outWindowStream.ErrorCode != S_OK) + return _outWindowStream.ErrorCode; + #endif + } + } + } + if (_rangeDecoder.Stream.WasFinished()) + return S_FALSE; + _reps[0] = rep0; + _reps[1] = rep1; + _reps[2] = rep2; + _reps[3] = rep3; + _state = state; + + return S_OK; +} + +STDMETHODIMP CDecoder::CodeReal(ISequentialInStream *inStream, + ISequentialOutStream *outStream, + const UInt64 *, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + SetInStream(inStream); + _outWindowStream.SetStream(outStream); + SetOutStreamSize(outSize); + CDecoderFlusher flusher(this); + + while (true) + { + UInt32 curSize = 1 << 18; + RINOK(CodeSpec(curSize)); + if (_remainLen == kLenIdFinished) + break; + if (progress != NULL) + { + UInt64 inSize = _rangeDecoder.GetProcessedSize(); + UInt64 nowPos64 = _outWindowStream.GetProcessedSize(); + RINOK(progress->SetRatioInfo(&inSize, &nowPos64)); + } + if (_outSizeDefined) + if (_outWindowStream.GetProcessedSize() >= _outSize) + break; + } + flusher.NeedFlush = false; + return Flush(); +} + + +#ifdef _NO_EXCEPTIONS + +#define LZMA_TRY_BEGIN +#define LZMA_TRY_END + +#else + +#define LZMA_TRY_BEGIN try { +#define LZMA_TRY_END } \ + catch(const CInBufferException &e) { return e.ErrorCode; } \ + catch(const CLZOutWindowException &e) { return e.ErrorCode; } \ + catch(...) { return S_FALSE; } + +#endif + + +STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress) +{ + LZMA_TRY_BEGIN + return CodeReal(inStream, outStream, inSize, outSize, progress); + LZMA_TRY_END +} + +STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *properties, UInt32 size) +{ + if (size < 5) + return E_INVALIDARG; + int lc = properties[0] % 9; + Byte remainder = (Byte)(properties[0] / 9); + int lp = remainder % 5; + int pb = remainder / 5; + if (pb > NLength::kNumPosStatesBitsMax) + return E_INVALIDARG; + _posStateMask = (1 << pb) - 1; + UInt32 dictionarySize = 0; + for (int i = 0; i < 4; i++) + dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8); + if (!_outWindowStream.Create(dictionarySize)) + return E_OUTOFMEMORY; + if (!_literalDecoder.Create(lp, lc)) + return E_OUTOFMEMORY; + if (!_rangeDecoder.Create(1 << 20)) + return E_OUTOFMEMORY; + return S_OK; +} + +STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value) +{ + *value = _rangeDecoder.GetProcessedSize(); + return S_OK; +} + +STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) +{ + _rangeDecoder.SetStream(inStream); + return S_OK; +} + +STDMETHODIMP CDecoder::ReleaseInStream() +{ + _rangeDecoder.ReleaseStream(); + return S_OK; +} + +STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize) +{ + if (_outSizeDefined = (outSize != NULL)) + _outSize = *outSize; + _remainLen = kLenIdNeedInit; + _outWindowStream.Init(); + return S_OK; +} + +#ifdef _ST_MODE + +STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize) +{ + LZMA_TRY_BEGIN + if (processedSize) + *processedSize = 0; + const UInt64 startPos = _outWindowStream.GetProcessedSize(); + _outWindowStream.SetMemStream((Byte *)data); + RINOK(CodeSpec(size)); + if (processedSize) + *processedSize = (UInt32)(_outWindowStream.GetProcessedSize() - startPos); + return Flush(); + LZMA_TRY_END +} + +#endif + +}} diff --git a/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.h b/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.h new file mode 100644 index 0000000000..d6370e250f --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/LZMA/LZMADecoder.h @@ -0,0 +1,251 @@ +// LZMA/Decoder.h + +#ifndef __LZMA_DECODER_H +#define __LZMA_DECODER_H + +#include "../../../Common/MyCom.h" +#include "../../../Common/Alloc.h" +#include "../../ICoder.h" +#include "../LZ/LZOutWindow.h" +#include "../RangeCoder/RangeCoderBitTree.h" + +#include "LZMA.h" + +namespace NCompress { +namespace NLZMA { + +typedef NRangeCoder::CBitDecoder CMyBitDecoder; + +class CLiteralDecoder2 +{ + CMyBitDecoder _decoders[0x300]; +public: + void Init() + { + for (int i = 0; i < 0x300; i++) + _decoders[i].Init(); + } + Byte DecodeNormal(NRangeCoder::CDecoder *rangeDecoder) + { + UInt32 symbol = 1; + RC_INIT_VAR + do + { + // symbol = (symbol << 1) | _decoders[0][symbol].Decode(rangeDecoder); + RC_GETBIT(kNumMoveBits, _decoders[symbol].Prob, symbol) + } + while (symbol < 0x100); + RC_FLUSH_VAR + return (Byte)symbol; + } + Byte DecodeWithMatchByte(NRangeCoder::CDecoder *rangeDecoder, Byte matchByte) + { + UInt32 symbol = 1; + RC_INIT_VAR + do + { + UInt32 matchBit = (matchByte >> 7) & 1; + matchByte <<= 1; + // UInt32 bit = _decoders[1 + matchBit][symbol].Decode(rangeDecoder); + // symbol = (symbol << 1) | bit; + UInt32 bit; + RC_GETBIT2(kNumMoveBits, _decoders[0x100 + (matchBit << 8) + symbol].Prob, symbol, + bit = 0, bit = 1) + if (matchBit != bit) + { + while (symbol < 0x100) + { + // symbol = (symbol << 1) | _decoders[0][symbol].Decode(rangeDecoder); + RC_GETBIT(kNumMoveBits, _decoders[symbol].Prob, symbol) + } + break; + } + } + while (symbol < 0x100); + RC_FLUSH_VAR + return (Byte)symbol; + } +}; + +class CLiteralDecoder +{ + CLiteralDecoder2 *_coders; + int _numPrevBits; + int _numPosBits; + UInt32 _posMask; +public: + CLiteralDecoder(): _coders(0) {} + ~CLiteralDecoder() { Free(); } + void Free() + { + MyFree(_coders); + _coders = 0; + } + bool Create(int numPosBits, int numPrevBits) + { + if (_coders == 0 || (numPosBits + numPrevBits) != + (_numPrevBits + _numPosBits) ) + { + Free(); + UInt32 numStates = 1 << (numPosBits + numPrevBits); + _coders = (CLiteralDecoder2 *)MyAlloc(numStates * sizeof(CLiteralDecoder2)); + } + _numPosBits = numPosBits; + _posMask = (1 << numPosBits) - 1; + _numPrevBits = numPrevBits; + return (_coders != 0); + } + void Init() + { + UInt32 numStates = 1 << (_numPrevBits + _numPosBits); + for (UInt32 i = 0; i < numStates; i++) + _coders[i].Init(); + } + UInt32 GetState(UInt32 pos, Byte prevByte) const + { return ((pos & _posMask) << _numPrevBits) + (prevByte >> (8 - _numPrevBits)); } + Byte DecodeNormal(NRangeCoder::CDecoder *rangeDecoder, UInt32 pos, Byte prevByte) + { return _coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); } + Byte DecodeWithMatchByte(NRangeCoder::CDecoder *rangeDecoder, UInt32 pos, Byte prevByte, Byte matchByte) + { return _coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); } +}; + +namespace NLength { + +class CDecoder +{ + CMyBitDecoder _choice; + CMyBitDecoder _choice2; + NRangeCoder::CBitTreeDecoder _lowCoder[kNumPosStatesMax]; + NRangeCoder::CBitTreeDecoder _midCoder[kNumPosStatesMax]; + NRangeCoder::CBitTreeDecoder _highCoder; +public: + void Init(UInt32 numPosStates) + { + _choice.Init(); + _choice2.Init(); + for (UInt32 posState = 0; posState < numPosStates; posState++) + { + _lowCoder[posState].Init(); + _midCoder[posState].Init(); + } + _highCoder.Init(); + } + UInt32 Decode(NRangeCoder::CDecoder *rangeDecoder, UInt32 posState) + { + if(_choice.Decode(rangeDecoder) == 0) + return _lowCoder[posState].Decode(rangeDecoder); + if(_choice2.Decode(rangeDecoder) == 0) + return kNumLowSymbols + _midCoder[posState].Decode(rangeDecoder); + return kNumLowSymbols + kNumMidSymbols + _highCoder.Decode(rangeDecoder); + } +}; + +} + +class CDecoder: + public ICompressCoder, + public ICompressSetDecoderProperties2, + public ICompressGetInStreamProcessedSize, + #ifdef _ST_MODE + public ICompressSetInStream, + public ICompressSetOutStreamSize, + public ISequentialInStream, + #endif + public CMyUnknownImp +{ + CLZOutWindow _outWindowStream; + NRangeCoder::CDecoder _rangeDecoder; + + CMyBitDecoder _isMatch[kNumStates][NLength::kNumPosStatesMax]; + CMyBitDecoder _isRep[kNumStates]; + CMyBitDecoder _isRepG0[kNumStates]; + CMyBitDecoder _isRepG1[kNumStates]; + CMyBitDecoder _isRepG2[kNumStates]; + CMyBitDecoder _isRep0Long[kNumStates][NLength::kNumPosStatesMax]; + + NRangeCoder::CBitTreeDecoder _posSlotDecoder[kNumLenToPosStates]; + + CMyBitDecoder _posDecoders[kNumFullDistances - kEndPosModelIndex]; + NRangeCoder::CBitTreeDecoder _posAlignDecoder; + + NLength::CDecoder _lenDecoder; + NLength::CDecoder _repMatchLenDecoder; + + CLiteralDecoder _literalDecoder; + + UInt32 _posStateMask; + + /////////////////// + // State + UInt32 _reps[4]; + CState _state; + Int32 _remainLen; // -1 means end of stream. // -2 means need Init + UInt64 _outSize; + bool _outSizeDefined; + + void Init(); + HRESULT CodeSpec(UInt32 size); +public: + + #ifdef _ST_MODE + MY_UNKNOWN_IMP5( + ICompressSetDecoderProperties2, + ICompressGetInStreamProcessedSize, + ICompressSetInStream, + ICompressSetOutStreamSize, + ISequentialInStream) + #else + MY_UNKNOWN_IMP2( + ICompressSetDecoderProperties2, + ICompressGetInStreamProcessedSize) + #endif + + void ReleaseStreams() + { + _outWindowStream.ReleaseStream(); + ReleaseInStream(); + } + + class CDecoderFlusher + { + CDecoder *_decoder; + public: + bool NeedFlush; + CDecoderFlusher(CDecoder *decoder): _decoder(decoder), NeedFlush(true) {} + ~CDecoderFlusher() + { + if (NeedFlush) + _decoder->Flush(); + _decoder->ReleaseStreams(); + } + }; + + HRESULT Flush() { return _outWindowStream.Flush(); } + + STDMETHOD(CodeReal)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize, + ICompressProgressInfo *progress); + + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size); + + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value); + + STDMETHOD(SetInStream)(ISequentialInStream *inStream); + STDMETHOD(ReleaseInStream)(); + STDMETHOD(SetOutStreamSize)(const UInt64 *outSize); + + #ifdef _ST_MODE + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize); + #endif + + CDecoder(): _outSizeDefined(false) {} + virtual ~CDecoder() {} +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoder.h b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoder.h new file mode 100644 index 0000000000..9828bc4b94 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoder.h @@ -0,0 +1,205 @@ +// Compress/RangeCoder/RangeCoder.h + +#ifndef __COMPRESS_RANGECODER_H +#define __COMPRESS_RANGECODER_H + +#include "../../Common/InBuffer.h" +#include "../../Common/OutBuffer.h" + +namespace NCompress { +namespace NRangeCoder { + +const int kNumTopBits = 24; +const UInt32 kTopValue = (1 << kNumTopBits); + +class CEncoder +{ + UInt32 _cacheSize; + Byte _cache; +public: + UInt64 Low; + UInt32 Range; + COutBuffer Stream; + bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); } + + void SetStream(ISequentialOutStream *stream) { Stream.SetStream(stream); } + void Init() + { + Stream.Init(); + Low = 0; + Range = 0xFFFFFFFF; + _cacheSize = 1; + _cache = 0; + } + + void FlushData() + { + // Low += 1; + for(int i = 0; i < 5; i++) + ShiftLow(); + } + + HRESULT FlushStream() { return Stream.Flush(); } + + void ReleaseStream() { Stream.ReleaseStream(); } + + void Encode(UInt32 start, UInt32 size, UInt32 total) + { + Low += start * (Range /= total); + Range *= size; + while (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + + void ShiftLow() + { + if ((UInt32)Low < (UInt32)0xFF000000 || (int)(Low >> 32) != 0) + { + Byte temp = _cache; + do + { + Stream.WriteByte((Byte)(temp + (Byte)(Low >> 32))); + temp = 0xFF; + } + while(--_cacheSize != 0); + _cache = (Byte)((UInt32)Low >> 24); + } + _cacheSize++; + Low = (UInt32)Low << 8; + } + + void EncodeDirectBits(UInt32 value, int numTotalBits) + { + for (int i = numTotalBits - 1; i >= 0; i--) + { + Range >>= 1; + if (((value >> i) & 1) == 1) + Low += Range; + if (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + } + + void EncodeBit(UInt32 size0, UInt32 numTotalBits, UInt32 symbol) + { + UInt32 newBound = (Range >> numTotalBits) * size0; + if (symbol == 0) + Range = newBound; + else + { + Low += newBound; + Range -= newBound; + } + while (Range < kTopValue) + { + Range <<= 8; + ShiftLow(); + } + } + + UInt64 GetProcessedSize() { return Stream.GetProcessedSize() + _cacheSize + 4; } +}; + +class CDecoder +{ +public: + CInBuffer Stream; + UInt32 Range; + UInt32 Code; + bool Create(UInt32 bufferSize) { return Stream.Create(bufferSize); } + + void Normalize() + { + while (Range < kTopValue) + { + Code = (Code << 8) | Stream.ReadByte(); + Range <<= 8; + } + } + + void SetStream(ISequentialInStream *stream) { Stream.SetStream(stream); } + void Init() + { + Stream.Init(); + Code = 0; + Range = 0xFFFFFFFF; + for(int i = 0; i < 5; i++) + Code = (Code << 8) | Stream.ReadByte(); + } + + void ReleaseStream() { Stream.ReleaseStream(); } + + UInt32 GetThreshold(UInt32 total) + { + return (Code) / ( Range /= total); + } + + void Decode(UInt32 start, UInt32 size) + { + Code -= start * Range; + Range *= size; + Normalize(); + } + + UInt32 DecodeDirectBits(int numTotalBits) + { + UInt32 range = Range; + UInt32 code = Code; + UInt32 result = 0; + for (int i = numTotalBits; i != 0; i--) + { + range >>= 1; + /* + result <<= 1; + if (code >= range) + { + code -= range; + result |= 1; + } + */ + UInt32 t = (code - range) >> 31; + code -= range & (t - 1); + result = (result << 1) | (1 - t); + + if (range < kTopValue) + { + code = (code << 8) | Stream.ReadByte(); + range <<= 8; + } + } + Range = range; + Code = code; + return result; + } + + UInt32 DecodeBit(UInt32 size0, UInt32 numTotalBits) + { + UInt32 newBound = (Range >> numTotalBits) * size0; + UInt32 symbol; + if (Code < newBound) + { + symbol = 0; + Range = newBound; + } + else + { + symbol = 1; + Code -= newBound; + Range -= newBound; + } + Normalize(); + return symbol; + } + + UInt64 GetProcessedSize() {return Stream.GetProcessedSize(); } +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.cpp b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.cpp new file mode 100644 index 0000000000..8d273c8f93 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.cpp @@ -0,0 +1,80 @@ +// Compress/RangeCoder/RangeCoderBit.cpp + +#include "StdAfx.h" + +#include "RangeCoderBit.h" + +namespace NCompress { +namespace NRangeCoder { + +UInt32 CPriceTables::ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; +static CPriceTables g_PriceTables; + +CPriceTables::CPriceTables() { Init(); } + +void CPriceTables::Init() +{ + const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits); + for(int i = kNumBits - 1; i >= 0; i--) + { + UInt32 start = 1 << (kNumBits - i - 1); + UInt32 end = 1 << (kNumBits - i); + for (UInt32 j = start; j < end; j++) + ProbPrices[j] = (i << kNumBitPriceShiftBits) + + (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1)); + } + + /* + // simplest: bad solution + for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++) + ProbPrices[i] = kBitPrice; + */ + + /* + const double kDummyMultMid = (1.0 / kBitPrice) / 2; + const double kDummyMultMid = 0; + // float solution + double ln2 = log(double(2)); + double lnAll = log(double(kBitModelTotal >> kNumMoveReducingBits)); + for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++) + ProbPrices[i] = UInt32((fabs(lnAll - log(double(i))) / ln2 + kDummyMultMid) * kBitPrice); + */ + + /* + // experimental, slow, solution: + for(UInt32 i = 1; i < (kBitModelTotal >> kNumMoveReducingBits) - 1; i++) + { + const int kCyclesBits = 5; + const UInt32 kCycles = (1 << kCyclesBits); + + UInt32 range = UInt32(-1); + UInt32 bitCount = 0; + for (UInt32 j = 0; j < kCycles; j++) + { + range >>= (kNumBitModelTotalBits - kNumMoveReducingBits); + range *= i; + while(range < (1 << 31)) + { + range <<= 1; + bitCount++; + } + } + bitCount <<= kNumBitPriceShiftBits; + range -= (1 << 31); + for (int k = kNumBitPriceShiftBits - 1; k >= 0; k--) + { + range <<= 1; + if (range > (1 << 31)) + { + bitCount += (1 << k); + range -= (1 << 31); + } + } + ProbPrices[i] = (bitCount + // + (1 << (kCyclesBits - 1)) + ) >> kCyclesBits; + } + */ +} + +}} diff --git a/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.h b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.h new file mode 100644 index 0000000000..64538e6879 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBit.h @@ -0,0 +1,120 @@ +// Compress/RangeCoder/RangeCoderBit.h + +#ifndef __COMPRESS_RANGECODER_BIT_H +#define __COMPRESS_RANGECODER_BIT_H + +#include "RangeCoder.h" + +namespace NCompress { +namespace NRangeCoder { + +const int kNumBitModelTotalBits = 11; +const UInt32 kBitModelTotal = (1 << kNumBitModelTotalBits); + +const int kNumMoveReducingBits = 2; + +const int kNumBitPriceShiftBits = 6; +const UInt32 kBitPrice = 1 << kNumBitPriceShiftBits; + +class CPriceTables +{ +public: + static UInt32 ProbPrices[kBitModelTotal >> kNumMoveReducingBits]; + static void Init(); + CPriceTables(); +}; + +template +class CBitModel +{ +public: + UInt32 Prob; + void UpdateModel(UInt32 symbol) + { + /* + Prob -= (Prob + ((symbol - 1) & ((1 << numMoveBits) - 1))) >> numMoveBits; + Prob += (1 - symbol) << (kNumBitModelTotalBits - numMoveBits); + */ + if (symbol == 0) + Prob += (kBitModelTotal - Prob) >> numMoveBits; + else + Prob -= (Prob) >> numMoveBits; + } +public: + void Init() { Prob = kBitModelTotal / 2; } +}; + +template +class CBitEncoder: public CBitModel +{ +public: + void Encode(CEncoder *encoder, UInt32 symbol) + { + /* + encoder->EncodeBit(this->Prob, kNumBitModelTotalBits, symbol); + this->UpdateModel(symbol); + */ + UInt32 newBound = (encoder->Range >> kNumBitModelTotalBits) * this->Prob; + if (symbol == 0) + { + encoder->Range = newBound; + this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits; + } + else + { + encoder->Low += newBound; + encoder->Range -= newBound; + this->Prob -= (this->Prob) >> numMoveBits; + } + if (encoder->Range < kTopValue) + { + encoder->Range <<= 8; + encoder->ShiftLow(); + } + } + UInt32 GetPrice(UInt32 symbol) const + { + return CPriceTables::ProbPrices[ + (((this->Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits]; + } + UInt32 GetPrice0() const { return CPriceTables::ProbPrices[this->Prob >> kNumMoveReducingBits]; } + UInt32 GetPrice1() const { return CPriceTables::ProbPrices[(kBitModelTotal - this->Prob) >> kNumMoveReducingBits]; } +}; + + +template +class CBitDecoder: public CBitModel +{ +public: + UInt32 Decode(CDecoder *decoder) + { + UInt32 newBound = (decoder->Range >> kNumBitModelTotalBits) * this->Prob; + if (decoder->Code < newBound) + { + decoder->Range = newBound; + this->Prob += (kBitModelTotal - this->Prob) >> numMoveBits; + if (decoder->Range < kTopValue) + { + decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte(); + decoder->Range <<= 8; + } + return 0; + } + else + { + decoder->Range -= newBound; + decoder->Code -= newBound; + this->Prob -= (this->Prob) >> numMoveBits; + if (decoder->Range < kTopValue) + { + decoder->Code = (decoder->Code << 8) | decoder->Stream.ReadByte(); + decoder->Range <<= 8; + } + return 1; + } + } +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBitTree.h b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBitTree.h new file mode 100644 index 0000000000..1fa023f3b8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderBitTree.h @@ -0,0 +1,161 @@ +// Compress/RangeCoder/RangeCoderBitTree.h + +#ifndef __COMPRESS_RANGECODER_BIT_TREE_H +#define __COMPRESS_RANGECODER_BIT_TREE_H + +#include "RangeCoderBit.h" +#include "RangeCoderOpt.h" + +namespace NCompress { +namespace NRangeCoder { + +template +class CBitTreeEncoder +{ + CBitEncoder Models[1 << NumBitLevels]; +public: + void Init() + { + for(UInt32 i = 1; i < (1 << NumBitLevels); i++) + Models[i].Init(); + } + void Encode(CEncoder *rangeEncoder, UInt32 symbol) + { + UInt32 modelIndex = 1; + for (int bitIndex = NumBitLevels; bitIndex != 0 ;) + { + bitIndex--; + UInt32 bit = (symbol >> bitIndex) & 1; + Models[modelIndex].Encode(rangeEncoder, bit); + modelIndex = (modelIndex << 1) | bit; + } + }; + void ReverseEncode(CEncoder *rangeEncoder, UInt32 symbol) + { + UInt32 modelIndex = 1; + for (int i = 0; i < NumBitLevels; i++) + { + UInt32 bit = symbol & 1; + Models[modelIndex].Encode(rangeEncoder, bit); + modelIndex = (modelIndex << 1) | bit; + symbol >>= 1; + } + } + UInt32 GetPrice(UInt32 symbol) const + { + symbol |= (1 << NumBitLevels); + UInt32 price = 0; + while (symbol != 1) + { + price += Models[symbol >> 1].GetPrice(symbol & 1); + symbol >>= 1; + } + return price; + } + UInt32 ReverseGetPrice(UInt32 symbol) const + { + UInt32 price = 0; + UInt32 modelIndex = 1; + for (int i = NumBitLevels; i != 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += Models[modelIndex].GetPrice(bit); + modelIndex = (modelIndex << 1) | bit; + } + return price; + } +}; + +template +class CBitTreeDecoder +{ + CBitDecoder Models[1 << NumBitLevels]; +public: + void Init() + { + for(UInt32 i = 1; i < (1 << NumBitLevels); i++) + Models[i].Init(); + } + UInt32 Decode(CDecoder *rangeDecoder) + { + UInt32 modelIndex = 1; + RC_INIT_VAR + for(int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--) + { + // modelIndex = (modelIndex << 1) + Models[modelIndex].Decode(rangeDecoder); + RC_GETBIT(numMoveBits, Models[modelIndex].Prob, modelIndex) + } + RC_FLUSH_VAR + return modelIndex - (1 << NumBitLevels); + }; + UInt32 ReverseDecode(CDecoder *rangeDecoder) + { + UInt32 modelIndex = 1; + UInt32 symbol = 0; + RC_INIT_VAR + for(int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) + { + // UInt32 bit = Models[modelIndex].Decode(rangeDecoder); + // modelIndex <<= 1; + // modelIndex += bit; + // symbol |= (bit << bitIndex); + RC_GETBIT2(numMoveBits, Models[modelIndex].Prob, modelIndex, ; , symbol |= (1 << bitIndex)) + } + RC_FLUSH_VAR + return symbol; + } +}; + +template +void ReverseBitTreeEncode(CBitEncoder *Models, + CEncoder *rangeEncoder, int NumBitLevels, UInt32 symbol) +{ + UInt32 modelIndex = 1; + for (int i = 0; i < NumBitLevels; i++) + { + UInt32 bit = symbol & 1; + Models[modelIndex].Encode(rangeEncoder, bit); + modelIndex = (modelIndex << 1) | bit; + symbol >>= 1; + } +} + +template +UInt32 ReverseBitTreeGetPrice(CBitEncoder *Models, + UInt32 NumBitLevels, UInt32 symbol) +{ + UInt32 price = 0; + UInt32 modelIndex = 1; + for (int i = NumBitLevels; i != 0; i--) + { + UInt32 bit = symbol & 1; + symbol >>= 1; + price += Models[modelIndex].GetPrice(bit); + modelIndex = (modelIndex << 1) | bit; + } + return price; +} + +template +UInt32 ReverseBitTreeDecode(CBitDecoder *Models, + CDecoder *rangeDecoder, int NumBitLevels) +{ + UInt32 modelIndex = 1; + UInt32 symbol = 0; + RC_INIT_VAR + for(int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++) + { + // UInt32 bit = Models[modelIndex].Decode(rangeDecoder); + // modelIndex <<= 1; + // modelIndex += bit; + // symbol |= (bit << bitIndex); + RC_GETBIT2(numMoveBits, Models[modelIndex].Prob, modelIndex, ; , symbol |= (1 << bitIndex)) + } + RC_FLUSH_VAR + return symbol; +} + +}} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderOpt.h b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderOpt.h new file mode 100644 index 0000000000..829fc83d77 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Compress/RangeCoder/RangeCoderOpt.h @@ -0,0 +1,31 @@ +// Compress/RangeCoder/RangeCoderOpt.h + +#ifndef __COMPRESS_RANGECODER_OPT_H +#define __COMPRESS_RANGECODER_OPT_H + +#define RC_INIT_VAR \ + UInt32 range = rangeDecoder->Range; \ + UInt32 code = rangeDecoder->Code; + +#define RC_FLUSH_VAR \ + rangeDecoder->Range = range; \ + rangeDecoder->Code = code; + +#define RC_NORMALIZE \ + if (range < NCompress::NRangeCoder::kTopValue) \ + { code = (code << 8) | rangeDecoder->Stream.ReadByte(); range <<= 8; } + +#define RC_GETBIT2(numMoveBits, prob, mi, A0, A1) \ + { UInt32 bound = (range >> NCompress::NRangeCoder::kNumBitModelTotalBits) * prob; \ + if (code < bound) \ + { A0; range = bound; \ + prob += (NCompress::NRangeCoder::kBitModelTotal - prob) >> numMoveBits; \ + mi <<= 1; } \ + else \ + { A1; range -= bound; code -= bound; prob -= (prob) >> numMoveBits; \ + mi = (mi + mi) + 1; }} \ + RC_NORMALIZE + +#define RC_GETBIT(numMoveBits, prob, mi) RC_GETBIT2(numMoveBits, prob, mi, ; , ;) + +#endif diff --git a/app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.cpp b/app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.cpp new file mode 100644 index 0000000000..04f27f4276 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.cpp @@ -0,0 +1,40 @@ +// FormatUtils.cpp + +#include "StdAfx.h" + +#include "FormatUtils.h" +#include "Common/IntToString.h" +#include "Windows/ResourceString.h" + +#ifdef LANG +#include "LangUtils.h" +#endif + +UString NumberToString(UInt64 number) +{ + wchar_t numberString[32]; + ConvertUInt64ToString(number, numberString); + return numberString; +} + +UString MyFormatNew(const UString &format, const UString &argument) +{ + UString result = format; + result.Replace(L"{0}", argument); + return result; +} + +UString MyFormatNew(UINT resourceID, + #ifdef LANG + UInt32 langID, + #endif + const UString &argument) +{ + return MyFormatNew( + #ifdef LANG + LangString(resourceID, langID), + #else + NWindows::MyLoadStringW(resourceID), + #endif + argument); +} diff --git a/app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.h b/app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.h new file mode 100644 index 0000000000..825ff6d2ed --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/FileManager/FormatUtils.h @@ -0,0 +1,18 @@ +// FormatUtils.h + +#ifndef __FORMATUTILS_H +#define __FORMATUTILS_H + +#include "Common/Types.h" +#include "Common/String.h" + +UString NumberToString(UInt64 number); + +UString MyFormatNew(const UString &format, const UString &argument); +UString MyFormatNew(UINT resourceID, + #ifdef LANG + UInt32 langID, + #endif + const UString &argument); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.cpp b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.cpp new file mode 100644 index 0000000000..67d7b49b9e --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.cpp @@ -0,0 +1,175 @@ +// ProgressDialog.cpp + +#include "StdAfx.h" +#include "resource.h" +#include "ProgressDialog.h" +#include "Common/IntToString.h" +#include "Common/IntToString.h" + +using namespace NWindows; + +static const UINT_PTR kTimerID = 3; +static const UINT kTimerElapse = 50; + +#ifdef LANG +#include "../../LangUtils.h" +#endif + +#ifdef LANG +static CIDLangPair kIDLangPairs[] = +{ + { IDCANCEL, 0x02000711 } +}; +#endif + +#ifndef _SFX +CProgressDialog::~CProgressDialog() +{ + AddToTitle(TEXT("")); +} +void CProgressDialog::AddToTitle(LPCWSTR s) +{ + if (MainWindow != 0) + ::MySetWindowText(MainWindow, UString(s) + MainTitle); +} +#endif + + + +bool CProgressDialog::OnInit() +{ + _range = UINT64(-1); + _prevPercentValue = -1; + + #ifdef LANG + // LangSetWindowText(HWND(*this), 0x02000C00); + LangSetDlgItemsText(HWND(*this), kIDLangPairs, sizeof(kIDLangPairs) / sizeof(kIDLangPairs[0])); + #endif + + m_ProgressBar.Attach(GetItem(IDC_PROGRESS1)); + _timer = SetTimer(kTimerID, kTimerElapse); + _dialogCreatedEvent.Set(); + SetText(_title); + return CModalDialog::OnInit(); +} + +void CProgressDialog::OnCancel() +{ + ProgressSynch.SetStopped(true); +} + +void CProgressDialog::SetRange(UINT64 range) +{ + _range = range; + _peviousPos = (UInt64)(Int64)-1; + _converter.Init(range); + m_ProgressBar.SetRange32(0 , _converter.Count(range)); // Test it for 100% +} + +void CProgressDialog::SetPos(UINT64 pos) +{ + bool redraw = true; + if (pos < _range && pos > _peviousPos) + { + UINT64 posDelta = pos - _peviousPos; + if (posDelta < (_range >> 10)) + redraw = false; + } + if(redraw) + { + m_ProgressBar.SetPos(_converter.Count(pos)); // Test it for 100% + _peviousPos = pos; + } +} + +bool CProgressDialog::OnTimer(WPARAM timerID, LPARAM callback) +{ + if (ProgressSynch.GetPaused()) + return true; + UINT64 total, completed; + ProgressSynch.GetProgress(total, completed); + if (total != _range) + SetRange(total); + SetPos(completed); + + if (total == 0) + total = 1; + + int percentValue = (int)(completed * 100 / total); + if (percentValue != _prevPercentValue) + { + wchar_t s[64]; + ConvertUInt64ToString(percentValue, s); + UString title = s; + title += L"% "; + SetText(title + _title); + #ifndef _SFX + AddToTitle(title + MainAddTitle); + #endif + _prevPercentValue = percentValue; + } + return true; +} + + +//////////////////// +// CU64ToI32Converter + +static const UINT64 kMaxIntValue = 0x7FFFFFFF; + +void CU64ToI32Converter::Init(UINT64 range) +{ + _numShiftBits = 0; + while(range > kMaxIntValue) + { + range >>= 1; + _numShiftBits++; + } +} + +int CU64ToI32Converter::Count(UINT64 aValue) +{ + return int(aValue >> _numShiftBits); +} + +const UINT CProgressDialog::kCloseMessage = WM_USER + 1; + +bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch(message) + { + case kCloseMessage: + { + KillTimer(_timer); + _timer = 0; + End(0); + return true; + } + case WM_SETTEXT: + { + if (_timer == 0) + return true; + } + } + return CModalDialog::OnMessage(message, wParam, lParam); +} + +bool CProgressDialog::OnButtonClicked(int buttonID, HWND buttonHWND) +{ + switch(buttonID) + { + case IDCANCEL: + { + bool paused = ProgressSynch.GetPaused();; + ProgressSynch.SetPaused(true); + int res = ::MessageBoxW(HWND(*this), + L"Are you sure you want to cancel?", + _title, MB_YESNOCANCEL); + ProgressSynch.SetPaused(paused); + if (res == IDCANCEL || res == IDNO) + return true; + break; + } + } + return CModalDialog::OnButtonClicked(buttonID, buttonHWND); +} diff --git a/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.h b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.h new file mode 100644 index 0000000000..d0d8db56f0 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/ProgressDialog.h @@ -0,0 +1,129 @@ +// ProgressDialog.h + +#ifndef __PROGRESSDIALOG_H +#define __PROGRESSDIALOG_H + +#include "resource.h" + +#include "Windows/Control/Dialog.h" +#include "Windows/Control/ProgressBar.h" +#include "Windows/Synchronization.h" + +class CProgressSynch +{ + NWindows::NSynchronization::CCriticalSection _criticalSection; + bool _stopped; + bool _paused; + UINT64 _total; + UINT64 _completed; +public: + CProgressSynch(): _stopped(false), _paused(false), _total(1), _completed(0) {} + + bool GetStopped() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + return _stopped; + } + void SetStopped(bool value) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + _stopped = value; + } + bool GetPaused() + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + return _paused; + } + void SetPaused(bool value) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + _paused = value; + } + void SetProgress(UINT64 total, UINT64 completed) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + _total = total; + _completed = completed; + } + void SetPos(UINT64 completed) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + _completed = completed; + } + void GetProgress(UINT64 &total, UINT64 &completed) + { + NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection); + total = _total; + completed = _completed; + } +}; + +class CU64ToI32Converter +{ + UINT64 _numShiftBits; +public: + void Init(UINT64 _range); + int Count(UINT64 aValue); +}; + +// class CProgressDialog: public NWindows::NControl::CModelessDialog + +class CProgressDialog: public NWindows::NControl::CModalDialog +{ +private: + UINT_PTR _timer; + + UString _title; + CU64ToI32Converter _converter; + UINT64 _peviousPos; + UINT64 _range; + NWindows::NControl::CProgressBar m_ProgressBar; + + int _prevPercentValue; + + bool OnTimer(WPARAM timerID, LPARAM callback); + void SetRange(UINT64 range); + void SetPos(UINT64 pos); + virtual bool OnInit(); + virtual void OnCancel(); + NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent; + #ifndef _SFX + void AddToTitle(LPCWSTR string); + #endif + bool OnButtonClicked(int buttonID, HWND buttonHWND); +public: + CProgressSynch ProgressSynch; + + #ifndef _SFX + HWND MainWindow; + UString MainTitle; + UString MainAddTitle; + ~CProgressDialog(); + #endif + + CProgressDialog(): _timer(0) + #ifndef _SFX + ,MainWindow(0) + #endif + {} + + void WaitCreating() { _dialogCreatedEvent.Lock(); } + + + INT_PTR Create(const UString &title, HWND wndParent = 0) + { + _title = title; + return CModalDialog::Create(IDD_DIALOG_PROGRESS, wndParent); + } + + static const UINT kCloseMessage; + + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam); + + void MyClose() + { + PostMessage(kCloseMessage); + }; +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/StdAfx.h b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/StdAfx.h new file mode 100644 index 0000000000..6447c20642 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/StdAfx.h @@ -0,0 +1,16 @@ +// stdafx.h + +#ifndef __STDAFX_H +#define __STDAFX_H + +#define _WIN32_WINNT 0x0400 + +// it's for Windows NT supporting (MENUITEMINFOW) +#define WINVER 0x0400 + +#include +#include + +#include "Common/NewHandler.h" + +#endif diff --git a/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.h b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.h new file mode 100644 index 0000000000..7f9828126f --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.h @@ -0,0 +1,3 @@ +#define IDD_DIALOG_PROGRESS 500 + +#define IDC_PROGRESS1 1000 diff --git a/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.rc b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.rc new file mode 100644 index 0000000000..71a76fe9e6 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/FileManager/Resource/ProgressDialog/resource.rc @@ -0,0 +1,20 @@ +#include "resource.h" +#include "../../../GuiCommon.rc" + +#define xSize2 172 +#define ySize2 42 +#define xSize (xSize2 + marg + marg) +#define ySize (ySize2 + marg + marg) + +#define bYPos (ySize - marg - bYSize) +#define bXPos (xSize - marg - bXSize) + + +IDD_DIALOG_PROGRESS DIALOG 0, 0, xSize, ySize MY_MODAL_DIALOG_STYLE +CAPTION "Progress" +MY_FONT +BEGIN + PUSHBUTTON "Cancel", IDCANCEL, bXPos, bYPos , bXSize, bYSize + CONTROL "Progress1", IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH | WS_BORDER, + marg,marg, xSize2, 14 +END diff --git a/app/win/installer/7zstub/src/7zip/GuiCommon.rc b/app/win/installer/7zstub/src/7zip/GuiCommon.rc new file mode 100644 index 0000000000..fb65dce844 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/GuiCommon.rc @@ -0,0 +1,37 @@ +#include +#include +#include + +#define marg 7 +#undef bXSize +#undef bYSize +#define bXSize 64 +#define bYSize 14 +#define bDotsSize 20 + +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#undef xSize2 +#undef ySize2 +#undef xSize +#undef ySize +#undef bXPos +#undef bYPos +#undef b1XPos +#undef b1YPos +#undef b2XPos +#undef b2YPos +#undef b3XPos +#undef b3YPos +#undef gPos +#undef gPos2 +#undef gSpace +#undef gSize +#undef marg2 +#undef marg3 + + +#define MY_MODAL_DIALOG_STYLE STYLE DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU +#define MY_PAGE_STYLE STYLE DS_FIXEDSYS | WS_CHILD | WS_DISABLED | WS_CAPTION + +#define MY_FONT FONT 8, "MS Shell Dlg" diff --git a/app/win/installer/7zstub/src/7zip/ICoder.h b/app/win/installer/7zstub/src/7zip/ICoder.h new file mode 100644 index 0000000000..508dac3fd0 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/ICoder.h @@ -0,0 +1,163 @@ +// ICoder.h + +#ifndef __ICODER_H +#define __ICODER_H + +#include "IStream.h" + +// "23170F69-40C1-278A-0000-000400xx0000" +#define CODER_INTERFACE(i, x) \ +DEFINE_GUID(IID_ ## i, \ +0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x04, 0x00, x, 0x00, 0x00); \ +struct i: public IUnknown + +CODER_INTERFACE(ICompressProgressInfo, 0x04) +{ + STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE; +}; + +CODER_INTERFACE(ICompressCoder, 0x05) +{ + STDMETHOD(Code)(ISequentialInStream *inStream, + ISequentialOutStream *outStream, + const UInt64 *inSize, + const UInt64 *outSize, + ICompressProgressInfo *progress) PURE; +}; + +CODER_INTERFACE(ICompressCoder2, 0x18) +{ + STDMETHOD(Code)(ISequentialInStream **inStreams, + const UInt64 **inSizes, + UInt32 numInStreams, + ISequentialOutStream **outStreams, + const UInt64 **outSizes, + UInt32 numOutStreams, + ICompressProgressInfo *progress) PURE; +}; + +namespace NCoderPropID +{ + enum EEnum + { + kDictionarySize = 0x400, + kUsedMemorySize, + kOrder, + kPosStateBits = 0x440, + kLitContextBits, + kLitPosBits, + kNumFastBytes = 0x450, + kMatchFinder, + kMatchFinderCycles, + kNumPasses = 0x460, + kAlgorithm = 0x470, + kMultiThread = 0x480, + kNumThreads, + kEndMarker = 0x490 + }; +} + +CODER_INTERFACE(ICompressSetCoderProperties, 0x20) +{ + STDMETHOD(SetCoderProperties)(const PROPID *propIDs, + const PROPVARIANT *properties, UInt32 numProperties) PURE; +}; + +/* +CODER_INTERFACE(ICompressSetCoderProperties, 0x21) +{ + STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE; +}; +*/ + +CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22) +{ + STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE; +}; + +CODER_INTERFACE(ICompressWriteCoderProperties, 0x23) +{ + STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStreams) PURE; +}; + +CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24) +{ + STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE; +}; + +CODER_INTERFACE(ICompressSetCoderMt, 0x25) +{ + STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE; +}; + +CODER_INTERFACE(ICompressGetSubStreamSize, 0x30) +{ + STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE; +}; + +CODER_INTERFACE(ICompressSetInStream, 0x31) +{ + STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE; + STDMETHOD(ReleaseInStream)() PURE; +}; + +CODER_INTERFACE(ICompressSetOutStream, 0x32) +{ + STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE; + STDMETHOD(ReleaseOutStream)() PURE; +}; + +CODER_INTERFACE(ICompressSetInStreamSize, 0x33) +{ + STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE; +}; + +CODER_INTERFACE(ICompressSetOutStreamSize, 0x34) +{ + STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE; +}; + +CODER_INTERFACE(ICompressFilter, 0x40) +{ + STDMETHOD(Init)() PURE; + STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) PURE; + // Filter return outSize (UInt32) + // if (outSize <= size): Filter have converted outSize bytes + // if (outSize > size): Filter have not converted anything. + // and it needs at least outSize bytes to convert one block + // (it's for crypto block algorithms). +}; + +CODER_INTERFACE(ICryptoProperties, 0x80) +{ + STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE; + STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE; +}; + +CODER_INTERFACE(ICryptoSetPassword, 0x90) +{ + STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE; +}; + +CODER_INTERFACE(ICryptoSetCRC, 0xA0) +{ + STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE; +}; + +////////////////////// +// It's for DLL file +namespace NMethodPropID +{ + enum EEnum + { + kID, + kName, + kDecoder, + kEncoder, + kInStreams, + kOutStreams, + kDescription + }; +} + +#endif diff --git a/app/win/installer/7zstub/src/7zip/IPassword.h b/app/win/installer/7zstub/src/7zip/IPassword.h new file mode 100644 index 0000000000..ba8acb0ec7 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/IPassword.h @@ -0,0 +1,26 @@ +// IPassword.h + +#ifndef __IPASSWORD_H +#define __IPASSWORD_H + +#include "../Common/MyUnknown.h" +#include "../Common/Types.h" + +// MIDL_INTERFACE("23170F69-40C1-278A-0000-000500xx0000") +#define PASSWORD_INTERFACE(i, x) \ +DEFINE_GUID(IID_ ## i, \ +0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x05, 0x00, x, 0x00, 0x00); \ +struct i: public IUnknown + +PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10) +{ + STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE; +}; + +PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11) +{ + STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE; +}; + +#endif + diff --git a/app/win/installer/7zstub/src/7zip/IProgress.h b/app/win/installer/7zstub/src/7zip/IProgress.h new file mode 100644 index 0000000000..fa2070dc7c --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/IProgress.h @@ -0,0 +1,32 @@ +// Interface/IProgress.h + +#ifndef __IPROGRESS_H +#define __IPROGRESS_H + +#include "../Common/MyUnknown.h" +#include "../Common/Types.h" + +// {23170F69-40C1-278A-0000-000000050000} +DEFINE_GUID(IID_IProgress, +0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00); +MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050000") +IProgress: public IUnknown +{ + STDMETHOD(SetTotal)(UInt64 total) PURE; + STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE; +}; + +/* +// {23170F69-40C1-278A-0000-000000050002} +DEFINE_GUID(IID_IProgress2, +0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x02); +MIDL_INTERFACE("23170F69-40C1-278A-0000-000000050002") +IProgress2: public IUnknown +{ +public: + STDMETHOD(SetTotal)(const UInt64 *total) PURE; + STDMETHOD(SetCompleted)(const UInt64 *completeValue) PURE; +}; +*/ + +#endif diff --git a/app/win/installer/7zstub/src/7zip/IStream.h b/app/win/installer/7zstub/src/7zip/IStream.h new file mode 100644 index 0000000000..d92b89aa70 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/IStream.h @@ -0,0 +1,62 @@ +// IStream.h + +#ifndef __ISTREAM_H +#define __ISTREAM_H + +#include "../Common/MyUnknown.h" +#include "../Common/Types.h" + +// "23170F69-40C1-278A-0000-000300xx0000" + +#define STREAM_INTERFACE_SUB(i, b, x) \ +DEFINE_GUID(IID_ ## i, \ +0x23170F69, 0x40C1, 0x278A, 0x00, 0x00, 0x00, 0x03, 0x00, x, 0x00, 0x00); \ +struct i: public b + +#define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x) + +STREAM_INTERFACE(ISequentialInStream, 0x01) +{ + STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE; + /* + Out: if size != 0, return_value = S_OK and (*processedSize == 0), + then there are no more bytes in stream. + if (size > 0) && there are bytes in stream, + this function must read at least 1 byte. + This function is allowed to read less than number of remaining bytes in stream. + You must call Read function in loop, if you need exact amount of data + */ +}; + +STREAM_INTERFACE(ISequentialOutStream, 0x02) +{ + STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE; + /* + if (size > 0) this function must write at least 1 byte. + This function is allowed to write less than "size". + You must call Write function in loop, if you need to write exact amount of data + */ +}; + +STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03) +{ + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; +}; + +STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04) +{ + STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE; + STDMETHOD(SetSize)(Int64 newSize) PURE; +}; + +STREAM_INTERFACE(IStreamGetSize, 0x06) +{ + STDMETHOD(GetSize)(UInt64 *size) PURE; +}; + +STREAM_INTERFACE(IOutStreamFlush, 0x07) +{ + STDMETHOD(Flush)() PURE; +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/MyVersion.h b/app/win/installer/7zstub/src/7zip/MyVersion.h new file mode 100644 index 0000000000..2bed0462a1 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/MyVersion.h @@ -0,0 +1,8 @@ +#define MY_VER_MAJOR 4 +#define MY_VER_MINOR 42 +#define MY_VER_BUILD 0 +#define MY_VERSION "4.42" +#define MY_7ZIP_VERSION "7-Zip 4.42" +#define MY_DATE "2006-05-14" +#define MY_COPYRIGHT "Copyright (c) 1999-2006 Igor Pavlov" +#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " " MY_DATE diff --git a/app/win/installer/7zstub/src/7zip/MyVersionInfo.rc b/app/win/installer/7zstub/src/7zip/MyVersionInfo.rc new file mode 100644 index 0000000000..b0a5c338c3 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/MyVersionInfo.rc @@ -0,0 +1,41 @@ +#include +#include "MyVersion.h" + +#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0 + +#ifdef DEBUG +#define DBG_FL VS_FF_DEBUG +#else +#define DBG_FL 0 +#endif + +#define MY_VERSION_INFO(fileType, descr, intName, origName) \ +LANGUAGE 9, 1 \ +1 VERSIONINFO \ + FILEVERSION MY_VER \ + PRODUCTVERSION MY_VER \ + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK \ + FILEFLAGS DBG_FL \ + FILEOS VOS_NT_WINDOWS32 \ + FILETYPE fileType \ + FILESUBTYPE 0x0L \ +BEGIN \ + BLOCK "StringFileInfo" \ + BEGIN \ + BLOCK "040904b0" \ + BEGIN \ + VALUE "CompanyName", "Igor Pavlov" \ + VALUE "FileDescription", descr \ + VALUE "FileVersion", MY_VERSION \ + VALUE "InternalName", intName \ + VALUE "LegalCopyright", MY_COPYRIGHT \ + VALUE "OriginalFilename", origName \ + VALUE "ProductName", "7-Zip" \ + VALUE "ProductVersion", MY_VERSION \ + END \ + END \ +END + +#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(VFT_APP, descr, intName, intName ".exe") + +#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(VFT_DLL, descr, intName, intName ".dll") diff --git a/app/win/installer/7zstub/src/7zip/PropID.h b/app/win/installer/7zstub/src/7zip/PropID.h new file mode 100644 index 0000000000..1dd6ed8213 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/PropID.h @@ -0,0 +1,51 @@ +// Interface/PropID.h + +#ifndef __INTERFACE_PROPID_H +#define __INTERFACE_PROPID_H + +enum +{ + kpidNoProperty = 0, + + kpidHandlerItemIndex = 2, + kpidPath, + kpidName, + kpidExtension, + kpidIsFolder, + kpidSize, + kpidPackedSize, + kpidAttributes, + kpidCreationTime, + kpidLastAccessTime, + kpidLastWriteTime, + kpidSolid, + kpidCommented, + kpidEncrypted, + kpidSplitBefore, + kpidSplitAfter, + kpidDictionarySize, + kpidCRC, + kpidType, + kpidIsAnti, + kpidMethod, + kpidHostOS, + kpidFileSystem, + kpidUser, + kpidGroup, + kpidBlock, + kpidComment, + kpidPosition, + kpidPrefix, + + kpidTotalSize = 0x1100, + kpidFreeSpace, + kpidClusterSize, + kpidVolumeName, + + kpidLocalName = 0x1200, + kpidProvider, + + kpidUserDefined = 0x10000 +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.cpp b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.cpp new file mode 100644 index 0000000000..bef05786b3 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.cpp @@ -0,0 +1,117 @@ +// ArchiveOpenCallback.cpp + +#include "StdAfx.h" + +#include "ArchiveOpenCallback.h" + +#include "Common/StringConvert.h" +#include "Windows/PropVariant.h" + +#include "../../Common/FileStreams.h" + +using namespace NWindows; + +STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes) +{ + return Callback->SetTotal(files, bytes); +} + +STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes) +{ + return Callback->SetTotal(files, bytes); +} + +STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value) +{ + NCOM::CPropVariant propVariant; + if (_subArchiveMode) + { + switch(propID) + { + case kpidName: + propVariant = _subArchiveName; + break; + } + propVariant.Detach(value); + return S_OK; + } + switch(propID) + { + case kpidName: + propVariant = _fileInfo.Name; + break; + case kpidIsFolder: + propVariant = _fileInfo.IsDirectory(); + break; + case kpidSize: + propVariant = _fileInfo.Size; + break; + case kpidAttributes: + propVariant = (UInt32)_fileInfo.Attributes; + break; + case kpidLastAccessTime: + propVariant = _fileInfo.LastAccessTime; + break; + case kpidCreationTime: + propVariant = _fileInfo.CreationTime; + break; + case kpidLastWriteTime: + propVariant = _fileInfo.LastWriteTime; + break; + } + propVariant.Detach(value); + return S_OK; +} + +int COpenCallbackImp::FindName(const UString &name) +{ + for (int i = 0; i < FileNames.Size(); i++) + if (name.CompareNoCase(FileNames[i]) == 0) + return i; + return -1; +} + +struct CInFileStreamVol: public CInFileStream +{ + UString Name; + COpenCallbackImp *OpenCallbackImp; + CMyComPtr OpenCallbackRef; + ~CInFileStreamVol() + { + int index = OpenCallbackImp->FindName(Name); + if (index >= 0) + OpenCallbackImp->FileNames.Delete(index); + } +}; + +STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, + IInStream **inStream) +{ + if (_subArchiveMode) + return S_FALSE; + RINOK(Callback->CheckBreak()); + *inStream = NULL; + UString fullPath = _folderPrefix + name; + if (!NFile::NFind::FindFile(fullPath, _fileInfo)) + return S_FALSE; + if (_fileInfo.IsDirectory()) + return S_FALSE; + CInFileStreamVol *inFile = new CInFileStreamVol; + CMyComPtr inStreamTemp = inFile; + if (!inFile->Open(fullPath)) + return ::GetLastError(); + *inStream = inStreamTemp.Detach(); + inFile->Name = name; + inFile->OpenCallbackImp = this; + inFile->OpenCallbackRef = this; + FileNames.Add(name); + return S_OK; +} + +#ifndef _NO_CRYPTO +STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password) +{ + return Callback->CryptoGetTextPassword(password); +} +#endif + diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.h b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.h new file mode 100644 index 0000000000..84d13edc56 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiveOpenCallback.h @@ -0,0 +1,87 @@ +// ArchiveOpenCallback.h + +#ifndef __ARCHIVE_OPEN_CALLBACK_H +#define __ARCHIVE_OPEN_CALLBACK_H + +#include "Common/String.h" +#include "Common/MyCom.h" +#include "Windows/FileFind.h" + +#ifndef _NO_CRYPTO +#include "../../IPassword.h" +#endif +#include "../../Archive/IArchive.h" + +struct IOpenCallbackUI +{ + virtual HRESULT CheckBreak() = 0; + virtual HRESULT SetTotal(const UInt64 *files, const UInt64 *bytes) = 0; + virtual HRESULT SetCompleted(const UInt64 *files, const UInt64 *bytes) = 0; + #ifndef _NO_CRYPTO + virtual HRESULT CryptoGetTextPassword(BSTR *password) = 0; + virtual HRESULT GetPasswordIfAny(UString &password) = 0; + #endif +}; + +class COpenCallbackImp: + public IArchiveOpenCallback, + public IArchiveOpenVolumeCallback, + public IArchiveOpenSetSubArchiveName, + #ifndef _NO_CRYPTO + public ICryptoGetTextPassword, + #endif + public CMyUnknownImp +{ +public: + #ifndef _NO_CRYPTO + MY_UNKNOWN_IMP3( + IArchiveOpenVolumeCallback, + ICryptoGetTextPassword, + IArchiveOpenSetSubArchiveName + ) + #else + MY_UNKNOWN_IMP2( + IArchiveOpenVolumeCallback, + IArchiveOpenSetSubArchiveName + ) + #endif + + STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes); + STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes); + + // IArchiveOpenVolumeCallback + STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value); + STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream); + + #ifndef _NO_CRYPTO + // ICryptoGetTextPassword + STDMETHOD(CryptoGetTextPassword)(BSTR *password); + #endif + + STDMETHOD(SetSubArchiveName(const wchar_t *name)) + { + _subArchiveMode = true; + _subArchiveName = name; + return S_OK; + } + +private: + UString _folderPrefix; + NWindows::NFile::NFind::CFileInfoW _fileInfo; + bool _subArchiveMode; + UString _subArchiveName; +public: + UStringVector FileNames; + IOpenCallbackUI *Callback; + void Init(const UString &folderPrefix, const UString &fileName) + { + _folderPrefix = folderPrefix; + if (!NWindows::NFile::NFind::FindFile(_folderPrefix + fileName, _fileInfo)) + throw 1; + FileNames.Clear(); + _subArchiveMode = false; + } + int FindName(const UString &name); +}; + +#endif diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.cpp b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.cpp new file mode 100644 index 0000000000..08c352190d --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.cpp @@ -0,0 +1,359 @@ +// ArchiverInfo.cpp + +#include "StdAfx.h" + +#include "ArchiverInfo.h" + +#ifndef EXCLUDE_COM + +#include "Common/StringConvert.h" +#include "Windows/FileFind.h" +#include "Windows/FileName.h" +#include "Windows/DLL.h" +#ifdef _WIN32 +#include "Windows/Registry.h" +#endif +#include "Windows/PropVariant.h" +#include "../../Archive/IArchive.h" + +using namespace NWindows; +using namespace NFile; + +#endif + +extern HINSTANCE g_hInstance; + +#ifndef EXCLUDE_COM + +static void SplitString(const UString &srcString, UStringVector &destStrings) +{ + destStrings.Clear(); + UString string; + int len = srcString.Length(); + if (len == 0) + return; + for (int i = 0; i < len; i++) + { + wchar_t c = srcString[i]; + if (c == L' ') + { + if (!string.IsEmpty()) + { + destStrings.Add(string); + string.Empty(); + } + } + else + string += c; + } + if (!string.IsEmpty()) + destStrings.Add(string); +} + +typedef UInt32 (WINAPI * GetHandlerPropertyFunc)( + PROPID propID, PROPVARIANT *value); + +static UString GetModuleFolderPrefix() +{ + UString path; + NDLL::MyGetModuleFileName(g_hInstance, path); + int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR); + return path.Left(pos + 1); +} + +static wchar_t *kFormatFolderName = L"Formats"; + +#ifdef _WIN32 +static LPCTSTR kRegistryPath = TEXT("Software\\7-zip"); +static LPCWSTR kProgramPathValue = L"Path"; +static bool ReadPathFromRegistry(HKEY baseKey, UString &path) +{ + NRegistry::CKey key; + if(key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS) + if (key.QueryValue(kProgramPathValue, path) == ERROR_SUCCESS) + { + NName::NormalizeDirPathPrefix(path); + return true; + } + return false; +} +#endif + +static UString GetBaseFolderPrefixFromRegistry() +{ + UString moduleFolderPrefix = GetModuleFolderPrefix(); + NFind::CFileInfoW fileInfo; + if (NFind::FindFile(moduleFolderPrefix + kFormatFolderName, fileInfo)) + if (fileInfo.IsDirectory()) + return moduleFolderPrefix; + UString path; + #ifdef _WIN32 + if(ReadPathFromRegistry(HKEY_CURRENT_USER, path)) + return path; + if(ReadPathFromRegistry(HKEY_LOCAL_MACHINE, path)) + return path; + #endif + return moduleFolderPrefix; +} + +typedef UInt32 (WINAPI *CreateObjectPointer)( + const GUID *clsID, + const GUID *interfaceID, + void **outObject); + +#endif + +#ifndef _SFX +static void SetBuffer(CByteBuffer &bb, const Byte *data, int size) +{ + bb.SetCapacity(size); + memmove((Byte *)bb, data, size); +} +#endif + +void ReadArchiverInfoList(CObjectVector &archivers) +{ + archivers.Clear(); + + #ifdef EXCLUDE_COM + + #ifdef FORMAT_7Z + { + CArchiverInfo item; + item.UpdateEnabled = true; + item.Name = L"7z"; + item.Extensions.Add(CArchiverExtInfo(L"7z")); + #ifndef _SFX + const unsigned char kSig[] = {'7' , 'z', 0xBC, 0xAF, 0x27, 0x1C}; + SetBuffer(item.StartSignature, kSig, 6); + #endif + archivers.Add(item); + } + #endif + + #ifdef FORMAT_BZIP2 + { + CArchiverInfo item; + item.UpdateEnabled = true; + item.KeepName = true; + item.Name = L"BZip2"; + item.Extensions.Add(CArchiverExtInfo(L"bz2")); + item.Extensions.Add(CArchiverExtInfo(L"tbz2", L".tar")); + #ifndef _SFX + const unsigned char sig[] = {'B' , 'Z', 'h' }; + SetBuffer(item.StartSignature, sig, 3); + #endif + archivers.Add(item); + } + #endif + + #ifdef FORMAT_GZIP + { + CArchiverInfo item; + item.UpdateEnabled = true; + item.Name = L"GZip"; + item.Extensions.Add(CArchiverExtInfo(L"gz")); + item.Extensions.Add(CArchiverExtInfo(L"tgz", L".tar")); + #ifndef _SFX + const unsigned char sig[] = { 0x1F, 0x8B }; + SetBuffer(item.StartSignature, sig, 2); + #endif + archivers.Add(item); + } + #endif + + #ifdef FORMAT_SPLIT + { + CArchiverInfo item; + item.UpdateEnabled = false; + item.KeepName = true; + item.Name = L"Split"; + item.Extensions.Add(CArchiverExtInfo(L"001")); + archivers.Add(item); + } + #endif + + #ifdef FORMAT_TAR + { + CArchiverInfo item; + item.UpdateEnabled = true; + item.Name = L"Tar"; + item.Extensions.Add(CArchiverExtInfo(L"tar")); + archivers.Add(item); + } + #endif + + #ifdef FORMAT_ZIP + { + CArchiverInfo item; + item.UpdateEnabled = true; + item.Name = L"Zip"; + item.Extensions.Add(CArchiverExtInfo(L"zip")); + #ifndef _SFX + const unsigned char sig[] = { 0x50, 0x4B, 0x03, 0x04 }; + SetBuffer(item.StartSignature, sig, 4); + #endif + archivers.Add(item); + } + #endif + + #ifdef FORMAT_CPIO + { + CArchiverInfo item; + item.Name = L"Cpio"; + item.Extensions.Add(CArchiverExtInfo(L"cpio")); + archivers.Add(item); + } + #endif + + #ifdef FORMAT_RPM + { + CArchiverInfo item; + item.Name = L"Rpm"; + item.Extensions.Add(CArchiverExtInfo(L"rpm", L".cpio.gz")); + archivers.Add(item); + } + #endif + + #ifdef FORMAT_ARJ + { + CArchiverInfo item; + item.Name = L"Arj"; + item.Extensions.Add(CArchiverExtInfo(L"arj")); + #ifndef _SFX + const unsigned char sig[] = { 0x60, 0xEA }; + SetBuffer(item.StartSignature, sig, 2); + #endif + archivers.Add(item); + } + #endif + + #ifdef FORMAT_Z + { + CArchiverInfo item; + item.Name = L"Z"; + item.Extensions.Add(CArchiverExtInfo(L"Z")); + #ifndef _SFX + const unsigned char sig[] = { 0x1F, 0x9D }; + SetBuffer(item.StartSignature, sig, 2); + #endif + archivers.Add(item); + } + #endif + + #else + + UString folderPath = GetBaseFolderPrefixFromRegistry() + + (UString)kFormatFolderName + (UString)WSTRING_PATH_SEPARATOR; + NFind::CEnumeratorW enumerator(folderPath + L"*"); + NFind::CFileInfoW fileInfo; + while (enumerator.Next(fileInfo)) + { + if (fileInfo.IsDirectory()) + continue; + UString filePath = folderPath + fileInfo.Name; + { + NDLL::CLibrary library; + if (!library.LoadEx(filePath, LOAD_LIBRARY_AS_DATAFILE)) + continue; + } + + NDLL::CLibrary library; + if (!library.Load(filePath)) + continue; + GetHandlerPropertyFunc getHandlerProperty = (GetHandlerPropertyFunc) + library.GetProcAddress("GetHandlerProperty"); + if (getHandlerProperty == NULL) + continue; + + CArchiverInfo item; + item.FilePath = filePath; + + NWindows::NCOM::CPropVariant prop; + if (getHandlerProperty(NArchive::kName, &prop) != S_OK) + continue; + if (prop.vt != VT_BSTR) + continue; + item.Name = prop.bstrVal; + prop.Clear(); + + if (getHandlerProperty(NArchive::kClassID, &prop) != S_OK) + continue; + if (prop.vt != VT_BSTR) + continue; + item.ClassID = *(const GUID *)prop.bstrVal; + prop.Clear(); + + if (getHandlerProperty(NArchive::kExtension, &prop) != S_OK) + continue; + if (prop.vt != VT_BSTR) + continue; + + UString ext = prop.bstrVal; + UString addExt; + + prop.Clear(); + + if (getHandlerProperty(NArchive::kAddExtension, &prop) != S_OK) + continue; + if (prop.vt == VT_BSTR) + { + addExt = prop.bstrVal; + } + else if (prop.vt != VT_EMPTY) + continue; + prop.Clear(); + + UStringVector exts, addExts; + SplitString(ext, exts); + SplitString(addExt, addExts); + + prop.Clear(); + for (int i = 0; i < exts.Size(); i++) + { + CArchiverExtInfo extInfo; + extInfo.Ext = exts[i]; + if (addExts.Size() > 0) + extInfo.AddExt = addExts[i]; + if (extInfo.AddExt == L"*") + extInfo.AddExt.Empty(); + item.Extensions.Add(extInfo); + } + + if (getHandlerProperty(NArchive::kUpdate, &prop) == S_OK) + if (prop.vt == VT_BOOL) + item.UpdateEnabled = VARIANT_BOOLToBool(prop.boolVal); + prop.Clear(); + + if (item.UpdateEnabled) + { + if (getHandlerProperty(NArchive::kKeepName, &prop) == S_OK) + if (prop.vt == VT_BOOL) + item.KeepName = VARIANT_BOOLToBool(prop.boolVal); + prop.Clear(); + } + + if (getHandlerProperty(NArchive::kStartSignature, &prop) == S_OK) + { + if (prop.vt == VT_BSTR) + { + UINT len = ::SysStringByteLen(prop.bstrVal); + item.StartSignature.SetCapacity(len); + memmove(item.StartSignature, prop.bstrVal, len); + } + } + prop.Clear(); + + if (getHandlerProperty(NArchive::kAssociate, &prop) == S_OK) + if (prop.vt == VT_BOOL) + item.Associate = VARIANT_BOOLToBool(prop.boolVal); + prop.Clear(); + + + archivers.Add(item); + } + + #endif +} + + diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.h b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.h new file mode 100644 index 0000000000..8c42f7c5b8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/ArchiverInfo.h @@ -0,0 +1,66 @@ +// ArchiverInfo.h + +#ifndef __ARCHIVERINFO_H +#define __ARCHIVERINFO_H + +#include "Common/String.h" +#include "Common/Types.h" +#include "Common/Buffer.h" + +struct CArchiverExtInfo +{ + UString Ext; + UString AddExt; + CArchiverExtInfo() {} + CArchiverExtInfo(const UString &ext): Ext(ext) {} + CArchiverExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {} +}; + +struct CArchiverInfo +{ + #ifndef EXCLUDE_COM + UString FilePath; + CLSID ClassID; + #endif + UString Name; + CObjectVector Extensions; + #ifndef _SFX + CByteBuffer StartSignature; + CByteBuffer FinishSignature; + bool Associate; + #endif + int FindExtension(const UString &ext) const + { + for (int i = 0; i < Extensions.Size(); i++) + if (ext.CompareNoCase(Extensions[i].Ext) == 0) + return i; + return -1; + } + UString GetAllExtensions() const + { + UString s; + for (int i = 0; i < Extensions.Size(); i++) + { + if (i > 0) + s += ' '; + s += Extensions[i].Ext; + } + return s; + } + const UString &GetMainExtension() const + { + return Extensions[0].Ext; + } + bool UpdateEnabled; + bool KeepName; + + CArchiverInfo(): UpdateEnabled(false), KeepName(false) + #ifndef _SFX + ,Associate(true) + #endif + {} +}; + +void ReadArchiverInfoList(CObjectVector &archivers); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.cpp b/app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.cpp new file mode 100644 index 0000000000..1ada83a89b --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.cpp @@ -0,0 +1,23 @@ +// DefaultName.cpp + +#include "StdAfx.h" + +#include "DefaultName.h" + +static const wchar_t *kEmptyFileAlias = L"[Content]"; + +UString GetDefaultName2(const UString &fileName, + const UString &extension, const UString &addSubExtension) +{ + int extLength = extension.Length(); + int fileNameLength = fileName.Length(); + if (fileNameLength > extLength + 1) + { + int dotPos = fileNameLength - (extLength + 1); + if (fileName[dotPos] == '.') + if (extension.CompareNoCase(fileName.Mid(dotPos + 1)) == 0) + return fileName.Left(dotPos) + addSubExtension; + } + return kEmptyFileAlias; +} + diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.h b/app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.h new file mode 100644 index 0000000000..1788cb8560 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/DefaultName.h @@ -0,0 +1,11 @@ +// DefaultName.h + +#ifndef __DEFAULTNAME_H +#define __DEFAULTNAME_H + +#include "Common/String.h" + +UString GetDefaultName2(const UString &fileName, + const UString &extension, const UString &addSubExtension); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.cpp b/app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.cpp new file mode 100644 index 0000000000..59cb31cc59 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.cpp @@ -0,0 +1,528 @@ +// OpenArchive.cpp + +#include "StdAfx.h" + +#include "OpenArchive.h" + +#include "Common/Wildcard.h" + +#include "Windows/FileName.h" +#include "Windows/FileDir.h" +#include "Windows/Defs.h" +#include "Windows/PropVariant.h" + +#include "../../Common/FileStreams.h" +#include "../../Common/StreamUtils.h" + +#include "Common/StringConvert.h" + +#ifdef FORMAT_7Z +#include "../../Archive/7z/7zHandler.h" +#endif + +#ifdef FORMAT_BZIP2 +#include "../../Archive/BZip2/BZip2Handler.h" +#endif + +#ifdef FORMAT_GZIP +#include "../../Archive/GZip/GZipHandler.h" +#endif + +#ifdef FORMAT_SPLIT +#include "../../Archive/Split/SplitHandler.h" +#endif + +#ifdef FORMAT_TAR +#include "../../Archive/Tar/TarHandler.h" +#endif + +#ifdef FORMAT_ZIP +#include "../../Archive/Zip/ZipHandler.h" +#endif + +#ifdef FORMAT_Z +#include "../../Archive/Z/ZHandler.h" +#endif + +#ifndef EXCLUDE_COM +#include "HandlerLoader.h" +#endif + +#include "DefaultName.h" + +using namespace NWindows; + +HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result) +{ + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidPath, &prop)); + if(prop.vt == VT_BSTR) + result = prop.bstrVal; + else if (prop.vt == VT_EMPTY) + result.Empty(); + else + return E_FAIL; + return S_OK; +} + +HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result) +{ + RINOK(GetArchiveItemPath(archive, index, result)); + if (result.IsEmpty()) + result = defaultName; + return S_OK; +} + +HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index, + const FILETIME &defaultFileTime, FILETIME &fileTime) +{ + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, kpidLastWriteTime, &prop)); + if (prop.vt == VT_FILETIME) + fileTime = prop.filetime; + else if (prop.vt == VT_EMPTY) + fileTime = defaultFileTime; + else + return E_FAIL; + return S_OK; +} + +static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result) +{ + NCOM::CPropVariant prop; + RINOK(archive->GetProperty(index, propID, &prop)); + if(prop.vt == VT_BOOL) + result = VARIANT_BOOLToBool(prop.boolVal); + else if (prop.vt == VT_EMPTY) + result = false; + else + return E_FAIL; + return S_OK; +} + +HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result) +{ + return IsArchiveItemProp(archive, index, kpidIsFolder, result); +} + +HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result) +{ + return IsArchiveItemProp(archive, index, kpidIsAnti, result); +} + +// Static-SFX (for Linux) can be big +const UInt64 kMaxCheckStartPosition = +#ifdef _WIN32 +1 << 20; +#else +1 << 22; +#endif + + +HRESULT ReOpenArchive(IInArchive *archive, const UString &fileName) +{ + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr inStream(inStreamSpec); + inStreamSpec->Open(fileName); + return archive->Open(inStream, &kMaxCheckStartPosition, NULL); +} + +#ifndef _SFX +static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size) +{ + for (size_t i = 0; i < size; i++) + if (p1[i] != p2[i]) + return false; + return true; +} +#endif + +HRESULT OpenArchive( + IInStream *inStream, + const UString &fileName, + #ifndef EXCLUDE_COM + HMODULE *module, + #endif + IInArchive **archiveResult, + CArchiverInfo &archiverInfoResult, + UString &defaultItemName, + IArchiveOpenCallback *openArchiveCallback) +{ + *archiveResult = NULL; + CObjectVector archiverInfoList; + ReadArchiverInfoList(archiverInfoList); + UString extension; + { + int dotPos = fileName.ReverseFind(L'.'); + if (dotPos >= 0) + extension = fileName.Mid(dotPos + 1); + } + CIntVector orderIndices; + int i; + bool finded = false; + for(i = 0; i < archiverInfoList.Size(); i++) + { + if (archiverInfoList[i].FindExtension(extension) >= 0) + { + orderIndices.Insert(0, i); + finded = true; + } + else + orderIndices.Add(i); + } + + #ifndef _SFX + if (!finded) + { + CByteBuffer byteBuffer; + const UInt32 kBufferSize = (200 << 10); + byteBuffer.SetCapacity(kBufferSize); + Byte *buffer = byteBuffer; + RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL)); + UInt32 processedSize; + RINOK(ReadStream(inStream, buffer, kBufferSize, &processedSize)); + int numFinded = 0; + for (int pos = (int)processedSize; pos >= 0 ; pos--) + { + for(int i = numFinded; i < orderIndices.Size(); i++) + { + int index = orderIndices[i]; + const CArchiverInfo &ai = archiverInfoList[index]; + const CByteBuffer &sig = ai.StartSignature; + if (sig.GetCapacity() == 0) + continue; + if (pos + sig.GetCapacity() > processedSize) + continue; + if (TestSignature(buffer + pos, sig, sig.GetCapacity())) + { + orderIndices.Delete(i); + orderIndices.Insert(0, index); + numFinded++; + } + } + } + } + #endif + + HRESULT badResult = S_OK; + for(i = 0; i < orderIndices.Size(); i++) + { + inStream->Seek(0, STREAM_SEEK_SET, NULL); + const CArchiverInfo &archiverInfo = archiverInfoList[orderIndices[i]]; + #ifndef EXCLUDE_COM + CHandlerLoader loader; + #endif + CMyComPtr archive; + + #ifdef FORMAT_7Z + if (archiverInfo.Name.CompareNoCase(L"7z") == 0) + archive = new NArchive::N7z::CHandler; + #endif + + #ifdef FORMAT_BZIP2 + if (archiverInfo.Name.CompareNoCase(L"BZip2") == 0) + archive = new NArchive::NBZip2::CHandler; + #endif + + #ifdef FORMAT_GZIP + if (archiverInfo.Name.CompareNoCase(L"GZip") == 0) + archive = new NArchive::NGZip::CHandler; + #endif + + #ifdef FORMAT_SPLIT + if (archiverInfo.Name.CompareNoCase(L"Split") == 0) + archive = new NArchive::NSplit::CHandler; + #endif + + #ifdef FORMAT_TAR + if (archiverInfo.Name.CompareNoCase(L"Tar") == 0) + archive = new NArchive::NTar::CHandler; + #endif + + #ifdef FORMAT_ZIP + if (archiverInfo.Name.CompareNoCase(L"Zip") == 0) + archive = new NArchive::NZip::CHandler; + #endif + + #ifdef FORMAT_Z + if (archiverInfo.Name.CompareNoCase(L"Z") == 0) + archive = new NArchive::NZ::CHandler; + #endif + + + #ifndef EXCLUDE_COM + if (!archive) + { + HRESULT result = loader.CreateHandler(archiverInfo.FilePath, + archiverInfo.ClassID, (void **)&archive, false); + if (result != S_OK) + continue; + } + #endif + + if (!archive) + return E_FAIL; + + HRESULT result = archive->Open(inStream, &kMaxCheckStartPosition, openArchiveCallback); + if(result == S_FALSE) + continue; + if(result != S_OK) + { + badResult = result; + if(result == E_ABORT) + break; + continue; + } + *archiveResult = archive.Detach(); + #ifndef EXCLUDE_COM + *module = loader.Detach(); + #endif + archiverInfoResult = archiverInfo; + int subExtIndex = archiverInfo.FindExtension(extension); + if (subExtIndex < 0) + subExtIndex = 0; + defaultItemName = GetDefaultName2(fileName, + archiverInfo.Extensions[subExtIndex].Ext, + archiverInfo.Extensions[subExtIndex].AddExt); + + return S_OK; + } + if (badResult != S_OK) + return badResult; + return S_FALSE; +} + +HRESULT OpenArchive(const UString &filePath, + #ifndef EXCLUDE_COM + HMODULE *module, + #endif + IInArchive **archiveResult, + CArchiverInfo &archiverInfo, + UString &defaultItemName, + IArchiveOpenCallback *openArchiveCallback) +{ + CInFileStream *inStreamSpec = new CInFileStream; + CMyComPtr inStream(inStreamSpec); + if (!inStreamSpec->Open(filePath)) + return GetLastError(); + return OpenArchive(inStream, ExtractFileNameFromPath(filePath), + #ifndef EXCLUDE_COM + module, + #endif + archiveResult, archiverInfo, + defaultItemName, openArchiveCallback); +} + +static void MakeDefaultName(UString &name) +{ + int dotPos = name.ReverseFind(L'.'); + if (dotPos < 0) + return; + UString ext = name.Mid(dotPos + 1); + if (ext.IsEmpty()) + return; + for (int pos = 0; pos < ext.Length(); pos++) + if (ext[pos] < L'0' || ext[pos] > L'9') + return; + name = name.Left(dotPos); +} + +HRESULT OpenArchive(const UString &fileName, + #ifndef EXCLUDE_COM + HMODULE *module0, + HMODULE *module1, + #endif + IInArchive **archive0, + IInArchive **archive1, + CArchiverInfo &archiverInfo0, + CArchiverInfo &archiverInfo1, + UString &defaultItemName0, + UString &defaultItemName1, + IArchiveOpenCallback *openArchiveCallback) +{ + HRESULT result = OpenArchive(fileName, + #ifndef EXCLUDE_COM + module0, + #endif + archive0, archiverInfo0, defaultItemName0, openArchiveCallback); + RINOK(result); + CMyComPtr getStream; + result = (*archive0)->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream); + if (result != S_OK || getStream == 0) + return S_OK; + + CMyComPtr subSeqStream; + result = getStream->GetStream(0, &subSeqStream); + if (result != S_OK) + return S_OK; + + CMyComPtr subStream; + if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK) + return S_OK; + if (!subStream) + return S_OK; + + UInt32 numItems; + RINOK((*archive0)->GetNumberOfItems(&numItems)); + if (numItems < 1) + return S_OK; + + UString subPath; + RINOK(GetArchiveItemPath(*archive0, 0, subPath)) + if (subPath.IsEmpty()) + { + MakeDefaultName(defaultItemName0); + subPath = defaultItemName0; + if (archiverInfo0.Name.CompareNoCase(L"7z") == 0) + { + if (subPath.Right(3).CompareNoCase(L".7z") != 0) + subPath += L".7z"; + } + } + else + subPath = ExtractFileNameFromPath(subPath); + + CMyComPtr setSubArchiveName; + openArchiveCallback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName); + if (setSubArchiveName) + setSubArchiveName->SetSubArchiveName(subPath); + + result = OpenArchive(subStream, subPath, + #ifndef EXCLUDE_COM + module1, + #endif + archive1, archiverInfo1, defaultItemName1, openArchiveCallback); + return S_OK; +} + +HRESULT MyOpenArchive(const UString &archiveName, + #ifndef EXCLUDE_COM + HMODULE *module, + #endif + IInArchive **archive, + UString &defaultItemName, + IOpenCallbackUI *openCallbackUI) +{ + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + CMyComPtr openCallback = openCallbackSpec; + openCallbackSpec->Callback = openCallbackUI; + + UString fullName; + int fileNamePartStartIndex; + NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex); + openCallbackSpec->Init( + fullName.Left(fileNamePartStartIndex), + fullName.Mid(fileNamePartStartIndex)); + + CArchiverInfo archiverInfo; + return OpenArchive(archiveName, + #ifndef EXCLUDE_COM + module, + #endif + archive, + archiverInfo, + defaultItemName, + openCallback); +} + +HRESULT MyOpenArchive(const UString &archiveName, + #ifndef EXCLUDE_COM + HMODULE *module0, + HMODULE *module1, + #endif + IInArchive **archive0, + IInArchive **archive1, + UString &defaultItemName0, + UString &defaultItemName1, + UStringVector &volumePaths, + IOpenCallbackUI *openCallbackUI) +{ + COpenCallbackImp *openCallbackSpec = new COpenCallbackImp; + CMyComPtr openCallback = openCallbackSpec; + openCallbackSpec->Callback = openCallbackUI; + + UString fullName; + int fileNamePartStartIndex; + NFile::NDirectory::MyGetFullPathName(archiveName, fullName, fileNamePartStartIndex); + UString prefix = fullName.Left(fileNamePartStartIndex); + UString name = fullName.Mid(fileNamePartStartIndex); + openCallbackSpec->Init(prefix, name); + + CArchiverInfo archiverInfo0, archiverInfo1; + HRESULT result = OpenArchive(archiveName, + #ifndef EXCLUDE_COM + module0, + module1, + #endif + archive0, + archive1, + archiverInfo0, + archiverInfo1, + defaultItemName0, + defaultItemName1, + openCallback); + RINOK(result); + volumePaths.Add(prefix + name); + for (int i = 0; i < openCallbackSpec->FileNames.Size(); i++) + volumePaths.Add(prefix + openCallbackSpec->FileNames[i]); + return S_OK; +} + +HRESULT CArchiveLink::Close() +{ + if (Archive1 != 0) + RINOK(Archive1->Close()); + if (Archive0 != 0) + RINOK(Archive0->Close()); + return S_OK; +} + +void CArchiveLink::Release() +{ + if (Archive1 != 0) + Archive1.Release(); + if (Archive0 != 0) + Archive0.Release(); + #ifndef EXCLUDE_COM + Library1.Free(); + Library0.Free(); + #endif +} + +HRESULT OpenArchive(const UString &archiveName, + CArchiveLink &archiveLink, + IArchiveOpenCallback *openCallback) +{ + return OpenArchive(archiveName, + #ifndef EXCLUDE_COM + &archiveLink.Library0, &archiveLink.Library1, + #endif + &archiveLink.Archive0, &archiveLink.Archive1, + archiveLink.ArchiverInfo0, archiveLink.ArchiverInfo1, + archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, + openCallback); +} + +HRESULT MyOpenArchive(const UString &archiveName, + CArchiveLink &archiveLink, + IOpenCallbackUI *openCallbackUI) +{ + return MyOpenArchive(archiveName, + #ifndef EXCLUDE_COM + &archiveLink.Library0, &archiveLink.Library1, + #endif + &archiveLink.Archive0, &archiveLink.Archive1, + archiveLink.DefaultItemName0, archiveLink.DefaultItemName1, + archiveLink.VolumePaths, + openCallbackUI); +} + +HRESULT ReOpenArchive(CArchiveLink &archiveLink, + const UString &fileName) +{ + if (archiveLink.GetNumLevels() > 1) + return E_NOTIMPL; + if (archiveLink.GetNumLevels() == 0) + return MyOpenArchive(fileName, archiveLink, 0); + return ReOpenArchive(archiveLink.GetArchive(), fileName); +} diff --git a/app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.h b/app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.h new file mode 100644 index 0000000000..be6d757d7f --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Common/OpenArchive.h @@ -0,0 +1,134 @@ +// OpenArchive.h + +#ifndef __OPENARCHIVE_H +#define __OPENARCHIVE_H + +#include "Common/String.h" +#include "Windows/FileFind.h" + +#include "../../Archive/IArchive.h" +#include "ArchiverInfo.h" +#include "ArchiveOpenCallback.h" + +#ifndef EXCLUDE_COM +#include "Windows/DLL.h" +#endif + +HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, UString &result); +HRESULT GetArchiveItemPath(IInArchive *archive, UInt32 index, const UString &defaultName, UString &result); +HRESULT GetArchiveItemFileTime(IInArchive *archive, UInt32 index, + const FILETIME &defaultFileTime, FILETIME &fileTime); +HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result); +HRESULT IsArchiveItemAnti(IInArchive *archive, UInt32 index, bool &result); + +struct ISetSubArchiveName +{ + virtual void SetSubArchiveName(const wchar_t *name) = 0; +}; + +HRESULT OpenArchive( + IInStream *inStream, + const UString &fileName, + #ifndef EXCLUDE_COM + HMODULE *module, + #endif + IInArchive **archiveResult, + CArchiverInfo &archiverInfoResult, + UString &defaultItemName, + IArchiveOpenCallback *openArchiveCallback); + +HRESULT OpenArchive(const UString &filePath, + #ifndef EXCLUDE_COM + HMODULE *module, + #endif + IInArchive **archive, + CArchiverInfo &archiverInfo, + UString &defaultItemName, + IArchiveOpenCallback *openArchiveCallback); + +HRESULT OpenArchive(const UString &filePath, + #ifndef EXCLUDE_COM + HMODULE *module0, + HMODULE *module1, + #endif + IInArchive **archive0, + IInArchive **archive1, + CArchiverInfo &archiverInfo0, + CArchiverInfo &archiverInfo1, + UString &defaultItemName0, + UString &defaultItemName1, + IArchiveOpenCallback *openArchiveCallback); + + +HRESULT ReOpenArchive(IInArchive *archive, + const UString &fileName); + +HRESULT MyOpenArchive(const UString &archiveName, + #ifndef EXCLUDE_COM + HMODULE *module, + #endif + IInArchive **archive, + UString &defaultItemName, + IOpenCallbackUI *openCallbackUI); + +HRESULT MyOpenArchive(const UString &archiveName, + #ifndef EXCLUDE_COM + HMODULE *module0, + HMODULE *module1, + #endif + IInArchive **archive0, + IInArchive **archive1, + UString &defaultItemName0, + UString &defaultItemName1, + UStringVector &volumePaths, + IOpenCallbackUI *openCallbackUI); + +struct CArchiveLink +{ + #ifndef EXCLUDE_COM + NWindows::NDLL::CLibrary Library0; + NWindows::NDLL::CLibrary Library1; + #endif + CMyComPtr Archive0; + CMyComPtr Archive1; + UString DefaultItemName0; + UString DefaultItemName1; + + CArchiverInfo ArchiverInfo0; + CArchiverInfo ArchiverInfo1; + + UStringVector VolumePaths; + + int GetNumLevels() const + { + int result = 0; + if (Archive0) + { + result++; + if (Archive1) + result++; + } + return result; + } + + + IInArchive *GetArchive() { return Archive1 != 0 ? Archive1: Archive0; } + UString GetDefaultItemName() { return Archive1 != 0 ? DefaultItemName1: DefaultItemName0; } + const CArchiverInfo &GetArchiverInfo() { return Archive1 != 0 ? ArchiverInfo1: ArchiverInfo0; } + HRESULT Close(); + void Release(); +}; + +HRESULT OpenArchive(const UString &archiveName, + CArchiveLink &archiveLink, + IArchiveOpenCallback *openCallback); + +HRESULT MyOpenArchive(const UString &archiveName, + CArchiveLink &archiveLink, + IOpenCallbackUI *openCallbackUI); + +HRESULT ReOpenArchive(CArchiveLink &archiveLink, + const UString &fileName); + +#endif + diff --git a/app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.cpp b/app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.cpp new file mode 100644 index 0000000000..92558930d8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.cpp @@ -0,0 +1,45 @@ +// MyMessages.cpp + +#include "StdAfx.h" + +#include "MyMessages.h" +#include "Common/String.h" +#include "Common/StringConvert.h" + +#include "Windows/Error.h" +#include "Windows/ResourceString.h" + +#ifdef LANG +#include "../../FileManager/LangUtils.h" +#endif + +using namespace NWindows; + +void MyMessageBox(HWND window, LPCWSTR message) +{ + ::MessageBoxW(window, message, L"7-Zip", 0); +} + +void MyMessageBox(UINT32 id + #ifdef LANG + ,UINT32 langID + #endif + ) +{ + #ifdef LANG + MyMessageBox(LangString(id, langID)); + #else + MyMessageBox(MyLoadStringW(id)); + #endif +} + +void ShowErrorMessage(HWND window, DWORD message) +{ + MyMessageBox(window, NError::MyFormatMessageW(message)); +} + +void ShowLastErrorMessage(HWND window) +{ + ShowErrorMessage(window, ::GetLastError()); +} + diff --git a/app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.h b/app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.h new file mode 100644 index 0000000000..e3a755eef8 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/Explorer/MyMessages.h @@ -0,0 +1,24 @@ +// MyMessages.h + +#ifndef __MYMESSAGES_H +#define __MYMESSAGES_H + +#include "Common/String.h" + +void MyMessageBox(HWND window, LPCWSTR message); + +inline void MyMessageBox(LPCWSTR message) + { MyMessageBox(0, message); } + +void MyMessageBox(UINT32 id + #ifdef LANG + ,UINT32 langID + #endif + ); + +void ShowErrorMessage(HWND window, DWORD errorMessage); +inline void ShowErrorMessage(DWORD errorMessage) + { ShowErrorMessage(0, errorMessage); } +void ShowLastErrorMessage(HWND window = 0); + +#endif diff --git a/app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.cpp b/app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.cpp new file mode 100644 index 0000000000..98afce4ca1 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.cpp @@ -0,0 +1,53 @@ +// OpenCallbackGUI.cpp + +#include "StdAfx.h" + +#include "OpenCallbackGUI.h" + +#include "Common/StdOutStream.h" +#include "Common/StdInStream.h" +#include "Common/StringConvert.h" + +#ifndef _NO_CRYPTO +#include "../../FileManager/Resource/PasswordDialog/PasswordDialog.h" +#endif + +HRESULT COpenCallbackGUI::CheckBreak() +{ + return S_OK; +} + +HRESULT COpenCallbackGUI::SetTotal(const UInt64 *files, const UInt64 *bytes) +{ + return S_OK; +} + +HRESULT COpenCallbackGUI::SetCompleted(const UInt64 *files, const UInt64 *bytes) +{ + return S_OK; +} + +#ifndef _NO_CRYPTO +HRESULT COpenCallbackGUI::CryptoGetTextPassword(BSTR *password) +{ + if (!PasswordIsDefined) + { + CPasswordDialog dialog; + if (dialog.Create(ParentWindow) == IDCANCEL) + return E_ABORT; + Password = dialog.Password; + PasswordIsDefined = true; + } + CMyComBSTR tempName(Password); + *password = tempName.Detach(); + return S_OK; +} + +HRESULT COpenCallbackGUI::GetPasswordIfAny(UString &password) +{ + if (PasswordIsDefined) + password = Password; + return S_OK; +} +#endif + diff --git a/app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.h b/app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.h new file mode 100644 index 0000000000..76a6ec41cf --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/UI/GUI/OpenCallbackGUI.h @@ -0,0 +1,30 @@ +// OpenCallbackGUI.h + +#ifndef __OPEN_CALLBACK_GUI_H +#define __OPEN_CALLBACK_GUI_H + +#include "../Common/ArchiveOpenCallback.h" + +class COpenCallbackGUI: public IOpenCallbackUI +{ +public: + HRESULT CheckBreak(); + HRESULT SetTotal(const UInt64 *files, const UInt64 *bytes); + HRESULT SetCompleted(const UInt64 *files, const UInt64 *bytes); + #ifndef _NO_CRYPTO + HRESULT CryptoGetTextPassword(BSTR *password); + HRESULT GetPasswordIfAny(UString &password); + bool PasswordIsDefined; + UString Password; + #endif + + HWND ParentWindow; + + COpenCallbackGUI(): + #ifndef _NO_CRYPTO + PasswordIsDefined(false), + #endif + ParentWindow(0) {} +}; + +#endif diff --git a/app/win/installer/7zstub/src/Common/Alloc.cpp b/app/win/installer/7zstub/src/Common/Alloc.cpp new file mode 100644 index 0000000000..dcb331ee9f --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Alloc.cpp @@ -0,0 +1,118 @@ +// Common/Alloc.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include "MyWindows.h" +#else +#include +#endif + +#include "Alloc.h" + +/* #define _SZ_ALLOC_DEBUG */ +/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */ +#ifdef _SZ_ALLOC_DEBUG +#include +int g_allocCount = 0; +int g_allocCountMid = 0; +int g_allocCountBig = 0; +#endif + +void *MyAlloc(size_t size) throw() +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc %10d bytes; count = %10d", size, g_allocCount++); + #endif + return ::malloc(size); +} + +void MyFree(void *address) throw() +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree; count = %10d", --g_allocCount); + #endif + + ::free(address); +} + +#ifdef _WIN32 + +void *MidAlloc(size_t size) throw() +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_Mid %10d bytes; count = %10d", size, g_allocCountMid++); + #endif + return ::VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +} + +void MidFree(void *address) throw() +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree_Mid; count = %10d", --g_allocCountMid); + #endif + if (address == 0) + return; + ::VirtualFree(address, 0, MEM_RELEASE); +} + +static SIZE_T g_LargePageSize = + #ifdef _WIN64 + (1 << 21); + #else + (1 << 22); + #endif + +typedef SIZE_T (WINAPI *GetLargePageMinimumP)(); + +bool SetLargePageSize() +{ + GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP) + ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum"); + if (largePageMinimum == 0) + return false; + SIZE_T size = largePageMinimum(); + if (size == 0 || (size & (size - 1)) != 0) + return false; + g_LargePageSize = size; + return true; +} + + +void *BigAlloc(size_t size) throw() +{ + if (size == 0) + return 0; + #ifdef _SZ_ALLOC_DEBUG + fprintf(stderr, "\nAlloc_Big %10d bytes; count = %10d", size, g_allocCountBig++); + #endif + + if (size >= (1 << 18)) + { + void *res = ::VirtualAlloc(0, (size + g_LargePageSize - 1) & (~(g_LargePageSize - 1)), + MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); + if (res != 0) + return res; + } + return ::VirtualAlloc(0, size, MEM_COMMIT, PAGE_READWRITE); +} + +void BigFree(void *address) throw() +{ + #ifdef _SZ_ALLOC_DEBUG + if (address != 0) + fprintf(stderr, "\nFree_Big; count = %10d", --g_allocCountBig); + #endif + + if (address == 0) + return; + ::VirtualFree(address, 0, MEM_RELEASE); +} + +#endif diff --git a/app/win/installer/7zstub/src/Common/Alloc.h b/app/win/installer/7zstub/src/Common/Alloc.h new file mode 100644 index 0000000000..2ae3891de6 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Alloc.h @@ -0,0 +1,29 @@ +// Common/Alloc.h + +#ifndef __COMMON_ALLOC_H +#define __COMMON_ALLOC_H + +#include + +void *MyAlloc(size_t size) throw(); +void MyFree(void *address) throw(); + +#ifdef _WIN32 + +bool SetLargePageSize(); + +void *MidAlloc(size_t size) throw(); +void MidFree(void *address) throw(); +void *BigAlloc(size_t size) throw(); +void BigFree(void *address) throw(); + +#else + +#define MidAlloc(size) MyAlloc(size) +#define MidFree(address) MyFree(address) +#define BigAlloc(size) MyAlloc(size) +#define BigFree(address) MyFree(address) + +#endif + +#endif diff --git a/app/win/installer/7zstub/src/Common/Buffer.h b/app/win/installer/7zstub/src/Common/Buffer.h new file mode 100644 index 0000000000..5099a15ad7 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Buffer.h @@ -0,0 +1,77 @@ +// Common/Buffer.h + +#ifndef __COMMON_BUFFER_H +#define __COMMON_BUFFER_H + +#include "Defs.h" + +template class CBuffer +{ +protected: + size_t _capacity; + T *_items; + void Free() + { + delete []_items; + _items = 0; + _capacity = 0; + } +public: + CBuffer(): _capacity(0), _items(0) {}; + CBuffer(const CBuffer &buffer): _capacity(0), _items(0) { *this = buffer; } + CBuffer(size_t size): _items(0), _capacity(0) { SetCapacity(size); } + virtual ~CBuffer() { delete []_items; } + operator T *() { return _items; }; + operator const T *() const { return _items; }; + size_t GetCapacity() const { return _capacity; } + void SetCapacity(size_t newCapacity) + { + if (newCapacity == _capacity) + return; + T *newBuffer; + if (newCapacity > 0) + { + newBuffer = new T[newCapacity]; + if(_capacity > 0) + memmove(newBuffer, _items, MyMin(_capacity, newCapacity) * sizeof(T)); + } + else + newBuffer = 0; + delete []_items; + _items = newBuffer; + _capacity = newCapacity; + } + CBuffer& operator=(const CBuffer &buffer) + { + Free(); + if(buffer._capacity > 0) + { + SetCapacity(buffer._capacity); + memmove(_items, buffer._items, buffer._capacity * sizeof(T)); + } + return *this; + } +}; + +template +bool operator==(const CBuffer& b1, const CBuffer& b2) +{ + if (b1.GetCapacity() != b2.GetCapacity()) + return false; + for (size_t i = 0; i < b1.GetCapacity(); i++) + if (b1[i] != b2[i]) + return false; + return true; +} + +template +bool operator!=(const CBuffer& b1, const CBuffer& b2) +{ + return !(b1 == b2); +} + +typedef CBuffer CCharBuffer; +typedef CBuffer CWCharBuffer; +typedef CBuffer CByteBuffer; + +#endif diff --git a/app/win/installer/7zstub/src/Common/CRC.cpp b/app/win/installer/7zstub/src/Common/CRC.cpp new file mode 100644 index 0000000000..92bc009c2f --- /dev/null +++ b/app/win/installer/7zstub/src/Common/CRC.cpp @@ -0,0 +1,61 @@ +// Common/CRC.cpp + +#include "StdAfx.h" + +#include "CRC.h" + +static const UInt32 kCRCPoly = 0xEDB88320; + +UInt32 CCRC::Table[256]; + +void CCRC::InitTable() +{ + for (UInt32 i = 0; i < 256; i++) + { + UInt32 r = i; + for (int j = 0; j < 8; j++) + if (r & 1) + r = (r >> 1) ^ kCRCPoly; + else + r >>= 1; + CCRC::Table[i] = r; + } +} + +class CCRCTableInit +{ +public: + CCRCTableInit() { CCRC::InitTable(); } +} g_CRCTableInit; + +void CCRC::UpdateByte(Byte b) +{ + _value = Table[((Byte)(_value)) ^ b] ^ (_value >> 8); +} + +void CCRC::UpdateUInt16(UInt16 v) +{ + UpdateByte(Byte(v)); + UpdateByte(Byte(v >> 8)); +} + +void CCRC::UpdateUInt32(UInt32 v) +{ + for (int i = 0; i < 4; i++) + UpdateByte((Byte)(v >> (8 * i))); +} + +void CCRC::UpdateUInt64(UInt64 v) +{ + for (int i = 0; i < 8; i++) + UpdateByte((Byte)(v >> (8 * i))); +} + +void CCRC::Update(const void *data, size_t size) +{ + UInt32 v = _value; + const Byte *p = (const Byte *)data; + for (; size > 0 ; size--, p++) + v = Table[((Byte)(v)) ^ *p] ^ (v >> 8); + _value = v; +} diff --git a/app/win/installer/7zstub/src/Common/CRC.h b/app/win/installer/7zstub/src/Common/CRC.h new file mode 100644 index 0000000000..c9d43d0055 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/CRC.h @@ -0,0 +1,36 @@ +// Common/CRC.h + +#ifndef __COMMON_CRC_H +#define __COMMON_CRC_H + +#include +#include "Types.h" + +class CCRC +{ + UInt32 _value; +public: + static UInt32 Table[256]; + static void InitTable(); + + CCRC(): _value(0xFFFFFFFF){}; + void Init() { _value = 0xFFFFFFFF; } + void UpdateByte(Byte v); + void UpdateUInt16(UInt16 v); + void UpdateUInt32(UInt32 v); + void UpdateUInt64(UInt64 v); + void Update(const void *data, size_t size); + UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; } + static UInt32 CalculateDigest(const void *data, size_t size) + { + CCRC crc; + crc.Update(data, size); + return crc.GetDigest(); + } + static bool VerifyDigest(UInt32 digest, const void *data, size_t size) + { + return (CalculateDigest(data, size) == digest); + } +}; + +#endif diff --git a/app/win/installer/7zstub/src/Common/ComTry.h b/app/win/installer/7zstub/src/Common/ComTry.h new file mode 100644 index 0000000000..98e5927663 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/ComTry.h @@ -0,0 +1,17 @@ +// ComTry.h + +#ifndef __COM_TRY_H +#define __COM_TRY_H + +#include "MyWindows.h" +// #include "Exception.h" +// #include "NewHandler.h" + +#define COM_TRY_BEGIN try { +#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; } + + // catch(const CNewException &) { return E_OUTOFMEMORY; }\ + // catch(const CSystemException &e) { return e.ErrorCode; }\ + // catch(...) { return E_FAIL; } + +#endif diff --git a/app/win/installer/7zstub/src/Common/CommandLineParser.cpp b/app/win/installer/7zstub/src/Common/CommandLineParser.cpp new file mode 100644 index 0000000000..8f6d2f8130 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/CommandLineParser.cpp @@ -0,0 +1,232 @@ +// CommandLineParser.cpp + +#include "StdAfx.h" + +#include "CommandLineParser.h" + +namespace NCommandLineParser { + +void SplitCommandLine(const UString &src, UString &dest1, UString &dest2) +{ + dest1.Empty(); + dest2.Empty(); + bool quoteMode = false; + int i; + for (i = 0; i < src.Length(); i++) + { + wchar_t c = src[i]; + if (c == L'\"') + quoteMode = !quoteMode; + else if (c == L' ' && !quoteMode) + { + i++; + break; + } + else + dest1 += c; + } + dest2 = src.Mid(i); +} + +void SplitCommandLine(const UString &s, UStringVector &parts) +{ + UString sTemp = s; + sTemp.Trim(); + parts.Clear(); + while (true) + { + UString s1, s2; + SplitCommandLine(sTemp, s1, s2); + // s1.Trim(); + // s2.Trim(); + if (!s1.IsEmpty()) + parts.Add(s1); + if (s2.IsEmpty()) + return; + sTemp = s2; + } +} + + +static const wchar_t kSwitchID1 = '-'; +// static const wchar_t kSwitchID2 = '/'; + +static const wchar_t kSwitchMinus = '-'; +static const wchar_t *kStopSwitchParsing = L"--"; + +static bool IsItSwitchChar(wchar_t c) +{ + return (c == kSwitchID1 /*|| c == kSwitchID2 */); +} + +CParser::CParser(int numSwitches): + _numSwitches(numSwitches) +{ + _switches = new CSwitchResult[_numSwitches]; +} + +CParser::~CParser() +{ + delete []_switches; +} + +void CParser::ParseStrings(const CSwitchForm *switchForms, + const UStringVector &commandStrings) +{ + int numCommandStrings = commandStrings.Size(); + bool stopSwitch = false; + for (int i = 0; i < numCommandStrings; i++) + { + const UString &s = commandStrings[i]; + if (stopSwitch) + NonSwitchStrings.Add(s); + else + if (s == kStopSwitchParsing) + stopSwitch = true; + else + if (!ParseString(s, switchForms)) + NonSwitchStrings.Add(s); + } +} + +// if string contains switch then function updates switch structures +// out: (string is a switch) +bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms) +{ + int len = s.Length(); + if (len == 0) + return false; + int pos = 0; + if (!IsItSwitchChar(s[pos])) + return false; + while(pos < len) + { + if (IsItSwitchChar(s[pos])) + pos++; + const int kNoLen = -1; + int matchedSwitchIndex = 0; // GCC Warning + int maxLen = kNoLen; + for(int switchIndex = 0; switchIndex < _numSwitches; switchIndex++) + { + int switchLen = MyStringLen(switchForms[switchIndex].IDString); + if (switchLen <= maxLen || pos + switchLen > len) + continue; + + UString temp = s + pos; + temp = temp.Left(switchLen); + if(temp.CompareNoCase(switchForms[switchIndex].IDString) == 0) + // if(_strnicmp(switchForms[switchIndex].IDString, LPCSTR(s) + pos, switchLen) == 0) + { + matchedSwitchIndex = switchIndex; + maxLen = switchLen; + } + } + if (maxLen == kNoLen) + throw "maxLen == kNoLen"; + CSwitchResult &matchedSwitch = _switches[matchedSwitchIndex]; + const CSwitchForm &switchForm = switchForms[matchedSwitchIndex]; + if ((!switchForm.Multi) && matchedSwitch.ThereIs) + throw "switch must be single"; + matchedSwitch.ThereIs = true; + pos += maxLen; + int tailSize = len - pos; + NSwitchType::EEnum type = switchForm.Type; + switch(type) + { + case NSwitchType::kPostMinus: + { + if (tailSize == 0) + matchedSwitch.WithMinus = false; + else + { + matchedSwitch.WithMinus = (s[pos] == kSwitchMinus); + if (matchedSwitch.WithMinus) + pos++; + } + break; + } + case NSwitchType::kPostChar: + { + if (tailSize < switchForm.MinLen) + throw "switch is not full"; + UString set = switchForm.PostCharSet; + const int kEmptyCharValue = -1; + if (tailSize == 0) + matchedSwitch.PostCharIndex = kEmptyCharValue; + else + { + int index = set.Find(s[pos]); + if (index < 0) + matchedSwitch.PostCharIndex = kEmptyCharValue; + else + { + matchedSwitch.PostCharIndex = index; + pos++; + } + } + break; + } + case NSwitchType::kLimitedPostString: + case NSwitchType::kUnLimitedPostString: + { + int minLen = switchForm.MinLen; + if (tailSize < minLen) + throw "switch is not full"; + if (type == NSwitchType::kUnLimitedPostString) + { + matchedSwitch.PostStrings.Add(s.Mid(pos)); + return true; + } + int maxLen = switchForm.MaxLen; + UString stringSwitch = s.Mid(pos, minLen); + pos += minLen; + for(int i = minLen; i < maxLen && pos < len; i++, pos++) + { + wchar_t c = s[pos]; + if (IsItSwitchChar(c)) + break; + stringSwitch += c; + } + matchedSwitch.PostStrings.Add(stringSwitch); + break; + } + case NSwitchType::kSimple: + break; + } + } + return true; +} + +const CSwitchResult& CParser::operator[](size_t index) const +{ + return _switches[index]; +} + +///////////////////////////////// +// Command parsing procedures + +int ParseCommand(int numCommandForms, const CCommandForm *commandForms, + const UString &commandString, UString &postString) +{ + for(int i = 0; i < numCommandForms; i++) + { + const UString id = commandForms[i].IDString; + if (commandForms[i].PostStringMode) + { + if(commandString.Find(id) == 0) + { + postString = commandString.Mid(id.Length()); + return i; + } + } + else + if (commandString == id) + { + postString.Empty(); + return i; + } + } + return -1; +} + +} diff --git a/app/win/installer/7zstub/src/Common/CommandLineParser.h b/app/win/installer/7zstub/src/Common/CommandLineParser.h new file mode 100644 index 0000000000..b74801a382 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/CommandLineParser.h @@ -0,0 +1,72 @@ +// Common/CommandLineParser.h + +#ifndef __COMMON_COMMANDLINEPARSER_H +#define __COMMON_COMMANDLINEPARSER_H + +#include "Common/String.h" + +namespace NCommandLineParser { + +void SplitCommandLine(const UString &src, UString &dest1, UString &dest2); +void SplitCommandLine(const UString &s, UStringVector &parts); + +namespace NSwitchType { + enum EEnum + { + kSimple, + kPostMinus, + kLimitedPostString, + kUnLimitedPostString, + kPostChar + }; +} + +struct CSwitchForm +{ + const wchar_t *IDString; + NSwitchType::EEnum Type; + bool Multi; + int MinLen; + int MaxLen; + const wchar_t *PostCharSet; +}; + +struct CSwitchResult +{ + bool ThereIs; + bool WithMinus; + UStringVector PostStrings; + int PostCharIndex; + CSwitchResult(): ThereIs(false) {}; +}; + +class CParser +{ + int _numSwitches; + CSwitchResult *_switches; + bool ParseString(const UString &s, const CSwitchForm *switchForms); +public: + UStringVector NonSwitchStrings; + CParser(int numSwitches); + ~CParser(); + void ParseStrings(const CSwitchForm *switchForms, + const UStringVector &commandStrings); + const CSwitchResult& operator[](size_t index) const; +}; + +///////////////////////////////// +// Command parsing procedures + +struct CCommandForm +{ + wchar_t *IDString; + bool PostStringMode; +}; + +// Returns: Index of form and postString; -1, if there is no match +int ParseCommand(int numCommandForms, const CCommandForm *commandForms, + const UString &commandString, UString &postString); + +} + +#endif diff --git a/app/win/installer/7zstub/src/Common/Defs.h b/app/win/installer/7zstub/src/Common/Defs.h new file mode 100644 index 0000000000..69b8ecea82 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Defs.h @@ -0,0 +1,20 @@ +// Common/Defs.h + +#ifndef __COMMON_DEFS_H +#define __COMMON_DEFS_H + +template inline T MyMin(T a, T b) + { return a < b ? a : b; } +template inline T MyMax(T a, T b) + { return a > b ? a : b; } + +template inline int MyCompare(T a, T b) + { return a < b ? -1 : (a == b ? 0 : 1); } + +inline int BoolToInt(bool value) + { return (value ? 1: 0); } + +inline bool IntToBool(int value) + { return (value != 0); } + +#endif diff --git a/app/win/installer/7zstub/src/Common/DynamicBuffer.h b/app/win/installer/7zstub/src/Common/DynamicBuffer.h new file mode 100644 index 0000000000..e75e3c4735 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/DynamicBuffer.h @@ -0,0 +1,47 @@ +// Common/DynamicBuffer.h + +#ifndef __COMMON_DYNAMICBUFFER_H +#define __COMMON_DYNAMICBUFFER_H + +#include "Buffer.h" + +template class CDynamicBuffer: public CBuffer +{ + void GrowLength(size_t size) + { + size_t delta; + if (this->_capacity > 64) + delta = this->_capacity / 4; + else if (this->_capacity > 8) + delta = 16; + else + delta = 4; + delta = MyMax(delta, size); + SetCapacity(this->_capacity + delta); + } +public: + CDynamicBuffer(): CBuffer() {}; + CDynamicBuffer(const CDynamicBuffer &buffer): CBuffer(buffer) {}; + CDynamicBuffer(size_t size): CBuffer(size) {}; + CDynamicBuffer& operator=(const CDynamicBuffer &buffer) + { + this->Free(); + if(buffer._capacity > 0) + { + SetCapacity(buffer._capacity); + memmove(this->_items, buffer._items, buffer._capacity * sizeof(T)); + } + return *this; + } + void EnsureCapacity(size_t capacity) + { + if (this->_capacity < capacity) + GrowLength(capacity - this->_capacity); + } +}; + +typedef CDynamicBuffer CCharDynamicBuffer; +typedef CDynamicBuffer CWCharDynamicBuffer; +typedef CDynamicBuffer CByteDynamicBuffer; + +#endif diff --git a/app/win/installer/7zstub/src/Common/IntToString.cpp b/app/win/installer/7zstub/src/Common/IntToString.cpp new file mode 100644 index 0000000000..4f22781441 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/IntToString.cpp @@ -0,0 +1,63 @@ +// Common/IntToString.cpp + +#include "StdAfx.h" + +#include "IntToString.h" + +void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base) +{ + if (base < 2 || base > 36) + { + *s = L'\0'; + return; + } + char temp[72]; + int pos = 0; + do + { + int delta = (int)(value % base); + temp[pos++] = (delta < 10) ? ('0' + delta) : ('a' + (delta - 10)); + value /= base; + } + while (value != 0); + do + *s++ = temp[--pos]; + while(pos > 0); + *s = '\0'; +} + +void ConvertUInt64ToString(UInt64 value, wchar_t *s) +{ + wchar_t temp[32]; + int pos = 0; + do + { + temp[pos++] = L'0' + (int)(value % 10); + value /= 10; + } + while (value != 0); + do + *s++ = temp[--pos]; + while(pos > 0); + *s = L'\0'; +} + +void ConvertInt64ToString(Int64 value, char *s) +{ + if (value < 0) + { + *s++ = '-'; + value = -value; + } + ConvertUInt64ToString(value, s); +} + +void ConvertInt64ToString(Int64 value, wchar_t *s) +{ + if (value < 0) + { + *s++ = L'-'; + value = -value; + } + ConvertUInt64ToString(value, s); +} diff --git a/app/win/installer/7zstub/src/Common/IntToString.h b/app/win/installer/7zstub/src/Common/IntToString.h new file mode 100644 index 0000000000..2f50ba95ab --- /dev/null +++ b/app/win/installer/7zstub/src/Common/IntToString.h @@ -0,0 +1,15 @@ +// Common/IntToString.h + +#ifndef __COMMON_INTTOSTRING_H +#define __COMMON_INTTOSTRING_H + +#include +#include "Types.h" + +void ConvertUInt64ToString(UInt64 value, char *s, UInt32 base = 10); +void ConvertUInt64ToString(UInt64 value, wchar_t *s); + +void ConvertInt64ToString(Int64 value, char *s); +void ConvertInt64ToString(Int64 value, wchar_t *s); + +#endif diff --git a/app/win/installer/7zstub/src/Common/MyCom.h b/app/win/installer/7zstub/src/Common/MyCom.h new file mode 100644 index 0000000000..8476b57282 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/MyCom.h @@ -0,0 +1,203 @@ +// MyCom.h + +#ifndef __MYCOM_H +#define __MYCOM_H + +#include "MyWindows.h" + +#define RINOK(x) { HRESULT __result_ = (x); if(__result_ != S_OK) return __result_; } + +template +class CMyComPtr +{ + T* _p; +public: + // typedef T _PtrClass; + CMyComPtr() { _p = NULL;} + CMyComPtr(T* p) {if ((_p = p) != NULL) p->AddRef(); } + CMyComPtr(const CMyComPtr& lp) + { + if ((_p = lp._p) != NULL) + _p->AddRef(); + } + ~CMyComPtr() { if (_p) _p->Release(); } + void Release() { if (_p) { _p->Release(); _p = NULL; } } + operator T*() const { return (T*)_p; } + // T& operator*() const { return *_p; } + T** operator&() { return &_p; } + T* operator->() const { return _p; } + T* operator=(T* p) + { + if (p != 0) + p->AddRef(); + if (_p) + _p->Release(); + _p = p; + return p; + } + T* operator=(const CMyComPtr& lp) { return (*this = lp._p); } + bool operator!() const { return (_p == NULL); } + // bool operator==(T* pT) const { return _p == pT; } + // Compare two objects for equivalence + void Attach(T* p2) + { + Release(); + _p = p2; + } + T* Detach() + { + T* pt = _p; + _p = NULL; + return pt; + } + #ifdef _WIN32 + HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) + { + return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p); + } + #endif + /* + HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL) + { + CLSID clsid; + HRESULT hr = CLSIDFromProgID(szProgID, &clsid); + ATLASSERT(_p == NULL); + if (SUCCEEDED(hr)) + hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p); + return hr; + } + */ + template + HRESULT QueryInterface(REFGUID iid, Q** pp) const + { + return _p->QueryInterface(iid, (void**)pp); + } +}; + +////////////////////////////////////////////////////////// + +class CMyComBSTR +{ +public: + BSTR m_str; + CMyComBSTR() { m_str = NULL; } + CMyComBSTR(LPCOLESTR pSrc) { m_str = ::SysAllocString(pSrc); } + // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); } + // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); } + CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); } + /* + CMyComBSTR(REFGUID src) + { + LPOLESTR szGuid; + StringFromCLSID(src, &szGuid); + m_str = ::SysAllocString(szGuid); + CoTaskMemFree(szGuid); + } + */ + ~CMyComBSTR() { ::SysFreeString(m_str); } + CMyComBSTR& operator=(const CMyComBSTR& src) + { + if (m_str != src.m_str) + { + if (m_str) + ::SysFreeString(m_str); + m_str = src.MyCopy(); + } + return *this; + } + CMyComBSTR& operator=(LPCOLESTR pSrc) + { + ::SysFreeString(m_str); + m_str = ::SysAllocString(pSrc); + return *this; + } + unsigned int Length() const { return ::SysStringLen(m_str); } + operator BSTR() const { return m_str; } + BSTR* operator&() { return &m_str; } + BSTR MyCopy() const + { + int byteLen = ::SysStringByteLen(m_str); + BSTR res = ::SysAllocStringByteLen(NULL, byteLen); + memmove(res, m_str, byteLen); + return res; + } + void Attach(BSTR src) { m_str = src; } + BSTR Detach() + { + BSTR s = m_str; + m_str = NULL; + return s; + } + void Empty() + { + ::SysFreeString(m_str); + m_str = NULL; + } + bool operator!() const { return (m_str == NULL); } +}; + + +////////////////////////////////////////////////////////// + +class CMyUnknownImp +{ +public: + ULONG __m_RefCount; + CMyUnknownImp(): __m_RefCount(0) {} +}; + +#define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \ + (REFGUID iid, void **outObject) { + +#define MY_QUERYINTERFACE_ENTRY(i) if (iid == IID_ ## i) \ + { *outObject = (void *)(i *)this; AddRef(); return S_OK; } + +#define MY_QUERYINTERFACE_END return E_NOINTERFACE; } + +#define MY_ADDREF_RELEASE \ +STDMETHOD_(ULONG, AddRef)() { return ++__m_RefCount; } \ +STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) \ + return __m_RefCount; delete this; return 0; } + +#define MY_UNKNOWN_IMP_SPEC(i) \ + MY_QUERYINTERFACE_BEGIN \ + i \ + MY_QUERYINTERFACE_END \ + MY_ADDREF_RELEASE + + +#define MY_UNKNOWN_IMP STDMETHOD(QueryInterface)(REFGUID, void **) { \ + MY_QUERYINTERFACE_END \ + MY_ADDREF_RELEASE + +#define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \ + MY_QUERYINTERFACE_ENTRY(i) \ + ) + +#define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \ + MY_QUERYINTERFACE_ENTRY(i1) \ + MY_QUERYINTERFACE_ENTRY(i2) \ + ) + +#define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \ + MY_QUERYINTERFACE_ENTRY(i1) \ + MY_QUERYINTERFACE_ENTRY(i2) \ + MY_QUERYINTERFACE_ENTRY(i3) \ + ) + +#define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \ + MY_QUERYINTERFACE_ENTRY(i1) \ + MY_QUERYINTERFACE_ENTRY(i2) \ + MY_QUERYINTERFACE_ENTRY(i3) \ + MY_QUERYINTERFACE_ENTRY(i4) \ + ) + +#define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \ + MY_QUERYINTERFACE_ENTRY(i1) \ + MY_QUERYINTERFACE_ENTRY(i2) \ + MY_QUERYINTERFACE_ENTRY(i3) \ + MY_QUERYINTERFACE_ENTRY(i4) \ + MY_QUERYINTERFACE_ENTRY(i5) \ + ) + +#endif diff --git a/app/win/installer/7zstub/src/Common/MyUnknown.h b/app/win/installer/7zstub/src/Common/MyUnknown.h new file mode 100644 index 0000000000..6cd32caddb --- /dev/null +++ b/app/win/installer/7zstub/src/Common/MyUnknown.h @@ -0,0 +1,24 @@ +// MyUnknown.h + +#ifndef __MYUNKNOWN_H +#define __MYUNKNOWN_H + +#ifdef _WIN32 + +#ifdef _WIN32_WCE +#if (_WIN32_WCE > 300) +#include +#else +#define MIDL_INTERFACE(x) struct +#endif +#else +#include +#endif + +#include + +#else +#include "MyWindows.h" +#endif + +#endif diff --git a/app/win/installer/7zstub/src/Common/MyWindows.cpp b/app/win/installer/7zstub/src/Common/MyWindows.cpp new file mode 100644 index 0000000000..a715036376 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/MyWindows.cpp @@ -0,0 +1,113 @@ +// MyWindows.cpp + +#include "StdAfx.h" + +#ifndef _WIN32 + +#include "MyWindows.h" +#include "Types.h" +#include + +static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); } +static inline void FreeForBSTR(void *pv) { ::free(pv);} + +static UINT MyStringLen(const wchar_t *s) +{ + UINT i; + for (i = 0; s[i] != '\0'; i++); + return i; +} + +BSTR SysAllocStringByteLen(LPCSTR psz, UINT len) +{ + int realLen = len + sizeof(UINT) + sizeof(OLECHAR) + sizeof(OLECHAR); + void *p = AllocateForBSTR(realLen); + if (p == 0) + return 0; + *(UINT *)p = len; + BSTR bstr = (BSTR)((UINT *)p + 1); + memmove(bstr, psz, len); + Byte *pb = ((Byte *)bstr) + len; + for (int i = 0; i < sizeof(OLECHAR) * 2; i++) + pb[i] = 0; + return bstr; +} + +BSTR SysAllocString(const OLECHAR *sz) +{ + if (sz == 0) + return 0; + UINT strLen = MyStringLen(sz); + UINT len = (strLen + 1) * sizeof(OLECHAR); + void *p = AllocateForBSTR(len + sizeof(UINT)); + if (p == 0) + return 0; + *(UINT *)p = strLen; + BSTR bstr = (BSTR)((UINT *)p + 1); + memmove(bstr, sz, len); + return bstr; +} + +void SysFreeString(BSTR bstr) +{ + if (bstr != 0) + FreeForBSTR((UINT *)bstr - 1); +} + +UINT SysStringByteLen(BSTR bstr) +{ + if (bstr == 0) + return 0; + return *((UINT *)bstr - 1); +} + +UINT SysStringLen(BSTR bstr) +{ + return SysStringByteLen(bstr) / sizeof(OLECHAR); +} + +HRESULT VariantClear(VARIANTARG *prop) +{ + if (prop->vt == VT_BSTR) + SysFreeString(prop->bstrVal); + prop->vt = VT_EMPTY; + return S_OK; +} + +HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src) +{ + HRESULT res = ::VariantClear(dest); + if (res != S_OK) + return res; + if (src->vt == VT_BSTR) + { + dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal, + SysStringByteLen(src->bstrVal)); + if (dest->bstrVal == 0) + return E_OUTOFMEMORY; + dest->vt = VT_BSTR; + } + else + *dest = *src; + return S_OK; +} + +LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2) +{ + if(ft1->dwHighDateTime < ft2->dwHighDateTime) + return -1; + if(ft1->dwHighDateTime > ft2->dwHighDateTime) + return 1; + if(ft1->dwLowDateTime < ft2->dwLowDateTime) + return -1; + if(ft1->dwLowDateTime > ft2->dwLowDateTime) + return 1; + return 0; +} + +DWORD GetLastError() +{ + return 0; +} + +#endif diff --git a/app/win/installer/7zstub/src/Common/MyWindows.h b/app/win/installer/7zstub/src/Common/MyWindows.h new file mode 100644 index 0000000000..773d185fe9 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/MyWindows.h @@ -0,0 +1,200 @@ +// MyWindows.h + +#ifndef __MYWINDOWS_H +#define __MYWINDOWS_H + +#ifdef _WIN32 + +#include + +#define CHAR_PATH_SEPARATOR '\\' +#define WCHAR_PATH_SEPARATOR L'\\' +#define STRING_PATH_SEPARATOR "\\" +#define WSTRING_PATH_SEPARATOR L"\\" + +#else + +#define CHAR_PATH_SEPARATOR '/' +#define WCHAR_PATH_SEPARATOR L'/' +#define STRING_PATH_SEPARATOR "/" +#define WSTRING_PATH_SEPARATOR L"/" + +#include // for wchar_t +#include + +#include "MyGuidDef.h" + +typedef char CHAR; +typedef unsigned char UCHAR; + +#undef BYTE +typedef unsigned char BYTE; + +typedef short SHORT; +typedef unsigned short USHORT; + +#undef WORD +typedef unsigned short WORD; +typedef short VARIANT_BOOL; + +typedef int INT; +typedef Int32 INT32; +typedef unsigned int UINT; +typedef UInt32 UINT32; +typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit +typedef UINT32 ULONG; + +#undef DWORD +typedef UINT32 DWORD; + +typedef Int64 LONGLONG; +typedef UInt64 ULONGLONG; + +typedef struct LARGE_INTEGER { LONGLONG QuadPart; }LARGE_INTEGER; +typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart;} ULARGE_INTEGER; + +typedef const CHAR *LPCSTR; +typedef CHAR TCHAR; +typedef const TCHAR *LPCTSTR; +typedef wchar_t WCHAR; +typedef WCHAR OLECHAR; +typedef const WCHAR *LPCWSTR; +typedef OLECHAR *BSTR; +typedef const OLECHAR *LPCOLESTR; +typedef OLECHAR *LPOLESTR; + +typedef struct _FILETIME +{ + DWORD dwLowDateTime; + DWORD dwHighDateTime; +}FILETIME; + +#define HRESULT LONG +#define FAILED(Status) ((HRESULT)(Status)<0) +typedef ULONG PROPID; +typedef LONG SCODE; + +#define S_OK ((HRESULT)0x00000000L) +#define S_FALSE ((HRESULT)0x00000001L) +#define E_NOTIMPL ((HRESULT)0x80004001L) +#define E_NOINTERFACE ((HRESULT)0x80004002L) +#define E_ABORT ((HRESULT)0x80004004L) +#define E_FAIL ((HRESULT)0x80004005L) +#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L) +#define E_OUTOFMEMORY ((HRESULT)0x8007000EL) +#define E_INVALIDARG ((HRESULT)0x80070057L) + +#ifdef _MSC_VER +#define STDMETHODCALLTYPE __stdcall +#else +#define STDMETHODCALLTYPE +#endif + +#define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f +#define STDMETHOD(f) STDMETHOD_(HRESULT, f) +#define STDMETHODIMP_(type) type STDMETHODCALLTYPE +#define STDMETHODIMP STDMETHODIMP_(HRESULT) + +#define PURE = 0 + +#define MIDL_INTERFACE(x) struct + +struct IUnknown +{ + STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE; + STDMETHOD_(ULONG, AddRef)() PURE; + STDMETHOD_(ULONG, Release)() PURE; +}; + +typedef IUnknown *LPUNKNOWN; + +#define VARIANT_TRUE ((VARIANT_BOOL)-1) +#define VARIANT_FALSE ((VARIANT_BOOL)0) + +enum VARENUM +{ + VT_EMPTY = 0, + VT_NULL = 1, + VT_I2 = 2, + VT_I4 = 3, + VT_R4 = 4, + VT_R8 = 5, + VT_CY = 6, + VT_DATE = 7, + VT_BSTR = 8, + VT_DISPATCH = 9, + VT_ERROR = 10, + VT_BOOL = 11, + VT_VARIANT = 12, + VT_UNKNOWN = 13, + VT_DECIMAL = 14, + VT_I1 = 16, + VT_UI1 = 17, + VT_UI2 = 18, + VT_UI4 = 19, + VT_I8 = 20, + VT_UI8 = 21, + VT_INT = 22, + VT_UINT = 23, + VT_VOID = 24, + VT_HRESULT = 25, + VT_FILETIME = 64 +}; + +typedef unsigned short VARTYPE; +typedef WORD PROPVAR_PAD1; +typedef WORD PROPVAR_PAD2; +typedef WORD PROPVAR_PAD3; + +typedef struct tagPROPVARIANT +{ + VARTYPE vt; + PROPVAR_PAD1 wReserved1; + PROPVAR_PAD2 wReserved2; + PROPVAR_PAD3 wReserved3; + union + { + CHAR cVal; + UCHAR bVal; + SHORT iVal; + USHORT uiVal; + LONG lVal; + ULONG ulVal; + INT intVal; + UINT uintVal; + LARGE_INTEGER hVal; + ULARGE_INTEGER uhVal; + VARIANT_BOOL boolVal; + SCODE scode; + FILETIME filetime; + BSTR bstrVal; + }; +} PROPVARIANT; + +typedef PROPVARIANT tagVARIANT; +typedef tagVARIANT VARIANT; +typedef VARIANT VARIANTARG; + +MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len); +MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz); +MY_EXTERN_C void SysFreeString(BSTR bstr); +MY_EXTERN_C UINT SysStringByteLen(BSTR bstr); +MY_EXTERN_C UINT SysStringLen(BSTR bstr); + +MY_EXTERN_C DWORD GetLastError(); +MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop); +MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, VARIANTARG *src); +MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2); + +#define CP_ACP 0 +#define CP_OEMCP 1 + +typedef enum tagSTREAM_SEEK +{ + STREAM_SEEK_SET = 0, + STREAM_SEEK_CUR = 1, + STREAM_SEEK_END = 2 +} STREAM_SEEK; + +#endif +#endif diff --git a/app/win/installer/7zstub/src/Common/NewHandler.cpp b/app/win/installer/7zstub/src/Common/NewHandler.cpp new file mode 100644 index 0000000000..75b1cf7dc3 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/NewHandler.cpp @@ -0,0 +1,116 @@ +// NewHandler.cpp + +#include "StdAfx.h" + +#include + +#include "NewHandler.h" + +// #define DEBUG_MEMORY_LEAK + +#ifndef DEBUG_MEMORY_LEAK + +#ifdef _WIN32 +void * +#ifdef _MSC_VER +__cdecl +#endif +operator new(size_t size) +{ + // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size); + void *p = ::malloc(size); + if (p == 0) + throw CNewException(); + return p; +} + +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p) throw() +{ + /* + if (p == 0) + return; + ::HeapFree(::GetProcessHeap(), 0, p); + */ + ::free(p); +} +#endif + +#else + +#pragma init_seg(lib) +const int kDebugSize = 1000000; +static void *a[kDebugSize]; +static int index = 0; + +static int numAllocs = 0; +void * __cdecl operator new(size_t size) +{ + numAllocs++; + void *p = HeapAlloc(GetProcessHeap(), 0, size); + if (index == 40) + { + int t = 1; + } + if (index < kDebugSize) + { + a[index] = p; + index++; + } + if (p == 0) + throw CNewException(); + printf("Alloc %6d, size = %8d\n", numAllocs, size); + return p; +} + +class CC +{ +public: + CC() + { + for (int i = 0; i < kDebugSize; i++) + a[i] = 0; + } + ~CC() + { + for (int i = 0; i < kDebugSize; i++) + if (a[i] != 0) + return; + } +} g_CC; + + +void __cdecl operator delete(void *p) +{ + if (p == 0) + return; + /* + for (int i = 0; i < index; i++) + if (a[i] == p) + a[i] = 0; + */ + HeapFree(GetProcessHeap(), 0, p); + numAllocs--; + printf("Free %d\n", numAllocs); +} + +#endif + +/* +int MemErrorVC(size_t) +{ + throw CNewException(); + // return 1; +} +CNewHandlerSetter::CNewHandlerSetter() +{ + // MemErrorOldVCFunction = _set_new_handler(MemErrorVC); +} +CNewHandlerSetter::~CNewHandlerSetter() +{ + // _set_new_handler(MemErrorOldVCFunction); +} +*/ diff --git a/app/win/installer/7zstub/src/Common/NewHandler.h b/app/win/installer/7zstub/src/Common/NewHandler.h new file mode 100644 index 0000000000..4c1727f824 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/NewHandler.h @@ -0,0 +1,16 @@ +// Common/NewHandler.h + +#ifndef __COMMON_NEWHANDLER_H +#define __COMMON_NEWHANDLER_H + +class CNewException {}; + +#ifdef _WIN32 +void +#ifdef _MSC_VER +__cdecl +#endif +operator delete(void *p) throw(); +#endif + +#endif diff --git a/app/win/installer/7zstub/src/Common/Random.cpp b/app/win/installer/7zstub/src/Common/Random.cpp new file mode 100644 index 0000000000..85d275c237 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Random.cpp @@ -0,0 +1,17 @@ +// Common/Random.cpp + +#include "StdAfx.h" + +#include +#include + +#include "Common/Random.h" + +void CRandom::Init(unsigned int seed) + { srand(seed); } + +void CRandom::Init() + { Init((unsigned int)time(NULL)); } + +int CRandom::Generate() const + { return rand(); } diff --git a/app/win/installer/7zstub/src/Common/Random.h b/app/win/installer/7zstub/src/Common/Random.h new file mode 100644 index 0000000000..f6fe5c4ef4 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Random.h @@ -0,0 +1,16 @@ +// Common/Random.h + +#ifndef __COMMON_RANDOM_H +#define __COMMON_RANDOM_H + +class CRandom +{ +public: + void Init(); + void Init(unsigned int seed); + int Generate() const; +}; + +#endif + + diff --git a/app/win/installer/7zstub/src/Common/StdInStream.cpp b/app/win/installer/7zstub/src/Common/StdInStream.cpp new file mode 100644 index 0000000000..e014f60b5b --- /dev/null +++ b/app/win/installer/7zstub/src/Common/StdInStream.cpp @@ -0,0 +1,78 @@ +// Common/StdInStream.cpp + +#include "StdAfx.h" + +#include +#include "StdInStream.h" + +static const char kIllegalChar = '\0'; +static const char kNewLineChar = '\n'; + +static const char *kEOFMessage = "Unexpected end of input stream"; +static const char *kReadErrorMessage ="Error reading input stream"; +static const char *kIllegalCharMessage = "Illegal character in input stream"; + +static LPCTSTR kFileOpenMode = TEXT("r"); + +CStdInStream g_StdIn(stdin); + +bool CStdInStream::Open(LPCTSTR fileName) +{ + Close(); + _stream = _tfopen(fileName, kFileOpenMode); + _streamIsOpen = (_stream != 0); + return _streamIsOpen; +} + +bool CStdInStream::Close() +{ + if(!_streamIsOpen) + return true; + _streamIsOpen = (fclose(_stream) != 0); + return !_streamIsOpen; +} + +CStdInStream::~CStdInStream() +{ + Close(); +} + +AString CStdInStream::ScanStringUntilNewLine() +{ + AString s; + while(true) + { + int intChar = GetChar(); + if(intChar == EOF) + throw kEOFMessage; + char c = char(intChar); + if (c == kIllegalChar) + throw kIllegalCharMessage; + if(c == kNewLineChar) + return s; + s += c; + } +} + +void CStdInStream::ReadToString(AString &resultString) +{ + resultString.Empty(); + int c; + while((c = GetChar()) != EOF) + resultString += char(c); +} + +bool CStdInStream::Eof() +{ + return (feof(_stream) != 0); +} + +int CStdInStream::GetChar() +{ + int c = getc(_stream); + if(c == EOF && !Eof()) + throw kReadErrorMessage; + return c; +} + + diff --git a/app/win/installer/7zstub/src/Common/StdInStream.h b/app/win/installer/7zstub/src/Common/StdInStream.h new file mode 100644 index 0000000000..4e81cef7a4 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/StdInStream.h @@ -0,0 +1,31 @@ +// Common/StdInStream.h + +#ifndef __COMMON_STDINSTREAM_H +#define __COMMON_STDINSTREAM_H + +#include + +#include "Common/String.h" +#include "Types.h" + +class CStdInStream +{ + bool _streamIsOpen; + FILE *_stream; +public: + CStdInStream(): _streamIsOpen(false) {}; + CStdInStream(FILE *stream): _streamIsOpen(false), _stream(stream) {}; + ~CStdInStream(); + bool Open(LPCTSTR fileName); + bool Close(); + + AString ScanStringUntilNewLine(); + void ReadToString(AString &resultString); + + bool Eof(); + int GetChar(); +}; + +extern CStdInStream g_StdIn; + +#endif diff --git a/app/win/installer/7zstub/src/Common/StdOutStream.cpp b/app/win/installer/7zstub/src/Common/StdOutStream.cpp new file mode 100644 index 0000000000..b66bc31546 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/StdOutStream.cpp @@ -0,0 +1,87 @@ +// Common/StdOutStream.cpp + +#include "StdAfx.h" + +#include + +#include "StdOutStream.h" +#include "Common/IntToString.h" +#include "Common/StringConvert.h" + +static const char kNewLineChar = '\n'; + +static const char *kFileOpenMode = "wt"; + +CStdOutStream g_StdOut(stdout); +CStdOutStream g_StdErr(stderr); + +bool CStdOutStream::Open(const char *fileName) +{ + Close(); + _stream = fopen(fileName, kFileOpenMode); + _streamIsOpen = (_stream != 0); + return _streamIsOpen; +} + +bool CStdOutStream::Close() +{ + if(!_streamIsOpen) + return true; + _streamIsOpen = (fclose(_stream) != 0); + return !_streamIsOpen; +} + +bool CStdOutStream::Flush() +{ + if(!_streamIsOpen) + return false; + return (fflush(_stream) == 0); +} + +CStdOutStream::~CStdOutStream () +{ + Close(); +} + +CStdOutStream & CStdOutStream::operator<<(CStdOutStream & (*aFunction)(CStdOutStream &)) +{ + (*aFunction)(*this); + return *this; +} + +CStdOutStream & endl(CStdOutStream & outStream) +{ + return outStream << kNewLineChar; +} + +CStdOutStream & CStdOutStream::operator<<(const char *string) +{ + fputs(string, _stream); + return *this; +} + +CStdOutStream & CStdOutStream::operator<<(const wchar_t *string) +{ + *this << (const char *)UnicodeStringToMultiByte(string, CP_OEMCP); + return *this; +} + +CStdOutStream & CStdOutStream::operator<<(char c) +{ + fputc(c, _stream); + return *this; +} + +CStdOutStream & CStdOutStream::operator<<(int number) +{ + char textString[32]; + ConvertInt64ToString(number, textString); + return operator<<(textString); +} + +CStdOutStream & CStdOutStream::operator<<(UInt64 number) +{ + char textString[32]; + ConvertUInt64ToString(number, textString); + return operator<<(textString); +} diff --git a/app/win/installer/7zstub/src/Common/StdOutStream.h b/app/win/installer/7zstub/src/Common/StdOutStream.h new file mode 100644 index 0000000000..390bcb2a3d --- /dev/null +++ b/app/win/installer/7zstub/src/Common/StdOutStream.h @@ -0,0 +1,35 @@ +// Common/StdOutStream.h + +#ifndef __COMMON_STDOUTSTREAM_H +#define __COMMON_STDOUTSTREAM_H + +#include + +#include "Types.h" + +class CStdOutStream +{ + bool _streamIsOpen; + FILE *_stream; +public: + CStdOutStream (): _streamIsOpen(false) {}; + CStdOutStream (FILE *stream): _streamIsOpen(false), _stream(stream) {}; + ~CStdOutStream (); + bool Open(const char *fileName); + bool Close(); + bool Flush(); + + CStdOutStream & operator<<(CStdOutStream & (* aFunction)(CStdOutStream &)); + CStdOutStream & operator<<(const char *string); + CStdOutStream & operator<<(const wchar_t *string); + CStdOutStream & operator<<(char c); + CStdOutStream & operator<<(int number); + CStdOutStream & operator<<(UInt64 number); +}; + +CStdOutStream & endl(CStdOutStream & outStream); + +extern CStdOutStream g_StdOut; +extern CStdOutStream g_StdErr; + +#endif diff --git a/app/win/installer/7zstub/src/Common/String.cpp b/app/win/installer/7zstub/src/Common/String.cpp new file mode 100644 index 0000000000..b6c12e99bf --- /dev/null +++ b/app/win/installer/7zstub/src/Common/String.cpp @@ -0,0 +1,198 @@ +// Common/String.cpp + +#include "StdAfx.h" + +#ifdef _WIN32 +#include "StringConvert.h" +#else +#include +#endif + +#include "Common/String.h" + + +#ifdef _WIN32 + +#ifndef _UNICODE + +wchar_t MyCharUpper(wchar_t c) +{ + if (c == 0) + return 0; + wchar_t *res = CharUpperW((LPWSTR)(unsigned int)c); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return (wchar_t)(unsigned int)res; + const int kBufferSize = 4; + char s[kBufferSize + 1]; + int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0); + if (numChars == 0 || numChars > kBufferSize) + return c; + s[numChars] = 0; + ::CharUpperA(s); + ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); + return c; +} + +wchar_t MyCharLower(wchar_t c) +{ + if (c == 0) + return 0; + wchar_t *res = CharLowerW((LPWSTR)(unsigned int)c); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return (wchar_t)(unsigned int)res; + const int kBufferSize = 4; + char s[kBufferSize + 1]; + int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufferSize, 0, 0); + if (numChars == 0 || numChars > kBufferSize) + return c; + s[numChars] = 0; + ::CharLowerA(s); + ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1); + return c; +} + +wchar_t * MyStringUpper(wchar_t *s) +{ + if (s == 0) + return 0; + wchar_t *res = CharUpperW(s); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return res; + AString a = UnicodeStringToMultiByte(s); + a.MakeUpper(); + return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); +} + +wchar_t * MyStringLower(wchar_t *s) +{ + if (s == 0) + return 0; + wchar_t *res = CharLowerW(s); + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return res; + AString a = UnicodeStringToMultiByte(s); + a.MakeLower(); + return MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a)); +} + +#endif + +/* +inline int ConvertCompareResult(int r) { return r - 2; } + +int MyStringCollate(const wchar_t *s1, const wchar_t *s2) +{ + int res = CompareStringW( + LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1); + #ifdef _UNICODE + return ConvertCompareResult(res); + #else + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return ConvertCompareResult(res); + return MyStringCollate(UnicodeStringToMultiByte(s1), + UnicodeStringToMultiByte(s2)); + #endif +} + +#ifndef _WIN32_WCE +int MyStringCollate(const char *s1, const char *s2) +{ + return ConvertCompareResult(CompareStringA( + LOCALE_USER_DEFAULT, SORT_STRINGSORT, s1, -1, s2, -1)); +} + +int MyStringCollateNoCase(const char *s1, const char *s2) +{ + return ConvertCompareResult(CompareStringA( + LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1)); +} +#endif + +int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2) +{ + int res = CompareStringW( + LOCALE_USER_DEFAULT, NORM_IGNORECASE | SORT_STRINGSORT, s1, -1, s2, -1); + #ifdef _UNICODE + return ConvertCompareResult(res); + #else + if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return ConvertCompareResult(res); + return MyStringCollateNoCase(UnicodeStringToMultiByte(s1), + UnicodeStringToMultiByte(s2)); + #endif +} +*/ + +#else + +wchar_t MyCharUpper(wchar_t c) +{ + return toupper(c); +} + +/* +int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2) +{ + while (true) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + wchar_t u1 = MyCharUpper(c1); + wchar_t u2 = MyCharUpper(c2); + + if (u1 < u2) return -1; + if (u1 > u2) return 1; + if (u1 == 0) return 0; + } +} +*/ + +#endif + +int MyStringCompare(const char *s1, const char *s2) +{ + while (true) + { + unsigned char c1 = (unsigned char)*s1++; + unsigned char c2 = (unsigned char)*s2++; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + if (c1 == 0) return 0; + } +} + +int MyStringCompare(const wchar_t *s1, const wchar_t *s2) +{ + while (true) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 < c2) return -1; + if (c1 > c2) return 1; + if (c1 == 0) return 0; + } +} + +int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) +{ + while (true) + { + wchar_t c1 = *s1++; + wchar_t c2 = *s2++; + if (c1 != c2) + { + wchar_t u1 = MyCharUpper(c1); + wchar_t u2 = MyCharUpper(c2); + if (u1 < u2) return -1; + if (u1 > u2) return 1; + } + if (c1 == 0) return 0; + } +} + +#ifdef _WIN32 +int MyStringCompareNoCase(const char *s1, const char *s2) +{ + return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2)); +} +#endif diff --git a/app/win/installer/7zstub/src/Common/String.h b/app/win/installer/7zstub/src/Common/String.h new file mode 100644 index 0000000000..72a2c741a4 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/String.h @@ -0,0 +1,631 @@ +// Common/String.h + +#ifndef __COMMON_STRING_H +#define __COMMON_STRING_H + +#include +// #include + +#include "Vector.h" + +#ifdef _WIN32 +#include "MyWindows.h" +#endif + +static const char *kTrimDefaultCharSet = " \n\t"; + +template +inline int MyStringLen(const T *s) +{ + int i; + for (i = 0; s[i] != '\0'; i++); + return i; +} + +template +inline T * MyStringCopy(T *dest, const T *src) +{ + T *destStart = dest; + while((*dest++ = *src++) != 0); + return destStart; +} + +inline wchar_t* MyStringGetNextCharPointer(wchar_t *p) + { return (p + 1); } +inline const wchar_t* MyStringGetNextCharPointer(const wchar_t *p) + { return (p + 1); } +inline wchar_t* MyStringGetPrevCharPointer(const wchar_t *, wchar_t *p) + { return (p - 1); } +inline const wchar_t* MyStringGetPrevCharPointer(const wchar_t *, const wchar_t *p) + { return (p - 1); } + +#ifdef _WIN32 + +inline char* MyStringGetNextCharPointer(char *p) + { return CharNextA(p); } +inline const char* MyStringGetNextCharPointer(const char *p) + { return CharNextA(p); } + +inline char* MyStringGetPrevCharPointer(char *base, char *p) + { return CharPrevA(base, p); } +inline const char* MyStringGetPrevCharPointer(const char *base, const char *p) + { return CharPrevA(base, p); } + +inline char MyCharUpper(char c) + { return (char)(unsigned int)CharUpperA((LPSTR)(unsigned int)(unsigned char)c); } +#ifdef _UNICODE +inline wchar_t MyCharUpper(wchar_t c) + { return (wchar_t)CharUpperW((LPWSTR)c); } +#else +wchar_t MyCharUpper(wchar_t c); +#endif + +inline char MyCharLower(char c) + { return (char)(unsigned int)CharLowerA((LPSTR)(unsigned int)(unsigned char)c); } +#ifdef _UNICODE +inline wchar_t MyCharLower(wchar_t c) + { return (wchar_t)CharLowerW((LPWSTR)c); } +#else +wchar_t MyCharLower(wchar_t c); +#endif + +inline char * MyStringUpper(char *s) { return CharUpperA(s); } +#ifdef _UNICODE +inline wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); } +#else +wchar_t * MyStringUpper(wchar_t *s); +#endif + +inline char * MyStringLower(char *s) { return CharLowerA(s); } +#ifdef _UNICODE +inline wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); } +#else +wchar_t * MyStringLower(wchar_t *s); +#endif + +#else // Standard-C +wchar_t MyCharUpper(wchar_t c); +#endif + +////////////////////////////////////// +// Compare + +/* +#ifndef _WIN32_WCE +int MyStringCollate(const char *s1, const char *s2); +int MyStringCollateNoCase(const char *s1, const char *s2); +#endif +int MyStringCollate(const wchar_t *s1, const wchar_t *s2); +int MyStringCollateNoCase(const wchar_t *s1, const wchar_t *s2); +*/ + +int MyStringCompare(const char *s1, const char *s2); +int MyStringCompare(const wchar_t *s1, const wchar_t *s2); + +#ifdef _WIN32 +int MyStringCompareNoCase(const char *s1, const char *s2); +#endif + +int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2); + +template +class CStringBase +{ + void TrimLeftWithCharSet(const CStringBase &charSet) + { + const T *p = _chars; + while (charSet.Find(*p) >= 0 && (*p != 0)) + p = GetNextCharPointer(p); + Delete(0, (int)(p - _chars)); + } + void TrimRightWithCharSet(const CStringBase &charSet) + { + const T *p = _chars; + const T *pLast = NULL; + while (*p != 0) + { + if (charSet.Find(*p) >= 0) + { + if (pLast == NULL) + pLast = p; + } + else + pLast = NULL; + p = GetNextCharPointer(p); + } + if(pLast != NULL) + { + int i = (int)(pLast - _chars); + Delete(i, _length - i); + } + + } + void MoveItems(int destIndex, int srcIndex) + { + memmove(_chars + destIndex, _chars + srcIndex, + sizeof(T) * (_length - srcIndex + 1)); + } + + void InsertSpace(int &index, int size) + { + CorrectIndex(index); + GrowLength(size); + MoveItems(index + size, index); + } + + static T *GetNextCharPointer(T *p) + { return MyStringGetNextCharPointer(p); } + static const T *GetNextCharPointer(const T *p) + { return MyStringGetNextCharPointer(p); } + static T *GetPrevCharPointer(T *base, T *p) + { return MyStringGetPrevCharPointer(base, p); } + static const T *GetPrevCharPointer(const T *base, const T *p) + { return MyStringGetPrevCharPointer(base, p); } +protected: + T *_chars; + int _length; + int _capacity; + + void SetCapacity(int newCapacity) + { + int realCapacity = newCapacity + 1; + if(realCapacity == _capacity) + return; + /* + const int kMaxStringSize = 0x20000000; + #ifndef _WIN32_WCE + if(newCapacity > kMaxStringSize || newCapacity < _length) + throw 1052337; + #endif + */ + T *newBuffer = new T[realCapacity]; + if(_capacity > 0) + { + for (int i = 0; i < (_length + 1); i++) + newBuffer[i] = _chars[i]; + delete []_chars; + _chars = newBuffer; + } + else + { + _chars = newBuffer; + _chars[0] = 0; + } + _capacity = realCapacity; + } + + void GrowLength(int n) + { + int freeSize = _capacity - _length - 1; + if (n <= freeSize) + return; + int delta; + if (_capacity > 64) + delta = _capacity / 2; + else if (_capacity > 8) + delta = 16; + else + delta = 4; + if (freeSize + delta < n) + delta = n - freeSize; + SetCapacity(_capacity + delta); + } + + void CorrectIndex(int &index) const + { + if (index > _length) + index = _length; + } + +public: + CStringBase(): _chars(0), _length(0), _capacity(0) + { SetCapacity(16 - 1); } + CStringBase(T c): _chars(0), _length(0), _capacity(0) + { + SetCapacity(1); + _chars[0] = c; + _chars[1] = 0; + _length = 1; + } + CStringBase(const T *chars): _chars(0), _length(0), _capacity(0) + { + int length = MyStringLen(chars); + SetCapacity(length); + MyStringCopy(_chars, chars); // can be optimized by memove() + _length = length; + } + CStringBase(const CStringBase &s): _chars(0), _length(0), _capacity(0) + { + SetCapacity(s._length); + MyStringCopy(_chars, s._chars); + _length = s._length; + } + ~CStringBase() { delete []_chars; } + + operator const T*() const { return _chars;} + + // The minimum size of the character buffer in characters. + // This value does not include space for a null terminator. + T* GetBuffer(int minBufLength) + { + if(minBufLength >= _capacity) + SetCapacity(minBufLength + 1); + return _chars; + } + void ReleaseBuffer() { ReleaseBuffer(MyStringLen(_chars)); } + void ReleaseBuffer(int newLength) + { + /* + #ifndef _WIN32_WCE + if(newLength >= _capacity) + throw 282217; + #endif + */ + _chars[newLength] = 0; + _length = newLength; + } + + CStringBase& operator=(T c) + { + Empty(); + SetCapacity(1); + _chars[0] = c; + _chars[1] = 0; + _length = 1; + return *this; + } + CStringBase& operator=(const T *chars) + { + Empty(); + int length = MyStringLen(chars); + SetCapacity(length); + MyStringCopy(_chars, chars); + _length = length; + return *this; + } + CStringBase& operator=(const CStringBase& s) + { + if(&s == this) + return *this; + Empty(); + SetCapacity(s._length); + MyStringCopy(_chars, s._chars); + _length = s._length; + return *this; + } + + CStringBase& operator+=(T c) + { + GrowLength(1); + _chars[_length] = c; + _chars[++_length] = 0; + return *this; + } + CStringBase& operator+=(const T *s) + { + int len = MyStringLen(s); + GrowLength(len); + MyStringCopy(_chars + _length, s); + _length += len; + return *this; + } + CStringBase& operator+=(const CStringBase &s) + { + GrowLength(s._length); + MyStringCopy(_chars + _length, s._chars); + _length += s._length; + return *this; + } + void Empty() + { + _length = 0; + _chars[0] = 0; + } + int Length() const { return _length; } + bool IsEmpty() const { return (_length == 0); } + + CStringBase Mid(int startIndex) const + { return Mid(startIndex, _length - startIndex); } + CStringBase Mid(int startIndex, int count ) const + { + if (startIndex + count > _length) + count = _length - startIndex; + + if (startIndex == 0 && startIndex + count == _length) + return *this; + + CStringBase result; + result.SetCapacity(count); + // MyStringNCopy(result._chars, _chars + startIndex, count); + for (int i = 0; i < count; i++) + result._chars[i] = _chars[startIndex + i]; + result._chars[count] = 0; + result._length = count; + return result; + } + CStringBase Left(int count) const + { return Mid(0, count); } + CStringBase Right(int count) const + { + if (count > _length) + count = _length; + return Mid(_length - count, count); + } + + void MakeUpper() + { MyStringUpper(_chars); } + void MakeLower() + { MyStringLower(_chars); } + + int Compare(const CStringBase& s) const + { return MyStringCompare(_chars, s._chars); } + + int CompareNoCase(const CStringBase& s) const + { return MyStringCompareNoCase(_chars, s._chars); } + /* + int Collate(const CStringBase& s) const + { return MyStringCollate(_chars, s._chars); } + int CollateNoCase(const CStringBase& s) const + { return MyStringCollateNoCase(_chars, s._chars); } + */ + + int Find(T c) const { return Find(c, 0); } + int Find(T c, int startIndex) const + { + T *p = _chars + startIndex; + while (true) + { + if (*p == c) + return (int)(p - _chars); + if (*p == 0) + return -1; + p = GetNextCharPointer(p); + } + } + int Find(const CStringBase &s) const { return Find(s, 0); } + int Find(const CStringBase &s, int startIndex) const + { + if (s.IsEmpty()) + return startIndex; + for (; startIndex < _length; startIndex++) + { + int j; + for (j = 0; j < s._length && startIndex + j < _length; j++) + if (_chars[startIndex+j] != s._chars[j]) + break; + if (j == s._length) + return startIndex; + } + return -1; + } + int ReverseFind(T c) const + { + if (_length == 0) + return -1; + T *p = _chars + _length - 1; + while (true) + { + if (*p == c) + return (int)(p - _chars); + if (p == _chars) + return -1; + p = GetPrevCharPointer(_chars, p); + } + } + int FindOneOf(const CStringBase &s) const + { + for(int i = 0; i < _length; i++) + if (s.Find(_chars[i]) >= 0) + return i; + return -1; + } + + void TrimLeft(T c) + { + const T *p = _chars; + while (c == *p) + p = GetNextCharPointer(p); + Delete(0, p - _chars); + } + private: + CStringBase GetTrimDefaultCharSet() + { + CStringBase charSet; + for(int i = 0; i < (int)(sizeof(kTrimDefaultCharSet) / + sizeof(kTrimDefaultCharSet[0])); i++) + charSet += (T)kTrimDefaultCharSet[i]; + return charSet; + } + public: + + void TrimLeft() + { + TrimLeftWithCharSet(GetTrimDefaultCharSet()); + } + void TrimRight() + { + TrimRightWithCharSet(GetTrimDefaultCharSet()); + } + void TrimRight(T c) + { + const T *p = _chars; + const T *pLast = NULL; + while (*p != 0) + { + if (*p == c) + { + if (pLast == NULL) + pLast = p; + } + else + pLast = NULL; + p = GetNextCharPointer(p); + } + if(pLast != NULL) + { + int i = pLast - _chars; + Delete(i, _length - i); + } + } + void Trim() + { + TrimRight(); + TrimLeft(); + } + + int Insert(int index, T c) + { + InsertSpace(index, 1); + _chars[index] = c; + _length++; + return _length; + } + int Insert(int index, const CStringBase &s) + { + CorrectIndex(index); + if (s.IsEmpty()) + return _length; + int numInsertChars = s.Length(); + InsertSpace(index, numInsertChars); + for(int i = 0; i < numInsertChars; i++) + _chars[index + i] = s[i]; + _length += numInsertChars; + return _length; + } + + // !!!!!!!!!!!!!!! test it if newChar = '\0' + int Replace(T oldChar, T newChar) + { + if (oldChar == newChar) + return 0; + int number = 0; + int pos = 0; + while (pos < Length()) + { + pos = Find(oldChar, pos); + if (pos < 0) + break; + _chars[pos] = newChar; + pos++; + number++; + } + return number; + } + int Replace(const CStringBase &oldString, const CStringBase &newString) + { + if (oldString.IsEmpty()) + return 0; + if (oldString == newString) + return 0; + int oldStringLength = oldString.Length(); + int newStringLength = newString.Length(); + int number = 0; + int pos = 0; + while (pos < _length) + { + pos = Find(oldString, pos); + if (pos < 0) + break; + Delete(pos, oldStringLength); + Insert(pos, newString); + pos += newStringLength; + number++; + } + return number; + } + int Delete(int index, int count = 1 ) + { + if (index + count > _length) + count = _length - index; + if (count > 0) + { + MoveItems(index, index + count); + _length -= count; + } + return _length; + } +}; + +template +CStringBase operator+(const CStringBase& s1, const CStringBase& s2) +{ + CStringBase result(s1); + result += s2; + return result; +} + +template +CStringBase operator+(const CStringBase& s, T c) +{ + CStringBase result(s); + result += c; + return result; +} + +template +CStringBase operator+(T c, const CStringBase& s) +{ + CStringBase result(c); + result += s; + return result; +} + +template +CStringBase operator+(const CStringBase& s, const T * chars) +{ + CStringBase result(s); + result += chars; + return result; +} + +template +CStringBase operator+(const T * chars, const CStringBase& s) +{ + CStringBase result(chars); + result += s; + return result; +} + +template +bool operator==(const CStringBase& s1, const CStringBase& s2) + { return (s1.Compare(s2) == 0); } + +template +bool operator<(const CStringBase& s1, const CStringBase& s2) + { return (s1.Compare(s2) < 0); } + +template +bool operator==(const T *s1, const CStringBase& s2) + { return (s2.Compare(s1) == 0); } + +template +bool operator==(const CStringBase& s1, const T *s2) + { return (s1.Compare(s2) == 0); } + +template +bool operator!=(const CStringBase& s1, const CStringBase& s2) + { return (s1.Compare(s2) != 0); } + +template +bool operator!=(const T *s1, const CStringBase& s2) + { return (s2.Compare(s1) != 0); } + +template +bool operator!=(const CStringBase& s1, const T *s2) + { return (s1.Compare(s2) != 0); } + +typedef CStringBase AString; +typedef CStringBase UString; + +typedef CObjectVector AStringVector; +typedef CObjectVector UStringVector; + +#ifdef _UNICODE + typedef UString CSysString; +#else + typedef AString CSysString; +#endif + +typedef CObjectVector CSysStringVector; + +#endif diff --git a/app/win/installer/7zstub/src/Common/StringConvert.cpp b/app/win/installer/7zstub/src/Common/StringConvert.cpp new file mode 100644 index 0000000000..4b5913ade7 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/StringConvert.cpp @@ -0,0 +1,93 @@ +// Common/StringConvert.cpp + +#include "StdAfx.h" + +#include "StringConvert.h" + +#ifndef _WIN32 +#include +#endif + +#ifdef _WIN32 +UString MultiByteToUnicodeString(const AString &srcString, UINT codePage) +{ + UString resultString; + if(!srcString.IsEmpty()) + { + int numChars = MultiByteToWideChar(codePage, 0, srcString, + srcString.Length(), resultString.GetBuffer(srcString.Length()), + srcString.Length() + 1); + #ifndef _WIN32_WCE + if(numChars == 0) + throw 282228; + #endif + resultString.ReleaseBuffer(numChars); + } + return resultString; +} + +AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage) +{ + AString resultString; + if(!srcString.IsEmpty()) + { + int numRequiredBytes = srcString.Length() * 2; + int numChars = WideCharToMultiByte(codePage, 0, srcString, + srcString.Length(), resultString.GetBuffer(numRequiredBytes), + numRequiredBytes + 1, NULL, NULL); + #ifndef _WIN32_WCE + if(numChars == 0) + throw 282229; + #endif + resultString.ReleaseBuffer(numChars); + } + return resultString; +} + +#ifndef _WIN32_WCE +AString SystemStringToOemString(const CSysString &srcString) +{ + AString result; + CharToOem(srcString, result.GetBuffer(srcString.Length() * 2)); + result.ReleaseBuffer(); + return result; +} +#endif + +#else + +UString MultiByteToUnicodeString(const AString &srcString, UINT codePage) +{ + UString resultString; + for (int i = 0; i < srcString.Length(); i++) + resultString += wchar_t(srcString[i]); + /* + if(!srcString.IsEmpty()) + { + int numChars = mbstowcs(resultString.GetBuffer(srcString.Length()), srcString, srcString.Length() + 1); + if (numChars < 0) throw "Your environment does not support UNICODE"; + resultString.ReleaseBuffer(numChars); + } + */ + return resultString; +} + +AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage) +{ + AString resultString; + for (int i = 0; i < srcString.Length(); i++) + resultString += char(srcString[i]); + /* + if(!srcString.IsEmpty()) + { + int numRequiredBytes = srcString.Length() * 6 + 1; + int numChars = wcstombs(resultString.GetBuffer(numRequiredBytes), srcString, numRequiredBytes); + if (numChars < 0) throw "Your environment does not support UNICODE"; + resultString.ReleaseBuffer(numChars); + } + */ + return resultString; +} + +#endif + diff --git a/app/win/installer/7zstub/src/Common/StringConvert.h b/app/win/installer/7zstub/src/Common/StringConvert.h new file mode 100644 index 0000000000..921e33c70e --- /dev/null +++ b/app/win/installer/7zstub/src/Common/StringConvert.h @@ -0,0 +1,71 @@ +// Common/StringConvert.h + +#ifndef __COMMON_STRINGCONVERT_H +#define __COMMON_STRINGCONVERT_H + +#include "MyWindows.h" +#include "Common/String.h" +#include "Types.h" + +UString MultiByteToUnicodeString(const AString &srcString, UINT codePage = CP_ACP); +AString UnicodeStringToMultiByte(const UString &srcString, UINT codePage = CP_ACP); + +inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString) + { return unicodeString; } +inline const UString& GetUnicodeString(const UString &unicodeString) + { return unicodeString; } +inline UString GetUnicodeString(const AString &ansiString) + { return MultiByteToUnicodeString(ansiString); } +inline UString GetUnicodeString(const AString &multiByteString, UINT codePage) + { return MultiByteToUnicodeString(multiByteString, codePage); } +inline const wchar_t* GetUnicodeString(const wchar_t* unicodeString, UINT) + { return unicodeString; } +inline const UString& GetUnicodeString(const UString &unicodeString, UINT) + { return unicodeString; } + +inline const char* GetAnsiString(const char* ansiString) + { return ansiString; } +inline const AString& GetAnsiString(const AString &ansiString) + { return ansiString; } +inline AString GetAnsiString(const UString &unicodeString) + { return UnicodeStringToMultiByte(unicodeString); } + +inline const char* GetOemString(const char* oemString) + { return oemString; } +inline const AString& GetOemString(const AString &oemString) + { return oemString; } +inline AString GetOemString(const UString &unicodeString) + { return UnicodeStringToMultiByte(unicodeString, CP_OEMCP); } + + +#ifdef _UNICODE + inline const wchar_t* GetSystemString(const wchar_t* unicodeString) + { return unicodeString;} + inline const UString& GetSystemString(const UString &unicodeString) + { return unicodeString;} + inline const wchar_t* GetSystemString(const wchar_t* unicodeString, UINT codePage) + { return unicodeString;} + inline const UString& GetSystemString(const UString &unicodeString, UINT codePage) + { return unicodeString;} + inline UString GetSystemString(const AString &multiByteString, UINT codePage) + { return MultiByteToUnicodeString(multiByteString, codePage);} + inline UString GetSystemString(const AString &multiByteString) + { return MultiByteToUnicodeString(multiByteString);} +#else + inline const char* GetSystemString(const char *ansiString) + { return ansiString; } + inline const AString& GetSystemString(const AString &multiByteString, UINT) + { return multiByteString; } + inline const char * GetSystemString(const char *multiByteString, UINT) + { return multiByteString; } + inline AString GetSystemString(const UString &unicodeString) + { return UnicodeStringToMultiByte(unicodeString); } + inline AString GetSystemString(const UString &unicodeString, UINT codePage) + { return UnicodeStringToMultiByte(unicodeString, codePage); } +#endif + +#ifndef _WIN32_WCE +AString SystemStringToOemString(const CSysString &srcString); +#endif + +#endif diff --git a/app/win/installer/7zstub/src/Common/TextConfig.cpp b/app/win/installer/7zstub/src/Common/TextConfig.cpp new file mode 100644 index 0000000000..0e19b5eee5 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/TextConfig.cpp @@ -0,0 +1,137 @@ +// Common/TextConfig.cpp + +#include "StdAfx.h" + +#include "Common/TextConfig.h" + +#include "Defs.h" +#include "Common/UTFConvert.h" + +static bool IsDelimitChar(char c) +{ + return (c == ' ' || c == 0x0A || c == 0x0D || + c == '\0' || c == '\t'); +} + +static AString GetIDString(const char *string, int &finishPos) +{ + AString result; + for (finishPos = 0; true; finishPos++) + { + char c = string[finishPos]; + if (IsDelimitChar(c) || c == '=') + return result; + result += c; + } +} + +static bool WaitNextLine(const AString &string, int &pos) +{ + for (;pos < string.Length(); pos++) + if (string[pos] == 0x0A) + return true; + return false; +} + +static bool SkipSpaces(const AString &string, int &pos) +{ + for (;pos < string.Length(); pos++) + { + char c = string[pos]; + if (!IsDelimitChar(c)) + { + if (c != ';') + return true; + if (!WaitNextLine(string, pos)) + return false; + } + } + return false; +} + +bool GetTextConfig(const AString &string, CObjectVector &pairs) +{ + pairs.Clear(); + int pos = 0; + + ///////////////////// + // read strings + + while (true) + { + if (!SkipSpaces(string, pos)) + break; + CTextConfigPair pair; + int finishPos; + AString temp = GetIDString(((const char *)string) + pos, finishPos); + if (!ConvertUTF8ToUnicode(temp, pair.ID)) + return false; + if (finishPos == 0) + return false; + pos += finishPos; + if (!SkipSpaces(string, pos)) + return false; + if (string[pos] != '=') + return false; + pos++; + if (!SkipSpaces(string, pos)) + return false; + if (string[pos] != '\"') + return false; + pos++; + AString message; + while(true) + { + if (pos >= string.Length()) + return false; + char c = string[pos++]; + if (c == '\"') + break; + if (c == '\\') + { + char c = string[pos++]; + switch(c) + { + case 'n': + message += '\n'; + break; + case 't': + message += '\t'; + break; + case '\\': + message += '\\'; + break; + case '\"': + message += '\"'; + break; + default: + message += '\\'; + message += c; + break; + } + } + else + message += c; + } + if (!ConvertUTF8ToUnicode(message, pair.String)) + return false; + pairs.Add(pair); + } + return true; +} + +int FindTextConfigItem(const CObjectVector &pairs, const UString &id) +{ + for (int i = 0; i < pairs.Size(); i++) + if (pairs[i].ID.Compare(id) == 0) + return i; + return -1; +} + +UString GetTextConfigValue(const CObjectVector &pairs, const UString &id) +{ + int index = FindTextConfigItem(pairs, id); + if (index < 0) + return UString(); + return pairs[index].String; +} diff --git a/app/win/installer/7zstub/src/Common/TextConfig.h b/app/win/installer/7zstub/src/Common/TextConfig.h new file mode 100644 index 0000000000..09e65761bd --- /dev/null +++ b/app/win/installer/7zstub/src/Common/TextConfig.h @@ -0,0 +1,22 @@ +// Common/TextConfig.h + +#ifndef __COMMON_TEXTCONFIG_H +#define __COMMON_TEXTCONFIG_H + +#include "Common/Vector.h" +#include "Common/String.h" + +struct CTextConfigPair +{ + UString ID; + UString String; +}; + +bool GetTextConfig(const AString &text, CObjectVector &pairs); + +int FindTextConfigItem(const CObjectVector &pairs, const UString &id); +UString GetTextConfigValue(const CObjectVector &pairs, const UString &id); + +#endif + + diff --git a/app/win/installer/7zstub/src/Common/Types.h b/app/win/installer/7zstub/src/Common/Types.h new file mode 100644 index 0000000000..52d07081e8 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Types.h @@ -0,0 +1,19 @@ +// Common/Types.h + +#ifndef __COMMON_TYPES_H +#define __COMMON_TYPES_H + +typedef unsigned char Byte; +typedef short Int16; +typedef unsigned short UInt16; +typedef int Int32; +typedef unsigned int UInt32; +#ifdef _MSC_VER +typedef __int64 Int64; +typedef unsigned __int64 UInt64; +#else +typedef long long int Int64; +typedef unsigned long long int UInt64; +#endif + +#endif diff --git a/app/win/installer/7zstub/src/Common/UTFConvert.cpp b/app/win/installer/7zstub/src/Common/UTFConvert.cpp new file mode 100644 index 0000000000..5414e6b8db --- /dev/null +++ b/app/win/installer/7zstub/src/Common/UTFConvert.cpp @@ -0,0 +1,91 @@ +// UTFConvert.cpp + +#include "StdAfx.h" + +#include "UTFConvert.h" +#include "Types.h" + +static Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC }; + +// These functions are for UTF8 <-> UTF16 conversion. + +bool ConvertUTF8ToUnicode(const AString &src, UString &dest) +{ + dest.Empty(); + for(int i = 0; i < src.Length();) + { + Byte c = (Byte)src[i++]; + if (c < 0x80) + { + dest += (wchar_t)c; + continue; + } + if(c < 0xC0) + return false; + int numAdds; + for (numAdds = 1; numAdds < 5; numAdds++) + if (c < kUtf8Limits[numAdds]) + break; + UInt32 value = (c - kUtf8Limits[numAdds - 1]); + do + { + if (i >= src.Length()) + return false; + Byte c2 = (Byte)src[i++]; + if (c2 < 0x80 || c2 >= 0xC0) + return false; + value <<= 6; + value |= (c2 - 0x80); + numAdds--; + } + while(numAdds > 0); + if (value < 0x10000) + dest += (wchar_t)(value); + else + { + value -= 0x10000; + if (value >= 0x100000) + return false; + dest += (wchar_t)(0xD800 + (value >> 10)); + dest += (wchar_t)(0xDC00 + (value & 0x3FF)); + } + } + return true; +} + +bool ConvertUnicodeToUTF8(const UString &src, AString &dest) +{ + dest.Empty(); + for(int i = 0; i < src.Length();) + { + UInt32 value = (UInt32)src[i++]; + if (value < 0x80) + { + dest += (char)value; + continue; + } + if (value >= 0xD800 && value < 0xE000) + { + if (value >= 0xDC00) + return false; + if (i >= src.Length()) + return false; + UInt32 c2 = (UInt32)src[i++]; + if (c2 < 0xDC00 || c2 >= 0xE000) + return false; + value = ((value - 0xD800) << 10) | (c2 - 0xDC00); + } + int numAdds; + for (numAdds = 1; numAdds < 5; numAdds++) + if (value < (((UInt32)1) << (numAdds * 5 + 6))) + break; + dest += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds))); + do + { + numAdds--; + dest += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F)); + } + while(numAdds > 0); + } + return true; +} diff --git a/app/win/installer/7zstub/src/Common/UTFConvert.h b/app/win/installer/7zstub/src/Common/UTFConvert.h new file mode 100644 index 0000000000..3dfff3fe82 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/UTFConvert.h @@ -0,0 +1,11 @@ +// Common/UTFConvert.h + +#ifndef __COMMON_UTFCONVERT_H +#define __COMMON_UTFCONVERT_H + +#include "Common/String.h" + +bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString); +bool ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString); + +#endif diff --git a/app/win/installer/7zstub/src/Common/Vector.cpp b/app/win/installer/7zstub/src/Common/Vector.cpp new file mode 100644 index 0000000000..f74d4c6c29 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Vector.cpp @@ -0,0 +1,74 @@ +// Common/Vector.cpp + +#include "StdAfx.h" + +#include + +#include "Vector.h" + +CBaseRecordVector::~CBaseRecordVector() + { delete []((unsigned char *)_items); } +void CBaseRecordVector::Clear() + { DeleteFrom(0); } +void CBaseRecordVector::DeleteBack() + { Delete(_size - 1); } +void CBaseRecordVector::DeleteFrom(int index) + { Delete(index, _size - index); } + +void CBaseRecordVector::ReserveOnePosition() +{ + if(_size != _capacity) + return; + int delta; + if (_capacity > 64) + delta = _capacity / 2; + else if (_capacity > 8) + delta = 8; + else + delta = 4; + Reserve(_capacity + delta); +} + +void CBaseRecordVector::Reserve(int newCapacity) +{ + if(newCapacity <= _capacity) + return; + /* + #ifndef _DEBUG + static const unsigned int kMaxVectorSize = 0xF0000000; + if(newCapacity < _size || + ((unsigned int )newCapacity * (unsigned int )_itemSize) > kMaxVectorSize) + throw 1052354; + #endif + */ + unsigned char *p = new unsigned char[newCapacity * _itemSize]; + int numRecordsToMove = _capacity; + memmove(p, _items, _itemSize * numRecordsToMove); + delete [](unsigned char *)_items; + _items = p; + _capacity = newCapacity; +} + +void CBaseRecordVector::MoveItems(int destIndex, int srcIndex) +{ + memmove(((unsigned char *)_items) + destIndex * _itemSize, + ((unsigned char *)_items) + srcIndex * _itemSize, + _itemSize * (_size - srcIndex)); +} + +void CBaseRecordVector::InsertOneItem(int index) +{ + ReserveOnePosition(); + MoveItems(index + 1, index); + _size++; +} + +void CBaseRecordVector::Delete(int index, int num) +{ + TestIndexAndCorrectNum(index, num); + if (num > 0) + { + MoveItems(index, index + num); + _size -= num; + } +} diff --git a/app/win/installer/7zstub/src/Common/Vector.h b/app/win/installer/7zstub/src/Common/Vector.h new file mode 100644 index 0000000000..593c64354c --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Vector.h @@ -0,0 +1,228 @@ +// Common/Vector.h + +#ifndef __COMMON_VECTOR_H +#define __COMMON_VECTOR_H + +#include "Defs.h" + +class CBaseRecordVector +{ + void MoveItems(int destIndex, int srcIndex); +protected: + int _capacity; + int _size; + void *_items; + size_t _itemSize; + + void ReserveOnePosition(); + void InsertOneItem(int index); + void TestIndexAndCorrectNum(int index, int &num) const + { if (index + num > _size) num = _size - index; } +public: + CBaseRecordVector(size_t itemSize): + _capacity(0), _size(0), _items(0), _itemSize(itemSize) {} + virtual ~CBaseRecordVector(); + int Size() const { return _size; } + bool IsEmpty() const { return (_size == 0); } + void Reserve(int newCapacity); + virtual void Delete(int index, int num = 1); + void Clear(); + void DeleteFrom(int index); + void DeleteBack(); +}; + +template +class CRecordVector: public CBaseRecordVector +{ +public: + CRecordVector():CBaseRecordVector(sizeof(T)){}; + CRecordVector(const CRecordVector &v): + CBaseRecordVector(sizeof(T)) { *this = v;} + CRecordVector& operator=(const CRecordVector &v) + { + Clear(); + return (*this += v); + } + CRecordVector& operator+=(const CRecordVector &v) + { + int size = v.Size(); + Reserve(Size() + size); + for(int i = 0; i < size; i++) + Add(v[i]); + return *this; + } + int Add(T item) + { + ReserveOnePosition(); + ((T *)_items)[_size] = item; + return _size++; + } + void Insert(int index, T item) + { + InsertOneItem(index); + ((T *)_items)[index] = item; + } + // T* GetPointer() const { return (T*)_items; } + // operator const T *() const { return _items; }; + const T& operator[](int index) const { return ((T *)_items)[index]; } + T& operator[](int index) { return ((T *)_items)[index]; } + const T& Front() const { return operator[](0); } + T& Front() { return operator[](0); } + const T& Back() const { return operator[](_size - 1); } + T& Back() { return operator[](_size - 1); } + + void Swap(int i, int j) + { + T temp = operator[](i); + operator[](i) = operator[](j); + operator[](j) = temp; + } + + int FindInSorted(const T& item) const + { + int left = 0, right = Size(); + while (left != right) + { + int mid = (left + right) / 2; + const T& midValue = (*this)[mid]; + if (item == midValue) + return mid; + if (item < midValue) + right = mid; + else + left = mid + 1; + } + return -1; + } + + void Sort(int left, int right) + { + if (right - left < 2) + return; + Swap(left, (left + right) / 2); + int last = left; + for (int i = left; i < right; i++) + if (operator[](i) < operator[](left)) + Swap(++last, i); + Swap(left, last); + Sort(left, last); + Sort(last + 1, right); + } + void Sort() { Sort(0, Size()); } + void Sort(int left, int right, int (*compare)(const T*, const T*, void *), void *param) + { + if (right - left < 2) + return; + Swap(left, (left + right) / 2); + int last = left; + for (int i = left; i < right; i++) + if (compare(&operator[](i), &operator[](left), param) < 0) + Swap(++last, i); + Swap(left, last); + Sort(left, last, compare, param); + Sort(last + 1, right, compare, param); + } + + void Sort(int (*compare)(const T*, const T*, void *), void *param) + { + Sort(0, Size(), compare, param); + } +}; + +typedef CRecordVector CIntVector; +typedef CRecordVector CUIntVector; +typedef CRecordVector CBoolVector; +typedef CRecordVector CByteVector; +typedef CRecordVector CPointerVector; + +template +class CObjectVector: public CPointerVector +{ +public: + CObjectVector(){}; + ~CObjectVector() { Clear(); } + CObjectVector(const CObjectVector &objectVector) + { *this = objectVector; } + CObjectVector& operator=(const CObjectVector &objectVector) + { + Clear(); + return (*this += objectVector); + } + CObjectVector& operator+=(const CObjectVector &objectVector) + { + int size = objectVector.Size(); + Reserve(Size() + size); + for(int i = 0; i < size; i++) + Add(objectVector[i]); + return *this; + } + const T& operator[](int index) const { return *((T *)CPointerVector::operator[](index)); } + T& operator[](int index) { return *((T *)CPointerVector::operator[](index)); } + T& Front() { return operator[](0); } + const T& Front() const { return operator[](0); } + T& Back() { return operator[](_size - 1); } + const T& Back() const { return operator[](_size - 1); } + int Add(const T& item) + { return CPointerVector::Add(new T(item)); } + void Insert(int index, const T& item) + { CPointerVector::Insert(index, new T(item)); } + virtual void Delete(int index, int num = 1) + { + TestIndexAndCorrectNum(index, num); + for(int i = 0; i < num; i++) + delete (T *)(((void **)_items)[index + i]); + CPointerVector::Delete(index, num); + } + int Find(const T& item) const + { + for(int i = 0; i < Size(); i++) + if (item == (*this)[i]) + return i; + return -1; + } + int FindInSorted(const T& item) const + { + int left = 0, right = Size(); + while (left != right) + { + int mid = (left + right) / 2; + const T& midValue = (*this)[mid]; + if (item == midValue) + return mid; + if (item < midValue) + right = mid; + else + left = mid + 1; + } + return -1; + } + int AddToSorted(const T& item) + { + int left = 0, right = Size(); + while (left != right) + { + int mid = (left + right) / 2; + const T& midValue = (*this)[mid]; + if (item == midValue) + { + right = mid + 1; + break; + } + if (item < midValue) + right = mid; + else + left = mid + 1; + } + Insert(right, item); + return right; + } + + void Sort(int (*compare)(void *const *, void *const *, void *), void *param) + { CPointerVector::Sort(compare, param); } + + static int CompareObjectItems(void *const *a1, void *const *a2, void *param) + { return MyCompare(*(*((const T **)a1)), *(*((const T **)a2))); } + void Sort() { CPointerVector::Sort(CompareObjectItems, 0); } +}; + +#endif diff --git a/app/win/installer/7zstub/src/Common/Wildcard.cpp b/app/win/installer/7zstub/src/Common/Wildcard.cpp new file mode 100644 index 0000000000..4b9e754e75 --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Wildcard.cpp @@ -0,0 +1,462 @@ +// Common/Wildcard.cpp + +#include "StdAfx.h" + +#include "Wildcard.h" + +static const wchar_t kPeriodChar = L'.'; +static const wchar_t kAnyCharsChar = L'*'; +static const wchar_t kAnyCharChar = L'?'; + +#ifdef _WIN32 +static const wchar_t kDirDelimiter1 = L'\\'; +#endif +static const wchar_t kDirDelimiter2 = L'/'; + +static const UString kWildCardCharSet = L"?*"; + +static const UString kIllegalWildCardFileNameChars= + L"\x1\x2\x3\x4\x5\x6\x7\x8\x9\xA\xB\xC\xD\xE\xF" + L"\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1F" + L"\"/:<>\\|"; + +static const UString kIllegalFileNameChars = kIllegalWildCardFileNameChars + + kWildCardCharSet; + +static inline bool IsCharDirLimiter(wchar_t c) +{ + return ( + #ifdef _WIN32 + c == kDirDelimiter1 || + #endif + c == kDirDelimiter2); +} + +// ----------------------------------------- +// this function tests is name matches mask +// ? - any wchar_t or empty +// * - any characters or empty + +static bool EnhancedMaskTest(const UString &mask, int maskPos, + const UString &name, int namePos) +{ + int maskLen = mask.Length() - maskPos; + int nameLen = name.Length() - namePos; + if (maskLen == 0) + if (nameLen == 0) + return true; + else + return false; + wchar_t maskChar = mask[maskPos]; + if(maskChar == kAnyCharChar) + { + /* + if (EnhancedMaskTest(mask, maskPos + 1, name, namePos)) + return true; + */ + if (nameLen == 0) + return false; + return EnhancedMaskTest(mask, maskPos + 1, name, namePos + 1); + } + else if(maskChar == kAnyCharsChar) + { + if (EnhancedMaskTest(mask, maskPos + 1, name, namePos)) + return true; + if (nameLen == 0) + return false; + return EnhancedMaskTest(mask, maskPos, name, namePos + 1); + } + else + { + wchar_t c = name[namePos]; + if (maskChar != c) +#ifdef _WIN32 + if (MyCharUpper(maskChar) != MyCharUpper(c)) +#endif + return false; + return EnhancedMaskTest(mask, maskPos + 1, name, namePos + 1); + } +} + +// -------------------------------------------------- +// Splits path to strings + +void SplitPathToParts(const UString &path, UStringVector &pathParts) +{ + pathParts.Clear(); + UString name; + int len = path.Length(); + if (len == 0) + return; + for (int i = 0; i < len; i++) + { + wchar_t c = path[i]; + if (IsCharDirLimiter(c)) + { + pathParts.Add(name); + name.Empty(); + } + else + name += c; + } + pathParts.Add(name); +} + +void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name) +{ + int i; + for(i = path.Length() - 1; i >= 0; i--) + if(IsCharDirLimiter(path[i])) + break; + dirPrefix = path.Left(i + 1); + name = path.Mid(i + 1); +} + +UString ExtractDirPrefixFromPath(const UString &path) +{ + int i; + for(i = path.Length() - 1; i >= 0; i--) + if(IsCharDirLimiter(path[i])) + break; + return path.Left(i + 1); +} + +UString ExtractFileNameFromPath(const UString &path) +{ + int i; + for(i = path.Length() - 1; i >= 0; i--) + if(IsCharDirLimiter(path[i])) + break; + return path.Mid(i + 1); +} + + +bool CompareWildCardWithName(const UString &mask, const UString &name) +{ + return EnhancedMaskTest(mask, 0, name, 0); +} + +bool DoesNameContainWildCard(const UString &path) +{ + return (path.FindOneOf(kWildCardCharSet) >= 0); +} + + +// ----------------------------------------------------------' +// NWildcard + +namespace NWildcard { + +static inline int BoolToIndex(bool value) +{ + return value ? 1: 0; +} + + +/* +M = MaskParts.Size(); +N = TestNameParts.Size(); + + File Dir +ForFile req M<=N [N-M, N) - + nonreq M=N [0, M) - + +ForDir req M 1) + return true; + } + return false; +} + +bool CCensorNode::AreThereIncludeItems() const +{ + if (IncludeItems.Size() > 0) + return true; + for (int i = 0; i < SubNodes.Size(); i++) + if (SubNodes[i].AreThereIncludeItems()) + return true; + return false; +} + +bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const +{ + const CObjectVector &items = include ? IncludeItems : ExcludeItems; + for (int i = 0; i < items.Size(); i++) + if (items[i].CheckPath(pathParts, isFile)) + return true; + return false; +} + +bool CCensorNode::CheckPath(UStringVector &pathParts, bool isFile, bool &include) const +{ + if (CheckPathCurrent(false, pathParts, isFile)) + { + include = false; + return true; + } + include = true; + bool finded = CheckPathCurrent(true, pathParts, isFile); + if (pathParts.Size() == 1) + return finded; + int index = FindSubNode(pathParts.Front()); + if (index >= 0) + { + UStringVector pathParts2 = pathParts; + pathParts2.Delete(0); + if (SubNodes[index].CheckPath(pathParts2, isFile, include)) + return true; + } + return finded; +} + +bool CCensorNode::CheckPath(const UString &path, bool isFile, bool &include) const +{ + UStringVector pathParts; + SplitPathToParts(path, pathParts); + return CheckPath(pathParts, isFile, include); +} + +bool CCensorNode::CheckPath(const UString &path, bool isFile) const +{ + bool include; + if(CheckPath(path, isFile, include)) + return include; + return false; +} + +bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const +{ + if (CheckPathCurrent(include, pathParts, isFile)) + return true; + if (Parent == 0) + return false; + pathParts.Insert(0, Name); + return Parent->CheckPathToRoot(include, pathParts, isFile); +} + +/* +bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const +{ + UStringVector pathParts; + SplitPathToParts(path, pathParts); + return CheckPathToRoot(include, pathParts, isFile); +} +*/ + +void CCensorNode::AddItem2(bool include, const UString &path, bool recursive) +{ + if (path.IsEmpty()) + return; + bool forFile = true; + bool forFolder = true; + UString path2 = path; + if (IsCharDirLimiter(path[path.Length() - 1])) + { + path2.Delete(path.Length() - 1); + forFile = false; + } + AddItem(include, path2, recursive, forFile, forFolder); +} + +void CCensorNode::ExtendExclude(const CCensorNode &fromNodes) +{ + ExcludeItems += fromNodes.ExcludeItems; + for (int i = 0; i < fromNodes.SubNodes.Size(); i++) + { + const CCensorNode &node = fromNodes.SubNodes[i]; + int subNodeIndex = FindSubNode(node.Name); + if (subNodeIndex < 0) + subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this)); + SubNodes[subNodeIndex].ExtendExclude(node); + } +} + +int CCensor::FindPrefix(const UString &prefix) const +{ + for (int i = 0; i < Pairs.Size(); i++) + if (Pairs[i].Prefix.CompareNoCase(prefix) == 0) + return i; + return -1; +} + +void CCensor::AddItem(bool include, const UString &path, bool recursive) +{ + UStringVector pathParts; + SplitPathToParts(path, pathParts); + bool forFile = true; + if (pathParts.Back().IsEmpty()) + { + forFile = false; + pathParts.DeleteBack(); + } + const UString &front = pathParts.Front(); + bool isAbs = false; + if (front.IsEmpty()) + isAbs = true; + else if (front.Length() == 2 && front[1] == L':') + isAbs = true; + else + { + for (int i = 0; i < pathParts.Size(); i++) + { + const UString &part = pathParts[i]; + if (part == L".." || part == L".") + { + isAbs = true; + break; + } + } + } + int numAbsParts = 0; + if (isAbs) + if (pathParts.Size() > 1) + numAbsParts = pathParts.Size() - 1; + else + numAbsParts = 1; + UString prefix; + for (int i = 0; i < numAbsParts; i++) + { + const UString &front = pathParts.Front(); + if (DoesNameContainWildCard(front)) + break; + prefix += front; + prefix += WCHAR_PATH_SEPARATOR; + pathParts.Delete(0); + } + int index = FindPrefix(prefix); + if (index < 0) + index = Pairs.Add(CPair(prefix)); + + CItem item; + item.PathParts = pathParts; + item.ForDir = true; + item.ForFile = forFile; + item.Recursive = recursive; + Pairs[index].Head.AddItem(include, item); +} + +bool CCensor::CheckPath(const UString &path, bool isFile) const +{ + bool finded = false; + for (int i = 0; i < Pairs.Size(); i++) + { + bool include; + if (Pairs[i].Head.CheckPath(path, isFile, include)) + { + if (!include) + return false; + finded = true; + } + } + return finded; +} + +void CCensor::ExtendExclude() +{ + int i; + for (i = 0; i < Pairs.Size(); i++) + if (Pairs[i].Prefix.IsEmpty()) + break; + if (i == Pairs.Size()) + return; + int index = i; + for (i = 0; i < Pairs.Size(); i++) + if (index != i) + Pairs[i].Head.ExtendExclude(Pairs[index].Head); +} + +} diff --git a/app/win/installer/7zstub/src/Common/Wildcard.h b/app/win/installer/7zstub/src/Common/Wildcard.h new file mode 100644 index 0000000000..7c94b4329f --- /dev/null +++ b/app/win/installer/7zstub/src/Common/Wildcard.h @@ -0,0 +1,78 @@ +// Common/Wildcard.h + +#ifndef __COMMON_WILDCARD_H +#define __COMMON_WILDCARD_H + +#include "Common/String.h" + +void SplitPathToParts(const UString &path, UStringVector &pathParts); +void SplitPathToParts(const UString &path, UString &dirPrefix, UString &name); +UString ExtractDirPrefixFromPath(const UString &path); +UString ExtractFileNameFromPath(const UString &path); +bool DoesNameContainWildCard(const UString &path); +bool CompareWildCardWithName(const UString &mask, const UString &name); + +namespace NWildcard { + +struct CItem +{ + UStringVector PathParts; + bool Recursive; + bool ForFile; + bool ForDir; + bool CheckPath(const UStringVector &pathParts, bool isFile) const; +}; + +class CCensorNode +{ + CCensorNode *Parent; + bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const; + void AddItemSimple(bool include, CItem &item); + bool CheckPath(UStringVector &pathParts, bool isFile, bool &include) const; +public: + CCensorNode(): Parent(0) { }; + CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { }; + UString Name; + CObjectVector SubNodes; + CObjectVector IncludeItems; + CObjectVector ExcludeItems; + + int FindSubNode(const UString &path) const; + + void AddItem(bool include, CItem &item); + void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir); + void AddItem2(bool include, const UString &path, bool recursive); + + bool NeedCheckSubDirs() const; + bool AreThereIncludeItems() const; + + bool CheckPath(const UString &path, bool isFile, bool &include) const; + bool CheckPath(const UString &path, bool isFile) const; + + bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const; + // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const; + void ExtendExclude(const CCensorNode &fromNodes); +}; + +struct CPair +{ + UString Prefix; + CCensorNode Head; + CPair(const UString &prefix): Prefix(prefix) { }; +}; + +class CCensor +{ + int FindPrefix(const UString &prefix) const; +public: + CObjectVector Pairs; + bool AllAreRelative() const + { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); } + void AddItem(bool include, const UString &path, bool recursive); + bool CheckPath(const UString &path, bool isFile) const; + void ExtendExclude(); +}; + +} + +#endif diff --git a/app/win/installer/7zstub/src/DOC/7zC.txt b/app/win/installer/7zstub/src/DOC/7zC.txt new file mode 100644 index 0000000000..2b67f9dcb5 --- /dev/null +++ b/app/win/installer/7zstub/src/DOC/7zC.txt @@ -0,0 +1,235 @@ +7z ANSI-C Decoder 4.23 +---------------------- + +7z ANSI-C Decoder 4.23 Copyright (C) 1999-2005 Igor Pavlov + +7z ANSI-C provides 7z/LZMA decoding. +7z ANSI-C version is simplified version ported from C++ code. + +LZMA is default and general compression method of 7z format +in 7-Zip compression program (www.7-zip.org). LZMA provides high +compression ratio and very fast decompression. + + +LICENSE +------- + +Read lzma.txt for information about license. + + +Files +--------------------- + +7zAlloc.* - Allocate and Free +7zBuffer.* - Buffer structure +7zCrc.* - CRC32 code +7zDecode.* - Low level memory->memory decoding +7zExtract.* - High level stream->memory decoding +7zHeader.* - .7z format constants +7zIn.* - .7z archive opening +7zItem.* - .7z structures +7zMain.c - Test application +7zMethodID.* - MethodID structure +7zTypes.h - Base types and constants + + +How To Use +---------- + +You must download 7-Zip program from www.7-zip.org. + +You can create .7z archive with 7z.exe or 7za.exe: + + 7za.exe a archive.7z *.htm -r -mx -m0fb=255 -mf=off + +If you have big number of files in archive, and you need fast extracting, +you can use partly-solid archives: + + 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K -mf=off + +In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only +512KB for extracting one file from such archive. + + +Limitations of current version of 7z ANSI-C Decoder +--------------------------------------------------- + + - It reads only "FileName", "Size", and "CRC" information for each file in archive. + - It supports only LZMA and Copy (no compression) methods. + - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names. + +These limitations will be fixed in future versions. + + +Using 7z ANSI-C Decoder Test application: +----------------------------------------- + +Usage: 7zDec + +: + e: Extract files from archive + l: List contents of archive + t: Test integrity of archive + +Example: + + 7zDec l archive.7z + +lists contents of archive.7z + + 7zDec e archive.7z + +extracts files from archive.7z to current folder. + + +How to use .7z Decoder +---------------------- + +.7z Decoder can be compiled in one of two modes: + +1) Default mode. In that mode 7z Decoder will read full compressed + block to RAM before decompressing. + +2) Mode with defined _LZMA_IN_CB. In that mode 7z Decoder can read + compressed block by parts. And you can specify desired buffer size. + So memory requirements can be reduced. But decompressing speed will + be 5-10% lower and code size is slightly larger. + + +Memory allocation +~~~~~~~~~~~~~~~~~ + +7z Decoder uses two memory pools: +1) Temporary pool +2) Main pool +Such scheme can allow you to avoid fragmentation of allocated blocks. + +Steps for using 7z decoder +-------------------------- + +Use code at 7zMain.c as example. + +1) Declare variables: + inStream /* implements ISzInStream interface */ + CArchiveDatabaseEx db; /* 7z archive database structure */ + ISzAlloc allocImp; /* memory functions for main pool */ + ISzAlloc allocTempImp; /* memory functions for temporary pool */ + +2) call InitCrcTable(); function to initialize CRC structures. + +3) call SzArDbExInit(&db); function to initialize db structures. + +4) call SzArchiveOpen(inStream, &db, &allocMain, &allocTemp) to open archive + +This function opens archive "inStream" and reads headers to "db". +All items in "db" will be allocated with "allocMain" functions. +SzArchiveOpen function allocates and frees temporary structures by "allocTemp" functions. + +5) List items or Extract items + + Listing code: + ~~~~~~~~~~~~~ + { + UInt32 i; + for (i = 0; i < db.Database.NumFiles; i++) + { + CFileItem *f = db.Database.Files + i; + printf("%10d %s\n", (int)f->Size, f->Name); + } + } + + Extracting code: + ~~~~~~~~~~~~~~~~ + + SZ_RESULT SzExtract( + ISzInStream *inStream, + CArchiveDatabaseEx *db, + UInt32 fileIndex, /* index of file */ + UInt32 *blockIndex, /* index of solid block */ + Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */ + size_t *outBufferSize, /* buffer size for output buffer */ + size_t *offset, /* offset of stream for required file in *outBuffer */ + size_t *outSizeProcessed, /* size of file in *outBuffer */ + ISzAlloc *allocMain, + ISzAlloc *allocTemp); + + If you need to decompress more than one file, you can send these values from previous call: + blockIndex, + outBuffer, + outBufferSize, + You can consider "outBuffer" as cache of solid block. If your archive is solid, + it will increase decompression speed. + + After decompressing you must free "outBuffer": + allocImp.Free(outBuffer); + +6) call SzArDbExFree(&db, allocImp.Free) to free allocated items in "db". + + + + +Memory requirements for .7z decoding +------------------------------------ + +Memory usage for Archive opening: + - Temporary pool: + - Memory for compressed .7z headers (if _LZMA_IN_CB is not defined) + - Memory for uncompressed .7z headers + - some other temporary blocks + - Main pool: + - Memory for database: + Estimated size of one file structures in solid archive: + - Size (4 or 8 Bytes) + - CRC32 (4 bytes) + - Some file information (4 bytes) + - File Name (variable length) + pointer + allocation structures + +Memory usage for archive Decompressing: + - Temporary pool: + - Memory for compressed solid block (if _LZMA_IN_CB is not defined) + - Memory for LZMA decompressing structures + - Main pool: + - Memory for decompressed solid block + + +If _LZMA_IN_CB is defined, 7z Decoder will not allocate memory for +compressed blocks. Instead of this, you must allocate buffer with desired +size before calling 7z Decoder. Use 7zMain.c as example. + + + +EXIT codes +----------- + +7z Decoder functions can return one of the following codes: + +#define SZ_OK (0) +#define SZE_DATA_ERROR (1) +#define SZE_OUTOFMEMORY (2) +#define SZE_CRC_ERROR (3) + +#define SZE_NOTIMPL (4) +#define SZE_FAIL (5) + +#define SZE_ARCHIVE_ERROR (6) + + + +LZMA Defines +------------ + +_LZMA_IN_CB - Use special callback mode for input stream to reduce memory requirements + +_SZ_FILE_SIZE_64 - define it if you need support for files larger than 4 GB +_SZ_NO_INT_64 - define it if your compiler doesn't support long long int + +_LZMA_PROB32 - it can increase LZMA decompressing speed on some 32-bit CPUs. + +_SZ_ONE_DIRECTORY - define it if you want to locate all source files to one directory +_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr. + + +--- + +http://www.7-zip.org +http://www.7-zip.org/support.html diff --git a/app/win/installer/7zstub/src/DOC/copying.txt b/app/win/installer/7zstub/src/DOC/copying.txt new file mode 100644 index 0000000000..f3926a6155 --- /dev/null +++ b/app/win/installer/7zstub/src/DOC/copying.txt @@ -0,0 +1,504 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + , 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! + + diff --git a/app/win/installer/7zstub/src/DOC/lzma.txt b/app/win/installer/7zstub/src/DOC/lzma.txt new file mode 100644 index 0000000000..fc7fae1bca --- /dev/null +++ b/app/win/installer/7zstub/src/DOC/lzma.txt @@ -0,0 +1,630 @@ +LZMA SDK 4.40 +------------- + +LZMA SDK Copyright (C) 1999-2006 Igor Pavlov + +LZMA SDK provides the documentation, samples, header files, libraries, +and tools you need to develop applications that use LZMA compression. + +LZMA is default and general compression method of 7z format +in 7-Zip compression program (www.7-zip.org). LZMA provides high +compression ratio and very fast decompression. + +LZMA is an improved version of famous LZ77 compression algorithm. +It was improved in way of maximum increasing of compression ratio, +keeping high decompression speed and low memory requirements for +decompressing. + + + +LICENSE +------- + +LZMA SDK is available under any of the following licenses: + +1) GNU Lesser General Public License (GNU LGPL) +2) Common Public License (CPL) +3) Simplified license for unmodified code (read SPECIAL EXCEPTION) +4) Proprietary license + +It means that you can select one of these four options and follow rules of that license. + + +1,2) GNU LGPL and CPL licenses are pretty similar and both these +licenses are classified as + - "Free software licenses" at http://www.gnu.org/ + - "OSI-approved" at http://www.opensource.org/ + + +3) SPECIAL EXCEPTION + +Igor Pavlov, as the author of this code, expressly permits you +to statically or dynamically link your code (or bind by name) +to the files from LZMA SDK without subjecting your linked +code to the terms of the CPL or GNU LGPL. +Any modifications or additions to files from LZMA SDK, however, +are subject to the GNU LGPL or CPL terms. + +SPECIAL EXCEPTION allows you to use LZMA SDK in applications with closed code, +while you keep LZMA SDK code unmodified. + + +SPECIAL EXCEPTION #2: Igor Pavlov, as the author of this code, expressly permits +you to use this code under the same terms and conditions contained in the License +Agreement you have for any previous version of LZMA SDK developed by Igor Pavlov. + +SPECIAL EXCEPTION #2 allows owners of proprietary licenses to use latest version +of LZMA SDK as update for previous versions. + + +SPECIAL EXCEPTION #3: Igor Pavlov, as the author of this code, expressly permits +you to use code of the following files: +BranchTypes.h, LzmaTypes.h, LzmaTest.c, LzmaStateTest.c, LzmaAlone.cpp, +LzmaAlone.cs, LzmaAlone.java +as public domain code. + + +4) Proprietary license + +LZMA SDK also can be available under a proprietary license which +can include: + +1) Right to modify code without subjecting modified code to the +terms of the CPL or GNU LGPL +2) Technical support for code + +To request such proprietary license or any additional consultations, +send email message from that page: +http://www.7-zip.org/support.html + + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +You should have received a copy of the Common Public License +along with this library. + + +LZMA SDK Contents +----------------- + +LZMA SDK includes: + + - C++ source code of LZMA compressing and decompressing + - ANSI-C compatible source code for LZMA decompressing + - C# source code for LZMA compressing and decompressing + - Java source code for LZMA compressing and decompressing + - Compiled file->file LZMA compressing/decompressing program for Windows system + +ANSI-C LZMA decompression code was ported from original C++ sources to C. +Also it was simplified and optimized for code size. +But it is fully compatible with LZMA from 7-Zip. + + +UNIX/Linux version +------------------ +To compile C++ version of file->file LZMA, go to directory +C/7zip/Compress/LZMA_Alone +and type "make" or "make clean all" to recompile all. + +In some UNIX/Linux versions you must compile LZMA with static libraries. +To compile with static libraries, change string in makefile +LIB = -lm +to string +LIB = -lm -static + + +Files +--------------------- +C - C / CPP source code +CS - C# source code +Java - Java source code +lzma.txt - LZMA SDK description (this file) +7zFormat.txt - 7z Format description +7zC.txt - 7z ANSI-C Decoder description (this file) +methods.txt - Compression method IDs for .7z +LGPL.txt - GNU Lesser General Public License +CPL.html - Common Public License +lzma.exe - Compiled file->file LZMA encoder/decoder for Windows +history.txt - history of the LZMA SDK + + +Source code structure +--------------------- + +C - C / CPP files + Common - common files for C++ projects + Windows - common files for Windows related code + 7zip - files related to 7-Zip Project + Common - common files for 7-Zip + Compress - files related to compression/decompression + LZ - files related to LZ (Lempel-Ziv) compression algorithm + BinTree - Binary Tree Match Finder for LZ algorithm + HashChain - Hash Chain Match Finder for LZ algorithm + Patricia - Patricia Match Finder for LZ algorithm + RangeCoder - Range Coder (special code of compression/decompression) + LZMA - LZMA compression/decompression on C++ + LZMA_Alone - file->file LZMA compression/decompression + LZMA_C - ANSI-C compatible LZMA decompressor + LzmaDecode.h - interface for LZMA decoding on ANSI-C + LzmaDecode.c - LZMA decoding on ANSI-C (new fastest version) + LzmaDecodeSize.c - LZMA decoding on ANSI-C (old size-optimized version) + LzmaTest.c - test application that decodes LZMA encoded file + LzmaTypes.h - basic types for LZMA Decoder + LzmaStateDecode.h - interface for LZMA decoding (State version) + LzmaStateDecode.c - LZMA decoding on ANSI-C (State version) + LzmaStateTest.c - test application (State version) + Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code + Archive - files related to archiving + 7z_C - 7z ANSI-C Decoder + +CS - C# files + 7zip + Common - some common files for 7-Zip + Compress - files related to compression/decompression + LZ - files related to LZ (Lempel-Ziv) compression algorithm + LZMA - LZMA compression/decompression + LzmaAlone - file->file LZMA compression/decompression + RangeCoder - Range Coder (special code of compression/decompression) + +Java - Java files + SevenZip + Compression - files related to compression/decompression + LZ - files related to LZ (Lempel-Ziv) compression algorithm + LZMA - LZMA compression/decompression + RangeCoder - Range Coder (special code of compression/decompression) + +C/C++ source code of LZMA SDK is part of 7-Zip project. + +You can find ANSI-C LZMA decompressing code at folder + C/7zip/Compress/LZMA_C +7-Zip doesn't use that ANSI-C LZMA code and that code was developed +specially for this SDK. And files from LZMA_C do not need files from +other directories of SDK for compiling. + +7-Zip source code can be downloaded from 7-Zip's SourceForge page: + + http://sourceforge.net/projects/sevenzip/ + + +LZMA features +------------- + - Variable dictionary size (up to 1 GB) + - Estimated compressing speed: about 1 MB/s on 1 GHz CPU + - Estimated decompressing speed: + - 8-12 MB/s on 1 GHz Intel Pentium 3 or AMD Athlon + - 500-1000 KB/s on 100 MHz ARM, MIPS, PowerPC or other simple RISC + - Small memory requirements for decompressing (8-32 KB + DictionarySize) + - Small code size for decompressing: 2-8 KB (depending from + speed optimizations) + +LZMA decoder uses only integer operations and can be +implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions). + +Some critical operations that affect to speed of LZMA decompression: + 1) 32*16 bit integer multiply + 2) Misspredicted branches (penalty mostly depends from pipeline length) + 3) 32-bit shift and arithmetic operations + +Speed of LZMA decompressing mostly depends from CPU speed. +Memory speed has no big meaning. But if your CPU has small data cache, +overall weight of memory speed will slightly increase. + + +How To Use +---------- + +Using LZMA encoder/decoder executable +-------------------------------------- + +Usage: LZMA inputFile outputFile [...] + + e: encode file + + d: decode file + + b: Benchmark. There are two tests: compressing and decompressing + with LZMA method. Benchmark shows rating in MIPS (million + instructions per second). Rating value is calculated from + measured speed and it is normalized with AMD Athlon 64 X2 CPU + results. Also Benchmark checks possible hardware errors (RAM + errors in most cases). Benchmark uses these settings: + (-a1, -d21, -fb32, -mfbt4). You can change only -d. Also you + can change number of iterations. Example for 30 iterations: + LZMA b 30 + Default number of iterations is 10. + + + + + -a{N}: set compression mode 0 = fast, 1 = normal + default: 1 (normal) + + d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB) + The maximum value for dictionary size is 1 GB = 2^30 bytes. + Dictionary size is calculated as DictionarySize = 2^N bytes. + For decompressing file compressed by LZMA method with dictionary + size D = 2^N you need about D bytes of memory (RAM). + + -fb{N}: set number of fast bytes - [5, 273], default: 128 + Usually big number gives a little bit better compression ratio + and slower compression process. + + -lc{N}: set number of literal context bits - [0, 8], default: 3 + Sometimes lc=4 gives gain for big files. + + -lp{N}: set number of literal pos bits - [0, 4], default: 0 + lp switch is intended for periodical data when period is + equal 2^N. For example, for 32-bit (4 bytes) + periodical data you can use lp=2. Often it's better to set lc0, + if you change lp switch. + + -pb{N}: set number of pos bits - [0, 4], default: 2 + pb switch is intended for periodical data + when period is equal 2^N. + + -mf{MF_ID}: set Match Finder. Default: bt4. + Algorithms from hc* group doesn't provide good compression + ratio, but they often works pretty fast in combination with + fast mode (-a0). + + Memory requirements depend from dictionary size + (parameter "d" in table below). + + MF_ID Memory Description + + bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing. + bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing. + bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing. + hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing. + + -eos: write End Of Stream marker. By default LZMA doesn't write + eos marker, since LZMA decoder knows uncompressed size + stored in .lzma file header. + + -si: Read data from stdin (it will write End Of Stream marker). + -so: Write data to stdout + + +Examples: + +1) LZMA e file.bin file.lzma -d16 -lc0 + +compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K) +and 0 literal context bits. -lc0 allows to reduce memory requirements +for decompression. + + +2) LZMA e file.bin file.lzma -lc0 -lp2 + +compresses file.bin to file.lzma with settings suitable +for 32-bit periodical data (for example, ARM or MIPS code). + +3) LZMA d file.lzma file.bin + +decompresses file.lzma to file.bin. + + +Compression ratio hints +----------------------- + +Recommendations +--------------- + +To increase compression ratio for LZMA compressing it's desirable +to have aligned data (if it's possible) and also it's desirable to locate +data in such order, where code is grouped in one place and data is +grouped in other place (it's better than such mixing: code, data, code, +data, ...). + + +Using Filters +------------- +You can increase compression ratio for some data types, using +special filters before compressing. For example, it's possible to +increase compression ratio on 5-10% for code for those CPU ISAs: +x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC. + +You can find C/C++ source code of such filters in folder "7zip/Compress/Branch" + +You can check compression ratio gain of these filters with such +7-Zip commands (example for ARM code): +No filter: + 7z a a1.7z a.bin -m0=lzma + +With filter for little-endian ARM code: + 7z a a2.7z a.bin -m0=bc_arm -m1=lzma + +With filter for big-endian ARM code (using additional Swap4 filter): + 7z a a3.7z a.bin -m0=swap4 -m1=bc_arm -m2=lzma + +It works in such manner: +Compressing = Filter_encoding + LZMA_encoding +Decompressing = LZMA_decoding + Filter_decoding + +Compressing and decompressing speed of such filters is very high, +so it will not increase decompressing time too much. +Moreover, it reduces decompression time for LZMA_decoding, +since compression ratio with filtering is higher. + +These filters convert CALL (calling procedure) instructions +from relative offsets to absolute addresses, so such data becomes more +compressible. Source code of these CALL filters is pretty simple +(about 20 lines of C++), so you can convert it from C++ version yourself. + +For some ISAs (for example, for MIPS) it's impossible to get gain from such filter. + + +LZMA compressed file format +--------------------------- +Offset Size Description + 0 1 Special LZMA properties for compressed data + 1 4 Dictionary size (little endian) + 5 8 Uncompressed size (little endian). -1 means unknown size + 13 Compressed data + + +ANSI-C LZMA Decoder +~~~~~~~~~~~~~~~~~~~ + +To compile ANSI-C LZMA Decoder you can use one of the following files sets: +1) LzmaDecode.h + LzmaDecode.c + LzmaTest.c (fastest version) +2) LzmaDecode.h + LzmaDecodeSize.c + LzmaTest.c (old size-optimized version) +3) LzmaStateDecode.h + LzmaStateDecode.c + LzmaStateTest.c (zlib-like interface) + + +Memory requirements for LZMA decoding +------------------------------------- + +LZMA decoder doesn't allocate memory itself, so you must +allocate memory and send it to LZMA. + +Stack usage of LZMA decoding function for local variables is not +larger than 200 bytes. + +How To decompress data +---------------------- + +LZMA Decoder (ANSI-C version) now supports 5 interfaces: +1) Single-call Decompressing +2) Single-call Decompressing with input stream callback +3) Multi-call Decompressing with output buffer +4) Multi-call Decompressing with input callback and output buffer +5) Multi-call State Decompressing (zlib-like interface) + +Variant-5 is similar to Variant-4, but Variant-5 doesn't use callback functions. + +Decompressing steps +------------------- + +1) read LZMA properties (5 bytes): + unsigned char properties[LZMA_PROPERTIES_SIZE]; + +2) read uncompressed size (8 bytes, little-endian) + +3) Decode properties: + + CLzmaDecoderState state; /* it's 24-140 bytes structure, if int is 32-bit */ + + if (LzmaDecodeProperties(&state.Properties, properties, LZMA_PROPERTIES_SIZE) != LZMA_RESULT_OK) + return PrintError(rs, "Incorrect stream properties"); + +4) Allocate memory block for internal Structures: + + state.Probs = (CProb *)malloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb)); + if (state.Probs == 0) + return PrintError(rs, kCantAllocateMessage); + + LZMA decoder uses array of CProb variables as internal structure. + By default, CProb is unsigned_short. But you can define _LZMA_PROB32 to make + it unsigned_int. It can increase speed on some 32-bit CPUs, but memory + usage will be doubled in that case. + + +5) Main Decompressing + +You must use one of the following interfaces: + +5.1 Single-call Decompressing +----------------------------- +When to use: RAM->RAM decompressing +Compile files: LzmaDecode.h, LzmaDecode.c +Compile defines: no defines +Memory Requirements: + - Input buffer: compressed size + - Output buffer: uncompressed size + - LZMA Internal Structures (~16 KB for default settings) + +Interface: + int res = LzmaDecode(&state, + inStream, compressedSize, &inProcessed, + outStream, outSize, &outProcessed); + + +5.2 Single-call Decompressing with input stream callback +-------------------------------------------------------- +When to use: File->RAM or Flash->RAM decompressing. +Compile files: LzmaDecode.h, LzmaDecode.c +Compile defines: _LZMA_IN_CB +Memory Requirements: + - Buffer for input stream: any size (for example, 16 KB) + - Output buffer: uncompressed size + - LZMA Internal Structures (~16 KB for default settings) + +Interface: + typedef struct _CBuffer + { + ILzmaInCallback InCallback; + FILE *File; + unsigned char Buffer[kInBufferSize]; + } CBuffer; + + int LzmaReadCompressed(void *object, const unsigned char **buffer, SizeT *size) + { + CBuffer *bo = (CBuffer *)object; + *buffer = bo->Buffer; + *size = MyReadFile(bo->File, bo->Buffer, kInBufferSize); + return LZMA_RESULT_OK; + } + + CBuffer g_InBuffer; + + g_InBuffer.File = inFile; + g_InBuffer.InCallback.Read = LzmaReadCompressed; + int res = LzmaDecode(&state, + &g_InBuffer.InCallback, + outStream, outSize, &outProcessed); + + +5.3 Multi-call decompressing with output buffer +----------------------------------------------- +When to use: RAM->File decompressing +Compile files: LzmaDecode.h, LzmaDecode.c +Compile defines: _LZMA_OUT_READ +Memory Requirements: + - Input buffer: compressed size + - Buffer for output stream: any size (for example, 16 KB) + - LZMA Internal Structures (~16 KB for default settings) + - LZMA dictionary (dictionary size is encoded in stream properties) + +Interface: + + state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); + + LzmaDecoderInit(&state); + do + { + LzmaDecode(&state, + inBuffer, inAvail, &inProcessed, + g_OutBuffer, outAvail, &outProcessed); + inAvail -= inProcessed; + inBuffer += inProcessed; + } + while you need more bytes + + see LzmaTest.c for more details. + + +5.4 Multi-call decompressing with input callback and output buffer +------------------------------------------------------------------ +When to use: File->File decompressing +Compile files: LzmaDecode.h, LzmaDecode.c +Compile defines: _LZMA_IN_CB, _LZMA_OUT_READ +Memory Requirements: + - Buffer for input stream: any size (for example, 16 KB) + - Buffer for output stream: any size (for example, 16 KB) + - LZMA Internal Structures (~16 KB for default settings) + - LZMA dictionary (dictionary size is encoded in stream properties) + +Interface: + + state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); + + LzmaDecoderInit(&state); + do + { + LzmaDecode(&state, + &bo.InCallback, + g_OutBuffer, outAvail, &outProcessed); + } + while you need more bytes + + see LzmaTest.c for more details: + + +5.5 Multi-call State Decompressing (zlib-like interface) +------------------------------------------------------------------ +When to use: file->file decompressing +Compile files: LzmaStateDecode.h, LzmaStateDecode.c +Compile defines: +Memory Requirements: + - Buffer for input stream: any size (for example, 16 KB) + - Buffer for output stream: any size (for example, 16 KB) + - LZMA Internal Structures (~16 KB for default settings) + - LZMA dictionary (dictionary size is encoded in stream properties) + +Interface: + + state.Dictionary = (unsigned char *)malloc(state.Properties.DictionarySize); + + + LzmaDecoderInit(&state); + do + { + res = LzmaDecode(&state, + inBuffer, inAvail, &inProcessed, + g_OutBuffer, outAvail, &outProcessed, + finishDecoding); + inAvail -= inProcessed; + inBuffer += inProcessed; + } + while you need more bytes + + see LzmaStateTest.c for more details: + + +6) Free all allocated blocks + + +Note +---- +LzmaDecodeSize.c is size-optimized version of LzmaDecode.c. +But compiled code of LzmaDecodeSize.c can be larger than +compiled code of LzmaDecode.c. So it's better to use +LzmaDecode.c in most cases. + + +EXIT codes +----------- + +LZMA decoder can return one of the following codes: + +#define LZMA_RESULT_OK 0 +#define LZMA_RESULT_DATA_ERROR 1 + +If you use callback function for input data and you return some +error code, LZMA Decoder also returns that code. + + + +LZMA Defines +------------ + +_LZMA_IN_CB - Use callback for input data + +_LZMA_OUT_READ - Use read function for output data + +_LZMA_LOC_OPT - Enable local speed optimizations inside code. + _LZMA_LOC_OPT is only for LzmaDecodeSize.c (size-optimized version). + _LZMA_LOC_OPT doesn't affect LzmaDecode.c (speed-optimized version) + and LzmaStateDecode.c + +_LZMA_PROB32 - It can increase speed on some 32-bit CPUs, + but memory usage will be doubled in that case + +_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler + and long is 32-bit. + +_LZMA_SYSTEM_SIZE_T - Define it if you want to use system's size_t. + You can use it to enable 64-bit sizes supporting + + + +C++ LZMA Encoder/Decoder +~~~~~~~~~~~~~~~~~~~~~~~~ +C++ LZMA code use COM-like interfaces. So if you want to use it, +you can study basics of COM/OLE. + +By default, LZMA Encoder contains all Match Finders. +But for compressing it's enough to have just one of them. +So for reducing size of compressing code you can define: + #define COMPRESS_MF_BT + #define COMPRESS_MF_BT4 +and it will use only bt4 match finder. + + +--- + +http://www.7-zip.org +http://www.7-zip.org/support.html diff --git a/app/win/installer/7zstub/src/DOC/readme.txt b/app/win/installer/7zstub/src/DOC/readme.txt new file mode 100644 index 0000000000..d12260367c --- /dev/null +++ b/app/win/installer/7zstub/src/DOC/readme.txt @@ -0,0 +1,226 @@ +7-Zip 4.42 Sources +------------------ + +7-Zip is a file archiver for Windows 95/98/ME/NT/2000/2003/XP. + +7-Zip Copyright (C) 1999-2006 Igor Pavlov. + + +License Info +------------ + +Most of 7-Zip source code is under GNU LGPL. + +Files in folders + 7zip/Compress/Rar20 + 7zip/Compress/Rar29 + 7zip/Compress/Rar29/Original +are licensed under "unRAR license + GNU LGPL" license. +Source code files in all other folders of this package are under GNU LGPL. + +"unRAR license + GNU LGPL" means that you must follow +GNU LGPL in all aspects while it is in agreement +with unRAR license. But you can not break unRAR license rules. +It means that unRAR license is main license in that pair. + +You can find unRAR license in file unrarLicense.txt +You can find GNU LGPL license in file copying.txt + + +GNU LGPL information: +--------------------- + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +unRAR license + GNU LGPL Notes +------------------------------ + +Please check main restriction from unRar license: + + 2. The unRAR sources may be used in any software to handle RAR + archives without limitations free of charge, but cannot be used + to re-create the RAR compression algorithm, which is proprietary. + Distribution of modified unRAR sources in separate form or as a + part of other software is permitted, provided that it is clearly + stated in the documentation and source comments that the code may + not be used to develop a RAR (WinRAR) compatible archiver. + +In brief it means: +1) You can compile and use compiled files under GNU LGPL rules, since + unRAR license almost has no restrictions for compiled files. + You can link these compiled files to LGPL programs. +2) You can fix bugs in source code and use compiled fixed version. +3) You can not use unRAR sources to re-create the RAR compression algorithm. + + +7zip\Compress\Rar29\Original folder contains files that are modified +versions of original unRAR source code files. + + +License notes +------------- + +You can support development of 7-Zip by registering. + +7-Zip is free software distributed under the GNU LGPL. +If you need license with other conditions, write to +http://www.7-zip.org/support.html + +--- +Also this package contains files from LZMA SDK +you can download LZMA SDK from this page: +http://www.7-zip.org/sdk.html +read about addtional licenses for LZMA SDK in file +DOC/lzma.txt + + +How to compile +-------------- +To compile sources you need Visual C++ 6.0. +For compiling some files you also need +new Platform SDK from Microsoft' Site: +http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm +or +http://www.microsoft.com/msdownload/platformsdk/sdkupdate/XPSP2FULLInstall.htm +or +http://www.microsoft.com/msdownload/platformsdk/sdkupdate/ + +If you use MSVC6, specify SDK directories at top of directories lists: +Tools / Options / Directories + - Include files + - Library files + + +To compile 7-Zip for AMD64 and IA64 you need: + Windows Server 2003 SP1 Platform SDK from microsoft.com + + + +Compiling under Unix/Linux +-------------------------- +Check this site for Posix/Linux version: +http://sourceforge.net/projects/p7zip/ + + +Notes: +------ +7-Zip consists of COM modules (DLL files). +But 7-Zip doesn't use standard COM interfaces for creating objects. +Look at +7zip\UI\Client7z folder for example of using DLL files of 7-Zip. +Some DLL files can use other DLL files from 7-Zip. +If you don't like it, you must use standalone version of DLL. +To compile standalone version of DLL you must include all used parts +to project and define some defs. +For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll +that works with 7z format. So you can use such DLL in your project +without additional DLL files. + + +Description of 7-Zip sources package +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +DOC Documentation +--- + 7zFormat.txt - 7z format description + copying.txt - GNU LGPL license + unRarLicense.txt - License for unRAR part of source code + history.txt - Sources history + Methods.txt - Compression method IDs + readme.txt - Readme file + lzma.txt - LZMA SDK description + 7zip.nsi - installer script for NSIS + + +Common Common modules +Windows Win32 wrappers + +7zip +------- + Common Common modules for 7-zip + + Archive 7-Zip Archive Format Plugins + -------- + Common + 7z + Arj + BZip2 + Cab + Cpio + GZip + Rar + Rpm + Split + Tar + Zip + + Bundle Modules that are bundles of other modules + ------ + Alone 7za.exe: Standalone version of 7z + Alone7z 7zr.exe: Standalone version of 7z that supports only 7z/LZMA/BCJ/BCJ2 + SFXCon 7zCon.sfx: Console 7z SFX module + SFXWin 7z.sfx: Windows 7z SFX module + SFXSetup 7zS.sfx: Windows 7z SFX module for Installers + Format7z 7za.dll: Standalone version of 7z.dll + + UI + -- + Agent Intermediary modules for FAR plugin and Explorer plugin + Console 7z.exe Console version + Explorer Explorer plugin + Resource Resources + Far FAR plugin + Client7z Test application for 7za.dll + + Compress + -------- + BZip2 BZip2 compressor + Original Download BZip2 compression sources from + http://sources.redhat.com/bzip2/index.html + to that folder. + Branch Branch converter + ByteSwap Byte Swap converter + Copy Copy coder + Deflate + Implode + Arj + LZMA + PPMd Dmitry Shkarin's PPMdH with small changes. + LZ Lempel - Ziv + MT Multi Thread Match finder + BinTree Match Finder based on Binary Tree + Patricia Match Finder based on Patricia algoritm + HashChain Match Finder based on Hash Chains + + Crypto Crypto modules + ------ + 7zAES Cipher for 7z + AES AES Cipher + Rar20 Cipher for Rar 2.0 + RarAES Cipher for Rar 3.0 + Zip Cipher for Zip + + FileManager File Manager + + +--- +Igor Pavlov +http://www.7-zip.org + + +--- +End of document + diff --git a/app/win/installer/7zstub/src/Windows/COM.cpp b/app/win/installer/7zstub/src/Windows/COM.cpp new file mode 100644 index 0000000000..f7ed066ae7 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/COM.cpp @@ -0,0 +1,37 @@ +// Windows/COM.cpp + +#include "StdAfx.h" + +#include "Windows/COM.h" +#include "Common/StringConvert.h" + +namespace NWindows { +namespace NCOM { + +// CoInitialize (NULL); must be called! + +UString GUIDToStringW(REFGUID guid) +{ + UString string; + const int kStringSize = 48; + StringFromGUID2(guid, string.GetBuffer(kStringSize), kStringSize); + string.ReleaseBuffer(); + return string; +} + +AString GUIDToStringA(REFGUID guid) +{ + return UnicodeStringToMultiByte(GUIDToStringW(guid)); +} + +HRESULT StringToGUIDW(const wchar_t *string, GUID &classID) +{ + return CLSIDFromString((wchar_t *)string, &classID); +} + +HRESULT StringToGUIDA(const char *string, GUID &classID) +{ + return StringToGUIDW(MultiByteToUnicodeString(string), classID); +} + +}} \ No newline at end of file diff --git a/app/win/installer/7zstub/src/Windows/COM.h b/app/win/installer/7zstub/src/Windows/COM.h new file mode 100644 index 0000000000..b0890c6c40 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/COM.h @@ -0,0 +1,57 @@ +// Windows/COM.h + +#ifndef __WINDOWS_COM_H +#define __WINDOWS_COM_H + +#include "Common/String.h" + +namespace NWindows { +namespace NCOM { + +class CComInitializer +{ +public: + CComInitializer() { CoInitialize(NULL);}; + ~CComInitializer() { CoUninitialize(); }; +}; + +class CStgMedium +{ + STGMEDIUM _object; +public: + bool _mustBeReleased; + CStgMedium(): _mustBeReleased(false) {} + ~CStgMedium() { Free(); } + void Free() + { + if(_mustBeReleased) + ReleaseStgMedium(&_object); + _mustBeReleased = false; + } + const STGMEDIUM* operator->() const { return &_object;} + STGMEDIUM* operator->() { return &_object;} + STGMEDIUM* operator&() { return &_object; } +}; + +////////////////////////////////// +// GUID <--> String Conversions +UString GUIDToStringW(REFGUID guid); +AString GUIDToStringA(REFGUID guid); +#ifdef UNICODE + #define GUIDToString GUIDToStringW +#else + #define GUIDToString GUIDToStringA +#endif // !UNICODE + +HRESULT StringToGUIDW(const wchar_t *string, GUID &classID); +HRESULT StringToGUIDA(const char *string, GUID &classID); +#ifdef UNICODE + #define StringToGUID StringToGUIDW +#else + #define StringToGUID StringToGUIDA +#endif // !UNICODE + + +}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Control/Dialog.cpp b/app/win/installer/7zstub/src/Windows/Control/Dialog.cpp new file mode 100644 index 0000000000..9d9891f512 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Control/Dialog.cpp @@ -0,0 +1,145 @@ +// Windows/Control/Dialog.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "Common/StringConvert.h" +#endif +#include "Windows/Control/Dialog.h" + +extern HINSTANCE g_hInstance; +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NControl { + +static INT_PTR APIENTRY DialogProcedure(HWND dialogHWND, UINT message, + WPARAM wParam, LPARAM lParam) +{ + CWindow dialogTmp(dialogHWND); + if (message == WM_INITDIALOG) + dialogTmp.SetUserDataLongPtr(lParam); + CDialog *dialog = (CDialog *)(dialogTmp.GetUserDataLongPtr()); + if (dialog == NULL) + return FALSE; + if (message == WM_INITDIALOG) + dialog->Attach(dialogHWND); + + return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); +} + +bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + return OnInit(); + case WM_COMMAND: + return OnCommand(wParam, lParam); + case WM_NOTIFY: + return OnNotify(wParam, (LPNMHDR) lParam); + case WM_HELP: + { + OnHelp((LPHELPINFO)lParam); + return true; + } + case WM_TIMER: + { + return OnTimer(wParam, lParam); + } + default: + return false; + } +} + +bool CDialog::OnCommand(WPARAM wParam, LPARAM lParam) +{ + return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam); +} + +bool CDialog::OnCommand(int code, int itemID, LPARAM lParam) +{ + if (code == BN_CLICKED) + return OnButtonClicked(itemID, (HWND)lParam); + return false; +} + +bool CDialog::OnButtonClicked(int buttonID, HWND buttonHWND) +{ + switch(buttonID) + { + case IDOK: + OnOK(); + break; + case IDCANCEL: + OnCancel(); + break; + case IDHELP: + OnHelp(); + break; + default: + return false; + } + return true; +} + +bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow) +{ + HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); + if (aHWND == 0) + return false; + Attach(aHWND); + return true; +} + +INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow) +{ + return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); +} + +#ifndef _UNICODE + +bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow) +{ + HWND aHWND; + if (g_IsNT) + aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); + else + { + AString name; + LPCSTR templateNameA; + if (IS_INTRESOURCE(templateName)) + templateNameA = (LPCSTR)templateName; + else + { + name = GetSystemString(templateName); + templateNameA = name; + } + aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); + } + if (aHWND == 0) + return false; + Attach(aHWND); + return true; +} + +INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow) +{ + if (g_IsNT) + return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this); + AString name; + LPCSTR templateNameA; + if (IS_INTRESOURCE(templateName)) + templateNameA = (LPCSTR)templateName; + else + { + name = GetSystemString(templateName); + templateNameA = name; + } + return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this); +} +#endif + +}} diff --git a/app/win/installer/7zstub/src/Windows/Control/Dialog.h b/app/win/installer/7zstub/src/Windows/Control/Dialog.h new file mode 100644 index 0000000000..2c78efcbac --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Control/Dialog.h @@ -0,0 +1,141 @@ +// Windows/Control/Dialog.h + +#ifndef __WINDOWS_CONTROL_DIALOG_H +#define __WINDOWS_CONTROL_DIALOG_H + +#include "Windows/Window.h" +#include "Windows/Defs.h" + +namespace NWindows { +namespace NControl { + +class CDialog: public CWindow +{ +public: + CDialog(HWND wndow = NULL): CWindow(wndow){}; + virtual ~CDialog() {}; + + HWND GetItem(int itemID) const + { return GetDlgItem(_window, itemID); } + + bool EnableItem(int itemID, bool enable) const + { return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); } + + bool SetItemText(int itemID, LPCTSTR s) + { return BOOLToBool(SetDlgItemText(_window, itemID, s)); } + + #ifndef _UNICODE + bool SetItemText(int itemID, LPCWSTR s) + { + CWindow window(GetItem(itemID)); + return window.SetText(s); + } + #endif + + UINT GetItemText(int itemID, LPTSTR string, int maxCount) + { return GetDlgItemText(_window, itemID, string, maxCount); } + #ifndef _UNICODE + /* + bool GetItemText(int itemID, LPWSTR string, int maxCount) + { + CWindow window(GetItem(itemID)); + return window.GetText(string, maxCount); + } + */ + #endif + + bool SetItemInt(int itemID, UINT value, bool isSigned) + { return BOOLToBool(SetDlgItemInt(_window, itemID, value, BoolToBOOL(isSigned))); } + bool GetItemInt(int itemID, bool isSigned, UINT &value) + { + BOOL result; + value = GetDlgItemInt(_window, itemID, &result, BoolToBOOL(isSigned)); + return BOOLToBool(result); + } + + HWND GetNextGroupItem(HWND control, bool previous) + { return GetNextDlgGroupItem(_window, control, BoolToBOOL(previous)); } + HWND GetNextTabItem(HWND control, bool previous) + { return GetNextDlgTabItem(_window, control, BoolToBOOL(previous)); } + + bool MapRect(LPRECT rect) + { return BOOLToBool(MapDialogRect(_window, rect)); } + + bool IsMessage(LPMSG message) + { return BOOLToBool(IsDialogMessage(_window, message)); } + + LRESULT SendItemMessage(int itemID, UINT message, WPARAM wParam, LPARAM lParam) + { return SendDlgItemMessage(_window, itemID, message, wParam, lParam); } + + bool CheckButton(int buttonID, UINT checkState) + { return BOOLToBool(CheckDlgButton(_window, buttonID, checkState)); } + bool CheckButton(int buttonID, bool checkState) + { return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); } + + UINT IsButtonChecked(int buttonID) const + { return IsDlgButtonChecked(_window, buttonID); } + bool IsButtonCheckedBool(int buttonID) const + { return (IsButtonChecked(buttonID) == BST_CHECKED); } + + bool CheckRadioButton(int firstButtonID, int lastButtonID, int checkButtonID) + { return BOOLToBool(::CheckRadioButton(_window, firstButtonID, lastButtonID, checkButtonID)); } + + virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam); + virtual bool OnInit() { return true; } + virtual bool OnCommand(WPARAM wParam, LPARAM lParam); + virtual bool OnCommand(int code, int itemID, LPARAM lParam); + virtual void OnHelp(LPHELPINFO helpInfo) { OnHelp(); }; + virtual void OnHelp() {}; + virtual bool OnButtonClicked(int buttonID, HWND buttonHWND); + virtual void OnOK() {}; + virtual void OnCancel() {}; + virtual bool OnNotify(UINT controlID, LPNMHDR lParam) { return false; } + virtual bool OnTimer(WPARAM timerID, LPARAM callback) { return false; } + + LONG_PTR SetMsgResult(LONG_PTR newLongPtr ) + { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); } + LONG_PTR GetMsgResult() const + { return GetLongPtr(DWLP_MSGRESULT); } +}; + +class CModelessDialog: public CDialog +{ +public: + bool Create(LPCTSTR templateName, HWND parentWindow); + #ifndef _UNICODE + bool Create(LPCWSTR templateName, HWND parentWindow); + #endif + virtual void OnOK() { Destroy(); } + virtual void OnCancel() { Destroy(); } +}; + +class CModalDialog: public CDialog +{ +public: + INT_PTR Create(LPCTSTR templateName, HWND parentWindow); + INT_PTR Create(UINT resID, HWND parentWindow) + { return Create(MAKEINTRESOURCEW(resID), parentWindow); } + #ifndef _UNICODE + INT_PTR Create(LPCWSTR templateName, HWND parentWindow); + #endif + + bool End(INT_PTR result) + { return BOOLToBool(::EndDialog(_window, result)); } + virtual void OnOK() { End(IDOK); } + virtual void OnCancel() { End(IDCANCEL); } +}; + +class CDialogChildControl: public NWindows::CWindow +{ +public: + int m_ID; + void Init(const NWindows::NControl::CDialog &parentDialog, int id) + { + m_ID = id; + Attach(parentDialog.GetItem(id)); + } +}; + +}} + +#endif \ No newline at end of file diff --git a/app/win/installer/7zstub/src/Windows/Control/ProgressBar.h b/app/win/installer/7zstub/src/Windows/Control/ProgressBar.h new file mode 100644 index 0000000000..682bab7043 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Control/ProgressBar.h @@ -0,0 +1,41 @@ +// Windows/Control/ProgressBar.h + +#ifndef __WINDOWS_CONTROL_PROGRESSBAR_H +#define __WINDOWS_CONTROL_PROGRESSBAR_H + +#include "Windows/Window.h" +#include "Windows/Defs.h" + +namespace NWindows { +namespace NControl { + +class CProgressBar: public CWindow +{ +public: + LRESULT SetPos(int pos) + { return SendMessage(PBM_SETPOS, pos, 0); } + LRESULT DeltaPos(int increment) + { return SendMessage(PBM_DELTAPOS, increment, 0); } + UINT GetPos() + { return SendMessage(PBM_GETPOS, 0, 0); } + LRESULT SetRange(unsigned short minValue, unsigned short maxValue) + { return SendMessage(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); } + DWORD SetRange32(int minValue, int maxValue) + { return SendMessage(PBM_SETRANGE32, minValue, maxValue); } + int SetStep(int aStep) + { return SendMessage(PBM_SETSTEP, aStep, 0); } + int StepIt() + { return SendMessage(PBM_STEPIT, 0, 0); } + + int GetRange(bool minValue, PPBRANGE range) + { return SendMessage(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); } + + COLORREF SetBarColor(COLORREF color) + { return SendMessage(PBM_SETBARCOLOR, 0, color); } + COLORREF SetBackgroundColor(COLORREF color) + { return SendMessage(PBM_SETBKCOLOR, 0, color); } +}; + +}} + +#endif \ No newline at end of file diff --git a/app/win/installer/7zstub/src/Windows/DLL.cpp b/app/win/installer/7zstub/src/Windows/DLL.cpp new file mode 100644 index 0000000000..b5aca7098d --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/DLL.cpp @@ -0,0 +1,115 @@ +// Windows/DLL.cpp + +#include "StdAfx.h" + +#include "DLL.h" +#include "Defs.h" +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NDLL { + +CLibrary::~CLibrary() +{ + Free(); +} + +bool CLibrary::Free() +{ + if (_module == 0) + return true; + // MessageBox(0, TEXT(""), TEXT("Free"), 0); + // Sleep(5000); + if (!::FreeLibrary(_module)) + return false; + _module = 0; + return true; +} + +bool CLibrary::LoadOperations(HMODULE newModule) +{ + if (newModule == NULL) + return false; + if(!Free()) + return false; + _module = newModule; + return true; +} + +bool CLibrary::LoadEx(LPCTSTR fileName, DWORD flags) +{ + // MessageBox(0, fileName, TEXT("LoadEx"), 0); + return LoadOperations(::LoadLibraryEx(fileName, NULL, flags)); +} + +bool CLibrary::Load(LPCTSTR fileName) +{ + // MessageBox(0, fileName, TEXT("Load"), 0); + // Sleep(5000); + // OutputDebugString(fileName); + // OutputDebugString(TEXT("\n")); + return LoadOperations(::LoadLibrary(fileName)); +} + +#ifndef _UNICODE +static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } +CSysString GetSysPath(LPCWSTR sysPath) + { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); } + +bool CLibrary::LoadEx(LPCWSTR fileName, DWORD flags) +{ + if (g_IsNT) + return LoadOperations(::LoadLibraryExW(fileName, NULL, flags)); + return LoadEx(GetSysPath(fileName), flags); +} +bool CLibrary::Load(LPCWSTR fileName) +{ + if (g_IsNT) + return LoadOperations(::LoadLibraryW(fileName)); + return Load(GetSysPath(fileName)); +} +#endif + +bool MyGetModuleFileName(HMODULE hModule, CSysString &result) +{ + result.Empty(); + TCHAR fullPath[MAX_PATH + 2]; + DWORD size = ::GetModuleFileName(hModule, fullPath, MAX_PATH + 1); + if (size <= MAX_PATH && size != 0) + { + result = fullPath; + return true; + } + return false; +} + +#ifndef _UNICODE +bool MyGetModuleFileName(HMODULE hModule, UString &result) +{ + result.Empty(); + if (g_IsNT) + { + wchar_t fullPath[MAX_PATH + 2]; + DWORD size = ::GetModuleFileNameW(hModule, fullPath, MAX_PATH + 1); + if (size <= MAX_PATH && size != 0) + { + result = fullPath; + return true; + } + return false; + } + CSysString resultSys; + if (!MyGetModuleFileName(hModule, resultSys)) + return false; + result = MultiByteToUnicodeString(resultSys, GetCurrentCodePage()); + return true; +} +#endif + +}} diff --git a/app/win/installer/7zstub/src/Windows/DLL.h b/app/win/installer/7zstub/src/Windows/DLL.h new file mode 100644 index 0000000000..6e60369661 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/DLL.h @@ -0,0 +1,54 @@ +// Windows/DLL.h + +#ifndef __WINDOWS_DLL_H +#define __WINDOWS_DLL_H + +#include "../Common/String.h" + +namespace NWindows { +namespace NDLL { + +class CLibrary +{ + bool LoadOperations(HMODULE newModule); +protected: + HMODULE _module; +public: + operator HMODULE() const { return _module; } + HMODULE* operator&() { return &_module; } + + CLibrary():_module(NULL) {}; + ~CLibrary(); + void Attach(HMODULE m) + { + Free(); + _module = m; + } + HMODULE Detach() + { + HMODULE m = _module; + _module = NULL; + return m; + } + + // operator HMODULE() const { return _module; }; + // bool IsLoaded() const { return (_module != NULL); }; + bool Free(); + bool LoadEx(LPCTSTR fileName, DWORD flags = LOAD_LIBRARY_AS_DATAFILE); + bool Load(LPCTSTR fileName); + #ifndef _UNICODE + bool LoadEx(LPCWSTR fileName, DWORD flags = LOAD_LIBRARY_AS_DATAFILE); + bool Load(LPCWSTR fileName); + #endif + FARPROC GetProcAddress(LPCSTR procName) const + { return ::GetProcAddress(_module, procName); } +}; + +bool MyGetModuleFileName(HMODULE hModule, CSysString &result); +#ifndef _UNICODE +bool MyGetModuleFileName(HMODULE hModule, UString &result); +#endif + +}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Defs.h b/app/win/installer/7zstub/src/Windows/Defs.h new file mode 100644 index 0000000000..1b0c97a52d --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Defs.h @@ -0,0 +1,18 @@ +// Windows/Defs.h + +#ifndef __WINDOWS_DEFS_H +#define __WINDOWS_DEFS_H + +inline bool BOOLToBool(BOOL value) + { return (value != FALSE); } + +inline BOOL BoolToBOOL(bool value) + { return (value ? TRUE: FALSE); } + +inline VARIANT_BOOL BoolToVARIANT_BOOL(bool value) + { return (value ? VARIANT_TRUE: VARIANT_FALSE); } + +inline bool VARIANT_BOOLToBool(VARIANT_BOOL value) + { return (value != VARIANT_FALSE); } + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Error.cpp b/app/win/installer/7zstub/src/Windows/Error.cpp new file mode 100644 index 0000000000..a361a49657 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Error.cpp @@ -0,0 +1,50 @@ +// Windows/Error.h + +#include "StdAfx.h" + +#include "Windows/Error.h" +#ifndef _UNICODE +#include "Common/StringConvert.h" +#endif + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NError { + +bool MyFormatMessage(DWORD messageID, CSysString &message) +{ + LPVOID msgBuf; + if(::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL,messageID, 0, (LPTSTR) &msgBuf,0, NULL) == 0) + return false; + message = (LPCTSTR)msgBuf; + ::LocalFree(msgBuf); + return true; +} + +#ifndef _UNICODE +bool MyFormatMessage(DWORD messageID, UString &message) +{ + if (g_IsNT) + { + LPVOID msgBuf; + if(::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, messageID, 0, (LPWSTR) &msgBuf, 0, NULL) == 0) + return false; + message = (LPCWSTR)msgBuf; + ::LocalFree(msgBuf); + return true; + } + CSysString messageSys; + bool result = MyFormatMessage(messageID, messageSys); + message = GetUnicodeString(messageSys); + return result; +} +#endif + +}} diff --git a/app/win/installer/7zstub/src/Windows/Error.h b/app/win/installer/7zstub/src/Windows/Error.h new file mode 100644 index 0000000000..de6ed20793 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Error.h @@ -0,0 +1,33 @@ +// Windows/Error.h + +#ifndef __WINDOWS_ERROR_H +#define __WINDOWS_ERROR_H + +#include "Common/String.h" + +namespace NWindows { +namespace NError { + +bool MyFormatMessage(DWORD messageID, CSysString &message); +inline CSysString MyFormatMessage(DWORD messageID) +{ + CSysString message; + MyFormatMessage(messageID, message); + return message; +} +#ifdef _UNICODE +inline UString MyFormatMessageW(DWORD messageID) + { return MyFormatMessage(messageID); } +#else +bool MyFormatMessage(DWORD messageID, UString &message); +inline UString MyFormatMessageW(DWORD messageID) +{ + UString message; + MyFormatMessage(messageID, message); + return message; +} +#endif + +}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/FileDir.cpp b/app/win/installer/7zstub/src/Windows/FileDir.cpp new file mode 100644 index 0000000000..5023172ab6 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileDir.cpp @@ -0,0 +1,672 @@ +// Windows/FileDir.cpp + +#include "StdAfx.h" + +#include "FileDir.h" +#include "FileName.h" +#include "FileFind.h" +#include "Defs.h" +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NFile { +namespace NDirectory { + +#ifndef _UNICODE +static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } +static UString GetUnicodePath(const CSysString &sysPath) + { return MultiByteToUnicodeString(sysPath, GetCurrentCodePage()); } +static CSysString GetSysPath(LPCWSTR sysPath) + { return UnicodeStringToMultiByte(sysPath, GetCurrentCodePage()); } +#endif + +bool MyGetWindowsDirectory(CSysString &path) +{ + UINT needLength = ::GetWindowsDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); +} + +bool MyGetSystemDirectory(CSysString &path) +{ + UINT needLength = ::GetSystemDirectory(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); +} + +#ifndef _UNICODE +bool MyGetWindowsDirectory(UString &path) +{ + if (g_IsNT) + { + UINT needLength = ::GetWindowsDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); + } + CSysString sysPath; + if (!MyGetWindowsDirectory(sysPath)) + return false; + path = GetUnicodePath(sysPath); + return true; +} + +bool MyGetSystemDirectory(UString &path) +{ + if (g_IsNT) + { + UINT needLength = ::GetSystemDirectoryW(path.GetBuffer(MAX_PATH + 1), MAX_PATH + 1); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); + } + CSysString sysPath; + if (!MyGetSystemDirectory(sysPath)) + return false; + path = GetUnicodePath(sysPath); + return true; +} +#endif + +#ifndef _UNICODE +bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes) +{ + if (g_IsNT) + return BOOLToBool(::SetFileAttributesW(fileName, fileAttributes)); + return MySetFileAttributes(GetSysPath(fileName), fileAttributes); +} + +bool MyRemoveDirectory(LPCWSTR pathName) +{ + if (g_IsNT) + return BOOLToBool(::RemoveDirectoryW(pathName)); + return MyRemoveDirectory(GetSysPath(pathName)); +} + +bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName) +{ + if (g_IsNT) + return BOOLToBool(::MoveFileW(existFileName, newFileName)); + return MyMoveFile(GetSysPath(existFileName), GetSysPath(newFileName)); +} +#endif + +bool MyCreateDirectory(LPCTSTR pathName) { return BOOLToBool(::CreateDirectory(pathName, NULL)); } + +#ifndef _UNICODE +bool MyCreateDirectory(LPCWSTR pathName) +{ + if (g_IsNT) + return BOOLToBool(::CreateDirectoryW(pathName, NULL)); + return MyCreateDirectory(GetSysPath(pathName)); +} +#endif + +/* +bool CreateComplexDirectory(LPCTSTR pathName) +{ + NName::CParsedPath path; + path.ParsePath(pathName); + CSysString fullPath = path.Prefix; + DWORD errorCode = ERROR_SUCCESS; + for(int i = 0; i < path.PathParts.Size(); i++) + { + const CSysString &string = path.PathParts[i]; + if(string.IsEmpty()) + { + if(i != path.PathParts.Size() - 1) + return false; + return true; + } + fullPath += path.PathParts[i]; + if(!MyCreateDirectory(fullPath)) + { + DWORD errorCode = GetLastError(); + if(errorCode != ERROR_ALREADY_EXISTS) + return false; + } + fullPath += NName::kDirDelimiter; + } + return true; +} +*/ + +bool CreateComplexDirectory(LPCTSTR _aPathName) +{ + CSysString pathName = _aPathName; + int pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR)); + if (pos > 0 && pos == pathName.Length() - 1) + { + if (pathName.Length() == 3 && pathName[1] == ':') + return true; // Disk folder; + pathName.Delete(pos); + } + CSysString pathName2 = pathName; + pos = pathName.Length(); + while(true) + { + if(MyCreateDirectory(pathName)) + break; + if(::GetLastError() == ERROR_ALREADY_EXISTS) + { + NFind::CFileInfo fileInfo; + if (!NFind::FindFile(pathName, fileInfo)) // For network folders + return true; + if (!fileInfo.IsDirectory()) + return false; + break; + } + pos = pathName.ReverseFind(TEXT(CHAR_PATH_SEPARATOR)); + if (pos < 0 || pos == 0) + return false; + if (pathName[pos - 1] == ':') + return false; + pathName = pathName.Left(pos); + } + pathName = pathName2; + while(pos < pathName.Length()) + { + pos = pathName.Find(TEXT(CHAR_PATH_SEPARATOR), pos + 1); + if (pos < 0) + pos = pathName.Length(); + if(!MyCreateDirectory(pathName.Left(pos))) + return false; + } + return true; +} + +#ifndef _UNICODE + +bool CreateComplexDirectory(LPCWSTR _aPathName) +{ + UString pathName = _aPathName; + int pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR); + if (pos > 0 && pos == pathName.Length() - 1) + { + if (pathName.Length() == 3 && pathName[1] == L':') + return true; // Disk folder; + pathName.Delete(pos); + } + UString pathName2 = pathName; + pos = pathName.Length(); + while(true) + { + if(MyCreateDirectory(pathName)) + break; + if(::GetLastError() == ERROR_ALREADY_EXISTS) + { + NFind::CFileInfoW fileInfo; + if (!NFind::FindFile(pathName, fileInfo)) // For network folders + return true; + if (!fileInfo.IsDirectory()) + return false; + break; + } + pos = pathName.ReverseFind(WCHAR_PATH_SEPARATOR); + if (pos < 0 || pos == 0) + return false; + if (pathName[pos - 1] == L':') + return false; + pathName = pathName.Left(pos); + } + pathName = pathName2; + while(pos < pathName.Length()) + { + pos = pathName.Find(WCHAR_PATH_SEPARATOR, pos + 1); + if (pos < 0) + pos = pathName.Length(); + if(!MyCreateDirectory(pathName.Left(pos))) + return false; + } + return true; +} + +#endif + +bool DeleteFileAlways(LPCTSTR name) +{ + if(!::SetFileAttributes(name, 0)) + return false; + return BOOLToBool(::DeleteFile(name)); +} + +#ifndef _UNICODE +bool DeleteFileAlways(LPCWSTR name) +{ + if (g_IsNT) + { + if(!MySetFileAttributes(name, 0)) + return false; + return BOOLToBool(::DeleteFileW(name)); + } + return DeleteFileAlways(GetSysPath(name)); +} +#endif + +static bool RemoveDirectorySubItems2(const CSysString pathPrefix, const NFind::CFileInfo &fileInfo) +{ + if(fileInfo.IsDirectory()) + return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name); + else + return DeleteFileAlways(pathPrefix + fileInfo.Name); +} + +bool RemoveDirectoryWithSubItems(const CSysString &path) +{ + NFind::CFileInfo fileInfo; + CSysString pathPrefix = path + NName::kDirDelimiter; + { + NFind::CEnumerator enumerator(pathPrefix + TCHAR(NName::kAnyStringWildcard)); + while(enumerator.Next(fileInfo)) + if(!RemoveDirectorySubItems2(pathPrefix, fileInfo)) + return false; + } + if(!BOOLToBool(::SetFileAttributes(path, 0))) + return false; + return BOOLToBool(::RemoveDirectory(path)); +} + +#ifndef _UNICODE +static bool RemoveDirectorySubItems2(const UString pathPrefix, const NFind::CFileInfoW &fileInfo) +{ + if(fileInfo.IsDirectory()) + return RemoveDirectoryWithSubItems(pathPrefix + fileInfo.Name); + else + return DeleteFileAlways(pathPrefix + fileInfo.Name); +} +bool RemoveDirectoryWithSubItems(const UString &path) +{ + NFind::CFileInfoW fileInfo; + UString pathPrefix = path + UString(NName::kDirDelimiter); + { + NFind::CEnumeratorW enumerator(pathPrefix + UString(NName::kAnyStringWildcard)); + while(enumerator.Next(fileInfo)) + if(!RemoveDirectorySubItems2(pathPrefix, fileInfo)) + return false; + } + if(!MySetFileAttributes(path, 0)) + return false; + return MyRemoveDirectory(path); +} +#endif + +#ifndef _WIN32_WCE + +bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath) +{ + DWORD needLength = ::GetShortPathName(longPath, shortPath.GetBuffer(MAX_PATH + 1), MAX_PATH + 1); + shortPath.ReleaseBuffer(); + return (needLength > 0 && needLength < MAX_PATH); +} + +bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, int &fileNamePartStartIndex) +{ + resultPath.Empty(); + LPTSTR fileNamePointer = 0; + LPTSTR buffer = resultPath.GetBuffer(MAX_PATH); + DWORD needLength = ::GetFullPathName(fileName, MAX_PATH + 1, buffer, &fileNamePointer); + resultPath.ReleaseBuffer(); + if (needLength == 0 || needLength >= MAX_PATH) + return false; + if (fileNamePointer == 0) + fileNamePartStartIndex = lstrlen(fileName); + else + fileNamePartStartIndex = (int)(fileNamePointer - buffer); + return true; +} + +#ifndef _UNICODE +bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, int &fileNamePartStartIndex) +{ + resultPath.Empty(); + if (g_IsNT) + { + LPWSTR fileNamePointer = 0; + LPWSTR buffer = resultPath.GetBuffer(MAX_PATH); + DWORD needLength = ::GetFullPathNameW(fileName, MAX_PATH + 1, buffer, &fileNamePointer); + resultPath.ReleaseBuffer(); + if (needLength == 0 || needLength >= MAX_PATH) + return false; + if (fileNamePointer == 0) + fileNamePartStartIndex = MyStringLen(fileName); + else + fileNamePartStartIndex = (int)(fileNamePointer - buffer); + } + else + { + CSysString sysPath; + if (!MyGetFullPathName(GetSysPath(fileName), sysPath, fileNamePartStartIndex)) + return false; + UString resultPath1 = GetUnicodePath(sysPath.Left(fileNamePartStartIndex)); + UString resultPath2 = GetUnicodePath(sysPath.Mid(fileNamePartStartIndex)); + fileNamePartStartIndex = resultPath1.Length(); + resultPath = resultPath1 + resultPath2; + } + return true; +} +#endif + + +bool MyGetFullPathName(LPCTSTR fileName, CSysString &path) +{ + int index; + return MyGetFullPathName(fileName, path, index); +} + +#ifndef _UNICODE +bool MyGetFullPathName(LPCWSTR fileName, UString &path) +{ + int index; + return MyGetFullPathName(fileName, path, index); +} +#endif + +bool GetOnlyName(LPCTSTR fileName, CSysString &resultName) +{ + int index; + if (!MyGetFullPathName(fileName, resultName, index)) + return false; + resultName = resultName.Mid(index); + return true; +} + +#ifndef _UNICODE +bool GetOnlyName(LPCWSTR fileName, UString &resultName) +{ + int index; + if (!MyGetFullPathName(fileName, resultName, index)) + return false; + resultName = resultName.Mid(index); + return true; +} +#endif + +bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName) +{ + int index; + if (!MyGetFullPathName(fileName, resultName, index)) + return false; + resultName = resultName.Left(index); + return true; +} + +#ifndef _UNICODE +bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName) +{ + int index; + if (!MyGetFullPathName(fileName, resultName, index)) + return false; + resultName = resultName.Left(index); + return true; +} +#endif + +bool MyGetCurrentDirectory(CSysString &path) +{ + DWORD needLength = ::GetCurrentDirectory(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1)); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); +} + +#ifndef _UNICODE +bool MySetCurrentDirectory(LPCWSTR path) +{ + if (g_IsNT) + return BOOLToBool(::SetCurrentDirectoryW(path)); + return MySetCurrentDirectory(GetSysPath(path)); +} +bool MyGetCurrentDirectory(UString &path) +{ + if (g_IsNT) + { + DWORD needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1)); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); + } + CSysString sysPath; + if (!MyGetCurrentDirectory(sysPath)) + return false; + path = GetUnicodePath(sysPath); + return true; +} +#endif +#endif + +bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, + CSysString &resultPath, UINT32 &filePart) +{ + LPTSTR filePartPointer; + DWORD value = ::SearchPath(path, fileName, extension, + MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer); + filePart = (UINT32)(filePartPointer - (LPCTSTR)resultPath); + resultPath.ReleaseBuffer(); + return (value > 0 && value <= MAX_PATH); +} + +#ifndef _UNICODE +bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, + UString &resultPath, UINT32 &filePart) +{ + if (g_IsNT) + { + LPWSTR filePartPointer = 0; + DWORD value = ::SearchPathW(path, fileName, extension, + MAX_PATH, resultPath.GetBuffer(MAX_PATH + 1), &filePartPointer); + filePart = (UINT32)(filePartPointer - (LPCWSTR)resultPath); + resultPath.ReleaseBuffer(); + return (value > 0 && value <= MAX_PATH); + } + + CSysString sysPath; + if (!MySearchPath( + path != 0 ? (LPCTSTR)GetSysPath(path): 0, + fileName != 0 ? (LPCTSTR)GetSysPath(fileName): 0, + extension != 0 ? (LPCTSTR)GetSysPath(extension): 0, + sysPath, filePart)) + return false; + UString resultPath1 = GetUnicodePath(sysPath.Left(filePart)); + UString resultPath2 = GetUnicodePath(sysPath.Mid(filePart)); + filePart = resultPath1.Length(); + resultPath = resultPath1 + resultPath2; + return true; +} +#endif + +bool MyGetTempPath(CSysString &path) +{ + DWORD needLength = ::GetTempPath(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1)); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); +} + +#ifndef _UNICODE +bool MyGetTempPath(UString &path) +{ + path.Empty(); + if (g_IsNT) + { + DWORD needLength = ::GetTempPathW(MAX_PATH + 1, path.GetBuffer(MAX_PATH + 1)); + path.ReleaseBuffer(); + return (needLength > 0 && needLength <= MAX_PATH); + } + CSysString sysPath; + if (!MyGetTempPath(sysPath)) + return false; + path = GetUnicodePath(sysPath); + return true; +} +#endif + +UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &path) +{ + UINT number = ::GetTempFileName(dirPath, prefix, 0, path.GetBuffer(MAX_PATH + 1)); + path.ReleaseBuffer(); + return number; +} + +#ifndef _UNICODE +UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &path) +{ + if (g_IsNT) + { + UINT number = ::GetTempFileNameW(dirPath, prefix, 0, path.GetBuffer(MAX_PATH)); + path.ReleaseBuffer(); + return number; + } + CSysString sysPath; + UINT number = MyGetTempFileName( + dirPath ? (LPCTSTR)GetSysPath(dirPath): 0, + prefix ? (LPCTSTR)GetSysPath(prefix): 0, + sysPath); + path = GetUnicodePath(sysPath); + return number; +} +#endif + +UINT CTempFile::Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath) +{ + Remove(); + UINT number = MyGetTempFileName(dirPath, prefix, resultPath); + if(number != 0) + { + _fileName = resultPath; + _mustBeDeleted = true; + } + return number; +} + +bool CTempFile::Create(LPCTSTR prefix, CSysString &resultPath) +{ + CSysString tempPath; + if(!MyGetTempPath(tempPath)) + return false; + if (Create(tempPath, prefix, resultPath) != 0) + return true; + if(!MyGetWindowsDirectory(tempPath)) + return false; + return (Create(tempPath, prefix, resultPath) != 0); +} + +bool CTempFile::Remove() +{ + if (!_mustBeDeleted) + return true; + _mustBeDeleted = !DeleteFileAlways(_fileName); + return !_mustBeDeleted; +} + +#ifndef _UNICODE + +UINT CTempFileW::Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath) +{ + Remove(); + UINT number = MyGetTempFileName(dirPath, prefix, resultPath); + if(number != 0) + { + _fileName = resultPath; + _mustBeDeleted = true; + } + return number; +} + +bool CTempFileW::Create(LPCWSTR prefix, UString &resultPath) +{ + UString tempPath; + if(!MyGetTempPath(tempPath)) + return false; + if (Create(tempPath, prefix, resultPath) != 0) + return true; + if(!MyGetWindowsDirectory(tempPath)) + return false; + return (Create(tempPath, prefix, resultPath) != 0); +} + +bool CTempFileW::Remove() +{ + if (!_mustBeDeleted) + return true; + _mustBeDeleted = !DeleteFileAlways(_fileName); + return !_mustBeDeleted; +} + +#endif + +bool CreateTempDirectory(LPCTSTR prefix, CSysString &dirName) +{ + /* + CSysString prefix = tempPath + prefixChars; + CRandom random; + random.Init(); + */ + while(true) + { + CTempFile tempFile; + if (!tempFile.Create(prefix, dirName)) + return false; + if (!::DeleteFile(dirName)) + return false; + /* + UINT32 randomNumber = random.Generate(); + TCHAR randomNumberString[32]; + _stprintf(randomNumberString, _T("%04X"), randomNumber); + dirName = prefix + randomNumberString; + */ + if(NFind::DoesFileExist(dirName)) + continue; + if (MyCreateDirectory(dirName)) + return true; + if (::GetLastError() != ERROR_ALREADY_EXISTS) + return false; + } +} + +bool CTempDirectory::Create(LPCTSTR prefix) +{ + Remove(); + return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir)); +} + +#ifndef _UNICODE + +bool CreateTempDirectory(LPCWSTR prefix, UString &dirName) +{ + /* + CSysString prefix = tempPath + prefixChars; + CRandom random; + random.Init(); + */ + while(true) + { + CTempFileW tempFile; + if (!tempFile.Create(prefix, dirName)) + return false; + if (!DeleteFileAlways(dirName)) + return false; + /* + UINT32 randomNumber = random.Generate(); + TCHAR randomNumberString[32]; + _stprintf(randomNumberString, _T("%04X"), randomNumber); + dirName = prefix + randomNumberString; + */ + if(NFind::DoesFileExist(dirName)) + continue; + if (MyCreateDirectory(dirName)) + return true; + if (::GetLastError() != ERROR_ALREADY_EXISTS) + return false; + } +} + +bool CTempDirectoryW::Create(LPCWSTR prefix) +{ + Remove(); + return (_mustBeDeleted = CreateTempDirectory(prefix, _tempDir)); +} + +#endif + +}}} diff --git a/app/win/installer/7zstub/src/Windows/FileDir.h b/app/win/installer/7zstub/src/Windows/FileDir.h new file mode 100644 index 0000000000..da9a5bbcc2 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileDir.h @@ -0,0 +1,189 @@ +// Windows/FileDir.h + +#ifndef __WINDOWS_FILEDIR_H +#define __WINDOWS_FILEDIR_H + +#include "../Common/String.h" +#include "Defs.h" + +namespace NWindows { +namespace NFile { +namespace NDirectory { + +bool MyGetWindowsDirectory(CSysString &path); +bool MyGetSystemDirectory(CSysString &path); +#ifndef _UNICODE +bool MyGetWindowsDirectory(UString &path); +bool MyGetSystemDirectory(UString &path); +#endif + +inline bool MySetFileAttributes(LPCTSTR fileName, DWORD fileAttributes) + { return BOOLToBool(::SetFileAttributes(fileName, fileAttributes)); } +#ifndef _UNICODE +bool MySetFileAttributes(LPCWSTR fileName, DWORD fileAttributes); +#endif + +inline bool MyMoveFile(LPCTSTR existFileName, LPCTSTR newFileName) + { return BOOLToBool(::MoveFile(existFileName, newFileName)); } +#ifndef _UNICODE +bool MyMoveFile(LPCWSTR existFileName, LPCWSTR newFileName); +#endif + +inline bool MyRemoveDirectory(LPCTSTR pathName) + { return BOOLToBool(::RemoveDirectory(pathName)); } +#ifndef _UNICODE +bool MyRemoveDirectory(LPCWSTR pathName); +#endif + +bool MyCreateDirectory(LPCTSTR pathName); +bool CreateComplexDirectory(LPCTSTR pathName); +#ifndef _UNICODE +bool MyCreateDirectory(LPCWSTR pathName); +bool CreateComplexDirectory(LPCWSTR pathName); +#endif + +bool DeleteFileAlways(LPCTSTR name); +#ifndef _UNICODE +bool DeleteFileAlways(LPCWSTR name); +#endif + +bool RemoveDirectoryWithSubItems(const CSysString &path); +#ifndef _UNICODE +bool RemoveDirectoryWithSubItems(const UString &path); +#endif + +#ifndef _WIN32_WCE +bool MyGetShortPathName(LPCTSTR longPath, CSysString &shortPath); + +bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath, + int &fileNamePartStartIndex); +bool MyGetFullPathName(LPCTSTR fileName, CSysString &resultPath); +bool GetOnlyName(LPCTSTR fileName, CSysString &resultName); +bool GetOnlyDirPrefix(LPCTSTR fileName, CSysString &resultName); +#ifndef _UNICODE +bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath, + int &fileNamePartStartIndex); +bool MyGetFullPathName(LPCWSTR fileName, UString &resultPath); +bool GetOnlyName(LPCWSTR fileName, UString &resultName); +bool GetOnlyDirPrefix(LPCWSTR fileName, UString &resultName); +#endif + +inline bool MySetCurrentDirectory(LPCTSTR path) + { return BOOLToBool(::SetCurrentDirectory(path)); } +bool MyGetCurrentDirectory(CSysString &resultPath); +#ifndef _UNICODE +bool MySetCurrentDirectory(LPCWSTR path); +bool MyGetCurrentDirectory(UString &resultPath); +#endif +#endif + +bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, + CSysString &resultPath, UINT32 &filePart); +#ifndef _UNICODE +bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, + UString &resultPath, UINT32 &filePart); +#endif + +inline bool MySearchPath(LPCTSTR path, LPCTSTR fileName, LPCTSTR extension, + CSysString &resultPath) +{ + UINT32 value; + return MySearchPath(path, fileName, extension, resultPath, value); +} + +#ifndef _UNICODE +inline bool MySearchPath(LPCWSTR path, LPCWSTR fileName, LPCWSTR extension, + UString &resultPath) +{ + UINT32 value; + return MySearchPath(path, fileName, extension, resultPath, value); +} +#endif + +bool MyGetTempPath(CSysString &resultPath); +#ifndef _UNICODE +bool MyGetTempPath(UString &resultPath); +#endif + +UINT MyGetTempFileName(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath); +#ifndef _UNICODE +UINT MyGetTempFileName(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath); +#endif + +class CTempFile +{ + bool _mustBeDeleted; + CSysString _fileName; +public: + CTempFile(): _mustBeDeleted(false) {} + ~CTempFile() { Remove(); } + void DisableDeleting() { _mustBeDeleted = false; } + UINT Create(LPCTSTR dirPath, LPCTSTR prefix, CSysString &resultPath); + bool Create(LPCTSTR prefix, CSysString &resultPath); + bool Remove(); +}; + +#ifdef _UNICODE +typedef CTempFile CTempFileW; +#else +class CTempFileW +{ + bool _mustBeDeleted; + UString _fileName; +public: + CTempFileW(): _mustBeDeleted(false) {} + ~CTempFileW() { Remove(); } + void DisableDeleting() { _mustBeDeleted = false; } + UINT Create(LPCWSTR dirPath, LPCWSTR prefix, UString &resultPath); + bool Create(LPCWSTR prefix, UString &resultPath); + bool Remove(); +}; +#endif + +bool CreateTempDirectory(LPCTSTR prefixChars, CSysString &dirName); + +class CTempDirectory +{ + bool _mustBeDeleted; + CSysString _tempDir; +public: + const CSysString &GetPath() const { return _tempDir; } + CTempDirectory(): _mustBeDeleted(false) {} + ~CTempDirectory() { Remove(); } + bool Create(LPCTSTR prefix) ; + bool Remove() + { + if (!_mustBeDeleted) + return true; + _mustBeDeleted = !RemoveDirectoryWithSubItems(_tempDir); + return (!_mustBeDeleted); + } + void DisableDeleting() { _mustBeDeleted = false; } +}; + +#ifdef _UNICODE +typedef CTempDirectory CTempDirectoryW; +#else +class CTempDirectoryW +{ + bool _mustBeDeleted; + UString _tempDir; +public: + const UString &GetPath() const { return _tempDir; } + CTempDirectoryW(): _mustBeDeleted(false) {} + ~CTempDirectoryW() { Remove(); } + bool Create(LPCWSTR prefix) ; + bool Remove() + { + if (!_mustBeDeleted) + return true; + _mustBeDeleted = !RemoveDirectoryWithSubItems(_tempDir); + return (!_mustBeDeleted); + } + void DisableDeleting() { _mustBeDeleted = false; } +}; +#endif + +}}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/FileFind.cpp b/app/win/installer/7zstub/src/Windows/FileFind.cpp new file mode 100644 index 0000000000..298df46440 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileFind.cpp @@ -0,0 +1,365 @@ +// Windows/FileFind.cpp + +#include "StdAfx.h" + +#include "FileFind.h" +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NFile { +namespace NFind { + +static const TCHAR kDot = TEXT('.'); + +bool CFileInfo::IsDots() const +{ + if (!IsDirectory() || Name.IsEmpty()) + return false; + if (Name[0] != kDot) + return false; + return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); +} + +#ifndef _UNICODE +bool CFileInfoW::IsDots() const +{ + if (!IsDirectory() || Name.IsEmpty()) + return false; + if (Name[0] != kDot) + return false; + return Name.Length() == 1 || (Name[1] == kDot && Name.Length() == 2); +} +#endif + +static void ConvertWIN32_FIND_DATA_To_FileInfo( + const WIN32_FIND_DATA &findData, + CFileInfo &fileInfo) +{ + fileInfo.Attributes = findData.dwFileAttributes; + fileInfo.CreationTime = findData.ftCreationTime; + fileInfo.LastAccessTime = findData.ftLastAccessTime; + fileInfo.LastWriteTime = findData.ftLastWriteTime; + fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; + fileInfo.Name = findData.cFileName; + #ifndef _WIN32_WCE + fileInfo.ReparseTag = findData.dwReserved0; + #else + fileInfo.ObjectID = findData.dwOID; + #endif +} + +#ifndef _UNICODE + +static inline UINT GetCurrentCodePage() { return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP; } + +static void ConvertWIN32_FIND_DATA_To_FileInfo( + const WIN32_FIND_DATAW &findData, + CFileInfoW &fileInfo) +{ + fileInfo.Attributes = findData.dwFileAttributes; + fileInfo.CreationTime = findData.ftCreationTime; + fileInfo.LastAccessTime = findData.ftLastAccessTime; + fileInfo.LastWriteTime = findData.ftLastWriteTime; + fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; + fileInfo.Name = findData.cFileName; + #ifndef _WIN32_WCE + fileInfo.ReparseTag = findData.dwReserved0; + #else + fileInfo.ObjectID = findData.dwOID; + #endif +} + +static void ConvertWIN32_FIND_DATA_To_FileInfo( + const WIN32_FIND_DATA &findData, + CFileInfoW &fileInfo) +{ + fileInfo.Attributes = findData.dwFileAttributes; + fileInfo.CreationTime = findData.ftCreationTime; + fileInfo.LastAccessTime = findData.ftLastAccessTime; + fileInfo.LastWriteTime = findData.ftLastWriteTime; + fileInfo.Size = (((UInt64)findData.nFileSizeHigh) << 32) + findData.nFileSizeLow; + fileInfo.Name = GetUnicodeString(findData.cFileName, GetCurrentCodePage()); + #ifndef _WIN32_WCE + fileInfo.ReparseTag = findData.dwReserved0; + #else + fileInfo.ObjectID = findData.dwOID; + #endif +} +#endif + +//////////////////////////////// +// CFindFile + +bool CFindFile::Close() +{ + if(!_handleAllocated) + return true; + bool result = BOOLToBool(::FindClose(_handle)); + _handleAllocated = !result; + return result; +} + +bool CFindFile::FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo) +{ + Close(); + WIN32_FIND_DATA findData; + _handle = ::FindFirstFile(wildcard, &findData); + if (_handleAllocated = (_handle != INVALID_HANDLE_VALUE)) + ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); + return _handleAllocated; +} + +#ifndef _UNICODE +bool CFindFile::FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo) +{ + Close(); + if (g_IsNT) + { + WIN32_FIND_DATAW findData; + _handle = ::FindFirstFileW(wildcard, &findData); + if (_handleAllocated = (_handle != INVALID_HANDLE_VALUE)) + ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); + } + else + { + WIN32_FIND_DATAA findData; + _handle = ::FindFirstFileA(UnicodeStringToMultiByte(wildcard, + GetCurrentCodePage()), &findData); + if (_handleAllocated = (_handle != INVALID_HANDLE_VALUE)) + ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); + } + return _handleAllocated; +} +#endif + +bool CFindFile::FindNext(CFileInfo &fileInfo) +{ + WIN32_FIND_DATA findData; + bool result = BOOLToBool(::FindNextFile(_handle, &findData)); + if (result) + ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); + return result; +} + +#ifndef _UNICODE +bool CFindFile::FindNext(CFileInfoW &fileInfo) +{ + if (g_IsNT) + { + WIN32_FIND_DATAW findData; + if (!::FindNextFileW(_handle, &findData)) + return false; + ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); + } + else + { + WIN32_FIND_DATAA findData; + if (!::FindNextFileA(_handle, &findData)) + return false; + ConvertWIN32_FIND_DATA_To_FileInfo(findData, fileInfo); + } + return true; +} +#endif + +bool FindFile(LPCTSTR wildcard, CFileInfo &fileInfo) +{ + CFindFile finder; + return finder.FindFirst(wildcard, fileInfo); +} + +#ifndef _UNICODE +bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo) +{ + CFindFile finder; + return finder.FindFirst(wildcard, fileInfo); +} +#endif + +bool DoesFileExist(LPCTSTR name) +{ + CFileInfo fileInfo; + return FindFile(name, fileInfo); +} + +#ifndef _UNICODE +bool DoesFileExist(LPCWSTR name) +{ + CFileInfoW fileInfo; + return FindFile(name, fileInfo); +} +#endif + +///////////////////////////////////// +// CEnumerator + +bool CEnumerator::NextAny(CFileInfo &fileInfo) +{ + if(_findFile.IsHandleAllocated()) + return _findFile.FindNext(fileInfo); + else + return _findFile.FindFirst(_wildcard, fileInfo); +} + +bool CEnumerator::Next(CFileInfo &fileInfo) +{ + while(true) + { + if(!NextAny(fileInfo)) + return false; + if(!fileInfo.IsDots()) + return true; + } +} + +bool CEnumerator::Next(CFileInfo &fileInfo, bool &found) +{ + if (Next(fileInfo)) + { + found = true; + return true; + } + found = false; + return (::GetLastError() == ERROR_NO_MORE_FILES); +} + +#ifndef _UNICODE +bool CEnumeratorW::NextAny(CFileInfoW &fileInfo) +{ + if(_findFile.IsHandleAllocated()) + return _findFile.FindNext(fileInfo); + else + return _findFile.FindFirst(_wildcard, fileInfo); +} + +bool CEnumeratorW::Next(CFileInfoW &fileInfo) +{ + while(true) + { + if(!NextAny(fileInfo)) + return false; + if(!fileInfo.IsDots()) + return true; + } +} + +bool CEnumeratorW::Next(CFileInfoW &fileInfo, bool &found) +{ + if (Next(fileInfo)) + { + found = true; + return true; + } + found = false; + return (::GetLastError() == ERROR_NO_MORE_FILES); +} + +#endif + +//////////////////////////////// +// CFindChangeNotification + +bool CFindChangeNotification::Close() +{ + if(_handle == INVALID_HANDLE_VALUE || _handle == 0) + return true; + bool result = BOOLToBool(::FindCloseChangeNotification(_handle)); + if (result) + _handle = INVALID_HANDLE_VALUE; + return result; +} + +HANDLE CFindChangeNotification::FindFirst(LPCTSTR pathName, bool watchSubtree, + DWORD notifyFilter) +{ + _handle = ::FindFirstChangeNotification(pathName, + BoolToBOOL(watchSubtree), notifyFilter); + return _handle; +} + +#ifndef _UNICODE +HANDLE CFindChangeNotification::FindFirst(LPCWSTR pathName, bool watchSubtree, + DWORD notifyFilter) +{ + if (g_IsNT) + return (_handle = ::FindFirstChangeNotificationW(pathName, BoolToBOOL(watchSubtree), notifyFilter)); + return FindFirst(UnicodeStringToMultiByte(pathName, GetCurrentCodePage()), watchSubtree, notifyFilter); +} +#endif + +#ifndef _WIN32_WCE +bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings) +{ + driveStrings.Clear(); + UINT32 size = GetLogicalDriveStrings(0, NULL); + if(size == 0) + return false; + CSysString buffer; + UINT32 newSize = GetLogicalDriveStrings(size, buffer.GetBuffer(size)); + if(newSize == 0) + return false; + if(newSize > size) + return false; + CSysString string; + for(UINT32 i = 0; i < newSize; i++) + { + TCHAR c = buffer[i]; + if(c == TEXT('\0')) + { + driveStrings.Add(string); + string.Empty(); + } + else + string += c; + } + if(!string.IsEmpty()) + return false; + return true; +} + +#ifndef _UNICODE +bool MyGetLogicalDriveStrings(UStringVector &driveStrings) +{ + driveStrings.Clear(); + if (g_IsNT) + { + UINT32 size = GetLogicalDriveStringsW(0, NULL); + if (size == 0) + return false; + UString buffer; + UINT32 newSize = GetLogicalDriveStringsW(size, buffer.GetBuffer(size)); + if(newSize == 0) + return false; + if(newSize > size) + return false; + UString string; + for(UINT32 i = 0; i < newSize; i++) + { + WCHAR c = buffer[i]; + if(c == L'\0') + { + driveStrings.Add(string); + string.Empty(); + } + else + string += c; + } + return string.IsEmpty(); + } + CSysStringVector driveStringsA; + bool res = MyGetLogicalDriveStrings(driveStringsA); + for (int i = 0; i < driveStringsA.Size(); i++) + driveStrings.Add(GetUnicodeString(driveStringsA[i])); + return res; +} +#endif + +#endif + +}}} diff --git a/app/win/installer/7zstub/src/Windows/FileFind.h b/app/win/installer/7zstub/src/Windows/FileFind.h new file mode 100644 index 0000000000..19c8fe3ede --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileFind.h @@ -0,0 +1,176 @@ +// Windows/FileFind.h + +#ifndef __WINDOWS_FILEFIND_H +#define __WINDOWS_FILEFIND_H + +#include "../Common/String.h" +#include "../Common/Types.h" +#include "FileName.h" +#include "Defs.h" + +namespace NWindows { +namespace NFile { +namespace NFind { + +namespace NAttributes +{ + inline bool IsReadOnly(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_READONLY) != 0; } + inline bool IsHidden(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_HIDDEN) != 0; } + inline bool IsSystem(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_SYSTEM) != 0; } + inline bool IsDirectory(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; } + inline bool IsArchived(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_ARCHIVE) != 0; } + inline bool IsCompressed(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_COMPRESSED) != 0; } + inline bool IsEncrypted(DWORD attributes) { return (attributes & FILE_ATTRIBUTE_ENCRYPTED) != 0; } +} + +class CFileInfoBase +{ + bool MatchesMask(UINT32 mask) const { return ((Attributes & mask) != 0); } +public: + DWORD Attributes; + FILETIME CreationTime; + FILETIME LastAccessTime; + FILETIME LastWriteTime; + UInt64 Size; + + #ifndef _WIN32_WCE + UINT32 ReparseTag; + #else + DWORD ObjectID; + #endif + + bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); } + bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); } + bool IsDirectory() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); } + bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); } + bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); } + bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); } + bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); } + bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); } + bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); } + bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); } + bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); } + bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); } +}; + +class CFileInfo: public CFileInfoBase +{ +public: + CSysString Name; + bool IsDots() const; +}; + +#ifdef _UNICODE +typedef CFileInfo CFileInfoW; +#else +class CFileInfoW: public CFileInfoBase +{ +public: + UString Name; + bool IsDots() const; +}; +#endif + +class CFindFile +{ + friend class CEnumerator; + HANDLE _handle; + bool _handleAllocated; +public: + bool IsHandleAllocated() const { return _handleAllocated; } + CFindFile(): _handleAllocated(false) {} + ~CFindFile() { Close(); } + bool FindFirst(LPCTSTR wildcard, CFileInfo &fileInfo); + bool FindNext(CFileInfo &fileInfo); + #ifndef _UNICODE + bool FindFirst(LPCWSTR wildcard, CFileInfoW &fileInfo); + bool FindNext(CFileInfoW &fileInfo); + #endif + bool Close(); +}; + +bool FindFile(LPCTSTR wildcard, CFileInfo &fileInfo); + +bool DoesFileExist(LPCTSTR name); +#ifndef _UNICODE +bool FindFile(LPCWSTR wildcard, CFileInfoW &fileInfo); +bool DoesFileExist(LPCWSTR name); +#endif + +class CEnumerator +{ + CFindFile _findFile; + CSysString _wildcard; + bool NextAny(CFileInfo &fileInfo); +public: + CEnumerator(): _wildcard(NName::kAnyStringWildcard) {} + CEnumerator(const CSysString &wildcard): _wildcard(wildcard) {} + bool Next(CFileInfo &fileInfo); + bool Next(CFileInfo &fileInfo, bool &found); +}; + +#ifdef _UNICODE +typedef CEnumerator CEnumeratorW; +#else +class CEnumeratorW +{ + CFindFile _findFile; + UString _wildcard; + bool NextAny(CFileInfoW &fileInfo); +public: + CEnumeratorW(): _wildcard(NName::kAnyStringWildcard) {} + CEnumeratorW(const UString &wildcard): _wildcard(wildcard) {} + bool Next(CFileInfoW &fileInfo); + bool Next(CFileInfoW &fileInfo, bool &found); +}; +#endif + +class CFindChangeNotification +{ + HANDLE _handle; +public: + operator HANDLE () { return _handle; } + CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {} + ~CFindChangeNotification() { Close(); } + bool Close(); + HANDLE FindFirst(LPCTSTR pathName, bool watchSubtree, DWORD notifyFilter); + #ifndef _UNICODE + HANDLE FindFirst(LPCWSTR pathName, bool watchSubtree, DWORD notifyFilter); + #endif + bool FindNext() + { return BOOLToBool(::FindNextChangeNotification(_handle)); } +}; + +#ifndef _WIN32_WCE +bool MyGetLogicalDriveStrings(CSysStringVector &driveStrings); +#ifndef _UNICODE +bool MyGetLogicalDriveStrings(UStringVector &driveStrings); +#endif +#endif + +inline bool MyGetCompressedFileSize(LPCTSTR fileName, UInt64 &size) +{ + DWORD highPart; + DWORD lowPart = ::GetCompressedFileSize(fileName, &highPart); + if (lowPart == INVALID_FILE_SIZE) + if (::GetLastError() != NO_ERROR) + return false; + size = (UInt64(highPart) << 32) | lowPart; + return true; +} + +inline bool MyGetCompressedFileSizeW(LPCWSTR fileName, UInt64 &size) +{ + DWORD highPart; + DWORD lowPart = ::GetCompressedFileSizeW(fileName, &highPart); + if (lowPart == INVALID_FILE_SIZE) + if (::GetLastError() != NO_ERROR) + return false; + size = (UInt64(highPart) << 32) | lowPart; + return true; +} + +}}} + +#endif + diff --git a/app/win/installer/7zstub/src/Windows/FileIO.cpp b/app/win/installer/7zstub/src/Windows/FileIO.cpp new file mode 100644 index 0000000000..20b5fc1594 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileIO.cpp @@ -0,0 +1,245 @@ +// Windows/FileIO.cpp + +#include "StdAfx.h" + +#include "FileIO.h" +#include "Defs.h" +#ifndef _UNICODE +#include "../Common/StringConvert.h" +#endif + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { +namespace NFile { +namespace NIO { + +CFileBase::~CFileBase() { Close(); } + +bool CFileBase::Create(LPCTSTR fileName, DWORD desiredAccess, + DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) +{ + Close(); + _handle = ::CreateFile(fileName, desiredAccess, shareMode, + (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, + flagsAndAttributes, (HANDLE) NULL); + return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE)); +} + +#ifndef _UNICODE +bool CFileBase::Create(LPCWSTR fileName, DWORD desiredAccess, + DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) +{ + if (g_IsNT) + { + Close(); + _handle = ::CreateFileW(fileName, desiredAccess, shareMode, + (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, + flagsAndAttributes, (HANDLE) NULL); + return (_fileIsOpen = (_handle != INVALID_HANDLE_VALUE)); + } + return Create(UnicodeStringToMultiByte(fileName, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP), + desiredAccess, shareMode, creationDisposition, flagsAndAttributes); +} +#endif + +bool CFileBase::Close() +{ + if(!_fileIsOpen) + return true; + bool result = BOOLToBool(::CloseHandle(_handle)); + _fileIsOpen = !result; + return result; +} + +bool CFileBase::GetPosition(UInt64 &position) const +{ + return Seek(0, FILE_CURRENT, position); +} + +bool CFileBase::GetLength(UInt64 &length) const +{ + DWORD sizeHigh; + DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh); + if(sizeLow == 0xFFFFFFFF) + if(::GetLastError() != NO_ERROR) + return false; + length = (((UInt64)sizeHigh) << 32) + sizeLow; + return true; +} + +bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const +{ + LARGE_INTEGER value; + value.QuadPart = distanceToMove; + value.LowPart = ::SetFilePointer(_handle, value.LowPart, &value.HighPart, moveMethod); + if (value.LowPart == 0xFFFFFFFF) + if(::GetLastError() != NO_ERROR) + return false; + newPosition = value.QuadPart; + return true; +} + +bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) +{ + return Seek(position, FILE_BEGIN, newPosition); +} + +bool CFileBase::SeekToBegin() +{ + UInt64 newPosition; + return Seek(0, newPosition); +} + +bool CFileBase::SeekToEnd(UInt64 &newPosition) +{ + return Seek(0, FILE_END, newPosition); +} + +bool CFileBase::GetFileInformation(CByHandleFileInfo &fileInfo) const +{ + BY_HANDLE_FILE_INFORMATION winFileInfo; + if(!::GetFileInformationByHandle(_handle, &winFileInfo)) + return false; + fileInfo.Attributes = winFileInfo.dwFileAttributes; + fileInfo.CreationTime = winFileInfo.ftCreationTime; + fileInfo.LastAccessTime = winFileInfo.ftLastAccessTime; + fileInfo.LastWriteTime = winFileInfo.ftLastWriteTime; + fileInfo.VolumeSerialNumber = winFileInfo.dwFileAttributes; + fileInfo.Size = (((UInt64)winFileInfo.nFileSizeHigh) << 32) + winFileInfo.nFileSizeLow; + fileInfo.NumberOfLinks = winFileInfo.nNumberOfLinks; + fileInfo.FileIndex = (((UInt64)winFileInfo.nFileIndexHigh) << 32) + winFileInfo.nFileIndexLow; + return true; +} + +///////////////////////// +// CInFile + +bool CInFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) + { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } + +bool CInFile::Open(LPCTSTR fileName) + { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } + +#ifndef _UNICODE +bool CInFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) + { return Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes); } + +bool CInFile::Open(LPCWSTR fileName) + { return Open(fileName, FILE_SHARE_READ, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); } +#endif + +// ReadFile and WriteFile functions in Windows have BUG: +// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1) +// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES +// (Insufficient system resources exist to complete the requested service). + +static UInt32 kChunkSizeMax = (1 << 24); + +bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + DWORD processedLoc = 0; + bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL)); + processedSize = (UInt32)processedLoc; + return res; +} + +bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) +{ + processedSize = 0; + do + { + UInt32 processedLoc = 0; + bool res = ReadPart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (void *)((unsigned char *)data + processedLoc); + size -= processedLoc; + } + while (size > 0); + return true; +} + +///////////////////////// +// COutFile + +bool COutFile::Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) + { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } + +static inline DWORD GetCreationDisposition(bool createAlways) + { return createAlways? CREATE_ALWAYS: CREATE_NEW; } + +bool COutFile::Open(LPCTSTR fileName, DWORD creationDisposition) + { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } + +bool COutFile::Create(LPCTSTR fileName, bool createAlways) + { return Open(fileName, GetCreationDisposition(createAlways)); } + +#ifndef _UNICODE + +bool COutFile::Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes) + { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); } + +bool COutFile::Open(LPCWSTR fileName, DWORD creationDisposition) + { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); } + +bool COutFile::Create(LPCWSTR fileName, bool createAlways) + { return Open(fileName, GetCreationDisposition(createAlways)); } + +#endif + +bool COutFile::SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime) + { return BOOLToBool(::SetFileTime(_handle, creationTime, lastAccessTime, lastWriteTime)); } + +bool COutFile::SetLastWriteTime(const FILETIME *lastWriteTime) + { return SetTime(NULL, NULL, lastWriteTime); } + +bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) +{ + if (size > kChunkSizeMax) + size = kChunkSizeMax; + DWORD processedLoc = 0; + bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL)); + processedSize = (UInt32)processedLoc; + return res; +} + +bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) +{ + processedSize = 0; + do + { + UInt32 processedLoc = 0; + bool res = WritePart(data, size, processedLoc); + processedSize += processedLoc; + if (!res) + return false; + if (processedLoc == 0) + return true; + data = (const void *)((const unsigned char *)data + processedLoc); + size -= processedLoc; + } + while (size > 0); + return true; +} + +bool COutFile::SetEndOfFile() { return BOOLToBool(::SetEndOfFile(_handle)); } + +bool COutFile::SetLength(UInt64 length) +{ + UInt64 newPosition; + if(!Seek(length, newPosition)) + return false; + if(newPosition != length) + return false; + return SetEndOfFile(); +} + +}}} diff --git a/app/win/installer/7zstub/src/Windows/FileIO.h b/app/win/installer/7zstub/src/Windows/FileIO.h new file mode 100644 index 0000000000..de66d7f3a9 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileIO.h @@ -0,0 +1,98 @@ +// Windows/FileIO.h + +#ifndef __WINDOWS_FILEIO_H +#define __WINDOWS_FILEIO_H + +#include "../Common/Types.h" + +namespace NWindows { +namespace NFile { +namespace NIO { + +struct CByHandleFileInfo +{ + DWORD Attributes; + FILETIME CreationTime; + FILETIME LastAccessTime; + FILETIME LastWriteTime; + DWORD VolumeSerialNumber; + UInt64 Size; + DWORD NumberOfLinks; + UInt64 FileIndex; +}; + +class CFileBase +{ +protected: + bool _fileIsOpen; + HANDLE _handle; + bool Create(LPCTSTR fileName, DWORD desiredAccess, + DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + #ifndef _UNICODE + bool Create(LPCWSTR fileName, DWORD desiredAccess, + DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + #endif + +public: + CFileBase(): _fileIsOpen(false){}; + virtual ~CFileBase(); + + virtual bool Close(); + + bool GetPosition(UInt64 &position) const; + bool GetLength(UInt64 &length) const; + + bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const; + bool Seek(UInt64 position, UInt64 &newPosition); + bool SeekToBegin(); + bool SeekToEnd(UInt64 &newPosition); + + bool GetFileInformation(CByHandleFileInfo &fileInfo) const; +}; + +class CInFile: public CFileBase +{ +public: + bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + bool Open(LPCTSTR fileName); + #ifndef _UNICODE + bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + bool Open(LPCWSTR fileName); + #endif + bool ReadPart(void *data, UInt32 size, UInt32 &processedSize); + bool Read(void *data, UInt32 size, UInt32 &processedSize); +}; + +class COutFile: public CFileBase +{ + // DWORD m_CreationDisposition; +public: + // COutFile(): m_CreationDisposition(CREATE_NEW){}; + bool Open(LPCTSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + bool Open(LPCTSTR fileName, DWORD creationDisposition); + bool Create(LPCTSTR fileName, bool createAlways); + + #ifndef _UNICODE + bool Open(LPCWSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes); + bool Open(LPCWSTR fileName, DWORD creationDisposition); + bool Create(LPCWSTR fileName, bool createAlways); + #endif + + /* + void SetOpenCreationDisposition(DWORD creationDisposition) + { m_CreationDisposition = creationDisposition; } + void SetOpenCreationDispositionCreateAlways() + { m_CreationDisposition = CREATE_ALWAYS; } + */ + + bool SetTime(const FILETIME *creationTime, const FILETIME *lastAccessTime, const FILETIME *lastWriteTime); + bool SetLastWriteTime(const FILETIME *lastWriteTime); + bool WritePart(const void *data, UInt32 size, UInt32 &processedSize); + bool Write(const void *data, UInt32 size, UInt32 &processedSize); + bool SetEndOfFile(); + bool SetLength(UInt64 length); +}; + +}}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/FileName.cpp b/app/win/installer/7zstub/src/Windows/FileName.cpp new file mode 100644 index 0000000000..4a8a504e35 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileName.cpp @@ -0,0 +1,111 @@ +// Windows/FileName.cpp + +#include "StdAfx.h" + +#include "Windows/FileName.h" +#include "Common/Wildcard.h" + +namespace NWindows { +namespace NFile { +namespace NName { + +static const wchar_t kDiskDelimiter = L':'; + +/* +static bool IsCharAPrefixDelimiter(wchar_t c) + { return (c == kDirDelimiter || c == kDiskDelimiter); } +*/ + +void NormalizeDirPathPrefix(CSysString &dirPath) +{ + if (dirPath.IsEmpty()) + return; + if (dirPath.ReverseFind(kDirDelimiter) != dirPath.Length() - 1) + dirPath += kDirDelimiter; +} + +#ifndef _UNICODE +void NormalizeDirPathPrefix(UString &dirPath) +{ + if (dirPath.IsEmpty()) + return; + if (dirPath.ReverseFind(wchar_t(kDirDelimiter)) != dirPath.Length() - 1) + dirPath += wchar_t(kDirDelimiter); +} +#endif + +namespace NPathType +{ + EEnum GetPathType(const UString &path) + { + if (path.Length() <= 2) + return kLocal; + if (path[0] == kDirDelimiter && path[1] == kDirDelimiter) + return kUNC; + return kLocal; + } +} + +void CParsedPath::ParsePath(const UString &path) +{ + int curPos = 0; + switch (NPathType::GetPathType(path)) + { + case NPathType::kLocal: + { + int posDiskDelimiter = path.Find(kDiskDelimiter); + if(posDiskDelimiter >= 0) + { + curPos = posDiskDelimiter + 1; + if (path.Length() > curPos) + if(path[curPos] == kDirDelimiter) + curPos++; + } + break; + } + case NPathType::kUNC: + { + int curPos = path.Find(kDirDelimiter, 2); + if(curPos < 0) + curPos = path.Length(); + else + curPos++; + } + } + Prefix = path.Left(curPos); + SplitPathToParts(path.Mid(curPos), PathParts); +} + +UString CParsedPath::MergePath() const +{ + UString result = Prefix; + for(int i = 0; i < PathParts.Size(); i++) + { + if (i != 0) + result += kDirDelimiter; + result += PathParts[i]; + } + return result; +} + +const wchar_t kExtensionDelimiter = L'.'; + +void SplitNameToPureNameAndExtension(const UString &fullName, + UString &pureName, UString &extensionDelimiter, UString &extension) +{ + int index = fullName.ReverseFind(kExtensionDelimiter); + if (index < 0) + { + pureName = fullName; + extensionDelimiter.Empty(); + extension.Empty(); + } + else + { + pureName = fullName.Left(index); + extensionDelimiter = kExtensionDelimiter; + extension = fullName.Mid(index + 1); + } +} + +}}} diff --git a/app/win/installer/7zstub/src/Windows/FileName.h b/app/win/installer/7zstub/src/Windows/FileName.h new file mode 100644 index 0000000000..a4e9f36c32 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/FileName.h @@ -0,0 +1,43 @@ +// Windows/FileName.h + +#ifndef __WINDOWS_FILENAME_H +#define __WINDOWS_FILENAME_H + +#include "../Common/String.h" + +namespace NWindows { +namespace NFile { +namespace NName { + +const TCHAR kDirDelimiter = CHAR_PATH_SEPARATOR; +const TCHAR kAnyStringWildcard = '*'; + +void NormalizeDirPathPrefix(CSysString &dirPath); // ensures that it ended with '\\' +#ifndef _UNICODE +void NormalizeDirPathPrefix(UString &dirPath); // ensures that it ended with '\\' +#endif + +namespace NPathType +{ + enum EEnum + { + kLocal, + kUNC + }; + EEnum GetPathType(const UString &path); +} + +struct CParsedPath +{ + UString Prefix; // Disk or UNC with slash + UStringVector PathParts; + void ParsePath(const UString &path); + UString MergePath() const; +}; + +void SplitNameToPureNameAndExtension(const UString &fullName, + UString &pureName, UString &extensionDelimiter, UString &extension); + +}}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Handle.h b/app/win/installer/7zstub/src/Windows/Handle.h new file mode 100644 index 0000000000..9e559e89e3 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Handle.h @@ -0,0 +1,37 @@ +// Windows/Handle.h + +#ifndef __WINDOWS_HANDLE_H +#define __WINDOWS_HANDLE_H + +namespace NWindows { + +class CHandle +{ +protected: + HANDLE _handle; +public: + operator HANDLE() { return _handle; } + CHandle(): _handle(NULL) {} + ~CHandle() { Close(); } + bool Close() + { + if (_handle == NULL) + return true; + if (!::CloseHandle(_handle)) + return false; + _handle = NULL; + return true; + } + void Attach(HANDLE handle) + { _handle = handle; } + HANDLE Detach() + { + HANDLE handle = _handle; + _handle = NULL; + return handle; + } +}; + +} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/PropVariant.cpp b/app/win/installer/7zstub/src/Windows/PropVariant.cpp new file mode 100644 index 0000000000..a4bfdd35b3 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/PropVariant.cpp @@ -0,0 +1,310 @@ +// Windows/PropVariant.cpp + +#include "StdAfx.h" + +#include "PropVariant.h" + +#include "../Common/Defs.h" + +namespace NWindows { +namespace NCOM { + +CPropVariant::CPropVariant(const PROPVARIANT& varSrc) +{ + vt = VT_EMPTY; + InternalCopy(&varSrc); +} + +CPropVariant::CPropVariant(const CPropVariant& varSrc) +{ + vt = VT_EMPTY; + InternalCopy(&varSrc); +} + +CPropVariant::CPropVariant(BSTR bstrSrc) +{ + vt = VT_EMPTY; + *this = bstrSrc; +} + +CPropVariant::CPropVariant(LPCOLESTR lpszSrc) +{ + vt = VT_EMPTY; + *this = lpszSrc; +} + +CPropVariant& CPropVariant::operator=(const CPropVariant& varSrc) +{ + InternalCopy(&varSrc); + return *this; +} +CPropVariant& CPropVariant::operator=(const PROPVARIANT& varSrc) +{ + InternalCopy(&varSrc); + return *this; +} + +CPropVariant& CPropVariant::operator=(BSTR bstrSrc) +{ + *this = (LPCOLESTR)bstrSrc; + return *this; +} + +CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc) +{ + InternalClear(); + vt = VT_BSTR; + bstrVal = ::SysAllocString(lpszSrc); + if (bstrVal == NULL && lpszSrc != NULL) + { + vt = VT_ERROR; + scode = E_OUTOFMEMORY; + } + return *this; +} + + +CPropVariant& CPropVariant::operator=(bool bSrc) +{ + if (vt != VT_BOOL) + { + InternalClear(); + vt = VT_BOOL; + } + boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE; + return *this; +} + +CPropVariant& CPropVariant::operator=(UInt32 value) +{ + if (vt != VT_UI4) + { + InternalClear(); + vt = VT_UI4; + } + ulVal = value; + return *this; +} + +CPropVariant& CPropVariant::operator=(UInt64 value) +{ + if (vt != VT_UI8) + { + InternalClear(); + vt = VT_UI8; + } + uhVal.QuadPart = value; + return *this; +} + +CPropVariant& CPropVariant::operator=(const FILETIME &value) +{ + if (vt != VT_FILETIME) + { + InternalClear(); + vt = VT_FILETIME; + } + filetime = value; + return *this; +} + +CPropVariant& CPropVariant::operator=(Int32 value) +{ + if (vt != VT_I4) + { + InternalClear(); + vt = VT_I4; + } + lVal = value; + + return *this; +} + +CPropVariant& CPropVariant::operator=(Byte value) +{ + if (vt != VT_UI1) + { + InternalClear(); + vt = VT_UI1; + } + bVal = value; + return *this; +} + +CPropVariant& CPropVariant::operator=(Int16 value) +{ + if (vt != VT_I2) + { + InternalClear(); + vt = VT_I2; + } + iVal = value; + return *this; +} + +/* +CPropVariant& CPropVariant::operator=(LONG value) +{ + if (vt != VT_I4) + { + InternalClear(); + vt = VT_I4; + } + lVal = value; + return *this; +} +*/ + +static HRESULT MyPropVariantClear(PROPVARIANT *propVariant) +{ + switch(propVariant->vt) + { + case VT_UI1: + case VT_I1: + case VT_I2: + case VT_UI2: + case VT_BOOL: + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_INT: + case VT_UINT: + case VT_ERROR: + case VT_FILETIME: + case VT_UI8: + case VT_R8: + case VT_CY: + case VT_DATE: + propVariant->vt = VT_EMPTY; + return S_OK; + } + return ::VariantClear((VARIANTARG *)propVariant); +} + +HRESULT CPropVariant::Clear() +{ + return MyPropVariantClear(this); +} + +HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) +{ + ::VariantClear((tagVARIANT *)this); + switch(pSrc->vt) + { + case VT_UI1: + case VT_I1: + case VT_I2: + case VT_UI2: + case VT_BOOL: + case VT_I4: + case VT_UI4: + case VT_R4: + case VT_INT: + case VT_UINT: + case VT_ERROR: + case VT_FILETIME: + case VT_UI8: + case VT_R8: + case VT_CY: + case VT_DATE: + memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT)); + return S_OK; + } + return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)(pSrc)); +} + + +HRESULT CPropVariant::Attach(PROPVARIANT* pSrc) +{ + HRESULT hr = Clear(); + if (FAILED(hr)) + return hr; + memcpy(this, pSrc, sizeof(PROPVARIANT)); + pSrc->vt = VT_EMPTY; + return S_OK; +} + +HRESULT CPropVariant::Detach(PROPVARIANT* pDest) +{ + HRESULT hr = MyPropVariantClear(pDest); + if (FAILED(hr)) + return hr; + memcpy(pDest, this, sizeof(PROPVARIANT)); + vt = VT_EMPTY; + return S_OK; +} + +HRESULT CPropVariant::InternalClear() +{ + HRESULT hr = Clear(); + if (FAILED(hr)) + { + vt = VT_ERROR; + scode = hr; + } + return hr; +} + +void CPropVariant::InternalCopy(const PROPVARIANT* pSrc) +{ + HRESULT hr = Copy(pSrc); + if (FAILED(hr)) + { + vt = VT_ERROR; + scode = hr; + } +} + +int CPropVariant::Compare(const CPropVariant &a) +{ + if(vt != a.vt) + return 0; // it's mean some bug + switch (vt) + { + case VT_EMPTY: + return 0; + + /* + case VT_I1: + return MyCompare(cVal, a.cVal); + */ + case VT_UI1: + return MyCompare(bVal, a.bVal); + + case VT_I2: + return MyCompare(iVal, a.iVal); + case VT_UI2: + return MyCompare(uiVal, a.uiVal); + + case VT_I4: + return MyCompare(lVal, a.lVal); + /* + case VT_INT: + return MyCompare(intVal, a.intVal); + */ + case VT_UI4: + return MyCompare(ulVal, a.ulVal); + /* + case VT_UINT: + return MyCompare(uintVal, a.uintVal); + */ + case VT_I8: + return MyCompare(hVal.QuadPart, a.hVal.QuadPart); + case VT_UI8: + return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart); + + case VT_BOOL: + return -MyCompare(boolVal, a.boolVal); + + case VT_FILETIME: + return ::CompareFileTime(&filetime, &a.filetime); + case VT_BSTR: + return 0; // Not implemented + // return MyCompare(aPropVarint.cVal); + + default: + return 0; + } +} + +}} diff --git a/app/win/installer/7zstub/src/Windows/PropVariant.h b/app/win/installer/7zstub/src/Windows/PropVariant.h new file mode 100644 index 0000000000..604a4b11b6 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/PropVariant.h @@ -0,0 +1,57 @@ +// Windows/PropVariant.h + +#ifndef __WINDOWS_PROPVARIANT_H +#define __WINDOWS_PROPVARIANT_H + +#include "../Common/MyWindows.h" +#include "../Common/Types.h" + +namespace NWindows { +namespace NCOM { + +class CPropVariant : public tagPROPVARIANT +{ +public: + CPropVariant() { vt = VT_EMPTY; } + ~CPropVariant() { Clear(); } + CPropVariant(const PROPVARIANT& varSrc); + CPropVariant(const CPropVariant& varSrc); + CPropVariant(BSTR bstrSrc); + CPropVariant(LPCOLESTR lpszSrc); + CPropVariant(bool bSrc) { vt = VT_BOOL; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); }; + CPropVariant(UInt32 value) { vt = VT_UI4; ulVal = value; } + CPropVariant(UInt64 value) { vt = VT_UI8; uhVal = *(ULARGE_INTEGER*)&value; } + CPropVariant(const FILETIME &value) { vt = VT_FILETIME; filetime = value; } + CPropVariant(Int32 value) { vt = VT_I4; lVal = value; } + CPropVariant(Byte value) { vt = VT_UI1; bVal = value; } + CPropVariant(Int16 value) { vt = VT_I2; iVal = value; } + // CPropVariant(LONG value, VARTYPE vtSrc = VT_I4) { vt = vtSrc; lVal = value; } + + CPropVariant& operator=(const CPropVariant& varSrc); + CPropVariant& operator=(const PROPVARIANT& varSrc); + CPropVariant& operator=(BSTR bstrSrc); + CPropVariant& operator=(LPCOLESTR lpszSrc); + CPropVariant& operator=(bool bSrc); + CPropVariant& operator=(UInt32 value); + CPropVariant& operator=(UInt64 value); + CPropVariant& operator=(const FILETIME &value); + + CPropVariant& operator=(Int32 value); + CPropVariant& operator=(Byte value); + CPropVariant& operator=(Int16 value); + // CPropVariant& operator=(LONG value); + + HRESULT Clear(); + HRESULT Copy(const PROPVARIANT* pSrc); + HRESULT Attach(PROPVARIANT* pSrc); + HRESULT Detach(PROPVARIANT* pDest); + + HRESULT InternalClear(); + void InternalCopy(const PROPVARIANT* pSrc); + + int Compare(const CPropVariant &a1); +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/PropVariantConversions.cpp b/app/win/installer/7zstub/src/Windows/PropVariantConversions.cpp new file mode 100644 index 0000000000..acf7955cb0 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/PropVariantConversions.cpp @@ -0,0 +1,145 @@ +// PropVariantConversions.cpp + +#include "StdAfx.h" + +#include + +#include "PropVariantConversions.h" + +#include "Windows/Defs.h" + +#include "Common/StringConvert.h" +#include "Common/IntToString.h" + +static UString ConvertUInt64ToString(UInt64 value) +{ + wchar_t buffer[32]; + ConvertUInt64ToString(value, buffer); + return buffer; +} + +static UString ConvertInt64ToString(Int64 value) +{ + wchar_t buffer[32]; + ConvertInt64ToString(value, buffer); + return buffer; +} + +/* +static void UIntToStringSpec(UInt32 value, char *s, int numPos) +{ + char s2[32]; + ConvertUInt64ToString(value, s2); + int len = strlen(s2); + int i; + for (i = 0; i < numPos - len; i++) + s[i] = '0'; + for (int j = 0; j < len; j++, i++) + s[i] = s2[j]; + s[i] = '\0'; +} +*/ + +bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime, bool includeSeconds) +{ + s[0] = '\0'; + SYSTEMTIME st; + if(!BOOLToBool(FileTimeToSystemTime(&ft, &st))) + return false; + /* + UIntToStringSpec(st.wYear, s, 4); + strcat(s, "-"); + UIntToStringSpec(st.wMonth, s + strlen(s), 2); + strcat(s, "-"); + UIntToStringSpec(st.wDay, s + strlen(s), 2); + if (includeTime) + { + strcat(s, " "); + UIntToStringSpec(st.wHour, s + strlen(s), 2); + strcat(s, ":"); + UIntToStringSpec(st.wMinute, s + strlen(s), 2); + if (includeSeconds) + { + strcat(s, ":"); + UIntToStringSpec(st.wSecond, s + strlen(s), 2); + } + } + */ + sprintf(s, "%04d-%02d-%02d", st.wYear, st.wMonth, st.wDay); + if (includeTime) + { + sprintf(s + strlen(s), " %02d:%02d", st.wHour, st.wMinute); + if (includeSeconds) + sprintf(s + strlen(s), ":%02d", st.wSecond); + } + return true; +} + +UString ConvertFileTimeToString(const FILETIME &fileTime, bool includeTime, bool includeSeconds) +{ + char s[32]; + ConvertFileTimeToString(fileTime, s, includeTime, includeSeconds); + return GetUnicodeString(s); +} + + +UString ConvertPropVariantToString(const PROPVARIANT &propVariant) +{ + switch (propVariant.vt) + { + case VT_EMPTY: + return UString(); + case VT_BSTR: + return propVariant.bstrVal; + case VT_UI1: + return ConvertUInt64ToString(propVariant.bVal); + case VT_UI2: + return ConvertUInt64ToString(propVariant.uiVal); + case VT_UI4: + return ConvertUInt64ToString(propVariant.ulVal); + case VT_UI8: + return ConvertUInt64ToString(propVariant.uhVal.QuadPart); + case VT_FILETIME: + return ConvertFileTimeToString(propVariant.filetime, true, true); + /* + case VT_I1: + return ConvertInt64ToString(propVariant.cVal); + */ + case VT_I2: + return ConvertInt64ToString(propVariant.iVal); + case VT_I4: + return ConvertInt64ToString(propVariant.lVal); + case VT_I8: + return ConvertInt64ToString(propVariant.hVal.QuadPart); + + case VT_BOOL: + return VARIANT_BOOLToBool(propVariant.boolVal) ? L"1" : L"0"; + default: + #ifndef _WIN32_WCE + throw 150245; + #else + return UString(); + #endif + } +} + +UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &propVariant) +{ + switch (propVariant.vt) + { + case VT_UI1: + return propVariant.bVal; + case VT_UI2: + return propVariant.uiVal; + case VT_UI4: + return propVariant.ulVal; + case VT_UI8: + return (UInt64)propVariant.uhVal.QuadPart; + default: + #ifndef _WIN32_WCE + throw 151199; + #else + return 0; + #endif + } +} diff --git a/app/win/installer/7zstub/src/Windows/PropVariantConversions.h b/app/win/installer/7zstub/src/Windows/PropVariantConversions.h new file mode 100644 index 0000000000..ea7e72417e --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/PropVariantConversions.h @@ -0,0 +1,14 @@ +// Windows/PropVariantConversions.h + +#ifndef __PROPVARIANTCONVERSIONS_H +#define __PROPVARIANTCONVERSIONS_H + +#include "Common/Types.h" +#include "Common/String.h" + +bool ConvertFileTimeToString(const FILETIME &ft, char *s, bool includeTime = true, bool includeSeconds = true); +UString ConvertFileTimeToString(const FILETIME &ft, bool includeTime = true, bool includeSeconds = true); +UString ConvertPropVariantToString(const PROPVARIANT &propVariant); +UInt64 ConvertPropVariantToUInt64(const PROPVARIANT &propVariant); + +#endif diff --git a/app/win/installer/7zstub/src/Windows/ResourceString.cpp b/app/win/installer/7zstub/src/Windows/ResourceString.cpp new file mode 100644 index 0000000000..679d5ef0ea --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/ResourceString.cpp @@ -0,0 +1,53 @@ +// Windows/ResourceString.cpp + +#include "StdAfx.h" + +#include "Windows/ResourceString.h" +#ifndef _UNICODE +#include "Common/StringConvert.h" +#endif + +extern HINSTANCE g_hInstance; +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +CSysString MyLoadString(UINT resourceID) +{ + CSysString s; + int size = 256; + int len; + do + { + size += 256; + len = ::LoadString(g_hInstance, resourceID, s.GetBuffer(size - 1), size); + } + while (size - len <= 1); + s.ReleaseBuffer(); + return s; +} + +#ifndef _UNICODE +UString MyLoadStringW(UINT resourceID) +{ + if (g_IsNT) + { + UString s; + int size = 256; + int len; + do + { + size += 256; + len = ::LoadStringW(g_hInstance, resourceID, s.GetBuffer(size - 1), size); + } + while (size - len <= 1); + s.ReleaseBuffer(); + return s; + } + return GetUnicodeString(MyLoadString(resourceID)); +} +#endif + +} diff --git a/app/win/installer/7zstub/src/Windows/ResourceString.h b/app/win/installer/7zstub/src/Windows/ResourceString.h new file mode 100644 index 0000000000..3a447514f7 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/ResourceString.h @@ -0,0 +1,20 @@ +// Windows/ResourceString.h + +#ifndef __WINDOWS_RESOURCESTRING_H +#define __WINDOWS_RESOURCESTRING_H + +#include "Common/String.h" + +namespace NWindows { + +CSysString MyLoadString(UINT resourceID); +#ifdef _UNICODE +inline UString MyLoadStringW(UINT resourceID) + { return MyLoadString(resourceID); } +#else +UString MyLoadStringW(UINT resourceID); +#endif + +} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Synchronization.cpp b/app/win/installer/7zstub/src/Windows/Synchronization.cpp new file mode 100644 index 0000000000..942d868609 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Synchronization.cpp @@ -0,0 +1,17 @@ +// Windows/Synchronization.cpp + +#include "StdAfx.h" + +#include "Synchronization.h" + +namespace NWindows { +namespace NSynchronization { + +CEvent::CEvent(bool manualReset, bool initiallyOwn, LPCTSTR name, + LPSECURITY_ATTRIBUTES securityAttributes) +{ + if (!Create(manualReset, initiallyOwn, name, securityAttributes)) + throw "CreateEvent error"; +} + +}} diff --git a/app/win/installer/7zstub/src/Windows/Synchronization.h b/app/win/installer/7zstub/src/Windows/Synchronization.h new file mode 100644 index 0000000000..aff3356be5 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Synchronization.h @@ -0,0 +1,114 @@ +// Windows/Synchronization.h + +#ifndef __WINDOWS_SYNCHRONIZATION_H +#define __WINDOWS_SYNCHRONIZATION_H + +#include "Defs.h" +#include "Handle.h" + +namespace NWindows { +namespace NSynchronization { + +class CObject: public CHandle +{ +public: + bool Lock(DWORD timeoutInterval = INFINITE) + { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0); } +}; + +class CBaseEvent: public CObject +{ +public: + bool Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, + LPSECURITY_ATTRIBUTES securityAttributes = NULL) + { + _handle = ::CreateEvent(securityAttributes, BoolToBOOL(manualReset), + BoolToBOOL(initiallyOwn), name); + return (_handle != 0); + } + + bool Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) + { + _handle = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name); + return (_handle != 0); + } + + bool Set() { return BOOLToBool(::SetEvent(_handle)); } + bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); } + bool Reset() { return BOOLToBool(::ResetEvent(_handle)); } +}; + +class CEvent: public CBaseEvent +{ +public: + CEvent() {}; + CEvent(bool manualReset, bool initiallyOwn, + LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES securityAttributes = NULL); +}; + +class CManualResetEvent: public CEvent +{ +public: + CManualResetEvent(bool initiallyOwn = false, LPCTSTR name = NULL, + LPSECURITY_ATTRIBUTES securityAttributes = NULL): + CEvent(true, initiallyOwn, name, securityAttributes) {}; +}; + +class CAutoResetEvent: public CEvent +{ +public: + CAutoResetEvent(bool initiallyOwn = false, LPCTSTR name = NULL, + LPSECURITY_ATTRIBUTES securityAttributes = NULL): + CEvent(false, initiallyOwn, name, securityAttributes) {}; +}; + +class CMutex: public CObject +{ +public: + bool Create(bool initiallyOwn, LPCTSTR name = NULL, + LPSECURITY_ATTRIBUTES securityAttributes = NULL) + { + _handle = ::CreateMutex(securityAttributes, BoolToBOOL(initiallyOwn), name); + return (_handle != 0); + } + bool Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name) + { + _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name); + return (_handle != 0); + } + bool Release() { return BOOLToBool(::ReleaseMutex(_handle)); } +}; + +class CMutexLock +{ + CMutex &_object; +public: + CMutexLock(CMutex &object): _object(object) { _object.Lock(); } + ~CMutexLock() { _object.Release(); } +}; + +class CCriticalSection +{ + CRITICAL_SECTION _object; + // void Initialize() { ::InitializeCriticalSection(&_object); } + // void Delete() { ::DeleteCriticalSection(&_object); } +public: + CCriticalSection() { ::InitializeCriticalSection(&_object); } + ~CCriticalSection() { ::DeleteCriticalSection(&_object); } + void Enter() { ::EnterCriticalSection(&_object); } + void Leave() { ::LeaveCriticalSection(&_object); } +}; + +class CCriticalSectionLock +{ + CCriticalSection &_object; + void Unlock() { _object.Leave(); } +public: + CCriticalSectionLock(CCriticalSection &object): _object(object) + {_object.Enter(); } + ~CCriticalSectionLock() { Unlock(); } +}; + +}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Thread.h b/app/win/installer/7zstub/src/Windows/Thread.h new file mode 100644 index 0000000000..76be6dfba1 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Thread.h @@ -0,0 +1,52 @@ +// Windows/Thread.h + +#ifndef __WINDOWS_THREAD_H +#define __WINDOWS_THREAD_H + +#include "Handle.h" +#include "Defs.h" + +namespace NWindows { + +class CThread: public CHandle +{ + bool IsOpen() const { return _handle != 0; } +public: + bool Create(LPSECURITY_ATTRIBUTES threadAttributes, + SIZE_T stackSize, LPTHREAD_START_ROUTINE startAddress, + LPVOID parameter, DWORD creationFlags, LPDWORD threadId) + { + _handle = ::CreateThread(threadAttributes, stackSize, startAddress, + parameter, creationFlags, threadId); + return (_handle != NULL); + } + bool Create(LPTHREAD_START_ROUTINE startAddress, LPVOID parameter) + { + DWORD threadId; + return Create(NULL, 0, startAddress, parameter, 0, &threadId); + } + + DWORD Resume() + { return ::ResumeThread(_handle); } + DWORD Suspend() + { return ::SuspendThread(_handle); } + bool Terminate(DWORD exitCode) + { return BOOLToBool(::TerminateThread(_handle, exitCode)); } + + int GetPriority() + { return ::GetThreadPriority(_handle); } + bool SetPriority(int priority) + { return BOOLToBool(::SetThreadPriority(_handle, priority)); } + + bool Wait() + { + if (!IsOpen()) + return true; + return (::WaitForSingleObject(_handle, INFINITE) == WAIT_OBJECT_0); + } + +}; + +} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Time.h b/app/win/installer/7zstub/src/Windows/Time.h new file mode 100644 index 0000000000..b16602aa18 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Time.h @@ -0,0 +1,66 @@ +// Windows/Time.h + +#ifndef __WINDOWS_TIME_H +#define __WINDOWS_TIME_H + +#include "Common/Types.h" +#include "Windows/Defs.h" + +namespace NWindows { +namespace NTime { + +inline bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) +{ + return BOOLToBool(::DosDateTimeToFileTime(UInt16(dosTime >> 16), + UInt16(dosTime & 0xFFFF), &fileTime)); +} + +const UInt32 kHighDosTime = 0xFF9FBF7D; +const UInt32 kLowDosTime = 0x210000; + +inline bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) +{ + WORD datePart, timePart; + if (!::FileTimeToDosDateTime(&fileTime, &datePart, &timePart)) + { + if (fileTime.dwHighDateTime >= 0x01C00000) // 2000 + dosTime = kHighDosTime; + else + dosTime = kLowDosTime; + return false; + } + dosTime = (((UInt32)datePart) << 16) + timePart; + return true; +} + +const UInt32 kNumTimeQuantumsInSecond = 10000000; +const UInt64 kUnixTimeStartValue = ((UInt64)kNumTimeQuantumsInSecond) * 60 * 60 * 24 * 134774; + +inline void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) +{ + UInt64 v = kUnixTimeStartValue + ((UInt64)unixTime) * kNumTimeQuantumsInSecond; + fileTime.dwLowDateTime = (DWORD)v; + fileTime.dwHighDateTime = (DWORD)(v >> 32); +} + +inline bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) +{ + UInt64 winTime = (((UInt64)fileTime.dwHighDateTime) << 32) + fileTime.dwLowDateTime; + if (winTime < kUnixTimeStartValue) + { + unixTime = 0; + return false; + } + winTime = (winTime - kUnixTimeStartValue) / kNumTimeQuantumsInSecond; + if (winTime > 0xFFFFFFFF) + { + unixTime = 0xFFFFFFFF; + return false; + } + unixTime = (UInt32)winTime; + return true; +} + +}} + +#endif diff --git a/app/win/installer/7zstub/src/Windows/Window.cpp b/app/win/installer/7zstub/src/Windows/Window.cpp new file mode 100644 index 0000000000..da87687073 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Window.cpp @@ -0,0 +1,169 @@ +// Windows/Window.cpp + +#include "StdAfx.h" + +#ifndef _UNICODE +#include "Common/StringConvert.h" +#endif +#include "Windows/Window.h" + +#ifndef _UNICODE +extern bool g_IsNT; +#endif + +namespace NWindows { + +#ifndef _UNICODE +ATOM MyRegisterClass(CONST WNDCLASSW *wndClass) +{ + if (g_IsNT) + return RegisterClassW(wndClass); + WNDCLASSA wndClassA; + wndClassA.style = wndClass->style; + wndClassA.lpfnWndProc = wndClass->lpfnWndProc; + wndClassA.cbClsExtra = wndClass->cbClsExtra; + wndClassA.cbWndExtra = wndClass->cbWndExtra; + wndClassA.hInstance = wndClass->hInstance; + wndClassA.hIcon = wndClass->hIcon; + wndClassA.hCursor = wndClass->hCursor; + wndClassA.hbrBackground = wndClass->hbrBackground; + AString menuName; + AString className; + if (IS_INTRESOURCE(wndClass->lpszMenuName)) + wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName; + else + { + menuName = GetSystemString(wndClass->lpszMenuName); + wndClassA.lpszMenuName = menuName; + } + if (IS_INTRESOURCE(wndClass->lpszClassName)) + wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName; + else + { + className = GetSystemString(wndClass->lpszClassName); + wndClassA.lpszClassName = className; + } + return RegisterClassA(&wndClassA); +} + +bool CWindow::Create(LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) +{ + if (g_IsNT) + { + _window = ::CreateWindowW(className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + return Create(GetSystemString(className), GetSystemString(windowName), + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); +} + +bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) +{ + if (g_IsNT) + { + _window = ::CreateWindowExW(exStyle, className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + AString classNameA; + LPCSTR classNameP; + if (IS_INTRESOURCE(className)) + classNameP = (LPCSTR)className; + else + { + classNameA = GetSystemString(className); + classNameP = classNameA; + } + AString windowNameA; + LPCSTR windowNameP; + if (IS_INTRESOURCE(windowName)) + windowNameP = (LPCSTR)windowName; + else + { + windowNameA = GetSystemString(windowName); + windowNameP = windowNameA; + } + return CreateEx(exStyle, classNameP, windowNameP, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); +} + +#endif + +#ifndef _UNICODE +bool MySetWindowText(HWND wnd, LPCWSTR s) +{ + if (g_IsNT) + return BOOLToBool(::SetWindowTextW(wnd, s)); + return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s))); +} +#endif + +bool CWindow::GetText(CSysString &s) +{ + s.Empty(); + int length = GetTextLength(); + if (length == 0) + return (::GetLastError() == ERROR_SUCCESS); + length = GetText(s.GetBuffer(length), length + 1); + s.ReleaseBuffer(); + if (length == 0) + return (::GetLastError() != ERROR_SUCCESS); + return true; +} + +#ifndef _UNICODE +bool CWindow::GetText(UString &s) +{ + if (g_IsNT) + { + s.Empty(); + int length = GetWindowTextLengthW(_window); + if (length == 0) + return (::GetLastError() == ERROR_SUCCESS); + length = GetWindowTextW(_window, s.GetBuffer(length), length + 1); + s.ReleaseBuffer(); + if (length == 0) + return (::GetLastError() == ERROR_SUCCESS); + return true; + } + CSysString sysString; + bool result = GetText(sysString); + s = GetUnicodeString(sysString); + return result; +} +#endif + + +/* +bool CWindow::ModifyStyleBase(int styleOffset, + DWORD remove, DWORD add, UINT flags) +{ + DWORD style = GetWindowLong(styleOffset); + DWORD newStyle = (style & ~remove) | add; + if (style == newStyle) + return false; // it is not good + + SetWindowLong(styleOffset, newStyle); + if (flags != 0) + { + ::SetWindowPos(_window, NULL, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags); + } + return TRUE; +} +*/ + +} diff --git a/app/win/installer/7zstub/src/Windows/Window.h b/app/win/installer/7zstub/src/Windows/Window.h new file mode 100644 index 0000000000..b7788a83d5 --- /dev/null +++ b/app/win/installer/7zstub/src/Windows/Window.h @@ -0,0 +1,211 @@ +// Windows/Window.h + +#ifndef __WINDOWS_WINDOW_H +#define __WINDOWS_WINDOW_H + +#include "Windows/Defs.h" +#include "Common/String.h" + +namespace NWindows { + +inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass) + { return ::RegisterClass(wndClass); } + +#ifndef _UNICODE +ATOM MyRegisterClass(CONST WNDCLASSW *wndClass); +#endif + +#ifdef _UNICODE +inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); } +#else +bool MySetWindowText(HWND wnd, LPCWSTR s); +#endif + + + +class CWindow +{ +private: + // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags); +protected: + HWND _window; +public: + CWindow(HWND newWindow = NULL): _window(newWindow){}; + CWindow& operator=(HWND newWindow) + { + _window = newWindow; + return *this; + } + operator HWND() const { return _window; } + void Attach(HWND newWindow) { _window = newWindow; } + HWND Detach() + { + HWND window = _window; + _window = NULL; + return window; + } + + HWND GetParent() const { return ::GetParent(_window); } + bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect )); } + bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); } + bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); } + bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); } + + bool CreateEx(DWORD exStyle, LPCTSTR className, + LPCTSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) + { + _window = ::CreateWindowEx(exStyle, className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + + bool Create(LPCTSTR className, + LPCTSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam) + { + _window = ::CreateWindow(className, windowName, + style, x, y, width, height, parentWindow, + idOrHMenu, instance, createParam); + return (_window != NULL); + } + + #ifndef _UNICODE + bool Create(LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam); + bool CreateEx(DWORD exStyle, LPCWSTR className, + LPCWSTR windowName, DWORD style, + int x, int y, int width, int height, + HWND parentWindow, HMENU idOrHMenu, + HINSTANCE instance, LPVOID createParam); + #endif + + + bool Destroy() + { + if (_window == NULL) + return true; + bool result = BOOLToBool(::DestroyWindow(_window)); + if(result) + _window = NULL; + return result; + } + bool IsWindow() { return BOOLToBool(::IsWindow(_window)); } + bool Move(int x, int y, int width, int height, bool repaint = true) + { return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); } + bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); } + bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); } + bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); } + bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); } + bool Update() { return BOOLToBool(::UpdateWindow(_window)); } + bool InvalidateRect(LPCRECT rect, bool backgroundErase = true) + { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); } + void SetRedraw(bool redraw = true) { SendMessage(WM_SETREDRAW, BoolToBOOL(redraw), 0); } + + #ifndef _WIN32_WCE + LONG SetStyle(LONG_PTR style) + { return SetLongPtr(GWL_STYLE, style); } + DWORD GetStyle( ) const + { return GetLongPtr(GWL_STYLE); } + #else + LONG SetStyle(LONG_PTR style) + { return SetLong(GWL_STYLE, style); } + DWORD GetStyle( ) const + { return GetLong(GWL_STYLE); } + #endif + + LONG_PTR SetLong(int index, LONG_PTR newLongPtr ) + { return ::SetWindowLong(_window, index, newLongPtr); } + LONG_PTR GetLong(int index) const + { return ::GetWindowLong(_window, index ); } + LONG_PTR SetUserDataLong(LONG_PTR newLongPtr ) + { return SetLong(GWLP_USERDATA, newLongPtr); } + LONG_PTR GetUserDataLong() const + { return GetLong(GWLP_USERDATA); } + + #ifndef _WIN32_WCE + LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr ) + { return ::SetWindowLongPtr(_window, index, newLongPtr); } + #ifndef _UNICODE + LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr ) + { return ::SetWindowLongPtrW(_window, index, newLongPtr); } + #endif + + LONG_PTR GetLongPtr(int index) const + { return ::GetWindowLongPtr(_window, index ); } + LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr ) + { return SetLongPtr(GWLP_USERDATA, newLongPtr); } + LONG_PTR GetUserDataLongPtr() const + { return GetLongPtr(GWLP_USERDATA); } + #endif + + /* + bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) + { return ModifyStyleBase(GWL_STYLE, remove, add, flags); } + bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0) + { return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); } + */ + + HWND SetFocus() { return ::SetFocus(_window); } + + LRESULT SendMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return ::SendMessage(_window, message, wParam, lParam) ;} + #ifndef _UNICODE + LRESULT SendMessageW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return ::SendMessageW(_window, message, wParam, lParam) ;} + #endif + + bool PostMessage(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)) ;} + #ifndef _UNICODE + LRESULT PostMessageW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0) + { return ::PostMessageW(_window, message, wParam, lParam) ;} + #endif + + bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); } + #ifndef _UNICODE + bool CWindow::SetText(LPCWSTR s) { return MySetWindowText(_window, s); } + #endif + + int GetTextLength() const + { return GetWindowTextLength(_window); } + UINT GetText(LPTSTR string, int maxCount) const + { return GetWindowText(_window, string, maxCount); } + bool GetText(CSysString &s); + #ifndef _UNICODE + /* + UINT GetText(LPWSTR string, int maxCount) const + { return GetWindowTextW(_window, string, maxCount); } + */ + bool GetText(UString &s); + #endif + + bool Enable(bool enable) + { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); } + + bool IsEnabled() + { return BOOLToBool(::IsWindowEnabled(_window)); } + + #ifndef _WIN32_WCE + HMENU GetSystemMenu(bool revert) + { return ::GetSystemMenu(_window, BoolToBOOL(revert)); } + #endif + + UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = 0) + { return ::SetTimer(_window, idEvent, elapse, timerFunc); } + bool KillTimer(UINT_PTR idEvent) + {return BOOLToBool(::KillTimer(_window, idEvent)); } +}; + +} + +#endif + diff --git a/app/win/installer/LICENSE b/app/win/installer/LICENSE new file mode 100644 index 0000000000..373395d73e --- /dev/null +++ b/app/win/installer/LICENSE @@ -0,0 +1,9 @@ +Please see the file toolkit/content/license.html for the copyright licensing +conditions attached to this codebase, including copies of the licenses +concerned. + +You are not granted rights or licenses to the trademarks of the +Mozilla Foundation or any party, including without limitation the +Firefox name or logo. + +For more information, see: http://www.mozilla.org/foundation/licensing.html diff --git a/app/win/installer/app.tag b/app/win/installer/app.tag new file mode 100644 index 0000000000..b4491d626d --- /dev/null +++ b/app/win/installer/app.tag @@ -0,0 +1,4 @@ +;!@Install@!UTF-8! +Title="Zotero" +RunProgram="setup.exe" +;!@InstallEnd@! \ No newline at end of file diff --git a/app/win/installer/baseLocale.nlf b/app/win/installer/baseLocale.nlf new file mode 100644 index 0000000000000000000000000000000000000000..4870afce1d4c108ef329424f6890b6383171ee76 GIT binary patch literal 398 zcmaiwy9&ZU5Jhk8S1hDZ!GM*$D54N7qCX&JH3453Bk0GgXEyQCS!8!-?qlxc`H18+ zmDfrc=UF}KOh+Bm)`hpHDtNUtSE31>s|Hl2ThL#j`Q;TTw_tg2^9?hBXZ?zM3*t1> z7_8smlQ7YIjF)kjOuYwYOqJ0u@pS4aR+oDZX52EMUK^@PyO1=-)xHR9gtKjS02lNE zGwqpmI;A7-W7V=)kvXnW_E@Wko4erimZI37NPOfoe zbJt-bfR>-N`-ft#S3rUN`c9ukg(0*n7U!dJWmsb%~X&l&%?QsoVD|~m z8u{9)@!YR6gf5pjIt7kB zyVuBS)yCNfcRTn{V`F7pLYrGyOT?+q+FDJVdG-=kErG@y-fhEMxA^PgoNHUq)WG{= zJhOqf45ZHFPuyK%b(O7oda5m|@!=PsEKO3#JYDt_a19zmbr`xYD+Y(u;&D4lx1**HZAc@3#Yi^y>o=K7)8a6T>oI7 zW^@_Ip(ZQr;NnghK@Y#jT1K<6@)$uMafK01*^gHK7~C+H-@NZUMqB6yuDroBAOF=* zcc=bWSV5~DF0@?nySGm=yX;2(CAi%LuRHkuC6j#`ALodRF5;mJd& z2k6x`Y|P_&TG{}aeMGsOe_EC$%(gQy%yGL4(f_UkcVITu+;R>C$#*B)Aw~Y( z;ob&!$@v9XOAay~Ju^KIT<+v*uIG;Q5959X@5L5Yrw zD>V~ngu9C8?5o1IT5b+kU5;f|y0x|wF>;K|^E^&*FDLWnX-^LifLH?=fjNN{yUe{9 zDe5?_WWPrzy?+{?bKt<3RTeS&G}9^?+K1Ft99L7A?^RF5)ccvWC6`m|S-SWPS-=Wpl}&4OPbBa&I{vTibM40oyO zF=O61{<=(2&;5`cPwz2zYZ-Q!^;)oRAukz&to*46WR>6@?LeQ_!8ErW-UmD%`oh(f zuuCL%<$id-_-8KA*?@J1@zDcQlofAb4?7LdNcM1A1@CNSBwLAy_JqCz)n1prCMKK+ z^eN5zMSdT$H#e9}IJvngpxE!ky(S~>L4Mqe@gZJapmqtVoZI@a)pxThAunshTn+c< z+{yUuZ)I@iEn3E2eh#nbT=R$(v8_7m&<}aqXa!}qEr*9+_~Ih{pg`RvTnI>h~m&P<+l_0i9)NFJ||n;8SEnwrC?Dt5|gJbUPml{d_D ztajJf-|LoRkH%TpUwQU3f{DJd`9)_v7lq`9o9SFWzK4|ybV8i_@8p%uc`54+dQtAp z+(6#x?7G4=V?FQk1bs5MdofF-Bx~BLdgyh z_7L%vVjTT}722a!@gkhAtMkVNwDGm~)4iLy0PbXlW@ViQa_eWl&S4cDChHP272obX z^*zm|q<`3z<;}gj-xwT&6`BXg4#g;ZcjDrqN{g@Yq<@3rnN`IbeQ&1K+x2@(FmArJ zc6yMv9I^j6qqE9$mOM*j@f1_)Y^ciQ)zZ_MybphH-sY5DKM68ZFi-JqlSX!`OR3Hv zv6ehz-l(4&%V=p&n~%tDS!ryZYlbXyyMB(0QHwj4;!IUWDvaQGE~uU-tE8qeE6aY4 z*)rD4SE6#KRMscNB7er*E%E6%xcpP>$M>JLW9?#g_(`M4lb8t_O}+!F%S8Oe=}?t! zx5iWq|^$9DbV@Z3{loGetL`%^cmvQ_NwIw VaXqVch@1-d{pFLhVGF-){sSku38w%6 literal 0 HcmV?d00001 diff --git a/app/win/installer/branding.nsi b/app/win/installer/branding.nsi new file mode 100644 index 0000000000..870940407a --- /dev/null +++ b/app/win/installer/branding.nsi @@ -0,0 +1,14 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# NSIS branding defines for unofficial builds. +# The official release build branding.nsi is located in other-license/branding/firefox/ +# The nightly build branding.nsi is located in browser/installer/windows/nsis/ + +# BrandFullNameInternal is used for some registry and file system values +# instead of BrandFullName and typically should not be modified. +!define BrandFullNameInternal "Zotero" +!define CompanyName "Corporation for Digital Scholarship" +!define URLInfoAbout "https://www.zotero.org" +!define URLUpdateInfo "https://www.zotero.org" diff --git a/app/win/installer/common.nsh b/app/win/installer/common.nsh new file mode 100755 index 0000000000..95d012141c --- /dev/null +++ b/app/win/installer/common.nsh @@ -0,0 +1,5620 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +Var TmpVal +; destination for unused stack pops. +Var Trash + +################################################################################ +# Helper defines and macros for toolkit applications + +/** + * Avoid creating macros / functions that overwrite registers (see the + * GetLongPath macro for one way to avoid this)! + * + * Before using the registers exchange the passed in params and save existing + * register values to the stack. + * + * Exch $R9 ; exhange the original $R9 with the top of the stack + * Exch 1 ; exchange the top of the stack with 1 below the top of the stack + * Exch $R8 ; exchange the original $R8 with the top of the stack + * Exch 2 ; exchange the top of the stack with 2 below the top of the stack + * Exch $R7 ; exchange the original $R7 with the top of the stack + * Push $R6 ; push the original $R6 onto the top of the stack + * Push $R5 ; push the original $R5 onto the top of the stack + * Push $R4 ; push the original $R4 onto the top of the stack + * + * + * + * ; Restore the values. + * Pop $R4 ; restore the value for $R4 from the top of the stack + * Pop $R5 ; restore the value for $R5 from the top of the stack + * Pop $R6 ; restore the value for $R6 from the top of the stack + * Exch $R7 ; exchange the new $R7 value with the top of the stack + * Exch 2 ; exchange the top of the stack with 2 below the top of the stack + * Exch $R8 ; exchange the new $R8 value with the top of the stack + * Exch 1 ; exchange the top of the stack with 2 below the top of the stack + * Exch $R9 ; exchange the new $R9 value with the top of the stack + * + * + * When inserting macros in common.nsh from another macro in common.nsh that + * can be used from the uninstaller _MOZFUNC_UN will be undefined when it is + * inserted. Use the following to redefine _MOZFUNC_UN with its original value + * (see the RegCleanMain macro for an example). + * + * !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + * !insertmacro ${_MOZFUNC_UN_TMP}FileJoin + * !insertmacro ${_MOZFUNC_UN_TMP}LineFind + * !insertmacro ${_MOZFUNC_UN_TMP}TextCompareNoDetails + * !insertmacro ${_MOZFUNC_UN_TMP}TrimNewLines + * !undef _MOZFUNC_UN + * !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + * !undef _MOZFUNC_UN_TMP + */ + +; When including a file provided by NSIS check if its verbose macro is defined +; to prevent loading the file a second time. +!ifmacrondef TEXTFUNC_VERBOSE + !include TextFunc.nsh +!endif + +!ifmacrondef FILEFUNC_VERBOSE + !include FileFunc.nsh +!endif + +!ifmacrondef LOGICLIB_VERBOSITY + !include LogicLib.nsh +!endif + +!ifndef WINMESSAGES_INCLUDED + !include WinMessages.nsh +!endif + +!ifndef MUI_VERBOSE + !include MUI.nsh +!endif + +; When including WinVer.nsh check if ___WINVER__NSH___ is defined to prevent +; loading the file a second time. NSIS versions prior to 2.21 didn't include +; WinVer.nsh so include it with the /NOFATAL option. +!ifndef ___WINVER__NSH___ + !include /NONFATAL WinVer.nsh +!endif + +!include x64.nsh + +; NSIS provided macros that we have overridden. +!include overrides.nsh + +!define SHORTCUTS_LOG "shortcuts_log.ini" + +; !define SHCNF_DWORD 0x0003 +; !define SHCNF_FLUSH 0x1000 +!define SHCNF_DWORDFLUSH 0x1003 +!ifndef SHCNE_ASSOCCHANGED + !define SHCNE_ASSOCCHANGED 0x08000000 +!endif + + +################################################################################ +# Macros for debugging + +/** + * The following two macros assist with verifying that a macro doesn't + * overwrite any registers. + * + * Usage: + * ${debugSetRegisters} + * + * ${debugDisplayRegisters} + */ + +/** + * Sets all register values to their name to assist with verifying that a macro + * doesn't overwrite any registers. + */ +!macro debugSetRegisters + StrCpy $0 "$$0" + StrCpy $1 "$$1" + StrCpy $2 "$$2" + StrCpy $3 "$$3" + StrCpy $4 "$$4" + StrCpy $5 "$$5" + StrCpy $6 "$$6" + StrCpy $7 "$$7" + StrCpy $8 "$$8" + StrCpy $9 "$$9" + StrCpy $R0 "$$R0" + StrCpy $R1 "$$R1" + StrCpy $R2 "$$R2" + StrCpy $R3 "$$R3" + StrCpy $R4 "$$R4" + StrCpy $R5 "$$R5" + StrCpy $R6 "$$R6" + StrCpy $R7 "$$R7" + StrCpy $R8 "$$R8" + StrCpy $R9 "$$R9" +!macroend +!define debugSetRegisters "!insertmacro debugSetRegisters" + +/** + * Displays all register values to assist with verifying that a macro doesn't + * overwrite any registers. + */ +!macro debugDisplayRegisters + MessageBox MB_OK \ + "Register Values:$\n\ + $$0 = $0$\n$$1 = $1$\n$$2 = $2$\n$$3 = $3$\n$$4 = $4$\n\ + $$5 = $5$\n$$6 = $6$\n$$7 = $7$\n$$8 = $8$\n$$9 = $9$\n\ + $$R0 = $R0$\n$$R1 = $R1$\n$$R2 = $R2$\n$$R3 = $R3$\n$$R4 = $R4$\n\ + $$R5 = $R5$\n$$R6 = $R6$\n$$R7 = $R7$\n$$R8 = $R8$\n$$R9 = $R9" +!macroend +!define debugDisplayRegisters "!insertmacro debugDisplayRegisters" + + +################################################################################ +# Modern User Interface (MUI) override macros + +; Removed macros in nsis 2.33u (ported from nsis 2.22) +; MUI_LANGUAGEFILE_DEFINE +; MUI_LANGUAGEFILE_LANGSTRING_PAGE +; MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE +; MUI_LANGUAGEFILE_LANGSTRING_DEFINE +; MUI_LANGUAGEFILE_UNLANGSTRING_PAGE + +!macro MOZ_MUI_LANGUAGEFILE_DEFINE DEFINE NAME + + !ifndef "${DEFINE}" + !define "${DEFINE}" "${${NAME}}" + !endif + !undef "${NAME}" + +!macroend + +!macro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE PAGE NAME + + !ifdef MUI_${PAGE}PAGE + LangString "${NAME}" 0 "${${NAME}}" + !undef "${NAME}" + !else + !undef "${NAME}" + !endif + +!macroend + +!macro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE PAGE NAME + + !ifdef MUI_${PAGE}PAGE | MUI_UN${PAGE}PAGE + LangString "${NAME}" 0 "${${NAME}}" + !undef "${NAME}" + !else + !undef "${NAME}" + !endif + +!macroend + +!macro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE DEFINE NAME + + !ifdef "${DEFINE}" + LangString "${NAME}" 0 "${${NAME}}" + !endif + !undef "${NAME}" + +!macroend + +!macro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE PAGE NAME + + !ifdef MUI_UNINSTALLER + !ifdef MUI_UN${PAGE}PAGE + LangString "${NAME}" 0 "${${NAME}}" + !undef "${NAME}" + !else + !undef "${NAME}" + !endif + !else + !undef "${NAME}" + !endif + +!macroend + +; Modified version of the following MUI macros to support Mozilla localization. +; MUI_LANGUAGE +; MUI_LANGUAGEFILE_BEGIN +; MOZ_MUI_LANGUAGEFILE_END +; See /Contrib/Modern UI/System.nsh for more information +!define MUI_INSTALLOPTIONS_READ "!insertmacro MUI_INSTALLOPTIONS_READ" + +!macro MOZ_MUI_LANGUAGE LANGUAGE + !verbose push + !verbose ${MUI_VERBOSE} + !include "${LANGUAGE}.nsh" + !verbose pop +!macroend + +!macro MOZ_MUI_LANGUAGEFILE_BEGIN LANGUAGE + !insertmacro MUI_INSERT + !ifndef "MUI_LANGUAGEFILE_${LANGUAGE}_USED" + !define "MUI_LANGUAGEFILE_${LANGUAGE}_USED" + LoadLanguageFile "${LANGUAGE}.nlf" + !else + !error "Modern UI language file ${LANGUAGE} included twice!" + !endif +!macroend + +; Custom version of MUI_LANGUAGEFILE_END. The macro to add the default MUI +; strings and the macros for several strings that are part of the NSIS MUI and +; not in our locale files have been commented out. +!macro MOZ_MUI_LANGUAGEFILE_END + +# !include "${NSISDIR}\Contrib\Modern UI\Language files\Default.nsh" + !ifdef MUI_LANGUAGEFILE_DEFAULT_USED + !undef MUI_LANGUAGEFILE_DEFAULT_USED + !warning "${LANGUAGE} Modern UI language file version doesn't match. Using default English texts for missing strings." + !endif + + !insertmacro MOZ_MUI_LANGUAGEFILE_DEFINE "MUI_${LANGUAGE}_LANGNAME" "MUI_LANGNAME" + + !ifndef MUI_LANGDLL_PUSHLIST + !define MUI_LANGDLL_PUSHLIST "'${MUI_${LANGUAGE}_LANGNAME}' ${LANG_${LANGUAGE}} " + !else + !ifdef MUI_LANGDLL_PUSHLIST_TEMP + !undef MUI_LANGDLL_PUSHLIST_TEMP + !endif + !define MUI_LANGDLL_PUSHLIST_TEMP "${MUI_LANGDLL_PUSHLIST}" + !undef MUI_LANGDLL_PUSHLIST + !define MUI_LANGDLL_PUSHLIST "'${MUI_${LANGUAGE}_LANGNAME}' ${LANG_${LANGUAGE}} ${MUI_LANGDLL_PUSHLIST_TEMP}" + !endif + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE WELCOME "MUI_TEXT_WELCOME_INFO_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE WELCOME "MUI_TEXT_WELCOME_INFO_TEXT" + +!ifdef MUI_TEXT_LICENSE_TITLE + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_TEXT_LICENSE_TITLE" +!endif +!ifdef MUI_TEXT_LICENSE_SUBTITLE + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_TEXT_LICENSE_SUBTITLE" +!endif +!ifdef MUI_INNERTEXT_LICENSE_TOP + !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_TOP" +!endif + +# !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM" + +!ifdef MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM_CHECKBOX" +!endif + +!ifdef MUI_INNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE LICENSE "MUI_INNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS" +!endif + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE COMPONENTS "MUI_TEXT_COMPONENTS_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE COMPONENTS "MUI_TEXT_COMPONENTS_SUBTITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE COMPONENTS "MUI_INNERTEXT_COMPONENTS_DESCRIPTION_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE COMPONENTS "MUI_INNERTEXT_COMPONENTS_DESCRIPTION_INFO" + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE DIRECTORY "MUI_TEXT_DIRECTORY_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE DIRECTORY "MUI_TEXT_DIRECTORY_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_TEXT_STARTMENU_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_TEXT_STARTMENU_SUBTITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_INNERTEXT_STARTMENU_TOP" +# !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE STARTMENU "MUI_INNERTEXT_STARTMENU_CHECKBOX" + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_INSTALLING_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_INSTALLING_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_FINISH_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_FINISH_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_ABORT_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE INSTFILES "MUI_TEXT_ABORT_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_BUTTONTEXT_FINISH" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_TEXT" + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_INFO_REBOOT" + !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_REBOOTNOW" + !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_REBOOTLATER" +# !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_RUN" +# !insertmacro MOZ_MUI_LANGUAGEFILE_MULTILANGSTRING_PAGE FINISH "MUI_TEXT_FINISH_SHOWREADME" + +; Support for using the existing MUI_TEXT_ABORTWARNING string +!ifdef MOZ_MUI_CUSTOM_ABORT + LangString MOZ_MUI_TEXT_ABORTWARNING 0 "${MUI_TEXT_ABORTWARNING}" +!endif + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE MUI_ABORTWARNING "MUI_TEXT_ABORTWARNING" + + + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE WELCOME "MUI_UNTEXT_WELCOME_INFO_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE WELCOME "MUI_UNTEXT_WELCOME_INFO_TEXT" + + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE CONFIRM "MUI_UNTEXT_CONFIRM_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE CONFIRM "MUI_UNTEXT_CONFIRM_SUBTITLE" + +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNTEXT_LICENSE_TITLE" +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNTEXT_LICENSE_SUBTITLE" + +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM" +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM_CHECKBOX" +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE LICENSE "MUI_UNINNERTEXT_LICENSE_BOTTOM_RADIOBUTTONS" + +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE COMPONENTS "MUI_UNTEXT_COMPONENTS_TITLE" +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE COMPONENTS "MUI_UNTEXT_COMPONENTS_SUBTITLE" + +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE DIRECTORY "MUI_UNTEXT_DIRECTORY_TITLE" +# !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE DIRECTORY "MUI_UNTEXT_DIRECTORY_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_UNINSTALLING_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_UNINSTALLING_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_FINISH_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_FINISH_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_ABORT_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE INSTFILES "MUI_UNTEXT_ABORT_SUBTITLE" + + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_TITLE" + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_TEXT" + !insertmacro MOZ_MUI_LANGUAGEFILE_UNLANGSTRING_PAGE FINISH "MUI_UNTEXT_FINISH_INFO_REBOOT" + + !insertmacro MOZ_MUI_LANGUAGEFILE_LANGSTRING_DEFINE MUI_UNABORTWARNING "MUI_UNTEXT_ABORTWARNING" + + !ifndef MUI_LANGDLL_LANGUAGES + !define MUI_LANGDLL_LANGUAGES "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' " + !define MUI_LANGDLL_LANGUAGES_CP "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' '${LANG_${LANGUAGE}_CP}' " + !else + !ifdef MUI_LANGDLL_LANGUAGES_TEMP + !undef MUI_LANGDLL_LANGUAGES_TEMP + !endif + !define MUI_LANGDLL_LANGUAGES_TEMP "${MUI_LANGDLL_LANGUAGES}" + !undef MUI_LANGDLL_LANGUAGES + + !ifdef MUI_LANGDLL_LANGUAGES_CP_TEMP + !undef MUI_LANGDLL_LANGUAGES_CP_TEMP + !endif + !define MUI_LANGDLL_LANGUAGES_CP_TEMP "${MUI_LANGDLL_LANGUAGES_CP}" + !undef MUI_LANGDLL_LANGUAGES_CP + + !define MUI_LANGDLL_LANGUAGES "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' ${MUI_LANGDLL_LANGUAGES_TEMP}" + !define MUI_LANGDLL_LANGUAGES_CP "'${LANGFILE_${LANGUAGE}_NAME}' '${LANG_${LANGUAGE}}' '${LANG_${LANGUAGE}_CP}' ${MUI_LANGDLL_LANGUAGES_CP_TEMP}" + !endif + +!macroend + +/** + * Creates an InstallOptions file with a UTF-16LE BOM and adds the RTL value + * to the Settings section. + * + * @param _FILE + * The name of the file to be created in $PLUGINSDIR. + */ +!macro InitInstallOptionsFile _FILE + Push $R9 + + FileOpen $R9 "$PLUGINSDIR\${_FILE}" w + FileWriteWord $R9 "65279" + FileClose $R9 + WriteIniStr "$PLUGINSDIR\${_FILE}" "Settings" "RTL" "$(^RTL)" + + Pop $R9 +!macroend + + +################################################################################ +# Macros for handling files in use + +/** + * Checks for files in use in the $INSTDIR directory. To check files in + * sub-directories this macro would need to be rewritten to create + * sub-directories in the temporary directory used to backup the files that are + * checked. + * + * Example usage: + * + * ; The first string to be pushed onto the stack MUST be "end" to indicate + * ; that there are no more files in the $INSTDIR directory to check. + * Push "end" + * Push "freebl3.dll" + * ; The last file pushed should be the app's main exe so if it is in use this + * ; macro will return after the first check. + * Push "${FileMainEXE}" + * ${CheckForFilesInUse} $R9 + * + * !IMPORTANT - this macro uses the $R7, $R8, and $R9 registers and makes no + * attempt to restore their original values. + * + * @return _RESULT + * false if all of the files popped from the stack are not in use. + * True if any of the files popped from the stack are in use. + * $R7 = Temporary backup directory where the files will be copied to. + * $R8 = value popped from the stack. This will either be a file name for a file + * in the $INSTDIR directory or "end" to indicate that there are no + * additional files to check. + * $R9 = _RESULT + */ +!macro CheckForFilesInUse + + !ifndef ${_MOZFUNC_UN}CheckForFilesInUse + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}CheckForFilesInUse "!insertmacro ${_MOZFUNC_UN}CheckForFilesInUseCall" + + Function ${_MOZFUNC_UN}CheckForFilesInUse + ; Create a temporary backup directory. + GetTempFileName $R7 "$INSTDIR" + Delete "$R7" + SetOutPath "$R7" + StrCpy $R9 "false" + + Pop $R8 + ${While} $R8 != "end" + ${Unless} ${FileExists} "$INSTDIR\$R8" + Pop $R8 ; get next file to check before continuing + ${Continue} + ${EndUnless} + + ClearErrors + CopyFiles /SILENT "$INSTDIR\$R8" "$R7\$R8" ; try to copy + ${If} ${Errors} + ; File is in use + StrCpy $R9 "true" + ${Break} + ${EndIf} + + Delete "$INSTDIR\$R8" ; delete original + ${If} ${Errors} + ; File is in use + StrCpy $R9 "true" + Delete "$R7\$R8" ; delete temp copy + ${Break} + ${EndIf} + + Pop $R8 ; get next file to check + ${EndWhile} + + ; clear stack + ${While} $R8 != "end" + Pop $R8 + ${EndWhile} + + ; restore everything + SetOutPath "$INSTDIR" + CopyFiles /SILENT "$R7\*" "$INSTDIR\" + RmDir /r "$R7" + SetOutPath "$EXEDIR" + ClearErrors + + Push $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro CheckForFilesInUseCall _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call CheckForFilesInUse + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.CheckForFilesInUseCall _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.CheckForFilesInUse + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.CheckForFilesInUse + !ifndef un.CheckForFilesInUse + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro CheckForFilesInUse + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * The macros below will automatically prepend un. to the function names when + * they are defined (e.g. !define un.RegCleanMain). + */ +!verbose push +!verbose 3 +!ifndef _MOZFUNC_VERBOSE + !define _MOZFUNC_VERBOSE 3 +!endif +!verbose ${_MOZFUNC_VERBOSE} +!define MOZFUNC_VERBOSE "!insertmacro MOZFUNC_VERBOSE" +!define _MOZFUNC_UN +!define _MOZFUNC_S +!verbose pop + +!macro MOZFUNC_VERBOSE _VERBOSE + !verbose push + !verbose 3 + !undef _MOZFUNC_VERBOSE + !define _MOZFUNC_VERBOSE ${_VERBOSE} + !verbose pop +!macroend + +/** + * Displays a MessageBox and then calls abort to prevent continuing to the + * next page when the specified Window Class is found. + * + * @param _WINDOW_CLASS + * The Window Class to search for with FindWindow. + * @param _MSG + * The message text to display in the message box. + * + * $R7 = return value from FindWindow + * $R8 = _WINDOW_CLASS + * $R9 = _MSG + */ +!macro ManualCloseAppPrompt + + !ifndef ${_MOZFUNC_UN}ManualCloseAppPrompt + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}ManualCloseAppPrompt "!insertmacro ${_MOZFUNC_UN}ManualCloseAppPromptCall" + + Function ${_MOZFUNC_UN}ManualCloseAppPrompt + Exch $R9 + Exch 1 + Exch $R8 + Push $R7 + + FindWindow $R7 "$R8" + ${If} $R7 <> 0 ; integer comparison + MessageBox MB_OK|MB_ICONQUESTION "$R9" /SD IDOK + Abort + ${EndIf} + + Pop $R7 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro ManualCloseAppPromptCall _WINDOW_CLASS _MSG + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_WINDOW_CLASS}" + Push "${_MSG}" + Call ManualCloseAppPrompt + !verbose pop +!macroend + +!macro un.ManualCloseAppPromptCall _WINDOW_CLASS _MSG + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_WINDOW_CLASS}" + Push "${_MSG}" + Call un.ManualCloseAppPrompt + !verbose pop +!macroend + +!macro un.ManualCloseAppPrompt + !ifndef un.ManualCloseAppPrompt + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro ManualCloseAppPrompt + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + + +################################################################################ +# Macros for working with the registry + +/** + * Writes a registry string using SHCTX and the supplied params and logs the + * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * + * @param _ROOT + * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). + * This will only be used for logging. + * @param _KEY + * The subkey in relation to the key root. + * @param _NAME + * The key value name to write to. + * @param _STR + * The string to write to the key value name. + * @param _LOG_UNINSTALL + * 0 = don't add to uninstall log, 1 = add to uninstall log. + * + * $R5 = _ROOT + * $R6 = _KEY + * $R7 = _NAME + * $R8 = _STR + * $R9 = _LOG_UNINSTALL + */ +!macro WriteRegStr2 + + !ifndef ${_MOZFUNC_UN}WriteRegStr2 + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}WriteRegStr2 "!insertmacro ${_MOZFUNC_UN}WriteRegStr2Call" + + Function ${_MOZFUNC_UN}WriteRegStr2 + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Exch 4 + Exch $R5 + + ClearErrors + WriteRegStr SHCTX "$R6" "$R7" "$R8" + + !ifndef NO_LOG + ${If} ${Errors} + ${LogMsg} "** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **" + ${Else} + ${If} $R9 == 1 ; add to the uninstall log? + ${LogUninstall} "RegVal: $R5 | $R6 | $R7" + ${EndIf} + ${LogMsg} "Added Registry String: $R5 | $R6 | $R7 | $R8" + ${EndIf} + !endif + + Exch $R5 + Exch 4 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro WriteRegStr2Call _ROOT _KEY _NAME _STR _LOG_UNINSTALL + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_ROOT}" + Push "${_KEY}" + Push "${_NAME}" + Push "${_STR}" + Push "${_LOG_UNINSTALL}" + Call WriteRegStr2 + !verbose pop +!macroend + +!macro un.WriteRegStr2Call _ROOT _KEY _NAME _STR _LOG_UNINSTALL + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_ROOT}" + Push "${_KEY}" + Push "${_NAME}" + Push "${_STR}" + Push "${_LOG_UNINSTALL}" + Call un.WriteRegStr2 + !verbose pop +!macroend + +!macro un.WriteRegStr2 + !ifndef un.WriteRegStr2 + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro WriteRegStr2 + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Writes a registry dword using SHCTX and the supplied params and logs the + * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * + * @param _ROOT + * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). + * This will only be used for logging. + * @param _KEY + * The subkey in relation to the key root. + * @param _NAME + * The key value name to write to. + * @param _DWORD + * The dword to write to the key value name. + * @param _LOG_UNINSTALL + * 0 = don't add to uninstall log, 1 = add to uninstall log. + * + * $R5 = _ROOT + * $R6 = _KEY + * $R7 = _NAME + * $R8 = _DWORD + * $R9 = _LOG_UNINSTALL + */ +!macro WriteRegDWORD2 + + !ifndef ${_MOZFUNC_UN}WriteRegDWORD2 + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}WriteRegDWORD2 "!insertmacro ${_MOZFUNC_UN}WriteRegDWORD2Call" + + Function ${_MOZFUNC_UN}WriteRegDWORD2 + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Exch 4 + Exch $R5 + + ClearErrors + WriteRegDWORD SHCTX "$R6" "$R7" "$R8" + + !ifndef NO_LOG + ${If} ${Errors} + ${LogMsg} "** ERROR Adding Registry DWord: $R5 | $R6 | $R7 | $R8 **" + ${Else} + ${If} $R9 == 1 ; add to the uninstall log? + ${LogUninstall} "RegVal: $R5 | $R6 | $R7" + ${EndIf} + ${LogMsg} "Added Registry DWord: $R5 | $R6 | $R7 | $R8" + ${EndIf} + !endif + + Exch $R5 + Exch 4 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro WriteRegDWORD2Call _ROOT _KEY _NAME _DWORD _LOG_UNINSTALL + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_ROOT}" + Push "${_KEY}" + Push "${_NAME}" + Push "${_DWORD}" + Push "${_LOG_UNINSTALL}" + Call WriteRegDWORD2 + !verbose pop +!macroend + +!macro un.WriteRegDWORD2Call _ROOT _KEY _NAME _DWORD _LOG_UNINSTALL + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_ROOT}" + Push "${_KEY}" + Push "${_NAME}" + Push "${_DWORD}" + Push "${_LOG_UNINSTALL}" + Call un.WriteRegDWORD2 + !verbose pop +!macroend + +!macro un.WriteRegDWORD2 + !ifndef un.WriteRegDWORD2 + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro WriteRegDWORD2 + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Writes a registry string to HKCR using the supplied params and logs the + * action to the install log and the uninstall log if _LOG_UNINSTALL equals 1. + * + * Define NO_LOG to prevent all logging when calling this from the uninstaller. + * + * @param _ROOT + * The registry key root as defined by NSIS (e.g. HKLM, HKCU, etc.). + * This will only be used for logging. + * @param _KEY + * The subkey in relation to the key root. + * @param _NAME + * The key value name to write to. + * @param _STR + * The string to write to the key value name. + * @param _LOG_UNINSTALL + * 0 = don't add to uninstall log, 1 = add to uninstall log. + * + * $R5 = _ROOT + * $R6 = _KEY + * $R7 = _NAME + * $R8 = _STR + * $R9 = _LOG_UNINSTALL + */ +!macro WriteRegStrHKCR + + !ifndef ${_MOZFUNC_UN}WriteRegStrHKCR + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}WriteRegStrHKCR "!insertmacro ${_MOZFUNC_UN}WriteRegStrHKCRCall" + + Function ${_MOZFUNC_UN}WriteRegStrHKCR + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Exch 4 + Exch $R5 + + ClearErrors + WriteRegStr HKCR "$R6" "$R7" "$R8" + + !ifndef NO_LOG + ${If} ${Errors} + ${LogMsg} "** ERROR Adding Registry String: $R5 | $R6 | $R7 | $R8 **" + ${Else} + ${If} $R9 == 1 ; add to the uninstall log? + ${LogUninstall} "RegVal: $R5 | $R6 | $R7" + ${EndIf} + ${LogMsg} "Added Registry String: $R5 | $R6 | $R7 | $R8" + ${EndIf} + !endif + + Exch $R5 + Exch 4 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro WriteRegStrHKCRCall _ROOT _KEY _NAME _STR _LOG_UNINSTALL + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_ROOT}" + Push "${_KEY}" + Push "${_NAME}" + Push "${_STR}" + Push "${_LOG_UNINSTALL}" + Call WriteRegStrHKCR + !verbose pop +!macroend + +!macro un.WriteRegStrHKCRCall _ROOT _KEY _NAME _STR _LOG_UNINSTALL + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_ROOT}" + Push "${_KEY}" + Push "${_NAME}" + Push "${_STR}" + Push "${_LOG_UNINSTALL}" + Call un.WriteRegStrHKCR + !verbose pop +!macroend + +!macro un.WriteRegStrHKCR + !ifndef un.WriteRegStrHKCR + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro WriteRegStrHKCR + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +!define KEY_SET_VALUE 0x0002 +!define KEY_WOW64_64KEY 0x0100 +!ifndef HAVE_64BIT_OS + !define CREATE_KEY_SAM ${KEY_SET_VALUE} +!else + !define CREATE_KEY_SAM ${KEY_SET_VALUE}|${KEY_WOW64_64KEY} +!endif + +################################################################################ +# Macros for adding file and protocol handlers + +/** + * Writes common registry values for a handler using SHCTX. + * + * @param _KEY + * The subkey in relation to the key root. + * @param _VALOPEN + * The path and args to launch the application. + * @param _VALICON + * The path to the binary that contains the icon group for the default icon + * followed by a comma and either the icon group's resource index or the icon + * group's resource id prefixed with a minus sign + * @param _DISPNAME + * The display name for the handler. If emtpy no value will be set. + * @param _ISPROTOCOL + * Sets protocol handler specific registry values when "true". + * @param _ISDDE + * Sets DDE specific registry values when "true". + * + * $R3 = string value of the current registry key path. + * $R4 = _KEY + * $R5 = _VALOPEN + * $R6 = _VALICON + * $R7 = _DISPNAME + * $R8 = _ISPROTOCOL + * $R9 = _ISDDE + */ +!macro AddHandlerValues + + !ifndef ${_MOZFUNC_UN}AddHandlerValues + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}AddHandlerValues "!insertmacro ${_MOZFUNC_UN}AddHandlerValuesCall" + + Function ${_MOZFUNC_UN}AddHandlerValues + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Exch 4 + Exch $R5 + Exch 5 + Exch $R4 + Push $R3 + + StrCmp "$R7" "" +6 +1 + ReadRegStr $R3 SHCTX "$R4" "FriendlyTypeName" + + StrCmp "$R3" "" +1 +3 + WriteRegStr SHCTX "$R4" "" "$R7" + WriteRegStr SHCTX "$R4" "FriendlyTypeName" "$R7" + + StrCmp "$R8" "true" +1 +2 + WriteRegStr SHCTX "$R4" "URL Protocol" "" + StrCpy $R3 "" + ReadRegDWord $R3 SHCTX "$R4" "EditFlags" + StrCmp $R3 "" +1 +3 ; Only add EditFlags if a value doesn't exist + DeleteRegValue SHCTX "$R4" "EditFlags" + WriteRegDWord SHCTX "$R4" "EditFlags" 0x00000002 + + StrCmp "$R6" "" +2 +1 + WriteRegStr SHCTX "$R4\DefaultIcon" "" "$R6" + + StrCmp "$R5" "" +2 +1 + WriteRegStr SHCTX "$R4\shell\open\command" "" "$R5" + +!ifdef DDEApplication + StrCmp "$R9" "true" +1 +11 + WriteRegStr SHCTX "$R4\shell\open\ddeexec" "" "$\"%1$\",,0,0,,,," + WriteRegStr SHCTX "$R4\shell\open\ddeexec" "NoActivateHandler" "" + WriteRegStr SHCTX "$R4\shell\open\ddeexec\Application" "" "${DDEApplication}" + WriteRegStr SHCTX "$R4\shell\open\ddeexec\Topic" "" "WWW_OpenURL" + ; The ifexec key may have been added by another application so try to + ; delete it to prevent it from breaking this app's shell integration. + ; Also, IE 6 and below doesn't remove this key when it sets itself as the + ; default handler and if this key exists IE's shell integration breaks. + DeleteRegKey HKLM "$R4\shell\open\ddeexec\ifexec" + DeleteRegKey HKCU "$R4\shell\open\ddeexec\ifexec" +!endif + + ClearErrors + + Pop $R3 + Exch $R4 + Exch 5 + Exch $R5 + Exch 4 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Push "${_VALOPEN}" + Push "${_VALICON}" + Push "${_DISPNAME}" + Push "${_ISPROTOCOL}" + Push "${_ISDDE}" + Call AddHandlerValues + !verbose pop +!macroend + +!macro un.AddHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _ISDDE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Push "${_VALOPEN}" + Push "${_VALICON}" + Push "${_DISPNAME}" + Push "${_ISPROTOCOL}" + Push "${_ISDDE}" + Call un.AddHandlerValues + !verbose pop +!macroend + +!macro un.AddHandlerValues + !ifndef un.AddHandlerValues + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro AddHandlerValues + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Writes common registry values for a handler that uses DDE using SHCTX. + * + * @param _KEY + * The key name in relation to the HKCR root. SOFTWARE\Classes is + * prefixed to this value when using SHCTX. + * @param _VALOPEN + * The path and args to launch the application. + * @param _VALICON + * The path to the binary that contains the icon group for the default icon + * followed by a comma and either the icon group's resource index or the icon + * group's resource id prefixed with a minus sign + * @param _DISPNAME + * The display name for the handler. If emtpy no value will be set. + * @param _ISPROTOCOL + * Sets protocol handler specific registry values when "true". + * @param _DDE_APPNAME + * Sets DDE specific registry values when not an empty string. + * + * $R0 = storage for SOFTWARE\Classes + * $R1 = string value of the current registry key path. + * $R2 = _KEY + * $R3 = _VALOPEN + * $R4 = _VALICON + * $R5 = _DISPNAME + * $R6 = _ISPROTOCOL + * $R7 = _DDE_APPNAME + * $R8 = _DDE_DEFAULT + * $R9 = _DDE_TOPIC + */ +!macro AddDDEHandlerValues + + !ifndef ${_MOZFUNC_UN}AddDDEHandlerValues + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}AddDDEHandlerValues "!insertmacro ${_MOZFUNC_UN}AddDDEHandlerValuesCall" + + Function ${_MOZFUNC_UN}AddDDEHandlerValues + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Exch 4 + Exch $R5 + Exch 5 + Exch $R4 + Exch 6 + Exch $R3 + Exch 7 + Exch $R2 + Push $R1 + Push $R0 + + StrCpy $R0 "SOFTWARE\Classes" + StrCmp "$R5" "" +6 +1 + ReadRegStr $R1 SHCTX "$R2" "FriendlyTypeName" + + StrCmp "$R1" "" +1 +3 + WriteRegStr SHCTX "$R0\$R2" "" "$R5" + WriteRegStr SHCTX "$R0\$R2" "FriendlyTypeName" "$R5" + + StrCmp "$R6" "true" +1 +2 + WriteRegStr SHCTX "$R0\$R2" "URL Protocol" "" + StrCpy $R1 "" + ReadRegDWord $R1 SHCTX "$R0\$R2" "EditFlags" + StrCmp $R1 "" +1 +3 ; Only add EditFlags if a value doesn't exist + DeleteRegValue SHCTX "$R0\$R2" "EditFlags" + WriteRegDWord SHCTX "$R0\$R2" "EditFlags" 0x00000002 + + StrCmp "$R4" "" +2 +1 + WriteRegStr SHCTX "$R0\$R2\DefaultIcon" "" "$R4" + + WriteRegStr SHCTX "$R0\$R2\shell" "" "open" + WriteRegStr SHCTX "$R0\$R2\shell\open\command" "" "$R3" + + WriteRegStr SHCTX "$R0\$R2\shell\open\ddeexec" "" "$R8" + WriteRegStr SHCTX "$R0\$R2\shell\open\ddeexec" "NoActivateHandler" "" + WriteRegStr SHCTX "$R0\$R2\shell\open\ddeexec\Application" "" "$R7" + WriteRegStr SHCTX "$R0\$R2\shell\open\ddeexec\Topic" "" "$R9" + + ; The ifexec key may have been added by another application so try to + ; delete it to prevent it from breaking this app's shell integration. + ; Also, IE 6 and below doesn't remove this key when it sets itself as the + ; default handler and if this key exists IE's shell integration breaks. + DeleteRegKey HKLM "$R0\$R2\shell\open\ddeexec\ifexec" + DeleteRegKey HKCU "$R0\$R2\shell\open\ddeexec\ifexec" + ClearErrors + + Pop $R0 + Pop $R1 + Exch $R2 + Exch 7 + Exch $R3 + Exch 6 + Exch $R4 + Exch 5 + Exch $R5 + Exch 4 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro AddDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _DDE_APPNAME _DDE_DEFAULT _DDE_TOPIC + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Push "${_VALOPEN}" + Push "${_VALICON}" + Push "${_DISPNAME}" + Push "${_ISPROTOCOL}" + Push "${_DDE_APPNAME}" + Push "${_DDE_DEFAULT}" + Push "${_DDE_TOPIC}" + Call AddDDEHandlerValues + !verbose pop +!macroend + +!macro un.AddDDEHandlerValuesCall _KEY _VALOPEN _VALICON _DISPNAME _ISPROTOCOL _DDE_APPNAME _DDE_DEFAULT _DDE_TOPIC + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Push "${_VALOPEN}" + Push "${_VALICON}" + Push "${_DISPNAME}" + Push "${_ISPROTOCOL}" + Push "${_DDE_APPNAME}" + Push "${_DDE_DEFAULT}" + Push "${_DDE_TOPIC}" + Call un.AddDDEHandlerValues + !verbose pop +!macroend + +!macro un.AddDDEHandlerValues + !ifndef un.AddDDEHandlerValues + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro AddDDEHandlerValues + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + + +################################################################################ +# Macros for handling DLL registration + +!macro RegisterDLL DLL + + ; The x64 regsvr32.exe registers x86 DLL's properly on Windows Vista and above + ; (not on Windows XP http://support.microsoft.com/kb/282747) so just use it + ; when installing on an x64 systems even when installing an x86 application. + ${If} ${RunningX64} + ${DisableX64FSRedirection} + ExecWait '"$SYSDIR\regsvr32.exe" /s "${DLL}"' + ${EnableX64FSRedirection} + ${Else} + RegDLL "${DLL}" + ${EndIf} + +!macroend + +!macro UnregisterDLL DLL + + ; The x64 regsvr32.exe registers x86 DLL's properly on Windows Vista and above + ; (not on Windows XP http://support.microsoft.com/kb/282747) so just use it + ; when installing on an x64 systems even when installing an x86 application. + ${If} ${RunningX64} + ${DisableX64FSRedirection} + ExecWait '"$SYSDIR\regsvr32.exe" /s /u "${DLL}"' + ${EnableX64FSRedirection} + ${Else} + UnRegDLL "${DLL}" + ${EndIf} + +!macroend + +!define RegisterDLL `!insertmacro RegisterDLL` +!define UnregisterDLL `!insertmacro UnregisterDLL` + + +################################################################################ +# Macros for retrieving existing install paths + +/** + * Finds a second installation of the application so we can make informed + * decisions about registry operations. This uses SHCTX to determine the + * registry hive so you must call SetShellVarContext first. + * + * @param _KEY + * The registry subkey (typically this will be Software\Mozilla). + * @return _RESULT + * false if a second install isn't found, path to the main exe if a + * second install is found. + * + * $R3 = stores the long path to $INSTDIR + * $R4 = counter for the outer loop's EnumRegKey + * $R5 = return value from ReadRegStr and RemoveQuotesFromPath + * $R6 = return value from GetParent + * $R7 = return value from the loop's EnumRegKey + * $R8 = storage for _KEY + * $R9 = _KEY and _RESULT + */ +!macro GetSecondInstallPath + + !ifndef ${_MOZFUNC_UN}GetSecondInstallPath + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetParent + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}GetSecondInstallPath "!insertmacro ${_MOZFUNC_UN}GetSecondInstallPathCall" + + Function ${_MOZFUNC_UN}GetSecondInstallPath + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + Push $R3 + + Push $INSTDIR + Call ${_MOZFUNC_UN}GetLongPath + Pop $R3 + + StrCpy $R4 0 ; set the counter for the loop to 0 + StrCpy $R8 "$R9" ; Registry key path to search + StrCpy $R9 "false" ; default return value + + loop: + EnumRegKey $R7 SHCTX $R8 $R4 + StrCmp $R7 "" end +1 ; if empty there are no more keys to enumerate + IntOp $R4 $R4 + 1 ; increment the loop's counter + ClearErrors + ReadRegStr $R5 SHCTX "$R8\$R7\bin" "PathToExe" + IfErrors loop + + Push $R5 + Call ${_MOZFUNC_UN}RemoveQuotesFromPath + Pop $R5 + + IfFileExists "$R5" +1 loop + Push $R5 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R5 + ${${_MOZFUNC_UN}GetParent} "$R5" $R6 + StrCmp "$R6" "$R3" loop +1 + StrCmp "$R6\${FileMainEXE}" "$R5" +1 loop + StrCpy $R9 "$R5" + + end: + ClearErrors + + Pop $R3 + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro GetSecondInstallPathCall _KEY _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call GetSecondInstallPath + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.GetSecondInstallPathCall _KEY _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call un.GetSecondInstallPath + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.GetSecondInstallPath + !ifndef un.GetSecondInstallPath + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro GetSecondInstallPath + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Finds an existing installation path for the application based on the + * application's executable name so we can default to using this path for the + * install. If there is zero or more than one installation of the application + * then we default to the default installation path. This uses SHCTX to + * determine the registry hive to read from so you must call SetShellVarContext + * first. + * + * @param _KEY + * The registry subkey (typically this will be Software\Mozilla\App Name). + * @return _RESULT + * false if a single install location for this app name isn't found, + * path to the install directory if a single install location is found. + * + * $R5 = counter for the loop's EnumRegKey + * $R6 = return value from EnumRegKey + * $R7 = return value from ReadRegStr + * $R8 = storage for _KEY + * $R9 = _KEY and _RESULT + */ +!macro GetSingleInstallPath + + !ifndef ${_MOZFUNC_UN}GetSingleInstallPath + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetParent + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}GetSingleInstallPath "!insertmacro ${_MOZFUNC_UN}GetSingleInstallPathCall" + + Function ${_MOZFUNC_UN}GetSingleInstallPath + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + + StrCpy $R8 $R9 + StrCpy $R9 "false" + StrCpy $R5 0 ; set the counter for the loop to 0 + + loop: + ClearErrors + EnumRegKey $R6 SHCTX $R8 $R5 + IfErrors cleanup + StrCmp $R6 "" cleanup +1 ; if empty there are no more keys to enumerate + IntOp $R5 $R5 + 1 ; increment the loop's counter + ClearErrors + ReadRegStr $R7 SHCTX "$R8\$R6\Main" "PathToExe" + IfErrors loop + Push $R7 + Call ${_MOZFUNC_UN}RemoveQuotesFromPath + Pop $R7 + GetFullPathName $R7 "$R7" + IfErrors loop + + StrCmp "$R9" "false" +1 +3 + StrCpy $R9 "$R7" + GoTo Loop + + StrCpy $R9 "false" + + cleanup: + StrCmp $R9 "false" end +1 + Push $R9 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R9 + ${${_MOZFUNC_UN}GetParent} "$R9" $R9 + + end: + ClearErrors + + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro GetSingleInstallPathCall _KEY _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call GetSingleInstallPath + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.GetSingleInstallPathCall _KEY _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call un.GetSingleInstallPath + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.GetSingleInstallPath + !ifndef un.GetSingleInstallPath + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro GetSingleInstallPath + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + + +################################################################################ +# Macros for working with the file system + +/** + * Attempts to delete a file if it exists. This will fail if the file is in use. + * + * @param _FILE + * The path to the file that is to be deleted. + */ +!macro DeleteFile _FILE + ${If} ${FileExists} "${_FILE}" + Delete "${_FILE}" + ${EndIf} +!macroend +!define DeleteFile "!insertmacro DeleteFile" + +/** + * Removes a directory if it exists and is empty. + * + * @param _DIR + * The path to the directory that is to be removed. + */ +!macro RemoveDir _DIR + ${If} ${FileExists} "${_DIR}" + RmDir "${_DIR}" + ${EndIf} +!macroend +!define RemoveDir "!insertmacro RemoveDir" + +/** + * Checks whether it is possible to create and delete a directory and a file in + * the install directory. Creation and deletion of files and directories are + * checked since a user may have rights for one and not the other. If creation + * and deletion of a file and a directory are successful this macro will return + * true... if not, this it return false. + * + * @return _RESULT + * true if files and directories can be created and deleted in the + * install directory otherwise false. + * + * $R8 = temporary filename in the installation directory returned from + * GetTempFileName. + * $R9 = _RESULT + */ +!macro CanWriteToInstallDir + + !ifndef ${_MOZFUNC_UN}CanWriteToInstallDir + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}CanWriteToInstallDir "!insertmacro ${_MOZFUNC_UN}CanWriteToInstallDirCall" + + Function ${_MOZFUNC_UN}CanWriteToInstallDir + Push $R9 + Push $R8 + + StrCpy $R9 "true" + + ; IfFileExists returns false for $INSTDIR when $INSTDIR is the root of a + ; UNC path so always try to create $INSTDIR + CreateDirectory "$INSTDIR\" + GetTempFileName $R8 "$INSTDIR\" + + ${Unless} ${FileExists} $R8 ; Can files be created? + StrCpy $R9 "false" + Goto done + ${EndUnless} + + Delete $R8 + ${If} ${FileExists} $R8 ; Can files be deleted? + StrCpy $R9 "false" + Goto done + ${EndIf} + + CreateDirectory $R8 + ${Unless} ${FileExists} $R8 ; Can directories be created? + StrCpy $R9 "false" + Goto done + ${EndUnless} + + RmDir $R8 + ${If} ${FileExists} $R8 ; Can directories be deleted? + StrCpy $R9 "false" + Goto done + ${EndIf} + + done: + + RmDir "$INSTDIR\" ; Only remove $INSTDIR if it is empty + ClearErrors + + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro CanWriteToInstallDirCall _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call CanWriteToInstallDir + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.CanWriteToInstallDirCall _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.CanWriteToInstallDir + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.CanWriteToInstallDir + !ifndef un.CanWriteToInstallDir + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro CanWriteToInstallDir + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Checks whether there is sufficient free space available for the installation + * directory using GetDiskFreeSpaceExW which respects disk quotas. This macro + * will calculate the size of all sections that are selected, compare that with + * the free space available, and if there is sufficient free space it will + * return true... if not, it will return false. + * + * @return _RESULT + * "true" if there is sufficient free space otherwise "false". + * + * $R5 = return value from SectionGetSize + * $R6 = return value from SectionGetFlags + * return value from an 'and' comparison of SectionGetFlags (1=selected) + * return value for lpFreeBytesAvailable from GetDiskFreeSpaceExW + * return value for System::Int64Op $R6 / 1024 + * return value for System::Int64Op $R6 > $R8 + * $R7 = the counter for enumerating the sections + * the temporary file name for the directory created under $INSTDIR passed + * to GetDiskFreeSpaceExW. + * $R8 = sum in KB of all selected sections + * $R9 = _RESULT + */ +!macro CheckDiskSpace + + !ifndef ${_MOZFUNC_UN}CheckDiskSpace + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}CheckDiskSpace "!insertmacro ${_MOZFUNC_UN}CheckDiskSpaceCall" + + Function ${_MOZFUNC_UN}CheckDiskSpace + Push $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + + ClearErrors + + StrCpy $R9 "true" ; default return value + StrCpy $R8 "0" ; sum in KB of all selected sections + StrCpy $R7 "0" ; counter for enumerating sections + + ; Enumerate the sections and sum up the sizes of the sections that are + ; selected. + SectionGetFlags $R7 $R6 + IfErrors +7 +1 + IntOp $R6 ${SF_SELECTED} & $R6 + IntCmp $R6 0 +3 +1 +1 + SectionGetSize $R7 $R5 + IntOp $R8 $R8 + $R5 + IntOp $R7 $R7 + 1 + GoTo -7 + + ; The directory passed to GetDiskFreeSpaceExW must exist for the call to + ; succeed. Since the CanWriteToInstallDir macro is called prior to this + ; macro the call to CreateDirectory will always succeed. + + ; IfFileExists returns false for $INSTDIR when $INSTDIR is the root of a + ; UNC path so always try to create $INSTDIR + CreateDirectory "$INSTDIR\" + GetTempFileName $R7 "$INSTDIR\" + Delete "$R7" + CreateDirectory "$R7" + + System::Call 'kernel32::GetDiskFreeSpaceExW(w, *l, *l, *l) i(R7, .R6, ., .) .' + + ; Convert to KB for comparison with $R8 which is in KB + System::Int64Op $R6 / 1024 + Pop $R6 + + System::Int64Op $R6 > $R8 + Pop $R6 + + IntCmp $R6 1 end +1 +1 + StrCpy $R9 "false" + + end: + RmDir "$R7" + RmDir "$INSTDIR\" ; Only remove $INSTDIR if it is empty + + ClearErrors + + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro CheckDiskSpaceCall _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call CheckDiskSpace + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.CheckDiskSpaceCall _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.CheckDiskSpace + Pop ${_RESULT} + !verbose pop +!macroend + +!macro un.CheckDiskSpace + !ifndef un.CheckDiskSpace + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro CheckDiskSpace + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** +* Returns the path found within a passed in string. The path is quoted or not +* with the exception of an unquoted non 8dot3 path without arguments that is +* also not a DefaultIcon path, is a 8dot3 path or not, has command line +* arguments, or is a registry DefaultIcon path (e.g. ,# where # +* is the icon's resuorce id). The string does not need to be a valid path or +* exist. It is up to the caller to pass in a string of one of the forms noted +* above and to verify existence if necessary. +* +* Examples: +* In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE -flag "%1" +* In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE,0 +* In: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE +* In: "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE" +* In: "C:\PROGRA~1\MOZILL~1\FIREFOX.EXE" -flag "%1" +* Out: C:\PROGRA~1\MOZILL~1\FIREFOX.EXE +* +* In: "C:\Program Files\Mozilla Firefox\firefox.exe" -flag "%1" +* In: C:\Program Files\Mozilla Firefox\firefox.exe,0 +* In: "C:\Program Files\Mozilla Firefox\firefox.exe" +* Out: C:\Program Files\Mozilla Firefox\firefox.exe +* +* @param _IN_PATH +* The string containing the path. +* @param _OUT_PATH +* The register to store the path to. +* +* $R7 = counter for the outer loop's EnumRegKey +* $R8 = return value from ReadRegStr +* $R9 = _IN_PATH and _OUT_PATH +*/ +!macro GetPathFromString + + !ifndef ${_MOZFUNC_UN}GetPathFromString + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}GetPathFromString "!insertmacro ${_MOZFUNC_UN}GetPathFromStringCall" + + Function ${_MOZFUNC_UN}GetPathFromString + Exch $R9 + Push $R8 + Push $R7 + + StrCpy $R7 0 ; Set the counter to 0. + + ; Handle quoted paths with arguments. + StrCpy $R8 $R9 1 ; Copy the first char. + StrCmp $R8 '"' +2 +1 ; Is it a "? + StrCmp $R8 "'" +1 +9 ; Is it a '? + StrCpy $R9 $R9 "" 1 ; Remove the first char. + IntOp $R7 $R7 + 1 ; Increment the counter. + StrCpy $R8 $R9 1 $R7 ; Starting from the counter copy the next char. + StrCmp $R8 "" end +1 ; Are there no more chars? + StrCmp $R8 '"' +2 +1 ; Is it a " char? + StrCmp $R8 "'" +1 -4 ; Is it a ' char? + StrCpy $R9 $R9 $R7 ; Copy chars up to the counter. + GoTo end + + ; Handle DefaultIcon paths. DefaultIcon paths are not quoted and end with + ; a , and a number. + IntOp $R7 $R7 - 1 ; Decrement the counter. + StrCpy $R8 $R9 1 $R7 ; Copy one char from the end minus the counter. + StrCmp $R8 '' +4 +1 ; Are there no more chars? + StrCmp $R8 ',' +1 -3 ; Is it a , char? + StrCpy $R9 $R9 $R7 ; Copy chars up to the end minus the counter. + GoTo end + + ; Handle unquoted paths with arguments. An unquoted path with arguments + ; must be an 8dot3 path. + StrCpy $R7 -1 ; Set the counter to -1 so it will start at 0. + IntOp $R7 $R7 + 1 ; Increment the counter. + StrCpy $R8 $R9 1 $R7 ; Starting from the counter copy the next char. + StrCmp $R8 "" end +1 ; Are there no more chars? + StrCmp $R8 " " +1 -3 ; Is it a space char? + StrCpy $R9 $R9 $R7 ; Copy chars up to the counter. + + end: + ClearErrors + + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro GetPathFromStringCall _IN_PATH _OUT_PATH + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_IN_PATH}" + Call GetPathFromString + Pop ${_OUT_PATH} + !verbose pop +!macroend + +!macro un.GetPathFromStringCall _IN_PATH _OUT_PATH + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_IN_PATH}" + Call un.GetPathFromString + Pop ${_OUT_PATH} + !verbose pop +!macroend + +!macro un.GetPathFromString + !ifndef un.GetPathFromString + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro GetPathFromString + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Removes the quotes from each end of a string if present. + * + * inputs: + * @0 = _IN_PATH - The string containing the path. + * outputs: + * @0 = _OUT_PATH - The register to store the long path. + * internal: + * $R7 = storage for single character comparison + * $R8 = storage for _IN_PATH + * $R9 = _IN_PATH and _OUT_PATH + */ +!macro RemoveQuotesFromPath UN +Function ${UN}RemoveQuotesFromPath + Exch $R9 + Push $R8 + Push $R7 + + StrCpy $R7 "$R9" 1 + StrCmp $R7 "$\"" +1 +2 + StrCpy $R9 "$R9" "" 1 + + StrCpy $R7 "$R9" "" -1 + StrCmp $R7 "$\"" +1 +2 + StrCpy $R9 "$R9" -1 + + Pop $R7 + Pop $R8 + Exch $R9 +FunctionEnd +!macroend + +!insertmacro RemoveQuotesFromPath "" +!insertmacro RemoveQuotesFromPath "un." + +/** + * Returns the long path for an existing file or directory. GetLongPathNameW + * may not be available on Win95 if Microsoft Layer for Unicode is not + * installed and GetFullPathName only returns a long path for the last file or + * directory that doesn't end with a \ in the path that it is passed. If the + * path does not exist on the file system this will return an empty string. To + * provide a consistent result trailing back-slashes are always removed. + * + * Note: 1024 used by GetLongPathNameW is the maximum NSIS string length. + * + * @param _IN_PATH + * The string containing the path. + * @param _OUT_PATH + * The register to store the long path. + * + * $R4 = counter value when the previous \ was found + * $R5 = directory or file name found during loop + * $R6 = return value from GetLongPathNameW and loop counter + * $R7 = long path from GetLongPathNameW and single char from path for comparison + * $R8 = storage for _IN_PATH + * $R9 = _IN_PATH _OUT_PATH + */ +!macro GetLongPath UN +Function ${UN}GetLongPath + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + + ClearErrors + + GetFullPathName $R8 "$R9" + IfErrors end_GetLongPath +1 ; If the path doesn't exist return an empty string. + + System::Call 'kernel32::GetLongPathNameW(w R8, w .R7, i 1024)i .R6' + StrCmp "$R7" "" +4 +1 ; Empty string when GetLongPathNameW is not present. + StrCmp $R6 0 +3 +1 ; Should never equal 0 since the path exists. + StrCpy $R9 "$R7" + GoTo end_GetLongPath + + ; Do it the hard way. + StrCpy $R4 0 ; Stores the position in the string of the last \ found. + StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. + + loop_GetLongPath: + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R7 $R8 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R7 "" +2 +1 ; Are there no more chars? + StrCmp $R7 "\" +1 -3 ; Is it a \? + + ; Copy chars starting from the previously found \ to the counter. + StrCpy $R5 $R8 $R6 $R4 + + ; If this is the first \ found we want to swap R9 with R5 so a \ will + ; be appended to the drive letter and colon (e.g. C: will become C:\). + StrCmp $R4 0 +1 +3 + StrCpy $R9 $R5 + StrCpy $R5 "" + + GetFullPathName $R9 "$R9\$R5" + + StrCmp $R7 "" end_GetLongPath +1 ; Are there no more chars? + + ; Store the counter for the current \ and prefix it for StrCpy operations. + StrCpy $R4 "+$R6" + IntOp $R6 $R6 + 1 ; Increment the counter so we skip over the \. + StrCpy $R8 $R8 "" $R6 ; Copy chars starting from the counter to the end. + StrCpy $R6 -1 ; Reset the counter to -1 so it will start over at 0. + GoTo loop_GetLongPath + + end_GetLongPath: + ; If there is a trailing slash remove it + StrCmp $R9 "" +4 +1 + StrCpy $R8 "$R9" "" -1 + StrCmp $R8 "\" +1 +2 + StrCpy $R9 "$R9" -1 + + ClearErrors + + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 +FunctionEnd +!macroend + +!insertmacro GetLongPath "" +!insertmacro GetLongPath "un." + +################################################################################ +# Macros for cleaning up the registry and file system + +/** + * Removes registry keys that reference this install location and for paths that + * no longer exist. This uses SHCTX to determine the registry hive so you must + * call SetShellVarContext first. + * + * @param _KEY + * The registry subkey (typically this will be Software\Mozilla). + * + * XXXrstrong - there is the potential for Key: Software/Mozilla/AppName, + * ValueName: CurrentVersion, ValueData: AppVersion to reference a key that is + * no longer available due to this cleanup. This should be no worse than prior + * to this reg cleanup since the referenced key would be for an app that is no + * longer installed on the system. + * + * $R0 = on x64 systems set to 'false' at the beginning of the macro when + * enumerating the x86 registry view and set to 'true' when enumerating + * the x64 registry view. + * $R1 = stores the long path to $INSTDIR + * $R2 = return value from the stack from the GetParent and GetLongPath macros + * $R3 = return value from the outer loop's EnumRegKey + * $R4 = return value from the inner loop's EnumRegKey + * $R5 = return value from ReadRegStr + * $R6 = counter for the outer loop's EnumRegKey + * $R7 = counter for the inner loop's EnumRegKey + * $R8 = return value from the stack from the RemoveQuotesFromPath macro + * $R9 = _KEY + */ +!macro RegCleanMain + + !ifndef ${_MOZFUNC_UN}RegCleanMain + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetParent + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}RegCleanMain "!insertmacro ${_MOZFUNC_UN}RegCleanMainCall" + + Function ${_MOZFUNC_UN}RegCleanMain + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + Push $R3 + Push $R2 + Push $R1 + Push $R0 + + Push $INSTDIR + Call ${_MOZFUNC_UN}GetLongPath + Pop $R1 + + StrCpy $R6 0 ; set the counter for the outer loop to 0 + + ${If} ${RunningX64} + StrCpy $R0 "false" + ; Set the registry to the 32 bit registry for 64 bit installations or to + ; the 64 bit registry for 32 bit installations at the beginning so it can + ; easily be set back to the correct registry view when finished. + !ifdef HAVE_64BIT_OS + SetRegView 32 + !else + SetRegView 64 + !endif + ${EndIf} + + outerloop: + EnumRegKey $R3 SHCTX $R9 $R6 + StrCmp $R3 "" end +1 ; if empty there are no more keys to enumerate + IntOp $R6 $R6 + 1 ; increment the outer loop's counter + ClearErrors + ReadRegStr $R5 SHCTX "$R9\$R3\bin" "PathToExe" + IfErrors 0 outercontinue + StrCpy $R7 0 ; set the counter for the inner loop to 0 + + innerloop: + EnumRegKey $R4 SHCTX "$R9\$R3" $R7 + StrCmp $R4 "" outerloop +1 ; if empty there are no more keys to enumerate + IntOp $R7 $R7 + 1 ; increment the inner loop's counter + ClearErrors + ReadRegStr $R5 SHCTX "$R9\$R3\$R4\Main" "PathToExe" + IfErrors innerloop + + Push $R5 + Call ${_MOZFUNC_UN}RemoveQuotesFromPath + Pop $R8 + ${${_MOZFUNC_UN}GetParent} "$R8" $R2 + Push $R2 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R2 + IfFileExists "$R2" +1 innerloop + StrCmp "$R2" "$R1" +1 innerloop + + ClearErrors + DeleteRegKey SHCTX "$R9\$R3\$R4" + IfErrors innerloop + IntOp $R7 $R7 - 1 ; decrement the inner loop's counter when the key is deleted successfully. + ClearErrors + DeleteRegKey /ifempty SHCTX "$R9\$R3" + IfErrors innerloop outerdecrement + + outercontinue: + Push $R5 + Call ${_MOZFUNC_UN}RemoveQuotesFromPath + Pop $R8 + ${${_MOZFUNC_UN}GetParent} "$R8" $R2 + Push $R2 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R2 + IfFileExists "$R2" +1 outerloop + StrCmp "$R2" "$R1" +1 outerloop + + ClearErrors + DeleteRegKey SHCTX "$R9\$R3" + IfErrors outerloop + + outerdecrement: + IntOp $R6 $R6 - 1 ; decrement the outer loop's counter when the key is deleted successfully. + ; Attempt to delete Software/Zotero. There is nothing we can do if the + ; user lacks permissions to delete this key. + DeleteRegKey /ifempty SHCTX "$R9" + ClearErrors + GoTo outerloop + + end: + ${If} ${RunningX64} + ${AndIf} "$R0" == "false" + ; Set the registry to the correct view. + !ifdef HAVE_64BIT_OS + SetRegView 64 + !else + SetRegView 32 + !endif + + StrCpy $R6 0 ; set the counter for the outer loop to 0 + StrCpy $R0 "true" + GoTo outerloop + ${EndIf} + + ClearErrors + + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro RegCleanMainCall _KEY + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call RegCleanMain + !verbose pop +!macroend + +!macro un.RegCleanMainCall _KEY + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_KEY}" + Call un.RegCleanMain + !verbose pop +!macroend + +!macro un.RegCleanMain + !ifndef un.RegCleanMain + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro RegCleanMain + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Searches for registry keys under \Software\Windows\CurrentVersion\Uninstall + * that reference this install location in both the 32 bit and 64 bit registry + * view. This macro uses SHCTX to determine the registry hive so you must call + * SetShellVarContext first. + * + * inputs: + * @0 = This determines which keys form a match. It will be overwritten on return. + * @1 = counter. Set to 0 on first call + * outputs: + * @0 = Set to registry key on every return. + * @1 = counter. Gets set so that you can call function again for another + * search result. Sets to 0 when all keys are exhausted. + * error flag: This flag will be set when no results were found + * internal: + * $R4 = stores the long path to $INSTDIR + * $R5 = return value from ReadRegStr + * $R6 = string for the base reg key + * $R7 = return value from EnumRegKey + * $R8 = Boolean value. True means a result has been found + * $R9 = return value from the stack from the RemoveQuotesFromPath and + GetLongPath macros + */ +!macro IterateUninstallKeys UN +Function ${UN}IterateUninstallKeys + Exch $0 + Exch 1 + Exch $1 + Push $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + + Push $0 + Call ${UN}GetLongPath + Pop $R4 + StrCpy $R6 "Software\Microsoft\Windows\CurrentVersion\Uninstall" + StrCpy $R7 "" + StrCpy $R8 "False" + + loop: + EnumRegKey $R7 SHCTX $R6 $1 + StrCmp $R7 "" end +1 + IntOp $1 $1 + 1 ; Increment the counter + ClearErrors + ReadRegStr $R5 SHCTX "$R6\$R7" "InstallLocation" + IfErrors loop + Push $R5 + Call ${UN}RemoveQuotesFromPath + Call ${UN}GetLongPath + Pop $R9 + StrCmp "$R9" "$R4" +1 loop + StrCpy $R8 "True" + + end: + ClearErrors + StrCmp $R8 "False" 0 +2 + SetErrors + StrCpy $0 "$R6\$R7" + + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Pop $R9 + Exch $1 + Exch 1 + Exch $0 +FunctionEnd +!macroend + +!insertmacro IterateUninstallKeys "" +!insertMacro IterateUninstallKeys "un." + +/** + * Removes all registry keys from \Software\Windows\CurrentVersion\Uninstall + * that reference this install location in both the 32 bit and 64 bit registry + * view. This macro uses SHCTX to determine the registry hive so you must call + * SetShellVarContext first. + * + * input: + * INSTDIR = used by IterateUninstallKeys to determine what needs to be deleted. + */ +!macro RegCleanUninstall + + !ifndef ${_MOZFUNC_UN}RegCleanUninstall + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}RegCleanUninstall "!insertmacro ${_MOZFUNC_UN}RegCleanUninstallCall" + + Function ${_MOZFUNC_UN}RegCleanUninstall + Push $1 + Push $0 + + StrCpy $0 "0" + + loop: + Push $0 + Push $INSTDIR + Call ${_MOZFUNC_UN}IterateUninstallKeys + ; The error flag means no key was found. + IfErrors done + Pop $1 + Pop $0 + DeleteRegKey SHCTX "$1" + IfErrors loop + IntOp $0 $0 - 1 ; Decrement the counter on successful deletion + Goto loop + done: + Pop $Trash + Pop $Trash + + Pop $0 + Pop $1 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro RegCleanUninstallCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call RegCleanUninstall + !verbose pop +!macroend + +!macro un.RegCleanUninstallCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.RegCleanUninstall + !verbose pop +!macroend + +!macro un.RegCleanUninstall + !ifndef un.RegCleanUninstall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro RegCleanUninstall + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Removes an application specific handler registry key under Software\Classes + * for both HKCU and HKLM when its open command refers to this install + * location or the install location doesn't exist. + * + * @param _HANDLER_NAME + * The registry name for the handler. + * + * $R7 = stores the long path to the $INSTDIR + * $R8 = stores the path to the open command's parent directory + * $R9 = _HANDLER_NAME + */ +!macro RegCleanAppHandler + + !ifndef ${_MOZFUNC_UN}RegCleanAppHandler + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetParent + !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}RegCleanAppHandler "!insertmacro ${_MOZFUNC_UN}RegCleanAppHandlerCall" + + Function ${_MOZFUNC_UN}RegCleanAppHandler + Exch $R9 + Push $R8 + Push $R7 + + ClearErrors + ReadRegStr $R8 HKCU "Software\Classes\$R9\shell\open\command" "" + IfErrors next +1 + ${${_MOZFUNC_UN}GetPathFromString} "$R8" $R8 + ${${_MOZFUNC_UN}GetParent} "$R8" $R8 + IfFileExists "$R8" +3 +1 + DeleteRegKey HKCU "Software\Classes\$R9" + GoTo next + + Push $R8 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R8 + Push $INSTDIR + Call ${_MOZFUNC_UN}GetLongPath + Pop $R7 + StrCmp "$R7" "$R8" +1 next + DeleteRegKey HKCU "Software\Classes\$R9" + + next: + ReadRegStr $R8 HKLM "Software\Classes\$R9\shell\open\command" "" + IfErrors end + ${${_MOZFUNC_UN}GetPathFromString} "$R8" $R8 + ${${_MOZFUNC_UN}GetParent} "$R8" $R8 + IfFileExists "$R8" +3 +1 + DeleteRegKey HKLM "Software\Classes\$R9" + GoTo end + + Push $R8 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R8 + Push $INSTDIR + Call ${_MOZFUNC_UN}GetLongPath + Pop $R7 + StrCmp "$R7" "$R8" +1 end + DeleteRegKey HKLM "Software\Classes\$R9" + + end: + + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro RegCleanAppHandlerCall _HANDLER_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_HANDLER_NAME}" + Call RegCleanAppHandler + !verbose pop +!macroend + +!macro un.RegCleanAppHandlerCall _HANDLER_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_HANDLER_NAME}" + Call un.RegCleanAppHandler + !verbose pop +!macroend + +!macro un.RegCleanAppHandler + !ifndef un.RegCleanAppHandler + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro RegCleanAppHandler + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Cleans up the registry for a protocol handler when its open command + * refers to this install location. For HKCU the registry key is deleted + * and for HKLM the values set by the application are deleted. + * + * @param _HANDLER_NAME + * The registry name for the handler. + * + * $R7 = stores the long path to $INSTDIR + * $R8 = stores the the long path to the open command's parent directory + * $R9 = _HANDLER_NAME + */ +!macro un.RegCleanProtocolHandler + + !ifndef un.RegCleanProtocolHandler + !insertmacro un.GetParent + !insertmacro un.GetPathFromString + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define un.RegCleanProtocolHandler "!insertmacro un.RegCleanProtocolHandlerCall" + + Function un.RegCleanProtocolHandler + Exch $R9 + Push $R8 + Push $R7 + + ReadRegStr $R8 HKCU "Software\Classes\$R9\shell\open\command" "" + Push $INSTDIR + Call un.GetLongPath + Pop $R7 + + StrCmp "$R8" "" next +1 + ${un.GetPathFromString} "$R8" $R8 + ${un.GetParent} "$R8" $R8 + Push $R8 + Call un.GetLongPath + Pop $R8 + StrCmp "$R7" "$R8" +1 next + DeleteRegKey HKCU "Software\Classes\$R9" + + next: + ReadRegStr $R8 HKLM "Software\Classes\$R9\shell\open\command" "" + StrCmp "$R8" "" end +1 + Push $INSTDIR + Call un.GetLongPath + Pop $R7 + ${un.GetPathFromString} "$R8" $R8 + ${un.GetParent} "$R8" $R8 + Push $R8 + Call un.GetLongPath + Pop $R8 + StrCmp "$R7" "$R8" +1 end + DeleteRegValue HKLM "Software\Classes\$R9\DefaultIcon" "" + DeleteRegValue HKLM "Software\Classes\$R9\shell\open" "" + DeleteRegValue HKLM "Software\Classes\$R9\shell\open\command" "" + DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec" "" + DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Application" "" + DeleteRegValue HKLM "Software\Classes\$R9\shell\ddeexec\Topic" "" + + end: + + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro un.RegCleanProtocolHandlerCall _HANDLER_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_HANDLER_NAME}" + Call un.RegCleanProtocolHandler + !verbose pop +!macroend + +/** + * Cleans up the registry for a file handler when the passed in value equals + * the default value for the file handler. For HKCU the registry key is deleted + * and for HKLM the default value is deleted. + * + * @param _HANDLER_NAME + * The registry name for the handler. + * @param _DEFAULT_VALUE + * The value to check for against the handler's default value. + * + * $R6 = stores the long path to $INSTDIR + * $R7 = _DEFAULT_VALUE + * $R9 = _HANDLER_NAME + */ +!macro RegCleanFileHandler + + !ifndef ${_MOZFUNC_UN}RegCleanFileHandler + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetParent + !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}RegCleanFileHandler "!insertmacro ${_MOZFUNC_UN}RegCleanFileHandlerCall" + + Function ${_MOZFUNC_UN}RegCleanFileHandler + Exch $R9 + Exch 1 + Exch $R8 + Push $R7 + + ReadRegStr $R7 HKCU "Software\Classes\$R9" "" + StrCmp "$R7" "$R8" +1 +2 + DeleteRegKey HKCU "Software\Classes\$R9" + + ReadRegStr $R7 HKLM "Software\Classes\$R9" "" + StrCmp "$R7" "$R8" +1 +2 + DeleteRegValue HKLM "Software\Classes\$R9" "" + + ClearErrors + + Pop $R7 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro RegCleanFileHandlerCall _HANDLER_NAME _DEFAULT_VALUE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_DEFAULT_VALUE}" + Push "${_HANDLER_NAME}" + Call RegCleanFileHandler + !verbose pop +!macroend + +!macro un.RegCleanFileHandlerCall _HANDLER_NAME _DEFAULT_VALUE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_DEFAULT_VALUE}" + Push "${_HANDLER_NAME}" + Call un.RegCleanFileHandler + !verbose pop +!macroend + +!macro un.RegCleanFileHandler + !ifndef un.RegCleanFileHandler + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro RegCleanFileHandler + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Checks if a handler's open command points to this installation directory. + * Uses SHCTX to determine the registry hive (e.g. HKLM or HKCU) to check. + * + * @param _HANDLER_NAME + * The registry name for the handler. + * @param _RESULT + * true if it is the handler's open command points to this + * installation directory and false if it does not. + * + * $R7 = stores the value of the open command and the path macros return values + * $R8 = stores the handler's registry key name + * $R9 = _DEFAULT_VALUE and _RESULT + */ +!macro IsHandlerForInstallDir + + !ifndef ${_MOZFUNC_UN}IsHandlerForInstallDir + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetParent + !insertmacro ${_MOZFUNC_UN_TMP}GetPathFromString + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}IsHandlerForInstallDir "!insertmacro ${_MOZFUNC_UN}IsHandlerForInstallDirCall" + + Function ${_MOZFUNC_UN}IsHandlerForInstallDir + Exch $R9 + Push $R8 + Push $R7 + + StrCpy $R8 "$R9" + StrCpy $R9 "false" + ReadRegStr $R7 SHCTX "Software\Classes\$R8\shell\open\command" "" + + ${If} $R7 != "" + ${GetPathFromString} "$R7" $R7 + ${GetParent} "$R7" $R7 + Push $R7 + Call GetLongPath + Pop $R7 + ${If} $R7 == $INSTDIR + StrCpy $R9 "true" + ${EndIf} + ${EndIf} + + ClearErrors + + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro IsHandlerForInstallDirCall _HANDLER_NAME _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_HANDLER_NAME}" + Call IsHandlerForInstallDir + Pop "${_RESULT}" + !verbose pop +!macroend + +!macro un.IsHandlerForInstallDirCall _HANDLER_NAME _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_HANDLER_NAME}" + Call un.IsHandlerForInstallDir + Pop "${_RESULT}" + !verbose pop +!macroend + +!macro un.IsHandlerForInstallDir + !ifndef un.IsHandlerForInstallDir + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro IsHandlerForInstallDir + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * If present removes the updates directory located in the profile's local + * directory for this installation. + * + * @param _REL_PROFILE_PATH + * The relative path to the profile directory from $LOCALAPPDATA. + * + * $R4 = various path values. + * $R5 = length of the long path to $PROGRAMFILES + * $R6 = length of the long path to $INSTDIR + * $R7 = long path to $PROGRAMFILES + * $R8 = long path to $INSTDIR + * $R9 = _REL_PROFILE_PATH + */ +!macro CleanUpdatesDir + + !ifndef ${_MOZFUNC_UN}CleanUpdatesDir + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}CleanUpdatesDir "!insertmacro ${_MOZFUNC_UN}CleanUpdatesDirCall" + + Function ${_MOZFUNC_UN}CleanUpdatesDir + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + + StrCmp $R9 "" end +1 ; The relative path to the app's profiles is required + Push $INSTDIR + Call ${_MOZFUNC_UN}GetLongPath + Pop $R8 + StrCmp $R8 "" end +1 + Push $PROGRAMFILES + Call ${_MOZFUNC_UN}GetLongPath + Pop $R7 + StrCmp $R7 "" end +1 + + StrLen $R6 "$R8" + StrLen $R5 "$R7" + ; Only continue If the length of $INSTDIR is greater than the length of + ; $PROGRAMFILES + IntCmp $R6 $R5 end end +1 + + ; Copy from the start of $INSTDIR the length of $PROGRAMFILES + StrCpy $R4 "$R8" $R5 + StrCmp "$R4" "$R7" +1 end ; Check if $INSTDIR is under $PROGRAMFILES + + ; Copy the relative path to $INSTDIR from $PROGRAMFILES + StrCpy $R4 "$R8" "" $R5 + + ; Concatenate the path to $LOCALAPPDATA the relative profile path and the + ; relative path to $INSTDIR from $PROGRAMFILES + StrCpy $R4 "$LOCALAPPDATA\$R9$R4" + Push $R4 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R4 + StrCmp $R4 "" end +1 + + IfFileExists "$R4\updates" +1 end + RmDir /r "$R4" + + end: + ClearErrors + + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro CleanUpdatesDirCall _REL_PROFILE_PATH + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_REL_PROFILE_PATH}" + Call CleanUpdatesDir + !verbose pop +!macroend + +!macro un.CleanUpdatesDirCall _REL_PROFILE_PATH + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_REL_PROFILE_PATH}" + Call un.CleanUpdatesDir + !verbose pop +!macroend + +!macro un.CleanUpdatesDir + !ifndef un.CleanUpdatesDir + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro CleanUpdatesDir + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Deletes shortcuts and Start Menu directories under Programs as specified by + * the shortcuts log ini file and on Windows 7 unpins TaskBar and Start Menu + * shortcuts. The shortcuts will not be deleted if the shortcut target isn't for + * this install location which is determined by the shortcut having a target of + * $INSTDIR\${FileMainEXE}. The context (All Users or Current User) of the + * $DESKTOP and $SMPROGRAMS constants depends on the + * SetShellVarContext setting and must be set by the caller of this macro. There + * is no All Users context for $QUICKLAUNCH but this will not cause a problem + * since the macro will just continue past the $QUICKLAUNCH shortcut deletion + * section on subsequent calls. + * + * The ini file sections must have the following format (the order of the + * sections in the ini file is not important): + * [SMPROGRAMS] + * ; RelativePath is the directory relative from the Start Menu + * ; Programs directory. + * RelativePath=Mozilla App + * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so + * ; on. There must not be a break in the sequence of the numbers. + * Shortcut1=Mozilla App.lnk + * Shortcut2=Mozilla App (Safe Mode).lnk + * [DESKTOP] + * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so + * ; on. There must not be a break in the sequence of the numbers. + * Shortcut1=Mozilla App.lnk + * Shortcut2=Mozilla App (Safe Mode).lnk + * [QUICKLAUNCH] + * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so + * ; on. There must not be a break in the sequence of the numbers for the + * ; suffix. + * Shortcut1=Mozilla App.lnk + * Shortcut2=Mozilla App (Safe Mode).lnk + * [STARTMENU] + * ; Shortcut1 is the first shortcut, Shortcut2 is the second shortcut, and so + * ; on. There must not be a break in the sequence of the numbers for the + * ; suffix. + * Shortcut1=Mozilla App.lnk + * Shortcut2=Mozilla App (Safe Mode).lnk + * + * $R4 = counter for appending to Shortcut for enumerating the ini file entries + * $R5 = return value from ShellLink::GetShortCutTarget and + * ApplicationID::UninstallPinnedItem + * $R6 = find handle and the long path to the Start Menu Programs directory + * (e.g. $SMPROGRAMS) + * $R7 = path to the $QUICKLAUNCH\User Pinned directory and the return value + * from ReadINIStr for the relative path to the applications directory + * under the Start Menu Programs directory and the long path to this + * directory + * $R8 = return filename from FindFirst / FindNext and the return value from + * ReadINIStr for enumerating shortcuts + * $R9 = long path to the shortcuts log ini file + */ +!macro DeleteShortcuts + + !ifndef ${_MOZFUNC_UN}DeleteShortcuts + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetParent + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}DeleteShortcuts "!insertmacro ${_MOZFUNC_UN}DeleteShortcutsCall" + + Function ${_MOZFUNC_UN}DeleteShortcuts + Push $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + + ${If} ${AtLeastWin7} + ; Since shortcuts that are pinned can later be removed without removing + ; the pinned shortcut unpin the pinned shortcuts for the application's + ; main exe using the pinned shortcuts themselves. + StrCpy $R7 "$QUICKLAUNCH\User Pinned" + + ${If} ${FileExists} "$R7\TaskBar" + ; Delete TaskBar pinned shortcuts for the application's main exe + FindFirst $R6 $R8 "$R7\TaskBar\*.lnk" + ${Do} + ${If} ${FileExists} "$R7\TaskBar\$R8" + ShellLink::GetShortCutTarget "$R7\TaskBar\$R8" + Pop $R5 + Push $R5 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R5 + ${If} "$R5" == "$INSTDIR\${FileMainEXE}" + ApplicationID::UninstallPinnedItem "$R7\TaskBar\$R8" + Pop $R5 + ${EndIf} + ${EndIf} + ClearErrors + FindNext $R6 $R8 + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${Loop} + FindClose $R6 + ${EndIf} + + ${If} ${FileExists} "$R7\StartMenu" + ; Delete Start Menu pinned shortcuts for the application's main exe + FindFirst $R6 $R8 "$R7\StartMenu\*.lnk" + ${Do} + ${If} ${FileExists} "$R7\StartMenu\$R8" + ShellLink::GetShortCutTarget "$R7\StartMenu\$R8" + Pop $R5 + Push $R5 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R5 + ${If} "$R5" == "$INSTDIR\${FileMainEXE}" + ApplicationID::UninstallPinnedItem "$R7\StartMenu\$R8" + Pop $R5 + ${EndIf} + ${EndIf} + ClearErrors + FindNext $R6 $R8 + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${Loop} + FindClose $R6 + ${EndIf} + ${EndIf} + + ; Don't call ApplicationID::UninstallPinnedItem since pinned items for + ; this application were removed above and removing them below will remove + ; the association of side by side installations. + Push "$INSTDIR\uninstall\${SHORTCUTS_LOG}" + Call ${_MOZFUNC_UN}GetLongPath + Pop $R9 + ${If} ${FileExists} "$R9" + ; Delete Start Menu shortcuts for this application + StrCpy $R4 -1 + ${Do} + IntOp $R4 $R4 + 1 ; Increment the counter + ClearErrors + ReadINIStr $R8 "$R9" "STARTMENU" "Shortcut$R4" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + + ${If} ${FileExists} "$SMPROGRAMS\$R8" + ShellLink::GetShortCutTarget "$SMPROGRAMS\$R8" + Pop $R5 + Push $R5 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R5 + ${If} "$INSTDIR\${FileMainEXE}" == "$R5" + Delete "$SMPROGRAMS\$R8" + ${EndIf} + ${EndIf} + ${Loop} + + ; Delete Quick Launch shortcuts for this application + StrCpy $R4 -1 + ${Do} + IntOp $R4 $R4 + 1 ; Increment the counter + ClearErrors + ReadINIStr $R8 "$R9" "QUICKLAUNCH" "Shortcut$R4" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + + ${If} ${FileExists} "$QUICKLAUNCH\$R8" + ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R8" + Pop $R5 + Push $R5 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R5 + ${If} "$INSTDIR\${FileMainEXE}" == "$R5" + Delete "$QUICKLAUNCH\$R8" + ${EndIf} + ${EndIf} + ${Loop} + + ; Delete Desktop shortcuts for this application + StrCpy $R4 -1 + ${Do} + IntOp $R4 $R4 + 1 ; Increment the counter + ClearErrors + ReadINIStr $R8 "$R9" "DESKTOP" "Shortcut$R4" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + + ${If} ${FileExists} "$DESKTOP\$R8" + ShellLink::GetShortCutTarget "$DESKTOP\$R8" + Pop $R5 + Push $R5 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R5 + ${If} "$INSTDIR\${FileMainEXE}" == "$R5" + Delete "$DESKTOP\$R8" + ${EndIf} + ${EndIf} + ${Loop} + + Push $SMPROGRAMS + Call ${_MOZFUNC_UN}GetLongPath + Pop $R6 + + ; Delete Start Menu Programs shortcuts for this application + ClearErrors + ReadINIStr $R7 "$R9" "SMPROGRAMS" "RelativePathToDir" + Push "$R6\$R7" + Call ${_MOZFUNC_UN}GetLongPath + Pop $R7 + ${Unless} "$R7" == "" + StrCpy $R4 -1 + ${Do} + IntOp $R4 $R4 + 1 ; Increment the counter + ClearErrors + ReadINIStr $R8 "$R9" "SMPROGRAMS" "Shortcut$R4" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + + ${If} ${FileExists} "$R7\$R8" + ShellLink::GetShortCutTarget "$R7\$R8" + Pop $R5 + Push $R5 + Call ${_MOZFUNC_UN}GetLongPath + Pop $R5 + ${If} "$INSTDIR\${FileMainEXE}" == "$R5" + Delete "$R7\$R8" + ${EndIf} + ${EndIf} + ${Loop} + + ; Delete Start Menu Programs directories for this application + ${Do} + ClearErrors + ${If} "$R6" == "$R7" + ${ExitDo} + ${EndIf} + RmDir "$R7" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${${_MOZFUNC_UN}GetParent} "$R7" $R7 + ${Loop} + ${EndUnless} + ${EndIf} + + ClearErrors + + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Pop $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro DeleteShortcutsCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call DeleteShortcuts + !verbose pop +!macroend + +!macro un.DeleteShortcutsCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.DeleteShortcuts + !verbose pop +!macroend + +!macro un.DeleteShortcuts + !ifndef un.DeleteShortcuts + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro DeleteShortcuts + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + + +################################################################################ +# Macros for parsing and updating the uninstall.log + +/** + * Updates the uninstall.log with new files added by software update. + * + * When modifying this macro be aware that LineFind uses all registers except + * $R0-$R3 and TextCompareNoDetails uses all registers except $R0-$R9 so be + * cautious. Callers of this macro are not affected. + */ +!macro UpdateUninstallLog + + !ifndef UpdateUninstallLog + !insertmacro FileJoin + !insertmacro LineFind + !insertmacro TextCompareNoDetails + !insertmacro TrimNewLines + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define UpdateUninstallLog "!insertmacro UpdateUninstallLogCall" + + Function UpdateUninstallLog + Push $R3 + Push $R2 + Push $R1 + Push $R0 + + ClearErrors + + GetFullPathName $R3 "$INSTDIR\uninstall" + ${If} ${FileExists} "$R3\uninstall.update" + ${LineFind} "$R3\uninstall.update" "" "1:-1" "CleanupUpdateLog" + + GetTempFileName $R2 "$R3" + FileOpen $R1 "$R2" w + ${TextCompareNoDetails} "$R3\uninstall.update" "$R3\uninstall.log" "SlowDiff" "CreateUpdateDiff" + FileClose $R1 + + IfErrors +2 0 + ${FileJoin} "$R3\uninstall.log" "$R2" "$R3\uninstall.log" + + ${DeleteFile} "$R2" + ${EndIf} + + ClearErrors + + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + FunctionEnd + + ; This callback MUST use labels vs. relative line numbers. + Function CleanupUpdateLog + StrCpy $R2 "$R9" 12 + StrCmp "$R2" "EXECUTE ADD " +1 skip + StrCpy $R9 "$R9" "" 12 + + Push $R6 + Push $R5 + Push $R4 + StrCpy $R4 "" ; Initialize to an empty string. + StrCpy $R6 -1 ; Set the counter to -1 so it will start at 0. + + loop: + IntOp $R6 $R6 + 1 ; Increment the counter. + StrCpy $R5 $R9 1 $R6 ; Starting from the counter copy the next char. + StrCmp $R5 "" copy ; Are there no more chars? + StrCmp $R5 "/" +1 +2 ; Is the char a /? + StrCpy $R5 "\" ; Replace the char with a \. + + StrCpy $R4 "$R4$R5" + GoTo loop + + copy: + StrCpy $R9 "File: \$R4" + Pop $R6 + Pop $R5 + Pop $R4 + GoTo end + + skip: + StrCpy $0 "SkipWrite" + + end: + Push $0 + FunctionEnd + + Function CreateUpdateDiff + ${TrimNewLines} "$9" $9 + ${If} $9 != "" + FileWrite $R1 "$9$\r$\n" + ${EndIf} + + Push 0 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro UpdateUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call UpdateUninstallLog + !verbose pop +!macroend + +/** + * Copies files from a source directory to a destination directory with logging + * to the uninstall.log. If any destination files are in use a reboot will be + * necessary to complete the installation and the reboot flag (see IfRebootFlag + * in the NSIS documentation). + * + * @param _PATH_TO_SOURCE + * Source path to copy the files from. This must not end with a \. + * + * @param _PATH_TO_DESTINATION + * Destination path to copy the files to. This must not end with a \. + * + * @param _PREFIX_ERROR_CREATEDIR + * Prefix for the directory creation error message. The directory path + * will be inserted below this string. + * + * @param _SUFFIX_ERROR_CREATEDIR + * Suffix for the directory creation error message. The directory path + * will be inserted above this string. + * + * $0 = destination file's parent directory used in the create_dir label + * $R0 = copied value from $R6 (e.g. _PATH_TO_SOURCE) + * $R1 = copied value from $R7 (e.g. _PATH_TO_DESTINATION) + * $R2 = string length of the path to source + * $R3 = relative path from the path to source + * $R4 = copied value from $R8 (e.g. _PREFIX_ERROR_CREATEDIR) + * $R5 = copied value from $R9 (e.g. _SUFFIX_ERROR_CREATEDIR) + * note: the LocateNoDetails macro uses these registers so we copy the values + * to other registers. + * $R6 = initially _PATH_TO_SOURCE and then set to "size" ($R6="" if directory, + * $R6="0" if file with /S=)"path\name" in callback + * $R7 = initially _PATH_TO_DESTINATION and then set to "name" in callback + * $R8 = initially _PREFIX_ERROR_CREATEDIR and then set to "path" in callback + * $R9 = initially _SUFFIX_ERROR_CREATEDIR and then set to "path\name" in + * callback + */ +!macro CopyFilesFromDir + + !ifndef CopyFilesFromDir + !insertmacro LocateNoDetails + !insertmacro OnEndCommon + !insertmacro WordReplace + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define CopyFilesFromDir "!insertmacro CopyFilesFromDirCall" + + Function CopyFilesFromDir + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Push $R5 + Push $R4 + Push $R3 + Push $R2 + Push $R1 + Push $R0 + Push $0 + + StrCpy $R0 "$R6" + StrCpy $R1 "$R7" + StrCpy $R4 "$R8" + StrCpy $R5 "$R9" + + StrLen $R2 "$R0" + + ${LocateNoDetails} "$R0" "/L=FD" "CopyFileCallback" + + Pop $0 + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + Pop $R4 + Pop $R5 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + Function CopyFileCallback + StrCpy $R3 $R8 "" $R2 ; $R3 always begins with a \. + + retry: + ClearErrors + StrCmp $R6 "" +1 copy_file + IfFileExists "$R1$R3\$R7" end +1 + StrCpy $0 "$R1$R3\$R7" + + create_dir: + ClearErrors + CreateDirectory "$0" + IfFileExists "$0" +1 err_create_dir ; protect against looping. + ${LogMsg} "Created Directory: $0" + StrCmp $R6 "" end copy_file + + err_create_dir: + ${LogMsg} "** ERROR Creating Directory: $0 **" + MessageBox MB_RETRYCANCEL|MB_ICONQUESTION "$R4$\r$\n$\r$\n$0$\r$\n$\r$\n$R5" IDRETRY retry + ${OnEndCommon} + Quit + + copy_file: + StrCpy $0 "$R1$R3" + StrCmp "$0" "$INSTDIR" +2 +1 + IfFileExists "$0" +1 create_dir + + ClearErrors + ${DeleteFile} "$R1$R3\$R7" + IfErrors +1 dest_clear + ClearErrors + Rename "$R1$R3\$R7" "$R1$R3\$R7.moz-delete" + IfErrors +1 reboot_delete + + ; file will replace destination file on reboot + Rename "$R9" "$R9.moz-upgrade" + CopyFiles /SILENT "$R9.moz-upgrade" "$R1$R3" + Rename /REBOOTOK "$R1$R3\$R7.moz-upgrade" "$R1$R3\$R7" + ${LogMsg} "Copied File: $R1$R3\$R7.moz-upgrade" + ${LogMsg} "Delayed Install File (Reboot Required): $R1$R3\$R7" + GoTo log_uninstall + + ; file will be deleted on reboot + reboot_delete: + CopyFiles /SILENT $R9 "$R1$R3" + Delete /REBOOTOK "$R1$R3\$R7.moz-delete" + ${LogMsg} "Installed File: $R1$R3\$R7" + ${LogMsg} "Delayed Delete File (Reboot Required): $R1$R3\$R7.moz-delete" + GoTo log_uninstall + + ; destination file doesn't exist - coast is clear + dest_clear: + CopyFiles /SILENT $R9 "$R1$R3" + ${LogMsg} "Installed File: $R1$R3\$R7" + + log_uninstall: + ; If the file is installed into the installation directory remove the + ; installation directory's path from the file path when writing to the + ; uninstall.log so it will be a relative path. This allows the same + ; helper.exe to be used with zip builds if we supply an uninstall.log. + ${WordReplace} "$R1$R3\$R7" "$INSTDIR" "" "+" $R3 + ${LogUninstall} "File: $R3" + + end: + Push 0 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro CopyFilesFromDirCall _PATH_TO_SOURCE _PATH_TO_DESTINATION \ + _PREFIX_ERROR_CREATEDIR _SUFFIX_ERROR_CREATEDIR + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_PATH_TO_SOURCE}" + Push "${_PATH_TO_DESTINATION}" + Push "${_PREFIX_ERROR_CREATEDIR}" + Push "${_SUFFIX_ERROR_CREATEDIR}" + Call CopyFilesFromDir + !verbose pop +!macroend + +/** + * Parses the uninstall.log on install to first remove a previous installation's + * files and then their directories if empty prior to installing. + * + * When modifying this macro be aware that LineFind uses all registers except + * $R0-$R3 so be cautious. Callers of this macro are not affected. + */ +!macro OnInstallUninstall + + !ifndef OnInstallUninstall + !insertmacro GetParent + !insertmacro LineFind + !insertmacro TrimNewLines + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define OnInstallUninstall "!insertmacro OnInstallUninstallCall" + + Function OnInstallUninstall + Push $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + Push $R3 + Push $R2 + Push $R1 + Push $R0 + Push $TmpVal + + IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end + + ${LogHeader} "Removing Previous Installation" + + ; Copy the uninstall log file to a temporary file + GetTempFileName $TmpVal + CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal" + + ; Delete files + ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveFilesCallback" + + ; Remove empty directories + ${LineFind} "$TmpVal" "/NUL" "1:-1" "RemoveDirsCallback" + + ; Delete the temporary uninstall log file + Delete /REBOOTOK "$TmpVal" + + ; Delete the uninstall log file + Delete "$INSTDIR\uninstall\uninstall.log" + + end: + ClearErrors + + Pop $TmpVal + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Pop $R9 + FunctionEnd + + Function RemoveFilesCallback + ${TrimNewLines} "$R9" $R9 + StrCpy $R1 "$R9" 5 ; Copy the first five chars + + StrCmp "$R1" "File:" +1 end + StrCpy $R9 "$R9" "" 6 ; Copy string starting after the 6th char + StrCpy $R0 "$R9" 1 ; Copy the first char + + StrCmp "$R0" "\" +1 end ; If this isn't a relative path goto end + StrCmp "$R9" "\install.log" end +1 ; Skip the install.log + StrCmp "$R9" "\MapiProxy_InUse.dll" end +1 ; Skip the MapiProxy_InUse.dll + StrCmp "$R9" "\mozMapi32_InUse.dll" end +1 ; Skip the mozMapi32_InUse.dll + + StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string + IfFileExists "$R1" +1 end + + ClearErrors + Delete "$R1" + ${Unless} ${Errors} + ${LogMsg} "Deleted File: $R1" + Goto end + ${EndUnless} + + ClearErrors + Rename "$R1" "$R1.moz-delete" + ${Unless} ${Errors} + Delete /REBOOTOK "$R1.moz-delete" + ${LogMsg} "Delayed Delete File (Reboot Required): $R1.moz-delete" + GoTo end + ${EndUnless} + + ; Check if the file exists in the source. If it does the new file will + ; replace the existing file when the system is rebooted. If it doesn't + ; the file will be deleted when the system is rebooted. + ${Unless} ${FileExists} "$EXEDIR\core$R9" + ${AndUnless} ${FileExists} "$EXEDIR\optional$R9" + Delete /REBOOTOK "$R1" + ${LogMsg} "Delayed Delete File (Reboot Required): $R1" + ${EndUnless} + + end: + ClearErrors + + Push 0 + FunctionEnd + + ; Using locate will leave file handles open to some of the directories + ; which will prevent the deletion of these directories. This parses the + ; uninstall.log and uses the file entries to find / remove empty + ; directories. + Function RemoveDirsCallback + ${TrimNewLines} "$R9" $R9 + StrCpy $R0 "$R9" 5 ; Copy the first five chars + StrCmp "$R0" "File:" +1 end + + StrCpy $R9 "$R9" "" 6 ; Copy string starting after the 6th char + StrCpy $R0 "$R9" 1 ; Copy the first char + + StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string + StrCmp "$R0" "\" loop end ; If this isn't a relative path goto end + + loop: + ${GetParent} "$R1" $R1 ; Get the parent directory for the path + StrCmp "$R1" "$INSTDIR" end +1 ; If the directory is the install dir goto end + + IfFileExists "$R1" +1 loop ; Only try to remove the dir if it exists + ClearErrors + RmDir "$R1" ; Remove the dir + IfErrors end +1 ; If we fail there is no use trying to remove its parent dir + ${LogMsg} "Deleted Directory: $R1" + GoTo loop + + end: + ClearErrors + + Push 0 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro OnInstallUninstallCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call OnInstallUninstall + !verbose pop +!macroend + +/** + * Parses the uninstall.log to unregister dll's, remove files, and remove + * empty directories for this installation. + * + * When modifying this macro be aware that LineFind uses all registers except + * $R0-$R3 so be cautious. Callers of this macro are not affected. + */ +!macro un.ParseUninstallLog + + !ifndef un.ParseUninstallLog + !insertmacro un.GetParent + !insertmacro un.LineFind + !insertmacro un.TrimNewLines + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define un.ParseUninstallLog "!insertmacro un.ParseUninstallLogCall" + + Function un.ParseUninstallLog + Push $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + Push $R3 + Push $R2 + Push $R1 + Push $R0 + Push $TmpVal + + IfFileExists "$INSTDIR\uninstall\uninstall.log" +1 end + + ; Copy the uninstall log file to a temporary file + GetTempFileName $TmpVal + CopyFiles /SILENT /FILESONLY "$INSTDIR\uninstall\uninstall.log" "$TmpVal" + + ; Unregister DLL's + ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.UnRegDLLsCallback" + + ; Delete files + ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveFilesCallback" + + ; Remove empty directories + ${un.LineFind} "$TmpVal" "/NUL" "1:-1" "un.RemoveDirsCallback" + + ; Delete the temporary uninstall log file + Delete /REBOOTOK "$TmpVal" + + end: + + Pop $TmpVal + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Pop $R9 + FunctionEnd + + Function un.RemoveFilesCallback + ${un.TrimNewLines} "$R9" $R9 + StrCpy $R1 "$R9" 5 + + StrCmp "$R1" "File:" +1 end + StrCpy $R9 "$R9" "" 6 + StrCpy $R0 "$R9" 1 + + StrCpy $R1 "$INSTDIR$R9" + StrCmp "$R0" "\" +2 +1 + StrCpy $R1 "$R9" + + IfFileExists "$R1" +1 end + Delete "$R1" + IfErrors +1 end + ClearErrors + Rename "$R1" "$R1.moz-delete" + IfErrors +1 +3 + Delete /REBOOTOK "$R1" + GoTo end + + Delete /REBOOTOK "$R1.moz-delete" + + end: + ClearErrors + + Push 0 + FunctionEnd + + Function un.UnRegDLLsCallback + ${un.TrimNewLines} "$R9" $R9 + StrCpy $R1 "$R9" 7 + + StrCmp $R1 "DLLReg:" +1 end + StrCpy $R9 "$R9" "" 8 + StrCpy $R0 "$R9" 1 + + StrCpy $R1 "$INSTDIR$R9" + StrCmp $R0 "\" +2 +1 + StrCpy $R1 "$R9" + + ${UnregisterDLL} $R1 + + end: + ClearErrors + + Push 0 + FunctionEnd + + ; Using locate will leave file handles open to some of the directories + ; which will prevent the deletion of these directories. This parses the + ; uninstall.log and uses the file entries to find / remove empty + ; directories. + Function un.RemoveDirsCallback + ${un.TrimNewLines} "$R9" $R9 + StrCpy $R0 "$R9" 5 ; Copy the first five chars + StrCmp "$R0" "File:" +1 end + + StrCpy $R9 "$R9" "" 6 ; Copy string starting after the 6th char + StrCpy $R0 "$R9" 1 ; Copy the first char + + StrCpy $R1 "$INSTDIR$R9" ; Copy the install dir path and suffix it with the string + StrCmp "$R0" "\" loop ; If this is a relative path goto the loop + StrCpy $R1 "$R9" ; Already a full path so copy the string + + loop: + ${un.GetParent} "$R1" $R1 ; Get the parent directory for the path + StrCmp "$R1" "$INSTDIR" end ; If the directory is the install dir goto end + + ; We only try to remove empty directories but the Desktop, StartMenu, and + ; QuickLaunch directories can be empty so guard against removing them. + SetShellVarContext all ; Set context to all users + StrCmp "$R1" "$DESKTOP" end ; All users desktop + StrCmp "$R1" "$STARTMENU" end ; All users start menu + + SetShellVarContext current ; Set context to all users + StrCmp "$R1" "$DESKTOP" end ; Current user desktop + StrCmp "$R1" "$STARTMENU" end ; Current user start menu + StrCmp "$R1" "$QUICKLAUNCH" end ; Current user quick launch + + IfFileExists "$R1" +1 +3 ; Only try to remove the dir if it exists + ClearErrors + RmDir "$R1" ; Remove the dir + IfErrors end ; If we fail there is no use trying to remove its parent dir + + StrCmp "$R0" "\" loop end ; Only loop when the path is relative to the install dir + + end: + ClearErrors + + Push 0 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro un.ParseUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.ParseUninstallLog + !verbose pop +!macroend + +/** + * Finds a valid Start Menu shortcut in the uninstall log and returns the + * relative path from the Start Menu's Programs directory to the shortcut's + * directory. + * + * When modifying this macro be aware that LineFind uses all registers except + * $R0-$R3 so be cautious. Callers of this macro are not affected. + * + * @return _REL_PATH_TO_DIR + * The relative path to the application's Start Menu directory from the + * Start Menu's Programs directory. + */ +!macro FindSMProgramsDir + + !ifndef FindSMProgramsDir + !insertmacro GetParent + !insertmacro LineFind + !insertmacro TrimNewLines + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define FindSMProgramsDir "!insertmacro FindSMProgramsDirCall" + + Function FindSMProgramsDir + Exch $R3 + Push $R2 + Push $R1 + Push $R0 + + StrCpy $R3 "" + ${If} ${FileExists} "$INSTDIR\uninstall\uninstall.log" + ${LineFind} "$INSTDIR\uninstall\uninstall.log" "/NUL" "1:-1" "FindSMProgramsDirRelPath" + ${EndIf} + ClearErrors + + Pop $R0 + Pop $R1 + Pop $R2 + Exch $R3 + FunctionEnd + + ; This callback MUST use labels vs. relative line numbers. + Function FindSMProgramsDirRelPath + Push 0 + ${TrimNewLines} "$R9" $R9 + StrCpy $R4 "$R9" 5 + + StrCmp "$R4" "File:" +1 end_FindSMProgramsDirRelPath + StrCpy $R9 "$R9" "" 6 + StrCpy $R4 "$R9" 1 + + StrCmp "$R4" "\" end_FindSMProgramsDirRelPath +1 + + SetShellVarContext all + Push $SMPROGRAMS + Call GetLongPath + Pop $R4 + StrLen $R2 "$R4" + StrCpy $R1 "$R9" $R2 + StrCmp "$R1" "$R4" +1 end_FindSMProgramsDirRelPath + IfFileExists "$R9" +1 end_FindSMProgramsDirRelPath + ShellLink::GetShortCutTarget "$R9" + Pop $R0 + StrCmp "$INSTDIR\${FileMainEXE}" "$R0" +1 end_FindSMProgramsDirRelPath + ${GetParent} "$R9" $R3 + IntOp $R2 $R2 + 1 + StrCpy $R3 "$R3" "" $R2 + + Pop $R4 ; Remove the previously pushed 0 from the stack and + push "StopLineFind" ; push StopLineFind to stop finding more lines. + + end_FindSMProgramsDirRelPath: + ClearErrors + + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro FindSMProgramsDirCall _REL_PATH_TO_DIR + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call FindSMProgramsDir + Pop ${_REL_PATH_TO_DIR} + !verbose pop +!macroend + + +################################################################################ +# Macros for custom branding + +/** + * Sets BrandFullName and / or BrandShortName to values provided in the specified + * ini file and defaults to BrandShortName and BrandFullName as defined in + * branding.nsi when the associated ini file entry is not specified. + * + * ini file format: + * [Branding] + * BrandFullName=Custom Full Name + * BrandShortName=Custom Short Name + * + * @param _PATH_TO_INI + * Path to the ini file. + * + * $R6 = return value from ReadINIStr + * $R7 = stores BrandShortName + * $R8 = stores BrandFullName + * $R9 = _PATH_TO_INI + */ +!macro SetBrandNameVars + + !ifndef ${_MOZFUNC_UN}SetBrandNameVars + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}WordReplace + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + ; Prevent declaring vars twice when the SetBrandNameVars macro is + ; inserted into both the installer and uninstaller. + !ifndef SetBrandNameVars + Var BrandFullName + Var BrandFullNameDA + Var BrandShortName + !endif + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}SetBrandNameVars "!insertmacro ${_MOZFUNC_UN}SetBrandNameVarsCall" + + Function ${_MOZFUNC_UN}SetBrandNameVars + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + + StrCpy $R8 "${BrandFullName}" + StrCpy $R7 "${BrandShortName}" + + IfFileExists "$R9" +1 finish + + ClearErrors + ReadINIStr $R6 $R9 "Branding" "BrandFullName" + IfErrors +2 +1 + StrCpy $R8 "$R6" + + ClearErrors + ReadINIStr $R6 $R9 "Branding" "BrandShortName" + IfErrors +2 +1 + StrCpy $R7 "$R6" + + finish: + StrCpy $BrandFullName "$R8" + ${${_MOZFUNC_UN}WordReplace} "$R8" "&" "&&" "+" $R8 + StrCpy $BrandFullNameDA "$R8" + StrCpy $BrandShortName "$R7" + + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro SetBrandNameVarsCall _PATH_TO_INI + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_PATH_TO_INI}" + Call SetBrandNameVars + !verbose pop +!macroend + +!macro un.SetBrandNameVarsCall _PATH_TO_INI + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_PATH_TO_INI}" + Call un.SetBrandNameVars + !verbose pop +!macroend + +!macro un.SetBrandNameVars + !ifndef un.SetBrandNameVars + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro SetBrandNameVars + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Replaces the wizard's header image with the one specified. + * + * @param _PATH_TO_IMAGE + * Fully qualified path to the bitmap to use for the header image. + * + * $R8 = hwnd for the control returned from GetDlgItem. + * $R9 = _PATH_TO_IMAGE + */ +!macro ChangeMUIHeaderImage + + !ifndef ${_MOZFUNC_UN}ChangeMUIHeaderImage + Var hHeaderBitmap + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}ChangeMUIHeaderImage "!insertmacro ${_MOZFUNC_UN}ChangeMUIHeaderImageCall" + + Function ${_MOZFUNC_UN}ChangeMUIHeaderImage + Exch $R9 + Push $R8 + + GetDlgItem $R8 $HWNDPARENT 1046 + System::Call 'user32::LoadImageW(i 0, w "$R9", i 0, i 0, i 0, i 0x0010|0x2000) i.s' + Pop $hHeaderBitmap + SendMessage $R8 ${STM_SETIMAGE} 0 $hHeaderBitmap + ; There is no way to specify a show function for a custom page so hide + ; and then show the control to force the bitmap to redraw. + ShowWindow $R8 ${SW_HIDE} + ShowWindow $R8 ${SW_SHOW} + + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro ChangeMUIHeaderImageCall _PATH_TO_IMAGE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_PATH_TO_IMAGE}" + Call ChangeMUIHeaderImage + !verbose pop +!macroend + +!macro un.ChangeMUIHeaderImageCall _PATH_TO_IMAGE + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_PATH_TO_IMAGE}" + Call un.ChangeMUIHeaderImage + !verbose pop +!macroend + +!macro un.ChangeMUIHeaderImage + !ifndef un.ChangeMUIHeaderImage + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro ChangeMUIHeaderImage + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + + +############################################################################## +# User interface callback helper macros + +/** + * Unloads dll's and releases references when the installer and uninstaller + * exit. + */ +!macro OnEndCommon + + !ifndef ${_MOZFUNC_UN}OnEndCommon + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}UnloadUAC + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}OnEndCommon "!insertmacro ${_MOZFUNC_UN}OnEndCommonCall" + + Function ${_MOZFUNC_UN}OnEndCommon + + ${${_MOZFUNC_UN}UnloadUAC} + StrCmp $hHeaderBitmap "" +3 +1 + System::Call "gdi32::DeleteObject(i s)" $hHeaderBitmap + StrCpy $hHeaderBitmap "" + + System::Free 0 + + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro OnEndCommonCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call OnEndCommon + !verbose pop +!macroend + +!macro un.OnEndCommonCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.OnEndCommon + !verbose pop +!macroend + +!macro un.OnEndCommon + !ifndef un.OnEndCommon + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro OnEndCommon + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Called from the installer's .onInit function not to be confused with the + * uninstaller's .onInit or the uninstaller's un.onInit functions. + * + * @param _WARN_UNSUPPORTED_MSG + * Message displayed when the Windows version is not supported. + * + * $R5 = return value from the GetSize macro + * $R6 = general string values, return value from GetTempFileName, return + * value from the GetSize macro + * $R7 = full path to the configuration ini file + * $R8 = used for OS Version and Service Pack detection and the return value + * from the GetParameters macro + * $R9 = _WARN_UNSUPPORTED_MSG + */ +!macro InstallOnInitCommon + + !ifndef InstallOnInitCommon + !insertmacro ElevateUAC + !insertmacro GetOptions + !insertmacro GetParameters + !insertmacro GetSize + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define InstallOnInitCommon "!insertmacro InstallOnInitCommonCall" + + Function InstallOnInitCommon + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + + !ifdef HAVE_64BIT_OS + ${Unless} ${RunningX64} + ${OrUnless} ${AtLeastWin7} + MessageBox MB_OK|MB_ICONSTOP "$R9" IDOK + ; Nothing initialized so no need to call OnEndCommon + Quit + ${EndUnless} + + SetRegView 64 + !else + ${Unless} ${AtLeastWin7} + MessageBox MB_OK|MB_ICONSTOP "$R9" IDOK + ; Nothing initialized so no need to call OnEndCommon + Quit + ${EndUnless} + !endif + + ${GetParameters} $R8 + + ; Require elevation if the user can elevate + ${ElevateUAC} + + ${If} $R8 != "" + ${Unless} ${Silent} + ; Manually check for /S in the command line due to Bug 506867 + ClearErrors + ${GetOptions} "$R8" "/S" $R7 + ${Unless} ${Errors} + SetSilent silent + ${Else} + ; Support for the deprecated -ms command line argument. The new command + ; line arguments are not supported when -ms is used. + ClearErrors + ${GetOptions} "$R8" "-ms" $R7 + ${Unless} ${Errors} + SetSilent silent + ${EndUnless} + ${EndUnless} + ${EndUnless} + + ; Support for specifying an installation configuration file. + ClearErrors + ${GetOptions} "$R8" "/INI=" $R7 + ${Unless} ${Errors} + ; The configuration file must also exist + ${If} ${FileExists} "$R7" + SetSilent silent + ReadINIStr $R8 $R7 "Install" "InstallDirectoryName" + ${If} $R8 != "" + !ifdef HAVE_64BIT_OS + StrCpy $INSTDIR "$PROGRAMFILES64\$R8" + !else + StrCpy $INSTDIR "$PROGRAMFILES32\$R8" + !endif + ${Else} + ReadINIStr $R8 $R7 "Install" "InstallDirectoryPath" + ${If} $R8 != "" + StrCpy $INSTDIR "$R8" + ${EndIf} + ${EndIf} + + ; Quit if we are unable to create the installation directory or we are + ; unable to write to a file in the installation directory. + ClearErrors + ${If} ${FileExists} "$INSTDIR" + GetTempFileName $R6 "$INSTDIR" + FileOpen $R5 "$R6" w + FileWrite $R5 "Write Access Test" + FileClose $R5 + Delete $R6 + ${If} ${Errors} + ; Nothing initialized so no need to call OnEndCommon + Quit + ${EndIf} + ${Else} + CreateDirectory "$INSTDIR" + ${If} ${Errors} + ; Nothing initialized so no need to call OnEndCommon + Quit + ${EndIf} + ${EndIf} + + ReadINIStr $R8 $R7 "Install" "QuickLaunchShortcut" + ${If} $R8 == "false" + StrCpy $AddQuickLaunchSC "0" + ${Else} + StrCpy $AddQuickLaunchSC "1" + ${EndIf} + + ReadINIStr $R8 $R7 "Install" "DesktopShortcut" + ${If} $R8 == "false" + StrCpy $AddDesktopSC "0" + ${Else} + StrCpy $AddDesktopSC "1" + ${EndIf} + + ReadINIStr $R8 $R7 "Install" "StartMenuShortcuts" + ${If} $R8 == "false" + StrCpy $AddStartMenuSC "0" + ${Else} + StrCpy $AddStartMenuSC "1" + ${EndIf} + + !ifndef NO_STARTMENU_DIR + ReadINIStr $R8 $R7 "Install" "StartMenuDirectoryName" + ${If} $R8 != "" + StrCpy $StartMenuDir "$R8" + ${EndIf} + !endif + ${EndIf} + ${EndUnless} + ${EndIf} + ClearErrors + + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro InstallOnInitCommonCall _WARN_UNSUPPORTED_MSG + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_WARN_UNSUPPORTED_MSG}" + Call InstallOnInitCommon + !verbose pop +!macroend + +/** + * Called from the MUI leaveOptions function to set the value of $INSTDIR. + */ +!macro LeaveOptionsCommon + + !ifndef LeaveOptionsCommon + !insertmacro CanWriteToInstallDir + +!ifndef NO_INSTDIR_FROM_REG + !insertmacro GetSingleInstallPath +!endif + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define LeaveOptionsCommon "!insertmacro LeaveOptionsCommonCall" + + Function LeaveOptionsCommon + Push $R9 + +!ifndef NO_INSTDIR_FROM_REG + SetShellVarContext all ; Set SHCTX to HKLM + ${GetSingleInstallPath} "Software\Zotero\${BrandFullNameInternal}" $R9 + + StrCmp "$R9" "false" +1 finish_get_install_dir + + SetShellVarContext current ; Set SHCTX to HKCU + ${GetSingleInstallPath} "Software\Zotero\${BrandFullNameInternal}" $R9 + + finish_get_install_dir: + StrCmp "$R9" "false" +2 +1 + StrCpy $INSTDIR "$R9" +!endif + + ; If the user doesn't have write access to the installation directory set + ; the installation directory to a subdirectory of the user's local + ; application directory (e.g. non-roaming). + ${CanWriteToInstallDir} $R9 + StrCmp "$R9" "false" +1 finish_check_install_dir + StrCpy $INSTDIR "$LOCALAPPDATA\${BrandFullName}\" + + finish_check_install_dir: + IfFileExists "$INSTDIR" +3 +1 + Pop $R9 + Return + + ; Always display the long path if the path already exists. + Push $INSTDIR + Call GetLongPath + Pop $INSTDIR + + ; The call to GetLongPath returns a long path without a trailing + ; back-slash. Append a \ to the path to prevent the directory + ; name from being appended when using the NSIS create new folder. + ; http://www.nullsoft.com/free/nsis/makensis.htm#InstallDir + StrCpy $INSTDIR "$INSTDIR\" + + Pop $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro LeaveOptionsCommonCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call LeaveOptionsCommon + !verbose pop +!macroend + +################################################################################ +# Install Section common macros. + +/** + * Performs common cleanup operations prior to the actual installation. + * This macro should be called first when installation starts. + */ +!macro InstallStartCleanupCommon + + !ifndef InstallStartCleanupCommon + !insertmacro EndUninstallLog + !insertmacro OnInstallUninstall + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define InstallStartCleanupCommon "!insertmacro InstallStartCleanupCommonCall" + + Function InstallStartCleanupCommon + + ; Remove files not removed by parsing the uninstall.log + Delete "$INSTDIR\install_wizard.log" + Delete "$INSTDIR\install_status.log" + + RmDir /r "$INSTDIR\updates" + Delete "$INSTDIR\updates.xml" + Delete "$INSTDIR\active-update.xml" + + RmDir /r "$INSTDIR\distribution" + + ; Remove files from the uninstall directory. + ${If} ${FileExists} "$INSTDIR\uninstall" + Delete "$INSTDIR\uninstall\*wizard*" + Delete "$INSTDIR\uninstall\uninstall.ini" + Delete "$INSTDIR\uninstall\cleanup.log" + Delete "$INSTDIR\uninstall\uninstall.update" + ${OnInstallUninstall} + ${EndIf} + + ; Since we write to the uninstall.log in this directory during the + ; installation create the directory if it doesn't already exist. + IfFileExists "$INSTDIR\uninstall" +2 +1 + CreateDirectory "$INSTDIR\uninstall" + + ; Application update uses a directory named tobedeleted in the $INSTDIR to + ; delete files on OS reboot when they are in use. Try to delete this + ; directory if it exists. + ${If} ${FileExists} "$INSTDIR\tobedeleted" + RmDir /r "$INSTDIR\tobedeleted" + ${EndIf} + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro InstallStartCleanupCommonCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call InstallStartCleanupCommon + !verbose pop +!macroend + +/** + * Performs common cleanup operations after the actual installation. + * This macro should be called last during the installation. + */ +!macro InstallEndCleanupCommon + + !ifndef InstallEndCleanupCommon + !insertmacro EndUninstallLog + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define InstallEndCleanupCommon "!insertmacro InstallEndCleanupCommonCall" + + Function InstallEndCleanupCommon + + ; Close the file handle to the uninstall.log + ${EndUninstallLog} + + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro InstallEndCleanupCommonCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call InstallEndCleanupCommon + !verbose pop +!macroend + + +################################################################################ +# UAC Related Macros + +/** + * Provides UAC elevation support for Vista and above (requires the UAC plugin). + * + * $0 = return values from calls to the UAC plugin (always uses $0) + * $R9 = return values from GetParameters and GetOptions macros + */ +!macro ElevateUAC + + !ifndef ${_MOZFUNC_UN}ElevateUAC + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP}GetOptions + !insertmacro ${_MOZFUNC_UN_TMP}GetParameters + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}ElevateUAC "!insertmacro ${_MOZFUNC_UN}ElevateUACCall" + + Function ${_MOZFUNC_UN}ElevateUAC + Push $R9 + Push $0 + +!ifndef NONADMIN_ELEVATE + ${If} ${AtLeastWinVista} + UAC::IsAdmin + ; If the user is not an admin already + ${If} "$0" != "1" + UAC::SupportsUAC + ; If the system supports UAC + ${If} "$0" == "1" + UAC::GetElevationType + ; If the user account has a split token + ${If} "$0" == "3" + UAC::RunElevated + UAC::Unload + ; Nothing besides UAC initialized so no need to call OnEndCommon + Quit + ${EndIf} + ${EndIf} + ${Else} + ${GetParameters} $R9 + ${If} $R9 != "" + ClearErrors + ${GetOptions} "$R9" "/UAC:" $0 + ; If the command line contains /UAC then we need to initialize + ; the UAC plugin to use UAC::ExecCodeSegment to execute code in + ; the non-elevated context. + ${Unless} ${Errors} + UAC::RunElevated + ${EndUnless} + ${EndIf} + ${EndIf} + ${EndIf} +!else + ${If} ${AtLeastWinVista} + UAC::IsAdmin + ; If the user is not an admin already + ${If} "$0" != "1" + UAC::SupportsUAC + ; If the system supports UAC require that the user elevate + ${If} "$0" == "1" + UAC::GetElevationType + ; If the user account has a split token + ${If} "$0" == "3" + UAC::RunElevated + UAC::Unload + ; Nothing besides UAC initialized so no need to call OnEndCommon + Quit + ${EndIf} + ${Else} + ; Check if UAC is enabled. If the user has turned UAC on or off + ; without rebooting this value will be incorrect. This is an + ; edgecase that we have to live with when trying to allow + ; installing when the user doesn't have privileges such as a public + ; computer while trying to also achieve UAC elevation. When this + ; happens the user will be presented with the runas dialog if the + ; value is 1 and won't be presented with the UAC dialog when the + ; value is 0. + ReadRegDWord $R9 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System" "EnableLUA" + ${If} "$R9" == "1" + ; This will display the UAC version of the runas dialog which + ; requires a password for an existing user account. + UAC::RunElevated + ${If} "$0" == "0" ; Was elevation successful + UAC::Unload + ; Nothing besides UAC initialized so no need to call OnEndCommon + Quit + ${EndIf} + ; Unload UAC since the elevation request was not successful and + ; install anyway. + UAC::Unload + ${EndIf} + ${EndIf} + ${Else} + ClearErrors + ${${_MOZFUNC_UN}GetParameters} $R9 + ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9 + ; If the command line contains /UAC then we need to initialize the UAC + ; plugin to use UAC::ExecCodeSegment to execute code in the + ; non-elevated context. + ${Unless} ${Errors} + UAC::RunElevated + ${EndUnless} + ${EndIf} + ${EndIf} +!endif + + ClearErrors + + Pop $0 + Pop $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro ElevateUACCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call ElevateUAC + !verbose pop +!macroend + +!macro un.ElevateUACCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.ElevateUAC + !verbose pop +!macroend + +!macro un.ElevateUAC + !ifndef un.ElevateUAC + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro ElevateUAC + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Unloads the UAC plugin so the NSIS plugins can be removed when the installer + * and uninstaller exit. + * + * $R9 = return values from GetParameters and GetOptions macros + */ +!macro UnloadUAC + + !ifndef ${_MOZFUNC_UN}UnloadUAC + !define _MOZFUNC_UN_TMP_UnloadUAC ${_MOZFUNC_UN} + !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetOptions + !insertmacro ${_MOZFUNC_UN_TMP_UnloadUAC}GetParameters + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP_UnloadUAC} + !undef _MOZFUNC_UN_TMP_UnloadUAC + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}UnloadUAC "!insertmacro ${_MOZFUNC_UN}UnloadUACCall" + + Function ${_MOZFUNC_UN}UnloadUAC + ${Unless} ${AtLeastWinVista} + Return + ${EndUnless} + + Push $R9 + + ClearErrors + ${${_MOZFUNC_UN}GetParameters} $R9 + ${${_MOZFUNC_UN}GetOptions} "$R9" "/UAC:" $R9 + ; If the command line contains /UAC then we need to unload the UAC plugin + IfErrors +2 +1 + UAC::Unload + + ClearErrors + + Pop $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro UnloadUACCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call UnloadUAC + !verbose pop +!macroend + +!macro un.UnloadUACCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call un.UnloadUAC + !verbose pop +!macroend + +!macro un.UnloadUAC + !ifndef un.UnloadUAC + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro UnloadUAC + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + + +################################################################################ +# Macros for uninstall.log and install.log logging +# +# Since these are used by other macros they should be inserted first. All of +# these macros can be easily inserted using the _LoggingCommon macro. + +/** + * Adds all logging macros in the correct order in one fell swoop as well as + * the vars for the install.log and uninstall.log file handles. + */ +!macro _LoggingCommon + Var /GLOBAL fhInstallLog + Var /GLOBAL fhUninstallLog + !insertmacro StartInstallLog + !insertmacro EndInstallLog + !insertmacro StartUninstallLog + !insertmacro EndUninstallLog +!macroend +!define _LoggingCommon "!insertmacro _LoggingCommon" + +/** + * Creates a file named install.log in the install directory (e.g. $INSTDIR) + * and adds the installation started message to the install.log for this + * installation. This also adds the fhInstallLog and fhUninstallLog vars used + * for logging. + * + * $fhInstallLog = filehandle for $INSTDIR\install.log + * + * @param _APP_NAME + * Typically the BrandFullName + * @param _AB_CD + * The locale identifier + * @param _APP_VERSION + * The application version + * @param _GRE_VERSION + * The Gecko Runtime Engine version + * + * $R6 = _APP_NAME + * $R7 = _AB_CD + * $R8 = _APP_VERSION + * $R9 = _GRE_VERSION + */ +!macro StartInstallLog + + !ifndef StartInstallLog + !insertmacro GetTime + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define StartInstallLog "!insertmacro StartInstallLogCall" + + Function StartInstallLog + Exch $R9 + Exch 1 + Exch $R8 + Exch 2 + Exch $R7 + Exch 3 + Exch $R6 + Push $R5 + Push $R4 + Push $R3 + Push $R2 + Push $R1 + Push $R0 + Push $9 + + ${DeleteFile} "$INSTDIR\install.log" + FileOpen $fhInstallLog "$INSTDIR\install.log" w + FileWriteWord $fhInstallLog "65279" + + ${GetTime} "" "L" $9 $R0 $R1 $R2 $R3 $R4 $R5 + FileWriteUTF16LE $fhInstallLog "$R6 Installation Started: $R1-$R0-$9 $R3:$R4:$R5" + ${WriteLogSeparator} + + ${LogHeader} "Installation Details" + ${LogMsg} "Install Dir: $INSTDIR" + ${LogMsg} "Locale : $R7" + ${LogMsg} "App Version: $R8" + ${LogMsg} "GRE Version: $R9" + + ${If} ${IsWinXP} + ${LogMsg} "OS Name : Windows XP" + ${ElseIf} ${IsWin2003} + ${LogMsg} "OS Name : Windows 2003" + ${ElseIf} ${IsWinVista} + ${LogMsg} "OS Name : Windows Vista" + ${ElseIf} ${IsWin7} + ${LogMsg} "OS Name : Windows 7" + ${ElseIf} ${IsWin8} + ${LogMsg} "OS Name : Windows 8" + ${ElseIf} ${AtLeastWin8} + ${LogMsg} "OS Name : Above Windows 8" + ${Else} + ${LogMsg} "OS Name : Unable to detect" + ${EndIf} + + !ifdef HAVE_64BIT_OS + ${LogMsg} "Target CPU : x64" + !else + ${LogMsg} "Target CPU : x86" + !endif + + Pop $9 + Pop $R0 + Pop $R1 + Pop $R2 + Pop $R3 + Pop $R4 + Pop $R5 + Exch $R6 + Exch 3 + Exch $R7 + Exch 2 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro StartInstallLogCall _APP_NAME _AB_CD _APP_VERSION _GRE_VERSION + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_APP_NAME}" + Push "${_AB_CD}" + Push "${_APP_VERSION}" + Push "${_GRE_VERSION}" + Call StartInstallLog + !verbose pop +!macroend + +/** + * Writes the installation finished message to the install.log and closes the + * file handles to the install.log and uninstall.log + * + * @param _APP_NAME + * + * $R9 = _APP_NAME + */ +!macro EndInstallLog + + !ifndef EndInstallLog + !insertmacro GetTime + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define EndInstallLog "!insertmacro EndInstallLogCall" + + Function EndInstallLog + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + Push $R4 + Push $R3 + Push $R2 + + ${WriteLogSeparator} + ${GetTime} "" "L" $R2 $R3 $R4 $R5 $R6 $R7 $R8 + FileWriteUTF16LE $fhInstallLog "$R9 Installation Finished: $R4-$R3-$R2 $R6:$R7:$R8$\r$\n" + FileClose $fhInstallLog + + Pop $R2 + Pop $R3 + Pop $R4 + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro EndInstallLogCall _APP_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_APP_NAME}" + Call EndInstallLog + !verbose pop +!macroend + +/** + * Opens the file handle to the uninstall.log. + * + * $fhUninstallLog = filehandle for $INSTDIR\uninstall\uninstall.log + */ +!macro StartUninstallLog + + !ifndef StartUninstallLog + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define StartUninstallLog "!insertmacro StartUninstallLogCall" + + Function StartUninstallLog + FileOpen $fhUninstallLog "$INSTDIR\uninstall\uninstall.log" w + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro StartUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call StartUninstallLog + !verbose pop +!macroend + +/** + * Closes the file handle to the uninstall.log. + */ +!macro EndUninstallLog + + !ifndef EndUninstallLog + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define EndUninstallLog "!insertmacro EndUninstallLogCall" + + Function EndUninstallLog + FileClose $fhUninstallLog + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro EndUninstallLogCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call EndUninstallLog + !verbose pop +!macroend + +/** + * Adds a section header to the human readable log. + * + * @param _HEADER + * The header text to write to the log. + */ +!macro LogHeader _HEADER + ${WriteLogSeparator} + FileWriteUTF16LE $fhInstallLog "${_HEADER}" + ${WriteLogSeparator} +!macroend +!define LogHeader "!insertmacro LogHeader" + +/** + * Adds a section message to the human readable log. + * + * @param _MSG + * The message text to write to the log. + */ +!macro LogMsg _MSG + FileWriteUTF16LE $fhInstallLog " ${_MSG}$\r$\n" +!macroend +!define LogMsg "!insertmacro LogMsg" + +/** + * Adds an uninstall entry to the uninstall log. + * + * @param _MSG + * The message text to write to the log. + */ +!macro LogUninstall _MSG + FileWrite $fhUninstallLog "${_MSG}$\r$\n" +!macroend +!define LogUninstall "!insertmacro LogUninstall" + +/** + * Adds a section divider to the human readable log. + */ +!macro WriteLogSeparator + FileWriteUTF16LE $fhInstallLog "$\r$\n----------------------------------------\ + ---------------------------------------$\r$\n" +!macroend +!define WriteLogSeparator "!insertmacro WriteLogSeparator" + + +################################################################################ +# Macros for managing the shortcuts log ini file + +/** + * Adds the most commonly used shortcut logging macros for the installer in one + * fell swoop. + */ +!macro _LoggingShortcutsCommon + !insertmacro LogDesktopShortcut + !insertmacro LogQuickLaunchShortcut + !insertmacro LogSMProgramsShortcut +!macroend +!define _LoggingShortcutsCommon "!insertmacro _LoggingShortcutsCommon" + +/** + * Creates the shortcuts log ini file with a UTF-16LE BOM if it doesn't exist. + */ +!macro initShortcutsLog + Push $R9 + + IfFileExists "$INSTDIR\uninstall\${SHORTCUTS_LOG}" +4 +1 + FileOpen $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" w + FileWriteWord $R9 "65279" + FileClose $R9 + + Pop $R9 +!macroend +!define initShortcutsLog "!insertmacro initShortcutsLog" + +/** + * Adds shortcut entries to the shortcuts log ini file. This macro is primarily + * a helper used by the LogDesktopShortcut, LogQuickLaunchShortcut, and + * LogSMProgramsShortcut macros but it can be used by other code if desired. If + * the value already exists the the value is not written to the file. + * + * @param _SECTION_NAME + * The section name to write to in the shortcut log ini file + * @param _FILE_NAME + * The shortcut's file name + * + * $R6 = return value from ReadIniStr for the shortcut file name + * $R7 = counter for supporting multiple shortcuts in the same location + * $R8 = _SECTION_NAME + * $R9 = _FILE_NAME + */ +!macro LogShortcut + + !ifndef LogShortcut + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define LogShortcut "!insertmacro LogShortcutCall" + + Function LogShortcut + Exch $R9 + Exch 1 + Exch $R8 + Push $R7 + Push $R6 + + ClearErrors + + !insertmacro initShortcutsLog + + StrCpy $R6 "" + StrCpy $R7 -1 + + StrCmp "$R6" "$R9" +5 +1 ; if the shortcut already exists don't add it + IntOp $R7 $R7 + 1 ; increment the counter + ReadIniStr $R6 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7" + IfErrors +1 -3 + WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "$R8" "Shortcut$R7" "$R9" + + ClearErrors + + Pop $R6 + Pop $R7 + Exch $R8 + Exch 1 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro LogShortcutCall _SECTION_NAME _FILE_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_SECTION_NAME}" + Push "${_FILE_NAME}" + Call LogShortcut + !verbose pop +!macroend + +/** + * Adds a Desktop shortcut entry to the shortcuts log ini file. + * + * @param _FILE_NAME + * The shortcut file name (e.g. shortcut.lnk) + */ +!macro LogDesktopShortcut + + !ifndef LogDesktopShortcut + !insertmacro LogShortcut + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define LogDesktopShortcut "!insertmacro LogDesktopShortcutCall" + + Function LogDesktopShortcut + Call LogShortcut + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro LogDesktopShortcutCall _FILE_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "DESKTOP" + Push "${_FILE_NAME}" + Call LogDesktopShortcut + !verbose pop +!macroend + +/** + * Adds a QuickLaunch shortcut entry to the shortcuts log ini file. + * + * @param _FILE_NAME + * The shortcut file name (e.g. shortcut.lnk) + */ +!macro LogQuickLaunchShortcut + + !ifndef LogQuickLaunchShortcut + !insertmacro LogShortcut + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define LogQuickLaunchShortcut "!insertmacro LogQuickLaunchShortcutCall" + + Function LogQuickLaunchShortcut + Call LogShortcut + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro LogQuickLaunchShortcutCall _FILE_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "QUICKLAUNCH" + Push "${_FILE_NAME}" + Call LogQuickLaunchShortcut + !verbose pop +!macroend + +/** + * Adds a Start Menu shortcut entry to the shortcuts log ini file. + * + * @param _FILE_NAME + * The shortcut file name (e.g. shortcut.lnk) + */ +!macro LogStartMenuShortcut + + !ifndef LogStartMenuShortcut + !insertmacro LogShortcut + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define LogStartMenuShortcut "!insertmacro LogStartMenuShortcutCall" + + Function LogStartMenuShortcut + Call LogShortcut + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro LogStartMenuShortcutCall _FILE_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "STARTMENU" + Push "${_FILE_NAME}" + Call LogStartMenuShortcut + !verbose pop +!macroend + +/** + * Adds a Start Menu Programs shortcut entry to the shortcuts log ini file. + * + * @param _FILE_NAME + * The shortcut file name (e.g. shortcut.lnk) + */ +!macro LogSMProgramsShortcut + + !ifndef LogSMProgramsShortcut + !insertmacro LogShortcut + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define LogSMProgramsShortcut "!insertmacro LogSMProgramsShortcutCall" + + Function LogSMProgramsShortcut + Call LogShortcut + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro LogSMProgramsShortcutCall _FILE_NAME + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "SMPROGRAMS" + Push "${_FILE_NAME}" + Call LogSMProgramsShortcut + !verbose pop +!macroend + +/** + * Adds the relative path from the Start Menu Programs directory for the + * application's Start Menu directory if it is different from the existing value + * to the shortcuts log ini file. + * + * @param _REL_PATH_TO_DIR + * The relative path from the Start Menu Programs directory to the + * program's directory. + * + * $R9 = _REL_PATH_TO_DIR + */ +!macro LogSMProgramsDirRelPath _REL_PATH_TO_DIR + Push $R9 + + !insertmacro initShortcutsLog + + ReadINIStr $R9 "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir" + StrCmp "$R9" "${_REL_PATH_TO_DIR}" +2 +1 + WriteINIStr "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" "RelativePathToDir" "${_REL_PATH_TO_DIR}" + + Pop $R9 +!macroend +!define LogSMProgramsDirRelPath "!insertmacro LogSMProgramsDirRelPath" + +/** + * Copies the value for the relative path from the Start Menu programs directory + * (e.g. $SMPROGRAMS) to the Start Menu directory as it is stored in the + * shortcuts log ini file to the variable specified in the first parameter. + */ +!macro GetSMProgramsDirRelPath _VAR + ReadINIStr ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" "SMPROGRAMS" \ + "RelativePathToDir" +!macroend +!define GetSMProgramsDirRelPath "!insertmacro GetSMProgramsDirRelPath" + +/** + * Copies the shortcuts log ini file path to the variable specified in the + * first parameter. + */ +!macro GetShortcutsLogPath _VAR + StrCpy ${_VAR} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" +!macroend +!define GetShortcutsLogPath "!insertmacro GetShortcutsLogPath" + +/** + * Deletes the shortcuts log ini file. + */ +!macro DeleteShortcutsLogFile + ${DeleteFile} "$INSTDIR\uninstall\${SHORTCUTS_LOG}" +!macroend +!define DeleteShortcutsLogFile "!insertmacro DeleteShortcutsLogFile" + + +################################################################################ +# Macros for managing specific Windows version features + +/** + * Sets the permitted layered service provider (LSP) categories on Windows + * Vista and above for the application. Consumers should call this after an + * installation log section has completed since this macro will log the results + * to the installation log along with a header. + * + * !IMPORTANT - When calling this macro from an uninstaller do not specify a + * parameter. The paramter is hardcoded with 0x00000000 to remove + * the LSP category for the application when performing an + * uninstall. + * + * @param _LSP_CATEGORIES + * The permitted LSP categories for the application. When called by an + * uninstaller this will always be 0x00000000. + * + * $R5 = error code popped from the stack for the WSCSetApplicationCategory call + * $R6 = return value from the WSCSetApplicationCategory call + * $R7 = string length for the long path to the main application executable + * $R8 = long path to the main application executable + * $R9 = _LSP_CATEGORIES + */ +!macro SetAppLSPCategories + + !ifndef ${_MOZFUNC_UN}SetAppLSPCategories + !define _MOZFUNC_UN_TMP ${_MOZFUNC_UN} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN ${_MOZFUNC_UN_TMP} + !undef _MOZFUNC_UN_TMP + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define ${_MOZFUNC_UN}SetAppLSPCategories "!insertmacro ${_MOZFUNC_UN}SetAppLSPCategoriesCall" + + Function ${_MOZFUNC_UN}SetAppLSPCategories + ${Unless} ${AtLeastWinVista} + Return + ${EndUnless} + + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + Push $R5 + + Push "$INSTDIR\${FileMainEXE}" + Call ${_MOZFUNC_UN}GetLongPath + Pop $R8 + StrLen $R7 "$R8" + + ; Remove existing categories by setting the permitted categories to + ; 0x00000000 since new categories are ANDed with existing categories. If + ; the param value stored in $R9 is 0x00000000 then skip the removal since + ; the categories will be removed by the second call to + ; WSCSetApplicationCategory. + StrCmp "$R9" "0x00000000" +2 +1 + System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\ + i 0x00000000, i n, *i) i" + + ; Set the permitted LSP categories + System::Call "Ws2_32::WSCSetApplicationCategory(w R8, i R7, w n, i 0,\ + i R9, i n, *i .s) i.R6" + Pop $R5 + +!ifndef NO_LOG + ${LogHeader} "Setting Permitted LSP Categories" + StrCmp "$R6" 0 +3 +1 + ${LogMsg} "** ERROR Setting LSP Categories: $R5 **" + GoTo +2 + ${LogMsg} "Permitted LSP Categories: $R9" +!endif + + ClearErrors + + Pop $R5 + Pop $R6 + Pop $R7 + Pop $R8 + Pop $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro SetAppLSPCategoriesCall _LSP_CATEGORIES + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_LSP_CATEGORIES}" + Call SetAppLSPCategories + !verbose pop +!macroend + +!macro un.SetAppLSPCategoriesCall + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "0x00000000" + Call un.SetAppLSPCategories + !verbose pop +!macroend + +!macro un.SetAppLSPCategories + !ifndef un.SetAppLSPCategories + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !undef _MOZFUNC_UN + !define _MOZFUNC_UN "un." + + !insertmacro SetAppLSPCategories + + !undef _MOZFUNC_UN + !define _MOZFUNC_UN + !verbose pop + !endif +!macroend + +/** + * Gets the number of pinned shortcut lnk files pinned to the Task Bar. + * + * @return _RESULT + * number of pinned shortcut lnk files. + * + * $R7 = file name returned from FindFirst and FindNext + * $R8 = find handle for FindFirst and FindNext + * $R9 = _RESULT + */ +!macro PinnedToTaskBarLnkCount + + !ifndef PinnedToTaskBarLnkCount + + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define PinnedToTaskBarLnkCount "!insertmacro PinnedToTaskBarLnkCountCall" + + Function PinnedToTaskBarLnkCount + Push $R9 + Push $R8 + Push $R7 + + StrCpy $R9 0 + + ${If} ${AtLeastWin7} + ${AndIf} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar" + FindFirst $R8 $R7 "$QUICKLAUNCH\User Pinned\TaskBar\*.lnk" + ${Do} + ${If} ${FileExists} "$QUICKLAUNCH\User Pinned\TaskBar\$R7" + IntOp $R9 $R9 + 1 + ${EndIf} + ClearErrors + FindNext $R8 $R7 + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${Loop} + FindClose $R8 + ${EndIf} + + ClearErrors + + Pop $R7 + Pop $R8 + Exch $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro PinnedToTaskBarLnkCountCall _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Call PinnedToTaskBarLnkCount + Pop ${_RESULT} + !verbose pop +!macroend + +/** + * Update Start Menu / TaskBar lnk files that point to the executable's path + * passed to the macro and all other shortcuts installed by the application with + * the current application user model ID. Requires ApplicationID. + * + * NOTE: this does not update Desktop shortcut application user model ID due to + * bug 633728. + * + * @param _EXE_PATH + * The main application executable path + * @param _APP_ID + * The application user model ID for the current install + * @return _RESULT + * false if no pinned shotcuts were found for this install location. + * true if pinned shotcuts were found for this install location. + */ +!macro UpdateShortcutAppModelIDs + + !ifndef UpdateShortcutAppModelIDs + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + !define UpdateShortcutAppModelIDs "!insertmacro UpdateShortcutAppModelIDsCall" + + Function UpdateShortcutAppModelIDs + ; stack: path, appid + Exch $R9 ; stack: $R9, appid | $R9 = path + Exch 1 ; stack: appid, $R9 + Exch $R8 ; stack: $R8, $R9 | $R8 = appid + Push $R7 ; stack: $R7, $R8, $R9 + Push $R6 + Push $R5 + Push $R4 + Push $R3 ; stack: $R3, $R5, $R6, $R7, $R8, $R9 + Push $R2 + + ; $R9 = main application executable path + ; $R8 = appid + ; $R7 = path to the application's start menu programs directory + ; $R6 = path to the shortcut log ini file + ; $R5 = shortcut filename + ; $R4 = GetShortCutTarget result + + StrCpy $R3 "false" + + ${If} ${AtLeastWin7} + ; installed shortcuts + Push "$INSTDIR\uninstall\${SHORTCUTS_LOG}" + Call ${_MOZFUNC_UN}GetLongPath + Pop $R6 + ${If} ${FileExists} "$R6" + ; Update the Start Menu shortcuts' App ID for this application + StrCpy $R2 -1 + ${Do} + IntOp $R2 $R2 + 1 ; Increment the counter + ClearErrors + ReadINIStr $R5 "$R6" "STARTMENU" "Shortcut$R2" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + + ${If} ${FileExists} "$SMPROGRAMS\$R5" + ShellLink::GetShortCutTarget "$SMPROGRAMS\$$R5" + Pop $R4 + Push $R4 + Call GetLongPath + Pop $R4 + ${If} "$R4" == "$R9" ; link path == install path + ApplicationID::Set "$SMPROGRAMS\$R5" "$R8" + Pop $R4 + ${EndIf} + ${EndIf} + ${Loop} + + ; Update the Quick Launch shortcuts' App ID for this application + StrCpy $R2 -1 + ${Do} + IntOp $R2 $R2 + 1 ; Increment the counter + ClearErrors + ReadINIStr $R5 "$R6" "QUICKLAUNCH" "Shortcut$R2" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + + ${If} ${FileExists} "$QUICKLAUNCH\$R5" + ShellLink::GetShortCutTarget "$QUICKLAUNCH\$R5" + Pop $R4 + Push $R4 + Call GetLongPath + Pop $R4 + ${If} "$R4" == "$R9" ; link path == install path + ApplicationID::Set "$QUICKLAUNCH\$R5" "$R8" + Pop $R4 + ${EndIf} + ${EndIf} + ${Loop} + + ; Update the Start Menu Programs shortcuts' App ID for this application + ClearErrors + ReadINIStr $R7 "$R6" "SMPROGRAMS" "RelativePathToDir" + ${Unless} ${Errors} + Push "$SMPROGRAMS\$R7" + Call ${_MOZFUNC_UN}GetLongPath + Pop $R7 + ${Unless} "$R7" == "" + StrCpy $R2 -1 + ${Do} + IntOp $R2 $R2 + 1 ; Increment the counter + ClearErrors + ReadINIStr $R5 "$R6" "SMPROGRAMS" "Shortcut$R2" + ${If} ${Errors} + ${ExitDo} + ${EndIf} + + ${If} ${FileExists} "$R7\$R5" + ShellLink::GetShortCutTarget "$R7\$R5" + Pop $R4 + Push "$R4" + Call GetLongPath + Pop $R4 + ${If} "$R4" == "$R9" ; link path == install path + ApplicationID::Set "$R7\$R5" "$R8" + Pop $R4 + ${EndIf} + ${EndIf} + ${Loop} + ${EndUnless} + ${EndUnless} + ${EndIf} + + StrCpy $R7 "$QUICKLAUNCH\User Pinned" + StrCpy $R3 "false" + + ; $R9 = main application executable path + ; $R8 = appid + ; $R7 = user pinned path + ; $R6 = find handle + ; $R5 = found filename + ; $R4 = GetShortCutTarget result + + ; TaskBar links + FindFirst $R6 $R5 "$R7\TaskBar\*.lnk" + ${Do} + ${If} ${FileExists} "$R7\TaskBar\$R5" + ShellLink::GetShortCutTarget "$R7\TaskBar\$R5" + Pop $R4 + ${If} "$R4" == "$R9" ; link path == install path + ApplicationID::Set "$R7\TaskBar\$R5" "$R8" + Pop $R4 ; pop Set result off the stack + StrCpy $R3 "true" + ${EndIf} + ${EndIf} + ClearErrors + FindNext $R6 $R5 + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${Loop} + FindClose $R6 + + ; Start menu links + FindFirst $R6 $R5 "$R7\StartMenu\*.lnk" + ${Do} + ${If} ${FileExists} "$R7\StartMenu\$R5" + ShellLink::GetShortCutTarget "$R7\StartMenu\$R5" + Pop $R4 + ${If} "$R4" == "$R9" ; link path == install path + ApplicationID::Set "$R7\StartMenu\$R5" "$R8" + Pop $R4 ; pop Set result off the stack + StrCpy $R3 "true" + ${EndIf} + ${EndIf} + ClearErrors + FindNext $R6 $R5 + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${Loop} + FindClose $R6 + ${EndIf} + + ClearErrors + + StrCpy $R9 $R3 + + Pop $R2 + Pop $R3 ; stack: $R4, $R5, $R6, $R7, $R8, $R9 + Pop $R4 ; stack: $R5, $R6, $R7, $R8, $R9 + Pop $R5 ; stack: $R6, $R7, $R8, $R9 + Pop $R6 ; stack: $R7, $R8, $R9 + Pop $R7 ; stack: $R8, $R9 + Exch $R8 ; stack: appid, $R9 | $R8 = old $R8 + Exch 1 ; stack: $R9, appid + Exch $R9 ; stack: path, appid | $R9 = old $R9 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro UpdateShortcutAppModelIDsCall _EXE_PATH _APP_ID _RESULT + !verbose push + !verbose ${_MOZFUNC_VERBOSE} + Push "${_APP_ID}" + Push "${_EXE_PATH}" + Call UpdateShortcutAppModelIDs + Pop ${_RESULT} + !verbose pop +!macroend diff --git a/app/win/installer/customLocale.nsh b/app/win/installer/customLocale.nsh new file mode 100644 index 0000000000000000000000000000000000000000..26845463580ecb77ed90ca64ad00d05d0805652a GIT binary patch literal 9024 zcmdU#Ur!rH6vgMcpJG)-ZYxz$pZii769Nk0#KsAcDp`OHbpe}VyM$Kx>TS<&Zidd*NQXp=-O>`Ww1!UH4tb zW$p+4%iP!QncLEM-W}=5FK(u*g*()pYd6-2kv^|9-|zaqb#vXB>)E-kzSr-ue$U;# ze%=~`ek!ZB@dEuXQXkA zKht~YxA3bX$BBM(Z>;Aw*O^vX>WyH98$F$A6mKtdccwX!h`ZPN#WgxkHG&z?dFn^n zDhtUm*7${&%WM^;zR*0#5M@NaGrf~(*0G*sl65ADGWo}@ZN^Ni&m=V?cy8b4x(d(D zs?X)8uiSbMcU)KAI+9*^Gk7S|z+I?^9rL@ZQ>|WpFgjUsa_uW7_vTlWr z&lfz1{CpCLtT$_D%f8!{&3c->qg9TSfz7naG@5l{#*!Bc$xv;*^jaw`$t{cUOg1NL zEau6bJw-bClU{is?;gloJ@>wWhD+tewN|{9*HZda&04KX&ucRB*s+k@cx~ZVBKJT5 zyT1B_2N$}VM#$#!?I}nN~CW4xb13%ra5{i36TtxCE|+m8vdA80YA>ABX5An z0S&o2^ZvA4|8WBwQ%|-Ov0dpg^ws5!B5}|ELZ70JQ8OxlA#}9%OnD!Wkt#qOT`Q`I zW2+0q0JX)m<^A9EbmC{C9+T-_m-iC@yNg ziN3_=E03ul`HrpzidK**dUN1f$`dS|&W%j|qb6T_FH%*h?@Pra*;Zx@c>S^YG!%mF z%M%?*A0_Q*t%)M*Qup=>*`1FbtMyY!Hg=oXY9KUxsn~D(s#h-om~F_3EgmaD&%Kpr zz|m0kqrNTOgRg-R@GGnghr-^0gODAtjSGE8#*y}9wO96igdEE5yA=|_TZlQZk8FEgtx^){)3vY+>fi)Md4#`VpChDs@RvY z=enx(f3)QK9I3P6#AEe|BE-11G1Oa+n^w&)RGB`%J&1ES5m;z!>MDoUum~7%;8URo zU@R(D6eG zF|1#y2}*9uPJOL5)F(S(EEQ2XZKb&^h#VmGq#y|uie1r-X^Jnf)$&PpW^68EKtb<3!z4dYSQKKxw>2JZhZyV+!d!NWa*6sIF zb;BaCYG+rh!RQrt;`yCyd3Q%1fm>r?4oGA?w_HEanjL1^rg&vrBO{vKd0&#Tmc^`e zsu6S$13&#K!QUd5HL+iQ2N9$1OWUrvFZp-u_CmB<}3! z$+5f=Iw&s`7xbqr>hPRly4A5Vrl%PGX7Ye6J0*GYSl97!1*Wn)3l)NII(hXK39a%B zpr@JW_0u7-*}~O{s`iP;gjCHXcd<16W9--yj?{G@2f~@vN|4X59c3fC&v1TFjm>qd zr+awx&5d!SR?qkN@AU?!1m!-{<~Ay$o>h_^AHN4$BgA7~y4b4?)?s&E?C6zI%&;(? zRfITsYG-e~{p)%t>-=xAXM1ZpZ1sH0jPH^a%Q+4P&PTU{$(xK_D8Rql=L~N&GezJ zd_IF*QR5i9R);S2jJ^J)q=%hwB1bl`e}%Wfeea~zt?t+eyff2yxE`#bi3O;PR)^>^ zSSJ?A=b!e$)XYoGH-5k`V}eA0^;dW+^jzsy$9^wzveTf0frnOm+04PtgAvqS&fm!0 z$FU}6iwJuzuZI)ERPJy2F2tdtvFCAeSHI|j4E24iIE5L(D)X$76CwCMmNpH>?t{0P zWd=I&#JCPf87`cSa45gh{?g6Zp>O(!Xy4&2MMUB^6v*TyBN?nbTtLHIW SvgMJtWgZ1ux|`qcFyB9rb?@o` literal 0 HcmV?d00001 diff --git a/app/win/installer/defines.nsi b/app/win/installer/defines.nsi new file mode 100644 index 0000000000..18ab264f42 --- /dev/null +++ b/app/win/installer/defines.nsi @@ -0,0 +1,81 @@ +#filter substitution +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Win7: AppVendor, AppName, and AppVersion must match the application.ini values +# of Vendor, Name, and Version. These values are used in registering shortcuts +# with the taskbar. ExplicitAppUserModelID registration when the app launches is +# handled in widget/src/windows/WinTaskbar.cpp. + +!define AppVendor "Zotero" +!define AppName "Zotero" +!define AppVersion "{{VERSION}}" +!define AppUserModelID "${AppVendor}.${AppName}.${AppVersion}" +!define GREVersion 2.0 +!define AB_CD "en-US" + +!define FileMainEXE "zotero.exe" +!define WindowClass "ZoteroMessageWindow" +!define AppRegName "Zotero" + +!define BrandShortName "Zotero" +!define PreReleaseSuffix "" +!define BrandFullName "${BrandFullNameInternal}${PreReleaseSuffix}" + +!define NO_UNINSTALL_SURVEY + +# LSP_CATEGORIES is the permitted LSP categories for the application. Each LSP +# category value is ANDed together to set multiple permitted categories. +# See http://msdn.microsoft.com/en-us/library/ms742253%28VS.85%29.aspx +# The value below removes all LSP categories previously set. +!define LSP_CATEGORIES "0x00000000" + +# NO_INSTDIR_FROM_REG is defined for pre-releases which have a PreReleaseSuffix +# (e.g. Alpha X, Beta X, etc.) to prevent finding a non-default installation +# directory in the registry and using that as the default. This prevents +# Beta releases built with official branding from finding an existing install +# of an official release and defaulting to its installation directory. +!if "@PRE_RELEASE_SUFFIX@" != "" +!define NO_INSTDIR_FROM_REG +!endif + +# ARCH is used when it is necessary to differentiate the x64 registry keys from +# the x86 registry keys (e.g. the uninstall registry key). +!ifdef HAVE_64BIT_OS + !define ARCH "x86" + !define MinSupportedVer "64-bit Microsoft Windows 7" +!else + !define ARCH "x64" + !define MinSupportedVer "Microsoft Windows 7" +!endif + +# File details shared by both the installer and uninstaller +VIProductVersion "1.0.0.0" +VIAddVersionKey "ProductName" "${BrandShortName}" +VIAddVersionKey "CompanyName" "${CompanyName}" +VIAddVersionKey "LegalCopyright" "${CompanyName}" +VIAddVersionKey "FileVersion" "${AppVersion}" +VIAddVersionKey "ProductVersion" "${AppVersion}" +# Comments is not used but left below commented out for future reference +# VIAddVersionKey "Comments" "Comments" + +# These are used for keeping track of user preferences. They are set to a +# default value in the installer's .OnInit callback, and then conditionally +# modified through the UI or an .ini file. + +!define DESKTOP_SHORTCUT_DISABLED 0 +!define DESKTOP_SHORTCUT_ENABLED 1 +!define DESKTOP_SHORTCUT_DEFAULT ${DESKTOP_SHORTCUT_ENABLED} + +!define START_MENU_SHORTCUT_DISABLED 0 +!define START_MENU_SHORTCUT_ENABLED 1 +!define START_MENU_SHORTCUT_DEFAULT ${START_MENU_SHORTCUT_ENABLED} + +!define QUICKLAUNCH_SHORTCUT_DISABLED 0 +!define QUICKLAUNCH_SHORTCUT_ENABLED 1 +!define QUICKLAUNCH_SHORTCUT_DEFAULT ${QUICKLAUNCH_SHORTCUT_ENABLED} + +!define INSTALLTYPE_BASIC 1 +!define INSTALLTYPE_CUSTOM 2 +!define INSTALLTYPE_DEFAULT ${INSTALLTYPE_BASIC} diff --git a/app/win/installer/installer.nsi b/app/win/installer/installer.nsi new file mode 100755 index 0000000000..c59166588a --- /dev/null +++ b/app/win/installer/installer.nsi @@ -0,0 +1,1069 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +# Required Plugins: +# AppAssocReg http://nsis.sourceforge.net/Application_Association_Registration_plug-in +# ApplicationID http://nsis.sourceforge.net/ApplicationID_plug-in +# ShellLink http://nsis.sourceforge.net/ShellLink_plug-in +# UAC http://nsis.sourceforge.net/UAC_plug-in + +; Set verbosity to 2 to lessen the noise in the build logs +!verbose 2 + +; TODO 7-Zip provides better compression than the lzma from NSIS so we add the files +; uncompressed and use 7-Zip to create a SFX archive of it +SetDatablockOptimize on +SetCompress off +#SetCompressor lzma +CRCCheck on + +RequestExecutionLevel user + +!addplugindir ./ + +Var PageName + +; These user preferences are initialized to default values in .onInit. They +; should only be changed in the UI, .ini handler, or command-line argument +; handlers. +Var AddDesktopSC +Var AddQuickLaunchSC +Var AddStartMenuSC +Var InstallType + +; By defining NO_STARTMENU_DIR an installer that doesn't provide an option for +; an application's Start Menu PROGRAMS directory and doesn't define the +; StartMenuDir variable can use the common InstallOnInitCommon macro. +!define NO_STARTMENU_DIR + +; On Vista and above attempt to elevate Standard Users in addition to users that +; are a member of the Administrators group. +!define NONADMIN_ELEVATE + +!define AbortSurveyURL "http://www.kampyle.com/feedback_form/ff-feedback-form.php?site_code=8166124&form_id=12116&url=" + +; Other included files may depend upon these includes! +; The following includes are provided by NSIS. +!include FileFunc.nsh +!include LogicLib.nsh +!include MUI.nsh +!include WinMessages.nsh +!include WinVer.nsh +!include WordFunc.nsh + +!insertmacro GetOptions +!insertmacro GetParameters +!insertmacro GetSize +!insertmacro StrFilter +!insertmacro WordFind +!insertmacro WordReplace + +; The following includes are custom. +!include branding.nsi +!include defines.nsi +!include common.nsh +!include locales.nsi + +VIAddVersionKey "FileDescription" "${BrandShortName} Installer" +VIAddVersionKey "OriginalFilename" "setup.exe" + +; Must be inserted before other macros that use logging +!insertmacro _LoggingCommon + +!insertmacro AddHandlerValues +!insertmacro CanWriteToInstallDir +!insertmacro ChangeMUIHeaderImage +!insertmacro CheckDiskSpace +!insertmacro CheckForFilesInUse +!insertmacro CleanUpdatesDir +!insertmacro CopyFilesFromDir +!insertmacro GetParent +!insertmacro GetPathFromString +!insertmacro IsHandlerForInstallDir +!insertmacro LogDesktopShortcut +!insertmacro LogQuickLaunchShortcut +!insertmacro LogStartMenuShortcut +!insertmacro ManualCloseAppPrompt +!insertmacro RegCleanMain +!insertmacro RegCleanUninstall +!insertmacro SetAppLSPCategories +!insertmacro SetBrandNameVars +!insertmacro UnloadUAC +!insertmacro UpdateShortcutAppModelIDs +!insertmacro WriteRegDWORD2 +!insertmacro WriteRegStr2 + +!include shared.nsh + +; Helper macros for ui callbacks. Insert these after shared.nsh +!insertmacro InstallEndCleanupCommon +!insertmacro InstallOnInitCommon +!insertmacro InstallStartCleanupCommon +!insertmacro LeaveOptionsCommon +!insertmacro OnEndCommon + +Name "${BrandFullName}" +OutFile "setup.exe" +!ifdef HAVE_64BIT_OS + InstallDir "$PROGRAMFILES64\${BrandFullName}\" +!else + InstallDir "$PROGRAMFILES32\${BrandFullName}\" +!endif +ShowInstDetails nevershow + +################################################################################ +# Modern User Interface - MUI + +!define MOZ_MUI_CUSTOM_ABORT +!define MUI_CUSTOMFUNCTION_ABORT "CustomAbort" +!define MUI_ICON setup.ico +!define MUI_UNICON setup.ico +!define MUI_WELCOMEPAGE_TITLE_3LINES +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_RIGHT +#TODO !define MUI_WELCOMEFINISHPAGE_BITMAP wizWatermark.bmp + +; Use a right to left header image when the language is right to left +#TODO !ifdef ${AB_CD}_rtl +#TODO !define MUI_HEADERIMAGE_BITMAP_RTL wizHeaderRTL.bmp +#TODO !else +#TODO !define MUI_HEADERIMAGE_BITMAP wizHeader.bmp +#TODO !endif + +/** + * Installation Pages + */ +; Welcome Page +!define MUI_PAGE_CUSTOMFUNCTION_PRE preWelcome +!insertmacro MUI_PAGE_WELCOME + +; Custom Options Page +Page custom preOptions leaveOptions + +; Select Install Directory Page +!define MUI_PAGE_CUSTOMFUNCTION_PRE preDirectory +!define MUI_PAGE_CUSTOMFUNCTION_LEAVE leaveDirectory +!define MUI_DIRECTORYPAGE_VERIFYONLEAVE +!insertmacro MUI_PAGE_DIRECTORY + +; Custom Shortcuts Page +Page custom preShortcuts leaveShortcuts + +; Custom Summary Page +Page custom preSummary + +; Install Files Page +!insertmacro MUI_PAGE_INSTFILES + +; Finish Page +!define MUI_FINISHPAGE_TITLE_3LINES +!define MUI_FINISHPAGE_RUN +!define MUI_FINISHPAGE_RUN_FUNCTION LaunchApp +!define MUI_FINISHPAGE_RUN_TEXT $(LAUNCH_TEXT) +!define MUI_PAGE_CUSTOMFUNCTION_PRE preFinish +!insertmacro MUI_PAGE_FINISH + +; Use the default dialog for IDD_VERIFY for a simple Banner +ChangeUI IDD_VERIFY "${NSISDIR}\Contrib\UIs\default.exe" + +; If a version beginning with $R1 is installed, uninstall that. +; This is used to uninstall the old Zotero Standalone installer and a 32-bit version on 64-bit Windows +Function UninstallOld + Push $R1 + Push $R2 + StrCpy $0 0 + + enum_uninst_keys: + EnumRegKey $1 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall" $0 + StrCmp $1 "" continue_installation + ; $R1 migth be "Zotero Standalone" or "Zotero", registry key name contains version and locale e.g. "Zotero 6.0.0 (x86 en-US)" so: + StrLen $3 $R1 ; $3 = length of $R1, e.g. 17 for "Zotero Standalone" + StrCpy $2 $1 $3 ; $2 = first $3 characters of $1, i.e. name without version and locale, e.g. "Zotero Standalone" + StrCmp $2 $R1 get_uninst_exe ; if the key we found is the one we're looking for (e.g. "Zotero Standalone"), go to get_uninst_exe + IntOp $0 $0 + 1 + Goto enum_uninst_keys ; loop through all keys + + get_uninst_exe: + ReadRegStr $2 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$1" "UninstallString" + ReadRegStr $3 HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\$1" "InstallLocation" + + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION \ + $R2 \ + /SD IDOK IDOK uninst + Abort + + uninst: + ; This doesn't actually wait, since the uninstaller copies itself to a temp folder, runs that, + ; and exits, so give it a few seconds to finish + ExecWait '"$2" /S' + Sleep 3000 + + ; Files that were added by an in-app update won't be automatically deleted by the 4.0 uninstaller, + ; so manually delete everything we know about as long as the directory name begins with "Zotero". + ; We don't just delete the directory because we don't know for sure that the user didn't do + ; something crazy like put their data directory in it. + ${GetFileName} $3 $4 + StrCpy $5 $4 6 + StrCmp $5 "Zotero" +1 continue_installation + RMDir /r /REBOOTOK "$3\chrome" + RMDir /r /REBOOTOK "$3\components" + RMDir /r /REBOOTOK "$3\defaults" + RMDir /r /REBOOTOK "$3\dictionaries" + RMDir /r /REBOOTOK "$3\extensions" + RMDir /r /REBOOTOK "$3\fonts" + RMDir /r /REBOOTOK "$3\gmp-clearkey" + RMDir /r /REBOOTOK "$3\uninstall" + RMDir /r /REBOOTOK "$3\xulrunner" + Delete /REBOOTOK "$3\*.chk" + Delete /REBOOTOK "$3\*.dll" + Delete /REBOOTOK "$3\*.exe" + Delete /REBOOTOK "$3\Accessible.tlb" + Delete /REBOOTOK "$3\dependentlibs.list" + Delete /REBOOTOK "$3\firefox.VisualElementsManifest.xml" + Delete /REBOOTOK "$3\omni.ja" + Delete /REBOOTOK "$3\platform.ini" + Delete /REBOOTOK "$3\precomplete" + Delete /REBOOTOK "$3\voucher.bin" + RMDir /REBOOTOK $3 + continue_installation: + ; End uninstallation + Pop $R2 + Pop $R1 +FunctionEnd + +################################################################################ +# Install Sections + +; Cleanup operations to perform at the start of the installation. +Section "-InstallStartCleanup" + ; I don't know that software upgrades are working correctly, but this + ; ensures that CheckExistingInstall always gets called. + IfSilent +1 non_silent + ; code from options page that needs to execute + ${LeaveOptionsCommon} + + ; code from last page shown (depending on installtype) that needs to + ; execute. + Call CheckExistingInstall + + Push $R9 + ${CanWriteToInstallDir} $R9 + ${If} $R9 == "false" + ; TODO: write to log file + Abort + ${EndIf} + + ${CheckDiskSpace} $R9 + ${If} $R9 == "false" + ; TODO: write to log file + Abort + ${EndIf} + Pop $R9 + + non_silent: + ; Try to delete the app executable and if we can't delete it try to find the + ; app's message window and prompt the user to close the app. This allows + ; running an instance that is located in another directory. If for whatever + ; reason there is no message window we will just rename the app's files and + ; then remove them on restart. + ClearErrors + ${DeleteFile} "$INSTDIR\${FileMainEXE}" + ${If} ${Errors} + ${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_INSTALL)" + ${EndIf} + + SetDetailsPrint both + DetailPrint $(STATUS_CLEANUP) + SetDetailsPrint none + + SetOutPath "$INSTDIR" + ${StartInstallLog} "${BrandFullName}" "${AB_CD}" "${AppVersion}" "${GREVersion}" + + ; Delete the app exe to prevent launching the app while we are installing. + ClearErrors + ${DeleteFile} "$INSTDIR\${FileMainEXE}" + ${If} ${Errors} + ; If the user closed the application it can take several seconds for it to + ; shut down completely. If the application is being used by another user we + ; can rename the file and then delete is when the system is restarted. + Sleep 5000 + ${DeleteFile} "$INSTDIR\${FileMainEXE}" + ClearErrors + ${EndIf} + + ; Remove the updates directory for Vista and above + ${CleanUpdatesDir} "Zotero\Zotero" + + + ${InstallStartCleanupCommon} +SectionEnd + +Section "-Application" APP_IDX + ${StartUninstallLog} + + SetDetailsPrint both + DetailPrint $(STATUS_INSTALL_APP) + SetDetailsPrint none + + ${LogHeader} "Installing Main Files" + ${CopyFilesFromDir} "$EXEDIR\core" "$INSTDIR" \ + "$(ERROR_CREATE_DIRECTORY_PREFIX)" \ + "$(ERROR_CREATE_DIRECTORY_SUFFIX)" + + ; Register DLLs + ; XXXrstrong - AccessibleMarshal.dll can be used by multiple applications but + ; is only registered for the last application installed. When the last + ; application installed is uninstalled AccessibleMarshal.dll will no longer be + ; registered. bug 338878 + ${LogHeader} "DLL Registration" + ClearErrors + ${RegisterDLL} "$INSTDIR\AccessibleMarshal.dll" + ${If} ${Errors} + ${LogMsg} "** ERROR Registering: $INSTDIR\AccessibleMarshal.dll **" + ${Else} + ${LogUninstall} "DLLReg: \AccessibleMarshal.dll" + ${LogMsg} "Registered: $INSTDIR\AccessibleMarshal.dll" + ${EndIf} + + ; Write extra files created by the application to the uninstall log so they + ; will be removed when the application is uninstalled. To remove an empty + ; directory write a bogus filename to the deepest directory and all empty + ; parent directories will be removed. + ${LogUninstall} "File: \components\compreg.dat" + ${LogUninstall} "File: \components\xpti.dat" + ${LogUninstall} "File: \active-update.xml" + ${LogUninstall} "File: \install.log" + ${LogUninstall} "File: \install_status.log" + ${LogUninstall} "File: \install_wizard.log" + ${LogUninstall} "File: \updates.xml" + + ClearErrors + + ${LogHeader} "Adding Registry Entries" + SetShellVarContext current ; Set SHCTX to HKCU + ${RegCleanMain} "Software\Zotero" + ${RegCleanUninstall} + ${UpdateProtocolHandlers} + + ClearErrors + WriteRegStr HKLM "Software\Zotero" "${BrandShortName}InstallerTest" "Write Test" + ${If} ${Errors} + StrCpy $TmpVal "HKCU" ; used primarily for logging + ${Else} + SetShellVarContext all ; Set SHCTX to HKLM + DeleteRegValue HKLM "Software\Zotero" "${BrandShortName}InstallerTest" + StrCpy $TmpVal "HKLM" ; used primarily for logging + ${RegCleanMain} "Software\Zotero" + ${RegCleanUninstall} + ${UpdateProtocolHandlers} + + ReadRegStr $0 HKLM "Software\zotero.org\Zotero" "CurrentVersion" + ${If} "$0" != "${GREVersion}" + WriteRegStr HKLM "Software\zotero.org\Zotero" "CurrentVersion" "${GREVersion}" + ${EndIf} + ${EndIf} + + ; The order that reg keys and values are added is important if you use the + ; uninstall log to remove them on uninstall. When using the uninstall log you + ; MUST add children first so they will be removed first on uninstall so they + ; will be empty when the key is deleted. This allows the uninstaller to + ; specify that only empty keys will be deleted. + ${SetAppKeys} + + ${FixClassKeys} + + ; Uninstall keys can only exist under HKLM on some versions of windows. Since + ; it doesn't cause problems always add them. + ${SetUninstallKeys} + + ; Register zotero protocol handler + ${SetHandlers} + + ; These need special handling on uninstall since they may be overwritten by + ; an install into a different location. + StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}" + ${WriteRegStr2} $TmpVal "$0" "" "$INSTDIR\${FileMainEXE}" 0 + ${WriteRegStr2} $TmpVal "$0" "Path" "$INSTDIR" 0 + + ${If} $TmpVal == "HKLM" + ; Set the permitted LSP Categories for WinVista and above + ${SetAppLSPCategories} ${LSP_CATEGORIES} + ${EndIf} + + ; Create shortcuts + ${LogHeader} "Adding Shortcuts" + + ; Remove the start menu shortcuts and directory if the SMPROGRAMS section + ; exists in the shortcuts_log.ini and the SMPROGRAMS. The installer's shortcut + ; creation code will create the shortcut in the root of the Start Menu + ; Programs directory. + ${RemoveStartMenuDir} + + ; Always add the application's shortcuts to the shortcuts log ini file. The + ; DeleteShortcuts macro will do the right thing on uninstall if the + ; shortcuts don't exist. + ${LogStartMenuShortcut} "${BrandFullName}.lnk" + ${LogQuickLaunchShortcut} "${BrandFullName}.lnk" + ${LogDesktopShortcut} "${BrandFullName}.lnk" + + ; Best effort to update the Win7 taskbar and start menu shortcut app model + ; id's. The possible contexts are current user / system and the user that + ; elevated the installer. + Call FixShortcutAppModelIDs + ; If the current context is all also perform Win7 taskbar and start menu link + ; maintenance for the current user context. + ${If} $TmpVal == "HKLM" + SetShellVarContext current ; Set SHCTX to HKCU + Call FixShortcutAppModelIDs + SetShellVarContext all ; Set SHCTX to HKLM + ${EndIf} + + ; If running elevated also perform Win7 taskbar and start menu link + ; maintenance for the unelevated user context in case that is different than + ; the current user. + ClearErrors + ${GetParameters} $0 + ${GetOptions} "$0" "/UAC:" $0 + ${Unless} ${Errors} + GetFunctionAddress $0 FixShortcutAppModelIDs + UAC::ExecCodeSegment $0 + ${EndUnless} + + ; UAC only allows elevating to an Admin account so there is no need to add + ; the Start Menu or Desktop shortcuts from the original unelevated process + ; since this will either add it for the user if unelevated or All Users if + ; elevated. + ${If} $AddStartMenuSC == ${START_MENU_SHORTCUT_ENABLED} + CreateShortCut "$SMPROGRAMS\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" + ${If} ${FileExists} "$SMPROGRAMS\${BrandFullName}.lnk" + ShellLink::SetShortCutWorkingDirectory "$SMPROGRAMS\${BrandFullName}.lnk" \ + "$INSTDIR" + ${If} ${AtLeastWin7} + ApplicationID::Set "$SMPROGRAMS\${BrandFullName}.lnk" "${AppUserModelID}" + ${EndIf} + ${LogMsg} "Added Shortcut: $SMPROGRAMS\${BrandFullName}.lnk" + ${Else} + ${LogMsg} "** ERROR Adding Shortcut: $SMPROGRAMS\${BrandFullName}.lnk" + ${EndIf} + ${EndIf} + + ${If} $AddDesktopSC == ${DESKTOP_SHORTCUT_ENABLED} + CreateShortCut "$DESKTOP\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" + ${If} ${FileExists} "$DESKTOP\${BrandFullName}.lnk" + ShellLink::SetShortCutWorkingDirectory "$DESKTOP\${BrandFullName}.lnk" \ + "$INSTDIR" + ${If} ${AtLeastWin7} + ApplicationID::Set "$DESKTOP\${BrandFullName}.lnk" "${AppUserModelID}" + ${EndIf} + ${LogMsg} "Added Shortcut: $DESKTOP\${BrandFullName}.lnk" + ${Else} + ${LogMsg} "** ERROR Adding Shortcut: $DESKTOP\${BrandFullName}.lnk" + ${EndIf} + ${EndIf} + + ; If elevated the Quick Launch shortcut must be added from the unelevated + ; original process. + ${If} $AddQuickLaunchSC == ${QUICKLAUNCH_SHORTCUT_ENABLED} + ${Unless} ${AtLeastWin7} + ClearErrors + ${GetParameters} $0 + ${GetOptions} "$0" "/UAC:" $0 + ${If} ${Errors} + Call AddQuickLaunchShortcut + ${LogMsg} "Added Shortcut: $QUICKLAUNCH\${BrandFullName}.lnk" + ${Else} + ; It is not possible to add a log entry from the unelevated process so + ; add the log entry without the path since there is no simple way to + ; know the correct full path. + ${LogMsg} "Added Quick Launch Shortcut: ${BrandFullName}.lnk" + GetFunctionAddress $0 AddQuickLaunchShortcut + UAC::ExecCodeSegment $0 + ${EndIf} + ${EndUnless} + ${EndIf} +SectionEnd + +; Cleanup operations to perform at the end of the installation. +Section "-InstallEndCleanup" + SetDetailsPrint both + DetailPrint "$(STATUS_CLEANUP)" + SetDetailsPrint none + + ; Refresh desktop icons + System::Call "shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i ${SHCNF_DWORDFLUSH}, i 0, i 0)" + + ${InstallEndCleanupCommon} + + ${If} ${RebootFlag} + ; When a reboot is required give SHChangeNotify time to finish the + ; refreshing the icons so the OS doesn't display the icons from helper.exe + Sleep 10000 + ${LogHeader} "Reboot Required To Finish Installation" + ; ${FileMainEXE}.moz-upgrade should never exist but just in case... + ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-upgrade" + Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-upgrade" + ${EndUnless} + + ${If} ${FileExists} "$INSTDIR\${FileMainEXE}" + ClearErrors + Rename "$INSTDIR\${FileMainEXE}" "$INSTDIR\${FileMainEXE}.moz-delete" + ${Unless} ${Errors} + Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete" + ${EndUnless} + ${EndIf} + + ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}" + CopyFiles /SILENT "$INSTDIR\uninstall\helper.exe" "$INSTDIR" + FileOpen $0 "$INSTDIR\${FileMainEXE}" w + FileWrite $0 "Will be deleted on restart" + Rename /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-upgrade" "$INSTDIR\${FileMainEXE}" + FileClose $0 + Delete "$INSTDIR\${FileMainEXE}" + Rename "$INSTDIR\helper.exe" "$INSTDIR\${FileMainEXE}" + ${EndUnless} + ${EndIf} +SectionEnd + +################################################################################ +# Install Abort Survey Functions + +Function CustomAbort + ${If} "${AB_CD}" == "en-US" + ${AndIf} "$PageName" != "" + ${AndIf} ${FileExists} "$EXEDIR\core\distribution\distribution.ini" + ReadINIStr $0 "$EXEDIR\core\distribution\distribution.ini" "Global" "about" + ClearErrors + ${WordFind} "$0" "Funnelcake" "E#" $1 + ${Unless} ${Errors} + ; Yes = fill out the survey and exit, No = don't fill out survey and exit, + ; Cancel = don't exit. + MessageBox MB_YESNO|MB_ICONEXCLAMATION \ + "Would you like to tell us why you are canceling this installation?" \ + IDYes +1 IDNO CustomAbort_finish + ${If} "$PageName" == "Welcome" + GetFunctionAddress $0 AbortSurveyWelcome + ${ElseIf} "$PageName" == "Options" + GetFunctionAddress $0 AbortSurveyOptions + ${ElseIf} "$PageName" == "Directory" + GetFunctionAddress $0 AbortSurveyDirectory + ${ElseIf} "$PageName" == "Shortcuts" + GetFunctionAddress $0 AbortSurveyShortcuts + ${ElseIf} "$PageName" == "Summary" + GetFunctionAddress $0 AbortSurveySummary + ${EndIf} + ClearErrors + ${GetParameters} $1 + ${GetOptions} "$1" "/UAC:" $2 + ${If} ${Errors} + Call $0 + ${Else} + UAC::ExecCodeSegment $0 + ${EndIf} + + CustomAbort_finish: + Return + ${EndUnless} + ${EndIf} + + MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(MOZ_MUI_TEXT_ABORTWARNING)" \ + IDYES +1 IDNO +2 + Return + Abort +FunctionEnd + +Function AbortSurveyWelcome + ExecShell "open" "${AbortSurveyURL}step1" +FunctionEnd + +Function AbortSurveyOptions + ExecShell "open" "${AbortSurveyURL}step2" +FunctionEnd + +Function AbortSurveyDirectory + ExecShell "open" "${AbortSurveyURL}step3" +FunctionEnd + +Function AbortSurveyShortcuts + ExecShell "open" "${AbortSurveyURL}step4" +FunctionEnd + +Function AbortSurveySummary + ExecShell "open" "${AbortSurveyURL}step5" +FunctionEnd + +################################################################################ +# Helper Functions + +Function AddQuickLaunchShortcut + CreateShortCut "$QUICKLAUNCH\${BrandFullName}.lnk" "$INSTDIR\${FileMainEXE}" + ${If} ${FileExists} "$QUICKLAUNCH\${BrandFullName}.lnk" + ShellLink::SetShortCutWorkingDirectory "$QUICKLAUNCH\${BrandFullName}.lnk" \ + "$INSTDIR" + ${EndIf} +FunctionEnd + +Function CheckExistingInstall + ; If there is a pending file copy from a previous upgrade don't allow + ; installing until after the system has rebooted. + IfFileExists "$INSTDIR\${FileMainEXE}.moz-upgrade" +1 +4 + MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2 + Reboot + Quit + + ; If there is a pending file deletion from a previous uninstall don't allow + ; installing until after the system has rebooted. + IfFileExists "$INSTDIR\${FileMainEXE}.moz-delete" +1 +4 + MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UNINSTALL)" IDNO +2 + Reboot + Quit + + ${If} ${FileExists} "$INSTDIR\${FileMainEXE}" + ; Disable the next, cancel, and back buttons + GetDlgItem $0 $HWNDPARENT 1 ; Next button + EnableWindow $0 0 + GetDlgItem $0 $HWNDPARENT 2 ; Cancel button + EnableWindow $0 0 + GetDlgItem $0 $HWNDPARENT 3 ; Back button + EnableWindow $0 0 + + Banner::show /NOUNLOAD "$(BANNER_CHECK_EXISTING)" + + ${If} "$TmpVal" == "FoundMessageWindow" + Sleep 5000 + ${EndIf} + + ${PushFilesToCheck} + + ; Store the return value in $TmpVal so it is less likely to be accidentally + ; overwritten elsewhere. + ${CheckForFilesInUse} $TmpVal + + Banner::destroy + + ; Enable the next, cancel, and back buttons + GetDlgItem $0 $HWNDPARENT 1 ; Next button + EnableWindow $0 1 + GetDlgItem $0 $HWNDPARENT 2 ; Cancel button + EnableWindow $0 1 + GetDlgItem $0 $HWNDPARENT 3 ; Back button + EnableWindow $0 1 + + ${If} "$TmpVal" == "true" + StrCpy $TmpVal "FoundMessageWindow" + ${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_INSTALL)" + StrCpy $TmpVal "true" + ${EndIf} + ${EndIf} +FunctionEnd + +Function LaunchApp + ${ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_LAUNCH)" + + ClearErrors + ${GetParameters} $0 + ${GetOptions} "$0" "/UAC:" $1 + ${If} ${Errors} + Exec "$\"$INSTDIR\${FileMainEXE}$\"" + ${Else} + GetFunctionAddress $0 LaunchAppFromElevatedProcess + UAC::ExecCodeSegment $0 + ${EndIf} +FunctionEnd + +Function LaunchAppFromElevatedProcess + ; Find the installation directory when launching using GetFunctionAddress + ; from an elevated installer since $INSTDIR will not be set in this installer + ReadRegStr $0 HKLM "Software\Classes\zotero\DefaultIcon" "" + ${GetPathFromString} "$0" $0 + ${GetParent} "$0" $1 + ; Set our current working directory to the application's install directory + ; otherwise the 7-Zip temp directory will be in use and won't be deleted. + SetOutPath "$1" + Exec "$\"$0$\"" +FunctionEnd + +################################################################################ +# Language + +!insertmacro MOZ_MUI_LANGUAGE 'baseLocale' +!verbose push +!verbose 3 +!include "overrideLocale.nsh" +!include "customLocale.nsh" +!verbose pop + +; Set this after the locale files to override it if it is in the locale +; using " " for BrandingText will hide the "Nullsoft Install System..." branding +BrandingText " " + +################################################################################ +# Page pre, show, and leave functions + +Function preWelcome + StrCpy $PageName "Welcome" + ${If} ${FileExists} "$EXEDIR\core\distribution\modern-wizard.bmp" + Delete "$PLUGINSDIR\modern-wizard.bmp" + CopyFiles /SILENT "$EXEDIR\core\distribution\modern-wizard.bmp" "$PLUGINSDIR\modern-wizard.bmp" + ${EndIf} +FunctionEnd + +Function preOptions + StrCpy $PageName "Options" + ${If} ${FileExists} "$EXEDIR\core\distribution\modern-header.bmp" + ${AndIf} $hHeaderBitmap == "" + Delete "$PLUGINSDIR\modern-header.bmp" + CopyFiles /SILENT "$EXEDIR\core\distribution\modern-header.bmp" "$PLUGINSDIR\modern-header.bmp" + ${ChangeMUIHeaderImage} "$PLUGINSDIR\modern-header.bmp" + ${EndIf} + !insertmacro MUI_HEADER_TEXT "$(OPTIONS_PAGE_TITLE)" "$(OPTIONS_PAGE_SUBTITLE)" + !insertmacro MUI_INSTALLOPTIONS_DISPLAY "options.ini" +FunctionEnd + +Function leaveOptions + ${MUI_INSTALLOPTIONS_READ} $0 "options.ini" "Settings" "State" + ${If} $0 != 0 + Abort + ${EndIf} + ${MUI_INSTALLOPTIONS_READ} $R0 "options.ini" "Field 2" "State" + StrCmp $R0 "1" +1 +2 + StrCpy $InstallType ${INSTALLTYPE_BASIC} + ${MUI_INSTALLOPTIONS_READ} $R0 "options.ini" "Field 3" "State" + StrCmp $R0 "1" +1 +2 + StrCpy $InstallType ${INSTALLTYPE_CUSTOM} + + ${LeaveOptionsCommon} + + ${If} $InstallType == ${INSTALLTYPE_BASIC} + Call CheckExistingInstall + ${EndIf} +FunctionEnd + +Function preDirectory + StrCpy $PageName "Directory" + Push $R9 + + ; Skip page if currently drive space and disk access exist for currently + ; selected install path. + IntCmp $InstallType ${INSTALLTYPE_CUSTOM} end +1 +1 + ${CanWriteToInstallDir} $R9 + StrCmp "$R9" "false" end +1 + ${CheckDiskSpace} $R9 + StrCmp "$R9" "false" end +1 + Abort + + end: + + Pop $R9 +FunctionEnd + +Function leaveDirectory + ${If} $InstallType == ${INSTALLTYPE_BASIC} + Call CheckExistingInstall + ${EndIf} + + ; Force user to try again if no drive space or disk access exist for + ; currently selected install path. + Push $R9 + ${CanWriteToInstallDir} $R9 + ${If} $R9 == "false" + MessageBox MB_OK|MB_ICONEXCLAMATION "$(WARN_WRITE_ACCESS)" + Abort + ${EndIf} + + ${CheckDiskSpace} $R9 + ${If} $R9 == "false" + MessageBox MB_OK|MB_ICONEXCLAMATION "$(WARN_DISK_SPACE)" + Abort + ${EndIf} + Pop $R9 +FunctionEnd + +Function preShortcuts + StrCpy $PageName "Shortcuts" + + ; Abort if not a custom install + IntCmp $InstallType ${INSTALLTYPE_CUSTOM} +2 +1 +1 + Abort + + !insertmacro MUI_HEADER_TEXT "$(SHORTCUTS_PAGE_TITLE)" "$(SHORTCUTS_PAGE_SUBTITLE)" + !insertmacro MUI_INSTALLOPTIONS_DISPLAY "shortcuts.ini" +FunctionEnd + +Function leaveShortcuts + ${MUI_INSTALLOPTIONS_READ} $0 "shortcuts.ini" "Settings" "State" + ${If} $0 != 0 + Abort + ${EndIf} + ${MUI_INSTALLOPTIONS_READ} $AddDesktopSC "shortcuts.ini" "Field 2" "State" + ${MUI_INSTALLOPTIONS_READ} $AddStartMenuSC "shortcuts.ini" "Field 3" "State" + ; This field doesn't exist when running on Windows 7 or above. + ${Unless} ${AtLeastWin7} + ${MUI_INSTALLOPTIONS_READ} $AddQuickLaunchSC "shortcuts.ini" "Field 4" "State" + ${EndUnless} + + ${If} $InstallType == ${INSTALLTYPE_CUSTOM} + Call CheckExistingInstall + ${EndIf} +FunctionEnd + +Function preSummary + StrCpy $PageName "Summary" + ; Setup the summary.ini file for the Custom Summary Page + WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "3" + + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Type "label" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Text "$(SUMMARY_INSTALLED_TO)" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Left "0" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Right "-1" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Top "5" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 1" Bottom "15" + + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Type "text" + ; The contents of this control must be set as follows in the pre function + ; ${MUI_INSTALLOPTIONS_READ} $1 "summary.ini" "Field 2" "HWND" + ; SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" state "" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Left "0" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Right "-1" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Top "17" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" Bottom "30" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 2" flags "READONLY" + + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Type "label" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Left "0" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Right "-1" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Top "130" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Bottom "150" + + ${If} ${FileExists} "$INSTDIR\${FileMainEXE}" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Text "$(SUMMARY_UPGRADE_CLICK)" + WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NextButtonText "$(UPGRADE_BUTTON)" + ${Else} + WriteINIStr "$PLUGINSDIR\summary.ini" "Field 3" Text "$(SUMMARY_INSTALL_CLICK)" + DeleteINIStr "$PLUGINSDIR\summary.ini" "Settings" NextButtonText + ${EndIf} + + + ; Remove the "Field 4" ini section in case the user hits back and changes the + ; installation directory which could change whether the make default checkbox + ; should be displayed. + DeleteINISec "$PLUGINSDIR\summary.ini" "Field 4" + + ; Check if it is possible to write to HKLM + ClearErrors + WriteRegStr HKLM "Software\Zotero" "${BrandShortName}InstallerTest" "Write Test" + ${Unless} ${Errors} + DeleteRegValue HKLM "Software\Zotero" "${BrandShortName}InstallerTest" + ; Check if Firefox is the http handler for this user. + SetShellVarContext current ; Set SHCTX to the current user + ${IsHandlerForInstallDir} "http" $R9 + ${If} $TmpVal == "HKLM" + SetShellVarContext all ; Set SHCTX to all users + ${EndIf} + ${EndUnless} + + ${If} "$TmpVal" == "true" + ; If there is already a Type entry in the "Field 4" section with a value of + ; checkbox then the set as the default browser checkbox is displayed and + ; this text must be moved below it. + ReadINIStr $0 "$PLUGINSDIR\summary.ini" "Field 4" "Type" + ${If} "$0" == "checkbox" + StrCpy $0 "5" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Top "53" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Bottom "68" + ${Else} + StrCpy $0 "4" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Top "35" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Bottom "50" + ${EndIf} + WriteINIStr "$PLUGINSDIR\summary.ini" "Settings" NumFields "$0" + + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Type "label" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Text "$(SUMMARY_REBOOT_REQUIRED_INSTALL)" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Left "0" + WriteINIStr "$PLUGINSDIR\summary.ini" "Field $0" Right "-1" + ${EndIf} + + !insertmacro MUI_HEADER_TEXT "$(SUMMARY_PAGE_TITLE)" "$(SUMMARY_PAGE_SUBTITLE)" + + ; The Summary custom page has a textbox that will automatically receive + ; focus. This sets the focus to the Install button instead. + !insertmacro MUI_INSTALLOPTIONS_INITDIALOG "summary.ini" + GetDlgItem $0 $HWNDPARENT 1 + System::Call "user32::SetFocus(i r0, i 0x0007, i,i)i" + ${MUI_INSTALLOPTIONS_READ} $1 "summary.ini" "Field 2" "HWND" + SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR" + !insertmacro MUI_INSTALLOPTIONS_SHOW +FunctionEnd + +; When we add an optional action to the finish page the cancel button is +; enabled. This disables it and leaves the finish button as the only choice. +Function preFinish + StrCpy $PageName "" + ${EndInstallLog} "${BrandFullName}" + !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "cancelenabled" "0" +FunctionEnd + +################################################################################ +# Initialization Functions + +Function .onInit + StrCpy $PageName "" + StrCpy $LANGUAGE 0 + + ; Starting user preferences need to be defined in code so that silent + ; installations will work correctly. These can later be modified in the .ini + ; file and command-line argument handlers. + StrCpy $AddDesktopSC "${DESKTOP_SHORTCUT_DEFAULT}" + StrCpy $AddStartMenuSC "${START_MENU_SHORTCUT_DEFAULT}" + StrCpy $AddQuickLaunchSC "${QUICKLAUNCH_SHORTCUT_DEFAULT}" + StrCpy $InstallType ${INSTALLTYPE_DEFAULT} + + ${SetBrandNameVars} "$EXEDIR\core\distribution\setup.ini" + + ${InstallOnInitCommon} "$(WARN_MIN_SUPPORTED_OS_MSG)" + + StrCpy $R1 "Zotero Standalone" + StrCpy $R2 "An older version of Zotero is installed. If you continue, the existing version will be removed.$\n$\nYour Zotero data will not be affected." + Call UninstallOld + + !ifdef HAVE_64BIT_OS + SetRegView 32 + StrCpy $R1 "Zotero" + StrCpy $R2 "A 32-bit version of Zotero is installed. If you continue, it will be replaced with a 64-bit version that offers better performance.$\n$\nYour Zotero data will not be affected." + Call UninstallOld + SetRegView 64 + !endif + + !ifndef HAVE_64BIT_OS + ${If} ${RunningX64} + MessageBox MB_OKCANCEL|MB_ICONEXCLAMATION|MB_DEFBUTTON2 \ + "This installer is for the 32-bit version of Zotero, but you appear to be running a 64-bit version of Windows.$\n$\nFor the best performance, please cancel and download the 64-bit version of Zotero." \ + /SD IDOK IDOK continue_architecture IDCANCEL cancel_architecture + cancel_architecture: + Abort + continue_architecture: + ${EndIf} + !endif + + !insertmacro InitInstallOptionsFile "options.ini" + !insertmacro InitInstallOptionsFile "shortcuts.ini" + !insertmacro InitInstallOptionsFile "summary.ini" + + WriteINIStr "$PLUGINSDIR\options.ini" "Settings" NumFields "5" + + WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Type "label" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Text "$(OPTIONS_SUMMARY)" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Left "0" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Right "-1" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Top "0" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 1" Bottom "10" + + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Type "RadioButton" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Text "$(OPTION_STANDARD_RADIO)" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Left "0" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Right "-1" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Top "25" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Bottom "35" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" State "1" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 2" Flags "GROUP" + + WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Type "RadioButton" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Text "$(OPTION_CUSTOM_RADIO)" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Left "0" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Right "-1" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Top "55" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" Bottom "65" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 3" State "0" + + WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Type "label" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Text "$(OPTION_STANDARD_DESC)" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Left "15" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Right "-1" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Top "37" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 4" Bottom "57" + + WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Type "label" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Text "$(OPTION_CUSTOM_DESC)" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Left "15" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Right "-1" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Top "67" + WriteINIStr "$PLUGINSDIR\options.ini" "Field 5" Bottom "87" + + ; Setup the shortcuts.ini file for the Custom Shortcuts Page + ; Don't offer to install the quick launch shortcut on Windows 7 + ${If} ${AtLeastWin7} + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Settings" NumFields "3" + ${Else} + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Settings" NumFields "4" + ${EndIf} + + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Type "label" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Text "$(CREATE_ICONS_DESC)" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Left "0" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Right "-1" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Top "5" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 1" Bottom "15" + + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Type "checkbox" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Text "$(ICONS_DESKTOP)" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Left "0" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Right "-1" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Top "20" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Bottom "30" + + ; Default UI selection synchronized with existing value. + Push $0 + StrCpy $0 "${DESKTOP_SHORTCUT_DISABLED}" + IntCmp $AddDesktopSC ${DESKTOP_SHORTCUT_ENABLED} +1 +2 +2 + StrCpy $0 "${DESKTOP_SHORTCUT_ENABLED}" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" State $0 + Pop $0 + + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 2" Flags "GROUP" + + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Type "checkbox" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Text "$(ICONS_STARTMENU)" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Left "0" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Right "-1" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Top "40" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" Bottom "50" + + ; Default UI selection synchronized with existing value. + Push $0 + StrCpy $0 "${START_MENU_SHORTCUT_DISABLED}" + IntCmp $AddStartMenuSC ${START_MENU_SHORTCUT_ENABLED} +1 +2 +2 + StrCpy $0 "${START_MENU_SHORTCUT_ENABLED}" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 3" State $0 + Pop $0 + + ; Don't offer to install the quick launch shortcut on Windows 7 + ${Unless} ${AtLeastWin7} + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Type "checkbox" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Text "$(ICONS_QUICKLAUNCH)" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Left "0" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Right "-1" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Top "60" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" Bottom "70" + + Push $0 + StrCpy $0 "0" + IntCmp $AddQuickLaunchSC ${QUICKLAUNCH_SHORTCUT_ENABLED} +1 +2 +2 + StrCpy $0 "1" + WriteINIStr "$PLUGINSDIR\shortcuts.ini" "Field 4" State $0 + Pop $0 + ${EndUnless} + + ; There must always be a core directory. + ${GetSize} "$EXEDIR\core\" "/S=0K" $R5 $R7 $R8 + SectionSetSize ${APP_IDX} $R5 + + ; Initialize $hHeaderBitmap to prevent redundant changing of the bitmap if + ; the user clicks the back button + StrCpy $hHeaderBitmap "" +FunctionEnd + +Function .onGUIEnd + ${OnEndCommon} +FunctionEnd diff --git a/app/win/installer/locales.nsi b/app/win/installer/locales.nsi new file mode 100755 index 0000000000..359d97f87e --- /dev/null +++ b/app/win/installer/locales.nsi @@ -0,0 +1,17 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +/** + * "One off" locale configuration settings for RTL (e.g. locale text is read + * right to left). + */ + +; Arabic +!define ar_rtl + +; Hebrew +!define he_rtl + +; Persian +!define fa_rtl diff --git a/app/win/installer/overrideLocale.nsh b/app/win/installer/overrideLocale.nsh new file mode 100644 index 0000000000000000000000000000000000000000..adb850168f5449a514b1bd7f5a6f51a63794e4ea GIT binary patch literal 7148 zcmd5>U2j`A4At{~g;o^VOHmYiEQSrSlNLtPWT-RjW!T`_j%PIfnC&FZpI>(lS%%Wp zwQigN!w@vFuPBlt4-cu^FMpqfQCNmq7=~Tggt>f<;dgwW;>k@|hdw0M_&g6Qtj6#P z|6+I+o`)WGaQ7s$wxBhm0QYo(r=)gEk(!zcK^ z%TDwI{64}{U9D+2#~D9kcT>X=BA_cV{D>IsKlw2{7(6085t%YmHE zu+sGJDCFz4^OlGywUsh8jYRHJGH_jFG+nFfxJF!=ztWpN>OmaH`DO4 zifGrAqrw@?C1L|PtSVYmUfKxKtpaJ?`D!Ho(67gOQ=+Qfqc*wyUfsZhr+T&mL#&Y# zW_pS|rv5b7YI)5W=n}ffksp8>*Z8y883{h4@Y5~)o&sskWQq=FvQfcgF?__HE98g_ zr%dQMVH{?7TI*0JV7ix(89+-6_t12Mzd7e>N1|WOxhs)3ER>$TfELy-qdCS-Kh+h^ zxe??p-|>hv;LpcF=B7_lWnUbFkXn7giE;p6>K0 z+zFGZ@2r9xSBw&SeniB`ckD}tXlMUehVLXcbxX|8zl+8YK7M?N$@hrtIjj$0pJ=&6 z-q-M+z0~-JbC2h)Jx*GMc~o9kGj$@lFLOg{I%P#-Rtx%! z9K8{gU1GJ&ETx&>i2Tlh^ed59Y(;#dUe!UIkMT`;Jfg`(O_ zmTQe?o?Xu&dlvJ{(>OmzOsVdFjmK1bdZPBsIZliZ(i5@T+G6~;Y}WBK1a8SyQ?S@A zJ`p)1Ae|n099)VSY0ABZWGxE5`vbK8g-RlS<^92Bl*?18F8yVHQ>>P;?v9w(4!KmB ziQ2p;sNYwD(gh^)jMZ!9@f@`8O#6_!PoA~GdRl}!4&F%Sr{NURlxI~LlcmqtZ&<|| zVQMF07%3u_yYBFN{>8jvQ?to*K3?-JG47m zF72tsqo#pzpW$?j8M~ZSoat&`?>Z-Wf+((O-Y?UoeTd3hNVW0}4m&hEabe=9d>mpjD9B$OROXQwt>Hk0S9O8G9EoS4`T@|w(_8cQCc>jFq2;@JuG zeUbT{>*kF>CkT`5vf|y%qph{JKQF$Av#X)RD)i7ixwfVUjs%w}Ek6E)jMW(Nepof6$H^IYR6m()zR$)4ced)8s^ zvz(4uCT4kG@)$JNx?`+6N*%1|X=mM>${P;81=qWN>Ir8QectVbO>fp2%k1(^N~&)v znPdK%vzv7(tJnIJKS1U2X26@=BwPRqL>dv~F`-O4Nz*2!a_sPw^xL)Rdk)iA>zeEX z7s&i+VwKP0!&9A8yCQiZOuUxg>|w_1ewI|?FzzS57tnc&zwNqHiNkgCuFC&A+0U8O zZ&Hlyp`4lTH>{>lyW%_iIz96?k/include/FileFunc.nsh for more information. +!macro LocateNoDetailsCall _PATH _OPTIONS _FUNC + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + Push $0 + Push `${_PATH}` + Push `${_OPTIONS}` + GetFunctionAddress $0 `${_FUNC}` + Push `$0` + Call LocateNoDetails + Pop $0 + !verbose pop +!macroend + +!macro LocateNoDetails + !ifndef ${_OVERRIDE_UN}LocateNoDetails + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + !define ${_OVERRIDE_UN}LocateNoDetails `!insertmacro ${_OVERRIDE_UN}LocateNoDetailsCall` + + Function ${_OVERRIDE_UN}LocateNoDetails + Exch $2 + Exch + Exch $1 + Exch + Exch 2 + Exch $0 + Exch 2 + Push $3 + Push $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + Push $R6 + Push $R7 + Push $R8 + Push $R9 + ClearErrors + + StrCpy $3 '' + StrCpy $4 '' + StrCpy $5 '' + StrCpy $6 '' + StrCpy $7 '' + StrCpy $8 0 + StrCpy $R7 '' + + StrCpy $R9 $0 1 -1 + StrCmp $R9 '\' 0 +3 + StrCpy $0 $0 -1 + goto -3 + IfFileExists '$0\*.*' 0 error + + option: + StrCpy $R9 $1 1 + StrCpy $1 $1 '' 1 + StrCmp $R9 ' ' -2 + StrCmp $R9 '' sizeset + StrCmp $R9 '/' 0 -4 + StrCpy $9 -1 + IntOp $9 $9 + 1 + StrCpy $R9 $1 1 $9 + StrCmp $R9 '' +2 + StrCmp $R9 '/' 0 -3 + StrCpy $R8 $1 $9 + StrCpy $R8 $R8 '' 2 + StrCpy $R9 $R8 '' -1 + StrCmp $R9 ' ' 0 +3 + StrCpy $R8 $R8 -1 + goto -3 + StrCpy $R9 $1 2 + StrCpy $1 $1 '' $9 + + StrCmp $R9 'L=' 0 mask + StrCpy $3 $R8 + StrCmp $3 '' +6 + StrCmp $3 'FD' +5 + StrCmp $3 'F' +4 + StrCmp $3 'D' +3 + StrCmp $3 'DE' +2 + StrCmp $3 'FDE' 0 error + goto option + + mask: + StrCmp $R9 'M=' 0 size + StrCpy $4 $R8 + goto option + + size: + StrCmp $R9 'S=' 0 gotosubdir + StrCpy $6 $R8 + goto option + + gotosubdir: + StrCmp $R9 'G=' 0 banner + StrCpy $7 $R8 + StrCmp $7 '' +3 + StrCmp $7 '1' +2 + StrCmp $7 '0' 0 error + goto option + + banner: + StrCmp $R9 'B=' 0 error + StrCpy $R7 $R8 + StrCmp $R7 '' +3 + StrCmp $R7 '1' +2 + StrCmp $R7 '0' 0 error + goto option + + sizeset: + StrCmp $6 '' default + StrCpy $9 0 + StrCpy $R9 $6 1 $9 + StrCmp $R9 '' +4 + StrCmp $R9 ':' +3 + IntOp $9 $9 + 1 + goto -4 + StrCpy $5 $6 $9 + IntOp $9 $9 + 1 + StrCpy $1 $6 1 -1 + StrCpy $6 $6 -1 $9 + StrCmp $5 '' +2 + IntOp $5 $5 + 0 + StrCmp $6 '' +2 + IntOp $6 $6 + 0 + + StrCmp $1 'B' 0 +3 + StrCpy $1 1 + goto default + StrCmp $1 'K' 0 +3 + StrCpy $1 1024 + goto default + StrCmp $1 'M' 0 +3 + StrCpy $1 1048576 + goto default + StrCmp $1 'G' 0 error + StrCpy $1 1073741824 + + default: + StrCmp $3 '' 0 +2 + StrCpy $3 'FD' + StrCmp $4 '' 0 +2 + StrCpy $4 '*.*' + StrCmp $7 '' 0 +2 + StrCpy $7 '1' + StrCmp $R7 '' 0 +2 + StrCpy $R7 '0' + StrCpy $7 'G$7B$R7' + + StrCpy $8 1 + Push $0 +; SetDetailsPrint textonly + + nextdir: + IntOp $8 $8 - 1 + Pop $R8 + + StrCpy $9 $7 2 2 + StrCmp $9 'B0' +3 + GetLabelAddress $9 findfirst + goto call +; DetailPrint 'Search in: $R8' + + findfirst: + FindFirst $0 $R7 '$R8\$4' + IfErrors subdir + StrCmp $R7 '.' 0 dir + FindNext $0 $R7 + StrCmp $R7 '..' 0 dir + FindNext $0 $R7 + IfErrors 0 dir + FindClose $0 + goto subdir + + dir: + IfFileExists '$R8\$R7\*.*' 0 file + StrCpy $R6 '' + StrCmp $3 'DE' +4 + StrCmp $3 'FDE' +3 + StrCmp $3 'FD' precall + StrCmp $3 'F' findnext precall + FindFirst $9 $R9 '$R8\$R7\*.*' + StrCmp $R9 '.' 0 +4 + FindNext $9 $R9 + StrCmp $R9 '..' 0 +2 + FindNext $9 $R9 + FindClose $9 + IfErrors precall findnext + + file: + StrCmp $3 'FDE' +3 + StrCmp $3 'FD' +2 + StrCmp $3 'F' 0 findnext + StrCpy $R6 0 + StrCmp $5$6 '' precall + FileOpen $9 '$R8\$R7' r + IfErrors +3 + FileSeek $9 0 END $R6 + FileClose $9 + System::Int64Op $R6 / $1 + Pop $R6 + StrCmp $5 '' +2 + IntCmp $R6 $5 0 findnext + StrCmp $6 '' +2 + IntCmp $R6 $6 0 0 findnext + + precall: + StrCpy $9 0 + StrCpy $R9 '$R8\$R7' + + call: + Push $0 + Push $1 + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + Push $R7 + Push $R8 + StrCmp $9 0 +4 + StrCpy $R6 '' + StrCpy $R7 '' + StrCpy $R9 '' + Call $2 + Pop $R9 + Pop $R8 + Pop $R7 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 + + IfErrors 0 +3 + FindClose $0 + goto error + StrCmp $R9 'StopLocateNoDetails' 0 +3 + FindClose $0 + goto clearstack + goto $9 + + findnext: + FindNext $0 $R7 + IfErrors 0 dir + FindClose $0 + + subdir: + StrCpy $9 $7 2 + StrCmp $9 'G0' end + FindFirst $0 $R7 '$R8\*.*' + StrCmp $R7 '.' 0 pushdir + FindNext $0 $R7 + StrCmp $R7 '..' 0 pushdir + FindNext $0 $R7 + IfErrors 0 pushdir + FindClose $0 + StrCmp $8 0 end nextdir + + pushdir: + IfFileExists '$R8\$R7\*.*' 0 +3 + Push '$R8\$R7' + IntOp $8 $8 + 1 + FindNext $0 $R7 + IfErrors 0 pushdir + FindClose $0 + StrCmp $8 0 end nextdir + + error: + SetErrors + + clearstack: + StrCmp $8 0 end + IntOp $8 $8 - 1 + Pop $R8 + goto clearstack + + end: +; SetDetailsPrint both + Pop $R9 + Pop $R8 + Pop $R7 + Pop $R6 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 + FunctionEnd + + !verbose pop + !endif +!macroend + +!macro un.LocateNoDetailsCall _PATH _OPTIONS _FUNC + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + Push $0 + Push `${_PATH}` + Push `${_OPTIONS}` + GetFunctionAddress $0 `${_FUNC}` + Push `$0` + Call un.LocateNoDetails + Pop $0 + !verbose pop +!macroend + +!macro un.LocateNoDetails + !ifndef un.LocateNoDetails + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + !undef _OVERRIDE_UN + !define _OVERRIDE_UN `un.` + + !insertmacro LocateNoDetails + + !undef _OVERRIDE_UN + !define _OVERRIDE_UN + !verbose pop + !endif +!macroend + +; Modified version of TextCompare from the NSIS Text Functions Header v2.4 (it +; has the same version in earlier versions of NSIS even though it has changed) +; that is distributed with NSIS v2.46-Unicode. This version has the calls to +; SetDetailsPrint commented out. +; See /include/TextFunc.nsh for more information. + +!macro TextCompareNoDetailsCall _FILE1 _FILE2 _OPTION _FUNC + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + Push $0 + Push `${_FILE1}` + Push `${_FILE2}` + Push `${_OPTION}` + GetFunctionAddress $0 `${_FUNC}` + Push `$0` + ${CallArtificialFunction} TextCompareNoDetails_ + Pop $0 + !verbose pop +!macroend + +!macro TextCompareNoDetailsSCall _FILE1 _FILE2 _OPTION _FUNC + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + Push $0 + Push `${_FILE1}` + Push `${_FILE2}` + Push `${_OPTION}` + GetFunctionAddress $0 `${_FUNC}` + Push `$0` + ${CallArtificialFunction} TextCompareNoDetailsS_ + Pop $0 + !verbose pop +!macroend + + +!macro TextCompareNoDetailsBody _OVERRIDE_S + Exch $3 + Exch + Exch $2 + Exch + Exch 2 + Exch $1 + Exch 2 + Exch 3 + Exch $0 + Exch 3 + Push $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + ClearErrors + + IfFileExists $0 0 TextFunc_TextCompareNoDetails${_OVERRIDE_S}_error + IfFileExists $1 0 TextFunc_TextCompareNoDetails${_OVERRIDE_S}_error + StrCmp $2 'FastDiff' +5 + StrCmp $2 'FastEqual' +4 + StrCmp $2 'SlowDiff' +3 + StrCmp $2 'SlowEqual' +2 + goto TextFunc_TextCompareNoDetails${_OVERRIDE_S}_error + + FileOpen $4 $0 r + IfErrors TextFunc_TextCompareNoDetails${_OVERRIDE_S}_error + FileOpen $5 $1 r + IfErrors TextFunc_TextCompareNoDetails${_OVERRIDE_S}_error +; SetDetailsPrint textonly + + StrCpy $6 0 + StrCpy $8 0 + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_nextline: + StrCmp${_OVERRIDE_S} $4 '' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_fast + IntOp $8 $8 + 1 + FileRead $4 $9 + IfErrors 0 +4 + FileClose $4 + StrCpy $4 '' + StrCmp${_OVERRIDE_S} $5 '' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_end + StrCmp $2 'FastDiff' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_fast + StrCmp $2 'FastEqual' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_fast TextFunc_TextCompareNoDetails${_OVERRIDE_S}_slow + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_fast: + StrCmp${_OVERRIDE_S} $5 '' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_call + IntOp $6 $6 + 1 + FileRead $5 $7 + IfErrors 0 +5 + FileClose $5 + StrCpy $5 '' + StrCmp${_OVERRIDE_S} $4 '' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_end + StrCmp $2 'FastDiff' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_call TextFunc_TextCompareNoDetails${_OVERRIDE_S}_close + StrCmp $2 'FastDiff' 0 +2 + StrCmp${_OVERRIDE_S} $7 $9 TextFunc_TextCompareNoDetails${_OVERRIDE_S}_nextline TextFunc_TextCompareNoDetails${_OVERRIDE_S}_call + StrCmp${_OVERRIDE_S} $7 $9 TextFunc_TextCompareNoDetails${_OVERRIDE_S}_call TextFunc_TextCompareNoDetails${_OVERRIDE_S}_nextline + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_slow: + StrCmp${_OVERRIDE_S} $4 '' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_close + StrCpy $6 '' +; DetailPrint '$8. $9' + FileSeek $5 0 + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_slownext: + FileRead $5 $7 + IfErrors 0 +2 + StrCmp $2 'SlowDiff' TextFunc_TextCompareNoDetails${_OVERRIDE_S}_call TextFunc_TextCompareNoDetails${_OVERRIDE_S}_nextline + StrCmp $2 'SlowDiff' 0 +2 + StrCmp${_OVERRIDE_S} $7 $9 TextFunc_TextCompareNoDetails${_OVERRIDE_S}_nextline TextFunc_TextCompareNoDetails${_OVERRIDE_S}_slownext + IntOp $6 $6 + 1 + StrCmp${_OVERRIDE_S} $7 $9 0 TextFunc_TextCompareNoDetails${_OVERRIDE_S}_slownext + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_call: + Push $2 + Push $3 + Push $4 + Push $5 + Push $6 + Push $7 + Push $8 + Push $9 + Call $3 + Pop $0 + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + StrCmp $0 'StopTextCompareNoDetails' 0 TextFunc_TextCompareNoDetails${_OVERRIDE_S}_nextline + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_close: + FileClose $4 + FileClose $5 + goto TextFunc_TextCompareNoDetails${_OVERRIDE_S}_end + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_error: + SetErrors + + TextFunc_TextCompareNoDetails${_OVERRIDE_S}_end: +; SetDetailsPrint both + Pop $9 + Pop $8 + Pop $7 + Pop $6 + Pop $5 + Pop $4 + Pop $3 + Pop $2 + Pop $1 + Pop $0 +!macroend + +!define TextCompareNoDetails `!insertmacro TextCompareNoDetailsCall` +!define un.TextCompareNoDetails `!insertmacro TextCompareNoDetailsCall` + +!macro TextCompareNoDetails +!macroend + +!macro un.TextCompareNoDetails +!macroend + +!macro TextCompareNoDetails_ + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + + !insertmacro TextCompareNoDetailsBody '' + + !verbose pop +!macroend + +!define TextCompareNoDetailsS `!insertmacro TextCompareNoDetailsSCall` +!define un.TextCompareNoDetailsS `!insertmacro TextCompareNoDetailsSCall` + +!macro TextCompareNoDetailsS +!macroend + +!macro un.TextCompareNoDetailsS +!macroend + +!macro TextCompareNoDetailsS_ + !verbose push + !verbose ${_OVERRIDE_VERBOSE} + + !insertmacro TextCompareNoDetailsBody 'S' + + !verbose pop +!macroend + +!endif diff --git a/app/win/installer/setup.ico b/app/win/installer/setup.ico new file mode 100644 index 0000000000000000000000000000000000000000..9801fed54fbaf217537693e628497a5002d20a77 GIT binary patch literal 25214 zcmeIacU)Ch6E-@C22<5H#y7@Tg1y9&*b+6?C>l#*i8aR9dyEaNphm$4R_r1wph&Y( zL=rgjLx8J#}3-^cyCD**_)^ha6lHJS@eTS2tLZ+*Znae!hbR`QAhZT zNAmIUA)m)SlpADAHEY(S+O=!bM<0De_3G851`Qg}mtTHK^nv{e{3o(AT#f&vXJlq* zXk>Uo&q&|!ppofn#7kEhnMrKe+TIXx7em9<2N8d2WVCTB;#G!brma!_zyUK;slRHK zq2UQ>#|+Jpo*@EaLsP`tPLL7OjZ9CFBpVtM#hU_8U7(IJR!9&ss)M9Uz8;{C8VJt{ z;9bV48K56PJ5DB;v)2a`G=LlojuPQ79swrGSP`-EpP1zdfPa!Ce_jcOhD)la>6w<8 zN(#nLNj5S?HB&<)vyu{!NP1@SZf0a|VPU~2hWC=z7>cyCk`gXfzw7I_wl_xsE?J`F z>+8?AKa-Y*dM288BYS&uyrP2CZ>Mi$X3u8KCF=K+Co#AsWWg3@l5gIwxsjPgu34Ru zk`j4OJLzFmQiAtNb$;5BBgW{AEP#Vj-b3=aQlCmR9TB_-SJ6?{`tva^jOf7=;_p2Y~MAg09Zgz_FoDJdz2px;D29>y5e#fz0y zpyUf-gfgizu6kI8hG<&t06hR@(v7UOGON^Ow^?W#vsIL!EQxl>( z06l=N26Pa=4YcK?j?|Sl1lhhCkY^Skq-z21#_aP4%R282mf*m)e-VV&ur9Y<_Kq zsWPpMoZ6|W#l^*%jN0ny=3+x5^Y!bEjWKT~>SomC4Gm3G5ioyjRF!UK%$RW}b$N9K zr5%0!Hl}9wcAD}^1x>oX{x*C2^-=*1l?ZOquRbau9TlW~rJ<_y)%H?BipxG!mv7fj zzl|X>?37dmBc=SwllpT(s=cu~y%?A(=_oHlV95B-piP^O@}?L9V~`4Zi;IC!Re2OM zF4ilq^Sr!y<;jz$q&yev8Dha#mCtEs?_sJgZ=_ef{JA4Xl=48_v>3!`+RyRu@Gw(G zpxDs362z(TF|RywN2 z(!pO4vdyG8I*{T@x^N(vGQ`R1`xU z6LoQE9~@X66wXqWE=Qf2sqsshwT�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 + // Note that -app must be the *first* argument. +- const char* appDataFile = getenv("XUL_APP_FILE"); ++ UniqueFreePtr iniPath = BinaryPath::GetApplicationIni(); ++ if (!iniPath) { ++ Output("Couldn't find application.ini.\n"); ++ return 255; ++ ++ } ++ char *appDataFile = iniPath.get(); + if ((!appDataFile || !*appDataFile) && (argc > 1 && IsArg(argv[1], "app"))) { + if (argc == 2) { + Output("Incorrect number of arguments passed to -app"); + return 255; + } + appDataFile = argv[2]; + + char appEnv[MAXPATHLEN]; +diff --git a/xpcom/build/BinaryPath.h b/xpcom/build/BinaryPath.h +--- a/xpcom/build/BinaryPath.h ++++ b/xpcom/build/BinaryPath.h +@@ -267,16 +267,43 @@ class BinaryPath { + if (NS_FAILED(Get(path))) { + return nullptr; + } + UniqueFreePtr result; + result.reset(strdup(path)); + return result; + } + ++ static UniqueFreePtr GetApplicationIni() { ++ char path[MAXPATHLEN]; ++ if (NS_FAILED(Get(path))) { ++ return nullptr; ++ } ++ ++ char *c = path + strlen(path); ++ while (c >= path && *c != '\\' && *c != '/') { ++ *c = NULL; ++ c--; ++ } ++ ++ if (c < path) { ++ return nullptr; ++ } ++ ++ char iniPath[MAXPATHLEN]; ++ int n = snprintf(iniPath, MAXPATHLEN, "%s\\app\\application.ini", path); ++ if (n < 0 || n >= MAXPATHLEN) { ++ return nullptr; ++ } ++ ++ UniqueFreePtr result; ++ result.reset(strdup(iniPath)); ++ return result; ++ } ++ + #ifdef MOZILLA_INTERNAL_API + static nsresult GetFile(nsIFile** aResult) { + nsCOMPtr lf; + # ifdef XP_WIN + wchar_t exePath[MAXPATHLEN]; + nsresult rv = GetW(exePath); + # else + char exePath[MAXPATHLEN]; diff --git a/app/win/resource-hacker-config.txt b/app/win/resource-hacker-config.txt new file mode 100644 index 0000000000..942abf99c2 --- /dev/null +++ b/app/win/resource-hacker-config.txt @@ -0,0 +1,9 @@ +[FILENAMES] +Open=firefox-{{ARCH}}.exe +Save=zotero_{{ARCH}}.exe +Log=CONSOLE +[COMMANDS] +-addoverwrite ../assets/icons/default/main-window.ico, ICONGROUP,1, +-addoverwrite ../assets/icons/default/main-window.ico, ICONGROUP,32512, +-delete VERSIONINFO,1 +-addoverwrite VersionInfo1.res, VERSIONINFO,1, diff --git a/app/win/update_exe b/app/win/update_exe new file mode 100755 index 0000000000..08c1b01e94 --- /dev/null +++ b/app/win/update_exe @@ -0,0 +1,43 @@ +#!/bin/bash +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +cd "$SCRIPT_DIR" + +rh="resource_hacker/ResourceHacker.exe" + +if [ ! -f "$rh" ]; then + echo "win/$rh not found" >&2 + exit 1 +fi + +if [[ -z "${1:-}" ]]; then + echo "Usage: $0 firefox_version" >&2 + exit 1 +fi +version=$1 + +for arch in win32 win64; do + zip="firefox-$version.en-US.$arch.zip" + if [ ! -f "$zip" ]; then + echo "$zip not found" >&2 + exit 1 + fi + rm -f firefox-$arch.exe + unzip -oj $zip firefox/firefox.exe + mv firefox.exe firefox-$arch.exe + + $rh -open VersionInfo1.rc -save VersionInfo1.res -action compile + + config=`cat resource-hacker-config.txt` + config_file="resource-hacker-config-$arch.txt" + echo "${config//\{\{ARCH\}\}/$arch}" > $config_file + $rh -script $config_file + rm $config_file + + rm VersionInfo1.res +done + +tar -Jcv zotero_win32.exe zotero_win64.exe > zotero.exe.tar.xz + +rm firefox-win??.exe zotero_win??.exe diff --git a/app/win/updater.exe b/app/win/updater.exe new file mode 100644 index 0000000000000000000000000000000000000000..db9cc6664f6f87657c218234ff9c495e3533efe8 GIT binary patch literal 282624 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


s0QU+~{xGp7b=5 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
    Z@h$xJ*?0N}vF{fy{37{^ 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 literal 0 HcmV?d00001 diff --git a/app/win/zotero.exe.tar.xz b/app/win/zotero.exe.tar.xz new file mode 100644 index 0000000000000000000000000000000000000000..45fa0750972ca079560d53e7c2b464b8e1a38075 GIT binary patch literal 398180 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�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⪚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

    v!!xGUh$Y4`D}uJVlp`}3Q? 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%0A7d4Cc+J}t8g4;0-3Y?@ z74zlMA@vi;$?W7;n;n=qrd0x;BE|EEWb9EQRg{nv5=DyWtVT6f3Q`n3ZZoyvZRWj6 z+|Z(uzdOG)8X!d?k$k2P0z;60J8`nV%MnWkb|FF7BxvMB*uI>hB6-FnJa>UZvq)SF zcApP36i@D2w-;&dF_kpZUom*C63jR~y|zJy@FOj}icL2q0K3<=ye}~w?Qf&?%~4

    rrLW^`Uqg{Dw=mp&KE!U56E}No7 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 literal 0 HcmV?d00001