?
Solved

Reading ISO files.

Posted on 2008-10-27
17
Medium Priority
?
425 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 

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 2000 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
 

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

Enroll in September's Course of the Month

This month’s featured course covers 16 hours of training in installation, management, and deployment of VMware vSphere virtualization environments. It's free for Premium Members, Team Accounts, and Qualified Experts!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Have you ever had your Delphi form/application just hanging while waiting for data to load? This is the article to read if you want to learn some things about adding threads for data loading in the background. First, I'll setup a general applica…
In this video you will find out how to export Office 365 mailboxes using the built in eDiscovery tool. Bear in mind that although this method might be useful in some cases, using PST files as Office 365 backup is troublesome in a long run (more on t…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Suggested Courses

719 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