Alternate Data Stream as data storage

Post your working scripts, libraries and tools
haichen
Posts: 337
Joined: 09 Feb 2014, 08:24

Alternate Data Stream as data storage

14 Feb 2020, 02:42

I like autohotkey programs that only consist of one script or one exe file.
That's why I don't like ini files. But to save data beyond the end of the program you can use ADS.
ADS or Alternate Data Streams are separately addressable attachments to a file.
Under Windows the file system NTFS allows invisible storage of content as alternate data streams in files and folders.
My functions read and write values in ini-format to an ADS in the script or compiled program.

Requirement: NTFS file system

Code: Select all

ADSreset(stream:="sfdata"){
	filedelete,% A_ScriptFullPath ":" stream
	return
}

ADSload(stream, params*){
	stream_1:=A_ScriptFullPath ":" stream
	; If something goes wrong, you can delete the ADS by
	; renaming the Program eg ads.ahk => adsreset.ahk - after that, rename it back.
	; ADS will be also deleted by copying to fat32
	if InStr(A_ScriptName, "reset"){
		filedelete,%stream_1%
		return
	}
	
	for index,param in params
		IniRead, %param%, %stream_1%, Section, %param% , %a_space%

	return
}


ADSsave(stream, params*){
	stream_1:=A_ScriptFullPath ":" stream
	if InStr(A_ScriptName, "reset"){
		filedelete,%stream_1%
		return
	}
	
	for index,param in params
		IniWrite,% %param%, %stream_1%, section, %param%
	
	return
}
simple example:

Code: Select all

Gui +Resize -DPIScale
Gui, Add, Edit, x10 y10 w200 h200 vMyEdit, 
Gui, Add, text, x+10  w160 h200 , Write some text, save data, reload (or quit and restart) the program. Then load data
Gui, Add, button,x10 gsave,save data to ADS
Gui, Add, button,gload,load data from ADS
Gui, Add, button,greload,reload the program
Gui, Add, button,y+20 greset,reset (delete ADS)
gui, show, x200 y200 w400, Alternate Data Stream as Ini
return

load:
Gui, submit, noHide
ADSload("sfdata", "MyEdit")
GuiControl,,myEdit, % MyEdit
return

save:
Gui, submit, noHide
ADSsave("sfdata", "MyEdit")
return

reload:
Reload
return

esc::
GuiClose:
ExitApp

Reset:
ADSreset("sfdata")
return

ADSreset(stream:="sfdata"){
	filedelete,% A_ScriptFullPath ":" stream
	return
}

ADSload(stream, params*){
	stream_1:=A_ScriptFullPath ":" stream
	; If something goes wrong, you can delete the ADS by
	; renaming the Program eg ads.ahk => adsreset.ahk - after that, rename it back.
	; ADS will be also deleted by copying to fat32
	if InStr(A_ScriptName, "reset"){
		filedelete,%stream_1%
		return
	}
	
	for index,param in params
		IniRead, %param%, %stream_1%, Section, %param% , %a_space%

	return
}


ADSsave(stream, params*){
	stream_1:=A_ScriptFullPath ":" stream
	if InStr(A_ScriptName, "reset"){
		filedelete,%stream_1%
		return
	}
	
	for index,param in params
		IniWrite,% %param%, %stream_1%, section, %param%
	
	return
}
more complex example:

Code: Select all

global var1, var2, var3, laststart, gx, gy, gh, gw

FormatTime, start , a_now, dd.MM.yyyy HH:mm:ss

ADSload("sfdata","var1","var2","var3","laststart")
if (var1="") or (var2="") or (var3="") or (laststart="")
	var1:=0, var2:=200, var3:="hallo ", laststart := start

var1  +=1
var2  *=3
var3 .="a"


Gui +Resize -DPIScale
Gui, Add, Text,, Resize and move the Window. `nClose and restart the Script.
Gui, Add, Text,vtt w300 h150, 
Gui, Add, button,greset,Reset
gui, show, x200 y200 w400 h300, Alternate Data Stream as data storage
loadGP()
GuiControl, , tt,  % "counter = " var1 " times started `nVar = " var2 "`notherVar = " var3 "`nLast Programstart = " laststart "`n`nX = " gx "`nY = " gy "`nWidth = " gw "`nHeight = " gh
return

esc::
GuiClose:
saveGP()
laststart := start
ADSsave("sfdata","var1","var2","var3","laststart")
ExitApp

saveGP(){
	WinGetPos, gx, gy, gw, gh, a
	ADSsave("sfdata","gx","gy","gw","gh")
	return
}


loadGP(){
	ADSload("sfdata","gx","gy","gw","gh")
	if (gx="") or (gy="") or (gw="") or (gh="")
		gx:=200, gy:=200, gw:=400, gh:=300
	else
		WinMove, a, , %gx%, %gy%, %gw%, %gh%
	return
}



Reset:
Gui, Submit , NoHide
ADSreset("sfdata")
Reload
return

ADSreset(stream:="sfdata"){
	filedelete,% A_ScriptFullPath ":" stream
	return
}

ADSload(stream, params*){
	stream_1:=A_ScriptFullPath ":" stream
	; If something goes wrong, you can delete the ADS by
	; renaming the Program eg ads.ahk => adsreset.ahk - after that, rename it back.
	; ADS will be also deleted by copying to fat32
	if InStr(A_ScriptName, "reset"){
		filedelete,%stream_1%
		return
	}
	
	for index,param in params
		IniRead, %param%, %stream_1%, Section, %param% , %a_space%

	return
}


ADSsave(stream, params*){
	stream_1:=A_ScriptFullPath ":" stream
	if InStr(A_ScriptName, "reset"){
		filedelete,%stream_1%
		return
	}
	
	for index,param in params
		IniWrite,% %param%, %stream_1%, section, %param%
	
	return
}
haichen
Posts: 337
Joined: 09 Feb 2014, 08:24

Re: Alternate Data Stream as data storage

14 Feb 2020, 03:21

I have added a simple example.
guest3456
Posts: 3051
Joined: 09 Oct 2013, 10:31

Re: Alternate Data Stream as data storage

14 Feb 2020, 12:28

haichen wrote:
14 Feb 2020, 02:42
But to save data beyond the end of the program you can use ADS.
ADS or Alternate Data Streams are separately addressable attachments to a file.
Under Windows the file system NTFS allows invisible storage of content as alternate data streams in files and folders.
some old information for reference:
https://autohotkey.com/board/topic/65007-trickhide-ini-file-as-part-of-the-script-file/
haichen wrote:
14 Feb 2020, 02:42
I like autohotkey programs that only consist of one script or one exe file.
That's why I don't like ini files.
you can store the ini information directly in your script inside a comment section:

Code: Select all

/*
[section]
item1=1
*/

IniRead, value, %A_ScriptFullPath%, section, item1, %A_Space%
value++
IniWrite, %value%, %A_ScriptFullPath%, section, item1

haichen
Posts: 337
Joined: 09 Feb 2014, 08:24

Re: Alternate Data Stream as data storage

14 Feb 2020, 13:53

I have been writing autohotkey scripts for quite some time, but I didn't know that. Thanks a lot. Really great.
haichen
Posts: 337
Joined: 09 Feb 2014, 08:24

Re: Alternate Data Stream as data storage

15 Feb 2020, 02:15

A nice trick, but it only works with uncompiled scripts.
Saving as Alternate Data Stream works without changes even after compilation.
So it allows the distribution of a compiled exe.
guest3456
Posts: 3051
Joined: 09 Oct 2013, 10:31

Re: Alternate Data Stream as data storage

15 Feb 2020, 20:41

haichen wrote:
15 Feb 2020, 02:15
A nice trick, but it only works with uncompiled scripts.
Saving as Alternate Data Stream works without changes even after compilation.
So it allows the distribution of a compiled exe.
yes obviously the ini trick needs an uncompiled script. data stream is a nice method

just me
Posts: 6790
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Alternate Data Stream as data storage

16 Feb 2020, 04:45

You have to keep in mind that when you copy the file to a none NTFS file system (i.e. a FAT formatted USB stick) all ADS information might be stripped.
haichen
Posts: 337
Joined: 09 Feb 2014, 08:24

Re: Alternate Data Stream as data storage

16 Feb 2020, 05:38

Yeah, I wrote that as a comment in the code. But as long as you don't want to start the program from USB-stick or any other Fat/Fat32 filesystem, it's like installing the program. I don't think you normally take an ini file with program settings with you to another computer. What I don't know is if the stream is preserved when downloading (OneDrive, Dropbox). Maybe you don't want to.

An error message would certainly be useful.

Code: Select all

DriveGet, fs, FileSystem,  % SubStr(A_ScriptDir,1,3)
if (fs <>"NTFS")
   msgbox, Program settings can only be saved under NTFS!
}

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Endif_, tidbit and 20 guests