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 ?
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 ?
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...
ASKER
...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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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;
ASKER
i'm getting stack overflow in the ISOScanFiles function.
ASKER
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.
ASKER
most likely it's this line:
While True Do
begin
FillChar(DR,SizeOf(TDirect oryRecord) ,0);
>>> ReadFile(ISOFile,DR,SizeOf (TDirector yRecord),B ytesRead,n il);
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).
While True Do
begin
FillChar(DR,SizeOf(TDirect
>>> ReadFile(ISOFile,DR,SizeOf
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).
ASKER
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 ?
ASKER
sorry, by loops i meant recursive executions of ISOScanFiles, as after 200 it didn't even start to come back from the recursion.
ASKER
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.
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.
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?
ASKER
yes, it works. maybe some time later i'll try to find out what's wrong with the recursion.
Check this link:
http://www.magiciso.com/tutorials/miso-burnwin.htm