Jump to content

Use text editor to view/edit/save binary files


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 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
  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Pickpocketz88
      Func _Binary($Int) ;Uncomment To Only Accept Integers #cs If IsInt($Int) = 0 Then Return 0 EndIf #ce If $Int < 0 Then ;Negative Numbers Will Break The Function Return 0000 EndIf Local $Integer = $Int Dim $Bin[1] = [Mod($Integer, 2)] Local $Counter = 1 Do $Integer = Floor($Integer / 2) _ArrayAdd($Bin, Mod($Integer, 2)) Until $Integer = 0 _ArrayReverse($Bin) ;Reverses The Array Because As Is, The Product Is Backwards ;A Loop To Remove Any Preceding 0's or Add 0's To Keep At Least Four Digits Select Case $Int <= 1 $Integer = "00" & _ArrayToString($Bin, "") Case $Int = 2 Or $Int = 3 $Integer = "0" & _ArrayToString($Bin, "") Case $Int >= 8 $Integer = StringTrimLeft(_ArrayToString($Bin, ""), 1) Case Else $Integer = _ArrayToString($Bin, "") EndSelect ;You Can Comment It Out Without Anything Else Having A Problem Return $Integer EndFunc I made this because I was writing something that I could use to play with Bitwise Operations and using Binary() by itself wasn't helping.
      It's very basic and will only take positive integers because that's all I needed but I'm sure with a little tweaking you could make it fit with negative and float types.
      It returns a string essentially but doesn't pose a problem when just changing numbers into binary digits.
      Example: If you were to do _Binary(5) you would get "0101" and _Binary(8) would return "1000"
      Between this last sentence and here I've changed this about a half dozen times to refine it a bit because without it checking if your number is < 0 it would break if a negative number was inserted and it wouldn't even have a problem if you put in Float Values, Regular or Special Characters but that negative value will do the trick lol.
      Anyway, I hope someone finds some use of this and thank you for reading!
      -Pick
    • By Colduction
      Hi AutoIt programmers, excuse me for bothering you with multiple topics.

      In AutoIt we can use Number() function to convert Hex string to number but it's output is different of C# output & and i wanna make it's output like AutoIt code.

      For e.g I use this in AutoIt:
      Local $dBinary = Binary("Hello") ; Create binary data from a string. Local $dExtract = Number(BinaryMid($dBinary, 1, 5)) ConsoleWrite($dExtract & @CRLF) And i use this for C#:
      using System; using System.Text; //NameSpace Is Use of Project Name namespace TEST { class Program { public static void Main(string[] args) { //declaring a variable and assigning hex value string dd = ToHex("Hello", Encoding.ASCII); decimal d = Int64.Parse(dd, System.Globalization.NumberStyles.HexNumber); Console.WriteLine("Result: " + d); //hit ENTER to exit Console.ReadLine(); } public static string ToHex(string sInput, Encoding oEncoding, bool b0x_Prefix = false) { byte[] a_binaryOutput = oEncoding.GetBytes(sInput); string sOutput = BitConverter.ToString(a_binaryOutput).Replace("-", ""); if (b0x_Prefix == false) { return sOutput; } else { return "0x" + sOutput; } } } }
      I say once again that excuse me for creating new topic, in fact i'm making a library for GAuthOTP from a topic in AutoIt.
    • By Colduction
      Hi AutoIt Programmers, i wanna figure out how to use Binary functions in C# like:

      BinaryMid
      BinaryLen
      IsBinary and other basic ones were too ez, but those two were hard to noob like me.

      I appreciate for your helps/hints.
    • By Divane
      Hello everyone. I need to convert any string to 3-digit decimal. It is possible to convert through online tools. Is there any way to do this in AutoIt.

      For Example ;
      8cdb3 = DECIMAL 056 099 100 098 051

      Is it possible the conversion above by AutoIt? Thanks.
    • By obiwanceleri
      Good evening! 
      I know this has been done to death in many programming languages and probably even in AutoIt. 
      But couldn't help myself and as a learning challenge I wrote "yet another converter" LOL
      I need your help to test it and show me "the error of my ways" but in a nutshell here's what it can do already (taken from my source file) :
      Converts all zip files recursively into a 7Zip file, with max compression REQUIRES AUTOIT Version 3.3.14.5 + Exact copy with attributes and folder structure + Extensive error checking, including files blocked by anti-virus (by file count) + Can stop process and restart later with the use of a log file + Can pause process (but in between compressing / extracting files) + Creates a .CSV file that can be used to check on compression ratios + Dynamic GUI that enables user to see console while 7zip is working + Gui can be stretched horizontally for long filenames + Up to 5 retries while transfering compressed files + Checks free space (at startup) to make sure you don't kill your OS LOL + Have converted 10,000+ files with no issues in file integrity. + Open to suggestions and program free to modify to your liking + Will eventually be fully modular and configurable (if there is interest for this) + Exit codes so you can have an idea where program went wrong (if it did) + Fully commented so users can tinker away. - Cannot save archive comments. - Not FULLY tested yet, do not use on .zip files that have no backups The program also has a very minimal GUI that can be stretched. Not a huge fan of million-button interfaces.
      I also assume some people running this program will have a 1024x768 monitor so the GUI is made accordingly.
      There is no way I am keeping this script for myself. If this is useful to anybody, feel free to use it and modify it. All I ask is you credit me (as I will credit those who contribute).
      Now here's the issues that are left to fix. Any help is greatly appreciated and I will add your name in the credits if you so wish.
      - For some reason while compression is under way, all my current explorer windows flicker; notably the cut-and-paste part. I can't seem to narrow it down. 
      - Also context menu is closed in explorer every time program compresses / extracts a new file
      - I've added support for retries if, for some reason, AutoIt can't move the converted file. This happened once after 5000-6000 conversions. Now that I've programmed the retries, the process is somewhat slower. It shouldn't affect speed though.  
      - After compressing 10,000+ files (Yes I have that many zip files! Think Mame) I've had a system meltdown. There's a leak somewhere. Am I supposed to close something and I'm not? I've added _IsPressed() lately so closing that .DLL is not the cause of this leak. 
      - Subtracting one array from another was a tricky thing to program (happens when user stops and restarts process), if you can think of a faster way I'm all in.
      Obviously if you find bugs or have suggestions, I'm all ears. 
      Changelog is included in the source file, including credits.
      PLEASE DON'T CONVERT ALL YOUR FILES YET. It's not fully tested (well I tested it but I need others to test too).
       
      Obiwanceleri
      Zip27z_102.au3
×
×
  • Create New...