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 0000000000..a24992b843 Binary files /dev/null and b/app/assets/branding/content/icon48.png differ diff --git a/app/assets/branding/content/icon64.png b/app/assets/branding/content/icon64.png new file mode 100644 index 0000000000..9ccf228ff4 Binary files /dev/null and b/app/assets/branding/content/icon64.png differ 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 0000000000..0fd6f5476a Binary files /dev/null and b/app/assets/icons/default/default16.png differ diff --git a/app/assets/icons/default/default256.png b/app/assets/icons/default/default256.png new file mode 100644 index 0000000000..ee34fd1083 Binary files /dev/null and b/app/assets/icons/default/default256.png differ diff --git a/app/assets/icons/default/default32.png b/app/assets/icons/default/default32.png new file mode 100644 index 0000000000..c8c09687a7 Binary files /dev/null and b/app/assets/icons/default/default32.png differ diff --git a/app/assets/icons/default/default48.png b/app/assets/icons/default/default48.png new file mode 100644 index 0000000000..a24992b843 Binary files /dev/null and b/app/assets/icons/default/default48.png differ diff --git a/app/assets/icons/default/main-window.ico b/app/assets/icons/default/main-window.ico new file mode 100644 index 0000000000..ab37a7544a Binary files /dev/null and b/app/assets/icons/default/main-window.ico differ diff --git a/app/assets/mac/chrome/skin/preferences/preferences.css b/app/assets/mac/chrome/skin/preferences/preferences.css new file mode 100644 index 0000000000..f866b7e1f0 --- /dev/null +++ b/app/assets/mac/chrome/skin/preferences/preferences.css @@ -0,0 +1,242 @@ +/* +# -*- 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 +# 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 0000000000..60fe8db563 Binary files /dev/null and b/app/linux/updater-i686 differ diff --git a/app/linux/updater-x86_64 b/app/linux/updater-x86_64 new file mode 100755 index 0000000000..862b2cb286 Binary files /dev/null and b/app/linux/updater-x86_64 differ diff --git a/app/linux/zotero b/app/linux/zotero new file mode 100755 index 0000000000..0b9f2be696 --- /dev/null +++ b/app/linux/zotero @@ -0,0 +1,16 @@ +#!/bin/bash + +# Increase open files limit +# +# Mozilla file functions (OS.File.move()/copy(), NetUtil.asyncFetch/asyncCopy()) can leave file +# descriptors open for a few seconds (even with an explicit inputStream.close() in the case of +# the latter), so a source installation that copies ~500 translators and styles (with fds for +# source and target) can exceed the default 1024 limit. +# Current hard-limit on Ubuntu 16.10 is 4096 +ulimit -n 4096 + +# Allow profile downgrade for Zotero +export MOZ_ALLOW_DOWNGRADE=1 + +CALLDIR="$(dirname "$(readlink -f "$0")")" +"$CALLDIR/zotero-bin" -app "$CALLDIR/app/application.ini" "$@" diff --git a/app/linux/zotero.desktop b/app/linux/zotero.desktop new file mode 100755 index 0000000000..705d0b3d46 --- /dev/null +++ b/app/linux/zotero.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Zotero +Exec=bash -c "$(dirname $(realpath $(echo %k | sed -e 's/^file:\/\///')))/zotero -url %U" +Icon=zotero.ico +Type=Application +Terminal=false +Categories=Office; +MimeType=text/plain;x-scheme-handler/zotero;application/x-research-info-systems;text/x-research-info-systems;text/ris;application/x-endnote-refer;application/x-inst-for-Scientific-info;application/mods+xml;application/rdf+xml;application/x-bibtex;text/x-bibtex;application/marc;application/vnd.citationstyles.style+xml +X-GNOME-SingleWindow=true diff --git a/app/mac/Contents/Info.plist b/app/mac/Contents/Info.plist new file mode 100644 index 0000000000..95332c7775 --- /dev/null +++ b/app/mac/Contents/Info.plist @@ -0,0 +1,204 @@ + + + + + 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 0000000000..4aec04140b Binary files /dev/null and b/app/mac/Contents/Resources/zotero.icns differ diff --git a/app/mac/DSStore b/app/mac/DSStore new file mode 100644 index 0000000000..8f1597ec26 Binary files /dev/null and b/app/mac/DSStore differ diff --git a/app/mac/build-and-unify b/app/mac/build-and-unify new file mode 100755 index 0000000000..a9e4398ec8 --- /dev/null +++ b/app/mac/build-and-unify @@ -0,0 +1,68 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +ROOT_DIR="$(dirname "$SCRIPT_DIR")" +. "$ROOT_DIR/config.sh" + +fx_app_name=Firefox.app + +# Get Mozilla source directory from command line +if [ -z "${1:-}" ]; then + echo "Usage: $0 /path/to/mozilla-unified" >&2 + exit 1 +fi +GECKO_PATH=$1 +mach=$GECKO_PATH/mach + +# Set ZOTERO_REPOS_DIR to use directory other than $HOME for zotero-standalone-build +if [ -n "${ZOTERO_REPOS_DIR:-}" ]; then + repos_dir=$ZOTERO_REPOS_DIR +else + repos_dir=$HOME +fi +if [ ! -d "$repos_dir/zotero-standalone-build" ]; then + echo "$repos_dir/zotero-standalone-build not found" >&2 + exit 1 +fi + +BUILD_DIR=`mktemp -d` +function cleanup { + rm -rf $BUILD_DIR +} +trap cleanup EXIT + +set -x + +export MOZ_BUILD_DATE=`date "+%Y%m%d%H%M%S"` + +# Install required Rust version +rustup toolchain install $RUST_VERSION +rustup target add aarch64-apple-darwin +rustup target add x86_64-apple-darwin +rustup default $RUST_VERSION + +cp "$SCRIPT_DIR/mozconfig" "$GECKO_PATH" + +# Build Firefox for Intel and Apple Silicon +export Z_ARCH=x64 +$mach build +$mach package +export Z_ARCH=aarch64 +$mach build +$mach package + +cd $BUILD_DIR + +# Unify into Universal build +# From https://searchfox.org/mozilla-central/rev/97c902e8f92b15dc63eb584bfc594ecb041242a4/taskcluster/scripts/misc/unify.sh +for i in x86_64 aarch64; do + $mach python -m mozbuild.action.unpack_dmg "$GECKO_PATH"/obj-$i-apple-darwin/dist/*.dmg $i +done +mv x86_64 x64 + +$mach python "$GECKO_PATH/toolkit/mozapps/installer/unify.py" x64/*.app aarch64/*.app + +cp x64/$fx_app_name/Contents/MacOS/firefox zotero +xz zotero +mv zotero.xz "$repos_dir"/zotero-standalone-build/mac/zotero.xz diff --git a/app/mac/entitlements.xml b/app/mac/entitlements.xml new file mode 100644 index 0000000000..bcf47d2194 --- /dev/null +++ b/app/mac/entitlements.xml @@ -0,0 +1,34 @@ + + + + + + + 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 0000000000..60a8289579 Binary files /dev/null and b/app/mac/updater.tar.bz2 differ diff --git a/app/mac/zotero.xz b/app/mac/zotero.xz new file mode 100644 index 0000000000..10c1ed3322 Binary files /dev/null and b/app/mac/zotero.xz differ 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 0000000000..53eda81330 Binary files /dev/null and b/app/win/VersionInfo1.rc differ 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 0000000000..463aa42a2f Binary files /dev/null and b/app/win/installer/7zstub/firefox/7zSD.sfx differ 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 0000000000..9801fed54f Binary files /dev/null and b/app/win/installer/7zstub/src/7zip/Bundles/SFXSetup-moz/setup.ico differ diff --git a/app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.cpp b/app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.cpp new file mode 100644 index 0000000000..9dae03d121 --- /dev/null +++ b/app/win/installer/7zstub/src/7zip/Common/FilePathAutoRename.cpp @@ -0,0 +1,57 @@ +// FilePathAutoRename.cpp + +#include "StdAfx.h" +#include "FilePathAutoRename.h" + +#include "Common/Defs.h" +#include "Common/IntToString.h" + +#include "Windows/FileName.h" +#include "Windows/FileFind.h" + +using namespace NWindows; + +static bool MakeAutoName(const UString &name, + const UString &extension, int value, UString &path) +{ + wchar_t number[32]; + ConvertUInt64ToString(value, number); + path = name; + path += number; + path += extension; + return NFile::NFind::DoesFileExist(path); +} + +bool AutoRenamePath(UString &fullProcessedPath) +{ + UString path; + int dotPos = fullProcessedPath.ReverseFind(L'.'); + + int slashPos = fullProcessedPath.ReverseFind(L'/'); + #ifdef _WIN32 + int slash1Pos = fullProcessedPath.ReverseFind(L'\\'); + slashPos = MyMax(slashPos, slash1Pos); + #endif + + UString name, extension; + if (dotPos > 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 0000000000..4870afce1d Binary files /dev/null and b/app/win/installer/baseLocale.nlf differ diff --git a/app/win/installer/baseLocale.nsh b/app/win/installer/baseLocale.nsh new file mode 100644 index 0000000000..9325f56cb2 Binary files /dev/null and b/app/win/installer/baseLocale.nsh differ 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 0000000000..2684546358 Binary files /dev/null and b/app/win/installer/customLocale.nsh differ 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 0000000000..adb850168f Binary files /dev/null and b/app/win/installer/overrideLocale.nsh differ diff --git a/app/win/installer/overrides.nsh b/app/win/installer/overrides.nsh new file mode 100755 index 0000000000..0f0f0efb80 --- /dev/null +++ b/app/win/installer/overrides.nsh @@ -0,0 +1,591 @@ +# 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/. + +################################################################################ +# Modified versions of macros provided by NSIS + +!ifndef OVERRIDES_INCLUDED +!define OVERRIDES_INCLUDED + +; When including a file 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 + +!macro __MOZ__WinVer_DefineOSTests WinVer + !insertmacro __WinVer_DefineOSTest AtLeast ${WinVer} "" + !insertmacro __WinVer_DefineOSTest AtMost ${WinVer} "" + !insertmacro __WinVer_DefineOSTest Is ${WinVer} "" +!macroend + +!ifndef WINVER_7 + !define WINVER_7 0x06010000 ;6.01.???? + !insertmacro __MOZ__WinVer_DefineOSTests 7 +!endif + +!ifndef WINVER_2008R2 + !define WINVER_2008R2 0x06010001 ;6.01.???? + !insertmacro __MOZ__WinVer_DefineOSTests 2008R2 +!endif + +!ifndef WINVER_8 + !define WINVER_8 0x06020000 ;6.02.???? + !insertmacro __MOZ__WinVer_DefineOSTests 8 +!endif + +!verbose push +!verbose 3 +!ifndef _OVERRIDE_VERBOSE + !define _OVERRIDE_VERBOSE 3 +!endif +!verbose ${_OVERRIDE_VERBOSE} +!define OVERRIDE_VERBOSE `!insertmacro OVERRIDE_VERBOSE` +!define _OVERRIDE_UN +!define _OVERRIDE_S +!verbose pop + +!macro OVERRIDE_VERBOSE _VERBOSE + !verbose push + !verbose 3 + !undef _OVERRIDE_VERBOSE + !define _OVERRIDE_VERBOSE ${_VERBOSE} + !verbose pop +!macroend + +; Modified version of Locate from the NSIS File Functions Header v3.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/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 0000000000..9801fed54f Binary files /dev/null and b/app/win/installer/setup.ico differ diff --git a/app/win/installer/shared.nsh b/app/win/installer/shared.nsh new file mode 100755 index 0000000000..f1f239bfb5 --- /dev/null +++ b/app/win/installer/shared.nsh @@ -0,0 +1,366 @@ +# 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/. + +!macro PostUpdate + ${CreateShortcutsLog} + + ; Remove registry entries for non-existent apps and for apps that point to our + ; install location in the Software\Zotero key and uninstall registry entries + ; that point to our install location for both HKCU and HKLM. + SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU) + ${RegCleanMain} "Software\Zotero" + ${RegCleanUninstall} + ${UpdateProtocolHandlers} + ; Win7 taskbar and start menu link maintenance + Call FixShortcutAppModelIDs + + ClearErrors + WriteRegStr HKLM "Software\Zotero" "${BrandShortName}InstallerTest" "Write Test" + ${If} ${Errors} + StrCpy $TmpVal "HKCU" ; used primarily for logging + ${Else} + SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM) + DeleteRegValue HKLM "Software\Zotero" "${BrandShortName}InstallerTest" + StrCpy $TmpVal "HKLM" ; used primarily for logging + ${RegCleanMain} "Software\Zotero" + ${RegCleanUninstall} + ${UpdateProtocolHandlers} + ${SetAppLSPCategories} ${LSP_CATEGORIES} + + ; Win7 taskbar and start menu link maintenance + Call FixShortcutAppModelIDs + + ReadRegStr $0 HKLM "Software\zotero.org\Zotero" "CurrentVersion" + ${If} "$0" != "${GREVersion}" + WriteRegStr HKLM "Software\zotero.org\Zotero" "CurrentVersion" "${GREVersion}" + ${EndIf} + ${EndIf} + + ${SetAppKeys} + ${FixClassKeys} + ${SetUninstallKeys} +!macroend +!define PostUpdate "!insertmacro PostUpdate" + +; Adds zotero:// protocol handler and makes Zotero open exported bib files +!macro SetHandlers + Push "$INSTDIR\${FileMainEXE}" + Call GetLongPath + Pop $8 + + ${AddHandlerValues} "Software\Classes\zotero" "$\"$8$\" -url $\"%1$\"" \ + "$8,1" "Zotero Protocol" "true" "" + + ; Add handlers for reference formats + ${AddHandlerValues} "Software\Classes\ZoteroRIS" "$\"$8$\" -file $\"%1$\"" \ + "$8,1" "Research Information Systems Document" "" "" + + ${AddHandlerValues} "Software\Classes\ZoteroISI" "$\"$8$\" -file $\"%1$\"" \ + "$8,1" "ISI Common Export Format Document" "" "" + + ${AddHandlerValues} "Software\Classes\ZoteroMODS" "$\"$8$\" -file $\"%1$\"" \ + "$8,1" "Metadata Object Description Schema Document" "" "" + + ${AddHandlerValues} "Software\Classes\ZoteroRDF" "$\"$8$\" -file $\"%1$\"" \ + "$8,1" "Resource Description Framework Document" "" "" + + ${AddHandlerValues} "Software\Classes\ZoteroBibTeX" "$\"$8$\" -file $\"%1$\"" \ + "$8,1" "BibTeX Document" "" "" + + ${AddHandlerValues} "Software\Classes\ZoteroMARC" "$\"$8$\" -file $\"%1$\"" \ + "$8,1" "MARC Document" "" "" + + ${AddHandlerValues} "Software\Classes\ZoteroCSL" "$\"$8$\" -file $\"%1$\"" \ + "$8,1" "CSL Citation Style" "" "" + + ; Associate file handlers + ReadRegStr $6 SHCTX "Software\Classes\.ris" "" + ${If} "$6" != "ZoteroRIS" + WriteRegStr SHCTX "Software\Classes\.ris" "" "ZoteroRIS" + WriteRegStr SHCTX "Software\Classes\.ris" "Content Type" "application/x-research-info-systems" + ${EndIf} + + ReadRegStr $6 SHCTX "Software\Classes\.mods" "" + ${If} "$6" != "ZoteroMODS" + WriteRegStr SHCTX "Software\Classes\.mods" "" "ZoteroMODS" + WriteRegStr SHCTX "Software\Classes\.mods" "Content Type" "application/mods+xml" + ${EndIf} + + ReadRegStr $6 SHCTX "Software\Classes\.isi" "" + ${If} "$6" != "ZoteroMODS" + WriteRegStr SHCTX "Software\Classes\.isi" "" "ZoteroISI" + WriteRegStr SHCTX "Software\Classes\.isi" "Content Type" "application/x-inst-for-Scientific-info" + ${EndIf} + + ReadRegStr $6 SHCTX "Software\Classes\.rdf" "" + ${If} "$6" != "ZoteroRDF" + WriteRegStr SHCTX "Software\Classes\.rdf" "" "ZoteroRDF" + WriteRegStr SHCTX "Software\Classes\.rdf" "Content Type" "application/rdf+xml" + ${EndIf} + + ReadRegStr $6 SHCTX "Software\Classes\.bib" "" + ${If} "$6" != "ZoteroBibTeX" + WriteRegStr SHCTX "Software\Classes\.bib" "" "ZoteroBibTeX" + WriteRegStr SHCTX "Software\Classes\.bib" "Content Type" "application/x-bibtex" + ${EndIf} + + ReadRegStr $6 SHCTX "Software\Classes\.bibtex" "" + ${If} "$6" != "ZoteroMARC" + WriteRegStr SHCTX "Software\Classes\.bibtex" "" "ZoteroBibTeX" + WriteRegStr SHCTX "Software\Classes\.bibtex" "Content Type" "application/x-bibtex" + ${EndIf} + + ReadRegStr $6 SHCTX "Software\Classes\.marc" "" + ${If} "$6" != "ZoteroMARC" + WriteRegStr SHCTX "Software\Classes\.marc" "" "ZoteroMARC" + WriteRegStr SHCTX "Software\Classes\.marc" "Content Type" "application/marc" + ${EndIf} + + ReadRegStr $6 SHCTX "Software\Classes\.csl" "" + ${If} "$6" != "ZoteroCSL" + WriteRegStr SHCTX "Software\Classes\.csl" "" "ZoteroCSL" + WriteRegStr SHCTX "Software\Classes\.csl" "Content Type" "application/vnd.citationstyles.style+xml" + ${EndIf} +!macroend +!define SetHandlers "!insertmacro SetHandlers" + +; Add Software\Zotero\ registry entries (uses SHCTX). +!macro SetAppKeys + Push $INSTDIR + Call GetLongPath + Pop $8 + StrCpy $0 "Software\Zotero\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Main" + ${WriteRegStr2} $TmpVal "$0" "Install Directory" "$8" 0 + ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$8\${FileMainEXE}" 0 + + StrCpy $0 "Software\Zotero\${BrandFullNameInternal}\${AppVersion} (${AB_CD})\Uninstall" + ${WriteRegStr2} $TmpVal "$0" "Description" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0 + + StrCpy $0 "Software\Zotero\${BrandFullNameInternal}\${AppVersion} (${AB_CD})" + ${WriteRegStr2} $TmpVal "$0" "" "${AppVersion} (${AB_CD})" 0 + + StrCpy $0 "Software\Zotero\${BrandFullNameInternal} ${AppVersion}\bin" + ${WriteRegStr2} $TmpVal "$0" "PathToExe" "$8\${FileMainEXE}" 0 + + StrCpy $0 "Software\Zotero\${BrandFullNameInternal} ${AppVersion}\extensions" + ${WriteRegStr2} $TmpVal "$0" "Components" "$8\components" 0 + ${WriteRegStr2} $TmpVal "$0" "Plugins" "$8\plugins" 0 + + StrCpy $0 "Software\Zotero\${BrandFullNameInternal} ${AppVersion}" + ${WriteRegStr2} $TmpVal "$0" "GeckoVer" "${GREVersion}" 0 + + StrCpy $0 "Software\Zotero\${BrandFullNameInternal}" + ${WriteRegStr2} $TmpVal "$0" "" "${GREVersion}" 0 + ${WriteRegStr2} $TmpVal "$0" "CurrentVersion" "${AppVersion} (${AB_CD})" 0 +!macroend +!define SetAppKeys "!insertmacro SetAppKeys" + +; Add uninstall registry entries. This macro tests for write access to determine +; if the uninstall keys should be added to HKLM or HKCU. +!macro SetUninstallKeys + StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\Uninstall\${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" + + StrCpy $2 "" + ClearErrors + WriteRegStr HKLM "$0" "${BrandShortName}InstallerTest" "Write Test" + ${If} ${Errors} + ; If the uninstall keys already exist in HKLM don't create them in HKCU + ClearErrors + ReadRegStr $2 "HKLM" $0 "DisplayName" + ${If} $2 == "" + ; Otherwise we don't have any keys for this product in HKLM so proceeed + ; to create them in HKCU. Better handling for this will be done in: + ; Bug 711044 - Better handling for 2 uninstall icons + StrCpy $1 "HKCU" + SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU) + ${EndIf} + ClearErrors + ${Else} + StrCpy $1 "HKLM" + SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM) + DeleteRegValue HKLM "$0" "${BrandShortName}InstallerTest" + ${EndIf} + + ${If} $2 == "" + Push $INSTDIR + Call GetLongPath + Pop $8 + + ; Write the uninstall registry keys + ${WriteRegStr2} $1 "$0" "Comments" "${BrandFullNameInternal} ${AppVersion} (${ARCH} ${AB_CD})" 0 + ${WriteRegStr2} $1 "$0" "DisplayIcon" "$8\${FileMainEXE},0" 0 + ${WriteRegStr2} $1 "$0" "DisplayName" "${BrandFullNameInternal}" 0 + ${WriteRegStr2} $1 "$0" "DisplayVersion" "${AppVersion}" 0 + ${WriteRegStr2} $1 "$0" "InstallLocation" "$8" 0 + ${WriteRegStr2} $1 "$0" "Publisher" "Corporation for Digital Scholarship" 0 + ${WriteRegStr2} $1 "$0" "UninstallString" "$8\uninstall\helper.exe" 0 + ${WriteRegStr2} $1 "$0" "URLInfoAbout" "${URLInfoAbout}" 0 + ${WriteRegStr2} $1 "$0" "URLUpdateInfo" "${URLUpdateInfo}" 0 + ${WriteRegDWORD2} $1 "$0" "NoModify" 1 0 + ${WriteRegDWORD2} $1 "$0" "NoRepair" 1 0 + + ${GetSize} "$8" "/S=0K" $R2 $R3 $R4 + ${WriteRegDWORD2} $1 "$0" "EstimatedSize" $R2 0 + + ${If} "$TmpVal" == "HKLM" + SetShellVarContext all ; Set SHCTX to all users (e.g. HKLM) + ${Else} + SetShellVarContext current ; Set SHCTX to the current user (e.g. HKCU) + ${EndIf} + ${EndIf} +!macroend +!define SetUninstallKeys "!insertmacro SetUninstallKeys" + +; Add app specific handler registry entries under Software\Classes if they +; don't exist (does not use SHCTX). +!macro FixClassKeys + StrCpy $1 "SOFTWARE\Classes" + + ; File handler keys and name value pairs that may need to be created during + ; install or upgrade. + ReadRegStr $0 HKCR ".shtml" "Content Type" + ${If} "$0" == "" + StrCpy $0 "$1\.shtml" + ${WriteRegStr2} $TmpVal "$1\.shtml" "" "shtmlfile" 0 + ${WriteRegStr2} $TmpVal "$1\.shtml" "Content Type" "text/html" 0 + ${WriteRegStr2} $TmpVal "$1\.shtml" "PerceivedType" "text" 0 + ${EndIf} + + ReadRegStr $0 HKCR ".xht" "Content Type" + ${If} "$0" == "" + ${WriteRegStr2} $TmpVal "$1\.xht" "" "xhtfile" 0 + ${WriteRegStr2} $TmpVal "$1\.xht" "Content Type" "application/xhtml+xml" 0 + ${EndIf} + + ReadRegStr $0 HKCR ".xhtml" "Content Type" + ${If} "$0" == "" + ${WriteRegStr2} $TmpVal "$1\.xhtml" "" "xhtmlfile" 0 + ${WriteRegStr2} $TmpVal "$1\.xhtml" "Content Type" "application/xhtml+xml" 0 + ${EndIf} +!macroend +!define FixClassKeys "!insertmacro FixClassKeys" + +; Updates protocol handlers if their registry open command value is for this +; install location (uses SHCTX). +!macro UpdateProtocolHandlers + ; Store the command to open the app with an url in a register for easy access. + Push "$INSTDIR\${FileMainEXE}" + Call GetLongPath + Pop $8 + + ; Only set the file and protocol handlers if the existing one under HKCR is + ; for this install location. + + ${IsHandlerForInstallDir} "zotero" $R9 + ${If} "$R9" == "true" + ${AddHandlerValues} "SOFTWARE\Classes\zotero" "$\"$8$\" -url $\"%1$\"" \ + "$8,1" "Zotero" "true" "" + ${EndIf} +!macroend +!define UpdateProtocolHandlers "!insertmacro UpdateProtocolHandlers" + +; Removes the application's start menu directory along with its shortcuts if +; they exist and if they exist creates a start menu shortcut in the root of the +; start menu directory (bug 598779). If the application's start menu directory +; is not empty after removing the shortucts the directory will not be removed +; since these additional items were not created by the installer (uses SHCTX). +!macro RemoveStartMenuDir + ${GetShortcutsLogPath} $0 + ${If} ${FileExists} "$0" + ; Delete Start Menu Programs shortcuts, directory if it is empty, and + ; parent directories if they are empty up to but not including the start + ; menu directory. + Push $SMPROGRAMS + Call GetLongPath + Pop $1 + ClearErrors + ReadINIStr $2 "$0" "SMPROGRAMS" "RelativePathToDir" + ${Unless} ${Errors} + Push "$1\$2" + Call GetLongPath + Pop $2 + ${If} "$2" != "" + ; Delete shortucts in the Start Menu Programs directory. + StrCpy $3 0 + ${Do} + ClearErrors + ReadINIStr $4 "$0" "SMPROGRAMS" "Shortcut$3" + ; Stop if there are no more entries + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${If} ${FileExists} "$2\$4" + ShellLink::GetShortCutTarget "$2\$4" + Pop $5 + ${If} "$INSTDIR\${FileMainEXE}" == "$5" + Delete "$2\$4" + ${EndIf} + ${EndIf} + IntOp $3 $3 + 1 ; Increment the counter + ${Loop} + ; Delete Start Menu Programs directory and parent directories + ${Do} + ; Stop if the current directory is the start menu directory + ${If} "$1" == "$2" + ${ExitDo} + ${EndIf} + ClearErrors + RmDir "$2" + ; Stop if removing the directory failed + ${If} ${Errors} + ${ExitDo} + ${EndIf} + ${GetParent} "$2" $2 + ${Loop} + ${EndIf} + DeleteINISec "$0" "SMPROGRAMS" + ${EndUnless} + ${EndIf} +!macroend +!define RemoveStartMenuDir "!insertmacro RemoveStartMenuDir" + +; Creates the shortcuts log ini file with the appropriate entries if it doesn't +; already exist. +!macro CreateShortcutsLog + ${GetShortcutsLogPath} $0 + ${Unless} ${FileExists} "$0" + ${LogStartMenuShortcut} "${BrandFullName}.lnk" + ${LogQuickLaunchShortcut} "${BrandFullName}.lnk" + ${LogDesktopShortcut} "${BrandFullName}.lnk" + ${EndUnless} +!macroend +!define CreateShortcutsLog "!insertmacro CreateShortcutsLog" + +; The files to check if they are in use during (un)install so the restart is +; required message is displayed. All files must be located in the $INSTDIR +; directory. +!macro PushFilesToCheck + ; The first string to be pushed onto the stack MUST be "end" to indicate + ; that there are no more files to check in $INSTDIR and the last string + ; should be ${FileMainEXE} so if it is in use the CheckForFilesInUse macro + ; returns after the first check. + Push "end" + Push "AccessibleMarshal.dll" + Push "freebl3.dll" + Push "nssckbi.dll" + Push "nspr4.dll" + Push "nssdbm3.dll" + Push "mozsqlite3.dll" + Push "xpcom.dll" + Push "crashreporter.exe" + Push "updater.exe" + Push "${FileMainEXE}" +!macroend +!define PushFilesToCheck "!insertmacro PushFilesToCheck" + +; Helper for updating the shortcut application model IDs. +Function FixShortcutAppModelIDs + ${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}" $0 +FunctionEnd + +; The !ifdef NO_LOG prevents warnings when compiling the installer.nsi due to +; this function only being used by the uninstaller.nsi. +!ifdef NO_LOG + +!endif diff --git a/app/win/installer/uninstaller.nsi b/app/win/installer/uninstaller.nsi new file mode 100755 index 0000000000..08a58f4611 --- /dev/null +++ b/app/win/installer/uninstaller.nsi @@ -0,0 +1,779 @@ +# 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 +# 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 + +; 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 +CRCCheck on + +RequestExecutionLevel user + +!addplugindir ./ + +; On Vista and above attempt to elevate Standard Users in addition to users that +; are a member of the Administrators group. +!define NONADMIN_ELEVATE + +; prevents compiling of the reg write logging. +!define NO_LOG + +; 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 GetSize +!insertmacro StrFilter +!insertmacro WordReplace + +!insertmacro un.GetParent + +; The following includes are custom. +!include branding.nsi +!include defines.nsi +!include common.nsh +!include locales.nsi + +; This is named BrandShortName helper because we use this for software update +; post update cleanup. +VIAddVersionKey "FileDescription" "${BrandShortName} Helper" +VIAddVersionKey "OriginalFilename" "helper.exe" + +!insertmacro AddHandlerValues +!insertmacro ElevateUAC +!insertmacro GetOptions +!insertmacro GetParameters +!insertmacro GetPathFromString +!insertmacro IsHandlerForInstallDir +!insertmacro LogDesktopShortcut +!insertmacro LogQuickLaunchShortcut +!insertmacro LogStartMenuShortcut +!insertmacro RegCleanMain +!insertmacro RegCleanUninstall +!insertmacro SetAppLSPCategories +!insertmacro SetBrandNameVars +!insertmacro UpdateShortcutAppModelIDs +!insertmacro UpdateUninstallLog +!insertmacro WriteRegDWORD2 +!insertmacro WriteRegStr2 + +!insertmacro un.ChangeMUIHeaderImage +!insertmacro un.CheckForFilesInUse +!insertmacro un.CleanUpdatesDir +!insertmacro un.DeleteShortcuts +!insertmacro un.ElevateUAC +!insertmacro un.GetSecondInstallPath +!insertmacro un.ManualCloseAppPrompt +!insertmacro un.ParseUninstallLog +!insertmacro un.RegCleanAppHandler +!insertmacro un.RegCleanFileHandler +!insertmacro un.RegCleanMain +!insertmacro un.RegCleanProtocolHandler +!insertmacro un.RegCleanUninstall +!insertmacro un.SetAppLSPCategories +!insertmacro un.SetBrandNameVars + +!include shared.nsh + +; Helper macros for ui callbacks. Insert these after shared.nsh +!insertmacro OnEndCommon + +!insertmacro un.OnEndCommon + +Name "${BrandFullName}" +OutFile "helper.exe" +!ifdef HAVE_64BIT_OS + InstallDir "$PROGRAMFILES64\${BrandFullName}\" +!else + InstallDir "$PROGRAMFILES32\${BrandFullName}\" +!endif +ShowUnInstDetails nevershow + +################################################################################ +# Modern User Interface - MUI + +!define MUI_ABORTWARNING +!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_UNWELCOMEFINISHPAGE_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 + +/** + * Uninstall Pages + */ +; Welcome Page +!define MUI_PAGE_CUSTOMFUNCTION_PRE un.preWelcome +!define MUI_PAGE_CUSTOMFUNCTION_LEAVE un.leaveWelcome +!insertmacro MUI_UNPAGE_WELCOME + +; Custom Uninstall Confirm Page +UninstPage custom un.preConfirm un.leaveConfirm + +; Remove Files Page +!insertmacro MUI_UNPAGE_INSTFILES + +; Finish Page + +; Don't setup the survey controls, functions, etc. when the application has +; defined NO_UNINSTALL_SURVEY +!ifndef NO_UNINSTALL_SURVEY +!define MUI_PAGE_CUSTOMFUNCTION_PRE un.preFinish +!define MUI_FINISHPAGE_SHOWREADME_NOTCHECKED +!define MUI_FINISHPAGE_SHOWREADME "" +!define MUI_FINISHPAGE_SHOWREADME_TEXT $(SURVEY_TEXT) +!define MUI_FINISHPAGE_SHOWREADME_FUNCTION un.Survey +!endif + +!insertmacro MUI_UNPAGE_FINISH + +; Use the default dialog for IDD_VERIFY for a simple Banner +ChangeUI IDD_VERIFY "${NSISDIR}\Contrib\UIs\default.exe" + +################################################################################ +# Install Sections +; Empty section required for the installer to compile as an uninstaller +Section "" +SectionEnd + +################################################################################ +# Uninstall Sections + +Section "Uninstall" + SetDetailsPrint textonly + DetailPrint $(STATUS_UNINSTALL_MAIN) + SetDetailsPrint none + + ; Handle a few uninstall tasks for the current user even if this ends up being + ; a system-wide uninstall. + ${MUI_INSTALLOPTIONS_READ} $0 "unconfirm.ini" "Field 3" "State" + ${If} "$0" == "1" + SetShellVarContext current + Push "Zotero\Zotero" + Call un.DeleteRelativeProfiles + RmDir "$APPDATA\Zotero" + ${EndIf} + + ; Check whether Zotero was installed under HKLM. If it was we will need to elevate. + SetShellVarContext all + Push "0" + Push $INSTDIR + Call un.IterateUninstallKeys + ; The error flag means no key was found. In that case set to user uninstall. + ; When a key is found in HKLM leave shell context to all and trigger + ; elevation prompt. + IfErrors 0 elevate + SetShellVarContext current + Goto elevation_complete + elevate: + ${un.ElevateUAC} + elevation_complete: + Pop $Trash + Pop $Trash + + ; Delete the app exe to prevent launching the app while we are uninstalling. + 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 still delete the files when the system is restarted. + Sleep 5000 + ${DeleteFile} "$INSTDIR\${FileMainEXE}" + ClearErrors + ${EndIf} + + ; Unregister resources associated with Win7 taskbar jump lists. + ApplicationID::UninstallJumpLists "${AppUserModelID}" + + ClearErrors + ${un.RegCleanMain} "Software\Zotero" + ${un.RegCleanUninstall} + ${un.DeleteShortcuts} + ${un.SetAppLSPCategories} + + ${un.RegCleanProtocolHandler} "zotero" + ${un.RegCleanAppHandler} "ZoteroRIS" + ${un.RegCleanAppHandler} "ZoteroISI" + ${un.RegCleanAppHandler} "ZoteroMODS" + ${un.RegCleanAppHandler} "ZoteroRDF" + ${un.RegCleanAppHandler} "ZoteroBibTeX" + ${un.RegCleanAppHandler} "ZoteroMARC" + ${un.RegCleanAppHandler} "ZoteroCSL" + + ClearErrors + ReadRegStr $R9 HKCR "ZoteroRDF" "" + ; Don't clean up the file handlers if the ZoteroRDF key still exists since + ; there should be a second installation that may be the default file handler + ${If} ${Errors} + ${un.RegCleanFileHandler} ".rdf" "ZoteroRDF" + ${un.RegCleanFileHandler} ".ris" "ZoteroRIS" + ${un.RegCleanFileHandler} ".isi" "ZoteroISI" + ${un.RegCleanFileHandler} ".mods" "ZoteroMODS" + ${un.RegCleanFileHandler} ".bib" "ZoteroBibTeX" + ${un.RegCleanFileHandler} ".bibtex" "ZoteroBibTeX" + ${un.RegCleanFileHandler} ".marc" "ZoteroMARC" + ${un.RegCleanFileHandler} ".csl" "ZoteroCSL" + ${EndIf} + + ${un.GetSecondInstallPath} "Software\Zotero" $R9 + + StrCpy $0 "Software\Microsoft\Windows\CurrentVersion\App Paths\${FileMainEXE}" + ${If} $R9 == "false" + DeleteRegKey SHCTX "$0" + StrCpy $0 "Software\Classes\MIME\Database\Content Type\application/x-xpinstall;app=firefox" + DeleteRegKey SHCTX "$0" + ${Else} + ReadRegStr $R1 SHCTX "$0" "" + Push $R1 + Call un.RemoveQuotesFromPath + Pop $R1 + ${un.GetParent} "$R1" $R1 + ${If} "$INSTDIR" == "$R1" + WriteRegStr SHCTX "$0" "" "$R9" + ${un.GetParent} "$R9" $R1 + WriteRegStr SHCTX "$0" "Path" "$R1" + ${EndIf} + ${EndIf} + + ; Remove directories and files we always control before parsing the uninstall + ; log so empty directories can be removed. + ${If} ${FileExists} "$INSTDIR\updates" + RmDir /r /REBOOTOK "$INSTDIR\updates" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\defaults\shortcuts" + RmDir /r /REBOOTOK "$INSTDIR\defaults\shortcuts" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\distribution" + RmDir /r /REBOOTOK "$INSTDIR\distribution" + ${EndIf} + ${If} ${FileExists} "$INSTDIR\removed-files" + Delete /REBOOTOK "$INSTDIR\removed-files" + ${EndIf} + + ; Remove the updates directory for Vista and above + ${un.CleanUpdatesDir} "Zotero\Zotero" + + ; Parse the uninstall log to unregister dll's and remove all installed + ; files / directories this install is responsible for. + ${un.ParseUninstallLog} + + ; Files that were added by an in-app update aren't currently being added to the uninstall log, + ; 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} $INSTDIR $R1 + StrCpy $R2 $R1 6 + StrCmp $R2 "Zotero" +1 post_delete + ${If} ${FileExists} "$INSTDIR\chrome" + RMDir /r /REBOOTOK "$INSTDIR\chrome" + ${EndIF} + ${If} ${FileExists} "$INSTDIR\components" + RMDir /r /REBOOTOK "$INSTDIR\components" + ${EndIF} + ${If} ${FileExists} "$INSTDIR\defaults" + RMDir /r /REBOOTOK "$INSTDIR\defaults" + ${EndIF} + ${If} ${FileExists} "$INSTDIR\dictionaries" + RMDir /r /REBOOTOK "$INSTDIR\dictionaries" + ${EndIF} + ${If} ${FileExists} "$INSTDIR\extensions" + RMDir /r /REBOOTOK "$INSTDIR\extensions" + ${EndIF} + ${If} ${FileExists} "$INSTDIR\fonts" + RMDir /r /REBOOTOK "$INSTDIR\fonts" + ${EndIF} + ${If} ${FileExists} "$INSTDIR\gmp-clearkey" + RMDir /r /REBOOTOK "$INSTDIR\gmp-clearkey" + ${EndIF} + ${If} ${FileExists} "$INSTDIR\xulrunner" + RMDir /r /REBOOTOK "$INSTDIR\xulrunner" + ${EndIF} + Delete /REBOOTOK "$INSTDIR\*.chk" + Delete /REBOOTOK "$INSTDIR\*.dll" + Delete /REBOOTOK "$INSTDIR\*.exe" + Delete /REBOOTOK "$INSTDIR\Accessible.tlb" + Delete /REBOOTOK "$INSTDIR\dependentlibs.list" + Delete /REBOOTOK "$INSTDIR\firefox.VisualElementsManifest.xml" + Delete /REBOOTOK "$INSTDIR\omni.ja" + Delete /REBOOTOK "$INSTDIR\platform.ini" + Delete /REBOOTOK "$INSTDIR\precomplete" + Delete /REBOOTOK "$INSTDIR\voucher.bin" + post_delete: + + ; Remove the uninstall directory that we control + RmDir /r /REBOOTOK "$INSTDIR\uninstall" + + ; Remove the installation directory if it is empty + ${RemoveDir} "$INSTDIR" + + ; If firefox.exe was successfully deleted yet we still need to restart to + ; remove other files create a dummy firefox.exe.moz-delete to prevent the + ; installer from allowing an install without restart when it is required + ; to complete an uninstall. + ${If} ${RebootFlag} + ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}.moz-delete" + FileOpen $0 "$INSTDIR\${FileMainEXE}.moz-delete" w + FileWrite $0 "Will be deleted on restart" + Delete /REBOOTOK "$INSTDIR\${FileMainEXE}.moz-delete" + FileClose $0 + ${EndUnless} + ${EndIf} + + ; Refresh desktop icons otherwise the start menu internet item won't be + ; removed and other ugly things will happen like recreation of the app's + ; clients registry key by the OS under some conditions. + System::Call "shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i 0, i 0, i 0)" +SectionEnd + +################################################################################ +# Helper Functions + +; Don't setup the survey controls, functions, etc. when the application has +; defined NO_UNINSTALL_SURVEY +!ifndef NO_UNINSTALL_SURVEY +Function un.Survey + Exec "$\"$TmpVal$\" $\"${SurveyURL}$\"" +FunctionEnd +!endif + +################################################################################ +# 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 un.preWelcome + ${If} ${FileExists} "$INSTDIR\distribution\modern-wizard.bmp" + Delete "$PLUGINSDIR\modern-wizard.bmp" + CopyFiles /SILENT "$INSTDIR\distribution\modern-wizard.bmp" "$PLUGINSDIR\modern-wizard.bmp" + ${EndIf} +FunctionEnd + +Function un.leaveWelcome + ${If} ${FileExists} "$INSTDIR\${FileMainEXE}" + Banner::show /NOUNLOAD "$(BANNER_CHECK_EXISTING)" + + ; If the message window has been found previously give the app an additional + ; five seconds to close. + ${If} "$TmpVal" == "FoundMessageWindow" + Sleep 5000 + ${EndIf} + + ${PushFilesToCheck} + + ${un.CheckForFilesInUse} $TmpVal + + Banner::destroy + + ; If there are files in use $TmpVal will be "true" + ${If} "$TmpVal" == "true" + ; If the message window is found the call to ManualCloseAppPrompt will + ; abort leaving the value of $TmpVal set to "FoundMessageWindow". + StrCpy $TmpVal "FoundMessageWindow" + ${un.ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_UNINSTALL)" + ; If the message window is not found set $TmpVal to "true" so the restart + ; required message is displayed. + StrCpy $TmpVal "true" + ${EndIf} + ${EndIf} +FunctionEnd + +Function un.preConfirm + ${If} ${FileExists} "$INSTDIR\distribution\modern-header.bmp" + ${AndIf} $hHeaderBitmap == "" + Delete "$PLUGINSDIR\modern-header.bmp" + CopyFiles /SILENT "$INSTDIR\distribution\modern-header.bmp" "$PLUGINSDIR\modern-header.bmp" + ${un.ChangeMUIHeaderImage} "$PLUGINSDIR\modern-header.bmp" + ${EndIf} + + ; Setup the unconfirm.ini file for the Custom Uninstall Confirm Page + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "5" + + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Type "label" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Text "$(UN_CONFIRM_UNINSTALLED_FROM)" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Left "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Right "-1" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Top "5" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 1" Bottom "15" + + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Type "text" + ; The contents of this control must be set as follows in the pre function + ; ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 2" "HWND" + ; SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" State "" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Left "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Right "-1" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Top "17" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" Bottom "30" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 2" flags "READONLY" + + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Type "checkbox" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Text "$(UN_REMOVE_PROFILES)" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Left "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Right "-1" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "40" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "50" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" State "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" flags "NOTIFY" + + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Type "text" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" State "$(UN_REMOVE_PROFILES_DESC)" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Left "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Right "-1" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Top "52" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Bottom "120" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" flags "MULTILINE|READONLY" + + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Type "label" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Text "$(UN_CONFIRM_CLICK)" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Left "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Right "-1" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Top "130" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 5" Bottom "150" + + ${If} "$TmpVal" == "true" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Type "label" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Text "$(SUMMARY_REBOOT_REQUIRED_UNINSTALL)" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Left "0" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Right "-1" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Top "35" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 6" Bottom "45" + + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Settings" NumFields "6" + + ; To insert this control reset Top / Bottom for controls below this one + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Top "55" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 3" Bottom "65" + WriteINIStr "$PLUGINSDIR\unconfirm.ini" "Field 4" Top "67" + ${EndIf} + + !insertmacro MUI_HEADER_TEXT "$(UN_CONFIRM_PAGE_TITLE)" "$(UN_CONFIRM_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 "unconfirm.ini" + GetDlgItem $0 $HWNDPARENT 1 + ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 4" "HWND" + SetCtlColors $1 0x000000 0xFFFFEE + ShowWindow $1 ${SW_HIDE} + System::Call "user32::SetFocus(i r0, i 0x0007, i,i)i" + ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 2" "HWND" + SendMessage $1 ${WM_SETTEXT} 0 "STR:$INSTDIR" + !insertmacro MUI_INSTALLOPTIONS_SHOW +FunctionEnd + +Function un.leaveConfirm + ${MUI_INSTALLOPTIONS_READ} $0 "unconfirm.ini" "Settings" "State" + StrCmp $0 "3" +1 continue + ${MUI_INSTALLOPTIONS_READ} $0 "unconfirm.ini" "Field 3" "State" + ${MUI_INSTALLOPTIONS_READ} $1 "unconfirm.ini" "Field 4" "HWND" + StrCmp $0 1 +1 +3 + ShowWindow $1 ${SW_SHOW} + Abort + + ShowWindow $1 ${SW_HIDE} + Abort + + continue: + + ; 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 if they are in use. + ClearErrors + ${DeleteFile} "$INSTDIR\${FileMainEXE}" + ${If} ${Errors} + ${un.ManualCloseAppPrompt} "${WindowClass}" "$(WARN_MANUALLY_CLOSE_APP_UNINSTALL)" + ${EndIf} +FunctionEnd + +!ifndef NO_UNINSTALL_SURVEY +Function un.preFinish + ; Do not modify the finish page if there is a reboot pending + ${Unless} ${RebootFlag} + ; Setup the survey controls, functions, etc. + StrCpy $TmpVal "SOFTWARE\Microsoft\IE Setup\Setup" + ClearErrors + ReadRegStr $0 HKLM $TmpVal "Path" + ${If} ${Errors} + !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "NumFields" "3" + ${Else} + ExpandEnvStrings $0 "$0" ; this value will usually contain %programfiles% + ${If} $0 != "\" + StrCpy $0 "$0\" + ${EndIf} + StrCpy $0 "$0\iexplore.exe" + ClearErrors + GetFullPathName $TmpVal $0 + ${If} ${Errors} + !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "NumFields" "3" + ${Else} + ; 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. + !insertmacro MUI_INSTALLOPTIONS_WRITE "ioSpecial.ini" "settings" "cancelenabled" "0" + ${EndIf} + ${EndIf} + ${EndUnless} +FunctionEnd +!endif + +################################################################################ +# Initialization Functions + +Function .onInit + ; Prevents breaking apps that don't use SetBrandNameVars + !ifdef SetBrandNameVars + ${SetBrandNameVars} "$EXEDIR\distribution\setup.ini" + !endif + + ; Prevent launching the application when a reboot is required and this + ; executable is the main application executable + IfFileExists "$EXEDIR\${FileMainEXE}.moz-upgrade" +1 +4 + MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2 + Reboot + Quit ; Nothing initialized so no need to call OnEndCommon + + ${GetParent} "$EXEDIR" $INSTDIR + Push $INSTDIR + Call GetLongPath + Pop $INSTDIR + IfFileExists "$INSTDIR\${FileMainEXE}" +2 +1 + Quit ; Nothing initialized so no need to call OnEndCommon + + ; Prevents breaking apps that don't use SetBrandNameVars + !ifdef SetBrandNameVars + ${SetBrandNameVars} "$INSTDIR\distribution\setup.ini" + !endif + + ; 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} + + ; Prevent all operations (e.g. set as default, postupdate, etc.) when a + ; reboot is required and the executable launched is helper.exe + IfFileExists "$INSTDIR\${FileMainEXE}.moz-upgrade" +1 +4 + MessageBox MB_YESNO|MB_ICONEXCLAMATION "$(WARN_RESTART_REQUIRED_UPGRADE)" IDNO +2 + Reboot + Quit ; Nothing initialized so no need to call OnEndCommon + + !ifdef HAVE_64BIT_OS + SetRegView 64 + !endif + + ${GetParameters} $R0 + + StrCmp "$R0" "" continue +1 + + ; Update this user's shortcuts with the latest app user model id. + ClearErrors + ${GetOptions} "$R0" "/UpdateShortcutAppUserModelIds" $R2 + IfErrors postupdate +1 + ${UpdateShortcutAppModelIDs} "$INSTDIR\${FileMainEXE}" "${AppUserModelID}" $R2 + StrCmp "$R2" "true" finish +1 ; true indicates that shortcuts have been updated + Quit ; Nothing initialized so no need to call OnEndCommon + + ; Do not attempt to elevate. The application launching this executable is + ; responsible for elevation if it is required. + postupdate: + ${WordReplace} "$R0" "$\"" "" "+" $R0 + ClearErrors + ${GetOptions} "$R0" "/PostUpdate" $R2 + IfErrors continue +1 + ; If the uninstall.log does not exist don't perform post update + ; operations. This prevents updating the registry for zip builds. + IfFileExists "$EXEDIR\uninstall.log" +2 +1 + Quit ; Nothing initialized so no need to call OnEndCommon + ${PostUpdate} + ClearErrors + ${GetOptions} "$R0" "/UninstallLog=" $R2 + IfErrors updateuninstalllog +1 + StrCmp "$R2" "" finish +1 + GetFullPathName $R3 "$R2" + IfFileExists "$R3" +1 finish + Delete "$INSTDIR\uninstall\*wizard*" + Delete "$INSTDIR\uninstall\uninstall.log" + CopyFiles /SILENT /FILESONLY "$R3" "$INSTDIR\uninstall\" + ${GetParent} "$R3" $R4 + Delete "$R3" + RmDir "$R4" + GoTo finish + + ; Do not attempt to elevate. The application launching this executable is + ; responsible for elevation if it is required. + updateuninstalllog: + ${UpdateUninstallLog} + + finish: + ${UnloadUAC} + System::Call "shell32::SHChangeNotify(i ${SHCNE_ASSOCCHANGED}, i 0, i 0, i 0)" + Quit ; Nothing initialized so no need to call OnEndCommon + + continue: + + ; If the uninstall.log does not exist don't perform uninstall + ; operations. This prevents running the uninstaller for zip builds. + IfFileExists "$INSTDIR\uninstall\uninstall.log" +2 +1 + Quit ; Nothing initialized so no need to call OnEndCommon + + ; If we made it this far then this installer is being used as an uninstaller. + WriteUninstaller "$EXEDIR\uninstaller.exe" + + ${Unless} ${Silent} + ; Manually check for /S in the command line due to Bug 506867 + ClearErrors + ${GetOptions} "$R0" "/S" $R2 + ${Unless} ${Errors} + SetSilent silent + ${Else} + ; Support for the deprecated -ms command line argument. + ClearErrors + ${GetOptions} "$R0" "-ms" $R2 + ${Unless} ${Errors} + SetSilent silent + ${EndUnless} + ${EndUnless} + ${EndUnless} + + ${If} ${Silent} + StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\" /S" + ${Else} + StrCpy $R1 "$\"$EXEDIR\uninstaller.exe$\"" + ${EndIf} + + ; When the uninstaller is launched it copies itself to the temp directory + ; so it won't be in use so it can delete itself. + ExecWait $R1 + ${DeleteFile} "$EXEDIR\uninstaller.exe" + SetErrorLevel 0 + Quit ; Nothing initialized so no need to call OnEndCommon +FunctionEnd + +Function un.onInit + StrCpy $LANGUAGE 0 + + ${un.GetParent} "$INSTDIR" $INSTDIR + Push $INSTDIR + Call un.GetLongPath + Pop $INSTDIR + ${Unless} ${FileExists} "$INSTDIR\${FileMainEXE}" + Abort + ${EndUnless} + + !ifdef HAVE_64BIT_OS + SetRegView 64 + !endif + + ; Prevents breaking apps that don't use SetBrandNameVars + !ifdef un.SetBrandNameVars + ${un.SetBrandNameVars} "$INSTDIR\distribution\setup.ini" + !endif + + ; Initialize $hHeaderBitmap to prevent redundant changing of the bitmap if + ; the user clicks the back button + StrCpy $hHeaderBitmap "" + + !insertmacro InitInstallOptionsFile "unconfirm.ini" +FunctionEnd + +Function .onGUIEnd + ${OnEndCommon} +FunctionEnd + +Function un.onGUIEnd + ${un.OnEndCommon} +FunctionEnd + +; Deletes all relative profiles specified in an application's profiles.ini and +; performs various other cleanup. + +; The SetShellVarContext setting should be set to current before calling this +; function. + +; @0 = _REL_PROFILE_PATH +; The relative path to the profile directory. + +; $R6 = value of IsRelative read from profiles.ini +; $R7 = value of Path to profile read from profiles.ini +; $R8 = counter for reading profiles (e.g. Profile0, Profile1, etc.) +; $R9 = _REL_PROFILE_PATH + +Function un.DeleteRelativeProfiles + Exch $R9 + Push $R8 + Push $R7 + Push $R6 + + StrCpy $R8 -1 + + loop: + IntOp $R8 $R8 + 1 ; Increment the counter. + ReadINIStr $R7 "$APPDATA\$R9\profiles.ini" "Profile$R8" "Path" + IfErrors end +1 + + ; Only remove relative profiles + ReadINIStr $R6 "$APPDATA\$R9\profiles.ini" "Profile$R8" "IsRelative" + StrCmp "$R6" "1" +1 loop + + ; Relative paths in profiles.ini use / as a separator + ${un.WordReplace} "$R7" "/" "\" "+" $R7 + + IfFileExists "$LOCALAPPDATA\$R9\$R7" +1 +2 + RmDir /r "$LOCALAPPDATA\$R9\$R7" + IfFileExists "$APPDATA\$R9\$R7" +1 +2 + RmDir /r "$APPDATA\$R9\$R7" + GoTo loop + + end: + ; Remove profiles directory under LOCALAPPDATA (e.g. cache, etc.) since + ; they are at times abandoned. + RmDir /r "$LOCALAPPDATA\$R9\Profiles" + RmDir /r "$APPDATA\$R9\Crash Reports" + Delete "$APPDATA\$R9\profiles.ini" + Delete "$APPDATA\$R9\console.log" + Delete "$APPDATA\$R9\pluginreg.dat" + RmDir "$APPDATA\$R9\Profiles" + RmDir "$APPDATA\$R9" + + Pop $R6 + Pop $R7 + Pop $R8 + Pop $R9 +FunctionEnd diff --git a/app/win/installer/updater_append.ini b/app/win/installer/updater_append.ini new file mode 100644 index 0000000000..af7742c12c --- /dev/null +++ b/app/win/installer/updater_append.ini @@ -0,0 +1,12 @@ + +; IMPORTANT: This file should always start with a newline in case a locale +; provided updater.ini does not end with a newline. +; Application to launch after an update has been successfully applied. This +; must be in the same directory or a sub-directory of the directory of the +; application executable that initiated the software update. +[PostUpdateWin] +; ExeRelPath is the path to the PostUpdateWin executable relative to the +; application executable. +ExeRelPath=uninstall\helper.exe +; ExeArg is the argument to pass to the PostUpdateWin exe +ExeArg=/PostUpdate diff --git a/app/win/mozconfig b/app/win/mozconfig new file mode 100644 index 0000000000..5028a3f008 --- /dev/null +++ b/app/win/mozconfig @@ -0,0 +1,26 @@ +# Set Z_ARCH=win32 on command line to build and package win32 +if [ "$Z_ARCH" == "win32" ]; then + ac_add_options --target=i686-pc-mingw32 + # https://bugzilla.mozilla.org/show_bug.cgi?id=1804548 + ac_add_options --without-wasm-sandboxed-libraries +fi + +ac_add_options --enable-bootstrap +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 +ac_add_options --enable-official-branding + +export MOZILLA_OFFICIAL=1 +export RELEASE_OR_BETA=1 +MOZ_REQUIRE_SIGNING= diff --git a/app/win/mozilla-102.patch b/app/win/mozilla-102.patch new file mode 100644 index 0000000000..55a022f90d --- /dev/null +++ b/app/win/mozilla-102.patch @@ -0,0 +1,80 @@ +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,28 @@ 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 ++ _putenv_s("MOZ_ALLOW_DOWNGRADE", "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 +@@ -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 0000000000..db9cc6664f Binary files /dev/null and b/app/win/updater.exe differ diff --git a/app/win/zotero.exe.tar.xz b/app/win/zotero.exe.tar.xz new file mode 100644 index 0000000000..45fa075097 Binary files /dev/null and b/app/win/zotero.exe.tar.xz differ