Supports ASCII, UTF8, and Unicode with/without BOM.
DO NOT use WritePreferenceXXX functions. It is not guaranteed to work.
Windows only.
Tested with PB 5.73 and 6.10 b1 x64 x86.
Code: Select all
; API_HookEngine Module by Peyman
; https://www.purebasic.fr/english/viewtopic.php?t=64746
DeclareModule API_HookEngine_MOD
Declare Hook(*OldFunctionAddress, *NewFunctionAddress)
Declare UnHook(*hook_ptr)
EndDeclareModule
Module API_HookEngine_MOD
EnableExplicit
Structure opcode
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
mov.u
CompilerElse
mov.a
CompilerEndIf
addr.i
push.a
ret.a
EndStructure
Structure hookstruct
addr.i
hook.opcode
orig.a[SizeOf(opcode)]
EndStructure
Procedure Hook(*OldFunctionAddress, *NewFunctionAddress)
Protected *hook_ptr.hookstruct
If *OldFunctionAddress = 0
ProcedureReturn 0
EndIf
*hook_ptr = AllocateMemory(SizeOf(hookstruct))
*hook_ptr\addr = *OldFunctionAddress
CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
*hook_ptr\hook\mov = $B848
CompilerElse
*hook_ptr\hook\mov = $B8
CompilerEndIf
*hook_ptr\hook\addr = *NewFunctionAddress
*hook_ptr\hook\push = $50
*hook_ptr\hook\ret = $C3
CopyMemory(*OldFunctionAddress, @*hook_ptr\orig, SizeOf(opcode))
If WriteProcessMemory_(GetCurrentProcess_(), *OldFunctionAddress, @*hook_ptr\hook, SizeOf(opcode), 0) = 0
FreeMemory(*hook_ptr)
ProcedureReturn 0
Else
ProcedureReturn *hook_ptr
EndIf
EndProcedure
Procedure UnHook(*hook_ptr.hookstruct)
Protected retValue
If *hook_ptr
If *hook_ptr\addr
If WriteProcessMemory_(GetCurrentProcess_(), *hook_ptr\addr, @*hook_ptr\orig, SizeOf(opcode), 0)
retValue = *hook_ptr\addr
FreeMemory(*hook_ptr)
ProcedureReturn retValue
EndIf
EndIf
EndIf
ProcedureReturn 0
EndProcedure
EndModule
Structure STRUC_MemStringData
BufferSize.i
*pBuffer
EndStructure
Procedure My_CreateFileW(lpFileName.s, dwDesiredAccess.l, dwShareMode.l, lpSecurityAttributes, dwCreationDisposition.l, dwFlagsAndAttributes.l, hTemplateFile)
Protected i_Result, s_MemStringData.s, *MemStringData.STRUC_MemStringData
If Left(lpFileName, 3) = "***"
s_MemStringData = PeekS(@lpFileName + SizeOf(Character) * 3)
If s_MemStringData
*MemStringData = Val(s_MemStringData)
If *MemStringData
If *MemStringData\pBuffer And *MemStringData\BufferSize > 0
i_Result = *MemStringData
EndIf
EndIf
EndIf
EndIf
ProcedureReturn i_Result
EndProcedure
Procedure My_ReadFile(*hFile.STRUC_MemStringData, *lpBuffer, nNumberOfBytesToRead.l, *lpNumberOfBytesRead.Long, *lpOverlapped)
Protected i_Result, UTF8_BOM = $BFBBEF
If *hFile And *lpBuffer
If nNumberOfBytesToRead = 3 And *hFile\BufferSize >= 3
CopyMemory(@UTF8_BOM, *lpBuffer, 3)
If *lpNumberOfBytesRead
*lpNumberOfBytesRead\l = 3
EndIf
i_Result = 1
ElseIf nNumberOfBytesToRead > 3 And nNumberOfBytesToRead = *hFile\BufferSize
CopyMemory(*hFile\pBuffer, *lpBuffer, nNumberOfBytesToRead)
If *lpNumberOfBytesRead
*lpNumberOfBytesRead\l = nNumberOfBytesToRead
EndIf
i_Result = 1
Else
Debug "Something wrong?"
If nNumberOfBytesToRead > *hFile\BufferSize
nNumberOfBytesToRead = *hFile\BufferSize
EndIf
CopyMemory(*hFile\pBuffer, *lpBuffer, nNumberOfBytesToRead)
If *lpNumberOfBytesRead
*lpNumberOfBytesRead\l = nNumberOfBytesToRead
EndIf
i_Result = 1
EndIf
EndIf
ProcedureReturn i_Result
EndProcedure
Procedure.l My_GetFileSize(*hFile.STRUC_MemStringData, *lpFileSizeHigh)
Protected i_Size
If *hFile : i_Size = *hFile\BufferSize + 3 : EndIf
ProcedureReturn i_Size
EndProcedure
; BufferSize: The byte length of the buffer.
; StringFormat: 0, #PB_UTF8, #PB_Unicode, #PB_Ascii
; Flags: #PB_Preference_NoSpace, #PB_Preference_GroupSeparator (Flags of the OpenPreferences function)
Procedure CatchPreferences(*Buffer, BufferSize, StringFormat = 0, Flags = 0)
Protected i_Result
Protected UTF8_BOM.l = $BFBBEF, UTF16LE_BOM.u = $FEFF
Protected *MemStringData.STRUC_MemStringData
Protected *s_UTF8, s_Contents.s, s_Name.s, i_Lib
Protected *CreateFileW, *ReadFile, *GetFileSize, *NewCreateFileW, *NewReadFile, *NewGetFileSize
If Not (*Buffer And BufferSize > 0 And (StringFormat = 0 Or StringFormat = #PB_UTF8 Or StringFormat = #PB_Unicode Or StringFormat = #PB_Ascii))
ProcedureReturn 0
EndIf
*MemStringData = AllocateMemory(SizeOf(STRUC_MemStringData))
If *MemStringData = 0 : ProcedureReturn 0 : EndIf
;Search BOM.
If BufferSize >= 2
If PeekU(*Buffer) = UTF16LE_BOM
*Buffer + 2
BufferSize - 2
StringFormat = #PB_Unicode
EndIf
EndIf
If BufferSize >= 3
If CompareMemory(*Buffer, @UTF8_BOM, 3)
*Buffer + 3
BufferSize - 3
StringFormat = #PB_UTF8
*MemStringData\pBuffer = *Buffer
*MemStringData\BufferSize = BufferSize
EndIf
EndIf
Repeat
If BufferSize <= 0 : Break : EndIf
Select StringFormat
Case 0, #PB_Ascii
s_Contents = PeekS(*Buffer, BufferSize, #PB_Ascii)
Case #PB_Unicode
s_Contents = PeekS(*Buffer, BufferSize / SizeOf(Character), #PB_Unicode)
Case #PB_UTF8
If *MemStringData\pBuffer = 0
*MemStringData\pBuffer = *Buffer
*MemStringData\BufferSize = BufferSize
EndIf
EndSelect
If s_Contents
*s_UTF8 = UTF8(s_Contents)
If *s_UTF8
*MemStringData\pBuffer = *s_UTF8
*MemStringData\BufferSize = MemorySize(*s_UTF8) - 1
EndIf
EndIf
If *MemStringData\pBuffer And *MemStringData\BufferSize > 0
i_Lib = OpenLibrary(#PB_Any, "kernel32.dll")
If i_Lib = 0 : Break : EndIf
*CreateFileW = GetFunction(i_Lib, "CreateFileW")
*ReadFile = GetFunction(i_Lib, "ReadFile")
*GetFileSize = GetFunction(i_Lib, "GetFileSize")
If *CreateFileW And *ReadFile And *GetFileSize
*NewCreateFileW = API_HookEngine_MOD::Hook(*CreateFileW, @My_CreateFileW())
*NewReadFile = API_HookEngine_MOD::Hook(*ReadFile, @My_ReadFile())
*NewGetFileSize = API_HookEngine_MOD::Hook(*GetFileSize, @My_GetFileSize())
EndIf
If *NewCreateFileW And *NewReadFile And *NewGetFileSize
s_Name = "***" + Str(*MemStringData)
If Flags
i_Result = OpenPreferences(s_Name, Flags)
Else
i_Result = OpenPreferences(s_Name)
EndIf
*CreateFileW = API_HookEngine_MOD::UnHook(*NewCreateFileW)
*ReadFile = API_HookEngine_MOD::UnHook(*NewReadFile)
*GetFileSize = API_HookEngine_MOD::UnHook(*NewGetFileSize)
If Not (*CreateFileW And *ReadFile And *GetFileSize)
i_Result = 0
EndIf
EndIf
EndIf
Break
ForEver
If i_Lib : CloseLibrary(i_Lib) : EndIf
If *s_UTF8 : FreeMemory(*s_UTF8) : EndIf
FreeMemory(*MemStringData)
ProcedureReturn i_Result
EndProcedure
Code: Select all
; Example 1:
If CatchPreferences(?start_asc, ?end_asc - ?start_asc, #PB_Ascii)
If ExaminePreferenceGroups()
While NextPreferenceGroup()
Debug "Group: " + PreferenceGroupName()
If ExaminePreferenceKeys()
While NextPreferenceKey()
kn.s = PreferenceKeyName()
kv.s = PreferenceKeyValue()
If kn
Debug " " + kn + " = " + kv
EndIf
Wend
EndIf
Wend
EndIf
; If PreferenceGroup("~~~~~")
; Debug ReadPreferenceString("~~~~~", "")
; EndIf
ClosePreferences()
EndIf
DataSection
start_asc:
IncludeBinary "your pref file ~~~~~~~~~~"
end_asc:
EndDataSection
Code: Select all
; Example 2:
s.s = ~";test pref.\n" +
~"[Global] \n" +
~"value1 = 100\n" +
~"value2 = 200\n" +
~"value3 = -300\n" +
~"value4 = -400\n" +
~"\n" +
~"[Data]\n" +
~"old1 = test1\n" +
~"old2 = test2\n" +
~"old3 = 13.5\n"
sz = StringByteLength(s)
If CatchPreferences(@s, sz, #PB_Unicode)
If ExaminePreferenceGroups()
While NextPreferenceGroup()
Debug "Group: " + PreferenceGroupName()
If ExaminePreferenceKeys()
While NextPreferenceKey()
kn.s = PreferenceKeyName()
kv.s = PreferenceKeyValue()
If kn
Debug " " + kn + " = " + kv
EndIf
Wend
EndIf
Wend
EndIf
Debug "----------------------------------"
If PreferenceGroup("Global")
Debug ReadPreferenceQuad("value3", 0)
EndIf
If PreferenceGroup("Data")
Debug ReadPreferenceFloat("old3", 0)
EndIf
ClosePreferences()
EndIf