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

DVD

开发平台:

Delphi

  1. {-----------------------------------------------------------------------------
  2.  Unit Name: DVDImage
  3.  Author:    Paul Fisher / Andrew Semack
  4.  Purpose:  Class for the creation of DVD Video Images
  5.  History:  ISO9660 plus UDF Micro Bridge
  6. -----------------------------------------------------------------------------}
  7. unit DVDImage;
  8. interface
  9. uses
  10.   CustomImage, Math, CovertFuncs, SysUtils, windows, ComCtrls, Classes,
  11.     DeviceTypes,
  12.   ISO9660MicroUDFClassTypes, ISO9660MicroUDFBootClass, ISO9660MicroUDFPrimaryVolClass,
  13.     ISO9660MicroUDFSupplementVolClass,
  14.   ISO9660MicroUDFstreamHandler, ISO9660MicroUDFImageTree,MicroUDFClassTypes,
  15.   PopulateMicroUDFRecords,MicroUDFConsts;
  16. const
  17.   DVDAudioDir = 'AUDIO_TS';
  18.   DVDVideoDir = 'VIDEO_TS';
  19. type
  20.   TDVDImage = class(TCustomImage)
  21.   private
  22.     FOnDVDStatus: TCDStatusEvent;
  23.     FFileName: string;
  24.     FVolID: string;
  25.     procedure GetImageData(const ALength: Cardinal);
  26.   protected
  27.     FImage: TImageStreamHandler;
  28.     FISOHeader: TISOHeader;
  29.     FBRClass: TBootRecordVolumeDescriptor;
  30.     FPVDClass: TPrimaryVolumeDescriptor;
  31.     FSVDClass: TSupplementaryVolumeDescriptor;
  32.     FVDSTClass: TVolumeDescriptorSetTerminator;
  33.     // DVD VIDEO UDF Records
  34.     FUDFBEA01 : UDF_BeginningExtendedAreaDesc;
  35.     FUDFNSR02 : UDF_NSRDescriptor;
  36.     FUDFTEA01 : UDF_TerminatingExtendedAreaDesc;
  37.     FUDF_PVD  : UDF_PrimaryVolumeDescriptor;
  38.     FUDF_IUVD : UDF_ImplementationUseVolumeDescriptor;
  39.     FUDF_PD   : UDF_PartitionDescriptor;
  40.     FUDF_LVD  : UDF_logicalVolDesc;
  41.     FUDF_USD  : UDF_UnallocSpaceDesc;
  42.     FUDF_TD   : UDF_TerminatingDesc;
  43.     FUDF_AVDP : UDF_AnchorVolumeDescriptorPointer;
  44.     FUDF_FSD  : UDF_FileSetDescriptor;
  45.     FUDF_LVID : UDF_logicalVolumeIntegrityDesc;
  46.     FTree: TImageTree;
  47.     procedure SetVolID(VolName: string);
  48.     procedure CreateVolumeDescriptors;
  49.     Procedure CreateUDFDescriptors;
  50.     procedure Log(const AFunction, AMessage: string);
  51.     function ParseDirectory(const AUsePrimaryVD: Boolean = True): Boolean;
  52.     function ParseDirectorySub(AParentDir: TDirectoryEntry; const AFileName:
  53.       string; var ADirectoryEntry: PDirectoryRecord): Boolean;
  54.     procedure WriteStructureTree(Primary: Boolean; ISOStream:
  55.       TImageStreamHandler; ADirEntry: TDirectoryEntry);
  56.     procedure WriteRootStructureTree(Primary: Boolean; ISOStream:
  57.       TImageStreamHandler; ADirEntry: TDirectoryEntry);
  58.     procedure WriteFileData(ISOStream: TImageStreamHandler; ADirEntry:
  59.       TDirectoryEntry);
  60.     procedure WritePathTableData(ISOStream: TImageStreamHandler; CurrentPointer:
  61.       Integer);
  62.     procedure WriteJolietPathTableData(ISOStream: TImageStreamHandler;
  63.       CurrentPointer: Integer);
  64.     // UDF File Structure, what a cock!
  65.     procedure WriteUDFRootStructureTree(ISOStream: TImageStreamHandler; ADirEntry: TDirectoryEntry);
  66.   public
  67.     constructor Create;
  68.     destructor Destroy; override;
  69.     function SaveDVDImageToDisk: Boolean;
  70.     function ParsePathTable(ATreeView: TTreeView = nil): Boolean;
  71.     function ExtractFile(const AFileEntry: TFileEntry; const AFileName: string):
  72.       Boolean;
  73.     function CloseImage: Boolean;
  74.   published
  75.     property OnDVDStatus: TCDStatusEvent read FOnDVDStatus write FOnDVDStatus;
  76.     property Filename: string read FFileName write FFileName;
  77.     property Structure: TImageTree read FTree;
  78.     property Volume_ID: string read FVolID write SetVolID;
  79.     property BootRecordVolumeDescriptor: TBootRecordVolumeDescriptor read
  80.       FBRClass write FBRClass;
  81.     property PrimaryVolumeDescriptor: TPrimaryVolumeDescriptor read FPVDClass
  82.       write FPVDClass;
  83.     property SupplementaryVolumeDescriptor: TSupplementaryVolumeDescriptor read
  84.       FSVDClass write FSVDClass;
  85.   end;
  86. implementation
  87. constructor TDVDImage.Create;
  88. begin
  89.   inherited Create;
  90.   FFileName := '';
  91.   FImage := nil;
  92.   FPVDClass := nil;
  93.   FSVDClass := nil;
  94.   FBRClass := nil;
  95.   ImageType := IT9660Image;
  96.   FTree := TImageTree.Create;
  97.   CreateVolumeDescriptors; // does this need to be moved ??
  98. end;
  99. destructor TDVDImage.Destroy;
  100. begin
  101.   if (Assigned(FTree)) then
  102.     FreeAndNil(FTree);
  103.   if (Assigned(FImage)) then
  104.     FreeAndNil(FImage);
  105.   if (Assigned(FPVDClass)) then
  106.     FreeAndNil(FPVDClass);
  107.   if (Assigned(FSVDClass)) then
  108.     FreeAndNil(FSVDClass);
  109.   if (Assigned(FBRClass)) then
  110.     FreeAndNil(FBRClass);
  111.   inherited;
  112. end;
  113. function TDVDImage.CloseImage: Boolean;
  114. begin
  115.   FFileName := '';
  116.   if Assigned(FImage) then
  117.     FreeAndNil(FImage);
  118.   if Assigned(FPVDClass) then
  119.     FreeAndNil(FPVDClass);
  120.   if Assigned(FSVDClass) then
  121.     FreeAndNil(FSVDClass);
  122.   if Assigned(FBRClass) then
  123.     FreeAndNil(FBRClass);
  124.   if Assigned(FTree) then
  125.     FreeAndNil(FTree);
  126.   Result := True;
  127. end;
  128. procedure TDVDImage.SetVolID(VolName: string);
  129. begin
  130.   FVolID := VolName;
  131.   if (Assigned(fPVDClass)) then
  132.       fPVDClass.VolumeIdentifier := VolName;
  133.   if (Assigned(fSVDClass)) then
  134.       fSVDClass.VolumeIdentifier := VolName;
  135. end;
  136. procedure TDVDImage.GetImageData(const ALength: Cardinal);
  137. var
  138.   OrgPtr,
  139.     Buffer: PByte;
  140.   Row: Cardinal;
  141.   Col: Word;
  142.   CharStr,
  143.     DumpStr: string;
  144. begin
  145.   GetMem(Buffer, ALength);
  146.   OrgPtr := Buffer;
  147.   try
  148.     FImage.Stream.ReadBuffer(Buffer^, ALength);
  149.     for Row := 0 to ((ALength - 1) div 16) do
  150.     begin
  151.       DumpStr := IntToHex(Cardinal(fImage.Stream.Position) - ALength + Row * 16,
  152.         8) + 'h | ';
  153.       CharStr := '';
  154.       for Col := 0 to Min(16, ALength - (Row + 1) * 16) do
  155.       begin
  156.         DumpStr := DumpStr + IntToHex(Buffer^, 2) + ' ';
  157.         if (Buffer^ > 32) then
  158.           CharStr := CharStr + Chr(Buffer^)
  159.         else
  160.           CharStr := CharStr + ' ';
  161.         Inc(Buffer);
  162.       end;
  163.       DumpStr := DumpStr + StringOfChar(' ', 61 - Length(DumpStr)) + '| ' +
  164.         CharStr;
  165.       Log('Dump', DumpStr);
  166.     end;
  167.   finally
  168.     FreeMem(OrgPtr, ALength);
  169.   end;
  170. end;
  171. function TDVDImage.ExtractFile(const AFileEntry: TFileEntry; const AFileName:
  172.   string): Boolean;
  173. var
  174.   lFStream: TFileStream;
  175.   lFSize: Int64;
  176.   lBuffer: Pointer;
  177. begin
  178.   Result := False;
  179.   if Assigned(AFileEntry) then
  180.   begin
  181.     fImage.SeekSector(AFileEntry.ISOData.LocationOfExtent.LittleEndian);
  182.     lFStream := TFileStream.Create(AFileName, fmCreate);
  183.     lFSize := AFileEntry.ISOData.DataLength.LittleEndian;
  184.     GetMem(lBuffer, fImage.SectorDataSize);
  185.     try
  186.       while (lFSize > 0) do
  187.       begin
  188.         fImage.ReadSector_Data(lBuffer^, fImage.SectorDataSize);
  189.         lFStream.WriteBuffer(lBuffer^, Min(lFSize, fImage.SectorDataSize));
  190.         Dec(lFSize, fImage.SectorDataSize);
  191.       end;
  192.       Result := True;
  193.     finally
  194.       lFStream.Free;
  195.       FreeMem(lBuffer, fImage.SectorDataSize);
  196.     end;
  197.   end;
  198. end;
  199. procedure TDVDImage.Log(const AFunction, AMessage: string);
  200. begin
  201.   if Assigned(OnDVDStatus) then
  202.     OnDVDStatus(AFunction + ' : ' + AMessage);
  203. end;
  204. Procedure TDVDImage.CreateUDFDescriptors;
  205. begin
  206.   //DVD Video records
  207.   FillChar(FUDFBEA01, SizeOf(FUDFBEA01), Char(0));
  208.   FUDFBEA01.StandardIdentifier := VSD_STD_ID_BEA01; //BEA01
  209.   FUDFBEA01.StructureVersion := $01;
  210.   FillChar(FUDFNSR02, SizeOf(FUDFNSR02), Char(0));
  211.   FUDFNSR02.StandardIdentifier := VSD_STD_ID_NSR02; //NSR02
  212.   FUDFNSR02.StructureVersion := $01;
  213.   FillChar(FUDFTEA01, SizeOf(FUDFTEA01), Char(0));
  214.   FUDFTEA01.StandardIdentifier := VSD_STD_ID_TEA01; //TEA01
  215.   FUDFTEA01.StructureVersion := $01;
  216. end;
  217. procedure TDVDImage.CreateVolumeDescriptors;
  218. begin
  219.   Log('CreateImage', 'ISO Header Created'); // ISO Header 32k of 0
  220.   FillChar(FISOHeader, SizeOf(FISOHeader), Char(0));
  221.   Log('CreateImage', 'Boot Record Volume Descriptor Created'); // Boot Record VD
  222.   if (Assigned(fBRClass)) then
  223.     fBRClass.Free;
  224.   FBRClass := TBootRecordVolumeDescriptor.Create;
  225.   Log('CreateImage', 'Primary Volume Descriptor Created');
  226.     // Primary Volume Descriptor
  227.   if (Assigned(fPVDClass)) then
  228.     fPVDClass.Free;
  229.   FPVDClass := TPrimaryVolumeDescriptor.Create;
  230.   Log('CreateImage', 'Supplementary Volume Descriptor Created');
  231.     // Supplementary Volume Descriptor
  232.   if (Assigned(FSVDClass)) then
  233.     FSVDClass.Free;
  234.   FSVDClass := TSupplementaryVolumeDescriptor.Create;
  235.   Log('CreateImage', 'Volume Descriptor Set Terminator Created');
  236.     // Volume Descriptor Set Terminator
  237.   FillChar(FVDSTClass, SizeOf(FVDSTClass), Char(0));
  238.   FVDSTClass.VolumeDescriptorType := vdtVDST;
  239.   FVDSTClass.StandardIdentifier := ISO_STANDARD_ID;
  240.   FVDSTClass.VolumeDescriptorVersion := 1;
  241.   CreateUDFDescriptors;
  242. end;
  243. procedure TDVDImage.WriteRootStructureTree(Primary: Boolean; ISOStream:
  244.   TImageStreamHandler; ADirEntry: TDirectoryEntry);
  245. var
  246.   DirIndex, FileIndex, Padd: Integer;
  247.   Dir: TDirectoryEntry;
  248.   RootDir: TRootDirectoryrecord;
  249.   Fil: TFileEntry;
  250.   TempPchar: PChar;
  251.   TempPWideChr: PWideChar;
  252.   PadByte, FileID: Byte;
  253.   FillBlock: array[0..2047] of Byte;
  254.   WideArray: array[0..127] of byte;
  255.   DIRRecSize: Integer;
  256.   Sector: Integer;
  257. begin
  258.   PadByte := $00;
  259.   FillChar(FillBlock, 2048, 0);
  260.   Log('Write Root Structure', 'Name : ' + ADirEntry.Name);
  261.   // fill in "." and ".." directory sections (i previosly missed)
  262.   RootDir := ADirEntry.RootISOData;
  263.   RootDir.LengthOfDirectoryRecord := $22;
  264.   RootDir.LengthOfFileIdentifier := 1;
  265.   RootDir.FileFlags := $02;
  266.   RootDir.VolumeSequenceNumber := BuildBothEndianWord(1);
  267.   RootDir.LocationOfExtent := ADirEntry.RootISOData.LocationOfExtent;
  268.   FileID := 0;
  269.   ISOStream.Stream.Write(RootDir, sizeof(TDirectoryrecord));
  270.   ISOStream.Stream.Write(FileID, sizeof(FileID)); // write file identifier
  271.   RootDir := ADirEntry.RootISOData;
  272.   RootDir.LengthOfDirectoryRecord := $22;
  273.   RootDir.LengthOfFileIdentifier := 1;
  274.   RootDir.FileFlags := $02;
  275.   RootDir.VolumeSequenceNumber := BuildBothEndianWord(1);
  276.   RootDir.LocationOfExtent := ADirEntry.RootISOData.LocationOfExtent;
  277.   FileID := 1;
  278.   ISOStream.Stream.Write(RootDir, sizeof(TDirectoryrecord));
  279.   ISOStream.Stream.Write(FileID, sizeof(FileID)); // write file identifier
  280.   // done with "." ".."
  281.   for DirIndex := 0 to ADirEntry.DirectoryCount - 1 do // write directories
  282.   begin
  283.     Dir := ADirEntry.Directories[DirIndex];
  284.     Dir.FillISOData(Primary);
  285.     ISOStream.Stream.Write(Dir.ISOData, sizeof(TDirectoryrecord));
  286.     if Primary = True then
  287.     begin
  288.       TempPchar := pchar(Dir.Name);
  289.       ISOStream.Stream.Write(TempPchar^, Dir.ISOData.LengthOfFileIdentifier);
  290.     end
  291.     else
  292.     begin
  293.       TempPWideChr := Dir.GetWideDirName;
  294.       FillChar(WideArray, 128, 0);
  295.       CopyMemory(@WideArray[1], @TempPWideChr[0],
  296.         (Dir.ISOData.LengthOfFileIdentifier) - 1); //makes it big endian wide char
  297.       ISOStream.Stream.Write(WideArray, Dir.ISOData.LengthOfFileIdentifier);
  298.     end;
  299.     DIRRecSize := sizeof(TDirectoryrecord) + Dir.ISOData.LengthOfFileIdentifier;
  300.       // get padding size
  301.     if (DIRRecSize mod 2) > 0 then
  302.       FImage.Stream.Write(PadByte, 1);
  303.   end;
  304.   for FileIndex := 0 to ADirEntry.FileCount - 1 do // write files
  305.   begin
  306.     Fil := ADirEntry.Files[FileIndex];
  307.     Fil.FillISOData(Primary);
  308.     ISOStream.Stream.Write(Fil.ISOData, sizeof(TDirectoryrecord));
  309.     if Primary = True then
  310.     begin
  311.       TempPchar := pchar(Fil.Name);
  312.       ISOStream.Stream.Write(TempPchar^, Fil.ISOData.LengthOfFileIdentifier);
  313.     end
  314.     else
  315.     begin
  316.       TempPWideChr := Fil.GetWideFileName;
  317.       FillChar(WideArray, 128, 0);
  318.       CopyMemory(@WideArray[1], @TempPWideChr[0],
  319.         (Fil.ISOData.LengthOfFileIdentifier) - 1); //makes it big endian wide char
  320.       ISOStream.Stream.Write(WideArray, Fil.ISOData.LengthOfFileIdentifier);
  321.     end;
  322.     DIRRecSize := sizeof(TDirectoryrecord) + Fil.ISOData.LengthOfFileIdentifier;
  323.       // get padding size
  324.     if (DIRRecSize mod 2) > 0 then
  325.       FImage.Stream.Write(PadByte, 1);
  326.   end;
  327.   //pad the remainder of the block
  328.   Padd := 2048 - (ISOstream.Stream.Position mod 2048);
  329.   if Padd < 2048 then
  330.     ISOStream.Stream.Write(FillBlock, Padd);
  331.   for DirIndex := 0 to ADirEntry.DirectoryCount - 1 do // Rescan directories
  332.   begin
  333.     Dir := ADirEntry.Directories[DirIndex];
  334.     Dir.FillISOData(Primary);
  335.     WriteStructureTree(Primary, ISOStream, Dir);
  336.   end;
  337.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  338.   Log('Write Root Structure', 'Current Pos After Structure: ' +
  339.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  340.     + ' : ' + inttostr(Sector));
  341.   Log('SaveImage',
  342.     '|----------------------------------------------------------|');
  343. end;
  344. procedure TDVDImage.WriteUDFRootStructureTree(ISOStream: TImageStreamHandler; ADirEntry: TDirectoryEntry);
  345. var
  346.   DirIndex, FileIndex, Padd: Integer;
  347.   Dir: TDirectoryEntry;
  348.   UDF_FID : UDF_FileIdentifierDescriptor;
  349.   Fil: TFileEntry;
  350.   TempPchar: PChar;
  351.   PadByte, FileID: Byte;
  352.   FillBlock: array[0..2047] of Byte;
  353.   DIRRecSize: Integer;
  354.   Sector: Integer;
  355. begin
  356.   PadByte := $00;
  357.   FillChar(FillBlock, 2048, 0);
  358.   FillChar(UDF_FID, sizeof(UDF_FID), 0);
  359.   Log('Write UDF Root Structure', 'Name : ' + ADirEntry.Name);
  360.   UDF_FID.DescriptorTag.TagIdentifier := TAG_IDENT_FID;
  361.   UDF_FID.DescriptorTag.DescriptorVersion := $0020;
  362.   UDF_FID.DescriptorTag.TagChecksum := $00;
  363.   UDF_FID.DescriptorTag.Reserved := $00;
  364.   UDF_FID.DescriptorTag.TagSerialNumber := $0000;
  365.   UDF_FID.DescriptorTag.DescriptorCRC := $0000;
  366.   UDF_FID.DescriptorTag.DescriptorCRCLength := $0000;
  367.   UDF_FID.DescriptorTag.TagLocation := 265;
  368.   UDF_FID.FileVersionNumber := $0001;
  369.   UDF_FID.FileCharacteristics := $0A;
  370.   UDF_FID.LengthOfFileIdentifier := $00;
  371.   UDF_FID.ICB.ExtentLength := $08000000;
  372.   UDF_FID.ICB.ExtentLocation.LogicalBlockNum := $00000020;
  373.   UDF_FID.ICB.ExtentLocation.PartitionReferenceNum := $0000;
  374.   FileID := 0;
  375.   ISOStream.Stream.Write(UDF_FID, sizeof(UDF_FID));
  376.   ISOStream.Stream.Write(FileID, sizeof(FileID)); // write file identifier
  377.   for DirIndex := 0 to ADirEntry.DirectoryCount - 1 do // write directories
  378.   begin
  379.     Dir := ADirEntry.Directories[DirIndex];
  380.     Dir.FillISOData(true);
  381.     UDF_FID.LengthOfFileIdentifier := Dir.ISOData.LengthOfFileIdentifier;
  382.     ISOStream.Stream.Write(UDF_FID, sizeof(UDF_FID));
  383.     TempPchar := pchar(Dir.Name);
  384.     ISOStream.Stream.Write(TempPchar^, UDF_FID.LengthOfFileIdentifier);
  385.     DIRRecSize := sizeof(UDF_FID) + UDF_FID.LengthOfFileIdentifier;
  386.       // get padding size
  387.     if (DIRRecSize mod 2) > 0 then
  388.       FImage.Stream.Write(PadByte, 1);
  389.   end;
  390.   for FileIndex := 0 to ADirEntry.FileCount - 1 do // write files
  391.   begin
  392.     Fil := ADirEntry.Files[FileIndex];
  393.     Fil.FillISOData(true);
  394.     UDF_FID.LengthOfFileIdentifier := Fil.ISOData.LengthOfFileIdentifier;
  395.     ISOStream.Stream.Write(UDF_FID, sizeof(UDF_FID));
  396.     TempPchar := pchar(Fil.Name);
  397.     ISOStream.Stream.Write(TempPchar^, Fil.ISOData.LengthOfFileIdentifier);
  398.     DIRRecSize := sizeof(UDF_FID) + UDF_FID.LengthOfFileIdentifier;
  399.       // get padding size
  400.     if (DIRRecSize mod 2) > 0 then
  401.       FImage.Stream.Write(PadByte, 1);
  402.   end;
  403.   //pad the remainder of the block
  404.   Padd := 2048 - (ISOstream.Stream.Position mod 2048);
  405.   if Padd < 2048 then
  406.     ISOStream.Stream.Write(FillBlock, Padd);
  407. {  for DirIndex := 0 to ADirEntry.DirectoryCount - 1 do // Rescan directories
  408.   begin
  409.     Dir := ADirEntry.Directories[DirIndex];
  410.     Dir.FillISOData(true);
  411.     WriteUDFStructureTree(true, ISOStream, Dir);
  412.   end;}
  413.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  414.   Log('Write Root Structure', 'Current Pos After UDF File Structure: ' +
  415.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  416.     + ' : ' + inttostr(Sector));
  417.   Log('SaveImage',
  418.     '|----------------------------------------------------------|');
  419. end;
  420. procedure TDVDImage.WriteStructureTree(Primary: Boolean; ISOStream:
  421.   TImageStreamHandler; ADirEntry: TDirectoryEntry);
  422. var
  423.   DirIndex, FileIndex, Padd: Integer;
  424.   Dir: TDirectoryEntry;
  425.   RootDir: TDirectoryrecord;
  426.   Fil: TFileEntry;
  427.   TempPchar: PChar;
  428.   TempPWideChr: PWideChar;
  429.   PadByte, FileID: Byte;
  430.   FillBlock: array[0..2047] of Byte;
  431.   WideArray: array[0..127] of byte;
  432.   DIRRecSize: Integer;
  433.   Sector: Integer;
  434. begin
  435.   PadByte := $00;
  436.   FillChar(FillBlock, 2048, 0);
  437.   Log('Write Structure', 'Name : ' + ADirEntry.Name);
  438.   // fill in "." and ".." directory sections (i previosly missed)
  439.   RootDir := ADirEntry.ISOData;
  440.   RootDir.LengthOfDirectoryRecord := $22;
  441.   RootDir.LengthOfFileIdentifier := 1;
  442.   RootDir.FileFlags := $02;
  443.   RootDir.VolumeSequenceNumber := BuildBothEndianWord(1);
  444.   RootDir.LocationOfExtent := ADirEntry.ISOData.LocationOfExtent;
  445.   FileID := $00;
  446.   ISOStream.Stream.Write(RootDir, sizeof(TDirectoryrecord));
  447.   ISOStream.Stream.Write(FileID, sizeof(FileID)); // write file identifier
  448.   if (ADirEntry.Parent = nil) then
  449.     RootDir.LocationOfExtent := ADirEntry.RootISOData.LocationOfExtent
  450.   else
  451.   begin
  452.     ADirEntry.Parent.FillISOData(Primary);
  453.     RootDir.LocationOfExtent := ADirEntry.Parent.ISOData.LocationOfExtent;
  454.   end;
  455.   FileID := $01;
  456.   ISOStream.Stream.Write(RootDir, sizeof(TDirectoryrecord));
  457.   ISOStream.Stream.Write(FileID, sizeof(FileID)); // write file identifier
  458.   // done with "." ".."
  459.   for DirIndex := 0 to ADirEntry.DirectoryCount - 1 do // write directories
  460.   begin
  461.     Dir := ADirEntry.Directories[DirIndex];
  462.     Dir.FillISOData(Primary);
  463.     ISOStream.Stream.Write(Dir.ISOData, sizeof(TDirectoryrecord));
  464.     if Primary = True then
  465.     begin
  466.       TempPchar := pchar(Dir.Name);
  467.       ISOStream.Stream.Write(TempPchar^, Dir.ISOData.LengthOfFileIdentifier);
  468.     end
  469.     else
  470.     begin
  471.       TempPWideChr := Dir.GetWideDirName;
  472.       FillChar(WideArray, 128, 0);
  473.       CopyMemory(@WideArray[1], @TempPWideChr[0],
  474.         (Dir.ISOData.LengthOfFileIdentifier) - 1); //makes it big endian wide char
  475.       ISOStream.Stream.Write(WideArray, Dir.ISOData.LengthOfFileIdentifier);
  476.     end;
  477.     DIRRecSize := sizeof(TDirectoryrecord) + Dir.ISOData.LengthOfFileIdentifier;
  478.       // get padding size
  479.     if (DIRRecSize mod 2) > 0 then
  480.       FImage.Stream.Write(PadByte, 1);
  481.   end;
  482.   for FileIndex := 0 to ADirEntry.FileCount - 1 do // write files
  483.   begin
  484.     Fil := ADirEntry.Files[FileIndex];
  485.     Fil.FillISOData(Primary);
  486.     ISOStream.Stream.Write(Fil.ISOData, sizeof(TDirectoryrecord));
  487.     if Primary = True then
  488.     begin
  489.       TempPchar := pchar(Fil.Name);
  490.       ISOStream.Stream.Write(TempPchar^, Fil.ISOData.LengthOfFileIdentifier);
  491.     end
  492.     else
  493.     begin
  494.       TempPWideChr := Fil.GetWideFileName;
  495.       FillChar(WideArray, 128, 0);
  496.       CopyMemory(@WideArray[1], @TempPWideChr[0],
  497.         (Fil.ISOData.LengthOfFileIdentifier) - 1); //makes it big endian wide char
  498.       ISOStream.Stream.Write(WideArray, Fil.ISOData.LengthOfFileIdentifier);
  499.     end;
  500.     DIRRecSize := sizeof(TDirectoryrecord) + Fil.ISOData.LengthOfFileIdentifier;
  501.       // get padding size
  502.     if (DIRRecSize mod 2) > 0 then
  503.       FImage.Stream.Write(PadByte, 1);
  504.   end;
  505.   //pad the remainder of the block
  506.   Padd := 2048 - (ISOstream.Stream.Position mod 2048);
  507.   if Padd < 2048 then
  508.     ISOStream.Stream.Write(FillBlock, Padd);
  509.   for DirIndex := 0 to ADirEntry.DirectoryCount - 1 do // Rescan directories
  510.   begin
  511.     Dir := ADirEntry.Directories[DirIndex];
  512.     WriteStructureTree(Primary, ISOStream, Dir);
  513.   end;
  514.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  515.   Log('Write Structure', 'Current Pos After Structure: ' +
  516.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  517.     + ' : ' + inttostr(Sector));
  518.   Log('SaveImage',
  519.     '|----------------------------------------------------------|');
  520. end;
  521. procedure TDVDImage.WriteFileData(ISOStream: TImageStreamHandler; ADirEntry:
  522.   TDirectoryEntry);
  523. var
  524.   DirIndex, FileIndex, Padd: Integer;
  525.   Dir: TDirectoryEntry;
  526.   Fil: TFileEntry;
  527.   PadByte: Byte;
  528.   FillBlock: array[0..2047] of Byte;
  529.   CDFile: TfileStream;
  530. begin
  531.   FillChar(FillBlock, 2048, 0);
  532.   for FileIndex := 0 to ADirEntry.FileCount - 1 do // write files
  533.   begin
  534.     Fil := ADirEntry.Files[FileIndex];
  535.     CDFile := TfileStream.Create(Fil.SourceFileName, fmOpenRead);
  536.     CDFile.Seek(0, soFromBeginning);
  537.     ISOStream.Stream.CopyFrom(CDFile, CDFile.Size);
  538.     CDFile.Free;
  539.   end;
  540.   //pad the remainder of the block
  541.   Padd := 2048 - (ISOstream.Stream.Position mod 2048);
  542.   if Padd < 2048 then
  543.     ISOStream.Stream.Write(FillBlock, Padd);
  544.   for DirIndex := 0 to ADirEntry.DirectoryCount - 1 do // Rescan directories
  545.   begin
  546.     Dir := ADirEntry.Directories[DirIndex];
  547.     WriteFileData(ISOStream, Dir);
  548.   end;
  549. end;
  550. procedure TDVDImage.WritePathTableData(ISOStream: TImageStreamHandler;
  551.   CurrentPointer: Integer);
  552. var
  553.   Index: Integer;
  554.   TempPchar, TempPadChar: Pchar;
  555.   PathRec: PPathTableRecord;
  556.   StreamPos: Integer;
  557.   ReverseByte: Cardinal;
  558.   CurrentStreamPointer, PadBytes, Sector: Integer;
  559. begin
  560.   TempPadChar := $00;
  561. //  CurrentStreamPointer := CurrentPointer;
  562.   // write out little endian path table sector 257
  563.   for Index := 0 to FTree.PathTableCount - 1 do
  564.   begin
  565.     PathRec := FTree.LittleEndianPathTable.Items[Index];
  566.     Log('SaveImage', 'Write Dir LPath Name: ' + PathRec^.DirectoryIdentifier);
  567.     FImage.Stream.Write(PathRec^.LengthOfDirectoryIdentifier, 1);
  568.       //ISO Path Table L
  569.     FImage.Stream.Write(PathRec^.ExtendedAttributeRecordLength, 1);
  570.     FImage.Stream.Write(PathRec^.LocationOfExtent, 4); 
  571.     FImage.Stream.Write(PathRec^.ParentDirectoryNumber, 2);
  572.     TempPchar := PathRec^.DirectoryIdentifier;
  573.     FImage.Stream.Write(TempPchar^, PathRec^.LengthOfDirectoryIdentifier);
  574.     if (PathRec^.LengthOfDirectoryIdentifier mod 2) > 0 then
  575.       FImage.Stream.Write(TempPadChar, 1);
  576.   end;
  577.         //Fill Up Gap to DVD size sectors sector 257
  578.   PadBytes := (258 * 2048); // get size
  579.   StreamPos := FImage.Stream.Position;
  580.   PadBytes := (PadBytes - StreamPos); // pad number
  581.   for Index := 1 to PadBytes do
  582.           FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  583.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  584.   Log('SaveImage', 'Current Pos After LPath Tables: ' +
  585.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  586.     + ' : ' + inttostr(Sector));
  587.  // CurrentStreamPointer := FImage.Stream.Position;
  588.   Log('SaveImage',
  589.     '|----------------------------------------------------------|');
  590.   // write out big endian path table sector 258
  591.   for Index := 0 to FTree.PathTableCount - 1 do
  592.   begin
  593.     PathRec := FTree.LittleEndianPathTable.Items[Index];
  594.     Log('SaveImage', 'Write Dir MPath Name: ' + PathRec^.DirectoryIdentifier);
  595.     FImage.Stream.Write(PathRec^.LengthOfDirectoryIdentifier, 1);
  596.       //ISO Path Table L
  597.     FImage.Stream.Write(PathRec^.ExtendedAttributeRecordLength, 1);
  598.     FImage.Stream.Write(PathRec^.LocationOfExtentM, 4);
  599.     ReverseByte := SwapWord(PathRec^.ParentDirectoryNumber);
  600.       // reverse to big endian
  601.     FImage.Stream.Write(ReverseByte, 2);
  602.     TempPchar := PathRec^.DirectoryIdentifier;
  603.     FImage.Stream.Write(TempPchar^, PathRec^.LengthOfDirectoryIdentifier);
  604.     if (PathRec^.LengthOfDirectoryIdentifier mod 2) > 0 then
  605.       FImage.Stream.Write(TempPadChar, 1); // padding byte
  606.   end;
  607.    //Fill Up Gap to DVD size sectors sector 258
  608.   PadBytes := (259 * 2048); // get size
  609.   StreamPos := FImage.Stream.Position;
  610.   PadBytes := (PadBytes - StreamPos); // pad number
  611.   for Index := 1 to PadBytes do
  612.           FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  613.   Log('SaveImage',
  614.     '|----------------------------------------------------------|');
  615.   // end of path table
  616. end;
  617. procedure TDVDImage.WriteJolietPathTableData(ISOStream: TImageStreamHandler;
  618.   CurrentPointer: Integer);
  619. var
  620.   Index: Integer;
  621.   TempPchar, TempPadChar: Pchar;
  622.   PathRec: PPathTableRecord;
  623.   StreamPos: Integer;
  624.   ReverseByte: Cardinal;
  625.   SectorOffsett: Integer;
  626.   CurrentStreamPointer, PadBytes, Sector: Integer;
  627. begin
  628.   TempPadChar := $00;
  629.   SectorOffsett := (FTree.JolietOffsett - FTree.DIRStartLBA);
  630.   CurrentStreamPointer := CurrentPointer;
  631.   // write out little endian path table sector 21
  632.   for Index := 0 to FTree.PathTableCount - 1 do
  633.   begin
  634.     PathRec := FTree.LittleEndianPathTable.Items[Index];
  635.     Log('SaveImage', 'Write Dir Joliet LPath Name: ' +
  636.       PathRec^.DirectoryIdentifierM);
  637.     FImage.Stream.Write(PathRec^.LengthOfDirectoryIdentifierM, 1);
  638.       //ISO Path Table L
  639.     FImage.Stream.Write(PathRec^.ExtendedAttributeRecordLength, 1);
  640.     PathRec^.JolietLocationOfExtent := (PathRec^.LocationOfExtent +
  641.       SectorOffsett);
  642.     FImage.Stream.Write(PathRec^.JolietLocationOfExtent, 4);
  643.     FImage.Stream.Write(PathRec^.ParentDirectoryNumber, 2);
  644.     TempPchar := PathRec^.DirectoryIdentifierM;
  645.     FImage.Stream.Write(TempPchar^, PathRec^.LengthOfDirectoryIdentifierM);
  646.     if (PathRec^.LengthOfDirectoryIdentifierM mod 2) > 0 then
  647.       FImage.Stream.Write(TempPadChar, 1);
  648.   end;
  649.   StreamPos := FImage.Stream.Position;
  650.   PadBytes := 2048 - (StreamPos - CurrentStreamPointer); // pad out to 2048
  651.   for Index := 1 to PadBytes do
  652.     FImage.Stream.Write(TempPadChar, 1);
  653.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  654.   Log('SaveImage', 'Current Pos After LPath Tables: ' +
  655.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  656.     + ' : ' + inttostr(Sector));
  657.   CurrentStreamPointer := FImage.Stream.Position;
  658.   Log('SaveImage',
  659.     '|----------------------------------------------------------|');
  660.   // write out big endian path table sector 22
  661.   for Index := 0 to FTree.PathTableCount - 1 do
  662.   begin
  663.     PathRec := FTree.LittleEndianPathTable.Items[Index];
  664.     Log('SaveImage', 'Write Dir Joliet MPath Name: ' +
  665.       PathRec^.DirectoryIdentifierM[0]);
  666.     FImage.Stream.Write(PathRec^.LengthOfDirectoryIdentifierM, 1);
  667.       //ISO Path Table L
  668.     FImage.Stream.Write(PathRec^.ExtendedAttributeRecordLength, 1);
  669.     PathRec^.JolietLocationOfExtentM :=
  670.       SwapDWord(PathRec^.JolietLocationOfExtent);
  671.     FImage.Stream.Write(PathRec^.JolietLocationOfExtentM, 4);
  672.     ReverseByte := SwapWord(PathRec^.ParentDirectoryNumber);
  673.       // reverse to big endian
  674.     FImage.Stream.Write(ReverseByte, 2);
  675.     TempPchar := PathRec^.DirectoryIdentifierM;
  676.     FImage.Stream.Write(TempPchar^, PathRec^.LengthOfDirectoryIdentifierM);
  677.     if (PathRec^.LengthOfDirectoryIdentifierM mod 2) > 0 then
  678.       FImage.Stream.Write(TempPadChar, 1); // padding byte
  679.   end;
  680.   StreamPos := FImage.Stream.Position;
  681.   PadBytes := 2048 - (StreamPos - CurrentStreamPointer); // pad out to 2048
  682.   for Index := 1 to PadBytes do
  683.     FImage.Stream.Write(TempPadChar, 1);
  684.   Log('SaveImage',
  685.     '|----------------------------------------------------------|');
  686.   // end of path table
  687. end;
  688. function TDVDImage.SaveDVDImageToDisk: Boolean;
  689. var
  690.   StartLBA, FileStartBlock: Integer;
  691.   TempPadChar: Pchar;
  692.   Index: Integer;
  693.  // PathRec: PPathTableRecord;
  694.   CurrentStreamPointer, PadBytes, Sector: Integer;
  695. begin
  696.   Result := False;
  697.   Sector := 0;
  698.   StartLBA := 258;
  699.   TempPadChar := $00;
  700.   FileStartBlock := 300;
  701.   if FFileName = '' then
  702.   begin
  703.     Log('SaveImage', 'No Filename Entered!');
  704.     exit;
  705.   end;
  706.   FImage := TImageStreamHandler.Create(FFileName, ybfMode1, ifCompleteSectors);
  707.   if (FImage.ISOBookFormat = ybfMode1) then
  708.     Log('SaveImage', 'DVD Video mode 1')
  709.   else if (FImage.ISOBookFormat = ybfMode2) then
  710.     Log('SaveImage', 'DVD Video mode 2');
  711.   Log('SaveImage', 'User data sector size is ' + IntToStr(FImage.SectorDataSize)
  712.     + ' bytes');
  713.   Log('SaveImage', 'Image data offset in image file is ' +
  714.     IntToStr(FImage.ImageOffset) + ' bytes');
  715.   if (FImage.SectorDataSize <> 2048) then
  716.   begin
  717.     Log('SaveImage',
  718.       'sorry, but sector size other than 2048 bytes are not yet supported...');
  719.     Exit;
  720.   end;
  721.   // Setup Directory tree and path tables (move to 256 for dvd video)
  722.   FTree.RefreshPathTables(StartLBA, FileStartBlock);
  723.   FTree.SortDirectories;
  724.   Log('SaveImage', 'Refresh Path Tables');
  725.   // Setup Root Directory tree and Fill Data
  726.   FTree.RootDirectory.FillRootISOData(True);
  727.   FTree.RootDirectory.SetupRootDirectoryLocationOfExtent(FTree.RootDirectory.StartLBA);
  728.   Log('SaveImage', 'Fill Root Directory Data');
  729.   // Start writing image data to file
  730.   Log('SaveImage',
  731.     '|----------------------------------------------------------|');
  732.   FImage.Stream.Write(FISOHeader, sizeof(FISOHeader)); //ISO Header 32k
  733.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  734.   Log('SaveImage', 'Write ISO Header : ' + inttostr(Sector));
  735.   Log('SaveImage',
  736.     '|----------------------------------------------------------|');
  737.   //setup primary volume descriptor
  738.   FPVDClass.VolumeIdentifier := FVolID;
  739.   FPVDClass.VolumeSpaceSize := BuildBothEndianDWord(FTree.FileLBA + FTree.FileBlocks);
  740.   FPVDClass.PathTableSize := BuildBothEndianDWord(FTree.PathTableLength);
  741.   copymemory(@FPVDClass.Descriptor.Primary.RootDirectory,
  742.     @FTree.RootDirectory.RootISOData, sizeof(TRootDirectoryRecord));
  743.   FImage.Stream.Write(FPVDClass.Descriptor, sizeof(FPVDClass.Descriptor));
  744.     //ISO Primary Volume Descriptor
  745.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  746.   Log('SaveImage', 'Write ISO Primary Volume Descriptor : ' + inttostr(Sector));
  747.   Log('SaveImage',
  748.     '|----------------------------------------------------------|');
  749.   // write volume set terminator
  750.   FImage.Stream.Write(FVDSTClass, sizeof(FVDSTClass));
  751.     //ISO Volume Set Terminator
  752.   Log('SaveImage', 'Write Volume Set Terminator');
  753.   Log('SaveImage',
  754.      '|----------------------------------------------------------|');
  755.   (* UDF Beginning Extended Area Descriptor (ECMA 167r3 2/9.2) *)
  756.   FImage.Stream.Write(FUDFBEA01, sizeof(FUDFBEA01));
  757.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  758.   Log('SaveImage', 'Beginning Extended Area Descriptor :' +  inttostr(Sector));
  759.   Log('SaveImage',
  760.     '|----------------------------------------------------------|');
  761.   (* UDF NSR Descriptor (ECMA 167r3 3/9.1) *)
  762.   FImage.Stream.Write(FUDFNSR02, sizeof(FUDFNSR02));
  763.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  764.   Log('SaveImage', 'NSR Descriptor :' +  inttostr(Sector));
  765.   Log('SaveImage',
  766.     '|----------------------------------------------------------|');
  767.   (* UDF Terminating Extended Area Descriptor (ECMA 167r3 2/9.3) *)
  768.   FImage.Stream.Write(FUDFTEA01, sizeof(FUDFTEA01));
  769.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  770.   Log('SaveImage', 'Terminating Extended Area Descriptor :' +  inttostr(Sector));
  771.   Log('SaveImage',
  772.     '|----------------------------------------------------------|');
  773.   //Fill Up Gap to DVD size sectors sector 32
  774.   PadBytes := (32 * 2048); // get size
  775.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  776.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  777.   for Index := 1 to PadBytes do
  778.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  779.   Log('SaveImage',
  780.     '|----------------------------------------------------------|');
  781.     //MICRO UDF VOLUME DESCRIPTORS ????
  782.     //PRIMARY FIRST ??
  783.   (* Primary Volume Descriptor (ECMA 167r3 3/10.1) *)
  784.   PopulateUDFPrimaryVolumeDescriptor(FUDF_PVD,32,FVolID);
  785.   FImage.Stream.Write(FUDF_PVD, sizeof(FUDF_PVD));
  786.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  787.   Log('SaveImage', 'UDF Primary Volume Descriptor :' +  inttostr(Sector));
  788.   Log('SaveImage',
  789.     '|----------------------------------------------------------|');
  790.     //Fill Up Gap to DVD size sectors sector 32
  791.   PadBytes := (33 * 2048); // get size
  792.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  793.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  794.   for Index := 1 to PadBytes do
  795.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  796.   (* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) *)
  797.    PopulateUDFImplementationUseVolumeDescriptor(FUDF_IUVD,33,FVolID);
  798.   FImage.Stream.Write(FUDF_IUVD, sizeof(FUDF_IUVD));
  799.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  800.   Log('SaveImage', 'UDF Implementation Use Volume Descriptor :' +  inttostr(Sector));
  801.   Log('SaveImage',
  802.     '|----------------------------------------------------------|');
  803.   //Fill Up Gap to DVD size sectors sector 33
  804.   PadBytes := (34 * 2048); // get size
  805.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  806.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  807.   for Index := 1 to PadBytes do
  808.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  809.   (* Partition Descriptor (ECMA 167r3 3/10.5) *)
  810.    PopulateUDFPartitionDescriptor(FUDF_PD,34,FVolID);
  811.   FImage.Stream.Write(FUDF_PD, sizeof(FUDF_PD));
  812.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  813.   Log('SaveImage', 'UDF Partition Descriptor  :' +  inttostr(Sector));
  814.   Log('SaveImage',
  815.     '|----------------------------------------------------------|');
  816.       //Fill Up Gap to DVD size sectors sector 34
  817.   PadBytes := (35 * 2048); // get size
  818.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  819.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  820.   for Index := 1 to PadBytes do
  821.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  822. (* Logical Volume Descriptor (ECMA 167r3 3/10.6) *)
  823.   PopulateUDFlogicalVolDesc(FUDF_LVD,35,FVolID);
  824.   FImage.Stream.Write(FUDF_LVD, sizeof(FUDF_LVD));
  825.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  826.   Log('SaveImage', 'Logical Volume Descriptor  :' +  inttostr(Sector));
  827.   Log('SaveImage',
  828.     '|----------------------------------------------------------|');
  829.       //Fill Up Gap to DVD size sectors sector 35
  830.   PadBytes := (36 * 2048); // get size
  831.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  832.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  833.   for Index := 1 to PadBytes do
  834.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  835. (* Unallocated Space Descriptor (ECMA 167r3 3/10.8) *)
  836.   PopulateUDFUnallocSpaceDesc(FUDF_USD,36,FVolID);
  837.   FImage.Stream.Write(FUDF_USD, sizeof(FUDF_USD));
  838.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  839.   Log('SaveImage', 'Unallocated Space Descriptor  :' +  inttostr(Sector));
  840.   Log('SaveImage',
  841.     '|----------------------------------------------------------|');
  842.       //Fill Up Gap to DVD size sectors sector 36
  843.   PadBytes := (37 * 2048); // get size
  844.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  845.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  846.   for Index := 1 to PadBytes do
  847.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  848. (* Terminating Descriptor (ECMA 167r3 3/10.9) *)
  849.   PopulateUDFTerminatingDesc(FUDF_TD,37,FVolID);
  850.   FImage.Stream.Write(FUDF_TD, sizeof(FUDF_TD));
  851.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  852.   Log('SaveImage', 'Terminating Descriptor  :' +  inttostr(Sector));
  853.   Log('SaveImage',
  854.     '|----------------------------------------------------------|');
  855.       //Fill Up Gap to DVD size sectors sector 37
  856.   PadBytes := (48 * 2048); // get size
  857.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  858.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  859.   for Index := 1 to PadBytes do
  860.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  861.   (* Primary Volume Descriptor (ECMA 167r3 3/10.1) *)
  862.   PopulateUDFPrimaryVolumeDescriptor(FUDF_PVD,48,FVolID);
  863.   FImage.Stream.Write(FUDF_PVD, sizeof(FUDF_PVD));
  864.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  865.   Log('SaveImage', 'UDF Primary Volume Descriptor :' +  inttostr(Sector));
  866.   Log('SaveImage',
  867.     '|----------------------------------------------------------|');
  868.     //Fill Up Gap to DVD size sectors sector 256
  869.   PadBytes := (49 * 2048); // get size
  870.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  871.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  872.   for Index := 1 to PadBytes do
  873.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  874.   (* Implementation Use Volume Descriptor (ECMA 167r3 3/10.4) *)
  875.    PopulateUDFImplementationUseVolumeDescriptor(FUDF_IUVD,49,FVolID);
  876.   FImage.Stream.Write(FUDF_IUVD, sizeof(FUDF_IUVD));
  877.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  878.   Log('SaveImage', 'UDF Implementation Use Volume Descriptor :' +  inttostr(Sector));
  879.   Log('SaveImage',
  880.     '|----------------------------------------------------------|');
  881.   //Fill Up Gap to DVD size sectors sector 49
  882.   PadBytes := (50 * 2048); // get size
  883.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  884.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  885.   for Index := 1 to PadBytes do
  886.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  887.   (* Partition Descriptor (ECMA 167r3 3/10.5) *)
  888.    PopulateUDFPartitionDescriptor(FUDF_PD,50,FVolID);
  889.   FImage.Stream.Write(FUDF_PD, sizeof(FUDF_PD));
  890.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  891.   Log('SaveImage', 'UDF Partition Descriptor  :' +  inttostr(Sector));
  892.   Log('SaveImage',
  893.     '|----------------------------------------------------------|');
  894.       //Fill Up Gap to DVD size sectors sector 34
  895.   PadBytes := (51 * 2048); // get size
  896.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  897.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  898.   for Index := 1 to PadBytes do
  899.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  900. (* Logical Volume Descriptor (ECMA 167r3 3/10.6) *)
  901.   PopulateUDFlogicalVolDesc(FUDF_LVD,51,FVolID);
  902.   FImage.Stream.Write(FUDF_LVD, sizeof(FUDF_LVD));
  903.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  904.   Log('SaveImage', 'Logical Volume Descriptor  :' +  inttostr(Sector));
  905.   Log('SaveImage',
  906.     '|----------------------------------------------------------|');
  907.       //Fill Up Gap to DVD size sectors sector 35
  908.   PadBytes := (52 * 2048); // get size
  909.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  910.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  911.   for Index := 1 to PadBytes do
  912.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  913. (* Unallocated Space Descriptor (ECMA 167r3 3/10.8) *)
  914.   PopulateUDFUnallocSpaceDesc(FUDF_USD,52,FVolID);
  915.   FImage.Stream.Write(FUDF_USD, sizeof(FUDF_USD));
  916.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  917.   Log('SaveImage', 'Unallocated Space Descriptor  :' +  inttostr(Sector));
  918.   Log('SaveImage',
  919.     '|----------------------------------------------------------|');
  920.       //Fill Up Gap to DVD size sectors sector 36
  921.   PadBytes := (53 * 2048); // get size
  922.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  923.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  924.   for Index := 1 to PadBytes do
  925.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  926. (* Terminating Descriptor (ECMA 167r3 3/10.9) *)
  927.   PopulateUDFTerminatingDesc(FUDF_TD,53,FVolID);
  928.   FImage.Stream.Write(FUDF_TD, sizeof(FUDF_TD));
  929.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  930.   Log('SaveImage', 'Terminating Descriptor  :' +  inttostr(Sector));
  931.   Log('SaveImage',
  932.     '|----------------------------------------------------------|');
  933.       //Fill Up Gap to DVD size sectors sector 37
  934.   PadBytes := (64 * 2048); // get size
  935.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  936.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  937.   for Index := 1 to PadBytes do
  938.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  939.     {64 - 65}
  940. (* Logical Volume Integrity Descriptor (ECMA 167r3 3/10.10) *)
  941.   FTree.ResetAllCounts;
  942.   PopulateUDFlogicalVolumeIntegrityDesc(FUDF_LVID,64,FTree.TotalFileCount,FTree.TotalDirCount);
  943.   FImage.Stream.Write(FUDF_LVID, sizeof(FUDF_LVID));
  944.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  945.   Log('SaveImage', 'Logical Volume Integrity Descriptor  :' +  inttostr(Sector));
  946.   Log('SaveImage',
  947.     '|----------------------------------------------------------|');
  948.       //Fill Up Gap to DVD size sectors sector 64
  949.   PadBytes := (65 * 2048); // get size
  950.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  951.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  952.   for Index := 1 to PadBytes do
  953.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  954. (* Terminating Descriptor (ECMA 167r3 3/10.9) *)
  955.   PopulateUDFTerminatingDesc(FUDF_TD,65,FVolID);
  956.   FImage.Stream.Write(FUDF_TD, sizeof(FUDF_TD));
  957.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  958.   Log('SaveImage', 'Terminating Descriptor  :' +  inttostr(Sector));
  959.   Log('SaveImage',
  960.     '|----------------------------------------------------------|');
  961.       //Fill Up Gap to DVD size sectors sector 256
  962.   PadBytes := (256 * 2048); // get size
  963.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  964.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  965.   for Index := 1 to PadBytes do
  966.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  967. (* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) *)
  968.   PopulateUDFAnchorVolumeDescriptorPointer(FUDF_AVDP,256,FVolID);
  969.   FImage.Stream.Write(FUDF_AVDP, sizeof(FUDF_AVDP));
  970.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  971.   Log('SaveImage', 'Anchor Volume Descriptor Pointer :' +  inttostr(Sector));
  972.   Log('SaveImage',
  973.     '|----------------------------------------------------------|');
  974.     //Fill Up Gap to DVD size sectors sector 257
  975.   PadBytes := (257 * 2048); // get size
  976.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  977.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  978.   for Index := 1 to PadBytes do
  979.       FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  980.   //write out Primary path table
  981.   WritePathTableData(FImage, CurrentStreamPointer);
  982. //  CurrentStreamPointer := FImage.Stream.Position;
  983.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  984.   Log('SaveImage', 'Current Pos After Pri Path Tables: ' +
  985.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  986.     + ' : ' + inttostr(Sector));
  987.   Log('SaveImage',
  988.     '|----------------------------------------------------------|');
  989.   // write directory and file tables start with root sector 300 start
  990.   WriteRootStructureTree(True, FImage, FTree.RootDirectory);
  991.   Log('SaveImage', 'Joliet Offsett: ' + inttostr(FTree.JolietOffsett));
  992.  // CurrentStreamPointer := FImage.Stream.Position;
  993.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  994.   Log('SaveImage', 'Current Pos After Write Structure: ' +
  995.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  996.     + ' : ' + inttostr(Sector));
  997.   Log('SaveImage',
  998.     '|----------------------------------------------------------|');
  999. (* File Set Descriptor (ECMA 167r3 4/14.1) *)
  1000.   PopulateUDFFileSetDescriptor(FUDF_FSD,262,FVolID);
  1001.   FImage.Stream.Write(FUDF_FSD, sizeof(FUDF_FSD));
  1002.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  1003.   Log('SaveImage', 'File Set Descriptor :' +  inttostr(Sector));
  1004.   Log('SaveImage',
  1005.     '|----------------------------------------------------------|');
  1006.     //Fill Up Gap to DVD size sectors sector 262
  1007.   PadBytes := (263 * 2048); // get size
  1008.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  1009.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  1010.   for Index := 1 to PadBytes do
  1011.       FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  1012. (* Terminating Descriptor (ECMA 167r3 3/10.9) *)
  1013.   PopulateUDFTerminatingDesc(FUDF_TD,263,FVolID);
  1014.   FImage.Stream.Write(FUDF_TD, sizeof(FUDF_TD));
  1015.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  1016.   Log('SaveImage', 'Terminating Descriptor  :' +  inttostr(Sector));
  1017.   Log('SaveImage',
  1018.     '|----------------------------------------------------------|');
  1019.       //Fill Up Gap to DVD size sectors sector 263
  1020.   PadBytes := (264 * 2048); // get size
  1021.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  1022.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  1023.   for Index := 1 to PadBytes do
  1024.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  1025.   WriteUDFRootStructureTree(FImage, FTree.RootDirectory);
  1026. //  CurrentStreamPointer := FImage.Stream.Position;
  1027.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  1028.   Log('SaveImage', 'Current Pos After Write UDF File Data: ' +
  1029.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  1030.     + ' : ' + inttostr(Sector));
  1031.   Log('SaveImage',
  1032.     '|----------------------------------------------------------|');
  1033.   //Fill Up Gap to DVD file start sectors
  1034.   PadBytes := (FTree.FileStartBlock * 2048); // get size
  1035.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  1036.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  1037.   for Index := 1 to PadBytes do
  1038.     FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  1039.   Log('SaveImage',
  1040.     '|----------------------------------------------------------|');
  1041.   // load up and write out files data
  1042.   WriteFileData(FImage, FTree.RootDirectory);
  1043.   CurrentStreamPointer := FImage.Stream.Position;
  1044.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  1045.   Log('SaveImage', 'Current Pos After Write File Data: ' +
  1046.     inttostr(FImage.Stream.Position) + ' : ' + inttohex(FImage.Stream.Position, 6)
  1047.     + ' : ' + inttostr(Sector));
  1048.   Log('SaveImage',
  1049.     '|----------------------------------------------------------|');
  1050.   PadBytes := (CurrentStreamPointer mod FImage.SectorDataSize); // pad number
  1051.   for Index := 1 to PadBytes do
  1052.       FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  1053.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  1054. (* Anchor Volume Descriptor Pointer (ECMA 167r3 3/10.2) *)
  1055.   PopulateUDFAnchorVolumeDescriptorPointer(FUDF_AVDP,Sector,FVolID);
  1056.   FImage.Stream.Write(FUDF_AVDP, sizeof(FUDF_AVDP));
  1057.   Sector := (FImage.Stream.Position div FImage.SectorDataSize);
  1058.   Log('SaveImage', 'Anchor Volume Descriptor Pointer :' +  inttostr(Sector));
  1059.   Log('SaveImage',
  1060.     '|----------------------------------------------------------|');
  1061.     //Fill Up Gap to DVD size sectors sector 257
  1062.   PadBytes := (Sector +1 * 2048); // get size
  1063.   CurrentStreamPointer := FImage.Stream.Position; // get current position
  1064.   PadBytes := (PadBytes - CurrentStreamPointer); // pad number
  1065.   for Index := 1 to PadBytes do
  1066.       FImage.Stream.Write(TempPadChar, 1); // pad out sectors
  1067.   FImage.Free;
  1068.   FImage := nil;
  1069.   Result := True;
  1070. end;
  1071. function TDVDImage.ParseDirectory(const AUsePrimaryVD: Boolean): Boolean;
  1072. var
  1073.   DirRootSourceRec: TRootDirectoryRecord;
  1074.   EndSector: Cardinal;
  1075.   DR: PDirectoryRecord;
  1076.   SecFileName: string;
  1077.   RecordSize: Integer;
  1078.   lWorkPtr,
  1079.     lBuffer: PByte;
  1080. begin
  1081.   Result := False;
  1082.   //RecordSize := SizeOf(TRootDirectoryRecord);
  1083.   RecordSize := SizeOf(TDirectoryRecord);
  1084.   if (AUsePrimaryVD) then
  1085.   begin
  1086.     Log('ParseDirectory', 'Parsing Directory Using Primary Volume Descriptor');
  1087.     DirRootSourceRec := fPVDClass.Descriptor.Primary.RootDirectory;
  1088.   end
  1089.   else
  1090.   begin
  1091.     Log('ParseDirectory',
  1092.       'Parsing Directory Using Supplementary Volume Descriptor...');
  1093.     if Assigned(fSVDClass) then
  1094.       DirRootSourceRec := fSVDClass.Descriptor.Primary.RootDirectory
  1095.     else
  1096.     begin
  1097.       Log('ParseDirectory', 'No Supplementary Volume Descriptor Found!');
  1098.       Log('ParseDirectory', 'Using Primary Volume Descriptor.');
  1099.       DirRootSourceRec := fPVDClass.Descriptor.Primary.RootDirectory;
  1100.     end;
  1101.   end;
  1102.   Log('ParseDirectory', 'directory sector ' +
  1103.     IntToStr(DirRootSourceRec.LocationOfExtent.LittleEndian));
  1104.   EndSector := DirRootSourceRec.LocationOfExtent.LittleEndian +
  1105.     (DirRootSourceRec.DataLength.LittleEndian + fImage.SectorDataSize - 1) div
  1106.       fImage.SectorDataSize;
  1107.   fImage.SeekSector(DirRootSourceRec.LocationOfExtent.LittleEndian);
  1108.   GetMem(lBuffer, fImage.SectorDataSize);
  1109.   try
  1110.     lWorkPtr := lBuffer;
  1111.     fImage.ReadSector_Data(lWorkPtr^, fImage.SectorDataSize);
  1112.     while (fImage.CurrentSector <= EndSector) do
  1113.     begin
  1114.       if (fImage.SectorDataSize - (Cardinal(lWorkPtr) - Cardinal(lBuffer))) <
  1115.         RecordSize then
  1116.       begin
  1117.         lWorkPtr := lBuffer;
  1118.         fImage.ReadSector_Data(lWorkPtr^, fImage.SectorDataSize);
  1119.       end;
  1120.       New(DR);
  1121.       Move(lWorkPtr^, DR^, RecordSize);
  1122.       Inc(lWorkPtr, RecordSize); // move pointer across
  1123.       SetLength(SecFileName, DR.LengthOfFileIdentifier);
  1124.       Move(lWorkPtr^, SecFileName[1], DR.LengthOfFileIdentifier);
  1125.       Inc(lWorkPtr, DR.LengthOfFileIdentifier);
  1126.       // padding bytes
  1127.       if ((RecordSize + DR.LengthOfFileIdentifier) < DR.LengthOfDirectoryRecord)
  1128.         then
  1129.         Inc(lWorkPtr, DR.LengthOfDirectoryRecord - RecordSize -
  1130.           DR.LengthOfFileIdentifier);
  1131.       ParseDirectorySub(FTree.RootDirectory, SecFileName, DR);
  1132.     end;
  1133.   finally
  1134.     FreeMem(lBuffer, fImage.SectorDataSize);
  1135.   end;
  1136. end;
  1137. function TDVDImage.ParseDirectorySub(AParentDir: TDirectoryEntry; const
  1138.   AFileName: string; var ADirectoryEntry: PDirectoryRecord): Boolean;
  1139. var
  1140.   EndSector: Cardinal;
  1141.   OldPosition: Integer;
  1142.   ActDir: TDirectoryEntry;
  1143.   FileEntry: TFileEntry;
  1144.   DRFileName: string;
  1145.   DR: PDirectoryRecord;
  1146.   RecordSize: Integer;
  1147.   lWorkPtr,
  1148.     lBuffer: PByte;
  1149. begin
  1150.   if (ADirectoryEntry.FileFlags and $2) = $2 then // directory
  1151.   begin
  1152.     OldPosition := fImage.CurrentSector;
  1153.     RecordSize := SizeOf(TDirectoryRecord);
  1154.     if (AFileName <> #0) and (AFileName <> #1) then
  1155.     begin
  1156.       ActDir := TDirectoryEntry.Create(fTree, AParentDir, dsfFromImage);
  1157.       ActDir.Name := UnicodeToStr(AFileName);
  1158.       ActDir.ISOData := ADirectoryEntry^;
  1159.       fImage.SeekSector(ADirectoryEntry.LocationOfExtent.LittleEndian);
  1160.       EndSector := ADirectoryEntry.LocationOfExtent.LittleEndian +
  1161.         (ADirectoryEntry.DataLength.LittleEndian + fImage.SectorDataSize - 1) div
  1162.           fImage.SectorDataSize;
  1163.       Dispose(ADirectoryEntry);
  1164.       ADirectoryEntry := nil;
  1165.       GetMem(lBuffer, fImage.SectorDataSize);
  1166.       try
  1167.         lWorkPtr := lBuffer;
  1168.         fImage.ReadSector_Data(lWorkPtr^, fImage.SectorDataSize);
  1169.         while (fImage.CurrentSector <= EndSector) do
  1170.         begin
  1171.           if (fImage.SectorDataSize - (Cardinal(lWorkPtr) - Cardinal(lBuffer)))
  1172.             < RecordSize then
  1173.           begin
  1174.             lWorkPtr := lBuffer;
  1175.             fImage.ReadSector_Data(lWorkPtr^, fImage.SectorDataSize);
  1176.           end;
  1177.           New(DR);
  1178.           Move(lWorkPtr^, DR^, RecordSize);
  1179.           Inc(lWorkPtr, RecordSize);
  1180.           SetLength(DRFileName, DR.LengthOfFileIdentifier);
  1181.           Move(lWorkPtr^, DRFileName[1], DR.LengthOfFileIdentifier);
  1182.           Inc(lWorkPtr, DR.LengthOfFileIdentifier);
  1183.           // padding bytes
  1184.           if ((RecordSize + DR.LengthOfFileIdentifier) <
  1185.             DR.LengthOfDirectoryRecord) then
  1186.             Inc(lWorkPtr, DR.LengthOfDirectoryRecord - RecordSize -
  1187.               DR.LengthOfFileIdentifier);
  1188.           ParseDirectorySub(ActDir, DRFileName, DR);
  1189.         end;
  1190.       finally
  1191.         FreeMem(lBuffer, fImage.SectorDataSize);
  1192.       end;
  1193.     end;
  1194.     fImage.SeekSector(OldPosition);
  1195.   end
  1196.   else
  1197.   begin
  1198.     if (AFileName <> '') and (ADirectoryEntry.DataLength.LittleEndian > 0) then
  1199.     begin
  1200.       FileEntry := TFileEntry.Create(AParentDir, dsfFromImage);
  1201.       FileEntry.Name := UnicodeToStr(AFileName);
  1202.       FileEntry.ISOData := ADirectoryEntry^;
  1203.     end;
  1204.   end;
  1205.   Result := True;
  1206. end;
  1207. function TDVDImage.ParsePathTable(ATreeView: TTreeView): Boolean;
  1208. var
  1209.   PathTableEntry: TPathTableRecord;
  1210.   FileName: string;
  1211.   SectorCount: Cardinal;
  1212.   Node: TTreeNode;
  1213.   PathTabelEntryNumber: Integer;
  1214.   lWorkPtr,
  1215.     lBuffer: PByte;
  1216.   i: Integer;
  1217.   IDLength: Integer;
  1218.   function FindParent(const AParentPathNumber: Integer): TTreeNode;
  1219.   begin
  1220.     Result := ATreeView.Items.GetFirstNode;
  1221.     while (Integer(Result.Data) <> AParentPathNumber) do
  1222.       Result := Result.GetNext;
  1223.   end;
  1224. begin
  1225.   Result := False;
  1226.   Log('ParsePathTable', 'path table first sector ' +
  1227.     IntToStr(fPVDClass.Descriptor.Primary.LocationOfTypeLPathTable));
  1228.   Log('ParsePathTable', 'path table length ' +
  1229.     IntToStr(fPVDClass.Descriptor.Primary.PathTableSize.LittleEndian) + ' bytes');
  1230.   if (Assigned(ATreeView)) then
  1231.     ATreeView.Items.Clear;
  1232.   SectorCount := (fPVDClass.Descriptor.Primary.PathTableSize.LittleEndian +
  1233.     fImage.SectorDataSize - 1) div fImage.SectorDataSize;
  1234.   fImage.SeekSector(fPVDClass.Descriptor.Primary.LocationOfTypeLPathTable);
  1235.   GetMem(lBuffer, SectorCount * fImage.SectorDataSize);
  1236.   lWorkPtr := lBuffer;
  1237.   try
  1238.     PathTabelEntryNumber := 0;
  1239.     for i := 1 to SectorCount do
  1240.     begin
  1241.       fImage.ReadSector_Data(lWorkPtr^, fImage.SectorDataSize);
  1242.       Inc(lWorkPtr, fImage.SectorDataSize);
  1243.     end;
  1244.     lWorkPtr := lBuffer;
  1245.     repeat
  1246.       FillChar(PathTableEntry, sizeof(PathTableEntry), 0);
  1247.       Move(lWorkPtr^, PathTableEntry.LengthOfDirectoryIdentifier, 1);
  1248.       Inc(lWorkPtr, 1);
  1249.       Move(lWorkPtr^, PathTableEntry.ExtendedAttributeRecordLength, 1);
  1250.       Inc(lWorkPtr, 1);
  1251.       Move(lWorkPtr^, PathTableEntry.LocationOfExtent, 4);
  1252.       Inc(lWorkPtr, 4);
  1253.       Move(lWorkPtr^, PathTableEntry.ParentDirectoryNumber, 2);
  1254.       Inc(lWorkPtr, 2);
  1255.       Move(lWorkPtr^, PathTableEntry.DirectoryIdentifier,
  1256.         PathTableEntry.LengthOfDirectoryIdentifier);
  1257.       Inc(lWorkPtr, PathTableEntry.LengthOfDirectoryIdentifier);
  1258.       FileName := PathTableEntry.DirectoryIdentifier;
  1259.       if (Odd(PathTableEntry.LengthOfDirectoryIdentifier)) then
  1260.         Inc(lWorkPtr, 1);
  1261.       Inc(PathTabelEntryNumber);
  1262.       if (PathTableEntry.LengthOfDirectoryIdentifier = 1) then
  1263.       begin
  1264.         if (Assigned(ATreeView)) and (PathTabelEntryNumber = 1) then
  1265.         begin
  1266.           Node := ATreeView.Items.AddChild(nil, '/');
  1267.           Node.Data := Pointer(PathTabelEntryNumber);
  1268.         end;
  1269.       end
  1270.       else
  1271.       begin
  1272.         if (Assigned(ATreeView)) then
  1273.         begin
  1274.           Node := ATreeView.Items.AddChild(FindParent(PathTableEntry.ParentDirectoryNumber), FileName);
  1275.           Node.Data := Pointer(PathTabelEntryNumber);
  1276.         end;
  1277.       end;
  1278.     until ((Cardinal(lWorkPtr) - Cardinal(lBuffer)) >=
  1279.       (fPVDClass.Descriptor.Primary.PathTableSize.LittleEndian - 2));
  1280.   finally
  1281.     FreeMem(lBuffer, SectorCount * fImage.SectorDataSize);
  1282.   end;
  1283. end;
  1284. end.