#include-once

; Anmerkung zur UDF =============================================================================================================
; Nicht Implementiert: Map, DllStruct, Object
; - Map: wird nachgereicht, sobald die nächste Stable Maps unterstützt und ich genug Zeit und Lust habe
; - DllStruct: Problemkind, da es keine Möglichkeit gibt anhand einer Structvariable auf die eigentliche Struktur zu schließen (z.B. 'int abc[2]')
; - Object: Da Objekte grundsätzlich "Alles" sein können ist es unmöglich sie als Ganzes (vorallem Zeitunabhängig) in einem String zu speichern.
; ===============================================================================================================================

; #INDEX# =======================================================================================================================
; Title .........: ArrayToStringEx
; AutoIt Version : 3.3.12.0
; Language ......: Deutsch
; Description ...: Funktion um 1D oder 2D Arrays in Strings umzuwandeln incl. Umkehrfunktion
; Author(s) .....: Mars
; ===============================================================================================================================

; #CURRENT# =====================================================================================================================
; _ArrayToStringEx
; _StringToArrayEx
; ===============================================================================================================================

; #INTERNAL_USE_ONLY# ===========================================================================================================
; __ArrayToString1D
; __Double
; __StringPop
; __StringPopInt
; __StringToArray1D
; ===============================================================================================================================

Global Const $___HexLen_UBound = 6 ; Maximal mögliche Arrayelemente = 2^24
Global Const $___HexLen_ArraySubscripts = 2 ; Maximal 64 Stück
Global Const $___HexLen_Empty = 0 ; Wird nicht verwendet
Global Const $___HexLen_uInt8 = 2 ; Nur interne Benutzung
Global Const $___HexLen_uInt16 = 4 ; Nur interne Benutzung
Global Const $___HexLen_Int32 = 8
Global Const $___HexLen_Int64 = 16
Global Const $___HexLen_Double = 16
Global Const $___HexLen_Ptr = 16 ; Mit 64 Bit sind in jedem Fall x86 und x64 Systeme abgesichert
Global Const $___HexLen_Bool = 2 ; Eigentlich nur 1 Bit, wir nehmen aber 1 Byte !
Global Const $___HexLen_Keyword = 2 ; Wird nicht verwendet
Global Const $___MaxLen_String = 8 ; 2^32 Zeichen
Global Const $___MaxLen_Binary = 8 ; 2^32 Zeichen
Global Const $___MaxLen_FuncName = 2 ; 256 Zeichen
Global Const $___MaxLen_ArrayString = $___MaxLen_String
Global Const $___MaxLen_MapString = $___MaxLen_String
Global Const $___MaxLen_DllStructString = $___MaxLen_String

Global Const $___HexLen_ID = 2
Global Const $___ID_Empty = '00'
Global Const $___ID_uInt8 = '01' ; Nur interne Benutzung
Global Const $___ID_uInt16 = '02' ; Nur interne Benutzung
Global Const $___ID_Int32 = '03'
Global Const $___ID_Int64 = '04'
Global Const $___ID_Double = '05'
Global Const $___ID_String = '06'
Global Const $___ID_Binary = '07'
Global Const $___ID_Ptr = '08'
Global Const $___ID_Bool = '09'
Global Const $___ID_Array = '0A'
Global Const $___ID_Function = '0B'
Global Const $___ID_Map = '0C'
Global Const $___ID_DllStruct = '0D'
Global Const $___ID_Keyword = '0E'

; #FUNCTION# ====================================================================================================================
; Author ........: Mars
; Modified.......:
; ===============================================================================================================================
Func _ArrayToStringEx($aArray) ; Für 1D und 2D Arrays
	If Not IsArray($aArray) Then Return
	Local $iDim = UBound($aArray, 0)
	If $iDim = 1 Then
		Return BinaryToString('0x' & Hex($iDim, $___HexLen_ArraySubscripts) & StringTrimLeft(StringToBinary(__ArrayToString1D($aArray)), 2))
	Else ; 2D
		Local $aSub[2] = [UBound($aArray, 1), UBound($aArray, 2)], $sTmp = ''
		Local $sRet = Hex($iDim, $___HexLen_ArraySubscripts) & Hex($aSub[0], $___HexLen_UBound) & Hex($aSub[1], $___HexLen_UBound)
		For $i = 0 To $aSub[0] - 1 Step 1
			$sTmp = StringTrimLeft(StringToBinary(__ArrayToString1D($aArray, $i)), 2)
			$sRet &= Hex(StringLen($sTmp), $___MaxLen_ArrayString) & $sTmp
		Next
		Return BinaryToString('0x' & $sRet)
	EndIf
EndFunc   ;==>_ArrayToStringEx

; #FUNCTION# ====================================================================================================================
; Author ........: Mars
; Modified.......:
; ===============================================================================================================================
Func _StringToArrayEx($sString)
	If $sString = '' Then Return
	__ValidString($sString)
	Local $iDim = __StringPopInt($sString, $___HexLen_ArraySubscripts)
	If $iDim = 1 Then
		Return __StringToArray1D($sString)
	Else ; 2D
		Local $aSub[2] = [__StringPopInt($sString, $___HexLen_UBound), __StringPopInt($sString, $___HexLen_UBound)]
		Local $aRet[$aSub[0]][$aSub[1]], $iLen
		For $i = 0 To $aSub[0] - 1 Step 1
			$iLen = __StringPopInt($sString, $___MaxLen_ArrayString)
			Local $a = __StringToArray1D(__StringPop($sString, $iLen))
			For $o = 0 To $aSub[1] - 1 Step 1
				$aRet[$i][$o] = $a[$o]
			Next
		Next
		Return $aRet
	EndIf
EndFunc   ;==>_StringToArrayEx

#Region - Internal

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Author ........: Mars
; Description ...: Hilfsfunktion für _ArrayToStringEx
; ===============================================================================================================================
Func __ArrayToString1D($aArray, $iIndex = 0)
	If Not IsArray($aArray) Then Return
	Local $iUBound
	If UBound($aArray, 0) = 2 Then ; 2D Array
		$iUBound = UBound($aArray, 2)
		Local $aLinear[$iUBound]
		For $i = 0 To $iUBound - 1 Step 1
			$aLinear[$i] = $aArray[$iIndex][$i]
		Next
		$aArray = $aLinear
	Else
		$iUBound = UBound($aArray)
	EndIf
	Local $sTmp = '', $sRet = Hex($iUBound, $___HexLen_UBound)
	For $i = 0 To $iUBound - 1 Step 1
		Switch VarGetType($aArray[$i])
			Case 'Int32'
				If $aArray[$i] >= 0 And $aArray[$i] < 256 Then
					$sRet &= $___ID_uInt8 & Hex($aArray[$i], $___HexLen_uInt8)
				ElseIf $aArray[$i] >= 0 And $aArray[$i] < 65536 Then
					$sRet &= $___ID_uInt16 & Hex($aArray[$i], $___HexLen_uInt16)
				Else
					$sRet &= $___ID_Int32 & Hex($aArray[$i], $___HexLen_Int32)
				EndIf
			Case 'Int64'
				$sRet &= $___ID_Int64 & Hex($aArray[$i], $___HexLen_Int64)
			Case 'Double'
				$sRet &= $___ID_Double & Hex($aArray[$i], $___HexLen_Double)
			Case 'String'
				$sRet &= ($aArray[$i] = '' ? $___ID_Empty : $___ID_String & Hex(StringLen($aArray[$i]), $___MaxLen_String) & StringTrimLeft(StringToBinary($aArray[$i]), 2))
			Case 'Binary'
				$sRet &= $___ID_Binary & Hex(BinaryLen($aArray[$i]), $___MaxLen_Binary) & StringTrimLeft($aArray[$i], 2)
			Case 'Ptr'
				$sRet &= $___ID_Ptr & Hex($aArray[$i], $___HexLen_Ptr)
			Case 'Bool'
				$sRet &= $___ID_Bool & Hex($aArray[$i], $___HexLen_Bool)
			Case 'Array'
				$sTmp = _ArrayToStringEx($aArray[$i])
				$sRet &= $___ID_Array & Hex(Int(StringLen($sTmp)), $___MaxLen_ArrayString) & StringTrimLeft(StringToBinary($sTmp), 2)
				$sTmp = ''
			Case 'Function'
				$sRet &= $___ID_Function & Hex(StringLen(FuncName($aArray[$i])), $___MaxLen_FuncName) & StringTrimLeft(StringToBinary(FuncName($aArray[$i])), 2)
			Case 'Map' ; ########## Nicht Implementiert ##########
			Case 'DLLStruct' ; ########## Nicht Implementiert ##########
			Case 'Keyword'
				$sRet &= $___ID_Keyword & ($aArray[$i] = Default ? '01' : '00')
			Case Else
				ConsoleWrite('! Error: Unbekannter Variablentyp: ' & VarGetType($aArray[$i]) & @CRLF)
		EndSwitch

	Next
	Return BinaryToString('0x' & $sRet)
EndFunc   ;==>__ArrayToString1D

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Author ........: Mars
; Description ...: Hilfsfunktion für _StringToArrayEx
; ===============================================================================================================================
Func __StringToArray1D($sString)
	If $sString = '' Then Return
	__ValidString($sString)
	Local $iUBound = __StringPopInt($sString, $___HexLen_UBound)
	Local $aRet[$iUBound], $sTmp = ''
	For $i = 0 To $iUBound - 1 Step 1
		$sTmp = __StringPop($sString, $___HexLen_ID)
		Switch $sTmp
			Case $___ID_Empty
				; Hier muss nichts gemacht werden
			Case $___ID_uInt8
				$aRet[$i] = __StringPopInt($sString, $___HexLen_uInt8)
			Case $___ID_uInt16
				$aRet[$i] = __StringPopInt($sString, $___HexLen_uInt16)
			Case $___ID_Int32
				$aRet[$i] = __StringPopInt($sString, $___HexLen_Int32)
			Case $___ID_Int64
				$aRet[$i] = __StringPopInt($sString, $___HexLen_Int64)
			Case $___ID_Double
				$aRet[$i] = __Double(__StringPop($sString, $___HexLen_Double))
			Case $___ID_String
				$aRet[$i] = BinaryToString('0x' & __StringPop($sString, 2 * __StringPopInt($sString, $___MaxLen_String)))
			Case $___ID_Binary
				$aRet[$i] = Binary('0x' & __StringPop($sString, 2 * __StringPopInt($sString, $___MaxLen_Binary)))
			Case $___ID_Ptr
				$aRet[$i] = Ptr('0x' & __StringPop($sString, $___HexLen_Ptr))
			Case $___ID_Bool
				$aRet[$i] = __StringPopInt($sString, $___HexLen_Bool) = 1
			Case $___ID_Array
				$sTmp = _StringToArrayEx(__StringPop($sString, 2 * __StringPopInt($sString, $___MaxLen_ArrayString)))
				$aRet[$i] = $sTmp
				$sTmp = ''
			Case $___ID_Function
				$aRet[$i] = Execute(BinaryToString('0x' & __StringPop($sString, 2 * __StringPopInt($sString, $___MaxLen_FuncName))))
			Case $___ID_Map ; ########## Nicht Implementiert ##########
			Case $___ID_DllStruct ; ########## Nicht Implementiert ##########
			Case $___ID_Keyword
				$aRet[$i] = (__StringPopInt($sString, 2) = 1 ? Default : Null)
			Case Else
				ConsoleWrite('! Error: Unbekannter Variablentyp: ID = ' & $sTmp & @CRLF)
		EndSwitch
	Next
	Return $aRet
EndFunc   ;==>__StringToArray1D

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Author ........: Mars
; Description ...: Hilfsfunktion für _StringToArrayEx und __StringToArray1D
; ===============================================================================================================================
Func __ValidString(ByRef $sString)
	If Not StringIsXDigit($sString) Then
		If IsBinary($sString) Then
			$sString = StringTrimLeft($sString, 2)
		Else
			$sString = StringTrimLeft(StringToBinary($sString), 2)
		EndIf
	EndIf
EndFunc   ;==>__ValidString

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Author ........: Mars
; Description ...: Cast Hex64-String -> Double | _Double('400921F9F01B866E') = 3.14159
; ===============================================================================================================================
Func __Double($sHex64)
	Local $vInt64 = DllStructCreate('INT64'), $nRet
	DllStructSetData($vInt64, 1, '0x' & $sHex64)
	Local $vDouble = DllStructCreate('Double', DllStructGetPtr($vInt64))
	$nRet = DllStructGetData($vDouble, 1)
	Return $nRet
EndFunc   ;==>__Double

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Author ........: Mars
; Example .......: $s = '01234' | $sRet = __StringPopInt($s, 3) -> $s = '34' | $sRet = '012'
; ===============================================================================================================================
Func __StringPop(ByRef $sString, $iCount = 1)
	If $iCount > 0 Then
		Local $sLeft = StringLeft($sString, $iCount)
		$sString = StringTrimLeft($sString, $iCount)
		Return $sLeft
	Else
		Local $sRight = StringRight($sString, -$iCount)
		$sString = StringTrimRight($sString, -$iCount)
		Return $sRight
	EndIf
EndFunc   ;==>__StringPop

; #INTERNAL_USE_ONLY# ===========================================================================================================
; Author ........: Mars
; Example .......: $s = '01234' | $iRet = __StringPopInt($s, 2) -> $s = '234' | $iRet = Int(0x01) = 1
; ===============================================================================================================================
Func __StringPopInt(ByRef $sString, $iCount = 1)
	Return Int('0x' & __StringPop($sString, $iCount))
EndFunc   ;==>__StringPopInt

#EndRegion - Internal
;EndRegion - Internal