MMFFile.pas
上传用户:hylc_2004
上传日期:2014-01-23
资源大小:46800k
文件大小:31k
源码类别:

Delphi控件源码

开发平台:

Delphi

  1. {========================================================================}
  2. {=                (c) 1995-98 SwiftSoft Ronald Dittrich                 =}
  3. {========================================================================}
  4. {=                          All Rights Reserved                         =}
  5. {========================================================================}
  6. {=  D 01099 Dresden             = Tel.: +0351-8012255                   =}
  7. {=  Loewenstr.7a                = info@swiftsoft.de                     =}
  8. {========================================================================}
  9. {=  Actual versions on http://www.swiftsoft.de/mmtools.html             =}
  10. {========================================================================}
  11. {=  This code is for reference purposes only and may not be copied or   =}
  12. {=  distributed in any format electronic or otherwise except one copy   =}
  13. {=  for backup purposes.                                                =}
  14. {=                                                                      =}
  15. {=  No Delphi Component Kit or Component individually or in a collection=}
  16. {=  subclassed or otherwise from the code in this unit, or associated   =}
  17. {=  .pas, .dfm, .dcu, .asm or .obj files may be sold or distributed     =}
  18. {=  without express permission from SwiftSoft.                          =}
  19. {=                                                                      =}
  20. {=  For more licence informations please refer to the associated        =}
  21. {=  HelpFile.                                                           =}
  22. {========================================================================}
  23. {=  $Date: 20.01.1998 - 18:00:00 $                                      =}
  24. {========================================================================}
  25. unit MMFFile;
  26. {$I COMPILER.INC}
  27. interface
  28. uses
  29.     Windows,
  30.     SysUtils,
  31.     Controls,
  32.     Classes,
  33.     MMSystem,
  34.     MMObj,
  35.     MMUtils,
  36.     MMString,
  37.     MMSearch;
  38. type
  39.     EMMFastFileError = class(Exception);
  40.     PFileEntry = ^TFileEntry;
  41.     TFileEntry = packed record
  42.        Name   : String[12];
  43.        Size   : Longint;
  44.        Offset : Longint;
  45.        Deleted: Boolean;
  46.     end;
  47.     PFileEntryArray = ^TFileEntryArray;
  48.     TFileEntryArray = array[0..0] of TFileEntry;
  49.     PFileHandle = ^TFileHandle;
  50.     TFileHandle = packed record
  51.        inUse: Boolean;
  52.        Pos  : Longint;
  53.        Size : Longint;
  54.        pfe  : PFileEntry;
  55.     end;
  56.     PFileHandleArray = ^TFileHandleArray;
  57.     TFileHandleArray = array[0..0] of TFileHandle;
  58.     {-- TMMFastFile -----------------------------------------------------}
  59.     TMMFastFile = class(TMMNonVisualComponent)
  60.     private
  61.        FFileName       : TFileName;
  62.        FMaxFiles       : integer;
  63.        FMaxHandles     : integer;
  64.        FHFile          : THandle;
  65.        FHFileMapping   : THandle;
  66.        FPFileEntries   : PFileEntryArray;
  67.        FPFileEntryCount: PLongint;
  68.        FPFileHandles   : PFileHandleArray;
  69.        FPBase          : PChar;
  70.        FNumDeleted     : integer;
  71.        FOnChange       : TNotifyEvent;
  72.        FOnHandlesLost  : TNotifyEvent;
  73.        procedure CreateFastFile(FileName: TFileName; nMaxFiles: integer);
  74.        procedure UpdateFastFile(Size: integer);
  75.        function  IsFastFile(FileName: TFileName): Boolean;
  76.        procedure SetFileName(aValue: TFileName);
  77.        procedure SetMaxFiles(aValue: integer);
  78.        procedure SetMaxHandles(aValue: integer);
  79.        function  GetCount: integer;
  80.        function  GetFileEntries(index: integer): TFileEntry;
  81.        function  GetFiles(index: integer): string;
  82.        function  GetFilesByName(Name: string): string;
  83.     protected
  84.        procedure Change; dynamic;
  85.        procedure HandlesLost; dynamic;
  86.        procedure Loaded; override;
  87.     public
  88.        constructor Create(AOwner: TComponent); override;
  89.        destructor  Destroy; override;
  90.        procedure Init;
  91.        procedure Done;
  92.        procedure Pack;
  93.        function  AddFile(const Name: TFileName): TFileName;
  94.        procedure RemoveFile(const Name: TFileName);
  95.        procedure RenameFile(const OldName, NewName: TFileName);
  96.        procedure ExtractFile(const Name, Path: TFileName);
  97.        function  FileExists(const Name: TFileName): Boolean;
  98.        function  FileSize(const Name: TFileName): integer;
  99.        function  FileOpen(const Name: TFileName): PFileHandle;
  100.        procedure FileClose(pfh: PFileHandle);
  101.        function  FileLock(pfh: PFileHandle; pos, size: integer): Pointer;
  102.        procedure FileUnlock(pfh: PFileHandle; pos, size: integer);
  103.        function  FileRead(pfh: PFileHandle; Buffer: PChar; size: integer): integer;
  104.        function  FileSeek(pfh: PFileHandle; pos, origin: integer): integer;
  105.        property  Count: integer read GetCount;
  106.        property  FileEntries[index: integer]: TFileEntry read GetFileEntries;
  107.        property  Files[index: integer]: string read GetFiles; default;
  108.        property  FilesByName[Name: string]: string read GetFilesByName;
  109.     published
  110.        property OnChange: TNotifyEvent read FOnChange write FOnChange;
  111.        property OnHandlesLost: TNotifyEvent read FOnHandlesLost write FOnHandlesLost;
  112.        property FileName: TFileName read FFileName write SetFileName;
  113.        property MaxFiles: integer read FMaxFiles write SetMaxFiles default 50;
  114.        property MaxHandles: integer read FMaxHandles write SetMaxHandles default 10;
  115.     end;
  116. implementation
  117. const
  118.     BLOCK_SIZE : integer = 16*1024;
  119.     KENNUNG    : array[0..8] of Char = 'FASTFILE'+#0;
  120. {========================================================================}
  121. { Compare: bsearch comparison routine                                    }
  122. {========================================================================}
  123. function Compare(p1, p2: PFileEntry): integer;
  124. begin
  125.    if p2.Deleted then Result := -1
  126.    else Result := CompareText(p1.Name,p2.Name);
  127. end;
  128. {-- TMMFastFile ---------------------------------------------------------}
  129. constructor TMMFastFile.Create(AOwner: TComponent);
  130. begin
  131.    inherited Create(AOwner);
  132.    FOnChange       := nil;
  133.    FOnHandlesLost  := nil;
  134.    FFileName       := '';
  135.    FMaxFiles       := 50;
  136.    FMaxHandles     := 10;
  137.    FHFile          := 0;
  138.    FHFileMapping   := 0;
  139.    FPFileEntries   := nil;
  140.    FPFileEntryCount:= nil;
  141.    FPFileHandles   := nil;
  142.    FPBase          := nil;
  143.    FNumDeleted     := 0;
  144.    ErrorCode := ComponentRegistered(InitCode, Self, ClassName);
  145.    if (ErrorCode <> 0) then RegisterFailed(InitCode, Self , ClassName);
  146. end;
  147. {-- TMMFastFile ---------------------------------------------------------}
  148. destructor TMMFastFile.Destroy;
  149. begin
  150.    Done;
  151.    inherited Destroy;
  152. end;
  153. {-- TMMFastFile ---------------------------------------------------------}
  154. procedure TMMFastFile.Loaded;
  155. begin
  156.    inherited;
  157.    if not (csDesigning in ComponentState) then
  158.    begin
  159.       if (FFileName <> '') then Init;
  160.    end;
  161. end;
  162. {-- TMMFastFile ---------------------------------------------------------}
  163. procedure TMMFastFile.Change;
  164. begin
  165.    if not (csDesigning in ComponentState) then
  166.       if assigned(FOnChange) then FOnChange(Self);
  167. end;
  168. {-- TMMFastFile ---------------------------------------------------------}
  169. procedure TMMFastFile.HandlesLost;
  170. begin
  171.    if not (csDesigning in ComponentState) and
  172.       not (csLoading in ComponentState) and
  173.       not (csDestroying in ComponentState) then
  174.       if assigned(FOnHandlesLost) then FOnHandlesLost(Self);
  175. end;
  176. {-- TMMFastFile ---------------------------------------------------------}
  177. procedure TMMFastFile.SetMaxFiles(aValue: integer);
  178. begin
  179.    if (aValue <> FMaxFiles) then
  180.    begin
  181.       if (FFileName <> '') then
  182.          raise EMMFastFileError.Create(LoadResStr(IDS_FFMAXFILESERROR));
  183.       FMaxFiles := Max(aValue,2);
  184.    end;
  185. end;
  186. {-- TMMFastFile ---------------------------------------------------------}
  187. procedure TMMFastFile.SetMaxHandles(aValue: integer);
  188. begin
  189.    if (aValue <> FMaxHandles) then
  190.    begin
  191.       if (FPFileHandles <> nil) then
  192.       begin
  193.          ReAllocMem(FPFileHandles, aValue*SizeOf(TFileHandle));
  194.          if aValue > FMaxHandles then
  195.             FillChar(FPFileHandles^[FMaxHandles+1],(aValue-FMaxHandles)*sizeOf(TFileHandle), 0)
  196.          else HandlesLost;
  197.       end;
  198.       FMaxHandles := aValue;
  199.    end;
  200. end;
  201. {-- TMMFastFile ---------------------------------------------------------}
  202. function TMMFastFile.IsFastFile(FileName: TFileName): Boolean;
  203. var
  204.    hIn: THandle;
  205.    Ken: array[0..255] of Char;
  206. begin
  207.    Result := False;
  208.    if (FileName <> '') and SysUtils.FileExists(FileName) then
  209.    begin
  210.       FillChar(Ken,sizeOf(Ken),0);
  211.       hIn := SysUtils.FileOpen(FileName, fmOpenRead or fmShareDenyNone);
  212.       try
  213.          if hIn > 0 then
  214.             if SysUtils.FileRead(hIn, Ken, sizeOf(KENNUNG)-1) = sizeOf(KENNUNG)-1 then
  215.                if StrComp(Ken, KENNUNG) = 0 then Result := True;
  216.       finally
  217.          SysUtils.FileClose(hIn);
  218.       end;
  219.    end;
  220.    {$IFDEF TRIAL}
  221.    {$DEFINE _HACK1}
  222.    {$I MMHACK.INC}
  223.    {$ENDIF}
  224. end;
  225. {-- TMMFastFile ---------------------------------------------------------}
  226. procedure TMMFastFile.SetFileName(aValue: TFileName);
  227. begin
  228.    if (aValue <> FFileName) then
  229.    begin
  230.       aValue := ExpandUNCFileName(aValue);
  231.       if SysUtils.FileExists(aValue) then
  232.          if not IsFastFile(aValue) then
  233.             raise EMMFastFileError.Create(LoadResStr(IDS_FFNOFASTFILE));
  234.       Done;
  235.       if not SysUtils.FileExists(aValue) then
  236.          CreateFastFile(aValue, FMaxFiles);
  237.       FFileName := aValue;
  238.       if (FFileName <> '') then Init;
  239.       if (csDesigning in ComponentState) then Done;
  240.    end;
  241.    {$IFDEF TRIAL}
  242.    {$DEFINE _HACK2}
  243.    {$I MMHACK.INC}
  244.    {$ENDIF}
  245. end;
  246. {-- TMMFastFile ---------------------------------------------------------}
  247. function TMMFastFile.GetCount: integer;
  248. begin
  249.    if FPFileEntryCount <> nil then Result := FPFileEntryCount^ - FNumDeleted
  250.    else Result := 0;
  251. end;
  252. {-- TMMFastFile ---------------------------------------------------------}
  253. function TMMFastFile.GetFileEntries(index: integer): TFileEntry;
  254. var
  255.    i,j: integer;
  256.    fe: TFileEntry;
  257. begin
  258.    if (FPFileEntries = nil) then
  259.       raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  260.    if (index < Count) then
  261.    begin
  262.       j := 0;
  263.       for i := 0 to FPFileEntryCount^-1 do
  264.       begin
  265.          fe := FPFileEntries[i];
  266.          if not fe.Deleted then
  267.          begin
  268.             if (j = index) then
  269.             begin
  270.                Result := fe;
  271.                exit;
  272.             end;
  273.             inc(j);
  274.          end;
  275.       end;
  276.    end;
  277.    FillChar(Result, sizeOf(Result), 0);
  278.    raise EMMFastFileError.Create(LoadResStr(IDS_FFBADINDEX));
  279. end;
  280. {-- TMMFastFile ---------------------------------------------------------}
  281. function TMMFastFile.GetFiles(index: integer): string;
  282. var
  283.    i,j: integer;
  284.    fe : TFileEntry;
  285. begin
  286.    if (FPFileEntries = nil) then
  287.       raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  288.    if (index < Count) then
  289.    begin
  290.       j := 0;
  291.       for i := 0 to FPFileEntryCount^-1 do
  292.       begin
  293.          fe := FPFileEntries[i];
  294.          if not fe.Deleted then
  295.          begin
  296.             if (j = index) then
  297.             begin
  298.                Result := fe.Name;
  299.                exit;
  300.             end;
  301.             inc(j);
  302.          end;
  303.       end;
  304.    end;
  305.    Result := '';
  306.    raise EMMFastFileError.Create(LoadResStr(IDS_FFBADINDEX));
  307. end;
  308. {-- TMMFastFile ---------------------------------------------------------}
  309. function TMMFastFile.GetFilesByName(Name: string): string;
  310. var
  311.    fe: TFileEntry;
  312.    pfe: PFileEntry;
  313. begin
  314.    if (FPFileEntries = nil) then
  315.       raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  316.    if (Name <> '') then
  317.    begin
  318.       fe.Name := PChar(Name);
  319.       pfe := lfind(@fe, FPFileEntries, FPFileEntryCount^, sizeof(TFileEntry), @Compare);
  320.       if (pfe <> nil) then
  321.       begin
  322.          Result := pfe.Name;
  323.       end;
  324.    end
  325.    else
  326.    begin
  327.       Result := '';
  328.       raise EMMFastFileError.Create(LoadResStr(IDS_FFBADFILENAME));
  329.    end;
  330. end;
  331. {-- TMMFastFile ---------------------------------------------------------}
  332. procedure TMMFastFile.CreateFastFile(FileName: TFileName; nMaxFiles: integer);
  333. var
  334.    hOut: integer;
  335.    pfe: PFileEntryArray;
  336.    Tmp: Longint;
  337. begin
  338.    if FileName = '' then exit;
  339.    hOut := FileCreate(FileName);
  340.    if (hOut < 0) then
  341.       raise EMMFastFileError.CreateFmt(LoadResStr(IDS_FFCREATEERROR),['FastFile']);
  342.    try
  343.       inc(nMaxFiles); // make place for one entry more
  344.       pfe := nil;
  345.       pfe := GlobalAllocMem(nMaxFiles * sizeOf(TFileEntry));
  346.       FillChar(pfe^, nMaxFiles * sizeOf(TFileEntry), 0);
  347.       FileName := ExpandUNCFileName(FileName);
  348.       if FileWrite(hOut, KENNUNG, sizeOf(KENNUNG)-1) <> sizeOf(KENNUNG)-1 then
  349.          raise EMMFastFileError.Create(LoadResStr(IDS_FFWRITEERROR));
  350.       // write the number of max directory entries
  351.       Tmp := nMaxFiles-1;
  352.       if FileWrite(hOut, Tmp, sizeOf(Tmp)) <> sizeOf(Tmp) then
  353.          raise EMMFastFileError.Create(LoadResStr(IDS_FFWRITEERROR));
  354.       // write the number of current directory entries (0)
  355.       Tmp := 0;
  356.       if FileWrite(hOut, Tmp, sizeOf(Tmp)) <> sizeOf(Tmp) then
  357.          raise EMMFastFileError.Create(LoadResStr(IDS_FFWRITEERROR));
  358.      {$IFDEF TRIAL}
  359.      {$DEFINE _HACK1}
  360.      {$I MMHACK.INC}
  361.      {$ENDIF}
  362.       // set the offset for the first entry
  363.       pfe[0].Offset := (sizeOf(KENNUNG)-1+2*sizeOf(Longint)) + nMaxFiles * sizeOF(TFileEntry);
  364.       if FileWrite(hOut, pfe^, nMaxFiles * sizeOf(TFileEntry)) <> nMaxFiles * sizeOf(TFileEntry) then
  365.          raise EMMFastFileError.Create(LoadResStr(IDS_FFWRITEERROR));
  366.    finally
  367.       SysUtils.FileClose(hOut);
  368.       GlobalFreeMem(Pointer(pfe));
  369.    end;
  370. end;
  371. {-- TMMFastFile ---------------------------------------------------------}
  372. procedure TMMFastFile.Init;
  373. begin
  374.    if (FFileName = '') or not SysUtils.FileExists(FFileName) then
  375.       raise EMMFastFileError.Create(LoadResStr(IDS_FFBADFILENAME));
  376.    // make sure any old FastFile is closed
  377.    Done;
  378.    try
  379.       // get a file handle array
  380.       ReAllocMem(FPFileHandles, FMaxHandles*SizeOf(TFileHandle));
  381.       if (FPFileHandles = nil) then OutOfMemoryError;
  382.       FillChar(FPFileHandles^, FMaxHandles * sizeOf(TFileHandle), 0);
  383.       // create a memory mapped file for the master file
  384.       FHFile := CreateFile(PChar(FFileName), GENERIC_READ or GENERIC_WRITE,
  385.                            FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
  386.                            OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
  387.       if (FHFile = 0) or (FHFile = HFILE_ERROR) then
  388.       begin
  389.          FHFile := 0;
  390.          raise EMMFastFileError.Create('CreateFile failed with Error Code: '+IntToStr(GetLastError));
  391.       end;
  392.       FHFileMapping := CreateFileMapping(FHFile,nil,PAGE_READWRITE,0,0,nil);
  393.       if (FHFileMapping = 0) then
  394.          raise EMMFastFileError.Create('CreateFileMapping failed with Error Code: '+IntToStr(GetLastError));
  395.       FPBase := MapViewOfFile(FHFileMapping, FILE_MAP_WRITE, 0, 0, 0);
  396.       if (FPBase = nil) then
  397.          raise EMMFastFileError.Create('MapViewOfFile failed with Error Code: '+IntToStr(GetLastError));
  398.       // get initial data from the memory mapped file
  399.       FMaxFiles := PLongint(FPBase+sizeOf(KENNUNG)-1)^;
  400.       FPFileEntryCount := PLongint(FPBase + sizeOf(KENNUNG)-1 + sizeOf(Longint));
  401.       FPFileEntries := PFileEntryArray(FPBase + sizeOf(KENNUNG)-1 + 2*sizeOf(Longint));
  402.    except
  403.       Done;
  404.       raise;
  405.    end;
  406. end;
  407. {-- TMMFastFile ---------------------------------------------------------}
  408. procedure TMMFastFile.UpdateFastFile(Size: integer);
  409. begin
  410.    try
  411.       if (FHFileMapping <> 0) then
  412.       begin
  413.          if (FPBase <> nil) then
  414.          begin
  415.             UnmapViewOfFile(FPBase);
  416.             FPBase := nil;
  417.          end;
  418.          CloseHandle(FHFileMapping);
  419.          FHFileMapping := 0;
  420.       end;
  421.       if (FHFile <> 0) then
  422.       FHFileMapping := CreateFileMapping(FHFile,nil,PAGE_READWRITE,0,Size,nil);
  423.       if (FHFileMapping = 0) then
  424.          raise EMMFastFileError.Create('CreateFileMapping failed with Error Code: '+IntToStr(GetLastError));
  425.       FPBase := MapViewOfFile(FHFileMapping, FILE_MAP_WRITE, 0, 0, 0);
  426.       if (FPBase = nil) then
  427.          raise EMMFastFileError.Create('MapViewOfFile failed with Error Code: '+IntToStr(GetLastError));
  428.       // get initial data from the memory mapped file
  429.       FMaxFiles := PLongint(FPBase+sizeOf(KENNUNG)-1)^;
  430.       FPFileEntryCount := PLongint(FPBase + sizeOf(KENNUNG)-1 + sizeOf(Longint));
  431.       FPFileEntries := PFileEntryArray(FPBase + sizeOf(KENNUNG)-1 + 2*sizeOf(Longint));
  432.       {$IFDEF TRIAL}
  433.       {$DEFINE _HACK2}
  434.       {$I MMHACK.INC}
  435.       {$ENDIF}
  436.       HandlesLost;
  437.    except
  438.       Done;
  439.       raise;
  440.    end;
  441. end;
  442. {-- TMMFastFile ---------------------------------------------------------}
  443. procedure TMMFastFile.Done;
  444. begin
  445.    Pack;
  446.    if (FHFileMapping <> 0) then
  447.    begin
  448.       if (FPBase <> nil) then UnmapViewOfFile(FPBase);
  449.       CloseHandle(FHFileMapping);
  450.       FHFileMapping := 0;
  451.    end;
  452.    if (FHFile <> 0) then
  453.    begin
  454.       CloseHandle(FHFile);
  455.       FHFile := 0;
  456.    end;
  457.    if (FPFileHandles <> nil) then
  458.    begin
  459.       ReAllocmem(FPFileHandles,0);
  460.       FPFileHandles := nil;
  461.    end;
  462.    FPBase := nil;
  463.    FPFileEntryCount := nil;
  464.    FPFileEntries := nil;
  465. end;
  466. {-- TMMFastFile ---------------------------------------------------------}
  467. function TMMFastFile.AddFile(const Name: TFileName): TFileName;
  468. var
  469.    hIn      : THandle;
  470.    Bytes,pos: integer;
  471.    Buffer   : PChar;
  472.    NewName  : String;
  473. begin
  474.    Result := '';
  475.     if (FPFileEntries = nil) then
  476.        raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  477.    hIn  := 0;
  478.    Buffer := nil;
  479.    try
  480.       // is place for more entry's ?
  481.       if (FPFileEntryCount^ >= FMaxFiles) then
  482.          raise EMMFastFileError.Create(LoadResStr(IDS_FFDIRFULL));
  483.       // get a short filename for the new file
  484.       NewName := GetShortFileName(Name);
  485.       if (NewName = '') then
  486.          raise EMMFastFileError.Create(LoadResStr(IDS_FFBADFILENAME));
  487.       // is the file already in directory or deleted ?
  488.       if FileExists(NewName) then
  489.          raise EMMFastFileError.Create(LoadResStr(IDS_FFDUPLICATEFILENAME));
  490.       // open the new file
  491.       hIn := SysUtils.FileOpen(Name, fmOpenRead);
  492.       if (hIn < 0) then
  493.          raise EMMFastFileError.Create(LoadResStr(IDS_FFOPENERROR));
  494.       Buffer := GlobalAllocMem(BLOCK_SIZE);
  495.       // adjust the size for the MemMapFile
  496.       UpdateFastFile(FPFileEntries[FPFileEntryCount^].Offset+ GetFileSize(Name));
  497.       pos := FPFileEntries[FPFileEntryCount^].Offset;
  498.       while True do
  499.       begin
  500.          Bytes := SysUtils.FileRead(hIn, Buffer^, BLOCK_SIZE);
  501.          if (Bytes = 0) then break;
  502.          if (Bytes < 0) then
  503.             raise EMMFastFileError.Create(LoadResStr(IDS_FFREADERROR));
  504.          try
  505.             move(Buffer^, (FPBase + pos)^, Bytes);
  506.             inc(pos, Bytes);
  507.          except
  508.             raise EMMFastFileError.Create(LoadResStr(IDS_FFWRITEERROR));
  509.          end;
  510.          if (Bytes < BLOCK_SIZE) then break;
  511.       end;
  512.       FPFileEntries[FPFileEntryCount^].Name := NewName;
  513.       FPFileEntries[FPFileEntryCount^].Deleted := False;
  514.       FPFileEntries[FPFileEntryCount^].Size := pos - FPFileEntries[FPFileEntryCount^].Offset;
  515.       // inc the directory entry counter
  516.       inc(FPFileEntryCount^);
  517.       // save current file position for the next entry
  518.       FPFileEntries[FPFileEntryCount^].Offset := pos;
  519.       Result := NewName;
  520.       Change;
  521.    finally
  522.       SysUtils.FileClose(hIn);
  523.       GlobalFreeMem(Pointer(Buffer));
  524.    end;
  525. end;
  526. {-- TMMFastFile ---------------------------------------------------------}
  527. procedure TMMFastFile.RemoveFile(const Name: TFileName);
  528. var
  529.    fe : TFileEntry;
  530.    pfe: PFileEntry;
  531.    i  : integer;
  532. begin
  533.     if (FPFileEntries = nil) then
  534.        raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  535.     if (Name = '') then
  536.        raise EMMFastFileError.Create(LoadResStr(IDS_FFBADFILENAME));
  537.     fe.Name := Name;
  538.     pfe := lfind(@fe, FPFileEntries, FPFileEntryCount^, sizeof(TFileEntry), @Compare);
  539.     if (pfe <> nil) then
  540.     begin
  541.        for i := 0 to FMaxHandles-1 do
  542.        begin
  543.           if (FPFileHandles[i].pfe <> nil) and
  544.              (FPFileHandles[i].pfe.Name = pfe.Name) then
  545.           begin
  546.              FPFileHandles[i].inUse := False;
  547.              break;
  548.           end;
  549.        end;
  550.        pfe.Deleted := True;
  551.        inc(FNumDeleted);
  552.        Change;
  553.     end
  554.     else raise EMMFastFileError.CreateFmt(LoadResStr(IDS_FFNOTFOUND),[Name]);
  555. end;
  556. {-- TMMFastFile ---------------------------------------------------------}
  557. procedure TMMFastFile.RenameFile(const OldName, NewName: TFileName);
  558. var
  559.    fe : TFileEntry;
  560.    pfe: PFileEntry;
  561. begin
  562.     if (FPFileEntries = nil) then
  563.        raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  564.     if (Name = '') or (NewName = '') then
  565.        raise EMMFastFileError.Create(LoadResStr(IDS_FFBADFILENAME));
  566.     if FileExists(NewName) then
  567.        raise EMMFastFileError.Create(LoadResStr(IDS_FFDUPLICATEFILENAME));
  568.     fe.Name := OldName;
  569.     pfe := lfind(@fe, FPFileEntries, FPFileEntryCount^, sizeof(TFileEntry), @Compare);
  570.     if (pfe <> nil) then
  571.     begin
  572.        pfe.Name := NewName;
  573.        Change;
  574.     end
  575.     else raise EMMFastFileError.CreateFmt(LoadResStr(IDS_FFNOTFOUND),[OldName]);
  576. end;
  577. {-- TMMFastFile ---------------------------------------------------------}
  578. procedure TMMFastFile.ExtractFile(const Name, Path: TFileName);
  579. var
  580.    hOut   : THandle;
  581.    pfh    : PFileHandle;
  582.    Buffer : PChar;
  583.    Bytes  : integer;
  584.    NewFile: TFileName;
  585. begin
  586.     if (FPFileEntries = nil) then
  587.        raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  588.     if not FileExists(Name) then
  589.        raise EMMFastFileError.Create(LoadResStr(IDS_FFBADFILENAME));
  590.     if (Path = '') then
  591.        raise EMMFastFileError.Create(LoadResStr(IDS_FFBADPATH));
  592.     Buffer := nil;
  593.     hOut := 0;
  594.     pfh := FileOpen(Name);
  595.     try
  596.        NewFile := ExpandUNCFileName(Path);
  597.        if ExtractFileName(NewFile) = '' then
  598.           NewFile := ExtractFilePath(NewFile) + Name;
  599.        hOut := SysUtils.FileCreate(NewFile);
  600.        if (hOut < 0) then
  601.           raise EMMFastFileError.CreateFmt(LoadResStr(IDS_FFCREATEERROR),[NewFile]);
  602.        Buffer := GlobalAllocMem(BLOCK_SIZE);
  603.        // copy the data in the file to the new file
  604.        while True do
  605.        begin
  606.           Bytes := FileRead(pfh, Buffer, BLOCK_SIZE);
  607.           if (Bytes = 0) then break;
  608.           if (Bytes < 0) then
  609.              raise EMMFastFileError.Create(LoadResStr(IDS_FFREADERROR)+' "'+Name+'"');
  610.           if SysUtils.FileWrite(hOut, Buffer^, Bytes) <> Bytes then
  611.             raise EMMFastFileError.Create(LoadResStr(IDS_FFWRITEERROR)+' "'+NewFile+'"');
  612.           if (Bytes < BLOCK_SIZE) then break;
  613.       end;
  614.     finally
  615.        FileClose(pfh);
  616.        SysUtils.FileClose(hOut);
  617.        GlobalFreeMem(Pointer(Buffer));
  618.     end;
  619. end;
  620. {-- TMMFastFile ---------------------------------------------------------}
  621. procedure TMMFastFile.Pack;
  622. var
  623.    i: integer;
  624.    TempFile: String;
  625.    hFile: THandle;
  626.    hFileMapping: THandle;
  627.    pBase: PChar;
  628.    feSrc: TFileEntry;
  629.    pfe: PFileEntryArray;
  630.    pfeCnt: PLongint;
  631.    NewSize: Longint;
  632.    pos: Longint;
  633. begin
  634.    if (FPFileEntries <> nil) and (FNumDeleted > 0) then
  635.    begin
  636.       SetLength(TempFile, MAX_PATH);
  637.       GetTempFileName(PChar(ExtractFilePath(FFileName)),'FAST'#0,0,PChar(TempFile));
  638.       CreateFastFile(TempFile,FMaxFiles);
  639.       try
  640.          if not SysUtils.FileExists(TempFile) then
  641.             raise EMMFastFileError.Create(LoadResStr(IDS_FFTEMPERROR));
  642.          NewSize := (sizeOf(KENNUNG)-1)+2*sizeOf(Longint)+FMaxFiles*sizeOf(TFileEntry);
  643.          for i := 0 to Count-1 do inc(NewSize, FileEntries[i].Size);
  644.          // create a memory mapped file for the temp file
  645.          hFile := CreateFile(PChar(TempFile), GENERIC_READ or GENERIC_WRITE,
  646.                            FILE_SHARE_READ or FILE_SHARE_WRITE, nil,
  647.                            OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0);
  648.          if (hFile = 0) or (hFile = HFILE_ERROR) then
  649.          begin
  650.             hFile := 0;
  651.             raise EMMFastFileError.Create('CreateFile failed with Error Code: '+IntToStr(GetLastError));
  652.          end;
  653.          hFileMapping := CreateFileMapping(hFile,nil,PAGE_READWRITE,0,NewSize,nil);
  654.          if (hFileMapping = 0) then
  655.          raise EMMFastFileError.Create('CreateFileMapping failed with Error Code: '+IntToStr(GetLastError));
  656.          pBase := MapViewOfFile(hFileMapping, FILE_MAP_WRITE, 0, 0, 0);
  657.          if (pBase = nil) then
  658.             raise EMMFastFileError.Create('MapViewOfFile failed with Error Code: '+IntToStr(GetLastError));
  659.          // get initial data from the memory mapped file
  660.          pfeCnt := PLongint(pBase + sizeOf(KENNUNG)-1 + sizeOf(Longint));
  661.          pfe := PFileEntryArray(pBase + sizeOf(KENNUNG)-1 + 2*sizeOf(Longint));
  662.          pos := pfe[0].Offset;
  663.          for i := 0 to Count-1 do
  664.          begin
  665.             try
  666.                feSrc := FileEntries[i];
  667.                pfe[i].Name := feSrc.Name;
  668.                pfe[i].Offset := pos;
  669.                pfe[i].Size := feSrc.Size;
  670.                pfe[i].Deleted := False;
  671.                move((FPBase + feSrc.Offset)^, (pBase + pos)^, feSrc.Size);
  672.                inc(pos, feSrc.Size);
  673.                inc(pfeCnt^);
  674.             except
  675.                raise EMMFastFileError.Create(LoadResStr(IDS_FFPACKERROR));
  676.             end;
  677.          end;
  678.          // save current file position for the next entry
  679.          pfe[pfeCnt^].Offset := pos;
  680.          HandlesLost;
  681.       finally
  682.          if (hFileMapping <> 0) then
  683.          begin
  684.             if (pBase <> nil) then UnmapViewOfFile(pBase);
  685.             CloseHandle(hFileMapping);
  686.          end;
  687.          if (hFile <> 0) then CloseHandle(hFile);
  688.       end;
  689.       FNumDeleted := 0;
  690.       // now delete the old FastFile
  691.       Done;
  692.       SysUtils.DeleteFile(FFileName);
  693.       SysUtils.RenameFile(TempFile,FFileName);
  694.       Init;
  695.    end;
  696. end;
  697. {-- TMMFastFile ---------------------------------------------------------}
  698. function TMMFastFile.FileExists(const Name: TFileName): Boolean;
  699. var
  700.    fe: TFileEntry;
  701.    pfe: PFileEntry;
  702. begin
  703.    Result := False;
  704.    if (FPFileEntries = nil) then
  705.       raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  706.    if (Name <> '') then
  707.    begin
  708.       fe.Name := Name;
  709.       pfe := lfind(@fe, FPFileEntries, FPFileEntryCount^, sizeof(TFileEntry), @Compare);
  710.       Result := (pfe <> nil);
  711.    end;
  712. end;
  713. {-- TMMFastFile ---------------------------------------------------------}
  714. function TMMFastFile.FileSize(const Name: TFileName): integer;
  715. var
  716.    pfh: PFileHandle;
  717. begin
  718.    Result := 0;
  719.    if FileExists(Name) then
  720.    begin
  721.       pfh := FileOpen(Name);
  722.       Result := pfh.Size;
  723.       FileClose(pfh);
  724.    end;
  725. end;
  726. {-- TMMFastFile ---------------------------------------------------------}
  727. function TMMFastFile.FileOpen(const Name: TFileName): PFileHandle;
  728. var
  729.    fe: TFileEntry;
  730.    pfe: PFileEntry;
  731.    i: Longint;
  732. begin
  733.     Result := nil;
  734.     if (FPFileEntries = nil) then
  735.        raise EMMFastFileError.Create(LoadResStr(IDS_FFNOTINIT));
  736.     if (Name = '') then
  737.        raise EMMFastFileError.Create(LoadResStr(IDS_FFBADFILENAME));
  738.     fe.Name := Name;
  739.     pfe := lfind(@fe, FPFileEntries, FPFileEntryCount^, sizeof(TFileEntry), @Compare);
  740.     if (pfe <> nil) then
  741.     begin
  742.        for i := 0 to FMaxHandles-1 do
  743.        begin
  744.           if not FPFileHandles[i].inUse then
  745.           begin
  746.              FPFileHandles[i].inUse := True;
  747.              FPFileHandles[i].Pos := pfe.Offset;
  748.              FPFileHandles[i].Size := pfe.Size;
  749.              FPFileHandles[i].pfe := pfe;
  750.              Result := @FPFileHandles[i];
  751.              exit;
  752.           end;
  753.        end;
  754.        raise EMMFastFileError.Create(LoadResStr(IDS_FFNOHANDLES));
  755.     end
  756.     else raise EMMFastFileError.CreateFmt(LoadResStr(IDS_FFNOTFOUND),[Name]);
  757. end;
  758. {-- TMMFastFile ---------------------------------------------------------}
  759. procedure TMMFastFile.FileClose(pfh: PFileHandle);
  760. begin
  761.    if (pfh <> nil) and (pfh.inUse = True) or pfh.pfe.Deleted then
  762.    begin
  763.       pfh.inUse := False;
  764.    end;
  765. end;
  766. {-- TMMFastFile ---------------------------------------------------------}
  767. function TMMFastFile.FileLock(pfh: PFileHandle; pos, size: integer): Pointer;
  768. begin
  769.    Result := nil;
  770.    if (pfh = nil) or (pfh.inUse <> True) or pfh.pfe.Deleted then
  771.       raise EMMFastFileError.Create(LoadResStr(IDS_FFBADHANDLE));
  772.    if (Size > 0) then
  773.    begin
  774.       if (pos+size) > PFileEntry(PChar(pfh.pfe)+sizeOf(pfh.pfe^)).Offset then
  775.          raise EMMFastFileError.Create(LoadResStr(IDS_FFFILEEND));
  776.       Result := FPBase + pfh.pfe.offset + pos;
  777.    end;
  778. end;
  779. {-- TMMFastFile ---------------------------------------------------------}
  780. procedure TMMFastFile.FileUnlock(pfh: PFileHandle; pos, size: integer);
  781. begin
  782.    if (pfh = nil) or (pfh.inUse <> True) or pfh.pfe.Deleted then
  783.       raise EMMFastFileError.Create(LoadResStr(IDS_FFBADHANDLE));
  784.    if (size > 0) then
  785.       if (pos+size) > PFileEntry(PChar(pfh.pfe)+sizeOf(pfh.pfe^)).Offset then
  786.          raise EMMFastFileError.Create(LoadResStr(IDS_FFFILEEND));
  787. end;
  788. {-- TMMFastFile ---------------------------------------------------------}
  789. function TMMFastFile.FileRead(pfh: PFileHandle; Buffer: PChar; size: integer): integer;
  790. begin
  791.    Result := 0;
  792.    if (pfh = nil) or (pfh.inUse <> True) or pfh.pfe.Deleted then
  793.       raise EMMFastFileError.Create(LoadResStr(IDS_FFBADHANDLE));
  794.    size := Min(size,PFileEntry(PChar(pfh.pfe)+sizeOf(pfh.pfe^)).Offset - pfh.pos);
  795.    if (size > 0) then
  796.    begin
  797.       move((FPBase + pfh.pos)^, Buffer^, size);
  798.       inc(pfh.pos,size);
  799.       Result := size;
  800.    end;
  801. end;
  802. {-- TMMFastFile ---------------------------------------------------------}
  803. function TMMFastFile.FileSeek(pfh: PFileHandle; pos, origin: integer): integer;
  804. var
  805.    pfe: PFileEntry;
  806. begin
  807.    Result := -1;
  808.    if (pfh = nil) or (pfh.inUse <> True) or pfh.pfe.Deleted then
  809.       raise EMMFastFileError.Create(LoadResStr(IDS_FFBADHANDLE));
  810.    pfe := pfh.pfe;
  811.    if (origin = SEEK_SET) then
  812.    begin
  813.       if (pos < 0) or (pos >= pfh.size) then
  814.          raise EMMFastFileError.Create(LoadResStr(IDS_FFBADOFFSET));
  815.       inc(pos,pfe.offset);
  816.    end
  817.    else if (origin = SEEK_END) then
  818.    begin
  819.       if (pos < 0) or (pos >= pfh.size) then
  820.          raise EMMFastFileError.Create(LoadResStr(IDS_FFBADOFFSET));
  821.       pos := PFileEntry(PChar(pfe)+sizeOf(pfe^)).offset - pos;
  822.    end
  823.    else if (origin = SEEK_CUR) then
  824.    begin
  825.       pos := pfh.pos + pos;
  826.       if (pos < pfe.offset) or (pos >= PFileEntry(PChar(pfe)+sizeOf(pfe^)).offset) then
  827.          raise EMMFastFileError.Create(LoadResStr(IDS_FFBADOFFSET));
  828.    end
  829.    else raise EMMFastFileError.Create(LoadResStr(IDS_FFBADORIGIN));
  830.    pfh.pos := pos;
  831.    Result := pos - pfe.offset;
  832. end;
  833. end.