Setup.ExtractFileFunc.pas 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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. Setup.RedirFunc, Setup.InstFunc, Setup.FileExtractor, Setup.LoggingFunc, Setup.MainFunc;
  18. procedure InternalExtractTemporaryFile(const DestName: String;
  19. const CurFile: PSetupFileEntry; const CurFileLocation: PSetupFileLocationEntry;
  20. const CreateDirs: Boolean);
  21. var
  22. DestFile: String;
  23. DestF: TFile;
  24. CurFileDate: TFileTime;
  25. begin
  26. DestFile := AddBackslash(TempInstallDir) + DestName;
  27. Log('Extracting temporary file: ' + DestFile);
  28. { Does not disable FS redirection, like everything else working on the temp dir }
  29. if CreateDirs then
  30. ForceDirectories(False, PathExtractPath(DestFile));
  31. DestF := TFile.Create(DestFile, fdCreateAlways, faWrite, fsNone);
  32. try
  33. try
  34. FileExtractor.SeekTo(CurFileLocation^, nil);
  35. FileExtractor.DecompressFile(CurFileLocation^, DestF, nil,
  36. not (foDontVerifyChecksum in CurFile^.Options));
  37. if CurFileLocation^.TimeStamp.HasTime then begin
  38. if floTimeStampInUTC in CurFileLocation^.Flags then
  39. CurFileDate := CurFileLocation^.TimeStamp
  40. else
  41. LocalFileTimeToFileTime(CurFileLocation^.TimeStamp, CurFileDate);
  42. SetFileTime(DestF.Handle, nil, nil, @CurFileDate);
  43. end;
  44. finally
  45. DestF.Free;
  46. end;
  47. except
  48. DeleteFile(DestFile);
  49. raise;
  50. end;
  51. AddAttributesToFile(False, DestFile, CurFile^.Attribs);
  52. end;
  53. procedure ExtractTemporaryFile(const BaseName: String);
  54. function EscapeBraces(const S: String): String;
  55. { Changes all '{' to '{{'. Uses ConstLeadBytes^ for the lead byte table. }
  56. var
  57. I: Integer;
  58. begin
  59. Result := S;
  60. I := 1;
  61. while I <= Length(Result) do begin
  62. if Result[I] = '{' then begin
  63. Insert('{', Result, I);
  64. Inc(I);
  65. end;
  66. Inc(I);
  67. end;
  68. end;
  69. var
  70. EscapedBaseName: String;
  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 var 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. CurFile: PSetupFileEntry;
  89. begin
  90. if Length(Pattern) >= MAX_PATH then
  91. InternalError('ExtractTemporaryFiles: Pattern too long');
  92. LowerPattern := PathLowercase(Pattern);
  93. Result := 0;
  94. for var CurFileNumber := 0 to Entries[seFile].Count-1 do begin
  95. CurFile := PSetupFileEntry(Entries[seFile][CurFileNumber]);
  96. if CurFile^.LocationEntry <> -1 then begin
  97. { Use ExpandConstEx2 to unescape any braces not in an embedded constant,
  98. while leaving constants unexpanded }
  99. DestName := ExpandConstEx2(CurFile^.DestName, [''], False);
  100. if WildcardMatch(PChar(PathLowercase(DestName)), PChar(LowerPattern)) then begin
  101. Delete(DestName, 1, PathDrivePartLengthEx(DestName, True)); { Remove any drive part }
  102. if Pos('{tmp}\', DestName) = 1 then
  103. Delete(DestName, 1, Length('{tmp}\'));
  104. if Pos(':', DestName) <> 0 then
  105. InternalError('ExtractTemporaryFiles: Invalid character in matched file name');
  106. InternalExtractTemporaryFile(DestName, CurFile, Entries[seFileLocation][CurFile^.LocationEntry], True);
  107. Inc(Result);
  108. end;
  109. end;
  110. end;
  111. if Result = 0 then
  112. InternalErrorFmt('ExtractTemporaryFiles: No files matching "%s" found', [Pattern]);
  113. end;
  114. end.