Setup.ExtractFileFunc.pas 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. unit Setup.ExtractFileFunc;
  2. {
  3. Inno Setup
  4. Copyright (C) 1997-2025 Jordan Russell
  5. Portions by Martijn Laan
  6. For conditions of distribution and use, see LICENSE.TXT.
  7. Installation procedures: ExtractTemporaryFile
  8. }
  9. interface
  10. procedure ExtractTemporaryFile(const BaseName: String);
  11. function ExtractTemporaryFiles(const Pattern: String): Integer;
  12. implementation
  13. uses
  14. Windows, SysUtils,
  15. PathFunc,
  16. Shared.CommonFunc, Shared.FileClass, Shared.Struct,
  17. SetupLdrAndSetup.RedirFunc,
  18. Setup.InstFunc, Setup.FileExtractor, Setup.LoggingFunc, Setup.MainFunc;
  19. procedure InternalExtractTemporaryFile(const DestName: String;
  20. const CurFile: PSetupFileEntry; const CurFileLocation: PSetupFileLocationEntry;
  21. const CreateDirs: Boolean);
  22. var
  23. DestFile: String;
  24. DestF: TFile;
  25. CurFileDate: TFileTime;
  26. begin
  27. DestFile := AddBackslash(TempInstallDir) + DestName;
  28. Log('Extracting temporary file: ' + DestFile);
  29. { Does not disable FS redirection, like everything else working on the temp dir }
  30. if CreateDirs then
  31. ForceDirectories(False, PathExtractPath(DestFile));
  32. DestF := TFile.Create(DestFile, fdCreateAlways, faWrite, fsNone);
  33. try
  34. try
  35. FileExtractor.SeekTo(CurFileLocation^, nil);
  36. FileExtractor.DecompressFile(CurFileLocation^, DestF, nil,
  37. not (foDontVerifyChecksum in CurFile^.Options));
  38. if floTimeStampInUTC in CurFileLocation^.Flags then
  39. CurFileDate := CurFileLocation^.SourceTimeStamp
  40. else
  41. LocalFileTimeToFileTime(CurFileLocation^.SourceTimeStamp, CurFileDate);
  42. SetFileTime(DestF.Handle, nil, nil, @CurFileDate);
  43. finally
  44. DestF.Free;
  45. end;
  46. except
  47. DeleteFile(DestFile);
  48. raise;
  49. end;
  50. AddAttributesToFile(False, DestFile, CurFile^.Attribs);
  51. end;
  52. procedure ExtractTemporaryFile(const BaseName: String);
  53. function EscapeBraces(const S: String): String;
  54. { Changes all '{' to '{{'. Uses ConstLeadBytes^ for the lead byte table. }
  55. var
  56. I: Integer;
  57. begin
  58. Result := S;
  59. I := 1;
  60. while I <= Length(Result) do begin
  61. if Result[I] = '{' then begin
  62. Insert('{', Result, I);
  63. Inc(I);
  64. end;
  65. Inc(I);
  66. end;
  67. end;
  68. var
  69. EscapedBaseName: String;
  70. CurFileNumber: Integer;
  71. CurFile: PSetupFileEntry;
  72. begin
  73. { We compare BaseName to the filename portion of TSetupFileEntry.DestName
  74. which has braces escaped, but BaseName does not; escape it to match }
  75. EscapedBaseName := EscapeBraces(BaseName);
  76. for CurFileNumber := 0 to Entries[seFile].Count-1 do begin
  77. CurFile := PSetupFileEntry(Entries[seFile][CurFileNumber]);
  78. if (CurFile^.LocationEntry <> -1) and (CompareText(PathExtractName(CurFile^.DestName), EscapedBaseName) = 0) then begin
  79. InternalExtractTemporaryFile(BaseName, CurFile, Entries[seFileLocation][CurFile^.LocationEntry], False);
  80. Exit;
  81. end;
  82. end;
  83. InternalErrorFmt('ExtractTemporaryFile: The file "%s" was not found', [BaseName]);
  84. end;
  85. function ExtractTemporaryFiles(const Pattern: String): Integer;
  86. var
  87. LowerPattern, DestName: String;
  88. CurFileNumber: Integer;
  89. CurFile: PSetupFileEntry;
  90. begin
  91. if Length(Pattern) >= MAX_PATH then
  92. InternalError('ExtractTemporaryFiles: Pattern too long');
  93. LowerPattern := PathLowercase(Pattern);
  94. Result := 0;
  95. for CurFileNumber := 0 to Entries[seFile].Count-1 do begin
  96. CurFile := PSetupFileEntry(Entries[seFile][CurFileNumber]);
  97. if CurFile^.LocationEntry <> -1 then begin
  98. { Use ExpandConstEx2 to unescape any braces not in an embedded constant,
  99. while leaving constants unexpanded }
  100. DestName := ExpandConstEx2(CurFile^.DestName, [''], False);
  101. if WildcardMatch(PChar(PathLowercase(DestName)), PChar(LowerPattern)) then begin
  102. Delete(DestName, 1, PathDrivePartLengthEx(DestName, True)); { Remove any drive part }
  103. if Pos('{tmp}\', DestName) = 1 then
  104. Delete(DestName, 1, Length('{tmp}\'));
  105. if Pos(':', DestName) <> 0 then
  106. InternalError('ExtractTemporaryFiles: Invalid character in matched file name');
  107. InternalExtractTemporaryFile(DestName, CurFile, Entries[seFileLocation][CurFile^.LocationEntry], True);
  108. Inc(Result);
  109. end;
  110. end;
  111. end;
  112. if Result = 0 then
  113. InternalErrorFmt('ExtractTemporaryFiles: No files matching "%s" found', [Pattern]);
  114. end;
  115. end.