ISO9660MicroUDFImageTree.pas
上传用户:wanyu_2000
上传日期:2021-02-21
资源大小:527k
文件大小:26k
源码类别:

DVD

开发平台:

Delphi

  1. {-----------------------------------------------------------------------------
  2.  Unit Name: ISO9660MicroUDFImageTree
  3.  Author:    Daniel Mann / Thomas Koos (original class) Dancemammal
  4.  Purpose:   Create ISO9660 Image (Structure only)
  5.  History:   Code originally from TISOlib
  6. -----------------------------------------------------------------------------}
  7. unit ISO9660MicroUDFImageTree;
  8. interface
  9. uses
  10.   SysUtils,
  11.   CovertFuncs,
  12.   Classes,
  13.   Windows,
  14.   Contnrs,
  15.   ISO9660MicroUDFClassTypes;
  16. Const
  17.        FilesPerBlock = 30; // fix for this problem
  18. type
  19.    TListSortCompare = function (Item1,Item2: Pointer): Integer;
  20. Type
  21.   TImageTree = Class;  // forward declaration
  22.   TFileEntry = Class; // forward declaration
  23.   TDataSourceFlag = (dsfFromImage, dsfFromLocal, dsfOldSession);
  24.   TEntryFlags     = (efNone, efAdded, efDeleted, efModified);
  25. TDirectoryEntry = Class
  26.   Private
  27.     Function GetDirCount: Integer;
  28.     Function GetFileCount: Integer;
  29.     Function GetDirEntry(Index: Integer): TDirectoryEntry;
  30.     Function GetFileEntry(Index: Integer): TFileEntry;
  31.   Protected
  32.     FDirID       : Integer;
  33.     FImageTree   : TImageTree;
  34.     FParent      : TDirectoryEntry;
  35.     FParentID    : Integer;
  36.     FDirectories : TObjectList;
  37.     FFiles       : TObjectList;
  38.     FSource      : TDataSourceFlag;
  39.     FFlags       : TEntryFlags;
  40.     FISOData     : TDirectoryRecord;
  41.     FRootISOData : TRootDirectoryRecord;
  42.     FName        : String;
  43.     FWideName    : PWideChar;
  44.     FBlocks      : Integer;
  45.     FLBAStart    : Integer;
  46.     LastError    : String;
  47.     Function    AddFile(AFileEntry : TFileEntry): Integer;
  48.     Function    DelFile(AFileEntry : TFileEntry): Boolean;
  49.     Function    AddDirectory(ADirEntry : TDirectoryEntry): Integer;
  50.     Function    BlockCount(Primary: Boolean): Integer;
  51.   Public
  52.     Constructor Create(AImageTree : TImageTree; AParentDir : TDirectoryEntry; Const ASource : TDataSourceFlag); Virtual;
  53.     Destructor  Destroy; Override;
  54.     Procedure   CreateLBAStart(Primary: Boolean; var Start : integer);
  55.    // Procedure   CreateLBAStart(var Start : integer);
  56.     Property    Files[Index: Integer]: TFileEntry             Read GetFileEntry;
  57.     Property    Directories[Index: Integer]: TDirectoryEntry  Read GetDirEntry;
  58.     Function    DelDirectory(ADirEntry : TDirectoryEntry): Boolean;
  59.     Function    DeleteFile(AFileEntry : TFileEntry): Boolean;
  60.     Procedure   MoveDirTo(ANewDirectory : TDirectoryEntry);
  61.     Procedure   FillISOData(Primary : Boolean);
  62.     Procedure   FillRootISOData(Primary : Boolean);
  63.     Procedure   SetupRootDirectoryLocationOfExtent(Extent : Integer);
  64.     Function    GetWideDirName : PWideChar;
  65.   Published
  66.     Property    FileCount      : Integer           Read  GetFileCount;
  67.     Property    DirectoryCount : Integer           Read  GetDirCount;
  68.     Property    Parent         : TDirectoryEntry   Read  FParent;
  69.     Property    Name           : String            Read  FName Write FName;
  70.     Property    ISOData        : TDirectoryRecord  Read  FISOData Write FISOData;
  71.     Property    RootISOData    : TRootDirectoryRecord  Read  FRootISOData Write FRootISOData;
  72.     Property    SourceOfData   : TDataSourceFlag   Read  FSource;
  73.     Property    Flags          : TEntryFlags       Read  FFlags;
  74.     Property    Blocks         : Integer           Read  FBlocks;
  75.     Property    StartLBA       : Integer           Read  FLBAStart;
  76.     Property    ParentID       : Integer           Read  FParentID  Write FParentID;
  77.     Property    DirID          : Integer           Read  FDirID  Write FDirID;
  78.   End;
  79. TFileEntry = Class
  80.   Private
  81.     Function    GetFullPath: String;
  82.   Protected
  83.     FDirectory   : TDirectoryEntry;
  84.     FName        : String;
  85.     FWideName    : PWideChar;
  86.     FSource      : TDataSourceFlag;
  87.     FFlags       : TEntryFlags;
  88.     FISOData     : TDirectoryRecord;
  89.     FSourceFile  : String;
  90.     FSourceBlockSize : Integer;
  91.     LastError    : String;
  92.     FLBAStart    : Integer;
  93.     Function    GetCDFSSize(FileSize : Integer) : Integer;
  94.   Public
  95.     Constructor Create(ADirectoryEntry : TDirectoryEntry; Const ASource : TDataSourceFlag); Virtual;
  96.     Destructor  Destroy; Override;
  97.     Procedure   MoveTo(ANewDirectoryEntry: TDirectoryEntry);
  98.     Procedure   FillISOData(Primary : Boolean);
  99.     Procedure   CreateLBAStart( var StartBlock : integer);
  100.     Function    GetWideFileName : PWideChar;
  101.   Published
  102.     Property    Name            : String              Read  FName  Write FName;
  103.     Property    Path            : String              Read  GetFullPath;
  104.       // ISO Data
  105.     Property    ISOData         : TDirectoryRecord    Read  FISOData Write FISOData;
  106.     Property    SourceOfData    : TDataSourceFlag     Read  FSource;
  107.     Property    Flags           : TEntryFlags         Read  FFlags;
  108.     Property    SourceFileName  : String              Read  FSourceFile Write FSourceFile;
  109.     Property    BlockSize       : Integer             Read  FSourceBlockSize;
  110.     Property    StartLBA        : Integer             Read  FLBAStart;
  111.   End;
  112. TImageTree = Class
  113.   Private
  114.   Protected
  115.     FRootDir : TDirectoryEntry;
  116.     FLittleEndianPathTable : TList;
  117.     FPathTableCount : Integer;
  118.     FCurrentPathTableCount : Integer;
  119.     FPathTableStopSector : Integer;
  120.     FFileBlocks : Integer;
  121.     LastError : String;
  122.     FFileStartBlock : Integer;
  123.     FJolietOffsett : Integer;
  124.     FDirectoryStartLBA : Integer;
  125.     FTotalFileCount : Integer;
  126.     FTotalDirCount : Integer;
  127.     Procedure AddDirectory(CurrentDir : TDirectoryEntry ; Parent : Integer);
  128.     Procedure RecurseFiles(CurrentDir : TDirectoryEntry);
  129.     Procedure RecurseCount(CurrentDir : TDirectoryEntry);
  130.     Procedure ScanAllDirectories(CurrentDir : TDirectoryEntry ; Parent : Integer);
  131.     Procedure ClearPathTables;
  132.     Function GetPathTableLength : Integer;
  133.     Function GetJolietPathTableLength : Integer;
  134.     Function GetTableCount : Integer;
  135.   Public
  136.     CurrentLBA : Integer;
  137.     FileLBA    : Integer;
  138.     Constructor Create; Virtual;
  139.     Destructor  Destroy; Override;
  140.     Procedure   RefreshPathTables(StartLBA, FileBlock : Integer);
  141.     procedure   SortDirectories;
  142.     Function    GetLastError : String;
  143.     Procedure   ResetAllCounts;
  144.   Published
  145.     Property    RootDirectory : TDirectoryEntry   Read  fRootDir;
  146.     Property    LittleEndianPathTable : TList   Read  FLittleEndianPathTable;
  147.     Property    PathTableCount : Integer Read GetTableCount;
  148.     Property    PathTableStopSector : Integer Read FPathTableStopSector;
  149.     Property    FileBlocks : Integer Read FFileBlocks;
  150.     Property    FileStartBlock : Integer Read FFileStartBlock;
  151.     Property    PathTableLength : Integer Read GetPathTableLength;
  152.     Property    JolietPathTableLength : Integer Read GetJolietPathTableLength;
  153.     Property    JolietOffsett : Integer Read FJolietOffsett write FJolietOffsett;
  154.     Property    DIRStartLBA : Integer Read FDirectoryStartLBA write FDirectoryStartLBA;
  155.     Property    TotalFileCount : Integer read FTotalFileCount;
  156.     Property    TotalDirCount : Integer read FTotalDirCount;
  157.   End;
  158. implementation
  159. { TDirectoryEntry }
  160. Function TDirectoryEntry.AddDirectory(ADirEntry: TDirectoryEntry): Integer;
  161. Begin
  162.   If ( FDirectories.IndexOf(ADirEntry) > -1 ) Then  LastError := ('Directory entry already added');
  163.   If ( Assigned(ADirEntry.FParent) ) And ( ADirEntry.FParent <> Self ) Then
  164.        LastError := ('Directory entry already added - use MoveDirTo() instead!');
  165.   Assert(ADirEntry.FParent = Self, 'Assertion: directory entry on AddDirectory() has different parent directory');
  166.   Result := FDirectories.Add(ADirEntry);
  167. End;
  168. Function TDirectoryEntry.AddFile(AFileEntry: TFileEntry): Integer;
  169. Begin
  170.   If ( fFiles.IndexOf(AFileEntry) > -1 ) Then
  171.     LastError := ('File entry already added');
  172.   If ( Assigned(AFileEntry.FDirectory) ) And
  173.      ( AFileEntry.FDirectory <> Self ) Then
  174.     LastError := ('File entry already listed in different directory');
  175.   Assert(AFileEntry.FDirectory <> Nil, 'Assertion: file entry on AddFile() has no directory assigned');
  176.   Result := FFiles.Add(AFileEntry);
  177. End;
  178. Constructor TDirectoryEntry.Create(AImageTree: TImageTree; AParentDir : TDirectoryEntry; Const ASource : TDataSourceFlag);
  179. Begin
  180.   Inherited Create;
  181.   FImageTree   := AImageTree;
  182.   FParent      := AParentDir;
  183.   FFiles       := TObjectList.Create(True);
  184.   FDirectories := TObjectList.Create(True);
  185.   If Assigned(FParent) Then FParent.AddDirectory(Self);
  186.   FSource      := ASource;
  187.   FFlags       := efNone;
  188.   FBlocks      := 0;
  189. End;
  190. Procedure TDirectoryEntry.SetupRootDirectoryLocationOfExtent(Extent : Integer);
  191. begin
  192.   FRootISOData.LocationOfExtent := BuildBothEndianDWord(Extent);
  193. end;
  194. Function TDirectoryEntry.GetWideDirName : PWideChar;
  195. begin
  196.    Result := FWideName;
  197. end;
  198. Procedure TDirectoryEntry.FillISOData(Primary : Boolean);
  199. var
  200.         RecordSize : Integer;
  201. Begin
  202.    FWideName := StrToUnicode(fName);
  203. if Primary = True then
  204.   With FISOData Do
  205.   Begin
  206.     RecordSize                    := sizeof(FISOData) + Length(fName);  // make record size even
  207.     if (RecordSize mod 2) > 0 then inc(RecordSize);
  208.     LengthOfDirectoryRecord       := RecordSize;
  209.     DataLength.LittleEndian       := 2048;
  210.     DataLength.BigEndian          := SwapDWord(DataLength.LittleEndian);
  211.     RecordingDateAndTime          := BuildDirectoryDateTime(NOW,0);
  212.     VolumeSequenceNumber.LittleEndian  := 1;
  213.     VolumeSequenceNumber.BigEndian  := SwapWord(VolumeSequenceNumber.LittleEndian);
  214.     FileFlags                     := $02;      // directory
  215.     LengthOfFileIdentifier        := Length(fName);
  216.     FileUnitSize                  := 0;
  217.     InterleaveGapSize             := 0;
  218.     LocationOfExtent              := BuildBothEndianDWord(FLBAStart);
  219.   End
  220.   else
  221.   With FISOData Do
  222.   Begin
  223.     RecordSize                    := sizeof(FISOData) + (Length(fName)* 2);  // make record size even
  224.     if (RecordSize mod 2) > 0 then inc(RecordSize);
  225.     LengthOfDirectoryRecord       := RecordSize;
  226.     DataLength.LittleEndian       := 2048;
  227.     DataLength.BigEndian          := SwapDWord(DataLength.LittleEndian);
  228.     RecordingDateAndTime          := BuildDirectoryDateTime(NOW,0);
  229.     VolumeSequenceNumber.LittleEndian  := 1;
  230.     VolumeSequenceNumber.BigEndian  := SwapWord(VolumeSequenceNumber.LittleEndian);
  231.     FileFlags                     := $02;      // directory
  232.     LengthOfFileIdentifier        := Length(fName)* 2;
  233.     FileUnitSize                  := 0;
  234.     InterleaveGapSize             := 0;
  235.     LocationOfExtent              := BuildBothEndianDWord(FLBAStart);
  236.   End
  237. End;
  238. Procedure TDirectoryEntry.FillRootISOData(Primary : Boolean);
  239. var
  240.         RecordSize : Integer;
  241. Begin
  242.    FWideName := StrToUnicode(fName);
  243. if Primary = True then
  244.   With FRootISOData Do
  245.   Begin
  246.     RecordSize                    := sizeof(FRootISOData);  // make record size even
  247.     if (RecordSize mod 2) > 0 then inc(RecordSize);
  248.     LengthOfDirectoryRecord       := RecordSize;
  249.     DataLength.LittleEndian       := 2048;
  250.     DataLength.BigEndian          := SwapDWord(DataLength.LittleEndian);
  251.     RecordingDateAndTime          := BuildDirectoryDateTime(NOW,0);
  252.     VolumeSequenceNumber.LittleEndian  := 1;
  253.     VolumeSequenceNumber.BigEndian  := SwapWord(VolumeSequenceNumber.LittleEndian);
  254.     FileFlags                     := $02;      // directory
  255.     LengthOfFileIdentifier        := 1;
  256.     FileUnitSize                  := 0;
  257.     InterleaveGapSize             := 0;
  258.     LocationOfExtent.LittleEndian := FLBAStart;
  259.     LocationOfExtent.BigEndian    := SwapDWord(LocationOfExtent.LittleEndian);
  260.     FileIdentifier                := 0;
  261.   End
  262.   else
  263.   With FRootISOData Do
  264.   Begin
  265.     RecordSize                    := sizeof(FRootISOData);  // make record size even
  266.     if (RecordSize mod 2) > 0 then inc(RecordSize);
  267.     LengthOfDirectoryRecord       := RecordSize;
  268.     DataLength.LittleEndian       := 2048;
  269.     DataLength.BigEndian          := SwapDWord(DataLength.LittleEndian);
  270.     RecordingDateAndTime          := BuildDirectoryDateTime(NOW,0);
  271.     VolumeSequenceNumber.LittleEndian  := 1;
  272.     VolumeSequenceNumber.BigEndian  := SwapDWord(VolumeSequenceNumber.LittleEndian);
  273.     FileFlags                     := $02;      // directory
  274.     LengthOfFileIdentifier        := 1;
  275.     FileUnitSize                  := 0;
  276.     InterleaveGapSize             := 0;
  277.     LocationOfExtent.LittleEndian := FLBAStart;
  278.     LocationOfExtent.BigEndian    := SwapDWord(LocationOfExtent.LittleEndian);
  279.     FileIdentifier                := 0;
  280.   End
  281. End;
  282. {Fix provided by Esteban : Thanks}
  283. Function TDirectoryEntry.BlockCount(Primary: Boolean): Integer;
  284.  var  Index : Integer;
  285.       iBytes : Integer;
  286.       Bytes : Extended;
  287.       MyFName : String;
  288.       MyFilename : String;
  289.       MyFileNameSize : Integer;
  290. Begin
  291.   Bytes := 0;
  292.   for Index := 0 to (FileCount - 1) do
  293.    begin
  294.    MyFName := ExtractFileName(GetFileEntry(Index).SourceFileName);
  295.    MyFilename := MyFName + ';1';
  296.    MyFileNameSize := Length(MyFilename);
  297.    MyFName := GetISOFilename(MyFName);
  298.   if (Primary = True) then
  299.    iBytes := sizeof(TDirectoryrecord) + Length(MyFName)
  300.   else
  301.    iBytes := sizeof(TDirectoryrecord) + (MyFileNameSize*2);
  302.   if (iBytes mod 2) > 0 then iBytes := iBytes + 1;
  303.   Bytes := Bytes + iBytes;
  304.   end;
  305.   for Index := 0 to (DirectoryCount - 1) do
  306.   begin
  307.      iBytes := sizeof(TDirectoryrecord) + Length(GetDirEntry(Index).Name);
  308.      if (Primary = False) then iBytes := iBytes + Length(GetDirEntry(Index).Name);
  309.      if (iBytes mod 2) > 0 then iBytes := iBytes + 1;
  310.      Bytes := Bytes + iBytes;
  311.   end;
  312.   Bytes := Bytes + 68; // Por los . y ..
  313.   Result := RoundUp(Bytes / 2048);
  314. End;
  315. {Procedure TDirectoryEntry.CreateLBAStart( var Start : integer);
  316. begin
  317.     FBlocks := RoundUp(GetFileCount / FilesPerBlock);
  318.     if FBlocks < 1 then FBlocks := 1;
  319.     Start := Start + FBlocks;
  320.     FLBAStart := Start;
  321. end;}
  322. {Fix provided by Esteban : Thanks}
  323. Procedure TDirectoryEntry.CreateLBAStart(Primary : Boolean ; var Start : integer);
  324. begin
  325.   FBlocks := BlockCount(Primary);
  326.   if FBlocks < 1 then FBlocks := 1;
  327.   Start := Start + FBlocks;
  328.   FLBAStart := Start;
  329. end;
  330. Function TDirectoryEntry.DelDirectory(ADirEntry: TDirectoryEntry): Boolean;
  331. Begin
  332.   Result := False;
  333.   If ( FDirectories.IndexOf(ADirEntry) = -1 ) Then Exit;
  334.   FDirectories.Extract(ADirEntry);
  335.   ADirEntry.FParent := Nil;
  336.   Result := True;
  337. End;
  338. Function TDirectoryEntry.DelFile(AFileEntry: TFileEntry): Boolean;
  339. Begin
  340.   Result := False;
  341.   If ( FFiles.IndexOf(AFileEntry) = -1 ) Then Exit;
  342.   FFiles.Extract(AFileEntry);
  343.   AFileEntry.fDirectory := Nil;
  344.   Result := True;
  345. End;
  346. Function TDirectoryEntry.DeleteFile(AFileEntry: TFileEntry): Boolean;
  347. Begin
  348.   Result := False;
  349.   If ( FFiles.IndexOf(AFileEntry) = -1 ) Then Exit;
  350.   FFiles.Extract(AFileEntry);
  351.   AFileEntry.fDirectory := Nil;
  352.   Result := True;
  353. End;
  354. Destructor TDirectoryEntry.Destroy;
  355. Begin
  356.   If ( Assigned(FFiles) ) Then FreeAndNil(FFiles);
  357.   If ( Assigned(FDirectories) ) Then FreeAndNil(FDirectories);
  358.   Inherited;
  359. End;
  360. Function TDirectoryEntry.GetDirCount: Integer;
  361. Begin
  362.   If ( Assigned(FDirectories) ) Then
  363.     Result := FDirectories.Count
  364.   Else
  365.     Result := 0;
  366. End;
  367. Function TDirectoryEntry.GetDirEntry(Index: Integer): TDirectoryEntry;
  368. Begin
  369.   Result := FDirectories[Index] As TDirectoryEntry;
  370. End;
  371. Function TDirectoryEntry.GetFileCount: Integer;
  372. Begin
  373.   If ( Assigned(FFiles) ) Then
  374.     Result := FFiles.Count
  375.   Else
  376.     Result := 0;
  377. End;
  378. Function TDirectoryEntry.GetFileEntry(Index: Integer): TFileEntry;
  379. Begin
  380.   Result := FFiles[Index] As TFileEntry;
  381. End;
  382. Procedure TDirectoryEntry.MoveDirTo(ANewDirectory: TDirectoryEntry);
  383. Begin
  384.   If ( Self = ANewDirectory ) Then
  385.     LastError := ('can not move directory to itself');
  386.   If ( fParent = ANewDirectory ) Then
  387.   Begin
  388.     Assert(False, 'senseless move of directory');
  389.     Exit;
  390.   End;
  391.   FParent.DelDirectory(Self);
  392.   FParent := ANewDirectory;
  393.   ANewDirectory.AddDirectory(Self);
  394. End;
  395. { TFileEntry }
  396. Constructor TFileEntry.Create(ADirectoryEntry: TDirectoryEntry; Const ASource : TDataSourceFlag);
  397. Begin
  398.   Inherited Create;
  399.   FSource     := ASource;
  400.   FSourceFile := '';
  401.   FDirectory  := ADirectoryEntry;
  402.   FDirectory.AddFile(Self);
  403.   FFlags      := efNone;
  404.   FSourceBlockSize := GetCDFSSize(RetrieveFileSize(fSourceFile));
  405. End;
  406. Destructor TFileEntry.Destroy;
  407. Begin
  408.   Inherited;
  409. End;
  410. Function TFileEntry.GetCDFSSize(FileSize : Integer):Integer;
  411. var
  412.      ResLength : Integer;
  413. begin
  414.     ResLength := 1;
  415.     if FileSize > 2048 then
  416.     begin
  417.       ResLength := FileSize div 2048;
  418.       if FileSize mod 2048 > 0 then ResLength := ResLength + 1;
  419.     end;
  420.     result := ResLength;
  421. end;
  422. Procedure TFileEntry.CreateLBAStart( var StartBlock : integer);
  423. begin
  424.     FLBAStart := StartBlock;
  425.     StartBlock := StartBlock + GetCDFSSize(RetrieveFileSize(fSourceFile));
  426. end;
  427. Function TFileEntry.GetWideFileName : PWideChar;
  428. begin
  429.    Result := FWideName;
  430. end;
  431. Procedure TFileEntry.FillISOData(Primary : Boolean);
  432. var
  433.         RecordSize : Integer;
  434.         FileNameSize : Integer;
  435.         Filename : String;
  436. Begin
  437.   If ( FSource <> dsfFromLocal ) Then
  438.      LastError := ('Can not fill ISO structure, Not a local file entry');
  439.   FName := ExtractFileName(FSourceFile);
  440.   Filename := FName + ';1';
  441.   FileNameSize := Length(Filename);
  442.   FWideName := StrToUnicode(Filename);
  443.   fName := GetISOFilename(fname);
  444. if Primary = True then
  445.   With FISOData Do
  446.   Begin
  447.     RecordSize                          := sizeof(FISOData) + Length(fName);
  448.     if (RecordSize mod 2) >0 then inc(RecordSize);
  449.     LengthOfDirectoryRecord             := RecordSize;
  450.     DataLength.LittleEndian             := RetrieveFileSize(fSourceFile);
  451.     DataLength.BigEndian                := SwapDWord(DataLength.LittleEndian);
  452.     RecordingDateAndTime                := BuildDirectoryDateTime(NOW,0);
  453.     VolumeSequenceNumber.LittleEndian   := 1;
  454.     VolumeSequenceNumber.BigEndian      := SwapWord(VolumeSequenceNumber.LittleEndian);
  455.     FileFlags                           := $00; //File
  456.     LengthOfFileIdentifier              := Length(fName);
  457.     FileUnitSize                        := 0;
  458.     InterleaveGapSize                   := 0;
  459.     LocationOfExtent.LittleEndian       := FLBAStart;
  460.     LocationOfExtent.BigEndian          := SwapDWord(LocationOfExtent.LittleEndian);
  461.   End
  462.    else
  463.   With FISOData Do
  464.   Begin
  465.     RecordSize                          := sizeof(FISOData) + (FileNameSize * 2);
  466.     if (RecordSize mod 2) >0 then inc(RecordSize);
  467.     LengthOfDirectoryRecord             := RecordSize;
  468.     DataLength.LittleEndian             := RetrieveFileSize(fSourceFile);
  469.     DataLength.BigEndian                := SwapDWord(DataLength.LittleEndian);
  470.     RecordingDateAndTime                := BuildDirectoryDateTime(NOW,0);
  471.     VolumeSequenceNumber.LittleEndian   := 1;
  472.     VolumeSequenceNumber.BigEndian      := SwapWord(VolumeSequenceNumber.LittleEndian);
  473.     FileFlags                           := $00; //File
  474.     LengthOfFileIdentifier              := (FileNameSize * 2);
  475.     FileUnitSize                        := 0;
  476.     InterleaveGapSize                   := 0;
  477.     LocationOfExtent.LittleEndian       := FLBAStart;
  478.     LocationOfExtent.BigEndian          := SwapDWord(LocationOfExtent.LittleEndian);
  479.   End;
  480. End;
  481. Function TFileEntry.GetFullPath: String;
  482. Var
  483.   ADir : TDirectoryEntry;
  484. Begin
  485.   ADir := fDirectory;
  486.   Result := '';
  487.   While ( Assigned(ADir) ) Do
  488.   Begin
  489.     Result := ADir.Name + '/' + Result;
  490.     ADir   := ADir.Parent;
  491.   End;
  492. End;
  493. Procedure TFileEntry.MoveTo(ANewDirectoryEntry: TDirectoryEntry);
  494. Begin
  495.   fDirectory.DelFile(Self);
  496.   fDirectory := ANewDirectoryEntry;
  497.   ANewDirectoryEntry.AddFile(Self);
  498. End;
  499. { TImageTree }
  500. Constructor TImageTree.Create;
  501. Begin
  502.   Inherited Create;
  503.   FFileBlocks := 0;
  504.   FTotalFileCount := 0;
  505.   FTotalDirCount  := 0;
  506.   FLittleEndianPathTable := TList.create;
  507.   FRootDir := TDirectoryEntry.Create(Self, Nil, dsfFromImage);
  508.   FRootDir.FName := char(0);
  509. End;
  510. Destructor TImageTree.Destroy;
  511. Begin
  512.   ClearPathTables;
  513.   If ( Assigned(FLittleEndianPathTable) ) Then FLittleEndianPathTable.Free;
  514.   If ( Assigned(fRootDir) ) Then FreeAndNil(fRootDir);
  515.   Inherited;
  516. End;
  517. Procedure TImageTree.ClearPathTables;
  518. Var
  519.    Index : Integer;
  520.    PathRec : PPathTableRecord;
  521. begin
  522.    FFileBlocks := 0;
  523.    if FLittleEndianPathTable.Count = 0 then exit;
  524. //   for Index := 0 to (FLittleEndianPathTable.Count - 1) do   //changed to fix AV error 
  525.    For Index := (FLittleEndianPathTable.Count - 1) downto 0 do
  526.    begin
  527.        PathRec := FLittleEndianPathTable.Items[Index];
  528.      try
  529.        if PathRec <> nil then
  530.             Dispose(PathRec);
  531.      except
  532.      end;
  533.       FLittleEndianPathTable.Delete(Index);
  534.    end;
  535.   FLittleEndianPathTable.Pack;
  536. end;
  537. Function TImageTree.GetPathTableLength : Integer;
  538. var
  539.      TableSize : Integer;
  540.      Index,SubSize : Integer;
  541.      PathRec : PPathTableRecord;
  542. begin
  543.    TableSize := 0;
  544.    for Index := 0 to FLittleEndianPathTable.Count - 1 do
  545.    begin
  546.      PathRec := FLittleEndianPathTable.Items[Index];
  547.      SubSize := PathRec^.LengthOfPathRecord;
  548.      TableSize := TableSize + SubSize;
  549.    end;
  550.    Result := TableSize;
  551. end;
  552. Function TImageTree.GetJolietPathTableLength : Integer;
  553. var
  554.      TableSize : Integer;
  555.      Index,SubSize : Integer;
  556.      PathRec : PPathTableRecord;
  557. begin
  558.    TableSize := 0;
  559.    for Index := 0 to FLittleEndianPathTable.Count - 1 do
  560.    begin
  561.      PathRec := FLittleEndianPathTable.Items[Index];
  562.      SubSize := PathRec^.LengthOfPathRecordM;
  563.      TableSize := TableSize + SubSize;
  564.    end;
  565.    Result := TableSize;
  566. end;
  567. Procedure TImageTree.RecurseFiles(CurrentDir : TDirectoryEntry);
  568. var
  569.      Index : Integer;
  570. begin
  571.     for Index := 0 to CurrentDir.FileCount -1 do
  572.     begin
  573.        CurrentDir.GetFileEntry(Index).CreateLBAStart(FileLBA);
  574.        FFileBlocks := FFileBlocks + CurrentDir.GetFileEntry(Index).BlockSize;
  575.     end;
  576. end;
  577. procedure TImageTree.SortDirectories;
  578. var
  579.    NoExchanges : boolean;
  580.    Index : Integer;
  581.    PathRec1,PathRec2 : PPathTableRecord;
  582. begin
  583. Repeat
  584. NoExchanges := true;
  585. For Index := 0 to FLittleEndianPathTable.Count -2 do
  586. begin
  587.                      PathRec1 := FLittleEndianPathTable.Items[index];
  588.                      PathRec2 := FLittleEndianPathTable.Items[index+1];
  589. if (PathRec1^.ParentDirectoryNumber > PathRec2^.ParentDirectoryNumber) then
  590. begin //we have to switch.
  591.                             NoExchanges := False; //We have to tell the sort we aren't done.
  592.                             FLittleEndianPathTable.Exchange(Index,Index+1);
  593. end;
  594. end;
  595. Until NoExchanges;
  596. end;
  597. Procedure TImageTree.AddDirectory(CurrentDir : TDirectoryEntry ; Parent : Integer);
  598. var
  599.      PathRecL : PPathTableRecord;
  600.      Temp : String;
  601.      WideChr : PWideChar;
  602.      Size : Integer;
  603. begin
  604.    CurrentDir.CreateLBAStart(True,CurrentLBA);
  605.    RecurseFiles(CurrentDir);
  606.    // do little endian list first
  607.    New(PathRecL);
  608.    FillChar(PathRecL^,sizeof(PathRecL^),$00);
  609.    PathRecL^.ParentDirectoryNumber := Parent;
  610.    PathRecL^.LengthOfDirectoryIdentifier := Length(CurrentDir.Name);
  611.    if (PathRecL^.LengthOfDirectoryIdentifier mod 2) > 0 then inc(PathRecL^.LengthOfDirectoryIdentifier);
  612.    StrPCopy(PathRecL^.DirectoryIdentifier,Copy(CurrentDir.Name, 1, Length(CurrentDir.Name)));
  613.    PathRecL^.LocationOfExtent := CurrentDir.StartLBA;
  614.    PathRecL^.LengthOfPathRecord := (8 + PathRecL^.LengthOfDirectoryIdentifier);
  615.    //do big endian list
  616.    Temp := CurrentDir.Name;
  617.    Size := (length(temp)+1)*2;
  618.    WideChr:= PWideChar(StrAlloc(Size));//important
  619.    StringToWideChar(temp,WideChr,Size + 1);
  620.    FillChar(PathRecL^.DirectoryIdentifierM,128,0);
  621.    CopyMemory(@PathRecL^.DirectoryIdentifierM[1],@WideChr[0],(length(Temp)*2)-1);//makes it big endian wide char
  622.    if Length(CurrentDir.Name) = 1 then
  623.         PathRecL^.LengthOfDirectoryIdentifierM := 1
  624.          else
  625.              PathRecL^.LengthOfDirectoryIdentifierM := Length(CurrentDir.Name)*2;
  626.    if (PathRecL^.LengthOfDirectoryIdentifierM mod 2) > 0 then inc(PathRecL^.LengthOfDirectoryIdentifierM);
  627.    PathRecL^.LocationOfExtentM := SwapDWord(CurrentDir.StartLBA);
  628.    PathRecL^.LengthOfPathRecordM := (8 + PathRecL^.LengthOfDirectoryIdentifierM);
  629.  // add to list
  630.    FLittleEndianPathTable.Add(PathRecL);
  631. end;
  632. Procedure TImageTree.RecurseCount(CurrentDir : TDirectoryEntry);
  633. var
  634.      Index : Integer;
  635. begin
  636.    Inc(FTotalDirCount);
  637.    Inc(FTotalFileCount,CurrentDir.GetFileCount);
  638.    For Index := 0 to CurrentDir.GetDirCount -1 do
  639.             RecurseCount(CurrentDir.GetDirEntry(Index));
  640. end;
  641. Procedure TImageTree.ResetAllCounts;
  642. begin
  643.    FTotalDirCount := 0;
  644.    FTotalFileCount := 0;
  645.    RecurseCount(RootDirectory);
  646. end;
  647. Procedure TImageTree.ScanAllDirectories(CurrentDir : TDirectoryEntry ; Parent : Integer);
  648. var
  649.      Index : Integer;
  650. begin
  651.    For Index := 0 to CurrentDir.GetDirCount -1 do
  652.    begin
  653.        AddDirectory(CurrentDir.GetDirEntry(Index),Parent);   // add to list under parent
  654.        if CurrentDir.GetDirEntry(Index).GetDirCount > 0 then
  655.           ScanAllDirectories(CurrentDir.GetDirEntry(Index),Parent +1);
  656.    end;
  657. end;
  658. Procedure TImageTree.RefreshPathTables(StartLBA, FileBlock : Integer);
  659. begin
  660.    if not Assigned(fRootDir) then Exit;
  661.    ClearPathTables;           // Clear all remaining path tables
  662.    CurrentLBA := StartLBA;          // setup start Logical Block Address
  663.    FDirectoryStartLBA := StartLBA;
  664.    FileLBA := FileBlock;
  665.    FFileStartBlock := FileLBA;
  666.    AddDirectory(FRootDir,1);   // Start With Root Directory
  667.    ScanAllDirectories(FRootDir,1);
  668.    FPathTableStopSector := CurrentLBA;
  669.    FJolietOffsett := CurrentLBA;
  670. end;
  671. Function TImageTree.GetTableCount : Integer;
  672. begin
  673.     Result := FLittleEndianPathTable.Count;
  674. end;
  675. Function TImageTree.GetLastError : String;
  676. begin
  677.     Result := LastError;
  678. end;
  679. end.