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

DVD

开发平台:

Delphi

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