Sign in to follow this  
Followers 0
CarlD

Use text editor to view/edit/save binary files

1 post in this topic

#1 ·  Posted (edited)

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

Share this post


Link to post
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
Sign in to follow this  
Followers 0

  • Similar Content

    • wakillon
      By wakillon
      BinaryToAu3Kompressor v1.0.5.4
       

       
      It's now possible to see the best compression ratio using LZMA, LZNT and Base64 compressions with differents combinations.
      Nothing too complicate, you drag'n drop a file on the picture and script Test all compression types and return the ratios.
      ( Test duration depends of file size, slowest compression is LZNT, but all decompressions are fast  )
      Free to you after, to choose the compression(s) you want...
      Yes, LZMA needs a dll ( embedded & compressed in script ) but brings a powerfull compression. 
      It opens scite with your file compressed to an au3 script with or without decompression function as you want.
      Hold Left Shift key when clicking button for just copy script to clipboard.
      Use the 3 compressions at a time works but doesn't give a good ratio, that's why i don't display it.
      Usefull for little files you want include in your scripts !
      No externals files needed, they are already in script.
      Previous downloads : 1103
      Source and Executable
      BinaryToAu3Kompressor will be added to the next version of >SciTEHopper
      Thanks to Ward for his >Base64.au3 and LZMA.au3, and trancexx for his >LZNT functions and his >Base64Decode function.
    • WoodGrain
      By WoodGrain
      Hi All,
      Trying to convert a number to binary zeros and ones but I'm getting a result I don't understand and looks more like hex than binary.
      Here's my basic code:
      $myNum = 11 $myNumBin = Binary($myNum) MsgBox(0, "Binary result", $myNumBin) What I want is "1011", what I get is 0x0B000000.
      Thanks!
    • theak
      By theak
      Trying to find a quick way to convert 30k+ WordPerfect files into Word.
      Will probably run it locally from an admin machine or server so user permissions won't affect it.
      My idea was just to open the file, select all, copy, open new word doc, paste, file, save....
      What would be the best way to go about scripting something in this way?
    • dejhost
      By dejhost
      Hello ,
      Here are three stepts that I would like to speed up - if possible: 
      STEP 1: I am generating an array, containing binary numbers  up to a certain amount of digits. My script adds leading zeros, so that each number has equal amount of digits.
      Example: 14 digit Binary array:
      I am using the code
      For $i = 0 to 2^$bit-1 ; $bit amount of digits. for example: 14 $binary = ( Dec2Bin($i) ) ; Check length of binary string $adig = $bit - StringLen($binary) ; Determine how many leading 0 have to be added $zeros = "" For $j = 1 To $adig ; add leading "0"s $zeros = $zeros & "0" Next $BinArray[$i] = $zeros & $binary ;Write binary-number to file, leading "0" Next Func Dec2Bin($D) Return (BitShift($D, 1) ? Dec2Bin(BitShift($D, 1)) : "") & BitAnd($D, 1) EndFunc ;==> Dec2Bin() AutoIt v3.3.12.0   to generate the binary number. 
      STEP 2: I reduce the array to unique values. In my application, the binary-numbers do not have a start-bit or end-bit. This means, that
        are actually the same numbers, and only one of them is to remain in the array. All alterations aren't unique and shall be removed. Here is my code:
      For $i = 0 to Ubound($BinArray)-1 ; shift through all rows For $j = 1 to $bit ; shift through all the bits If $i = Ubound($BinArray) Then ; exit before exceeding the arrays boundries ExitLoop 2 EndIf $BinArray[$i] = StringRight ( $BinArray[$i], 1 ) & StringLeft ( $BinArray[$i], $bit-1 ) $BinArray = _ArrayUnique($BinArray, 0, 0, 0, 0, $ARRAYUNIQUE_AUTO) If @error <> 0 Then Msgbox(0, "Error in _ArrayUnique", "The Error Code is " & @error & " Abort.") Exit EndIf Next Next STEP 3: Finally, I write the remaining array into a text-file.
      For $i = 0 to Ubound($BinArray)-1 FileWrite($hFileOpen, $i & @TAB & $BinArray[$i] & @CRLF) Next  
      So my question is: any idea how to speed up this procedure? There certainly is a way to do this smarter. Btw.: Step 2 is optional.
      Thanks for helping,
      dejhost 
    • am632
      By am632
      Hi,
      I have a binary string that I want to convert to octal, The string I want to convert is,
      10001001010100000100111001000111000011010000101000011010
       
      The String is read from a .txt file
      Once its converted it should read this,
      4   2   2   5   0   1   1   6   2   1   6   0   6   4   1   2   0   6   10
      which I want written to the .txt file to overwrite the original binary string.
      The 10 at the end should be ignored as there are not 3 digits to convert.
      I'm thinking it should read the string from left to right to get the next 3 digits before converting them to its oct value. would this be the best way to do this or is there a better way?
      If i'm on the right track can anyone give me an example of how to write this script please?
      I've looked at the StringLeft function & StringReplace but I'm not sure how to use them the correct way to accomplish what I'm trying to do.
      Thanks