Here's a question to start off the thread.
Earlier today I was trying to get write some basic AHK functions which allow me to convert characters which I've copied to the clipboard to a different representation. For instance, my initial use case was something like this: I want to be able to copy a series of bytes from my hex editor (as hex bytes) and use a hotkey to trigger a function (or series of functions) which will bit-invert those bytes, then save them as hex bytes back to the clipboard. Once that's done, I can paste them back into my hex editor and see the ASCII representation of the inverted bytes.
The strategy I used to go about this was seemingly simple, but possibly too complex. I'm not sure. I assume up front that the bytes I'm copying are already valid hex bytes, 0-9 and A-F, regardless of case (uppercase everything internally), and ignore whitespace (SPC, TAB, and RET). Convert from hex to a binary value, invert the value, then convert from binary to hex and save to the clipboard.
I'm not terribly familiar with writing functions in AHK; mostly I use it for hotstrings and hotkeys only. I tried my hand at a couple different approaches, none of which worked fully. I also looked at the following code samples on the AHK Community Forums, which seemed really interesting, but also overkill for what I want.
http://www.autohotkey.com/forum/topic21172.htmlhttp://www.autohotkey.com/forum/topic21172-105.htmlI did find some code in AutoIt (v3) that I modified only slightly that works well (at least the one bit I've tested), but the problem is that I don't run AutoIt like I run AutoHotkey, i.e. running in my system tray, capturing key macros, replacing text, etc. I probably can run AutoIt that way (I'd have to look into it), but generally I run AutoIt scripts for specific tasks, and don't really use it the same way I use AutoHotkey. While I could just write hotkeys in AutoHotkey to call the AutoIt scripts, that gets rid of the idea of having this be self-contained in my standard AHK script, and complicates deployment.
Any ideas? I'm open to all approaches, as long as I can make sense of the code.
Thanks in advance!
Here's the edited AutoIt code (as it stands right now):
; baseconv.au3 -- Base conversion functions for representative strings (binary
; strings, decimal values, hex values).
; ==============================================================================
; FUNCTIONS
; ==============================================================================
;
; Original code for functions by "ptrex" on AutoIt Forums
; http://www.autoitscript.com/forum/index.php?showtopic=70507
; --------------------------------------------------------------------------
; BinStr2Dec
; --------------------------------------------------------------------------
Func BinStr2Dec($strBin)
Local $Return
Local $lngResult
Local $intIndex
If StringRegExp($strBin,'[0-1]') then
$lngResult = 0
For $intIndex = StringLen($strBin) to 1 step -1
$strDigit = StringMid($strBin, $intIndex, 1)
Select
case $strDigit="0"
; do nothing
case $strDigit="1"
$lngResult = $lngResult + (2 ^ (StringLen($strBin)-$intIndex))
case else
; invalid binary digit, so the whole thing is invalid
$lngResult = 0
$intIndex = 0 ; stop the loop
EndSelect
Next
$Return = $lngResult
Return $Return
Else
MsgBox(0,"Error","Wrong input, try again ...")
Return
EndIf
EndFunc
; --------------------------------------------------------------------------
; Dec2BinStr
; --------------------------------------------------------------------------
Func Dec2BinStr($iDec)
Local $i, $sBinChar = ""
If StringRegExp($iDec,'[[:digit:]]') then
$i = 1
Do
$x = 16^$i
$i +=1
; Determine the Octects
Until $iDec < $x
For $n = 4*($i-1) To 1 Step -1
If BitAND(2 ^ ($n-1), $iDec) Then
$sBinChar &= "1"
Else
$sBinChar &= "0"
EndIf
Next
Return $sBinChar
Else
MsgBox(0,"Error","Wrong input, try again ...")
Return
EndIf
EndFunc
; --------------------------------------------------------------------------
; Hex2Dec
; --------------------------------------------------------------------------
Func Hex2Dec($Input)
Local $Temp, $i, $Pos, $Ret, $Output
If StringRegExp($input,'[[:xdigit:]]') then
$Temp = StringSplit($Input,"")
For $i = 1 to $Temp[0]
$Pos = $Temp[0] - $i
$Ret = Dec (Hex ("0x" & $temp[$i] )) * 16 ^ $Pos
$Output = $Output + $Ret
Next
return $Output
Else
MsgBox(0,"Error","Wrong input, try again ...")
Return
EndIf
EndFunc
; --------------------------------------------------------------------------
; Dec2Hex
; --------------------------------------------------------------------------
Func Dec2Hex($Input)
local $Output, $Ret
If StringRegExp($input,'[[:digit:]]') then
Do
$Ret = Int(mod($Input,16))
$Input = $Input/16
$Output = $Output & StringRight(Hex($Ret),1)
Until Int(mod($Ret,16))= 0
Return StringMid(_StringReverse($Output),2)
Else
MsgBox(0,"Error","Wrong input, try again ...")
Return
EndIf
EndFunc
; --------------------------------------------------------------------------
; BinStr2Hex
; --------------------------------------------------------------------------
Func BinStr2Hex($strBin)
Local $test, $Result = '',$numbytes,$nb
If StringRegExp($strBin,'[0-1]') then
if $strBin = '' Then
SetError(-2)
Return
endif
Local $bits = "0000|0001|0010|0011|0100|0101|0110|0111|1000|1001|1010|1011|1100|1101|1110|1111"
$bits = stringsplit($bits,'|')
#region check string is binary
$test = stringreplace($strBin,'1','')
$test = stringreplace($test,'0','')
if $test <> '' Then
SetError(-1);non binary character detected
Return
endif
#endregion check string is binary
#region make binary string an integral multiple of 4 characters
While 1
$nb = Mod(StringLen($strBin),4)
if $nb = 0 then exitloop
$strBin = '0' & $strBin
WEnd
#endregion make binary string an integral multiple of 4 characters
$numbytes = Int(StringLen($strBin)/4);the number of bytes
Dim $bytes[$numbytes],$Deci[$numbytes]
For $j = 0 to $numbytes - 1;for each byte
;extract the next byte
$bytes[$j] = StringMid($strBin,1+4*$j,4)
;find what the dec value of the byte is
for $k = 0 to 15;for all the 16 possible hex values
if $bytes[$j] = $bits[$k+1] Then
$Deci[$j] = $k
ExitLoop
EndIf
next
Next
;now we have the decimal value for each byte, so stitch the string together again
$Result = ''
for $l = 0 to $numbytes - 1
$Result &= Hex($Deci[$l],1)
Next
return $Result
Else
MsgBox(0,"Error","Wrong input, try again ...")
Return
EndIf
EndFunc
; --------------------------------------------------------------------------
; Hex2BinStr
; --------------------------------------------------------------------------
Func Hex2BinStr($strHex)
Local $Allowed = '0123456789ABCDEF'
Local $Test,$n
Local $Result = ''
if $strHex = '' then
SetError(-2)
Return
EndIf
$strHex = StringSplit($strHex,'')
for $n = 1 to $strHex[0]
if not StringInStr($Allowed,$strHex[$n]) Then
SetError(-1)
return 0
EndIf
Next
Local $bits = "0000|0001|0010|0011|0100|0101|0110|0111|1000|1001|1010|1011|1100|1101|1110|1111"
$bits = stringsplit($bits,'|')
for $n = 1 to $strHex[0]
$Result &= $bits[Dec($strHex[$n])+1]
Next
Return $Result
EndFunc
; ==============================================================================
; TEST CODE
; ==============================================================================
; Quick and drity, not good test code, but works for now.
; Currently only tests Hex2BinStr.
Dim $testVal1 = "DEAD"
Dim $returnVal1 = Hex2BinStr($testVal1)
MsgBox(0,"Results",$returnVal1)
; Expected value: 1101111010101101
Dim $testVal2 = "2152"
Dim $returnVal2 = Hex2BinStr($testVal2)
MsgBox(0,"Results",$returnVal2)
; Expected value: 0010000101010010
Dim $testVal3 = "b57b"
Dim $returnVal3 = Hex2BinStr($testVal3)
MsgBox(0,"Results",$returnVal3)
; Expected value: 1011010101111011