Jump to content

Use text editor to view/edit/save binary files


CarlD
 Share

Recommended Posts

This code is a subset of an AutoIt tool I wrote for the classic DOS word-processor XyWrite. The tool allows 7-bit Ascii encoding of XyWrite Programming Language programs, with "readability aids" that mimic the way this code looks natively on the DOS screen. This is a special 7-bit encoding that we've used for many years in the XyWrite community to discuss XPL code on the XyWrite Mailing List. But that's neither here nor there.

The present subset consists of three utilities, which I offer here for what they're worth. The first, DVIEW.AU3, takes a binary file and displays it in the default Windows text editor, displaying only Ascii chars 32-127, the other chars being represented by ".". The command-line usage is:
DVIEW.AU3 <file_in><Enter>

The second, DREAD.AU3 (that's "Dee-Read", not "dread" ;) ), provides a similar display, except that characters outside the Ascii 32-127 range are represented by "{nnn}", where "nnn" is the 3-digit decimal Ascii number. (The initial "D" in these utilities' names stands for "decimal".) The output from DREAD.AU3 can be edited to make simple patches to binary files. The output file is named DREAD.TXT. The usage is:
DREAD.AU3 <file_in><Enter>

The third utility, DWRITE.AU3, takes DREAD output and writes it back to disk as a binary file. So, once you edit the output from DREAD, you write it to disk with:
DWRITE.AU3 <file_in><Enter>
The default file_in is DREAD.TXT -- i.e., the output of DREAD.AU3. The output file is named DWRITE.BIN, which can be renamed as desired.

You'll see that each of these scripts processes the input file character by character. If there's a faster way of doing this, for example by manipulating bit patterns, I'd be pleased to hear about it.

Here are the three scripts. Enjoy.

; DVIEW.AU3 -- AutoIt v3 [CarlD rev.9/27/15]
; Display a decimal view of a binary file
;
; Usage:
; DREAD.AU3 file_in

ProgressOn(@ScriptName,"Working")

Global $iLnLen = 0; Line length meter
Local $sTmp = "";   Temp string var

Local $sInFile = @ScriptDir & "\DVIEW.IN"
If $CmdLine[0] > 0 Then $sInFile = $CmdLine[1]
If Not FileExists($sInFile) Then
    ProgressOff()
    MsgBox(16, @Scriptname, $sInFile & " does not exist!", 3)
    Exit
EndIf

Local $sTmpFile = @ScriptDir & "\DVIEW.TMP"
Local $sOutFile = @ScriptDir & "\DVIEW.TXT"

If FileExists($sTmpFile) Then FileDelete($sTmpFile)
If FileExists($sOutFile) Then FileDelete($sOutFile)

Local $hWrIn = FileOpen($sInFile, 16);  Handle for source file
Local $sToEncode = FileRead($hWrIn);    Binary (hex) string to encode
FileClose($hWrIn)

Global $sEncoded = "";  Encoded output (string)
Local $aEncoded = HexToDec($sToEncode); Binary (hex) to decimal array
Local $iAsc = "";   Decimal Ascii number of current char

; Loop through each byte of input string
For $i = 1 To UBound($aEncoded) - 1
    $iAsc = StringFormat("%03u", $aEncoded[$i])
    $sTmp = ""

    If $iAsc > 31 And $iAsc < 128 Then
        $sTmp = Chr($aEncoded[$i])
    Else
        $sTmp = "."
    EndIf

    $sTmp = AddCrLf($sTmp)
    If $iLnLen = 0 And $sTmp = "." Then $sTmp = "{046}"
    If $iLnLen = 0 And $sTmp = ">" Then $sTmp = "{062}"
    $sEncoded &= $sTmp  
Next    

; Trim double CrLf to one; change trailing space to "{032}"
If StringRight($sEncoded, 2) = @CRLF Then _
    $sEncoded = StringTrimRight($sEncoded, 2)
If StringRight($sEncoded, 1) = " " Then _
    $sEncoded = StringTrimRight($sEncoded, 1) & "{032}"

; Add header and footer
Local $sHeader = "DVIEW v1.0" & @CRLF
$sEncoded = $sHeader & "b-gin [" & $sInFile & "]" & @CRLF & _
    $sEncoded & @CRLF & "-nd DVIEW" & @CRLF

; Write output file
Local $hWrOut = FileOpen($sTmpFile, 2)
FileWrite($sTmpFile, $sEncoded)
FileClose($hWrOut)
FileMove($sTmpFile, $sOutFile, 1)

ProgressSet(100, "Done")
Sleep(2000)
ProgressOff()
ShellExecute($sOutFile)

; --------- Function DeFinitions ---------

Func HexToDec($sHexIn); Convert hex string to decimal array
    $aHexChars = StringSplit($sHexIn, "")
    Local $aHexIn[UBound($aHexChars) / 2]
    Local $j = 0
    For $i = 1 To UBound($aHexChars) Step 2
        If $i + 1 <= UBound($aHexChars) Then
            $aHexIn[$j] = $aHexChars[$i] & $aHexChars[$i + 1]
            $j += 1
        Else
            ExitLoop
        EndIf
    Next
    Local $aDecOut[UBound($aHexIn)]
    For $i = 0 To UBound($aHexIn) - 1
        $aDecOut[$i] = Dec($aHexIn[$i])
    Next
    Return $aDecOut
EndFunc   ;==>HexToDec

Func AddCrLf($sIn); Add line breaks to output
    $iLnLen += StringLen($sIn)
    If $iLnLen > 74 Then
        $sIn &= @CRLF
        $iLnLen = 0
    EndIf
    Return $sIn
EndFunc   ;==>AddCrLf
; DREAD.AU3 -- AutoIt v3 [CarlD rev.9/27/15]
; Display a decimal view of a binary file
;
; Usage:
; DREAD.AU3 file_in

ProgressOn(@ScriptName,"Working")

Global $iLnLen = 0; Line length meter
Local $sTmp = "";   Temp string var

Local $sInFile = @ScriptDir & "\DREAD.IN"
If $CmdLine[0] > 0 Then $sInFile = $CmdLine[1]
If Not FileExists($sInFile) Then
    ProgressOff()
    MsgBox(16, @Scriptname, $sInFile & " does not exist!", 3)
    Exit
EndIf

Local $sTmpFile = @ScriptDir & "\DREAD.TMP"
Local $sOutFile = @ScriptDir & "\DREAD.TXT"

If FileExists($sTmpFile) Then FileDelete($sTmpFile)
If FileExists($sOutFile) Then FileDelete($sOutFile)

Local $hWrIn = FileOpen($sInFile, 16);  Handle for source file
Local $sToEncode = FileRead($hWrIn);    Binary (hex) string to encode
FileClose($hWrIn)

Global $sEncoded = "";  Encoded output (string)
Local $aEncoded = HexToDec($sToEncode); Binary (hex) to decimal array
Local $iAsc = "";   Decimal Ascii number of current char

; Loop through each byte of input string
For $i = 1 To UBound($aEncoded) - 1
    $iAsc = StringFormat("%03u", $aEncoded[$i])
    $sTmp = ""

    If $iAsc > 31 And $iAsc < 128 Then
        $sTmp = Chr($aEncoded[$i])
    Else
        $sTmp = "{" & $iAsc & "}"
    EndIf

    $sTmp = AddCrLf($sTmp)
    If $iLnLen = 0 And $sTmp = "." Then $sTmp = "{046}"
    If $iLnLen = 0 And $sTmp = ">" Then $sTmp = "{062}"
    $sEncoded &= $sTmp  
Next    

; Trim double CrLf to one; change trailing space to "{032}"
If StringRight($sEncoded, 2) = @CRLF Then _
    $sEncoded = StringTrimRight($sEncoded, 2)
If StringRight($sEncoded, 1) = " " Then _
    $sEncoded = StringTrimRight($sEncoded, 1) & "{032}"

; Add header and footer
Local $sHeader = "DeeREAD v1.0" & @CRLF
$sEncoded = $sHeader & "b-gin [" & $sInFile & "]" & @CRLF & _
    $sEncoded & @CRLF & "-nd DeeREAD" & @CRLF

; Write output file
Local $hWrOut = FileOpen($sTmpFile, 2)
FileWrite($sTmpFile, $sEncoded)
FileClose($hWrOut)
FileMove($sTmpFile, $sOutFile, 1)

ProgressSet(100, "Done")
Sleep(2000)
ProgressOff()
ShellExecute($sOutFile)

; --------- Function DeFinitions ---------

Func HexToDec($sHexIn); Convert hex string to decimal array
    $aHexChars = StringSplit($sHexIn, "")
    Local $aHexIn[UBound($aHexChars) / 2]
    Local $j = 0
    For $i = 1 To UBound($aHexChars) Step 2
        If $i + 1 <= UBound($aHexChars) Then
            $aHexIn[$j] = $aHexChars[$i] & $aHexChars[$i + 1]
            $j += 1
        Else
            ExitLoop
        EndIf
    Next
    Local $aDecOut[UBound($aHexIn)]
    For $i = 0 To UBound($aHexIn) - 1
        $aDecOut[$i] = Dec($aHexIn[$i])
    Next
    Return $aDecOut
EndFunc   ;==>HexToDec

Func AddCrLf($sIn); Add line breaks to output
    $iLnLen += StringLen($sIn)
    If $iLnLen > 74 Then
        If $sIn = " " Then $sIn = "{032}"
        $sIn &= @CRLF
        $iLnLen = 0
    EndIf
    Return $sIn
EndFunc   ;==>AddCrLf
; DWRITE.AU3 -- AutoIt v3 [CarlD rev.9/27/15]
; Write DVIEW encoding as binary file
;
;   Usage:
; DWRITE.AU3 file_in
; Output is sent to @ScriptDir & "DWRITE.BIN"

ProgressOn(@ScriptName,"Working")

Local $sInFile = @ScriptDir & "\DREAD.TXT"
If $CmdLine[0] > 0 Then $sInFile = $CmdLine[1]
If Not FileExists($sInFile) Then
    ProgressOff()
    MsgBox(16, @Scriptname, $sInFile & " does not exist!", 3)
    Exit
EndIf

Local $sTmpFile = @ScriptDir & "\DWRITE.TMP"
Local $sOutFile = @ScriptDir & "\DWRITE.BIN"

Local $hWrIn = FileOpen($sInFile);  Handle for source file
Local $sMaster = FileRead($hWrIn);  Master string to decode
FileClose($hWrIn)
Local $sToDecode = ""
Local $aTmp = ""

; Remove header|footer
If StringLeft($sMaster, 9) = "DeeREAD v" Then _
        $sMaster = StringTrimLeft($sMaster, StringInStr($sMaster, "]"))
If StringRight($sMaster, 13) = "-nd DeeREAD" & @CRLF Then _
        $sMaster = StringTrimRight($sMaster, 13)

Local $sFinished = ""
Local $iChunkSz = 512
Local $iAdd = 0

; - - - - - - Main Loop - - - - - -
While $sMaster
    If StringLen($sMaster) > $iChunkSz Then
        $sToDecode = StringLeft($sMaster, $iChunkSz)
        $sMaster = StringTrimLeft($sMaster, $iChunkSz)
        If StringRight($sToDecode, 2) <> @CRLF Then
            $iAdd = 1 + StringInStr($sMaster, @CRLF)
            $sToDecode &= StringLeft($sMaster, $iAdd)
            $sMaster = StringTrimLeft($sMaster, $iAdd)
        EndIf
    Else
        $sToDecode = $sMaster
        $sMaster = ""
    EndIf

    ;   Strip CrLfs
    $sToDecode = StringReplace($sToDecode, @CRLF, "")

    ;       "{nnn}" ==> 1-byte Ascii char;
    Local $aTmp = StringSplit($sToDecode, "{")
    Local $iAsc = -1
    For $i = 1 To UBound($aTmp) - 1
        $iAsc = StringLeft($aTmp[$i], 3)
        If StringInStr($aTmp[$i], "}") = 4 And _
                StringIsDigit($iAsc) Then
            If $iAsc > -1 And $iAsc < 256 Then
                $sToDecode = StringReplace($sToDecode, "{" & _
                        StringLeft($aTmp[$i], 4), Chr($iAsc))
            EndIf
        EndIf
    Next

    $sFinished &= $sToDecode
    $sToDecode = ""
WEnd
; - - - - - End Main Loop - - - - -

; Write output file
Local $hWrOut = FileOpen($sTmpFile, 2)
FileWrite($sTmpFile, $sFinished)
FileClose($hWrOut)
FileMove($sTmpFile, $sOutFile, 1)
ProgressOff()
MsgBox(0, @ScriptName, "Output in " & $sOutFile, 5)
; Done
Edited by CarlD
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...