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

DVD

开发平台:

Delphi

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