- I've added support for Floats and Doubles.
- Note: the script is now for AHK v2.
Code: Select all
;AHK v2 script
;'PuzGet'/'PuzPut' - recreate NumGet/NumPut functionality
;where 'Puz' refers to 'Code Puzzle Thread'
;note: when converting from/to Floats,
;the fractions could be *fractionally* different,
;although the tests show the expected accuracy
;note: the maths of handling the raw binary data
;of the Floats is very fiddly, so errors are possible
;AHK v2 is used because you can convert from/to Doubles
;by using the address of a variable
w:: ;test PuzPut and PuzGet functions
VarSetCapacity(vData1, 8, 0)
VarSetCapacity(vData2, 8, 0)
NumPut(-12345678, &vData1, "Int")
PuzPut(-12345678, &vData2, "Int")
MsgBox(NumGet(&vData1, "Int"))
MsgBox(NumGet(&vData2, "Int"))
MsgBox(PuzGet(&vData1, "Int"))
return
q:: ;test PuzPut and PuzGet functions
;oType := StrSplit("Char,Short,Int,Int64,Ptr,UChar,UShort,UInt,UInt64,UPtr", ",")
;oType := StrSplit("Char,Short,Int,Int64,Ptr,UChar,UShort,UInt,UInt64,UPtr,Float,Double", ",")
oType := StrSplit("Float,Double", ",")
VarSetCapacity(vData1, 8)
VarSetCapacity(vData2, 8)
Loop 10000
{
vNum := Random(-2147483648, 2147483647)
vNum *= 256**3
vTemp := Random(1, oType.Length())
vType := oType[vTemp]
NumPut(vNum, &vData1, vType)
PuzPut(vNum, &vData2, vType)
vNum1 := NumGet(&vData1, vType)
vNum2 := NumGet(&vData2, vType)
vNum1X := PuzGet(&vData1, vType)
vHex1 := Format("0x{:X}", vNum1)
vHex2 := Format("0x{:X}", vNum2)
vHex1X := Format("0x{:X}", vNum1X)
;if 0
if !(vNum1 = vNum2)
;if !InStr(vType, "Int64")
MsgBox("put`r`n" "index: " A_Index "`r`n" vType "`r`n" vNum1 "`r`n" vNum2 "`r`n" vHex1 "`r`n" vHex2)
;if 0
if !(vNum1 = vNum1X)
MsgBox("get`r`n" "index: " A_Index "`r`n" vType "`r`n" vNum1 "`r`n" vNum1X "`r`n" vHex1 "`r`n" vHex1X)
}
MsgBox("done")
return
;==================================================
PuzGet(vAddr, vType:="UPtr")
{
local
static oChar, oType := {Char:1, Short:2, Int:4, Int64:8, Ptr:A_PtrSize=8?8:4}
static vIsReady := 0
if !vIsReady
{
oChar := {0:0}
VarSetCapacity(vData, 1, 0)
Loop 255
PuzPut(A_Index, &vData, "UChar")
, vOrd := Ord(StrGet(&vData, 1, "CP0"))
, oChar[vOrd] := A_Index
vIsReady := 1
}
if (vType = "Double")
{
vData := 0.0
memcpy(&vData, vAddr, 8)
return vData
}
if (vType = "Float")
{
vNum := PuzGet(vAddr+0, "UInt")
vSign := !!(vNum & 0x80000000)
vPow := ((vNum & 0x7F800000) >> 23)
vNum := vNum & 0x7FFFFF
if (vPow = 255)
vPow := 2047
else if (vPow > 0)
vPow := (vPow - 127 + 1023)
;else if (vPow = 0)
; vPow := 0
vNum <<= (52-23)
vTemp := (vSign ? -0x8000000000000000 : 0) | (vPow << 52) | vNum
VarSetCapacity(vData, 8)
PuzPut(vTemp, &vData, "Int64")
return PuzGet(&vData, "Double")
}
vIsSigned := !RegExMatch(vType, "i)^U")
vSize := oType[RegExReplace(vType, "i)^U")]
vNum := 0
Loop vSize
vNum |= oChar[Ord(StrGet(vAddr+A_Index-1, 1, "CP0"))] << (A_Index*8-8)
if vIsSigned
if (vSize = 1) && (vNum >= 128)
return vNum - 256
else if (vSize = 2) && (vNum >= 32768)
return vNum - 65536
else if (vSize = 4) && (vNum >= 2147483648)
return vNum - 4294967296
return vNum
}
PuzPut(vNum, vAddr, vType:="UPtr")
{
local
static oChar, oType := {Char:1, Short:2, Int:4, Int64:8, Ptr:A_PtrSize=8?8:4}
static vIsReady := 0, vDataNull := 0
if !vIsReady
{
;oChar := {0:""}
oChar := {}
VarSetCapacity(vDataNull, 1, 0)
Loop 255
oChar[A_Index] := Chr(A_Index)
vIsReady := 1
}
if (vType = "Double")
{
vData := vNum + 0.0
memcpy(vAddr, &vData, 8)
return
}
if (vType = "Float")
{
vData := vNum + 0.0
vNum := PuzGet(&vData, "Int64")
;0x8000000000000000 (UInt64) = 0x8000000000000000 - 0x10000000000000000 (Int64) = -0x8000000000000000 (Int64)
vSign := !!(vNum & -0x8000000000000000)
vPow := ((vNum & 0x7FF0000000000000) >> 52)
vNum := vNum & 0xFFFFFFFFFFFFF
if (vPow = 2047)
vPow := 255
else if (vPow > 0)
vPow := (vPow - 1023 + 127) & 0xFF
;else if (vPow = 0)
; vPow := 0
vNum >>= (52-23)
vTemp := (vSign << 31) | (vPow << 23) | vNum
PuzPut(vTemp, vAddr+0, "UInt")
return
}
vSize := oType[RegExReplace(vType, "i)^U")]
Loop Min(vSize, 7)
vTemp := vNum & (0xFF << (A_Index*8-8))
, vTemp >>= (A_Index*8-8)
, (vTemp=0) ? memcpy(vAddr+A_Index-1, &vDataNull, 1) : memcpy(vAddr+A_Index-1, oChar.GetAddress(vTemp), 1)
;0xFF00000000000000 (UInt64) = (0xFF00000000000000 - 0x10000000000000000) (Int64) = -0x100000000000000 (Int64)
if (vSize = 8)
vTemp := SubStr(Format("0x{:016X}", vNum & -0x100000000000000), 1, 4)
, vTemp := Integer(vTemp)
, (vTemp=0) ? memcpy(vAddr+7, &vDataNull, 1) : memcpy(vAddr+7, oChar.GetAddress(vTemp), 1)
}
memcpy(dest, src, count){
/*
void *memcpy(
void *dest,
const void *src,
size_t count
);
url: https://msdn.microsoft.com/en-us/library/dswaw1wk.aspx (memcpy)
*/
return dllcall("MSVCRT.dll\memcpy", "ptr", dest, "ptr", src, "ptr", count, "cdecl")
}
- Haha cheers re. the function names.