StrPut/StrGet + hex/base64

Post your working scripts, libraries and tools for AHK v1.1 and older
User avatar
jeeswg
Posts: 6902
Joined: 19 Dec 2016, 01:58
Location: UK

StrPut/StrGet + hex/base64

12 Jun 2018, 17:56

- I thought that it would be good if hex/base64 support were added to StrPut/StrGet.
- I had in mind, for the Encoding parameter: 'hex' for lower-case hex, 'Hex' (or any other case other than 'hex') for upper-case hex, and 'Base64' (any case).
- I've tried to implement all of the more fiddly ideas in my wish list request myself, as custom functions, to explore their feasibility, and, to explain clearly my intentions, being some reasons. AFAIK this, my extended Sort function, and my slightly-improved dialogs are the last examples.
Sort function + extra features - AutoHotkey Community
https://autohotkey.com/boards/viewtopic.php?f=6&t=50431
slightly-improved dialogs - AutoHotkey Community
https://autohotkey.com/boards/viewtopic ... 37&t=45220
- WARNING: If something like this was in theory to be implemented as built-in functionality, into AHK, the design could be subtly or significantly different. However, I did try to create functions that matched the nature of StrPut/StrGet. Also, errors relating to writing to specific memory addresses and allocating memory can lead to script crashes. Also, these functions have not been extensively tested.

Code: Select all

;functions:
;JEE_HexGet(vAddr, oParams*) ;vAddr, vSize, vCase:="U"
;JEE_HexPut(ByRef vHex, oParams*)
;JEE_Base64Get(vAddr, oParams*) ;vAddr, vSize
;JEE_Base64Put(ByRef vBase64, oParams*)
;JEE_StrGet(vAddr, oParams*)
;JEE_StrPut(vText, oParams*)
;JEE_StrIsType(vText, vType)

;notes (base64):
;Base64 - Wikipedia
;https://en.wikipedia.org/wiki/Base64
;Specifically, given an input of n bytes, the output will be [4*Ceil(n/3)] bytes long, including padding characters.

;notes (StrPut/StrGet):
;StrPut / StrGet
;https://autohotkey.com/docs/commands/StrPutGet.htm
;[the default encoding is *CP0* (ANSI) and not CP0/UTF-16 depending on A_IsUnicode]
;Specify an empty string or "CP0" to use the system default ANSI code page.
;[StrPut with UTF-16 returns a char count, not a byte count]
;StrPut returns char count, but VarSetCapacity needs bytes.

q:: ;add hex/base64 support to StrPut/StrGet
;we need a rare string as an example:
;for use with CP0/UTF-8/UTF-16 it can be any string
;it must be a valid hex string (0-9A-F, multiple of 2 bytes)
;it must be a valid base64 string (A-Za-z0-9+/, multiple of 4 bytes, padded with =)
;so this requires: (0-9A-F, multiple of 4 bytes)
vText := "aabbccddeeff"
;vText := "aabbccddeeffaabbccddeeff"
vList := ",CP0,UTF-8,UTF-16,Hex,hex,Base64"
vOutput := ""
Loop, Parse, vList, % ","
{
	vEnc := A_LoopField
	vMult := (vEnc = "UTF-16"||vEnc = "CP1200") ? 2 : 1
	vSize := JEE_StrPut(vText, A_LoopField)
	vSize2 := vSize
	VarSetCapacity(vData, vMult*vSize, 0)
	if (vEnc = "Hex")
		vSize2 *= 4
	else if (vEnc = "Base64")
		vSize2 := 4*Ceil(vSize/3)
	JEE_StrPut(vText, &vData, vSize2, vEnc)
	vRet := JEE_StrGet(&vData, vSize, vEnc)
	vOutput .= (vMult*vSize) "`t" A_LoopField "`t" vRet "`r`n"
}
MsgBox, % vOutput
return

;==================================================

; q:: ;hex get/put example (data)
; vHex := "AABBCCDD"
; VarSetCapacity(vData, StrLen(vHex)/2, 0)
; JEE_HexPut(vHex, &vData)
; vNum := NumGet(&vData, 0, "UInt")
; MsgBox, % Format("0x{:X}", vNum) ;0xDDCCBBAA
; MsgBox, % JEE_HexGet(&vData, 3) ;AABBCC
; MsgBox, % JEE_HexGet(&vData, 3, "L") ;aabbcc
; return

; ;hex get example (file)
; vPath := A_AhkPath
; if !oFile := FileOpen(vPath, "r")
; 	return
; vSize := oFile.Length
; VarSetCapacity(vData, vSize)
; oFile.RawRead(&vData, oFile.Length)
; oFile.Close()
; Clipboard := JEE_HexGet(&vData, vSize)
; return

;cf. StrGet(Address [, Length] [, Encoding := None])
;case: U/L (upper/lower)
JEE_HexGet(vAddr, oParams*) ;vAddr, vSize, vCase:="U"
{
	static vIsVistaPlus := (DllCall("kernel32\GetVersion", UInt) & 0xFF) >= 6
	vCase := "U"
	if (oParams.Length() = 2) ;Address, Length, Case
		vSize := oParams.1, vCase := oParams.2
	else if !JEE_StrIsType(oParams.1, "number") ;Address, Case
		vCase := oParams.1, vSize := 0
	else if (oParams.1 = 0) ;Address, Length
		return
	else if oParams.HasKey(1) ;Address, Length
		vSize := oParams.1
	else ;Address
		vSize := 0
	if vIsVistaPlus
	{
		;CRYPT_STRING_NOCRLF := 0x40000000
		;CRYPT_STRING_HEXRAW := 0xC ;to return raw hex (not supported by Windows XP)
		DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4000000C, Ptr,0, UIntP,vChars)
		VarSetCapacity(vHex, vChars*2, 0)
		DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4000000C, Str,vHex, UIntP,vChars)
	}
	else
	{
		;CRYPT_STRING_HEX := 0x4 ;to return space/CRLF-separated text
		DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4, Ptr,0, UIntP,vChars)
		VarSetCapacity(vHex, vChars*2, 0)
		DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x4, Str,vHex, UIntP,vChars)
		vHex := StrReplace(vHex, "`r`n")
		vHex := StrReplace(vHex, " ")
	}
	return (vCase = "L") ? vHex : Format("{:U}", vHex)
}

;==================================================

;cf. StrPut(String [, Encoding := None])
;cf. StrPut(String, Address [, Length] [, Encoding := None])
JEE_HexPut(ByRef vHex, oParams*)
{
	if !oParams.Length()
		return Floor(StrLen(vHex)/2)
	vAddr := oParams.RemoveAt(1)
	if oParams.HasKey(1)
		vChars := oParams.1
	else
		vChars := StrLen(vHex)
	;CRYPT_STRING_HEX := 0x4
	;CRYPT_STRING_HEXRAW := 0xC ;(not supported by Windows XP)
	;DllCall("crypt32\CryptStringToBinary", Ptr,&vHex, UInt,vChars, UInt,0x4, Ptr,0, UIntP,vSize, Ptr,0, Ptr,0)
	vSize := Floor(vChars/2)
	DllCall("crypt32\CryptStringToBinary", Ptr,&vHex, UInt,vChars, UInt,0x4, Ptr,vAddr, UIntP,vSize, Ptr,0, Ptr,0)
	return vSize ;bytes written
}

;==================================================

; q:: ;base64 get/put example
; ;create ANSI string 'abcdefghijklmnopqrstuvwxyz'
; VarSetCapacity(vData, 26, 0)
; Loop, 26
; 	NumPut(96+A_Index, &vData, A_Index-1, "UChar")
; vSize := 26
; vBase64 := JEE_Base64Get(&vData, vSize)
; MsgBox, % vBase64 ;YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo=

; vBase64 := "YWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXo="
; vSize := JEE_Base64Put(vBase64)
; VarSetCapacity(vAnsi, vSize+1, 0)
; JEE_Base64Put(vBase64, &vAnsi)
; MsgBox, % StrGet(&vAnsi, "CP0")
; return

;cf. StrGet(Address [, Length] [, Encoding := None])
JEE_Base64Get(vAddr, oParams*) ;vAddr, vSize
{
	if (oParams.Length() = 2)
		vSize := oParams.1
	if !JEE_StrIsType(oParams.1, "number")
		vSize := 0
	else if (oParams.1 = 0)
		return
	else if oParams.HasKey(1)
		vSize := oParams.1
	else
		vSize := 0
	if !JEE_StrIsType(vSize, "number")
		vSize := 0
	;CRYPT_STRING_BASE64 := 0x1
	DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x1, Ptr,0, UIntP,vChars)
	VarSetCapacity(vBase64, vChars*2, 0)
	DllCall("crypt32\CryptBinaryToString", Ptr,vAddr, UInt,vSize, UInt,0x1, Str,vBase64, UIntP,vChars)
	return StrReplace(vBase64, "`r`n")
}

;==================================================

;cf. StrPut(String [, Encoding := None])
;cf. StrPut(String, Address [, Length] [, Encoding := None])
JEE_Base64Put(ByRef vBase64, oParams*)
{
	if !oParams.Length()
	{
		DllCall("crypt32\CryptStringToBinary", Ptr,&vBase64, UInt,vChars, UInt,0x1, Ptr,0, UIntP,vSize, Ptr,0, Ptr,0)
		return vSize
	}
	vAddr := oParams.RemoveAt(1)
	if oParams.HasKey(1)
		vChars := oParams.1
	else
		vChars := StrLen(vBase64)
	;CRYPT_STRING_BASE64 := 0x1
	DllCall("crypt32\CryptStringToBinary", Ptr,&vBase64, UInt,vChars, UInt,0x1, Ptr,0, UIntP,vSize, Ptr,0, Ptr,0)
	DllCall("crypt32\CryptStringToBinary", Ptr,&vBase64, UInt,vChars, UInt,0x1, Ptr,vAddr, UIntP,vSize, Ptr,0, Ptr,0)
	return vSize ;bytes written
}

;==================================================

;StrPut(String [, Encoding := None])
;StrPut(String, Address [, Length] [, Encoding := None])
;StrGet(Address [, Length] [, Encoding := None])

;StrPut(vText [, vEnc:=""])
;StrPut(vText, vAddr [, vLen] [, vEnc:=""])
;StrGet(vAddr [, vLen] [, vEnc:=""])
;JEE_HexPut(vText)
;JEE_HexPut(vText, vAddr [, vLen])
;JEE_HexGet(vAddr, vSize, vCase:="U")
;JEE_Base64Put(vText)
;JEE_Base64Put(vText, vAddr [, vLen])
;JEE_Base64Get(vAddr, vSize)

;cf. StrGet(Address [, Length] [, Encoding := None])
JEE_StrGet(vAddr, oParams*)
{
	if !oParams.Length()
		return StrGet(vAddr) ;Address
	else if (oParams.Length() > 2)
		return
	else if (oParams.Length() = 1) ;Address, Length
	&& JEE_StrIsType(oParams.1, "number")
		return StrGet(vAddr, oParams.1)
	vEnc := oParams.Pop()
	if (vEnc == "hex")
		vFunc := "JEE_HexGet", vEnc := "L"
	else if (vEnc = "Hex")
		vFunc := "JEE_HexGet", vEnc := "U"
	else if (vEnc = "Base64")
		vFunc := "JEE_Base64Get", vEnc := ""
	else
		vFunc := "StrGet"
	if oParams.Length() ;Address, Length, Encoding
		return %vFunc%(vAddr, oParams.1, vEnc)
	else ;Address, Encoding
		return %vFunc%(vAddr, vEnc)
}

;==================================================

;cf. StrPut(String [, Encoding := None])
;cf. StrPut(String, Address [, Length] [, Encoding := None])
JEE_StrPut(vText, oParams*)
{
	if !oParams.Length() ;String
		return StrPut(vText)
	else if (oParams.Length() > 3)
		return
	if !JEE_StrIsType(oParams.1, "number") ;String, Encoding
		if (oParams.1 = "Hex")
			return JEE_HexPut(vText)
		else if (oParams.1 = "Base64")
			return JEE_Base64Put(vText)
		else
			return StrPut(vText, oParams.1)
	if (oParams.Length() = 2)
	&& JEE_StrIsType(oParams.2, "number") ;String, Address, Length
		return StrPut(vText, oParams.1, oParams.2)
	vEnc := oParams.Pop()
	if (vEnc = "Hex")
		vFunc := "JEE_HexPut"
	else if (vEnc = "Base64")
		vFunc := "JEE_Base64Put"
	else
		vFunc := "StrPut"
	if (oParams.Length() = 2)
		return %vFunc%(vText, oParams.1, oParams.2, vEnc) ;String, Address, Length, Encoding
	else
		return %vFunc%(vText, oParams.1) ;String, Address, Encoding
}

;==================================================

;If Var is [not] integer|float|number|digit|xdigit|alpha|upper|lower|alnum|space|time
;e.g. if JEE_StrIsType(vText, "digit")
JEE_StrIsType(vText, vType)
{
	%vType% := vType ;for AHK v2
	;if JEE_StrIsType(vText, vType) ;[appearance of line below if converted, warning: this would cause an infinite loop]
	if vText is %vType% ;[DO NOT CONVERT]
		return 1
	else
		return 0
}

;==================================================
[EDIT:] The functions now check for 'number' instead of 'integer'.
homepage | tutorials | wish list | fun threads | donate
WARNING: copy your posts/messages before hitting Submit as you may lose them due to CAPTCHA

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: Descolada and 69 guests