Link to home
Start Free TrialLog in
Avatar of tadzio_blah
tadzio_blah

asked on

Reading ISO files.

Hi

I need to read the root directory of an ISO file, and detect if it's an DVD or a CD. Anyone can help with this ?
Avatar of TECH_NET
TECH_NET

Use MagicISO s.w

Check this link:
http://www.magiciso.com/tutorials/miso-burnwin.htm
Avatar of tadzio_blah

ASKER

um... this is the programming/delphi zone of EE, so as you can imagine I don't want to know what apps can do that (i know a lot of those, IMO a lot better than magicISO)... i need a code that can do that
I would have recommended using clonedvd but i figured that CloneCD detect CD iso images as DVD
sorry, my bad...
...anyways... can anyone post some DELPHI CODE that i can use (or a unit that handles ISO files), and NOT an app name ?
ASKER CERTIFIED SOLUTION
Avatar of ThievingSix
ThievingSix
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Here's an example on how to use it. It gets some data from the file named param.sfo inside the iso.
function TfrmMain.LoadISOName(FileName: String): String;
var
  ISOFile : Cardinal;
  Files : TDirectoryArrayRecord;
  Filter : TSearchFilter;
  FilesFound : Cardinal;
  Offset : Cardinal;
  Size : Cardinal;
  BytesRead : Cardinal;
  Buffer : Array Of Char;
  ISOName : String;
  I,
  Max : Integer;
begin
  Result := '';
  ISOFile := CreateFile(PChar(FileName),GENERIC_READ,0,nil,OPEN_EXISTING,0,0);
  If ISOFile = INVALID_HANDLE_VALUE Then Exit;
  Try
    SetLength(Files,1);
    FillChar(Filter,SizeOf(TSearchFilter),0);
    Filter.Flags := FILTER_BY_NAME;
    Filter.lwType := ISO_FLAG_FILE;
    Filter.Name := 'PARAM.SFO';
    Filter.DataSize := 9;
    FilesFound := ISOSearchFiles(ISOFile,Files,1,@Filter);
    If FilesFound = 0 Then Exit;
    Offset := Files[0].ExtentLocation * SECTOR_SIZE;
    Size := Files[0].DataLength;
    If Size > 0 Then
      begin
      SetLength(Buffer,Size);
      SetFilePointer(ISOFile,Offset,nil,FILE_BEGIN);
      ReadFile(ISOFile,Buffer[0],Size,BytesRead,nil);
      ISOName := Copy(String(Buffer),$159,255);
      ISOName := Copy(ISOName,1,Pos(#0,ISOName) - 1);
      I := 1;
      Max := Length(ISOName);
      While I <= Max Do
        begin
        If Not(ISOName[I] in ['a'..'z','A'..'Z','0'..'9','-','+','.',' ']) Then
          begin
          Delete(ISOName,I,1);
          Dec(Max);
        end
        Else
          begin
          Inc(I);
        end;
      end;
      Result := ISOName;
    end;
  Finally
    CloseHandle(ISOFile);
  end;
end;

Open in new window

i'm getting stack overflow in the ISOScanFiles function.
the stack overflow error surfaces when the searched file is not in the iso. (i've tried it with an iso that contained just 49 files and 2 dirs, and also with one that contained couple thousand files - so it's not the file count that produces the error).
Have you stepped through the code to find exactly where it's coming from? Because I've used this on iso files that are missing the searched file.
most likely it's this line:

  While True Do
    begin
    FillChar(DR,SizeOf(TDirectoryRecord),0);
>>>    ReadFile(ISOFile,DR,SizeOf(TDirectoryRecord),BytesRead,nil);
    If DR.DirectoryLength = 0 Then

in ISOScanFiles. I think it's trying to read beyond the directory contents until it finds the correct file name (just a suggestion, hanen't had the time to properly step it).
That wouldn't give you a stack overflow error. If the ReadFile fails, then the DR.DirectoryLength would be 0 because we initialized the DR variable that way. In that case the infinite loop fails. You should step through it or use a logging device inside the function(Log event results and find out where it last gets to before fail).
i've stepped throught 200 repeats (don't have the patience to do more) of that while loop, and i've used iso with 49 files and 2 directories - are those 200 repeats normal with that small amount of files/dirs ?
sorry, by loops i meant recursive executions of ISOScanFiles, as after 200 it didn't even start to come back from the recursion.
since, i need to only look for the file in the root dir of the iso i've shortened your code a little.
now it doesn't produce the exception (that's not a surprise since i've removed the recursive part).
nevertheless, there's something wrong with the recirsion in your code.
unit uISO;
 
interface
 
uses
  Windows, Sysutils, Math, StrUtils;
 
type
  PDirectoryRecord = ^TDirectoryRecord;
  TDirectoryRecord = packed record
    DirectoryLength   : Byte;
    XARLength         : Byte;
    ExtentLocation    : LongWord;
    ExtentLocationBE  : LongWord;
    DataLength        : LongWord;
    DataLengthBE      : LongWord;
    DateTime          : Array[0..6] Of Byte;
    FileFlags         : Byte;
    FileUnitSize      : Byte;
    InterleaveGapSize : Byte;
    ValueSequenceNum  : LongWord;
    FileNameLength    : Byte;
    FileName          : Array[0..255] Of Char;
  end;
  TDirectoryArrayRecord = Array Of TDirectoryRecord;
  PSearchFilter = ^TSearchFilter;
  TSearchFilter = record
    Flags    : LongWord;
    Name     : Array[0..255] Of Char;
    lwType   : LongWord;
    Size     : LongWord;
    SizeType : LongWord;
    Data     : Pointer;
    DataSize : LongWord;
  end;
 
const
  SECTOR_SIZE          = 2048;
  ISO_FLAG_FILE        = $00;
  ISO_FLAG_EXISTENCE   = $01;
  ISO_FLAG_DIRECTORY   = $02;
  ISO_FLAG_ASSOCIATED  = $04;
  ISO_FLAG_RECORD      = $08;
  ISO_FLAG_PROTECTION  = $10;
  ISO_FLAG_MULTIEXTENT = $80;
  FILTER_BY_NAME       = $01;
 
function ISOSearchFiles(ISOFile: Cardinal; Output: TDirectoryArrayRecord; Max: Integer; Start: Integer = 0): Integer;
 
implementation
 
function PosLen(SubStr, Str: PChar; Length: Integer): Bool;
begin
  Result := Not(CompareMem(SubStr,Str,Length));
end;
 
function ISOScanFiles(ISOFile: Cardinal; Output: TDirectoryArrayRecord; Max: Integer; i: integer) : integer;
var
  DR : TDirectoryRecord;
  fPointer : Cardinal;
  Add : Integer;
  OldDirLen : Cardinal;
  BytesRead : Cardinal;
 
begin
  OldDirLen := 0;
  fPointer := SetFilePointer(ISOFile, 0, nil, FILE_CURRENT);
  while True do
    begin
      FillChar(DR, SizeOf(TDirectoryRecord), 0);
      ReadFile(ISOFile, DR, SizeOf(TDirectoryRecord), BytesRead, nil);
      if (DR.DirectoryLength = 0) then
        begin
          if ((SECTOR_SIZE - (fPointer mod SECTOR_SIZE)) <= OldDirLen) then
            begin
              fPointer := fPointer + (SECTOR_SIZE - (fPointer mod SECTOR_SIZE));
              SetFilePointer(ISOFile, fPointer, nil, FILE_BEGIN);
              ReadFile(ISOFile, DR, SizeOf(TDirectoryRecord), BytesRead, nil);
              if (DR.DirectoryLength = 0) then Break;
            end
          else
            Break;
        end;
      if ((DR.FileName[1] <> #0) AND (DR.FileName[1] <> #1)) then
        begin
          Add := 1;
          if not(ContainsText(string(DR.FileName), 'system.cnf')) then Add := 0;
          if (i = Max) then Break;
          if ((Add <> 0) AND (DR.DataLength <> 0)) then
            begin
              Output[i] := DR;
              i := i + 1;
            end;
        end;
    fPointer := fPointer + DR.DirectoryLength;
    OldDirLen := DR.DirectoryLength;
    SetFilePointer(ISOFile, fPointer, nil, FILE_BEGIN);
  end;
  Result := i;
end;
 
function ISOSearchFiles(ISOFile: Cardinal; Output: TDirectoryArrayRecord; Max: Integer; Start: integer = 0): integer;
var
  DR : TDirectoryRecord;
  BytesRead : Cardinal;
 
begin
  SetFilePointer(ISOFile, (16 * SECTOR_SIZE) + 156, nil, FILE_BEGIN);
  ReadFile(ISOFile, DR, SizeOf(TDirectoryRecord), BytesRead, nil);
  SetFilePointer(ISOFile, DR.ExtentLocation * SECTOR_SIZE, nil, FILE_BEGIN);
  Result := ISOScanFiles(ISOFile, Output, Max, Start);
end;
 
end.

Open in new window

The iso's I'm dealing with might be a tad different from yours. But the code works for me. With your modification does it now work for you?
yes, it works. maybe some time later i'll try to find out what's wrong with the recursion.