Go Back  Xtreme Visual Basic Talk > Visual Basic .NET (2002/2003/2005/2008, including Express editions) > .NET File I/O and Registry > How to read a opened .iso, and show the user an hexadecimal offset.


Reply
 
Thread Tools Display Modes
  #1  
Old 05-29-2008, 09:31 AM
bmxje bmxje is offline
Newcomer
 
Join Date: May 2008
Posts: 2
Default How to read a opened .iso, and show the user an hexadecimal offset.

Hello,
I'm planning to make a program that can read an hexadecimal Offset of a Iso, in the way an Hexeditor would do.
For example:
The Iso i'm using is called example.iso, and Offset 00008800 in that iso starts with "02" (see screenshot 1).

Screen 1:
http://img138.imageshack.us/img138/7...xeditortv5.png

Now i want my program, to identify Offset 00008800, and show the user the first 2 numbers of Offset 00008800, so the user can check if the numbers are "02". Without using a Hexeditor.(See screen 2: )
Screen 2:
http://img515.imageshack.us/img515/8226/formshowpx3.png

(Note: i want the 2 nubers to show up in the second textbox)

How can i do that with Visual Basic?
I already wrote a opendialog script:
Code:
Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        OpenFileDialog1.InitialDirectory = "C:\"
        OpenFileDialog1.Title = "Select file"
        OpenFileDialog1.FileName = ""

        If OpenFileDialog1.ShowDialog() <> Windows.Forms.DialogResult.Cancel Then
            TextBox1.Text = OpenFileDialog1.FileName

        Else
            TextBox1.Text = ""

        End If

    End Sub

    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        My.Computer.FileSystem.ReadAllBytes(TextBox1.Text)


    End Sub
End Class
So what i basicly want to know, is how do i read the Offset 00008800, and display them in the Second textbox.
Thanks in advance!
Reply With Quote
  #2  
Old 05-29-2008, 02:23 PM
AtmaWeapon's Avatar
AtmaWeapon AtmaWeapon is online now
Ultimate Contributor

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 7,598
Default

Well, you are asking a question in the form, "I need a solution to this specific problem." I could answer it directly, but it wouldn't provide any insight into the underlying problem and the next time you face something similar you'd have another question.

If we change your specific question into a general question, we go from, "How do I display the numeric values of two bytes at this location?" to, "How do you read a byte at a specific offset in a file?" I'm going to walk you through the train of thought that leads to the solution to this general problem.

The basis of I/O operations in .NET is the Stream class. It defines a Position property that indicates the current location in the stream and a Seek method that allows you to move to a specific location in a stream. Not all streams allow random access (seeking), so these will work only if the CanSeek property returns true. I'll cover two approaches, but there's no reason why seeking shouldn't be supported in the classes we're using.

Stream is abstract (MustInherit), so we need to find an implementation that does the job. FileStream looks like a good choice, since we're working with a file. Reading the documentation indicates that in most cases, we'll be able to use random access, though if the file isn't a disk file this is not true, so we will need to check the CanSeek property before doing any random access.

Now that we know what our tool will be, let's discuss the requirements of our function. Our desired output is the value of a byte at a particular offset. We definitely need to pass the offset into this function, but it needs to have access to the stream as well. We could pass it a file name, but then retrieving multiple bytes in a row would open the file multiple times and seek multiple times; it's probably better to take a Stream parameter. Since we will be moving around in the stream, we'll make that parameter ByRef to point out that it will be modified by calling our function. We'll return Integer instead of a Byte; if the function fails to read the value (for example, the stream is smaller than the offset indicates), we'll return the integer value -1, which is impossible to represent in a Byte so the caller can tell if an error happened. Finally, we want to support the operation whether random access is available or not.

Given these requirements, the function is pretty straightforward:
Code:
    ' NOTE: to maintain consistency between streams that do and don't support random access,
    ' the offset is always relative to the current position.  If you want the offset to be from
    ' the beginning, make sure the stream position is at the beginning.
    Public Function GetByteAtOffset(ByRef stream As Stream, ByVal offset As Long) As Integer
        ' Initialize to invalid value; nothing changes it if errors happen
        Dim byteValue As Integer = -1
        Dim seekResult As Long

        If stream.CanSeek Then
            seekResult = stream.Seek(offset, SeekOrigin.Current)
            If seekResult = offset Then
                ' This executes if the seek call succeeds; ReadByte returns -1 if it can't read
                ' the value, so this conveniently handles error cases.
                byteValue = stream.ReadByte()
            End If
        Else
            ' We can't seek; we'll have to read EVERY value until we reach offset
            Dim byteCount As Integer = 0
            Dim lastValue As Integer = 0

            While byteCount < offset AndAlso Not lastValue = -1
                lastValue = stream.ReadByte()
                byteCount += 1
            End While

            ' We've advanced the file position to the offset; set the final value
            byteValue = stream.ReadByte()
        End If

        Return byteValue
    End Function
This can be used to solve your problem easily; you first tell it to read to offset 8800 (I'm assuming it's in hex), then read the byte, then read again since the function advances the pointer:
Code:
        Dim offsetAddress As Long = &H8800
        Dim values(1) As Integer

        Using input As New FileStream("data.iso", FileMode.Open)
            values(0) = GetByteAtOffset(input, 10)
            values(1) = input.ReadByte()
        End Using

        If values(0) = -1 OrElse values(1) = -1 Then
            Console.WriteLine("Error reading file.")
        Else
            Console.WriteLine("Values: {0:X2} {1:X2}", values(0), values(1))
        End If
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #3  
Old 05-29-2008, 03:22 PM
bmxje bmxje is offline
Newcomer
 
Join Date: May 2008
Posts: 2
Default

Thanks for your very clear reply.
There are a few things i dont get just jet.
First,
Yes it is a Hex code, but my Offset would be 00008800 right? in stead of &H8800?


If i take the second approch, i got this:

Code:
Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        OpenFileDialog1.InitialDirectory = "C:\"
        OpenFileDialog1.Title = "Select file"
        OpenFileDialog1.FileName = ""

        If OpenFileDialog1.ShowDialog() <> Windows.Forms.DialogResult.Cancel Then
            TextBox1.Text = OpenFileDialog1.FileName

        Else
            TextBox1.Text = ""

        End If

    End Sub

    Private Sub TextBox1_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.TextChanged

    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Dim offsetAddress As Long = &H8800
        Dim values(1) As Integer

        Using input As New FileStream(TextBox1.Text, FileMode.Open)
            values(0) = GetByteAtOffset(input, 10)
            values(1) = input.ReadByte()
        End Using

        If values(0) = -1 OrElse values(1) = -1 Then
            Console.WriteLine("Error reading file.")
        Else
            Console.WriteLine("Values: {0:X2} {1:X2}", values(0), values(1))
        End If

    End Sub
End Class
The only problem here is:
Using input As New FileStream(TextBox1.Text, FileMode.Open)
Couse it sais, Name of FileStream is not declaired.
If i press the error button, it sais i should place System.IO. in front of it, but sceince i'm already streaming i cant do that right?

Thanks again!

Last edited by bmxje; 05-29-2008 at 03:51 PM.
Reply With Quote
  #4  
Old 05-29-2008, 04:19 PM
AtmaWeapon's Avatar
AtmaWeapon AtmaWeapon is online now
Ultimate Contributor

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 7,598
Default

This is a fundamental language feature of VB .NET.

VB .NET hides this somewhat, but every class in the .NET framework is in a namespace. The Form class is actually fully defined as System.Windows.Forms.Form, because it is in the System.Windows.Forms namespace. In a bare-bones VB .NET application, no namespaces are imported so you would have to type the System.Windows.Forms.Form every time you wanted a form; this is called it's fully qualified name since it is the namespace and the class name.

But you don't have to do that in a Windows Forms project in Visual Studio. Why? (These instructions are for VS 2008; VS 2005 might be slightly different but the concept is the same.) Right-click your project and select "Properties". Click the "References" tab. At the bottom, you'll see a list labeled "Imported Namespaces". These namespaces are automatically imported into every single file in your project. Here's how importing works:

When I type "Form" in the document, the VB compiler first checks my solution for a class named Form. If it cannot find a class in my solution, it starts looking in the namespaces listed in this box; it finds System.Windows.Forms.Form and it figures this is what it means.

This isn't the only way to import a namespace, and in fact I personally never use it. If, at the top of your file (outside of the class definition), you use an Imports statement, you can import a namespace into that particular file.

For example, in your case FileStream's fully qualified name is System.IO.FileStream. You can either type its fully qualified name, or make the top of your code file look like this:
Code:
Imports System.IO

Public Class Form1
...
The reason for this feature is one of simplicity; the more namespaces you import the less useful Intellisense becomes and the more likely your class names and variable names will clash with an imported name. For example, suppose you were making a printing library and you wanted a class named "Form" to represent a form that can be printed. If there were no namespaces, you could not use this class name because System.Windows.Forms.Form is already using it. Because of namespaces, you can make your class be bmxje.Printing.Form with no problems, and there's no ambiguity.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:

Powered by liquidweb