2
0
Эх сурвалжийг харах

Merge branch 'main' into files-downloadarchive

Martijn Laan 2 сар өмнө
parent
commit
c87fc4e99b

+ 18 - 0
.github/workflows/sync-fork.yml

@@ -0,0 +1,18 @@
+name: sync-fork
+on:
+  schedule:
+    - cron: '0 0 * * *'
+  workflow_dispatch:
+jobs:
+  sync:
+    # Only set the topic `has-issrc-build-env-sync-token` if the secret is available
+    if: contains(github.event.repository.topics, 'has-issrc-build-env-sync-token')
+    runs-on: ubuntu-latest
+    permissions:
+      contents: write
+    steps:
+      - run: gh repo sync $REPOSITORY -b $BRANCH_NAME
+        env:
+          GITHUB_TOKEN: ${{ secrets.ISSRC_BUILD_ENV_SYNC_TOKEN }}
+          REPOSITORY: ${{ github.repository }}
+          BRANCH_NAME: ${{ github.ref_name }}

+ 3 - 1
ISHelp/isetup.xml

@@ -1750,6 +1750,7 @@ Instructs Setup to proceed to comparing time stamps (last write/modified time) i
 <flag name="extractarchive">
 <p>This flag instructs Setup not to copy an existing archive file, but instead to extract it. Optionally use the <tt>ExtractArchivePassword</tt> parameter to specify a password.</p>
 <p>The supported archive formats, beyond .7z, and the support for password-protected and multi-volume archives, depend on the <link topic="setup_archiveextraction">ArchiveExtraction</link> [Setup] section directive, that must not be set to <tt>basic</tt>.</p>
+<p>To allow the extraction of archives with custom extensions, such as self-extracting archives, call <link topic="isxfunc_MapArchiveExtensions">MapArchiveExtensions</link>.</p>
 <p>This flag must be combined with the <tt>external</tt> and <tt>ignoreversion</tt> flags, meaning it should only be used on files private to your application, <i>never</i> on shared system files.</p>
 <p>This flag is usually combined with the <tt>recursesubdirs</tt> and <tt>createallsubdirs</tt> flags.</p>
 <p>Using a solid archive is not recommended; extraction performance may degrade depending on the solid block size.</p>
@@ -4788,7 +4789,7 @@ ExtraDiskSpaceRequired=1_048_576</pre></example>
 <p><tt>basic</tt> uses an embedded version of the "7z ANSI-C Decoder" from the LZMA SDK by Igor Pavlov, as-is, except that Unicode support and error messages were improved and that it outputs memory requirements. It only supports .7z archives that are not password-protected.</p>
 <p><tt>enhanced/nopassword</tt> internally uses 7zxr.dll from the 7-Zip source code by Igor Pavlov, as-is, except that it was recompiled, code-signed, and renamed to is7zxr.dll. Compared to <tt>basic</tt>, it has lower memory requirements for archives that contain large files but increases the size of the Setup file(s). It still only supports .7z archives that are not password-protected.</p>
 <p><tt>enhanced</tt> uses 7zxa.dll instead of 7zxr.dll, recompiled, code-signed, and renamed to is7zxa.dll. It still only supports .7z archives, but they may be password-protected.</p>
-<p><tt>full</tt> uses 7z.dll instead of 7zxa.dll, recompiled, code-signed, and renamed to is7z.dll. It supports multiple archive formats, although not as many as the original 7z.dll, to reduce its size. It supports multi-volume archives.</p>
+<p><tt>full</tt> uses 7z.dll instead of 7zxa.dll, recompiled, code-signed, and renamed to is7z.dll. It supports multiple archive formats, although not as many as the original 7z.dll, to reduce its size. Additionally, it supports multi-volume archives.</p>
 <p>The following table summarizes the differences between these methods.</p>
 <indent>
 <table>
@@ -4811,6 +4812,7 @@ ExtraDiskSpaceRequired=1_048_576</pre></example>
 </ul>
 <p><b>See also:</b><br/>
 <link topic="isxfunc_ExtractArchive">ExtractArchive</link><br/>
+<link topic="isxfunc_MapArchiveExtensions">MapArchiveExtensions</link><br/>
 <link topic="isxfunc_CreateExtractionPage">CreateExtractionPage</link>
 </p>
 </body>

+ 22 - 1
ISHelp/isxfunc.xml

@@ -1913,17 +1913,36 @@ end;</pre></example>
         <description><p>Extracts the specified archive to the specified directory, with or without preserving full path names.</p>
 <p>An exception will be raised if there was an error.</p>
 <p>The supported archive formats, beyond .7z, and the support for password-protected and multi-volume archives, depend on the <link topic="setup_archiveextraction">ArchiveExtraction</link> [Setup] section directive.</p>
+<p>To allow the extraction of archives with custom extensions, such as self-extracting archives, call <link topic="isxfunc_MapArchiveExtensions">MapArchiveExtensions</link>.</p>
 <p>Set OnExtractionProgress to a function to be informed of progress, or <tt>nil</tt> otherwise.</p>
-<p>When extracting without preservering path names (i.e. FullPaths is set to False), ensure that the archive does not contain multiple files with the same name. Doing so will help avoid file-in-use errors.</p>
+<p>When extracting without preserving path names (i.e. FullPaths is set to False), ensure that the archive does not contain multiple files with the same name. Doing so will help avoid file-in-use errors.</p>
 <p>See <i>CodeDownloadFiles.iss</i> for an example of archive extraction using just a [Files] entry instead.</p></description>
         <remarks><p>TOnExtractionProgress is defined as:</p>
 <p><tt>TOnExtractionProgress = function(const ArchiveName, FileName: String; const Progress, ProgressMax: Int64): Boolean;</tt></p>
 <p>Return True to allow the extraction to continue, False otherwise.</p></remarks>
         <seealso><p><link topic="isxfunc_CreateExtractionPage">CreateExtractionPage</link><br />
+<link topic="isxfunc_MapArchiveExtensions">MapArchiveExtensions</link><br />
 <link topic="isxfunc_CreateDownloadPage">CreateDownloadPage</link><br />
 <link topic="isxfunc_DownloadTemporaryFile">DownloadTemporaryFile</link><br />
 <link topic="isxfunc_ExtractTemporaryFile">ExtractTemporaryFile</link></p></seealso>
       </function>
+      <function>
+        <name>MapArchiveExtensions</name>
+        <prototype>procedure MapArchiveExtensions(const DestExt, SourceExt: String);</prototype>
+        <description><p>Allows files with a specified destination extension, such as .exe, to be treated as if they have a different source extension, such as .7z, for extraction purposes.</p>
+<p>An exception will be raised if there was an error.</p></description>
+        <seealso><p><link topic="isxfunc_ExtractArchive">ExtractArchive</link><br/>
+<link topic="isxfunc_CreateExtractionPage">CreateExtractionPage</link></p></seealso>
+        <example><pre>
+[Files]
+Source: "{src}\My7ZipSFX.exe; DestDir: "{app}"; Flags: external extractarchive recursesubdirs createallsubdirs ignoreversion
+
+[Code]
+function InitializeSetup: Boolean;
+begin
+  MapArchiveExtensions('.exe', '.7z');
+end;</pre></example>
+      </function>
     </subcategory>
     <subcategory>
       <function>
@@ -2726,6 +2745,7 @@ Page := CreateOutputMsgMemoPage(wpWelcome,
         <prototype>function CreateExtractionPage(const ACaption, ADescription: String; const OnExtractionProgress: TOnExtractionProgress): TExtractionWizardPage;</prototype>
         <description><p>Creates a wizard page to extract archives and show progress.</p>
 <p>The supported archive formats, beyond .7z, and the support for password-protected and multi-volume archives, depend on the <link topic="setup_archiveextraction">ArchiveExtraction</link> [Setup] section directive.</p>
+<p>To allow the extraction of archives with custom extensions, such as self-extracting archives, call <link topic="isxfunc_MapArchiveExtensions">MapArchiveExtensions</link>.</p>
 <p>Set OnExtractionProgress to a function to be informed of progress, or <tt>nil</tt> otherwise.</p>    
 <p>Unlike the other types of wizard pages, progress pages are not displayed as part of the normal page sequence (note that there is no <tt>AfterID</tt> parameter). A progress page can only be displayed programmatically by calling its <tt>Show</tt> method.</p></description>
         <remarks><p>Call the <tt>Show</tt> method to activate and show the page. When you're finished with it, call the <tt>Hide</tt> method to revert to the previous page.</p>
@@ -2737,6 +2757,7 @@ Page := CreateOutputMsgMemoPage(wpWelcome,
         <example><p>See <i>CodeDownloadFiles.iss</i> for an example of <tt>CreateDownloadPage</tt> which works very similar to <tt>CreateExtractionPage</tt>, and an example of archive extraction using just a [Files] entry instead.</p></example>
         <seealso><p><link topic="scriptclasses" anchor="TExtractionWizardPage">TExtractionWizardPage</link><br />
 <link topic="isxfunc_ExtractArchive">ExtractArchive</link><br />
+<link topic="isxfunc_MapArchiveExtensions">MapArchiveExtensions</link><br />
 <link topic="isxfunc_CreateOutputProgressPage">CreateOutputProgressPage</link></p></seealso>
       </function>
       <function>

+ 60 - 49
Projects/Src/Compression.SevenZipDLLDecoder.pas

@@ -21,6 +21,8 @@ function SevenZipDLLInit(const SevenZipLibrary: HMODULE;
   [ref] const VersionNumbers: TFileVersionNumbers): Boolean;
 procedure SevenZipDLLDeInit;
 
+procedure MapArchiveExtensions(const DestExt, SourceExt: String);
+
 procedure ExtractArchiveRedir(const DisableFsRedir: Boolean;
   const ArchiveFilename, DestDir, Password: String; const FullPaths: Boolean;
   const OnExtractionProgress: TOnExtractionProgress);
@@ -52,7 +54,7 @@ type
 implementation
 
 uses
-  Classes, SysUtils, Forms, Variants, ActiveX, ComObj, Generics.Collections,
+  Classes, SysUtils, Forms, Variants, ActiveX, ComObj, Generics.Collections, Generics.Defaults,
   Compression.SevenZipDLLDecoder.Interfaces, PathFunc,
   Shared.SetupMessageIDs, Shared.CommonFunc,
   SetupLdrAndSetup.Messages, SetupLdrAndSetup.RedirFunc,
@@ -222,48 +224,7 @@ begin
   SevenZipError(ExceptMessage, LogMessage);
 end;
 
-function GetHandler(const Filename, NotFoundErrorMsg: String): TGUID;
-begin
-  const Ext = PathExtractExt(Filename);
-  if SameText(Ext, '.7z') then
-    Result := CLSID_Handler7z
-  else if SameText(Ext, '.zip') then
-    Result := CLSID_HandlerZip
-  else if SameText(Ext, '.gz') then
-    Result := CLSID_HandlerGzip
-  else if SameText(Ext, '.bz2') then
-    Result := CLSID_HandlerBZip2
-  else if SameText(Ext, '.xz') then
-    Result := CLSID_HandlerXz
-  else if SameText(Ext, '.tar') then
-    Result := CLSID_HandlerTar
-  else if SameText(Ext, '.rar') then
-    Result := CLSID_HandlerRar
-  else if SameText(Ext, '.iso') then
-    Result := CLSID_HandlerIso
-  else if SameText(Ext, '.msi') then
-    Result := CLSID_HandlerCompound
-  else if SameText(Ext, '.cab') then
-    Result := CLSID_HandlerCab
-  else if SameText(Ext, '.rpm') then
-    Result := CLSID_HandlerRpm
-  else if SameText(Ext, '.vhd') then
-    Result := CLSID_HandlerVhd
-  else if SameText(Ext, '.vhdx') then
-    Result := CLSID_HandlerVhdx
-  else if SameText(Ext, '.vdi') then
-    Result := CLSID_HandlerVDI
-  else if SameText(Ext, '.vmdk') then
-    Result := CLSID_HandlerVMDK
-  else if SameText(Ext, '.wim') then
-    Result := CLSID_HandlerWim
-  else if SameText(Ext, '.dmg') then
-    Result := CLSID_HandlerDmg
-  else if SameText(Ext, '.001') then
-    Result := CLSID_HandlerSplit
-  else
-    InternalError(NotFoundErrorMsg);
-end;
+function GetHandler(const Filename, NotFoundErrorMsg: String): TGUID; forward;
 
 const
   varFileTime = 64; { Delphi lacks proper VT_FILETIME support }
@@ -962,9 +923,13 @@ end;
 
 { Additional helper functions }
 
+type
+  TSevenZipHandlers = TDictionary<String, TGUID>;
+
 var
   CreateSevenZipObject: function(const clsid, iid: TGUID; var outObject): HRESULT; stdcall;
   VersionBanner: String;
+  Handlers: TSevenZipHandlers;
 
 function SevenZipDLLInit(const SevenZipLibrary: HMODULE;
   [ref] const VersionNumbers: TFileVersionNumbers): Boolean;
@@ -975,6 +940,45 @@ begin
     VersionBanner := Format(' %u.%.2u', [(VersionNumbers.MS shr 16) and $FFFF, VersionNumbers.MS and $FFFF])
   else
     VersionBanner := '';
+
+  Handlers := TSevenZipHandlers.Create(TIStringComparer.Ordinal);
+  Handlers.Add('.7z', CLSID_Handler7z);
+  Handlers.Add('.zip', CLSID_HandlerZip);
+  Handlers.Add('.gz', CLSID_HandlerGzip);
+  Handlers.Add('.bz2', CLSID_HandlerBZip2);
+  Handlers.Add('.xz', CLSID_HandlerXz);
+  Handlers.Add('.tar', CLSID_HandlerTar);
+  Handlers.Add('.rar', CLSID_HandlerRar);
+  Handlers.Add('.iso', CLSID_HandlerIso);
+  Handlers.Add('.msi', CLSID_HandlerCompound);
+  Handlers.Add('.cab', CLSID_HandlerCab);
+  Handlers.Add('.rpm', CLSID_HandlerRpm);
+  Handlers.Add('.vhd', CLSID_HandlerVhd);
+  Handlers.Add('.vhdx', CLSID_HandlerVhdx);
+  Handlers.Add('.vdi', CLSID_HandlerVDI);
+  Handlers.Add('.vmdk', CLSID_HandlerVMDK);
+  Handlers.Add('.wim', CLSID_HandlerWim);
+  Handlers.Add('.dmg', CLSID_HandlerDmg);
+  Handlers.Add('.001', CLSID_HandlerSplit);
+end;
+
+function GetHandlerForExt(const Ext, NotFoundErrorMsg: String): TGUID;
+begin
+  if not Handlers.TryGetValue(Ext, Result) then
+    InternalError(NotFoundErrorMsg);
+end;
+
+function GetHandler(const Filename, NotFoundErrorMsg: String): TGUID;
+begin;
+  Result := GetHandlerForExt(PathExtractExt(Filename), NotFoundErrorMsg);
+end;
+
+procedure MapArchiveExtensions(const DestExt, SourceExt: String);
+begin
+  if (Length(DestExt) < 2) or (DestExt[1] <> '.') then
+    InternalError('MapArchiveExtensions: Invalid DestExt');
+  const clsid = GetHandlerForExt(SourceExt, 'MapArchiveExtensions: Invalid SourceExt');
+  Handlers.AddOrSetValue(DestExt, clsid);
 end;
 
 var
@@ -1013,7 +1017,8 @@ begin
     SevenZipError(SetupMessages[msgArchiveIsCorrupted], 'Cannot get number of items');
 
   if numItems = 1 then begin
-    { Get inner archive stream if it exists - See OpenArchive.cpp CArchiveLink::Open }
+    { Get inner archive stream if it exists - See OpenArchive.cpp CArchiveLink::Open
+      Give up trying to get or open it on any error }
     var MainSubFile: Cardinal;
     var SubSeqStream: ISequentialInStream;
     if not GetProperty(Result, $FFFF, kpidMainSubfile, MainSubFile) or
@@ -1032,7 +1037,12 @@ begin
     if MainSubFilePath = '' then
       MainSubFilePath := PathChangeExt(ArchiveFilename, '');
 
-    const SubClsid = GetHandler(MainSubFilePath, '');
+    var SubClsid: TGUID;
+    try
+      SubClsid := GetHandler(MainSubFilePath, '');
+    except
+      Exit;
+    end;
     var SubResult: IInArchive;
     if CreateSevenZipObject(SubClsid, IInArchive, SubResult) <> S_OK then
       Exit;
@@ -1040,11 +1050,13 @@ begin
     var SubScanSize := DefaultScanSize;
     const SubOpenCallback: IArchiveOpenCallback =
       TArchiveOpenCallbackWithStreamBackup.Create(Password, InStream); { In tests the backup of InStream wasn't needed but better safe than sorry }
+    var SubNumItems: UInt32;
     if (SubResult.Open(SubStream, @SubScanSize, SubOpenCallback) <> S_OK) or
-       (SubResult.GetNumberOfItems(numItems) <> S_OK) then
+       (SubResult.GetNumberOfItems(SubNumItems) <> S_OK) then
       Exit;
 
     Result := SubResult;
+    numItems := SubNumItems;
   end;
 end;
 
@@ -1266,10 +1278,9 @@ end;
 
 procedure SevenZipDLLDeInit;
 begin
+  FreeAndNil(Handlers);
   { ArchiveFindStates has references to 7-Zip so must be cleared before the DLL is unloaded }
-  ArchiveFindStates.Free;
+  FreeAndNil(ArchiveFindStates);
 end;
 
-{ TArchiveOpenCallbackWithStreamBackup }
-
 end.

+ 4 - 0
Projects/Src/Setup.ScriptFunc.pas

@@ -1838,6 +1838,10 @@ var
           raise Exception.Create(FmtSetupMessage1(msgErrorExtractionFailed, GetExceptMessage));
       end;
     end);
+    RegisterScriptFunc('MapArchiveExtensions', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
+    begin
+      MapArchiveExtensions(Stack.GetString(PStart), Stack.GetString(PStart-1));
+    end);
     RegisterScriptFunc('DEBUGGING', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
       Stack.SetBool(PStart, Debugging);

+ 1 - 0
Projects/Src/Shared.ScriptFunc.pas

@@ -542,6 +542,7 @@ initialization
     'function InitializeBitmapImageFromIcon(const BitmapImage: TBitmapImage; const IconFilename: String; const BkColor: TColor; const AscendingTrySizes: TArrayOfInteger): Boolean;',
     'procedure Extract7ZipArchive(const ArchiveFileName, DestDir: String; const FullPaths: Boolean; const OnExtractionProgress: TOnExtractionProgress);',
     'procedure ExtractArchive(const ArchiveFilename, DestDir, Password: String; const FullPaths: Boolean; const OnExtractionProgress: TOnExtractionProgress);',
+    'procedure MapArchiveExtensions(const DestExt, SourceExt: String);',
     'function Debugging: Boolean;',
     'function StringJoin(const Separator: String; const Values: TArrayOfString): String;',
     'function StringSplit(const S: String; const Separators: TArrayOfString; const Typ: TSplitType): TArrayOfString;',

+ 7 - 0
README.md

@@ -273,6 +273,13 @@ https://github.com/YOUR-USER-NAME/issrc to add the topic).
 Once that's done, you're set! The next time you push a branch to your fork, the
 workflow will be triggered automatically.
 
+To set up automatic synchronization for your fork, first create a Fine-Grained Personal
+Access Token with access to your fork or all repositories you own, ensuring it has Read and
+Write permissions for Contents. After that, add this token as a new repository secret, under
+the name `ISSRC_BUILD_ENV_ZIP_SYNC_TOKEN`. Finally, indicate that your fork has this secret,
+by adding the topic `has-issrc-build-env-sync-token`. Your fork will nowsynchronize daily,
+and will automatically run the aforementioned build workflow on changes, if it's configured.
+
 <!-- Link references -->
 [CONTRIBUTING.md]: <CONTRIBUTING.md>
 [Projects\Bin]: <Projects/Bin>

+ 2 - 1
whatsnew.htm

@@ -50,7 +50,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
         <li><tt>basic</tt> (default) is the method introduced by Inno Setup 6.4.0. It only supports .7z archives that are not password-protected.</li>
         <li><tt>enhanced/nopassword</tt> is a new method and internally uses 7zxr.dll from the 7-Zip source code by Igor Pavlov, as-is, except that it was recompiled, code-signed, and renamed to is7zxr.dll. Compared to <tt>basic</tt>, it has lower memory requirements for archives that contain large files but increases the size of the Setup file(s). It still only supports .7z archives that are not password-protected.</li>
         <li><tt>enhanced</tt> uses 7zxa.dll instead of 7zxr.dll, recompiled, code-signed, and renamed to is7zxa.dll. It still only supports .7z archives, but they may be password-protected.</li>
-        <li><tt>full</tt> uses 7z.dll instead of 7zxa.dll, recompiled, code-signed, and renamed to is7z.dll. It supports multiple archive formats (.7z, .zip, .rar, and more), although not as many as the original 7z.dll, to reduce its size.</li>
+        <li><tt>full</tt> uses 7z.dll instead of 7zxa.dll, recompiled, code-signed, and renamed to is7z.dll. It supports multiple archive formats (.7z, .zip, .rar, and more), although not as many as the original 7z.dll, to reduce its size. Additionally, it supports multi-volume archives.</li>
       </ul>
       New documentation topic <a href="https://jrsoftware.org/ishelp/index.php?topic=setup_archiveextraction">ArchiveExtraction</a> has a table summarizing the differences between these methods.
     </li>
@@ -78,6 +78,7 @@ Source: "{tmp}\MyProg-ExtraReadmes.7z"; DestDir: "{app}"; \
     <ul>
       <li>New support function <tt>ExtractArchive</tt> replaces the deprecated <tt>Extract7ZipArchive</tt>. <tt>ExtractArchive</tt> includes an additional parameter to optionally specify a password.</li>
       <li><tt>ExtractArchive</tt> and <tt>CreateExtractionPage</tt> now overwrite read-only files which already exist in the destination directory without prompting the user. Previously this would cause an extraction error.</li>
+      <li>Added new <tt>MapArchiveExtensions</tt> support function to allow the extraction of archives with custom extensions, such as self-extracting archives.</li>
       <li>Added new <tt>AddEx</tt> function to support class <tt>TExtractionWizardPage</tt> to add password-protected archives.</li>
     </ul>
   </li>