diff --git a/tim2view.dproj b/tim2view.dproj index 0733094..c4e3ce8 100644 --- a/tim2view.dproj +++ b/tim2view.dproj @@ -6,7 +6,7 @@ tim2view.dpr True Release - Win64 + Win32 3 Application diff --git a/tim2view.res b/tim2view.res index 2a0bfa4..acce4cd 100644 Binary files a/tim2view.res and b/tim2view.res differ diff --git a/units/uCDIMAGE.pas b/units/uCDIMAGE.pas index b0aab88..a296f9b 100644 --- a/units/uCDIMAGE.pas +++ b/units/uCDIMAGE.pas @@ -78,12 +78,15 @@ begin Exit; pFile := GetMemory(cSectorHeaderSize); - tmp := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - tmp.Read(pFile^[0], cSectorHeaderSize); - Result := ((Sz mod cSectorSize) = 0) and - (CompareMem(@cSectorHeader, pFile, cSectorHeaderSize)); - tmp.free; - FreeMemory(pFile); + + try + tmp := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + tmp.Read(pFile^[0], cSectorHeaderSize); + Result := ((Sz mod cSectorSize) = 0) and (CompareMem(@cSectorHeader, pFile, cSectorHeaderSize)); + finally + tmp.free; + FreeMemory(pFile); + end; end; procedure ReplaceTimInFileFromMemory(const FileName: string; TIM: PTIM; diff --git a/units/uCommon.pas b/units/uCommon.pas index a49bb62..e576287 100644 --- a/units/uCommon.pas +++ b/units/uCommon.pas @@ -7,16 +7,19 @@ uses const cProgramName = 'Tim2View by [Lab 313]'; - cProgramVersion = '2.0 Stable'; + cProgramVersion = '2.0 Release'; cExtractedTimsDir = 'TIMS'; + cExtractedPngsDir = 'PNGS'; cMaxFileSize = $2EAEED80; cAutoExtractionTimFormat = '%s_%.6d_%.2db' + '.tim'; + cAutoExtractionPngFormat = '%s_%.6d_%.2db_%.2dc' + '.png'; cCLUTGridColsCount = 32; sStatusBarScanningFile = 'Scanning File...'; sStatusBarTimsExtracting = 'TIMs Extracting...'; - sStatusBarTimsExtracted = 'Exctracted Successfully!'; + sStatusBarPngsExtracting = 'PNGs Extracting...'; + sStatusBarExtracted = 'Exctracted Successfully!'; sStatusBarParsingResult = 'Parsing Result...'; sScanResultGood = 'Scan completed!'; sSelectDirCaption = 'Please, select directory for scan...'; diff --git a/units/uMain.dfm b/units/uMain.dfm index db58765..d18c0cf 100644 --- a/units/uMain.dfm +++ b/units/uMain.dfm @@ -576,9 +576,9 @@ object frmMain: TfrmMain TabOrder = 0 object lvList: TListView Left = 0 - Top = 0 + Top = 49 Width = 240 - Height = 481 + Height = 432 Align = alClient Columns = < item @@ -613,6 +613,39 @@ object frmMain: TfrmMain ViewStyle = vsReport OnChange = lvListChange OnData = lvListData + ExplicitLeft = 1 + ExplicitTop = 28 + ExplicitHeight = 448 + end + object pnlExtractAll: TPanel + Left = 0 + Top = 0 + Width = 240 + Height = 49 + Align = alTop + BevelOuter = bvLowered + TabOrder = 1 + object btnExtractAllTims: TButton + Left = 139 + Top = 1 + Width = 100 + Height = 47 + Action = actExtractPNGs + Align = alRight + TabOrder = 0 + WordWrap = True + ExplicitLeft = 128 + end + object btnExtractPNGs: TButton + Left = 1 + Top = 1 + Width = 100 + Height = 47 + Action = actExtractTIMs + Align = alLeft + TabOrder = 1 + WordWrap = True + end end end object pnlImage: TPanel @@ -923,11 +956,17 @@ object frmMain: TfrmMain Caption = '&Open TIMs with T2V' OnExecute = actAssocTimsExecute end - object actExtractList: TAction - Caption = '&Extract TIMs' + object actExtractTIMs: TAction + Caption = 'Extract all &TIMs'#13#10'(Shift+F2)' Enabled = False - ShortCut = 112 - OnExecute = actExtractListExecute + ShortCut = 8305 + OnExecute = actExtractTIMsExecute + end + object actExtractPNGs: TAction + Caption = '&Extract all PNGs'#13#10'(Shift+F4)' + Enabled = False + ShortCut = 8307 + OnExecute = actExtractPNGsExecute end object actChangeClutIdx: TAction end @@ -941,12 +980,6 @@ object frmMain: TfrmMain object pmList: TPopupMenu Left = 640 Top = 502 - object ExtractTIMs1: TMenuItem - Action = actExtractList - end - object N6: TMenuItem - Caption = '-' - end object ExtractTIM1: TMenuItem Action = actExtractTim end diff --git a/units/uMain.pas b/units/uMain.pas index 5c9f022..3587f5b 100644 --- a/units/uMain.pas +++ b/units/uMain.pas @@ -77,14 +77,16 @@ type mnTimInfoMain: TMenuItem; actAssocTims: TAction; mnAssociate: TMenuItem; - N6: TMenuItem; - actExtractList: TAction; - ExtractTIMs1: TMenuItem; + actExtractTIMs: TAction; pbTim: TImage; btnShowClut: TButton; cbbCLUT: TComboBox; actReturnFocus: TAction; actDrawSelectedTim: TAction; + actExtractPNGs: TAction; + pnlExtractAll: TPanel; + btnExtractAllTims: TButton; + btnExtractPNGs: TButton; procedure btnStopScanClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure lvListData(Sender: TObject; Item: TListItem); @@ -107,13 +109,14 @@ type procedure actStretchExecute(Sender: TObject); procedure actTimInfoExecute(Sender: TObject); procedure actAssocTimsExecute(Sender: TObject); - procedure actExtractListExecute(Sender: TObject); + procedure actExtractTIMsExecute(Sender: TObject); procedure cbbTranspModeChange(Sender: TObject); procedure btnShowClutClick(Sender: TObject); procedure lvListChange(Sender: TObject; Item: TListItem; Change: TItemChange); procedure actReturnFocusExecute(Sender: TObject); procedure actDrawSelectedTimExecute(Sender: TObject); + procedure actExtractPNGsExecute(Sender: TObject); private { Private declarations } // pResult: PNativeXml; @@ -134,7 +137,8 @@ type function ListIdx: Integer; function TimIdx(Index: Integer): TScanTim; function SelTim(NewBitMode: Integer = $FF): PTIM; - function SelTimName: string; + function FormatTimName(const FileName: string; ListIdx_, BitMode: Integer): string; + function FormatPngName(const FileName: string; ListIdx_, BitMode, Clut: Integer): string; procedure DrawSelTim; procedure DrawSelClut; procedure UpdateCLUTInfo; @@ -158,7 +162,7 @@ var implementation uses - uCDIMAGE, uBrowseForFolder, System.Win.Registry; + uCDIMAGE, uBrowseForFolder, System.Win.Registry, Vcl.Imaging.pngimage; {$R *.dfm} @@ -319,10 +323,10 @@ begin Close; end; -procedure TfrmMain.actExtractListExecute(Sender: TObject); +procedure TfrmMain.actExtractTIMsExecute(Sender: TObject); var I, OFFSET, BIT_MODE, SIZE: Integer; - FName, TIM_NAME, Path: string; + FName, Path: string; IsImage: Boolean; ScanTim: TScanTim; TIM: PTIM; @@ -332,6 +336,8 @@ begin FName := ScanRes.ScanFile; IsImage := ScanRes.IsImage; + pbProgress.Position := 0; + pbProgress.Max := ScanRes.Count; for I := 1 to ScanRes.Count do begin ScanTim := TimIdx(I - 1); @@ -339,26 +345,79 @@ begin SIZE := ScanTim.Size; BIT_MODE := ScanTim.BitMode; - TIM_NAME := Format(cAutoExtractionTimFormat, [ExtractJustName(FName), I, BIT_MODE]); - Path := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)) + cExtractedTimsDir); CreateDir(Path); Path := IncludeTrailingPathDelimiter(Path + ExtractFileName(FName)); CreateDir(Path); TIM := LoadTimFromFile(FName, OFFSET, IsImage, SIZE); - SaveTimToFile(Path + TIM_NAME, TIM); + SaveTimToFile(Path + FormatTimName(FName, I - 1, BIT_MODE), TIM); FreeTIM(TIM); + + pbProgress.Position := I; + Application.ProcessMessages; end; - lblStatus.Caption := sStatusBarTimsExtracted; + lblStatus.Caption := sStatusBarExtracted; MessageBeep(MB_ICONINFORMATION); + pbProgress.Position := 0; +end; + +procedure TfrmMain.actExtractPNGsExecute(Sender: TObject); +var + I, OFFSET, BIT_MODE, SIZE: Integer; + FName, Path: string; + IsImage: Boolean; + ScanTim: TScanTim; + TIM: PTIM; + PNG_: PPNGImage; +begin + lblStatus.Caption := sStatusBarPngsExtracting; + + FName := ScanRes.ScanFile; + IsImage := ScanRes.IsImage; + + New(PNG_); + + pbProgress.Position := 0; + pbProgress.Max := ScanRes.Count; + for I := 1 to ScanRes.Count do + begin + ScanTim := TimIdx(I - 1); + OFFSET := ScanTim.Position; + SIZE := ScanTim.Size; + BIT_MODE := ScanTim.BitMode; + + Path := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0)) + cExtractedPngsDir); + CreateDir(Path); + Path := IncludeTrailingPathDelimiter(Path + ExtractFileName(FName)); + CreateDir(Path); + + PNG_^ := TPngImage.CreateBlank(COLOR_RGBALPHA, 16, ScanTim.Width, ScanTim.Height); + PNG_^.CompressionLevel := 0; + PNG_^.Filters := []; + + TIM := LoadTimFromFile(FName, OFFSET, IsImage, SIZE); + TimToPNG(TIM, cbbCLUT.ItemIndex, PNG_, cbbTranspMode.ItemIndex); + + PNG_^.SaveToFile(Path + FormatPngName(FName, I - 1, BIT_MODE, 0)); + PNG_^.Free; + + FreeTIM(TIM); + + pbProgress.Position := I; + Application.ProcessMessages; + end; + Dispose(PNG_); + lblStatus.Caption := sStatusBarExtracted; + MessageBeep(MB_ICONINFORMATION); + pbProgress.Position := 0; end; procedure TfrmMain.actExtractTimExecute(Sender: TObject); var TIM: PTIM; begin - dlgSaveTIM.FileName := SelTimName; + dlgSaveTIM.FileName := FormatTimName(ScanRes.ScanFile, ListIdx, TimIdx(ListIdx).BitMode); if not dlgSaveTIM.Execute then Exit; @@ -423,12 +482,8 @@ begin end; procedure TfrmMain.actTim2PngExecute(Sender: TObject); -var - FName: string; begin - FName := SelTimName; - FName := ChangeFileExt(FName, '.png'); - dlgSavePNG.FileName := FName; + dlgSavePNG.FileName := FormatPngName(ScanRes.ScanFile, ListIdx, TimIdx(ListIdx).BitMode, cbbCLUT.ItemIndex); if not dlgSavePNG.Execute then Exit; @@ -459,8 +514,8 @@ begin + Tab + '%s' + Row + Row + 'HEADER INFO' + Row + 'Version:' + Tab + '%d' + Row + 'BPP:' + Tab + '%d' - + Row + Row, [SelTimName, Index + 1, TimIdx(Index).Position, - BppToBitMode(TIM), IsGoodTIM, + + Row + Row, [FormatTimName(ScanRes.ScanFile, Index, TimIdx(Index).BitMode), + Index + 1, TimIdx(Index).Position, BppToBitMode(TIM), IsGoodTIM, GetTimVersion(TIM), GetTimBPP(TIM)]); @@ -558,7 +613,8 @@ begin cbbFiles.Enabled := (cbbFiles.Items.Count <> 0); lvList.Enabled := cbbFiles.Enabled; - actExtractList.Enabled := cbbFiles.Enabled; + actExtractTIMs.Enabled := cbbFiles.Enabled; + actExtractPNGs.Enabled := cbbFiles.Enabled; actCloseFile.Enabled := cbbFiles.Enabled; actCloseFiles.Enabled := cbbFiles.Enabled; actReplaceTim.Enabled := (lvList.SelCount = 1); @@ -587,9 +643,14 @@ begin Result^.HEAD^.bBPP := NewBitMode; end; -function TfrmMain.SelTimName: string; +function TfrmMain.FormatTimName(const FileName: string; ListIdx_, BitMode: Integer): string; begin - Result := Format(cAutoExtractionTimFormat, [ExtractJustName(ScanRes.ScanFile), ListIdx + 1, TimIdx(ListIdx).BitMode]); + Result := Format(cAutoExtractionTimFormat, [ExtractJustName(FileName), ListIdx_ + 1, BitMode]); +end; + +function TfrmMain.FormatPngName(const FileName: string; ListIdx_, BitMode, Clut: Integer): string; +begin + Result := Format(cAutoExtractionPngFormat, [ExtractJustName(FileName), ListIdx_ + 1, BitMode, Clut + 1]); end; procedure TfrmMain.DrawSelClut; @@ -647,10 +708,10 @@ begin PNG^ := nil; end; - if cbbCLUT.Text = sThisTimHasNoClut then + (*if cbbCLUT.Text = sThisTimHasNoClut then Index := -1 else - Index := cbbCLUT.ItemIndex; + *)Index := cbbCLUT.ItemIndex; TimToPNG(TIM, Index, PNG, cbbTranspMode.ItemIndex); PNG.AssignTo(pbTim.Picture.Bitmap); diff --git a/units/uScanThread.pas b/units/uScanThread.pas index 5691d49..69ff85e 100644 --- a/units/uScanThread.pas +++ b/units/uScanThread.pas @@ -89,87 +89,91 @@ var begin Synchronize(StartScan); - pSrcFileStream := TFileStream.Create(pScanResult.ScanFile, fmOpenRead or - fmShareDenyWrite); - pSrcFileStream.Position := 0; + try + if pScanResult.IsImage then + pSectorBufferSize := cSectorBufferSize + else + pSectorBufferSize := cClearBufferSize; - if pScanResult.IsImage then - pSectorBufferSize := cSectorBufferSize - else - pSectorBufferSize := cClearBufferSize; + pClearBufferSize := cClearBufferSize; - pClearBufferSize := cClearBufferSize; + SectorBuffer := GetMemory(pSectorBufferSize); + ClearBuffer := GetMemory(pClearBufferSize); - SectorBuffer := GetMemory(pSectorBufferSize); - ClearBuffer := GetMemory(pClearBufferSize); + pSrcFileStream := TFileStream.Create(pScanResult.ScanFile, fmOpenRead or + fmShareDenyWrite); - TIM := CreateTIM; + pSrcFileStream.Position := 0; - pStatusText := sStatusBarScanningFile; - Synchronize(SetStatusText); + TIM := CreateTIM; - pRealBufSize := pSrcFileStream.Read(SectorBuffer^[0], pSectorBufferSize); - Inc(pFilePos, pRealBufSize); - ClearSectorBuffer(SectorBuffer, ClearBuffer); + pStatusText := sStatusBarScanningFile; + Synchronize(SetStatusText); - pScanFinished := False; - pTIMNumber := 0; + pRealBufSize := pSrcFileStream.Read(SectorBuffer^[0], pSectorBufferSize); + Inc(pFilePos, pRealBufSize); + ClearSectorBuffer(SectorBuffer, ClearBuffer); - while not pStopScan do - begin - if LoadTimFromBuf(ClearBuffer, TIM, pClearBufferPosition) then + pScanFinished := False; + pTIMNumber := 0; + + while not pStopScan do begin - if pScanResult.IsImage then - pTimPosition := pFilePos - pRealBufSize + - ((pClearBufferPosition - 1) div cSectorDataSize) * cSectorSize + - ((pClearBufferPosition - 1) mod cSectorDataSize) + cSectorInfoSize - else - pTimPosition := pFilePos - pRealBufSize + (pClearBufferPosition - 1); - - if pTimPosition >= pFileSize then Break; - - TIM^.dwTimPosition := pTimPosition; - Inc(pTIMNumber); - TIM^.dwTimNumber := pTIMNumber; - AddResult(TIM); - end; - - if pClearBufferPosition = (pClearBufferSize div 2) then - begin - if pScanFinished then Break; - - pScanFinished := (pFilePos = pFileSize); - pClearBufferPosition := 0; - Move(SectorBuffer^[pSectorBufferSize div 2], SectorBuffer^[0], pSectorBufferSize div 2); - - if pScanFinished then + if LoadTimFromBuf(ClearBuffer, TIM, pClearBufferPosition) then begin - if pRealBufSize >= (pSectorBufferSize div 2) then - // Need to check file size - pRealBufSize := pRealBufSize - (pSectorBufferSize div 2); - end - else - begin - pRealBufSize := pSrcFileStream.Read(SectorBuffer^[pSectorBufferSize div 2], pSectorBufferSize div 2); - Inc(pFilePos, pRealBufSize); - pRealBufSize := pRealBufSize + (pSectorBufferSize div 2); + if pScanResult.IsImage then + pTimPosition := pFilePos - pRealBufSize + + ((pClearBufferPosition - 1) div cSectorDataSize) * cSectorSize + + ((pClearBufferPosition - 1) mod cSectorDataSize) + cSectorInfoSize + else + pTimPosition := pFilePos - pRealBufSize + (pClearBufferPosition - 1); + + if pTimPosition >= pFileSize then Break; + + TIM^.dwTimPosition := pTimPosition; + Inc(pTIMNumber); + TIM^.dwTimNumber := pTIMNumber; + AddResult(TIM); end; - Synchronize(UpdateProgressBar); + if pClearBufferPosition = (pClearBufferSize div 2) then + begin + if pScanFinished then Break; - ClearSectorBuffer(SectorBuffer, ClearBuffer); + pScanFinished := (pFilePos = pFileSize); + pClearBufferPosition := 0; + Move(SectorBuffer^[pSectorBufferSize div 2], SectorBuffer^[0], pSectorBufferSize div 2); + + if pScanFinished then + begin + if pRealBufSize >= (pSectorBufferSize div 2) then + // Need to check file size + pRealBufSize := pRealBufSize - (pSectorBufferSize div 2); + end + else + begin + pRealBufSize := pSrcFileStream.Read(SectorBuffer^[pSectorBufferSize div 2], pSectorBufferSize div 2); + Inc(pFilePos, pRealBufSize); + pRealBufSize := pRealBufSize + (pSectorBufferSize div 2); + end; + + Synchronize(UpdateProgressBar); + + ClearSectorBuffer(SectorBuffer, ClearBuffer); + end; end; + finally + FreeTIM(TIM); + FreeMemory(SectorBuffer); + FreeMemory(ClearBuffer); + + pSrcFileStream.Free; + pStopScan := True; + pFilePos := 0; + pStatusText := ''; + + Synchronize(FinishScan); end; - FreeTIM(TIM); - FreeMemory(SectorBuffer); - FreeMemory(ClearBuffer); - - pSrcFileStream.Free; - pStopScan := True; - pFilePos := 0; - pStatusText := ''; - - Synchronize(FinishScan); end; procedure TScanThread.FinishScan; @@ -201,7 +205,8 @@ procedure TScanThread.StartScan; begin frmMain.cbbFiles.Enabled := False; frmMain.lvList.Enabled := False; - frmMain.actExtractList.Enabled := False; + frmMain.actExtractTIMs.Enabled := False; + frmMain.actExtractPNGs.Enabled := False; frmMain.pbProgress.Max := GetFileSizeAPI(pScanResult.ScanFile); frmMain.pbProgress.Position := 0; diff --git a/units/uSettings.pas b/units/uSettings.pas index 0623c6f..6ac9c24 100644 --- a/units/uSettings.pas +++ b/units/uSettings.pas @@ -35,19 +35,19 @@ unit uSettings; { TSettings } - procedure TCustomSettings.LoadFromFile() ; - var - Stream: TStream; - begin - if not FileExists(FFileName) then Exit; +procedure TCustomSettings.LoadFromFile() ; +var + Stream: TStream; +begin + if not FileExists(FFileName) then Exit; - Stream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyWrite) ; - try - LoadFromStream(Stream) ; - finally - Stream.Free; - end; - end; + try + Stream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyWrite) ; + LoadFromStream(Stream) ; + finally + Stream.Free; + end; +end; procedure TCustomSettings.LoadFromStream(const Stream: TStream) ; var diff --git a/units/uTIM.pas b/units/uTIM.pas index 8802b05..0cf0d76 100644 --- a/units/uTIM.pas +++ b/units/uTIM.pas @@ -372,56 +372,58 @@ var Sector: TCDSector; P, TIM_FULL_SECTORS: Integer; begin - sImageStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + sImageStream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - TimSectorNumber := Position div cSectorSize + 1; - TimOffsetInSector := Position mod cSectorSize - cSectorInfoSize; - TimStartSectorPos := (TimSectorNumber - 1) * cSectorSize; - FirstPartSize := cSectorDataSize - TimOffsetInSector; + TimSectorNumber := Position div cSectorSize + 1; + TimOffsetInSector := Position mod cSectorSize - cSectorInfoSize; + TimStartSectorPos := (TimSectorNumber - 1) * cSectorSize; + FirstPartSize := cSectorDataSize - TimOffsetInSector; - New(TIM_BUF); - P := 0; + New(TIM_BUF); + P := 0; - if SIZE < FirstPartSize then - FirstPartSize := SIZE; + if SIZE < FirstPartSize then + FirstPartSize := SIZE; - sImageStream.Seek(TimStartSectorPos, soBeginning); - sImageStream.Read(Sector, cSectorSize); - - Move(Sector.dwData[TimOffsetInSector], TIM_BUF^[P], FirstPartSize); - Inc(P, FirstPartSize); - - Inc(TimStartSectorPos, cSectorSize); - sImageStream.Seek(TimStartSectorPos, soBeginning); - - TIM_FULL_SECTORS := (SIZE - P) div cSectorDataSize; - - while TIM_FULL_SECTORS > 0 do - begin + sImageStream.Seek(TimStartSectorPos, soBeginning); sImageStream.Read(Sector, cSectorSize); - Move(Sector.dwData[0], TIM_BUF^[P], cSectorDataSize); - Inc(P, cSectorDataSize); + Move(Sector.dwData[TimOffsetInSector], TIM_BUF^[P], FirstPartSize); + Inc(P, FirstPartSize); Inc(TimStartSectorPos, cSectorSize); sImageStream.Seek(TimStartSectorPos, soBeginning); - Dec(TIM_FULL_SECTORS); + TIM_FULL_SECTORS := (SIZE - P) div cSectorDataSize; + + while TIM_FULL_SECTORS > 0 do + begin + sImageStream.Read(Sector, cSectorSize); + + Move(Sector.dwData[0], TIM_BUF^[P], cSectorDataSize); + Inc(P, cSectorDataSize); + + Inc(TimStartSectorPos, cSectorSize); + sImageStream.Seek(TimStartSectorPos, soBeginning); + + Dec(TIM_FULL_SECTORS); + end; + + sImageStream.Read(Sector, cSectorSize); + + if SIZE > P then + begin + LastPartSize := SIZE - P; + Move(Sector.dwData[0], TIM_BUF^[P], LastPartSize); + end; + finally + P := 0; + Result := nil; + LoadTimFromBuf(TIM_BUF, Result, P); + sImageStream.Free; + Dispose(TIM_BUF); end; - - sImageStream.Read(Sector, cSectorSize); - - if SIZE > P then - begin - LastPartSize := SIZE - P; - Move(Sector.dwData[0], TIM_BUF^[P], LastPartSize); - end; - - P := 0; - Result := nil; - LoadTimFromBuf(TIM_BUF, Result, P); - sImageStream.Free; - Dispose(TIM_BUF); end; function LoadTimFromStream(Stream: TStream; var Position: Integer; @@ -455,9 +457,12 @@ var begin if not ImageScan then begin - sTIM := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); - Result := LoadTimFromStream(sTIM, Position, dwSize); - sTIM.Free; + try + sTIM := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + Result := LoadTimFromStream(sTIM, Position, dwSize); + finally + sTIM.Free; + end; Exit; end; @@ -468,8 +473,7 @@ procedure SaveTimToFile(const FileName: string; TIM: PTIM); var tmp: TMemoryStream; begin - if TIM = nil then - Exit; + if TIM = nil then Exit; tmp := TMemoryStream.Create; tmp.Write(TIM^.DATA^[0], TIM^.dwSize);