Solved

Reading ISO files.

Posted on 2008-10-27
17
422 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

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
 

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

Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

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

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
There's a multitude of different network monitoring solutions out there, and you're probably wondering what makes NetCrunch so special. It's completely agentless, but does let you create an agent, if you desire. It offers powerful scalability …
Monitoring a network: why having a policy is the best policy? Michael Kulchisky, MCSE, MCSA, MCP, VTSP, VSP, CCSP outlines the enormous benefits of having a policy-based approach when monitoring medium and large networks. Software utilized in this v…
Suggested Courses
Course of the Month8 days, 6 hours left to enroll

617 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