1 (изменено: serzh82saratov, 2017-03-08 20:50:50)

Тема: AHK: Сохранение массива в строку

Если требуется сохранить массив, например по завершении работы сохранить в ключ ини файла или текстовый файл, а при старте скрипта восстановить массив, то используя приведённые функции можно перевести массив в строку и обратно.
Оригинал здесь, я посчитал удобным адаптировать его для использования с Base64.

ObjToBase64 - передаём массив, получаем строку.
ObjFromBase64 - передаём строку, получаем массив.

Тема для обсуждения.


ObjToBase64(obj) {
	If !IsObject(obj)
		Return
	VarSetCapacity(Bin, Size := RawObjectSize(obj, 0) + 8, 0)
    RawObject(obj, NumPut(Size - 8, 0 + (addr := &Bin), "Int64"), 0)
	DllCall("Crypt32.dll\CryptBinaryToString"  
		, Ptr, addr, UInt, Size, UInt, 0x00000001|0x40000000, UInt, 0, UIntP, TChars, "CDECL Int")
	VarSetCapacity(Base64, Req := TChars * (A_IsUnicode ? 2 : 1 ))
	DllCall("Crypt32.dll\CryptBinaryToString"  
		, Ptr, addr, UInt, Size, UInt, 0x00000001|0x40000000, Str, Base64, UIntP, Req, "CDECL Int")
	Return Base64
}

ObjFromBase64(Base64) {
	DllCall("Crypt32.dll\CryptStringToBinary", Ptr, &Base64
		, UInt, StrLen(Base64), UInt, 1, UInt, 0, UIntP, Bytes, Int, 0, Int, 0, "CDECL Int")
	VarSetCapacity(OutData, Req := Bytes * (A_IsUnicode ? 2 : 1))
	DllCall("Crypt32.dll\CryptStringToBinary", Ptr, &Base64
		, UInt, StrLen(Base64), UInt, 1, Str, OutData, UIntP, Req, Int, 0, Int, 0, "CDECL Int")
	Return ObjLoad(&OutData)
}

RawObject(obj, addr, buf := 0, objects := 0) {
	; Type.Enum:    Char.1 UChar.2 Short.3 UShort.4 Int.5 UInt.6 Int64.7 UInt64.8 Double.9 String.10 Object.11
	; Negative for keys and positive for values
	if !objects
		objects:={(""):0,(obj):0}
	else objects[obj]:=(++objects[""])
	for k,v in obj
	{ ; 9 = Int64 for size and Char for type
		If IsObject(k){
			If objects.HasKey(k)
				NumPut(-12,addr+0,"Char"),NumPut(objects[k],addr+1,"Int64"),addr+=9
			else NumPut(-11,addr+0,"Char"),NumPut(sz:=RawObjectSize(k,buf),addr+1,"Int64"),RawObject(k,addr+9,buf,objects),addr+=sz+9
		}else if (k+0="")
			NumPut(-10,addr+0,"Char"),NumPut(sz:=StrPut(k,addr+9)*2,addr+1,"Int64"),addr+=sz+9
		else NumPut( InStr(k,".")?-9:k>4294967295?-8:k>65535?-6:k>255?-4:k>-1?-2:k>-129?-1:k>-32769?-3:k>-2147483649?-5:-7,addr+0,"Char")
			,NumPut(k,addr+1,InStr(k,".")?"Double":k>4294967295?"UInt64":k>65535?"UInt":k>255?"UShort":k>-1?"UChar":k>-129?"Char":k>-32769?"Short":k>-2147483649?"Int":"Int64")
			,addr+=InStr(k,".")||k>4294967295?9:k>65535?5:k>255?3:k>-129?2:k>-32769?3:k>-2147483649?5:9
		If IsObject(v){
			if objects.HasKey(v)
				NumPut( 12,addr+0,"Char"),NumPut(objects[v],addr+1,"Int64"),addr+=9
			else NumPut( 11,addr+0,"Char"),NumPut(sz:=RawObjectSize(v,buf),addr+1,"Int64"),RawObject(v,addr+9,buf,objects),addr+=sz+9
			}else if (v+0="")
		NumPut( 10,addr+0,"Char"),NumPut(sz:=buf?obj.GetCapacity(k):StrPut(v)*2,addr+1,"Int64"),DllCall("RtlMoveMemory","PTR",addr+9,"PTR",buf?obj.GetAddress(k):&v,"PTR",sz),addr+=sz+9
		else NumPut(InStr(v,".")?9:v>4294967295?8:v>65535?6:v>255?4:v>-1?2:v>-129?1:v>-32769?3:v>-2147483649?5:7,addr+0,"Char")
			,NumPut(v,addr+1,InStr(v,".")?"Double":v>4294967295?"UInt64":v>65535?"UInt":v>255?"UShort":v>-1?"UChar":v>-129?"Char":v>-32769?"Short":v>-2147483649?"Int":"Int64")
			,addr+=InStr(v,".")||v>4294967295?9:v>65535?5:v>255?3:v>-129?2:v>-32769?3:v>-2147483649?5:9
	}
}

RawObjectSize(obj,buf:=0,objects:=0){
	if !objects
		objects:={(obj):1}
	else if !objects.HasKey(obj)
		objects[obj]:=1
	for k,v in obj
	{
		If IsObject(k)
			sz+=objects.HasKey(k)?9:RawObjectSize(k,buf,objects)+9
		else if (k+0="")
			sz+=StrPut(k)*2+9
		else sz+=InStr(k,".")||k>4294967295?9:k>65535?5:k>255?3:k>-129?2:k>-32769?3:k>-2147483649?5:9
		If IsObject(v)
			sz+=objects.HasKey(v)?9:RawObjectSize(v,buf,objects)+9
		else if (v+0="")
			sz+=(buf?obj.GetCapacity(k):StrPut(v)*2)+9
		else sz+=InStr(v,".")||v>4294967295?9:v>65535?5:v>255?3:v>-129?2:v>-32769?3:v>-2147483649?5:9
	}
	return sz
}

ObjLoad(addr, objects := 0) {
	obj:=[],end:=addr+8+(sz:=NumGet(addr+0,"Int64")),addr+=8
	if !objects
		objects:={0:obj}
	else objects.Push(obj)
	While addr<end{ ; 9 = Int64 for size and Char for type
		If NumGet(addr+0,"Char")=-12
			k:=objects[NumGet(addr+1,"Int64")],addr+=9
		else if NumGet(addr+0,"Char")=-11
			k:=ObjLoad(addr+1,objects),addr+=9+NumGet(addr+1,"Int64")
		else if NumGet(addr+0,"Char")=-10
			sz:=NumGet(addr+1,"Int64"),k:=StrGet(addr+9),addr+=sz+9
		else k:=NumGet(addr+1,SubStr("Char  UChar Short UShortInt   UInt  Int64 UInt64Double",(sz:=-NumGet(addr+0,"Char"))*6-5,6)),addr+=SubStr("112244888",sz,1)+1
		If NumGet(addr+0,"Char")= 12
			obj[k]:=objects[NumGet(addr+1,"Int64")],addr+=9
		else if NumGet(addr+0,"Char")= 11
			obj[k]:=ObjLoad(addr+1,objects),addr+=9+NumGet(addr+1,"Int64")
		else if NumGet(addr+0,"Char")= 10
			obj[k]:=StrGet(addr+9),obj.SetCapacity(k,sz:=NumGet(addr+1,"Int64")),DllCall("RtlMoveMemory","PTR",obj.GetAddress(k),"PTR",addr+9,"PTR",sz),addr+=sz+9
		else obj[k]:=NumGet(addr+1,SubStr("Char  UChar Short UShortInt   UInt  Int64 UInt64Double",(sz:=NumGet(addr+0,"Char"))*6-5,6)),addr+=SubStr("112244888",sz,1)+1
	}
	return obj
}

Пример:


#SingleInstance Force
#NoEnv

Arr := {"1key":{2key:[,,"value"]}}
Base64 := ObjToBase64(Arr)
MsgBox % Base64

Obj := ObjFromBase64(Base64)
MsgBox % Obj.1key.2key[3]

Prefix := {"LAlt":"<!","LCtrl":"<^","LShift":"<+","LWin":"<#"}
Base64 := ObjToBase64(Prefix)
MsgBox % Base64

Obj := ObjFromBase64(Base64)
for k, v in Obj
	MsgBox % k " : " v


B := ["Ivan", 345, "London"]
Base64 := ObjToBase64(B)
MsgBox % Base64

Obj := ObjFromBase64(Base64)
for k, v in Obj
	MsgBox % k " : " v
По вопросам возмездной помощи пишите в личку
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.26.00 (Unicode 32-bit).