Solved

Reading ISO files.

Posted on 2008-10-27
17
411 Views
Last Modified: 2010-05-18
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 ?
0
Comment
Question by:tadzio_blah
  • 9
  • 5
  • 3
17 Comments
 

Expert Comment

by:TECH_NET
ID: 22813750
Use MagicISO s.w

Check this link:
http://www.magiciso.com/tutorials/miso-burnwin.htm
0
 

Author Comment

by:tadzio_blah
ID: 22813783
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
0
 

Expert Comment

by:TECH_NET
ID: 22813796
I would have recommended using clonedvd but i figured that CloneCD detect CD iso images as DVD
0
 

Expert Comment

by:TECH_NET
ID: 22813809
sorry, my bad...
0
 

Author Comment

by:tadzio_blah
ID: 22813825
...anyways... can anyone post some DELPHI CODE that i can use (or a unit that handles ISO files), and NOT an app name ?
0
 
LVL 13

Accepted Solution

by:
ThievingSix earned 500 total points
ID: 22813971
Your in luck. I was just doing something along these lines.  Unfortunately I don't know how to differentiate between DVD's and CD's. But you can get a list of all files, directories, and their size/location with the code below.


unit uISO;
 

interface
 

uses

  Windows, Sysutils, Math;
 

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;

  FILTER_BY_TYPE       = $02;

  FILTER_BY_SIZE       = $04;

  FILTER_BY_DATA       = $08;

  SIZE_EQUAL           = $00;

  SIZE_GREATER         = $01;

  SIZE_LOWER           = $02;
 

function ISOSearchFiles(ISOFile: Cardinal; Output: TDirectoryArrayRecord; Max: Integer; Filter: PSearchFilter; 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; Filter: PSearchFilter; I: Integer): Integer;

var

  DR : TDirectoryRecord;

  fPointer : Cardinal;

  Add : Integer;

  OldDirLen : Cardinal;

  BytesRead : Cardinal;

  Data : PByte;

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

        Inc(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

        begin

        Break;

      end;

    end;

    If (DR.FileName[1] <> #0) And (DR.FileName[1] <> #1) Then

      begin

      Add := 1;

      If Filter <> nil Then

        begin

        If (Filter^.Flags And FILTER_BY_NAME) <> 0 Then

          begin

          If PosLen(PChar(String(DR.FileName)),PChar(String(Filter^.Name)),Filter^.DataSize) Then

            begin

            Add := 0;

          end;

        end;

        If (Filter^.Flags And FILTER_BY_TYPE) <> 0 Then

          begin

          If (Filter^.lwType = ISO_FLAG_FILE) And ((DR.FileFlags And ISO_FLAG_DIRECTORY) <> 0) Then

            begin

            Add := 0;

          end

          Else If (Filter^.lwType = ISO_FLAG_DIRECTORY) And Not((DR.FileFlags And ISO_FLAG_DIRECTORY) <> 0) Then

            begin

            Add := 0;

          end;

        end;

        If (Filter^.Flags And FILTER_BY_SIZE) <> 0 Then

          begin

          If (Filter^.SizeType = SIZE_EQUAL) And (DR.DataLength <> Filter^.Size) Then

            begin

            Add := 0;

          end

          Else If (Filter^.SizeType = SIZE_GREATER) And (DR.DataLength <= Filter^.Size) Then

            begin

            Add := 0;

          end

          Else If (Filter^.SizeType = SIZE_LOWER) And (DR.DataLength >= Filter^.Size) Then

            begin

            Add := 0;

          end;

        end

        Else If (Filter^.Flags And FILTER_BY_DATA) <> 0 Then

          begin

          Data := AllocMem(Filter^.DataSize);

          SetFilePointer(ISOFile,DR.ExtentLocation * SECTOR_SIZE,nil,FILE_BEGIN);

          ReadFile(ISOFile,Data^,Filter^.DataSize,BytesRead,nil);

          If Not(CompareMem(Data,Filter^.Data,Filter^.DataSize)) Then

            begin

            Add := 0;

          end;

        end;

      end;

      If (DR.FileFlags And ISO_FLAG_DIRECTORY) <> 0 Then

        begin

        SetFilePointer(ISOFile,DR.ExtentLocation * SECTOR_SIZE,nil,FILE_BEGIN);

        I := ISOScanFiles(ISOFile,Output,Max,Filter,I);

      end;

      If I = Max Then Break;

      If (Add <> 0) And(DR.DataLength <> 0) Then

        begin

        Output[I] := DR;

        Inc(I);

      end;

    end;

    Inc(fPointer,DR.DirectoryLength);

    OldDirLen := DR.DirectoryLength;

    SetFilePointer(ISOFile,fPointer,nil,FILE_BEGIN);

  end;

  Result := I;

end;
 

function ISOSearchFiles(ISOFile: Cardinal; Output: TDirectoryArrayRecord; Max: Integer; Filter: PSearchFilter; 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,Filter,Start);

end;
 

end.

Open in new window

0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 22813984
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

0
 

Author Comment

by:tadzio_blah
ID: 22815896
i'm getting stack overflow in the ISOScanFiles function.
0
Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

 

Author Comment

by:tadzio_blah
ID: 22816012
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).
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 22819727
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.
0
 

Author Comment

by:tadzio_blah
ID: 22822777
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).
0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 22822810
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).
0
 

Author Comment

by:tadzio_blah
ID: 22823163
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 ?
0
 

Author Comment

by:tadzio_blah
ID: 22823204
sorry, by loops i meant recursive executions of ISOScanFiles, as after 200 it didn't even start to come back from the recursion.
0
 

Author Comment

by:tadzio_blah
ID: 22823349
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

0
 
LVL 13

Expert Comment

by:ThievingSix
ID: 22823691
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?
0
 

Author Comment

by:tadzio_blah
ID: 22827505
yes, it works. maybe some time later i'll try to find out what's wrong with the recursion.
0

Featured Post

How to run any project with ease

Manage projects of all sizes how you want. Great for personal to-do lists, project milestones, team priorities and launch plans.
- Combine task lists, docs, spreadsheets, and chat in one
- View and edit from mobile/offline
- Cut down on emails

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now