76 (изменено: serzh82saratov, 2017-11-15 16:21:18)

Re: AHK: Сохранение Массива в файл

Вроде так:


#SingleInstance Force
#NoEnv

arr := {"  11":"888   ","11  ":"  999"}
Base64 := ObjToBase64(arr)
for k, v in ObjFromBase64(Base64)
	MsgBox, , Читаем полученное, % "|" k  "|"  v "|"
	
B := ["Ivan", 345, "London"]
Base64 := ObjToBase64(B)
Obj := ObjFromBase64(Base64)
for k, v in Obj
	MsgBox % k " : " v

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


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
			NumPut(-10,addr+0,"Char"),NumPut(sz:=StrPut(k,addr+9)*2,addr+1,"Int64"),addr+=sz+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
		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
	}
}

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 
			sz+=StrPut(k)*2+9
		If IsObject(v)
			sz+=objects.HasKey(v)?9:RawObjectSize(v,buf,objects)+9
		else 
			sz+=(buf?obj.GetCapacity(k):StrPut(v)*2)+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 {
			If !(k ~="S)\s") && (k + 0 != "")
				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]:=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
}
По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

77 (изменено: serzh82saratov, 2017-11-15 16:21:39)

Re: AHK: Сохранение Массива в файл

Заменил на это:

		else if NumGet(addr+0,"Char")= 10 {
			If !(k ~="S)\s") && (k + 0 != "")
				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]:=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 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
По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

78

Re: AHK: Сохранение Массива в файл

Баг нашёл.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

79

Re: AHK: Сохранение Массива в файл

Я не понял, можешь на примере кода, для функций из коллекции.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

80 (изменено: teadrinker, 2018-07-26 21:19:12)

Re: AHK: Сохранение Массива в файл

Если в скрипте установлена кодировка файлов, например UTF-8, то когда файл открывается с помощью f:=FileOpen(obj,"rw-rwd"), указатель находится не в нулевой позиции, а в позиции за BOM, в данном случае 3, и дамп записывается с третьего байта, в то время как читается он с нулевого, и скрипт зацикливается.

Баг уже исправлен.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

81

Re: AHK: Сохранение Массива в файл

Просто у меня в коллекции нет FileOpen, потому не понял в чём вопрос. А про f.Pos := 0 ты сам уже давно как то говорил, я с тех пор после FileOpen указатель всегда на ноль ставлю.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

82

Re: AHK: Сохранение Массива в файл

Если предполагается писать в RAW-формате, можно, как и предложено, указывать FileOpen(file, "w", "cp0").

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

83

Re: AHK: Сохранение Массива в файл

Ясно, просто у меня в коллекции всё переделано в строку base64, то бишь писать будем как текст, как бы тему создавал для того чтобы можно было писать массив ключом в обычный ини файл.
У меня по началу была проблема, я тогда всё переделал под строки, в смысле запись чисел производится как строки. Это конечно понижает производительность, но думаю не критично, и может оградить от большинства коллизий с большими числами, и сохранением каких то значений в первозданном виде, SetFormat чтобы не мешал например, или иными символами в них, как была проблема с пробелами. Хотя сейчас проверил тот пример на обновлённом коде из той темы, работает правильно.
Вообщем думаю оставить как есть, а для искушенных ссылка приведена.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

84

Re: AHK: Сохранение Массива в файл

Не знаю, будет ли это мнение уместно, но так же, очень удобным, да ещё и довольно универсальным, нашёл для себя использование класса JSON на этот же самый манер. Для перевода "туда" и "обратно", подобное простому:


ObjDump(o := "", fileName := "ObjDump") {
	if (IsObject( o )) {
		file := FileOpen(fileName, "w", "UTF-8")
		file.Write(JSON.Stringify( o ))
		file.Close()
		return true
	} file := FileOpen(fileName, "r", "UTF-8")
	content := JSON.Parse( file.Read() )
	file.Close()
	return content
}

Выглядит более очеловеченным и в текстовом редакторе можно поглядеть на него прямо как на понятную запись. Как считаете?

Да ещё, выглядит делом крайне полезным, добавить этот класс в коллекцию. С молчаливого согласия teadrinker, я его нещадно пользую в своих меркантильных делах, кто-то ещё, этим наверняка промышляет, а кто-то, юзает забугорные поделки, которые к прочему, не очень-то и корректны в некоторых случаях да и выглядят громоздко.

Добавьте пожалуйста. Поддержим отечественного производителя!

85

Re: AHK: Сохранение Массива в файл

Json можно использовать, но с некоторыми оговорками:

obj := [0xFF, 0xFFFF]
MsgBox, % JSON.Stringify(obj)

obj := ["0xFF", "0xFFFF"]
MsgBox, % JSON.Stringify(obj)

И ещё что-то подобное вроде было, сейчас уже не помню.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

86

Re: AHK: Сохранение Массива в файл

Да просто поместите это в комментарий в первых строках кода и делов то!
Предупреждён - значит вооружён!

87

Re: AHK: Сохранение Массива в файл

А эти символы должны возвращаться с наклонной чертой?

obj := ["`n`r	"]
MsgBox, % JSON.Stringify(obj)
По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

88

Re: AHK: Сохранение Массива в файл

Ну да, в JScript они так обозначаются. Кроме того, это и из исходного кода метода Stringify видно:

      for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(08), "\b"]]
         obj := StrReplace( obj, v[1], v[2] )
Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

89

Re: AHK: Сохранение Массива в файл

А в JSON нет простых массивов?


obj := [,,"value"]
MsgBox, % obj := JSON.Stringify(obj)
По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

90

Re: AHK: Сохранение Массива в файл

Почему нет? Заполни все ключи, и будет "простой" массив.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

91

Re: AHK: Сохранение Массива в файл

teadrinker пишет:

Заполни все ключи

А это нельзя учесть в коде?

teadrinker пишет:

Ну да, в JScript они так обозначаются

А почему не всегда?


obj := ["0xFF	"]
MsgBox, % JSON.Stringify(obj)
По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

92

Re: AHK: Сохранение Массива в файл

serzh82saratov пишет:

А это нельзя учесть в коде?

И что должно быть в результате? В массивах array в JScript пропуски ключей не поддерживаются.

serzh82saratov пишет:

А почему не всегда?

По той же причине, что и

obj := ["0xFF   "]
MsgBox, % obj[1]*1

Скажем так, особенность восприятия AHK числовых и строчных значений.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

93

Re: AHK: Сохранение Массива в файл

teadrinker пишет:

пропуски ключей не поддерживаются.

Да, я думал что просто 1 и 2 равно пусто, но нет.

obj := [,,"value"]
MsgBox % obj.haskey(1)
teadrinker пишет:

особенность восприятия AHK числовых и строчных значений.

Так это вроде легко починить, после арифметики надо проверить пробел и табуляцию.

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

94 (изменено: teadrinker, 2018-08-01 14:39:02)

Re: AHK: Сохранение Массива в файл

Можно, но не все проблемы решает:

obj := ["0xFF	"]
MsgBox, % str := JSON.Stringify(obj)
obj2 := JSON.Parse(str)

for k, v in obj2
   MsgBox, % "|" . v . "|"

obj := ["0xFF"]
MsgBox, % str := JSON.Stringify(obj)
obj2 := JSON.Parse(str)

for k, v in obj2
   MsgBox, % "|" . v . "|"

class JSON
{
   static JS := JSON._GetJScripObject()
   
   Parse(JsonString)  {
      try oJSON := this.JS.("(" JsonString ")")
      catch  {
         MsgBox, Wrong JsonString!
         Return
      }
      Return this._CreateObject(oJSON)
   }
   
   Stringify(obj)  {
      if IsObject( obj )  {
         isArray := true
         for key in obj
            if !( key = A_Index || isArray := false )
               break
            
         for k, v in obj
            str .= ( A_Index = 1 ? "" : "," ) . ( isArray ? "" : this.Stringify(k) . ":" ) . this.Stringify(v)

         return isArray ? "[" str "]" : "{" str "}"
      }
      else if (obj*1 && !RegExMatch(obj, "\s"))
         return obj
      
      for k, v in [["\", "\\"], [A_Tab, "\t"], ["""", "\"""], ["/", "\/"], ["`n", "\n"], ["`r", "\r"], [Chr(12), "\f"], [Chr(08), "\b"]]
         obj := StrReplace( obj, v[1], v[2] )
      
      while RegexMatch( obj, "[^\x20-\x7e]", key )  {
         str := Asc( key )
         val := "\u" . Chr( ( ( str >> 12 ) & 15 ) + ( ( ( str >> 12 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( ( str >> 8 ) & 15 ) + ( ( ( str >> 8 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( ( str >> 4 ) & 15 ) + ( ( ( str >> 4 ) & 15 ) < 10 ? 48 : 55 ) )
               . Chr( ( str & 15 ) + ( ( str & 15 ) < 10 ? 48 : 55 ) )
         obj := StrReplace(obj, key, val)
      }
      Return """" obj """"
   }
   
   GetFromUrl(url, body := "", contentType := "", userAgent := "")  {
      ; в случае удачи будет возвращена строка, в случае ошибки — массив с одним элементом-строкой с описанием ошибки
      try  {
         XmlHttp := ComObjCreate("Microsoft.XmlHttp")
         XmlHttp.Open("GET", url, false)
         ( contentType && XmlHttp.SetRequestHeader("Content-Type", contentType) )
         ( userAgent && XmlHttp.SetRequestHeader("User-Agent", userAgent) )
         XmlHttp.Send(body)
      }
      catch e
         Return ["Error!`n" . e.Message]
      status := XmlHttp.Status
      Return status = 200 ? XmlHttp.ResponseText : ["Error! Status: " . status . ", ResponseText: " . XmlHttp.ResponseText]
   }

   _GetJScripObject()  {
      VarSetCapacity(tmpFile, ((MAX_PATH := 260) - 14) << !!A_IsUnicode, 0)
      DllCall("GetTempFileName", Str, A_Temp, Str, "AHK", UInt, 0, Str, tmpFile)
      
      FileAppend,
      (
      <component>
      <public><method name='eval'/></public>
      <script language='JScript'></script>
      </component>
      ), % tmpFile
      
      JS := ObjBindMethod( ComObjGet("script:" . tmpFile), "eval" )
      FileDelete, % tmpFile
      JSON._AddMethods(JS)
      Return JS
   }

   _AddMethods(ByRef JS)  {
      JScript =
      (
         Object.prototype.GetKeys = function () {
            var keys = []
            for (var k in this)
               if (this.hasOwnProperty(k))
                  keys.push(k)
            return keys
         }
         Object.prototype.IsArray = function () {
            var toStandardString = {}.toString
            return toStandardString.call(this) == '[object Array]'
         }
      )
      JS.("delete ActiveXObject; delete GetObject;")
      JS.(JScript)
   }

   _CreateObject(ObjJS)  {
      res := ObjJS.IsArray()
      if (res = "")
         Return ObjJS
      
      else if (res = -1)  {
         obj := []
         Loop % ObjJS.length
            obj[A_Index] := this._CreateObject(ObjJS[A_Index - 1])
      }
      else if (res = 0)  {
         obj := {}
         keys := ObjJS.GetKeys()
         Loop % keys.length
            k := keys[A_Index - 1], obj[k] := this._CreateObject(ObjJS[k])
      }
      Return obj
   }
}

AutoHotkey не может наверняка отличить строку от числа.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

95

Re: AHK: Сохранение Массива в файл

Тогда нужно учитывать, что любая запись шестнадцатеричного вида будет восприниматься как число, приводимое к десятичному виду, если в ней нет хотя-бы одного словесного символа, или символа окончания, или новой строки, а пробелы и табы ПЕРЕД и ЗА которыми ничего не следует - просто обрезаются в любых количествах, так как их присутствие не нагружает запись смыслом.

96

Re: AHK: Сохранение Массива в файл

Да, как-то так можно. Попозже могу выложить.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

97 (изменено: serzh82saratov, 2018-08-01 21:06:48)

Re: AHK: Сохранение Массива в файл

KusochekDobra пишет:

если в ней нет хотя-бы одного словесного символа, или символа окончания, или новой строки

С ними вроде математика и так пусто вернёт. Только пробелы и табы не влияет на математику. Но думаю obj ~= "\s" самое то.

KusochekDobra пишет:

ПЕРЕД и ЗА которыми ничего не следует - просто обрезаются в любых количествах, так как их присутствие не нагружает запись смыслом.

А это зачем? Если они туда зачем то попали, значит это надо было, и это строка, а строки надо бы сохранять в оригинале.

obj*1

А если ноль?

По вопросам возмездной помощи пишите письма
E-Mail: serzh82saratov@mail.ru
OS: Win7x64, AutoHotkey_L v1.1.30.01 (Unicode 32-bit).

98

Re: AHK: Сохранение Массива в файл

Пробелы тоже думаю, надо сохранять, пусть пользователь решает, нужны они, или нет.

serzh82saratov пишет:

А если ноль?

Да, нужно на пустоту проверять, уже исправил у себя.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg

99

Re: AHK: Сохранение Массива в файл

Хотел было глупость написать, что, если JSON пользуют для передачи данных, то он должен по идее так себя и вести, но, действительно в "тру-js" - сохраняются все табы и пробелы:

console.log(JSON.stringify({empty5Space: '   5  ', empty5Tab: '			5		'}))

И я ещё донышко-постигающее, так что сильно палками не бейте, коллеги! Какие-то моменты мне пока не ведомы.
Спасибо за ваше компетентное участие!